(QCtype): Remove duplicate declaration and
[bpt/emacs.git] / src / xfns.c
CommitLineData
01f1ba30 1/* Functions for the X window system.
edf36fe6 2 Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
333b20bb 3 Free Software Foundation.
01f1ba30
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
1113d9db 9the Free Software Foundation; either version 2, or (at your option)
01f1ba30
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
01f1ba30 21
c389a86d 22#include <config.h>
68c45bf0 23#include <signal.h>
333b20bb 24#include <stdio.h>
d62c8769 25#include <math.h>
c389a86d 26
3ecaf7e5
RS
27#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
30
40e6f148 31/* This makes the fields of a Display accessible, in Xlib header files. */
333b20bb 32
40e6f148
RS
33#define XLIB_ILLEGAL_ACCESS
34
01f1ba30
JB
35#include "lisp.h"
36#include "xterm.h"
f676886a 37#include "frame.h"
01f1ba30
JB
38#include "window.h"
39#include "buffer.h"
58cad5ed 40#include "intervals.h"
01f1ba30 41#include "dispextern.h"
1f98fa48 42#include "keyboard.h"
9ac0d9e0 43#include "blockinput.h"
57bda87a 44#include <epaths.h>
942ea06d 45#include "charset.h"
96db09e4 46#include "coding.h"
942ea06d 47#include "fontset.h"
333b20bb
GM
48#include "systime.h"
49#include "termhooks.h"
4ae9a85e 50#include "atimer.h"
01f1ba30
JB
51
52#ifdef HAVE_X_WINDOWS
67ba84d1 53
67ba84d1 54#include <ctype.h>
63cec32f
GM
55#include <sys/types.h>
56#include <sys/stat.h>
01f1ba30 57
0a93081c 58#ifndef VMS
0505a740 59#if 1 /* Used to be #ifdef EMACS_BITMAP_FILES, but this should always work. */
ef493a27
RS
60#include "bitmaps/gray.xbm"
61#else
dbc4e1c1 62#include <X11/bitmaps/gray>
ef493a27 63#endif
0a93081c
JB
64#else
65#include "[.bitmaps]gray.xbm"
66#endif
dbc4e1c1 67
9ef48a9d
RS
68#ifdef USE_X_TOOLKIT
69#include <X11/Shell.h>
70
398ffa92 71#ifndef USE_MOTIF
9ef48a9d
RS
72#include <X11/Xaw/Paned.h>
73#include <X11/Xaw/Label.h>
398ffa92 74#endif /* USE_MOTIF */
9ef48a9d
RS
75
76#ifdef USG
77#undef USG /* ####KLUDGE for Solaris 2.2 and up */
78#include <X11/Xos.h>
79#define USG
80#else
81#include <X11/Xos.h>
82#endif
83
84#include "widget.h"
85
86#include "../lwlib/lwlib.h"
87
333b20bb
GM
88#ifdef USE_MOTIF
89#include <Xm/Xm.h>
90#include <Xm/DialogS.h>
91#include <Xm/FileSB.h>
92#endif
93
3b882b1d
RS
94/* Do the EDITRES protocol if running X11R5
95 Exception: HP-UX (at least version A.09.05) has X11R5 without EditRes */
333b20bb 96
3b882b1d 97#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
6c32dd68 98#define HACK_EDITRES
b9dc4443 99extern void _XEditResCheckMessages ();
6c32dd68
PR
100#endif /* R5 + Athena */
101
333b20bb
GM
102/* Unique id counter for widgets created by the Lucid Widget Library. */
103
6c32dd68
PR
104extern LWLIB_ID widget_id_tick;
105
e3881aa0 106#ifdef USE_LUCID
82c90203 107/* This is part of a kludge--see lwlib/xlwmenu.c. */
03e2c340 108extern XFontStruct *xlwmenu_default_font;
e3881aa0 109#endif
9ef48a9d 110
6bc20398 111extern void free_frame_menubar ();
d62c8769 112extern double atof ();
333b20bb 113
fc2cdd9a
GM
114#ifdef USE_MOTIF
115
116/* LessTif/Motif version info. */
117
118static Lisp_Object Vmotif_version_string;
119
120#endif /* USE_MOTIF */
121
9ef48a9d
RS
122#endif /* USE_X_TOOLKIT */
123
9d317b2c
RS
124#ifdef HAVE_X11R4
125#define MAXREQUEST(dpy) (XMaxRequestSize (dpy))
126#else
127#define MAXREQUEST(dpy) ((dpy)->max_request_size)
128#endif
129
333b20bb
GM
130/* The gray bitmap `bitmaps/gray'. This is done because xterm.c uses
131 it, and including `bitmaps/gray' more than once is a problem when
132 config.h defines `static' as an empty replacement string. */
133
134int gray_bitmap_width = gray_width;
135int gray_bitmap_height = gray_height;
62906360 136char *gray_bitmap_bits = gray_bits;
333b20bb 137
498e9ac3 138/* The name we're using in resource queries. Most often "emacs". */
333b20bb 139
d387c960 140Lisp_Object Vx_resource_name;
ac63d3d6 141
498e9ac3
RS
142/* The application class we're using in resource queries.
143 Normally "Emacs". */
333b20bb 144
498e9ac3
RS
145Lisp_Object Vx_resource_class;
146
0af913d7 147/* Non-zero means we're allowed to display an hourglass cursor. */
333b20bb 148
0af913d7 149int display_hourglass_p;
333b20bb 150
01f1ba30 151/* The background and shape of the mouse pointer, and shape when not
b9dc4443 152 over text or in the modeline. */
333b20bb 153
01f1ba30 154Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 155Lisp_Object Vx_hourglass_pointer_shape;
333b20bb 156
ca0ecbf5 157/* The shape when over mouse-sensitive text. */
333b20bb 158
ca0ecbf5 159Lisp_Object Vx_sensitive_text_pointer_shape;
01f1ba30 160
8fb4ec9c
GM
161/* If non-nil, the pointer shape to indicate that windows can be
162 dragged horizontally. */
163
164Lisp_Object Vx_window_horizontal_drag_shape;
165
b9dc4443 166/* Color of chars displayed in cursor box. */
333b20bb 167
01f1ba30
JB
168Lisp_Object Vx_cursor_fore_pixel;
169
b9dc4443 170/* Nonzero if using X. */
333b20bb 171
b9dc4443 172static int x_in_use;
01f1ba30 173
b9dc4443 174/* Non nil if no window manager is in use. */
333b20bb 175
01f1ba30
JB
176Lisp_Object Vx_no_window_manager;
177
f1c7b5a6 178/* Search path for bitmap files. */
333b20bb 179
f1c7b5a6
RS
180Lisp_Object Vx_bitmap_file_path;
181
942ea06d 182/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
333b20bb 183
942ea06d
KH
184Lisp_Object Vx_pixel_size_width_font_regexp;
185
f9942c9e
JB
186Lisp_Object Qauto_raise;
187Lisp_Object Qauto_lower;
dbc4e1c1 188Lisp_Object Qbar;
f9942c9e
JB
189Lisp_Object Qborder_color;
190Lisp_Object Qborder_width;
dbc4e1c1 191Lisp_Object Qbox;
f9942c9e 192Lisp_Object Qcursor_color;
dbc4e1c1 193Lisp_Object Qcursor_type;
f9942c9e 194Lisp_Object Qgeometry;
f9942c9e
JB
195Lisp_Object Qicon_left;
196Lisp_Object Qicon_top;
197Lisp_Object Qicon_type;
80534dd6 198Lisp_Object Qicon_name;
f9942c9e
JB
199Lisp_Object Qinternal_border_width;
200Lisp_Object Qleft;
1ab3d87e 201Lisp_Object Qright;
f9942c9e 202Lisp_Object Qmouse_color;
baaed68e 203Lisp_Object Qnone;
2cbebefb 204Lisp_Object Qouter_window_id;
f9942c9e 205Lisp_Object Qparent_id;
4701395c 206Lisp_Object Qscroll_bar_width;
8af1d7ca 207Lisp_Object Qsuppress_icon;
333b20bb 208extern Lisp_Object Qtop;
01f1ba30 209Lisp_Object Qundefined_color;
a3c87d4e 210Lisp_Object Qvertical_scroll_bars;
49795535 211Lisp_Object Qvisibility;
f9942c9e 212Lisp_Object Qwindow_id;
f676886a 213Lisp_Object Qx_frame_parameter;
9ef48a9d 214Lisp_Object Qx_resource_name;
4fe1de12
RS
215Lisp_Object Quser_position;
216Lisp_Object Quser_size;
0cafb359 217extern Lisp_Object Qdisplay;
333b20bb 218Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
7c7ff7f5 219Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
ae782866 220Lisp_Object Qcompound_text, Qcancel_timer;
ea0a1f53 221Lisp_Object Qwait_for_wm;
49d41073
EZ
222Lisp_Object Qfullscreen;
223Lisp_Object Qfullwidth;
224Lisp_Object Qfullheight;
225Lisp_Object Qfullboth;
01f1ba30 226
b9dc4443 227/* The below are defined in frame.c. */
333b20bb 228
baaed68e 229extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
c2304e02 230extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
9ea173e8 231extern Lisp_Object Qtool_bar_lines;
f9942c9e 232
01f1ba30
JB
233extern Lisp_Object Vwindow_system_version;
234
a367641f 235Lisp_Object Qface_set_after_frame_default;
333b20bb 236
f1d2ce7f 237#if GLYPH_DEBUG
eaf1eea9
GM
238int image_cache_refcount, dpyinfo_refcount;
239#endif
240
241
01f1ba30 242\f
11ae94fe 243/* Error if we are not connected to X. */
333b20bb 244
7fc9de26 245void
11ae94fe
RS
246check_x ()
247{
b9dc4443 248 if (! x_in_use)
11ae94fe
RS
249 error ("X windows are not in use or not initialized");
250}
251
1c59f5df
RS
252/* Nonzero if we can use mouse menus.
253 You should not call this unless HAVE_MENUS is defined. */
75cc8ee5
RS
254
255int
1c59f5df 256have_menus_p ()
75cc8ee5 257{
b9dc4443
RS
258 return x_in_use;
259}
260
261/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
262 and checking validity for X. */
263
264FRAME_PTR
265check_x_frame (frame)
266 Lisp_Object frame;
267{
268 FRAME_PTR f;
269
270 if (NILP (frame))
0fe92f72 271 frame = selected_frame;
b7826503 272 CHECK_LIVE_FRAME (frame);
0fe92f72 273 f = XFRAME (frame);
b9dc4443 274 if (! FRAME_X_P (f))
1c59f5df 275 error ("Non-X frame used");
b9dc4443 276 return f;
75cc8ee5
RS
277}
278
b9dc4443
RS
279/* Let the user specify an X display with a frame.
280 nil stands for the selected frame--or, if that is not an X frame,
281 the first X display on the list. */
282
283static struct x_display_info *
284check_x_display_info (frame)
285 Lisp_Object frame;
286{
8ec8a5ec
GM
287 struct x_display_info *dpyinfo = NULL;
288
b9dc4443
RS
289 if (NILP (frame))
290 {
0fe92f72
GM
291 struct frame *sf = XFRAME (selected_frame);
292
293 if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
8ec8a5ec 294 dpyinfo = FRAME_X_DISPLAY_INFO (sf);
b9dc4443 295 else if (x_display_list != 0)
8ec8a5ec 296 dpyinfo = x_display_list;
b9dc4443
RS
297 else
298 error ("X windows are not in use or not initialized");
299 }
300 else if (STRINGP (frame))
8ec8a5ec 301 dpyinfo = x_display_info_for_name (frame);
b9dc4443
RS
302 else
303 {
304 FRAME_PTR f;
305
b7826503 306 CHECK_LIVE_FRAME (frame);
b9dc4443
RS
307 f = XFRAME (frame);
308 if (! FRAME_X_P (f))
1c59f5df 309 error ("Non-X frame used");
8ec8a5ec 310 dpyinfo = FRAME_X_DISPLAY_INFO (f);
b9dc4443 311 }
8ec8a5ec
GM
312
313 return dpyinfo;
b9dc4443 314}
333b20bb 315
b9dc4443 316\f
f676886a
JB
317/* Return the Emacs frame-object corresponding to an X window.
318 It could be the frame's main window or an icon window. */
01f1ba30 319
34ca5317 320/* This function can be called during GC, so use GC_xxx type test macros. */
bcb2db92 321
f676886a 322struct frame *
2d271e2e
KH
323x_window_to_frame (dpyinfo, wdesc)
324 struct x_display_info *dpyinfo;
01f1ba30
JB
325 int wdesc;
326{
f676886a
JB
327 Lisp_Object tail, frame;
328 struct frame *f;
01f1ba30 329
8e713be6 330 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
01f1ba30 331 {
8e713be6 332 frame = XCAR (tail);
34ca5317 333 if (!GC_FRAMEP (frame))
01f1ba30 334 continue;
f676886a 335 f = XFRAME (frame);
2d764c78 336 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
2d271e2e 337 continue;
0af913d7 338 if (f->output_data.x->hourglass_window == wdesc)
17cbbf95 339 return f;
9ef48a9d 340#ifdef USE_X_TOOLKIT
7556890b
RS
341 if ((f->output_data.x->edit_widget
342 && XtWindow (f->output_data.x->edit_widget) == wdesc)
333b20bb
GM
343 /* A tooltip frame? */
344 || (!f->output_data.x->edit_widget
345 && FRAME_X_WINDOW (f) == wdesc)
7556890b 346 || f->output_data.x->icon_desc == wdesc)
9ef48a9d
RS
347 return f;
348#else /* not USE_X_TOOLKIT */
fe24a618 349 if (FRAME_X_WINDOW (f) == wdesc
7556890b 350 || f->output_data.x->icon_desc == wdesc)
f676886a 351 return f;
9ef48a9d
RS
352#endif /* not USE_X_TOOLKIT */
353 }
354 return 0;
355}
356
357#ifdef USE_X_TOOLKIT
358/* Like x_window_to_frame but also compares the window with the widget's
359 windows. */
360
361struct frame *
2d271e2e
KH
362x_any_window_to_frame (dpyinfo, wdesc)
363 struct x_display_info *dpyinfo;
9ef48a9d
RS
364 int wdesc;
365{
366 Lisp_Object tail, frame;
17cbbf95 367 struct frame *f, *found;
7556890b 368 struct x_output *x;
9ef48a9d 369
17cbbf95
GM
370 found = NULL;
371 for (tail = Vframe_list; GC_CONSP (tail) && !found; tail = XCDR (tail))
9ef48a9d 372 {
8e713be6 373 frame = XCAR (tail);
34ca5317 374 if (!GC_FRAMEP (frame))
9ef48a9d 375 continue;
17cbbf95 376
9ef48a9d 377 f = XFRAME (frame);
17cbbf95 378 if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo)
333b20bb 379 {
17cbbf95
GM
380 /* This frame matches if the window is any of its widgets. */
381 x = f->output_data.x;
0af913d7 382 if (x->hourglass_window == wdesc)
17cbbf95
GM
383 found = f;
384 else if (x->widget)
385 {
386 if (wdesc == XtWindow (x->widget)
387 || wdesc == XtWindow (x->column_widget)
388 || wdesc == XtWindow (x->edit_widget))
389 found = f;
390 /* Match if the window is this frame's menubar. */
391 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
392 found = f;
393 }
394 else if (FRAME_X_WINDOW (f) == wdesc)
395 /* A tooltip frame. */
396 found = f;
333b20bb 397 }
01f1ba30 398 }
17cbbf95
GM
399
400 return found;
01f1ba30 401}
5e65b9ab 402
5fbc3f3a
KH
403/* Likewise, but exclude the menu bar widget. */
404
405struct frame *
406x_non_menubar_window_to_frame (dpyinfo, wdesc)
407 struct x_display_info *dpyinfo;
408 int wdesc;
409{
410 Lisp_Object tail, frame;
411 struct frame *f;
7556890b 412 struct x_output *x;
5fbc3f3a 413
8e713be6 414 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
5fbc3f3a 415 {
8e713be6 416 frame = XCAR (tail);
5fbc3f3a
KH
417 if (!GC_FRAMEP (frame))
418 continue;
419 f = XFRAME (frame);
2d764c78 420 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
5fbc3f3a 421 continue;
7556890b 422 x = f->output_data.x;
5fbc3f3a 423 /* This frame matches if the window is any of its widgets. */
0af913d7 424 if (x->hourglass_window == wdesc)
17cbbf95
GM
425 return f;
426 else if (x->widget)
333b20bb
GM
427 {
428 if (wdesc == XtWindow (x->widget)
429 || wdesc == XtWindow (x->column_widget)
430 || wdesc == XtWindow (x->edit_widget))
431 return f;
432 }
433 else if (FRAME_X_WINDOW (f) == wdesc)
434 /* A tooltip frame. */
5fbc3f3a
KH
435 return f;
436 }
437 return 0;
438}
439
fd3a3022
RS
440/* Likewise, but consider only the menu bar widget. */
441
442struct frame *
443x_menubar_window_to_frame (dpyinfo, wdesc)
444 struct x_display_info *dpyinfo;
445 int wdesc;
446{
447 Lisp_Object tail, frame;
448 struct frame *f;
7556890b 449 struct x_output *x;
fd3a3022 450
8e713be6 451 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
fd3a3022 452 {
8e713be6 453 frame = XCAR (tail);
fd3a3022
RS
454 if (!GC_FRAMEP (frame))
455 continue;
456 f = XFRAME (frame);
2d764c78 457 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
fd3a3022 458 continue;
7556890b 459 x = f->output_data.x;
fd3a3022 460 /* Match if the window is this frame's menubar. */
333b20bb
GM
461 if (x->menubar_widget
462 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
fd3a3022
RS
463 return f;
464 }
465 return 0;
466}
467
5e65b9ab
RS
468/* Return the frame whose principal (outermost) window is WDESC.
469 If WDESC is some other (smaller) window, we return 0. */
470
471struct frame *
2d271e2e
KH
472x_top_window_to_frame (dpyinfo, wdesc)
473 struct x_display_info *dpyinfo;
5e65b9ab
RS
474 int wdesc;
475{
476 Lisp_Object tail, frame;
477 struct frame *f;
7556890b 478 struct x_output *x;
5e65b9ab 479
8e713be6 480 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
5e65b9ab 481 {
8e713be6 482 frame = XCAR (tail);
34ca5317 483 if (!GC_FRAMEP (frame))
5e65b9ab
RS
484 continue;
485 f = XFRAME (frame);
2d764c78 486 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
2d271e2e 487 continue;
7556890b 488 x = f->output_data.x;
333b20bb
GM
489
490 if (x->widget)
491 {
492 /* This frame matches if the window is its topmost widget. */
493 if (wdesc == XtWindow (x->widget))
494 return f;
7a994728
KH
495#if 0 /* I don't know why it did this,
496 but it seems logically wrong,
497 and it causes trouble for MapNotify events. */
333b20bb
GM
498 /* Match if the window is this frame's menubar. */
499 if (x->menubar_widget
500 && wdesc == XtWindow (x->menubar_widget))
501 return f;
7a994728 502#endif
333b20bb
GM
503 }
504 else if (FRAME_X_WINDOW (f) == wdesc)
505 /* Tooltip frame. */
506 return f;
5e65b9ab
RS
507 }
508 return 0;
509}
9ef48a9d 510#endif /* USE_X_TOOLKIT */
01f1ba30 511
01f1ba30 512\f
203c1d73
RS
513
514/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
515 id, which is just an int that this section returns. Bitmaps are
516 reference counted so they can be shared among frames.
517
518 Bitmap indices are guaranteed to be > 0, so a negative number can
519 be used to indicate no bitmap.
520
521 If you use x_create_bitmap_from_data, then you must keep track of
522 the bitmaps yourself. That is, creating a bitmap from the same
b9dc4443 523 data more than once will not be caught. */
203c1d73
RS
524
525
f1c7b5a6
RS
526/* Functions to access the contents of a bitmap, given an id. */
527
528int
529x_bitmap_height (f, id)
530 FRAME_PTR f;
531 int id;
532{
08a90d6a 533 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
f1c7b5a6
RS
534}
535
536int
537x_bitmap_width (f, id)
538 FRAME_PTR f;
539 int id;
540{
08a90d6a 541 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
f1c7b5a6
RS
542}
543
544int
545x_bitmap_pixmap (f, id)
546 FRAME_PTR f;
547 int id;
548{
08a90d6a 549 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
f1c7b5a6
RS
550}
551
552
203c1d73
RS
553/* Allocate a new bitmap record. Returns index of new record. */
554
555static int
08a90d6a
RS
556x_allocate_bitmap_record (f)
557 FRAME_PTR f;
203c1d73 558{
08a90d6a
RS
559 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
560 int i;
561
562 if (dpyinfo->bitmaps == NULL)
203c1d73 563 {
08a90d6a
RS
564 dpyinfo->bitmaps_size = 10;
565 dpyinfo->bitmaps
566 = (struct x_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
567 dpyinfo->bitmaps_last = 1;
203c1d73
RS
568 return 1;
569 }
570
08a90d6a
RS
571 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
572 return ++dpyinfo->bitmaps_last;
203c1d73 573
08a90d6a
RS
574 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
575 if (dpyinfo->bitmaps[i].refcount == 0)
576 return i + 1;
203c1d73 577
08a90d6a
RS
578 dpyinfo->bitmaps_size *= 2;
579 dpyinfo->bitmaps
580 = (struct x_bitmap_record *) xrealloc (dpyinfo->bitmaps,
581 dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
582 return ++dpyinfo->bitmaps_last;
203c1d73
RS
583}
584
585/* Add one reference to the reference count of the bitmap with id ID. */
586
587void
f1c7b5a6
RS
588x_reference_bitmap (f, id)
589 FRAME_PTR f;
203c1d73
RS
590 int id;
591{
08a90d6a 592 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
203c1d73
RS
593}
594
595/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
596
597int
598x_create_bitmap_from_data (f, bits, width, height)
599 struct frame *f;
600 char *bits;
601 unsigned int width, height;
602{
08a90d6a 603 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
203c1d73
RS
604 Pixmap bitmap;
605 int id;
606
b9dc4443 607 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
203c1d73
RS
608 bits, width, height);
609
610 if (! bitmap)
611 return -1;
612
08a90d6a
RS
613 id = x_allocate_bitmap_record (f);
614 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
615 dpyinfo->bitmaps[id - 1].file = NULL;
616 dpyinfo->bitmaps[id - 1].refcount = 1;
617 dpyinfo->bitmaps[id - 1].depth = 1;
618 dpyinfo->bitmaps[id - 1].height = height;
619 dpyinfo->bitmaps[id - 1].width = width;
203c1d73
RS
620
621 return id;
622}
623
624/* Create bitmap from file FILE for frame F. */
625
626int
627x_create_bitmap_from_file (f, file)
628 struct frame *f;
f1c7b5a6 629 Lisp_Object file;
203c1d73 630{
08a90d6a 631 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
203c1d73
RS
632 unsigned int width, height;
633 Pixmap bitmap;
634 int xhot, yhot, result, id;
f1c7b5a6
RS
635 Lisp_Object found;
636 int fd;
637 char *filename;
203c1d73
RS
638
639 /* Look for an existing bitmap with the same name. */
08a90d6a 640 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
203c1d73 641 {
08a90d6a
RS
642 if (dpyinfo->bitmaps[id].refcount
643 && dpyinfo->bitmaps[id].file
644 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
203c1d73 645 {
08a90d6a 646 ++dpyinfo->bitmaps[id].refcount;
203c1d73
RS
647 return id + 1;
648 }
649 }
650
f1c7b5a6 651 /* Search bitmap-file-path for the file, if appropriate. */
c0ec53ad 652 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
f1c7b5a6
RS
653 if (fd < 0)
654 return -1;
68c45bf0 655 emacs_close (fd);
f1c7b5a6
RS
656
657 filename = (char *) XSTRING (found)->data;
658
b9dc4443 659 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f1c7b5a6 660 filename, &width, &height, &bitmap, &xhot, &yhot);
203c1d73
RS
661 if (result != BitmapSuccess)
662 return -1;
663
08a90d6a
RS
664 id = x_allocate_bitmap_record (f);
665 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
666 dpyinfo->bitmaps[id - 1].refcount = 1;
9f2a85b2 667 dpyinfo->bitmaps[id - 1].file
fc932ac6 668 = (char *) xmalloc (STRING_BYTES (XSTRING (file)) + 1);
08a90d6a
RS
669 dpyinfo->bitmaps[id - 1].depth = 1;
670 dpyinfo->bitmaps[id - 1].height = height;
671 dpyinfo->bitmaps[id - 1].width = width;
672 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
203c1d73
RS
673
674 return id;
675}
676
677/* Remove reference to bitmap with id number ID. */
678
968b1234 679void
f1c7b5a6
RS
680x_destroy_bitmap (f, id)
681 FRAME_PTR f;
203c1d73
RS
682 int id;
683{
08a90d6a
RS
684 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
685
203c1d73
RS
686 if (id > 0)
687 {
08a90d6a
RS
688 --dpyinfo->bitmaps[id - 1].refcount;
689 if (dpyinfo->bitmaps[id - 1].refcount == 0)
203c1d73 690 {
ed662bdd 691 BLOCK_INPUT;
08a90d6a
RS
692 XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].pixmap);
693 if (dpyinfo->bitmaps[id - 1].file)
203c1d73 694 {
333b20bb 695 xfree (dpyinfo->bitmaps[id - 1].file);
08a90d6a 696 dpyinfo->bitmaps[id - 1].file = NULL;
203c1d73 697 }
ed662bdd 698 UNBLOCK_INPUT;
203c1d73
RS
699 }
700 }
701}
702
08a90d6a 703/* Free all the bitmaps for the display specified by DPYINFO. */
203c1d73 704
08a90d6a
RS
705static void
706x_destroy_all_bitmaps (dpyinfo)
707 struct x_display_info *dpyinfo;
203c1d73 708{
08a90d6a
RS
709 int i;
710 for (i = 0; i < dpyinfo->bitmaps_last; i++)
711 if (dpyinfo->bitmaps[i].refcount > 0)
712 {
713 XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].pixmap);
714 if (dpyinfo->bitmaps[i].file)
333b20bb 715 xfree (dpyinfo->bitmaps[i].file);
08a90d6a
RS
716 }
717 dpyinfo->bitmaps_last = 0;
203c1d73
RS
718}
719\f
f676886a 720/* Connect the frame-parameter names for X frames
01f1ba30
JB
721 to the ways of passing the parameter values to the window system.
722
723 The name of a parameter, as a Lisp symbol,
f676886a 724 has an `x-frame-parameter' property which is an integer in Lisp
9fb026ab 725 that is an index in this table. */
01f1ba30 726
f676886a 727struct x_frame_parm_table
01f1ba30
JB
728{
729 char *name;
d62c8769 730 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
01f1ba30
JB
731};
732
eaf1eea9
GM
733static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
734static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
52de7ce9 735static void x_change_window_heights P_ ((Lisp_Object, int));
14819cb3 736static void x_disable_image P_ ((struct frame *, struct image *));
d62c8769 737void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
563b67aa 738static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
ea0a1f53 739static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object));
49d41073 740static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
d62c8769
GM
741void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
742void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
743void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
744void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
745void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
746void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
747void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
b3ba0aa8 748static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
d62c8769
GM
749void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
750void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
751void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
752 Lisp_Object));
753void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
754void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
755void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
756void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
757 Lisp_Object));
758void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
759void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
760void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
761void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
762void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
9ea173e8 763void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
333b20bb
GM
764void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
765 Lisp_Object));
766void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
767 Lisp_Object));
768static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
769 Lisp_Object,
770 Lisp_Object,
771 char *, char *,
772 int));
d62c8769 773static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
4a8e312c
GM
774static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
775 Lisp_Object));
b243755a
GM
776static void init_color_table P_ ((void));
777static void free_color_table P_ ((void));
778static unsigned long *colors_in_color_table P_ ((int *n));
779static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
780static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
781
782
01f1ba30 783
f676886a 784static struct x_frame_parm_table x_frame_parms[] =
01f1ba30 785{
9908a324
PJ
786 {"auto-raise", x_set_autoraise},
787 {"auto-lower", x_set_autolower},
788 {"background-color", x_set_background_color},
789 {"border-color", x_set_border_color},
790 {"border-width", x_set_border_width},
791 {"cursor-color", x_set_cursor_color},
792 {"cursor-type", x_set_cursor_type},
793 {"font", x_set_font},
794 {"foreground-color", x_set_foreground_color},
795 {"icon-name", x_set_icon_name},
796 {"icon-type", x_set_icon_type},
797 {"internal-border-width", x_set_internal_border_width},
798 {"menu-bar-lines", x_set_menu_bar_lines},
799 {"mouse-color", x_set_mouse_color},
800 {"name", x_explicitly_set_name},
801 {"scroll-bar-width", x_set_scroll_bar_width},
802 {"title", x_set_title},
803 {"unsplittable", x_set_unsplittable},
804 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
805 {"visibility", x_set_visibility},
806 {"tool-bar-lines", x_set_tool_bar_lines},
807 {"scroll-bar-foreground", x_set_scroll_bar_foreground},
808 {"scroll-bar-background", x_set_scroll_bar_background},
809 {"screen-gamma", x_set_screen_gamma},
810 {"line-spacing", x_set_line_spacing},
811 {"left-fringe", x_set_fringe_width},
812 {"right-fringe", x_set_fringe_width},
49d41073
EZ
813 {"wait-for-wm", x_set_wait_for_wm},
814 {"fullscreen", x_set_fullscreen},
815
01f1ba30
JB
816};
817
f676886a 818/* Attach the `x-frame-parameter' properties to
01f1ba30
JB
819 the Lisp symbol names of parameters relevant to X. */
820
201d8c78 821void
01f1ba30
JB
822init_x_parm_symbols ()
823{
824 int i;
825
d043f1a4 826 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
f676886a 827 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
01f1ba30
JB
828 make_number (i));
829}
830\f
49d41073
EZ
831
832/* Really try to move where we want to be in case of fullscreen. Some WMs
833 moves the window where we tell them. Some (mwm, twm) moves the outer
834 window manager window there instead.
835 Try to compensate for those WM here. */
836static void
837x_fullscreen_move (f, new_top, new_left)
838 struct frame *f;
839 int new_top;
840 int new_left;
841{
842 if (new_top != f->output_data.x->top_pos
843 || new_left != f->output_data.x->left_pos)
844 {
845 int move_x = new_left + f->output_data.x->x_pixels_outer_diff;
846 int move_y = new_top + f->output_data.x->y_pixels_outer_diff;
847
848 f->output_data.x->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
849 x_set_offset (f, move_x, move_y, 1);
850 }
851}
852
e8cc313b 853/* Change the parameters of frame F as specified by ALIST.
64362cd4
GM
854 If a parameter is not specially recognized, do nothing special;
855 otherwise call the `x_set_...' function for that parameter.
856 Except for certain geometry properties, always call store_frame_param
857 to store the new value in the parameter alist. */
d043f1a4 858
f9942c9e
JB
859void
860x_set_frame_parameters (f, alist)
861 FRAME_PTR f;
862 Lisp_Object alist;
863{
864 Lisp_Object tail;
865
866 /* If both of these parameters are present, it's more efficient to
867 set them both at once. So we wait until we've looked at the
868 entire list before we set them. */
e4f79258 869 int width, height;
f9942c9e
JB
870
871 /* Same here. */
872 Lisp_Object left, top;
f9942c9e 873
a59e4f3d
RS
874 /* Same with these. */
875 Lisp_Object icon_left, icon_top;
876
f5e70acd
RS
877 /* Record in these vectors all the parms specified. */
878 Lisp_Object *parms;
879 Lisp_Object *values;
a797a73d 880 int i, p;
e1d962d7 881 int left_no_change = 0, top_no_change = 0;
a59e4f3d 882 int icon_left_no_change = 0, icon_top_no_change = 0;
5f9338d5 883 int fullscreen_is_being_set = 0;
203c1d73 884
7589a1d9
RS
885 struct gcpro gcpro1, gcpro2;
886
f5e70acd
RS
887 i = 0;
888 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
889 i++;
890
891 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
892 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
f9942c9e 893
f5e70acd
RS
894 /* Extract parm names and values into those vectors. */
895
896 i = 0;
f9942c9e
JB
897 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
898 {
333b20bb 899 Lisp_Object elt;
f9942c9e
JB
900
901 elt = Fcar (tail);
f5e70acd
RS
902 parms[i] = Fcar (elt);
903 values[i] = Fcdr (elt);
904 i++;
905 }
7589a1d9
RS
906 /* TAIL and ALIST are not used again below here. */
907 alist = tail = Qnil;
908
909 GCPRO2 (*parms, *values);
910 gcpro1.nvars = i;
911 gcpro2.nvars = i;
f5e70acd 912
7589a1d9
RS
913 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
914 because their values appear in VALUES and strings are not valid. */
e4f79258 915 top = left = Qunbound;
a59e4f3d 916 icon_left = icon_top = Qunbound;
f9942c9e 917
e4f79258
RS
918 /* Provide default values for HEIGHT and WIDTH. */
919 if (FRAME_NEW_WIDTH (f))
920 width = FRAME_NEW_WIDTH (f);
921 else
922 width = FRAME_WIDTH (f);
923
924 if (FRAME_NEW_HEIGHT (f))
925 height = FRAME_NEW_HEIGHT (f);
926 else
927 height = FRAME_HEIGHT (f);
928
a797a73d
GV
929 /* Process foreground_color and background_color before anything else.
930 They are independent of other properties, but other properties (e.g.,
931 cursor_color) are dependent upon them. */
b3ba0aa8 932 /* Process default font as well, since fringe widths depends on it. */
49d41073 933 /* Also, process fullscreen, width and height depend upon that */
a797a73d
GV
934 for (p = 0; p < i; p++)
935 {
936 Lisp_Object prop, val;
937
938 prop = parms[p];
939 val = values[p];
b3ba0aa8
KS
940 if (EQ (prop, Qforeground_color)
941 || EQ (prop, Qbackground_color)
49d41073
EZ
942 || EQ (prop, Qfont)
943 || EQ (prop, Qfullscreen))
a797a73d
GV
944 {
945 register Lisp_Object param_index, old_value;
946
a797a73d 947 old_value = get_frame_param (f, prop);
f0b9a067 948 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
c7e609d5
MB
949
950 if (NILP (Fequal (val, old_value)))
951 {
952 store_frame_param (f, prop, val);
953
954 param_index = Fget (prop, Qx_frame_parameter);
955 if (NATNUMP (param_index)
956 && (XFASTINT (param_index)
957 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
958 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
959 }
a797a73d
GV
960 }
961 }
962
f5e70acd
RS
963 /* Now process them in reverse of specified order. */
964 for (i--; i >= 0; i--)
965 {
966 Lisp_Object prop, val;
967
968 prop = parms[i];
969 val = values[i];
970
e4f79258
RS
971 if (EQ (prop, Qwidth) && NUMBERP (val))
972 width = XFASTINT (val);
973 else if (EQ (prop, Qheight) && NUMBERP (val))
974 height = XFASTINT (val);
f5e70acd 975 else if (EQ (prop, Qtop))
f9942c9e 976 top = val;
f5e70acd 977 else if (EQ (prop, Qleft))
f9942c9e 978 left = val;
a59e4f3d
RS
979 else if (EQ (prop, Qicon_top))
980 icon_top = val;
981 else if (EQ (prop, Qicon_left))
982 icon_left = val;
b3ba0aa8
KS
983 else if (EQ (prop, Qforeground_color)
984 || EQ (prop, Qbackground_color)
49d41073
EZ
985 || EQ (prop, Qfont)
986 || EQ (prop, Qfullscreen))
a797a73d
GV
987 /* Processed above. */
988 continue;
f9942c9e
JB
989 else
990 {
98381190 991 register Lisp_Object param_index, old_value;
ea96210c 992
98381190 993 old_value = get_frame_param (f, prop);
c7e609d5 994
9f7e52b4 995 store_frame_param (f, prop, val);
c7e609d5 996
9f7e52b4
GM
997 param_index = Fget (prop, Qx_frame_parameter);
998 if (NATNUMP (param_index)
999 && (XFASTINT (param_index)
1000 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
1001 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
f9942c9e
JB
1002 }
1003 }
1004
11378c41
RS
1005 /* Don't die if just one of these was set. */
1006 if (EQ (left, Qunbound))
e1d962d7
RS
1007 {
1008 left_no_change = 1;
7556890b
RS
1009 if (f->output_data.x->left_pos < 0)
1010 left = Fcons (Qplus, Fcons (make_number (f->output_data.x->left_pos), Qnil));
e1d962d7 1011 else
7556890b 1012 XSETINT (left, f->output_data.x->left_pos);
e1d962d7 1013 }
11378c41 1014 if (EQ (top, Qunbound))
e1d962d7
RS
1015 {
1016 top_no_change = 1;
7556890b
RS
1017 if (f->output_data.x->top_pos < 0)
1018 top = Fcons (Qplus, Fcons (make_number (f->output_data.x->top_pos), Qnil));
e1d962d7 1019 else
7556890b 1020 XSETINT (top, f->output_data.x->top_pos);
e1d962d7 1021 }
11378c41 1022
a59e4f3d
RS
1023 /* If one of the icon positions was not set, preserve or default it. */
1024 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
1025 {
1026 icon_left_no_change = 1;
1027 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
1028 if (NILP (icon_left))
1029 XSETINT (icon_left, 0);
1030 }
1031 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
1032 {
1033 icon_top_no_change = 1;
1034 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
1035 if (NILP (icon_top))
1036 XSETINT (icon_top, 0);
1037 }
1038
5f9338d5 1039 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
49d41073
EZ
1040 {
1041 /* If the frame is visible already and the fullscreen parameter is
1042 being set, it is too late to set WM manager hints to specify
1043 size and position.
1044 Here we first get the width, height and position that applies to
1045 fullscreen. We then move the frame to the appropriate
1046 position. Resize of the frame is taken care of in the code after
5f9338d5 1047 this if-statement. */
49d41073
EZ
1048 int new_left, new_top;
1049
1050 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
1051 x_fullscreen_move (f, new_top, new_left);
1052 }
1053
499ea23b 1054 /* Don't set these parameters unless they've been explicitly
d387c960
JB
1055 specified. The window might be mapped or resized while we're in
1056 this function, and we don't want to override that unless the lisp
1057 code has asked for it.
1058
1059 Don't set these parameters unless they actually differ from the
1060 window's current parameters; the window may not actually exist
1061 yet. */
f9942c9e
JB
1062 {
1063 Lisp_Object frame;
1064
1f11a5ca
RS
1065 check_frame_size (f, &height, &width);
1066
191ed777 1067 XSETFRAME (frame, f);
11378c41 1068
e4f79258
RS
1069 if (width != FRAME_WIDTH (f)
1070 || height != FRAME_HEIGHT (f)
d6f80ae9 1071 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
e4f79258 1072 Fset_frame_size (frame, make_number (width), make_number (height));
f10f0b79
RS
1073
1074 if ((!NILP (left) || !NILP (top))
e1d962d7 1075 && ! (left_no_change && top_no_change)
7556890b
RS
1076 && ! (NUMBERP (left) && XINT (left) == f->output_data.x->left_pos
1077 && NUMBERP (top) && XINT (top) == f->output_data.x->top_pos))
f10f0b79 1078 {
e1d962d7
RS
1079 int leftpos = 0;
1080 int toppos = 0;
f10f0b79
RS
1081
1082 /* Record the signs. */
7556890b 1083 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
e1d962d7 1084 if (EQ (left, Qminus))
7556890b 1085 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7
RS
1086 else if (INTEGERP (left))
1087 {
1088 leftpos = XINT (left);
1089 if (leftpos < 0)
7556890b 1090 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7 1091 }
8e713be6
KR
1092 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1093 && CONSP (XCDR (left))
1094 && INTEGERP (XCAR (XCDR (left))))
e1d962d7 1095 {
8e713be6 1096 leftpos = - XINT (XCAR (XCDR (left)));
7556890b 1097 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7 1098 }
8e713be6
KR
1099 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1100 && CONSP (XCDR (left))
1101 && INTEGERP (XCAR (XCDR (left))))
e1d962d7 1102 {
8e713be6 1103 leftpos = XINT (XCAR (XCDR (left)));
e1d962d7
RS
1104 }
1105
1106 if (EQ (top, Qminus))
7556890b 1107 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7
RS
1108 else if (INTEGERP (top))
1109 {
1110 toppos = XINT (top);
1111 if (toppos < 0)
7556890b 1112 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7 1113 }
8e713be6
KR
1114 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1115 && CONSP (XCDR (top))
1116 && INTEGERP (XCAR (XCDR (top))))
e1d962d7 1117 {
8e713be6 1118 toppos = - XINT (XCAR (XCDR (top)));
7556890b 1119 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7 1120 }
8e713be6
KR
1121 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1122 && CONSP (XCDR (top))
1123 && INTEGERP (XCAR (XCDR (top))))
e1d962d7 1124 {
8e713be6 1125 toppos = XINT (XCAR (XCDR (top)));
e1d962d7
RS
1126 }
1127
1128
1129 /* Store the numeric value of the position. */
7556890b
RS
1130 f->output_data.x->top_pos = toppos;
1131 f->output_data.x->left_pos = leftpos;
e1d962d7 1132
7556890b 1133 f->output_data.x->win_gravity = NorthWestGravity;
f10f0b79
RS
1134
1135 /* Actually set that position, and convert to absolute. */
f0e72e79 1136 x_set_offset (f, leftpos, toppos, -1);
f10f0b79 1137 }
a59e4f3d
RS
1138
1139 if ((!NILP (icon_left) || !NILP (icon_top))
1140 && ! (icon_left_no_change && icon_top_no_change))
1141 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
f9942c9e 1142 }
7589a1d9
RS
1143
1144 UNGCPRO;
f9942c9e 1145}
01f1ba30 1146
08a90d6a 1147/* Store the screen positions of frame F into XPTR and YPTR.
e9445337
RS
1148 These are the positions of the containing window manager window,
1149 not Emacs's own window. */
1150
1151void
1152x_real_positions (f, xptr, yptr)
1153 FRAME_PTR f;
1154 int *xptr, *yptr;
1155{
49d41073
EZ
1156 int win_x, win_y, outer_x, outer_y;
1157 int real_x = 0, real_y = 0;
1158 int had_errors = 0;
1159 Window win = f->output_data.x->parent_desc;
e9445337 1160
49d41073 1161 int count;
043835a3 1162
49d41073
EZ
1163 BLOCK_INPUT;
1164
1165 count = x_catch_errors (FRAME_X_DISPLAY (f));
043835a3 1166
49d41073
EZ
1167 if (win == FRAME_X_DISPLAY_INFO (f)->root_window)
1168 win = FRAME_OUTER_WINDOW (f);
1169
1170 /* This loop traverses up the containment tree until we hit the root
1171 window. Window managers may intersect many windows between our window
1172 and the root window. The window we find just before the root window
1173 should be the outer WM window. */
1174 for (;;)
e9445337 1175 {
49d41073
EZ
1176 Window wm_window, rootw;
1177 Window *tmp_children;
1178 unsigned int tmp_nchildren;
e7161ad9 1179 int success;
ca7bac79 1180
e7161ad9
RS
1181 success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
1182 &wm_window, &tmp_children, &tmp_nchildren);
08a90d6a 1183
49d41073 1184 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
08a90d6a 1185
e7161ad9
RS
1186 /* Don't free tmp_children if XQueryTree failed. */
1187 if (! success)
1188 break;
1189
1190 XFree ((char *) tmp_children);
1191
49d41073
EZ
1192 if (wm_window == rootw || had_errors)
1193 break;
08a90d6a 1194
49d41073
EZ
1195 win = wm_window;
1196 }
1197
1198 if (! had_errors)
1199 {
1200 int ign;
1201 Window child, rootw;
1202
1203 /* Get the real coordinates for the WM window upper left corner */
1204 XGetGeometry (FRAME_X_DISPLAY (f), win,
1205 &rootw, &real_x, &real_y, &ign, &ign, &ign, &ign);
1206
1207 /* Translate real coordinates to coordinates relative to our
1208 window. For our window, the upper left corner is 0, 0.
1209 Since the upper left corner of the WM window is outside
1210 our window, win_x and win_y will be negative:
1211
1212 ------------------ ---> x
1213 | title |
1214 | ----------------- v y
1215 | | our window
1216 */
8a07bba0 1217 XTranslateCoordinates (FRAME_X_DISPLAY (f),
e9445337 1218
8a07bba0 1219 /* From-window, to-window. */
8a07bba0 1220 FRAME_X_DISPLAY_INFO (f)->root_window,
49d41073 1221 FRAME_X_WINDOW (f),
e9445337 1222
8a07bba0 1223 /* From-position, to-position. */
49d41073 1224 real_x, real_y, &win_x, &win_y,
08a90d6a 1225
8a07bba0
RS
1226 /* Child of win. */
1227 &child);
e9445337 1228
49d41073 1229 if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
845e9d85 1230 {
49d41073
EZ
1231 outer_x = win_x;
1232 outer_y = win_y;
845e9d85 1233 }
49d41073
EZ
1234 else
1235 {
1236 XTranslateCoordinates (FRAME_X_DISPLAY (f),
ca7bac79 1237
49d41073
EZ
1238 /* From-window, to-window. */
1239 FRAME_X_DISPLAY_INFO (f)->root_window,
1240 FRAME_OUTER_WINDOW (f),
1241
1242 /* From-position, to-position. */
1243 real_x, real_y, &outer_x, &outer_y,
1244
1245 /* Child of win. */
1246 &child);
e9445337 1247 }
08a90d6a 1248
49d41073
EZ
1249 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
1250 }
1251
1252 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
1253
1254 UNBLOCK_INPUT;
1255
1256 if (had_errors) return;
1257
1258 f->output_data.x->x_pixels_diff = -win_x;
1259 f->output_data.x->y_pixels_diff = -win_y;
1260 f->output_data.x->x_pixels_outer_diff = -outer_x;
1261 f->output_data.x->y_pixels_outer_diff = -outer_y;
1262
1263 *xptr = real_x;
1264 *yptr = real_y;
e9445337
RS
1265}
1266
f676886a 1267/* Insert a description of internally-recorded parameters of frame X
01f1ba30
JB
1268 into the parameter alist *ALISTPTR that is to be given to the user.
1269 Only parameters that are specific to the X window system
f676886a 1270 and whose values are not correctly recorded in the frame's
01f1ba30
JB
1271 param_alist need to be considered here. */
1272
968b1234 1273void
f676886a
JB
1274x_report_frame_params (f, alistptr)
1275 struct frame *f;
01f1ba30
JB
1276 Lisp_Object *alistptr;
1277{
1278 char buf[16];
9b002b8d
KH
1279 Lisp_Object tem;
1280
1281 /* Represent negative positions (off the top or left screen edge)
1282 in a way that Fmodify_frame_parameters will understand correctly. */
7556890b
RS
1283 XSETINT (tem, f->output_data.x->left_pos);
1284 if (f->output_data.x->left_pos >= 0)
9b002b8d
KH
1285 store_in_alist (alistptr, Qleft, tem);
1286 else
1287 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1288
7556890b
RS
1289 XSETINT (tem, f->output_data.x->top_pos);
1290 if (f->output_data.x->top_pos >= 0)
9b002b8d
KH
1291 store_in_alist (alistptr, Qtop, tem);
1292 else
1293 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
01f1ba30 1294
f9942c9e 1295 store_in_alist (alistptr, Qborder_width,
7556890b 1296 make_number (f->output_data.x->border_width));
f9942c9e 1297 store_in_alist (alistptr, Qinternal_border_width,
7556890b 1298 make_number (f->output_data.x->internal_border_width));
30bf44e0
KS
1299 store_in_alist (alistptr, Qleft_fringe,
1300 make_number (f->output_data.x->left_fringe_width));
1301 store_in_alist (alistptr, Qright_fringe,
1302 make_number (f->output_data.x->right_fringe_width));
99f7c77f
EZ
1303 store_in_alist (alistptr, Qscroll_bar_width,
1304 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1305 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1306 : 0));
7c118b57 1307 sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f));
f9942c9e 1308 store_in_alist (alistptr, Qwindow_id,
01f1ba30 1309 build_string (buf));
333b20bb
GM
1310#ifdef USE_X_TOOLKIT
1311 /* Tooltip frame may not have this widget. */
1312 if (f->output_data.x->widget)
1313#endif
1314 sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f));
2cbebefb
RS
1315 store_in_alist (alistptr, Qouter_window_id,
1316 build_string (buf));
f468da95 1317 store_in_alist (alistptr, Qicon_name, f->icon_name);
a8ccd803 1318 FRAME_SAMPLE_VISIBILITY (f);
d043f1a4
RS
1319 store_in_alist (alistptr, Qvisibility,
1320 (FRAME_VISIBLE_P (f) ? Qt
1321 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
34ae77b5 1322 store_in_alist (alistptr, Qdisplay,
8e713be6 1323 XCAR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
e4f79258 1324
8c239ac3
RS
1325 if (f->output_data.x->parent_desc == FRAME_X_DISPLAY_INFO (f)->root_window)
1326 tem = Qnil;
1327 else
1328 XSETFASTINT (tem, f->output_data.x->parent_desc);
1329 store_in_alist (alistptr, Qparent_id, tem);
01f1ba30
JB
1330}
1331\f
82978295 1332
d62c8769
GM
1333
1334/* Gamma-correct COLOR on frame F. */
1335
1336void
1337gamma_correct (f, color)
1338 struct frame *f;
1339 XColor *color;
1340{
1341 if (f->gamma)
1342 {
1343 color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5;
1344 color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5;
1345 color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5;
1346 }
1347}
1348
1349
7b746c38
GM
1350/* Decide if color named COLOR_NAME is valid for use on frame F. If
1351 so, return the RGB values in COLOR. If ALLOC_P is non-zero,
1352 allocate the color. Value is zero if COLOR_NAME is invalid, or
1353 no color could be allocated. */
e12d55b2 1354
01f1ba30 1355int
7b746c38
GM
1356x_defined_color (f, color_name, color, alloc_p)
1357 struct frame *f;
1358 char *color_name;
1359 XColor *color;
1360 int alloc_p;
01f1ba30 1361{
7b746c38
GM
1362 int success_p;
1363 Display *dpy = FRAME_X_DISPLAY (f);
1364 Colormap cmap = FRAME_X_COLORMAP (f);
01f1ba30
JB
1365
1366 BLOCK_INPUT;
7b746c38
GM
1367 success_p = XParseColor (dpy, cmap, color_name, color);
1368 if (success_p && alloc_p)
1369 success_p = x_alloc_nearest_color (f, cmap, color);
01f1ba30
JB
1370 UNBLOCK_INPUT;
1371
7b746c38 1372 return success_p;
01f1ba30
JB
1373}
1374
9b2956e2
GM
1375
1376/* Return the pixel color value for color COLOR_NAME on frame F. If F
1377 is a monochrome frame, return MONO_COLOR regardless of what ARG says.
1378 Signal an error if color can't be allocated. */
01f1ba30
JB
1379
1380int
9b2956e2 1381x_decode_color (f, color_name, mono_color)
b9dc4443 1382 FRAME_PTR f;
9b2956e2
GM
1383 Lisp_Object color_name;
1384 int mono_color;
01f1ba30 1385{
b9dc4443 1386 XColor cdef;
01f1ba30 1387
b7826503 1388 CHECK_STRING (color_name);
01f1ba30 1389
9b2956e2
GM
1390#if 0 /* Don't do this. It's wrong when we're not using the default
1391 colormap, it makes freeing difficult, and it's probably not
1392 an important optimization. */
1393 if (strcmp (XSTRING (color_name)->data, "black") == 0)
b9dc4443 1394 return BLACK_PIX_DEFAULT (f);
9b2956e2 1395 else if (strcmp (XSTRING (color_name)->data, "white") == 0)
b9dc4443 1396 return WHITE_PIX_DEFAULT (f);
9b2956e2 1397#endif
01f1ba30 1398
9b2956e2 1399 /* Return MONO_COLOR for monochrome frames. */
b9dc4443 1400 if (FRAME_X_DISPLAY_INFO (f)->n_planes == 1)
9b2956e2 1401 return mono_color;
01f1ba30 1402
2d764c78 1403 /* x_defined_color is responsible for coping with failures
95626e11 1404 by looking for a near-miss. */
9b2956e2 1405 if (x_defined_color (f, XSTRING (color_name)->data, &cdef, 1))
95626e11
RS
1406 return cdef.pixel;
1407
c301be26
GM
1408 Fsignal (Qerror, Fcons (build_string ("Undefined color"),
1409 Fcons (color_name, Qnil)));
1410 return 0;
01f1ba30 1411}
9b2956e2
GM
1412
1413
01f1ba30 1414\f
563b67aa
GM
1415/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1416 the previous value of that parameter, NEW_VALUE is the new value. */
1417
1418static void
1419x_set_line_spacing (f, new_value, old_value)
1420 struct frame *f;
1421 Lisp_Object new_value, old_value;
1422{
1423 if (NILP (new_value))
1424 f->extra_line_spacing = 0;
1425 else if (NATNUMP (new_value))
1426 f->extra_line_spacing = XFASTINT (new_value);
1427 else
1a948b17 1428 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
563b67aa
GM
1429 Fcons (new_value, Qnil)));
1430 if (FRAME_VISIBLE_P (f))
1431 redraw_frame (f);
1432}
1433
1434
ea0a1f53
GM
1435/* Change the `wait-for-wm' frame parameter of frame F. OLD_VALUE is
1436 the previous value of that parameter, NEW_VALUE is the new value.
1437 See also the comment of wait_for_wm in struct x_output. */
1438
1439static void
1440x_set_wait_for_wm (f, new_value, old_value)
1441 struct frame *f;
1442 Lisp_Object new_value, old_value;
1443{
1444 f->output_data.x->wait_for_wm = !NILP (new_value);
1445}
1446
1447
49d41073
EZ
1448/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
1449 the previous value of that parameter, NEW_VALUE is the new value. */
1450
1451static void
1452x_set_fullscreen (f, new_value, old_value)
1453 struct frame *f;
1454 Lisp_Object new_value, old_value;
1455{
1456 if (NILP (new_value))
1457 f->output_data.x->want_fullscreen = FULLSCREEN_NONE;
1458 else if (EQ (new_value, Qfullboth))
1459 f->output_data.x->want_fullscreen = FULLSCREEN_BOTH;
1460 else if (EQ (new_value, Qfullwidth))
1461 f->output_data.x->want_fullscreen = FULLSCREEN_WIDTH;
1462 else if (EQ (new_value, Qfullheight))
1463 f->output_data.x->want_fullscreen = FULLSCREEN_HEIGHT;
1464}
1465
1466
d62c8769 1467/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
ea0a1f53
GM
1468 the previous value of that parameter, NEW_VALUE is the new
1469 value. */
d62c8769
GM
1470
1471static void
1472x_set_screen_gamma (f, new_value, old_value)
1473 struct frame *f;
1474 Lisp_Object new_value, old_value;
1475{
1476 if (NILP (new_value))
1477 f->gamma = 0;
1478 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1479 /* The value 0.4545 is the normal viewing gamma. */
1480 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1481 else
1a948b17 1482 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
d62c8769
GM
1483 Fcons (new_value, Qnil)));
1484
1485 clear_face_cache (0);
1486}
1487
1488
f676886a 1489/* Functions called only from `x_set_frame_param'
01f1ba30
JB
1490 to set individual parameters.
1491
fe24a618 1492 If FRAME_X_WINDOW (f) is 0,
f676886a 1493 the frame is being created and its X-window does not exist yet.
01f1ba30
JB
1494 In that case, just record the parameter's new value
1495 in the standard place; do not attempt to change the window. */
1496
1497void
f676886a
JB
1498x_set_foreground_color (f, arg, oldval)
1499 struct frame *f;
01f1ba30
JB
1500 Lisp_Object arg, oldval;
1501{
09393d07
GM
1502 struct x_output *x = f->output_data.x;
1503 unsigned long fg, old_fg;
a76206dc 1504
09393d07
GM
1505 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1506 old_fg = x->foreground_pixel;
1507 x->foreground_pixel = fg;
a76206dc 1508
fe24a618 1509 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1510 {
09393d07 1511 Display *dpy = FRAME_X_DISPLAY (f);
36d42089 1512
09393d07
GM
1513 BLOCK_INPUT;
1514 XSetForeground (dpy, x->normal_gc, fg);
1515 XSetBackground (dpy, x->reverse_gc, fg);
36d42089 1516
09393d07
GM
1517 if (x->cursor_pixel == old_fg)
1518 {
1519 unload_color (f, x->cursor_pixel);
1520 x->cursor_pixel = x_copy_color (f, fg);
1521 XSetBackground (dpy, x->cursor_gc, x->cursor_pixel);
1522 }
1523
01f1ba30 1524 UNBLOCK_INPUT;
09393d07 1525
05c8abbe 1526 update_face_from_frame_parameter (f, Qforeground_color, arg);
09393d07 1527
179956b9 1528 if (FRAME_VISIBLE_P (f))
f676886a 1529 redraw_frame (f);
01f1ba30 1530 }
09393d07
GM
1531
1532 unload_color (f, old_fg);
01f1ba30
JB
1533}
1534
1535void
f676886a
JB
1536x_set_background_color (f, arg, oldval)
1537 struct frame *f;
01f1ba30
JB
1538 Lisp_Object arg, oldval;
1539{
09393d07
GM
1540 struct x_output *x = f->output_data.x;
1541 unsigned long bg;
01f1ba30 1542
09393d07
GM
1543 bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1544 unload_color (f, x->background_pixel);
1545 x->background_pixel = bg;
a76206dc 1546
fe24a618 1547 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1548 {
09393d07 1549 Display *dpy = FRAME_X_DISPLAY (f);
36d42089 1550
09393d07
GM
1551 BLOCK_INPUT;
1552 XSetBackground (dpy, x->normal_gc, bg);
1553 XSetForeground (dpy, x->reverse_gc, bg);
1554 XSetWindowBackground (dpy, FRAME_X_WINDOW (f), bg);
1555 XSetForeground (dpy, x->cursor_gc, bg);
1556
f76e0368
GM
1557#ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with
1558 toolkit scroll bars. */
1559 {
1560 Lisp_Object bar;
1561 for (bar = FRAME_SCROLL_BARS (f);
1562 !NILP (bar);
1563 bar = XSCROLL_BAR (bar)->next)
1564 {
1565 Window window = SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar));
1566 XSetWindowBackground (dpy, window, bg);
1567 }
1568 }
1569#endif /* USE_TOOLKIT_SCROLL_BARS */
01f1ba30 1570
09393d07 1571 UNBLOCK_INPUT;
05c8abbe 1572 update_face_from_frame_parameter (f, Qbackground_color, arg);
ea96210c 1573
179956b9 1574 if (FRAME_VISIBLE_P (f))
f676886a 1575 redraw_frame (f);
01f1ba30
JB
1576 }
1577}
1578
1579void
f676886a
JB
1580x_set_mouse_color (f, arg, oldval)
1581 struct frame *f;
01f1ba30
JB
1582 Lisp_Object arg, oldval;
1583{
09393d07
GM
1584 struct x_output *x = f->output_data.x;
1585 Display *dpy = FRAME_X_DISPLAY (f);
95f80c78 1586 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
0af913d7 1587 Cursor hourglass_cursor, horizontal_drag_cursor;
1dc6cfa6 1588 int count;
51a1d2d8 1589 unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
09393d07 1590 unsigned long mask_color = x->background_pixel;
a76206dc 1591
51a1d2d8 1592 /* Don't let pointers be invisible. */
09393d07 1593 if (mask_color == pixel)
bcf26b38
GM
1594 {
1595 x_free_colors (f, &pixel, 1);
09393d07 1596 pixel = x_copy_color (f, x->foreground_pixel);
bcf26b38 1597 }
a76206dc 1598
09393d07
GM
1599 unload_color (f, x->mouse_pixel);
1600 x->mouse_pixel = pixel;
01f1ba30
JB
1601
1602 BLOCK_INPUT;
fe24a618 1603
eb8c3be9 1604 /* It's not okay to crash if the user selects a screwy cursor. */
09393d07 1605 count = x_catch_errors (dpy);
fe24a618 1606
09393d07 1607 if (!NILP (Vx_pointer_shape))
01f1ba30 1608 {
b7826503 1609 CHECK_NUMBER (Vx_pointer_shape);
09393d07 1610 cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
01f1ba30
JB
1611 }
1612 else
09393d07
GM
1613 cursor = XCreateFontCursor (dpy, XC_xterm);
1614 x_check_errors (dpy, "bad text pointer cursor: %s");
01f1ba30 1615
09393d07 1616 if (!NILP (Vx_nontext_pointer_shape))
01f1ba30 1617 {
b7826503 1618 CHECK_NUMBER (Vx_nontext_pointer_shape);
09393d07
GM
1619 nontext_cursor
1620 = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
01f1ba30
JB
1621 }
1622 else
09393d07
GM
1623 nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
1624 x_check_errors (dpy, "bad nontext pointer cursor: %s");
01f1ba30 1625
09393d07 1626 if (!NILP (Vx_hourglass_pointer_shape))
333b20bb 1627 {
b7826503 1628 CHECK_NUMBER (Vx_hourglass_pointer_shape);
09393d07
GM
1629 hourglass_cursor
1630 = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
333b20bb
GM
1631 }
1632 else
09393d07
GM
1633 hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
1634 x_check_errors (dpy, "bad hourglass pointer cursor: %s");
333b20bb 1635
09393d07
GM
1636 x_check_errors (dpy, "bad nontext pointer cursor: %s");
1637 if (!NILP (Vx_mode_pointer_shape))
01f1ba30 1638 {
b7826503 1639 CHECK_NUMBER (Vx_mode_pointer_shape);
09393d07 1640 mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
01f1ba30
JB
1641 }
1642 else
09393d07
GM
1643 mode_cursor = XCreateFontCursor (dpy, XC_xterm);
1644 x_check_errors (dpy, "bad modeline pointer cursor: %s");
95f80c78 1645
09393d07 1646 if (!NILP (Vx_sensitive_text_pointer_shape))
95f80c78 1647 {
b7826503 1648 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ca0ecbf5 1649 cross_cursor
09393d07 1650 = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
95f80c78
FP
1651 }
1652 else
09393d07 1653 cross_cursor = XCreateFontCursor (dpy, XC_crosshair);
01f1ba30 1654
8fb4ec9c
GM
1655 if (!NILP (Vx_window_horizontal_drag_shape))
1656 {
b7826503 1657 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
8fb4ec9c 1658 horizontal_drag_cursor
09393d07 1659 = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
8fb4ec9c
GM
1660 }
1661 else
1662 horizontal_drag_cursor
09393d07 1663 = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
8fb4ec9c 1664
fe24a618 1665 /* Check and report errors with the above calls. */
09393d07
GM
1666 x_check_errors (dpy, "can't set cursor shape: %s");
1667 x_uncatch_errors (dpy, count);
fe24a618 1668
01f1ba30
JB
1669 {
1670 XColor fore_color, back_color;
1671
09393d07 1672 fore_color.pixel = x->mouse_pixel;
a31fedb7 1673 x_query_color (f, &fore_color);
01f1ba30 1674 back_color.pixel = mask_color;
a31fedb7
GM
1675 x_query_color (f, &back_color);
1676
09393d07
GM
1677 XRecolorCursor (dpy, cursor, &fore_color, &back_color);
1678 XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
1679 XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
1680 XRecolorCursor (dpy, cross_cursor, &fore_color, &back_color);
1681 XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
1682 XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
01f1ba30 1683 }
01f1ba30 1684
fe24a618 1685 if (FRAME_X_WINDOW (f) != 0)
09393d07
GM
1686 XDefineCursor (dpy, FRAME_X_WINDOW (f), cursor);
1687
1688 if (cursor != x->text_cursor
1689 && x->text_cursor != 0)
1690 XFreeCursor (dpy, x->text_cursor);
1691 x->text_cursor = cursor;
1692
1693 if (nontext_cursor != x->nontext_cursor
1694 && x->nontext_cursor != 0)
1695 XFreeCursor (dpy, x->nontext_cursor);
1696 x->nontext_cursor = nontext_cursor;
1697
1698 if (hourglass_cursor != x->hourglass_cursor
1699 && x->hourglass_cursor != 0)
1700 XFreeCursor (dpy, x->hourglass_cursor);
1701 x->hourglass_cursor = hourglass_cursor;
1702
1703 if (mode_cursor != x->modeline_cursor
1704 && x->modeline_cursor != 0)
1705 XFreeCursor (dpy, f->output_data.x->modeline_cursor);
1706 x->modeline_cursor = mode_cursor;
333b20bb 1707
09393d07
GM
1708 if (cross_cursor != x->cross_cursor
1709 && x->cross_cursor != 0)
1710 XFreeCursor (dpy, x->cross_cursor);
1711 x->cross_cursor = cross_cursor;
01f1ba30 1712
09393d07
GM
1713 if (horizontal_drag_cursor != x->horizontal_drag_cursor
1714 && x->horizontal_drag_cursor != 0)
1715 XFreeCursor (dpy, x->horizontal_drag_cursor);
1716 x->horizontal_drag_cursor = horizontal_drag_cursor;
8fb4ec9c 1717
09393d07 1718 XFlush (dpy);
01f1ba30 1719 UNBLOCK_INPUT;
05c8abbe
GM
1720
1721 update_face_from_frame_parameter (f, Qmouse_color, arg);
01f1ba30
JB
1722}
1723
1724void
f676886a
JB
1725x_set_cursor_color (f, arg, oldval)
1726 struct frame *f;
01f1ba30
JB
1727 Lisp_Object arg, oldval;
1728{
a76206dc 1729 unsigned long fore_pixel, pixel;
10168ebb 1730 int fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
09393d07 1731 struct x_output *x = f->output_data.x;
01f1ba30 1732
10168ebb
GM
1733 if (!NILP (Vx_cursor_fore_pixel))
1734 {
1735 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
1736 WHITE_PIX_DEFAULT (f));
1737 fore_pixel_allocated_p = 1;
1738 }
01f1ba30 1739 else
09393d07 1740 fore_pixel = x->background_pixel;
10168ebb 1741
a76206dc 1742 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
10168ebb 1743 pixel_allocated_p = 1;
a76206dc 1744
f9942c9e 1745 /* Make sure that the cursor color differs from the background color. */
09393d07 1746 if (pixel == x->background_pixel)
01f1ba30 1747 {
10168ebb
GM
1748 if (pixel_allocated_p)
1749 {
1750 x_free_colors (f, &pixel, 1);
1751 pixel_allocated_p = 0;
1752 }
1753
09393d07 1754 pixel = x->mouse_pixel;
a76206dc 1755 if (pixel == fore_pixel)
10168ebb
GM
1756 {
1757 if (fore_pixel_allocated_p)
1758 {
1759 x_free_colors (f, &fore_pixel, 1);
1760 fore_pixel_allocated_p = 0;
1761 }
09393d07 1762 fore_pixel = x->background_pixel;
10168ebb 1763 }
01f1ba30 1764 }
a76206dc 1765
09393d07 1766 unload_color (f, x->cursor_foreground_pixel);
10168ebb
GM
1767 if (!fore_pixel_allocated_p)
1768 fore_pixel = x_copy_color (f, fore_pixel);
09393d07 1769 x->cursor_foreground_pixel = fore_pixel;
01f1ba30 1770
09393d07 1771 unload_color (f, x->cursor_pixel);
10168ebb
GM
1772 if (!pixel_allocated_p)
1773 pixel = x_copy_color (f, pixel);
09393d07 1774 x->cursor_pixel = pixel;
a76206dc 1775
fe24a618 1776 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1777 {
01f1ba30 1778 BLOCK_INPUT;
09393d07
GM
1779 XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
1780 XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);
01f1ba30 1781 UNBLOCK_INPUT;
01f1ba30 1782
179956b9 1783 if (FRAME_VISIBLE_P (f))
01f1ba30 1784 {
cedadcfa
RS
1785 x_update_cursor (f, 0);
1786 x_update_cursor (f, 1);
01f1ba30
JB
1787 }
1788 }
05c8abbe
GM
1789
1790 update_face_from_frame_parameter (f, Qcursor_color, arg);
01f1ba30 1791}
943b580d 1792\f
f676886a 1793/* Set the border-color of frame F to value described by ARG.
01f1ba30
JB
1794 ARG can be a string naming a color.
1795 The border-color is used for the border that is drawn by the X server.
1796 Note that this does not fully take effect if done before
f676886a 1797 F has an x-window; it must be redone when the window is created.
01f1ba30
JB
1798
1799 Note: this is done in two routines because of the way X10 works.
1800
1801 Note: under X11, this is normally the province of the window manager,
b9dc4443 1802 and so emacs' border colors may be overridden. */
01f1ba30
JB
1803
1804void
f676886a
JB
1805x_set_border_color (f, arg, oldval)
1806 struct frame *f;
01f1ba30
JB
1807 Lisp_Object arg, oldval;
1808{
01f1ba30
JB
1809 int pix;
1810
b7826503 1811 CHECK_STRING (arg);
b9dc4443 1812 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
f676886a 1813 x_set_border_pixel (f, pix);
05c8abbe 1814 update_face_from_frame_parameter (f, Qborder_color, arg);
01f1ba30
JB
1815}
1816
f676886a 1817/* Set the border-color of frame F to pixel value PIX.
01f1ba30 1818 Note that this does not fully take effect if done before
f676886a 1819 F has an x-window. */
01f1ba30 1820
968b1234 1821void
f676886a
JB
1822x_set_border_pixel (f, pix)
1823 struct frame *f;
01f1ba30
JB
1824 int pix;
1825{
a76206dc 1826 unload_color (f, f->output_data.x->border_pixel);
7556890b 1827 f->output_data.x->border_pixel = pix;
01f1ba30 1828
7556890b 1829 if (FRAME_X_WINDOW (f) != 0 && f->output_data.x->border_width > 0)
01f1ba30 1830 {
01f1ba30 1831 BLOCK_INPUT;
b9dc4443 1832 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
270958e8 1833 (unsigned long)pix);
01f1ba30
JB
1834 UNBLOCK_INPUT;
1835
179956b9 1836 if (FRAME_VISIBLE_P (f))
f676886a 1837 redraw_frame (f);
01f1ba30
JB
1838 }
1839}
1840
0d1469d6
GM
1841
1842/* Value is the internal representation of the specified cursor type
1843 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
1844 of the bar cursor. */
1845
1846enum text_cursor_kinds
1847x_specified_cursor_type (arg, width)
1848 Lisp_Object arg;
1849 int *width;
dbc4e1c1 1850{
0d1469d6
GM
1851 enum text_cursor_kinds type;
1852
dbc4e1c1 1853 if (EQ (arg, Qbar))
c3211206 1854 {
0d1469d6
GM
1855 type = BAR_CURSOR;
1856 *width = 2;
c3211206 1857 }
08ac8554
GM
1858 else if (CONSP (arg)
1859 && EQ (XCAR (arg), Qbar)
1860 && INTEGERP (XCDR (arg))
1861 && XINT (XCDR (arg)) >= 0)
c3211206 1862 {
0d1469d6
GM
1863 type = BAR_CURSOR;
1864 *width = XINT (XCDR (arg));
c3211206 1865 }
08ac8554 1866 else if (NILP (arg))
0d1469d6 1867 type = NO_CURSOR;
dbc4e1c1 1868 else
c3211206
RS
1869 /* Treat anything unknown as "box cursor".
1870 It was bad to signal an error; people have trouble fixing
1871 .Xdefaults with Emacs, when it has something bad in it. */
0d1469d6
GM
1872 type = FILLED_BOX_CURSOR;
1873
1874 return type;
1875}
1876
1877void
1878x_set_cursor_type (f, arg, oldval)
1879 FRAME_PTR f;
1880 Lisp_Object arg, oldval;
1881{
1882 int width;
1883
1884 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
1885 f->output_data.x->cursor_width = width;
dbc4e1c1 1886
75691005
RS
1887 /* Make sure the cursor gets redrawn. */
1888 cursor_type_changed = 1;
dbc4e1c1 1889}
943b580d 1890\f
01f1ba30 1891void
f676886a
JB
1892x_set_icon_type (f, arg, oldval)
1893 struct frame *f;
01f1ba30
JB
1894 Lisp_Object arg, oldval;
1895{
01f1ba30
JB
1896 int result;
1897
203c1d73
RS
1898 if (STRINGP (arg))
1899 {
1900 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1901 return;
1902 }
1903 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
01f1ba30
JB
1904 return;
1905
1906 BLOCK_INPUT;
265a9e55 1907 if (NILP (arg))
80534dd6 1908 result = x_text_icon (f,
f468da95
RS
1909 (char *) XSTRING ((!NILP (f->icon_name)
1910 ? f->icon_name
80534dd6 1911 : f->name))->data);
f1c7b5a6
RS
1912 else
1913 result = x_bitmap_icon (f, arg);
01f1ba30
JB
1914
1915 if (result)
1916 {
01f1ba30 1917 UNBLOCK_INPUT;
0fb53770 1918 error ("No icon window available");
01f1ba30
JB
1919 }
1920
b9dc4443 1921 XFlush (FRAME_X_DISPLAY (f));
01f1ba30
JB
1922 UNBLOCK_INPUT;
1923}
1924
f1c7b5a6 1925/* Return non-nil if frame F wants a bitmap icon. */
0fb53770 1926
f1c7b5a6 1927Lisp_Object
0fb53770
RS
1928x_icon_type (f)
1929 FRAME_PTR f;
1930{
1931 Lisp_Object tem;
1932
1933 tem = assq_no_quit (Qicon_type, f->param_alist);
f1c7b5a6 1934 if (CONSP (tem))
8e713be6 1935 return XCDR (tem);
f1c7b5a6
RS
1936 else
1937 return Qnil;
0fb53770
RS
1938}
1939
80534dd6
KH
1940void
1941x_set_icon_name (f, arg, oldval)
1942 struct frame *f;
1943 Lisp_Object arg, oldval;
1944{
80534dd6
KH
1945 int result;
1946
1947 if (STRINGP (arg))
1948 {
1949 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1950 return;
1951 }
1952 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
1953 return;
1954
f468da95 1955 f->icon_name = arg;
80534dd6 1956
7556890b 1957 if (f->output_data.x->icon_bitmap != 0)
80534dd6
KH
1958 return;
1959
1960 BLOCK_INPUT;
1961
1962 result = x_text_icon (f,
f468da95
RS
1963 (char *) XSTRING ((!NILP (f->icon_name)
1964 ? f->icon_name
943b580d
RS
1965 : !NILP (f->title)
1966 ? f->title
80534dd6
KH
1967 : f->name))->data);
1968
1969 if (result)
1970 {
1971 UNBLOCK_INPUT;
1972 error ("No icon window available");
1973 }
1974
80534dd6
KH
1975 XFlush (FRAME_X_DISPLAY (f));
1976 UNBLOCK_INPUT;
1977}
943b580d 1978\f
01f1ba30 1979void
f676886a
JB
1980x_set_font (f, arg, oldval)
1981 struct frame *f;
01f1ba30
JB
1982 Lisp_Object arg, oldval;
1983{
ea96210c 1984 Lisp_Object result;
942ea06d 1985 Lisp_Object fontset_name;
a367641f 1986 Lisp_Object frame;
57c5889c 1987 int old_fontset = f->output_data.x->fontset;
01f1ba30 1988
b7826503 1989 CHECK_STRING (arg);
01f1ba30 1990
49965a29 1991 fontset_name = Fquery_fontset (arg, Qnil);
942ea06d 1992
01f1ba30 1993 BLOCK_INPUT;
942ea06d
KH
1994 result = (STRINGP (fontset_name)
1995 ? x_new_fontset (f, XSTRING (fontset_name)->data)
1996 : x_new_font (f, XSTRING (arg)->data));
01f1ba30
JB
1997 UNBLOCK_INPUT;
1998
ea96210c 1999 if (EQ (result, Qnil))
1c59f5df 2000 error ("Font `%s' is not defined", XSTRING (arg)->data);
ea96210c 2001 else if (EQ (result, Qt))
26e18ed9 2002 error ("The characters of the given font have varying widths");
ea96210c
JB
2003 else if (STRINGP (result))
2004 {
57c5889c
GM
2005 if (STRINGP (fontset_name))
2006 {
2007 /* Fontset names are built from ASCII font names, so the
2008 names may be equal despite there was a change. */
2009 if (old_fontset == f->output_data.x->fontset)
2010 return;
2011 }
2012 else if (!NILP (Fequal (result, oldval)))
1d090605 2013 return;
57c5889c 2014
ea96210c 2015 store_frame_param (f, Qfont, result);
333b20bb 2016 recompute_basic_faces (f);
ea96210c
JB
2017 }
2018 else
2019 abort ();
a367641f 2020
8938a4fb 2021 do_pending_window_change (0);
95aa0336 2022
333b20bb
GM
2023 /* Don't call `face-set-after-frame-default' when faces haven't been
2024 initialized yet. This is the case when called from
2025 Fx_create_frame. In that case, the X widget or window doesn't
2026 exist either, and we can end up in x_report_frame_params with a
2027 null widget which gives a segfault. */
2028 if (FRAME_FACE_CACHE (f))
2029 {
2030 XSETFRAME (frame, f);
2031 call1 (Qface_set_after_frame_default, frame);
2032 }
01f1ba30
JB
2033}
2034
b3ba0aa8
KS
2035static void
2036x_set_fringe_width (f, new_value, old_value)
2037 struct frame *f;
2038 Lisp_Object new_value, old_value;
2039{
2040 x_compute_fringe_widths (f, 1);
2041}
2042
01f1ba30 2043void
f676886a
JB
2044x_set_border_width (f, arg, oldval)
2045 struct frame *f;
01f1ba30
JB
2046 Lisp_Object arg, oldval;
2047{
b7826503 2048 CHECK_NUMBER (arg);
01f1ba30 2049
7556890b 2050 if (XINT (arg) == f->output_data.x->border_width)
01f1ba30
JB
2051 return;
2052
fe24a618 2053 if (FRAME_X_WINDOW (f) != 0)
01f1ba30
JB
2054 error ("Cannot change the border width of a window");
2055
7556890b 2056 f->output_data.x->border_width = XINT (arg);
01f1ba30
JB
2057}
2058
2059void
f676886a
JB
2060x_set_internal_border_width (f, arg, oldval)
2061 struct frame *f;
01f1ba30
JB
2062 Lisp_Object arg, oldval;
2063{
7556890b 2064 int old = f->output_data.x->internal_border_width;
01f1ba30 2065
b7826503 2066 CHECK_NUMBER (arg);
7556890b
RS
2067 f->output_data.x->internal_border_width = XINT (arg);
2068 if (f->output_data.x->internal_border_width < 0)
2069 f->output_data.x->internal_border_width = 0;
01f1ba30 2070
d3b06468 2071#ifdef USE_X_TOOLKIT
2a8a07d4 2072 if (f->output_data.x->edit_widget)
968b1234 2073 widget_store_internal_border (f->output_data.x->edit_widget);
d3b06468 2074#endif
2a8a07d4 2075
7556890b 2076 if (f->output_data.x->internal_border_width == old)
01f1ba30
JB
2077 return;
2078
fe24a618 2079 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 2080 {
363f7e15 2081 x_set_window_size (f, 0, f->width, f->height);
f676886a 2082 SET_FRAME_GARBAGED (f);
8938a4fb 2083 do_pending_window_change (0);
01f1ba30 2084 }
ea42193a
GM
2085 else
2086 SET_FRAME_GARBAGED (f);
01f1ba30
JB
2087}
2088
d043f1a4
RS
2089void
2090x_set_visibility (f, value, oldval)
2091 struct frame *f;
2092 Lisp_Object value, oldval;
2093{
2094 Lisp_Object frame;
191ed777 2095 XSETFRAME (frame, f);
d043f1a4
RS
2096
2097 if (NILP (value))
363f7e15 2098 Fmake_frame_invisible (frame, Qt);
49795535 2099 else if (EQ (value, Qicon))
d043f1a4 2100 Ficonify_frame (frame);
49795535
JB
2101 else
2102 Fmake_frame_visible (frame);
d043f1a4 2103}
52de7ce9 2104
943b580d 2105\f
52de7ce9
GM
2106/* Change window heights in windows rooted in WINDOW by N lines. */
2107
d043f1a4 2108static void
52de7ce9 2109x_change_window_heights (window, n)
d043f1a4
RS
2110 Lisp_Object window;
2111 int n;
2112{
47c0f58b 2113 struct window *w = XWINDOW (window);
d043f1a4 2114
e33f7330
KH
2115 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2116 XSETFASTINT (w->height, XFASTINT (w->height) - n);
d043f1a4 2117
4336c705
GM
2118 if (INTEGERP (w->orig_top))
2119 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2120 if (INTEGERP (w->orig_height))
2121 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2122
47c0f58b
RS
2123 /* Handle just the top child in a vertical split. */
2124 if (!NILP (w->vchild))
52de7ce9 2125 x_change_window_heights (w->vchild, n);
d043f1a4 2126
47c0f58b
RS
2127 /* Adjust all children in a horizontal split. */
2128 for (window = w->hchild; !NILP (window); window = w->next)
2129 {
2130 w = XWINDOW (window);
52de7ce9 2131 x_change_window_heights (window, n);
d043f1a4
RS
2132 }
2133}
2134
2135void
2136x_set_menu_bar_lines (f, value, oldval)
2137 struct frame *f;
2138 Lisp_Object value, oldval;
2139{
2140 int nlines;
b6d7acec 2141#ifndef USE_X_TOOLKIT
d043f1a4 2142 int olines = FRAME_MENU_BAR_LINES (f);
b6d7acec 2143#endif
d043f1a4 2144
f64ba6ea
JB
2145 /* Right now, menu bars don't work properly in minibuf-only frames;
2146 most of the commands try to apply themselves to the minibuffer
333b20bb 2147 frame itself, and get an error because you can't switch buffers
f64ba6ea 2148 in or split the minibuffer window. */
519066d2 2149 if (FRAME_MINIBUF_ONLY_P (f))
f64ba6ea
JB
2150 return;
2151
6a5e54e2 2152 if (INTEGERP (value))
d043f1a4
RS
2153 nlines = XINT (value);
2154 else
2155 nlines = 0;
2156
3d09b6be
RS
2157 /* Make sure we redisplay all windows in this frame. */
2158 windows_or_buffers_changed++;
2159
9ef48a9d
RS
2160#ifdef USE_X_TOOLKIT
2161 FRAME_MENU_BAR_LINES (f) = 0;
2162 if (nlines)
0d8ef3f4
RS
2163 {
2164 FRAME_EXTERNAL_MENU_BAR (f) = 1;
97a1ff91 2165 if (FRAME_X_P (f) && f->output_data.x->menubar_widget == 0)
0d8ef3f4
RS
2166 /* Make sure next redisplay shows the menu bar. */
2167 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt;
2168 }
9ef48a9d
RS
2169 else
2170 {
6bc20398
FP
2171 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2172 free_frame_menubar (f);
9ef48a9d 2173 FRAME_EXTERNAL_MENU_BAR (f) = 0;
97a1ff91
RS
2174 if (FRAME_X_P (f))
2175 f->output_data.x->menubar_widget = 0;
9ef48a9d
RS
2176 }
2177#else /* not USE_X_TOOLKIT */
d043f1a4 2178 FRAME_MENU_BAR_LINES (f) = nlines;
52de7ce9 2179 x_change_window_heights (f->root_window, nlines - olines);
9ef48a9d 2180#endif /* not USE_X_TOOLKIT */
333b20bb
GM
2181 adjust_glyphs (f);
2182}
2183
2184
2185/* Set the number of lines used for the tool bar of frame F to VALUE.
2186 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2187 is the old number of tool bar lines. This function changes the
2188 height of all windows on frame F to match the new tool bar height.
2189 The frame's height doesn't change. */
2190
2191void
9ea173e8 2192x_set_tool_bar_lines (f, value, oldval)
333b20bb
GM
2193 struct frame *f;
2194 Lisp_Object value, oldval;
2195{
52de7ce9
GM
2196 int delta, nlines, root_height;
2197 Lisp_Object root_window;
333b20bb 2198
e870b7ba
GM
2199 /* Treat tool bars like menu bars. */
2200 if (FRAME_MINIBUF_ONLY_P (f))
2201 return;
2202
333b20bb
GM
2203 /* Use VALUE only if an integer >= 0. */
2204 if (INTEGERP (value) && XINT (value) >= 0)
2205 nlines = XFASTINT (value);
2206 else
2207 nlines = 0;
2208
2209 /* Make sure we redisplay all windows in this frame. */
2210 ++windows_or_buffers_changed;
2211
9ea173e8 2212 delta = nlines - FRAME_TOOL_BAR_LINES (f);
52de7ce9
GM
2213
2214 /* Don't resize the tool-bar to more than we have room for. */
2215 root_window = FRAME_ROOT_WINDOW (f);
2216 root_height = XINT (XWINDOW (root_window)->height);
2217 if (root_height - delta < 1)
2218 {
2219 delta = root_height - 1;
2220 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2221 }
2222
9ea173e8 2223 FRAME_TOOL_BAR_LINES (f) = nlines;
52de7ce9 2224 x_change_window_heights (root_window, delta);
333b20bb 2225 adjust_glyphs (f);
ccba751c
GM
2226
2227 /* We also have to make sure that the internal border at the top of
2228 the frame, below the menu bar or tool bar, is redrawn when the
2229 tool bar disappears. This is so because the internal border is
2230 below the tool bar if one is displayed, but is below the menu bar
2231 if there isn't a tool bar. The tool bar draws into the area
2232 below the menu bar. */
2233 if (FRAME_X_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2234 {
2235 updating_frame = f;
2236 clear_frame ();
fb3cd89b 2237 clear_current_matrices (f);
ccba751c
GM
2238 updating_frame = NULL;
2239 }
b6f91066
GM
2240
2241 /* If the tool bar gets smaller, the internal border below it
2242 has to be cleared. It was formerly part of the display
2243 of the larger tool bar, and updating windows won't clear it. */
2244 if (delta < 0)
2245 {
2246 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2247 int width = PIXEL_WIDTH (f);
2248 int y = nlines * CANON_Y_UNIT (f);
2249
2250 BLOCK_INPUT;
161d30fd
GM
2251 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2252 0, y, width, height, False);
b6f91066 2253 UNBLOCK_INPUT;
ddc24747
GM
2254
2255 if (WINDOWP (f->tool_bar_window))
2256 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
b6f91066 2257 }
333b20bb
GM
2258}
2259
2260
2261/* Set the foreground color for scroll bars on frame F to VALUE.
2262 VALUE should be a string, a color name. If it isn't a string or
2263 isn't a valid color name, do nothing. OLDVAL is the old value of
2264 the frame parameter. */
2265
2266void
2267x_set_scroll_bar_foreground (f, value, oldval)
2268 struct frame *f;
2269 Lisp_Object value, oldval;
2270{
2271 unsigned long pixel;
2272
2273 if (STRINGP (value))
2274 pixel = x_decode_color (f, value, BLACK_PIX_DEFAULT (f));
2275 else
2276 pixel = -1;
2277
2278 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
2279 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
2280
2281 f->output_data.x->scroll_bar_foreground_pixel = pixel;
2282 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2283 {
2284 /* Remove all scroll bars because they have wrong colors. */
2285 if (condemn_scroll_bars_hook)
2286 (*condemn_scroll_bars_hook) (f);
2287 if (judge_scroll_bars_hook)
2288 (*judge_scroll_bars_hook) (f);
05c8abbe
GM
2289
2290 update_face_from_frame_parameter (f, Qscroll_bar_foreground, value);
333b20bb
GM
2291 redraw_frame (f);
2292 }
2293}
2294
2295
2296/* Set the background color for scroll bars on frame F to VALUE VALUE
2297 should be a string, a color name. If it isn't a string or isn't a
2298 valid color name, do nothing. OLDVAL is the old value of the frame
2299 parameter. */
2300
2301void
2302x_set_scroll_bar_background (f, value, oldval)
2303 struct frame *f;
2304 Lisp_Object value, oldval;
2305{
2306 unsigned long pixel;
2307
2308 if (STRINGP (value))
2309 pixel = x_decode_color (f, value, WHITE_PIX_DEFAULT (f));
2310 else
2311 pixel = -1;
2312
2313 if (f->output_data.x->scroll_bar_background_pixel != -1)
2314 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
2315
f15340b7
MB
2316#ifdef USE_TOOLKIT_SCROLL_BARS
2317 /* Scrollbar shadow colors. */
2318 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
2319 {
2320 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
2321 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
2322 }
2323 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
2324 {
2325 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
2326 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
2327 }
2328#endif /* USE_TOOLKIT_SCROLL_BARS */
2329
333b20bb
GM
2330 f->output_data.x->scroll_bar_background_pixel = pixel;
2331 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2332 {
2333 /* Remove all scroll bars because they have wrong colors. */
2334 if (condemn_scroll_bars_hook)
2335 (*condemn_scroll_bars_hook) (f);
2336 if (judge_scroll_bars_hook)
2337 (*judge_scroll_bars_hook) (f);
2338
05c8abbe 2339 update_face_from_frame_parameter (f, Qscroll_bar_background, value);
333b20bb
GM
2340 redraw_frame (f);
2341 }
d043f1a4 2342}
333b20bb 2343
943b580d 2344\f
3a258507 2345/* Encode Lisp string STRING as a text in a format appropriate for
96db09e4
KH
2346 XICCC (X Inter Client Communication Conventions).
2347
2348 If STRING contains only ASCII characters, do no conversion and
2349 return the string data of STRING. Otherwise, encode the text by
2350 CODING_SYSTEM, and return a newly allocated memory area which
2351 should be freed by `xfree' by a caller.
2352
37323f34
EZ
2353 SELECTIONP non-zero means the string is being encoded for an X
2354 selection, so it is safe to run pre-write conversions (which
2355 may run Lisp code).
2356
96db09e4
KH
2357 Store the byte length of resulting text in *TEXT_BYTES.
2358
d60660d6 2359 If the text contains only ASCII and Latin-1, store 1 in *STRING_P,
96db09e4 2360 which means that the `encoding' of the result can be `STRING'.
d60660d6 2361 Otherwise store 0 in *STRINGP, which means that the `encoding' of
96db09e4
KH
2362 the result should be `COMPOUND_TEXT'. */
2363
2364unsigned char *
37323f34 2365x_encode_text (string, coding_system, selectionp, text_bytes, stringp)
96db09e4 2366 Lisp_Object string, coding_system;
d60660d6 2367 int *text_bytes, *stringp;
37323f34 2368 int selectionp;
96db09e4
KH
2369{
2370 unsigned char *str = XSTRING (string)->data;
2371 int chars = XSTRING (string)->size;
2372 int bytes = STRING_BYTES (XSTRING (string));
2373 int charset_info;
2374 int bufsize;
2375 unsigned char *buf;
2376 struct coding_system coding;
2377
2378 charset_info = find_charset_in_text (str, chars, bytes, NULL, Qnil);
2379 if (charset_info == 0)
2380 {
2381 /* No multibyte character in OBJ. We need not encode it. */
2382 *text_bytes = bytes;
d60660d6 2383 *stringp = 1;
96db09e4
KH
2384 return str;
2385 }
2386
2387 setup_coding_system (coding_system, &coding);
37323f34
EZ
2388 if (selectionp
2389 && SYMBOLP (coding.pre_write_conversion)
2390 && !NILP (Ffboundp (coding.pre_write_conversion)))
2391 {
2392 string = run_pre_post_conversion_on_str (string, &coding, 1);
2393 str = XSTRING (string)->data;
2394 chars = XSTRING (string)->size;
2395 bytes = STRING_BYTES (XSTRING (string));
2396 }
96db09e4
KH
2397 coding.src_multibyte = 1;
2398 coding.dst_multibyte = 0;
2399 coding.mode |= CODING_MODE_LAST_BLOCK;
d60660d6
KH
2400 if (coding.type == coding_type_iso2022)
2401 coding.flags |= CODING_FLAG_ISO_SAFE;
35bc5887
KH
2402 /* We suppress producing escape sequences for composition. */
2403 coding.composing = COMPOSITION_DISABLED;
96db09e4
KH
2404 bufsize = encoding_buffer_size (&coding, bytes);
2405 buf = (unsigned char *) xmalloc (bufsize);
2406 encode_coding (&coding, str, buf, bytes, bufsize);
2407 *text_bytes = coding.produced;
d60660d6 2408 *stringp = (charset_info == 1 || !EQ (coding_system, Qcompound_text));
96db09e4
KH
2409 return buf;
2410}
2411
2412\f
75f9d625 2413/* Change the name of frame F to NAME. If NAME is nil, set F's name to
f945b920
JB
2414 x_id_name.
2415
2416 If EXPLICIT is non-zero, that indicates that lisp code is setting the
75f9d625
DM
2417 name; if NAME is a string, set F's name to NAME and set
2418 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
f945b920
JB
2419
2420 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2421 suggesting a new name, which lisp code should override; if
2422 F->explicit_name is set, ignore the new name; otherwise, set it. */
2423
2424void
2425x_set_name (f, name, explicit)
2426 struct frame *f;
2427 Lisp_Object name;
2428 int explicit;
2429{
2430 /* Make sure that requests from lisp code override requests from
2431 Emacs redisplay code. */
2432 if (explicit)
2433 {
2434 /* If we're switching from explicit to implicit, we had better
2435 update the mode lines and thereby update the title. */
2436 if (f->explicit_name && NILP (name))
cf177271 2437 update_mode_lines = 1;
f945b920
JB
2438
2439 f->explicit_name = ! NILP (name);
2440 }
2441 else if (f->explicit_name)
2442 return;
2443
2444 /* If NAME is nil, set the name to the x_id_name. */
2445 if (NILP (name))
f10f0b79
RS
2446 {
2447 /* Check for no change needed in this very common case
2448 before we do any consing. */
08a90d6a
RS
2449 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->x_id_name,
2450 XSTRING (f->name)->data))
f10f0b79 2451 return;
08a90d6a 2452 name = build_string (FRAME_X_DISPLAY_INFO (f)->x_id_name);
f10f0b79 2453 }
62265f1c 2454 else
b7826503 2455 CHECK_STRING (name);
01f1ba30 2456
f945b920
JB
2457 /* Don't change the name if it's already NAME. */
2458 if (! NILP (Fstring_equal (name, f->name)))
daa37602
JB
2459 return;
2460
943b580d
RS
2461 f->name = name;
2462
2463 /* For setting the frame title, the title parameter should override
2464 the name parameter. */
2465 if (! NILP (f->title))
2466 name = f->title;
2467
fe24a618 2468 if (FRAME_X_WINDOW (f))
01f1ba30 2469 {
01f1ba30 2470 BLOCK_INPUT;
fe24a618
JB
2471#ifdef HAVE_X11R4
2472 {
80534dd6 2473 XTextProperty text, icon;
d60660d6 2474 int bytes, stringp;
11270583 2475 Lisp_Object coding_system;
80534dd6 2476
11270583
KH
2477 coding_system = Vlocale_coding_system;
2478 if (NILP (coding_system))
2479 coding_system = Qcompound_text;
37323f34 2480 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2481 text.encoding = (stringp ? XA_STRING
96db09e4 2482 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
fe24a618 2483 text.format = 8;
96db09e4 2484 text.nitems = bytes;
80534dd6 2485
96db09e4
KH
2486 if (NILP (f->icon_name))
2487 {
2488 icon = text;
2489 }
2490 else
2491 {
37323f34 2492 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2493 &bytes, &stringp);
2494 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2495 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2496 icon.format = 8;
2497 icon.nitems = bytes;
2498 }
9ef48a9d 2499#ifdef USE_X_TOOLKIT
b9dc4443 2500 XSetWMName (FRAME_X_DISPLAY (f),
7556890b
RS
2501 XtWindow (f->output_data.x->widget), &text);
2502 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
80534dd6 2503 &icon);
9ef48a9d 2504#else /* not USE_X_TOOLKIT */
b9dc4443 2505 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
80534dd6 2506 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
9ef48a9d 2507#endif /* not USE_X_TOOLKIT */
96db09e4
KH
2508 if (!NILP (f->icon_name)
2509 && icon.value != XSTRING (f->icon_name)->data)
2510 xfree (icon.value);
2511 if (text.value != XSTRING (name)->data)
2512 xfree (text.value);
fe24a618 2513 }
9ef48a9d 2514#else /* not HAVE_X11R4 */
b9dc4443 2515 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
fe24a618 2516 XSTRING (name)->data);
b9dc4443 2517 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
fe24a618 2518 XSTRING (name)->data);
9ef48a9d 2519#endif /* not HAVE_X11R4 */
01f1ba30
JB
2520 UNBLOCK_INPUT;
2521 }
f945b920
JB
2522}
2523
2524/* This function should be called when the user's lisp code has
2525 specified a name for the frame; the name will override any set by the
2526 redisplay code. */
2527void
2528x_explicitly_set_name (f, arg, oldval)
2529 FRAME_PTR f;
2530 Lisp_Object arg, oldval;
2531{
2532 x_set_name (f, arg, 1);
2533}
2534
2535/* This function should be called by Emacs redisplay code to set the
2536 name; names set this way will never override names set by the user's
2537 lisp code. */
25250031 2538void
f945b920
JB
2539x_implicitly_set_name (f, arg, oldval)
2540 FRAME_PTR f;
2541 Lisp_Object arg, oldval;
2542{
2543 x_set_name (f, arg, 0);
01f1ba30 2544}
943b580d
RS
2545\f
2546/* Change the title of frame F to NAME.
2547 If NAME is nil, use the frame name as the title.
01f1ba30 2548
943b580d
RS
2549 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2550 name; if NAME is a string, set F's name to NAME and set
2551 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2552
2553 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2554 suggesting a new name, which lisp code should override; if
2555 F->explicit_name is set, ignore the new name; otherwise, set it. */
2556
2557void
d62c8769 2558x_set_title (f, name, old_name)
943b580d 2559 struct frame *f;
d62c8769 2560 Lisp_Object name, old_name;
943b580d
RS
2561{
2562 /* Don't change the title if it's already NAME. */
2563 if (EQ (name, f->title))
2564 return;
2565
2566 update_mode_lines = 1;
2567
2568 f->title = name;
2569
2570 if (NILP (name))
2571 name = f->name;
beb403b3 2572 else
b7826503 2573 CHECK_STRING (name);
943b580d
RS
2574
2575 if (FRAME_X_WINDOW (f))
2576 {
2577 BLOCK_INPUT;
2578#ifdef HAVE_X11R4
2579 {
2580 XTextProperty text, icon;
d60660d6 2581 int bytes, stringp;
11270583 2582 Lisp_Object coding_system;
943b580d 2583
11270583
KH
2584 coding_system = Vlocale_coding_system;
2585 if (NILP (coding_system))
2586 coding_system = Qcompound_text;
37323f34 2587 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2588 text.encoding = (stringp ? XA_STRING
96db09e4 2589 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
943b580d 2590 text.format = 8;
96db09e4 2591 text.nitems = bytes;
943b580d 2592
96db09e4
KH
2593 if (NILP (f->icon_name))
2594 {
2595 icon = text;
2596 }
2597 else
2598 {
37323f34 2599 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2600 &bytes, &stringp);
2601 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2602 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2603 icon.format = 8;
2604 icon.nitems = bytes;
2605 }
943b580d
RS
2606#ifdef USE_X_TOOLKIT
2607 XSetWMName (FRAME_X_DISPLAY (f),
2608 XtWindow (f->output_data.x->widget), &text);
2609 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
2610 &icon);
2611#else /* not USE_X_TOOLKIT */
2612 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
2613 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
2614#endif /* not USE_X_TOOLKIT */
96db09e4
KH
2615 if (!NILP (f->icon_name)
2616 && icon.value != XSTRING (f->icon_name)->data)
2617 xfree (icon.value);
2618 if (text.value != XSTRING (name)->data)
2619 xfree (text.value);
943b580d
RS
2620 }
2621#else /* not HAVE_X11R4 */
2622 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2623 XSTRING (name)->data);
2624 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2625 XSTRING (name)->data);
2626#endif /* not HAVE_X11R4 */
2627 UNBLOCK_INPUT;
2628 }
2629}
2630\f
01f1ba30 2631void
f676886a
JB
2632x_set_autoraise (f, arg, oldval)
2633 struct frame *f;
01f1ba30
JB
2634 Lisp_Object arg, oldval;
2635{
f676886a 2636 f->auto_raise = !EQ (Qnil, arg);
01f1ba30
JB
2637}
2638
2639void
f676886a
JB
2640x_set_autolower (f, arg, oldval)
2641 struct frame *f;
01f1ba30
JB
2642 Lisp_Object arg, oldval;
2643{
f676886a 2644 f->auto_lower = !EQ (Qnil, arg);
01f1ba30 2645}
179956b9 2646
eac358ef
KH
2647void
2648x_set_unsplittable (f, arg, oldval)
2649 struct frame *f;
2650 Lisp_Object arg, oldval;
2651{
2652 f->no_split = !NILP (arg);
2653}
2654
179956b9 2655void
a3c87d4e 2656x_set_vertical_scroll_bars (f, arg, oldval)
179956b9
JB
2657 struct frame *f;
2658 Lisp_Object arg, oldval;
2659{
1ab3d87e
RS
2660 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2661 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2662 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2663 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
179956b9 2664 {
1ab3d87e
RS
2665 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2666 = (NILP (arg)
2667 ? vertical_scroll_bar_none
2668 : EQ (Qright, arg)
2669 ? vertical_scroll_bar_right
2670 : vertical_scroll_bar_left);
179956b9 2671
cf177271
JB
2672 /* We set this parameter before creating the X window for the
2673 frame, so we can get the geometry right from the start.
2674 However, if the window hasn't been created yet, we shouldn't
2675 call x_set_window_size. */
2676 if (FRAME_X_WINDOW (f))
363f7e15 2677 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2678 do_pending_window_change (0);
179956b9
JB
2679 }
2680}
4701395c
KH
2681
2682void
2683x_set_scroll_bar_width (f, arg, oldval)
2684 struct frame *f;
2685 Lisp_Object arg, oldval;
2686{
a672c74d
RS
2687 int wid = FONT_WIDTH (f->output_data.x->font);
2688
dff9a538
KH
2689 if (NILP (arg))
2690 {
c6e9d03b
GM
2691#ifdef USE_TOOLKIT_SCROLL_BARS
2692 /* A minimum width of 14 doesn't look good for toolkit scroll bars. */
333b20bb
GM
2693 int width = 16 + 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM;
2694 FRAME_SCROLL_BAR_COLS (f) = (width + wid - 1) / wid;
2695 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = width;
2696#else
2697 /* Make the actual width at least 14 pixels and a multiple of a
2698 character width. */
a672c74d 2699 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
333b20bb
GM
2700
2701 /* Use all of that space (aside from required margins) for the
2702 scroll bar. */
dff9a538 2703 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
333b20bb 2704#endif
a672c74d 2705
a90ab372
RS
2706 if (FRAME_X_WINDOW (f))
2707 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2708 do_pending_window_change (0);
dff9a538
KH
2709 }
2710 else if (INTEGERP (arg) && XINT (arg) > 0
2711 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
4701395c 2712 {
09d8c7ac
RS
2713 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
2714 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
0a26b136 2715
4701395c
KH
2716 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2717 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
2718 if (FRAME_X_WINDOW (f))
2719 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2720 }
dca97592 2721
8938a4fb 2722 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
333b20bb
GM
2723 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2724 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
4701395c 2725}
333b20bb
GM
2726
2727
01f1ba30 2728\f
f676886a 2729/* Subroutines of creating an X frame. */
01f1ba30 2730
b7975ee4
KH
2731/* Make sure that Vx_resource_name is set to a reasonable value.
2732 Fix it up, or set it to `emacs' if it is too hopeless. */
2733
d387c960
JB
2734static void
2735validate_x_resource_name ()
2736{
333b20bb 2737 int len = 0;
0e78b377
RS
2738 /* Number of valid characters in the resource name. */
2739 int good_count = 0;
2740 /* Number of invalid characters in the resource name. */
2741 int bad_count = 0;
2742 Lisp_Object new;
2743 int i;
2744
498e9ac3
RS
2745 if (!STRINGP (Vx_resource_class))
2746 Vx_resource_class = build_string (EMACS_CLASS);
2747
cf204347
RS
2748 if (STRINGP (Vx_resource_name))
2749 {
cf204347
RS
2750 unsigned char *p = XSTRING (Vx_resource_name)->data;
2751 int i;
2752
fc932ac6 2753 len = STRING_BYTES (XSTRING (Vx_resource_name));
0e78b377
RS
2754
2755 /* Only letters, digits, - and _ are valid in resource names.
2756 Count the valid characters and count the invalid ones. */
cf204347
RS
2757 for (i = 0; i < len; i++)
2758 {
2759 int c = p[i];
2760 if (! ((c >= 'a' && c <= 'z')
2761 || (c >= 'A' && c <= 'Z')
2762 || (c >= '0' && c <= '9')
2763 || c == '-' || c == '_'))
0e78b377
RS
2764 bad_count++;
2765 else
2766 good_count++;
cf204347
RS
2767 }
2768 }
2769 else
0e78b377
RS
2770 /* Not a string => completely invalid. */
2771 bad_count = 5, good_count = 0;
2772
2773 /* If name is valid already, return. */
2774 if (bad_count == 0)
2775 return;
2776
2777 /* If name is entirely invalid, or nearly so, use `emacs'. */
2778 if (good_count == 0
2779 || (good_count == 1 && bad_count > 0))
2780 {
b7975ee4 2781 Vx_resource_name = build_string ("emacs");
0e78b377
RS
2782 return;
2783 }
2784
2785 /* Name is partly valid. Copy it and replace the invalid characters
2786 with underscores. */
2787
2788 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2789
2790 for (i = 0; i < len; i++)
2791 {
2792 int c = XSTRING (new)->data[i];
2793 if (! ((c >= 'a' && c <= 'z')
2794 || (c >= 'A' && c <= 'Z')
2795 || (c >= '0' && c <= '9')
2796 || c == '-' || c == '_'))
2797 XSTRING (new)->data[i] = '_';
2798 }
d387c960
JB
2799}
2800
2801
01f1ba30 2802extern char *x_get_string_resource ();
01f1ba30 2803
cf177271 2804DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
03265352 2805 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
c061c855
GM
2806This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2807class, where INSTANCE is the name under which Emacs was invoked, or
2808the name specified by the `-name' or `-rn' command-line arguments.
2809
2810The optional arguments COMPONENT and SUBCLASS add to the key and the
2811class, respectively. You must specify both of them or neither.
2812If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
7ee72033
MB
2813and the class is `Emacs.CLASS.SUBCLASS'. */)
2814 (attribute, class, component, subclass)
cf177271 2815 Lisp_Object attribute, class, component, subclass;
01f1ba30
JB
2816{
2817 register char *value;
2818 char *name_key;
2819 char *class_key;
2820
11ae94fe
RS
2821 check_x ();
2822
b7826503
PJ
2823 CHECK_STRING (attribute);
2824 CHECK_STRING (class);
cf177271 2825
8fabe6f4 2826 if (!NILP (component))
b7826503 2827 CHECK_STRING (component);
8fabe6f4 2828 if (!NILP (subclass))
b7826503 2829 CHECK_STRING (subclass);
8fabe6f4
RS
2830 if (NILP (component) != NILP (subclass))
2831 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2832
d387c960
JB
2833 validate_x_resource_name ();
2834
b7975ee4
KH
2835 /* Allocate space for the components, the dots which separate them,
2836 and the final '\0'. Make them big enough for the worst case. */
fc932ac6 2837 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
b7975ee4 2838 + (STRINGP (component)
fc932ac6
RS
2839 ? STRING_BYTES (XSTRING (component)) : 0)
2840 + STRING_BYTES (XSTRING (attribute))
b7975ee4
KH
2841 + 3);
2842
fc932ac6
RS
2843 class_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_class))
2844 + STRING_BYTES (XSTRING (class))
b7975ee4 2845 + (STRINGP (subclass)
fc932ac6 2846 ? STRING_BYTES (XSTRING (subclass)) : 0)
b7975ee4
KH
2847 + 3);
2848
2849 /* Start with emacs.FRAMENAME for the name (the specific one)
2850 and with `Emacs' for the class key (the general one). */
2851 strcpy (name_key, XSTRING (Vx_resource_name)->data);
498e9ac3 2852 strcpy (class_key, XSTRING (Vx_resource_class)->data);
b7975ee4
KH
2853
2854 strcat (class_key, ".");
2855 strcat (class_key, XSTRING (class)->data);
2856
2857 if (!NILP (component))
01f1ba30 2858 {
b7975ee4
KH
2859 strcat (class_key, ".");
2860 strcat (class_key, XSTRING (subclass)->data);
2861
2862 strcat (name_key, ".");
2863 strcat (name_key, XSTRING (component)->data);
01f1ba30
JB
2864 }
2865
b7975ee4
KH
2866 strcat (name_key, ".");
2867 strcat (name_key, XSTRING (attribute)->data);
2868
b9dc4443
RS
2869 value = x_get_string_resource (check_x_display_info (Qnil)->xrdb,
2870 name_key, class_key);
01f1ba30
JB
2871
2872 if (value != (char *) 0)
2873 return build_string (value);
2874 else
2875 return Qnil;
2876}
2877
abb4b7ec
RS
2878/* Get an X resource, like Fx_get_resource, but for display DPYINFO. */
2879
333b20bb 2880Lisp_Object
abb4b7ec
RS
2881display_x_get_resource (dpyinfo, attribute, class, component, subclass)
2882 struct x_display_info *dpyinfo;
2883 Lisp_Object attribute, class, component, subclass;
2884{
2885 register char *value;
2886 char *name_key;
2887 char *class_key;
2888
b7826503
PJ
2889 CHECK_STRING (attribute);
2890 CHECK_STRING (class);
abb4b7ec
RS
2891
2892 if (!NILP (component))
b7826503 2893 CHECK_STRING (component);
abb4b7ec 2894 if (!NILP (subclass))
b7826503 2895 CHECK_STRING (subclass);
abb4b7ec
RS
2896 if (NILP (component) != NILP (subclass))
2897 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2898
2899 validate_x_resource_name ();
2900
2901 /* Allocate space for the components, the dots which separate them,
2902 and the final '\0'. Make them big enough for the worst case. */
fc932ac6 2903 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
abb4b7ec 2904 + (STRINGP (component)
fc932ac6
RS
2905 ? STRING_BYTES (XSTRING (component)) : 0)
2906 + STRING_BYTES (XSTRING (attribute))
abb4b7ec
RS
2907 + 3);
2908
fc932ac6
RS
2909 class_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_class))
2910 + STRING_BYTES (XSTRING (class))
abb4b7ec 2911 + (STRINGP (subclass)
fc932ac6 2912 ? STRING_BYTES (XSTRING (subclass)) : 0)
abb4b7ec
RS
2913 + 3);
2914
2915 /* Start with emacs.FRAMENAME for the name (the specific one)
2916 and with `Emacs' for the class key (the general one). */
2917 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2918 strcpy (class_key, XSTRING (Vx_resource_class)->data);
2919
2920 strcat (class_key, ".");
2921 strcat (class_key, XSTRING (class)->data);
2922
2923 if (!NILP (component))
2924 {
2925 strcat (class_key, ".");
2926 strcat (class_key, XSTRING (subclass)->data);
2927
2928 strcat (name_key, ".");
2929 strcat (name_key, XSTRING (component)->data);
2930 }
2931
2932 strcat (name_key, ".");
2933 strcat (name_key, XSTRING (attribute)->data);
2934
2935 value = x_get_string_resource (dpyinfo->xrdb, name_key, class_key);
2936
2937 if (value != (char *) 0)
2938 return build_string (value);
2939 else
2940 return Qnil;
2941}
2942
3402e1a4
RS
2943/* Used when C code wants a resource value. */
2944
2945char *
2946x_get_resource_string (attribute, class)
2947 char *attribute, *class;
2948{
3402e1a4
RS
2949 char *name_key;
2950 char *class_key;
0fe92f72 2951 struct frame *sf = SELECTED_FRAME ();
3402e1a4
RS
2952
2953 /* Allocate space for the components, the dots which separate them,
2954 and the final '\0'. */
fc932ac6 2955 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3402e1a4
RS
2956 + strlen (attribute) + 2);
2957 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2958 + strlen (class) + 2);
2959
2960 sprintf (name_key, "%s.%s",
2961 XSTRING (Vinvocation_name)->data,
2962 attribute);
2963 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2964
0fe92f72 2965 return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
b9dc4443 2966 name_key, class_key);
3402e1a4
RS
2967}
2968
60fb3ee1
JB
2969/* Types we might convert a resource string into. */
2970enum resource_types
333b20bb
GM
2971{
2972 RES_TYPE_NUMBER,
d62c8769 2973 RES_TYPE_FLOAT,
333b20bb
GM
2974 RES_TYPE_BOOLEAN,
2975 RES_TYPE_STRING,
2976 RES_TYPE_SYMBOL
2977};
60fb3ee1 2978
01f1ba30 2979/* Return the value of parameter PARAM.
60fb3ee1 2980
f676886a 2981 First search ALIST, then Vdefault_frame_alist, then the X defaults
cf177271 2982 database, using ATTRIBUTE as the attribute name and CLASS as its class.
60fb3ee1
JB
2983
2984 Convert the resource to the type specified by desired_type.
2985
f9942c9e
JB
2986 If no default is specified, return Qunbound. If you call
2987 x_get_arg, make sure you deal with Qunbound in a reasonable way,
a59e4f3d 2988 and don't let it get stored in any Lisp-visible variables! */
01f1ba30
JB
2989
2990static Lisp_Object
abb4b7ec
RS
2991x_get_arg (dpyinfo, alist, param, attribute, class, type)
2992 struct x_display_info *dpyinfo;
3c254570 2993 Lisp_Object alist, param;
60fb3ee1 2994 char *attribute;
cf177271 2995 char *class;
60fb3ee1 2996 enum resource_types type;
01f1ba30
JB
2997{
2998 register Lisp_Object tem;
2999
3000 tem = Fassq (param, alist);
3001 if (EQ (tem, Qnil))
f676886a 3002 tem = Fassq (param, Vdefault_frame_alist);
f9942c9e 3003 if (EQ (tem, Qnil))
01f1ba30 3004 {
60fb3ee1 3005
f9942c9e 3006 if (attribute)
60fb3ee1 3007 {
abb4b7ec
RS
3008 tem = display_x_get_resource (dpyinfo,
3009 build_string (attribute),
3010 build_string (class),
3011 Qnil, Qnil);
f9942c9e
JB
3012
3013 if (NILP (tem))
3014 return Qunbound;
3015
3016 switch (type)
3017 {
333b20bb 3018 case RES_TYPE_NUMBER:
f9942c9e
JB
3019 return make_number (atoi (XSTRING (tem)->data));
3020
d62c8769
GM
3021 case RES_TYPE_FLOAT:
3022 return make_float (atof (XSTRING (tem)->data));
3023
333b20bb 3024 case RES_TYPE_BOOLEAN:
f9942c9e
JB
3025 tem = Fdowncase (tem);
3026 if (!strcmp (XSTRING (tem)->data, "on")
3027 || !strcmp (XSTRING (tem)->data, "true"))
3028 return Qt;
3029 else
3030 return Qnil;
3031
333b20bb 3032 case RES_TYPE_STRING:
f9942c9e
JB
3033 return tem;
3034
333b20bb 3035 case RES_TYPE_SYMBOL:
49795535
JB
3036 /* As a special case, we map the values `true' and `on'
3037 to Qt, and `false' and `off' to Qnil. */
3038 {
98381190
KH
3039 Lisp_Object lower;
3040 lower = Fdowncase (tem);
26ae6b61
KH
3041 if (!strcmp (XSTRING (lower)->data, "on")
3042 || !strcmp (XSTRING (lower)->data, "true"))
49795535 3043 return Qt;
26ae6b61
KH
3044 else if (!strcmp (XSTRING (lower)->data, "off")
3045 || !strcmp (XSTRING (lower)->data, "false"))
49795535
JB
3046 return Qnil;
3047 else
89032215 3048 return Fintern (tem, Qnil);
49795535 3049 }
f945b920 3050
f9942c9e
JB
3051 default:
3052 abort ();
3053 }
60fb3ee1 3054 }
f9942c9e
JB
3055 else
3056 return Qunbound;
01f1ba30
JB
3057 }
3058 return Fcdr (tem);
3059}
3060
e4f79258
RS
3061/* Like x_get_arg, but also record the value in f->param_alist. */
3062
3063static Lisp_Object
3064x_get_and_record_arg (f, alist, param, attribute, class, type)
3065 struct frame *f;
3066 Lisp_Object alist, param;
3067 char *attribute;
3068 char *class;
3069 enum resource_types type;
3070{
3071 Lisp_Object value;
3072
abb4b7ec
RS
3073 value = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, param,
3074 attribute, class, type);
e4f79258
RS
3075 if (! NILP (value))
3076 store_frame_param (f, param, value);
3077
3078 return value;
3079}
3080
f676886a 3081/* Record in frame F the specified or default value according to ALIST
e8cc313b
KH
3082 of the parameter named PROP (a Lisp symbol).
3083 If no value is specified for PROP, look for an X default for XPROP
f676886a 3084 on the frame named NAME.
01f1ba30
JB
3085 If that is not found either, use the value DEFLT. */
3086
3087static Lisp_Object
cf177271 3088x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
f676886a 3089 struct frame *f;
01f1ba30 3090 Lisp_Object alist;
f9942c9e 3091 Lisp_Object prop;
01f1ba30
JB
3092 Lisp_Object deflt;
3093 char *xprop;
cf177271 3094 char *xclass;
60fb3ee1 3095 enum resource_types type;
01f1ba30 3096{
01f1ba30
JB
3097 Lisp_Object tem;
3098
abb4b7ec 3099 tem = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, prop, xprop, xclass, type);
f9942c9e 3100 if (EQ (tem, Qunbound))
01f1ba30 3101 tem = deflt;
f9942c9e 3102 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
01f1ba30
JB
3103 return tem;
3104}
333b20bb
GM
3105
3106
3107/* Record in frame F the specified or default value according to ALIST
3108 of the parameter named PROP (a Lisp symbol). If no value is
3109 specified for PROP, look for an X default for XPROP on the frame
3110 named NAME. If that is not found either, use the value DEFLT. */
3111
3112static Lisp_Object
3113x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass,
3114 foreground_p)
3115 struct frame *f;
3116 Lisp_Object alist;
3117 Lisp_Object prop;
3118 char *xprop;
3119 char *xclass;
3120 int foreground_p;
3121{
3122 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3123 Lisp_Object tem;
3124
3125 tem = x_get_arg (dpyinfo, alist, prop, xprop, xclass, RES_TYPE_STRING);
3126 if (EQ (tem, Qunbound))
3127 {
3128#ifdef USE_TOOLKIT_SCROLL_BARS
3129
3130 /* See if an X resource for the scroll bar color has been
3131 specified. */
3132 tem = display_x_get_resource (dpyinfo,
3133 build_string (foreground_p
3134 ? "foreground"
3135 : "background"),
c0ec53ad 3136 empty_string,
333b20bb 3137 build_string ("verticalScrollBar"),
c0ec53ad 3138 empty_string);
333b20bb
GM
3139 if (!STRINGP (tem))
3140 {
3141 /* If nothing has been specified, scroll bars will use a
3142 toolkit-dependent default. Because these defaults are
3143 difficult to get at without actually creating a scroll
3144 bar, use nil to indicate that no color has been
3145 specified. */
3146 tem = Qnil;
3147 }
3148
3149#else /* not USE_TOOLKIT_SCROLL_BARS */
3150
3151 tem = Qnil;
3152
3153#endif /* not USE_TOOLKIT_SCROLL_BARS */
3154 }
3155
3156 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3157 return tem;
3158}
3159
3160
01f1ba30 3161\f
8af1d7ca 3162DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
7ee72033 3163 doc: /* Parse an X-style geometry string STRING.
c061c855
GM
3164Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3165The properties returned may include `top', `left', `height', and `width'.
3166The value of `left' or `top' may be an integer,
3167or a list (+ N) meaning N pixels relative to top/left corner,
7ee72033
MB
3168or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3169 (string)
a6605e5c 3170 Lisp_Object string;
01f1ba30
JB
3171{
3172 int geometry, x, y;
3173 unsigned int width, height;
f83f10ba 3174 Lisp_Object result;
01f1ba30 3175
b7826503 3176 CHECK_STRING (string);
01f1ba30
JB
3177
3178 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3179 &x, &y, &width, &height);
3180
f83f10ba
RS
3181#if 0
3182 if (!!(geometry & XValue) != !!(geometry & YValue))
3183 error ("Must specify both x and y position, or neither");
3184#endif
3185
3186 result = Qnil;
3187 if (geometry & XValue)
01f1ba30 3188 {
f83f10ba
RS
3189 Lisp_Object element;
3190
e1d962d7
RS
3191 if (x >= 0 && (geometry & XNegative))
3192 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3193 else if (x < 0 && ! (geometry & XNegative))
3194 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
f83f10ba
RS
3195 else
3196 element = Fcons (Qleft, make_number (x));
3197 result = Fcons (element, result);
3198 }
3199
3200 if (geometry & YValue)
3201 {
3202 Lisp_Object element;
3203
e1d962d7
RS
3204 if (y >= 0 && (geometry & YNegative))
3205 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3206 else if (y < 0 && ! (geometry & YNegative))
3207 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
f83f10ba
RS
3208 else
3209 element = Fcons (Qtop, make_number (y));
3210 result = Fcons (element, result);
01f1ba30 3211 }
f83f10ba
RS
3212
3213 if (geometry & WidthValue)
3214 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3215 if (geometry & HeightValue)
3216 result = Fcons (Fcons (Qheight, make_number (height)), result);
3217
3218 return result;
01f1ba30
JB
3219}
3220
01f1ba30 3221/* Calculate the desired size and position of this window,
f83f10ba 3222 and return the flags saying which aspects were specified.
8fc2766b
RS
3223
3224 This function does not make the coordinates positive. */
01f1ba30
JB
3225
3226#define DEFAULT_ROWS 40
3227#define DEFAULT_COLS 80
3228
f9942c9e 3229static int
f676886a
JB
3230x_figure_window_size (f, parms)
3231 struct frame *f;
01f1ba30
JB
3232 Lisp_Object parms;
3233{
4fe1de12 3234 register Lisp_Object tem0, tem1, tem2;
01f1ba30 3235 long window_prompting = 0;
abb4b7ec 3236 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
3237
3238 /* Default values if we fall through.
3239 Actually, if that happens we should get
b9dc4443 3240 window manager prompting. */
1ab3d87e 3241 SET_FRAME_WIDTH (f, DEFAULT_COLS);
f676886a 3242 f->height = DEFAULT_ROWS;
bd0b85c3
RS
3243 /* Window managers expect that if program-specified
3244 positions are not (0,0), they're intentional, not defaults. */
7556890b
RS
3245 f->output_data.x->top_pos = 0;
3246 f->output_data.x->left_pos = 0;
01f1ba30 3247
333b20bb
GM
3248 tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3249 tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3250 tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3251 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3252 {
f83f10ba
RS
3253 if (!EQ (tem0, Qunbound))
3254 {
b7826503 3255 CHECK_NUMBER (tem0);
f83f10ba
RS
3256 f->height = XINT (tem0);
3257 }
3258 if (!EQ (tem1, Qunbound))
3259 {
b7826503 3260 CHECK_NUMBER (tem1);
1ab3d87e 3261 SET_FRAME_WIDTH (f, XINT (tem1));
f83f10ba
RS
3262 }
3263 if (!NILP (tem2) && !EQ (tem2, Qunbound))
4fe1de12
RS
3264 window_prompting |= USSize;
3265 else
3266 window_prompting |= PSize;
01f1ba30 3267 }
01f1ba30 3268
7556890b 3269 f->output_data.x->vertical_scroll_bar_extra
a444c70b
KH
3270 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3271 ? 0
7556890b 3272 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
b3ba0aa8
KS
3273
3274 x_compute_fringe_widths (f, 0);
3275
7556890b
RS
3276 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3277 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
01f1ba30 3278
333b20bb
GM
3279 tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3280 tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3281 tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3282 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3283 {
f83f10ba
RS
3284 if (EQ (tem0, Qminus))
3285 {
7556890b 3286 f->output_data.x->top_pos = 0;
f83f10ba
RS
3287 window_prompting |= YNegative;
3288 }
8e713be6
KR
3289 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3290 && CONSP (XCDR (tem0))
3291 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3292 {
8e713be6 3293 f->output_data.x->top_pos = - XINT (XCAR (XCDR (tem0)));
e1d962d7
RS
3294 window_prompting |= YNegative;
3295 }
8e713be6
KR
3296 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3297 && CONSP (XCDR (tem0))
3298 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3299 {
8e713be6 3300 f->output_data.x->top_pos = XINT (XCAR (XCDR (tem0)));
e1d962d7 3301 }
f83f10ba 3302 else if (EQ (tem0, Qunbound))
7556890b 3303 f->output_data.x->top_pos = 0;
f83f10ba
RS
3304 else
3305 {
b7826503 3306 CHECK_NUMBER (tem0);
7556890b
RS
3307 f->output_data.x->top_pos = XINT (tem0);
3308 if (f->output_data.x->top_pos < 0)
f83f10ba
RS
3309 window_prompting |= YNegative;
3310 }
3311
3312 if (EQ (tem1, Qminus))
3313 {
7556890b 3314 f->output_data.x->left_pos = 0;
f83f10ba
RS
3315 window_prompting |= XNegative;
3316 }
8e713be6
KR
3317 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3318 && CONSP (XCDR (tem1))
3319 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3320 {
8e713be6 3321 f->output_data.x->left_pos = - XINT (XCAR (XCDR (tem1)));
e1d962d7
RS
3322 window_prompting |= XNegative;
3323 }
8e713be6
KR
3324 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3325 && CONSP (XCDR (tem1))
3326 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3327 {
8e713be6 3328 f->output_data.x->left_pos = XINT (XCAR (XCDR (tem1)));
e1d962d7 3329 }
f83f10ba 3330 else if (EQ (tem1, Qunbound))
7556890b 3331 f->output_data.x->left_pos = 0;
f83f10ba
RS
3332 else
3333 {
b7826503 3334 CHECK_NUMBER (tem1);
7556890b
RS
3335 f->output_data.x->left_pos = XINT (tem1);
3336 if (f->output_data.x->left_pos < 0)
f83f10ba
RS
3337 window_prompting |= XNegative;
3338 }
3339
c3724dc2 3340 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
4fe1de12
RS
3341 window_prompting |= USPosition;
3342 else
3343 window_prompting |= PPosition;
01f1ba30 3344 }
f83f10ba 3345
49d41073
EZ
3346 if (f->output_data.x->want_fullscreen != FULLSCREEN_NONE)
3347 {
3348 int left, top;
3349 int width, height;
3350
3351 /* It takes both for some WM:s to place it where we want */
3352 window_prompting = USPosition | PPosition;
3353 x_fullscreen_adjust (f, &width, &height, &top, &left);
3354 f->width = width;
3355 f->height = height;
3356 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3357 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3358 f->output_data.x->left_pos = left;
3359 f->output_data.x->top_pos = top;
3360 }
3361
739f2f53 3362 return window_prompting;
01f1ba30
JB
3363}
3364
f58534a3
RS
3365#if !defined (HAVE_X11R4) && !defined (HAVE_XSETWMPROTOCOLS)
3366
3367Status
3368XSetWMProtocols (dpy, w, protocols, count)
3369 Display *dpy;
3370 Window w;
3371 Atom *protocols;
3372 int count;
3373{
3374 Atom prop;
3375 prop = XInternAtom (dpy, "WM_PROTOCOLS", False);
3376 if (prop == None) return False;
3377 XChangeProperty (dpy, w, prop, XA_ATOM, 32, PropModeReplace,
3378 (unsigned char *) protocols, count);
3379 return True;
3380}
9ef48a9d
RS
3381#endif /* not HAVE_X11R4 && not HAVE_XSETWMPROTOCOLS */
3382\f
3383#ifdef USE_X_TOOLKIT
3384
8e3d10a9
RS
3385/* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS,
3386 WM_DELETE_WINDOW, and WM_SAVE_YOURSELF, then add them. (They may
59aa6c90
RS
3387 already be present because of the toolkit (Motif adds some of them,
3388 for example, but Xt doesn't). */
9ef48a9d
RS
3389
3390static void
b9dc4443
RS
3391hack_wm_protocols (f, widget)
3392 FRAME_PTR f;
9ef48a9d
RS
3393 Widget widget;
3394{
3395 Display *dpy = XtDisplay (widget);
3396 Window w = XtWindow (widget);
3397 int need_delete = 1;
3398 int need_focus = 1;
59aa6c90 3399 int need_save = 1;
9ef48a9d
RS
3400
3401 BLOCK_INPUT;
3402 {
3403 Atom type, *atoms = 0;
3404 int format = 0;
3405 unsigned long nitems = 0;
3406 unsigned long bytes_after;
3407
270958e8
KH
3408 if ((XGetWindowProperty (dpy, w,
3409 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
34d5ae1e 3410 (long)0, (long)100, False, XA_ATOM,
270958e8
KH
3411 &type, &format, &nitems, &bytes_after,
3412 (unsigned char **) &atoms)
3413 == Success)
9ef48a9d
RS
3414 && format == 32 && type == XA_ATOM)
3415 while (nitems > 0)
3416 {
3417 nitems--;
b9dc4443
RS
3418 if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window)
3419 need_delete = 0;
3420 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus)
3421 need_focus = 0;
3422 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself)
3423 need_save = 0;
9ef48a9d
RS
3424 }
3425 if (atoms) XFree ((char *) atoms);
3426 }
3427 {
3428 Atom props [10];
3429 int count = 0;
b9dc4443
RS
3430 if (need_delete)
3431 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
3432 if (need_focus)
3433 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus;
3434 if (need_save)
3435 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
9ef48a9d 3436 if (count)
b9dc4443
RS
3437 XChangeProperty (dpy, w, FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3438 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3439 (unsigned char *) props, count);
3440 }
3441 UNBLOCK_INPUT;
3442}
3443#endif
86779fac
GM
3444
3445
5a7df7d7
GM
3446\f
3447/* Support routines for XIC (X Input Context). */
86779fac 3448
5a7df7d7
GM
3449#ifdef HAVE_X_I18N
3450
3451static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
3452static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
3453
3454
3455/* Supported XIM styles, ordered by preferenc. */
3456
3457static XIMStyle supported_xim_styles[] =
3458{
3459 XIMPreeditPosition | XIMStatusArea,
3460 XIMPreeditPosition | XIMStatusNothing,
3461 XIMPreeditPosition | XIMStatusNone,
3462 XIMPreeditNothing | XIMStatusArea,
3463 XIMPreeditNothing | XIMStatusNothing,
3464 XIMPreeditNothing | XIMStatusNone,
3465 XIMPreeditNone | XIMStatusArea,
3466 XIMPreeditNone | XIMStatusNothing,
3467 XIMPreeditNone | XIMStatusNone,
3468 0,
3469};
3470
3471
3472/* Create an X fontset on frame F with base font name
3473 BASE_FONTNAME.. */
3474
3475static XFontSet
3476xic_create_xfontset (f, base_fontname)
86779fac 3477 struct frame *f;
5a7df7d7 3478 char *base_fontname;
86779fac 3479{
5a7df7d7
GM
3480 XFontSet xfs;
3481 char **missing_list;
3482 int missing_count;
3483 char *def_string;
86779fac 3484
5a7df7d7
GM
3485 xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
3486 base_fontname, &missing_list,
3487 &missing_count, &def_string);
3488 if (missing_list)
3489 XFreeStringList (missing_list);
3490
3491 /* No need to free def_string. */
3492 return xfs;
3493}
3494
3495
3496/* Value is the best input style, given user preferences USER (already
3497 checked to be supported by Emacs), and styles supported by the
3498 input method XIM. */
3499
3500static XIMStyle
3501best_xim_style (user, xim)
3502 XIMStyles *user;
3503 XIMStyles *xim;
3504{
3505 int i, j;
3506
3507 for (i = 0; i < user->count_styles; ++i)
3508 for (j = 0; j < xim->count_styles; ++j)
3509 if (user->supported_styles[i] == xim->supported_styles[j])
3510 return user->supported_styles[i];
3511
3512 /* Return the default style. */
3513 return XIMPreeditNothing | XIMStatusNothing;
3514}
3515
3516/* Create XIC for frame F. */
3517
5df79d3d
GM
3518static XIMStyle xic_style;
3519
5a7df7d7
GM
3520void
3521create_frame_xic (f)
3522 struct frame *f;
3523{
5a7df7d7
GM
3524 XIM xim;
3525 XIC xic = NULL;
3526 XFontSet xfs = NULL;
86779fac 3527
5a7df7d7
GM
3528 if (FRAME_XIC (f))
3529 return;
3530
3531 xim = FRAME_X_XIM (f);
3532 if (xim)
3533 {
d9d57cb2
DL
3534 XRectangle s_area;
3535 XPoint spot;
5a7df7d7
GM
3536 XVaNestedList preedit_attr;
3537 XVaNestedList status_attr;
3538 char *base_fontname;
3539 int fontset;
3540
d9d57cb2
DL
3541 s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
3542 spot.x = 0; spot.y = 1;
5a7df7d7
GM
3543 /* Create X fontset. */
3544 fontset = FRAME_FONTSET (f);
3545 if (fontset < 0)
3546 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3547 else
3548 {
6ecb43ce
KH
3549 /* Determine the base fontname from the ASCII font name of
3550 FONTSET. */
3551 char *ascii_font = (char *) XSTRING (fontset_ascii (fontset))->data;
3552 char *p = ascii_font;
5a7df7d7 3553 int i;
6ecb43ce
KH
3554
3555 for (i = 0; *p; p++)
3556 if (*p == '-') i++;
3557 if (i != 14)
3558 /* As the font name doesn't conform to XLFD, we can't
3559 modify it to get a suitable base fontname for the
3560 frame. */
3561 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3562 else
3563 {
3564 int len = strlen (ascii_font) + 1;
8ec8a5ec 3565 char *p1 = NULL;
6ecb43ce
KH
3566
3567 for (i = 0, p = ascii_font; i < 8; p++)
3568 {
3569 if (*p == '-')
3570 {
3571 i++;
3572 if (i == 3)
3573 p1 = p + 1;
3574 }
3575 }
3576 base_fontname = (char *) alloca (len);
3577 bzero (base_fontname, len);
3578 strcpy (base_fontname, "-*-*-");
3579 bcopy (p1, base_fontname + 5, p - p1);
3580 strcat (base_fontname, "*-*-*-*-*-*-*");
3581 }
5a7df7d7
GM
3582 }
3583 xfs = xic_create_xfontset (f, base_fontname);
86779fac 3584
5a7df7d7
GM
3585 /* Determine XIC style. */
3586 if (xic_style == 0)
3587 {
3588 XIMStyles supported_list;
3589 supported_list.count_styles = (sizeof supported_xim_styles
3590 / sizeof supported_xim_styles[0]);
3591 supported_list.supported_styles = supported_xim_styles;
3592 xic_style = best_xim_style (&supported_list,
3593 FRAME_X_XIM_STYLES (f));
3594 }
86779fac 3595
5a7df7d7
GM
3596 preedit_attr = XVaCreateNestedList (0,
3597 XNFontSet, xfs,
3598 XNForeground,
3599 FRAME_FOREGROUND_PIXEL (f),
3600 XNBackground,
3601 FRAME_BACKGROUND_PIXEL (f),
3602 (xic_style & XIMPreeditPosition
3603 ? XNSpotLocation
3604 : NULL),
3605 &spot,
3606 NULL);
3607 status_attr = XVaCreateNestedList (0,
3608 XNArea,
3609 &s_area,
3610 XNFontSet,
3611 xfs,
3612 XNForeground,
3613 FRAME_FOREGROUND_PIXEL (f),
3614 XNBackground,
3615 FRAME_BACKGROUND_PIXEL (f),
3616 NULL);
3617
3618 xic = XCreateIC (xim,
3619 XNInputStyle, xic_style,
3620 XNClientWindow, FRAME_X_WINDOW(f),
3621 XNFocusWindow, FRAME_X_WINDOW(f),
3622 XNStatusAttributes, status_attr,
3623 XNPreeditAttributes, preedit_attr,
3624 NULL);
3625 XFree (preedit_attr);
3626 XFree (status_attr);
3627 }
3628
3629 FRAME_XIC (f) = xic;
3630 FRAME_XIC_STYLE (f) = xic_style;
3631 FRAME_XIC_FONTSET (f) = xfs;
86779fac
GM
3632}
3633
5a7df7d7
GM
3634
3635/* Destroy XIC and free XIC fontset of frame F, if any. */
3636
3637void
3638free_frame_xic (f)
3639 struct frame *f;
3640{
3641 if (FRAME_XIC (f) == NULL)
3642 return;
3643
3644 XDestroyIC (FRAME_XIC (f));
3645 if (FRAME_XIC_FONTSET (f))
3646 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3647
3648 FRAME_XIC (f) = NULL;
3649 FRAME_XIC_FONTSET (f) = NULL;
3650}
3651
3652
3653/* Place preedit area for XIC of window W's frame to specified
3654 pixel position X/Y. X and Y are relative to window W. */
3655
3656void
3657xic_set_preeditarea (w, x, y)
3658 struct window *w;
3659 int x, y;
3660{
3661 struct frame *f = XFRAME (w->frame);
3662 XVaNestedList attr;
3663 XPoint spot;
3664
3665 spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
3666 spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
3667 attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
3668 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3669 XFree (attr);
3670}
3671
3672
3673/* Place status area for XIC in bottom right corner of frame F.. */
3674
3675void
3676xic_set_statusarea (f)
3677 struct frame *f;
3678{
3679 XIC xic = FRAME_XIC (f);
3680 XVaNestedList attr;
3681 XRectangle area;
3682 XRectangle *needed;
3683
3684 /* Negotiate geometry of status area. If input method has existing
3685 status area, use its current size. */
3686 area.x = area.y = area.width = area.height = 0;
3687 attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
3688 XSetICValues (xic, XNStatusAttributes, attr, NULL);
3689 XFree (attr);
3690
3691 attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
3692 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3693 XFree (attr);
3694
3695 if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
3696 {
3697 attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
3698 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3699 XFree (attr);
3700 }
3701
3702 area.width = needed->width;
3703 area.height = needed->height;
3704 area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
3705 area.y = (PIXEL_HEIGHT (f) - area.height
3706 - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
3707 XFree (needed);
3708
3709 attr = XVaCreateNestedList (0, XNArea, &area, NULL);
3710 XSetICValues(xic, XNStatusAttributes, attr, NULL);
3711 XFree (attr);
3712}
3713
3714
3715/* Set X fontset for XIC of frame F, using base font name
3716 BASE_FONTNAME. Called when a new Emacs fontset is chosen. */
3717
3718void
3719xic_set_xfontset (f, base_fontname)
3720 struct frame *f;
3721 char *base_fontname;
3722{
3723 XVaNestedList attr;
3724 XFontSet xfs;
3725
3726 xfs = xic_create_xfontset (f, base_fontname);
3727
3728 attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
3729 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
3730 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3731 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
3732 XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
3733 XFree (attr);
3734
3735 if (FRAME_XIC_FONTSET (f))
3736 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3737 FRAME_XIC_FONTSET (f) = xfs;
3738}
3739
3740#endif /* HAVE_X_I18N */
3741
3742
9ef48a9d 3743\f
8fc2766b
RS
3744#ifdef USE_X_TOOLKIT
3745
3746/* Create and set up the X widget for frame F. */
f58534a3 3747
01f1ba30 3748static void
a7f7d550
FP
3749x_window (f, window_prompting, minibuffer_only)
3750 struct frame *f;
3751 long window_prompting;
3752 int minibuffer_only;
01f1ba30 3753{
9ef48a9d 3754 XClassHint class_hints;
31ac8d8c
FP
3755 XSetWindowAttributes attributes;
3756 unsigned long attribute_mask;
9ef48a9d
RS
3757 Widget shell_widget;
3758 Widget pane_widget;
6c32dd68 3759 Widget frame_widget;
9ef48a9d
RS
3760 Arg al [25];
3761 int ac;
3762
3763 BLOCK_INPUT;
3764
b7975ee4
KH
3765 /* Use the resource name as the top-level widget name
3766 for looking up resources. Make a non-Lisp copy
3767 for the window manager, so GC relocation won't bother it.
3768
3769 Elsewhere we specify the window name for the window manager. */
3770
cca176a0 3771 {
b7975ee4
KH
3772 char *str = (char *) XSTRING (Vx_resource_name)->data;
3773 f->namebuf = (char *) xmalloc (strlen (str) + 1);
cca176a0
KH
3774 strcpy (f->namebuf, str);
3775 }
9ef48a9d
RS
3776
3777 ac = 0;
3778 XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
3779 XtSetArg (al[ac], XtNinput, 1); ac++;
97787173 3780 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
7556890b 3781 XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
9b2956e2
GM
3782 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3783 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3784 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
cca176a0 3785 shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
7a994728 3786 applicationShellWidgetClass,
82c90203 3787 FRAME_X_DISPLAY (f), al, ac);
9ef48a9d 3788
7556890b 3789 f->output_data.x->widget = shell_widget;
9ef48a9d
RS
3790 /* maybe_set_screen_title_format (shell_widget); */
3791
6c32dd68
PR
3792 pane_widget = lw_create_widget ("main", "pane", widget_id_tick++,
3793 (widget_value *) NULL,
3794 shell_widget, False,
3795 (lw_callback) NULL,
3796 (lw_callback) NULL,
b6e11efd 3797 (lw_callback) NULL,
6c32dd68 3798 (lw_callback) NULL);
9ef48a9d 3799
9b2956e2
GM
3800 ac = 0;
3801 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3802 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3803 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3804 XtSetValues (pane_widget, al, ac);
7556890b 3805 f->output_data.x->column_widget = pane_widget;
a7f7d550 3806
9ef48a9d 3807 /* mappedWhenManaged to false tells to the paned window to not map/unmap
5e65b9ab 3808 the emacs screen when changing menubar. This reduces flickering. */
9ef48a9d
RS
3809
3810 ac = 0;
3811 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
3812 XtSetArg (al[ac], XtNshowGrip, 0); ac++;
3813 XtSetArg (al[ac], XtNallowResize, 1); ac++;
3814 XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
3815 XtSetArg (al[ac], XtNemacsFrame, f); ac++;
9b2956e2
GM
3816 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3817 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3818 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3819 frame_widget = XtCreateWidget (f->namebuf, emacsFrameClass, pane_widget,
3820 al, ac);
9ef48a9d 3821
7556890b 3822 f->output_data.x->edit_widget = frame_widget;
9ef48a9d 3823
6c32dd68 3824 XtManageChild (frame_widget);
a7f7d550
FP
3825
3826 /* Do some needed geometry management. */
3827 {
3828 int len;
3829 char *tem, shell_position[32];
3830 Arg al[2];
3831 int ac = 0;
5031cc10 3832 int extra_borders = 0;
8fc2766b 3833 int menubar_size
7556890b
RS
3834 = (f->output_data.x->menubar_widget
3835 ? (f->output_data.x->menubar_widget->core.height
3836 + f->output_data.x->menubar_widget->core.border_width)
8fc2766b 3837 : 0);
a7f7d550 3838
f7008aff
RS
3839#if 0 /* Experimentally, we now get the right results
3840 for -geometry -0-0 without this. 24 Aug 96, rms. */
01cbdba5
RS
3841 if (FRAME_EXTERNAL_MENU_BAR (f))
3842 {
dd254b21 3843 Dimension ibw = 0;
01cbdba5
RS
3844 XtVaGetValues (pane_widget, XtNinternalBorderWidth, &ibw, NULL);
3845 menubar_size += ibw;
3846 }
f7008aff 3847#endif
01cbdba5 3848
7556890b 3849 f->output_data.x->menubar_height = menubar_size;
00983aba 3850
440b0bfd 3851#ifndef USE_LUCID
5031cc10
KH
3852 /* Motif seems to need this amount added to the sizes
3853 specified for the shell widget. The Athena/Lucid widgets don't.
3854 Both conclusions reached experimentally. -- rms. */
440b0bfd
RS
3855 XtVaGetValues (f->output_data.x->edit_widget, XtNinternalBorderWidth,
3856 &extra_borders, NULL);
3857 extra_borders *= 2;
3858#endif
5031cc10 3859
97787173
RS
3860 /* Convert our geometry parameters into a geometry string
3861 and specify it.
3862 Note that we do not specify here whether the position
3863 is a user-specified or program-specified one.
3864 We pass that information later, in x_wm_set_size_hints. */
3865 {
7556890b 3866 int left = f->output_data.x->left_pos;
97787173 3867 int xneg = window_prompting & XNegative;
7556890b 3868 int top = f->output_data.x->top_pos;
97787173
RS
3869 int yneg = window_prompting & YNegative;
3870 if (xneg)
3871 left = -left;
3872 if (yneg)
3873 top = -top;
c760f47e
KH
3874
3875 if (window_prompting & USPosition)
5031cc10
KH
3876 sprintf (shell_position, "=%dx%d%c%d%c%d",
3877 PIXEL_WIDTH (f) + extra_borders,
3878 PIXEL_HEIGHT (f) + menubar_size + extra_borders,
c760f47e
KH
3879 (xneg ? '-' : '+'), left,
3880 (yneg ? '-' : '+'), top);
3881 else
5031cc10
KH
3882 sprintf (shell_position, "=%dx%d",
3883 PIXEL_WIDTH (f) + extra_borders,
3884 PIXEL_HEIGHT (f) + menubar_size + extra_borders);
97787173
RS
3885 }
3886
a7f7d550 3887 len = strlen (shell_position) + 1;
77110caa
RS
3888 /* We don't free this because we don't know whether
3889 it is safe to free it while the frame exists.
3890 It isn't worth the trouble of arranging to free it
3891 when the frame is deleted. */
a7f7d550
FP
3892 tem = (char *) xmalloc (len);
3893 strncpy (tem, shell_position, len);
3894 XtSetArg (al[ac], XtNgeometry, tem); ac++;
3895 XtSetValues (shell_widget, al, ac);
3896 }
3897
9ef48a9d
RS
3898 XtManageChild (pane_widget);
3899 XtRealizeWidget (shell_widget);
3900
6c32dd68 3901 FRAME_X_WINDOW (f) = XtWindow (frame_widget);
9ef48a9d
RS
3902
3903 validate_x_resource_name ();
b7975ee4 3904
9ef48a9d 3905 class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
498e9ac3 3906 class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
b9dc4443 3907 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
5a7df7d7
GM
3908
3909#ifdef HAVE_X_I18N
3910 FRAME_XIC (f) = NULL;
4bd777b8 3911#ifdef USE_XIM
5a7df7d7 3912 create_frame_xic (f);
4bd777b8 3913#endif
5a7df7d7 3914#endif
64d16748 3915
7556890b
RS
3916 f->output_data.x->wm_hints.input = True;
3917 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 3918 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3919 &f->output_data.x->wm_hints);
b8228beb 3920
c4ec904f 3921 hack_wm_protocols (f, shell_widget);
9ef48a9d 3922
6c32dd68
PR
3923#ifdef HACK_EDITRES
3924 XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0);
3925#endif
3926
9ef48a9d 3927 /* Do a stupid property change to force the server to generate a
333b20bb 3928 PropertyNotify event so that the event_stream server timestamp will
9ef48a9d
RS
3929 be initialized to something relevant to the time we created the window.
3930 */
6c32dd68 3931 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
b9dc4443
RS
3932 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3933 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3934 (unsigned char*) NULL, 0);
3935
5a7df7d7 3936 /* Make all the standard events reach the Emacs frame. */
31ac8d8c 3937 attributes.event_mask = STANDARD_EVENT_SET;
5a7df7d7
GM
3938
3939#ifdef HAVE_X_I18N
3940 if (FRAME_XIC (f))
3941 {
3942 /* XIM server might require some X events. */
3943 unsigned long fevent = NoEventMask;
3944 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
3945 attributes.event_mask |= fevent;
3946 }
3947#endif /* HAVE_X_I18N */
3948
31ac8d8c
FP
3949 attribute_mask = CWEventMask;
3950 XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
3951 attribute_mask, &attributes);
3952
6c32dd68 3953 XtMapWidget (frame_widget);
9ef48a9d 3954
8fc2766b
RS
3955 /* x_set_name normally ignores requests to set the name if the
3956 requested name is the same as the current name. This is the one
3957 place where that assumption isn't correct; f->name is set, but
3958 the X server hasn't been told. */
3959 {
3960 Lisp_Object name;
3961 int explicit = f->explicit_name;
3962
3963 f->explicit_name = 0;
3964 name = f->name;
3965 f->name = Qnil;
3966 x_set_name (f, name, explicit);
3967 }
3968
b9dc4443 3969 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3970 f->output_data.x->text_cursor);
8fc2766b
RS
3971
3972 UNBLOCK_INPUT;
3973
495fa05e
GM
3974 /* This is a no-op, except under Motif. Make sure main areas are
3975 set to something reasonable, in case we get an error later. */
3976 lw_set_main_areas (pane_widget, 0, frame_widget);
8fc2766b
RS
3977}
3978
9ef48a9d
RS
3979#else /* not USE_X_TOOLKIT */
3980
8fc2766b
RS
3981/* Create and set up the X window for frame F. */
3982
201d8c78 3983void
8fc2766b
RS
3984x_window (f)
3985 struct frame *f;
3986
3987{
3988 XClassHint class_hints;
3989 XSetWindowAttributes attributes;
3990 unsigned long attribute_mask;
3991
7556890b
RS
3992 attributes.background_pixel = f->output_data.x->background_pixel;
3993 attributes.border_pixel = f->output_data.x->border_pixel;
01f1ba30
JB
3994 attributes.bit_gravity = StaticGravity;
3995 attributes.backing_store = NotUseful;
3996 attributes.save_under = True;
3997 attributes.event_mask = STANDARD_EVENT_SET;
9b2956e2
GM
3998 attributes.colormap = FRAME_X_COLORMAP (f);
3999 attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
4000 | CWColormap);
01f1ba30
JB
4001
4002 BLOCK_INPUT;
fe24a618 4003 FRAME_X_WINDOW (f)
b9dc4443 4004 = XCreateWindow (FRAME_X_DISPLAY (f),
7556890b
RS
4005 f->output_data.x->parent_desc,
4006 f->output_data.x->left_pos,
4007 f->output_data.x->top_pos,
f676886a 4008 PIXEL_WIDTH (f), PIXEL_HEIGHT (f),
7556890b 4009 f->output_data.x->border_width,
01f1ba30
JB
4010 CopyFromParent, /* depth */
4011 InputOutput, /* class */
383d6ffc 4012 FRAME_X_VISUAL (f),
01f1ba30 4013 attribute_mask, &attributes);
5a7df7d7
GM
4014
4015#ifdef HAVE_X_I18N
4bd777b8 4016#ifdef USE_XIM
5a7df7d7
GM
4017 create_frame_xic (f);
4018 if (FRAME_XIC (f))
4019 {
4020 /* XIM server might require some X events. */
4021 unsigned long fevent = NoEventMask;
4022 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
4023 attributes.event_mask |= fevent;
4024 attribute_mask = CWEventMask;
4025 XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4026 attribute_mask, &attributes);
4027 }
4bd777b8 4028#endif
5a7df7d7
GM
4029#endif /* HAVE_X_I18N */
4030
d387c960 4031 validate_x_resource_name ();
b7975ee4 4032
d387c960 4033 class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
498e9ac3 4034 class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
b9dc4443 4035 XSetClassHint (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &class_hints);
01f1ba30 4036
00983aba
KH
4037 /* The menubar is part of the ordinary display;
4038 it does not count in addition to the height of the window. */
7556890b 4039 f->output_data.x->menubar_height = 0;
00983aba 4040
179956b9
JB
4041 /* This indicates that we use the "Passive Input" input model.
4042 Unless we do this, we don't get the Focus{In,Out} events that we
4043 need to draw the cursor correctly. Accursed bureaucrats.
b9dc4443 4044 XWhipsAndChains (FRAME_X_DISPLAY (f), IronMaiden, &TheRack); */
179956b9 4045
7556890b
RS
4046 f->output_data.x->wm_hints.input = True;
4047 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 4048 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4049 &f->output_data.x->wm_hints);
6d078211 4050 f->output_data.x->wm_hints.icon_pixmap = None;
179956b9 4051
032e4ebe
RS
4052 /* Request "save yourself" and "delete window" commands from wm. */
4053 {
4054 Atom protocols[2];
b9dc4443
RS
4055 protocols[0] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
4056 protocols[1] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
4057 XSetWMProtocols (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), protocols, 2);
032e4ebe 4058 }
9ef48a9d 4059
e373f201
JB
4060 /* x_set_name normally ignores requests to set the name if the
4061 requested name is the same as the current name. This is the one
4062 place where that assumption isn't correct; f->name is set, but
4063 the X server hasn't been told. */
4064 {
98381190 4065 Lisp_Object name;
cf177271 4066 int explicit = f->explicit_name;
e373f201 4067
cf177271 4068 f->explicit_name = 0;
98381190
KH
4069 name = f->name;
4070 f->name = Qnil;
cf177271 4071 x_set_name (f, name, explicit);
e373f201
JB
4072 }
4073
b9dc4443 4074 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4075 f->output_data.x->text_cursor);
9ef48a9d 4076
01f1ba30
JB
4077 UNBLOCK_INPUT;
4078
fe24a618 4079 if (FRAME_X_WINDOW (f) == 0)
9ef48a9d 4080 error ("Unable to create window");
01f1ba30
JB
4081}
4082
8fc2766b
RS
4083#endif /* not USE_X_TOOLKIT */
4084
01f1ba30
JB
4085/* Handle the icon stuff for this window. Perhaps later we might
4086 want an x_set_icon_position which can be called interactively as
b9dc4443 4087 well. */
01f1ba30
JB
4088
4089static void
f676886a
JB
4090x_icon (f, parms)
4091 struct frame *f;
01f1ba30
JB
4092 Lisp_Object parms;
4093{
f9942c9e 4094 Lisp_Object icon_x, icon_y;
abb4b7ec 4095 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
4096
4097 /* Set the position of the icon. Note that twm groups all
b9dc4443 4098 icons in an icon window. */
333b20bb
GM
4099 icon_x = x_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4100 icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
f9942c9e 4101 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
01f1ba30 4102 {
b7826503
PJ
4103 CHECK_NUMBER (icon_x);
4104 CHECK_NUMBER (icon_y);
01f1ba30 4105 }
f9942c9e 4106 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
01f1ba30 4107 error ("Both left and top icon corners of icon must be specified");
01f1ba30 4108
f9942c9e
JB
4109 BLOCK_INPUT;
4110
fe24a618
JB
4111 if (! EQ (icon_x, Qunbound))
4112 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
f9942c9e 4113
01f1ba30 4114 /* Start up iconic or window? */
49795535 4115 x_wm_set_window_state
333b20bb
GM
4116 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL),
4117 Qicon)
49795535
JB
4118 ? IconicState
4119 : NormalState));
01f1ba30 4120
f468da95
RS
4121 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4122 ? f->icon_name
4123 : f->name))->data);
80534dd6 4124
01f1ba30
JB
4125 UNBLOCK_INPUT;
4126}
4127
b243755a 4128/* Make the GCs needed for this window, setting the
01f1ba30
JB
4129 background, border and mouse colors; also create the
4130 mouse cursor and the gray border tile. */
4131
f945b920
JB
4132static char cursor_bits[] =
4133 {
4134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4138 };
4139
01f1ba30 4140static void
f676886a
JB
4141x_make_gc (f)
4142 struct frame *f;
01f1ba30
JB
4143{
4144 XGCValues gc_values;
01f1ba30 4145
6afb1d07
JB
4146 BLOCK_INPUT;
4147
b243755a 4148 /* Create the GCs of this frame.
9ef48a9d 4149 Note that many default values are used. */
01f1ba30
JB
4150
4151 /* Normal video */
7556890b
RS
4152 gc_values.font = f->output_data.x->font->fid;
4153 gc_values.foreground = f->output_data.x->foreground_pixel;
4154 gc_values.background = f->output_data.x->background_pixel;
9ef48a9d 4155 gc_values.line_width = 0; /* Means 1 using fast algorithm. */
959e647d
GM
4156 f->output_data.x->normal_gc
4157 = XCreateGC (FRAME_X_DISPLAY (f),
4158 FRAME_X_WINDOW (f),
4159 GCLineWidth | GCFont | GCForeground | GCBackground,
4160 &gc_values);
01f1ba30 4161
b9dc4443 4162 /* Reverse video style. */
7556890b
RS
4163 gc_values.foreground = f->output_data.x->background_pixel;
4164 gc_values.background = f->output_data.x->foreground_pixel;
959e647d
GM
4165 f->output_data.x->reverse_gc
4166 = XCreateGC (FRAME_X_DISPLAY (f),
4167 FRAME_X_WINDOW (f),
4168 GCFont | GCForeground | GCBackground | GCLineWidth,
4169 &gc_values);
01f1ba30 4170
9ef48a9d 4171 /* Cursor has cursor-color background, background-color foreground. */
7556890b
RS
4172 gc_values.foreground = f->output_data.x->background_pixel;
4173 gc_values.background = f->output_data.x->cursor_pixel;
01f1ba30
JB
4174 gc_values.fill_style = FillOpaqueStippled;
4175 gc_values.stipple
b9dc4443
RS
4176 = XCreateBitmapFromData (FRAME_X_DISPLAY (f),
4177 FRAME_X_DISPLAY_INFO (f)->root_window,
01f1ba30 4178 cursor_bits, 16, 16);
7556890b 4179 f->output_data.x->cursor_gc
b9dc4443 4180 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
01f1ba30 4181 (GCFont | GCForeground | GCBackground
ac1f48a4 4182 | GCFillStyle /* | GCStipple */ | GCLineWidth),
01f1ba30
JB
4183 &gc_values);
4184
333b20bb
GM
4185 /* Reliefs. */
4186 f->output_data.x->white_relief.gc = 0;
4187 f->output_data.x->black_relief.gc = 0;
4188
01f1ba30 4189 /* Create the gray border tile used when the pointer is not in
f676886a 4190 the frame. Since this depends on the frame's pixel values,
9ef48a9d 4191 this must be done on a per-frame basis. */
7556890b 4192 f->output_data.x->border_tile
d043f1a4 4193 = (XCreatePixmapFromBitmapData
b9dc4443 4194 (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
d043f1a4 4195 gray_bits, gray_width, gray_height,
7556890b
RS
4196 f->output_data.x->foreground_pixel,
4197 f->output_data.x->background_pixel,
ab452f99 4198 DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f))));
6afb1d07
JB
4199
4200 UNBLOCK_INPUT;
01f1ba30 4201}
01f1ba30 4202
959e647d
GM
4203
4204/* Free what was was allocated in x_make_gc. */
4205
4206void
4207x_free_gcs (f)
4208 struct frame *f;
4209{
4210 Display *dpy = FRAME_X_DISPLAY (f);
4211
4212 BLOCK_INPUT;
4213
4214 if (f->output_data.x->normal_gc)
4215 {
4216 XFreeGC (dpy, f->output_data.x->normal_gc);
4217 f->output_data.x->normal_gc = 0;
4218 }
4219
4220 if (f->output_data.x->reverse_gc)
4221 {
4222 XFreeGC (dpy, f->output_data.x->reverse_gc);
4223 f->output_data.x->reverse_gc = 0;
4224 }
4225
4226 if (f->output_data.x->cursor_gc)
4227 {
4228 XFreeGC (dpy, f->output_data.x->cursor_gc);
4229 f->output_data.x->cursor_gc = 0;
4230 }
4231
4232 if (f->output_data.x->border_tile)
4233 {
4234 XFreePixmap (dpy, f->output_data.x->border_tile);
4235 f->output_data.x->border_tile = 0;
4236 }
4237
4238 UNBLOCK_INPUT;
4239}
4240
4241
eaf1eea9
GM
4242/* Handler for signals raised during x_create_frame and
4243 x_create_top_frame. FRAME is the frame which is partially
4244 constructed. */
4245
4246static Lisp_Object
4247unwind_create_frame (frame)
4248 Lisp_Object frame;
4249{
4250 struct frame *f = XFRAME (frame);
4251
4252 /* If frame is ``official'', nothing to do. */
4253 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4254 {
f1d2ce7f 4255#if GLYPH_DEBUG
eaf1eea9
GM
4256 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4257#endif
4258
4259 x_free_frame_resources (f);
4260
4261 /* Check that reference counts are indeed correct. */
4262 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4263 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a 4264 return Qt;
eaf1eea9
GM
4265 }
4266
4267 return Qnil;
4268}
4269
4270
f676886a 4271DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
01f1ba30 4272 1, 1, 0,
7ee72033 4273 doc: /* Make a new X window, which is called a "frame" in Emacs terms.
c061c855
GM
4274Returns an Emacs frame object.
4275ALIST is an alist of frame parameters.
4276If the parameters specify that the frame should not have a minibuffer,
4277and do not specify a specific minibuffer window to use,
4278then `default-minibuffer-frame' must be a frame whose minibuffer can
4279be shared by the new frame.
4280
7ee72033
MB
4281This function is an internal primitive--use `make-frame' instead. */)
4282 (parms)
01f1ba30
JB
4283 Lisp_Object parms;
4284{
f676886a 4285 struct frame *f;
2365c027 4286 Lisp_Object frame, tem;
01f1ba30
JB
4287 Lisp_Object name;
4288 int minibuffer_only = 0;
4289 long window_prompting = 0;
4290 int width, height;
eaf1eea9 4291 int count = BINDING_STACK_SIZE ();
ecaca587 4292 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
b9dc4443 4293 Lisp_Object display;
333b20bb 4294 struct x_display_info *dpyinfo = NULL;
a59e4f3d 4295 Lisp_Object parent;
e557f19d 4296 struct kboard *kb;
01f1ba30 4297
11ae94fe 4298 check_x ();
01f1ba30 4299
b7975ee4
KH
4300 /* Use this general default value to start with
4301 until we know if this frame has a specified name. */
4302 Vx_resource_name = Vinvocation_name;
4303
333b20bb 4304 display = x_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING);
b9dc4443
RS
4305 if (EQ (display, Qunbound))
4306 display = Qnil;
4307 dpyinfo = check_x_display_info (display);
e557f19d
KH
4308#ifdef MULTI_KBOARD
4309 kb = dpyinfo->kboard;
4310#else
4311 kb = &the_only_kboard;
4312#endif
b9dc4443 4313
333b20bb 4314 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
6a5e54e2 4315 if (!STRINGP (name)
cf177271
JB
4316 && ! EQ (name, Qunbound)
4317 && ! NILP (name))
08a90d6a 4318 error ("Invalid frame name--not a string or nil");
01f1ba30 4319
b7975ee4
KH
4320 if (STRINGP (name))
4321 Vx_resource_name = name;
4322
a59e4f3d 4323 /* See if parent window is specified. */
333b20bb 4324 parent = x_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
a59e4f3d
RS
4325 if (EQ (parent, Qunbound))
4326 parent = Qnil;
4327 if (! NILP (parent))
b7826503 4328 CHECK_NUMBER (parent);
a59e4f3d 4329
ecaca587
RS
4330 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4331 /* No need to protect DISPLAY because that's not used after passing
4332 it to make_frame_without_minibuffer. */
4333 frame = Qnil;
4334 GCPRO4 (parms, parent, name, frame);
333b20bb
GM
4335 tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
4336 RES_TYPE_SYMBOL);
f9942c9e 4337 if (EQ (tem, Qnone) || NILP (tem))
2526c290 4338 f = make_frame_without_minibuffer (Qnil, kb, display);
f9942c9e 4339 else if (EQ (tem, Qonly))
01f1ba30 4340 {
f676886a 4341 f = make_minibuffer_frame ();
01f1ba30
JB
4342 minibuffer_only = 1;
4343 }
6a5e54e2 4344 else if (WINDOWP (tem))
2526c290 4345 f = make_frame_without_minibuffer (tem, kb, display);
f9942c9e
JB
4346 else
4347 f = make_frame (1);
01f1ba30 4348
ecaca587
RS
4349 XSETFRAME (frame, f);
4350
a3c87d4e
JB
4351 /* Note that X Windows does support scroll bars. */
4352 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
179956b9 4353
08a90d6a 4354 f->output_method = output_x_window;
7556890b
RS
4355 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
4356 bzero (f->output_data.x, sizeof (struct x_output));
4357 f->output_data.x->icon_bitmap = -1;
0ecca023 4358 f->output_data.x->fontset = -1;
333b20bb
GM
4359 f->output_data.x->scroll_bar_foreground_pixel = -1;
4360 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
4361#ifdef USE_TOOLKIT_SCROLL_BARS
4362 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
4363 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
4364#endif /* USE_TOOLKIT_SCROLL_BARS */
eaf1eea9 4365 record_unwind_protect (unwind_create_frame, frame);
08a90d6a 4366
f468da95 4367 f->icon_name
333b20bb
GM
4368 = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
4369 RES_TYPE_STRING);
f468da95
RS
4370 if (! STRINGP (f->icon_name))
4371 f->icon_name = Qnil;
80534dd6 4372
08a90d6a 4373 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 4374#if GLYPH_DEBUG
eaf1eea9
GM
4375 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
4376 dpyinfo_refcount = dpyinfo->reference_count;
4377#endif /* GLYPH_DEBUG */
73410c76 4378#ifdef MULTI_KBOARD
e557f19d 4379 FRAME_KBOARD (f) = kb;
73410c76 4380#endif
08a90d6a 4381
9b2956e2
GM
4382 /* These colors will be set anyway later, but it's important
4383 to get the color reference counts right, so initialize them! */
4384 {
4385 Lisp_Object black;
4386 struct gcpro gcpro1;
cefecbcf
GM
4387
4388 /* Function x_decode_color can signal an error. Make
4389 sure to initialize color slots so that we won't try
4390 to free colors we haven't allocated. */
4391 f->output_data.x->foreground_pixel = -1;
4392 f->output_data.x->background_pixel = -1;
4393 f->output_data.x->cursor_pixel = -1;
4394 f->output_data.x->cursor_foreground_pixel = -1;
4395 f->output_data.x->border_pixel = -1;
4396 f->output_data.x->mouse_pixel = -1;
9b2956e2
GM
4397
4398 black = build_string ("black");
4399 GCPRO1 (black);
4400 f->output_data.x->foreground_pixel
4401 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4402 f->output_data.x->background_pixel
4403 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4404 f->output_data.x->cursor_pixel
4405 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4406 f->output_data.x->cursor_foreground_pixel
4407 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4408 f->output_data.x->border_pixel
4409 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4410 f->output_data.x->mouse_pixel
4411 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4412 UNGCPRO;
4413 }
4414
a59e4f3d
RS
4415 /* Specify the parent under which to make this X window. */
4416
4417 if (!NILP (parent))
4418 {
8c239ac3 4419 f->output_data.x->parent_desc = (Window) XFASTINT (parent);
7556890b 4420 f->output_data.x->explicit_parent = 1;
a59e4f3d
RS
4421 }
4422 else
4423 {
7556890b
RS
4424 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
4425 f->output_data.x->explicit_parent = 0;
a59e4f3d
RS
4426 }
4427
cf177271
JB
4428 /* Set the name; the functions to which we pass f expect the name to
4429 be set. */
4430 if (EQ (name, Qunbound) || NILP (name))
4431 {
08a90d6a 4432 f->name = build_string (dpyinfo->x_id_name);
cf177271
JB
4433 f->explicit_name = 0;
4434 }
4435 else
4436 {
4437 f->name = name;
4438 f->explicit_name = 1;
9ef48a9d
RS
4439 /* use the frame's title when getting resources for this frame. */
4440 specbind (Qx_resource_name, name);
cf177271 4441 }
01f1ba30 4442
01f1ba30
JB
4443 /* Extract the window parameters from the supplied values
4444 that are needed to determine window geometry. */
d387c960
JB
4445 {
4446 Lisp_Object font;
4447
333b20bb 4448 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
2ee3abaa 4449
6817eab4 4450 BLOCK_INPUT;
e5e548e3
RS
4451 /* First, try whatever font the caller has specified. */
4452 if (STRINGP (font))
942ea06d 4453 {
49965a29 4454 tem = Fquery_fontset (font, Qnil);
477f8642
KH
4455 if (STRINGP (tem))
4456 font = x_new_fontset (f, XSTRING (tem)->data);
942ea06d
KH
4457 else
4458 font = x_new_font (f, XSTRING (font)->data);
4459 }
333b20bb 4460
e5e548e3 4461 /* Try out a font which we hope has bold and italic variations. */
333b20bb
GM
4462 if (!STRINGP (font))
4463 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
e5e548e3 4464 if (!STRINGP (font))
a6ac02af 4465 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3 4466 if (! STRINGP (font))
a6ac02af 4467 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3
RS
4468 if (! STRINGP (font))
4469 /* This was formerly the first thing tried, but it finds too many fonts
4470 and takes too long. */
4471 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
4472 /* If those didn't work, look for something which will at least work. */
4473 if (! STRINGP (font))
a6ac02af 4474 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
6817eab4
JB
4475 UNBLOCK_INPUT;
4476 if (! STRINGP (font))
e5e548e3
RS
4477 font = build_string ("fixed");
4478
477f8642 4479 x_default_parameter (f, parms, Qfont, font,
333b20bb 4480 "font", "Font", RES_TYPE_STRING);
d387c960 4481 }
9ef48a9d 4482
e3881aa0 4483#ifdef USE_LUCID
82c90203
RS
4484 /* Prevent lwlib/xlwmenu.c from crashing because of a bug
4485 whereby it fails to get any font. */
7556890b 4486 xlwmenu_default_font = f->output_data.x->font;
dd254b21 4487#endif
82c90203 4488
cf177271 4489 x_default_parameter (f, parms, Qborder_width, make_number (2),
333b20bb
GM
4490 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
4491
4e397688 4492 /* This defaults to 1 in order to match xterm. We recognize either
ddf768c3
JB
4493 internalBorderWidth or internalBorder (which is what xterm calls
4494 it). */
4495 if (NILP (Fassq (Qinternal_border_width, parms)))
4496 {
4497 Lisp_Object value;
4498
abb4b7ec 4499 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
333b20bb 4500 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
ddf768c3
JB
4501 if (! EQ (value, Qunbound))
4502 parms = Fcons (Fcons (Qinternal_border_width, value),
4503 parms);
4504 }
dca97592 4505 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
333b20bb
GM
4506 "internalBorderWidth", "internalBorderWidth",
4507 RES_TYPE_NUMBER);
1ab3d87e 4508 x_default_parameter (f, parms, Qvertical_scroll_bars, Qleft,
333b20bb
GM
4509 "verticalScrollBars", "ScrollBars",
4510 RES_TYPE_SYMBOL);
01f1ba30 4511
b9dc4443 4512 /* Also do the stuff which must be set before the window exists. */
cf177271 4513 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
333b20bb 4514 "foreground", "Foreground", RES_TYPE_STRING);
cf177271 4515 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
0b60fc91 4516 "background", "Background", RES_TYPE_STRING);
cf177271 4517 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
333b20bb 4518 "pointerColor", "Foreground", RES_TYPE_STRING);
cf177271 4519 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
333b20bb 4520 "cursorColor", "Foreground", RES_TYPE_STRING);
cf177271 4521 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
333b20bb 4522 "borderColor", "BorderColor", RES_TYPE_STRING);
d62c8769
GM
4523 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
4524 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
563b67aa
GM
4525 x_default_parameter (f, parms, Qline_spacing, Qnil,
4526 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
b3ba0aa8
KS
4527 x_default_parameter (f, parms, Qleft_fringe, Qnil,
4528 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4529 x_default_parameter (f, parms, Qright_fringe, Qnil,
4530 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
333b20bb
GM
4531
4532 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
4533 "scrollBarForeground",
4534 "ScrollBarForeground", 1);
4535 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
4536 "scrollBarBackground",
4537 "ScrollBarBackground", 0);
4538
4539 /* Init faces before x_default_parameter is called for scroll-bar
4540 parameters because that function calls x_set_scroll_bar_width,
4541 which calls change_frame_size, which calls Fset_window_buffer,
4542 which runs hooks, which call Fvertical_motion. At the end, we
4543 end up in init_iterator with a null face cache, which should not
4544 happen. */
4545 init_frame_faces (f);
4546
c7bcb20d 4547 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
333b20bb 4548 "menuBar", "MenuBar", RES_TYPE_NUMBER);
e33455ca 4549 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
333b20bb 4550 "toolBar", "ToolBar", RES_TYPE_NUMBER);
79873d50 4551 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
333b20bb
GM
4552 "bufferPredicate", "BufferPredicate",
4553 RES_TYPE_SYMBOL);
c2304e02 4554 x_default_parameter (f, parms, Qtitle, Qnil,
333b20bb 4555 "title", "Title", RES_TYPE_STRING);
ea0a1f53
GM
4556 x_default_parameter (f, parms, Qwait_for_wm, Qt,
4557 "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
49d41073
EZ
4558 x_default_parameter (f, parms, Qfullscreen, Qnil,
4559 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
90eb1019 4560
7556890b 4561 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
35f59f6b
GM
4562
4563 /* Add the tool-bar height to the initial frame height so that the
4564 user gets a text display area of the size he specified with -g or
4565 via .Xdefaults. Later changes of the tool-bar height don't
4566 change the frame size. This is done so that users can create
4567 tall Emacs frames without having to guess how tall the tool-bar
4568 will get. */
4569 if (FRAME_TOOL_BAR_LINES (f))
4570 {
4571 int margin, relief, bar_height;
4572
8ed86491 4573 relief = (tool_bar_button_relief >= 0
35f59f6b
GM
4574 ? tool_bar_button_relief
4575 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
4576
4577 if (INTEGERP (Vtool_bar_button_margin)
4578 && XINT (Vtool_bar_button_margin) > 0)
4579 margin = XFASTINT (Vtool_bar_button_margin);
4580 else if (CONSP (Vtool_bar_button_margin)
4581 && INTEGERP (XCDR (Vtool_bar_button_margin))
4582 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
4583 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
4584 else
4585 margin = 0;
4586
4587 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
4588 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
4589 }
4590
4591 /* Compute the size of the X window. */
f676886a 4592 window_prompting = x_figure_window_size (f, parms);
01f1ba30 4593
f83f10ba 4594 if (window_prompting & XNegative)
2365c027 4595 {
f83f10ba 4596 if (window_prompting & YNegative)
7556890b 4597 f->output_data.x->win_gravity = SouthEastGravity;
f83f10ba 4598 else
7556890b 4599 f->output_data.x->win_gravity = NorthEastGravity;
f83f10ba
RS
4600 }
4601 else
4602 {
4603 if (window_prompting & YNegative)
7556890b 4604 f->output_data.x->win_gravity = SouthWestGravity;
f83f10ba 4605 else
7556890b 4606 f->output_data.x->win_gravity = NorthWestGravity;
2365c027
RS
4607 }
4608
7556890b 4609 f->output_data.x->size_hint_flags = window_prompting;
38d22040 4610
495fa05e
GM
4611 tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4612 f->no_split = minibuffer_only || EQ (tem, Qt);
4613
6a1bcd01 4614 /* Create the X widget or window. */
a7f7d550
FP
4615#ifdef USE_X_TOOLKIT
4616 x_window (f, window_prompting, minibuffer_only);
4617#else
f676886a 4618 x_window (f);
a7f7d550 4619#endif
495fa05e 4620
f676886a
JB
4621 x_icon (f, parms);
4622 x_make_gc (f);
01f1ba30 4623
495fa05e
GM
4624 /* Now consider the frame official. */
4625 FRAME_X_DISPLAY_INFO (f)->reference_count++;
4626 Vframe_list = Fcons (frame, Vframe_list);
4627
f9942c9e
JB
4628 /* We need to do this after creating the X window, so that the
4629 icon-creation functions can say whose icon they're describing. */
cf177271 4630 x_default_parameter (f, parms, Qicon_type, Qnil,
333b20bb 4631 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
f9942c9e 4632
cf177271 4633 x_default_parameter (f, parms, Qauto_raise, Qnil,
333b20bb 4634 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
cf177271 4635 x_default_parameter (f, parms, Qauto_lower, Qnil,
333b20bb 4636 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
dbc4e1c1 4637 x_default_parameter (f, parms, Qcursor_type, Qbox,
333b20bb 4638 "cursorType", "CursorType", RES_TYPE_SYMBOL);
28d7281d
GM
4639 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4640 "scrollBarWidth", "ScrollBarWidth",
4641 RES_TYPE_NUMBER);
f9942c9e 4642
f676886a 4643 /* Dimensions, especially f->height, must be done via change_frame_size.
01f1ba30 4644 Change will not be effected unless different from the current
b9dc4443 4645 f->height. */
f676886a
JB
4646 width = f->width;
4647 height = f->height;
6a1bcd01 4648
1ab3d87e
RS
4649 f->height = 0;
4650 SET_FRAME_WIDTH (f, 0);
8938a4fb 4651 change_frame_size (f, height, width, 1, 0, 0);
d043f1a4 4652
4a967a9b
GM
4653 /* Set up faces after all frame parameters are known. This call
4654 also merges in face attributes specified for new frames. If we
4655 don't do this, the `menu' face for instance won't have the right
4656 colors, and the menu bar won't appear in the specified colors for
4657 new frames. */
4658 call1 (Qface_set_after_frame_default, frame);
4659
495fa05e
GM
4660#ifdef USE_X_TOOLKIT
4661 /* Create the menu bar. */
4662 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4663 {
4664 /* If this signals an error, we haven't set size hints for the
4665 frame and we didn't make it visible. */
4666 initialize_frame_menubar (f);
4667
4668 /* This is a no-op, except under Motif where it arranges the
4669 main window for the widgets on it. */
4670 lw_set_main_areas (f->output_data.x->column_widget,
4671 f->output_data.x->menubar_widget,
4672 f->output_data.x->edit_widget);
4673 }
4674#endif /* USE_X_TOOLKIT */
4675
4676 /* Tell the server what size and position, etc, we want, and how
4677 badly we want them. This should be done after we have the menu
4678 bar so that its size can be taken into account. */
01f1ba30 4679 BLOCK_INPUT;
7989f084 4680 x_wm_set_size_hint (f, window_prompting, 0);
01f1ba30
JB
4681 UNBLOCK_INPUT;
4682
495fa05e
GM
4683 /* Make the window appear on the frame and enable display, unless
4684 the caller says not to. However, with explicit parent, Emacs
4685 cannot control visibility, so don't try. */
7556890b 4686 if (! f->output_data.x->explicit_parent)
a59e4f3d
RS
4687 {
4688 Lisp_Object visibility;
49795535 4689
333b20bb
GM
4690 visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
4691 RES_TYPE_SYMBOL);
a59e4f3d
RS
4692 if (EQ (visibility, Qunbound))
4693 visibility = Qt;
49795535 4694
a59e4f3d
RS
4695 if (EQ (visibility, Qicon))
4696 x_iconify_frame (f);
4697 else if (! NILP (visibility))
4698 x_make_frame_visible (f);
4699 else
4700 /* Must have been Qnil. */
4701 ;
4702 }
01f1ba30 4703
495fa05e 4704 UNGCPRO;
9e57df62
GM
4705
4706 /* Make sure windows on this frame appear in calls to next-window
4707 and similar functions. */
4708 Vwindow_list = Qnil;
4709
9ef48a9d 4710 return unbind_to (count, frame);
01f1ba30
JB
4711}
4712
eaf1eea9 4713
0d17d282
KH
4714/* FRAME is used only to get a handle on the X display. We don't pass the
4715 display info directly because we're called from frame.c, which doesn't
4716 know about that structure. */
e4f79258 4717
87498171 4718Lisp_Object
0d17d282
KH
4719x_get_focus_frame (frame)
4720 struct frame *frame;
87498171 4721{
0d17d282 4722 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (frame);
87498171 4723 Lisp_Object xfocus;
0d17d282 4724 if (! dpyinfo->x_focus_frame)
87498171
KH
4725 return Qnil;
4726
0d17d282 4727 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
87498171
KH
4728 return xfocus;
4729}
f0614854 4730
3decc1e7
GM
4731
4732/* In certain situations, when the window manager follows a
4733 click-to-focus policy, there seems to be no way around calling
4734 XSetInputFocus to give another frame the input focus .
4735
4736 In an ideal world, XSetInputFocus should generally be avoided so
4737 that applications don't interfere with the window manager's focus
4738 policy. But I think it's okay to use when it's clearly done
4739 following a user-command. */
4740
4741DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
7ee72033
MB
4742 doc: /* Set the input focus to FRAME.
4743FRAME nil means use the selected frame. */)
4744 (frame)
3decc1e7
GM
4745 Lisp_Object frame;
4746{
4747 struct frame *f = check_x_frame (frame);
4748 Display *dpy = FRAME_X_DISPLAY (f);
4749 int count;
4750
4751 BLOCK_INPUT;
4752 count = x_catch_errors (dpy);
4753 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4754 RevertToParent, CurrentTime);
4755 x_uncatch_errors (dpy, count);
4756 UNBLOCK_INPUT;
4757
4758 return Qnil;
4759}
4760
f0614854 4761\f
2d764c78 4762DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7ee72033
MB
4763 doc: /* Internal function called by `color-defined-p', which see. */)
4764 (color, frame)
b9dc4443 4765 Lisp_Object color, frame;
e12d55b2 4766{
b9dc4443
RS
4767 XColor foo;
4768 FRAME_PTR f = check_x_frame (frame);
e12d55b2 4769
b7826503 4770 CHECK_STRING (color);
b9dc4443 4771
2d764c78 4772 if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
e12d55b2
RS
4773 return Qt;
4774 else
4775 return Qnil;
4776}
4777
2d764c78 4778DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7ee72033
MB
4779 doc: /* Internal function called by `color-values', which see. */)
4780 (color, frame)
b9dc4443 4781 Lisp_Object color, frame;
01f1ba30 4782{
b9dc4443
RS
4783 XColor foo;
4784 FRAME_PTR f = check_x_frame (frame);
4785
b7826503 4786 CHECK_STRING (color);
01f1ba30 4787
2d764c78 4788 if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
57c82a63
RS
4789 {
4790 Lisp_Object rgb[3];
4791
4792 rgb[0] = make_number (foo.red);
4793 rgb[1] = make_number (foo.green);
4794 rgb[2] = make_number (foo.blue);
4795 return Flist (3, rgb);
4796 }
01f1ba30
JB
4797 else
4798 return Qnil;
4799}
4800
2d764c78 4801DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7ee72033
MB
4802 doc: /* Internal function called by `display-color-p', which see. */)
4803 (display)
08a90d6a 4804 Lisp_Object display;
01f1ba30 4805{
08a90d6a 4806 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 4807
b9dc4443 4808 if (dpyinfo->n_planes <= 2)
01f1ba30
JB
4809 return Qnil;
4810
b9dc4443 4811 switch (dpyinfo->visual->class)
01f1ba30
JB
4812 {
4813 case StaticColor:
4814 case PseudoColor:
4815 case TrueColor:
4816 case DirectColor:
4817 return Qt;
4818
4819 default:
4820 return Qnil;
4821 }
4822}
4823
d0c9d219 4824DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
c061c855 4825 0, 1, 0,
7ee72033 4826 doc: /* Return t if the X display supports shades of gray.
c061c855
GM
4827Note that color displays do support shades of gray.
4828The optional argument DISPLAY specifies which display to ask about.
4829DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4830If omitted or nil, that stands for the selected frame's display. */)
4831 (display)
08a90d6a 4832 Lisp_Object display;
d0c9d219 4833{
08a90d6a 4834 struct x_display_info *dpyinfo = check_x_display_info (display);
d0c9d219 4835
ae6b58f9 4836 if (dpyinfo->n_planes <= 1)
b9dc4443
RS
4837 return Qnil;
4838
ae6b58f9
RS
4839 switch (dpyinfo->visual->class)
4840 {
4841 case StaticColor:
4842 case PseudoColor:
4843 case TrueColor:
4844 case DirectColor:
4845 case StaticGray:
4846 case GrayScale:
4847 return Qt;
4848
4849 default:
4850 return Qnil;
4851 }
d0c9d219
RS
4852}
4853
41beb8fc 4854DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
c061c855 4855 0, 1, 0,
7ee72033 4856 doc: /* Returns the width in pixels of the X display DISPLAY.
c061c855
GM
4857The optional argument DISPLAY specifies which display to ask about.
4858DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4859If omitted or nil, that stands for the selected frame's display. */)
4860 (display)
08a90d6a 4861 Lisp_Object display;
41beb8fc 4862{
08a90d6a 4863 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4864
4865 return make_number (dpyinfo->width);
41beb8fc
RS
4866}
4867
4868DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
c061c855 4869 Sx_display_pixel_height, 0, 1, 0,
7ee72033 4870 doc: /* Returns the height in pixels of the X display DISPLAY.
c061c855
GM
4871The optional argument DISPLAY specifies which display to ask about.
4872DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4873If omitted or nil, that stands for the selected frame's display. */)
4874 (display)
08a90d6a 4875 Lisp_Object display;
41beb8fc 4876{
08a90d6a 4877 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4878
4879 return make_number (dpyinfo->height);
41beb8fc
RS
4880}
4881
4882DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
c061c855 4883 0, 1, 0,
7ee72033 4884 doc: /* Returns the number of bitplanes of the X display DISPLAY.
c061c855
GM
4885The optional argument DISPLAY specifies which display to ask about.
4886DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4887If omitted or nil, that stands for the selected frame's display. */)
4888 (display)
08a90d6a 4889 Lisp_Object display;
41beb8fc 4890{
08a90d6a 4891 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4892
4893 return make_number (dpyinfo->n_planes);
41beb8fc
RS
4894}
4895
4896DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
c061c855 4897 0, 1, 0,
7ee72033 4898 doc: /* Returns the number of color cells of the X display DISPLAY.
c061c855
GM
4899The optional argument DISPLAY specifies which display to ask about.
4900DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4901If omitted or nil, that stands for the selected frame's display. */)
4902 (display)
08a90d6a 4903 Lisp_Object display;
41beb8fc 4904{
08a90d6a 4905 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4906
4907 return make_number (DisplayCells (dpyinfo->display,
4908 XScreenNumberOfScreen (dpyinfo->screen)));
41beb8fc
RS
4909}
4910
9d317b2c
RS
4911DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4912 Sx_server_max_request_size,
c061c855 4913 0, 1, 0,
7ee72033 4914 doc: /* Returns the maximum request size of the X server of display DISPLAY.
c061c855
GM
4915The optional argument DISPLAY specifies which display to ask about.
4916DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4917If omitted or nil, that stands for the selected frame's display. */)
4918 (display)
08a90d6a 4919 Lisp_Object display;
9d317b2c 4920{
08a90d6a 4921 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4922
4923 return make_number (MAXREQUEST (dpyinfo->display));
9d317b2c
RS
4924}
4925
41beb8fc 4926DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7ee72033 4927 doc: /* Returns the vendor ID string of the X server of display DISPLAY.
c061c855
GM
4928The optional argument DISPLAY specifies which display to ask about.
4929DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4930If omitted or nil, that stands for the selected frame's display. */)
4931 (display)
08a90d6a 4932 Lisp_Object display;
41beb8fc 4933{
08a90d6a 4934 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4935 char *vendor = ServerVendor (dpyinfo->display);
4936
41beb8fc
RS
4937 if (! vendor) vendor = "";
4938 return build_string (vendor);
4939}
4940
4941DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7ee72033 4942 doc: /* Returns the version numbers of the X server of display DISPLAY.
c061c855
GM
4943The value is a list of three integers: the major and minor
4944version numbers of the X Protocol in use, and the vendor-specific release
4945number. See also the function `x-server-vendor'.
4946
4947The optional argument DISPLAY specifies which display to ask about.
4948DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4949If omitted or nil, that stands for the selected frame's display. */)
4950 (display)
08a90d6a 4951 Lisp_Object display;
41beb8fc 4952{
08a90d6a 4953 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443 4954 Display *dpy = dpyinfo->display;
11ae94fe 4955
41beb8fc
RS
4956 return Fcons (make_number (ProtocolVersion (dpy)),
4957 Fcons (make_number (ProtocolRevision (dpy)),
4958 Fcons (make_number (VendorRelease (dpy)), Qnil)));
4959}
4960
4961DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7ee72033 4962 doc: /* Return the number of screens on the X server of display DISPLAY.
c061c855
GM
4963The optional argument DISPLAY specifies which display to ask about.
4964DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4965If omitted or nil, that stands for the selected frame's display. */)
4966 (display)
08a90d6a 4967 Lisp_Object display;
41beb8fc 4968{
08a90d6a 4969 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4970
4971 return make_number (ScreenCount (dpyinfo->display));
41beb8fc
RS
4972}
4973
4974DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7ee72033 4975 doc: /* Return the height in millimeters of the X display DISPLAY.
c061c855
GM
4976The optional argument DISPLAY specifies which display to ask about.
4977DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4978If omitted or nil, that stands for the selected frame's display. */)
4979 (display)
08a90d6a 4980 Lisp_Object display;
41beb8fc 4981{
08a90d6a 4982 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4983
4984 return make_number (HeightMMOfScreen (dpyinfo->screen));
41beb8fc
RS
4985}
4986
4987DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7ee72033 4988 doc: /* Return the width in millimeters of the X display DISPLAY.
c061c855
GM
4989The optional argument DISPLAY specifies which display to ask about.
4990DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4991If omitted or nil, that stands for the selected frame's display. */)
4992 (display)
08a90d6a 4993 Lisp_Object display;
41beb8fc 4994{
08a90d6a 4995 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4996
4997 return make_number (WidthMMOfScreen (dpyinfo->screen));
41beb8fc
RS
4998}
4999
5000DEFUN ("x-display-backing-store", Fx_display_backing_store,
c061c855 5001 Sx_display_backing_store, 0, 1, 0,
7ee72033 5002 doc: /* Returns an indication of whether X display DISPLAY does backing store.
c061c855
GM
5003The value may be `always', `when-mapped', or `not-useful'.
5004The optional argument DISPLAY specifies which display to ask about.
5005DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5006If omitted or nil, that stands for the selected frame's display. */)
5007 (display)
08a90d6a 5008 Lisp_Object display;
41beb8fc 5009{
08a90d6a 5010 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5011 Lisp_Object result;
11ae94fe 5012
b9dc4443 5013 switch (DoesBackingStore (dpyinfo->screen))
41beb8fc
RS
5014 {
5015 case Always:
8ec8a5ec
GM
5016 result = intern ("always");
5017 break;
41beb8fc
RS
5018
5019 case WhenMapped:
8ec8a5ec
GM
5020 result = intern ("when-mapped");
5021 break;
41beb8fc
RS
5022
5023 case NotUseful:
8ec8a5ec
GM
5024 result = intern ("not-useful");
5025 break;
41beb8fc
RS
5026
5027 default:
5028 error ("Strange value for BackingStore parameter of screen");
8ec8a5ec 5029 result = Qnil;
41beb8fc 5030 }
8ec8a5ec
GM
5031
5032 return result;
41beb8fc
RS
5033}
5034
5035DEFUN ("x-display-visual-class", Fx_display_visual_class,
c061c855 5036 Sx_display_visual_class, 0, 1, 0,
7ee72033 5037 doc: /* Return the visual class of the X display DISPLAY.
c061c855
GM
5038The value is one of the symbols `static-gray', `gray-scale',
5039`static-color', `pseudo-color', `true-color', or `direct-color'.
5040
5041The optional argument DISPLAY specifies which display to ask about.
5042DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5043If omitted or nil, that stands for the selected frame's display. */)
5044 (display)
08a90d6a 5045 Lisp_Object display;
41beb8fc 5046{
08a90d6a 5047 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5048 Lisp_Object result;
11ae94fe 5049
b9dc4443 5050 switch (dpyinfo->visual->class)
41beb8fc 5051 {
8ec8a5ec
GM
5052 case StaticGray:
5053 result = intern ("static-gray");
5054 break;
5055 case GrayScale:
5056 result = intern ("gray-scale");
5057 break;
5058 case StaticColor:
5059 result = intern ("static-color");
5060 break;
5061 case PseudoColor:
5062 result = intern ("pseudo-color");
5063 break;
5064 case TrueColor:
5065 result = intern ("true-color");
5066 break;
5067 case DirectColor:
5068 result = intern ("direct-color");
5069 break;
41beb8fc
RS
5070 default:
5071 error ("Display has an unknown visual class");
8ec8a5ec 5072 result = Qnil;
41beb8fc 5073 }
8ec8a5ec
GM
5074
5075 return result;
41beb8fc
RS
5076}
5077
5078DEFUN ("x-display-save-under", Fx_display_save_under,
c061c855 5079 Sx_display_save_under, 0, 1, 0,
7ee72033 5080 doc: /* Returns t if the X display DISPLAY supports the save-under feature.
c061c855
GM
5081The optional argument DISPLAY specifies which display to ask about.
5082DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5083If omitted or nil, that stands for the selected frame's display. */)
5084 (display)
08a90d6a 5085 Lisp_Object display;
41beb8fc 5086{
08a90d6a 5087 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5088
b9dc4443 5089 if (DoesSaveUnders (dpyinfo->screen) == True)
41beb8fc
RS
5090 return Qt;
5091 else
5092 return Qnil;
5093}
5094\f
b9dc4443 5095int
55caf99c
RS
5096x_pixel_width (f)
5097 register struct frame *f;
01f1ba30 5098{
55caf99c 5099 return PIXEL_WIDTH (f);
01f1ba30
JB
5100}
5101
b9dc4443 5102int
55caf99c
RS
5103x_pixel_height (f)
5104 register struct frame *f;
01f1ba30 5105{
55caf99c
RS
5106 return PIXEL_HEIGHT (f);
5107}
5108
b9dc4443 5109int
55caf99c
RS
5110x_char_width (f)
5111 register struct frame *f;
5112{
7556890b 5113 return FONT_WIDTH (f->output_data.x->font);
55caf99c
RS
5114}
5115
b9dc4443 5116int
55caf99c
RS
5117x_char_height (f)
5118 register struct frame *f;
5119{
7556890b 5120 return f->output_data.x->line_height;
01f1ba30 5121}
b9dc4443
RS
5122
5123int
f03f2489
RS
5124x_screen_planes (f)
5125 register struct frame *f;
b9dc4443 5126{
f03f2489 5127 return FRAME_X_DISPLAY_INFO (f)->n_planes;
b9dc4443 5128}
01f1ba30 5129
a6ad00c0
GM
5130
5131\f
5132/************************************************************************
5133 X Displays
5134 ************************************************************************/
5135
01f1ba30 5136\f
a6ad00c0
GM
5137/* Mapping visual names to visuals. */
5138
5139static struct visual_class
5140{
5141 char *name;
5142 int class;
5143}
5144visual_classes[] =
5145{
5146 {"StaticGray", StaticGray},
5147 {"GrayScale", GrayScale},
5148 {"StaticColor", StaticColor},
5149 {"PseudoColor", PseudoColor},
5150 {"TrueColor", TrueColor},
5151 {"DirectColor", DirectColor},
9908a324 5152 {NULL, 0}
a6ad00c0
GM
5153};
5154
5155
404daac1 5156#ifndef HAVE_XSCREENNUMBEROFSCREEN
a6ad00c0
GM
5157
5158/* Value is the screen number of screen SCR. This is a substitute for
5159 the X function with the same name when that doesn't exist. */
5160
404daac1
RS
5161int
5162XScreenNumberOfScreen (scr)
5163 register Screen *scr;
5164{
a6ad00c0
GM
5165 Display *dpy = scr->display;
5166 int i;
3df34fdb 5167
a6ad00c0 5168 for (i = 0; i < dpy->nscreens; ++i)
fbd5ceb2 5169 if (scr == dpy->screens + i)
a6ad00c0 5170 break;
404daac1 5171
a6ad00c0 5172 return i;
404daac1 5173}
a6ad00c0 5174
404daac1
RS
5175#endif /* not HAVE_XSCREENNUMBEROFSCREEN */
5176
01f1ba30 5177
a6ad00c0
GM
5178/* Select the visual that should be used on display DPYINFO. Set
5179 members of DPYINFO appropriately. Called from x_term_init. */
fe24a618 5180
a6ad00c0
GM
5181void
5182select_visual (dpyinfo)
5183 struct x_display_info *dpyinfo;
5184{
5185 Display *dpy = dpyinfo->display;
5186 Screen *screen = dpyinfo->screen;
5187 Lisp_Object value;
fe24a618 5188
a6ad00c0
GM
5189 /* See if a visual is specified. */
5190 value = display_x_get_resource (dpyinfo,
5191 build_string ("visualClass"),
5192 build_string ("VisualClass"),
5193 Qnil, Qnil);
5194 if (STRINGP (value))
5195 {
5196 /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
5197 of `PseudoColor', `TrueColor' etc. and DEPTH is the color
5198 depth, a decimal number. NAME is compared with case ignored. */
5199 char *s = (char *) alloca (STRING_BYTES (XSTRING (value)) + 1);
5200 char *dash;
5201 int i, class = -1;
5202 XVisualInfo vinfo;
5203
5204 strcpy (s, XSTRING (value)->data);
5205 dash = index (s, '-');
5206 if (dash)
5207 {
5208 dpyinfo->n_planes = atoi (dash + 1);
5209 *dash = '\0';
5210 }
5211 else
5212 /* We won't find a matching visual with depth 0, so that
5213 an error will be printed below. */
5214 dpyinfo->n_planes = 0;
f0614854 5215
a6ad00c0
GM
5216 /* Determine the visual class. */
5217 for (i = 0; visual_classes[i].name; ++i)
5218 if (xstricmp (s, visual_classes[i].name) == 0)
5219 {
5220 class = visual_classes[i].class;
5221 break;
5222 }
01f1ba30 5223
a6ad00c0
GM
5224 /* Look up a matching visual for the specified class. */
5225 if (class == -1
5226 || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
5227 dpyinfo->n_planes, class, &vinfo))
5228 fatal ("Invalid visual specification `%s'", XSTRING (value)->data);
5229
5230 dpyinfo->visual = vinfo.visual;
5231 }
01f1ba30
JB
5232 else
5233 {
a6ad00c0
GM
5234 int n_visuals;
5235 XVisualInfo *vinfo, vinfo_template;
5236
5237 dpyinfo->visual = DefaultVisualOfScreen (screen);
5238
5239#ifdef HAVE_X11R4
5240 vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
5241#else
5242 vinfo_template.visualid = dpyinfo->visual->visualid;
5243#endif
5244 vinfo_template.screen = XScreenNumberOfScreen (screen);
5245 vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
5246 &vinfo_template, &n_visuals);
5247 if (n_visuals != 1)
5248 fatal ("Can't get proper X visual info");
5249
94ac875b 5250 dpyinfo->n_planes = vinfo->depth;
a6ad00c0
GM
5251 XFree ((char *) vinfo);
5252 }
01f1ba30 5253}
01f1ba30 5254
a6ad00c0 5255
b9dc4443
RS
5256/* Return the X display structure for the display named NAME.
5257 Open a new connection if necessary. */
5258
5259struct x_display_info *
5260x_display_info_for_name (name)
5261 Lisp_Object name;
5262{
08a90d6a 5263 Lisp_Object names;
b9dc4443
RS
5264 struct x_display_info *dpyinfo;
5265
b7826503 5266 CHECK_STRING (name);
b9dc4443 5267
806048df
RS
5268 if (! EQ (Vwindow_system, intern ("x")))
5269 error ("Not using X Windows");
5270
08a90d6a
RS
5271 for (dpyinfo = x_display_list, names = x_display_name_list;
5272 dpyinfo;
8e713be6 5273 dpyinfo = dpyinfo->next, names = XCDR (names))
b9dc4443
RS
5274 {
5275 Lisp_Object tem;
8e713be6 5276 tem = Fstring_equal (XCAR (XCAR (names)), name);
08a90d6a 5277 if (!NILP (tem))
b9dc4443
RS
5278 return dpyinfo;
5279 }
5280
b7975ee4
KH
5281 /* Use this general default value to start with. */
5282 Vx_resource_name = Vinvocation_name;
5283
b9dc4443
RS
5284 validate_x_resource_name ();
5285
9b207e8e 5286 dpyinfo = x_term_init (name, (char *)0,
b7975ee4 5287 (char *) XSTRING (Vx_resource_name)->data);
b9dc4443 5288
08a90d6a 5289 if (dpyinfo == 0)
1b4ec1c8 5290 error ("Cannot connect to X server %s", XSTRING (name)->data);
08a90d6a 5291
b9dc4443
RS
5292 x_in_use = 1;
5293 XSETFASTINT (Vwindow_system_version, 11);
5294
5295 return dpyinfo;
5296}
5297
a6ad00c0 5298
01f1ba30 5299DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
c061c855 5300 1, 3, 0,
7ee72033 5301 doc: /* Open a connection to an X server.
c061c855
GM
5302DISPLAY is the name of the display to connect to.
5303Optional second arg XRM-STRING is a string of resources in xrdb format.
5304If the optional third arg MUST-SUCCEED is non-nil,
7ee72033
MB
5305terminate Emacs if we can't open the connection. */)
5306 (display, xrm_string, must_succeed)
08a90d6a 5307 Lisp_Object display, xrm_string, must_succeed;
01f1ba30 5308{
01f1ba30 5309 unsigned char *xrm_option;
b9dc4443 5310 struct x_display_info *dpyinfo;
01f1ba30 5311
b7826503 5312 CHECK_STRING (display);
d387c960 5313 if (! NILP (xrm_string))
b7826503 5314 CHECK_STRING (xrm_string);
01f1ba30 5315
806048df
RS
5316 if (! EQ (Vwindow_system, intern ("x")))
5317 error ("Not using X Windows");
5318
d387c960
JB
5319 if (! NILP (xrm_string))
5320 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
01f1ba30
JB
5321 else
5322 xrm_option = (unsigned char *) 0;
d387c960
JB
5323
5324 validate_x_resource_name ();
5325
e1b1bee8 5326 /* This is what opens the connection and sets x_current_display.
b9dc4443
RS
5327 This also initializes many symbols, such as those used for input. */
5328 dpyinfo = x_term_init (display, xrm_option,
b7975ee4 5329 (char *) XSTRING (Vx_resource_name)->data);
f1c16f36 5330
08a90d6a
RS
5331 if (dpyinfo == 0)
5332 {
5333 if (!NILP (must_succeed))
10ffbc14
GM
5334 fatal ("Cannot connect to X server %s.\n\
5335Check the DISPLAY environment variable or use `-d'.\n\
5336Also use the `xhost' program to verify that it is set to permit\n\
1b4ec1c8 5337connections from your machine.\n",
08a90d6a
RS
5338 XSTRING (display)->data);
5339 else
1b4ec1c8 5340 error ("Cannot connect to X server %s", XSTRING (display)->data);
08a90d6a
RS
5341 }
5342
b9dc4443 5343 x_in_use = 1;
01f1ba30 5344
b9dc4443 5345 XSETFASTINT (Vwindow_system_version, 11);
01f1ba30
JB
5346 return Qnil;
5347}
5348
08a90d6a
RS
5349DEFUN ("x-close-connection", Fx_close_connection,
5350 Sx_close_connection, 1, 1, 0,
7ee72033 5351 doc: /* Close the connection to DISPLAY's X server.
c061c855 5352For DISPLAY, specify either a frame or a display name (a string).
7ee72033
MB
5353If DISPLAY is nil, that stands for the selected frame's display. */)
5354 (display)
c061c855 5355 Lisp_Object display;
01f1ba30 5356{
08a90d6a 5357 struct x_display_info *dpyinfo = check_x_display_info (display);
08a90d6a 5358 int i;
3457bc6e 5359
08a90d6a
RS
5360 if (dpyinfo->reference_count > 0)
5361 error ("Display still has frames on it");
01f1ba30 5362
08a90d6a
RS
5363 BLOCK_INPUT;
5364 /* Free the fonts in the font table. */
5365 for (i = 0; i < dpyinfo->n_fonts; i++)
333b20bb
GM
5366 if (dpyinfo->font_table[i].name)
5367 {
6ecb43ce
KH
5368 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
5369 xfree (dpyinfo->font_table[i].full_name);
333b20bb 5370 xfree (dpyinfo->font_table[i].name);
333b20bb
GM
5371 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
5372 }
5373
08a90d6a
RS
5374 x_destroy_all_bitmaps (dpyinfo);
5375 XSetCloseDownMode (dpyinfo->display, DestroyAll);
82c90203
RS
5376
5377#ifdef USE_X_TOOLKIT
5378 XtCloseDisplay (dpyinfo->display);
5379#else
08a90d6a 5380 XCloseDisplay (dpyinfo->display);
82c90203 5381#endif
08a90d6a
RS
5382
5383 x_delete_display (dpyinfo);
5384 UNBLOCK_INPUT;
3457bc6e 5385
01f1ba30
JB
5386 return Qnil;
5387}
5388
08a90d6a 5389DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7ee72033
MB
5390 doc: /* Return the list of display names that Emacs has connections to. */)
5391 ()
08a90d6a
RS
5392{
5393 Lisp_Object tail, result;
5394
5395 result = Qnil;
8e713be6
KR
5396 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
5397 result = Fcons (XCAR (XCAR (tail)), result);
08a90d6a
RS
5398
5399 return result;
5400}
5401
5402DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7ee72033 5403 doc: /* If ON is non-nil, report X errors as soon as the erring request is made.
c061c855
GM
5404If ON is nil, allow buffering of requests.
5405Turning on synchronization prohibits the Xlib routines from buffering
5406requests and seriously degrades performance, but makes debugging much
5407easier.
5408The optional second argument DISPLAY specifies which display to act on.
5409DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5410If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
5411 (on, display)
08a90d6a 5412 Lisp_Object display, on;
01f1ba30 5413{
08a90d6a 5414 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5415
b9dc4443 5416 XSynchronize (dpyinfo->display, !EQ (on, Qnil));
01f1ba30
JB
5417
5418 return Qnil;
5419}
5420
b9dc4443 5421/* Wait for responses to all X commands issued so far for frame F. */
6b7b1820
RS
5422
5423void
b9dc4443
RS
5424x_sync (f)
5425 FRAME_PTR f;
6b7b1820 5426{
4e87f4d2 5427 BLOCK_INPUT;
b9dc4443 5428 XSync (FRAME_X_DISPLAY (f), False);
4e87f4d2 5429 UNBLOCK_INPUT;
6b7b1820 5430}
333b20bb 5431
01f1ba30 5432\f
333b20bb
GM
5433/***********************************************************************
5434 Image types
5435 ***********************************************************************/
f1c16f36 5436
333b20bb
GM
5437/* Value is the number of elements of vector VECTOR. */
5438
5439#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
5440
5441/* List of supported image types. Use define_image_type to add new
5442 types. Use lookup_image_type to find a type for a given symbol. */
5443
5444static struct image_type *image_types;
5445
333b20bb
GM
5446/* The symbol `image' which is the car of the lists used to represent
5447 images in Lisp. */
5448
5449extern Lisp_Object Qimage;
5450
5451/* The symbol `xbm' which is used as the type symbol for XBM images. */
5452
5453Lisp_Object Qxbm;
5454
5455/* Keywords. */
5456
0fe92f72 5457extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
5458extern Lisp_Object QCdata, QCtype;
5459Lisp_Object QCascent, QCmargin, QCrelief;
d2dc8167 5460Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4a8e312c 5461Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
333b20bb
GM
5462
5463/* Other symbols. */
5464
4a8e312c 5465Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
333b20bb
GM
5466
5467/* Time in seconds after which images should be removed from the cache
5468 if not displayed. */
5469
fcf431dc 5470Lisp_Object Vimage_cache_eviction_delay;
333b20bb
GM
5471
5472/* Function prototypes. */
5473
5474static void define_image_type P_ ((struct image_type *type));
5475static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
5476static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
5477static void x_laplace P_ ((struct frame *, struct image *));
4a8e312c 5478static void x_emboss P_ ((struct frame *, struct image *));
45158a91
GM
5479static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
5480 Lisp_Object));
333b20bb
GM
5481
5482
5483/* Define a new image type from TYPE. This adds a copy of TYPE to
5484 image_types and adds the symbol *TYPE->type to Vimage_types. */
5485
5486static void
5487define_image_type (type)
5488 struct image_type *type;
5489{
5490 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
5491 The initialized data segment is read-only. */
5492 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
5493 bcopy (type, p, sizeof *p);
5494 p->next = image_types;
5495 image_types = p;
5496 Vimage_types = Fcons (*p->type, Vimage_types);
5497}
5498
5499
5500/* Look up image type SYMBOL, and return a pointer to its image_type
5501 structure. Value is null if SYMBOL is not a known image type. */
5502
5503static INLINE struct image_type *
5504lookup_image_type (symbol)
5505 Lisp_Object symbol;
5506{
5507 struct image_type *type;
5508
5509 for (type = image_types; type; type = type->next)
5510 if (EQ (symbol, *type->type))
5511 break;
5512
5513 return type;
5514}
5515
5516
5517/* Value is non-zero if OBJECT is a valid Lisp image specification. A
5518 valid image specification is a list whose car is the symbol
5519 `image', and whose rest is a property list. The property list must
5520 contain a value for key `:type'. That value must be the name of a
5521 supported image type. The rest of the property list depends on the
5522 image type. */
5523
5524int
5525valid_image_p (object)
5526 Lisp_Object object;
5527{
5528 int valid_p = 0;
5529
5530 if (CONSP (object) && EQ (XCAR (object), Qimage))
5531 {
1783ffa2
GM
5532 Lisp_Object tem;
5533
5534 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
5535 if (EQ (XCAR (tem), QCtype))
5536 {
5537 tem = XCDR (tem);
5538 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
5539 {
5540 struct image_type *type;
5541 type = lookup_image_type (XCAR (tem));
5542 if (type)
5543 valid_p = type->valid_p (object);
5544 }
5545
5546 break;
5547 }
333b20bb
GM
5548 }
5549
5550 return valid_p;
5551}
5552
5553
7ab1745f
GM
5554/* Log error message with format string FORMAT and argument ARG.
5555 Signaling an error, e.g. when an image cannot be loaded, is not a
5556 good idea because this would interrupt redisplay, and the error
5557 message display would lead to another redisplay. This function
5558 therefore simply displays a message. */
333b20bb
GM
5559
5560static void
5561image_error (format, arg1, arg2)
5562 char *format;
5563 Lisp_Object arg1, arg2;
5564{
7ab1745f 5565 add_to_log (format, arg1, arg2);
333b20bb
GM
5566}
5567
5568
5569\f
5570/***********************************************************************
5571 Image specifications
5572 ***********************************************************************/
5573
5574enum image_value_type
5575{
5576 IMAGE_DONT_CHECK_VALUE_TYPE,
5577 IMAGE_STRING_VALUE,
6f1be3b9 5578 IMAGE_STRING_OR_NIL_VALUE,
333b20bb
GM
5579 IMAGE_SYMBOL_VALUE,
5580 IMAGE_POSITIVE_INTEGER_VALUE,
3ed61e75 5581 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
333b20bb 5582 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7c7ff7f5 5583 IMAGE_ASCENT_VALUE,
333b20bb
GM
5584 IMAGE_INTEGER_VALUE,
5585 IMAGE_FUNCTION_VALUE,
5586 IMAGE_NUMBER_VALUE,
5587 IMAGE_BOOL_VALUE
5588};
5589
5590/* Structure used when parsing image specifications. */
5591
5592struct image_keyword
5593{
5594 /* Name of keyword. */
5595 char *name;
5596
5597 /* The type of value allowed. */
5598 enum image_value_type type;
5599
5600 /* Non-zero means key must be present. */
5601 int mandatory_p;
5602
5603 /* Used to recognize duplicate keywords in a property list. */
5604 int count;
5605
5606 /* The value that was found. */
5607 Lisp_Object value;
5608};
5609
5610
bfd2209f
GM
5611static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
5612 int, Lisp_Object));
333b20bb
GM
5613static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
5614
5615
5616/* Parse image spec SPEC according to KEYWORDS. A valid image spec
5617 has the format (image KEYWORD VALUE ...). One of the keyword/
5618 value pairs must be `:type TYPE'. KEYWORDS is a vector of
5619 image_keywords structures of size NKEYWORDS describing other
bfd2209f 5620 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
333b20bb
GM
5621
5622static int
bfd2209f 5623parse_image_spec (spec, keywords, nkeywords, type)
333b20bb
GM
5624 Lisp_Object spec;
5625 struct image_keyword *keywords;
5626 int nkeywords;
5627 Lisp_Object type;
333b20bb
GM
5628{
5629 int i;
5630 Lisp_Object plist;
5631
5632 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
5633 return 0;
5634
5635 plist = XCDR (spec);
5636 while (CONSP (plist))
5637 {
5638 Lisp_Object key, value;
5639
5640 /* First element of a pair must be a symbol. */
5641 key = XCAR (plist);
5642 plist = XCDR (plist);
5643 if (!SYMBOLP (key))
5644 return 0;
5645
5646 /* There must follow a value. */
5647 if (!CONSP (plist))
5648 return 0;
5649 value = XCAR (plist);
5650 plist = XCDR (plist);
5651
5652 /* Find key in KEYWORDS. Error if not found. */
5653 for (i = 0; i < nkeywords; ++i)
5654 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
5655 break;
5656
5657 if (i == nkeywords)
bfd2209f 5658 continue;
333b20bb
GM
5659
5660 /* Record that we recognized the keyword. If a keywords
5661 was found more than once, it's an error. */
5662 keywords[i].value = value;
5663 ++keywords[i].count;
5664
5665 if (keywords[i].count > 1)
5666 return 0;
5667
5668 /* Check type of value against allowed type. */
5669 switch (keywords[i].type)
5670 {
5671 case IMAGE_STRING_VALUE:
5672 if (!STRINGP (value))
5673 return 0;
5674 break;
5675
6f1be3b9
GM
5676 case IMAGE_STRING_OR_NIL_VALUE:
5677 if (!STRINGP (value) && !NILP (value))
5678 return 0;
5679 break;
5680
333b20bb
GM
5681 case IMAGE_SYMBOL_VALUE:
5682 if (!SYMBOLP (value))
5683 return 0;
5684 break;
5685
5686 case IMAGE_POSITIVE_INTEGER_VALUE:
5687 if (!INTEGERP (value) || XINT (value) <= 0)
5688 return 0;
5689 break;
5690
3ed61e75
GM
5691 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
5692 if (INTEGERP (value) && XINT (value) >= 0)
5693 break;
5694 if (CONSP (value)
5695 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
5696 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
5697 break;
5698 return 0;
5699
7c7ff7f5
GM
5700 case IMAGE_ASCENT_VALUE:
5701 if (SYMBOLP (value) && EQ (value, Qcenter))
5702 break;
5703 else if (INTEGERP (value)
5704 && XINT (value) >= 0
5705 && XINT (value) <= 100)
5706 break;
5707 return 0;
5708
333b20bb
GM
5709 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
5710 if (!INTEGERP (value) || XINT (value) < 0)
5711 return 0;
5712 break;
5713
5714 case IMAGE_DONT_CHECK_VALUE_TYPE:
5715 break;
5716
5717 case IMAGE_FUNCTION_VALUE:
5718 value = indirect_function (value);
5719 if (SUBRP (value)
5720 || COMPILEDP (value)
5721 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
5722 break;
5723 return 0;
5724
5725 case IMAGE_NUMBER_VALUE:
5726 if (!INTEGERP (value) && !FLOATP (value))
5727 return 0;
5728 break;
5729
5730 case IMAGE_INTEGER_VALUE:
5731 if (!INTEGERP (value))
5732 return 0;
5733 break;
5734
5735 case IMAGE_BOOL_VALUE:
5736 if (!NILP (value) && !EQ (value, Qt))
5737 return 0;
5738 break;
5739
5740 default:
5741 abort ();
5742 break;
5743 }
5744
5745 if (EQ (key, QCtype) && !EQ (type, value))
5746 return 0;
5747 }
5748
5749 /* Check that all mandatory fields are present. */
5750 for (i = 0; i < nkeywords; ++i)
5751 if (keywords[i].mandatory_p && keywords[i].count == 0)
5752 return 0;
5753
5754 return NILP (plist);
5755}
5756
5757
5758/* Return the value of KEY in image specification SPEC. Value is nil
5759 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
5760 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
5761
5762static Lisp_Object
5763image_spec_value (spec, key, found)
5764 Lisp_Object spec, key;
5765 int *found;
5766{
5767 Lisp_Object tail;
5768
5769 xassert (valid_image_p (spec));
5770
5771 for (tail = XCDR (spec);
5772 CONSP (tail) && CONSP (XCDR (tail));
5773 tail = XCDR (XCDR (tail)))
5774 {
5775 if (EQ (XCAR (tail), key))
5776 {
5777 if (found)
5778 *found = 1;
5779 return XCAR (XCDR (tail));
5780 }
5781 }
5782
5783 if (found)
5784 *found = 0;
5785 return Qnil;
5786}
5787
5788
42677916 5789DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
7ee72033 5790 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
c061c855
GM
5791PIXELS non-nil means return the size in pixels, otherwise return the
5792size in canonical character units.
5793FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5794or omitted means use the selected frame. */)
5795 (spec, pixels, frame)
42677916
GM
5796 Lisp_Object spec, pixels, frame;
5797{
5798 Lisp_Object size;
5799
5800 size = Qnil;
5801 if (valid_image_p (spec))
5802 {
5803 struct frame *f = check_x_frame (frame);
83676598 5804 int id = lookup_image (f, spec);
42677916 5805 struct image *img = IMAGE_FROM_ID (f, id);
3ed61e75
GM
5806 int width = img->width + 2 * img->hmargin;
5807 int height = img->height + 2 * img->vmargin;
42677916
GM
5808
5809 if (NILP (pixels))
5810 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
5811 make_float ((double) height / CANON_Y_UNIT (f)));
5812 else
5813 size = Fcons (make_number (width), make_number (height));
5814 }
5815 else
5816 error ("Invalid image specification");
5817
5818 return size;
5819}
5820
333b20bb 5821
b243755a 5822DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
7ee72033 5823 doc: /* Return t if image SPEC has a mask bitmap.
c061c855 5824FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5825or omitted means use the selected frame. */)
5826 (spec, frame)
b243755a
GM
5827 Lisp_Object spec, frame;
5828{
5829 Lisp_Object mask;
5830
5831 mask = Qnil;
5832 if (valid_image_p (spec))
5833 {
5834 struct frame *f = check_x_frame (frame);
83676598 5835 int id = lookup_image (f, spec);
b243755a
GM
5836 struct image *img = IMAGE_FROM_ID (f, id);
5837 if (img->mask)
5838 mask = Qt;
5839 }
5840 else
5841 error ("Invalid image specification");
5842
5843 return mask;
5844}
5845
5846
333b20bb
GM
5847\f
5848/***********************************************************************
5849 Image type independent image structures
5850 ***********************************************************************/
5851
5852static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
5853static void free_image P_ ((struct frame *f, struct image *img));
5854
5855
5856/* Allocate and return a new image structure for image specification
5857 SPEC. SPEC has a hash value of HASH. */
5858
5859static struct image *
5860make_image (spec, hash)
5861 Lisp_Object spec;
5862 unsigned hash;
5863{
5864 struct image *img = (struct image *) xmalloc (sizeof *img);
5865
5866 xassert (valid_image_p (spec));
5867 bzero (img, sizeof *img);
5868 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
5869 xassert (img->type != NULL);
5870 img->spec = spec;
5871 img->data.lisp_val = Qnil;
5872 img->ascent = DEFAULT_IMAGE_ASCENT;
5873 img->hash = hash;
5874 return img;
5875}
5876
5877
5878/* Free image IMG which was used on frame F, including its resources. */
5879
5880static void
5881free_image (f, img)
5882 struct frame *f;
5883 struct image *img;
5884{
5885 if (img)
5886 {
5887 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5888
5889 /* Remove IMG from the hash table of its cache. */
5890 if (img->prev)
5891 img->prev->next = img->next;
5892 else
5893 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
5894
5895 if (img->next)
5896 img->next->prev = img->prev;
5897
5898 c->images[img->id] = NULL;
5899
5900 /* Free resources, then free IMG. */
5901 img->type->free (f, img);
5902 xfree (img);
5903 }
5904}
5905
5906
5907/* Prepare image IMG for display on frame F. Must be called before
5908 drawing an image. */
5909
5910void
5911prepare_image_for_display (f, img)
5912 struct frame *f;
5913 struct image *img;
5914{
5915 EMACS_TIME t;
5916
5917 /* We're about to display IMG, so set its timestamp to `now'. */
5918 EMACS_GET_TIME (t);
5919 img->timestamp = EMACS_SECS (t);
5920
5921 /* If IMG doesn't have a pixmap yet, load it now, using the image
5922 type dependent loader function. */
dd00328a 5923 if (img->pixmap == None && !img->load_failed_p)
209061be 5924 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
5925}
5926
5927
7c7ff7f5
GM
5928/* Value is the number of pixels for the ascent of image IMG when
5929 drawn in face FACE. */
5930
5931int
5932image_ascent (img, face)
5933 struct image *img;
5934 struct face *face;
5935{
3ed61e75 5936 int height = img->height + img->vmargin;
7c7ff7f5
GM
5937 int ascent;
5938
5939 if (img->ascent == CENTERED_IMAGE_ASCENT)
5940 {
5941 if (face->font)
3694cb3f
MB
5942 /* This expression is arranged so that if the image can't be
5943 exactly centered, it will be moved slightly up. This is
5944 because a typical font is `top-heavy' (due to the presence
5945 uppercase letters), so the image placement should err towards
5946 being top-heavy too. It also just generally looks better. */
5947 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
7c7ff7f5
GM
5948 else
5949 ascent = height / 2;
5950 }
5951 else
5952 ascent = height * img->ascent / 100.0;
5953
5954 return ascent;
5955}
5956
f20a3b7a
MB
5957\f
5958/* Image background colors. */
5959
5960static unsigned long
5961four_corners_best (ximg, width, height)
5962 XImage *ximg;
5963 unsigned long width, height;
5964{
b350c2e5
GM
5965 unsigned long corners[4], best;
5966 int i, best_count;
f20a3b7a 5967
b350c2e5
GM
5968 /* Get the colors at the corners of ximg. */
5969 corners[0] = XGetPixel (ximg, 0, 0);
5970 corners[1] = XGetPixel (ximg, width - 1, 0);
5971 corners[2] = XGetPixel (ximg, width - 1, height - 1);
5972 corners[3] = XGetPixel (ximg, 0, height - 1);
f20a3b7a 5973
b350c2e5
GM
5974 /* Choose the most frequently found color as background. */
5975 for (i = best_count = 0; i < 4; ++i)
5976 {
5977 int j, n;
f20a3b7a 5978
b350c2e5
GM
5979 for (j = n = 0; j < 4; ++j)
5980 if (corners[i] == corners[j])
5981 ++n;
f20a3b7a 5982
b350c2e5
GM
5983 if (n > best_count)
5984 best = corners[i], best_count = n;
5985 }
f20a3b7a 5986
b350c2e5 5987 return best;
f20a3b7a
MB
5988}
5989
5990/* Return the `background' field of IMG. If IMG doesn't have one yet,
5991 it is guessed heuristically. If non-zero, XIMG is an existing XImage
5992 object to use for the heuristic. */
5993
5994unsigned long
5995image_background (img, f, ximg)
5996 struct image *img;
5997 struct frame *f;
5998 XImage *ximg;
5999{
6000 if (! img->background_valid)
6001 /* IMG doesn't have a background yet, try to guess a reasonable value. */
6002 {
6003 int free_ximg = !ximg;
6004
6005 if (! ximg)
6006 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
6007 0, 0, img->width, img->height, ~0, ZPixmap);
6008
6009 img->background = four_corners_best (ximg, img->width, img->height);
6010
6011 if (free_ximg)
6012 XDestroyImage (ximg);
6013
6014 img->background_valid = 1;
6015 }
6016
6017 return img->background;
6018}
6019
6020/* Return the `background_transparent' field of IMG. If IMG doesn't
6021 have one yet, it is guessed heuristically. If non-zero, MASK is an
6022 existing XImage object to use for the heuristic. */
6023
6024int
6025image_background_transparent (img, f, mask)
6026 struct image *img;
6027 struct frame *f;
6028 XImage *mask;
6029{
6030 if (! img->background_transparent_valid)
6031 /* IMG doesn't have a background yet, try to guess a reasonable value. */
6032 {
6033 if (img->mask)
6034 {
6035 int free_mask = !mask;
6036
6037 if (! mask)
6038 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
6039 0, 0, img->width, img->height, ~0, ZPixmap);
6040
6041 img->background_transparent
6042 = !four_corners_best (mask, img->width, img->height);
6043
6044 if (free_mask)
6045 XDestroyImage (mask);
6046 }
6047 else
6048 img->background_transparent = 0;
6049
6050 img->background_transparent_valid = 1;
6051 }
6052
6053 return img->background_transparent;
6054}
7c7ff7f5 6055
333b20bb
GM
6056\f
6057/***********************************************************************
6058 Helper functions for X image types
6059 ***********************************************************************/
6060
dd00328a
GM
6061static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
6062 int, int));
333b20bb
GM
6063static void x_clear_image P_ ((struct frame *f, struct image *img));
6064static unsigned long x_alloc_image_color P_ ((struct frame *f,
6065 struct image *img,
6066 Lisp_Object color_name,
6067 unsigned long dflt));
6068
dd00328a
GM
6069
6070/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
6071 free the pixmap if any. MASK_P non-zero means clear the mask
6072 pixmap if any. COLORS_P non-zero means free colors allocated for
6073 the image, if any. */
333b20bb
GM
6074
6075static void
dd00328a 6076x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
333b20bb
GM
6077 struct frame *f;
6078 struct image *img;
dd00328a 6079 int pixmap_p, mask_p, colors_p;
333b20bb 6080{
dd00328a 6081 if (pixmap_p && img->pixmap)
333b20bb 6082 {
333b20bb 6083 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 6084 img->pixmap = None;
f20a3b7a 6085 img->background_valid = 0;
f4779de9
GM
6086 }
6087
dd00328a 6088 if (mask_p && img->mask)
f4779de9
GM
6089 {
6090 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 6091 img->mask = None;
f20a3b7a 6092 img->background_transparent_valid = 0;
333b20bb
GM
6093 }
6094
dd00328a 6095 if (colors_p && img->ncolors)
333b20bb 6096 {
462d5d40 6097 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
6098 xfree (img->colors);
6099 img->colors = NULL;
6100 img->ncolors = 0;
6101 }
dd00328a
GM
6102}
6103
6104/* Free X resources of image IMG which is used on frame F. */
6105
6106static void
6107x_clear_image (f, img)
6108 struct frame *f;
6109 struct image *img;
6110{
6111 BLOCK_INPUT;
6112 x_clear_image_1 (f, img, 1, 1, 1);
f4779de9 6113 UNBLOCK_INPUT;
333b20bb
GM
6114}
6115
6116
6117/* Allocate color COLOR_NAME for image IMG on frame F. If color
6118 cannot be allocated, use DFLT. Add a newly allocated color to
6119 IMG->colors, so that it can be freed again. Value is the pixel
6120 color. */
6121
6122static unsigned long
6123x_alloc_image_color (f, img, color_name, dflt)
6124 struct frame *f;
6125 struct image *img;
6126 Lisp_Object color_name;
6127 unsigned long dflt;
6128{
6129 XColor color;
6130 unsigned long result;
6131
6132 xassert (STRINGP (color_name));
6133
2d764c78 6134 if (x_defined_color (f, XSTRING (color_name)->data, &color, 1))
333b20bb
GM
6135 {
6136 /* This isn't called frequently so we get away with simply
6137 reallocating the color vector to the needed size, here. */
6138 ++img->ncolors;
6139 img->colors =
6140 (unsigned long *) xrealloc (img->colors,
6141 img->ncolors * sizeof *img->colors);
6142 img->colors[img->ncolors - 1] = color.pixel;
6143 result = color.pixel;
6144 }
6145 else
6146 result = dflt;
6147
6148 return result;
6149}
6150
6151
6152\f
6153/***********************************************************************
6154 Image Cache
6155 ***********************************************************************/
6156
6157static void cache_image P_ ((struct frame *f, struct image *img));
ad18ffb1 6158static void postprocess_image P_ ((struct frame *, struct image *));
333b20bb
GM
6159
6160
6161/* Return a new, initialized image cache that is allocated from the
6162 heap. Call free_image_cache to free an image cache. */
6163
6164struct image_cache *
6165make_image_cache ()
6166{
6167 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
6168 int size;
6169
6170 bzero (c, sizeof *c);
6171 c->size = 50;
6172 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
6173 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
6174 c->buckets = (struct image **) xmalloc (size);
6175 bzero (c->buckets, size);
6176 return c;
6177}
6178
6179
6180/* Free image cache of frame F. Be aware that X frames share images
6181 caches. */
6182
6183void
6184free_image_cache (f)
6185 struct frame *f;
6186{
6187 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6188 if (c)
6189 {
6190 int i;
6191
6192 /* Cache should not be referenced by any frame when freed. */
6193 xassert (c->refcount == 0);
6194
6195 for (i = 0; i < c->used; ++i)
6196 free_image (f, c->images[i]);
6197 xfree (c->images);
333b20bb 6198 xfree (c->buckets);
e3130015 6199 xfree (c);
333b20bb
GM
6200 FRAME_X_IMAGE_CACHE (f) = NULL;
6201 }
6202}
6203
6204
6205/* Clear image cache of frame F. FORCE_P non-zero means free all
6206 images. FORCE_P zero means clear only images that haven't been
6207 displayed for some time. Should be called from time to time to
6208 reduce the number of loaded images. If image-eviction-seconds is
6209 non-nil, this frees images in the cache which weren't displayed for
6210 at least that many seconds. */
6211
6212void
6213clear_image_cache (f, force_p)
6214 struct frame *f;
6215 int force_p;
6216{
6217 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6218
83676598 6219 if (c && INTEGERP (Vimage_cache_eviction_delay))
333b20bb
GM
6220 {
6221 EMACS_TIME t;
6222 unsigned long old;
f4779de9 6223 int i, nfreed;
333b20bb
GM
6224
6225 EMACS_GET_TIME (t);
fcf431dc 6226 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
f4779de9
GM
6227
6228 /* Block input so that we won't be interrupted by a SIGIO
6229 while being in an inconsistent state. */
6230 BLOCK_INPUT;
333b20bb 6231
f4779de9 6232 for (i = nfreed = 0; i < c->used; ++i)
333b20bb
GM
6233 {
6234 struct image *img = c->images[i];
6235 if (img != NULL
f4779de9 6236 && (force_p || img->timestamp < old))
333b20bb
GM
6237 {
6238 free_image (f, img);
f4779de9 6239 ++nfreed;
333b20bb
GM
6240 }
6241 }
6242
6243 /* We may be clearing the image cache because, for example,
6244 Emacs was iconified for a longer period of time. In that
6245 case, current matrices may still contain references to
6246 images freed above. So, clear these matrices. */
f4779de9 6247 if (nfreed)
333b20bb 6248 {
f4779de9
GM
6249 Lisp_Object tail, frame;
6250
6251 FOR_EACH_FRAME (tail, frame)
6252 {
6253 struct frame *f = XFRAME (frame);
6254 if (FRAME_X_P (f)
6255 && FRAME_X_IMAGE_CACHE (f) == c)
83676598 6256 clear_current_matrices (f);
f4779de9
GM
6257 }
6258
333b20bb
GM
6259 ++windows_or_buffers_changed;
6260 }
f4779de9
GM
6261
6262 UNBLOCK_INPUT;
333b20bb
GM
6263 }
6264}
6265
6266
6267DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6268 0, 1, 0,
7ee72033 6269 doc: /* Clear the image cache of FRAME.
c061c855 6270FRAME nil or omitted means use the selected frame.
7ee72033
MB
6271FRAME t means clear the image caches of all frames. */)
6272 (frame)
333b20bb
GM
6273 Lisp_Object frame;
6274{
6275 if (EQ (frame, Qt))
6276 {
6277 Lisp_Object tail;
6278
6279 FOR_EACH_FRAME (tail, frame)
6280 if (FRAME_X_P (XFRAME (frame)))
6281 clear_image_cache (XFRAME (frame), 1);
6282 }
6283 else
6284 clear_image_cache (check_x_frame (frame), 1);
6285
6286 return Qnil;
6287}
6288
6289
ad18ffb1
GM
6290/* Compute masks and transform image IMG on frame F, as specified
6291 by the image's specification, */
6292
6293static void
6294postprocess_image (f, img)
6295 struct frame *f;
6296 struct image *img;
6297{
6298 /* Manipulation of the image's mask. */
6299 if (img->pixmap)
6300 {
6301 Lisp_Object conversion, spec;
6302 Lisp_Object mask;
6303
6304 spec = img->spec;
6305
6306 /* `:heuristic-mask t'
6307 `:mask heuristic'
6308 means build a mask heuristically.
6309 `:heuristic-mask (R G B)'
6310 `:mask (heuristic (R G B))'
6311 means build a mask from color (R G B) in the
6312 image.
6313 `:mask nil'
6314 means remove a mask, if any. */
6315
6316 mask = image_spec_value (spec, QCheuristic_mask, NULL);
6317 if (!NILP (mask))
6318 x_build_heuristic_mask (f, img, mask);
6319 else
6320 {
6321 int found_p;
6322
6323 mask = image_spec_value (spec, QCmask, &found_p);
6324
6325 if (EQ (mask, Qheuristic))
6326 x_build_heuristic_mask (f, img, Qt);
6327 else if (CONSP (mask)
6328 && EQ (XCAR (mask), Qheuristic))
6329 {
6330 if (CONSP (XCDR (mask)))
6331 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
6332 else
6333 x_build_heuristic_mask (f, img, XCDR (mask));
6334 }
6335 else if (NILP (mask) && found_p && img->mask)
6336 {
6337 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6338 img->mask = None;
6339 }
6340 }
6341
6342
6343 /* Should we apply an image transformation algorithm? */
6344 conversion = image_spec_value (spec, QCconversion, NULL);
6345 if (EQ (conversion, Qdisabled))
6346 x_disable_image (f, img);
6347 else if (EQ (conversion, Qlaplace))
6348 x_laplace (f, img);
6349 else if (EQ (conversion, Qemboss))
6350 x_emboss (f, img);
6351 else if (CONSP (conversion)
6352 && EQ (XCAR (conversion), Qedge_detection))
6353 {
6354 Lisp_Object tem;
6355 tem = XCDR (conversion);
6356 if (CONSP (tem))
6357 x_edge_detection (f, img,
6358 Fplist_get (tem, QCmatrix),
6359 Fplist_get (tem, QCcolor_adjustment));
6360 }
6361 }
6362}
6363
6364
333b20bb 6365/* Return the id of image with Lisp specification SPEC on frame F.
83676598 6366 SPEC must be a valid Lisp image specification (see valid_image_p). */
333b20bb
GM
6367
6368int
83676598 6369lookup_image (f, spec)
333b20bb
GM
6370 struct frame *f;
6371 Lisp_Object spec;
6372{
6373 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6374 struct image *img;
6375 int i;
6376 unsigned hash;
6377 struct gcpro gcpro1;
4f7ca1f1 6378 EMACS_TIME now;
333b20bb
GM
6379
6380 /* F must be a window-system frame, and SPEC must be a valid image
6381 specification. */
6382 xassert (FRAME_WINDOW_P (f));
6383 xassert (valid_image_p (spec));
6384
6385 GCPRO1 (spec);
6386
6387 /* Look up SPEC in the hash table of the image cache. */
6388 hash = sxhash (spec, 0);
6389 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6390
6391 for (img = c->buckets[i]; img; img = img->next)
6392 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6393 break;
6394
6395 /* If not found, create a new image and cache it. */
6396 if (img == NULL)
6397 {
ad18ffb1
GM
6398 extern Lisp_Object Qpostscript;
6399
28c7826c 6400 BLOCK_INPUT;
333b20bb
GM
6401 img = make_image (spec, hash);
6402 cache_image (f, img);
83676598 6403 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
6404
6405 /* If we can't load the image, and we don't have a width and
6406 height, use some arbitrary width and height so that we can
6407 draw a rectangle for it. */
83676598 6408 if (img->load_failed_p)
333b20bb
GM
6409 {
6410 Lisp_Object value;
6411
6412 value = image_spec_value (spec, QCwidth, NULL);
6413 img->width = (INTEGERP (value)
6414 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6415 value = image_spec_value (spec, QCheight, NULL);
6416 img->height = (INTEGERP (value)
6417 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6418 }
6419 else
6420 {
6421 /* Handle image type independent image attributes
f20a3b7a
MB
6422 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
6423 `:background COLOR'. */
6424 Lisp_Object ascent, margin, relief, bg;
333b20bb
GM
6425
6426 ascent = image_spec_value (spec, QCascent, NULL);
6427 if (INTEGERP (ascent))
6428 img->ascent = XFASTINT (ascent);
7c7ff7f5
GM
6429 else if (EQ (ascent, Qcenter))
6430 img->ascent = CENTERED_IMAGE_ASCENT;
333b20bb
GM
6431
6432 margin = image_spec_value (spec, QCmargin, NULL);
6433 if (INTEGERP (margin) && XINT (margin) >= 0)
3ed61e75
GM
6434 img->vmargin = img->hmargin = XFASTINT (margin);
6435 else if (CONSP (margin) && INTEGERP (XCAR (margin))
6436 && INTEGERP (XCDR (margin)))
6437 {
6438 if (XINT (XCAR (margin)) > 0)
6439 img->hmargin = XFASTINT (XCAR (margin));
6440 if (XINT (XCDR (margin)) > 0)
6441 img->vmargin = XFASTINT (XCDR (margin));
6442 }
333b20bb
GM
6443
6444 relief = image_spec_value (spec, QCrelief, NULL);
6445 if (INTEGERP (relief))
6446 {
6447 img->relief = XINT (relief);
3ed61e75
GM
6448 img->hmargin += abs (img->relief);
6449 img->vmargin += abs (img->relief);
333b20bb
GM
6450 }
6451
f20a3b7a
MB
6452 if (! img->background_valid)
6453 {
6454 bg = image_spec_value (img->spec, QCbackground, NULL);
6455 if (!NILP (bg))
6456 {
6457 img->background
6458 = x_alloc_image_color (f, img, bg,
6459 FRAME_BACKGROUND_PIXEL (f));
6460 img->background_valid = 1;
6461 }
6462 }
6463
ad18ffb1
GM
6464 /* Do image transformations and compute masks, unless we
6465 don't have the image yet. */
6466 if (!EQ (*img->type->type, Qpostscript))
6467 postprocess_image (f, img);
333b20bb 6468 }
dd00328a 6469
28c7826c
GM
6470 UNBLOCK_INPUT;
6471 xassert (!interrupt_input_blocked);
333b20bb
GM
6472 }
6473
4f7ca1f1
GM
6474 /* We're using IMG, so set its timestamp to `now'. */
6475 EMACS_GET_TIME (now);
6476 img->timestamp = EMACS_SECS (now);
6477
333b20bb
GM
6478 UNGCPRO;
6479
6480 /* Value is the image id. */
6481 return img->id;
6482}
6483
6484
6485/* Cache image IMG in the image cache of frame F. */
6486
6487static void
6488cache_image (f, img)
6489 struct frame *f;
6490 struct image *img;
6491{
6492 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6493 int i;
6494
6495 /* Find a free slot in c->images. */
6496 for (i = 0; i < c->used; ++i)
6497 if (c->images[i] == NULL)
6498 break;
6499
6500 /* If no free slot found, maybe enlarge c->images. */
6501 if (i == c->used && c->used == c->size)
6502 {
6503 c->size *= 2;
6504 c->images = (struct image **) xrealloc (c->images,
6505 c->size * sizeof *c->images);
6506 }
6507
6508 /* Add IMG to c->images, and assign IMG an id. */
6509 c->images[i] = img;
6510 img->id = i;
6511 if (i == c->used)
6512 ++c->used;
6513
6514 /* Add IMG to the cache's hash table. */
6515 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6516 img->next = c->buckets[i];
6517 if (img->next)
6518 img->next->prev = img;
6519 img->prev = NULL;
6520 c->buckets[i] = img;
6521}
6522
6523
6524/* Call FN on every image in the image cache of frame F. Used to mark
6525 Lisp Objects in the image cache. */
6526
6527void
6528forall_images_in_image_cache (f, fn)
6529 struct frame *f;
6530 void (*fn) P_ ((struct image *img));
6531{
6532 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6533 {
6534 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6535 if (c)
6536 {
6537 int i;
6538 for (i = 0; i < c->used; ++i)
6539 if (c->images[i])
6540 fn (c->images[i]);
6541 }
6542 }
6543}
6544
6545
6546\f
6547/***********************************************************************
6548 X support code
6549 ***********************************************************************/
6550
45158a91
GM
6551static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
6552 XImage **, Pixmap *));
333b20bb
GM
6553static void x_destroy_x_image P_ ((XImage *));
6554static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6555
6556
6557/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6558 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6559 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6560 via xmalloc. Print error messages via image_error if an error
45158a91 6561 occurs. Value is non-zero if successful. */
333b20bb
GM
6562
6563static int
45158a91 6564x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
333b20bb 6565 struct frame *f;
333b20bb
GM
6566 int width, height, depth;
6567 XImage **ximg;
6568 Pixmap *pixmap;
6569{
6570 Display *display = FRAME_X_DISPLAY (f);
6571 Screen *screen = FRAME_X_SCREEN (f);
6572 Window window = FRAME_X_WINDOW (f);
6573
6574 xassert (interrupt_input_blocked);
6575
6576 if (depth <= 0)
6577 depth = DefaultDepthOfScreen (screen);
6578 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6579 depth, ZPixmap, 0, NULL, width, height,
6580 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6581 if (*ximg == NULL)
6582 {
45158a91 6583 image_error ("Unable to allocate X image", Qnil, Qnil);
333b20bb
GM
6584 return 0;
6585 }
6586
6587 /* Allocate image raster. */
6588 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6589
6590 /* Allocate a pixmap of the same size. */
6591 *pixmap = XCreatePixmap (display, window, width, height, depth);
dd00328a 6592 if (*pixmap == None)
333b20bb
GM
6593 {
6594 x_destroy_x_image (*ximg);
6595 *ximg = NULL;
45158a91 6596 image_error ("Unable to create X pixmap", Qnil, Qnil);
333b20bb
GM
6597 return 0;
6598 }
6599
6600 return 1;
6601}
6602
6603
6604/* Destroy XImage XIMG. Free XIMG->data. */
6605
6606static void
6607x_destroy_x_image (ximg)
6608 XImage *ximg;
6609{
6610 xassert (interrupt_input_blocked);
6611 if (ximg)
6612 {
6613 xfree (ximg->data);
6614 ximg->data = NULL;
6615 XDestroyImage (ximg);
6616 }
6617}
6618
6619
6620/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6621 are width and height of both the image and pixmap. */
6622
ea6b19ca 6623static void
333b20bb
GM
6624x_put_x_image (f, ximg, pixmap, width, height)
6625 struct frame *f;
6626 XImage *ximg;
6627 Pixmap pixmap;
6628{
6629 GC gc;
6630
6631 xassert (interrupt_input_blocked);
6632 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6633 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6634 XFreeGC (FRAME_X_DISPLAY (f), gc);
6635}
6636
6637
6638\f
6639/***********************************************************************
5be6c3b0 6640 File Handling
333b20bb
GM
6641 ***********************************************************************/
6642
6643static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5be6c3b0
GM
6644static char *slurp_file P_ ((char *, int *));
6645
333b20bb
GM
6646
6647/* Find image file FILE. Look in data-directory, then
6648 x-bitmap-file-path. Value is the full name of the file found, or
6649 nil if not found. */
6650
6651static Lisp_Object
6652x_find_image_file (file)
6653 Lisp_Object file;
6654{
6655 Lisp_Object file_found, search_path;
6656 struct gcpro gcpro1, gcpro2;
6657 int fd;
6658
6659 file_found = Qnil;
6660 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6661 GCPRO2 (file_found, search_path);
6662
6663 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 6664 fd = openp (search_path, file, Qnil, &file_found, 0);
333b20bb 6665
939d6465 6666 if (fd == -1)
333b20bb
GM
6667 file_found = Qnil;
6668 else
6669 close (fd);
6670
6671 UNGCPRO;
6672 return file_found;
6673}
6674
6675
5be6c3b0
GM
6676/* Read FILE into memory. Value is a pointer to a buffer allocated
6677 with xmalloc holding FILE's contents. Value is null if an error
b243755a 6678 occurred. *SIZE is set to the size of the file. */
5be6c3b0
GM
6679
6680static char *
6681slurp_file (file, size)
6682 char *file;
6683 int *size;
6684{
6685 FILE *fp = NULL;
6686 char *buf = NULL;
6687 struct stat st;
6688
6689 if (stat (file, &st) == 0
6690 && (fp = fopen (file, "r")) != NULL
6691 && (buf = (char *) xmalloc (st.st_size),
6692 fread (buf, 1, st.st_size, fp) == st.st_size))
6693 {
6694 *size = st.st_size;
6695 fclose (fp);
6696 }
6697 else
6698 {
6699 if (fp)
6700 fclose (fp);
6701 if (buf)
6702 {
6703 xfree (buf);
6704 buf = NULL;
6705 }
6706 }
6707
6708 return buf;
6709}
6710
6711
333b20bb
GM
6712\f
6713/***********************************************************************
6714 XBM images
6715 ***********************************************************************/
6716
5be6c3b0 6717static int xbm_scan P_ ((char **, char *, char *, int *));
333b20bb 6718static int xbm_load P_ ((struct frame *f, struct image *img));
5be6c3b0
GM
6719static int xbm_load_image P_ ((struct frame *f, struct image *img,
6720 char *, char *));
333b20bb 6721static int xbm_image_p P_ ((Lisp_Object object));
5be6c3b0
GM
6722static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
6723 unsigned char **));
6724static int xbm_file_p P_ ((Lisp_Object));
333b20bb
GM
6725
6726
6727/* Indices of image specification fields in xbm_format, below. */
6728
6729enum xbm_keyword_index
6730{
6731 XBM_TYPE,
6732 XBM_FILE,
6733 XBM_WIDTH,
6734 XBM_HEIGHT,
6735 XBM_DATA,
6736 XBM_FOREGROUND,
6737 XBM_BACKGROUND,
6738 XBM_ASCENT,
6739 XBM_MARGIN,
6740 XBM_RELIEF,
6741 XBM_ALGORITHM,
6742 XBM_HEURISTIC_MASK,
4a8e312c 6743 XBM_MASK,
333b20bb
GM
6744 XBM_LAST
6745};
6746
6747/* Vector of image_keyword structures describing the format
6748 of valid XBM image specifications. */
6749
6750static struct image_keyword xbm_format[XBM_LAST] =
6751{
6752 {":type", IMAGE_SYMBOL_VALUE, 1},
6753 {":file", IMAGE_STRING_VALUE, 0},
6754 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6755 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6756 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
6757 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6758 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
7c7ff7f5 6759 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 6760 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 6761 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 6762 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
6763 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6764 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
6765};
6766
6767/* Structure describing the image type XBM. */
6768
6769static struct image_type xbm_type =
6770{
6771 &Qxbm,
6772 xbm_image_p,
6773 xbm_load,
6774 x_clear_image,
6775 NULL
6776};
6777
6778/* Tokens returned from xbm_scan. */
6779
6780enum xbm_token
6781{
6782 XBM_TK_IDENT = 256,
6783 XBM_TK_NUMBER
6784};
6785
6786
6787/* Return non-zero if OBJECT is a valid XBM-type image specification.
6788 A valid specification is a list starting with the symbol `image'
6789 The rest of the list is a property list which must contain an
6790 entry `:type xbm..
6791
6792 If the specification specifies a file to load, it must contain
6793 an entry `:file FILENAME' where FILENAME is a string.
6794
6795 If the specification is for a bitmap loaded from memory it must
6796 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6797 WIDTH and HEIGHT are integers > 0. DATA may be:
6798
6799 1. a string large enough to hold the bitmap data, i.e. it must
6800 have a size >= (WIDTH + 7) / 8 * HEIGHT
6801
6802 2. a bool-vector of size >= WIDTH * HEIGHT
6803
6804 3. a vector of strings or bool-vectors, one for each line of the
6805 bitmap.
6806
5be6c3b0
GM
6807 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
6808 may not be specified in this case because they are defined in the
6809 XBM file.
6810
333b20bb
GM
6811 Both the file and data forms may contain the additional entries
6812 `:background COLOR' and `:foreground COLOR'. If not present,
6813 foreground and background of the frame on which the image is
e3130015 6814 displayed is used. */
333b20bb
GM
6815
6816static int
6817xbm_image_p (object)
6818 Lisp_Object object;
6819{
6820 struct image_keyword kw[XBM_LAST];
6821
6822 bcopy (xbm_format, kw, sizeof kw);
bfd2209f 6823 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
333b20bb
GM
6824 return 0;
6825
6826 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6827
6828 if (kw[XBM_FILE].count)
6829 {
6830 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6831 return 0;
6832 }
5be6c3b0
GM
6833 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
6834 {
6835 /* In-memory XBM file. */
6836 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
6837 return 0;
6838 }
333b20bb
GM
6839 else
6840 {
6841 Lisp_Object data;
6842 int width, height;
6843
6844 /* Entries for `:width', `:height' and `:data' must be present. */
6845 if (!kw[XBM_WIDTH].count
6846 || !kw[XBM_HEIGHT].count
6847 || !kw[XBM_DATA].count)
6848 return 0;
6849
6850 data = kw[XBM_DATA].value;
6851 width = XFASTINT (kw[XBM_WIDTH].value);
6852 height = XFASTINT (kw[XBM_HEIGHT].value);
6853
6854 /* Check type of data, and width and height against contents of
6855 data. */
6856 if (VECTORP (data))
6857 {
6858 int i;
6859
6860 /* Number of elements of the vector must be >= height. */
6861 if (XVECTOR (data)->size < height)
6862 return 0;
6863
6864 /* Each string or bool-vector in data must be large enough
6865 for one line of the image. */
6866 for (i = 0; i < height; ++i)
6867 {
6868 Lisp_Object elt = XVECTOR (data)->contents[i];
6869
6870 if (STRINGP (elt))
6871 {
6872 if (XSTRING (elt)->size
6873 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6874 return 0;
6875 }
6876 else if (BOOL_VECTOR_P (elt))
6877 {
6878 if (XBOOL_VECTOR (elt)->size < width)
6879 return 0;
6880 }
6881 else
6882 return 0;
6883 }
6884 }
6885 else if (STRINGP (data))
6886 {
6887 if (XSTRING (data)->size
6888 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6889 return 0;
6890 }
6891 else if (BOOL_VECTOR_P (data))
6892 {
6893 if (XBOOL_VECTOR (data)->size < width * height)
6894 return 0;
6895 }
6896 else
6897 return 0;
6898 }
6899
333b20bb
GM
6900 return 1;
6901}
6902
6903
6904/* Scan a bitmap file. FP is the stream to read from. Value is
6905 either an enumerator from enum xbm_token, or a character for a
6906 single-character token, or 0 at end of file. If scanning an
6907 identifier, store the lexeme of the identifier in SVAL. If
6908 scanning a number, store its value in *IVAL. */
6909
6910static int
5be6c3b0
GM
6911xbm_scan (s, end, sval, ival)
6912 char **s, *end;
333b20bb
GM
6913 char *sval;
6914 int *ival;
6915{
6916 int c;
0a695da7
GM
6917
6918 loop:
333b20bb
GM
6919
6920 /* Skip white space. */
5be6c3b0 6921 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
6922 ;
6923
5be6c3b0 6924 if (*s >= end)
333b20bb
GM
6925 c = 0;
6926 else if (isdigit (c))
6927 {
6928 int value = 0, digit;
6929
5be6c3b0 6930 if (c == '0' && *s < end)
333b20bb 6931 {
5be6c3b0 6932 c = *(*s)++;
333b20bb
GM
6933 if (c == 'x' || c == 'X')
6934 {
5be6c3b0 6935 while (*s < end)
333b20bb 6936 {
5be6c3b0 6937 c = *(*s)++;
333b20bb
GM
6938 if (isdigit (c))
6939 digit = c - '0';
6940 else if (c >= 'a' && c <= 'f')
6941 digit = c - 'a' + 10;
6942 else if (c >= 'A' && c <= 'F')
6943 digit = c - 'A' + 10;
6944 else
6945 break;
6946 value = 16 * value + digit;
6947 }
6948 }
6949 else if (isdigit (c))
6950 {
6951 value = c - '0';
5be6c3b0
GM
6952 while (*s < end
6953 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6954 value = 8 * value + c - '0';
6955 }
6956 }
6957 else
6958 {
6959 value = c - '0';
5be6c3b0
GM
6960 while (*s < end
6961 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6962 value = 10 * value + c - '0';
6963 }
6964
5be6c3b0
GM
6965 if (*s < end)
6966 *s = *s - 1;
333b20bb
GM
6967 *ival = value;
6968 c = XBM_TK_NUMBER;
6969 }
6970 else if (isalpha (c) || c == '_')
6971 {
6972 *sval++ = c;
5be6c3b0
GM
6973 while (*s < end
6974 && (c = *(*s)++, (isalnum (c) || c == '_')))
333b20bb
GM
6975 *sval++ = c;
6976 *sval = 0;
5be6c3b0
GM
6977 if (*s < end)
6978 *s = *s - 1;
333b20bb
GM
6979 c = XBM_TK_IDENT;
6980 }
0a695da7
GM
6981 else if (c == '/' && **s == '*')
6982 {
6983 /* C-style comment. */
6984 ++*s;
6985 while (**s && (**s != '*' || *(*s + 1) != '/'))
6986 ++*s;
6987 if (**s)
6988 {
6989 *s += 2;
6990 goto loop;
6991 }
6992 }
333b20bb
GM
6993
6994 return c;
6995}
6996
6997
6998/* Replacement for XReadBitmapFileData which isn't available under old
5be6c3b0
GM
6999 X versions. CONTENTS is a pointer to a buffer to parse; END is the
7000 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
7001 the image. Return in *DATA the bitmap data allocated with xmalloc.
7002 Value is non-zero if successful. DATA null means just test if
b243755a 7003 CONTENTS looks like an in-memory XBM file. */
333b20bb
GM
7004
7005static int
5be6c3b0
GM
7006xbm_read_bitmap_data (contents, end, width, height, data)
7007 char *contents, *end;
333b20bb
GM
7008 int *width, *height;
7009 unsigned char **data;
7010{
5be6c3b0 7011 char *s = contents;
333b20bb
GM
7012 char buffer[BUFSIZ];
7013 int padding_p = 0;
7014 int v10 = 0;
7015 int bytes_per_line, i, nbytes;
7016 unsigned char *p;
7017 int value;
7018 int LA1;
7019
7020#define match() \
5be6c3b0 7021 LA1 = xbm_scan (&s, end, buffer, &value)
333b20bb
GM
7022
7023#define expect(TOKEN) \
7024 if (LA1 != (TOKEN)) \
7025 goto failure; \
7026 else \
7027 match ()
7028
7029#define expect_ident(IDENT) \
7030 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
7031 match (); \
7032 else \
7033 goto failure
7034
333b20bb 7035 *width = *height = -1;
5be6c3b0
GM
7036 if (data)
7037 *data = NULL;
7038 LA1 = xbm_scan (&s, end, buffer, &value);
333b20bb
GM
7039
7040 /* Parse defines for width, height and hot-spots. */
7041 while (LA1 == '#')
7042 {
333b20bb
GM
7043 match ();
7044 expect_ident ("define");
7045 expect (XBM_TK_IDENT);
7046
7047 if (LA1 == XBM_TK_NUMBER);
7048 {
7049 char *p = strrchr (buffer, '_');
7050 p = p ? p + 1 : buffer;
7051 if (strcmp (p, "width") == 0)
7052 *width = value;
7053 else if (strcmp (p, "height") == 0)
7054 *height = value;
7055 }
7056 expect (XBM_TK_NUMBER);
7057 }
7058
7059 if (*width < 0 || *height < 0)
7060 goto failure;
5be6c3b0
GM
7061 else if (data == NULL)
7062 goto success;
333b20bb
GM
7063
7064 /* Parse bits. Must start with `static'. */
7065 expect_ident ("static");
7066 if (LA1 == XBM_TK_IDENT)
7067 {
7068 if (strcmp (buffer, "unsigned") == 0)
7069 {
7070 match ();
7071 expect_ident ("char");
7072 }
7073 else if (strcmp (buffer, "short") == 0)
7074 {
7075 match ();
7076 v10 = 1;
7077 if (*width % 16 && *width % 16 < 9)
7078 padding_p = 1;
7079 }
7080 else if (strcmp (buffer, "char") == 0)
7081 match ();
7082 else
7083 goto failure;
7084 }
7085 else
7086 goto failure;
7087
7088 expect (XBM_TK_IDENT);
7089 expect ('[');
7090 expect (']');
7091 expect ('=');
7092 expect ('{');
7093
7094 bytes_per_line = (*width + 7) / 8 + padding_p;
7095 nbytes = bytes_per_line * *height;
7096 p = *data = (char *) xmalloc (nbytes);
7097
7098 if (v10)
7099 {
333b20bb
GM
7100 for (i = 0; i < nbytes; i += 2)
7101 {
7102 int val = value;
7103 expect (XBM_TK_NUMBER);
7104
7105 *p++ = val;
7106 if (!padding_p || ((i + 2) % bytes_per_line))
7107 *p++ = value >> 8;
7108
7109 if (LA1 == ',' || LA1 == '}')
7110 match ();
7111 else
7112 goto failure;
7113 }
7114 }
7115 else
7116 {
7117 for (i = 0; i < nbytes; ++i)
7118 {
7119 int val = value;
7120 expect (XBM_TK_NUMBER);
7121
7122 *p++ = val;
7123
7124 if (LA1 == ',' || LA1 == '}')
7125 match ();
7126 else
7127 goto failure;
7128 }
7129 }
7130
5be6c3b0 7131 success:
333b20bb
GM
7132 return 1;
7133
7134 failure:
7135
5be6c3b0 7136 if (data && *data)
333b20bb
GM
7137 {
7138 xfree (*data);
7139 *data = NULL;
7140 }
7141 return 0;
7142
7143#undef match
7144#undef expect
7145#undef expect_ident
7146}
7147
7148
5be6c3b0
GM
7149/* Load XBM image IMG which will be displayed on frame F from buffer
7150 CONTENTS. END is the end of the buffer. Value is non-zero if
7151 successful. */
333b20bb
GM
7152
7153static int
5be6c3b0 7154xbm_load_image (f, img, contents, end)
333b20bb
GM
7155 struct frame *f;
7156 struct image *img;
5be6c3b0 7157 char *contents, *end;
333b20bb
GM
7158{
7159 int rc;
7160 unsigned char *data;
7161 int success_p = 0;
333b20bb 7162
5be6c3b0 7163 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
333b20bb
GM
7164 if (rc)
7165 {
7166 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7167 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7168 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7169 Lisp_Object value;
7170
7171 xassert (img->width > 0 && img->height > 0);
7172
7173 /* Get foreground and background colors, maybe allocate colors. */
7174 value = image_spec_value (img->spec, QCforeground, NULL);
7175 if (!NILP (value))
7176 foreground = x_alloc_image_color (f, img, value, foreground);
333b20bb
GM
7177 value = image_spec_value (img->spec, QCbackground, NULL);
7178 if (!NILP (value))
f20a3b7a
MB
7179 {
7180 background = x_alloc_image_color (f, img, value, background);
7181 img->background = background;
7182 img->background_valid = 1;
7183 }
333b20bb 7184
333b20bb
GM
7185 img->pixmap
7186 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7187 FRAME_X_WINDOW (f),
7188 data,
7189 img->width, img->height,
7190 foreground, background,
7191 depth);
7192 xfree (data);
7193
dd00328a 7194 if (img->pixmap == None)
333b20bb
GM
7195 {
7196 x_clear_image (f, img);
5be6c3b0 7197 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
7198 }
7199 else
7200 success_p = 1;
333b20bb
GM
7201 }
7202 else
45158a91 7203 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
333b20bb 7204
333b20bb
GM
7205 return success_p;
7206}
7207
7208
5be6c3b0
GM
7209/* Value is non-zero if DATA looks like an in-memory XBM file. */
7210
7211static int
7212xbm_file_p (data)
7213 Lisp_Object data;
7214{
7215 int w, h;
7216 return (STRINGP (data)
7217 && xbm_read_bitmap_data (XSTRING (data)->data,
7218 (XSTRING (data)->data
7219 + STRING_BYTES (XSTRING (data))),
7220 &w, &h, NULL));
7221}
7222
7223
333b20bb
GM
7224/* Fill image IMG which is used on frame F with pixmap data. Value is
7225 non-zero if successful. */
7226
7227static int
7228xbm_load (f, img)
7229 struct frame *f;
7230 struct image *img;
7231{
7232 int success_p = 0;
7233 Lisp_Object file_name;
7234
7235 xassert (xbm_image_p (img->spec));
7236
7237 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7238 file_name = image_spec_value (img->spec, QCfile, NULL);
7239 if (STRINGP (file_name))
5be6c3b0
GM
7240 {
7241 Lisp_Object file;
7242 char *contents;
7243 int size;
7244 struct gcpro gcpro1;
7245
7246 file = x_find_image_file (file_name);
7247 GCPRO1 (file);
7248 if (!STRINGP (file))
7249 {
7250 image_error ("Cannot find image file `%s'", file_name, Qnil);
7251 UNGCPRO;
7252 return 0;
7253 }
7254
7255 contents = slurp_file (XSTRING (file)->data, &size);
7256 if (contents == NULL)
7257 {
7258 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7259 UNGCPRO;
7260 return 0;
7261 }
7262
7263 success_p = xbm_load_image (f, img, contents, contents + size);
7264 UNGCPRO;
7265 }
333b20bb
GM
7266 else
7267 {
7268 struct image_keyword fmt[XBM_LAST];
7269 Lisp_Object data;
7270 int depth;
7271 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7272 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7273 char *bits;
9b207e8e 7274 int parsed_p;
5be6c3b0
GM
7275 int in_memory_file_p = 0;
7276
7277 /* See if data looks like an in-memory XBM file. */
7278 data = image_spec_value (img->spec, QCdata, NULL);
7279 in_memory_file_p = xbm_file_p (data);
333b20bb 7280
5be6c3b0 7281 /* Parse the image specification. */
333b20bb 7282 bcopy (xbm_format, fmt, sizeof fmt);
bfd2209f 7283 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
333b20bb
GM
7284 xassert (parsed_p);
7285
7286 /* Get specified width, and height. */
5be6c3b0
GM
7287 if (!in_memory_file_p)
7288 {
7289 img->width = XFASTINT (fmt[XBM_WIDTH].value);
7290 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
7291 xassert (img->width > 0 && img->height > 0);
7292 }
333b20bb 7293
333b20bb 7294 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
7295 if (fmt[XBM_FOREGROUND].count
7296 && STRINGP (fmt[XBM_FOREGROUND].value))
333b20bb
GM
7297 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
7298 foreground);
6f1be3b9
GM
7299 if (fmt[XBM_BACKGROUND].count
7300 && STRINGP (fmt[XBM_BACKGROUND].value))
333b20bb
GM
7301 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
7302 background);
7303
5be6c3b0
GM
7304 if (in_memory_file_p)
7305 success_p = xbm_load_image (f, img, XSTRING (data)->data,
7306 (XSTRING (data)->data
7307 + STRING_BYTES (XSTRING (data))));
7308 else
333b20bb 7309 {
5be6c3b0
GM
7310 if (VECTORP (data))
7311 {
7312 int i;
7313 char *p;
7314 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
333b20bb 7315
5be6c3b0
GM
7316 p = bits = (char *) alloca (nbytes * img->height);
7317 for (i = 0; i < img->height; ++i, p += nbytes)
7318 {
7319 Lisp_Object line = XVECTOR (data)->contents[i];
7320 if (STRINGP (line))
7321 bcopy (XSTRING (line)->data, p, nbytes);
7322 else
7323 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
7324 }
7325 }
7326 else if (STRINGP (data))
7327 bits = XSTRING (data)->data;
7328 else
7329 bits = XBOOL_VECTOR (data)->data;
7330
7331 /* Create the pixmap. */
7332 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7333 img->pixmap
7334 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7335 FRAME_X_WINDOW (f),
7336 bits,
7337 img->width, img->height,
7338 foreground, background,
7339 depth);
7340 if (img->pixmap)
7341 success_p = 1;
7342 else
333b20bb 7343 {
5be6c3b0
GM
7344 image_error ("Unable to create pixmap for XBM image `%s'",
7345 img->spec, Qnil);
7346 x_clear_image (f, img);
333b20bb
GM
7347 }
7348 }
333b20bb
GM
7349 }
7350
7351 return success_p;
7352}
7353
7354
7355\f
7356/***********************************************************************
7357 XPM images
7358 ***********************************************************************/
7359
7360#if HAVE_XPM
7361
7362static int xpm_image_p P_ ((Lisp_Object object));
7363static int xpm_load P_ ((struct frame *f, struct image *img));
7364static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
7365
7366#include "X11/xpm.h"
7367
7368/* The symbol `xpm' identifying XPM-format images. */
7369
7370Lisp_Object Qxpm;
7371
7372/* Indices of image specification fields in xpm_format, below. */
7373
7374enum xpm_keyword_index
7375{
7376 XPM_TYPE,
7377 XPM_FILE,
7378 XPM_DATA,
7379 XPM_ASCENT,
7380 XPM_MARGIN,
7381 XPM_RELIEF,
7382 XPM_ALGORITHM,
7383 XPM_HEURISTIC_MASK,
4a8e312c 7384 XPM_MASK,
333b20bb 7385 XPM_COLOR_SYMBOLS,
f20a3b7a 7386 XPM_BACKGROUND,
333b20bb
GM
7387 XPM_LAST
7388};
7389
7390/* Vector of image_keyword structures describing the format
7391 of valid XPM image specifications. */
7392
7393static struct image_keyword xpm_format[XPM_LAST] =
7394{
7395 {":type", IMAGE_SYMBOL_VALUE, 1},
7396 {":file", IMAGE_STRING_VALUE, 0},
7397 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 7398 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 7399 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 7400 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 7401 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 7402 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 7403 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
7404 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7405 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
7406};
7407
7408/* Structure describing the image type XBM. */
7409
7410static struct image_type xpm_type =
7411{
7412 &Qxpm,
7413 xpm_image_p,
7414 xpm_load,
7415 x_clear_image,
7416 NULL
7417};
7418
7419
b243755a
GM
7420/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
7421 functions for allocating image colors. Our own functions handle
7422 color allocation failures more gracefully than the ones on the XPM
7423 lib. */
7424
7425#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
7426#define ALLOC_XPM_COLORS
7427#endif
7428
7429#ifdef ALLOC_XPM_COLORS
7430
f72c62ad 7431static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
b243755a
GM
7432static void xpm_free_color_cache P_ ((void));
7433static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
f72c62ad
GM
7434static int xpm_color_bucket P_ ((char *));
7435static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
7436 XColor *, int));
b243755a
GM
7437
7438/* An entry in a hash table used to cache color definitions of named
7439 colors. This cache is necessary to speed up XPM image loading in
7440 case we do color allocations ourselves. Without it, we would need
7441 a call to XParseColor per pixel in the image. */
7442
7443struct xpm_cached_color
7444{
7445 /* Next in collision chain. */
7446 struct xpm_cached_color *next;
7447
7448 /* Color definition (RGB and pixel color). */
7449 XColor color;
7450
7451 /* Color name. */
7452 char name[1];
7453};
7454
7455/* The hash table used for the color cache, and its bucket vector
7456 size. */
7457
7458#define XPM_COLOR_CACHE_BUCKETS 1001
7459struct xpm_cached_color **xpm_color_cache;
7460
b243755a
GM
7461/* Initialize the color cache. */
7462
7463static void
f72c62ad
GM
7464xpm_init_color_cache (f, attrs)
7465 struct frame *f;
7466 XpmAttributes *attrs;
b243755a
GM
7467{
7468 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
7469 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
7470 memset (xpm_color_cache, 0, nbytes);
7471 init_color_table ();
f72c62ad
GM
7472
7473 if (attrs->valuemask & XpmColorSymbols)
7474 {
7475 int i;
7476 XColor color;
7477
7478 for (i = 0; i < attrs->numsymbols; ++i)
7479 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7480 attrs->colorsymbols[i].value, &color))
7481 {
7482 color.pixel = lookup_rgb_color (f, color.red, color.green,
7483 color.blue);
7484 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
7485 }
7486 }
b243755a
GM
7487}
7488
7489
7490/* Free the color cache. */
7491
7492static void
7493xpm_free_color_cache ()
7494{
7495 struct xpm_cached_color *p, *next;
7496 int i;
7497
7498 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
7499 for (p = xpm_color_cache[i]; p; p = next)
7500 {
7501 next = p->next;
7502 xfree (p);
7503 }
7504
7505 xfree (xpm_color_cache);
7506 xpm_color_cache = NULL;
7507 free_color_table ();
7508}
7509
7510
f72c62ad
GM
7511/* Return the bucket index for color named COLOR_NAME in the color
7512 cache. */
7513
7514static int
7515xpm_color_bucket (color_name)
7516 char *color_name;
7517{
7518 unsigned h = 0;
7519 char *s;
7520
7521 for (s = color_name; *s; ++s)
7522 h = (h << 2) ^ *s;
7523 return h %= XPM_COLOR_CACHE_BUCKETS;
7524}
7525
7526
7527/* On frame F, cache values COLOR for color with name COLOR_NAME.
7528 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
7529 entry added. */
7530
7531static struct xpm_cached_color *
7532xpm_cache_color (f, color_name, color, bucket)
7533 struct frame *f;
7534 char *color_name;
7535 XColor *color;
7536 int bucket;
7537{
7538 size_t nbytes;
7539 struct xpm_cached_color *p;
7540
7541 if (bucket < 0)
7542 bucket = xpm_color_bucket (color_name);
7543
7544 nbytes = sizeof *p + strlen (color_name);
7545 p = (struct xpm_cached_color *) xmalloc (nbytes);
7546 strcpy (p->name, color_name);
7547 p->color = *color;
7548 p->next = xpm_color_cache[bucket];
7549 xpm_color_cache[bucket] = p;
7550 return p;
7551}
7552
7553
b243755a
GM
7554/* Look up color COLOR_NAME for frame F in the color cache. If found,
7555 return the cached definition in *COLOR. Otherwise, make a new
7556 entry in the cache and allocate the color. Value is zero if color
7557 allocation failed. */
7558
7559static int
7560xpm_lookup_color (f, color_name, color)
7561 struct frame *f;
7562 char *color_name;
7563 XColor *color;
7564{
b243755a 7565 struct xpm_cached_color *p;
83676598 7566 int h = xpm_color_bucket (color_name);
b243755a
GM
7567
7568 for (p = xpm_color_cache[h]; p; p = p->next)
7569 if (strcmp (p->name, color_name) == 0)
7570 break;
7571
7572 if (p != NULL)
7573 *color = p->color;
7574 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7575 color_name, color))
7576 {
b243755a
GM
7577 color->pixel = lookup_rgb_color (f, color->red, color->green,
7578 color->blue);
f72c62ad 7579 p = xpm_cache_color (f, color_name, color, h);
b243755a 7580 }
f72c62ad 7581
b243755a
GM
7582 return p != NULL;
7583}
7584
7585
7586/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
7587 CLOSURE is a pointer to the frame on which we allocate the
7588 color. Return in *COLOR the allocated color. Value is non-zero
7589 if successful. */
7590
7591static int
7592xpm_alloc_color (dpy, cmap, color_name, color, closure)
7593 Display *dpy;
7594 Colormap cmap;
7595 char *color_name;
7596 XColor *color;
7597 void *closure;
7598{
7599 return xpm_lookup_color ((struct frame *) closure, color_name, color);
7600}
7601
7602
7603/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
7604 is a pointer to the frame on which we allocate the color. Value is
7605 non-zero if successful. */
7606
7607static int
7608xpm_free_colors (dpy, cmap, pixels, npixels, closure)
7609 Display *dpy;
7610 Colormap cmap;
7611 Pixel *pixels;
7612 int npixels;
7613 void *closure;
7614{
7615 return 1;
7616}
7617
7618#endif /* ALLOC_XPM_COLORS */
7619
7620
333b20bb
GM
7621/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7622 for XPM images. Such a list must consist of conses whose car and
7623 cdr are strings. */
7624
7625static int
7626xpm_valid_color_symbols_p (color_symbols)
7627 Lisp_Object color_symbols;
7628{
7629 while (CONSP (color_symbols))
7630 {
7631 Lisp_Object sym = XCAR (color_symbols);
7632 if (!CONSP (sym)
7633 || !STRINGP (XCAR (sym))
7634 || !STRINGP (XCDR (sym)))
7635 break;
7636 color_symbols = XCDR (color_symbols);
7637 }
7638
7639 return NILP (color_symbols);
7640}
7641
7642
7643/* Value is non-zero if OBJECT is a valid XPM image specification. */
7644
7645static int
7646xpm_image_p (object)
7647 Lisp_Object object;
7648{
7649 struct image_keyword fmt[XPM_LAST];
7650 bcopy (xpm_format, fmt, sizeof fmt);
bfd2209f 7651 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
333b20bb
GM
7652 /* Either `:file' or `:data' must be present. */
7653 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7654 /* Either no `:color-symbols' or it's a list of conses
7655 whose car and cdr are strings. */
7656 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7c7ff7f5 7657 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
333b20bb
GM
7658}
7659
7660
7661/* Load image IMG which will be displayed on frame F. Value is
7662 non-zero if successful. */
7663
7664static int
7665xpm_load (f, img)
7666 struct frame *f;
7667 struct image *img;
7668{
9b207e8e 7669 int rc;
333b20bb
GM
7670 XpmAttributes attrs;
7671 Lisp_Object specified_file, color_symbols;
7672
7673 /* Configure the XPM lib. Use the visual of frame F. Allocate
7674 close colors. Return colors allocated. */
7675 bzero (&attrs, sizeof attrs);
9b2956e2
GM
7676 attrs.visual = FRAME_X_VISUAL (f);
7677 attrs.colormap = FRAME_X_COLORMAP (f);
333b20bb 7678 attrs.valuemask |= XpmVisual;
9b2956e2 7679 attrs.valuemask |= XpmColormap;
b243755a
GM
7680
7681#ifdef ALLOC_XPM_COLORS
7682 /* Allocate colors with our own functions which handle
7683 failing color allocation more gracefully. */
7684 attrs.color_closure = f;
7685 attrs.alloc_color = xpm_alloc_color;
7686 attrs.free_colors = xpm_free_colors;
7687 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
7688#else /* not ALLOC_XPM_COLORS */
7689 /* Let the XPM lib allocate colors. */
333b20bb 7690 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 7691#ifdef XpmAllocCloseColors
333b20bb
GM
7692 attrs.alloc_close_colors = 1;
7693 attrs.valuemask |= XpmAllocCloseColors;
b243755a 7694#else /* not XpmAllocCloseColors */
e4c082be
RS
7695 attrs.closeness = 600;
7696 attrs.valuemask |= XpmCloseness;
b243755a
GM
7697#endif /* not XpmAllocCloseColors */
7698#endif /* ALLOC_XPM_COLORS */
333b20bb
GM
7699
7700 /* If image specification contains symbolic color definitions, add
7701 these to `attrs'. */
7702 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7703 if (CONSP (color_symbols))
7704 {
7705 Lisp_Object tail;
7706 XpmColorSymbol *xpm_syms;
7707 int i, size;
7708
7709 attrs.valuemask |= XpmColorSymbols;
7710
7711 /* Count number of symbols. */
7712 attrs.numsymbols = 0;
7713 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7714 ++attrs.numsymbols;
7715
7716 /* Allocate an XpmColorSymbol array. */
7717 size = attrs.numsymbols * sizeof *xpm_syms;
7718 xpm_syms = (XpmColorSymbol *) alloca (size);
7719 bzero (xpm_syms, size);
7720 attrs.colorsymbols = xpm_syms;
7721
7722 /* Fill the color symbol array. */
7723 for (tail = color_symbols, i = 0;
7724 CONSP (tail);
7725 ++i, tail = XCDR (tail))
7726 {
7727 Lisp_Object name = XCAR (XCAR (tail));
7728 Lisp_Object color = XCDR (XCAR (tail));
7729 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
7730 strcpy (xpm_syms[i].name, XSTRING (name)->data);
7731 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
7732 strcpy (xpm_syms[i].value, XSTRING (color)->data);
7733 }
7734 }
7735
7736 /* Create a pixmap for the image, either from a file, or from a
7737 string buffer containing data in the same format as an XPM file. */
b243755a 7738#ifdef ALLOC_XPM_COLORS
f72c62ad 7739 xpm_init_color_cache (f, &attrs);
b243755a
GM
7740#endif
7741
333b20bb
GM
7742 specified_file = image_spec_value (img->spec, QCfile, NULL);
7743 if (STRINGP (specified_file))
7744 {
7745 Lisp_Object file = x_find_image_file (specified_file);
7746 if (!STRINGP (file))
7747 {
45158a91 7748 image_error ("Cannot find image file `%s'", specified_file, Qnil);
333b20bb
GM
7749 return 0;
7750 }
7751
7752 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7753 XSTRING (file)->data, &img->pixmap, &img->mask,
7754 &attrs);
7755 }
7756 else
7757 {
7758 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7759 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7760 XSTRING (buffer)->data,
7761 &img->pixmap, &img->mask,
7762 &attrs);
7763 }
333b20bb
GM
7764
7765 if (rc == XpmSuccess)
7766 {
b243755a
GM
7767#ifdef ALLOC_XPM_COLORS
7768 img->colors = colors_in_color_table (&img->ncolors);
7769#else /* not ALLOC_XPM_COLORS */
f47a9ec4
KR
7770 int i;
7771
333b20bb
GM
7772 img->ncolors = attrs.nalloc_pixels;
7773 img->colors = (unsigned long *) xmalloc (img->ncolors
7774 * sizeof *img->colors);
7775 for (i = 0; i < attrs.nalloc_pixels; ++i)
3b4ae1cc
GM
7776 {
7777 img->colors[i] = attrs.alloc_pixels[i];
7778#ifdef DEBUG_X_COLORS
7779 register_color (img->colors[i]);
7780#endif
7781 }
b243755a 7782#endif /* not ALLOC_XPM_COLORS */
333b20bb
GM
7783
7784 img->width = attrs.width;
7785 img->height = attrs.height;
7786 xassert (img->width > 0 && img->height > 0);
7787
7788 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
333b20bb 7789 XpmFreeAttributes (&attrs);
333b20bb
GM
7790 }
7791 else
7792 {
7793 switch (rc)
7794 {
7795 case XpmOpenFailed:
7796 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7797 break;
7798
7799 case XpmFileInvalid:
7800 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7801 break;
7802
7803 case XpmNoMemory:
7804 image_error ("Out of memory (%s)", img->spec, Qnil);
7805 break;
7806
7807 case XpmColorFailed:
7808 image_error ("Color allocation error (%s)", img->spec, Qnil);
7809 break;
7810
7811 default:
7812 image_error ("Unknown error (%s)", img->spec, Qnil);
7813 break;
7814 }
7815 }
7816
b243755a
GM
7817#ifdef ALLOC_XPM_COLORS
7818 xpm_free_color_cache ();
7819#endif
333b20bb
GM
7820 return rc == XpmSuccess;
7821}
7822
7823#endif /* HAVE_XPM != 0 */
7824
7825\f
7826/***********************************************************************
7827 Color table
7828 ***********************************************************************/
7829
7830/* An entry in the color table mapping an RGB color to a pixel color. */
7831
7832struct ct_color
7833{
7834 int r, g, b;
7835 unsigned long pixel;
7836
7837 /* Next in color table collision list. */
7838 struct ct_color *next;
7839};
7840
7841/* The bucket vector size to use. Must be prime. */
7842
7843#define CT_SIZE 101
7844
7845/* Value is a hash of the RGB color given by R, G, and B. */
7846
7847#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7848
7849/* The color hash table. */
7850
7851struct ct_color **ct_table;
7852
7853/* Number of entries in the color table. */
7854
7855int ct_colors_allocated;
7856
333b20bb
GM
7857/* Initialize the color table. */
7858
7859static void
7860init_color_table ()
7861{
7862 int size = CT_SIZE * sizeof (*ct_table);
7863 ct_table = (struct ct_color **) xmalloc (size);
7864 bzero (ct_table, size);
7865 ct_colors_allocated = 0;
7866}
7867
7868
7869/* Free memory associated with the color table. */
7870
7871static void
7872free_color_table ()
7873{
7874 int i;
7875 struct ct_color *p, *next;
7876
7877 for (i = 0; i < CT_SIZE; ++i)
7878 for (p = ct_table[i]; p; p = next)
7879 {
7880 next = p->next;
7881 xfree (p);
7882 }
7883
7884 xfree (ct_table);
7885 ct_table = NULL;
7886}
7887
7888
7889/* Value is a pixel color for RGB color R, G, B on frame F. If an
7890 entry for that color already is in the color table, return the
7891 pixel color of that entry. Otherwise, allocate a new color for R,
7892 G, B, and make an entry in the color table. */
7893
7894static unsigned long
7895lookup_rgb_color (f, r, g, b)
7896 struct frame *f;
7897 int r, g, b;
7898{
7899 unsigned hash = CT_HASH_RGB (r, g, b);
7900 int i = hash % CT_SIZE;
7901 struct ct_color *p;
7902
7903 for (p = ct_table[i]; p; p = p->next)
7904 if (p->r == r && p->g == g && p->b == b)
7905 break;
7906
7907 if (p == NULL)
7908 {
7909 XColor color;
7910 Colormap cmap;
7911 int rc;
7912
7913 color.red = r;
7914 color.green = g;
7915 color.blue = b;
7916
9b2956e2 7917 cmap = FRAME_X_COLORMAP (f);
d62c8769 7918 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7919
7920 if (rc)
7921 {
7922 ++ct_colors_allocated;
7923
7924 p = (struct ct_color *) xmalloc (sizeof *p);
7925 p->r = r;
7926 p->g = g;
7927 p->b = b;
7928 p->pixel = color.pixel;
7929 p->next = ct_table[i];
7930 ct_table[i] = p;
7931 }
7932 else
7933 return FRAME_FOREGROUND_PIXEL (f);
7934 }
7935
7936 return p->pixel;
7937}
7938
7939
7940/* Look up pixel color PIXEL which is used on frame F in the color
7941 table. If not already present, allocate it. Value is PIXEL. */
7942
7943static unsigned long
7944lookup_pixel_color (f, pixel)
7945 struct frame *f;
7946 unsigned long pixel;
7947{
7948 int i = pixel % CT_SIZE;
7949 struct ct_color *p;
7950
7951 for (p = ct_table[i]; p; p = p->next)
7952 if (p->pixel == pixel)
7953 break;
7954
7955 if (p == NULL)
7956 {
7957 XColor color;
7958 Colormap cmap;
7959 int rc;
7960
9b2956e2 7961 cmap = FRAME_X_COLORMAP (f);
333b20bb 7962 color.pixel = pixel;
a31fedb7 7963 x_query_color (f, &color);
d62c8769 7964 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7965
7966 if (rc)
7967 {
7968 ++ct_colors_allocated;
7969
7970 p = (struct ct_color *) xmalloc (sizeof *p);
7971 p->r = color.red;
7972 p->g = color.green;
7973 p->b = color.blue;
7974 p->pixel = pixel;
7975 p->next = ct_table[i];
7976 ct_table[i] = p;
7977 }
7978 else
7979 return FRAME_FOREGROUND_PIXEL (f);
7980 }
7981
7982 return p->pixel;
7983}
7984
7985
7986/* Value is a vector of all pixel colors contained in the color table,
7987 allocated via xmalloc. Set *N to the number of colors. */
7988
7989static unsigned long *
7990colors_in_color_table (n)
7991 int *n;
7992{
7993 int i, j;
7994 struct ct_color *p;
7995 unsigned long *colors;
7996
7997 if (ct_colors_allocated == 0)
7998 {
7999 *n = 0;
8000 colors = NULL;
8001 }
8002 else
8003 {
8004 colors = (unsigned long *) xmalloc (ct_colors_allocated
8005 * sizeof *colors);
8006 *n = ct_colors_allocated;
8007
8008 for (i = j = 0; i < CT_SIZE; ++i)
8009 for (p = ct_table[i]; p; p = p->next)
8010 colors[j++] = p->pixel;
8011 }
8012
8013 return colors;
8014}
8015
8016
8017\f
8018/***********************************************************************
8019 Algorithms
8020 ***********************************************************************/
8021
4a8e312c
GM
8022static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
8023static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
8024static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
8025
d2dc8167 8026/* Non-zero means draw a cross on images having `:conversion
14819cb3
GM
8027 disabled'. */
8028
8029int cross_disabled_images;
8030
4a8e312c
GM
8031/* Edge detection matrices for different edge-detection
8032 strategies. */
8033
8034static int emboss_matrix[9] = {
8035 /* x - 1 x x + 1 */
8036 2, -1, 0, /* y - 1 */
8037 -1, 0, 1, /* y */
8038 0, 1, -2 /* y + 1 */
8039};
333b20bb 8040
4a8e312c
GM
8041static int laplace_matrix[9] = {
8042 /* x - 1 x x + 1 */
8043 1, 0, 0, /* y - 1 */
8044 0, 0, 0, /* y */
8045 0, 0, -1 /* y + 1 */
8046};
333b20bb 8047
14819cb3
GM
8048/* Value is the intensity of the color whose red/green/blue values
8049 are R, G, and B. */
8050
8051#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
8052
333b20bb 8053
4a8e312c
GM
8054/* On frame F, return an array of XColor structures describing image
8055 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
8056 non-zero means also fill the red/green/blue members of the XColor
8057 structures. Value is a pointer to the array of XColors structures,
8058 allocated with xmalloc; it must be freed by the caller. */
8059
8060static XColor *
8061x_to_xcolors (f, img, rgb_p)
333b20bb 8062 struct frame *f;
4a8e312c
GM
8063 struct image *img;
8064 int rgb_p;
333b20bb 8065{
4a8e312c
GM
8066 int x, y;
8067 XColor *colors, *p;
8068 XImage *ximg;
333b20bb 8069
4a8e312c
GM
8070 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
8071
8072 /* Get the X image IMG->pixmap. */
8073 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8074 0, 0, img->width, img->height, ~0, ZPixmap);
333b20bb 8075
4a8e312c
GM
8076 /* Fill the `pixel' members of the XColor array. I wished there
8077 were an easy and portable way to circumvent XGetPixel. */
8078 p = colors;
8079 for (y = 0; y < img->height; ++y)
8080 {
8081 XColor *row = p;
8082
8083 for (x = 0; x < img->width; ++x, ++p)
8084 p->pixel = XGetPixel (ximg, x, y);
8085
8086 if (rgb_p)
a31fedb7 8087 x_query_colors (f, row, img->width);
4a8e312c
GM
8088 }
8089
8090 XDestroyImage (ximg);
4a8e312c 8091 return colors;
333b20bb
GM
8092}
8093
8094
4a8e312c
GM
8095/* Create IMG->pixmap from an array COLORS of XColor structures, whose
8096 RGB members are set. F is the frame on which this all happens.
8097 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
333b20bb
GM
8098
8099static void
4a8e312c 8100x_from_xcolors (f, img, colors)
333b20bb 8101 struct frame *f;
4a8e312c
GM
8102 struct image *img;
8103 XColor *colors;
333b20bb 8104{
4a8e312c
GM
8105 int x, y;
8106 XImage *oimg;
8107 Pixmap pixmap;
8108 XColor *p;
8109
4a8e312c 8110 init_color_table ();
333b20bb 8111
4a8e312c
GM
8112 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
8113 &oimg, &pixmap);
8114 p = colors;
8115 for (y = 0; y < img->height; ++y)
8116 for (x = 0; x < img->width; ++x, ++p)
8117 {
8118 unsigned long pixel;
8119 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
8120 XPutPixel (oimg, x, y, pixel);
8121 }
8122
8123 xfree (colors);
dd00328a 8124 x_clear_image_1 (f, img, 1, 0, 1);
4a8e312c
GM
8125
8126 x_put_x_image (f, oimg, pixmap, img->width, img->height);
8127 x_destroy_x_image (oimg);
8128 img->pixmap = pixmap;
8129 img->colors = colors_in_color_table (&img->ncolors);
8130 free_color_table ();
333b20bb
GM
8131}
8132
8133
4a8e312c
GM
8134/* On frame F, perform edge-detection on image IMG.
8135
8136 MATRIX is a nine-element array specifying the transformation
8137 matrix. See emboss_matrix for an example.
8138
8139 COLOR_ADJUST is a color adjustment added to each pixel of the
8140 outgoing image. */
333b20bb
GM
8141
8142static void
4a8e312c 8143x_detect_edges (f, img, matrix, color_adjust)
333b20bb
GM
8144 struct frame *f;
8145 struct image *img;
4a8e312c 8146 int matrix[9], color_adjust;
333b20bb 8147{
4a8e312c
GM
8148 XColor *colors = x_to_xcolors (f, img, 1);
8149 XColor *new, *p;
8150 int x, y, i, sum;
333b20bb 8151
4a8e312c
GM
8152 for (i = sum = 0; i < 9; ++i)
8153 sum += abs (matrix[i]);
333b20bb 8154
4a8e312c 8155#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
333b20bb 8156
4a8e312c 8157 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
333b20bb 8158
4a8e312c
GM
8159 for (y = 0; y < img->height; ++y)
8160 {
8161 p = COLOR (new, 0, y);
8162 p->red = p->green = p->blue = 0xffff/2;
8163 p = COLOR (new, img->width - 1, y);
8164 p->red = p->green = p->blue = 0xffff/2;
8165 }
8166
8167 for (x = 1; x < img->width - 1; ++x)
8168 {
8169 p = COLOR (new, x, 0);
8170 p->red = p->green = p->blue = 0xffff/2;
8171 p = COLOR (new, x, img->height - 1);
8172 p->red = p->green = p->blue = 0xffff/2;
8173 }
333b20bb 8174
4a8e312c 8175 for (y = 1; y < img->height - 1; ++y)
333b20bb 8176 {
4a8e312c
GM
8177 p = COLOR (new, 1, y);
8178
8179 for (x = 1; x < img->width - 1; ++x, ++p)
8180 {
14819cb3 8181 int r, g, b, y1, x1;
4a8e312c
GM
8182
8183 r = g = b = i = 0;
8184 for (y1 = y - 1; y1 < y + 2; ++y1)
8185 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
8186 if (matrix[i])
8187 {
8188 XColor *t = COLOR (colors, x1, y1);
8189 r += matrix[i] * t->red;
8190 g += matrix[i] * t->green;
8191 b += matrix[i] * t->blue;
8192 }
333b20bb 8193
4a8e312c
GM
8194 r = (r / sum + color_adjust) & 0xffff;
8195 g = (g / sum + color_adjust) & 0xffff;
8196 b = (b / sum + color_adjust) & 0xffff;
14819cb3 8197 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
333b20bb 8198 }
333b20bb
GM
8199 }
8200
4a8e312c
GM
8201 xfree (colors);
8202 x_from_xcolors (f, img, new);
333b20bb 8203
4a8e312c
GM
8204#undef COLOR
8205}
8206
8207
8208/* Perform the pre-defined `emboss' edge-detection on image IMG
8209 on frame F. */
8210
8211static void
8212x_emboss (f, img)
8213 struct frame *f;
8214 struct image *img;
8215{
8216 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
8217}
8218
8219
8220/* Perform the pre-defined `laplace' edge-detection on image IMG
8221 on frame F. */
8222
8223static void
8224x_laplace (f, img)
8225 struct frame *f;
8226 struct image *img;
8227{
8228 x_detect_edges (f, img, laplace_matrix, 45000);
8229}
8230
8231
8232/* Perform edge-detection on image IMG on frame F, with specified
8233 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
8234
8235 MATRIX must be either
8236
8237 - a list of at least 9 numbers in row-major form
8238 - a vector of at least 9 numbers
8239
8240 COLOR_ADJUST nil means use a default; otherwise it must be a
8241 number. */
8242
8243static void
8244x_edge_detection (f, img, matrix, color_adjust)
8245 struct frame *f;
8246 struct image *img;
8247 Lisp_Object matrix, color_adjust;
8248{
8249 int i = 0;
8250 int trans[9];
333b20bb 8251
4a8e312c
GM
8252 if (CONSP (matrix))
8253 {
8254 for (i = 0;
8255 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
8256 ++i, matrix = XCDR (matrix))
8257 trans[i] = XFLOATINT (XCAR (matrix));
8258 }
8259 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
8260 {
8261 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
8262 trans[i] = XFLOATINT (AREF (matrix, i));
8263 }
333b20bb 8264
4a8e312c
GM
8265 if (NILP (color_adjust))
8266 color_adjust = make_number (0xffff / 2);
333b20bb 8267
4a8e312c
GM
8268 if (i == 9 && NUMBERP (color_adjust))
8269 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
333b20bb
GM
8270}
8271
8272
14819cb3
GM
8273/* Transform image IMG on frame F so that it looks disabled. */
8274
8275static void
8276x_disable_image (f, img)
8277 struct frame *f;
8278 struct image *img;
8279{
8280 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
dd00328a 8281
14819cb3
GM
8282 if (dpyinfo->n_planes >= 2)
8283 {
8284 /* Color (or grayscale). Convert to gray, and equalize. Just
8285 drawing such images with a stipple can look very odd, so
8286 we're using this method instead. */
8287 XColor *colors = x_to_xcolors (f, img, 1);
8288 XColor *p, *end;
8289 const int h = 15000;
8290 const int l = 30000;
8291
8292 for (p = colors, end = colors + img->width * img->height;
8293 p < end;
8294 ++p)
8295 {
8296 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
8297 int i2 = (0xffff - h - l) * i / 0xffff + l;
8298 p->red = p->green = p->blue = i2;
8299 }
8300
8301 x_from_xcolors (f, img, colors);
8302 }
8303
8304 /* Draw a cross over the disabled image, if we must or if we
8305 should. */
8306 if (dpyinfo->n_planes < 2 || cross_disabled_images)
8307 {
8308 Display *dpy = FRAME_X_DISPLAY (f);
8309 GC gc;
8310
14819cb3
GM
8311 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
8312 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
8313 XDrawLine (dpy, img->pixmap, gc, 0, 0,
8314 img->width - 1, img->height - 1);
8315 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
8316 img->width - 1, 0);
8317 XFreeGC (dpy, gc);
8318
8319 if (img->mask)
8320 {
8321 gc = XCreateGC (dpy, img->mask, 0, NULL);
8322 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
8323 XDrawLine (dpy, img->mask, gc, 0, 0,
8324 img->width - 1, img->height - 1);
8325 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
8326 img->width - 1, 0);
8327 XFreeGC (dpy, gc);
8328 }
14819cb3
GM
8329 }
8330}
8331
8332
333b20bb
GM
8333/* Build a mask for image IMG which is used on frame F. FILE is the
8334 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
8335 determine the background color of IMG. If it is a list '(R G B)',
8336 with R, G, and B being integers >= 0, take that as the color of the
8337 background. Otherwise, determine the background color of IMG
8338 heuristically. Value is non-zero if successful. */
333b20bb
GM
8339
8340static int
45158a91 8341x_build_heuristic_mask (f, img, how)
333b20bb 8342 struct frame *f;
333b20bb
GM
8343 struct image *img;
8344 Lisp_Object how;
8345{
8346 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 8347 XImage *ximg, *mask_img;
f20a3b7a 8348 int x, y, rc, use_img_background;
8ec8a5ec 8349 unsigned long bg = 0;
333b20bb 8350
4a8e312c
GM
8351 if (img->mask)
8352 {
8353 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 8354 img->mask = None;
f20a3b7a 8355 img->background_transparent_valid = 0;
4a8e312c 8356 }
dd00328a 8357
333b20bb 8358 /* Create an image and pixmap serving as mask. */
45158a91 8359 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
333b20bb
GM
8360 &mask_img, &img->mask);
8361 if (!rc)
28c7826c 8362 return 0;
333b20bb
GM
8363
8364 /* Get the X image of IMG->pixmap. */
8365 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
8366 ~0, ZPixmap);
8367
fcf431dc 8368 /* Determine the background color of ximg. If HOW is `(R G B)'
f20a3b7a
MB
8369 take that as color. Otherwise, use the image's background color. */
8370 use_img_background = 1;
fcf431dc
GM
8371
8372 if (CONSP (how))
8373 {
cac1daf0 8374 int rgb[3], i;
fcf431dc 8375
cac1daf0 8376 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
fcf431dc
GM
8377 {
8378 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
8379 how = XCDR (how);
8380 }
8381
8382 if (i == 3 && NILP (how))
8383 {
8384 char color_name[30];
fcf431dc 8385 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
053b3256
GM
8386 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
8387 use_img_background = 0;
fcf431dc
GM
8388 }
8389 }
8390
f20a3b7a 8391 if (use_img_background)
43f7c3ea 8392 bg = four_corners_best (ximg, img->width, img->height);
333b20bb
GM
8393
8394 /* Set all bits in mask_img to 1 whose color in ximg is different
8395 from the background color bg. */
8396 for (y = 0; y < img->height; ++y)
8397 for (x = 0; x < img->width; ++x)
8398 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
8399
f20a3b7a
MB
8400 /* Fill in the background_transparent field while we have the mask handy. */
8401 image_background_transparent (img, f, mask_img);
8402
333b20bb
GM
8403 /* Put mask_img into img->mask. */
8404 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8405 x_destroy_x_image (mask_img);
8406 XDestroyImage (ximg);
8407
333b20bb
GM
8408 return 1;
8409}
8410
8411
8412\f
8413/***********************************************************************
8414 PBM (mono, gray, color)
8415 ***********************************************************************/
8416
8417static int pbm_image_p P_ ((Lisp_Object object));
8418static int pbm_load P_ ((struct frame *f, struct image *img));
63cec32f 8419static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
333b20bb
GM
8420
8421/* The symbol `pbm' identifying images of this type. */
8422
8423Lisp_Object Qpbm;
8424
8425/* Indices of image specification fields in gs_format, below. */
8426
8427enum pbm_keyword_index
8428{
8429 PBM_TYPE,
8430 PBM_FILE,
63cec32f 8431 PBM_DATA,
333b20bb
GM
8432 PBM_ASCENT,
8433 PBM_MARGIN,
8434 PBM_RELIEF,
8435 PBM_ALGORITHM,
8436 PBM_HEURISTIC_MASK,
4a8e312c 8437 PBM_MASK,
be0b1fac
GM
8438 PBM_FOREGROUND,
8439 PBM_BACKGROUND,
333b20bb
GM
8440 PBM_LAST
8441};
8442
8443/* Vector of image_keyword structures describing the format
8444 of valid user-defined image specifications. */
8445
8446static struct image_keyword pbm_format[PBM_LAST] =
8447{
8448 {":type", IMAGE_SYMBOL_VALUE, 1},
63cec32f
GM
8449 {":file", IMAGE_STRING_VALUE, 0},
8450 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8451 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8452 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8453 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8454 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8455 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
be0b1fac 8456 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
8457 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8458 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8459};
8460
8461/* Structure describing the image type `pbm'. */
8462
8463static struct image_type pbm_type =
8464{
8465 &Qpbm,
8466 pbm_image_p,
8467 pbm_load,
8468 x_clear_image,
8469 NULL
8470};
8471
8472
8473/* Return non-zero if OBJECT is a valid PBM image specification. */
8474
8475static int
8476pbm_image_p (object)
8477 Lisp_Object object;
8478{
8479 struct image_keyword fmt[PBM_LAST];
8480
8481 bcopy (pbm_format, fmt, sizeof fmt);
8482
7c7ff7f5 8483 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
333b20bb 8484 return 0;
63cec32f
GM
8485
8486 /* Must specify either :data or :file. */
8487 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
333b20bb
GM
8488}
8489
8490
63cec32f
GM
8491/* Scan a decimal number from *S and return it. Advance *S while
8492 reading the number. END is the end of the string. Value is -1 at
8493 end of input. */
333b20bb
GM
8494
8495static int
63cec32f
GM
8496pbm_scan_number (s, end)
8497 unsigned char **s, *end;
333b20bb 8498{
8ec8a5ec 8499 int c = 0, val = -1;
333b20bb 8500
63cec32f 8501 while (*s < end)
333b20bb
GM
8502 {
8503 /* Skip white-space. */
63cec32f 8504 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
8505 ;
8506
8507 if (c == '#')
8508 {
8509 /* Skip comment to end of line. */
63cec32f 8510 while (*s < end && (c = *(*s)++, c != '\n'))
333b20bb
GM
8511 ;
8512 }
8513 else if (isdigit (c))
8514 {
8515 /* Read decimal number. */
8516 val = c - '0';
63cec32f 8517 while (*s < end && (c = *(*s)++, isdigit (c)))
333b20bb
GM
8518 val = 10 * val + c - '0';
8519 break;
8520 }
8521 else
8522 break;
8523 }
8524
8525 return val;
8526}
8527
8528
8529/* Load PBM image IMG for use on frame F. */
8530
8531static int
8532pbm_load (f, img)
8533 struct frame *f;
8534 struct image *img;
8535{
333b20bb 8536 int raw_p, x, y;
b6d7acec 8537 int width, height, max_color_idx = 0;
333b20bb
GM
8538 XImage *ximg;
8539 Lisp_Object file, specified_file;
8540 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
8541 struct gcpro gcpro1;
63cec32f
GM
8542 unsigned char *contents = NULL;
8543 unsigned char *end, *p;
8544 int size;
333b20bb
GM
8545
8546 specified_file = image_spec_value (img->spec, QCfile, NULL);
63cec32f 8547 file = Qnil;
333b20bb 8548 GCPRO1 (file);
333b20bb 8549
63cec32f 8550 if (STRINGP (specified_file))
333b20bb 8551 {
63cec32f
GM
8552 file = x_find_image_file (specified_file);
8553 if (!STRINGP (file))
8554 {
8555 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8556 UNGCPRO;
8557 return 0;
8558 }
333b20bb 8559
5be6c3b0 8560 contents = slurp_file (XSTRING (file)->data, &size);
63cec32f
GM
8561 if (contents == NULL)
8562 {
8563 image_error ("Error reading `%s'", file, Qnil);
8564 UNGCPRO;
8565 return 0;
8566 }
8567
8568 p = contents;
8569 end = contents + size;
8570 }
8571 else
333b20bb 8572 {
63cec32f
GM
8573 Lisp_Object data;
8574 data = image_spec_value (img->spec, QCdata, NULL);
8575 p = XSTRING (data)->data;
8576 end = p + STRING_BYTES (XSTRING (data));
333b20bb
GM
8577 }
8578
63cec32f
GM
8579 /* Check magic number. */
8580 if (end - p < 2 || *p++ != 'P')
333b20bb 8581 {
45158a91 8582 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f
GM
8583 error:
8584 xfree (contents);
333b20bb
GM
8585 UNGCPRO;
8586 return 0;
8587 }
8588
63cec32f 8589 switch (*p++)
333b20bb
GM
8590 {
8591 case '1':
8592 raw_p = 0, type = PBM_MONO;
8593 break;
8594
8595 case '2':
8596 raw_p = 0, type = PBM_GRAY;
8597 break;
8598
8599 case '3':
8600 raw_p = 0, type = PBM_COLOR;
8601 break;
8602
8603 case '4':
8604 raw_p = 1, type = PBM_MONO;
8605 break;
8606
8607 case '5':
8608 raw_p = 1, type = PBM_GRAY;
8609 break;
8610
8611 case '6':
8612 raw_p = 1, type = PBM_COLOR;
8613 break;
8614
8615 default:
45158a91 8616 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f 8617 goto error;
333b20bb
GM
8618 }
8619
8620 /* Read width, height, maximum color-component. Characters
8621 starting with `#' up to the end of a line are ignored. */
63cec32f
GM
8622 width = pbm_scan_number (&p, end);
8623 height = pbm_scan_number (&p, end);
333b20bb
GM
8624
8625 if (type != PBM_MONO)
8626 {
63cec32f 8627 max_color_idx = pbm_scan_number (&p, end);
333b20bb
GM
8628 if (raw_p && max_color_idx > 255)
8629 max_color_idx = 255;
8630 }
8631
63cec32f
GM
8632 if (width < 0
8633 || height < 0
333b20bb 8634 || (type != PBM_MONO && max_color_idx < 0))
63cec32f 8635 goto error;
333b20bb 8636
45158a91 8637 if (!x_create_x_image_and_pixmap (f, width, height, 0,
333b20bb 8638 &ximg, &img->pixmap))
28c7826c 8639 goto error;
333b20bb
GM
8640
8641 /* Initialize the color hash table. */
8642 init_color_table ();
8643
8644 if (type == PBM_MONO)
8645 {
8646 int c = 0, g;
be0b1fac
GM
8647 struct image_keyword fmt[PBM_LAST];
8648 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
8649 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
8650
8651 /* Parse the image specification. */
8652 bcopy (pbm_format, fmt, sizeof fmt);
8653 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
8654
8655 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
8656 if (fmt[PBM_FOREGROUND].count
8657 && STRINGP (fmt[PBM_FOREGROUND].value))
be0b1fac 8658 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
6f1be3b9
GM
8659 if (fmt[PBM_BACKGROUND].count
8660 && STRINGP (fmt[PBM_BACKGROUND].value))
f20a3b7a
MB
8661 {
8662 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
8663 img->background = bg;
8664 img->background_valid = 1;
8665 }
333b20bb
GM
8666
8667 for (y = 0; y < height; ++y)
8668 for (x = 0; x < width; ++x)
8669 {
8670 if (raw_p)
8671 {
8672 if ((x & 7) == 0)
63cec32f 8673 c = *p++;
333b20bb
GM
8674 g = c & 0x80;
8675 c <<= 1;
8676 }
8677 else
63cec32f 8678 g = pbm_scan_number (&p, end);
333b20bb 8679
be0b1fac 8680 XPutPixel (ximg, x, y, g ? fg : bg);
333b20bb
GM
8681 }
8682 }
8683 else
8684 {
8685 for (y = 0; y < height; ++y)
8686 for (x = 0; x < width; ++x)
8687 {
8688 int r, g, b;
8689
8690 if (type == PBM_GRAY)
63cec32f 8691 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
333b20bb
GM
8692 else if (raw_p)
8693 {
63cec32f
GM
8694 r = *p++;
8695 g = *p++;
8696 b = *p++;
333b20bb
GM
8697 }
8698 else
8699 {
63cec32f
GM
8700 r = pbm_scan_number (&p, end);
8701 g = pbm_scan_number (&p, end);
8702 b = pbm_scan_number (&p, end);
333b20bb
GM
8703 }
8704
8705 if (r < 0 || g < 0 || b < 0)
8706 {
333b20bb
GM
8707 xfree (ximg->data);
8708 ximg->data = NULL;
8709 XDestroyImage (ximg);
45158a91
GM
8710 image_error ("Invalid pixel value in image `%s'",
8711 img->spec, Qnil);
63cec32f 8712 goto error;
333b20bb
GM
8713 }
8714
8715 /* RGB values are now in the range 0..max_color_idx.
8716 Scale this to the range 0..0xffff supported by X. */
8717 r = (double) r * 65535 / max_color_idx;
8718 g = (double) g * 65535 / max_color_idx;
8719 b = (double) b * 65535 / max_color_idx;
8720 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8721 }
8722 }
8723
333b20bb
GM
8724 /* Store in IMG->colors the colors allocated for the image, and
8725 free the color table. */
8726 img->colors = colors_in_color_table (&img->ncolors);
8727 free_color_table ();
f20a3b7a
MB
8728
8729 /* Maybe fill in the background field while we have ximg handy. */
8730 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8731 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
8732
8733 /* Put the image into a pixmap. */
8734 x_put_x_image (f, ximg, img->pixmap, width, height);
8735 x_destroy_x_image (ximg);
333b20bb
GM
8736
8737 img->width = width;
8738 img->height = height;
8739
8740 UNGCPRO;
63cec32f 8741 xfree (contents);
333b20bb
GM
8742 return 1;
8743}
8744
8745
8746\f
8747/***********************************************************************
8748 PNG
8749 ***********************************************************************/
8750
8751#if HAVE_PNG
8752
8753#include <png.h>
8754
8755/* Function prototypes. */
8756
8757static int png_image_p P_ ((Lisp_Object object));
8758static int png_load P_ ((struct frame *f, struct image *img));
8759
8760/* The symbol `png' identifying images of this type. */
8761
8762Lisp_Object Qpng;
8763
8764/* Indices of image specification fields in png_format, below. */
8765
8766enum png_keyword_index
8767{
8768 PNG_TYPE,
63448a4d 8769 PNG_DATA,
333b20bb
GM
8770 PNG_FILE,
8771 PNG_ASCENT,
8772 PNG_MARGIN,
8773 PNG_RELIEF,
8774 PNG_ALGORITHM,
8775 PNG_HEURISTIC_MASK,
4a8e312c 8776 PNG_MASK,
f20a3b7a 8777 PNG_BACKGROUND,
333b20bb
GM
8778 PNG_LAST
8779};
8780
8781/* Vector of image_keyword structures describing the format
8782 of valid user-defined image specifications. */
8783
8784static struct image_keyword png_format[PNG_LAST] =
8785{
8786 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8787 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8788 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8789 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8790 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8791 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8792 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8793 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 8794 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a 8795 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8796};
8797
06482119 8798/* Structure describing the image type `png'. */
333b20bb
GM
8799
8800static struct image_type png_type =
8801{
8802 &Qpng,
8803 png_image_p,
8804 png_load,
8805 x_clear_image,
8806 NULL
8807};
8808
8809
8810/* Return non-zero if OBJECT is a valid PNG image specification. */
8811
8812static int
8813png_image_p (object)
8814 Lisp_Object object;
8815{
8816 struct image_keyword fmt[PNG_LAST];
8817 bcopy (png_format, fmt, sizeof fmt);
8818
7c7ff7f5 8819 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
333b20bb 8820 return 0;
63448a4d 8821
63cec32f
GM
8822 /* Must specify either the :data or :file keyword. */
8823 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
333b20bb
GM
8824}
8825
8826
8827/* Error and warning handlers installed when the PNG library
8828 is initialized. */
8829
8830static void
8831my_png_error (png_ptr, msg)
8832 png_struct *png_ptr;
8833 char *msg;
8834{
8835 xassert (png_ptr != NULL);
8836 image_error ("PNG error: %s", build_string (msg), Qnil);
8837 longjmp (png_ptr->jmpbuf, 1);
8838}
8839
8840
8841static void
8842my_png_warning (png_ptr, msg)
8843 png_struct *png_ptr;
8844 char *msg;
8845{
8846 xassert (png_ptr != NULL);
8847 image_error ("PNG warning: %s", build_string (msg), Qnil);
8848}
8849
5ad6a5fb
GM
8850/* Memory source for PNG decoding. */
8851
63448a4d
WP
8852struct png_memory_storage
8853{
5ad6a5fb
GM
8854 unsigned char *bytes; /* The data */
8855 size_t len; /* How big is it? */
8856 int index; /* Where are we? */
63448a4d
WP
8857};
8858
5ad6a5fb
GM
8859
8860/* Function set as reader function when reading PNG image from memory.
8861 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8862 bytes from the input to DATA. */
8863
63448a4d 8864static void
5ad6a5fb
GM
8865png_read_from_memory (png_ptr, data, length)
8866 png_structp png_ptr;
8867 png_bytep data;
8868 png_size_t length;
63448a4d 8869{
5ad6a5fb
GM
8870 struct png_memory_storage *tbr
8871 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
63448a4d 8872
5ad6a5fb
GM
8873 if (length > tbr->len - tbr->index)
8874 png_error (png_ptr, "Read error");
8875
8876 bcopy (tbr->bytes + tbr->index, data, length);
8877 tbr->index = tbr->index + length;
63448a4d 8878}
333b20bb
GM
8879
8880/* Load PNG image IMG for use on frame F. Value is non-zero if
8881 successful. */
8882
8883static int
8884png_load (f, img)
8885 struct frame *f;
8886 struct image *img;
8887{
8888 Lisp_Object file, specified_file;
63448a4d 8889 Lisp_Object specified_data;
b6d7acec 8890 int x, y, i;
333b20bb
GM
8891 XImage *ximg, *mask_img = NULL;
8892 struct gcpro gcpro1;
8893 png_struct *png_ptr = NULL;
8894 png_info *info_ptr = NULL, *end_info = NULL;
8ec8a5ec 8895 FILE *volatile fp = NULL;
333b20bb 8896 png_byte sig[8];
8ec8a5ec
GM
8897 png_byte * volatile pixels = NULL;
8898 png_byte ** volatile rows = NULL;
333b20bb
GM
8899 png_uint_32 width, height;
8900 int bit_depth, color_type, interlace_type;
8901 png_byte channels;
8902 png_uint_32 row_bytes;
8903 int transparent_p;
333b20bb
GM
8904 double screen_gamma, image_gamma;
8905 int intent;
63448a4d 8906 struct png_memory_storage tbr; /* Data to be read */
333b20bb
GM
8907
8908 /* Find out what file to load. */
8909 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8910 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8911 file = Qnil;
8912 GCPRO1 (file);
333b20bb 8913
63448a4d 8914 if (NILP (specified_data))
5ad6a5fb
GM
8915 {
8916 file = x_find_image_file (specified_file);
8917 if (!STRINGP (file))
63448a4d 8918 {
45158a91 8919 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
8920 UNGCPRO;
8921 return 0;
8922 }
333b20bb 8923
5ad6a5fb
GM
8924 /* Open the image file. */
8925 fp = fopen (XSTRING (file)->data, "rb");
8926 if (!fp)
8927 {
45158a91 8928 image_error ("Cannot open image file `%s'", file, Qnil);
5ad6a5fb
GM
8929 UNGCPRO;
8930 fclose (fp);
8931 return 0;
8932 }
63448a4d 8933
5ad6a5fb
GM
8934 /* Check PNG signature. */
8935 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8936 || !png_check_sig (sig, sizeof sig))
8937 {
45158a91 8938 image_error ("Not a PNG file: `%s'", file, Qnil);
5ad6a5fb
GM
8939 UNGCPRO;
8940 fclose (fp);
8941 return 0;
63448a4d 8942 }
5ad6a5fb 8943 }
63448a4d 8944 else
5ad6a5fb
GM
8945 {
8946 /* Read from memory. */
8947 tbr.bytes = XSTRING (specified_data)->data;
8948 tbr.len = STRING_BYTES (XSTRING (specified_data));
8949 tbr.index = 0;
63448a4d 8950
5ad6a5fb
GM
8951 /* Check PNG signature. */
8952 if (tbr.len < sizeof sig
8953 || !png_check_sig (tbr.bytes, sizeof sig))
8954 {
45158a91 8955 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5ad6a5fb
GM
8956 UNGCPRO;
8957 return 0;
63448a4d 8958 }
333b20bb 8959
5ad6a5fb
GM
8960 /* Need to skip past the signature. */
8961 tbr.bytes += sizeof (sig);
8962 }
8963
333b20bb
GM
8964 /* Initialize read and info structs for PNG lib. */
8965 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8966 my_png_error, my_png_warning);
8967 if (!png_ptr)
8968 {
63448a4d 8969 if (fp) fclose (fp);
333b20bb
GM
8970 UNGCPRO;
8971 return 0;
8972 }
8973
8974 info_ptr = png_create_info_struct (png_ptr);
8975 if (!info_ptr)
8976 {
8977 png_destroy_read_struct (&png_ptr, NULL, NULL);
63448a4d 8978 if (fp) fclose (fp);
333b20bb
GM
8979 UNGCPRO;
8980 return 0;
8981 }
8982
8983 end_info = png_create_info_struct (png_ptr);
8984 if (!end_info)
8985 {
8986 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
63448a4d 8987 if (fp) fclose (fp);
333b20bb
GM
8988 UNGCPRO;
8989 return 0;
8990 }
8991
8992 /* Set error jump-back. We come back here when the PNG library
8993 detects an error. */
8994 if (setjmp (png_ptr->jmpbuf))
8995 {
8996 error:
8997 if (png_ptr)
8998 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8999 xfree (pixels);
9000 xfree (rows);
63448a4d 9001 if (fp) fclose (fp);
333b20bb
GM
9002 UNGCPRO;
9003 return 0;
9004 }
9005
9006 /* Read image info. */
63448a4d 9007 if (!NILP (specified_data))
5ad6a5fb 9008 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
63448a4d 9009 else
5ad6a5fb 9010 png_init_io (png_ptr, fp);
63448a4d 9011
333b20bb
GM
9012 png_set_sig_bytes (png_ptr, sizeof sig);
9013 png_read_info (png_ptr, info_ptr);
9014 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
9015 &interlace_type, NULL, NULL);
9016
9017 /* If image contains simply transparency data, we prefer to
9018 construct a clipping mask. */
9019 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
9020 transparent_p = 1;
9021 else
9022 transparent_p = 0;
9023
9024 /* This function is easier to write if we only have to handle
9025 one data format: RGB or RGBA with 8 bits per channel. Let's
9026 transform other formats into that format. */
9027
9028 /* Strip more than 8 bits per channel. */
9029 if (bit_depth == 16)
9030 png_set_strip_16 (png_ptr);
9031
9032 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
9033 if available. */
9034 png_set_expand (png_ptr);
9035
9036 /* Convert grayscale images to RGB. */
9037 if (color_type == PNG_COLOR_TYPE_GRAY
9038 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9039 png_set_gray_to_rgb (png_ptr);
9040
d4405ed7 9041 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
333b20bb
GM
9042
9043 /* Tell the PNG lib to handle gamma correction for us. */
9044
6c1aa34d 9045#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
333b20bb 9046 if (png_get_sRGB (png_ptr, info_ptr, &intent))
d4405ed7
RS
9047 /* The libpng documentation says this is right in this case. */
9048 png_set_gamma (png_ptr, screen_gamma, 0.45455);
6c1aa34d
GM
9049 else
9050#endif
9051 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
333b20bb
GM
9052 /* Image contains gamma information. */
9053 png_set_gamma (png_ptr, screen_gamma, image_gamma);
9054 else
d4405ed7
RS
9055 /* Use the standard default for the image gamma. */
9056 png_set_gamma (png_ptr, screen_gamma, 0.45455);
333b20bb
GM
9057
9058 /* Handle alpha channel by combining the image with a background
9059 color. Do this only if a real alpha channel is supplied. For
9060 simple transparency, we prefer a clipping mask. */
9061 if (!transparent_p)
9062 {
f20a3b7a
MB
9063 png_color_16 *image_bg;
9064 Lisp_Object specified_bg
9065 = image_spec_value (img->spec, QCbackground, NULL);
9066
f2f0a644 9067 if (STRINGP (specified_bg))
f20a3b7a
MB
9068 /* The user specified `:background', use that. */
9069 {
9070 XColor color;
f2f0a644 9071 if (x_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
f20a3b7a
MB
9072 {
9073 png_color_16 user_bg;
9074
9075 bzero (&user_bg, sizeof user_bg);
9076 user_bg.red = color.red;
9077 user_bg.green = color.green;
9078 user_bg.blue = color.blue;
333b20bb 9079
f20a3b7a
MB
9080 png_set_background (png_ptr, &user_bg,
9081 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9082 }
9083 }
9084 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
333b20bb
GM
9085 /* Image contains a background color with which to
9086 combine the image. */
f20a3b7a 9087 png_set_background (png_ptr, image_bg,
333b20bb
GM
9088 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
9089 else
9090 {
9091 /* Image does not contain a background color with which
9092 to combine the image data via an alpha channel. Use
9093 the frame's background instead. */
9094 XColor color;
9095 Colormap cmap;
9096 png_color_16 frame_background;
9097
9b2956e2 9098 cmap = FRAME_X_COLORMAP (f);
333b20bb 9099 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a31fedb7 9100 x_query_color (f, &color);
333b20bb
GM
9101
9102 bzero (&frame_background, sizeof frame_background);
9103 frame_background.red = color.red;
9104 frame_background.green = color.green;
9105 frame_background.blue = color.blue;
9106
9107 png_set_background (png_ptr, &frame_background,
9108 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9109 }
9110 }
9111
9112 /* Update info structure. */
9113 png_read_update_info (png_ptr, info_ptr);
9114
9115 /* Get number of channels. Valid values are 1 for grayscale images
9116 and images with a palette, 2 for grayscale images with transparency
9117 information (alpha channel), 3 for RGB images, and 4 for RGB
9118 images with alpha channel, i.e. RGBA. If conversions above were
9119 sufficient we should only have 3 or 4 channels here. */
9120 channels = png_get_channels (png_ptr, info_ptr);
9121 xassert (channels == 3 || channels == 4);
9122
9123 /* Number of bytes needed for one row of the image. */
9124 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
9125
9126 /* Allocate memory for the image. */
9127 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
9128 rows = (png_byte **) xmalloc (height * sizeof *rows);
9129 for (i = 0; i < height; ++i)
9130 rows[i] = pixels + i * row_bytes;
9131
9132 /* Read the entire image. */
9133 png_read_image (png_ptr, rows);
9134 png_read_end (png_ptr, info_ptr);
5ad6a5fb
GM
9135 if (fp)
9136 {
9137 fclose (fp);
9138 fp = NULL;
9139 }
333b20bb 9140
333b20bb 9141 /* Create the X image and pixmap. */
45158a91 9142 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
333b20bb 9143 &img->pixmap))
28c7826c 9144 goto error;
333b20bb
GM
9145
9146 /* Create an image and pixmap serving as mask if the PNG image
9147 contains an alpha channel. */
9148 if (channels == 4
9149 && !transparent_p
45158a91 9150 && !x_create_x_image_and_pixmap (f, width, height, 1,
333b20bb
GM
9151 &mask_img, &img->mask))
9152 {
9153 x_destroy_x_image (ximg);
9154 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 9155 img->pixmap = None;
333b20bb
GM
9156 goto error;
9157 }
9158
9159 /* Fill the X image and mask from PNG data. */
9160 init_color_table ();
9161
9162 for (y = 0; y < height; ++y)
9163 {
9164 png_byte *p = rows[y];
9165
9166 for (x = 0; x < width; ++x)
9167 {
9168 unsigned r, g, b;
9169
9170 r = *p++ << 8;
9171 g = *p++ << 8;
9172 b = *p++ << 8;
9173 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9174
9175 /* An alpha channel, aka mask channel, associates variable
9176 transparency with an image. Where other image formats
9177 support binary transparency---fully transparent or fully
9178 opaque---PNG allows up to 254 levels of partial transparency.
9179 The PNG library implements partial transparency by combining
9180 the image with a specified background color.
9181
9182 I'm not sure how to handle this here nicely: because the
9183 background on which the image is displayed may change, for
9184 real alpha channel support, it would be necessary to create
9185 a new image for each possible background.
9186
9187 What I'm doing now is that a mask is created if we have
9188 boolean transparency information. Otherwise I'm using
9189 the frame's background color to combine the image with. */
9190
9191 if (channels == 4)
9192 {
9193 if (mask_img)
9194 XPutPixel (mask_img, x, y, *p > 0);
9195 ++p;
9196 }
9197 }
9198 }
9199
f20a3b7a
MB
9200 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9201 /* Set IMG's background color from the PNG image, unless the user
9202 overrode it. */
9203 {
9204 png_color_16 *bg;
9205 if (png_get_bKGD (png_ptr, info_ptr, &bg))
9206 {
f2f0a644 9207 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
f20a3b7a
MB
9208 img->background_valid = 1;
9209 }
9210 }
9211
333b20bb
GM
9212 /* Remember colors allocated for this image. */
9213 img->colors = colors_in_color_table (&img->ncolors);
9214 free_color_table ();
9215
9216 /* Clean up. */
9217 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9218 xfree (rows);
9219 xfree (pixels);
9220
9221 img->width = width;
9222 img->height = height;
9223
f20a3b7a
MB
9224 /* Maybe fill in the background field while we have ximg handy. */
9225 IMAGE_BACKGROUND (img, f, ximg);
9226
333b20bb
GM
9227 /* Put the image into the pixmap, then free the X image and its buffer. */
9228 x_put_x_image (f, ximg, img->pixmap, width, height);
9229 x_destroy_x_image (ximg);
9230
9231 /* Same for the mask. */
9232 if (mask_img)
9233 {
f20a3b7a
MB
9234 /* Fill in the background_transparent field while we have the mask
9235 handy. */
9236 image_background_transparent (img, f, mask_img);
9237
333b20bb
GM
9238 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9239 x_destroy_x_image (mask_img);
9240 }
9241
333b20bb
GM
9242 UNGCPRO;
9243 return 1;
9244}
9245
9246#endif /* HAVE_PNG != 0 */
9247
9248
9249\f
9250/***********************************************************************
9251 JPEG
9252 ***********************************************************************/
9253
9254#if HAVE_JPEG
9255
ba06aba4
GM
9256/* Work around a warning about HAVE_STDLIB_H being redefined in
9257 jconfig.h. */
9258#ifdef HAVE_STDLIB_H
9259#define HAVE_STDLIB_H_1
9260#undef HAVE_STDLIB_H
9261#endif /* HAVE_STLIB_H */
9262
333b20bb
GM
9263#include <jpeglib.h>
9264#include <jerror.h>
9265#include <setjmp.h>
9266
ba06aba4
GM
9267#ifdef HAVE_STLIB_H_1
9268#define HAVE_STDLIB_H 1
9269#endif
9270
333b20bb
GM
9271static int jpeg_image_p P_ ((Lisp_Object object));
9272static int jpeg_load P_ ((struct frame *f, struct image *img));
9273
9274/* The symbol `jpeg' identifying images of this type. */
9275
9276Lisp_Object Qjpeg;
9277
9278/* Indices of image specification fields in gs_format, below. */
9279
9280enum jpeg_keyword_index
9281{
9282 JPEG_TYPE,
8e39770a 9283 JPEG_DATA,
333b20bb
GM
9284 JPEG_FILE,
9285 JPEG_ASCENT,
9286 JPEG_MARGIN,
9287 JPEG_RELIEF,
9288 JPEG_ALGORITHM,
9289 JPEG_HEURISTIC_MASK,
4a8e312c 9290 JPEG_MASK,
f20a3b7a 9291 JPEG_BACKGROUND,
333b20bb
GM
9292 JPEG_LAST
9293};
9294
9295/* Vector of image_keyword structures describing the format
9296 of valid user-defined image specifications. */
9297
9298static struct image_keyword jpeg_format[JPEG_LAST] =
9299{
9300 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9301 {":data", IMAGE_STRING_VALUE, 0},
8e39770a 9302 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9303 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9304 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9305 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9306 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9307 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9308 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9309 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9310};
9311
9312/* Structure describing the image type `jpeg'. */
9313
9314static struct image_type jpeg_type =
9315{
9316 &Qjpeg,
9317 jpeg_image_p,
9318 jpeg_load,
9319 x_clear_image,
9320 NULL
9321};
9322
9323
9324/* Return non-zero if OBJECT is a valid JPEG image specification. */
9325
9326static int
9327jpeg_image_p (object)
9328 Lisp_Object object;
9329{
9330 struct image_keyword fmt[JPEG_LAST];
9331
9332 bcopy (jpeg_format, fmt, sizeof fmt);
9333
7c7ff7f5 9334 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
333b20bb 9335 return 0;
8e39770a 9336
63cec32f
GM
9337 /* Must specify either the :data or :file keyword. */
9338 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
333b20bb
GM
9339}
9340
8e39770a 9341
333b20bb
GM
9342struct my_jpeg_error_mgr
9343{
9344 struct jpeg_error_mgr pub;
9345 jmp_buf setjmp_buffer;
9346};
9347
e3130015 9348
333b20bb
GM
9349static void
9350my_error_exit (cinfo)
9351 j_common_ptr cinfo;
9352{
9353 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
9354 longjmp (mgr->setjmp_buffer, 1);
9355}
9356
e3130015 9357
8e39770a
GM
9358/* Init source method for JPEG data source manager. Called by
9359 jpeg_read_header() before any data is actually read. See
9360 libjpeg.doc from the JPEG lib distribution. */
9361
9362static void
9363our_init_source (cinfo)
9364 j_decompress_ptr cinfo;
9365{
9366}
9367
9368
9369/* Fill input buffer method for JPEG data source manager. Called
9370 whenever more data is needed. We read the whole image in one step,
9371 so this only adds a fake end of input marker at the end. */
9372
9373static boolean
9374our_fill_input_buffer (cinfo)
9375 j_decompress_ptr cinfo;
9376{
9377 /* Insert a fake EOI marker. */
9378 struct jpeg_source_mgr *src = cinfo->src;
9379 static JOCTET buffer[2];
9380
9381 buffer[0] = (JOCTET) 0xFF;
9382 buffer[1] = (JOCTET) JPEG_EOI;
9383
9384 src->next_input_byte = buffer;
9385 src->bytes_in_buffer = 2;
9386 return TRUE;
9387}
9388
9389
9390/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
9391 is the JPEG data source manager. */
9392
9393static void
9394our_skip_input_data (cinfo, num_bytes)
9395 j_decompress_ptr cinfo;
9396 long num_bytes;
9397{
9398 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
9399
9400 if (src)
9401 {
9402 if (num_bytes > src->bytes_in_buffer)
5ad6a5fb 9403 ERREXIT (cinfo, JERR_INPUT_EOF);
8e39770a
GM
9404
9405 src->bytes_in_buffer -= num_bytes;
9406 src->next_input_byte += num_bytes;
9407 }
9408}
9409
9410
9411/* Method to terminate data source. Called by
9412 jpeg_finish_decompress() after all data has been processed. */
9413
9414static void
9415our_term_source (cinfo)
9416 j_decompress_ptr cinfo;
9417{
9418}
9419
9420
9421/* Set up the JPEG lib for reading an image from DATA which contains
9422 LEN bytes. CINFO is the decompression info structure created for
9423 reading the image. */
9424
9425static void
9426jpeg_memory_src (cinfo, data, len)
9427 j_decompress_ptr cinfo;
9428 JOCTET *data;
9429 unsigned int len;
9430{
9431 struct jpeg_source_mgr *src;
9432
9433 if (cinfo->src == NULL)
9434 {
9435 /* First time for this JPEG object? */
9436 cinfo->src = (struct jpeg_source_mgr *)
9437 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
9438 sizeof (struct jpeg_source_mgr));
9439 src = (struct jpeg_source_mgr *) cinfo->src;
9440 src->next_input_byte = data;
9441 }
9442
9443 src = (struct jpeg_source_mgr *) cinfo->src;
9444 src->init_source = our_init_source;
9445 src->fill_input_buffer = our_fill_input_buffer;
9446 src->skip_input_data = our_skip_input_data;
9447 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
9448 src->term_source = our_term_source;
9449 src->bytes_in_buffer = len;
9450 src->next_input_byte = data;
9451}
9452
5ad6a5fb 9453
333b20bb
GM
9454/* Load image IMG for use on frame F. Patterned after example.c
9455 from the JPEG lib. */
9456
9457static int
9458jpeg_load (f, img)
9459 struct frame *f;
9460 struct image *img;
9461{
9462 struct jpeg_decompress_struct cinfo;
9463 struct my_jpeg_error_mgr mgr;
9464 Lisp_Object file, specified_file;
8e39770a 9465 Lisp_Object specified_data;
8ec8a5ec 9466 FILE * volatile fp = NULL;
333b20bb
GM
9467 JSAMPARRAY buffer;
9468 int row_stride, x, y;
9469 XImage *ximg = NULL;
b6d7acec 9470 int rc;
333b20bb
GM
9471 unsigned long *colors;
9472 int width, height;
9473 struct gcpro gcpro1;
9474
9475 /* Open the JPEG file. */
9476 specified_file = image_spec_value (img->spec, QCfile, NULL);
8e39770a 9477 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9478 file = Qnil;
9479 GCPRO1 (file);
8e39770a 9480
8e39770a 9481 if (NILP (specified_data))
333b20bb 9482 {
8e39770a 9483 file = x_find_image_file (specified_file);
8e39770a
GM
9484 if (!STRINGP (file))
9485 {
45158a91 9486 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8e39770a
GM
9487 UNGCPRO;
9488 return 0;
9489 }
333b20bb 9490
8e39770a
GM
9491 fp = fopen (XSTRING (file)->data, "r");
9492 if (fp == NULL)
9493 {
9494 image_error ("Cannot open `%s'", file, Qnil);
9495 UNGCPRO;
9496 return 0;
9497 }
333b20bb
GM
9498 }
9499
5ad6a5fb
GM
9500 /* Customize libjpeg's error handling to call my_error_exit when an
9501 error is detected. This function will perform a longjmp. */
333b20bb 9502 cinfo.err = jpeg_std_error (&mgr.pub);
14358466 9503 mgr.pub.error_exit = my_error_exit;
333b20bb
GM
9504
9505 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
9506 {
5ad6a5fb
GM
9507 if (rc == 1)
9508 {
9509 /* Called from my_error_exit. Display a JPEG error. */
9510 char buffer[JMSG_LENGTH_MAX];
9511 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
45158a91 9512 image_error ("Error reading JPEG image `%s': %s", img->spec,
5ad6a5fb
GM
9513 build_string (buffer));
9514 }
333b20bb
GM
9515
9516 /* Close the input file and destroy the JPEG object. */
5ad6a5fb 9517 if (fp)
8ec8a5ec 9518 fclose ((FILE *) fp);
333b20bb
GM
9519 jpeg_destroy_decompress (&cinfo);
9520
5ad6a5fb
GM
9521 /* If we already have an XImage, free that. */
9522 x_destroy_x_image (ximg);
333b20bb 9523
5ad6a5fb
GM
9524 /* Free pixmap and colors. */
9525 x_clear_image (f, img);
333b20bb 9526
5ad6a5fb
GM
9527 UNGCPRO;
9528 return 0;
333b20bb
GM
9529 }
9530
9531 /* Create the JPEG decompression object. Let it read from fp.
63448a4d 9532 Read the JPEG image header. */
333b20bb 9533 jpeg_create_decompress (&cinfo);
8e39770a
GM
9534
9535 if (NILP (specified_data))
8ec8a5ec 9536 jpeg_stdio_src (&cinfo, (FILE *) fp);
8e39770a
GM
9537 else
9538 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
9539 STRING_BYTES (XSTRING (specified_data)));
63448a4d 9540
333b20bb
GM
9541 jpeg_read_header (&cinfo, TRUE);
9542
9543 /* Customize decompression so that color quantization will be used.
63448a4d 9544 Start decompression. */
333b20bb
GM
9545 cinfo.quantize_colors = TRUE;
9546 jpeg_start_decompress (&cinfo);
9547 width = img->width = cinfo.output_width;
9548 height = img->height = cinfo.output_height;
9549
333b20bb 9550 /* Create X image and pixmap. */
45158a91 9551 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
28c7826c 9552 longjmp (mgr.setjmp_buffer, 2);
333b20bb
GM
9553
9554 /* Allocate colors. When color quantization is used,
5ad6a5fb
GM
9555 cinfo.actual_number_of_colors has been set with the number of
9556 colors generated, and cinfo.colormap is a two-dimensional array
9557 of color indices in the range 0..cinfo.actual_number_of_colors.
9558 No more than 255 colors will be generated. */
333b20bb 9559 {
5ad6a5fb
GM
9560 int i, ir, ig, ib;
9561
9562 if (cinfo.out_color_components > 2)
9563 ir = 0, ig = 1, ib = 2;
9564 else if (cinfo.out_color_components > 1)
9565 ir = 0, ig = 1, ib = 0;
9566 else
9567 ir = 0, ig = 0, ib = 0;
9568
9569 /* Use the color table mechanism because it handles colors that
9570 cannot be allocated nicely. Such colors will be replaced with
9571 a default color, and we don't have to care about which colors
9572 can be freed safely, and which can't. */
9573 init_color_table ();
9574 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
9575 * sizeof *colors);
333b20bb 9576
5ad6a5fb
GM
9577 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
9578 {
9579 /* Multiply RGB values with 255 because X expects RGB values
9580 in the range 0..0xffff. */
9581 int r = cinfo.colormap[ir][i] << 8;
9582 int g = cinfo.colormap[ig][i] << 8;
9583 int b = cinfo.colormap[ib][i] << 8;
9584 colors[i] = lookup_rgb_color (f, r, g, b);
9585 }
333b20bb 9586
5ad6a5fb
GM
9587 /* Remember those colors actually allocated. */
9588 img->colors = colors_in_color_table (&img->ncolors);
9589 free_color_table ();
333b20bb
GM
9590 }
9591
9592 /* Read pixels. */
9593 row_stride = width * cinfo.output_components;
9594 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
5ad6a5fb 9595 row_stride, 1);
333b20bb
GM
9596 for (y = 0; y < height; ++y)
9597 {
5ad6a5fb
GM
9598 jpeg_read_scanlines (&cinfo, buffer, 1);
9599 for (x = 0; x < cinfo.output_width; ++x)
9600 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
333b20bb
GM
9601 }
9602
9603 /* Clean up. */
9604 jpeg_finish_decompress (&cinfo);
9605 jpeg_destroy_decompress (&cinfo);
5ad6a5fb 9606 if (fp)
8ec8a5ec 9607 fclose ((FILE *) fp);
f20a3b7a
MB
9608
9609 /* Maybe fill in the background field while we have ximg handy. */
9610 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9611 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9612
9613 /* Put the image into the pixmap. */
9614 x_put_x_image (f, ximg, img->pixmap, width, height);
9615 x_destroy_x_image (ximg);
333b20bb
GM
9616 UNGCPRO;
9617 return 1;
9618}
9619
9620#endif /* HAVE_JPEG */
9621
9622
9623\f
9624/***********************************************************************
9625 TIFF
9626 ***********************************************************************/
9627
9628#if HAVE_TIFF
9629
cf4790ad 9630#include <tiffio.h>
333b20bb
GM
9631
9632static int tiff_image_p P_ ((Lisp_Object object));
9633static int tiff_load P_ ((struct frame *f, struct image *img));
9634
9635/* The symbol `tiff' identifying images of this type. */
9636
9637Lisp_Object Qtiff;
9638
9639/* Indices of image specification fields in tiff_format, below. */
9640
9641enum tiff_keyword_index
9642{
9643 TIFF_TYPE,
63448a4d 9644 TIFF_DATA,
333b20bb
GM
9645 TIFF_FILE,
9646 TIFF_ASCENT,
9647 TIFF_MARGIN,
9648 TIFF_RELIEF,
9649 TIFF_ALGORITHM,
9650 TIFF_HEURISTIC_MASK,
4a8e312c 9651 TIFF_MASK,
f20a3b7a 9652 TIFF_BACKGROUND,
333b20bb
GM
9653 TIFF_LAST
9654};
9655
9656/* Vector of image_keyword structures describing the format
9657 of valid user-defined image specifications. */
9658
9659static struct image_keyword tiff_format[TIFF_LAST] =
9660{
9661 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9662 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9663 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9664 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9665 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9666 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9667 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9668 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9669 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9670 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9671};
9672
9673/* Structure describing the image type `tiff'. */
9674
9675static struct image_type tiff_type =
9676{
9677 &Qtiff,
9678 tiff_image_p,
9679 tiff_load,
9680 x_clear_image,
9681 NULL
9682};
9683
9684
9685/* Return non-zero if OBJECT is a valid TIFF image specification. */
9686
9687static int
9688tiff_image_p (object)
9689 Lisp_Object object;
9690{
9691 struct image_keyword fmt[TIFF_LAST];
9692 bcopy (tiff_format, fmt, sizeof fmt);
9693
7c7ff7f5 9694 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
333b20bb 9695 return 0;
5ad6a5fb 9696
63cec32f
GM
9697 /* Must specify either the :data or :file keyword. */
9698 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
333b20bb
GM
9699}
9700
5ad6a5fb
GM
9701
9702/* Reading from a memory buffer for TIFF images Based on the PNG
9703 memory source, but we have to provide a lot of extra functions.
9704 Blah.
63448a4d
WP
9705
9706 We really only need to implement read and seek, but I am not
9707 convinced that the TIFF library is smart enough not to destroy
9708 itself if we only hand it the function pointers we need to
5ad6a5fb
GM
9709 override. */
9710
9711typedef struct
9712{
63448a4d
WP
9713 unsigned char *bytes;
9714 size_t len;
9715 int index;
5ad6a5fb
GM
9716}
9717tiff_memory_source;
63448a4d 9718
e3130015 9719
5ad6a5fb
GM
9720static size_t
9721tiff_read_from_memory (data, buf, size)
9722 thandle_t data;
9723 tdata_t buf;
9724 tsize_t size;
63448a4d 9725{
5ad6a5fb 9726 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9727
9728 if (size > src->len - src->index)
5ad6a5fb
GM
9729 return (size_t) -1;
9730 bcopy (src->bytes + src->index, buf, size);
63448a4d
WP
9731 src->index += size;
9732 return size;
9733}
9734
e3130015 9735
5ad6a5fb
GM
9736static size_t
9737tiff_write_from_memory (data, buf, size)
9738 thandle_t data;
9739 tdata_t buf;
9740 tsize_t size;
63448a4d
WP
9741{
9742 return (size_t) -1;
9743}
9744
e3130015 9745
5ad6a5fb
GM
9746static toff_t
9747tiff_seek_in_memory (data, off, whence)
9748 thandle_t data;
9749 toff_t off;
9750 int whence;
63448a4d 9751{
5ad6a5fb 9752 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9753 int idx;
9754
9755 switch (whence)
5ad6a5fb
GM
9756 {
9757 case SEEK_SET: /* Go from beginning of source. */
9758 idx = off;
9759 break;
9760
9761 case SEEK_END: /* Go from end of source. */
9762 idx = src->len + off;
9763 break;
9764
9765 case SEEK_CUR: /* Go from current position. */
9766 idx = src->index + off;
9767 break;
9768
9769 default: /* Invalid `whence'. */
9770 return -1;
9771 }
9772
9773 if (idx > src->len || idx < 0)
9774 return -1;
9775
63448a4d
WP
9776 src->index = idx;
9777 return src->index;
9778}
9779
e3130015 9780
5ad6a5fb
GM
9781static int
9782tiff_close_memory (data)
9783 thandle_t data;
63448a4d
WP
9784{
9785 /* NOOP */
5ad6a5fb 9786 return 0;
63448a4d
WP
9787}
9788
e3130015 9789
5ad6a5fb
GM
9790static int
9791tiff_mmap_memory (data, pbase, psize)
9792 thandle_t data;
9793 tdata_t *pbase;
9794 toff_t *psize;
63448a4d
WP
9795{
9796 /* It is already _IN_ memory. */
5ad6a5fb 9797 return 0;
63448a4d
WP
9798}
9799
e3130015 9800
5ad6a5fb
GM
9801static void
9802tiff_unmap_memory (data, base, size)
9803 thandle_t data;
9804 tdata_t base;
9805 toff_t size;
63448a4d
WP
9806{
9807 /* We don't need to do this. */
63448a4d
WP
9808}
9809
e3130015 9810
5ad6a5fb
GM
9811static toff_t
9812tiff_size_of_memory (data)
9813 thandle_t data;
63448a4d 9814{
5ad6a5fb 9815 return ((tiff_memory_source *) data)->len;
63448a4d 9816}
333b20bb 9817
e3130015 9818
c6892044
GM
9819static void
9820tiff_error_handler (title, format, ap)
9821 const char *title, *format;
9822 va_list ap;
9823{
9824 char buf[512];
9825 int len;
9826
9827 len = sprintf (buf, "TIFF error: %s ", title);
9828 vsprintf (buf + len, format, ap);
9829 add_to_log (buf, Qnil, Qnil);
9830}
9831
9832
9833static void
9834tiff_warning_handler (title, format, ap)
9835 const char *title, *format;
9836 va_list ap;
9837{
9838 char buf[512];
9839 int len;
9840
9841 len = sprintf (buf, "TIFF warning: %s ", title);
9842 vsprintf (buf + len, format, ap);
9843 add_to_log (buf, Qnil, Qnil);
9844}
9845
9846
333b20bb
GM
9847/* Load TIFF image IMG for use on frame F. Value is non-zero if
9848 successful. */
9849
9850static int
9851tiff_load (f, img)
9852 struct frame *f;
9853 struct image *img;
9854{
9855 Lisp_Object file, specified_file;
63448a4d 9856 Lisp_Object specified_data;
333b20bb
GM
9857 TIFF *tiff;
9858 int width, height, x, y;
9859 uint32 *buf;
9860 int rc;
9861 XImage *ximg;
9862 struct gcpro gcpro1;
63448a4d 9863 tiff_memory_source memsrc;
333b20bb
GM
9864
9865 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9866 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9867 file = Qnil;
9868 GCPRO1 (file);
63448a4d 9869
c6892044
GM
9870 TIFFSetErrorHandler (tiff_error_handler);
9871 TIFFSetWarningHandler (tiff_warning_handler);
9872
63448a4d 9873 if (NILP (specified_data))
5ad6a5fb
GM
9874 {
9875 /* Read from a file */
9876 file = x_find_image_file (specified_file);
9877 if (!STRINGP (file))
63448a4d 9878 {
45158a91 9879 image_error ("Cannot find image file `%s'", file, Qnil);
5ad6a5fb
GM
9880 UNGCPRO;
9881 return 0;
9882 }
63448a4d 9883
5ad6a5fb
GM
9884 /* Try to open the image file. */
9885 tiff = TIFFOpen (XSTRING (file)->data, "r");
9886 if (tiff == NULL)
9887 {
9888 image_error ("Cannot open `%s'", file, Qnil);
9889 UNGCPRO;
9890 return 0;
63448a4d 9891 }
5ad6a5fb 9892 }
63448a4d 9893 else
5ad6a5fb
GM
9894 {
9895 /* Memory source! */
9896 memsrc.bytes = XSTRING (specified_data)->data;
9897 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9898 memsrc.index = 0;
9899
9900 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9901 (TIFFReadWriteProc) tiff_read_from_memory,
9902 (TIFFReadWriteProc) tiff_write_from_memory,
9903 tiff_seek_in_memory,
9904 tiff_close_memory,
9905 tiff_size_of_memory,
9906 tiff_mmap_memory,
9907 tiff_unmap_memory);
9908
9909 if (!tiff)
63448a4d 9910 {
45158a91 9911 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
5ad6a5fb
GM
9912 UNGCPRO;
9913 return 0;
63448a4d 9914 }
5ad6a5fb 9915 }
333b20bb
GM
9916
9917 /* Get width and height of the image, and allocate a raster buffer
9918 of width x height 32-bit values. */
9919 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9920 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9921 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9922
9923 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9924 TIFFClose (tiff);
9925 if (!rc)
9926 {
45158a91 9927 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
333b20bb
GM
9928 xfree (buf);
9929 UNGCPRO;
9930 return 0;
9931 }
9932
333b20bb 9933 /* Create the X image and pixmap. */
45158a91 9934 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9935 {
333b20bb
GM
9936 xfree (buf);
9937 UNGCPRO;
9938 return 0;
9939 }
9940
9941 /* Initialize the color table. */
9942 init_color_table ();
9943
9944 /* Process the pixel raster. Origin is in the lower-left corner. */
9945 for (y = 0; y < height; ++y)
9946 {
9947 uint32 *row = buf + y * width;
9948
9949 for (x = 0; x < width; ++x)
9950 {
9951 uint32 abgr = row[x];
9952 int r = TIFFGetR (abgr) << 8;
9953 int g = TIFFGetG (abgr) << 8;
9954 int b = TIFFGetB (abgr) << 8;
9955 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9956 }
9957 }
9958
9959 /* Remember the colors allocated for the image. Free the color table. */
9960 img->colors = colors_in_color_table (&img->ncolors);
9961 free_color_table ();
f20a3b7a
MB
9962
9963 img->width = width;
9964 img->height = height;
9965
9966 /* Maybe fill in the background field while we have ximg handy. */
9967 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9968 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9969
9970 /* Put the image into the pixmap, then free the X image and its buffer. */
9971 x_put_x_image (f, ximg, img->pixmap, width, height);
9972 x_destroy_x_image (ximg);
9973 xfree (buf);
333b20bb
GM
9974
9975 UNGCPRO;
9976 return 1;
9977}
9978
9979#endif /* HAVE_TIFF != 0 */
9980
9981
9982\f
9983/***********************************************************************
9984 GIF
9985 ***********************************************************************/
9986
9987#if HAVE_GIF
9988
9989#include <gif_lib.h>
9990
9991static int gif_image_p P_ ((Lisp_Object object));
9992static int gif_load P_ ((struct frame *f, struct image *img));
9993
9994/* The symbol `gif' identifying images of this type. */
9995
9996Lisp_Object Qgif;
9997
9998/* Indices of image specification fields in gif_format, below. */
9999
10000enum gif_keyword_index
10001{
10002 GIF_TYPE,
63448a4d 10003 GIF_DATA,
333b20bb
GM
10004 GIF_FILE,
10005 GIF_ASCENT,
10006 GIF_MARGIN,
10007 GIF_RELIEF,
10008 GIF_ALGORITHM,
10009 GIF_HEURISTIC_MASK,
4a8e312c 10010 GIF_MASK,
333b20bb 10011 GIF_IMAGE,
f20a3b7a 10012 GIF_BACKGROUND,
333b20bb
GM
10013 GIF_LAST
10014};
10015
10016/* Vector of image_keyword structures describing the format
10017 of valid user-defined image specifications. */
10018
10019static struct image_keyword gif_format[GIF_LAST] =
10020{
10021 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 10022 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 10023 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 10024 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10025 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10026 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10027 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 10028 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10029 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 10030 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
f20a3b7a 10031 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10032};
10033
10034/* Structure describing the image type `gif'. */
10035
10036static struct image_type gif_type =
10037{
10038 &Qgif,
10039 gif_image_p,
10040 gif_load,
10041 x_clear_image,
10042 NULL
10043};
10044
e3130015 10045
333b20bb
GM
10046/* Return non-zero if OBJECT is a valid GIF image specification. */
10047
10048static int
10049gif_image_p (object)
10050 Lisp_Object object;
10051{
10052 struct image_keyword fmt[GIF_LAST];
10053 bcopy (gif_format, fmt, sizeof fmt);
10054
7c7ff7f5 10055 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
333b20bb 10056 return 0;
5ad6a5fb 10057
63cec32f
GM
10058 /* Must specify either the :data or :file keyword. */
10059 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
333b20bb
GM
10060}
10061
e3130015 10062
63448a4d
WP
10063/* Reading a GIF image from memory
10064 Based on the PNG memory stuff to a certain extent. */
10065
5ad6a5fb
GM
10066typedef struct
10067{
63448a4d
WP
10068 unsigned char *bytes;
10069 size_t len;
10070 int index;
5ad6a5fb
GM
10071}
10072gif_memory_source;
63448a4d 10073
e3130015 10074
f036834a
GM
10075/* Make the current memory source available to gif_read_from_memory.
10076 It's done this way because not all versions of libungif support
10077 a UserData field in the GifFileType structure. */
10078static gif_memory_source *current_gif_memory_src;
10079
5ad6a5fb
GM
10080static int
10081gif_read_from_memory (file, buf, len)
10082 GifFileType *file;
10083 GifByteType *buf;
10084 int len;
63448a4d 10085{
f036834a 10086 gif_memory_source *src = current_gif_memory_src;
63448a4d 10087
5ad6a5fb
GM
10088 if (len > src->len - src->index)
10089 return -1;
63448a4d 10090
5ad6a5fb 10091 bcopy (src->bytes + src->index, buf, len);
63448a4d
WP
10092 src->index += len;
10093 return len;
10094}
333b20bb 10095
5ad6a5fb 10096
333b20bb
GM
10097/* Load GIF image IMG for use on frame F. Value is non-zero if
10098 successful. */
10099
10100static int
10101gif_load (f, img)
10102 struct frame *f;
10103 struct image *img;
10104{
10105 Lisp_Object file, specified_file;
63448a4d 10106 Lisp_Object specified_data;
333b20bb
GM
10107 int rc, width, height, x, y, i;
10108 XImage *ximg;
10109 ColorMapObject *gif_color_map;
10110 unsigned long pixel_colors[256];
10111 GifFileType *gif;
10112 struct gcpro gcpro1;
10113 Lisp_Object image;
10114 int ino, image_left, image_top, image_width, image_height;
63448a4d 10115 gif_memory_source memsrc;
9b784e96 10116 unsigned char *raster;
333b20bb
GM
10117
10118 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 10119 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
10120 file = Qnil;
10121 GCPRO1 (file);
63448a4d
WP
10122
10123 if (NILP (specified_data))
5ad6a5fb
GM
10124 {
10125 file = x_find_image_file (specified_file);
10126 if (!STRINGP (file))
63448a4d 10127 {
45158a91 10128 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
10129 UNGCPRO;
10130 return 0;
10131 }
333b20bb 10132
5ad6a5fb
GM
10133 /* Open the GIF file. */
10134 gif = DGifOpenFileName (XSTRING (file)->data);
10135 if (gif == NULL)
10136 {
10137 image_error ("Cannot open `%s'", file, Qnil);
10138 UNGCPRO;
10139 return 0;
63448a4d 10140 }
5ad6a5fb 10141 }
63448a4d 10142 else
5ad6a5fb
GM
10143 {
10144 /* Read from memory! */
f036834a 10145 current_gif_memory_src = &memsrc;
5ad6a5fb
GM
10146 memsrc.bytes = XSTRING (specified_data)->data;
10147 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10148 memsrc.index = 0;
63448a4d 10149
5ad6a5fb
GM
10150 gif = DGifOpen(&memsrc, gif_read_from_memory);
10151 if (!gif)
10152 {
45158a91 10153 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
5ad6a5fb
GM
10154 UNGCPRO;
10155 return 0;
63448a4d 10156 }
5ad6a5fb 10157 }
333b20bb
GM
10158
10159 /* Read entire contents. */
10160 rc = DGifSlurp (gif);
10161 if (rc == GIF_ERROR)
10162 {
45158a91 10163 image_error ("Error reading `%s'", img->spec, Qnil);
333b20bb
GM
10164 DGifCloseFile (gif);
10165 UNGCPRO;
10166 return 0;
10167 }
10168
3ccff1e3 10169 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
10170 ino = INTEGERP (image) ? XFASTINT (image) : 0;
10171 if (ino >= gif->ImageCount)
10172 {
45158a91
GM
10173 image_error ("Invalid image number `%s' in image `%s'",
10174 image, img->spec);
333b20bb
GM
10175 DGifCloseFile (gif);
10176 UNGCPRO;
10177 return 0;
10178 }
10179
c7f07c4c
PJ
10180 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
10181 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
333b20bb 10182
333b20bb 10183 /* Create the X image and pixmap. */
45158a91 10184 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 10185 {
333b20bb
GM
10186 DGifCloseFile (gif);
10187 UNGCPRO;
10188 return 0;
10189 }
10190
10191 /* Allocate colors. */
10192 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
10193 if (!gif_color_map)
10194 gif_color_map = gif->SColorMap;
10195 init_color_table ();
10196 bzero (pixel_colors, sizeof pixel_colors);
10197
10198 for (i = 0; i < gif_color_map->ColorCount; ++i)
10199 {
10200 int r = gif_color_map->Colors[i].Red << 8;
10201 int g = gif_color_map->Colors[i].Green << 8;
10202 int b = gif_color_map->Colors[i].Blue << 8;
10203 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
10204 }
10205
10206 img->colors = colors_in_color_table (&img->ncolors);
10207 free_color_table ();
10208
10209 /* Clear the part of the screen image that are not covered by
10210 the image from the GIF file. Full animated GIF support
10211 requires more than can be done here (see the gif89 spec,
10212 disposal methods). Let's simply assume that the part
10213 not covered by a sub-image is in the frame's background color. */
10214 image_top = gif->SavedImages[ino].ImageDesc.Top;
10215 image_left = gif->SavedImages[ino].ImageDesc.Left;
10216 image_width = gif->SavedImages[ino].ImageDesc.Width;
10217 image_height = gif->SavedImages[ino].ImageDesc.Height;
10218
10219 for (y = 0; y < image_top; ++y)
10220 for (x = 0; x < width; ++x)
10221 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10222
10223 for (y = image_top + image_height; y < height; ++y)
10224 for (x = 0; x < width; ++x)
10225 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10226
10227 for (y = image_top; y < image_top + image_height; ++y)
10228 {
10229 for (x = 0; x < image_left; ++x)
10230 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10231 for (x = image_left + image_width; x < width; ++x)
10232 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10233 }
10234
9b784e96
GM
10235 /* Read the GIF image into the X image. We use a local variable
10236 `raster' here because RasterBits below is a char *, and invites
10237 problems with bytes >= 0x80. */
10238 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
10239
333b20bb
GM
10240 if (gif->SavedImages[ino].ImageDesc.Interlace)
10241 {
10242 static int interlace_start[] = {0, 4, 2, 1};
10243 static int interlace_increment[] = {8, 8, 4, 2};
9b207e8e 10244 int pass;
06482119
GM
10245 int row = interlace_start[0];
10246
10247 pass = 0;
333b20bb 10248
06482119 10249 for (y = 0; y < image_height; y++)
333b20bb 10250 {
06482119
GM
10251 if (row >= image_height)
10252 {
10253 row = interlace_start[++pass];
10254 while (row >= image_height)
10255 row = interlace_start[++pass];
10256 }
10257
10258 for (x = 0; x < image_width; x++)
10259 {
9b784e96 10260 int i = raster[(y * image_width) + x];
06482119
GM
10261 XPutPixel (ximg, x + image_left, row + image_top,
10262 pixel_colors[i]);
10263 }
10264
10265 row += interlace_increment[pass];
333b20bb
GM
10266 }
10267 }
10268 else
10269 {
10270 for (y = 0; y < image_height; ++y)
10271 for (x = 0; x < image_width; ++x)
10272 {
9b784e96 10273 int i = raster[y * image_width + x];
333b20bb
GM
10274 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
10275 }
10276 }
10277
10278 DGifCloseFile (gif);
f20a3b7a
MB
10279
10280 /* Maybe fill in the background field while we have ximg handy. */
10281 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10282 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
10283
10284 /* Put the image into the pixmap, then free the X image and its buffer. */
10285 x_put_x_image (f, ximg, img->pixmap, width, height);
10286 x_destroy_x_image (ximg);
333b20bb
GM
10287
10288 UNGCPRO;
10289 return 1;
10290}
10291
10292#endif /* HAVE_GIF != 0 */
10293
10294
10295\f
10296/***********************************************************************
10297 Ghostscript
10298 ***********************************************************************/
10299
10300static int gs_image_p P_ ((Lisp_Object object));
10301static int gs_load P_ ((struct frame *f, struct image *img));
10302static void gs_clear_image P_ ((struct frame *f, struct image *img));
10303
fcf431dc 10304/* The symbol `postscript' identifying images of this type. */
333b20bb 10305
fcf431dc 10306Lisp_Object Qpostscript;
333b20bb
GM
10307
10308/* Keyword symbols. */
10309
10310Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
10311
10312/* Indices of image specification fields in gs_format, below. */
10313
10314enum gs_keyword_index
10315{
10316 GS_TYPE,
10317 GS_PT_WIDTH,
10318 GS_PT_HEIGHT,
10319 GS_FILE,
10320 GS_LOADER,
10321 GS_BOUNDING_BOX,
10322 GS_ASCENT,
10323 GS_MARGIN,
10324 GS_RELIEF,
10325 GS_ALGORITHM,
10326 GS_HEURISTIC_MASK,
4a8e312c 10327 GS_MASK,
f20a3b7a 10328 GS_BACKGROUND,
333b20bb
GM
10329 GS_LAST
10330};
10331
10332/* Vector of image_keyword structures describing the format
10333 of valid user-defined image specifications. */
10334
10335static struct image_keyword gs_format[GS_LAST] =
10336{
10337 {":type", IMAGE_SYMBOL_VALUE, 1},
10338 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10339 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10340 {":file", IMAGE_STRING_VALUE, 1},
10341 {":loader", IMAGE_FUNCTION_VALUE, 0},
10342 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7c7ff7f5 10343 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10344 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10345 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10346 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10347 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
10348 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10349 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10350};
10351
10352/* Structure describing the image type `ghostscript'. */
10353
10354static struct image_type gs_type =
10355{
fcf431dc 10356 &Qpostscript,
333b20bb
GM
10357 gs_image_p,
10358 gs_load,
10359 gs_clear_image,
10360 NULL
10361};
10362
10363
10364/* Free X resources of Ghostscript image IMG which is used on frame F. */
10365
10366static void
10367gs_clear_image (f, img)
10368 struct frame *f;
10369 struct image *img;
10370{
10371 /* IMG->data.ptr_val may contain a recorded colormap. */
10372 xfree (img->data.ptr_val);
10373 x_clear_image (f, img);
10374}
10375
10376
10377/* Return non-zero if OBJECT is a valid Ghostscript image
10378 specification. */
10379
10380static int
10381gs_image_p (object)
10382 Lisp_Object object;
10383{
10384 struct image_keyword fmt[GS_LAST];
10385 Lisp_Object tem;
10386 int i;
10387
10388 bcopy (gs_format, fmt, sizeof fmt);
10389
7c7ff7f5 10390 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
333b20bb
GM
10391 return 0;
10392
10393 /* Bounding box must be a list or vector containing 4 integers. */
10394 tem = fmt[GS_BOUNDING_BOX].value;
10395 if (CONSP (tem))
10396 {
10397 for (i = 0; i < 4; ++i, tem = XCDR (tem))
10398 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
10399 return 0;
10400 if (!NILP (tem))
10401 return 0;
10402 }
10403 else if (VECTORP (tem))
10404 {
10405 if (XVECTOR (tem)->size != 4)
10406 return 0;
10407 for (i = 0; i < 4; ++i)
10408 if (!INTEGERP (XVECTOR (tem)->contents[i]))
10409 return 0;
10410 }
10411 else
10412 return 0;
10413
10414 return 1;
10415}
10416
10417
10418/* Load Ghostscript image IMG for use on frame F. Value is non-zero
10419 if successful. */
10420
10421static int
10422gs_load (f, img)
10423 struct frame *f;
10424 struct image *img;
10425{
10426 char buffer[100];
10427 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
10428 struct gcpro gcpro1, gcpro2;
10429 Lisp_Object frame;
10430 double in_width, in_height;
10431 Lisp_Object pixel_colors = Qnil;
10432
10433 /* Compute pixel size of pixmap needed from the given size in the
10434 image specification. Sizes in the specification are in pt. 1 pt
10435 = 1/72 in, xdpi and ydpi are stored in the frame's X display
10436 info. */
10437 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
10438 in_width = XFASTINT (pt_width) / 72.0;
10439 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
10440 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
10441 in_height = XFASTINT (pt_height) / 72.0;
10442 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
10443
10444 /* Create the pixmap. */
dd00328a 10445 xassert (img->pixmap == None);
333b20bb
GM
10446 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10447 img->width, img->height,
10448 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
333b20bb
GM
10449
10450 if (!img->pixmap)
10451 {
45158a91 10452 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
10453 return 0;
10454 }
10455
10456 /* Call the loader to fill the pixmap. It returns a process object
10457 if successful. We do not record_unwind_protect here because
10458 other places in redisplay like calling window scroll functions
10459 don't either. Let the Lisp loader use `unwind-protect' instead. */
10460 GCPRO2 (window_and_pixmap_id, pixel_colors);
10461
10462 sprintf (buffer, "%lu %lu",
10463 (unsigned long) FRAME_X_WINDOW (f),
10464 (unsigned long) img->pixmap);
10465 window_and_pixmap_id = build_string (buffer);
10466
10467 sprintf (buffer, "%lu %lu",
10468 FRAME_FOREGROUND_PIXEL (f),
10469 FRAME_BACKGROUND_PIXEL (f));
10470 pixel_colors = build_string (buffer);
10471
10472 XSETFRAME (frame, f);
10473 loader = image_spec_value (img->spec, QCloader, NULL);
10474 if (NILP (loader))
10475 loader = intern ("gs-load-image");
10476
10477 img->data.lisp_val = call6 (loader, frame, img->spec,
10478 make_number (img->width),
10479 make_number (img->height),
10480 window_and_pixmap_id,
10481 pixel_colors);
10482 UNGCPRO;
10483 return PROCESSP (img->data.lisp_val);
10484}
10485
10486
10487/* Kill the Ghostscript process that was started to fill PIXMAP on
10488 frame F. Called from XTread_socket when receiving an event
10489 telling Emacs that Ghostscript has finished drawing. */
10490
10491void
10492x_kill_gs_process (pixmap, f)
10493 Pixmap pixmap;
10494 struct frame *f;
10495{
10496 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
10497 int class, i;
10498 struct image *img;
10499
10500 /* Find the image containing PIXMAP. */
10501 for (i = 0; i < c->used; ++i)
10502 if (c->images[i]->pixmap == pixmap)
10503 break;
10504
daba7643
GM
10505 /* Should someone in between have cleared the image cache, for
10506 instance, give up. */
10507 if (i == c->used)
10508 return;
10509
333b20bb
GM
10510 /* Kill the GS process. We should have found PIXMAP in the image
10511 cache and its image should contain a process object. */
333b20bb
GM
10512 img = c->images[i];
10513 xassert (PROCESSP (img->data.lisp_val));
10514 Fkill_process (img->data.lisp_val, Qnil);
10515 img->data.lisp_val = Qnil;
10516
10517 /* On displays with a mutable colormap, figure out the colors
10518 allocated for the image by looking at the pixels of an XImage for
10519 img->pixmap. */
383d6ffc 10520 class = FRAME_X_VISUAL (f)->class;
333b20bb
GM
10521 if (class != StaticColor && class != StaticGray && class != TrueColor)
10522 {
10523 XImage *ximg;
10524
10525 BLOCK_INPUT;
10526
10527 /* Try to get an XImage for img->pixmep. */
10528 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10529 0, 0, img->width, img->height, ~0, ZPixmap);
10530 if (ximg)
10531 {
10532 int x, y;
10533
10534 /* Initialize the color table. */
10535 init_color_table ();
10536
10537 /* For each pixel of the image, look its color up in the
10538 color table. After having done so, the color table will
10539 contain an entry for each color used by the image. */
10540 for (y = 0; y < img->height; ++y)
10541 for (x = 0; x < img->width; ++x)
10542 {
10543 unsigned long pixel = XGetPixel (ximg, x, y);
10544 lookup_pixel_color (f, pixel);
10545 }
10546
10547 /* Record colors in the image. Free color table and XImage. */
10548 img->colors = colors_in_color_table (&img->ncolors);
10549 free_color_table ();
10550 XDestroyImage (ximg);
10551
10552#if 0 /* This doesn't seem to be the case. If we free the colors
10553 here, we get a BadAccess later in x_clear_image when
10554 freeing the colors. */
10555 /* We have allocated colors once, but Ghostscript has also
10556 allocated colors on behalf of us. So, to get the
10557 reference counts right, free them once. */
10558 if (img->ncolors)
462d5d40 10559 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
10560#endif
10561 }
10562 else
10563 image_error ("Cannot get X image of `%s'; colors will not be freed",
45158a91 10564 img->spec, Qnil);
333b20bb
GM
10565
10566 UNBLOCK_INPUT;
10567 }
ad18ffb1
GM
10568
10569 /* Now that we have the pixmap, compute mask and transform the
10570 image if requested. */
10571 BLOCK_INPUT;
10572 postprocess_image (f, img);
10573 UNBLOCK_INPUT;
333b20bb
GM
10574}
10575
10576
10577\f
10578/***********************************************************************
10579 Window properties
10580 ***********************************************************************/
10581
10582DEFUN ("x-change-window-property", Fx_change_window_property,
10583 Sx_change_window_property, 2, 3, 0,
7ee72033 10584 doc: /* Change window property PROP to VALUE on the X window of FRAME.
c061c855 10585PROP and VALUE must be strings. FRAME nil or omitted means use the
7ee72033
MB
10586selected frame. Value is VALUE. */)
10587 (prop, value, frame)
333b20bb
GM
10588 Lisp_Object frame, prop, value;
10589{
10590 struct frame *f = check_x_frame (frame);
10591 Atom prop_atom;
10592
b7826503
PJ
10593 CHECK_STRING (prop);
10594 CHECK_STRING (value);
333b20bb
GM
10595
10596 BLOCK_INPUT;
10597 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10598 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10599 prop_atom, XA_STRING, 8, PropModeReplace,
10600 XSTRING (value)->data, XSTRING (value)->size);
10601
10602 /* Make sure the property is set when we return. */
10603 XFlush (FRAME_X_DISPLAY (f));
10604 UNBLOCK_INPUT;
10605
10606 return value;
10607}
10608
10609
10610DEFUN ("x-delete-window-property", Fx_delete_window_property,
10611 Sx_delete_window_property, 1, 2, 0,
7ee72033
MB
10612 doc: /* Remove window property PROP from X window of FRAME.
10613FRAME nil or omitted means use the selected frame. Value is PROP. */)
10614 (prop, frame)
333b20bb
GM
10615 Lisp_Object prop, frame;
10616{
10617 struct frame *f = check_x_frame (frame);
10618 Atom prop_atom;
10619
b7826503 10620 CHECK_STRING (prop);
333b20bb
GM
10621 BLOCK_INPUT;
10622 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10623 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
10624
10625 /* Make sure the property is removed when we return. */
10626 XFlush (FRAME_X_DISPLAY (f));
10627 UNBLOCK_INPUT;
10628
10629 return prop;
10630}
10631
10632
10633DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
10634 1, 2, 0,
7ee72033 10635 doc: /* Value is the value of window property PROP on FRAME.
c061c855
GM
10636If FRAME is nil or omitted, use the selected frame. Value is nil
10637if FRAME hasn't a property with name PROP or if PROP has no string
7ee72033
MB
10638value. */)
10639 (prop, frame)
333b20bb
GM
10640 Lisp_Object prop, frame;
10641{
10642 struct frame *f = check_x_frame (frame);
10643 Atom prop_atom;
10644 int rc;
10645 Lisp_Object prop_value = Qnil;
10646 char *tmp_data = NULL;
10647 Atom actual_type;
10648 int actual_format;
10649 unsigned long actual_size, bytes_remaining;
10650
b7826503 10651 CHECK_STRING (prop);
333b20bb
GM
10652 BLOCK_INPUT;
10653 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10654 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10655 prop_atom, 0, 0, False, XA_STRING,
10656 &actual_type, &actual_format, &actual_size,
10657 &bytes_remaining, (unsigned char **) &tmp_data);
10658 if (rc == Success)
10659 {
10660 int size = bytes_remaining;
10661
10662 XFree (tmp_data);
10663 tmp_data = NULL;
10664
10665 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10666 prop_atom, 0, bytes_remaining,
10667 False, XA_STRING,
10668 &actual_type, &actual_format,
10669 &actual_size, &bytes_remaining,
10670 (unsigned char **) &tmp_data);
4c8c7926 10671 if (rc == Success && tmp_data)
333b20bb
GM
10672 prop_value = make_string (tmp_data, size);
10673
10674 XFree (tmp_data);
10675 }
10676
10677 UNBLOCK_INPUT;
10678 return prop_value;
10679}
10680
10681
10682\f
10683/***********************************************************************
10684 Busy cursor
10685 ***********************************************************************/
10686
4ae9a85e 10687/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 10688 an hourglass cursor on all frames. */
333b20bb 10689
0af913d7 10690static struct atimer *hourglass_atimer;
333b20bb 10691
0af913d7 10692/* Non-zero means an hourglass cursor is currently shown. */
333b20bb 10693
0af913d7 10694static int hourglass_shown_p;
333b20bb 10695
0af913d7 10696/* Number of seconds to wait before displaying an hourglass cursor. */
333b20bb 10697
0af913d7 10698static Lisp_Object Vhourglass_delay;
333b20bb 10699
0af913d7 10700/* Default number of seconds to wait before displaying an hourglass
4ae9a85e
GM
10701 cursor. */
10702
0af913d7 10703#define DEFAULT_HOURGLASS_DELAY 1
4ae9a85e
GM
10704
10705/* Function prototypes. */
10706
0af913d7
GM
10707static void show_hourglass P_ ((struct atimer *));
10708static void hide_hourglass P_ ((void));
4ae9a85e
GM
10709
10710
0af913d7 10711/* Cancel a currently active hourglass timer, and start a new one. */
4ae9a85e
GM
10712
10713void
0af913d7 10714start_hourglass ()
333b20bb 10715{
4ae9a85e 10716 EMACS_TIME delay;
3caa99d3 10717 int secs, usecs = 0;
4ae9a85e 10718
0af913d7 10719 cancel_hourglass ();
4ae9a85e 10720
0af913d7
GM
10721 if (INTEGERP (Vhourglass_delay)
10722 && XINT (Vhourglass_delay) > 0)
10723 secs = XFASTINT (Vhourglass_delay);
10724 else if (FLOATP (Vhourglass_delay)
10725 && XFLOAT_DATA (Vhourglass_delay) > 0)
3caa99d3
GM
10726 {
10727 Lisp_Object tem;
0af913d7 10728 tem = Ftruncate (Vhourglass_delay, Qnil);
3caa99d3 10729 secs = XFASTINT (tem);
0af913d7 10730 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
3caa99d3 10731 }
4ae9a85e 10732 else
0af913d7 10733 secs = DEFAULT_HOURGLASS_DELAY;
4ae9a85e 10734
3caa99d3 10735 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
10736 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
10737 show_hourglass, NULL);
4ae9a85e
GM
10738}
10739
10740
0af913d7 10741/* Cancel the hourglass cursor timer if active, hide a busy cursor if
4ae9a85e
GM
10742 shown. */
10743
10744void
0af913d7 10745cancel_hourglass ()
4ae9a85e 10746{
0af913d7 10747 if (hourglass_atimer)
99f01f62 10748 {
0af913d7
GM
10749 cancel_atimer (hourglass_atimer);
10750 hourglass_atimer = NULL;
99f01f62
GM
10751 }
10752
0af913d7
GM
10753 if (hourglass_shown_p)
10754 hide_hourglass ();
4ae9a85e
GM
10755}
10756
10757
0af913d7
GM
10758/* Timer function of hourglass_atimer. TIMER is equal to
10759 hourglass_atimer.
4ae9a85e 10760
0af913d7
GM
10761 Display an hourglass pointer on all frames by mapping the frames'
10762 hourglass_window. Set the hourglass_p flag in the frames'
10763 output_data.x structure to indicate that an hourglass cursor is
10764 shown on the frames. */
4ae9a85e
GM
10765
10766static void
0af913d7 10767show_hourglass (timer)
4ae9a85e
GM
10768 struct atimer *timer;
10769{
10770 /* The timer implementation will cancel this timer automatically
0af913d7 10771 after this function has run. Set hourglass_atimer to null
4ae9a85e 10772 so that we know the timer doesn't have to be canceled. */
0af913d7 10773 hourglass_atimer = NULL;
4ae9a85e 10774
0af913d7 10775 if (!hourglass_shown_p)
333b20bb
GM
10776 {
10777 Lisp_Object rest, frame;
4ae9a85e
GM
10778
10779 BLOCK_INPUT;
10780
333b20bb 10781 FOR_EACH_FRAME (rest, frame)
5f7a1890
GM
10782 {
10783 struct frame *f = XFRAME (frame);
10784
10785 if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
10786 {
10787 Display *dpy = FRAME_X_DISPLAY (f);
10788
10789#ifdef USE_X_TOOLKIT
10790 if (f->output_data.x->widget)
10791#else
10792 if (FRAME_OUTER_WINDOW (f))
10793#endif
10794 {
0af913d7 10795 f->output_data.x->hourglass_p = 1;
4ae9a85e 10796
0af913d7 10797 if (!f->output_data.x->hourglass_window)
5f7a1890
GM
10798 {
10799 unsigned long mask = CWCursor;
10800 XSetWindowAttributes attrs;
4ae9a85e 10801
0af913d7 10802 attrs.cursor = f->output_data.x->hourglass_cursor;
4ae9a85e 10803
0af913d7 10804 f->output_data.x->hourglass_window
5f7a1890
GM
10805 = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
10806 0, 0, 32000, 32000, 0, 0,
10807 InputOnly,
10808 CopyFromParent,
10809 mask, &attrs);
10810 }
4ae9a85e 10811
0af913d7 10812 XMapRaised (dpy, f->output_data.x->hourglass_window);
5f7a1890
GM
10813 XFlush (dpy);
10814 }
10815 }
10816 }
333b20bb 10817
0af913d7 10818 hourglass_shown_p = 1;
4ae9a85e
GM
10819 UNBLOCK_INPUT;
10820 }
333b20bb
GM
10821}
10822
10823
0af913d7
GM
10824/* Hide the hourglass pointer on all frames, if it is currently
10825 shown. */
333b20bb 10826
4ae9a85e 10827static void
0af913d7 10828hide_hourglass ()
4ae9a85e 10829{
0af913d7 10830 if (hourglass_shown_p)
333b20bb 10831 {
4ae9a85e
GM
10832 Lisp_Object rest, frame;
10833
10834 BLOCK_INPUT;
10835 FOR_EACH_FRAME (rest, frame)
333b20bb 10836 {
4ae9a85e
GM
10837 struct frame *f = XFRAME (frame);
10838
10839 if (FRAME_X_P (f)
10840 /* Watch out for newly created frames. */
0af913d7 10841 && f->output_data.x->hourglass_window)
4ae9a85e 10842 {
0af913d7
GM
10843 XUnmapWindow (FRAME_X_DISPLAY (f),
10844 f->output_data.x->hourglass_window);
10845 /* Sync here because XTread_socket looks at the
10846 hourglass_p flag that is reset to zero below. */
4ae9a85e 10847 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 10848 f->output_data.x->hourglass_p = 0;
4ae9a85e 10849 }
333b20bb 10850 }
333b20bb 10851
0af913d7 10852 hourglass_shown_p = 0;
4ae9a85e
GM
10853 UNBLOCK_INPUT;
10854 }
333b20bb
GM
10855}
10856
10857
10858\f
10859/***********************************************************************
10860 Tool tips
10861 ***********************************************************************/
10862
10863static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
275841bf 10864 Lisp_Object, Lisp_Object));
06d62053 10865static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
ab452f99 10866 Lisp_Object, int, int, int *, int *));
333b20bb 10867
44b5a125 10868/* The frame of a currently visible tooltip. */
333b20bb 10869
44b5a125 10870Lisp_Object tip_frame;
333b20bb
GM
10871
10872/* If non-nil, a timer started that hides the last tooltip when it
10873 fires. */
10874
10875Lisp_Object tip_timer;
10876Window tip_window;
10877
06d62053
GM
10878/* If non-nil, a vector of 3 elements containing the last args
10879 with which x-show-tip was called. See there. */
10880
10881Lisp_Object last_show_tip_args;
10882
d63931a2
GM
10883/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
10884
10885Lisp_Object Vx_max_tooltip_size;
10886
eaf1eea9
GM
10887
10888static Lisp_Object
10889unwind_create_tip_frame (frame)
10890 Lisp_Object frame;
10891{
c844a81a
GM
10892 Lisp_Object deleted;
10893
10894 deleted = unwind_create_frame (frame);
10895 if (EQ (deleted, Qt))
10896 {
10897 tip_window = None;
10898 tip_frame = Qnil;
10899 }
10900
10901 return deleted;
eaf1eea9
GM
10902}
10903
10904
333b20bb 10905/* Create a frame for a tooltip on the display described by DPYINFO.
275841bf
GM
10906 PARMS is a list of frame parameters. TEXT is the string to
10907 display in the tip frame. Value is the frame.
eaf1eea9
GM
10908
10909 Note that functions called here, esp. x_default_parameter can
10910 signal errors, for instance when a specified color name is
10911 undefined. We have to make sure that we're in a consistent state
10912 when this happens. */
333b20bb
GM
10913
10914static Lisp_Object
275841bf 10915x_create_tip_frame (dpyinfo, parms, text)
333b20bb 10916 struct x_display_info *dpyinfo;
275841bf 10917 Lisp_Object parms, text;
333b20bb
GM
10918{
10919 struct frame *f;
10920 Lisp_Object frame, tem;
10921 Lisp_Object name;
333b20bb
GM
10922 long window_prompting = 0;
10923 int width, height;
eaf1eea9 10924 int count = BINDING_STACK_SIZE ();
b6d7acec 10925 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb 10926 struct kboard *kb;
06d62053 10927 int face_change_count_before = face_change_count;
275841bf
GM
10928 Lisp_Object buffer;
10929 struct buffer *old_buffer;
333b20bb
GM
10930
10931 check_x ();
10932
10933 /* Use this general default value to start with until we know if
10934 this frame has a specified name. */
10935 Vx_resource_name = Vinvocation_name;
10936
10937#ifdef MULTI_KBOARD
10938 kb = dpyinfo->kboard;
10939#else
10940 kb = &the_only_kboard;
10941#endif
10942
10943 /* Get the name of the frame to use for resource lookup. */
10944 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10945 if (!STRINGP (name)
10946 && !EQ (name, Qunbound)
10947 && !NILP (name))
10948 error ("Invalid frame name--not a string or nil");
10949 Vx_resource_name = name;
10950
10951 frame = Qnil;
10952 GCPRO3 (parms, name, frame);
44b5a125 10953 f = make_frame (1);
333b20bb 10954 XSETFRAME (frame, f);
275841bf
GM
10955
10956 buffer = Fget_buffer_create (build_string (" *tip*"));
10957 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10958 old_buffer = current_buffer;
10959 set_buffer_internal_1 (XBUFFER (buffer));
d63931a2 10960 current_buffer->truncate_lines = Qnil;
275841bf
GM
10961 Ferase_buffer ();
10962 Finsert (1, &text);
10963 set_buffer_internal_1 (old_buffer);
10964
333b20bb 10965 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
8a1a7743 10966 record_unwind_protect (unwind_create_tip_frame, frame);
333b20bb 10967
eaf1eea9
GM
10968 /* By setting the output method, we're essentially saying that
10969 the frame is live, as per FRAME_LIVE_P. If we get a signal
10970 from this point on, x_destroy_window might screw up reference
10971 counts etc. */
333b20bb
GM
10972 f->output_method = output_x_window;
10973 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10974 bzero (f->output_data.x, sizeof (struct x_output));
10975 f->output_data.x->icon_bitmap = -1;
10976 f->output_data.x->fontset = -1;
61d461a8
GM
10977 f->output_data.x->scroll_bar_foreground_pixel = -1;
10978 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
10979#ifdef USE_TOOLKIT_SCROLL_BARS
10980 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
10981 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
10982#endif /* USE_TOOLKIT_SCROLL_BARS */
333b20bb
GM
10983 f->icon_name = Qnil;
10984 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 10985#if GLYPH_DEBUG
eaf1eea9
GM
10986 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
10987 dpyinfo_refcount = dpyinfo->reference_count;
10988#endif /* GLYPH_DEBUG */
333b20bb
GM
10989#ifdef MULTI_KBOARD
10990 FRAME_KBOARD (f) = kb;
10991#endif
10992 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10993 f->output_data.x->explicit_parent = 0;
10994
61d461a8
GM
10995 /* These colors will be set anyway later, but it's important
10996 to get the color reference counts right, so initialize them! */
10997 {
10998 Lisp_Object black;
10999 struct gcpro gcpro1;
11000
11001 black = build_string ("black");
11002 GCPRO1 (black);
11003 f->output_data.x->foreground_pixel
11004 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11005 f->output_data.x->background_pixel
11006 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11007 f->output_data.x->cursor_pixel
11008 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11009 f->output_data.x->cursor_foreground_pixel
11010 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11011 f->output_data.x->border_pixel
11012 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11013 f->output_data.x->mouse_pixel
11014 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11015 UNGCPRO;
11016 }
11017
333b20bb
GM
11018 /* Set the name; the functions to which we pass f expect the name to
11019 be set. */
11020 if (EQ (name, Qunbound) || NILP (name))
11021 {
11022 f->name = build_string (dpyinfo->x_id_name);
11023 f->explicit_name = 0;
11024 }
11025 else
11026 {
11027 f->name = name;
11028 f->explicit_name = 1;
11029 /* use the frame's title when getting resources for this frame. */
11030 specbind (Qx_resource_name, name);
11031 }
11032
eaf1eea9
GM
11033 /* Extract the window parameters from the supplied values that are
11034 needed to determine window geometry. */
333b20bb
GM
11035 {
11036 Lisp_Object font;
11037
11038 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
11039
11040 BLOCK_INPUT;
11041 /* First, try whatever font the caller has specified. */
11042 if (STRINGP (font))
11043 {
11044 tem = Fquery_fontset (font, Qnil);
11045 if (STRINGP (tem))
11046 font = x_new_fontset (f, XSTRING (tem)->data);
11047 else
11048 font = x_new_font (f, XSTRING (font)->data);
11049 }
11050
11051 /* Try out a font which we hope has bold and italic variations. */
11052 if (!STRINGP (font))
11053 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
11054 if (!STRINGP (font))
11055 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11056 if (! STRINGP (font))
11057 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11058 if (! STRINGP (font))
11059 /* This was formerly the first thing tried, but it finds too many fonts
11060 and takes too long. */
11061 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
11062 /* If those didn't work, look for something which will at least work. */
11063 if (! STRINGP (font))
11064 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
11065 UNBLOCK_INPUT;
11066 if (! STRINGP (font))
11067 font = build_string ("fixed");
11068
11069 x_default_parameter (f, parms, Qfont, font,
11070 "font", "Font", RES_TYPE_STRING);
11071 }
11072
11073 x_default_parameter (f, parms, Qborder_width, make_number (2),
11074 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
11075
11076 /* This defaults to 2 in order to match xterm. We recognize either
11077 internalBorderWidth or internalBorder (which is what xterm calls
11078 it). */
11079 if (NILP (Fassq (Qinternal_border_width, parms)))
11080 {
11081 Lisp_Object value;
11082
11083 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
11084 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
11085 if (! EQ (value, Qunbound))
11086 parms = Fcons (Fcons (Qinternal_border_width, value),
11087 parms);
11088 }
11089
11090 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
11091 "internalBorderWidth", "internalBorderWidth",
11092 RES_TYPE_NUMBER);
11093
11094 /* Also do the stuff which must be set before the window exists. */
11095 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
11096 "foreground", "Foreground", RES_TYPE_STRING);
11097 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
11098 "background", "Background", RES_TYPE_STRING);
11099 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
11100 "pointerColor", "Foreground", RES_TYPE_STRING);
11101 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
11102 "cursorColor", "Foreground", RES_TYPE_STRING);
11103 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
11104 "borderColor", "BorderColor", RES_TYPE_STRING);
11105
11106 /* Init faces before x_default_parameter is called for scroll-bar
11107 parameters because that function calls x_set_scroll_bar_width,
11108 which calls change_frame_size, which calls Fset_window_buffer,
11109 which runs hooks, which call Fvertical_motion. At the end, we
11110 end up in init_iterator with a null face cache, which should not
11111 happen. */
11112 init_frame_faces (f);
11113
11114 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
11115 window_prompting = x_figure_window_size (f, parms);
11116
11117 if (window_prompting & XNegative)
11118 {
11119 if (window_prompting & YNegative)
11120 f->output_data.x->win_gravity = SouthEastGravity;
11121 else
11122 f->output_data.x->win_gravity = NorthEastGravity;
11123 }
11124 else
11125 {
11126 if (window_prompting & YNegative)
11127 f->output_data.x->win_gravity = SouthWestGravity;
11128 else
11129 f->output_data.x->win_gravity = NorthWestGravity;
11130 }
11131
11132 f->output_data.x->size_hint_flags = window_prompting;
11133 {
11134 XSetWindowAttributes attrs;
11135 unsigned long mask;
11136
11137 BLOCK_INPUT;
c51d2b5e
GM
11138 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
11139 if (DoesSaveUnders (dpyinfo->screen))
11140 mask |= CWSaveUnder;
11141
9b2956e2
GM
11142 /* Window managers look at the override-redirect flag to determine
11143 whether or net to give windows a decoration (Xlib spec, chapter
333b20bb
GM
11144 3.2.8). */
11145 attrs.override_redirect = True;
11146 attrs.save_under = True;
11147 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
11148 /* Arrange for getting MapNotify and UnmapNotify events. */
11149 attrs.event_mask = StructureNotifyMask;
11150 tip_window
11151 = FRAME_X_WINDOW (f)
11152 = XCreateWindow (FRAME_X_DISPLAY (f),
11153 FRAME_X_DISPLAY_INFO (f)->root_window,
11154 /* x, y, width, height */
11155 0, 0, 1, 1,
11156 /* Border. */
11157 1,
11158 CopyFromParent, InputOutput, CopyFromParent,
11159 mask, &attrs);
11160 UNBLOCK_INPUT;
11161 }
11162
11163 x_make_gc (f);
11164
333b20bb
GM
11165 x_default_parameter (f, parms, Qauto_raise, Qnil,
11166 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11167 x_default_parameter (f, parms, Qauto_lower, Qnil,
11168 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11169 x_default_parameter (f, parms, Qcursor_type, Qbox,
11170 "cursorType", "CursorType", RES_TYPE_SYMBOL);
11171
11172 /* Dimensions, especially f->height, must be done via change_frame_size.
11173 Change will not be effected unless different from the current
11174 f->height. */
11175 width = f->width;
11176 height = f->height;
11177 f->height = 0;
11178 SET_FRAME_WIDTH (f, 0);
8938a4fb 11179 change_frame_size (f, height, width, 1, 0, 0);
333b20bb 11180
035d5114 11181 /* Set up faces after all frame parameters are known. This call
6801a572
GM
11182 also merges in face attributes specified for new frames.
11183
11184 Frame parameters may be changed if .Xdefaults contains
11185 specifications for the default font. For example, if there is an
11186 `Emacs.default.attributeBackground: pink', the `background-color'
11187 attribute of the frame get's set, which let's the internal border
11188 of the tooltip frame appear in pink. Prevent this. */
11189 {
11190 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
11191
11192 /* Set tip_frame here, so that */
11193 tip_frame = frame;
11194 call1 (Qface_set_after_frame_default, frame);
11195
11196 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
11197 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
11198 Qnil));
11199 }
035d5114 11200
333b20bb
GM
11201 f->no_split = 1;
11202
11203 UNGCPRO;
11204
11205 /* It is now ok to make the frame official even if we get an error
11206 below. And the frame needs to be on Vframe_list or making it
11207 visible won't work. */
11208 Vframe_list = Fcons (frame, Vframe_list);
11209
11210 /* Now that the frame is official, it counts as a reference to
11211 its display. */
11212 FRAME_X_DISPLAY_INFO (f)->reference_count++;
11213
06d62053
GM
11214 /* Setting attributes of faces of the tooltip frame from resources
11215 and similar will increment face_change_count, which leads to the
11216 clearing of all current matrices. Since this isn't necessary
11217 here, avoid it by resetting face_change_count to the value it
11218 had before we created the tip frame. */
11219 face_change_count = face_change_count_before;
11220
eaf1eea9 11221 /* Discard the unwind_protect. */
333b20bb
GM
11222 return unbind_to (count, frame);
11223}
11224
11225
06d62053
GM
11226/* Compute where to display tip frame F. PARMS is the list of frame
11227 parameters for F. DX and DY are specified offsets from the current
ab452f99
GM
11228 location of the mouse. WIDTH and HEIGHT are the width and height
11229 of the tooltip. Return coordinates relative to the root window of
11230 the display in *ROOT_X, and *ROOT_Y. */
06d62053
GM
11231
11232static void
ab452f99 11233compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
06d62053
GM
11234 struct frame *f;
11235 Lisp_Object parms, dx, dy;
ab452f99 11236 int width, height;
06d62053
GM
11237 int *root_x, *root_y;
11238{
11239 Lisp_Object left, top;
11240 int win_x, win_y;
11241 Window root, child;
11242 unsigned pmask;
11243
11244 /* User-specified position? */
11245 left = Fcdr (Fassq (Qleft, parms));
11246 top = Fcdr (Fassq (Qtop, parms));
11247
11248 /* Move the tooltip window where the mouse pointer is. Resize and
11249 show it. */
570d22b0 11250 if (!INTEGERP (left) || !INTEGERP (top))
ab452f99
GM
11251 {
11252 BLOCK_INPUT;
11253 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
11254 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
11255 UNBLOCK_INPUT;
11256 }
06d62053 11257
06d62053
GM
11258 if (INTEGERP (top))
11259 *root_y = XINT (top);
ab452f99
GM
11260 else if (*root_y + XINT (dy) - height < 0)
11261 *root_y -= XINT (dy);
11262 else
11263 {
11264 *root_y -= height;
11265 *root_y += XINT (dy);
11266 }
11267
11268 if (INTEGERP (left))
11269 *root_x = XINT (left);
d682d3df
RS
11270 else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width)
11271 /* It fits to the right of the pointer. */
11272 *root_x += XINT (dx);
11273 else if (width + XINT (dx) <= *root_x)
11274 /* It fits to the left of the pointer. */
ab452f99
GM
11275 *root_x -= width + XINT (dx);
11276 else
d682d3df
RS
11277 /* Put it left-justified on the screen--it ought to fit that way. */
11278 *root_x = 0;
06d62053
GM
11279}
11280
11281
0634ce98 11282DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
7ee72033 11283 doc: /* Show STRING in a "tooltip" window on frame FRAME.
c061c855
GM
11284A tooltip window is a small X window displaying a string.
11285
11286FRAME nil or omitted means use the selected frame.
11287
11288PARMS is an optional list of frame parameters which can be used to
11289change the tooltip's appearance.
11290
11291Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
11292means use the default timeout of 5 seconds.
11293
11294If the list of frame parameters PARAMS contains a `left' parameters,
11295the tooltip is displayed at that x-position. Otherwise it is
11296displayed at the mouse position, with offset DX added (default is 5 if
11297DX isn't specified). Likewise for the y-position; if a `top' frame
11298parameter is specified, it determines the y-position of the tooltip
11299window, otherwise it is displayed at the mouse position, with offset
11300DY added (default is -10).
11301
11302A tooltip's maximum size is specified by `x-max-tooltip-size'.
7ee72033
MB
11303Text larger than the specified size is clipped. */)
11304 (string, frame, parms, timeout, dx, dy)
0634ce98 11305 Lisp_Object string, frame, parms, timeout, dx, dy;
333b20bb
GM
11306{
11307 struct frame *f;
11308 struct window *w;
06d62053 11309 int root_x, root_y;
333b20bb
GM
11310 struct buffer *old_buffer;
11311 struct text_pos pos;
11312 int i, width, height;
393f2d14 11313 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
333b20bb 11314 int old_windows_or_buffers_changed = windows_or_buffers_changed;
06d62053 11315 int count = BINDING_STACK_SIZE ();
333b20bb
GM
11316
11317 specbind (Qinhibit_redisplay, Qt);
11318
393f2d14 11319 GCPRO4 (string, parms, frame, timeout);
333b20bb 11320
b7826503 11321 CHECK_STRING (string);
333b20bb
GM
11322 f = check_x_frame (frame);
11323 if (NILP (timeout))
11324 timeout = make_number (5);
11325 else
b7826503 11326 CHECK_NATNUM (timeout);
0634ce98
GM
11327
11328 if (NILP (dx))
11329 dx = make_number (5);
11330 else
b7826503 11331 CHECK_NUMBER (dx);
0634ce98
GM
11332
11333 if (NILP (dy))
12c67a7f 11334 dy = make_number (-10);
0634ce98 11335 else
b7826503 11336 CHECK_NUMBER (dy);
333b20bb 11337
06d62053
GM
11338 if (NILP (last_show_tip_args))
11339 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
11340
11341 if (!NILP (tip_frame))
11342 {
11343 Lisp_Object last_string = AREF (last_show_tip_args, 0);
11344 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
11345 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
11346
11347 if (EQ (frame, last_frame)
11348 && !NILP (Fequal (last_string, string))
11349 && !NILP (Fequal (last_parms, parms)))
11350 {
11351 struct frame *f = XFRAME (tip_frame);
11352
11353 /* Only DX and DY have changed. */
11354 if (!NILP (tip_timer))
ae782866
GM
11355 {
11356 Lisp_Object timer = tip_timer;
11357 tip_timer = Qnil;
11358 call1 (Qcancel_timer, timer);
11359 }
06d62053
GM
11360
11361 BLOCK_INPUT;
ab452f99
GM
11362 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
11363 PIXEL_HEIGHT (f), &root_x, &root_y);
06d62053 11364 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11365 root_x, root_y);
06d62053
GM
11366 UNBLOCK_INPUT;
11367 goto start_timer;
11368 }
11369 }
11370
333b20bb
GM
11371 /* Hide a previous tip, if any. */
11372 Fx_hide_tip ();
11373
06d62053
GM
11374 ASET (last_show_tip_args, 0, string);
11375 ASET (last_show_tip_args, 1, frame);
11376 ASET (last_show_tip_args, 2, parms);
11377
333b20bb
GM
11378 /* Add default values to frame parameters. */
11379 if (NILP (Fassq (Qname, parms)))
11380 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
11381 if (NILP (Fassq (Qinternal_border_width, parms)))
11382 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
11383 if (NILP (Fassq (Qborder_width, parms)))
11384 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
11385 if (NILP (Fassq (Qborder_color, parms)))
11386 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
11387 if (NILP (Fassq (Qbackground_color, parms)))
11388 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
11389 parms);
11390
11391 /* Create a frame for the tooltip, and record it in the global
11392 variable tip_frame. */
275841bf 11393 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
44b5a125 11394 f = XFRAME (frame);
333b20bb 11395
d63931a2 11396 /* Set up the frame's root window. */
333b20bb
GM
11397 w = XWINDOW (FRAME_ROOT_WINDOW (f));
11398 w->left = w->top = make_number (0);
d63931a2
GM
11399
11400 if (CONSP (Vx_max_tooltip_size)
11401 && INTEGERP (XCAR (Vx_max_tooltip_size))
11402 && XINT (XCAR (Vx_max_tooltip_size)) > 0
11403 && INTEGERP (XCDR (Vx_max_tooltip_size))
11404 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
11405 {
11406 w->width = XCAR (Vx_max_tooltip_size);
11407 w->height = XCDR (Vx_max_tooltip_size);
11408 }
11409 else
11410 {
11411 w->width = make_number (80);
11412 w->height = make_number (40);
11413 }
11414
11415 f->window_width = XINT (w->width);
333b20bb
GM
11416 adjust_glyphs (f);
11417 w->pseudo_window_p = 1;
11418
11419 /* Display the tooltip text in a temporary buffer. */
333b20bb 11420 old_buffer = current_buffer;
275841bf 11421 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
d63931a2 11422 current_buffer->truncate_lines = Qnil;
333b20bb
GM
11423 clear_glyph_matrix (w->desired_matrix);
11424 clear_glyph_matrix (w->current_matrix);
11425 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
11426 try_window (FRAME_ROOT_WINDOW (f), pos);
11427
11428 /* Compute width and height of the tooltip. */
11429 width = height = 0;
11430 for (i = 0; i < w->desired_matrix->nrows; ++i)
11431 {
11432 struct glyph_row *row = &w->desired_matrix->rows[i];
11433 struct glyph *last;
11434 int row_width;
11435
11436 /* Stop at the first empty row at the end. */
11437 if (!row->enabled_p || !row->displays_text_p)
11438 break;
11439
d7bf0342
GM
11440 /* Let the row go over the full width of the frame. */
11441 row->full_width_p = 1;
333b20bb 11442
e3130015 11443 /* There's a glyph at the end of rows that is used to place
333b20bb
GM
11444 the cursor there. Don't include the width of this glyph. */
11445 if (row->used[TEXT_AREA])
11446 {
11447 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
11448 row_width = row->pixel_width - last->pixel_width;
11449 }
11450 else
11451 row_width = row->pixel_width;
11452
11453 height += row->height;
11454 width = max (width, row_width);
11455 }
11456
11457 /* Add the frame's internal border to the width and height the X
11458 window should have. */
11459 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11460 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11461
11462 /* Move the tooltip window where the mouse pointer is. Resize and
11463 show it. */
ab452f99 11464 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
0634ce98 11465
0634ce98 11466 BLOCK_INPUT;
333b20bb 11467 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11468 root_x, root_y, width, height);
333b20bb
GM
11469 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11470 UNBLOCK_INPUT;
06d62053 11471
333b20bb
GM
11472 /* Draw into the window. */
11473 w->must_be_updated_p = 1;
11474 update_single_window (w, 1);
11475
11476 /* Restore original current buffer. */
11477 set_buffer_internal_1 (old_buffer);
11478 windows_or_buffers_changed = old_windows_or_buffers_changed;
11479
06d62053 11480 start_timer:
333b20bb
GM
11481 /* Let the tip disappear after timeout seconds. */
11482 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
11483 intern ("x-hide-tip"));
a744a2ec
DL
11484
11485 UNGCPRO;
333b20bb
GM
11486 return unbind_to (count, Qnil);
11487}
11488
11489
11490DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
7ee72033
MB
11491 doc: /* Hide the current tooltip window, if there is any.
11492Value is t if tooltip was open, nil otherwise. */)
11493 ()
333b20bb 11494{
44b5a125 11495 int count;
c0006262
GM
11496 Lisp_Object deleted, frame, timer;
11497 struct gcpro gcpro1, gcpro2;
44b5a125
GM
11498
11499 /* Return quickly if nothing to do. */
c0006262 11500 if (NILP (tip_timer) && NILP (tip_frame))
44b5a125 11501 return Qnil;
333b20bb 11502
c0006262
GM
11503 frame = tip_frame;
11504 timer = tip_timer;
11505 GCPRO2 (frame, timer);
11506 tip_frame = tip_timer = deleted = Qnil;
11507
44b5a125 11508 count = BINDING_STACK_SIZE ();
333b20bb 11509 specbind (Qinhibit_redisplay, Qt);
44b5a125 11510 specbind (Qinhibit_quit, Qt);
333b20bb 11511
c0006262 11512 if (!NILP (timer))
ae782866 11513 call1 (Qcancel_timer, timer);
333b20bb 11514
c0006262 11515 if (FRAMEP (frame))
333b20bb 11516 {
44b5a125
GM
11517 Fdelete_frame (frame, Qnil);
11518 deleted = Qt;
f6c44811
GM
11519
11520#ifdef USE_LUCID
11521 /* Bloodcurdling hack alert: The Lucid menu bar widget's
11522 redisplay procedure is not called when a tip frame over menu
11523 items is unmapped. Redisplay the menu manually... */
11524 {
11525 struct frame *f = SELECTED_FRAME ();
11526 Widget w = f->output_data.x->menubar_widget;
11527 extern void xlwmenu_redisplay P_ ((Widget));
9180dc8c 11528
f6c44811 11529 if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
dbc64aa7 11530 && w != NULL)
f6c44811
GM
11531 {
11532 BLOCK_INPUT;
11533 xlwmenu_redisplay (w);
11534 UNBLOCK_INPUT;
11535 }
11536 }
11537#endif /* USE_LUCID */
333b20bb
GM
11538 }
11539
c0006262 11540 UNGCPRO;
44b5a125 11541 return unbind_to (count, deleted);
333b20bb
GM
11542}
11543
11544
11545\f
11546/***********************************************************************
11547 File selection dialog
11548 ***********************************************************************/
11549
11550#ifdef USE_MOTIF
11551
11552/* Callback for "OK" and "Cancel" on file selection dialog. */
11553
11554static void
11555file_dialog_cb (widget, client_data, call_data)
11556 Widget widget;
11557 XtPointer call_data, client_data;
11558{
11559 int *result = (int *) client_data;
11560 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
11561 *result = cb->reason;
11562}
11563
11564
a779d213
GM
11565/* Callback for unmapping a file selection dialog. This is used to
11566 capture the case where a dialog is closed via a window manager's
11567 closer button, for example. Using a XmNdestroyCallback didn't work
11568 in this case. */
11569
11570static void
11571file_dialog_unmap_cb (widget, client_data, call_data)
11572 Widget widget;
11573 XtPointer call_data, client_data;
11574{
11575 int *result = (int *) client_data;
11576 *result = XmCR_CANCEL;
11577}
11578
11579
333b20bb 11580DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
7ee72033 11581 doc: /* Read file name, prompting with PROMPT in directory DIR.
c061c855
GM
11582Use a file selection dialog.
11583Select DEFAULT-FILENAME in the dialog's file selection box, if
11584specified. Don't let the user enter a file name in the file
7ee72033
MB
11585selection dialog's entry field, if MUSTMATCH is non-nil. */)
11586 (prompt, dir, default_filename, mustmatch)
333b20bb
GM
11587 Lisp_Object prompt, dir, default_filename, mustmatch;
11588{
11589 int result;
0fe92f72 11590 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
11591 Lisp_Object file = Qnil;
11592 Widget dialog, text, list, help;
11593 Arg al[10];
11594 int ac = 0;
11595 extern XtAppContext Xt_app_con;
333b20bb 11596 XmString dir_xmstring, pattern_xmstring;
333b20bb
GM
11597 int count = specpdl_ptr - specpdl;
11598 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
11599
11600 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
11601 CHECK_STRING (prompt);
11602 CHECK_STRING (dir);
333b20bb
GM
11603
11604 /* Prevent redisplay. */
11605 specbind (Qinhibit_redisplay, Qt);
11606
11607 BLOCK_INPUT;
11608
11609 /* Create the dialog with PROMPT as title, using DIR as initial
11610 directory and using "*" as pattern. */
11611 dir = Fexpand_file_name (dir, Qnil);
11612 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data);
11613 pattern_xmstring = XmStringCreateLocalized ("*");
11614
11615 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac;
11616 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
11617 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
11618 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
11619 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
11620 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
11621 "fsb", al, ac);
11622 XmStringFree (dir_xmstring);
11623 XmStringFree (pattern_xmstring);
11624
11625 /* Add callbacks for OK and Cancel. */
11626 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
11627 (XtPointer) &result);
11628 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
11629 (XtPointer) &result);
a779d213
GM
11630 XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
11631 (XtPointer) &result);
333b20bb
GM
11632
11633 /* Disable the help button since we can't display help. */
11634 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
11635 XtSetSensitive (help, False);
11636
11637 /* Mark OK button as default. */
11638 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
11639 XmNshowAsDefault, True, NULL);
11640
11641 /* If MUSTMATCH is non-nil, disable the file entry field of the
11642 dialog, so that the user must select a file from the files list
11643 box. We can't remove it because we wouldn't have a way to get at
11644 the result file name, then. */
11645 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
11646 if (!NILP (mustmatch))
11647 {
11648 Widget label;
11649 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
11650 XtSetSensitive (text, False);
11651 XtSetSensitive (label, False);
11652 }
11653
11654 /* Manage the dialog, so that list boxes get filled. */
11655 XtManageChild (dialog);
11656
11657 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
11658 must include the path for this to work. */
11659 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
11660 if (STRINGP (default_filename))
11661 {
11662 XmString default_xmstring;
11663 int item_pos;
11664
11665 default_xmstring
11666 = XmStringCreateLocalized (XSTRING (default_filename)->data);
11667
11668 if (!XmListItemExists (list, default_xmstring))
11669 {
11670 /* Add a new item if DEFAULT_FILENAME is not in the list. */
11671 XmListAddItem (list, default_xmstring, 0);
11672 item_pos = 0;
11673 }
11674 else
11675 item_pos = XmListItemPos (list, default_xmstring);
11676 XmStringFree (default_xmstring);
11677
11678 /* Select the item and scroll it into view. */
11679 XmListSelectPos (list, item_pos, True);
11680 XmListSetPos (list, item_pos);
11681 }
11682
563b384d
GM
11683 /* Process events until the user presses Cancel or OK. Block
11684 and unblock input here so that we get a chance of processing
11685 expose events. */
11686 UNBLOCK_INPUT;
03100098 11687 result = 0;
a779d213 11688 while (result == 0)
563b384d
GM
11689 {
11690 BLOCK_INPUT;
11691 XtAppProcessEvent (Xt_app_con, XtIMAll);
11692 UNBLOCK_INPUT;
11693 }
11694 BLOCK_INPUT;
03100098 11695
333b20bb
GM
11696 /* Get the result. */
11697 if (result == XmCR_OK)
11698 {
11699 XmString text;
11700 String data;
11701
d1670063 11702 XtVaGetValues (dialog, XmNtextString, &text, NULL);
333b20bb
GM
11703 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
11704 XmStringFree (text);
11705 file = build_string (data);
11706 XtFree (data);
11707 }
11708 else
11709 file = Qnil;
11710
11711 /* Clean up. */
11712 XtUnmanageChild (dialog);
11713 XtDestroyWidget (dialog);
11714 UNBLOCK_INPUT;
11715 UNGCPRO;
11716
11717 /* Make "Cancel" equivalent to C-g. */
11718 if (NILP (file))
11719 Fsignal (Qquit, Qnil);
11720
11721 return unbind_to (count, file);
11722}
11723
11724#endif /* USE_MOTIF */
11725
333b20bb
GM
11726
11727\f
82bab41c
GM
11728/***********************************************************************
11729 Keyboard
11730 ***********************************************************************/
11731
11732#ifdef HAVE_XKBGETKEYBOARD
11733#include <X11/XKBlib.h>
11734#include <X11/keysym.h>
11735#endif
11736
11737DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
11738 Sx_backspace_delete_keys_p, 0, 1, 0,
7ee72033 11739 doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME.
c061c855
GM
11740FRAME nil means use the selected frame.
11741Value is t if we know that both keys are present, and are mapped to the
7ee72033
MB
11742usual X keysyms. */)
11743 (frame)
82bab41c
GM
11744 Lisp_Object frame;
11745{
11746#ifdef HAVE_XKBGETKEYBOARD
11747 XkbDescPtr kb;
11748 struct frame *f = check_x_frame (frame);
11749 Display *dpy = FRAME_X_DISPLAY (f);
11750 Lisp_Object have_keys;
46f6a258 11751 int major, minor, op, event, error;
82bab41c
GM
11752
11753 BLOCK_INPUT;
46f6a258
GM
11754
11755 /* Check library version in case we're dynamically linked. */
11756 major = XkbMajorVersion;
11757 minor = XkbMinorVersion;
11758 if (!XkbLibraryVersion (&major, &minor))
c1efd260
GM
11759 {
11760 UNBLOCK_INPUT;
11761 return Qnil;
11762 }
46f6a258
GM
11763
11764 /* Check that the server supports XKB. */
11765 major = XkbMajorVersion;
11766 minor = XkbMinorVersion;
11767 if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
c1efd260
GM
11768 {
11769 UNBLOCK_INPUT;
11770 return Qnil;
11771 }
46f6a258
GM
11772
11773 have_keys = Qnil;
c1efd260 11774 kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
82bab41c
GM
11775 if (kb)
11776 {
11777 int delete_keycode = 0, backspace_keycode = 0, i;
c1efd260
GM
11778
11779 if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
82bab41c 11780 {
c1efd260
GM
11781 for (i = kb->min_key_code;
11782 (i < kb->max_key_code
11783 && (delete_keycode == 0 || backspace_keycode == 0));
11784 ++i)
11785 {
d63931a2
GM
11786 /* The XKB symbolic key names can be seen most easily in
11787 the PS file generated by `xkbprint -label name
11788 $DISPLAY'. */
c1efd260
GM
11789 if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
11790 delete_keycode = i;
11791 else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
11792 backspace_keycode = i;
11793 }
11794
11795 XkbFreeNames (kb, 0, True);
82bab41c
GM
11796 }
11797
c1efd260 11798 XkbFreeClientMap (kb, 0, True);
82bab41c
GM
11799
11800 if (delete_keycode
11801 && backspace_keycode
11802 && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
11803 && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
11804 have_keys = Qt;
11805 }
11806 UNBLOCK_INPUT;
11807 return have_keys;
11808#else /* not HAVE_XKBGETKEYBOARD */
11809 return Qnil;
11810#endif /* not HAVE_XKBGETKEYBOARD */
11811}
11812
11813
11814\f
333b20bb
GM
11815/***********************************************************************
11816 Initialization
11817 ***********************************************************************/
11818
11819void
11820syms_of_xfns ()
11821{
11822 /* This is zero if not using X windows. */
11823 x_in_use = 0;
11824
11825 /* The section below is built by the lisp expression at the top of the file,
11826 just above where these variables are declared. */
11827 /*&&& init symbols here &&&*/
11828 Qauto_raise = intern ("auto-raise");
11829 staticpro (&Qauto_raise);
11830 Qauto_lower = intern ("auto-lower");
11831 staticpro (&Qauto_lower);
11832 Qbar = intern ("bar");
dbc4e1c1 11833 staticpro (&Qbar);
f9942c9e
JB
11834 Qborder_color = intern ("border-color");
11835 staticpro (&Qborder_color);
11836 Qborder_width = intern ("border-width");
11837 staticpro (&Qborder_width);
dbc4e1c1
JB
11838 Qbox = intern ("box");
11839 staticpro (&Qbox);
f9942c9e
JB
11840 Qcursor_color = intern ("cursor-color");
11841 staticpro (&Qcursor_color);
dbc4e1c1
JB
11842 Qcursor_type = intern ("cursor-type");
11843 staticpro (&Qcursor_type);
f9942c9e
JB
11844 Qgeometry = intern ("geometry");
11845 staticpro (&Qgeometry);
f9942c9e
JB
11846 Qicon_left = intern ("icon-left");
11847 staticpro (&Qicon_left);
11848 Qicon_top = intern ("icon-top");
11849 staticpro (&Qicon_top);
11850 Qicon_type = intern ("icon-type");
11851 staticpro (&Qicon_type);
80534dd6
KH
11852 Qicon_name = intern ("icon-name");
11853 staticpro (&Qicon_name);
f9942c9e
JB
11854 Qinternal_border_width = intern ("internal-border-width");
11855 staticpro (&Qinternal_border_width);
11856 Qleft = intern ("left");
11857 staticpro (&Qleft);
1ab3d87e
RS
11858 Qright = intern ("right");
11859 staticpro (&Qright);
f9942c9e
JB
11860 Qmouse_color = intern ("mouse-color");
11861 staticpro (&Qmouse_color);
baaed68e
JB
11862 Qnone = intern ("none");
11863 staticpro (&Qnone);
f9942c9e
JB
11864 Qparent_id = intern ("parent-id");
11865 staticpro (&Qparent_id);
4701395c
KH
11866 Qscroll_bar_width = intern ("scroll-bar-width");
11867 staticpro (&Qscroll_bar_width);
8af1d7ca
JB
11868 Qsuppress_icon = intern ("suppress-icon");
11869 staticpro (&Qsuppress_icon);
01f1ba30 11870 Qundefined_color = intern ("undefined-color");
f9942c9e 11871 staticpro (&Qundefined_color);
a3c87d4e
JB
11872 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
11873 staticpro (&Qvertical_scroll_bars);
49795535
JB
11874 Qvisibility = intern ("visibility");
11875 staticpro (&Qvisibility);
f9942c9e
JB
11876 Qwindow_id = intern ("window-id");
11877 staticpro (&Qwindow_id);
2cbebefb
RS
11878 Qouter_window_id = intern ("outer-window-id");
11879 staticpro (&Qouter_window_id);
f9942c9e
JB
11880 Qx_frame_parameter = intern ("x-frame-parameter");
11881 staticpro (&Qx_frame_parameter);
9ef48a9d
RS
11882 Qx_resource_name = intern ("x-resource-name");
11883 staticpro (&Qx_resource_name);
4fe1de12
RS
11884 Quser_position = intern ("user-position");
11885 staticpro (&Quser_position);
11886 Quser_size = intern ("user-size");
11887 staticpro (&Quser_size);
333b20bb
GM
11888 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
11889 staticpro (&Qscroll_bar_foreground);
11890 Qscroll_bar_background = intern ("scroll-bar-background");
11891 staticpro (&Qscroll_bar_background);
d62c8769
GM
11892 Qscreen_gamma = intern ("screen-gamma");
11893 staticpro (&Qscreen_gamma);
563b67aa
GM
11894 Qline_spacing = intern ("line-spacing");
11895 staticpro (&Qline_spacing);
7c7ff7f5
GM
11896 Qcenter = intern ("center");
11897 staticpro (&Qcenter);
96db09e4
KH
11898 Qcompound_text = intern ("compound-text");
11899 staticpro (&Qcompound_text);
ae782866
GM
11900 Qcancel_timer = intern ("cancel-timer");
11901 staticpro (&Qcancel_timer);
ea0a1f53
GM
11902 Qwait_for_wm = intern ("wait-for-wm");
11903 staticpro (&Qwait_for_wm);
49d41073
EZ
11904 Qfullscreen = intern ("fullscreen");
11905 staticpro (&Qfullscreen);
11906 Qfullwidth = intern ("fullwidth");
11907 staticpro (&Qfullwidth);
11908 Qfullheight = intern ("fullheight");
11909 staticpro (&Qfullheight);
11910 Qfullboth = intern ("fullboth");
11911 staticpro (&Qfullboth);
f9942c9e
JB
11912 /* This is the end of symbol initialization. */
11913
58cad5ed
KH
11914 /* Text property `display' should be nonsticky by default. */
11915 Vtext_property_default_nonsticky
11916 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
11917
11918
333b20bb
GM
11919 Qlaplace = intern ("laplace");
11920 staticpro (&Qlaplace);
4a8e312c
GM
11921 Qemboss = intern ("emboss");
11922 staticpro (&Qemboss);
11923 Qedge_detection = intern ("edge-detection");
11924 staticpro (&Qedge_detection);
11925 Qheuristic = intern ("heuristic");
11926 staticpro (&Qheuristic);
11927 QCmatrix = intern (":matrix");
11928 staticpro (&QCmatrix);
11929 QCcolor_adjustment = intern (":color-adjustment");
11930 staticpro (&QCcolor_adjustment);
11931 QCmask = intern (":mask");
11932 staticpro (&QCmask);
11933
a367641f
RS
11934 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
11935 staticpro (&Qface_set_after_frame_default);
11936
01f1ba30
JB
11937 Fput (Qundefined_color, Qerror_conditions,
11938 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
11939 Fput (Qundefined_color, Qerror_message,
11940 build_string ("Undefined color"));
11941
f9942c9e
JB
11942 init_x_parm_symbols ();
11943
7ee72033
MB
11944 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
11945 doc: /* Non-nil means always draw a cross over disabled images.
c061c855
GM
11946Disabled images are those having an `:conversion disabled' property.
11947A cross is always drawn on black & white displays. */);
14819cb3
GM
11948 cross_disabled_images = 0;
11949
7ee72033
MB
11950 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
11951 doc: /* List of directories to search for bitmap files for X. */);
e241c09b 11952 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 11953
7ee72033
MB
11954 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
11955 doc: /* The shape of the pointer when over text.
c061c855
GM
11956Changing the value does not affect existing frames
11957unless you set the mouse color. */);
01f1ba30
JB
11958 Vx_pointer_shape = Qnil;
11959
7ee72033
MB
11960 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
11961 doc: /* The name Emacs uses to look up X resources.
c061c855
GM
11962`x-get-resource' uses this as the first component of the instance name
11963when requesting resource values.
11964Emacs initially sets `x-resource-name' to the name under which Emacs
11965was invoked, or to the value specified with the `-name' or `-rn'
11966switches, if present.
11967
11968It may be useful to bind this variable locally around a call
11969to `x-get-resource'. See also the variable `x-resource-class'. */);
d387c960 11970 Vx_resource_name = Qnil;
ac63d3d6 11971
7ee72033
MB
11972 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
11973 doc: /* The class Emacs uses to look up X resources.
c061c855
GM
11974`x-get-resource' uses this as the first component of the instance class
11975when requesting resource values.
11976
11977Emacs initially sets `x-resource-class' to "Emacs".
11978
11979Setting this variable permanently is not a reasonable thing to do,
11980but binding this variable locally around a call to `x-get-resource'
11981is a reasonable practice. See also the variable `x-resource-name'. */);
498e9ac3
RS
11982 Vx_resource_class = build_string (EMACS_CLASS);
11983
ca0ecbf5 11984#if 0 /* This doesn't really do anything. */
7ee72033
MB
11985 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
11986 doc: /* The shape of the pointer when not over text.
c061c855
GM
11987This variable takes effect when you create a new frame
11988or when you set the mouse color. */);
af01ef26 11989#endif
01f1ba30
JB
11990 Vx_nontext_pointer_shape = Qnil;
11991
7ee72033
MB
11992 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
11993 doc: /* The shape of the pointer when Emacs is busy.
c061c855
GM
11994This variable takes effect when you create a new frame
11995or when you set the mouse color. */);
0af913d7 11996 Vx_hourglass_pointer_shape = Qnil;
333b20bb 11997
7ee72033
MB
11998 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
11999 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 12000 display_hourglass_p = 1;
333b20bb 12001
7ee72033
MB
12002 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
12003 doc: /* *Seconds to wait before displaying an hourglass pointer.
c061c855 12004Value must be an integer or float. */);
0af913d7 12005 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
4ae9a85e 12006
ca0ecbf5 12007#if 0 /* This doesn't really do anything. */
7ee72033
MB
12008 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
12009 doc: /* The shape of the pointer when over the mode line.
c061c855
GM
12010This variable takes effect when you create a new frame
12011or when you set the mouse color. */);
af01ef26 12012#endif
01f1ba30
JB
12013 Vx_mode_pointer_shape = Qnil;
12014
d3b06468 12015 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
7ee72033
MB
12016 &Vx_sensitive_text_pointer_shape,
12017 doc: /* The shape of the pointer when over mouse-sensitive text.
c061c855
GM
12018This variable takes effect when you create a new frame
12019or when you set the mouse color. */);
ca0ecbf5 12020 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 12021
8fb4ec9c 12022 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
7ee72033
MB
12023 &Vx_window_horizontal_drag_shape,
12024 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
c061c855
GM
12025This variable takes effect when you create a new frame
12026or when you set the mouse color. */);
8fb4ec9c
GM
12027 Vx_window_horizontal_drag_shape = Qnil;
12028
7ee72033
MB
12029 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
12030 doc: /* A string indicating the foreground color of the cursor box. */);
01f1ba30
JB
12031 Vx_cursor_fore_pixel = Qnil;
12032
7ee72033
MB
12033 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
12034 doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS).
c061c855 12035Text larger than this is clipped. */);
d63931a2
GM
12036 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
12037
7ee72033
MB
12038 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
12039 doc: /* Non-nil if no X window manager is in use.
c061c855
GM
12040Emacs doesn't try to figure this out; this is always nil
12041unless you set it to something else. */);
2d38195d
RS
12042 /* We don't have any way to find this out, so set it to nil
12043 and maybe the user would like to set it to t. */
12044 Vx_no_window_manager = Qnil;
1d3dac41 12045
942ea06d 12046 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
7ee72033
MB
12047 &Vx_pixel_size_width_font_regexp,
12048 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
c061c855
GM
12049
12050Since Emacs gets width of a font matching with this regexp from
12051PIXEL_SIZE field of the name, font finding mechanism gets faster for
12052such a font. This is especially effective for such large fonts as
12053Chinese, Japanese, and Korean. */);
942ea06d
KH
12054 Vx_pixel_size_width_font_regexp = Qnil;
12055
7ee72033
MB
12056 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
12057 doc: /* Time after which cached images are removed from the cache.
c061c855
GM
12058When an image has not been displayed this many seconds, remove it
12059from the image cache. Value must be an integer or nil with nil
12060meaning don't clear the cache. */);
fcf431dc 12061 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb 12062
1d3dac41 12063#ifdef USE_X_TOOLKIT
6f3f6a8d 12064 Fprovide (intern ("x-toolkit"), Qnil);
5b827abb 12065#ifdef USE_MOTIF
6f3f6a8d 12066 Fprovide (intern ("motif"), Qnil);
fc2cdd9a 12067
7ee72033
MB
12068 DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
12069 doc: /* Version info for LessTif/Motif. */);
fc2cdd9a
GM
12070 Vmotif_version_string = build_string (XmVERSION_STRING);
12071#endif /* USE_MOTIF */
12072#endif /* USE_X_TOOLKIT */
01f1ba30 12073
01f1ba30 12074 defsubr (&Sx_get_resource);
333b20bb
GM
12075
12076 /* X window properties. */
12077 defsubr (&Sx_change_window_property);
12078 defsubr (&Sx_delete_window_property);
12079 defsubr (&Sx_window_property);
12080
2d764c78 12081 defsubr (&Sxw_display_color_p);
d0c9d219 12082 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
12083 defsubr (&Sxw_color_defined_p);
12084 defsubr (&Sxw_color_values);
9d317b2c 12085 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
12086 defsubr (&Sx_server_vendor);
12087 defsubr (&Sx_server_version);
12088 defsubr (&Sx_display_pixel_width);
12089 defsubr (&Sx_display_pixel_height);
12090 defsubr (&Sx_display_mm_width);
12091 defsubr (&Sx_display_mm_height);
12092 defsubr (&Sx_display_screens);
12093 defsubr (&Sx_display_planes);
12094 defsubr (&Sx_display_color_cells);
12095 defsubr (&Sx_display_visual_class);
12096 defsubr (&Sx_display_backing_store);
12097 defsubr (&Sx_display_save_under);
8af1d7ca 12098 defsubr (&Sx_parse_geometry);
f676886a 12099 defsubr (&Sx_create_frame);
01f1ba30 12100 defsubr (&Sx_open_connection);
08a90d6a
RS
12101 defsubr (&Sx_close_connection);
12102 defsubr (&Sx_display_list);
01f1ba30 12103 defsubr (&Sx_synchronize);
3decc1e7 12104 defsubr (&Sx_focus_frame);
82bab41c
GM
12105 defsubr (&Sx_backspace_delete_keys_p);
12106
942ea06d
KH
12107 /* Setting callback functions for fontset handler. */
12108 get_font_info_func = x_get_font_info;
333b20bb
GM
12109
12110#if 0 /* This function pointer doesn't seem to be used anywhere.
12111 And the pointer assigned has the wrong type, anyway. */
942ea06d 12112 list_fonts_func = x_list_fonts;
333b20bb
GM
12113#endif
12114
942ea06d 12115 load_font_func = x_load_font;
bc1958c4 12116 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
12117 query_font_func = x_query_font;
12118 set_frame_fontset_func = x_set_font;
12119 check_window_system_func = check_x;
333b20bb
GM
12120
12121 /* Images. */
12122 Qxbm = intern ("xbm");
12123 staticpro (&Qxbm);
d2dc8167
GM
12124 QCconversion = intern (":conversion");
12125 staticpro (&QCconversion);
333b20bb
GM
12126 QCheuristic_mask = intern (":heuristic-mask");
12127 staticpro (&QCheuristic_mask);
12128 QCcolor_symbols = intern (":color-symbols");
12129 staticpro (&QCcolor_symbols);
333b20bb
GM
12130 QCascent = intern (":ascent");
12131 staticpro (&QCascent);
12132 QCmargin = intern (":margin");
12133 staticpro (&QCmargin);
12134 QCrelief = intern (":relief");
12135 staticpro (&QCrelief);
fcf431dc
GM
12136 Qpostscript = intern ("postscript");
12137 staticpro (&Qpostscript);
333b20bb
GM
12138 QCloader = intern (":loader");
12139 staticpro (&QCloader);
12140 QCbounding_box = intern (":bounding-box");
12141 staticpro (&QCbounding_box);
12142 QCpt_width = intern (":pt-width");
12143 staticpro (&QCpt_width);
12144 QCpt_height = intern (":pt-height");
12145 staticpro (&QCpt_height);
3ccff1e3
GM
12146 QCindex = intern (":index");
12147 staticpro (&QCindex);
333b20bb
GM
12148 Qpbm = intern ("pbm");
12149 staticpro (&Qpbm);
12150
12151#if HAVE_XPM
12152 Qxpm = intern ("xpm");
12153 staticpro (&Qxpm);
12154#endif
12155
12156#if HAVE_JPEG
12157 Qjpeg = intern ("jpeg");
12158 staticpro (&Qjpeg);
12159#endif
12160
12161#if HAVE_TIFF
12162 Qtiff = intern ("tiff");
12163 staticpro (&Qtiff);
12164#endif
12165
12166#if HAVE_GIF
12167 Qgif = intern ("gif");
12168 staticpro (&Qgif);
12169#endif
12170
12171#if HAVE_PNG
12172 Qpng = intern ("png");
12173 staticpro (&Qpng);
12174#endif
12175
12176 defsubr (&Sclear_image_cache);
42677916 12177 defsubr (&Simage_size);
b243755a 12178 defsubr (&Simage_mask_p);
333b20bb 12179
0af913d7
GM
12180 hourglass_atimer = NULL;
12181 hourglass_shown_p = 0;
333b20bb
GM
12182
12183 defsubr (&Sx_show_tip);
12184 defsubr (&Sx_hide_tip);
333b20bb 12185 tip_timer = Qnil;
44b5a125
GM
12186 staticpro (&tip_timer);
12187 tip_frame = Qnil;
12188 staticpro (&tip_frame);
333b20bb 12189
06d62053
GM
12190 last_show_tip_args = Qnil;
12191 staticpro (&last_show_tip_args);
12192
333b20bb
GM
12193#ifdef USE_MOTIF
12194 defsubr (&Sx_file_dialog);
12195#endif
12196}
12197
12198
12199void
12200init_xfns ()
12201{
12202 image_types = NULL;
12203 Vimage_types = Qnil;
12204
12205 define_image_type (&xbm_type);
12206 define_image_type (&gs_type);
12207 define_image_type (&pbm_type);
12208
12209#if HAVE_XPM
12210 define_image_type (&xpm_type);
12211#endif
12212
12213#if HAVE_JPEG
12214 define_image_type (&jpeg_type);
12215#endif
12216
12217#if HAVE_TIFF
12218 define_image_type (&tiff_type);
12219#endif
12220
12221#if HAVE_GIF
12222 define_image_type (&gif_type);
12223#endif
12224
12225#if HAVE_PNG
12226 define_image_type (&png_type);
12227#endif
01f1ba30
JB
12228}
12229
12230#endif /* HAVE_X_WINDOWS */