(P_): Definitions deleted.
[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
JB
1886
1887 /* Make sure the cursor gets redrawn. This is overkill, but how
1888 often do people change cursor types? */
1889 update_mode_lines++;
1890}
943b580d 1891\f
01f1ba30 1892void
f676886a
JB
1893x_set_icon_type (f, arg, oldval)
1894 struct frame *f;
01f1ba30
JB
1895 Lisp_Object arg, oldval;
1896{
01f1ba30
JB
1897 int result;
1898
203c1d73
RS
1899 if (STRINGP (arg))
1900 {
1901 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1902 return;
1903 }
1904 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
01f1ba30
JB
1905 return;
1906
1907 BLOCK_INPUT;
265a9e55 1908 if (NILP (arg))
80534dd6 1909 result = x_text_icon (f,
f468da95
RS
1910 (char *) XSTRING ((!NILP (f->icon_name)
1911 ? f->icon_name
80534dd6 1912 : f->name))->data);
f1c7b5a6
RS
1913 else
1914 result = x_bitmap_icon (f, arg);
01f1ba30
JB
1915
1916 if (result)
1917 {
01f1ba30 1918 UNBLOCK_INPUT;
0fb53770 1919 error ("No icon window available");
01f1ba30
JB
1920 }
1921
b9dc4443 1922 XFlush (FRAME_X_DISPLAY (f));
01f1ba30
JB
1923 UNBLOCK_INPUT;
1924}
1925
f1c7b5a6 1926/* Return non-nil if frame F wants a bitmap icon. */
0fb53770 1927
f1c7b5a6 1928Lisp_Object
0fb53770
RS
1929x_icon_type (f)
1930 FRAME_PTR f;
1931{
1932 Lisp_Object tem;
1933
1934 tem = assq_no_quit (Qicon_type, f->param_alist);
f1c7b5a6 1935 if (CONSP (tem))
8e713be6 1936 return XCDR (tem);
f1c7b5a6
RS
1937 else
1938 return Qnil;
0fb53770
RS
1939}
1940
80534dd6
KH
1941void
1942x_set_icon_name (f, arg, oldval)
1943 struct frame *f;
1944 Lisp_Object arg, oldval;
1945{
80534dd6
KH
1946 int result;
1947
1948 if (STRINGP (arg))
1949 {
1950 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1951 return;
1952 }
1953 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
1954 return;
1955
f468da95 1956 f->icon_name = arg;
80534dd6 1957
7556890b 1958 if (f->output_data.x->icon_bitmap != 0)
80534dd6
KH
1959 return;
1960
1961 BLOCK_INPUT;
1962
1963 result = x_text_icon (f,
f468da95
RS
1964 (char *) XSTRING ((!NILP (f->icon_name)
1965 ? f->icon_name
943b580d
RS
1966 : !NILP (f->title)
1967 ? f->title
80534dd6
KH
1968 : f->name))->data);
1969
1970 if (result)
1971 {
1972 UNBLOCK_INPUT;
1973 error ("No icon window available");
1974 }
1975
80534dd6
KH
1976 XFlush (FRAME_X_DISPLAY (f));
1977 UNBLOCK_INPUT;
1978}
943b580d 1979\f
01f1ba30 1980void
f676886a
JB
1981x_set_font (f, arg, oldval)
1982 struct frame *f;
01f1ba30
JB
1983 Lisp_Object arg, oldval;
1984{
ea96210c 1985 Lisp_Object result;
942ea06d 1986 Lisp_Object fontset_name;
a367641f 1987 Lisp_Object frame;
57c5889c 1988 int old_fontset = f->output_data.x->fontset;
01f1ba30 1989
b7826503 1990 CHECK_STRING (arg);
01f1ba30 1991
49965a29 1992 fontset_name = Fquery_fontset (arg, Qnil);
942ea06d 1993
01f1ba30 1994 BLOCK_INPUT;
942ea06d
KH
1995 result = (STRINGP (fontset_name)
1996 ? x_new_fontset (f, XSTRING (fontset_name)->data)
1997 : x_new_font (f, XSTRING (arg)->data));
01f1ba30
JB
1998 UNBLOCK_INPUT;
1999
ea96210c 2000 if (EQ (result, Qnil))
1c59f5df 2001 error ("Font `%s' is not defined", XSTRING (arg)->data);
ea96210c 2002 else if (EQ (result, Qt))
26e18ed9 2003 error ("The characters of the given font have varying widths");
ea96210c
JB
2004 else if (STRINGP (result))
2005 {
57c5889c
GM
2006 if (STRINGP (fontset_name))
2007 {
2008 /* Fontset names are built from ASCII font names, so the
2009 names may be equal despite there was a change. */
2010 if (old_fontset == f->output_data.x->fontset)
2011 return;
2012 }
2013 else if (!NILP (Fequal (result, oldval)))
1d090605 2014 return;
57c5889c 2015
ea96210c 2016 store_frame_param (f, Qfont, result);
333b20bb 2017 recompute_basic_faces (f);
ea96210c
JB
2018 }
2019 else
2020 abort ();
a367641f 2021
8938a4fb 2022 do_pending_window_change (0);
95aa0336 2023
333b20bb
GM
2024 /* Don't call `face-set-after-frame-default' when faces haven't been
2025 initialized yet. This is the case when called from
2026 Fx_create_frame. In that case, the X widget or window doesn't
2027 exist either, and we can end up in x_report_frame_params with a
2028 null widget which gives a segfault. */
2029 if (FRAME_FACE_CACHE (f))
2030 {
2031 XSETFRAME (frame, f);
2032 call1 (Qface_set_after_frame_default, frame);
2033 }
01f1ba30
JB
2034}
2035
b3ba0aa8
KS
2036static void
2037x_set_fringe_width (f, new_value, old_value)
2038 struct frame *f;
2039 Lisp_Object new_value, old_value;
2040{
2041 x_compute_fringe_widths (f, 1);
2042}
2043
01f1ba30 2044void
f676886a
JB
2045x_set_border_width (f, arg, oldval)
2046 struct frame *f;
01f1ba30
JB
2047 Lisp_Object arg, oldval;
2048{
b7826503 2049 CHECK_NUMBER (arg);
01f1ba30 2050
7556890b 2051 if (XINT (arg) == f->output_data.x->border_width)
01f1ba30
JB
2052 return;
2053
fe24a618 2054 if (FRAME_X_WINDOW (f) != 0)
01f1ba30
JB
2055 error ("Cannot change the border width of a window");
2056
7556890b 2057 f->output_data.x->border_width = XINT (arg);
01f1ba30
JB
2058}
2059
2060void
f676886a
JB
2061x_set_internal_border_width (f, arg, oldval)
2062 struct frame *f;
01f1ba30
JB
2063 Lisp_Object arg, oldval;
2064{
7556890b 2065 int old = f->output_data.x->internal_border_width;
01f1ba30 2066
b7826503 2067 CHECK_NUMBER (arg);
7556890b
RS
2068 f->output_data.x->internal_border_width = XINT (arg);
2069 if (f->output_data.x->internal_border_width < 0)
2070 f->output_data.x->internal_border_width = 0;
01f1ba30 2071
d3b06468 2072#ifdef USE_X_TOOLKIT
2a8a07d4 2073 if (f->output_data.x->edit_widget)
968b1234 2074 widget_store_internal_border (f->output_data.x->edit_widget);
d3b06468 2075#endif
2a8a07d4 2076
7556890b 2077 if (f->output_data.x->internal_border_width == old)
01f1ba30
JB
2078 return;
2079
fe24a618 2080 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 2081 {
363f7e15 2082 x_set_window_size (f, 0, f->width, f->height);
f676886a 2083 SET_FRAME_GARBAGED (f);
8938a4fb 2084 do_pending_window_change (0);
01f1ba30 2085 }
ea42193a
GM
2086 else
2087 SET_FRAME_GARBAGED (f);
01f1ba30
JB
2088}
2089
d043f1a4
RS
2090void
2091x_set_visibility (f, value, oldval)
2092 struct frame *f;
2093 Lisp_Object value, oldval;
2094{
2095 Lisp_Object frame;
191ed777 2096 XSETFRAME (frame, f);
d043f1a4
RS
2097
2098 if (NILP (value))
363f7e15 2099 Fmake_frame_invisible (frame, Qt);
49795535 2100 else if (EQ (value, Qicon))
d043f1a4 2101 Ficonify_frame (frame);
49795535
JB
2102 else
2103 Fmake_frame_visible (frame);
d043f1a4 2104}
52de7ce9 2105
943b580d 2106\f
52de7ce9
GM
2107/* Change window heights in windows rooted in WINDOW by N lines. */
2108
d043f1a4 2109static void
52de7ce9 2110x_change_window_heights (window, n)
d043f1a4
RS
2111 Lisp_Object window;
2112 int n;
2113{
47c0f58b 2114 struct window *w = XWINDOW (window);
d043f1a4 2115
e33f7330
KH
2116 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2117 XSETFASTINT (w->height, XFASTINT (w->height) - n);
d043f1a4 2118
4336c705
GM
2119 if (INTEGERP (w->orig_top))
2120 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2121 if (INTEGERP (w->orig_height))
2122 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2123
47c0f58b
RS
2124 /* Handle just the top child in a vertical split. */
2125 if (!NILP (w->vchild))
52de7ce9 2126 x_change_window_heights (w->vchild, n);
d043f1a4 2127
47c0f58b
RS
2128 /* Adjust all children in a horizontal split. */
2129 for (window = w->hchild; !NILP (window); window = w->next)
2130 {
2131 w = XWINDOW (window);
52de7ce9 2132 x_change_window_heights (window, n);
d043f1a4
RS
2133 }
2134}
2135
2136void
2137x_set_menu_bar_lines (f, value, oldval)
2138 struct frame *f;
2139 Lisp_Object value, oldval;
2140{
2141 int nlines;
b6d7acec 2142#ifndef USE_X_TOOLKIT
d043f1a4 2143 int olines = FRAME_MENU_BAR_LINES (f);
b6d7acec 2144#endif
d043f1a4 2145
f64ba6ea
JB
2146 /* Right now, menu bars don't work properly in minibuf-only frames;
2147 most of the commands try to apply themselves to the minibuffer
333b20bb 2148 frame itself, and get an error because you can't switch buffers
f64ba6ea 2149 in or split the minibuffer window. */
519066d2 2150 if (FRAME_MINIBUF_ONLY_P (f))
f64ba6ea
JB
2151 return;
2152
6a5e54e2 2153 if (INTEGERP (value))
d043f1a4
RS
2154 nlines = XINT (value);
2155 else
2156 nlines = 0;
2157
3d09b6be
RS
2158 /* Make sure we redisplay all windows in this frame. */
2159 windows_or_buffers_changed++;
2160
9ef48a9d
RS
2161#ifdef USE_X_TOOLKIT
2162 FRAME_MENU_BAR_LINES (f) = 0;
2163 if (nlines)
0d8ef3f4
RS
2164 {
2165 FRAME_EXTERNAL_MENU_BAR (f) = 1;
97a1ff91 2166 if (FRAME_X_P (f) && f->output_data.x->menubar_widget == 0)
0d8ef3f4
RS
2167 /* Make sure next redisplay shows the menu bar. */
2168 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt;
2169 }
9ef48a9d
RS
2170 else
2171 {
6bc20398
FP
2172 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2173 free_frame_menubar (f);
9ef48a9d 2174 FRAME_EXTERNAL_MENU_BAR (f) = 0;
97a1ff91
RS
2175 if (FRAME_X_P (f))
2176 f->output_data.x->menubar_widget = 0;
9ef48a9d
RS
2177 }
2178#else /* not USE_X_TOOLKIT */
d043f1a4 2179 FRAME_MENU_BAR_LINES (f) = nlines;
52de7ce9 2180 x_change_window_heights (f->root_window, nlines - olines);
9ef48a9d 2181#endif /* not USE_X_TOOLKIT */
333b20bb
GM
2182 adjust_glyphs (f);
2183}
2184
2185
2186/* Set the number of lines used for the tool bar of frame F to VALUE.
2187 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2188 is the old number of tool bar lines. This function changes the
2189 height of all windows on frame F to match the new tool bar height.
2190 The frame's height doesn't change. */
2191
2192void
9ea173e8 2193x_set_tool_bar_lines (f, value, oldval)
333b20bb
GM
2194 struct frame *f;
2195 Lisp_Object value, oldval;
2196{
52de7ce9
GM
2197 int delta, nlines, root_height;
2198 Lisp_Object root_window;
333b20bb 2199
e870b7ba
GM
2200 /* Treat tool bars like menu bars. */
2201 if (FRAME_MINIBUF_ONLY_P (f))
2202 return;
2203
333b20bb
GM
2204 /* Use VALUE only if an integer >= 0. */
2205 if (INTEGERP (value) && XINT (value) >= 0)
2206 nlines = XFASTINT (value);
2207 else
2208 nlines = 0;
2209
2210 /* Make sure we redisplay all windows in this frame. */
2211 ++windows_or_buffers_changed;
2212
9ea173e8 2213 delta = nlines - FRAME_TOOL_BAR_LINES (f);
52de7ce9
GM
2214
2215 /* Don't resize the tool-bar to more than we have room for. */
2216 root_window = FRAME_ROOT_WINDOW (f);
2217 root_height = XINT (XWINDOW (root_window)->height);
2218 if (root_height - delta < 1)
2219 {
2220 delta = root_height - 1;
2221 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2222 }
2223
9ea173e8 2224 FRAME_TOOL_BAR_LINES (f) = nlines;
52de7ce9 2225 x_change_window_heights (root_window, delta);
333b20bb 2226 adjust_glyphs (f);
ccba751c
GM
2227
2228 /* We also have to make sure that the internal border at the top of
2229 the frame, below the menu bar or tool bar, is redrawn when the
2230 tool bar disappears. This is so because the internal border is
2231 below the tool bar if one is displayed, but is below the menu bar
2232 if there isn't a tool bar. The tool bar draws into the area
2233 below the menu bar. */
2234 if (FRAME_X_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2235 {
2236 updating_frame = f;
2237 clear_frame ();
fb3cd89b 2238 clear_current_matrices (f);
ccba751c
GM
2239 updating_frame = NULL;
2240 }
b6f91066
GM
2241
2242 /* If the tool bar gets smaller, the internal border below it
2243 has to be cleared. It was formerly part of the display
2244 of the larger tool bar, and updating windows won't clear it. */
2245 if (delta < 0)
2246 {
2247 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2248 int width = PIXEL_WIDTH (f);
2249 int y = nlines * CANON_Y_UNIT (f);
2250
2251 BLOCK_INPUT;
161d30fd
GM
2252 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2253 0, y, width, height, False);
b6f91066 2254 UNBLOCK_INPUT;
ddc24747
GM
2255
2256 if (WINDOWP (f->tool_bar_window))
2257 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
b6f91066 2258 }
333b20bb
GM
2259}
2260
2261
2262/* Set the foreground color for scroll bars on frame F to VALUE.
2263 VALUE should be a string, a color name. If it isn't a string or
2264 isn't a valid color name, do nothing. OLDVAL is the old value of
2265 the frame parameter. */
2266
2267void
2268x_set_scroll_bar_foreground (f, value, oldval)
2269 struct frame *f;
2270 Lisp_Object value, oldval;
2271{
2272 unsigned long pixel;
2273
2274 if (STRINGP (value))
2275 pixel = x_decode_color (f, value, BLACK_PIX_DEFAULT (f));
2276 else
2277 pixel = -1;
2278
2279 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
2280 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
2281
2282 f->output_data.x->scroll_bar_foreground_pixel = pixel;
2283 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2284 {
2285 /* Remove all scroll bars because they have wrong colors. */
2286 if (condemn_scroll_bars_hook)
2287 (*condemn_scroll_bars_hook) (f);
2288 if (judge_scroll_bars_hook)
2289 (*judge_scroll_bars_hook) (f);
05c8abbe
GM
2290
2291 update_face_from_frame_parameter (f, Qscroll_bar_foreground, value);
333b20bb
GM
2292 redraw_frame (f);
2293 }
2294}
2295
2296
2297/* Set the background color for scroll bars on frame F to VALUE VALUE
2298 should be a string, a color name. If it isn't a string or isn't a
2299 valid color name, do nothing. OLDVAL is the old value of the frame
2300 parameter. */
2301
2302void
2303x_set_scroll_bar_background (f, value, oldval)
2304 struct frame *f;
2305 Lisp_Object value, oldval;
2306{
2307 unsigned long pixel;
2308
2309 if (STRINGP (value))
2310 pixel = x_decode_color (f, value, WHITE_PIX_DEFAULT (f));
2311 else
2312 pixel = -1;
2313
2314 if (f->output_data.x->scroll_bar_background_pixel != -1)
2315 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
2316
f15340b7
MB
2317#ifdef USE_TOOLKIT_SCROLL_BARS
2318 /* Scrollbar shadow colors. */
2319 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
2320 {
2321 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
2322 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
2323 }
2324 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
2325 {
2326 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
2327 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
2328 }
2329#endif /* USE_TOOLKIT_SCROLL_BARS */
2330
333b20bb
GM
2331 f->output_data.x->scroll_bar_background_pixel = pixel;
2332 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2333 {
2334 /* Remove all scroll bars because they have wrong colors. */
2335 if (condemn_scroll_bars_hook)
2336 (*condemn_scroll_bars_hook) (f);
2337 if (judge_scroll_bars_hook)
2338 (*judge_scroll_bars_hook) (f);
2339
05c8abbe 2340 update_face_from_frame_parameter (f, Qscroll_bar_background, value);
333b20bb
GM
2341 redraw_frame (f);
2342 }
d043f1a4 2343}
333b20bb 2344
943b580d 2345\f
3a258507 2346/* Encode Lisp string STRING as a text in a format appropriate for
96db09e4
KH
2347 XICCC (X Inter Client Communication Conventions).
2348
2349 If STRING contains only ASCII characters, do no conversion and
2350 return the string data of STRING. Otherwise, encode the text by
2351 CODING_SYSTEM, and return a newly allocated memory area which
2352 should be freed by `xfree' by a caller.
2353
37323f34
EZ
2354 SELECTIONP non-zero means the string is being encoded for an X
2355 selection, so it is safe to run pre-write conversions (which
2356 may run Lisp code).
2357
96db09e4
KH
2358 Store the byte length of resulting text in *TEXT_BYTES.
2359
d60660d6 2360 If the text contains only ASCII and Latin-1, store 1 in *STRING_P,
96db09e4 2361 which means that the `encoding' of the result can be `STRING'.
d60660d6 2362 Otherwise store 0 in *STRINGP, which means that the `encoding' of
96db09e4
KH
2363 the result should be `COMPOUND_TEXT'. */
2364
2365unsigned char *
37323f34 2366x_encode_text (string, coding_system, selectionp, text_bytes, stringp)
96db09e4 2367 Lisp_Object string, coding_system;
d60660d6 2368 int *text_bytes, *stringp;
37323f34 2369 int selectionp;
96db09e4
KH
2370{
2371 unsigned char *str = XSTRING (string)->data;
2372 int chars = XSTRING (string)->size;
2373 int bytes = STRING_BYTES (XSTRING (string));
2374 int charset_info;
2375 int bufsize;
2376 unsigned char *buf;
2377 struct coding_system coding;
2378
2379 charset_info = find_charset_in_text (str, chars, bytes, NULL, Qnil);
2380 if (charset_info == 0)
2381 {
2382 /* No multibyte character in OBJ. We need not encode it. */
2383 *text_bytes = bytes;
d60660d6 2384 *stringp = 1;
96db09e4
KH
2385 return str;
2386 }
2387
2388 setup_coding_system (coding_system, &coding);
37323f34
EZ
2389 if (selectionp
2390 && SYMBOLP (coding.pre_write_conversion)
2391 && !NILP (Ffboundp (coding.pre_write_conversion)))
2392 {
2393 string = run_pre_post_conversion_on_str (string, &coding, 1);
2394 str = XSTRING (string)->data;
2395 chars = XSTRING (string)->size;
2396 bytes = STRING_BYTES (XSTRING (string));
2397 }
96db09e4
KH
2398 coding.src_multibyte = 1;
2399 coding.dst_multibyte = 0;
2400 coding.mode |= CODING_MODE_LAST_BLOCK;
d60660d6
KH
2401 if (coding.type == coding_type_iso2022)
2402 coding.flags |= CODING_FLAG_ISO_SAFE;
35bc5887
KH
2403 /* We suppress producing escape sequences for composition. */
2404 coding.composing = COMPOSITION_DISABLED;
96db09e4
KH
2405 bufsize = encoding_buffer_size (&coding, bytes);
2406 buf = (unsigned char *) xmalloc (bufsize);
2407 encode_coding (&coding, str, buf, bytes, bufsize);
2408 *text_bytes = coding.produced;
d60660d6 2409 *stringp = (charset_info == 1 || !EQ (coding_system, Qcompound_text));
96db09e4
KH
2410 return buf;
2411}
2412
2413\f
75f9d625 2414/* Change the name of frame F to NAME. If NAME is nil, set F's name to
f945b920
JB
2415 x_id_name.
2416
2417 If EXPLICIT is non-zero, that indicates that lisp code is setting the
75f9d625
DM
2418 name; if NAME is a string, set F's name to NAME and set
2419 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
f945b920
JB
2420
2421 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2422 suggesting a new name, which lisp code should override; if
2423 F->explicit_name is set, ignore the new name; otherwise, set it. */
2424
2425void
2426x_set_name (f, name, explicit)
2427 struct frame *f;
2428 Lisp_Object name;
2429 int explicit;
2430{
2431 /* Make sure that requests from lisp code override requests from
2432 Emacs redisplay code. */
2433 if (explicit)
2434 {
2435 /* If we're switching from explicit to implicit, we had better
2436 update the mode lines and thereby update the title. */
2437 if (f->explicit_name && NILP (name))
cf177271 2438 update_mode_lines = 1;
f945b920
JB
2439
2440 f->explicit_name = ! NILP (name);
2441 }
2442 else if (f->explicit_name)
2443 return;
2444
2445 /* If NAME is nil, set the name to the x_id_name. */
2446 if (NILP (name))
f10f0b79
RS
2447 {
2448 /* Check for no change needed in this very common case
2449 before we do any consing. */
08a90d6a
RS
2450 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->x_id_name,
2451 XSTRING (f->name)->data))
f10f0b79 2452 return;
08a90d6a 2453 name = build_string (FRAME_X_DISPLAY_INFO (f)->x_id_name);
f10f0b79 2454 }
62265f1c 2455 else
b7826503 2456 CHECK_STRING (name);
01f1ba30 2457
f945b920
JB
2458 /* Don't change the name if it's already NAME. */
2459 if (! NILP (Fstring_equal (name, f->name)))
daa37602
JB
2460 return;
2461
943b580d
RS
2462 f->name = name;
2463
2464 /* For setting the frame title, the title parameter should override
2465 the name parameter. */
2466 if (! NILP (f->title))
2467 name = f->title;
2468
fe24a618 2469 if (FRAME_X_WINDOW (f))
01f1ba30 2470 {
01f1ba30 2471 BLOCK_INPUT;
fe24a618
JB
2472#ifdef HAVE_X11R4
2473 {
80534dd6 2474 XTextProperty text, icon;
d60660d6 2475 int bytes, stringp;
11270583 2476 Lisp_Object coding_system;
80534dd6 2477
11270583
KH
2478 coding_system = Vlocale_coding_system;
2479 if (NILP (coding_system))
2480 coding_system = Qcompound_text;
37323f34 2481 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2482 text.encoding = (stringp ? XA_STRING
96db09e4 2483 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
fe24a618 2484 text.format = 8;
96db09e4 2485 text.nitems = bytes;
80534dd6 2486
96db09e4
KH
2487 if (NILP (f->icon_name))
2488 {
2489 icon = text;
2490 }
2491 else
2492 {
37323f34 2493 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2494 &bytes, &stringp);
2495 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2496 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2497 icon.format = 8;
2498 icon.nitems = bytes;
2499 }
9ef48a9d 2500#ifdef USE_X_TOOLKIT
b9dc4443 2501 XSetWMName (FRAME_X_DISPLAY (f),
7556890b
RS
2502 XtWindow (f->output_data.x->widget), &text);
2503 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
80534dd6 2504 &icon);
9ef48a9d 2505#else /* not USE_X_TOOLKIT */
b9dc4443 2506 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
80534dd6 2507 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
9ef48a9d 2508#endif /* not USE_X_TOOLKIT */
96db09e4
KH
2509 if (!NILP (f->icon_name)
2510 && icon.value != XSTRING (f->icon_name)->data)
2511 xfree (icon.value);
2512 if (text.value != XSTRING (name)->data)
2513 xfree (text.value);
fe24a618 2514 }
9ef48a9d 2515#else /* not HAVE_X11R4 */
b9dc4443 2516 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
fe24a618 2517 XSTRING (name)->data);
b9dc4443 2518 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
fe24a618 2519 XSTRING (name)->data);
9ef48a9d 2520#endif /* not HAVE_X11R4 */
01f1ba30
JB
2521 UNBLOCK_INPUT;
2522 }
f945b920
JB
2523}
2524
2525/* This function should be called when the user's lisp code has
2526 specified a name for the frame; the name will override any set by the
2527 redisplay code. */
2528void
2529x_explicitly_set_name (f, arg, oldval)
2530 FRAME_PTR f;
2531 Lisp_Object arg, oldval;
2532{
2533 x_set_name (f, arg, 1);
2534}
2535
2536/* This function should be called by Emacs redisplay code to set the
2537 name; names set this way will never override names set by the user's
2538 lisp code. */
25250031 2539void
f945b920
JB
2540x_implicitly_set_name (f, arg, oldval)
2541 FRAME_PTR f;
2542 Lisp_Object arg, oldval;
2543{
2544 x_set_name (f, arg, 0);
01f1ba30 2545}
943b580d
RS
2546\f
2547/* Change the title of frame F to NAME.
2548 If NAME is nil, use the frame name as the title.
01f1ba30 2549
943b580d
RS
2550 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2551 name; if NAME is a string, set F's name to NAME and set
2552 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2553
2554 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2555 suggesting a new name, which lisp code should override; if
2556 F->explicit_name is set, ignore the new name; otherwise, set it. */
2557
2558void
d62c8769 2559x_set_title (f, name, old_name)
943b580d 2560 struct frame *f;
d62c8769 2561 Lisp_Object name, old_name;
943b580d
RS
2562{
2563 /* Don't change the title if it's already NAME. */
2564 if (EQ (name, f->title))
2565 return;
2566
2567 update_mode_lines = 1;
2568
2569 f->title = name;
2570
2571 if (NILP (name))
2572 name = f->name;
beb403b3 2573 else
b7826503 2574 CHECK_STRING (name);
943b580d
RS
2575
2576 if (FRAME_X_WINDOW (f))
2577 {
2578 BLOCK_INPUT;
2579#ifdef HAVE_X11R4
2580 {
2581 XTextProperty text, icon;
d60660d6 2582 int bytes, stringp;
11270583 2583 Lisp_Object coding_system;
943b580d 2584
11270583
KH
2585 coding_system = Vlocale_coding_system;
2586 if (NILP (coding_system))
2587 coding_system = Qcompound_text;
37323f34 2588 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2589 text.encoding = (stringp ? XA_STRING
96db09e4 2590 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
943b580d 2591 text.format = 8;
96db09e4 2592 text.nitems = bytes;
943b580d 2593
96db09e4
KH
2594 if (NILP (f->icon_name))
2595 {
2596 icon = text;
2597 }
2598 else
2599 {
37323f34 2600 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2601 &bytes, &stringp);
2602 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2603 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2604 icon.format = 8;
2605 icon.nitems = bytes;
2606 }
943b580d
RS
2607#ifdef USE_X_TOOLKIT
2608 XSetWMName (FRAME_X_DISPLAY (f),
2609 XtWindow (f->output_data.x->widget), &text);
2610 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
2611 &icon);
2612#else /* not USE_X_TOOLKIT */
2613 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
2614 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
2615#endif /* not USE_X_TOOLKIT */
96db09e4
KH
2616 if (!NILP (f->icon_name)
2617 && icon.value != XSTRING (f->icon_name)->data)
2618 xfree (icon.value);
2619 if (text.value != XSTRING (name)->data)
2620 xfree (text.value);
943b580d
RS
2621 }
2622#else /* not HAVE_X11R4 */
2623 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2624 XSTRING (name)->data);
2625 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2626 XSTRING (name)->data);
2627#endif /* not HAVE_X11R4 */
2628 UNBLOCK_INPUT;
2629 }
2630}
2631\f
01f1ba30 2632void
f676886a
JB
2633x_set_autoraise (f, arg, oldval)
2634 struct frame *f;
01f1ba30
JB
2635 Lisp_Object arg, oldval;
2636{
f676886a 2637 f->auto_raise = !EQ (Qnil, arg);
01f1ba30
JB
2638}
2639
2640void
f676886a
JB
2641x_set_autolower (f, arg, oldval)
2642 struct frame *f;
01f1ba30
JB
2643 Lisp_Object arg, oldval;
2644{
f676886a 2645 f->auto_lower = !EQ (Qnil, arg);
01f1ba30 2646}
179956b9 2647
eac358ef
KH
2648void
2649x_set_unsplittable (f, arg, oldval)
2650 struct frame *f;
2651 Lisp_Object arg, oldval;
2652{
2653 f->no_split = !NILP (arg);
2654}
2655
179956b9 2656void
a3c87d4e 2657x_set_vertical_scroll_bars (f, arg, oldval)
179956b9
JB
2658 struct frame *f;
2659 Lisp_Object arg, oldval;
2660{
1ab3d87e
RS
2661 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2662 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2663 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2664 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
179956b9 2665 {
1ab3d87e
RS
2666 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2667 = (NILP (arg)
2668 ? vertical_scroll_bar_none
2669 : EQ (Qright, arg)
2670 ? vertical_scroll_bar_right
2671 : vertical_scroll_bar_left);
179956b9 2672
cf177271
JB
2673 /* We set this parameter before creating the X window for the
2674 frame, so we can get the geometry right from the start.
2675 However, if the window hasn't been created yet, we shouldn't
2676 call x_set_window_size. */
2677 if (FRAME_X_WINDOW (f))
363f7e15 2678 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2679 do_pending_window_change (0);
179956b9
JB
2680 }
2681}
4701395c
KH
2682
2683void
2684x_set_scroll_bar_width (f, arg, oldval)
2685 struct frame *f;
2686 Lisp_Object arg, oldval;
2687{
a672c74d
RS
2688 int wid = FONT_WIDTH (f->output_data.x->font);
2689
dff9a538
KH
2690 if (NILP (arg))
2691 {
c6e9d03b
GM
2692#ifdef USE_TOOLKIT_SCROLL_BARS
2693 /* A minimum width of 14 doesn't look good for toolkit scroll bars. */
333b20bb
GM
2694 int width = 16 + 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM;
2695 FRAME_SCROLL_BAR_COLS (f) = (width + wid - 1) / wid;
2696 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = width;
2697#else
2698 /* Make the actual width at least 14 pixels and a multiple of a
2699 character width. */
a672c74d 2700 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
333b20bb
GM
2701
2702 /* Use all of that space (aside from required margins) for the
2703 scroll bar. */
dff9a538 2704 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
333b20bb 2705#endif
a672c74d 2706
a90ab372
RS
2707 if (FRAME_X_WINDOW (f))
2708 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2709 do_pending_window_change (0);
dff9a538
KH
2710 }
2711 else if (INTEGERP (arg) && XINT (arg) > 0
2712 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
4701395c 2713 {
09d8c7ac
RS
2714 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
2715 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
0a26b136 2716
4701395c
KH
2717 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2718 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
2719 if (FRAME_X_WINDOW (f))
2720 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2721 }
dca97592 2722
8938a4fb 2723 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
333b20bb
GM
2724 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2725 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
4701395c 2726}
333b20bb
GM
2727
2728
01f1ba30 2729\f
f676886a 2730/* Subroutines of creating an X frame. */
01f1ba30 2731
b7975ee4
KH
2732/* Make sure that Vx_resource_name is set to a reasonable value.
2733 Fix it up, or set it to `emacs' if it is too hopeless. */
2734
d387c960
JB
2735static void
2736validate_x_resource_name ()
2737{
333b20bb 2738 int len = 0;
0e78b377
RS
2739 /* Number of valid characters in the resource name. */
2740 int good_count = 0;
2741 /* Number of invalid characters in the resource name. */
2742 int bad_count = 0;
2743 Lisp_Object new;
2744 int i;
2745
498e9ac3
RS
2746 if (!STRINGP (Vx_resource_class))
2747 Vx_resource_class = build_string (EMACS_CLASS);
2748
cf204347
RS
2749 if (STRINGP (Vx_resource_name))
2750 {
cf204347
RS
2751 unsigned char *p = XSTRING (Vx_resource_name)->data;
2752 int i;
2753
fc932ac6 2754 len = STRING_BYTES (XSTRING (Vx_resource_name));
0e78b377
RS
2755
2756 /* Only letters, digits, - and _ are valid in resource names.
2757 Count the valid characters and count the invalid ones. */
cf204347
RS
2758 for (i = 0; i < len; i++)
2759 {
2760 int c = p[i];
2761 if (! ((c >= 'a' && c <= 'z')
2762 || (c >= 'A' && c <= 'Z')
2763 || (c >= '0' && c <= '9')
2764 || c == '-' || c == '_'))
0e78b377
RS
2765 bad_count++;
2766 else
2767 good_count++;
cf204347
RS
2768 }
2769 }
2770 else
0e78b377
RS
2771 /* Not a string => completely invalid. */
2772 bad_count = 5, good_count = 0;
2773
2774 /* If name is valid already, return. */
2775 if (bad_count == 0)
2776 return;
2777
2778 /* If name is entirely invalid, or nearly so, use `emacs'. */
2779 if (good_count == 0
2780 || (good_count == 1 && bad_count > 0))
2781 {
b7975ee4 2782 Vx_resource_name = build_string ("emacs");
0e78b377
RS
2783 return;
2784 }
2785
2786 /* Name is partly valid. Copy it and replace the invalid characters
2787 with underscores. */
2788
2789 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2790
2791 for (i = 0; i < len; i++)
2792 {
2793 int c = XSTRING (new)->data[i];
2794 if (! ((c >= 'a' && c <= 'z')
2795 || (c >= 'A' && c <= 'Z')
2796 || (c >= '0' && c <= '9')
2797 || c == '-' || c == '_'))
2798 XSTRING (new)->data[i] = '_';
2799 }
d387c960
JB
2800}
2801
2802
01f1ba30 2803extern char *x_get_string_resource ();
01f1ba30 2804
cf177271 2805DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
03265352 2806 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
c061c855
GM
2807This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2808class, where INSTANCE is the name under which Emacs was invoked, or
2809the name specified by the `-name' or `-rn' command-line arguments.
2810
2811The optional arguments COMPONENT and SUBCLASS add to the key and the
2812class, respectively. You must specify both of them or neither.
2813If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
7ee72033
MB
2814and the class is `Emacs.CLASS.SUBCLASS'. */)
2815 (attribute, class, component, subclass)
cf177271 2816 Lisp_Object attribute, class, component, subclass;
01f1ba30
JB
2817{
2818 register char *value;
2819 char *name_key;
2820 char *class_key;
2821
11ae94fe
RS
2822 check_x ();
2823
b7826503
PJ
2824 CHECK_STRING (attribute);
2825 CHECK_STRING (class);
cf177271 2826
8fabe6f4 2827 if (!NILP (component))
b7826503 2828 CHECK_STRING (component);
8fabe6f4 2829 if (!NILP (subclass))
b7826503 2830 CHECK_STRING (subclass);
8fabe6f4
RS
2831 if (NILP (component) != NILP (subclass))
2832 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2833
d387c960
JB
2834 validate_x_resource_name ();
2835
b7975ee4
KH
2836 /* Allocate space for the components, the dots which separate them,
2837 and the final '\0'. Make them big enough for the worst case. */
fc932ac6 2838 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
b7975ee4 2839 + (STRINGP (component)
fc932ac6
RS
2840 ? STRING_BYTES (XSTRING (component)) : 0)
2841 + STRING_BYTES (XSTRING (attribute))
b7975ee4
KH
2842 + 3);
2843
fc932ac6
RS
2844 class_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_class))
2845 + STRING_BYTES (XSTRING (class))
b7975ee4 2846 + (STRINGP (subclass)
fc932ac6 2847 ? STRING_BYTES (XSTRING (subclass)) : 0)
b7975ee4
KH
2848 + 3);
2849
2850 /* Start with emacs.FRAMENAME for the name (the specific one)
2851 and with `Emacs' for the class key (the general one). */
2852 strcpy (name_key, XSTRING (Vx_resource_name)->data);
498e9ac3 2853 strcpy (class_key, XSTRING (Vx_resource_class)->data);
b7975ee4
KH
2854
2855 strcat (class_key, ".");
2856 strcat (class_key, XSTRING (class)->data);
2857
2858 if (!NILP (component))
01f1ba30 2859 {
b7975ee4
KH
2860 strcat (class_key, ".");
2861 strcat (class_key, XSTRING (subclass)->data);
2862
2863 strcat (name_key, ".");
2864 strcat (name_key, XSTRING (component)->data);
01f1ba30
JB
2865 }
2866
b7975ee4
KH
2867 strcat (name_key, ".");
2868 strcat (name_key, XSTRING (attribute)->data);
2869
b9dc4443
RS
2870 value = x_get_string_resource (check_x_display_info (Qnil)->xrdb,
2871 name_key, class_key);
01f1ba30
JB
2872
2873 if (value != (char *) 0)
2874 return build_string (value);
2875 else
2876 return Qnil;
2877}
2878
abb4b7ec
RS
2879/* Get an X resource, like Fx_get_resource, but for display DPYINFO. */
2880
333b20bb 2881Lisp_Object
abb4b7ec
RS
2882display_x_get_resource (dpyinfo, attribute, class, component, subclass)
2883 struct x_display_info *dpyinfo;
2884 Lisp_Object attribute, class, component, subclass;
2885{
2886 register char *value;
2887 char *name_key;
2888 char *class_key;
2889
b7826503
PJ
2890 CHECK_STRING (attribute);
2891 CHECK_STRING (class);
abb4b7ec
RS
2892
2893 if (!NILP (component))
b7826503 2894 CHECK_STRING (component);
abb4b7ec 2895 if (!NILP (subclass))
b7826503 2896 CHECK_STRING (subclass);
abb4b7ec
RS
2897 if (NILP (component) != NILP (subclass))
2898 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2899
2900 validate_x_resource_name ();
2901
2902 /* Allocate space for the components, the dots which separate them,
2903 and the final '\0'. Make them big enough for the worst case. */
fc932ac6 2904 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
abb4b7ec 2905 + (STRINGP (component)
fc932ac6
RS
2906 ? STRING_BYTES (XSTRING (component)) : 0)
2907 + STRING_BYTES (XSTRING (attribute))
abb4b7ec
RS
2908 + 3);
2909
fc932ac6
RS
2910 class_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_class))
2911 + STRING_BYTES (XSTRING (class))
abb4b7ec 2912 + (STRINGP (subclass)
fc932ac6 2913 ? STRING_BYTES (XSTRING (subclass)) : 0)
abb4b7ec
RS
2914 + 3);
2915
2916 /* Start with emacs.FRAMENAME for the name (the specific one)
2917 and with `Emacs' for the class key (the general one). */
2918 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2919 strcpy (class_key, XSTRING (Vx_resource_class)->data);
2920
2921 strcat (class_key, ".");
2922 strcat (class_key, XSTRING (class)->data);
2923
2924 if (!NILP (component))
2925 {
2926 strcat (class_key, ".");
2927 strcat (class_key, XSTRING (subclass)->data);
2928
2929 strcat (name_key, ".");
2930 strcat (name_key, XSTRING (component)->data);
2931 }
2932
2933 strcat (name_key, ".");
2934 strcat (name_key, XSTRING (attribute)->data);
2935
2936 value = x_get_string_resource (dpyinfo->xrdb, name_key, class_key);
2937
2938 if (value != (char *) 0)
2939 return build_string (value);
2940 else
2941 return Qnil;
2942}
2943
3402e1a4
RS
2944/* Used when C code wants a resource value. */
2945
2946char *
2947x_get_resource_string (attribute, class)
2948 char *attribute, *class;
2949{
3402e1a4
RS
2950 char *name_key;
2951 char *class_key;
0fe92f72 2952 struct frame *sf = SELECTED_FRAME ();
3402e1a4
RS
2953
2954 /* Allocate space for the components, the dots which separate them,
2955 and the final '\0'. */
fc932ac6 2956 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3402e1a4
RS
2957 + strlen (attribute) + 2);
2958 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2959 + strlen (class) + 2);
2960
2961 sprintf (name_key, "%s.%s",
2962 XSTRING (Vinvocation_name)->data,
2963 attribute);
2964 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2965
0fe92f72 2966 return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
b9dc4443 2967 name_key, class_key);
3402e1a4
RS
2968}
2969
60fb3ee1
JB
2970/* Types we might convert a resource string into. */
2971enum resource_types
333b20bb
GM
2972{
2973 RES_TYPE_NUMBER,
d62c8769 2974 RES_TYPE_FLOAT,
333b20bb
GM
2975 RES_TYPE_BOOLEAN,
2976 RES_TYPE_STRING,
2977 RES_TYPE_SYMBOL
2978};
60fb3ee1 2979
01f1ba30 2980/* Return the value of parameter PARAM.
60fb3ee1 2981
f676886a 2982 First search ALIST, then Vdefault_frame_alist, then the X defaults
cf177271 2983 database, using ATTRIBUTE as the attribute name and CLASS as its class.
60fb3ee1
JB
2984
2985 Convert the resource to the type specified by desired_type.
2986
f9942c9e
JB
2987 If no default is specified, return Qunbound. If you call
2988 x_get_arg, make sure you deal with Qunbound in a reasonable way,
a59e4f3d 2989 and don't let it get stored in any Lisp-visible variables! */
01f1ba30
JB
2990
2991static Lisp_Object
abb4b7ec
RS
2992x_get_arg (dpyinfo, alist, param, attribute, class, type)
2993 struct x_display_info *dpyinfo;
3c254570 2994 Lisp_Object alist, param;
60fb3ee1 2995 char *attribute;
cf177271 2996 char *class;
60fb3ee1 2997 enum resource_types type;
01f1ba30
JB
2998{
2999 register Lisp_Object tem;
3000
3001 tem = Fassq (param, alist);
3002 if (EQ (tem, Qnil))
f676886a 3003 tem = Fassq (param, Vdefault_frame_alist);
f9942c9e 3004 if (EQ (tem, Qnil))
01f1ba30 3005 {
60fb3ee1 3006
f9942c9e 3007 if (attribute)
60fb3ee1 3008 {
abb4b7ec
RS
3009 tem = display_x_get_resource (dpyinfo,
3010 build_string (attribute),
3011 build_string (class),
3012 Qnil, Qnil);
f9942c9e
JB
3013
3014 if (NILP (tem))
3015 return Qunbound;
3016
3017 switch (type)
3018 {
333b20bb 3019 case RES_TYPE_NUMBER:
f9942c9e
JB
3020 return make_number (atoi (XSTRING (tem)->data));
3021
d62c8769
GM
3022 case RES_TYPE_FLOAT:
3023 return make_float (atof (XSTRING (tem)->data));
3024
333b20bb 3025 case RES_TYPE_BOOLEAN:
f9942c9e
JB
3026 tem = Fdowncase (tem);
3027 if (!strcmp (XSTRING (tem)->data, "on")
3028 || !strcmp (XSTRING (tem)->data, "true"))
3029 return Qt;
3030 else
3031 return Qnil;
3032
333b20bb 3033 case RES_TYPE_STRING:
f9942c9e
JB
3034 return tem;
3035
333b20bb 3036 case RES_TYPE_SYMBOL:
49795535
JB
3037 /* As a special case, we map the values `true' and `on'
3038 to Qt, and `false' and `off' to Qnil. */
3039 {
98381190
KH
3040 Lisp_Object lower;
3041 lower = Fdowncase (tem);
26ae6b61
KH
3042 if (!strcmp (XSTRING (lower)->data, "on")
3043 || !strcmp (XSTRING (lower)->data, "true"))
49795535 3044 return Qt;
26ae6b61
KH
3045 else if (!strcmp (XSTRING (lower)->data, "off")
3046 || !strcmp (XSTRING (lower)->data, "false"))
49795535
JB
3047 return Qnil;
3048 else
89032215 3049 return Fintern (tem, Qnil);
49795535 3050 }
f945b920 3051
f9942c9e
JB
3052 default:
3053 abort ();
3054 }
60fb3ee1 3055 }
f9942c9e
JB
3056 else
3057 return Qunbound;
01f1ba30
JB
3058 }
3059 return Fcdr (tem);
3060}
3061
e4f79258
RS
3062/* Like x_get_arg, but also record the value in f->param_alist. */
3063
3064static Lisp_Object
3065x_get_and_record_arg (f, alist, param, attribute, class, type)
3066 struct frame *f;
3067 Lisp_Object alist, param;
3068 char *attribute;
3069 char *class;
3070 enum resource_types type;
3071{
3072 Lisp_Object value;
3073
abb4b7ec
RS
3074 value = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, param,
3075 attribute, class, type);
e4f79258
RS
3076 if (! NILP (value))
3077 store_frame_param (f, param, value);
3078
3079 return value;
3080}
3081
f676886a 3082/* Record in frame F the specified or default value according to ALIST
e8cc313b
KH
3083 of the parameter named PROP (a Lisp symbol).
3084 If no value is specified for PROP, look for an X default for XPROP
f676886a 3085 on the frame named NAME.
01f1ba30
JB
3086 If that is not found either, use the value DEFLT. */
3087
3088static Lisp_Object
cf177271 3089x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
f676886a 3090 struct frame *f;
01f1ba30 3091 Lisp_Object alist;
f9942c9e 3092 Lisp_Object prop;
01f1ba30
JB
3093 Lisp_Object deflt;
3094 char *xprop;
cf177271 3095 char *xclass;
60fb3ee1 3096 enum resource_types type;
01f1ba30 3097{
01f1ba30
JB
3098 Lisp_Object tem;
3099
abb4b7ec 3100 tem = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, prop, xprop, xclass, type);
f9942c9e 3101 if (EQ (tem, Qunbound))
01f1ba30 3102 tem = deflt;
f9942c9e 3103 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
01f1ba30
JB
3104 return tem;
3105}
333b20bb
GM
3106
3107
3108/* Record in frame F the specified or default value according to ALIST
3109 of the parameter named PROP (a Lisp symbol). If no value is
3110 specified for PROP, look for an X default for XPROP on the frame
3111 named NAME. If that is not found either, use the value DEFLT. */
3112
3113static Lisp_Object
3114x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass,
3115 foreground_p)
3116 struct frame *f;
3117 Lisp_Object alist;
3118 Lisp_Object prop;
3119 char *xprop;
3120 char *xclass;
3121 int foreground_p;
3122{
3123 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3124 Lisp_Object tem;
3125
3126 tem = x_get_arg (dpyinfo, alist, prop, xprop, xclass, RES_TYPE_STRING);
3127 if (EQ (tem, Qunbound))
3128 {
3129#ifdef USE_TOOLKIT_SCROLL_BARS
3130
3131 /* See if an X resource for the scroll bar color has been
3132 specified. */
3133 tem = display_x_get_resource (dpyinfo,
3134 build_string (foreground_p
3135 ? "foreground"
3136 : "background"),
c0ec53ad 3137 empty_string,
333b20bb 3138 build_string ("verticalScrollBar"),
c0ec53ad 3139 empty_string);
333b20bb
GM
3140 if (!STRINGP (tem))
3141 {
3142 /* If nothing has been specified, scroll bars will use a
3143 toolkit-dependent default. Because these defaults are
3144 difficult to get at without actually creating a scroll
3145 bar, use nil to indicate that no color has been
3146 specified. */
3147 tem = Qnil;
3148 }
3149
3150#else /* not USE_TOOLKIT_SCROLL_BARS */
3151
3152 tem = Qnil;
3153
3154#endif /* not USE_TOOLKIT_SCROLL_BARS */
3155 }
3156
3157 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3158 return tem;
3159}
3160
3161
01f1ba30 3162\f
8af1d7ca 3163DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
7ee72033 3164 doc: /* Parse an X-style geometry string STRING.
c061c855
GM
3165Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3166The properties returned may include `top', `left', `height', and `width'.
3167The value of `left' or `top' may be an integer,
3168or a list (+ N) meaning N pixels relative to top/left corner,
7ee72033
MB
3169or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3170 (string)
a6605e5c 3171 Lisp_Object string;
01f1ba30
JB
3172{
3173 int geometry, x, y;
3174 unsigned int width, height;
f83f10ba 3175 Lisp_Object result;
01f1ba30 3176
b7826503 3177 CHECK_STRING (string);
01f1ba30
JB
3178
3179 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3180 &x, &y, &width, &height);
3181
f83f10ba
RS
3182#if 0
3183 if (!!(geometry & XValue) != !!(geometry & YValue))
3184 error ("Must specify both x and y position, or neither");
3185#endif
3186
3187 result = Qnil;
3188 if (geometry & XValue)
01f1ba30 3189 {
f83f10ba
RS
3190 Lisp_Object element;
3191
e1d962d7
RS
3192 if (x >= 0 && (geometry & XNegative))
3193 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3194 else if (x < 0 && ! (geometry & XNegative))
3195 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
f83f10ba
RS
3196 else
3197 element = Fcons (Qleft, make_number (x));
3198 result = Fcons (element, result);
3199 }
3200
3201 if (geometry & YValue)
3202 {
3203 Lisp_Object element;
3204
e1d962d7
RS
3205 if (y >= 0 && (geometry & YNegative))
3206 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3207 else if (y < 0 && ! (geometry & YNegative))
3208 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
f83f10ba
RS
3209 else
3210 element = Fcons (Qtop, make_number (y));
3211 result = Fcons (element, result);
01f1ba30 3212 }
f83f10ba
RS
3213
3214 if (geometry & WidthValue)
3215 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3216 if (geometry & HeightValue)
3217 result = Fcons (Fcons (Qheight, make_number (height)), result);
3218
3219 return result;
01f1ba30
JB
3220}
3221
01f1ba30 3222/* Calculate the desired size and position of this window,
f83f10ba 3223 and return the flags saying which aspects were specified.
8fc2766b
RS
3224
3225 This function does not make the coordinates positive. */
01f1ba30
JB
3226
3227#define DEFAULT_ROWS 40
3228#define DEFAULT_COLS 80
3229
f9942c9e 3230static int
f676886a
JB
3231x_figure_window_size (f, parms)
3232 struct frame *f;
01f1ba30
JB
3233 Lisp_Object parms;
3234{
4fe1de12 3235 register Lisp_Object tem0, tem1, tem2;
01f1ba30 3236 long window_prompting = 0;
abb4b7ec 3237 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
3238
3239 /* Default values if we fall through.
3240 Actually, if that happens we should get
b9dc4443 3241 window manager prompting. */
1ab3d87e 3242 SET_FRAME_WIDTH (f, DEFAULT_COLS);
f676886a 3243 f->height = DEFAULT_ROWS;
bd0b85c3
RS
3244 /* Window managers expect that if program-specified
3245 positions are not (0,0), they're intentional, not defaults. */
7556890b
RS
3246 f->output_data.x->top_pos = 0;
3247 f->output_data.x->left_pos = 0;
01f1ba30 3248
333b20bb
GM
3249 tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3250 tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3251 tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3252 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3253 {
f83f10ba
RS
3254 if (!EQ (tem0, Qunbound))
3255 {
b7826503 3256 CHECK_NUMBER (tem0);
f83f10ba
RS
3257 f->height = XINT (tem0);
3258 }
3259 if (!EQ (tem1, Qunbound))
3260 {
b7826503 3261 CHECK_NUMBER (tem1);
1ab3d87e 3262 SET_FRAME_WIDTH (f, XINT (tem1));
f83f10ba
RS
3263 }
3264 if (!NILP (tem2) && !EQ (tem2, Qunbound))
4fe1de12
RS
3265 window_prompting |= USSize;
3266 else
3267 window_prompting |= PSize;
01f1ba30 3268 }
01f1ba30 3269
7556890b 3270 f->output_data.x->vertical_scroll_bar_extra
a444c70b
KH
3271 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3272 ? 0
7556890b 3273 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
b3ba0aa8
KS
3274
3275 x_compute_fringe_widths (f, 0);
3276
7556890b
RS
3277 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3278 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
01f1ba30 3279
333b20bb
GM
3280 tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3281 tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3282 tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3283 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3284 {
f83f10ba
RS
3285 if (EQ (tem0, Qminus))
3286 {
7556890b 3287 f->output_data.x->top_pos = 0;
f83f10ba
RS
3288 window_prompting |= YNegative;
3289 }
8e713be6
KR
3290 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3291 && CONSP (XCDR (tem0))
3292 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3293 {
8e713be6 3294 f->output_data.x->top_pos = - XINT (XCAR (XCDR (tem0)));
e1d962d7
RS
3295 window_prompting |= YNegative;
3296 }
8e713be6
KR
3297 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3298 && CONSP (XCDR (tem0))
3299 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3300 {
8e713be6 3301 f->output_data.x->top_pos = XINT (XCAR (XCDR (tem0)));
e1d962d7 3302 }
f83f10ba 3303 else if (EQ (tem0, Qunbound))
7556890b 3304 f->output_data.x->top_pos = 0;
f83f10ba
RS
3305 else
3306 {
b7826503 3307 CHECK_NUMBER (tem0);
7556890b
RS
3308 f->output_data.x->top_pos = XINT (tem0);
3309 if (f->output_data.x->top_pos < 0)
f83f10ba
RS
3310 window_prompting |= YNegative;
3311 }
3312
3313 if (EQ (tem1, Qminus))
3314 {
7556890b 3315 f->output_data.x->left_pos = 0;
f83f10ba
RS
3316 window_prompting |= XNegative;
3317 }
8e713be6
KR
3318 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3319 && CONSP (XCDR (tem1))
3320 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3321 {
8e713be6 3322 f->output_data.x->left_pos = - XINT (XCAR (XCDR (tem1)));
e1d962d7
RS
3323 window_prompting |= XNegative;
3324 }
8e713be6
KR
3325 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3326 && CONSP (XCDR (tem1))
3327 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3328 {
8e713be6 3329 f->output_data.x->left_pos = XINT (XCAR (XCDR (tem1)));
e1d962d7 3330 }
f83f10ba 3331 else if (EQ (tem1, Qunbound))
7556890b 3332 f->output_data.x->left_pos = 0;
f83f10ba
RS
3333 else
3334 {
b7826503 3335 CHECK_NUMBER (tem1);
7556890b
RS
3336 f->output_data.x->left_pos = XINT (tem1);
3337 if (f->output_data.x->left_pos < 0)
f83f10ba
RS
3338 window_prompting |= XNegative;
3339 }
3340
c3724dc2 3341 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
4fe1de12
RS
3342 window_prompting |= USPosition;
3343 else
3344 window_prompting |= PPosition;
01f1ba30 3345 }
f83f10ba 3346
49d41073
EZ
3347 if (f->output_data.x->want_fullscreen != FULLSCREEN_NONE)
3348 {
3349 int left, top;
3350 int width, height;
3351
3352 /* It takes both for some WM:s to place it where we want */
3353 window_prompting = USPosition | PPosition;
3354 x_fullscreen_adjust (f, &width, &height, &top, &left);
3355 f->width = width;
3356 f->height = height;
3357 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3358 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3359 f->output_data.x->left_pos = left;
3360 f->output_data.x->top_pos = top;
3361 }
3362
739f2f53 3363 return window_prompting;
01f1ba30
JB
3364}
3365
f58534a3
RS
3366#if !defined (HAVE_X11R4) && !defined (HAVE_XSETWMPROTOCOLS)
3367
3368Status
3369XSetWMProtocols (dpy, w, protocols, count)
3370 Display *dpy;
3371 Window w;
3372 Atom *protocols;
3373 int count;
3374{
3375 Atom prop;
3376 prop = XInternAtom (dpy, "WM_PROTOCOLS", False);
3377 if (prop == None) return False;
3378 XChangeProperty (dpy, w, prop, XA_ATOM, 32, PropModeReplace,
3379 (unsigned char *) protocols, count);
3380 return True;
3381}
9ef48a9d
RS
3382#endif /* not HAVE_X11R4 && not HAVE_XSETWMPROTOCOLS */
3383\f
3384#ifdef USE_X_TOOLKIT
3385
8e3d10a9
RS
3386/* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS,
3387 WM_DELETE_WINDOW, and WM_SAVE_YOURSELF, then add them. (They may
59aa6c90
RS
3388 already be present because of the toolkit (Motif adds some of them,
3389 for example, but Xt doesn't). */
9ef48a9d
RS
3390
3391static void
b9dc4443
RS
3392hack_wm_protocols (f, widget)
3393 FRAME_PTR f;
9ef48a9d
RS
3394 Widget widget;
3395{
3396 Display *dpy = XtDisplay (widget);
3397 Window w = XtWindow (widget);
3398 int need_delete = 1;
3399 int need_focus = 1;
59aa6c90 3400 int need_save = 1;
9ef48a9d
RS
3401
3402 BLOCK_INPUT;
3403 {
3404 Atom type, *atoms = 0;
3405 int format = 0;
3406 unsigned long nitems = 0;
3407 unsigned long bytes_after;
3408
270958e8
KH
3409 if ((XGetWindowProperty (dpy, w,
3410 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
34d5ae1e 3411 (long)0, (long)100, False, XA_ATOM,
270958e8
KH
3412 &type, &format, &nitems, &bytes_after,
3413 (unsigned char **) &atoms)
3414 == Success)
9ef48a9d
RS
3415 && format == 32 && type == XA_ATOM)
3416 while (nitems > 0)
3417 {
3418 nitems--;
b9dc4443
RS
3419 if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window)
3420 need_delete = 0;
3421 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus)
3422 need_focus = 0;
3423 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself)
3424 need_save = 0;
9ef48a9d
RS
3425 }
3426 if (atoms) XFree ((char *) atoms);
3427 }
3428 {
3429 Atom props [10];
3430 int count = 0;
b9dc4443
RS
3431 if (need_delete)
3432 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
3433 if (need_focus)
3434 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus;
3435 if (need_save)
3436 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
9ef48a9d 3437 if (count)
b9dc4443
RS
3438 XChangeProperty (dpy, w, FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3439 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3440 (unsigned char *) props, count);
3441 }
3442 UNBLOCK_INPUT;
3443}
3444#endif
86779fac
GM
3445
3446
5a7df7d7
GM
3447\f
3448/* Support routines for XIC (X Input Context). */
86779fac 3449
5a7df7d7
GM
3450#ifdef HAVE_X_I18N
3451
3452static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
3453static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
3454
3455
3456/* Supported XIM styles, ordered by preferenc. */
3457
3458static XIMStyle supported_xim_styles[] =
3459{
3460 XIMPreeditPosition | XIMStatusArea,
3461 XIMPreeditPosition | XIMStatusNothing,
3462 XIMPreeditPosition | XIMStatusNone,
3463 XIMPreeditNothing | XIMStatusArea,
3464 XIMPreeditNothing | XIMStatusNothing,
3465 XIMPreeditNothing | XIMStatusNone,
3466 XIMPreeditNone | XIMStatusArea,
3467 XIMPreeditNone | XIMStatusNothing,
3468 XIMPreeditNone | XIMStatusNone,
3469 0,
3470};
3471
3472
3473/* Create an X fontset on frame F with base font name
3474 BASE_FONTNAME.. */
3475
3476static XFontSet
3477xic_create_xfontset (f, base_fontname)
86779fac 3478 struct frame *f;
5a7df7d7 3479 char *base_fontname;
86779fac 3480{
5a7df7d7
GM
3481 XFontSet xfs;
3482 char **missing_list;
3483 int missing_count;
3484 char *def_string;
86779fac 3485
5a7df7d7
GM
3486 xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
3487 base_fontname, &missing_list,
3488 &missing_count, &def_string);
3489 if (missing_list)
3490 XFreeStringList (missing_list);
3491
3492 /* No need to free def_string. */
3493 return xfs;
3494}
3495
3496
3497/* Value is the best input style, given user preferences USER (already
3498 checked to be supported by Emacs), and styles supported by the
3499 input method XIM. */
3500
3501static XIMStyle
3502best_xim_style (user, xim)
3503 XIMStyles *user;
3504 XIMStyles *xim;
3505{
3506 int i, j;
3507
3508 for (i = 0; i < user->count_styles; ++i)
3509 for (j = 0; j < xim->count_styles; ++j)
3510 if (user->supported_styles[i] == xim->supported_styles[j])
3511 return user->supported_styles[i];
3512
3513 /* Return the default style. */
3514 return XIMPreeditNothing | XIMStatusNothing;
3515}
3516
3517/* Create XIC for frame F. */
3518
5df79d3d
GM
3519static XIMStyle xic_style;
3520
5a7df7d7
GM
3521void
3522create_frame_xic (f)
3523 struct frame *f;
3524{
5a7df7d7
GM
3525 XIM xim;
3526 XIC xic = NULL;
3527 XFontSet xfs = NULL;
86779fac 3528
5a7df7d7
GM
3529 if (FRAME_XIC (f))
3530 return;
3531
3532 xim = FRAME_X_XIM (f);
3533 if (xim)
3534 {
d9d57cb2
DL
3535 XRectangle s_area;
3536 XPoint spot;
5a7df7d7
GM
3537 XVaNestedList preedit_attr;
3538 XVaNestedList status_attr;
3539 char *base_fontname;
3540 int fontset;
3541
d9d57cb2
DL
3542 s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
3543 spot.x = 0; spot.y = 1;
5a7df7d7
GM
3544 /* Create X fontset. */
3545 fontset = FRAME_FONTSET (f);
3546 if (fontset < 0)
3547 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3548 else
3549 {
6ecb43ce
KH
3550 /* Determine the base fontname from the ASCII font name of
3551 FONTSET. */
3552 char *ascii_font = (char *) XSTRING (fontset_ascii (fontset))->data;
3553 char *p = ascii_font;
5a7df7d7 3554 int i;
6ecb43ce
KH
3555
3556 for (i = 0; *p; p++)
3557 if (*p == '-') i++;
3558 if (i != 14)
3559 /* As the font name doesn't conform to XLFD, we can't
3560 modify it to get a suitable base fontname for the
3561 frame. */
3562 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3563 else
3564 {
3565 int len = strlen (ascii_font) + 1;
8ec8a5ec 3566 char *p1 = NULL;
6ecb43ce
KH
3567
3568 for (i = 0, p = ascii_font; i < 8; p++)
3569 {
3570 if (*p == '-')
3571 {
3572 i++;
3573 if (i == 3)
3574 p1 = p + 1;
3575 }
3576 }
3577 base_fontname = (char *) alloca (len);
3578 bzero (base_fontname, len);
3579 strcpy (base_fontname, "-*-*-");
3580 bcopy (p1, base_fontname + 5, p - p1);
3581 strcat (base_fontname, "*-*-*-*-*-*-*");
3582 }
5a7df7d7
GM
3583 }
3584 xfs = xic_create_xfontset (f, base_fontname);
86779fac 3585
5a7df7d7
GM
3586 /* Determine XIC style. */
3587 if (xic_style == 0)
3588 {
3589 XIMStyles supported_list;
3590 supported_list.count_styles = (sizeof supported_xim_styles
3591 / sizeof supported_xim_styles[0]);
3592 supported_list.supported_styles = supported_xim_styles;
3593 xic_style = best_xim_style (&supported_list,
3594 FRAME_X_XIM_STYLES (f));
3595 }
86779fac 3596
5a7df7d7
GM
3597 preedit_attr = XVaCreateNestedList (0,
3598 XNFontSet, xfs,
3599 XNForeground,
3600 FRAME_FOREGROUND_PIXEL (f),
3601 XNBackground,
3602 FRAME_BACKGROUND_PIXEL (f),
3603 (xic_style & XIMPreeditPosition
3604 ? XNSpotLocation
3605 : NULL),
3606 &spot,
3607 NULL);
3608 status_attr = XVaCreateNestedList (0,
3609 XNArea,
3610 &s_area,
3611 XNFontSet,
3612 xfs,
3613 XNForeground,
3614 FRAME_FOREGROUND_PIXEL (f),
3615 XNBackground,
3616 FRAME_BACKGROUND_PIXEL (f),
3617 NULL);
3618
3619 xic = XCreateIC (xim,
3620 XNInputStyle, xic_style,
3621 XNClientWindow, FRAME_X_WINDOW(f),
3622 XNFocusWindow, FRAME_X_WINDOW(f),
3623 XNStatusAttributes, status_attr,
3624 XNPreeditAttributes, preedit_attr,
3625 NULL);
3626 XFree (preedit_attr);
3627 XFree (status_attr);
3628 }
3629
3630 FRAME_XIC (f) = xic;
3631 FRAME_XIC_STYLE (f) = xic_style;
3632 FRAME_XIC_FONTSET (f) = xfs;
86779fac
GM
3633}
3634
5a7df7d7
GM
3635
3636/* Destroy XIC and free XIC fontset of frame F, if any. */
3637
3638void
3639free_frame_xic (f)
3640 struct frame *f;
3641{
3642 if (FRAME_XIC (f) == NULL)
3643 return;
3644
3645 XDestroyIC (FRAME_XIC (f));
3646 if (FRAME_XIC_FONTSET (f))
3647 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3648
3649 FRAME_XIC (f) = NULL;
3650 FRAME_XIC_FONTSET (f) = NULL;
3651}
3652
3653
3654/* Place preedit area for XIC of window W's frame to specified
3655 pixel position X/Y. X and Y are relative to window W. */
3656
3657void
3658xic_set_preeditarea (w, x, y)
3659 struct window *w;
3660 int x, y;
3661{
3662 struct frame *f = XFRAME (w->frame);
3663 XVaNestedList attr;
3664 XPoint spot;
3665
3666 spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
3667 spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
3668 attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
3669 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3670 XFree (attr);
3671}
3672
3673
3674/* Place status area for XIC in bottom right corner of frame F.. */
3675
3676void
3677xic_set_statusarea (f)
3678 struct frame *f;
3679{
3680 XIC xic = FRAME_XIC (f);
3681 XVaNestedList attr;
3682 XRectangle area;
3683 XRectangle *needed;
3684
3685 /* Negotiate geometry of status area. If input method has existing
3686 status area, use its current size. */
3687 area.x = area.y = area.width = area.height = 0;
3688 attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
3689 XSetICValues (xic, XNStatusAttributes, attr, NULL);
3690 XFree (attr);
3691
3692 attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
3693 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3694 XFree (attr);
3695
3696 if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
3697 {
3698 attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
3699 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3700 XFree (attr);
3701 }
3702
3703 area.width = needed->width;
3704 area.height = needed->height;
3705 area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
3706 area.y = (PIXEL_HEIGHT (f) - area.height
3707 - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
3708 XFree (needed);
3709
3710 attr = XVaCreateNestedList (0, XNArea, &area, NULL);
3711 XSetICValues(xic, XNStatusAttributes, attr, NULL);
3712 XFree (attr);
3713}
3714
3715
3716/* Set X fontset for XIC of frame F, using base font name
3717 BASE_FONTNAME. Called when a new Emacs fontset is chosen. */
3718
3719void
3720xic_set_xfontset (f, base_fontname)
3721 struct frame *f;
3722 char *base_fontname;
3723{
3724 XVaNestedList attr;
3725 XFontSet xfs;
3726
3727 xfs = xic_create_xfontset (f, base_fontname);
3728
3729 attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
3730 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
3731 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3732 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
3733 XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
3734 XFree (attr);
3735
3736 if (FRAME_XIC_FONTSET (f))
3737 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3738 FRAME_XIC_FONTSET (f) = xfs;
3739}
3740
3741#endif /* HAVE_X_I18N */
3742
3743
9ef48a9d 3744\f
8fc2766b
RS
3745#ifdef USE_X_TOOLKIT
3746
3747/* Create and set up the X widget for frame F. */
f58534a3 3748
01f1ba30 3749static void
a7f7d550
FP
3750x_window (f, window_prompting, minibuffer_only)
3751 struct frame *f;
3752 long window_prompting;
3753 int minibuffer_only;
01f1ba30 3754{
9ef48a9d 3755 XClassHint class_hints;
31ac8d8c
FP
3756 XSetWindowAttributes attributes;
3757 unsigned long attribute_mask;
9ef48a9d
RS
3758 Widget shell_widget;
3759 Widget pane_widget;
6c32dd68 3760 Widget frame_widget;
9ef48a9d
RS
3761 Arg al [25];
3762 int ac;
3763
3764 BLOCK_INPUT;
3765
b7975ee4
KH
3766 /* Use the resource name as the top-level widget name
3767 for looking up resources. Make a non-Lisp copy
3768 for the window manager, so GC relocation won't bother it.
3769
3770 Elsewhere we specify the window name for the window manager. */
3771
cca176a0 3772 {
b7975ee4
KH
3773 char *str = (char *) XSTRING (Vx_resource_name)->data;
3774 f->namebuf = (char *) xmalloc (strlen (str) + 1);
cca176a0
KH
3775 strcpy (f->namebuf, str);
3776 }
9ef48a9d
RS
3777
3778 ac = 0;
3779 XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
3780 XtSetArg (al[ac], XtNinput, 1); ac++;
97787173 3781 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
7556890b 3782 XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
9b2956e2
GM
3783 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3784 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3785 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
cca176a0 3786 shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
7a994728 3787 applicationShellWidgetClass,
82c90203 3788 FRAME_X_DISPLAY (f), al, ac);
9ef48a9d 3789
7556890b 3790 f->output_data.x->widget = shell_widget;
9ef48a9d
RS
3791 /* maybe_set_screen_title_format (shell_widget); */
3792
6c32dd68
PR
3793 pane_widget = lw_create_widget ("main", "pane", widget_id_tick++,
3794 (widget_value *) NULL,
3795 shell_widget, False,
3796 (lw_callback) NULL,
3797 (lw_callback) NULL,
b6e11efd 3798 (lw_callback) NULL,
6c32dd68 3799 (lw_callback) NULL);
9ef48a9d 3800
9b2956e2
GM
3801 ac = 0;
3802 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3803 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3804 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3805 XtSetValues (pane_widget, al, ac);
7556890b 3806 f->output_data.x->column_widget = pane_widget;
a7f7d550 3807
9ef48a9d 3808 /* mappedWhenManaged to false tells to the paned window to not map/unmap
5e65b9ab 3809 the emacs screen when changing menubar. This reduces flickering. */
9ef48a9d
RS
3810
3811 ac = 0;
3812 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
3813 XtSetArg (al[ac], XtNshowGrip, 0); ac++;
3814 XtSetArg (al[ac], XtNallowResize, 1); ac++;
3815 XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
3816 XtSetArg (al[ac], XtNemacsFrame, f); ac++;
9b2956e2
GM
3817 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3818 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3819 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3820 frame_widget = XtCreateWidget (f->namebuf, emacsFrameClass, pane_widget,
3821 al, ac);
9ef48a9d 3822
7556890b 3823 f->output_data.x->edit_widget = frame_widget;
9ef48a9d 3824
6c32dd68 3825 XtManageChild (frame_widget);
a7f7d550
FP
3826
3827 /* Do some needed geometry management. */
3828 {
3829 int len;
3830 char *tem, shell_position[32];
3831 Arg al[2];
3832 int ac = 0;
5031cc10 3833 int extra_borders = 0;
8fc2766b 3834 int menubar_size
7556890b
RS
3835 = (f->output_data.x->menubar_widget
3836 ? (f->output_data.x->menubar_widget->core.height
3837 + f->output_data.x->menubar_widget->core.border_width)
8fc2766b 3838 : 0);
a7f7d550 3839
f7008aff
RS
3840#if 0 /* Experimentally, we now get the right results
3841 for -geometry -0-0 without this. 24 Aug 96, rms. */
01cbdba5
RS
3842 if (FRAME_EXTERNAL_MENU_BAR (f))
3843 {
dd254b21 3844 Dimension ibw = 0;
01cbdba5
RS
3845 XtVaGetValues (pane_widget, XtNinternalBorderWidth, &ibw, NULL);
3846 menubar_size += ibw;
3847 }
f7008aff 3848#endif
01cbdba5 3849
7556890b 3850 f->output_data.x->menubar_height = menubar_size;
00983aba 3851
440b0bfd 3852#ifndef USE_LUCID
5031cc10
KH
3853 /* Motif seems to need this amount added to the sizes
3854 specified for the shell widget. The Athena/Lucid widgets don't.
3855 Both conclusions reached experimentally. -- rms. */
440b0bfd
RS
3856 XtVaGetValues (f->output_data.x->edit_widget, XtNinternalBorderWidth,
3857 &extra_borders, NULL);
3858 extra_borders *= 2;
3859#endif
5031cc10 3860
97787173
RS
3861 /* Convert our geometry parameters into a geometry string
3862 and specify it.
3863 Note that we do not specify here whether the position
3864 is a user-specified or program-specified one.
3865 We pass that information later, in x_wm_set_size_hints. */
3866 {
7556890b 3867 int left = f->output_data.x->left_pos;
97787173 3868 int xneg = window_prompting & XNegative;
7556890b 3869 int top = f->output_data.x->top_pos;
97787173
RS
3870 int yneg = window_prompting & YNegative;
3871 if (xneg)
3872 left = -left;
3873 if (yneg)
3874 top = -top;
c760f47e
KH
3875
3876 if (window_prompting & USPosition)
5031cc10
KH
3877 sprintf (shell_position, "=%dx%d%c%d%c%d",
3878 PIXEL_WIDTH (f) + extra_borders,
3879 PIXEL_HEIGHT (f) + menubar_size + extra_borders,
c760f47e
KH
3880 (xneg ? '-' : '+'), left,
3881 (yneg ? '-' : '+'), top);
3882 else
5031cc10
KH
3883 sprintf (shell_position, "=%dx%d",
3884 PIXEL_WIDTH (f) + extra_borders,
3885 PIXEL_HEIGHT (f) + menubar_size + extra_borders);
97787173
RS
3886 }
3887
a7f7d550 3888 len = strlen (shell_position) + 1;
77110caa
RS
3889 /* We don't free this because we don't know whether
3890 it is safe to free it while the frame exists.
3891 It isn't worth the trouble of arranging to free it
3892 when the frame is deleted. */
a7f7d550
FP
3893 tem = (char *) xmalloc (len);
3894 strncpy (tem, shell_position, len);
3895 XtSetArg (al[ac], XtNgeometry, tem); ac++;
3896 XtSetValues (shell_widget, al, ac);
3897 }
3898
9ef48a9d
RS
3899 XtManageChild (pane_widget);
3900 XtRealizeWidget (shell_widget);
3901
6c32dd68 3902 FRAME_X_WINDOW (f) = XtWindow (frame_widget);
9ef48a9d
RS
3903
3904 validate_x_resource_name ();
b7975ee4 3905
9ef48a9d 3906 class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
498e9ac3 3907 class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
b9dc4443 3908 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
5a7df7d7
GM
3909
3910#ifdef HAVE_X_I18N
3911 FRAME_XIC (f) = NULL;
4bd777b8 3912#ifdef USE_XIM
5a7df7d7 3913 create_frame_xic (f);
4bd777b8 3914#endif
5a7df7d7 3915#endif
64d16748 3916
7556890b
RS
3917 f->output_data.x->wm_hints.input = True;
3918 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 3919 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3920 &f->output_data.x->wm_hints);
b8228beb 3921
c4ec904f 3922 hack_wm_protocols (f, shell_widget);
9ef48a9d 3923
6c32dd68
PR
3924#ifdef HACK_EDITRES
3925 XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0);
3926#endif
3927
9ef48a9d 3928 /* Do a stupid property change to force the server to generate a
333b20bb 3929 PropertyNotify event so that the event_stream server timestamp will
9ef48a9d
RS
3930 be initialized to something relevant to the time we created the window.
3931 */
6c32dd68 3932 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
b9dc4443
RS
3933 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3934 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3935 (unsigned char*) NULL, 0);
3936
5a7df7d7 3937 /* Make all the standard events reach the Emacs frame. */
31ac8d8c 3938 attributes.event_mask = STANDARD_EVENT_SET;
5a7df7d7
GM
3939
3940#ifdef HAVE_X_I18N
3941 if (FRAME_XIC (f))
3942 {
3943 /* XIM server might require some X events. */
3944 unsigned long fevent = NoEventMask;
3945 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
3946 attributes.event_mask |= fevent;
3947 }
3948#endif /* HAVE_X_I18N */
3949
31ac8d8c
FP
3950 attribute_mask = CWEventMask;
3951 XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
3952 attribute_mask, &attributes);
3953
6c32dd68 3954 XtMapWidget (frame_widget);
9ef48a9d 3955
8fc2766b
RS
3956 /* x_set_name normally ignores requests to set the name if the
3957 requested name is the same as the current name. This is the one
3958 place where that assumption isn't correct; f->name is set, but
3959 the X server hasn't been told. */
3960 {
3961 Lisp_Object name;
3962 int explicit = f->explicit_name;
3963
3964 f->explicit_name = 0;
3965 name = f->name;
3966 f->name = Qnil;
3967 x_set_name (f, name, explicit);
3968 }
3969
b9dc4443 3970 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3971 f->output_data.x->text_cursor);
8fc2766b
RS
3972
3973 UNBLOCK_INPUT;
3974
495fa05e
GM
3975 /* This is a no-op, except under Motif. Make sure main areas are
3976 set to something reasonable, in case we get an error later. */
3977 lw_set_main_areas (pane_widget, 0, frame_widget);
8fc2766b
RS
3978}
3979
9ef48a9d
RS
3980#else /* not USE_X_TOOLKIT */
3981
8fc2766b
RS
3982/* Create and set up the X window for frame F. */
3983
201d8c78 3984void
8fc2766b
RS
3985x_window (f)
3986 struct frame *f;
3987
3988{
3989 XClassHint class_hints;
3990 XSetWindowAttributes attributes;
3991 unsigned long attribute_mask;
3992
7556890b
RS
3993 attributes.background_pixel = f->output_data.x->background_pixel;
3994 attributes.border_pixel = f->output_data.x->border_pixel;
01f1ba30
JB
3995 attributes.bit_gravity = StaticGravity;
3996 attributes.backing_store = NotUseful;
3997 attributes.save_under = True;
3998 attributes.event_mask = STANDARD_EVENT_SET;
9b2956e2
GM
3999 attributes.colormap = FRAME_X_COLORMAP (f);
4000 attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
4001 | CWColormap);
01f1ba30
JB
4002
4003 BLOCK_INPUT;
fe24a618 4004 FRAME_X_WINDOW (f)
b9dc4443 4005 = XCreateWindow (FRAME_X_DISPLAY (f),
7556890b
RS
4006 f->output_data.x->parent_desc,
4007 f->output_data.x->left_pos,
4008 f->output_data.x->top_pos,
f676886a 4009 PIXEL_WIDTH (f), PIXEL_HEIGHT (f),
7556890b 4010 f->output_data.x->border_width,
01f1ba30
JB
4011 CopyFromParent, /* depth */
4012 InputOutput, /* class */
383d6ffc 4013 FRAME_X_VISUAL (f),
01f1ba30 4014 attribute_mask, &attributes);
5a7df7d7
GM
4015
4016#ifdef HAVE_X_I18N
4bd777b8 4017#ifdef USE_XIM
5a7df7d7
GM
4018 create_frame_xic (f);
4019 if (FRAME_XIC (f))
4020 {
4021 /* XIM server might require some X events. */
4022 unsigned long fevent = NoEventMask;
4023 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
4024 attributes.event_mask |= fevent;
4025 attribute_mask = CWEventMask;
4026 XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4027 attribute_mask, &attributes);
4028 }
4bd777b8 4029#endif
5a7df7d7
GM
4030#endif /* HAVE_X_I18N */
4031
d387c960 4032 validate_x_resource_name ();
b7975ee4 4033
d387c960 4034 class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
498e9ac3 4035 class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
b9dc4443 4036 XSetClassHint (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &class_hints);
01f1ba30 4037
00983aba
KH
4038 /* The menubar is part of the ordinary display;
4039 it does not count in addition to the height of the window. */
7556890b 4040 f->output_data.x->menubar_height = 0;
00983aba 4041
179956b9
JB
4042 /* This indicates that we use the "Passive Input" input model.
4043 Unless we do this, we don't get the Focus{In,Out} events that we
4044 need to draw the cursor correctly. Accursed bureaucrats.
b9dc4443 4045 XWhipsAndChains (FRAME_X_DISPLAY (f), IronMaiden, &TheRack); */
179956b9 4046
7556890b
RS
4047 f->output_data.x->wm_hints.input = True;
4048 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 4049 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4050 &f->output_data.x->wm_hints);
6d078211 4051 f->output_data.x->wm_hints.icon_pixmap = None;
179956b9 4052
032e4ebe
RS
4053 /* Request "save yourself" and "delete window" commands from wm. */
4054 {
4055 Atom protocols[2];
b9dc4443
RS
4056 protocols[0] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
4057 protocols[1] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
4058 XSetWMProtocols (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), protocols, 2);
032e4ebe 4059 }
9ef48a9d 4060
e373f201
JB
4061 /* x_set_name normally ignores requests to set the name if the
4062 requested name is the same as the current name. This is the one
4063 place where that assumption isn't correct; f->name is set, but
4064 the X server hasn't been told. */
4065 {
98381190 4066 Lisp_Object name;
cf177271 4067 int explicit = f->explicit_name;
e373f201 4068
cf177271 4069 f->explicit_name = 0;
98381190
KH
4070 name = f->name;
4071 f->name = Qnil;
cf177271 4072 x_set_name (f, name, explicit);
e373f201
JB
4073 }
4074
b9dc4443 4075 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4076 f->output_data.x->text_cursor);
9ef48a9d 4077
01f1ba30
JB
4078 UNBLOCK_INPUT;
4079
fe24a618 4080 if (FRAME_X_WINDOW (f) == 0)
9ef48a9d 4081 error ("Unable to create window");
01f1ba30
JB
4082}
4083
8fc2766b
RS
4084#endif /* not USE_X_TOOLKIT */
4085
01f1ba30
JB
4086/* Handle the icon stuff for this window. Perhaps later we might
4087 want an x_set_icon_position which can be called interactively as
b9dc4443 4088 well. */
01f1ba30
JB
4089
4090static void
f676886a
JB
4091x_icon (f, parms)
4092 struct frame *f;
01f1ba30
JB
4093 Lisp_Object parms;
4094{
f9942c9e 4095 Lisp_Object icon_x, icon_y;
abb4b7ec 4096 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
4097
4098 /* Set the position of the icon. Note that twm groups all
b9dc4443 4099 icons in an icon window. */
333b20bb
GM
4100 icon_x = x_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4101 icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
f9942c9e 4102 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
01f1ba30 4103 {
b7826503
PJ
4104 CHECK_NUMBER (icon_x);
4105 CHECK_NUMBER (icon_y);
01f1ba30 4106 }
f9942c9e 4107 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
01f1ba30 4108 error ("Both left and top icon corners of icon must be specified");
01f1ba30 4109
f9942c9e
JB
4110 BLOCK_INPUT;
4111
fe24a618
JB
4112 if (! EQ (icon_x, Qunbound))
4113 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
f9942c9e 4114
01f1ba30 4115 /* Start up iconic or window? */
49795535 4116 x_wm_set_window_state
333b20bb
GM
4117 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL),
4118 Qicon)
49795535
JB
4119 ? IconicState
4120 : NormalState));
01f1ba30 4121
f468da95
RS
4122 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4123 ? f->icon_name
4124 : f->name))->data);
80534dd6 4125
01f1ba30
JB
4126 UNBLOCK_INPUT;
4127}
4128
b243755a 4129/* Make the GCs needed for this window, setting the
01f1ba30
JB
4130 background, border and mouse colors; also create the
4131 mouse cursor and the gray border tile. */
4132
f945b920
JB
4133static char cursor_bits[] =
4134 {
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4139 };
4140
01f1ba30 4141static void
f676886a
JB
4142x_make_gc (f)
4143 struct frame *f;
01f1ba30
JB
4144{
4145 XGCValues gc_values;
01f1ba30 4146
6afb1d07
JB
4147 BLOCK_INPUT;
4148
b243755a 4149 /* Create the GCs of this frame.
9ef48a9d 4150 Note that many default values are used. */
01f1ba30
JB
4151
4152 /* Normal video */
7556890b
RS
4153 gc_values.font = f->output_data.x->font->fid;
4154 gc_values.foreground = f->output_data.x->foreground_pixel;
4155 gc_values.background = f->output_data.x->background_pixel;
9ef48a9d 4156 gc_values.line_width = 0; /* Means 1 using fast algorithm. */
959e647d
GM
4157 f->output_data.x->normal_gc
4158 = XCreateGC (FRAME_X_DISPLAY (f),
4159 FRAME_X_WINDOW (f),
4160 GCLineWidth | GCFont | GCForeground | GCBackground,
4161 &gc_values);
01f1ba30 4162
b9dc4443 4163 /* Reverse video style. */
7556890b
RS
4164 gc_values.foreground = f->output_data.x->background_pixel;
4165 gc_values.background = f->output_data.x->foreground_pixel;
959e647d
GM
4166 f->output_data.x->reverse_gc
4167 = XCreateGC (FRAME_X_DISPLAY (f),
4168 FRAME_X_WINDOW (f),
4169 GCFont | GCForeground | GCBackground | GCLineWidth,
4170 &gc_values);
01f1ba30 4171
9ef48a9d 4172 /* Cursor has cursor-color background, background-color foreground. */
7556890b
RS
4173 gc_values.foreground = f->output_data.x->background_pixel;
4174 gc_values.background = f->output_data.x->cursor_pixel;
01f1ba30
JB
4175 gc_values.fill_style = FillOpaqueStippled;
4176 gc_values.stipple
b9dc4443
RS
4177 = XCreateBitmapFromData (FRAME_X_DISPLAY (f),
4178 FRAME_X_DISPLAY_INFO (f)->root_window,
01f1ba30 4179 cursor_bits, 16, 16);
7556890b 4180 f->output_data.x->cursor_gc
b9dc4443 4181 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
01f1ba30 4182 (GCFont | GCForeground | GCBackground
ac1f48a4 4183 | GCFillStyle /* | GCStipple */ | GCLineWidth),
01f1ba30
JB
4184 &gc_values);
4185
333b20bb
GM
4186 /* Reliefs. */
4187 f->output_data.x->white_relief.gc = 0;
4188 f->output_data.x->black_relief.gc = 0;
4189
01f1ba30 4190 /* Create the gray border tile used when the pointer is not in
f676886a 4191 the frame. Since this depends on the frame's pixel values,
9ef48a9d 4192 this must be done on a per-frame basis. */
7556890b 4193 f->output_data.x->border_tile
d043f1a4 4194 = (XCreatePixmapFromBitmapData
b9dc4443 4195 (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
d043f1a4 4196 gray_bits, gray_width, gray_height,
7556890b
RS
4197 f->output_data.x->foreground_pixel,
4198 f->output_data.x->background_pixel,
ab452f99 4199 DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f))));
6afb1d07
JB
4200
4201 UNBLOCK_INPUT;
01f1ba30 4202}
01f1ba30 4203
959e647d
GM
4204
4205/* Free what was was allocated in x_make_gc. */
4206
4207void
4208x_free_gcs (f)
4209 struct frame *f;
4210{
4211 Display *dpy = FRAME_X_DISPLAY (f);
4212
4213 BLOCK_INPUT;
4214
4215 if (f->output_data.x->normal_gc)
4216 {
4217 XFreeGC (dpy, f->output_data.x->normal_gc);
4218 f->output_data.x->normal_gc = 0;
4219 }
4220
4221 if (f->output_data.x->reverse_gc)
4222 {
4223 XFreeGC (dpy, f->output_data.x->reverse_gc);
4224 f->output_data.x->reverse_gc = 0;
4225 }
4226
4227 if (f->output_data.x->cursor_gc)
4228 {
4229 XFreeGC (dpy, f->output_data.x->cursor_gc);
4230 f->output_data.x->cursor_gc = 0;
4231 }
4232
4233 if (f->output_data.x->border_tile)
4234 {
4235 XFreePixmap (dpy, f->output_data.x->border_tile);
4236 f->output_data.x->border_tile = 0;
4237 }
4238
4239 UNBLOCK_INPUT;
4240}
4241
4242
eaf1eea9
GM
4243/* Handler for signals raised during x_create_frame and
4244 x_create_top_frame. FRAME is the frame which is partially
4245 constructed. */
4246
4247static Lisp_Object
4248unwind_create_frame (frame)
4249 Lisp_Object frame;
4250{
4251 struct frame *f = XFRAME (frame);
4252
4253 /* If frame is ``official'', nothing to do. */
4254 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4255 {
f1d2ce7f 4256#if GLYPH_DEBUG
eaf1eea9
GM
4257 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4258#endif
4259
4260 x_free_frame_resources (f);
4261
4262 /* Check that reference counts are indeed correct. */
4263 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4264 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a 4265 return Qt;
eaf1eea9
GM
4266 }
4267
4268 return Qnil;
4269}
4270
4271
f676886a 4272DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
01f1ba30 4273 1, 1, 0,
7ee72033 4274 doc: /* Make a new X window, which is called a "frame" in Emacs terms.
c061c855
GM
4275Returns an Emacs frame object.
4276ALIST is an alist of frame parameters.
4277If the parameters specify that the frame should not have a minibuffer,
4278and do not specify a specific minibuffer window to use,
4279then `default-minibuffer-frame' must be a frame whose minibuffer can
4280be shared by the new frame.
4281
7ee72033
MB
4282This function is an internal primitive--use `make-frame' instead. */)
4283 (parms)
01f1ba30
JB
4284 Lisp_Object parms;
4285{
f676886a 4286 struct frame *f;
2365c027 4287 Lisp_Object frame, tem;
01f1ba30
JB
4288 Lisp_Object name;
4289 int minibuffer_only = 0;
4290 long window_prompting = 0;
4291 int width, height;
eaf1eea9 4292 int count = BINDING_STACK_SIZE ();
ecaca587 4293 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
b9dc4443 4294 Lisp_Object display;
333b20bb 4295 struct x_display_info *dpyinfo = NULL;
a59e4f3d 4296 Lisp_Object parent;
e557f19d 4297 struct kboard *kb;
01f1ba30 4298
11ae94fe 4299 check_x ();
01f1ba30 4300
b7975ee4
KH
4301 /* Use this general default value to start with
4302 until we know if this frame has a specified name. */
4303 Vx_resource_name = Vinvocation_name;
4304
333b20bb 4305 display = x_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING);
b9dc4443
RS
4306 if (EQ (display, Qunbound))
4307 display = Qnil;
4308 dpyinfo = check_x_display_info (display);
e557f19d
KH
4309#ifdef MULTI_KBOARD
4310 kb = dpyinfo->kboard;
4311#else
4312 kb = &the_only_kboard;
4313#endif
b9dc4443 4314
333b20bb 4315 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
6a5e54e2 4316 if (!STRINGP (name)
cf177271
JB
4317 && ! EQ (name, Qunbound)
4318 && ! NILP (name))
08a90d6a 4319 error ("Invalid frame name--not a string or nil");
01f1ba30 4320
b7975ee4
KH
4321 if (STRINGP (name))
4322 Vx_resource_name = name;
4323
a59e4f3d 4324 /* See if parent window is specified. */
333b20bb 4325 parent = x_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
a59e4f3d
RS
4326 if (EQ (parent, Qunbound))
4327 parent = Qnil;
4328 if (! NILP (parent))
b7826503 4329 CHECK_NUMBER (parent);
a59e4f3d 4330
ecaca587
RS
4331 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4332 /* No need to protect DISPLAY because that's not used after passing
4333 it to make_frame_without_minibuffer. */
4334 frame = Qnil;
4335 GCPRO4 (parms, parent, name, frame);
333b20bb
GM
4336 tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
4337 RES_TYPE_SYMBOL);
f9942c9e 4338 if (EQ (tem, Qnone) || NILP (tem))
2526c290 4339 f = make_frame_without_minibuffer (Qnil, kb, display);
f9942c9e 4340 else if (EQ (tem, Qonly))
01f1ba30 4341 {
f676886a 4342 f = make_minibuffer_frame ();
01f1ba30
JB
4343 minibuffer_only = 1;
4344 }
6a5e54e2 4345 else if (WINDOWP (tem))
2526c290 4346 f = make_frame_without_minibuffer (tem, kb, display);
f9942c9e
JB
4347 else
4348 f = make_frame (1);
01f1ba30 4349
ecaca587
RS
4350 XSETFRAME (frame, f);
4351
a3c87d4e
JB
4352 /* Note that X Windows does support scroll bars. */
4353 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
179956b9 4354
08a90d6a 4355 f->output_method = output_x_window;
7556890b
RS
4356 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
4357 bzero (f->output_data.x, sizeof (struct x_output));
4358 f->output_data.x->icon_bitmap = -1;
0ecca023 4359 f->output_data.x->fontset = -1;
333b20bb
GM
4360 f->output_data.x->scroll_bar_foreground_pixel = -1;
4361 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
4362#ifdef USE_TOOLKIT_SCROLL_BARS
4363 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
4364 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
4365#endif /* USE_TOOLKIT_SCROLL_BARS */
eaf1eea9 4366 record_unwind_protect (unwind_create_frame, frame);
08a90d6a 4367
f468da95 4368 f->icon_name
333b20bb
GM
4369 = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
4370 RES_TYPE_STRING);
f468da95
RS
4371 if (! STRINGP (f->icon_name))
4372 f->icon_name = Qnil;
80534dd6 4373
08a90d6a 4374 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 4375#if GLYPH_DEBUG
eaf1eea9
GM
4376 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
4377 dpyinfo_refcount = dpyinfo->reference_count;
4378#endif /* GLYPH_DEBUG */
73410c76 4379#ifdef MULTI_KBOARD
e557f19d 4380 FRAME_KBOARD (f) = kb;
73410c76 4381#endif
08a90d6a 4382
9b2956e2
GM
4383 /* These colors will be set anyway later, but it's important
4384 to get the color reference counts right, so initialize them! */
4385 {
4386 Lisp_Object black;
4387 struct gcpro gcpro1;
cefecbcf
GM
4388
4389 /* Function x_decode_color can signal an error. Make
4390 sure to initialize color slots so that we won't try
4391 to free colors we haven't allocated. */
4392 f->output_data.x->foreground_pixel = -1;
4393 f->output_data.x->background_pixel = -1;
4394 f->output_data.x->cursor_pixel = -1;
4395 f->output_data.x->cursor_foreground_pixel = -1;
4396 f->output_data.x->border_pixel = -1;
4397 f->output_data.x->mouse_pixel = -1;
9b2956e2
GM
4398
4399 black = build_string ("black");
4400 GCPRO1 (black);
4401 f->output_data.x->foreground_pixel
4402 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4403 f->output_data.x->background_pixel
4404 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4405 f->output_data.x->cursor_pixel
4406 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4407 f->output_data.x->cursor_foreground_pixel
4408 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4409 f->output_data.x->border_pixel
4410 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4411 f->output_data.x->mouse_pixel
4412 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4413 UNGCPRO;
4414 }
4415
a59e4f3d
RS
4416 /* Specify the parent under which to make this X window. */
4417
4418 if (!NILP (parent))
4419 {
8c239ac3 4420 f->output_data.x->parent_desc = (Window) XFASTINT (parent);
7556890b 4421 f->output_data.x->explicit_parent = 1;
a59e4f3d
RS
4422 }
4423 else
4424 {
7556890b
RS
4425 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
4426 f->output_data.x->explicit_parent = 0;
a59e4f3d
RS
4427 }
4428
cf177271
JB
4429 /* Set the name; the functions to which we pass f expect the name to
4430 be set. */
4431 if (EQ (name, Qunbound) || NILP (name))
4432 {
08a90d6a 4433 f->name = build_string (dpyinfo->x_id_name);
cf177271
JB
4434 f->explicit_name = 0;
4435 }
4436 else
4437 {
4438 f->name = name;
4439 f->explicit_name = 1;
9ef48a9d
RS
4440 /* use the frame's title when getting resources for this frame. */
4441 specbind (Qx_resource_name, name);
cf177271 4442 }
01f1ba30 4443
01f1ba30
JB
4444 /* Extract the window parameters from the supplied values
4445 that are needed to determine window geometry. */
d387c960
JB
4446 {
4447 Lisp_Object font;
4448
333b20bb 4449 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
2ee3abaa 4450
6817eab4 4451 BLOCK_INPUT;
e5e548e3
RS
4452 /* First, try whatever font the caller has specified. */
4453 if (STRINGP (font))
942ea06d 4454 {
49965a29 4455 tem = Fquery_fontset (font, Qnil);
477f8642
KH
4456 if (STRINGP (tem))
4457 font = x_new_fontset (f, XSTRING (tem)->data);
942ea06d
KH
4458 else
4459 font = x_new_font (f, XSTRING (font)->data);
4460 }
333b20bb 4461
e5e548e3 4462 /* Try out a font which we hope has bold and italic variations. */
333b20bb
GM
4463 if (!STRINGP (font))
4464 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
e5e548e3 4465 if (!STRINGP (font))
a6ac02af 4466 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3 4467 if (! STRINGP (font))
a6ac02af 4468 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3
RS
4469 if (! STRINGP (font))
4470 /* This was formerly the first thing tried, but it finds too many fonts
4471 and takes too long. */
4472 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
4473 /* If those didn't work, look for something which will at least work. */
4474 if (! STRINGP (font))
a6ac02af 4475 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
6817eab4
JB
4476 UNBLOCK_INPUT;
4477 if (! STRINGP (font))
e5e548e3
RS
4478 font = build_string ("fixed");
4479
477f8642 4480 x_default_parameter (f, parms, Qfont, font,
333b20bb 4481 "font", "Font", RES_TYPE_STRING);
d387c960 4482 }
9ef48a9d 4483
e3881aa0 4484#ifdef USE_LUCID
82c90203
RS
4485 /* Prevent lwlib/xlwmenu.c from crashing because of a bug
4486 whereby it fails to get any font. */
7556890b 4487 xlwmenu_default_font = f->output_data.x->font;
dd254b21 4488#endif
82c90203 4489
cf177271 4490 x_default_parameter (f, parms, Qborder_width, make_number (2),
333b20bb
GM
4491 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
4492
4e397688 4493 /* This defaults to 1 in order to match xterm. We recognize either
ddf768c3
JB
4494 internalBorderWidth or internalBorder (which is what xterm calls
4495 it). */
4496 if (NILP (Fassq (Qinternal_border_width, parms)))
4497 {
4498 Lisp_Object value;
4499
abb4b7ec 4500 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
333b20bb 4501 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
ddf768c3
JB
4502 if (! EQ (value, Qunbound))
4503 parms = Fcons (Fcons (Qinternal_border_width, value),
4504 parms);
4505 }
dca97592 4506 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
333b20bb
GM
4507 "internalBorderWidth", "internalBorderWidth",
4508 RES_TYPE_NUMBER);
1ab3d87e 4509 x_default_parameter (f, parms, Qvertical_scroll_bars, Qleft,
333b20bb
GM
4510 "verticalScrollBars", "ScrollBars",
4511 RES_TYPE_SYMBOL);
01f1ba30 4512
b9dc4443 4513 /* Also do the stuff which must be set before the window exists. */
cf177271 4514 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
333b20bb 4515 "foreground", "Foreground", RES_TYPE_STRING);
cf177271 4516 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
0b60fc91 4517 "background", "Background", RES_TYPE_STRING);
cf177271 4518 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
333b20bb 4519 "pointerColor", "Foreground", RES_TYPE_STRING);
cf177271 4520 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
333b20bb 4521 "cursorColor", "Foreground", RES_TYPE_STRING);
cf177271 4522 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
333b20bb 4523 "borderColor", "BorderColor", RES_TYPE_STRING);
d62c8769
GM
4524 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
4525 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
563b67aa
GM
4526 x_default_parameter (f, parms, Qline_spacing, Qnil,
4527 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
b3ba0aa8
KS
4528 x_default_parameter (f, parms, Qleft_fringe, Qnil,
4529 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4530 x_default_parameter (f, parms, Qright_fringe, Qnil,
4531 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
333b20bb
GM
4532
4533 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
4534 "scrollBarForeground",
4535 "ScrollBarForeground", 1);
4536 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
4537 "scrollBarBackground",
4538 "ScrollBarBackground", 0);
4539
4540 /* Init faces before x_default_parameter is called for scroll-bar
4541 parameters because that function calls x_set_scroll_bar_width,
4542 which calls change_frame_size, which calls Fset_window_buffer,
4543 which runs hooks, which call Fvertical_motion. At the end, we
4544 end up in init_iterator with a null face cache, which should not
4545 happen. */
4546 init_frame_faces (f);
4547
c7bcb20d 4548 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
333b20bb 4549 "menuBar", "MenuBar", RES_TYPE_NUMBER);
e33455ca 4550 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
333b20bb 4551 "toolBar", "ToolBar", RES_TYPE_NUMBER);
79873d50 4552 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
333b20bb
GM
4553 "bufferPredicate", "BufferPredicate",
4554 RES_TYPE_SYMBOL);
c2304e02 4555 x_default_parameter (f, parms, Qtitle, Qnil,
333b20bb 4556 "title", "Title", RES_TYPE_STRING);
ea0a1f53
GM
4557 x_default_parameter (f, parms, Qwait_for_wm, Qt,
4558 "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
49d41073
EZ
4559 x_default_parameter (f, parms, Qfullscreen, Qnil,
4560 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
90eb1019 4561
7556890b 4562 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
35f59f6b
GM
4563
4564 /* Add the tool-bar height to the initial frame height so that the
4565 user gets a text display area of the size he specified with -g or
4566 via .Xdefaults. Later changes of the tool-bar height don't
4567 change the frame size. This is done so that users can create
4568 tall Emacs frames without having to guess how tall the tool-bar
4569 will get. */
4570 if (FRAME_TOOL_BAR_LINES (f))
4571 {
4572 int margin, relief, bar_height;
4573
8ed86491 4574 relief = (tool_bar_button_relief >= 0
35f59f6b
GM
4575 ? tool_bar_button_relief
4576 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
4577
4578 if (INTEGERP (Vtool_bar_button_margin)
4579 && XINT (Vtool_bar_button_margin) > 0)
4580 margin = XFASTINT (Vtool_bar_button_margin);
4581 else if (CONSP (Vtool_bar_button_margin)
4582 && INTEGERP (XCDR (Vtool_bar_button_margin))
4583 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
4584 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
4585 else
4586 margin = 0;
4587
4588 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
4589 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
4590 }
4591
4592 /* Compute the size of the X window. */
f676886a 4593 window_prompting = x_figure_window_size (f, parms);
01f1ba30 4594
f83f10ba 4595 if (window_prompting & XNegative)
2365c027 4596 {
f83f10ba 4597 if (window_prompting & YNegative)
7556890b 4598 f->output_data.x->win_gravity = SouthEastGravity;
f83f10ba 4599 else
7556890b 4600 f->output_data.x->win_gravity = NorthEastGravity;
f83f10ba
RS
4601 }
4602 else
4603 {
4604 if (window_prompting & YNegative)
7556890b 4605 f->output_data.x->win_gravity = SouthWestGravity;
f83f10ba 4606 else
7556890b 4607 f->output_data.x->win_gravity = NorthWestGravity;
2365c027
RS
4608 }
4609
7556890b 4610 f->output_data.x->size_hint_flags = window_prompting;
38d22040 4611
495fa05e
GM
4612 tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4613 f->no_split = minibuffer_only || EQ (tem, Qt);
4614
6a1bcd01 4615 /* Create the X widget or window. */
a7f7d550
FP
4616#ifdef USE_X_TOOLKIT
4617 x_window (f, window_prompting, minibuffer_only);
4618#else
f676886a 4619 x_window (f);
a7f7d550 4620#endif
495fa05e 4621
f676886a
JB
4622 x_icon (f, parms);
4623 x_make_gc (f);
01f1ba30 4624
495fa05e
GM
4625 /* Now consider the frame official. */
4626 FRAME_X_DISPLAY_INFO (f)->reference_count++;
4627 Vframe_list = Fcons (frame, Vframe_list);
4628
f9942c9e
JB
4629 /* We need to do this after creating the X window, so that the
4630 icon-creation functions can say whose icon they're describing. */
cf177271 4631 x_default_parameter (f, parms, Qicon_type, Qnil,
333b20bb 4632 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
f9942c9e 4633
cf177271 4634 x_default_parameter (f, parms, Qauto_raise, Qnil,
333b20bb 4635 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
cf177271 4636 x_default_parameter (f, parms, Qauto_lower, Qnil,
333b20bb 4637 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
dbc4e1c1 4638 x_default_parameter (f, parms, Qcursor_type, Qbox,
333b20bb 4639 "cursorType", "CursorType", RES_TYPE_SYMBOL);
28d7281d
GM
4640 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4641 "scrollBarWidth", "ScrollBarWidth",
4642 RES_TYPE_NUMBER);
f9942c9e 4643
f676886a 4644 /* Dimensions, especially f->height, must be done via change_frame_size.
01f1ba30 4645 Change will not be effected unless different from the current
b9dc4443 4646 f->height. */
f676886a
JB
4647 width = f->width;
4648 height = f->height;
6a1bcd01 4649
1ab3d87e
RS
4650 f->height = 0;
4651 SET_FRAME_WIDTH (f, 0);
8938a4fb 4652 change_frame_size (f, height, width, 1, 0, 0);
d043f1a4 4653
4a967a9b
GM
4654 /* Set up faces after all frame parameters are known. This call
4655 also merges in face attributes specified for new frames. If we
4656 don't do this, the `menu' face for instance won't have the right
4657 colors, and the menu bar won't appear in the specified colors for
4658 new frames. */
4659 call1 (Qface_set_after_frame_default, frame);
4660
495fa05e
GM
4661#ifdef USE_X_TOOLKIT
4662 /* Create the menu bar. */
4663 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4664 {
4665 /* If this signals an error, we haven't set size hints for the
4666 frame and we didn't make it visible. */
4667 initialize_frame_menubar (f);
4668
4669 /* This is a no-op, except under Motif where it arranges the
4670 main window for the widgets on it. */
4671 lw_set_main_areas (f->output_data.x->column_widget,
4672 f->output_data.x->menubar_widget,
4673 f->output_data.x->edit_widget);
4674 }
4675#endif /* USE_X_TOOLKIT */
4676
4677 /* Tell the server what size and position, etc, we want, and how
4678 badly we want them. This should be done after we have the menu
4679 bar so that its size can be taken into account. */
01f1ba30 4680 BLOCK_INPUT;
7989f084 4681 x_wm_set_size_hint (f, window_prompting, 0);
01f1ba30
JB
4682 UNBLOCK_INPUT;
4683
495fa05e
GM
4684 /* Make the window appear on the frame and enable display, unless
4685 the caller says not to. However, with explicit parent, Emacs
4686 cannot control visibility, so don't try. */
7556890b 4687 if (! f->output_data.x->explicit_parent)
a59e4f3d
RS
4688 {
4689 Lisp_Object visibility;
49795535 4690
333b20bb
GM
4691 visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
4692 RES_TYPE_SYMBOL);
a59e4f3d
RS
4693 if (EQ (visibility, Qunbound))
4694 visibility = Qt;
49795535 4695
a59e4f3d
RS
4696 if (EQ (visibility, Qicon))
4697 x_iconify_frame (f);
4698 else if (! NILP (visibility))
4699 x_make_frame_visible (f);
4700 else
4701 /* Must have been Qnil. */
4702 ;
4703 }
01f1ba30 4704
495fa05e 4705 UNGCPRO;
9e57df62
GM
4706
4707 /* Make sure windows on this frame appear in calls to next-window
4708 and similar functions. */
4709 Vwindow_list = Qnil;
4710
9ef48a9d 4711 return unbind_to (count, frame);
01f1ba30
JB
4712}
4713
eaf1eea9 4714
0d17d282
KH
4715/* FRAME is used only to get a handle on the X display. We don't pass the
4716 display info directly because we're called from frame.c, which doesn't
4717 know about that structure. */
e4f79258 4718
87498171 4719Lisp_Object
0d17d282
KH
4720x_get_focus_frame (frame)
4721 struct frame *frame;
87498171 4722{
0d17d282 4723 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (frame);
87498171 4724 Lisp_Object xfocus;
0d17d282 4725 if (! dpyinfo->x_focus_frame)
87498171
KH
4726 return Qnil;
4727
0d17d282 4728 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
87498171
KH
4729 return xfocus;
4730}
f0614854 4731
3decc1e7
GM
4732
4733/* In certain situations, when the window manager follows a
4734 click-to-focus policy, there seems to be no way around calling
4735 XSetInputFocus to give another frame the input focus .
4736
4737 In an ideal world, XSetInputFocus should generally be avoided so
4738 that applications don't interfere with the window manager's focus
4739 policy. But I think it's okay to use when it's clearly done
4740 following a user-command. */
4741
4742DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
7ee72033
MB
4743 doc: /* Set the input focus to FRAME.
4744FRAME nil means use the selected frame. */)
4745 (frame)
3decc1e7
GM
4746 Lisp_Object frame;
4747{
4748 struct frame *f = check_x_frame (frame);
4749 Display *dpy = FRAME_X_DISPLAY (f);
4750 int count;
4751
4752 BLOCK_INPUT;
4753 count = x_catch_errors (dpy);
4754 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4755 RevertToParent, CurrentTime);
4756 x_uncatch_errors (dpy, count);
4757 UNBLOCK_INPUT;
4758
4759 return Qnil;
4760}
4761
f0614854 4762\f
2d764c78 4763DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7ee72033
MB
4764 doc: /* Internal function called by `color-defined-p', which see. */)
4765 (color, frame)
b9dc4443 4766 Lisp_Object color, frame;
e12d55b2 4767{
b9dc4443
RS
4768 XColor foo;
4769 FRAME_PTR f = check_x_frame (frame);
e12d55b2 4770
b7826503 4771 CHECK_STRING (color);
b9dc4443 4772
2d764c78 4773 if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
e12d55b2
RS
4774 return Qt;
4775 else
4776 return Qnil;
4777}
4778
2d764c78 4779DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7ee72033
MB
4780 doc: /* Internal function called by `color-values', which see. */)
4781 (color, frame)
b9dc4443 4782 Lisp_Object color, frame;
01f1ba30 4783{
b9dc4443
RS
4784 XColor foo;
4785 FRAME_PTR f = check_x_frame (frame);
4786
b7826503 4787 CHECK_STRING (color);
01f1ba30 4788
2d764c78 4789 if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
57c82a63
RS
4790 {
4791 Lisp_Object rgb[3];
4792
4793 rgb[0] = make_number (foo.red);
4794 rgb[1] = make_number (foo.green);
4795 rgb[2] = make_number (foo.blue);
4796 return Flist (3, rgb);
4797 }
01f1ba30
JB
4798 else
4799 return Qnil;
4800}
4801
2d764c78 4802DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7ee72033
MB
4803 doc: /* Internal function called by `display-color-p', which see. */)
4804 (display)
08a90d6a 4805 Lisp_Object display;
01f1ba30 4806{
08a90d6a 4807 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 4808
b9dc4443 4809 if (dpyinfo->n_planes <= 2)
01f1ba30
JB
4810 return Qnil;
4811
b9dc4443 4812 switch (dpyinfo->visual->class)
01f1ba30
JB
4813 {
4814 case StaticColor:
4815 case PseudoColor:
4816 case TrueColor:
4817 case DirectColor:
4818 return Qt;
4819
4820 default:
4821 return Qnil;
4822 }
4823}
4824
d0c9d219 4825DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
c061c855 4826 0, 1, 0,
7ee72033 4827 doc: /* Return t if the X display supports shades of gray.
c061c855
GM
4828Note that color displays do support shades of gray.
4829The optional argument DISPLAY specifies which display to ask about.
4830DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4831If omitted or nil, that stands for the selected frame's display. */)
4832 (display)
08a90d6a 4833 Lisp_Object display;
d0c9d219 4834{
08a90d6a 4835 struct x_display_info *dpyinfo = check_x_display_info (display);
d0c9d219 4836
ae6b58f9 4837 if (dpyinfo->n_planes <= 1)
b9dc4443
RS
4838 return Qnil;
4839
ae6b58f9
RS
4840 switch (dpyinfo->visual->class)
4841 {
4842 case StaticColor:
4843 case PseudoColor:
4844 case TrueColor:
4845 case DirectColor:
4846 case StaticGray:
4847 case GrayScale:
4848 return Qt;
4849
4850 default:
4851 return Qnil;
4852 }
d0c9d219
RS
4853}
4854
41beb8fc 4855DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
c061c855 4856 0, 1, 0,
7ee72033 4857 doc: /* Returns the width in pixels of the X display DISPLAY.
c061c855
GM
4858The optional argument DISPLAY specifies which display to ask about.
4859DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4860If omitted or nil, that stands for the selected frame's display. */)
4861 (display)
08a90d6a 4862 Lisp_Object display;
41beb8fc 4863{
08a90d6a 4864 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4865
4866 return make_number (dpyinfo->width);
41beb8fc
RS
4867}
4868
4869DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
c061c855 4870 Sx_display_pixel_height, 0, 1, 0,
7ee72033 4871 doc: /* Returns the height in pixels of the X display DISPLAY.
c061c855
GM
4872The optional argument DISPLAY specifies which display to ask about.
4873DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4874If omitted or nil, that stands for the selected frame's display. */)
4875 (display)
08a90d6a 4876 Lisp_Object display;
41beb8fc 4877{
08a90d6a 4878 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4879
4880 return make_number (dpyinfo->height);
41beb8fc
RS
4881}
4882
4883DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
c061c855 4884 0, 1, 0,
7ee72033 4885 doc: /* Returns the number of bitplanes of the X display DISPLAY.
c061c855
GM
4886The optional argument DISPLAY specifies which display to ask about.
4887DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4888If omitted or nil, that stands for the selected frame's display. */)
4889 (display)
08a90d6a 4890 Lisp_Object display;
41beb8fc 4891{
08a90d6a 4892 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4893
4894 return make_number (dpyinfo->n_planes);
41beb8fc
RS
4895}
4896
4897DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
c061c855 4898 0, 1, 0,
7ee72033 4899 doc: /* Returns the number of color cells of the X display DISPLAY.
c061c855
GM
4900The optional argument DISPLAY specifies which display to ask about.
4901DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4902If omitted or nil, that stands for the selected frame's display. */)
4903 (display)
08a90d6a 4904 Lisp_Object display;
41beb8fc 4905{
08a90d6a 4906 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4907
4908 return make_number (DisplayCells (dpyinfo->display,
4909 XScreenNumberOfScreen (dpyinfo->screen)));
41beb8fc
RS
4910}
4911
9d317b2c
RS
4912DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4913 Sx_server_max_request_size,
c061c855 4914 0, 1, 0,
7ee72033 4915 doc: /* Returns the maximum request size of the X server of display DISPLAY.
c061c855
GM
4916The optional argument DISPLAY specifies which display to ask about.
4917DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4918If omitted or nil, that stands for the selected frame's display. */)
4919 (display)
08a90d6a 4920 Lisp_Object display;
9d317b2c 4921{
08a90d6a 4922 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4923
4924 return make_number (MAXREQUEST (dpyinfo->display));
9d317b2c
RS
4925}
4926
41beb8fc 4927DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7ee72033 4928 doc: /* Returns the vendor ID string of the X server of display DISPLAY.
c061c855
GM
4929The optional argument DISPLAY specifies which display to ask about.
4930DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4931If omitted or nil, that stands for the selected frame's display. */)
4932 (display)
08a90d6a 4933 Lisp_Object display;
41beb8fc 4934{
08a90d6a 4935 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4936 char *vendor = ServerVendor (dpyinfo->display);
4937
41beb8fc
RS
4938 if (! vendor) vendor = "";
4939 return build_string (vendor);
4940}
4941
4942DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7ee72033 4943 doc: /* Returns the version numbers of the X server of display DISPLAY.
c061c855
GM
4944The value is a list of three integers: the major and minor
4945version numbers of the X Protocol in use, and the vendor-specific release
4946number. See also the function `x-server-vendor'.
4947
4948The optional argument DISPLAY specifies which display to ask about.
4949DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4950If omitted or nil, that stands for the selected frame's display. */)
4951 (display)
08a90d6a 4952 Lisp_Object display;
41beb8fc 4953{
08a90d6a 4954 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443 4955 Display *dpy = dpyinfo->display;
11ae94fe 4956
41beb8fc
RS
4957 return Fcons (make_number (ProtocolVersion (dpy)),
4958 Fcons (make_number (ProtocolRevision (dpy)),
4959 Fcons (make_number (VendorRelease (dpy)), Qnil)));
4960}
4961
4962DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7ee72033 4963 doc: /* Return the number of screens on the X server of display DISPLAY.
c061c855
GM
4964The optional argument DISPLAY specifies which display to ask about.
4965DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4966If omitted or nil, that stands for the selected frame's display. */)
4967 (display)
08a90d6a 4968 Lisp_Object display;
41beb8fc 4969{
08a90d6a 4970 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4971
4972 return make_number (ScreenCount (dpyinfo->display));
41beb8fc
RS
4973}
4974
4975DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7ee72033 4976 doc: /* Return the height in millimeters of the X display DISPLAY.
c061c855
GM
4977The optional argument DISPLAY specifies which display to ask about.
4978DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4979If omitted or nil, that stands for the selected frame's display. */)
4980 (display)
08a90d6a 4981 Lisp_Object display;
41beb8fc 4982{
08a90d6a 4983 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4984
4985 return make_number (HeightMMOfScreen (dpyinfo->screen));
41beb8fc
RS
4986}
4987
4988DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7ee72033 4989 doc: /* Return the width in millimeters of the X display DISPLAY.
c061c855
GM
4990The optional argument DISPLAY specifies which display to ask about.
4991DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4992If omitted or nil, that stands for the selected frame's display. */)
4993 (display)
08a90d6a 4994 Lisp_Object display;
41beb8fc 4995{
08a90d6a 4996 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4997
4998 return make_number (WidthMMOfScreen (dpyinfo->screen));
41beb8fc
RS
4999}
5000
5001DEFUN ("x-display-backing-store", Fx_display_backing_store,
c061c855 5002 Sx_display_backing_store, 0, 1, 0,
7ee72033 5003 doc: /* Returns an indication of whether X display DISPLAY does backing store.
c061c855
GM
5004The value may be `always', `when-mapped', or `not-useful'.
5005The optional argument DISPLAY specifies which display to ask about.
5006DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5007If omitted or nil, that stands for the selected frame's display. */)
5008 (display)
08a90d6a 5009 Lisp_Object display;
41beb8fc 5010{
08a90d6a 5011 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5012 Lisp_Object result;
11ae94fe 5013
b9dc4443 5014 switch (DoesBackingStore (dpyinfo->screen))
41beb8fc
RS
5015 {
5016 case Always:
8ec8a5ec
GM
5017 result = intern ("always");
5018 break;
41beb8fc
RS
5019
5020 case WhenMapped:
8ec8a5ec
GM
5021 result = intern ("when-mapped");
5022 break;
41beb8fc
RS
5023
5024 case NotUseful:
8ec8a5ec
GM
5025 result = intern ("not-useful");
5026 break;
41beb8fc
RS
5027
5028 default:
5029 error ("Strange value for BackingStore parameter of screen");
8ec8a5ec 5030 result = Qnil;
41beb8fc 5031 }
8ec8a5ec
GM
5032
5033 return result;
41beb8fc
RS
5034}
5035
5036DEFUN ("x-display-visual-class", Fx_display_visual_class,
c061c855 5037 Sx_display_visual_class, 0, 1, 0,
7ee72033 5038 doc: /* Return the visual class of the X display DISPLAY.
c061c855
GM
5039The value is one of the symbols `static-gray', `gray-scale',
5040`static-color', `pseudo-color', `true-color', or `direct-color'.
5041
5042The optional argument DISPLAY specifies which display to ask about.
5043DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5044If omitted or nil, that stands for the selected frame's display. */)
5045 (display)
08a90d6a 5046 Lisp_Object display;
41beb8fc 5047{
08a90d6a 5048 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5049 Lisp_Object result;
11ae94fe 5050
b9dc4443 5051 switch (dpyinfo->visual->class)
41beb8fc 5052 {
8ec8a5ec
GM
5053 case StaticGray:
5054 result = intern ("static-gray");
5055 break;
5056 case GrayScale:
5057 result = intern ("gray-scale");
5058 break;
5059 case StaticColor:
5060 result = intern ("static-color");
5061 break;
5062 case PseudoColor:
5063 result = intern ("pseudo-color");
5064 break;
5065 case TrueColor:
5066 result = intern ("true-color");
5067 break;
5068 case DirectColor:
5069 result = intern ("direct-color");
5070 break;
41beb8fc
RS
5071 default:
5072 error ("Display has an unknown visual class");
8ec8a5ec 5073 result = Qnil;
41beb8fc 5074 }
8ec8a5ec
GM
5075
5076 return result;
41beb8fc
RS
5077}
5078
5079DEFUN ("x-display-save-under", Fx_display_save_under,
c061c855 5080 Sx_display_save_under, 0, 1, 0,
7ee72033 5081 doc: /* Returns t if the X display DISPLAY supports the save-under feature.
c061c855
GM
5082The optional argument DISPLAY specifies which display to ask about.
5083DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5084If omitted or nil, that stands for the selected frame's display. */)
5085 (display)
08a90d6a 5086 Lisp_Object display;
41beb8fc 5087{
08a90d6a 5088 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5089
b9dc4443 5090 if (DoesSaveUnders (dpyinfo->screen) == True)
41beb8fc
RS
5091 return Qt;
5092 else
5093 return Qnil;
5094}
5095\f
b9dc4443 5096int
55caf99c
RS
5097x_pixel_width (f)
5098 register struct frame *f;
01f1ba30 5099{
55caf99c 5100 return PIXEL_WIDTH (f);
01f1ba30
JB
5101}
5102
b9dc4443 5103int
55caf99c
RS
5104x_pixel_height (f)
5105 register struct frame *f;
01f1ba30 5106{
55caf99c
RS
5107 return PIXEL_HEIGHT (f);
5108}
5109
b9dc4443 5110int
55caf99c
RS
5111x_char_width (f)
5112 register struct frame *f;
5113{
7556890b 5114 return FONT_WIDTH (f->output_data.x->font);
55caf99c
RS
5115}
5116
b9dc4443 5117int
55caf99c
RS
5118x_char_height (f)
5119 register struct frame *f;
5120{
7556890b 5121 return f->output_data.x->line_height;
01f1ba30 5122}
b9dc4443
RS
5123
5124int
f03f2489
RS
5125x_screen_planes (f)
5126 register struct frame *f;
b9dc4443 5127{
f03f2489 5128 return FRAME_X_DISPLAY_INFO (f)->n_planes;
b9dc4443 5129}
01f1ba30 5130
a6ad00c0
GM
5131
5132\f
5133/************************************************************************
5134 X Displays
5135 ************************************************************************/
5136
01f1ba30 5137\f
a6ad00c0
GM
5138/* Mapping visual names to visuals. */
5139
5140static struct visual_class
5141{
5142 char *name;
5143 int class;
5144}
5145visual_classes[] =
5146{
5147 {"StaticGray", StaticGray},
5148 {"GrayScale", GrayScale},
5149 {"StaticColor", StaticColor},
5150 {"PseudoColor", PseudoColor},
5151 {"TrueColor", TrueColor},
5152 {"DirectColor", DirectColor},
9908a324 5153 {NULL, 0}
a6ad00c0
GM
5154};
5155
5156
404daac1 5157#ifndef HAVE_XSCREENNUMBEROFSCREEN
a6ad00c0
GM
5158
5159/* Value is the screen number of screen SCR. This is a substitute for
5160 the X function with the same name when that doesn't exist. */
5161
404daac1
RS
5162int
5163XScreenNumberOfScreen (scr)
5164 register Screen *scr;
5165{
a6ad00c0
GM
5166 Display *dpy = scr->display;
5167 int i;
3df34fdb 5168
a6ad00c0 5169 for (i = 0; i < dpy->nscreens; ++i)
fbd5ceb2 5170 if (scr == dpy->screens + i)
a6ad00c0 5171 break;
404daac1 5172
a6ad00c0 5173 return i;
404daac1 5174}
a6ad00c0 5175
404daac1
RS
5176#endif /* not HAVE_XSCREENNUMBEROFSCREEN */
5177
01f1ba30 5178
a6ad00c0
GM
5179/* Select the visual that should be used on display DPYINFO. Set
5180 members of DPYINFO appropriately. Called from x_term_init. */
fe24a618 5181
a6ad00c0
GM
5182void
5183select_visual (dpyinfo)
5184 struct x_display_info *dpyinfo;
5185{
5186 Display *dpy = dpyinfo->display;
5187 Screen *screen = dpyinfo->screen;
5188 Lisp_Object value;
fe24a618 5189
a6ad00c0
GM
5190 /* See if a visual is specified. */
5191 value = display_x_get_resource (dpyinfo,
5192 build_string ("visualClass"),
5193 build_string ("VisualClass"),
5194 Qnil, Qnil);
5195 if (STRINGP (value))
5196 {
5197 /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
5198 of `PseudoColor', `TrueColor' etc. and DEPTH is the color
5199 depth, a decimal number. NAME is compared with case ignored. */
5200 char *s = (char *) alloca (STRING_BYTES (XSTRING (value)) + 1);
5201 char *dash;
5202 int i, class = -1;
5203 XVisualInfo vinfo;
5204
5205 strcpy (s, XSTRING (value)->data);
5206 dash = index (s, '-');
5207 if (dash)
5208 {
5209 dpyinfo->n_planes = atoi (dash + 1);
5210 *dash = '\0';
5211 }
5212 else
5213 /* We won't find a matching visual with depth 0, so that
5214 an error will be printed below. */
5215 dpyinfo->n_planes = 0;
f0614854 5216
a6ad00c0
GM
5217 /* Determine the visual class. */
5218 for (i = 0; visual_classes[i].name; ++i)
5219 if (xstricmp (s, visual_classes[i].name) == 0)
5220 {
5221 class = visual_classes[i].class;
5222 break;
5223 }
01f1ba30 5224
a6ad00c0
GM
5225 /* Look up a matching visual for the specified class. */
5226 if (class == -1
5227 || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
5228 dpyinfo->n_planes, class, &vinfo))
5229 fatal ("Invalid visual specification `%s'", XSTRING (value)->data);
5230
5231 dpyinfo->visual = vinfo.visual;
5232 }
01f1ba30
JB
5233 else
5234 {
a6ad00c0
GM
5235 int n_visuals;
5236 XVisualInfo *vinfo, vinfo_template;
5237
5238 dpyinfo->visual = DefaultVisualOfScreen (screen);
5239
5240#ifdef HAVE_X11R4
5241 vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
5242#else
5243 vinfo_template.visualid = dpyinfo->visual->visualid;
5244#endif
5245 vinfo_template.screen = XScreenNumberOfScreen (screen);
5246 vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
5247 &vinfo_template, &n_visuals);
5248 if (n_visuals != 1)
5249 fatal ("Can't get proper X visual info");
5250
94ac875b 5251 dpyinfo->n_planes = vinfo->depth;
a6ad00c0
GM
5252 XFree ((char *) vinfo);
5253 }
01f1ba30 5254}
01f1ba30 5255
a6ad00c0 5256
b9dc4443
RS
5257/* Return the X display structure for the display named NAME.
5258 Open a new connection if necessary. */
5259
5260struct x_display_info *
5261x_display_info_for_name (name)
5262 Lisp_Object name;
5263{
08a90d6a 5264 Lisp_Object names;
b9dc4443
RS
5265 struct x_display_info *dpyinfo;
5266
b7826503 5267 CHECK_STRING (name);
b9dc4443 5268
806048df
RS
5269 if (! EQ (Vwindow_system, intern ("x")))
5270 error ("Not using X Windows");
5271
08a90d6a
RS
5272 for (dpyinfo = x_display_list, names = x_display_name_list;
5273 dpyinfo;
8e713be6 5274 dpyinfo = dpyinfo->next, names = XCDR (names))
b9dc4443
RS
5275 {
5276 Lisp_Object tem;
8e713be6 5277 tem = Fstring_equal (XCAR (XCAR (names)), name);
08a90d6a 5278 if (!NILP (tem))
b9dc4443
RS
5279 return dpyinfo;
5280 }
5281
b7975ee4
KH
5282 /* Use this general default value to start with. */
5283 Vx_resource_name = Vinvocation_name;
5284
b9dc4443
RS
5285 validate_x_resource_name ();
5286
9b207e8e 5287 dpyinfo = x_term_init (name, (char *)0,
b7975ee4 5288 (char *) XSTRING (Vx_resource_name)->data);
b9dc4443 5289
08a90d6a 5290 if (dpyinfo == 0)
1b4ec1c8 5291 error ("Cannot connect to X server %s", XSTRING (name)->data);
08a90d6a 5292
b9dc4443
RS
5293 x_in_use = 1;
5294 XSETFASTINT (Vwindow_system_version, 11);
5295
5296 return dpyinfo;
5297}
5298
a6ad00c0 5299
01f1ba30 5300DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
c061c855 5301 1, 3, 0,
7ee72033 5302 doc: /* Open a connection to an X server.
c061c855
GM
5303DISPLAY is the name of the display to connect to.
5304Optional second arg XRM-STRING is a string of resources in xrdb format.
5305If the optional third arg MUST-SUCCEED is non-nil,
7ee72033
MB
5306terminate Emacs if we can't open the connection. */)
5307 (display, xrm_string, must_succeed)
08a90d6a 5308 Lisp_Object display, xrm_string, must_succeed;
01f1ba30 5309{
01f1ba30 5310 unsigned char *xrm_option;
b9dc4443 5311 struct x_display_info *dpyinfo;
01f1ba30 5312
b7826503 5313 CHECK_STRING (display);
d387c960 5314 if (! NILP (xrm_string))
b7826503 5315 CHECK_STRING (xrm_string);
01f1ba30 5316
806048df
RS
5317 if (! EQ (Vwindow_system, intern ("x")))
5318 error ("Not using X Windows");
5319
d387c960
JB
5320 if (! NILP (xrm_string))
5321 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
01f1ba30
JB
5322 else
5323 xrm_option = (unsigned char *) 0;
d387c960
JB
5324
5325 validate_x_resource_name ();
5326
e1b1bee8 5327 /* This is what opens the connection and sets x_current_display.
b9dc4443
RS
5328 This also initializes many symbols, such as those used for input. */
5329 dpyinfo = x_term_init (display, xrm_option,
b7975ee4 5330 (char *) XSTRING (Vx_resource_name)->data);
f1c16f36 5331
08a90d6a
RS
5332 if (dpyinfo == 0)
5333 {
5334 if (!NILP (must_succeed))
10ffbc14
GM
5335 fatal ("Cannot connect to X server %s.\n\
5336Check the DISPLAY environment variable or use `-d'.\n\
5337Also use the `xhost' program to verify that it is set to permit\n\
1b4ec1c8 5338connections from your machine.\n",
08a90d6a
RS
5339 XSTRING (display)->data);
5340 else
1b4ec1c8 5341 error ("Cannot connect to X server %s", XSTRING (display)->data);
08a90d6a
RS
5342 }
5343
b9dc4443 5344 x_in_use = 1;
01f1ba30 5345
b9dc4443 5346 XSETFASTINT (Vwindow_system_version, 11);
01f1ba30
JB
5347 return Qnil;
5348}
5349
08a90d6a
RS
5350DEFUN ("x-close-connection", Fx_close_connection,
5351 Sx_close_connection, 1, 1, 0,
7ee72033 5352 doc: /* Close the connection to DISPLAY's X server.
c061c855 5353For DISPLAY, specify either a frame or a display name (a string).
7ee72033
MB
5354If DISPLAY is nil, that stands for the selected frame's display. */)
5355 (display)
c061c855 5356 Lisp_Object display;
01f1ba30 5357{
08a90d6a 5358 struct x_display_info *dpyinfo = check_x_display_info (display);
08a90d6a 5359 int i;
3457bc6e 5360
08a90d6a
RS
5361 if (dpyinfo->reference_count > 0)
5362 error ("Display still has frames on it");
01f1ba30 5363
08a90d6a
RS
5364 BLOCK_INPUT;
5365 /* Free the fonts in the font table. */
5366 for (i = 0; i < dpyinfo->n_fonts; i++)
333b20bb
GM
5367 if (dpyinfo->font_table[i].name)
5368 {
6ecb43ce
KH
5369 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
5370 xfree (dpyinfo->font_table[i].full_name);
333b20bb 5371 xfree (dpyinfo->font_table[i].name);
333b20bb
GM
5372 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
5373 }
5374
08a90d6a
RS
5375 x_destroy_all_bitmaps (dpyinfo);
5376 XSetCloseDownMode (dpyinfo->display, DestroyAll);
82c90203
RS
5377
5378#ifdef USE_X_TOOLKIT
5379 XtCloseDisplay (dpyinfo->display);
5380#else
08a90d6a 5381 XCloseDisplay (dpyinfo->display);
82c90203 5382#endif
08a90d6a
RS
5383
5384 x_delete_display (dpyinfo);
5385 UNBLOCK_INPUT;
3457bc6e 5386
01f1ba30
JB
5387 return Qnil;
5388}
5389
08a90d6a 5390DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7ee72033
MB
5391 doc: /* Return the list of display names that Emacs has connections to. */)
5392 ()
08a90d6a
RS
5393{
5394 Lisp_Object tail, result;
5395
5396 result = Qnil;
8e713be6
KR
5397 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
5398 result = Fcons (XCAR (XCAR (tail)), result);
08a90d6a
RS
5399
5400 return result;
5401}
5402
5403DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7ee72033 5404 doc: /* If ON is non-nil, report X errors as soon as the erring request is made.
c061c855
GM
5405If ON is nil, allow buffering of requests.
5406Turning on synchronization prohibits the Xlib routines from buffering
5407requests and seriously degrades performance, but makes debugging much
5408easier.
5409The optional second argument DISPLAY specifies which display to act on.
5410DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5411If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
5412 (on, display)
08a90d6a 5413 Lisp_Object display, on;
01f1ba30 5414{
08a90d6a 5415 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5416
b9dc4443 5417 XSynchronize (dpyinfo->display, !EQ (on, Qnil));
01f1ba30
JB
5418
5419 return Qnil;
5420}
5421
b9dc4443 5422/* Wait for responses to all X commands issued so far for frame F. */
6b7b1820
RS
5423
5424void
b9dc4443
RS
5425x_sync (f)
5426 FRAME_PTR f;
6b7b1820 5427{
4e87f4d2 5428 BLOCK_INPUT;
b9dc4443 5429 XSync (FRAME_X_DISPLAY (f), False);
4e87f4d2 5430 UNBLOCK_INPUT;
6b7b1820 5431}
333b20bb 5432
01f1ba30 5433\f
333b20bb
GM
5434/***********************************************************************
5435 Image types
5436 ***********************************************************************/
f1c16f36 5437
333b20bb
GM
5438/* Value is the number of elements of vector VECTOR. */
5439
5440#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
5441
5442/* List of supported image types. Use define_image_type to add new
5443 types. Use lookup_image_type to find a type for a given symbol. */
5444
5445static struct image_type *image_types;
5446
333b20bb
GM
5447/* The symbol `image' which is the car of the lists used to represent
5448 images in Lisp. */
5449
5450extern Lisp_Object Qimage;
5451
5452/* The symbol `xbm' which is used as the type symbol for XBM images. */
5453
5454Lisp_Object Qxbm;
5455
5456/* Keywords. */
5457
0fe92f72 5458extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
90ebdb19
GM
5459extern Lisp_Object QCdata;
5460Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
d2dc8167 5461Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4a8e312c 5462Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
333b20bb
GM
5463
5464/* Other symbols. */
5465
4a8e312c 5466Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
333b20bb
GM
5467
5468/* Time in seconds after which images should be removed from the cache
5469 if not displayed. */
5470
fcf431dc 5471Lisp_Object Vimage_cache_eviction_delay;
333b20bb
GM
5472
5473/* Function prototypes. */
5474
5475static void define_image_type P_ ((struct image_type *type));
5476static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
5477static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
5478static void x_laplace P_ ((struct frame *, struct image *));
4a8e312c 5479static void x_emboss P_ ((struct frame *, struct image *));
45158a91
GM
5480static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
5481 Lisp_Object));
333b20bb
GM
5482
5483
5484/* Define a new image type from TYPE. This adds a copy of TYPE to
5485 image_types and adds the symbol *TYPE->type to Vimage_types. */
5486
5487static void
5488define_image_type (type)
5489 struct image_type *type;
5490{
5491 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
5492 The initialized data segment is read-only. */
5493 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
5494 bcopy (type, p, sizeof *p);
5495 p->next = image_types;
5496 image_types = p;
5497 Vimage_types = Fcons (*p->type, Vimage_types);
5498}
5499
5500
5501/* Look up image type SYMBOL, and return a pointer to its image_type
5502 structure. Value is null if SYMBOL is not a known image type. */
5503
5504static INLINE struct image_type *
5505lookup_image_type (symbol)
5506 Lisp_Object symbol;
5507{
5508 struct image_type *type;
5509
5510 for (type = image_types; type; type = type->next)
5511 if (EQ (symbol, *type->type))
5512 break;
5513
5514 return type;
5515}
5516
5517
5518/* Value is non-zero if OBJECT is a valid Lisp image specification. A
5519 valid image specification is a list whose car is the symbol
5520 `image', and whose rest is a property list. The property list must
5521 contain a value for key `:type'. That value must be the name of a
5522 supported image type. The rest of the property list depends on the
5523 image type. */
5524
5525int
5526valid_image_p (object)
5527 Lisp_Object object;
5528{
5529 int valid_p = 0;
5530
5531 if (CONSP (object) && EQ (XCAR (object), Qimage))
5532 {
1783ffa2
GM
5533 Lisp_Object tem;
5534
5535 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
5536 if (EQ (XCAR (tem), QCtype))
5537 {
5538 tem = XCDR (tem);
5539 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
5540 {
5541 struct image_type *type;
5542 type = lookup_image_type (XCAR (tem));
5543 if (type)
5544 valid_p = type->valid_p (object);
5545 }
5546
5547 break;
5548 }
333b20bb
GM
5549 }
5550
5551 return valid_p;
5552}
5553
5554
7ab1745f
GM
5555/* Log error message with format string FORMAT and argument ARG.
5556 Signaling an error, e.g. when an image cannot be loaded, is not a
5557 good idea because this would interrupt redisplay, and the error
5558 message display would lead to another redisplay. This function
5559 therefore simply displays a message. */
333b20bb
GM
5560
5561static void
5562image_error (format, arg1, arg2)
5563 char *format;
5564 Lisp_Object arg1, arg2;
5565{
7ab1745f 5566 add_to_log (format, arg1, arg2);
333b20bb
GM
5567}
5568
5569
5570\f
5571/***********************************************************************
5572 Image specifications
5573 ***********************************************************************/
5574
5575enum image_value_type
5576{
5577 IMAGE_DONT_CHECK_VALUE_TYPE,
5578 IMAGE_STRING_VALUE,
6f1be3b9 5579 IMAGE_STRING_OR_NIL_VALUE,
333b20bb
GM
5580 IMAGE_SYMBOL_VALUE,
5581 IMAGE_POSITIVE_INTEGER_VALUE,
3ed61e75 5582 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
333b20bb 5583 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7c7ff7f5 5584 IMAGE_ASCENT_VALUE,
333b20bb
GM
5585 IMAGE_INTEGER_VALUE,
5586 IMAGE_FUNCTION_VALUE,
5587 IMAGE_NUMBER_VALUE,
5588 IMAGE_BOOL_VALUE
5589};
5590
5591/* Structure used when parsing image specifications. */
5592
5593struct image_keyword
5594{
5595 /* Name of keyword. */
5596 char *name;
5597
5598 /* The type of value allowed. */
5599 enum image_value_type type;
5600
5601 /* Non-zero means key must be present. */
5602 int mandatory_p;
5603
5604 /* Used to recognize duplicate keywords in a property list. */
5605 int count;
5606
5607 /* The value that was found. */
5608 Lisp_Object value;
5609};
5610
5611
bfd2209f
GM
5612static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
5613 int, Lisp_Object));
333b20bb
GM
5614static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
5615
5616
5617/* Parse image spec SPEC according to KEYWORDS. A valid image spec
5618 has the format (image KEYWORD VALUE ...). One of the keyword/
5619 value pairs must be `:type TYPE'. KEYWORDS is a vector of
5620 image_keywords structures of size NKEYWORDS describing other
bfd2209f 5621 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
333b20bb
GM
5622
5623static int
bfd2209f 5624parse_image_spec (spec, keywords, nkeywords, type)
333b20bb
GM
5625 Lisp_Object spec;
5626 struct image_keyword *keywords;
5627 int nkeywords;
5628 Lisp_Object type;
333b20bb
GM
5629{
5630 int i;
5631 Lisp_Object plist;
5632
5633 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
5634 return 0;
5635
5636 plist = XCDR (spec);
5637 while (CONSP (plist))
5638 {
5639 Lisp_Object key, value;
5640
5641 /* First element of a pair must be a symbol. */
5642 key = XCAR (plist);
5643 plist = XCDR (plist);
5644 if (!SYMBOLP (key))
5645 return 0;
5646
5647 /* There must follow a value. */
5648 if (!CONSP (plist))
5649 return 0;
5650 value = XCAR (plist);
5651 plist = XCDR (plist);
5652
5653 /* Find key in KEYWORDS. Error if not found. */
5654 for (i = 0; i < nkeywords; ++i)
5655 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
5656 break;
5657
5658 if (i == nkeywords)
bfd2209f 5659 continue;
333b20bb
GM
5660
5661 /* Record that we recognized the keyword. If a keywords
5662 was found more than once, it's an error. */
5663 keywords[i].value = value;
5664 ++keywords[i].count;
5665
5666 if (keywords[i].count > 1)
5667 return 0;
5668
5669 /* Check type of value against allowed type. */
5670 switch (keywords[i].type)
5671 {
5672 case IMAGE_STRING_VALUE:
5673 if (!STRINGP (value))
5674 return 0;
5675 break;
5676
6f1be3b9
GM
5677 case IMAGE_STRING_OR_NIL_VALUE:
5678 if (!STRINGP (value) && !NILP (value))
5679 return 0;
5680 break;
5681
333b20bb
GM
5682 case IMAGE_SYMBOL_VALUE:
5683 if (!SYMBOLP (value))
5684 return 0;
5685 break;
5686
5687 case IMAGE_POSITIVE_INTEGER_VALUE:
5688 if (!INTEGERP (value) || XINT (value) <= 0)
5689 return 0;
5690 break;
5691
3ed61e75
GM
5692 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
5693 if (INTEGERP (value) && XINT (value) >= 0)
5694 break;
5695 if (CONSP (value)
5696 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
5697 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
5698 break;
5699 return 0;
5700
7c7ff7f5
GM
5701 case IMAGE_ASCENT_VALUE:
5702 if (SYMBOLP (value) && EQ (value, Qcenter))
5703 break;
5704 else if (INTEGERP (value)
5705 && XINT (value) >= 0
5706 && XINT (value) <= 100)
5707 break;
5708 return 0;
5709
333b20bb
GM
5710 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
5711 if (!INTEGERP (value) || XINT (value) < 0)
5712 return 0;
5713 break;
5714
5715 case IMAGE_DONT_CHECK_VALUE_TYPE:
5716 break;
5717
5718 case IMAGE_FUNCTION_VALUE:
5719 value = indirect_function (value);
5720 if (SUBRP (value)
5721 || COMPILEDP (value)
5722 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
5723 break;
5724 return 0;
5725
5726 case IMAGE_NUMBER_VALUE:
5727 if (!INTEGERP (value) && !FLOATP (value))
5728 return 0;
5729 break;
5730
5731 case IMAGE_INTEGER_VALUE:
5732 if (!INTEGERP (value))
5733 return 0;
5734 break;
5735
5736 case IMAGE_BOOL_VALUE:
5737 if (!NILP (value) && !EQ (value, Qt))
5738 return 0;
5739 break;
5740
5741 default:
5742 abort ();
5743 break;
5744 }
5745
5746 if (EQ (key, QCtype) && !EQ (type, value))
5747 return 0;
5748 }
5749
5750 /* Check that all mandatory fields are present. */
5751 for (i = 0; i < nkeywords; ++i)
5752 if (keywords[i].mandatory_p && keywords[i].count == 0)
5753 return 0;
5754
5755 return NILP (plist);
5756}
5757
5758
5759/* Return the value of KEY in image specification SPEC. Value is nil
5760 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
5761 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
5762
5763static Lisp_Object
5764image_spec_value (spec, key, found)
5765 Lisp_Object spec, key;
5766 int *found;
5767{
5768 Lisp_Object tail;
5769
5770 xassert (valid_image_p (spec));
5771
5772 for (tail = XCDR (spec);
5773 CONSP (tail) && CONSP (XCDR (tail));
5774 tail = XCDR (XCDR (tail)))
5775 {
5776 if (EQ (XCAR (tail), key))
5777 {
5778 if (found)
5779 *found = 1;
5780 return XCAR (XCDR (tail));
5781 }
5782 }
5783
5784 if (found)
5785 *found = 0;
5786 return Qnil;
5787}
5788
5789
42677916 5790DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
7ee72033 5791 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
c061c855
GM
5792PIXELS non-nil means return the size in pixels, otherwise return the
5793size in canonical character units.
5794FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5795or omitted means use the selected frame. */)
5796 (spec, pixels, frame)
42677916
GM
5797 Lisp_Object spec, pixels, frame;
5798{
5799 Lisp_Object size;
5800
5801 size = Qnil;
5802 if (valid_image_p (spec))
5803 {
5804 struct frame *f = check_x_frame (frame);
83676598 5805 int id = lookup_image (f, spec);
42677916 5806 struct image *img = IMAGE_FROM_ID (f, id);
3ed61e75
GM
5807 int width = img->width + 2 * img->hmargin;
5808 int height = img->height + 2 * img->vmargin;
42677916
GM
5809
5810 if (NILP (pixels))
5811 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
5812 make_float ((double) height / CANON_Y_UNIT (f)));
5813 else
5814 size = Fcons (make_number (width), make_number (height));
5815 }
5816 else
5817 error ("Invalid image specification");
5818
5819 return size;
5820}
5821
333b20bb 5822
b243755a 5823DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
7ee72033 5824 doc: /* Return t if image SPEC has a mask bitmap.
c061c855 5825FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5826or omitted means use the selected frame. */)
5827 (spec, frame)
b243755a
GM
5828 Lisp_Object spec, frame;
5829{
5830 Lisp_Object mask;
5831
5832 mask = Qnil;
5833 if (valid_image_p (spec))
5834 {
5835 struct frame *f = check_x_frame (frame);
83676598 5836 int id = lookup_image (f, spec);
b243755a
GM
5837 struct image *img = IMAGE_FROM_ID (f, id);
5838 if (img->mask)
5839 mask = Qt;
5840 }
5841 else
5842 error ("Invalid image specification");
5843
5844 return mask;
5845}
5846
5847
333b20bb
GM
5848\f
5849/***********************************************************************
5850 Image type independent image structures
5851 ***********************************************************************/
5852
5853static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
5854static void free_image P_ ((struct frame *f, struct image *img));
5855
5856
5857/* Allocate and return a new image structure for image specification
5858 SPEC. SPEC has a hash value of HASH. */
5859
5860static struct image *
5861make_image (spec, hash)
5862 Lisp_Object spec;
5863 unsigned hash;
5864{
5865 struct image *img = (struct image *) xmalloc (sizeof *img);
5866
5867 xassert (valid_image_p (spec));
5868 bzero (img, sizeof *img);
5869 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
5870 xassert (img->type != NULL);
5871 img->spec = spec;
5872 img->data.lisp_val = Qnil;
5873 img->ascent = DEFAULT_IMAGE_ASCENT;
5874 img->hash = hash;
5875 return img;
5876}
5877
5878
5879/* Free image IMG which was used on frame F, including its resources. */
5880
5881static void
5882free_image (f, img)
5883 struct frame *f;
5884 struct image *img;
5885{
5886 if (img)
5887 {
5888 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5889
5890 /* Remove IMG from the hash table of its cache. */
5891 if (img->prev)
5892 img->prev->next = img->next;
5893 else
5894 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
5895
5896 if (img->next)
5897 img->next->prev = img->prev;
5898
5899 c->images[img->id] = NULL;
5900
5901 /* Free resources, then free IMG. */
5902 img->type->free (f, img);
5903 xfree (img);
5904 }
5905}
5906
5907
5908/* Prepare image IMG for display on frame F. Must be called before
5909 drawing an image. */
5910
5911void
5912prepare_image_for_display (f, img)
5913 struct frame *f;
5914 struct image *img;
5915{
5916 EMACS_TIME t;
5917
5918 /* We're about to display IMG, so set its timestamp to `now'. */
5919 EMACS_GET_TIME (t);
5920 img->timestamp = EMACS_SECS (t);
5921
5922 /* If IMG doesn't have a pixmap yet, load it now, using the image
5923 type dependent loader function. */
dd00328a 5924 if (img->pixmap == None && !img->load_failed_p)
209061be 5925 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
5926}
5927
5928
7c7ff7f5
GM
5929/* Value is the number of pixels for the ascent of image IMG when
5930 drawn in face FACE. */
5931
5932int
5933image_ascent (img, face)
5934 struct image *img;
5935 struct face *face;
5936{
3ed61e75 5937 int height = img->height + img->vmargin;
7c7ff7f5
GM
5938 int ascent;
5939
5940 if (img->ascent == CENTERED_IMAGE_ASCENT)
5941 {
5942 if (face->font)
3694cb3f
MB
5943 /* This expression is arranged so that if the image can't be
5944 exactly centered, it will be moved slightly up. This is
5945 because a typical font is `top-heavy' (due to the presence
5946 uppercase letters), so the image placement should err towards
5947 being top-heavy too. It also just generally looks better. */
5948 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
7c7ff7f5
GM
5949 else
5950 ascent = height / 2;
5951 }
5952 else
5953 ascent = height * img->ascent / 100.0;
5954
5955 return ascent;
5956}
5957
f20a3b7a
MB
5958\f
5959/* Image background colors. */
5960
5961static unsigned long
5962four_corners_best (ximg, width, height)
5963 XImage *ximg;
5964 unsigned long width, height;
5965{
b350c2e5
GM
5966 unsigned long corners[4], best;
5967 int i, best_count;
f20a3b7a 5968
b350c2e5
GM
5969 /* Get the colors at the corners of ximg. */
5970 corners[0] = XGetPixel (ximg, 0, 0);
5971 corners[1] = XGetPixel (ximg, width - 1, 0);
5972 corners[2] = XGetPixel (ximg, width - 1, height - 1);
5973 corners[3] = XGetPixel (ximg, 0, height - 1);
f20a3b7a 5974
b350c2e5
GM
5975 /* Choose the most frequently found color as background. */
5976 for (i = best_count = 0; i < 4; ++i)
5977 {
5978 int j, n;
f20a3b7a 5979
b350c2e5
GM
5980 for (j = n = 0; j < 4; ++j)
5981 if (corners[i] == corners[j])
5982 ++n;
f20a3b7a 5983
b350c2e5
GM
5984 if (n > best_count)
5985 best = corners[i], best_count = n;
5986 }
f20a3b7a 5987
b350c2e5 5988 return best;
f20a3b7a
MB
5989}
5990
5991/* Return the `background' field of IMG. If IMG doesn't have one yet,
5992 it is guessed heuristically. If non-zero, XIMG is an existing XImage
5993 object to use for the heuristic. */
5994
5995unsigned long
5996image_background (img, f, ximg)
5997 struct image *img;
5998 struct frame *f;
5999 XImage *ximg;
6000{
6001 if (! img->background_valid)
6002 /* IMG doesn't have a background yet, try to guess a reasonable value. */
6003 {
6004 int free_ximg = !ximg;
6005
6006 if (! ximg)
6007 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
6008 0, 0, img->width, img->height, ~0, ZPixmap);
6009
6010 img->background = four_corners_best (ximg, img->width, img->height);
6011
6012 if (free_ximg)
6013 XDestroyImage (ximg);
6014
6015 img->background_valid = 1;
6016 }
6017
6018 return img->background;
6019}
6020
6021/* Return the `background_transparent' field of IMG. If IMG doesn't
6022 have one yet, it is guessed heuristically. If non-zero, MASK is an
6023 existing XImage object to use for the heuristic. */
6024
6025int
6026image_background_transparent (img, f, mask)
6027 struct image *img;
6028 struct frame *f;
6029 XImage *mask;
6030{
6031 if (! img->background_transparent_valid)
6032 /* IMG doesn't have a background yet, try to guess a reasonable value. */
6033 {
6034 if (img->mask)
6035 {
6036 int free_mask = !mask;
6037
6038 if (! mask)
6039 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
6040 0, 0, img->width, img->height, ~0, ZPixmap);
6041
6042 img->background_transparent
6043 = !four_corners_best (mask, img->width, img->height);
6044
6045 if (free_mask)
6046 XDestroyImage (mask);
6047 }
6048 else
6049 img->background_transparent = 0;
6050
6051 img->background_transparent_valid = 1;
6052 }
6053
6054 return img->background_transparent;
6055}
7c7ff7f5 6056
333b20bb
GM
6057\f
6058/***********************************************************************
6059 Helper functions for X image types
6060 ***********************************************************************/
6061
dd00328a
GM
6062static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
6063 int, int));
333b20bb
GM
6064static void x_clear_image P_ ((struct frame *f, struct image *img));
6065static unsigned long x_alloc_image_color P_ ((struct frame *f,
6066 struct image *img,
6067 Lisp_Object color_name,
6068 unsigned long dflt));
6069
dd00328a
GM
6070
6071/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
6072 free the pixmap if any. MASK_P non-zero means clear the mask
6073 pixmap if any. COLORS_P non-zero means free colors allocated for
6074 the image, if any. */
333b20bb
GM
6075
6076static void
dd00328a 6077x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
333b20bb
GM
6078 struct frame *f;
6079 struct image *img;
dd00328a 6080 int pixmap_p, mask_p, colors_p;
333b20bb 6081{
dd00328a 6082 if (pixmap_p && img->pixmap)
333b20bb 6083 {
333b20bb 6084 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 6085 img->pixmap = None;
f20a3b7a 6086 img->background_valid = 0;
f4779de9
GM
6087 }
6088
dd00328a 6089 if (mask_p && img->mask)
f4779de9
GM
6090 {
6091 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 6092 img->mask = None;
f20a3b7a 6093 img->background_transparent_valid = 0;
333b20bb
GM
6094 }
6095
dd00328a 6096 if (colors_p && img->ncolors)
333b20bb 6097 {
462d5d40 6098 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
6099 xfree (img->colors);
6100 img->colors = NULL;
6101 img->ncolors = 0;
6102 }
dd00328a
GM
6103}
6104
6105/* Free X resources of image IMG which is used on frame F. */
6106
6107static void
6108x_clear_image (f, img)
6109 struct frame *f;
6110 struct image *img;
6111{
6112 BLOCK_INPUT;
6113 x_clear_image_1 (f, img, 1, 1, 1);
f4779de9 6114 UNBLOCK_INPUT;
333b20bb
GM
6115}
6116
6117
6118/* Allocate color COLOR_NAME for image IMG on frame F. If color
6119 cannot be allocated, use DFLT. Add a newly allocated color to
6120 IMG->colors, so that it can be freed again. Value is the pixel
6121 color. */
6122
6123static unsigned long
6124x_alloc_image_color (f, img, color_name, dflt)
6125 struct frame *f;
6126 struct image *img;
6127 Lisp_Object color_name;
6128 unsigned long dflt;
6129{
6130 XColor color;
6131 unsigned long result;
6132
6133 xassert (STRINGP (color_name));
6134
2d764c78 6135 if (x_defined_color (f, XSTRING (color_name)->data, &color, 1))
333b20bb
GM
6136 {
6137 /* This isn't called frequently so we get away with simply
6138 reallocating the color vector to the needed size, here. */
6139 ++img->ncolors;
6140 img->colors =
6141 (unsigned long *) xrealloc (img->colors,
6142 img->ncolors * sizeof *img->colors);
6143 img->colors[img->ncolors - 1] = color.pixel;
6144 result = color.pixel;
6145 }
6146 else
6147 result = dflt;
6148
6149 return result;
6150}
6151
6152
6153\f
6154/***********************************************************************
6155 Image Cache
6156 ***********************************************************************/
6157
6158static void cache_image P_ ((struct frame *f, struct image *img));
ad18ffb1 6159static void postprocess_image P_ ((struct frame *, struct image *));
333b20bb
GM
6160
6161
6162/* Return a new, initialized image cache that is allocated from the
6163 heap. Call free_image_cache to free an image cache. */
6164
6165struct image_cache *
6166make_image_cache ()
6167{
6168 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
6169 int size;
6170
6171 bzero (c, sizeof *c);
6172 c->size = 50;
6173 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
6174 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
6175 c->buckets = (struct image **) xmalloc (size);
6176 bzero (c->buckets, size);
6177 return c;
6178}
6179
6180
6181/* Free image cache of frame F. Be aware that X frames share images
6182 caches. */
6183
6184void
6185free_image_cache (f)
6186 struct frame *f;
6187{
6188 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6189 if (c)
6190 {
6191 int i;
6192
6193 /* Cache should not be referenced by any frame when freed. */
6194 xassert (c->refcount == 0);
6195
6196 for (i = 0; i < c->used; ++i)
6197 free_image (f, c->images[i]);
6198 xfree (c->images);
333b20bb 6199 xfree (c->buckets);
e3130015 6200 xfree (c);
333b20bb
GM
6201 FRAME_X_IMAGE_CACHE (f) = NULL;
6202 }
6203}
6204
6205
6206/* Clear image cache of frame F. FORCE_P non-zero means free all
6207 images. FORCE_P zero means clear only images that haven't been
6208 displayed for some time. Should be called from time to time to
6209 reduce the number of loaded images. If image-eviction-seconds is
6210 non-nil, this frees images in the cache which weren't displayed for
6211 at least that many seconds. */
6212
6213void
6214clear_image_cache (f, force_p)
6215 struct frame *f;
6216 int force_p;
6217{
6218 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6219
83676598 6220 if (c && INTEGERP (Vimage_cache_eviction_delay))
333b20bb
GM
6221 {
6222 EMACS_TIME t;
6223 unsigned long old;
f4779de9 6224 int i, nfreed;
333b20bb
GM
6225
6226 EMACS_GET_TIME (t);
fcf431dc 6227 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
f4779de9
GM
6228
6229 /* Block input so that we won't be interrupted by a SIGIO
6230 while being in an inconsistent state. */
6231 BLOCK_INPUT;
333b20bb 6232
f4779de9 6233 for (i = nfreed = 0; i < c->used; ++i)
333b20bb
GM
6234 {
6235 struct image *img = c->images[i];
6236 if (img != NULL
f4779de9 6237 && (force_p || img->timestamp < old))
333b20bb
GM
6238 {
6239 free_image (f, img);
f4779de9 6240 ++nfreed;
333b20bb
GM
6241 }
6242 }
6243
6244 /* We may be clearing the image cache because, for example,
6245 Emacs was iconified for a longer period of time. In that
6246 case, current matrices may still contain references to
6247 images freed above. So, clear these matrices. */
f4779de9 6248 if (nfreed)
333b20bb 6249 {
f4779de9
GM
6250 Lisp_Object tail, frame;
6251
6252 FOR_EACH_FRAME (tail, frame)
6253 {
6254 struct frame *f = XFRAME (frame);
6255 if (FRAME_X_P (f)
6256 && FRAME_X_IMAGE_CACHE (f) == c)
83676598 6257 clear_current_matrices (f);
f4779de9
GM
6258 }
6259
333b20bb
GM
6260 ++windows_or_buffers_changed;
6261 }
f4779de9
GM
6262
6263 UNBLOCK_INPUT;
333b20bb
GM
6264 }
6265}
6266
6267
6268DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6269 0, 1, 0,
7ee72033 6270 doc: /* Clear the image cache of FRAME.
c061c855 6271FRAME nil or omitted means use the selected frame.
7ee72033
MB
6272FRAME t means clear the image caches of all frames. */)
6273 (frame)
333b20bb
GM
6274 Lisp_Object frame;
6275{
6276 if (EQ (frame, Qt))
6277 {
6278 Lisp_Object tail;
6279
6280 FOR_EACH_FRAME (tail, frame)
6281 if (FRAME_X_P (XFRAME (frame)))
6282 clear_image_cache (XFRAME (frame), 1);
6283 }
6284 else
6285 clear_image_cache (check_x_frame (frame), 1);
6286
6287 return Qnil;
6288}
6289
6290
ad18ffb1
GM
6291/* Compute masks and transform image IMG on frame F, as specified
6292 by the image's specification, */
6293
6294static void
6295postprocess_image (f, img)
6296 struct frame *f;
6297 struct image *img;
6298{
6299 /* Manipulation of the image's mask. */
6300 if (img->pixmap)
6301 {
6302 Lisp_Object conversion, spec;
6303 Lisp_Object mask;
6304
6305 spec = img->spec;
6306
6307 /* `:heuristic-mask t'
6308 `:mask heuristic'
6309 means build a mask heuristically.
6310 `:heuristic-mask (R G B)'
6311 `:mask (heuristic (R G B))'
6312 means build a mask from color (R G B) in the
6313 image.
6314 `:mask nil'
6315 means remove a mask, if any. */
6316
6317 mask = image_spec_value (spec, QCheuristic_mask, NULL);
6318 if (!NILP (mask))
6319 x_build_heuristic_mask (f, img, mask);
6320 else
6321 {
6322 int found_p;
6323
6324 mask = image_spec_value (spec, QCmask, &found_p);
6325
6326 if (EQ (mask, Qheuristic))
6327 x_build_heuristic_mask (f, img, Qt);
6328 else if (CONSP (mask)
6329 && EQ (XCAR (mask), Qheuristic))
6330 {
6331 if (CONSP (XCDR (mask)))
6332 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
6333 else
6334 x_build_heuristic_mask (f, img, XCDR (mask));
6335 }
6336 else if (NILP (mask) && found_p && img->mask)
6337 {
6338 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6339 img->mask = None;
6340 }
6341 }
6342
6343
6344 /* Should we apply an image transformation algorithm? */
6345 conversion = image_spec_value (spec, QCconversion, NULL);
6346 if (EQ (conversion, Qdisabled))
6347 x_disable_image (f, img);
6348 else if (EQ (conversion, Qlaplace))
6349 x_laplace (f, img);
6350 else if (EQ (conversion, Qemboss))
6351 x_emboss (f, img);
6352 else if (CONSP (conversion)
6353 && EQ (XCAR (conversion), Qedge_detection))
6354 {
6355 Lisp_Object tem;
6356 tem = XCDR (conversion);
6357 if (CONSP (tem))
6358 x_edge_detection (f, img,
6359 Fplist_get (tem, QCmatrix),
6360 Fplist_get (tem, QCcolor_adjustment));
6361 }
6362 }
6363}
6364
6365
333b20bb 6366/* Return the id of image with Lisp specification SPEC on frame F.
83676598 6367 SPEC must be a valid Lisp image specification (see valid_image_p). */
333b20bb
GM
6368
6369int
83676598 6370lookup_image (f, spec)
333b20bb
GM
6371 struct frame *f;
6372 Lisp_Object spec;
6373{
6374 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6375 struct image *img;
6376 int i;
6377 unsigned hash;
6378 struct gcpro gcpro1;
4f7ca1f1 6379 EMACS_TIME now;
333b20bb
GM
6380
6381 /* F must be a window-system frame, and SPEC must be a valid image
6382 specification. */
6383 xassert (FRAME_WINDOW_P (f));
6384 xassert (valid_image_p (spec));
6385
6386 GCPRO1 (spec);
6387
6388 /* Look up SPEC in the hash table of the image cache. */
6389 hash = sxhash (spec, 0);
6390 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6391
6392 for (img = c->buckets[i]; img; img = img->next)
6393 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6394 break;
6395
6396 /* If not found, create a new image and cache it. */
6397 if (img == NULL)
6398 {
ad18ffb1
GM
6399 extern Lisp_Object Qpostscript;
6400
28c7826c 6401 BLOCK_INPUT;
333b20bb
GM
6402 img = make_image (spec, hash);
6403 cache_image (f, img);
83676598 6404 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
6405
6406 /* If we can't load the image, and we don't have a width and
6407 height, use some arbitrary width and height so that we can
6408 draw a rectangle for it. */
83676598 6409 if (img->load_failed_p)
333b20bb
GM
6410 {
6411 Lisp_Object value;
6412
6413 value = image_spec_value (spec, QCwidth, NULL);
6414 img->width = (INTEGERP (value)
6415 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6416 value = image_spec_value (spec, QCheight, NULL);
6417 img->height = (INTEGERP (value)
6418 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6419 }
6420 else
6421 {
6422 /* Handle image type independent image attributes
f20a3b7a
MB
6423 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
6424 `:background COLOR'. */
6425 Lisp_Object ascent, margin, relief, bg;
333b20bb
GM
6426
6427 ascent = image_spec_value (spec, QCascent, NULL);
6428 if (INTEGERP (ascent))
6429 img->ascent = XFASTINT (ascent);
7c7ff7f5
GM
6430 else if (EQ (ascent, Qcenter))
6431 img->ascent = CENTERED_IMAGE_ASCENT;
333b20bb
GM
6432
6433 margin = image_spec_value (spec, QCmargin, NULL);
6434 if (INTEGERP (margin) && XINT (margin) >= 0)
3ed61e75
GM
6435 img->vmargin = img->hmargin = XFASTINT (margin);
6436 else if (CONSP (margin) && INTEGERP (XCAR (margin))
6437 && INTEGERP (XCDR (margin)))
6438 {
6439 if (XINT (XCAR (margin)) > 0)
6440 img->hmargin = XFASTINT (XCAR (margin));
6441 if (XINT (XCDR (margin)) > 0)
6442 img->vmargin = XFASTINT (XCDR (margin));
6443 }
333b20bb
GM
6444
6445 relief = image_spec_value (spec, QCrelief, NULL);
6446 if (INTEGERP (relief))
6447 {
6448 img->relief = XINT (relief);
3ed61e75
GM
6449 img->hmargin += abs (img->relief);
6450 img->vmargin += abs (img->relief);
333b20bb
GM
6451 }
6452
f20a3b7a
MB
6453 if (! img->background_valid)
6454 {
6455 bg = image_spec_value (img->spec, QCbackground, NULL);
6456 if (!NILP (bg))
6457 {
6458 img->background
6459 = x_alloc_image_color (f, img, bg,
6460 FRAME_BACKGROUND_PIXEL (f));
6461 img->background_valid = 1;
6462 }
6463 }
6464
ad18ffb1
GM
6465 /* Do image transformations and compute masks, unless we
6466 don't have the image yet. */
6467 if (!EQ (*img->type->type, Qpostscript))
6468 postprocess_image (f, img);
333b20bb 6469 }
dd00328a 6470
28c7826c
GM
6471 UNBLOCK_INPUT;
6472 xassert (!interrupt_input_blocked);
333b20bb
GM
6473 }
6474
4f7ca1f1
GM
6475 /* We're using IMG, so set its timestamp to `now'. */
6476 EMACS_GET_TIME (now);
6477 img->timestamp = EMACS_SECS (now);
6478
333b20bb
GM
6479 UNGCPRO;
6480
6481 /* Value is the image id. */
6482 return img->id;
6483}
6484
6485
6486/* Cache image IMG in the image cache of frame F. */
6487
6488static void
6489cache_image (f, img)
6490 struct frame *f;
6491 struct image *img;
6492{
6493 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6494 int i;
6495
6496 /* Find a free slot in c->images. */
6497 for (i = 0; i < c->used; ++i)
6498 if (c->images[i] == NULL)
6499 break;
6500
6501 /* If no free slot found, maybe enlarge c->images. */
6502 if (i == c->used && c->used == c->size)
6503 {
6504 c->size *= 2;
6505 c->images = (struct image **) xrealloc (c->images,
6506 c->size * sizeof *c->images);
6507 }
6508
6509 /* Add IMG to c->images, and assign IMG an id. */
6510 c->images[i] = img;
6511 img->id = i;
6512 if (i == c->used)
6513 ++c->used;
6514
6515 /* Add IMG to the cache's hash table. */
6516 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6517 img->next = c->buckets[i];
6518 if (img->next)
6519 img->next->prev = img;
6520 img->prev = NULL;
6521 c->buckets[i] = img;
6522}
6523
6524
6525/* Call FN on every image in the image cache of frame F. Used to mark
6526 Lisp Objects in the image cache. */
6527
6528void
6529forall_images_in_image_cache (f, fn)
6530 struct frame *f;
6531 void (*fn) P_ ((struct image *img));
6532{
6533 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6534 {
6535 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6536 if (c)
6537 {
6538 int i;
6539 for (i = 0; i < c->used; ++i)
6540 if (c->images[i])
6541 fn (c->images[i]);
6542 }
6543 }
6544}
6545
6546
6547\f
6548/***********************************************************************
6549 X support code
6550 ***********************************************************************/
6551
45158a91
GM
6552static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
6553 XImage **, Pixmap *));
333b20bb
GM
6554static void x_destroy_x_image P_ ((XImage *));
6555static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6556
6557
6558/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6559 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6560 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6561 via xmalloc. Print error messages via image_error if an error
45158a91 6562 occurs. Value is non-zero if successful. */
333b20bb
GM
6563
6564static int
45158a91 6565x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
333b20bb 6566 struct frame *f;
333b20bb
GM
6567 int width, height, depth;
6568 XImage **ximg;
6569 Pixmap *pixmap;
6570{
6571 Display *display = FRAME_X_DISPLAY (f);
6572 Screen *screen = FRAME_X_SCREEN (f);
6573 Window window = FRAME_X_WINDOW (f);
6574
6575 xassert (interrupt_input_blocked);
6576
6577 if (depth <= 0)
6578 depth = DefaultDepthOfScreen (screen);
6579 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6580 depth, ZPixmap, 0, NULL, width, height,
6581 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6582 if (*ximg == NULL)
6583 {
45158a91 6584 image_error ("Unable to allocate X image", Qnil, Qnil);
333b20bb
GM
6585 return 0;
6586 }
6587
6588 /* Allocate image raster. */
6589 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6590
6591 /* Allocate a pixmap of the same size. */
6592 *pixmap = XCreatePixmap (display, window, width, height, depth);
dd00328a 6593 if (*pixmap == None)
333b20bb
GM
6594 {
6595 x_destroy_x_image (*ximg);
6596 *ximg = NULL;
45158a91 6597 image_error ("Unable to create X pixmap", Qnil, Qnil);
333b20bb
GM
6598 return 0;
6599 }
6600
6601 return 1;
6602}
6603
6604
6605/* Destroy XImage XIMG. Free XIMG->data. */
6606
6607static void
6608x_destroy_x_image (ximg)
6609 XImage *ximg;
6610{
6611 xassert (interrupt_input_blocked);
6612 if (ximg)
6613 {
6614 xfree (ximg->data);
6615 ximg->data = NULL;
6616 XDestroyImage (ximg);
6617 }
6618}
6619
6620
6621/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6622 are width and height of both the image and pixmap. */
6623
ea6b19ca 6624static void
333b20bb
GM
6625x_put_x_image (f, ximg, pixmap, width, height)
6626 struct frame *f;
6627 XImage *ximg;
6628 Pixmap pixmap;
6629{
6630 GC gc;
6631
6632 xassert (interrupt_input_blocked);
6633 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6634 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6635 XFreeGC (FRAME_X_DISPLAY (f), gc);
6636}
6637
6638
6639\f
6640/***********************************************************************
5be6c3b0 6641 File Handling
333b20bb
GM
6642 ***********************************************************************/
6643
6644static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5be6c3b0
GM
6645static char *slurp_file P_ ((char *, int *));
6646
333b20bb
GM
6647
6648/* Find image file FILE. Look in data-directory, then
6649 x-bitmap-file-path. Value is the full name of the file found, or
6650 nil if not found. */
6651
6652static Lisp_Object
6653x_find_image_file (file)
6654 Lisp_Object file;
6655{
6656 Lisp_Object file_found, search_path;
6657 struct gcpro gcpro1, gcpro2;
6658 int fd;
6659
6660 file_found = Qnil;
6661 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6662 GCPRO2 (file_found, search_path);
6663
6664 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 6665 fd = openp (search_path, file, Qnil, &file_found, 0);
333b20bb 6666
939d6465 6667 if (fd == -1)
333b20bb
GM
6668 file_found = Qnil;
6669 else
6670 close (fd);
6671
6672 UNGCPRO;
6673 return file_found;
6674}
6675
6676
5be6c3b0
GM
6677/* Read FILE into memory. Value is a pointer to a buffer allocated
6678 with xmalloc holding FILE's contents. Value is null if an error
b243755a 6679 occurred. *SIZE is set to the size of the file. */
5be6c3b0
GM
6680
6681static char *
6682slurp_file (file, size)
6683 char *file;
6684 int *size;
6685{
6686 FILE *fp = NULL;
6687 char *buf = NULL;
6688 struct stat st;
6689
6690 if (stat (file, &st) == 0
6691 && (fp = fopen (file, "r")) != NULL
6692 && (buf = (char *) xmalloc (st.st_size),
6693 fread (buf, 1, st.st_size, fp) == st.st_size))
6694 {
6695 *size = st.st_size;
6696 fclose (fp);
6697 }
6698 else
6699 {
6700 if (fp)
6701 fclose (fp);
6702 if (buf)
6703 {
6704 xfree (buf);
6705 buf = NULL;
6706 }
6707 }
6708
6709 return buf;
6710}
6711
6712
333b20bb
GM
6713\f
6714/***********************************************************************
6715 XBM images
6716 ***********************************************************************/
6717
5be6c3b0 6718static int xbm_scan P_ ((char **, char *, char *, int *));
333b20bb 6719static int xbm_load P_ ((struct frame *f, struct image *img));
5be6c3b0
GM
6720static int xbm_load_image P_ ((struct frame *f, struct image *img,
6721 char *, char *));
333b20bb 6722static int xbm_image_p P_ ((Lisp_Object object));
5be6c3b0
GM
6723static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
6724 unsigned char **));
6725static int xbm_file_p P_ ((Lisp_Object));
333b20bb
GM
6726
6727
6728/* Indices of image specification fields in xbm_format, below. */
6729
6730enum xbm_keyword_index
6731{
6732 XBM_TYPE,
6733 XBM_FILE,
6734 XBM_WIDTH,
6735 XBM_HEIGHT,
6736 XBM_DATA,
6737 XBM_FOREGROUND,
6738 XBM_BACKGROUND,
6739 XBM_ASCENT,
6740 XBM_MARGIN,
6741 XBM_RELIEF,
6742 XBM_ALGORITHM,
6743 XBM_HEURISTIC_MASK,
4a8e312c 6744 XBM_MASK,
333b20bb
GM
6745 XBM_LAST
6746};
6747
6748/* Vector of image_keyword structures describing the format
6749 of valid XBM image specifications. */
6750
6751static struct image_keyword xbm_format[XBM_LAST] =
6752{
6753 {":type", IMAGE_SYMBOL_VALUE, 1},
6754 {":file", IMAGE_STRING_VALUE, 0},
6755 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6756 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6757 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
6758 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6759 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
7c7ff7f5 6760 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 6761 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 6762 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 6763 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
6764 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6765 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
6766};
6767
6768/* Structure describing the image type XBM. */
6769
6770static struct image_type xbm_type =
6771{
6772 &Qxbm,
6773 xbm_image_p,
6774 xbm_load,
6775 x_clear_image,
6776 NULL
6777};
6778
6779/* Tokens returned from xbm_scan. */
6780
6781enum xbm_token
6782{
6783 XBM_TK_IDENT = 256,
6784 XBM_TK_NUMBER
6785};
6786
6787
6788/* Return non-zero if OBJECT is a valid XBM-type image specification.
6789 A valid specification is a list starting with the symbol `image'
6790 The rest of the list is a property list which must contain an
6791 entry `:type xbm..
6792
6793 If the specification specifies a file to load, it must contain
6794 an entry `:file FILENAME' where FILENAME is a string.
6795
6796 If the specification is for a bitmap loaded from memory it must
6797 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6798 WIDTH and HEIGHT are integers > 0. DATA may be:
6799
6800 1. a string large enough to hold the bitmap data, i.e. it must
6801 have a size >= (WIDTH + 7) / 8 * HEIGHT
6802
6803 2. a bool-vector of size >= WIDTH * HEIGHT
6804
6805 3. a vector of strings or bool-vectors, one for each line of the
6806 bitmap.
6807
5be6c3b0
GM
6808 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
6809 may not be specified in this case because they are defined in the
6810 XBM file.
6811
333b20bb
GM
6812 Both the file and data forms may contain the additional entries
6813 `:background COLOR' and `:foreground COLOR'. If not present,
6814 foreground and background of the frame on which the image is
e3130015 6815 displayed is used. */
333b20bb
GM
6816
6817static int
6818xbm_image_p (object)
6819 Lisp_Object object;
6820{
6821 struct image_keyword kw[XBM_LAST];
6822
6823 bcopy (xbm_format, kw, sizeof kw);
bfd2209f 6824 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
333b20bb
GM
6825 return 0;
6826
6827 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6828
6829 if (kw[XBM_FILE].count)
6830 {
6831 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6832 return 0;
6833 }
5be6c3b0
GM
6834 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
6835 {
6836 /* In-memory XBM file. */
6837 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
6838 return 0;
6839 }
333b20bb
GM
6840 else
6841 {
6842 Lisp_Object data;
6843 int width, height;
6844
6845 /* Entries for `:width', `:height' and `:data' must be present. */
6846 if (!kw[XBM_WIDTH].count
6847 || !kw[XBM_HEIGHT].count
6848 || !kw[XBM_DATA].count)
6849 return 0;
6850
6851 data = kw[XBM_DATA].value;
6852 width = XFASTINT (kw[XBM_WIDTH].value);
6853 height = XFASTINT (kw[XBM_HEIGHT].value);
6854
6855 /* Check type of data, and width and height against contents of
6856 data. */
6857 if (VECTORP (data))
6858 {
6859 int i;
6860
6861 /* Number of elements of the vector must be >= height. */
6862 if (XVECTOR (data)->size < height)
6863 return 0;
6864
6865 /* Each string or bool-vector in data must be large enough
6866 for one line of the image. */
6867 for (i = 0; i < height; ++i)
6868 {
6869 Lisp_Object elt = XVECTOR (data)->contents[i];
6870
6871 if (STRINGP (elt))
6872 {
6873 if (XSTRING (elt)->size
6874 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6875 return 0;
6876 }
6877 else if (BOOL_VECTOR_P (elt))
6878 {
6879 if (XBOOL_VECTOR (elt)->size < width)
6880 return 0;
6881 }
6882 else
6883 return 0;
6884 }
6885 }
6886 else if (STRINGP (data))
6887 {
6888 if (XSTRING (data)->size
6889 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6890 return 0;
6891 }
6892 else if (BOOL_VECTOR_P (data))
6893 {
6894 if (XBOOL_VECTOR (data)->size < width * height)
6895 return 0;
6896 }
6897 else
6898 return 0;
6899 }
6900
333b20bb
GM
6901 return 1;
6902}
6903
6904
6905/* Scan a bitmap file. FP is the stream to read from. Value is
6906 either an enumerator from enum xbm_token, or a character for a
6907 single-character token, or 0 at end of file. If scanning an
6908 identifier, store the lexeme of the identifier in SVAL. If
6909 scanning a number, store its value in *IVAL. */
6910
6911static int
5be6c3b0
GM
6912xbm_scan (s, end, sval, ival)
6913 char **s, *end;
333b20bb
GM
6914 char *sval;
6915 int *ival;
6916{
6917 int c;
0a695da7
GM
6918
6919 loop:
333b20bb
GM
6920
6921 /* Skip white space. */
5be6c3b0 6922 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
6923 ;
6924
5be6c3b0 6925 if (*s >= end)
333b20bb
GM
6926 c = 0;
6927 else if (isdigit (c))
6928 {
6929 int value = 0, digit;
6930
5be6c3b0 6931 if (c == '0' && *s < end)
333b20bb 6932 {
5be6c3b0 6933 c = *(*s)++;
333b20bb
GM
6934 if (c == 'x' || c == 'X')
6935 {
5be6c3b0 6936 while (*s < end)
333b20bb 6937 {
5be6c3b0 6938 c = *(*s)++;
333b20bb
GM
6939 if (isdigit (c))
6940 digit = c - '0';
6941 else if (c >= 'a' && c <= 'f')
6942 digit = c - 'a' + 10;
6943 else if (c >= 'A' && c <= 'F')
6944 digit = c - 'A' + 10;
6945 else
6946 break;
6947 value = 16 * value + digit;
6948 }
6949 }
6950 else if (isdigit (c))
6951 {
6952 value = c - '0';
5be6c3b0
GM
6953 while (*s < end
6954 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6955 value = 8 * value + c - '0';
6956 }
6957 }
6958 else
6959 {
6960 value = c - '0';
5be6c3b0
GM
6961 while (*s < end
6962 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6963 value = 10 * value + c - '0';
6964 }
6965
5be6c3b0
GM
6966 if (*s < end)
6967 *s = *s - 1;
333b20bb
GM
6968 *ival = value;
6969 c = XBM_TK_NUMBER;
6970 }
6971 else if (isalpha (c) || c == '_')
6972 {
6973 *sval++ = c;
5be6c3b0
GM
6974 while (*s < end
6975 && (c = *(*s)++, (isalnum (c) || c == '_')))
333b20bb
GM
6976 *sval++ = c;
6977 *sval = 0;
5be6c3b0
GM
6978 if (*s < end)
6979 *s = *s - 1;
333b20bb
GM
6980 c = XBM_TK_IDENT;
6981 }
0a695da7
GM
6982 else if (c == '/' && **s == '*')
6983 {
6984 /* C-style comment. */
6985 ++*s;
6986 while (**s && (**s != '*' || *(*s + 1) != '/'))
6987 ++*s;
6988 if (**s)
6989 {
6990 *s += 2;
6991 goto loop;
6992 }
6993 }
333b20bb
GM
6994
6995 return c;
6996}
6997
6998
6999/* Replacement for XReadBitmapFileData which isn't available under old
5be6c3b0
GM
7000 X versions. CONTENTS is a pointer to a buffer to parse; END is the
7001 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
7002 the image. Return in *DATA the bitmap data allocated with xmalloc.
7003 Value is non-zero if successful. DATA null means just test if
b243755a 7004 CONTENTS looks like an in-memory XBM file. */
333b20bb
GM
7005
7006static int
5be6c3b0
GM
7007xbm_read_bitmap_data (contents, end, width, height, data)
7008 char *contents, *end;
333b20bb
GM
7009 int *width, *height;
7010 unsigned char **data;
7011{
5be6c3b0 7012 char *s = contents;
333b20bb
GM
7013 char buffer[BUFSIZ];
7014 int padding_p = 0;
7015 int v10 = 0;
7016 int bytes_per_line, i, nbytes;
7017 unsigned char *p;
7018 int value;
7019 int LA1;
7020
7021#define match() \
5be6c3b0 7022 LA1 = xbm_scan (&s, end, buffer, &value)
333b20bb
GM
7023
7024#define expect(TOKEN) \
7025 if (LA1 != (TOKEN)) \
7026 goto failure; \
7027 else \
7028 match ()
7029
7030#define expect_ident(IDENT) \
7031 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
7032 match (); \
7033 else \
7034 goto failure
7035
333b20bb 7036 *width = *height = -1;
5be6c3b0
GM
7037 if (data)
7038 *data = NULL;
7039 LA1 = xbm_scan (&s, end, buffer, &value);
333b20bb
GM
7040
7041 /* Parse defines for width, height and hot-spots. */
7042 while (LA1 == '#')
7043 {
333b20bb
GM
7044 match ();
7045 expect_ident ("define");
7046 expect (XBM_TK_IDENT);
7047
7048 if (LA1 == XBM_TK_NUMBER);
7049 {
7050 char *p = strrchr (buffer, '_');
7051 p = p ? p + 1 : buffer;
7052 if (strcmp (p, "width") == 0)
7053 *width = value;
7054 else if (strcmp (p, "height") == 0)
7055 *height = value;
7056 }
7057 expect (XBM_TK_NUMBER);
7058 }
7059
7060 if (*width < 0 || *height < 0)
7061 goto failure;
5be6c3b0
GM
7062 else if (data == NULL)
7063 goto success;
333b20bb
GM
7064
7065 /* Parse bits. Must start with `static'. */
7066 expect_ident ("static");
7067 if (LA1 == XBM_TK_IDENT)
7068 {
7069 if (strcmp (buffer, "unsigned") == 0)
7070 {
7071 match ();
7072 expect_ident ("char");
7073 }
7074 else if (strcmp (buffer, "short") == 0)
7075 {
7076 match ();
7077 v10 = 1;
7078 if (*width % 16 && *width % 16 < 9)
7079 padding_p = 1;
7080 }
7081 else if (strcmp (buffer, "char") == 0)
7082 match ();
7083 else
7084 goto failure;
7085 }
7086 else
7087 goto failure;
7088
7089 expect (XBM_TK_IDENT);
7090 expect ('[');
7091 expect (']');
7092 expect ('=');
7093 expect ('{');
7094
7095 bytes_per_line = (*width + 7) / 8 + padding_p;
7096 nbytes = bytes_per_line * *height;
7097 p = *data = (char *) xmalloc (nbytes);
7098
7099 if (v10)
7100 {
333b20bb
GM
7101 for (i = 0; i < nbytes; i += 2)
7102 {
7103 int val = value;
7104 expect (XBM_TK_NUMBER);
7105
7106 *p++ = val;
7107 if (!padding_p || ((i + 2) % bytes_per_line))
7108 *p++ = value >> 8;
7109
7110 if (LA1 == ',' || LA1 == '}')
7111 match ();
7112 else
7113 goto failure;
7114 }
7115 }
7116 else
7117 {
7118 for (i = 0; i < nbytes; ++i)
7119 {
7120 int val = value;
7121 expect (XBM_TK_NUMBER);
7122
7123 *p++ = val;
7124
7125 if (LA1 == ',' || LA1 == '}')
7126 match ();
7127 else
7128 goto failure;
7129 }
7130 }
7131
5be6c3b0 7132 success:
333b20bb
GM
7133 return 1;
7134
7135 failure:
7136
5be6c3b0 7137 if (data && *data)
333b20bb
GM
7138 {
7139 xfree (*data);
7140 *data = NULL;
7141 }
7142 return 0;
7143
7144#undef match
7145#undef expect
7146#undef expect_ident
7147}
7148
7149
5be6c3b0
GM
7150/* Load XBM image IMG which will be displayed on frame F from buffer
7151 CONTENTS. END is the end of the buffer. Value is non-zero if
7152 successful. */
333b20bb
GM
7153
7154static int
5be6c3b0 7155xbm_load_image (f, img, contents, end)
333b20bb
GM
7156 struct frame *f;
7157 struct image *img;
5be6c3b0 7158 char *contents, *end;
333b20bb
GM
7159{
7160 int rc;
7161 unsigned char *data;
7162 int success_p = 0;
333b20bb 7163
5be6c3b0 7164 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
333b20bb
GM
7165 if (rc)
7166 {
7167 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7168 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7169 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7170 Lisp_Object value;
7171
7172 xassert (img->width > 0 && img->height > 0);
7173
7174 /* Get foreground and background colors, maybe allocate colors. */
7175 value = image_spec_value (img->spec, QCforeground, NULL);
7176 if (!NILP (value))
7177 foreground = x_alloc_image_color (f, img, value, foreground);
333b20bb
GM
7178 value = image_spec_value (img->spec, QCbackground, NULL);
7179 if (!NILP (value))
f20a3b7a
MB
7180 {
7181 background = x_alloc_image_color (f, img, value, background);
7182 img->background = background;
7183 img->background_valid = 1;
7184 }
333b20bb 7185
333b20bb
GM
7186 img->pixmap
7187 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7188 FRAME_X_WINDOW (f),
7189 data,
7190 img->width, img->height,
7191 foreground, background,
7192 depth);
7193 xfree (data);
7194
dd00328a 7195 if (img->pixmap == None)
333b20bb
GM
7196 {
7197 x_clear_image (f, img);
5be6c3b0 7198 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
7199 }
7200 else
7201 success_p = 1;
333b20bb
GM
7202 }
7203 else
45158a91 7204 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
333b20bb 7205
333b20bb
GM
7206 return success_p;
7207}
7208
7209
5be6c3b0
GM
7210/* Value is non-zero if DATA looks like an in-memory XBM file. */
7211
7212static int
7213xbm_file_p (data)
7214 Lisp_Object data;
7215{
7216 int w, h;
7217 return (STRINGP (data)
7218 && xbm_read_bitmap_data (XSTRING (data)->data,
7219 (XSTRING (data)->data
7220 + STRING_BYTES (XSTRING (data))),
7221 &w, &h, NULL));
7222}
7223
7224
333b20bb
GM
7225/* Fill image IMG which is used on frame F with pixmap data. Value is
7226 non-zero if successful. */
7227
7228static int
7229xbm_load (f, img)
7230 struct frame *f;
7231 struct image *img;
7232{
7233 int success_p = 0;
7234 Lisp_Object file_name;
7235
7236 xassert (xbm_image_p (img->spec));
7237
7238 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7239 file_name = image_spec_value (img->spec, QCfile, NULL);
7240 if (STRINGP (file_name))
5be6c3b0
GM
7241 {
7242 Lisp_Object file;
7243 char *contents;
7244 int size;
7245 struct gcpro gcpro1;
7246
7247 file = x_find_image_file (file_name);
7248 GCPRO1 (file);
7249 if (!STRINGP (file))
7250 {
7251 image_error ("Cannot find image file `%s'", file_name, Qnil);
7252 UNGCPRO;
7253 return 0;
7254 }
7255
7256 contents = slurp_file (XSTRING (file)->data, &size);
7257 if (contents == NULL)
7258 {
7259 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7260 UNGCPRO;
7261 return 0;
7262 }
7263
7264 success_p = xbm_load_image (f, img, contents, contents + size);
7265 UNGCPRO;
7266 }
333b20bb
GM
7267 else
7268 {
7269 struct image_keyword fmt[XBM_LAST];
7270 Lisp_Object data;
7271 int depth;
7272 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7273 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7274 char *bits;
9b207e8e 7275 int parsed_p;
5be6c3b0
GM
7276 int in_memory_file_p = 0;
7277
7278 /* See if data looks like an in-memory XBM file. */
7279 data = image_spec_value (img->spec, QCdata, NULL);
7280 in_memory_file_p = xbm_file_p (data);
333b20bb 7281
5be6c3b0 7282 /* Parse the image specification. */
333b20bb 7283 bcopy (xbm_format, fmt, sizeof fmt);
bfd2209f 7284 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
333b20bb
GM
7285 xassert (parsed_p);
7286
7287 /* Get specified width, and height. */
5be6c3b0
GM
7288 if (!in_memory_file_p)
7289 {
7290 img->width = XFASTINT (fmt[XBM_WIDTH].value);
7291 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
7292 xassert (img->width > 0 && img->height > 0);
7293 }
333b20bb 7294
333b20bb 7295 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
7296 if (fmt[XBM_FOREGROUND].count
7297 && STRINGP (fmt[XBM_FOREGROUND].value))
333b20bb
GM
7298 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
7299 foreground);
6f1be3b9
GM
7300 if (fmt[XBM_BACKGROUND].count
7301 && STRINGP (fmt[XBM_BACKGROUND].value))
333b20bb
GM
7302 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
7303 background);
7304
5be6c3b0
GM
7305 if (in_memory_file_p)
7306 success_p = xbm_load_image (f, img, XSTRING (data)->data,
7307 (XSTRING (data)->data
7308 + STRING_BYTES (XSTRING (data))));
7309 else
333b20bb 7310 {
5be6c3b0
GM
7311 if (VECTORP (data))
7312 {
7313 int i;
7314 char *p;
7315 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
333b20bb 7316
5be6c3b0
GM
7317 p = bits = (char *) alloca (nbytes * img->height);
7318 for (i = 0; i < img->height; ++i, p += nbytes)
7319 {
7320 Lisp_Object line = XVECTOR (data)->contents[i];
7321 if (STRINGP (line))
7322 bcopy (XSTRING (line)->data, p, nbytes);
7323 else
7324 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
7325 }
7326 }
7327 else if (STRINGP (data))
7328 bits = XSTRING (data)->data;
7329 else
7330 bits = XBOOL_VECTOR (data)->data;
7331
7332 /* Create the pixmap. */
7333 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7334 img->pixmap
7335 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7336 FRAME_X_WINDOW (f),
7337 bits,
7338 img->width, img->height,
7339 foreground, background,
7340 depth);
7341 if (img->pixmap)
7342 success_p = 1;
7343 else
333b20bb 7344 {
5be6c3b0
GM
7345 image_error ("Unable to create pixmap for XBM image `%s'",
7346 img->spec, Qnil);
7347 x_clear_image (f, img);
333b20bb
GM
7348 }
7349 }
333b20bb
GM
7350 }
7351
7352 return success_p;
7353}
7354
7355
7356\f
7357/***********************************************************************
7358 XPM images
7359 ***********************************************************************/
7360
7361#if HAVE_XPM
7362
7363static int xpm_image_p P_ ((Lisp_Object object));
7364static int xpm_load P_ ((struct frame *f, struct image *img));
7365static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
7366
7367#include "X11/xpm.h"
7368
7369/* The symbol `xpm' identifying XPM-format images. */
7370
7371Lisp_Object Qxpm;
7372
7373/* Indices of image specification fields in xpm_format, below. */
7374
7375enum xpm_keyword_index
7376{
7377 XPM_TYPE,
7378 XPM_FILE,
7379 XPM_DATA,
7380 XPM_ASCENT,
7381 XPM_MARGIN,
7382 XPM_RELIEF,
7383 XPM_ALGORITHM,
7384 XPM_HEURISTIC_MASK,
4a8e312c 7385 XPM_MASK,
333b20bb 7386 XPM_COLOR_SYMBOLS,
f20a3b7a 7387 XPM_BACKGROUND,
333b20bb
GM
7388 XPM_LAST
7389};
7390
7391/* Vector of image_keyword structures describing the format
7392 of valid XPM image specifications. */
7393
7394static struct image_keyword xpm_format[XPM_LAST] =
7395{
7396 {":type", IMAGE_SYMBOL_VALUE, 1},
7397 {":file", IMAGE_STRING_VALUE, 0},
7398 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 7399 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 7400 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 7401 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 7402 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 7403 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 7404 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
7405 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7406 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
7407};
7408
7409/* Structure describing the image type XBM. */
7410
7411static struct image_type xpm_type =
7412{
7413 &Qxpm,
7414 xpm_image_p,
7415 xpm_load,
7416 x_clear_image,
7417 NULL
7418};
7419
7420
b243755a
GM
7421/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
7422 functions for allocating image colors. Our own functions handle
7423 color allocation failures more gracefully than the ones on the XPM
7424 lib. */
7425
7426#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
7427#define ALLOC_XPM_COLORS
7428#endif
7429
7430#ifdef ALLOC_XPM_COLORS
7431
f72c62ad 7432static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
b243755a
GM
7433static void xpm_free_color_cache P_ ((void));
7434static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
f72c62ad
GM
7435static int xpm_color_bucket P_ ((char *));
7436static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
7437 XColor *, int));
b243755a
GM
7438
7439/* An entry in a hash table used to cache color definitions of named
7440 colors. This cache is necessary to speed up XPM image loading in
7441 case we do color allocations ourselves. Without it, we would need
7442 a call to XParseColor per pixel in the image. */
7443
7444struct xpm_cached_color
7445{
7446 /* Next in collision chain. */
7447 struct xpm_cached_color *next;
7448
7449 /* Color definition (RGB and pixel color). */
7450 XColor color;
7451
7452 /* Color name. */
7453 char name[1];
7454};
7455
7456/* The hash table used for the color cache, and its bucket vector
7457 size. */
7458
7459#define XPM_COLOR_CACHE_BUCKETS 1001
7460struct xpm_cached_color **xpm_color_cache;
7461
b243755a
GM
7462/* Initialize the color cache. */
7463
7464static void
f72c62ad
GM
7465xpm_init_color_cache (f, attrs)
7466 struct frame *f;
7467 XpmAttributes *attrs;
b243755a
GM
7468{
7469 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
7470 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
7471 memset (xpm_color_cache, 0, nbytes);
7472 init_color_table ();
f72c62ad
GM
7473
7474 if (attrs->valuemask & XpmColorSymbols)
7475 {
7476 int i;
7477 XColor color;
7478
7479 for (i = 0; i < attrs->numsymbols; ++i)
7480 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7481 attrs->colorsymbols[i].value, &color))
7482 {
7483 color.pixel = lookup_rgb_color (f, color.red, color.green,
7484 color.blue);
7485 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
7486 }
7487 }
b243755a
GM
7488}
7489
7490
7491/* Free the color cache. */
7492
7493static void
7494xpm_free_color_cache ()
7495{
7496 struct xpm_cached_color *p, *next;
7497 int i;
7498
7499 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
7500 for (p = xpm_color_cache[i]; p; p = next)
7501 {
7502 next = p->next;
7503 xfree (p);
7504 }
7505
7506 xfree (xpm_color_cache);
7507 xpm_color_cache = NULL;
7508 free_color_table ();
7509}
7510
7511
f72c62ad
GM
7512/* Return the bucket index for color named COLOR_NAME in the color
7513 cache. */
7514
7515static int
7516xpm_color_bucket (color_name)
7517 char *color_name;
7518{
7519 unsigned h = 0;
7520 char *s;
7521
7522 for (s = color_name; *s; ++s)
7523 h = (h << 2) ^ *s;
7524 return h %= XPM_COLOR_CACHE_BUCKETS;
7525}
7526
7527
7528/* On frame F, cache values COLOR for color with name COLOR_NAME.
7529 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
7530 entry added. */
7531
7532static struct xpm_cached_color *
7533xpm_cache_color (f, color_name, color, bucket)
7534 struct frame *f;
7535 char *color_name;
7536 XColor *color;
7537 int bucket;
7538{
7539 size_t nbytes;
7540 struct xpm_cached_color *p;
7541
7542 if (bucket < 0)
7543 bucket = xpm_color_bucket (color_name);
7544
7545 nbytes = sizeof *p + strlen (color_name);
7546 p = (struct xpm_cached_color *) xmalloc (nbytes);
7547 strcpy (p->name, color_name);
7548 p->color = *color;
7549 p->next = xpm_color_cache[bucket];
7550 xpm_color_cache[bucket] = p;
7551 return p;
7552}
7553
7554
b243755a
GM
7555/* Look up color COLOR_NAME for frame F in the color cache. If found,
7556 return the cached definition in *COLOR. Otherwise, make a new
7557 entry in the cache and allocate the color. Value is zero if color
7558 allocation failed. */
7559
7560static int
7561xpm_lookup_color (f, color_name, color)
7562 struct frame *f;
7563 char *color_name;
7564 XColor *color;
7565{
b243755a 7566 struct xpm_cached_color *p;
83676598 7567 int h = xpm_color_bucket (color_name);
b243755a
GM
7568
7569 for (p = xpm_color_cache[h]; p; p = p->next)
7570 if (strcmp (p->name, color_name) == 0)
7571 break;
7572
7573 if (p != NULL)
7574 *color = p->color;
7575 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7576 color_name, color))
7577 {
b243755a
GM
7578 color->pixel = lookup_rgb_color (f, color->red, color->green,
7579 color->blue);
f72c62ad 7580 p = xpm_cache_color (f, color_name, color, h);
b243755a 7581 }
f72c62ad 7582
b243755a
GM
7583 return p != NULL;
7584}
7585
7586
7587/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
7588 CLOSURE is a pointer to the frame on which we allocate the
7589 color. Return in *COLOR the allocated color. Value is non-zero
7590 if successful. */
7591
7592static int
7593xpm_alloc_color (dpy, cmap, color_name, color, closure)
7594 Display *dpy;
7595 Colormap cmap;
7596 char *color_name;
7597 XColor *color;
7598 void *closure;
7599{
7600 return xpm_lookup_color ((struct frame *) closure, color_name, color);
7601}
7602
7603
7604/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
7605 is a pointer to the frame on which we allocate the color. Value is
7606 non-zero if successful. */
7607
7608static int
7609xpm_free_colors (dpy, cmap, pixels, npixels, closure)
7610 Display *dpy;
7611 Colormap cmap;
7612 Pixel *pixels;
7613 int npixels;
7614 void *closure;
7615{
7616 return 1;
7617}
7618
7619#endif /* ALLOC_XPM_COLORS */
7620
7621
333b20bb
GM
7622/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7623 for XPM images. Such a list must consist of conses whose car and
7624 cdr are strings. */
7625
7626static int
7627xpm_valid_color_symbols_p (color_symbols)
7628 Lisp_Object color_symbols;
7629{
7630 while (CONSP (color_symbols))
7631 {
7632 Lisp_Object sym = XCAR (color_symbols);
7633 if (!CONSP (sym)
7634 || !STRINGP (XCAR (sym))
7635 || !STRINGP (XCDR (sym)))
7636 break;
7637 color_symbols = XCDR (color_symbols);
7638 }
7639
7640 return NILP (color_symbols);
7641}
7642
7643
7644/* Value is non-zero if OBJECT is a valid XPM image specification. */
7645
7646static int
7647xpm_image_p (object)
7648 Lisp_Object object;
7649{
7650 struct image_keyword fmt[XPM_LAST];
7651 bcopy (xpm_format, fmt, sizeof fmt);
bfd2209f 7652 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
333b20bb
GM
7653 /* Either `:file' or `:data' must be present. */
7654 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7655 /* Either no `:color-symbols' or it's a list of conses
7656 whose car and cdr are strings. */
7657 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7c7ff7f5 7658 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
333b20bb
GM
7659}
7660
7661
7662/* Load image IMG which will be displayed on frame F. Value is
7663 non-zero if successful. */
7664
7665static int
7666xpm_load (f, img)
7667 struct frame *f;
7668 struct image *img;
7669{
9b207e8e 7670 int rc;
333b20bb
GM
7671 XpmAttributes attrs;
7672 Lisp_Object specified_file, color_symbols;
7673
7674 /* Configure the XPM lib. Use the visual of frame F. Allocate
7675 close colors. Return colors allocated. */
7676 bzero (&attrs, sizeof attrs);
9b2956e2
GM
7677 attrs.visual = FRAME_X_VISUAL (f);
7678 attrs.colormap = FRAME_X_COLORMAP (f);
333b20bb 7679 attrs.valuemask |= XpmVisual;
9b2956e2 7680 attrs.valuemask |= XpmColormap;
b243755a
GM
7681
7682#ifdef ALLOC_XPM_COLORS
7683 /* Allocate colors with our own functions which handle
7684 failing color allocation more gracefully. */
7685 attrs.color_closure = f;
7686 attrs.alloc_color = xpm_alloc_color;
7687 attrs.free_colors = xpm_free_colors;
7688 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
7689#else /* not ALLOC_XPM_COLORS */
7690 /* Let the XPM lib allocate colors. */
333b20bb 7691 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 7692#ifdef XpmAllocCloseColors
333b20bb
GM
7693 attrs.alloc_close_colors = 1;
7694 attrs.valuemask |= XpmAllocCloseColors;
b243755a 7695#else /* not XpmAllocCloseColors */
e4c082be
RS
7696 attrs.closeness = 600;
7697 attrs.valuemask |= XpmCloseness;
b243755a
GM
7698#endif /* not XpmAllocCloseColors */
7699#endif /* ALLOC_XPM_COLORS */
333b20bb
GM
7700
7701 /* If image specification contains symbolic color definitions, add
7702 these to `attrs'. */
7703 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7704 if (CONSP (color_symbols))
7705 {
7706 Lisp_Object tail;
7707 XpmColorSymbol *xpm_syms;
7708 int i, size;
7709
7710 attrs.valuemask |= XpmColorSymbols;
7711
7712 /* Count number of symbols. */
7713 attrs.numsymbols = 0;
7714 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7715 ++attrs.numsymbols;
7716
7717 /* Allocate an XpmColorSymbol array. */
7718 size = attrs.numsymbols * sizeof *xpm_syms;
7719 xpm_syms = (XpmColorSymbol *) alloca (size);
7720 bzero (xpm_syms, size);
7721 attrs.colorsymbols = xpm_syms;
7722
7723 /* Fill the color symbol array. */
7724 for (tail = color_symbols, i = 0;
7725 CONSP (tail);
7726 ++i, tail = XCDR (tail))
7727 {
7728 Lisp_Object name = XCAR (XCAR (tail));
7729 Lisp_Object color = XCDR (XCAR (tail));
7730 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
7731 strcpy (xpm_syms[i].name, XSTRING (name)->data);
7732 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
7733 strcpy (xpm_syms[i].value, XSTRING (color)->data);
7734 }
7735 }
7736
7737 /* Create a pixmap for the image, either from a file, or from a
7738 string buffer containing data in the same format as an XPM file. */
b243755a 7739#ifdef ALLOC_XPM_COLORS
f72c62ad 7740 xpm_init_color_cache (f, &attrs);
b243755a
GM
7741#endif
7742
333b20bb
GM
7743 specified_file = image_spec_value (img->spec, QCfile, NULL);
7744 if (STRINGP (specified_file))
7745 {
7746 Lisp_Object file = x_find_image_file (specified_file);
7747 if (!STRINGP (file))
7748 {
45158a91 7749 image_error ("Cannot find image file `%s'", specified_file, Qnil);
333b20bb
GM
7750 return 0;
7751 }
7752
7753 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7754 XSTRING (file)->data, &img->pixmap, &img->mask,
7755 &attrs);
7756 }
7757 else
7758 {
7759 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7760 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7761 XSTRING (buffer)->data,
7762 &img->pixmap, &img->mask,
7763 &attrs);
7764 }
333b20bb
GM
7765
7766 if (rc == XpmSuccess)
7767 {
b243755a
GM
7768#ifdef ALLOC_XPM_COLORS
7769 img->colors = colors_in_color_table (&img->ncolors);
7770#else /* not ALLOC_XPM_COLORS */
f47a9ec4
KR
7771 int i;
7772
333b20bb
GM
7773 img->ncolors = attrs.nalloc_pixels;
7774 img->colors = (unsigned long *) xmalloc (img->ncolors
7775 * sizeof *img->colors);
7776 for (i = 0; i < attrs.nalloc_pixels; ++i)
3b4ae1cc
GM
7777 {
7778 img->colors[i] = attrs.alloc_pixels[i];
7779#ifdef DEBUG_X_COLORS
7780 register_color (img->colors[i]);
7781#endif
7782 }
b243755a 7783#endif /* not ALLOC_XPM_COLORS */
333b20bb
GM
7784
7785 img->width = attrs.width;
7786 img->height = attrs.height;
7787 xassert (img->width > 0 && img->height > 0);
7788
7789 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
333b20bb 7790 XpmFreeAttributes (&attrs);
333b20bb
GM
7791 }
7792 else
7793 {
7794 switch (rc)
7795 {
7796 case XpmOpenFailed:
7797 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7798 break;
7799
7800 case XpmFileInvalid:
7801 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7802 break;
7803
7804 case XpmNoMemory:
7805 image_error ("Out of memory (%s)", img->spec, Qnil);
7806 break;
7807
7808 case XpmColorFailed:
7809 image_error ("Color allocation error (%s)", img->spec, Qnil);
7810 break;
7811
7812 default:
7813 image_error ("Unknown error (%s)", img->spec, Qnil);
7814 break;
7815 }
7816 }
7817
b243755a
GM
7818#ifdef ALLOC_XPM_COLORS
7819 xpm_free_color_cache ();
7820#endif
333b20bb
GM
7821 return rc == XpmSuccess;
7822}
7823
7824#endif /* HAVE_XPM != 0 */
7825
7826\f
7827/***********************************************************************
7828 Color table
7829 ***********************************************************************/
7830
7831/* An entry in the color table mapping an RGB color to a pixel color. */
7832
7833struct ct_color
7834{
7835 int r, g, b;
7836 unsigned long pixel;
7837
7838 /* Next in color table collision list. */
7839 struct ct_color *next;
7840};
7841
7842/* The bucket vector size to use. Must be prime. */
7843
7844#define CT_SIZE 101
7845
7846/* Value is a hash of the RGB color given by R, G, and B. */
7847
7848#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7849
7850/* The color hash table. */
7851
7852struct ct_color **ct_table;
7853
7854/* Number of entries in the color table. */
7855
7856int ct_colors_allocated;
7857
333b20bb
GM
7858/* Initialize the color table. */
7859
7860static void
7861init_color_table ()
7862{
7863 int size = CT_SIZE * sizeof (*ct_table);
7864 ct_table = (struct ct_color **) xmalloc (size);
7865 bzero (ct_table, size);
7866 ct_colors_allocated = 0;
7867}
7868
7869
7870/* Free memory associated with the color table. */
7871
7872static void
7873free_color_table ()
7874{
7875 int i;
7876 struct ct_color *p, *next;
7877
7878 for (i = 0; i < CT_SIZE; ++i)
7879 for (p = ct_table[i]; p; p = next)
7880 {
7881 next = p->next;
7882 xfree (p);
7883 }
7884
7885 xfree (ct_table);
7886 ct_table = NULL;
7887}
7888
7889
7890/* Value is a pixel color for RGB color R, G, B on frame F. If an
7891 entry for that color already is in the color table, return the
7892 pixel color of that entry. Otherwise, allocate a new color for R,
7893 G, B, and make an entry in the color table. */
7894
7895static unsigned long
7896lookup_rgb_color (f, r, g, b)
7897 struct frame *f;
7898 int r, g, b;
7899{
7900 unsigned hash = CT_HASH_RGB (r, g, b);
7901 int i = hash % CT_SIZE;
7902 struct ct_color *p;
7903
7904 for (p = ct_table[i]; p; p = p->next)
7905 if (p->r == r && p->g == g && p->b == b)
7906 break;
7907
7908 if (p == NULL)
7909 {
7910 XColor color;
7911 Colormap cmap;
7912 int rc;
7913
7914 color.red = r;
7915 color.green = g;
7916 color.blue = b;
7917
9b2956e2 7918 cmap = FRAME_X_COLORMAP (f);
d62c8769 7919 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7920
7921 if (rc)
7922 {
7923 ++ct_colors_allocated;
7924
7925 p = (struct ct_color *) xmalloc (sizeof *p);
7926 p->r = r;
7927 p->g = g;
7928 p->b = b;
7929 p->pixel = color.pixel;
7930 p->next = ct_table[i];
7931 ct_table[i] = p;
7932 }
7933 else
7934 return FRAME_FOREGROUND_PIXEL (f);
7935 }
7936
7937 return p->pixel;
7938}
7939
7940
7941/* Look up pixel color PIXEL which is used on frame F in the color
7942 table. If not already present, allocate it. Value is PIXEL. */
7943
7944static unsigned long
7945lookup_pixel_color (f, pixel)
7946 struct frame *f;
7947 unsigned long pixel;
7948{
7949 int i = pixel % CT_SIZE;
7950 struct ct_color *p;
7951
7952 for (p = ct_table[i]; p; p = p->next)
7953 if (p->pixel == pixel)
7954 break;
7955
7956 if (p == NULL)
7957 {
7958 XColor color;
7959 Colormap cmap;
7960 int rc;
7961
9b2956e2 7962 cmap = FRAME_X_COLORMAP (f);
333b20bb 7963 color.pixel = pixel;
a31fedb7 7964 x_query_color (f, &color);
d62c8769 7965 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7966
7967 if (rc)
7968 {
7969 ++ct_colors_allocated;
7970
7971 p = (struct ct_color *) xmalloc (sizeof *p);
7972 p->r = color.red;
7973 p->g = color.green;
7974 p->b = color.blue;
7975 p->pixel = pixel;
7976 p->next = ct_table[i];
7977 ct_table[i] = p;
7978 }
7979 else
7980 return FRAME_FOREGROUND_PIXEL (f);
7981 }
7982
7983 return p->pixel;
7984}
7985
7986
7987/* Value is a vector of all pixel colors contained in the color table,
7988 allocated via xmalloc. Set *N to the number of colors. */
7989
7990static unsigned long *
7991colors_in_color_table (n)
7992 int *n;
7993{
7994 int i, j;
7995 struct ct_color *p;
7996 unsigned long *colors;
7997
7998 if (ct_colors_allocated == 0)
7999 {
8000 *n = 0;
8001 colors = NULL;
8002 }
8003 else
8004 {
8005 colors = (unsigned long *) xmalloc (ct_colors_allocated
8006 * sizeof *colors);
8007 *n = ct_colors_allocated;
8008
8009 for (i = j = 0; i < CT_SIZE; ++i)
8010 for (p = ct_table[i]; p; p = p->next)
8011 colors[j++] = p->pixel;
8012 }
8013
8014 return colors;
8015}
8016
8017
8018\f
8019/***********************************************************************
8020 Algorithms
8021 ***********************************************************************/
8022
4a8e312c
GM
8023static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
8024static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
8025static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
8026
d2dc8167 8027/* Non-zero means draw a cross on images having `:conversion
14819cb3
GM
8028 disabled'. */
8029
8030int cross_disabled_images;
8031
4a8e312c
GM
8032/* Edge detection matrices for different edge-detection
8033 strategies. */
8034
8035static int emboss_matrix[9] = {
8036 /* x - 1 x x + 1 */
8037 2, -1, 0, /* y - 1 */
8038 -1, 0, 1, /* y */
8039 0, 1, -2 /* y + 1 */
8040};
333b20bb 8041
4a8e312c
GM
8042static int laplace_matrix[9] = {
8043 /* x - 1 x x + 1 */
8044 1, 0, 0, /* y - 1 */
8045 0, 0, 0, /* y */
8046 0, 0, -1 /* y + 1 */
8047};
333b20bb 8048
14819cb3
GM
8049/* Value is the intensity of the color whose red/green/blue values
8050 are R, G, and B. */
8051
8052#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
8053
333b20bb 8054
4a8e312c
GM
8055/* On frame F, return an array of XColor structures describing image
8056 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
8057 non-zero means also fill the red/green/blue members of the XColor
8058 structures. Value is a pointer to the array of XColors structures,
8059 allocated with xmalloc; it must be freed by the caller. */
8060
8061static XColor *
8062x_to_xcolors (f, img, rgb_p)
333b20bb 8063 struct frame *f;
4a8e312c
GM
8064 struct image *img;
8065 int rgb_p;
333b20bb 8066{
4a8e312c
GM
8067 int x, y;
8068 XColor *colors, *p;
8069 XImage *ximg;
333b20bb 8070
4a8e312c
GM
8071 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
8072
8073 /* Get the X image IMG->pixmap. */
8074 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8075 0, 0, img->width, img->height, ~0, ZPixmap);
333b20bb 8076
4a8e312c
GM
8077 /* Fill the `pixel' members of the XColor array. I wished there
8078 were an easy and portable way to circumvent XGetPixel. */
8079 p = colors;
8080 for (y = 0; y < img->height; ++y)
8081 {
8082 XColor *row = p;
8083
8084 for (x = 0; x < img->width; ++x, ++p)
8085 p->pixel = XGetPixel (ximg, x, y);
8086
8087 if (rgb_p)
a31fedb7 8088 x_query_colors (f, row, img->width);
4a8e312c
GM
8089 }
8090
8091 XDestroyImage (ximg);
4a8e312c 8092 return colors;
333b20bb
GM
8093}
8094
8095
4a8e312c
GM
8096/* Create IMG->pixmap from an array COLORS of XColor structures, whose
8097 RGB members are set. F is the frame on which this all happens.
8098 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
333b20bb
GM
8099
8100static void
4a8e312c 8101x_from_xcolors (f, img, colors)
333b20bb 8102 struct frame *f;
4a8e312c
GM
8103 struct image *img;
8104 XColor *colors;
333b20bb 8105{
4a8e312c
GM
8106 int x, y;
8107 XImage *oimg;
8108 Pixmap pixmap;
8109 XColor *p;
8110
4a8e312c 8111 init_color_table ();
333b20bb 8112
4a8e312c
GM
8113 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
8114 &oimg, &pixmap);
8115 p = colors;
8116 for (y = 0; y < img->height; ++y)
8117 for (x = 0; x < img->width; ++x, ++p)
8118 {
8119 unsigned long pixel;
8120 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
8121 XPutPixel (oimg, x, y, pixel);
8122 }
8123
8124 xfree (colors);
dd00328a 8125 x_clear_image_1 (f, img, 1, 0, 1);
4a8e312c
GM
8126
8127 x_put_x_image (f, oimg, pixmap, img->width, img->height);
8128 x_destroy_x_image (oimg);
8129 img->pixmap = pixmap;
8130 img->colors = colors_in_color_table (&img->ncolors);
8131 free_color_table ();
333b20bb
GM
8132}
8133
8134
4a8e312c
GM
8135/* On frame F, perform edge-detection on image IMG.
8136
8137 MATRIX is a nine-element array specifying the transformation
8138 matrix. See emboss_matrix for an example.
8139
8140 COLOR_ADJUST is a color adjustment added to each pixel of the
8141 outgoing image. */
333b20bb
GM
8142
8143static void
4a8e312c 8144x_detect_edges (f, img, matrix, color_adjust)
333b20bb
GM
8145 struct frame *f;
8146 struct image *img;
4a8e312c 8147 int matrix[9], color_adjust;
333b20bb 8148{
4a8e312c
GM
8149 XColor *colors = x_to_xcolors (f, img, 1);
8150 XColor *new, *p;
8151 int x, y, i, sum;
333b20bb 8152
4a8e312c
GM
8153 for (i = sum = 0; i < 9; ++i)
8154 sum += abs (matrix[i]);
333b20bb 8155
4a8e312c 8156#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
333b20bb 8157
4a8e312c 8158 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
333b20bb 8159
4a8e312c
GM
8160 for (y = 0; y < img->height; ++y)
8161 {
8162 p = COLOR (new, 0, y);
8163 p->red = p->green = p->blue = 0xffff/2;
8164 p = COLOR (new, img->width - 1, y);
8165 p->red = p->green = p->blue = 0xffff/2;
8166 }
8167
8168 for (x = 1; x < img->width - 1; ++x)
8169 {
8170 p = COLOR (new, x, 0);
8171 p->red = p->green = p->blue = 0xffff/2;
8172 p = COLOR (new, x, img->height - 1);
8173 p->red = p->green = p->blue = 0xffff/2;
8174 }
333b20bb 8175
4a8e312c 8176 for (y = 1; y < img->height - 1; ++y)
333b20bb 8177 {
4a8e312c
GM
8178 p = COLOR (new, 1, y);
8179
8180 for (x = 1; x < img->width - 1; ++x, ++p)
8181 {
14819cb3 8182 int r, g, b, y1, x1;
4a8e312c
GM
8183
8184 r = g = b = i = 0;
8185 for (y1 = y - 1; y1 < y + 2; ++y1)
8186 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
8187 if (matrix[i])
8188 {
8189 XColor *t = COLOR (colors, x1, y1);
8190 r += matrix[i] * t->red;
8191 g += matrix[i] * t->green;
8192 b += matrix[i] * t->blue;
8193 }
333b20bb 8194
4a8e312c
GM
8195 r = (r / sum + color_adjust) & 0xffff;
8196 g = (g / sum + color_adjust) & 0xffff;
8197 b = (b / sum + color_adjust) & 0xffff;
14819cb3 8198 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
333b20bb 8199 }
333b20bb
GM
8200 }
8201
4a8e312c
GM
8202 xfree (colors);
8203 x_from_xcolors (f, img, new);
333b20bb 8204
4a8e312c
GM
8205#undef COLOR
8206}
8207
8208
8209/* Perform the pre-defined `emboss' edge-detection on image IMG
8210 on frame F. */
8211
8212static void
8213x_emboss (f, img)
8214 struct frame *f;
8215 struct image *img;
8216{
8217 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
8218}
8219
8220
8221/* Perform the pre-defined `laplace' edge-detection on image IMG
8222 on frame F. */
8223
8224static void
8225x_laplace (f, img)
8226 struct frame *f;
8227 struct image *img;
8228{
8229 x_detect_edges (f, img, laplace_matrix, 45000);
8230}
8231
8232
8233/* Perform edge-detection on image IMG on frame F, with specified
8234 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
8235
8236 MATRIX must be either
8237
8238 - a list of at least 9 numbers in row-major form
8239 - a vector of at least 9 numbers
8240
8241 COLOR_ADJUST nil means use a default; otherwise it must be a
8242 number. */
8243
8244static void
8245x_edge_detection (f, img, matrix, color_adjust)
8246 struct frame *f;
8247 struct image *img;
8248 Lisp_Object matrix, color_adjust;
8249{
8250 int i = 0;
8251 int trans[9];
333b20bb 8252
4a8e312c
GM
8253 if (CONSP (matrix))
8254 {
8255 for (i = 0;
8256 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
8257 ++i, matrix = XCDR (matrix))
8258 trans[i] = XFLOATINT (XCAR (matrix));
8259 }
8260 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
8261 {
8262 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
8263 trans[i] = XFLOATINT (AREF (matrix, i));
8264 }
333b20bb 8265
4a8e312c
GM
8266 if (NILP (color_adjust))
8267 color_adjust = make_number (0xffff / 2);
333b20bb 8268
4a8e312c
GM
8269 if (i == 9 && NUMBERP (color_adjust))
8270 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
333b20bb
GM
8271}
8272
8273
14819cb3
GM
8274/* Transform image IMG on frame F so that it looks disabled. */
8275
8276static void
8277x_disable_image (f, img)
8278 struct frame *f;
8279 struct image *img;
8280{
8281 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
dd00328a 8282
14819cb3
GM
8283 if (dpyinfo->n_planes >= 2)
8284 {
8285 /* Color (or grayscale). Convert to gray, and equalize. Just
8286 drawing such images with a stipple can look very odd, so
8287 we're using this method instead. */
8288 XColor *colors = x_to_xcolors (f, img, 1);
8289 XColor *p, *end;
8290 const int h = 15000;
8291 const int l = 30000;
8292
8293 for (p = colors, end = colors + img->width * img->height;
8294 p < end;
8295 ++p)
8296 {
8297 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
8298 int i2 = (0xffff - h - l) * i / 0xffff + l;
8299 p->red = p->green = p->blue = i2;
8300 }
8301
8302 x_from_xcolors (f, img, colors);
8303 }
8304
8305 /* Draw a cross over the disabled image, if we must or if we
8306 should. */
8307 if (dpyinfo->n_planes < 2 || cross_disabled_images)
8308 {
8309 Display *dpy = FRAME_X_DISPLAY (f);
8310 GC gc;
8311
14819cb3
GM
8312 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
8313 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
8314 XDrawLine (dpy, img->pixmap, gc, 0, 0,
8315 img->width - 1, img->height - 1);
8316 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
8317 img->width - 1, 0);
8318 XFreeGC (dpy, gc);
8319
8320 if (img->mask)
8321 {
8322 gc = XCreateGC (dpy, img->mask, 0, NULL);
8323 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
8324 XDrawLine (dpy, img->mask, gc, 0, 0,
8325 img->width - 1, img->height - 1);
8326 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
8327 img->width - 1, 0);
8328 XFreeGC (dpy, gc);
8329 }
14819cb3
GM
8330 }
8331}
8332
8333
333b20bb
GM
8334/* Build a mask for image IMG which is used on frame F. FILE is the
8335 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
8336 determine the background color of IMG. If it is a list '(R G B)',
8337 with R, G, and B being integers >= 0, take that as the color of the
8338 background. Otherwise, determine the background color of IMG
8339 heuristically. Value is non-zero if successful. */
333b20bb
GM
8340
8341static int
45158a91 8342x_build_heuristic_mask (f, img, how)
333b20bb 8343 struct frame *f;
333b20bb
GM
8344 struct image *img;
8345 Lisp_Object how;
8346{
8347 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 8348 XImage *ximg, *mask_img;
f20a3b7a 8349 int x, y, rc, use_img_background;
8ec8a5ec 8350 unsigned long bg = 0;
333b20bb 8351
4a8e312c
GM
8352 if (img->mask)
8353 {
8354 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 8355 img->mask = None;
f20a3b7a 8356 img->background_transparent_valid = 0;
4a8e312c 8357 }
dd00328a 8358
333b20bb 8359 /* Create an image and pixmap serving as mask. */
45158a91 8360 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
333b20bb
GM
8361 &mask_img, &img->mask);
8362 if (!rc)
28c7826c 8363 return 0;
333b20bb
GM
8364
8365 /* Get the X image of IMG->pixmap. */
8366 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
8367 ~0, ZPixmap);
8368
fcf431dc 8369 /* Determine the background color of ximg. If HOW is `(R G B)'
f20a3b7a
MB
8370 take that as color. Otherwise, use the image's background color. */
8371 use_img_background = 1;
fcf431dc
GM
8372
8373 if (CONSP (how))
8374 {
cac1daf0 8375 int rgb[3], i;
fcf431dc 8376
cac1daf0 8377 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
fcf431dc
GM
8378 {
8379 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
8380 how = XCDR (how);
8381 }
8382
8383 if (i == 3 && NILP (how))
8384 {
8385 char color_name[30];
fcf431dc 8386 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
053b3256
GM
8387 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
8388 use_img_background = 0;
fcf431dc
GM
8389 }
8390 }
8391
f20a3b7a 8392 if (use_img_background)
43f7c3ea 8393 bg = four_corners_best (ximg, img->width, img->height);
333b20bb
GM
8394
8395 /* Set all bits in mask_img to 1 whose color in ximg is different
8396 from the background color bg. */
8397 for (y = 0; y < img->height; ++y)
8398 for (x = 0; x < img->width; ++x)
8399 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
8400
f20a3b7a
MB
8401 /* Fill in the background_transparent field while we have the mask handy. */
8402 image_background_transparent (img, f, mask_img);
8403
333b20bb
GM
8404 /* Put mask_img into img->mask. */
8405 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8406 x_destroy_x_image (mask_img);
8407 XDestroyImage (ximg);
8408
333b20bb
GM
8409 return 1;
8410}
8411
8412
8413\f
8414/***********************************************************************
8415 PBM (mono, gray, color)
8416 ***********************************************************************/
8417
8418static int pbm_image_p P_ ((Lisp_Object object));
8419static int pbm_load P_ ((struct frame *f, struct image *img));
63cec32f 8420static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
333b20bb
GM
8421
8422/* The symbol `pbm' identifying images of this type. */
8423
8424Lisp_Object Qpbm;
8425
8426/* Indices of image specification fields in gs_format, below. */
8427
8428enum pbm_keyword_index
8429{
8430 PBM_TYPE,
8431 PBM_FILE,
63cec32f 8432 PBM_DATA,
333b20bb
GM
8433 PBM_ASCENT,
8434 PBM_MARGIN,
8435 PBM_RELIEF,
8436 PBM_ALGORITHM,
8437 PBM_HEURISTIC_MASK,
4a8e312c 8438 PBM_MASK,
be0b1fac
GM
8439 PBM_FOREGROUND,
8440 PBM_BACKGROUND,
333b20bb
GM
8441 PBM_LAST
8442};
8443
8444/* Vector of image_keyword structures describing the format
8445 of valid user-defined image specifications. */
8446
8447static struct image_keyword pbm_format[PBM_LAST] =
8448{
8449 {":type", IMAGE_SYMBOL_VALUE, 1},
63cec32f
GM
8450 {":file", IMAGE_STRING_VALUE, 0},
8451 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8452 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8453 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8454 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8455 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8456 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
be0b1fac 8457 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
8458 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8459 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8460};
8461
8462/* Structure describing the image type `pbm'. */
8463
8464static struct image_type pbm_type =
8465{
8466 &Qpbm,
8467 pbm_image_p,
8468 pbm_load,
8469 x_clear_image,
8470 NULL
8471};
8472
8473
8474/* Return non-zero if OBJECT is a valid PBM image specification. */
8475
8476static int
8477pbm_image_p (object)
8478 Lisp_Object object;
8479{
8480 struct image_keyword fmt[PBM_LAST];
8481
8482 bcopy (pbm_format, fmt, sizeof fmt);
8483
7c7ff7f5 8484 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
333b20bb 8485 return 0;
63cec32f
GM
8486
8487 /* Must specify either :data or :file. */
8488 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
333b20bb
GM
8489}
8490
8491
63cec32f
GM
8492/* Scan a decimal number from *S and return it. Advance *S while
8493 reading the number. END is the end of the string. Value is -1 at
8494 end of input. */
333b20bb
GM
8495
8496static int
63cec32f
GM
8497pbm_scan_number (s, end)
8498 unsigned char **s, *end;
333b20bb 8499{
8ec8a5ec 8500 int c = 0, val = -1;
333b20bb 8501
63cec32f 8502 while (*s < end)
333b20bb
GM
8503 {
8504 /* Skip white-space. */
63cec32f 8505 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
8506 ;
8507
8508 if (c == '#')
8509 {
8510 /* Skip comment to end of line. */
63cec32f 8511 while (*s < end && (c = *(*s)++, c != '\n'))
333b20bb
GM
8512 ;
8513 }
8514 else if (isdigit (c))
8515 {
8516 /* Read decimal number. */
8517 val = c - '0';
63cec32f 8518 while (*s < end && (c = *(*s)++, isdigit (c)))
333b20bb
GM
8519 val = 10 * val + c - '0';
8520 break;
8521 }
8522 else
8523 break;
8524 }
8525
8526 return val;
8527}
8528
8529
8530/* Load PBM image IMG for use on frame F. */
8531
8532static int
8533pbm_load (f, img)
8534 struct frame *f;
8535 struct image *img;
8536{
333b20bb 8537 int raw_p, x, y;
b6d7acec 8538 int width, height, max_color_idx = 0;
333b20bb
GM
8539 XImage *ximg;
8540 Lisp_Object file, specified_file;
8541 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
8542 struct gcpro gcpro1;
63cec32f
GM
8543 unsigned char *contents = NULL;
8544 unsigned char *end, *p;
8545 int size;
333b20bb
GM
8546
8547 specified_file = image_spec_value (img->spec, QCfile, NULL);
63cec32f 8548 file = Qnil;
333b20bb 8549 GCPRO1 (file);
333b20bb 8550
63cec32f 8551 if (STRINGP (specified_file))
333b20bb 8552 {
63cec32f
GM
8553 file = x_find_image_file (specified_file);
8554 if (!STRINGP (file))
8555 {
8556 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8557 UNGCPRO;
8558 return 0;
8559 }
333b20bb 8560
5be6c3b0 8561 contents = slurp_file (XSTRING (file)->data, &size);
63cec32f
GM
8562 if (contents == NULL)
8563 {
8564 image_error ("Error reading `%s'", file, Qnil);
8565 UNGCPRO;
8566 return 0;
8567 }
8568
8569 p = contents;
8570 end = contents + size;
8571 }
8572 else
333b20bb 8573 {
63cec32f
GM
8574 Lisp_Object data;
8575 data = image_spec_value (img->spec, QCdata, NULL);
8576 p = XSTRING (data)->data;
8577 end = p + STRING_BYTES (XSTRING (data));
333b20bb
GM
8578 }
8579
63cec32f
GM
8580 /* Check magic number. */
8581 if (end - p < 2 || *p++ != 'P')
333b20bb 8582 {
45158a91 8583 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f
GM
8584 error:
8585 xfree (contents);
333b20bb
GM
8586 UNGCPRO;
8587 return 0;
8588 }
8589
63cec32f 8590 switch (*p++)
333b20bb
GM
8591 {
8592 case '1':
8593 raw_p = 0, type = PBM_MONO;
8594 break;
8595
8596 case '2':
8597 raw_p = 0, type = PBM_GRAY;
8598 break;
8599
8600 case '3':
8601 raw_p = 0, type = PBM_COLOR;
8602 break;
8603
8604 case '4':
8605 raw_p = 1, type = PBM_MONO;
8606 break;
8607
8608 case '5':
8609 raw_p = 1, type = PBM_GRAY;
8610 break;
8611
8612 case '6':
8613 raw_p = 1, type = PBM_COLOR;
8614 break;
8615
8616 default:
45158a91 8617 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f 8618 goto error;
333b20bb
GM
8619 }
8620
8621 /* Read width, height, maximum color-component. Characters
8622 starting with `#' up to the end of a line are ignored. */
63cec32f
GM
8623 width = pbm_scan_number (&p, end);
8624 height = pbm_scan_number (&p, end);
333b20bb
GM
8625
8626 if (type != PBM_MONO)
8627 {
63cec32f 8628 max_color_idx = pbm_scan_number (&p, end);
333b20bb
GM
8629 if (raw_p && max_color_idx > 255)
8630 max_color_idx = 255;
8631 }
8632
63cec32f
GM
8633 if (width < 0
8634 || height < 0
333b20bb 8635 || (type != PBM_MONO && max_color_idx < 0))
63cec32f 8636 goto error;
333b20bb 8637
45158a91 8638 if (!x_create_x_image_and_pixmap (f, width, height, 0,
333b20bb 8639 &ximg, &img->pixmap))
28c7826c 8640 goto error;
333b20bb
GM
8641
8642 /* Initialize the color hash table. */
8643 init_color_table ();
8644
8645 if (type == PBM_MONO)
8646 {
8647 int c = 0, g;
be0b1fac
GM
8648 struct image_keyword fmt[PBM_LAST];
8649 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
8650 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
8651
8652 /* Parse the image specification. */
8653 bcopy (pbm_format, fmt, sizeof fmt);
8654 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
8655
8656 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
8657 if (fmt[PBM_FOREGROUND].count
8658 && STRINGP (fmt[PBM_FOREGROUND].value))
be0b1fac 8659 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
6f1be3b9
GM
8660 if (fmt[PBM_BACKGROUND].count
8661 && STRINGP (fmt[PBM_BACKGROUND].value))
f20a3b7a
MB
8662 {
8663 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
8664 img->background = bg;
8665 img->background_valid = 1;
8666 }
333b20bb
GM
8667
8668 for (y = 0; y < height; ++y)
8669 for (x = 0; x < width; ++x)
8670 {
8671 if (raw_p)
8672 {
8673 if ((x & 7) == 0)
63cec32f 8674 c = *p++;
333b20bb
GM
8675 g = c & 0x80;
8676 c <<= 1;
8677 }
8678 else
63cec32f 8679 g = pbm_scan_number (&p, end);
333b20bb 8680
be0b1fac 8681 XPutPixel (ximg, x, y, g ? fg : bg);
333b20bb
GM
8682 }
8683 }
8684 else
8685 {
8686 for (y = 0; y < height; ++y)
8687 for (x = 0; x < width; ++x)
8688 {
8689 int r, g, b;
8690
8691 if (type == PBM_GRAY)
63cec32f 8692 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
333b20bb
GM
8693 else if (raw_p)
8694 {
63cec32f
GM
8695 r = *p++;
8696 g = *p++;
8697 b = *p++;
333b20bb
GM
8698 }
8699 else
8700 {
63cec32f
GM
8701 r = pbm_scan_number (&p, end);
8702 g = pbm_scan_number (&p, end);
8703 b = pbm_scan_number (&p, end);
333b20bb
GM
8704 }
8705
8706 if (r < 0 || g < 0 || b < 0)
8707 {
333b20bb
GM
8708 xfree (ximg->data);
8709 ximg->data = NULL;
8710 XDestroyImage (ximg);
45158a91
GM
8711 image_error ("Invalid pixel value in image `%s'",
8712 img->spec, Qnil);
63cec32f 8713 goto error;
333b20bb
GM
8714 }
8715
8716 /* RGB values are now in the range 0..max_color_idx.
8717 Scale this to the range 0..0xffff supported by X. */
8718 r = (double) r * 65535 / max_color_idx;
8719 g = (double) g * 65535 / max_color_idx;
8720 b = (double) b * 65535 / max_color_idx;
8721 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8722 }
8723 }
8724
333b20bb
GM
8725 /* Store in IMG->colors the colors allocated for the image, and
8726 free the color table. */
8727 img->colors = colors_in_color_table (&img->ncolors);
8728 free_color_table ();
f20a3b7a
MB
8729
8730 /* Maybe fill in the background field while we have ximg handy. */
8731 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8732 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
8733
8734 /* Put the image into a pixmap. */
8735 x_put_x_image (f, ximg, img->pixmap, width, height);
8736 x_destroy_x_image (ximg);
333b20bb
GM
8737
8738 img->width = width;
8739 img->height = height;
8740
8741 UNGCPRO;
63cec32f 8742 xfree (contents);
333b20bb
GM
8743 return 1;
8744}
8745
8746
8747\f
8748/***********************************************************************
8749 PNG
8750 ***********************************************************************/
8751
8752#if HAVE_PNG
8753
8754#include <png.h>
8755
8756/* Function prototypes. */
8757
8758static int png_image_p P_ ((Lisp_Object object));
8759static int png_load P_ ((struct frame *f, struct image *img));
8760
8761/* The symbol `png' identifying images of this type. */
8762
8763Lisp_Object Qpng;
8764
8765/* Indices of image specification fields in png_format, below. */
8766
8767enum png_keyword_index
8768{
8769 PNG_TYPE,
63448a4d 8770 PNG_DATA,
333b20bb
GM
8771 PNG_FILE,
8772 PNG_ASCENT,
8773 PNG_MARGIN,
8774 PNG_RELIEF,
8775 PNG_ALGORITHM,
8776 PNG_HEURISTIC_MASK,
4a8e312c 8777 PNG_MASK,
f20a3b7a 8778 PNG_BACKGROUND,
333b20bb
GM
8779 PNG_LAST
8780};
8781
8782/* Vector of image_keyword structures describing the format
8783 of valid user-defined image specifications. */
8784
8785static struct image_keyword png_format[PNG_LAST] =
8786{
8787 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8788 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8789 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8790 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8791 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8792 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8793 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8794 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 8795 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a 8796 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8797};
8798
06482119 8799/* Structure describing the image type `png'. */
333b20bb
GM
8800
8801static struct image_type png_type =
8802{
8803 &Qpng,
8804 png_image_p,
8805 png_load,
8806 x_clear_image,
8807 NULL
8808};
8809
8810
8811/* Return non-zero if OBJECT is a valid PNG image specification. */
8812
8813static int
8814png_image_p (object)
8815 Lisp_Object object;
8816{
8817 struct image_keyword fmt[PNG_LAST];
8818 bcopy (png_format, fmt, sizeof fmt);
8819
7c7ff7f5 8820 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
333b20bb 8821 return 0;
63448a4d 8822
63cec32f
GM
8823 /* Must specify either the :data or :file keyword. */
8824 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
333b20bb
GM
8825}
8826
8827
8828/* Error and warning handlers installed when the PNG library
8829 is initialized. */
8830
8831static void
8832my_png_error (png_ptr, msg)
8833 png_struct *png_ptr;
8834 char *msg;
8835{
8836 xassert (png_ptr != NULL);
8837 image_error ("PNG error: %s", build_string (msg), Qnil);
8838 longjmp (png_ptr->jmpbuf, 1);
8839}
8840
8841
8842static void
8843my_png_warning (png_ptr, msg)
8844 png_struct *png_ptr;
8845 char *msg;
8846{
8847 xassert (png_ptr != NULL);
8848 image_error ("PNG warning: %s", build_string (msg), Qnil);
8849}
8850
5ad6a5fb
GM
8851/* Memory source for PNG decoding. */
8852
63448a4d
WP
8853struct png_memory_storage
8854{
5ad6a5fb
GM
8855 unsigned char *bytes; /* The data */
8856 size_t len; /* How big is it? */
8857 int index; /* Where are we? */
63448a4d
WP
8858};
8859
5ad6a5fb
GM
8860
8861/* Function set as reader function when reading PNG image from memory.
8862 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8863 bytes from the input to DATA. */
8864
63448a4d 8865static void
5ad6a5fb
GM
8866png_read_from_memory (png_ptr, data, length)
8867 png_structp png_ptr;
8868 png_bytep data;
8869 png_size_t length;
63448a4d 8870{
5ad6a5fb
GM
8871 struct png_memory_storage *tbr
8872 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
63448a4d 8873
5ad6a5fb
GM
8874 if (length > tbr->len - tbr->index)
8875 png_error (png_ptr, "Read error");
8876
8877 bcopy (tbr->bytes + tbr->index, data, length);
8878 tbr->index = tbr->index + length;
63448a4d 8879}
333b20bb
GM
8880
8881/* Load PNG image IMG for use on frame F. Value is non-zero if
8882 successful. */
8883
8884static int
8885png_load (f, img)
8886 struct frame *f;
8887 struct image *img;
8888{
8889 Lisp_Object file, specified_file;
63448a4d 8890 Lisp_Object specified_data;
b6d7acec 8891 int x, y, i;
333b20bb
GM
8892 XImage *ximg, *mask_img = NULL;
8893 struct gcpro gcpro1;
8894 png_struct *png_ptr = NULL;
8895 png_info *info_ptr = NULL, *end_info = NULL;
8ec8a5ec 8896 FILE *volatile fp = NULL;
333b20bb 8897 png_byte sig[8];
8ec8a5ec
GM
8898 png_byte * volatile pixels = NULL;
8899 png_byte ** volatile rows = NULL;
333b20bb
GM
8900 png_uint_32 width, height;
8901 int bit_depth, color_type, interlace_type;
8902 png_byte channels;
8903 png_uint_32 row_bytes;
8904 int transparent_p;
333b20bb
GM
8905 double screen_gamma, image_gamma;
8906 int intent;
63448a4d 8907 struct png_memory_storage tbr; /* Data to be read */
333b20bb
GM
8908
8909 /* Find out what file to load. */
8910 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8911 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8912 file = Qnil;
8913 GCPRO1 (file);
333b20bb 8914
63448a4d 8915 if (NILP (specified_data))
5ad6a5fb
GM
8916 {
8917 file = x_find_image_file (specified_file);
8918 if (!STRINGP (file))
63448a4d 8919 {
45158a91 8920 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
8921 UNGCPRO;
8922 return 0;
8923 }
333b20bb 8924
5ad6a5fb
GM
8925 /* Open the image file. */
8926 fp = fopen (XSTRING (file)->data, "rb");
8927 if (!fp)
8928 {
45158a91 8929 image_error ("Cannot open image file `%s'", file, Qnil);
5ad6a5fb
GM
8930 UNGCPRO;
8931 fclose (fp);
8932 return 0;
8933 }
63448a4d 8934
5ad6a5fb
GM
8935 /* Check PNG signature. */
8936 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8937 || !png_check_sig (sig, sizeof sig))
8938 {
45158a91 8939 image_error ("Not a PNG file: `%s'", file, Qnil);
5ad6a5fb
GM
8940 UNGCPRO;
8941 fclose (fp);
8942 return 0;
63448a4d 8943 }
5ad6a5fb 8944 }
63448a4d 8945 else
5ad6a5fb
GM
8946 {
8947 /* Read from memory. */
8948 tbr.bytes = XSTRING (specified_data)->data;
8949 tbr.len = STRING_BYTES (XSTRING (specified_data));
8950 tbr.index = 0;
63448a4d 8951
5ad6a5fb
GM
8952 /* Check PNG signature. */
8953 if (tbr.len < sizeof sig
8954 || !png_check_sig (tbr.bytes, sizeof sig))
8955 {
45158a91 8956 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5ad6a5fb
GM
8957 UNGCPRO;
8958 return 0;
63448a4d 8959 }
333b20bb 8960
5ad6a5fb
GM
8961 /* Need to skip past the signature. */
8962 tbr.bytes += sizeof (sig);
8963 }
8964
333b20bb
GM
8965 /* Initialize read and info structs for PNG lib. */
8966 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8967 my_png_error, my_png_warning);
8968 if (!png_ptr)
8969 {
63448a4d 8970 if (fp) fclose (fp);
333b20bb
GM
8971 UNGCPRO;
8972 return 0;
8973 }
8974
8975 info_ptr = png_create_info_struct (png_ptr);
8976 if (!info_ptr)
8977 {
8978 png_destroy_read_struct (&png_ptr, NULL, NULL);
63448a4d 8979 if (fp) fclose (fp);
333b20bb
GM
8980 UNGCPRO;
8981 return 0;
8982 }
8983
8984 end_info = png_create_info_struct (png_ptr);
8985 if (!end_info)
8986 {
8987 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
63448a4d 8988 if (fp) fclose (fp);
333b20bb
GM
8989 UNGCPRO;
8990 return 0;
8991 }
8992
8993 /* Set error jump-back. We come back here when the PNG library
8994 detects an error. */
8995 if (setjmp (png_ptr->jmpbuf))
8996 {
8997 error:
8998 if (png_ptr)
8999 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9000 xfree (pixels);
9001 xfree (rows);
63448a4d 9002 if (fp) fclose (fp);
333b20bb
GM
9003 UNGCPRO;
9004 return 0;
9005 }
9006
9007 /* Read image info. */
63448a4d 9008 if (!NILP (specified_data))
5ad6a5fb 9009 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
63448a4d 9010 else
5ad6a5fb 9011 png_init_io (png_ptr, fp);
63448a4d 9012
333b20bb
GM
9013 png_set_sig_bytes (png_ptr, sizeof sig);
9014 png_read_info (png_ptr, info_ptr);
9015 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
9016 &interlace_type, NULL, NULL);
9017
9018 /* If image contains simply transparency data, we prefer to
9019 construct a clipping mask. */
9020 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
9021 transparent_p = 1;
9022 else
9023 transparent_p = 0;
9024
9025 /* This function is easier to write if we only have to handle
9026 one data format: RGB or RGBA with 8 bits per channel. Let's
9027 transform other formats into that format. */
9028
9029 /* Strip more than 8 bits per channel. */
9030 if (bit_depth == 16)
9031 png_set_strip_16 (png_ptr);
9032
9033 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
9034 if available. */
9035 png_set_expand (png_ptr);
9036
9037 /* Convert grayscale images to RGB. */
9038 if (color_type == PNG_COLOR_TYPE_GRAY
9039 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9040 png_set_gray_to_rgb (png_ptr);
9041
d4405ed7 9042 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
333b20bb
GM
9043
9044 /* Tell the PNG lib to handle gamma correction for us. */
9045
6c1aa34d 9046#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
333b20bb 9047 if (png_get_sRGB (png_ptr, info_ptr, &intent))
d4405ed7
RS
9048 /* The libpng documentation says this is right in this case. */
9049 png_set_gamma (png_ptr, screen_gamma, 0.45455);
6c1aa34d
GM
9050 else
9051#endif
9052 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
333b20bb
GM
9053 /* Image contains gamma information. */
9054 png_set_gamma (png_ptr, screen_gamma, image_gamma);
9055 else
d4405ed7
RS
9056 /* Use the standard default for the image gamma. */
9057 png_set_gamma (png_ptr, screen_gamma, 0.45455);
333b20bb
GM
9058
9059 /* Handle alpha channel by combining the image with a background
9060 color. Do this only if a real alpha channel is supplied. For
9061 simple transparency, we prefer a clipping mask. */
9062 if (!transparent_p)
9063 {
f20a3b7a
MB
9064 png_color_16 *image_bg;
9065 Lisp_Object specified_bg
9066 = image_spec_value (img->spec, QCbackground, NULL);
9067
f2f0a644 9068 if (STRINGP (specified_bg))
f20a3b7a
MB
9069 /* The user specified `:background', use that. */
9070 {
9071 XColor color;
f2f0a644 9072 if (x_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
f20a3b7a
MB
9073 {
9074 png_color_16 user_bg;
9075
9076 bzero (&user_bg, sizeof user_bg);
9077 user_bg.red = color.red;
9078 user_bg.green = color.green;
9079 user_bg.blue = color.blue;
333b20bb 9080
f20a3b7a
MB
9081 png_set_background (png_ptr, &user_bg,
9082 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9083 }
9084 }
9085 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
333b20bb
GM
9086 /* Image contains a background color with which to
9087 combine the image. */
f20a3b7a 9088 png_set_background (png_ptr, image_bg,
333b20bb
GM
9089 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
9090 else
9091 {
9092 /* Image does not contain a background color with which
9093 to combine the image data via an alpha channel. Use
9094 the frame's background instead. */
9095 XColor color;
9096 Colormap cmap;
9097 png_color_16 frame_background;
9098
9b2956e2 9099 cmap = FRAME_X_COLORMAP (f);
333b20bb 9100 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a31fedb7 9101 x_query_color (f, &color);
333b20bb
GM
9102
9103 bzero (&frame_background, sizeof frame_background);
9104 frame_background.red = color.red;
9105 frame_background.green = color.green;
9106 frame_background.blue = color.blue;
9107
9108 png_set_background (png_ptr, &frame_background,
9109 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9110 }
9111 }
9112
9113 /* Update info structure. */
9114 png_read_update_info (png_ptr, info_ptr);
9115
9116 /* Get number of channels. Valid values are 1 for grayscale images
9117 and images with a palette, 2 for grayscale images with transparency
9118 information (alpha channel), 3 for RGB images, and 4 for RGB
9119 images with alpha channel, i.e. RGBA. If conversions above were
9120 sufficient we should only have 3 or 4 channels here. */
9121 channels = png_get_channels (png_ptr, info_ptr);
9122 xassert (channels == 3 || channels == 4);
9123
9124 /* Number of bytes needed for one row of the image. */
9125 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
9126
9127 /* Allocate memory for the image. */
9128 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
9129 rows = (png_byte **) xmalloc (height * sizeof *rows);
9130 for (i = 0; i < height; ++i)
9131 rows[i] = pixels + i * row_bytes;
9132
9133 /* Read the entire image. */
9134 png_read_image (png_ptr, rows);
9135 png_read_end (png_ptr, info_ptr);
5ad6a5fb
GM
9136 if (fp)
9137 {
9138 fclose (fp);
9139 fp = NULL;
9140 }
333b20bb 9141
333b20bb 9142 /* Create the X image and pixmap. */
45158a91 9143 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
333b20bb 9144 &img->pixmap))
28c7826c 9145 goto error;
333b20bb
GM
9146
9147 /* Create an image and pixmap serving as mask if the PNG image
9148 contains an alpha channel. */
9149 if (channels == 4
9150 && !transparent_p
45158a91 9151 && !x_create_x_image_and_pixmap (f, width, height, 1,
333b20bb
GM
9152 &mask_img, &img->mask))
9153 {
9154 x_destroy_x_image (ximg);
9155 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 9156 img->pixmap = None;
333b20bb
GM
9157 goto error;
9158 }
9159
9160 /* Fill the X image and mask from PNG data. */
9161 init_color_table ();
9162
9163 for (y = 0; y < height; ++y)
9164 {
9165 png_byte *p = rows[y];
9166
9167 for (x = 0; x < width; ++x)
9168 {
9169 unsigned r, g, b;
9170
9171 r = *p++ << 8;
9172 g = *p++ << 8;
9173 b = *p++ << 8;
9174 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9175
9176 /* An alpha channel, aka mask channel, associates variable
9177 transparency with an image. Where other image formats
9178 support binary transparency---fully transparent or fully
9179 opaque---PNG allows up to 254 levels of partial transparency.
9180 The PNG library implements partial transparency by combining
9181 the image with a specified background color.
9182
9183 I'm not sure how to handle this here nicely: because the
9184 background on which the image is displayed may change, for
9185 real alpha channel support, it would be necessary to create
9186 a new image for each possible background.
9187
9188 What I'm doing now is that a mask is created if we have
9189 boolean transparency information. Otherwise I'm using
9190 the frame's background color to combine the image with. */
9191
9192 if (channels == 4)
9193 {
9194 if (mask_img)
9195 XPutPixel (mask_img, x, y, *p > 0);
9196 ++p;
9197 }
9198 }
9199 }
9200
f20a3b7a
MB
9201 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9202 /* Set IMG's background color from the PNG image, unless the user
9203 overrode it. */
9204 {
9205 png_color_16 *bg;
9206 if (png_get_bKGD (png_ptr, info_ptr, &bg))
9207 {
f2f0a644 9208 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
f20a3b7a
MB
9209 img->background_valid = 1;
9210 }
9211 }
9212
333b20bb
GM
9213 /* Remember colors allocated for this image. */
9214 img->colors = colors_in_color_table (&img->ncolors);
9215 free_color_table ();
9216
9217 /* Clean up. */
9218 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9219 xfree (rows);
9220 xfree (pixels);
9221
9222 img->width = width;
9223 img->height = height;
9224
f20a3b7a
MB
9225 /* Maybe fill in the background field while we have ximg handy. */
9226 IMAGE_BACKGROUND (img, f, ximg);
9227
333b20bb
GM
9228 /* Put the image into the pixmap, then free the X image and its buffer. */
9229 x_put_x_image (f, ximg, img->pixmap, width, height);
9230 x_destroy_x_image (ximg);
9231
9232 /* Same for the mask. */
9233 if (mask_img)
9234 {
f20a3b7a
MB
9235 /* Fill in the background_transparent field while we have the mask
9236 handy. */
9237 image_background_transparent (img, f, mask_img);
9238
333b20bb
GM
9239 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9240 x_destroy_x_image (mask_img);
9241 }
9242
333b20bb
GM
9243 UNGCPRO;
9244 return 1;
9245}
9246
9247#endif /* HAVE_PNG != 0 */
9248
9249
9250\f
9251/***********************************************************************
9252 JPEG
9253 ***********************************************************************/
9254
9255#if HAVE_JPEG
9256
ba06aba4
GM
9257/* Work around a warning about HAVE_STDLIB_H being redefined in
9258 jconfig.h. */
9259#ifdef HAVE_STDLIB_H
9260#define HAVE_STDLIB_H_1
9261#undef HAVE_STDLIB_H
9262#endif /* HAVE_STLIB_H */
9263
333b20bb
GM
9264#include <jpeglib.h>
9265#include <jerror.h>
9266#include <setjmp.h>
9267
ba06aba4
GM
9268#ifdef HAVE_STLIB_H_1
9269#define HAVE_STDLIB_H 1
9270#endif
9271
333b20bb
GM
9272static int jpeg_image_p P_ ((Lisp_Object object));
9273static int jpeg_load P_ ((struct frame *f, struct image *img));
9274
9275/* The symbol `jpeg' identifying images of this type. */
9276
9277Lisp_Object Qjpeg;
9278
9279/* Indices of image specification fields in gs_format, below. */
9280
9281enum jpeg_keyword_index
9282{
9283 JPEG_TYPE,
8e39770a 9284 JPEG_DATA,
333b20bb
GM
9285 JPEG_FILE,
9286 JPEG_ASCENT,
9287 JPEG_MARGIN,
9288 JPEG_RELIEF,
9289 JPEG_ALGORITHM,
9290 JPEG_HEURISTIC_MASK,
4a8e312c 9291 JPEG_MASK,
f20a3b7a 9292 JPEG_BACKGROUND,
333b20bb
GM
9293 JPEG_LAST
9294};
9295
9296/* Vector of image_keyword structures describing the format
9297 of valid user-defined image specifications. */
9298
9299static struct image_keyword jpeg_format[JPEG_LAST] =
9300{
9301 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9302 {":data", IMAGE_STRING_VALUE, 0},
8e39770a 9303 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9304 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9305 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9306 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9307 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9308 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9309 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9310 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9311};
9312
9313/* Structure describing the image type `jpeg'. */
9314
9315static struct image_type jpeg_type =
9316{
9317 &Qjpeg,
9318 jpeg_image_p,
9319 jpeg_load,
9320 x_clear_image,
9321 NULL
9322};
9323
9324
9325/* Return non-zero if OBJECT is a valid JPEG image specification. */
9326
9327static int
9328jpeg_image_p (object)
9329 Lisp_Object object;
9330{
9331 struct image_keyword fmt[JPEG_LAST];
9332
9333 bcopy (jpeg_format, fmt, sizeof fmt);
9334
7c7ff7f5 9335 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
333b20bb 9336 return 0;
8e39770a 9337
63cec32f
GM
9338 /* Must specify either the :data or :file keyword. */
9339 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
333b20bb
GM
9340}
9341
8e39770a 9342
333b20bb
GM
9343struct my_jpeg_error_mgr
9344{
9345 struct jpeg_error_mgr pub;
9346 jmp_buf setjmp_buffer;
9347};
9348
e3130015 9349
333b20bb
GM
9350static void
9351my_error_exit (cinfo)
9352 j_common_ptr cinfo;
9353{
9354 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
9355 longjmp (mgr->setjmp_buffer, 1);
9356}
9357
e3130015 9358
8e39770a
GM
9359/* Init source method for JPEG data source manager. Called by
9360 jpeg_read_header() before any data is actually read. See
9361 libjpeg.doc from the JPEG lib distribution. */
9362
9363static void
9364our_init_source (cinfo)
9365 j_decompress_ptr cinfo;
9366{
9367}
9368
9369
9370/* Fill input buffer method for JPEG data source manager. Called
9371 whenever more data is needed. We read the whole image in one step,
9372 so this only adds a fake end of input marker at the end. */
9373
9374static boolean
9375our_fill_input_buffer (cinfo)
9376 j_decompress_ptr cinfo;
9377{
9378 /* Insert a fake EOI marker. */
9379 struct jpeg_source_mgr *src = cinfo->src;
9380 static JOCTET buffer[2];
9381
9382 buffer[0] = (JOCTET) 0xFF;
9383 buffer[1] = (JOCTET) JPEG_EOI;
9384
9385 src->next_input_byte = buffer;
9386 src->bytes_in_buffer = 2;
9387 return TRUE;
9388}
9389
9390
9391/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
9392 is the JPEG data source manager. */
9393
9394static void
9395our_skip_input_data (cinfo, num_bytes)
9396 j_decompress_ptr cinfo;
9397 long num_bytes;
9398{
9399 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
9400
9401 if (src)
9402 {
9403 if (num_bytes > src->bytes_in_buffer)
5ad6a5fb 9404 ERREXIT (cinfo, JERR_INPUT_EOF);
8e39770a
GM
9405
9406 src->bytes_in_buffer -= num_bytes;
9407 src->next_input_byte += num_bytes;
9408 }
9409}
9410
9411
9412/* Method to terminate data source. Called by
9413 jpeg_finish_decompress() after all data has been processed. */
9414
9415static void
9416our_term_source (cinfo)
9417 j_decompress_ptr cinfo;
9418{
9419}
9420
9421
9422/* Set up the JPEG lib for reading an image from DATA which contains
9423 LEN bytes. CINFO is the decompression info structure created for
9424 reading the image. */
9425
9426static void
9427jpeg_memory_src (cinfo, data, len)
9428 j_decompress_ptr cinfo;
9429 JOCTET *data;
9430 unsigned int len;
9431{
9432 struct jpeg_source_mgr *src;
9433
9434 if (cinfo->src == NULL)
9435 {
9436 /* First time for this JPEG object? */
9437 cinfo->src = (struct jpeg_source_mgr *)
9438 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
9439 sizeof (struct jpeg_source_mgr));
9440 src = (struct jpeg_source_mgr *) cinfo->src;
9441 src->next_input_byte = data;
9442 }
9443
9444 src = (struct jpeg_source_mgr *) cinfo->src;
9445 src->init_source = our_init_source;
9446 src->fill_input_buffer = our_fill_input_buffer;
9447 src->skip_input_data = our_skip_input_data;
9448 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
9449 src->term_source = our_term_source;
9450 src->bytes_in_buffer = len;
9451 src->next_input_byte = data;
9452}
9453
5ad6a5fb 9454
333b20bb
GM
9455/* Load image IMG for use on frame F. Patterned after example.c
9456 from the JPEG lib. */
9457
9458static int
9459jpeg_load (f, img)
9460 struct frame *f;
9461 struct image *img;
9462{
9463 struct jpeg_decompress_struct cinfo;
9464 struct my_jpeg_error_mgr mgr;
9465 Lisp_Object file, specified_file;
8e39770a 9466 Lisp_Object specified_data;
8ec8a5ec 9467 FILE * volatile fp = NULL;
333b20bb
GM
9468 JSAMPARRAY buffer;
9469 int row_stride, x, y;
9470 XImage *ximg = NULL;
b6d7acec 9471 int rc;
333b20bb
GM
9472 unsigned long *colors;
9473 int width, height;
9474 struct gcpro gcpro1;
9475
9476 /* Open the JPEG file. */
9477 specified_file = image_spec_value (img->spec, QCfile, NULL);
8e39770a 9478 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9479 file = Qnil;
9480 GCPRO1 (file);
8e39770a 9481
8e39770a 9482 if (NILP (specified_data))
333b20bb 9483 {
8e39770a 9484 file = x_find_image_file (specified_file);
8e39770a
GM
9485 if (!STRINGP (file))
9486 {
45158a91 9487 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8e39770a
GM
9488 UNGCPRO;
9489 return 0;
9490 }
333b20bb 9491
8e39770a
GM
9492 fp = fopen (XSTRING (file)->data, "r");
9493 if (fp == NULL)
9494 {
9495 image_error ("Cannot open `%s'", file, Qnil);
9496 UNGCPRO;
9497 return 0;
9498 }
333b20bb
GM
9499 }
9500
5ad6a5fb
GM
9501 /* Customize libjpeg's error handling to call my_error_exit when an
9502 error is detected. This function will perform a longjmp. */
333b20bb 9503 cinfo.err = jpeg_std_error (&mgr.pub);
14358466 9504 mgr.pub.error_exit = my_error_exit;
333b20bb
GM
9505
9506 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
9507 {
5ad6a5fb
GM
9508 if (rc == 1)
9509 {
9510 /* Called from my_error_exit. Display a JPEG error. */
9511 char buffer[JMSG_LENGTH_MAX];
9512 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
45158a91 9513 image_error ("Error reading JPEG image `%s': %s", img->spec,
5ad6a5fb
GM
9514 build_string (buffer));
9515 }
333b20bb
GM
9516
9517 /* Close the input file and destroy the JPEG object. */
5ad6a5fb 9518 if (fp)
8ec8a5ec 9519 fclose ((FILE *) fp);
333b20bb
GM
9520 jpeg_destroy_decompress (&cinfo);
9521
5ad6a5fb
GM
9522 /* If we already have an XImage, free that. */
9523 x_destroy_x_image (ximg);
333b20bb 9524
5ad6a5fb
GM
9525 /* Free pixmap and colors. */
9526 x_clear_image (f, img);
333b20bb 9527
5ad6a5fb
GM
9528 UNGCPRO;
9529 return 0;
333b20bb
GM
9530 }
9531
9532 /* Create the JPEG decompression object. Let it read from fp.
63448a4d 9533 Read the JPEG image header. */
333b20bb 9534 jpeg_create_decompress (&cinfo);
8e39770a
GM
9535
9536 if (NILP (specified_data))
8ec8a5ec 9537 jpeg_stdio_src (&cinfo, (FILE *) fp);
8e39770a
GM
9538 else
9539 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
9540 STRING_BYTES (XSTRING (specified_data)));
63448a4d 9541
333b20bb
GM
9542 jpeg_read_header (&cinfo, TRUE);
9543
9544 /* Customize decompression so that color quantization will be used.
63448a4d 9545 Start decompression. */
333b20bb
GM
9546 cinfo.quantize_colors = TRUE;
9547 jpeg_start_decompress (&cinfo);
9548 width = img->width = cinfo.output_width;
9549 height = img->height = cinfo.output_height;
9550
333b20bb 9551 /* Create X image and pixmap. */
45158a91 9552 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
28c7826c 9553 longjmp (mgr.setjmp_buffer, 2);
333b20bb
GM
9554
9555 /* Allocate colors. When color quantization is used,
5ad6a5fb
GM
9556 cinfo.actual_number_of_colors has been set with the number of
9557 colors generated, and cinfo.colormap is a two-dimensional array
9558 of color indices in the range 0..cinfo.actual_number_of_colors.
9559 No more than 255 colors will be generated. */
333b20bb 9560 {
5ad6a5fb
GM
9561 int i, ir, ig, ib;
9562
9563 if (cinfo.out_color_components > 2)
9564 ir = 0, ig = 1, ib = 2;
9565 else if (cinfo.out_color_components > 1)
9566 ir = 0, ig = 1, ib = 0;
9567 else
9568 ir = 0, ig = 0, ib = 0;
9569
9570 /* Use the color table mechanism because it handles colors that
9571 cannot be allocated nicely. Such colors will be replaced with
9572 a default color, and we don't have to care about which colors
9573 can be freed safely, and which can't. */
9574 init_color_table ();
9575 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
9576 * sizeof *colors);
333b20bb 9577
5ad6a5fb
GM
9578 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
9579 {
9580 /* Multiply RGB values with 255 because X expects RGB values
9581 in the range 0..0xffff. */
9582 int r = cinfo.colormap[ir][i] << 8;
9583 int g = cinfo.colormap[ig][i] << 8;
9584 int b = cinfo.colormap[ib][i] << 8;
9585 colors[i] = lookup_rgb_color (f, r, g, b);
9586 }
333b20bb 9587
5ad6a5fb
GM
9588 /* Remember those colors actually allocated. */
9589 img->colors = colors_in_color_table (&img->ncolors);
9590 free_color_table ();
333b20bb
GM
9591 }
9592
9593 /* Read pixels. */
9594 row_stride = width * cinfo.output_components;
9595 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
5ad6a5fb 9596 row_stride, 1);
333b20bb
GM
9597 for (y = 0; y < height; ++y)
9598 {
5ad6a5fb
GM
9599 jpeg_read_scanlines (&cinfo, buffer, 1);
9600 for (x = 0; x < cinfo.output_width; ++x)
9601 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
333b20bb
GM
9602 }
9603
9604 /* Clean up. */
9605 jpeg_finish_decompress (&cinfo);
9606 jpeg_destroy_decompress (&cinfo);
5ad6a5fb 9607 if (fp)
8ec8a5ec 9608 fclose ((FILE *) fp);
f20a3b7a
MB
9609
9610 /* Maybe fill in the background field while we have ximg handy. */
9611 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9612 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9613
9614 /* Put the image into the pixmap. */
9615 x_put_x_image (f, ximg, img->pixmap, width, height);
9616 x_destroy_x_image (ximg);
333b20bb
GM
9617 UNGCPRO;
9618 return 1;
9619}
9620
9621#endif /* HAVE_JPEG */
9622
9623
9624\f
9625/***********************************************************************
9626 TIFF
9627 ***********************************************************************/
9628
9629#if HAVE_TIFF
9630
cf4790ad 9631#include <tiffio.h>
333b20bb
GM
9632
9633static int tiff_image_p P_ ((Lisp_Object object));
9634static int tiff_load P_ ((struct frame *f, struct image *img));
9635
9636/* The symbol `tiff' identifying images of this type. */
9637
9638Lisp_Object Qtiff;
9639
9640/* Indices of image specification fields in tiff_format, below. */
9641
9642enum tiff_keyword_index
9643{
9644 TIFF_TYPE,
63448a4d 9645 TIFF_DATA,
333b20bb
GM
9646 TIFF_FILE,
9647 TIFF_ASCENT,
9648 TIFF_MARGIN,
9649 TIFF_RELIEF,
9650 TIFF_ALGORITHM,
9651 TIFF_HEURISTIC_MASK,
4a8e312c 9652 TIFF_MASK,
f20a3b7a 9653 TIFF_BACKGROUND,
333b20bb
GM
9654 TIFF_LAST
9655};
9656
9657/* Vector of image_keyword structures describing the format
9658 of valid user-defined image specifications. */
9659
9660static struct image_keyword tiff_format[TIFF_LAST] =
9661{
9662 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9663 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9664 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9665 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9666 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9667 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9668 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9669 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9670 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9671 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9672};
9673
9674/* Structure describing the image type `tiff'. */
9675
9676static struct image_type tiff_type =
9677{
9678 &Qtiff,
9679 tiff_image_p,
9680 tiff_load,
9681 x_clear_image,
9682 NULL
9683};
9684
9685
9686/* Return non-zero if OBJECT is a valid TIFF image specification. */
9687
9688static int
9689tiff_image_p (object)
9690 Lisp_Object object;
9691{
9692 struct image_keyword fmt[TIFF_LAST];
9693 bcopy (tiff_format, fmt, sizeof fmt);
9694
7c7ff7f5 9695 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
333b20bb 9696 return 0;
5ad6a5fb 9697
63cec32f
GM
9698 /* Must specify either the :data or :file keyword. */
9699 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
333b20bb
GM
9700}
9701
5ad6a5fb
GM
9702
9703/* Reading from a memory buffer for TIFF images Based on the PNG
9704 memory source, but we have to provide a lot of extra functions.
9705 Blah.
63448a4d
WP
9706
9707 We really only need to implement read and seek, but I am not
9708 convinced that the TIFF library is smart enough not to destroy
9709 itself if we only hand it the function pointers we need to
5ad6a5fb
GM
9710 override. */
9711
9712typedef struct
9713{
63448a4d
WP
9714 unsigned char *bytes;
9715 size_t len;
9716 int index;
5ad6a5fb
GM
9717}
9718tiff_memory_source;
63448a4d 9719
e3130015 9720
5ad6a5fb
GM
9721static size_t
9722tiff_read_from_memory (data, buf, size)
9723 thandle_t data;
9724 tdata_t buf;
9725 tsize_t size;
63448a4d 9726{
5ad6a5fb 9727 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9728
9729 if (size > src->len - src->index)
5ad6a5fb
GM
9730 return (size_t) -1;
9731 bcopy (src->bytes + src->index, buf, size);
63448a4d
WP
9732 src->index += size;
9733 return size;
9734}
9735
e3130015 9736
5ad6a5fb
GM
9737static size_t
9738tiff_write_from_memory (data, buf, size)
9739 thandle_t data;
9740 tdata_t buf;
9741 tsize_t size;
63448a4d
WP
9742{
9743 return (size_t) -1;
9744}
9745
e3130015 9746
5ad6a5fb
GM
9747static toff_t
9748tiff_seek_in_memory (data, off, whence)
9749 thandle_t data;
9750 toff_t off;
9751 int whence;
63448a4d 9752{
5ad6a5fb 9753 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9754 int idx;
9755
9756 switch (whence)
5ad6a5fb
GM
9757 {
9758 case SEEK_SET: /* Go from beginning of source. */
9759 idx = off;
9760 break;
9761
9762 case SEEK_END: /* Go from end of source. */
9763 idx = src->len + off;
9764 break;
9765
9766 case SEEK_CUR: /* Go from current position. */
9767 idx = src->index + off;
9768 break;
9769
9770 default: /* Invalid `whence'. */
9771 return -1;
9772 }
9773
9774 if (idx > src->len || idx < 0)
9775 return -1;
9776
63448a4d
WP
9777 src->index = idx;
9778 return src->index;
9779}
9780
e3130015 9781
5ad6a5fb
GM
9782static int
9783tiff_close_memory (data)
9784 thandle_t data;
63448a4d
WP
9785{
9786 /* NOOP */
5ad6a5fb 9787 return 0;
63448a4d
WP
9788}
9789
e3130015 9790
5ad6a5fb
GM
9791static int
9792tiff_mmap_memory (data, pbase, psize)
9793 thandle_t data;
9794 tdata_t *pbase;
9795 toff_t *psize;
63448a4d
WP
9796{
9797 /* It is already _IN_ memory. */
5ad6a5fb 9798 return 0;
63448a4d
WP
9799}
9800
e3130015 9801
5ad6a5fb
GM
9802static void
9803tiff_unmap_memory (data, base, size)
9804 thandle_t data;
9805 tdata_t base;
9806 toff_t size;
63448a4d
WP
9807{
9808 /* We don't need to do this. */
63448a4d
WP
9809}
9810
e3130015 9811
5ad6a5fb
GM
9812static toff_t
9813tiff_size_of_memory (data)
9814 thandle_t data;
63448a4d 9815{
5ad6a5fb 9816 return ((tiff_memory_source *) data)->len;
63448a4d 9817}
333b20bb 9818
e3130015 9819
c6892044
GM
9820static void
9821tiff_error_handler (title, format, ap)
9822 const char *title, *format;
9823 va_list ap;
9824{
9825 char buf[512];
9826 int len;
9827
9828 len = sprintf (buf, "TIFF error: %s ", title);
9829 vsprintf (buf + len, format, ap);
9830 add_to_log (buf, Qnil, Qnil);
9831}
9832
9833
9834static void
9835tiff_warning_handler (title, format, ap)
9836 const char *title, *format;
9837 va_list ap;
9838{
9839 char buf[512];
9840 int len;
9841
9842 len = sprintf (buf, "TIFF warning: %s ", title);
9843 vsprintf (buf + len, format, ap);
9844 add_to_log (buf, Qnil, Qnil);
9845}
9846
9847
333b20bb
GM
9848/* Load TIFF image IMG for use on frame F. Value is non-zero if
9849 successful. */
9850
9851static int
9852tiff_load (f, img)
9853 struct frame *f;
9854 struct image *img;
9855{
9856 Lisp_Object file, specified_file;
63448a4d 9857 Lisp_Object specified_data;
333b20bb
GM
9858 TIFF *tiff;
9859 int width, height, x, y;
9860 uint32 *buf;
9861 int rc;
9862 XImage *ximg;
9863 struct gcpro gcpro1;
63448a4d 9864 tiff_memory_source memsrc;
333b20bb
GM
9865
9866 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9867 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9868 file = Qnil;
9869 GCPRO1 (file);
63448a4d 9870
c6892044
GM
9871 TIFFSetErrorHandler (tiff_error_handler);
9872 TIFFSetWarningHandler (tiff_warning_handler);
9873
63448a4d 9874 if (NILP (specified_data))
5ad6a5fb
GM
9875 {
9876 /* Read from a file */
9877 file = x_find_image_file (specified_file);
9878 if (!STRINGP (file))
63448a4d 9879 {
45158a91 9880 image_error ("Cannot find image file `%s'", file, Qnil);
5ad6a5fb
GM
9881 UNGCPRO;
9882 return 0;
9883 }
63448a4d 9884
5ad6a5fb
GM
9885 /* Try to open the image file. */
9886 tiff = TIFFOpen (XSTRING (file)->data, "r");
9887 if (tiff == NULL)
9888 {
9889 image_error ("Cannot open `%s'", file, Qnil);
9890 UNGCPRO;
9891 return 0;
63448a4d 9892 }
5ad6a5fb 9893 }
63448a4d 9894 else
5ad6a5fb
GM
9895 {
9896 /* Memory source! */
9897 memsrc.bytes = XSTRING (specified_data)->data;
9898 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9899 memsrc.index = 0;
9900
9901 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9902 (TIFFReadWriteProc) tiff_read_from_memory,
9903 (TIFFReadWriteProc) tiff_write_from_memory,
9904 tiff_seek_in_memory,
9905 tiff_close_memory,
9906 tiff_size_of_memory,
9907 tiff_mmap_memory,
9908 tiff_unmap_memory);
9909
9910 if (!tiff)
63448a4d 9911 {
45158a91 9912 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
5ad6a5fb
GM
9913 UNGCPRO;
9914 return 0;
63448a4d 9915 }
5ad6a5fb 9916 }
333b20bb
GM
9917
9918 /* Get width and height of the image, and allocate a raster buffer
9919 of width x height 32-bit values. */
9920 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9921 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9922 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9923
9924 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9925 TIFFClose (tiff);
9926 if (!rc)
9927 {
45158a91 9928 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
333b20bb
GM
9929 xfree (buf);
9930 UNGCPRO;
9931 return 0;
9932 }
9933
333b20bb 9934 /* Create the X image and pixmap. */
45158a91 9935 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9936 {
333b20bb
GM
9937 xfree (buf);
9938 UNGCPRO;
9939 return 0;
9940 }
9941
9942 /* Initialize the color table. */
9943 init_color_table ();
9944
9945 /* Process the pixel raster. Origin is in the lower-left corner. */
9946 for (y = 0; y < height; ++y)
9947 {
9948 uint32 *row = buf + y * width;
9949
9950 for (x = 0; x < width; ++x)
9951 {
9952 uint32 abgr = row[x];
9953 int r = TIFFGetR (abgr) << 8;
9954 int g = TIFFGetG (abgr) << 8;
9955 int b = TIFFGetB (abgr) << 8;
9956 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9957 }
9958 }
9959
9960 /* Remember the colors allocated for the image. Free the color table. */
9961 img->colors = colors_in_color_table (&img->ncolors);
9962 free_color_table ();
f20a3b7a
MB
9963
9964 img->width = width;
9965 img->height = height;
9966
9967 /* Maybe fill in the background field while we have ximg handy. */
9968 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9969 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9970
9971 /* Put the image into the pixmap, then free the X image and its buffer. */
9972 x_put_x_image (f, ximg, img->pixmap, width, height);
9973 x_destroy_x_image (ximg);
9974 xfree (buf);
333b20bb
GM
9975
9976 UNGCPRO;
9977 return 1;
9978}
9979
9980#endif /* HAVE_TIFF != 0 */
9981
9982
9983\f
9984/***********************************************************************
9985 GIF
9986 ***********************************************************************/
9987
9988#if HAVE_GIF
9989
9990#include <gif_lib.h>
9991
9992static int gif_image_p P_ ((Lisp_Object object));
9993static int gif_load P_ ((struct frame *f, struct image *img));
9994
9995/* The symbol `gif' identifying images of this type. */
9996
9997Lisp_Object Qgif;
9998
9999/* Indices of image specification fields in gif_format, below. */
10000
10001enum gif_keyword_index
10002{
10003 GIF_TYPE,
63448a4d 10004 GIF_DATA,
333b20bb
GM
10005 GIF_FILE,
10006 GIF_ASCENT,
10007 GIF_MARGIN,
10008 GIF_RELIEF,
10009 GIF_ALGORITHM,
10010 GIF_HEURISTIC_MASK,
4a8e312c 10011 GIF_MASK,
333b20bb 10012 GIF_IMAGE,
f20a3b7a 10013 GIF_BACKGROUND,
333b20bb
GM
10014 GIF_LAST
10015};
10016
10017/* Vector of image_keyword structures describing the format
10018 of valid user-defined image specifications. */
10019
10020static struct image_keyword gif_format[GIF_LAST] =
10021{
10022 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 10023 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 10024 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 10025 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10026 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10027 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10028 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 10029 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10030 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 10031 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
f20a3b7a 10032 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10033};
10034
10035/* Structure describing the image type `gif'. */
10036
10037static struct image_type gif_type =
10038{
10039 &Qgif,
10040 gif_image_p,
10041 gif_load,
10042 x_clear_image,
10043 NULL
10044};
10045
e3130015 10046
333b20bb
GM
10047/* Return non-zero if OBJECT is a valid GIF image specification. */
10048
10049static int
10050gif_image_p (object)
10051 Lisp_Object object;
10052{
10053 struct image_keyword fmt[GIF_LAST];
10054 bcopy (gif_format, fmt, sizeof fmt);
10055
7c7ff7f5 10056 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
333b20bb 10057 return 0;
5ad6a5fb 10058
63cec32f
GM
10059 /* Must specify either the :data or :file keyword. */
10060 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
333b20bb
GM
10061}
10062
e3130015 10063
63448a4d
WP
10064/* Reading a GIF image from memory
10065 Based on the PNG memory stuff to a certain extent. */
10066
5ad6a5fb
GM
10067typedef struct
10068{
63448a4d
WP
10069 unsigned char *bytes;
10070 size_t len;
10071 int index;
5ad6a5fb
GM
10072}
10073gif_memory_source;
63448a4d 10074
e3130015 10075
f036834a
GM
10076/* Make the current memory source available to gif_read_from_memory.
10077 It's done this way because not all versions of libungif support
10078 a UserData field in the GifFileType structure. */
10079static gif_memory_source *current_gif_memory_src;
10080
5ad6a5fb
GM
10081static int
10082gif_read_from_memory (file, buf, len)
10083 GifFileType *file;
10084 GifByteType *buf;
10085 int len;
63448a4d 10086{
f036834a 10087 gif_memory_source *src = current_gif_memory_src;
63448a4d 10088
5ad6a5fb
GM
10089 if (len > src->len - src->index)
10090 return -1;
63448a4d 10091
5ad6a5fb 10092 bcopy (src->bytes + src->index, buf, len);
63448a4d
WP
10093 src->index += len;
10094 return len;
10095}
333b20bb 10096
5ad6a5fb 10097
333b20bb
GM
10098/* Load GIF image IMG for use on frame F. Value is non-zero if
10099 successful. */
10100
10101static int
10102gif_load (f, img)
10103 struct frame *f;
10104 struct image *img;
10105{
10106 Lisp_Object file, specified_file;
63448a4d 10107 Lisp_Object specified_data;
333b20bb
GM
10108 int rc, width, height, x, y, i;
10109 XImage *ximg;
10110 ColorMapObject *gif_color_map;
10111 unsigned long pixel_colors[256];
10112 GifFileType *gif;
10113 struct gcpro gcpro1;
10114 Lisp_Object image;
10115 int ino, image_left, image_top, image_width, image_height;
63448a4d 10116 gif_memory_source memsrc;
9b784e96 10117 unsigned char *raster;
333b20bb
GM
10118
10119 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 10120 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
10121 file = Qnil;
10122 GCPRO1 (file);
63448a4d
WP
10123
10124 if (NILP (specified_data))
5ad6a5fb
GM
10125 {
10126 file = x_find_image_file (specified_file);
10127 if (!STRINGP (file))
63448a4d 10128 {
45158a91 10129 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
10130 UNGCPRO;
10131 return 0;
10132 }
333b20bb 10133
5ad6a5fb
GM
10134 /* Open the GIF file. */
10135 gif = DGifOpenFileName (XSTRING (file)->data);
10136 if (gif == NULL)
10137 {
10138 image_error ("Cannot open `%s'", file, Qnil);
10139 UNGCPRO;
10140 return 0;
63448a4d 10141 }
5ad6a5fb 10142 }
63448a4d 10143 else
5ad6a5fb
GM
10144 {
10145 /* Read from memory! */
f036834a 10146 current_gif_memory_src = &memsrc;
5ad6a5fb
GM
10147 memsrc.bytes = XSTRING (specified_data)->data;
10148 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10149 memsrc.index = 0;
63448a4d 10150
5ad6a5fb
GM
10151 gif = DGifOpen(&memsrc, gif_read_from_memory);
10152 if (!gif)
10153 {
45158a91 10154 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
5ad6a5fb
GM
10155 UNGCPRO;
10156 return 0;
63448a4d 10157 }
5ad6a5fb 10158 }
333b20bb
GM
10159
10160 /* Read entire contents. */
10161 rc = DGifSlurp (gif);
10162 if (rc == GIF_ERROR)
10163 {
45158a91 10164 image_error ("Error reading `%s'", img->spec, Qnil);
333b20bb
GM
10165 DGifCloseFile (gif);
10166 UNGCPRO;
10167 return 0;
10168 }
10169
3ccff1e3 10170 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
10171 ino = INTEGERP (image) ? XFASTINT (image) : 0;
10172 if (ino >= gif->ImageCount)
10173 {
45158a91
GM
10174 image_error ("Invalid image number `%s' in image `%s'",
10175 image, img->spec);
333b20bb
GM
10176 DGifCloseFile (gif);
10177 UNGCPRO;
10178 return 0;
10179 }
10180
c7f07c4c
PJ
10181 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
10182 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
333b20bb 10183
333b20bb 10184 /* Create the X image and pixmap. */
45158a91 10185 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 10186 {
333b20bb
GM
10187 DGifCloseFile (gif);
10188 UNGCPRO;
10189 return 0;
10190 }
10191
10192 /* Allocate colors. */
10193 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
10194 if (!gif_color_map)
10195 gif_color_map = gif->SColorMap;
10196 init_color_table ();
10197 bzero (pixel_colors, sizeof pixel_colors);
10198
10199 for (i = 0; i < gif_color_map->ColorCount; ++i)
10200 {
10201 int r = gif_color_map->Colors[i].Red << 8;
10202 int g = gif_color_map->Colors[i].Green << 8;
10203 int b = gif_color_map->Colors[i].Blue << 8;
10204 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
10205 }
10206
10207 img->colors = colors_in_color_table (&img->ncolors);
10208 free_color_table ();
10209
10210 /* Clear the part of the screen image that are not covered by
10211 the image from the GIF file. Full animated GIF support
10212 requires more than can be done here (see the gif89 spec,
10213 disposal methods). Let's simply assume that the part
10214 not covered by a sub-image is in the frame's background color. */
10215 image_top = gif->SavedImages[ino].ImageDesc.Top;
10216 image_left = gif->SavedImages[ino].ImageDesc.Left;
10217 image_width = gif->SavedImages[ino].ImageDesc.Width;
10218 image_height = gif->SavedImages[ino].ImageDesc.Height;
10219
10220 for (y = 0; y < image_top; ++y)
10221 for (x = 0; x < width; ++x)
10222 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10223
10224 for (y = image_top + image_height; y < height; ++y)
10225 for (x = 0; x < width; ++x)
10226 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10227
10228 for (y = image_top; y < image_top + image_height; ++y)
10229 {
10230 for (x = 0; x < image_left; ++x)
10231 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10232 for (x = image_left + image_width; x < width; ++x)
10233 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10234 }
10235
9b784e96
GM
10236 /* Read the GIF image into the X image. We use a local variable
10237 `raster' here because RasterBits below is a char *, and invites
10238 problems with bytes >= 0x80. */
10239 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
10240
333b20bb
GM
10241 if (gif->SavedImages[ino].ImageDesc.Interlace)
10242 {
10243 static int interlace_start[] = {0, 4, 2, 1};
10244 static int interlace_increment[] = {8, 8, 4, 2};
9b207e8e 10245 int pass;
06482119
GM
10246 int row = interlace_start[0];
10247
10248 pass = 0;
333b20bb 10249
06482119 10250 for (y = 0; y < image_height; y++)
333b20bb 10251 {
06482119
GM
10252 if (row >= image_height)
10253 {
10254 row = interlace_start[++pass];
10255 while (row >= image_height)
10256 row = interlace_start[++pass];
10257 }
10258
10259 for (x = 0; x < image_width; x++)
10260 {
9b784e96 10261 int i = raster[(y * image_width) + x];
06482119
GM
10262 XPutPixel (ximg, x + image_left, row + image_top,
10263 pixel_colors[i]);
10264 }
10265
10266 row += interlace_increment[pass];
333b20bb
GM
10267 }
10268 }
10269 else
10270 {
10271 for (y = 0; y < image_height; ++y)
10272 for (x = 0; x < image_width; ++x)
10273 {
9b784e96 10274 int i = raster[y * image_width + x];
333b20bb
GM
10275 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
10276 }
10277 }
10278
10279 DGifCloseFile (gif);
f20a3b7a
MB
10280
10281 /* Maybe fill in the background field while we have ximg handy. */
10282 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10283 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
10284
10285 /* Put the image into the pixmap, then free the X image and its buffer. */
10286 x_put_x_image (f, ximg, img->pixmap, width, height);
10287 x_destroy_x_image (ximg);
333b20bb
GM
10288
10289 UNGCPRO;
10290 return 1;
10291}
10292
10293#endif /* HAVE_GIF != 0 */
10294
10295
10296\f
10297/***********************************************************************
10298 Ghostscript
10299 ***********************************************************************/
10300
10301static int gs_image_p P_ ((Lisp_Object object));
10302static int gs_load P_ ((struct frame *f, struct image *img));
10303static void gs_clear_image P_ ((struct frame *f, struct image *img));
10304
fcf431dc 10305/* The symbol `postscript' identifying images of this type. */
333b20bb 10306
fcf431dc 10307Lisp_Object Qpostscript;
333b20bb
GM
10308
10309/* Keyword symbols. */
10310
10311Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
10312
10313/* Indices of image specification fields in gs_format, below. */
10314
10315enum gs_keyword_index
10316{
10317 GS_TYPE,
10318 GS_PT_WIDTH,
10319 GS_PT_HEIGHT,
10320 GS_FILE,
10321 GS_LOADER,
10322 GS_BOUNDING_BOX,
10323 GS_ASCENT,
10324 GS_MARGIN,
10325 GS_RELIEF,
10326 GS_ALGORITHM,
10327 GS_HEURISTIC_MASK,
4a8e312c 10328 GS_MASK,
f20a3b7a 10329 GS_BACKGROUND,
333b20bb
GM
10330 GS_LAST
10331};
10332
10333/* Vector of image_keyword structures describing the format
10334 of valid user-defined image specifications. */
10335
10336static struct image_keyword gs_format[GS_LAST] =
10337{
10338 {":type", IMAGE_SYMBOL_VALUE, 1},
10339 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10340 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10341 {":file", IMAGE_STRING_VALUE, 1},
10342 {":loader", IMAGE_FUNCTION_VALUE, 0},
10343 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7c7ff7f5 10344 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10345 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10346 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10347 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10348 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
10349 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10350 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10351};
10352
10353/* Structure describing the image type `ghostscript'. */
10354
10355static struct image_type gs_type =
10356{
fcf431dc 10357 &Qpostscript,
333b20bb
GM
10358 gs_image_p,
10359 gs_load,
10360 gs_clear_image,
10361 NULL
10362};
10363
10364
10365/* Free X resources of Ghostscript image IMG which is used on frame F. */
10366
10367static void
10368gs_clear_image (f, img)
10369 struct frame *f;
10370 struct image *img;
10371{
10372 /* IMG->data.ptr_val may contain a recorded colormap. */
10373 xfree (img->data.ptr_val);
10374 x_clear_image (f, img);
10375}
10376
10377
10378/* Return non-zero if OBJECT is a valid Ghostscript image
10379 specification. */
10380
10381static int
10382gs_image_p (object)
10383 Lisp_Object object;
10384{
10385 struct image_keyword fmt[GS_LAST];
10386 Lisp_Object tem;
10387 int i;
10388
10389 bcopy (gs_format, fmt, sizeof fmt);
10390
7c7ff7f5 10391 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
333b20bb
GM
10392 return 0;
10393
10394 /* Bounding box must be a list or vector containing 4 integers. */
10395 tem = fmt[GS_BOUNDING_BOX].value;
10396 if (CONSP (tem))
10397 {
10398 for (i = 0; i < 4; ++i, tem = XCDR (tem))
10399 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
10400 return 0;
10401 if (!NILP (tem))
10402 return 0;
10403 }
10404 else if (VECTORP (tem))
10405 {
10406 if (XVECTOR (tem)->size != 4)
10407 return 0;
10408 for (i = 0; i < 4; ++i)
10409 if (!INTEGERP (XVECTOR (tem)->contents[i]))
10410 return 0;
10411 }
10412 else
10413 return 0;
10414
10415 return 1;
10416}
10417
10418
10419/* Load Ghostscript image IMG for use on frame F. Value is non-zero
10420 if successful. */
10421
10422static int
10423gs_load (f, img)
10424 struct frame *f;
10425 struct image *img;
10426{
10427 char buffer[100];
10428 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
10429 struct gcpro gcpro1, gcpro2;
10430 Lisp_Object frame;
10431 double in_width, in_height;
10432 Lisp_Object pixel_colors = Qnil;
10433
10434 /* Compute pixel size of pixmap needed from the given size in the
10435 image specification. Sizes in the specification are in pt. 1 pt
10436 = 1/72 in, xdpi and ydpi are stored in the frame's X display
10437 info. */
10438 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
10439 in_width = XFASTINT (pt_width) / 72.0;
10440 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
10441 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
10442 in_height = XFASTINT (pt_height) / 72.0;
10443 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
10444
10445 /* Create the pixmap. */
dd00328a 10446 xassert (img->pixmap == None);
333b20bb
GM
10447 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10448 img->width, img->height,
10449 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
333b20bb
GM
10450
10451 if (!img->pixmap)
10452 {
45158a91 10453 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
10454 return 0;
10455 }
10456
10457 /* Call the loader to fill the pixmap. It returns a process object
10458 if successful. We do not record_unwind_protect here because
10459 other places in redisplay like calling window scroll functions
10460 don't either. Let the Lisp loader use `unwind-protect' instead. */
10461 GCPRO2 (window_and_pixmap_id, pixel_colors);
10462
10463 sprintf (buffer, "%lu %lu",
10464 (unsigned long) FRAME_X_WINDOW (f),
10465 (unsigned long) img->pixmap);
10466 window_and_pixmap_id = build_string (buffer);
10467
10468 sprintf (buffer, "%lu %lu",
10469 FRAME_FOREGROUND_PIXEL (f),
10470 FRAME_BACKGROUND_PIXEL (f));
10471 pixel_colors = build_string (buffer);
10472
10473 XSETFRAME (frame, f);
10474 loader = image_spec_value (img->spec, QCloader, NULL);
10475 if (NILP (loader))
10476 loader = intern ("gs-load-image");
10477
10478 img->data.lisp_val = call6 (loader, frame, img->spec,
10479 make_number (img->width),
10480 make_number (img->height),
10481 window_and_pixmap_id,
10482 pixel_colors);
10483 UNGCPRO;
10484 return PROCESSP (img->data.lisp_val);
10485}
10486
10487
10488/* Kill the Ghostscript process that was started to fill PIXMAP on
10489 frame F. Called from XTread_socket when receiving an event
10490 telling Emacs that Ghostscript has finished drawing. */
10491
10492void
10493x_kill_gs_process (pixmap, f)
10494 Pixmap pixmap;
10495 struct frame *f;
10496{
10497 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
10498 int class, i;
10499 struct image *img;
10500
10501 /* Find the image containing PIXMAP. */
10502 for (i = 0; i < c->used; ++i)
10503 if (c->images[i]->pixmap == pixmap)
10504 break;
10505
daba7643
GM
10506 /* Should someone in between have cleared the image cache, for
10507 instance, give up. */
10508 if (i == c->used)
10509 return;
10510
333b20bb
GM
10511 /* Kill the GS process. We should have found PIXMAP in the image
10512 cache and its image should contain a process object. */
333b20bb
GM
10513 img = c->images[i];
10514 xassert (PROCESSP (img->data.lisp_val));
10515 Fkill_process (img->data.lisp_val, Qnil);
10516 img->data.lisp_val = Qnil;
10517
10518 /* On displays with a mutable colormap, figure out the colors
10519 allocated for the image by looking at the pixels of an XImage for
10520 img->pixmap. */
383d6ffc 10521 class = FRAME_X_VISUAL (f)->class;
333b20bb
GM
10522 if (class != StaticColor && class != StaticGray && class != TrueColor)
10523 {
10524 XImage *ximg;
10525
10526 BLOCK_INPUT;
10527
10528 /* Try to get an XImage for img->pixmep. */
10529 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10530 0, 0, img->width, img->height, ~0, ZPixmap);
10531 if (ximg)
10532 {
10533 int x, y;
10534
10535 /* Initialize the color table. */
10536 init_color_table ();
10537
10538 /* For each pixel of the image, look its color up in the
10539 color table. After having done so, the color table will
10540 contain an entry for each color used by the image. */
10541 for (y = 0; y < img->height; ++y)
10542 for (x = 0; x < img->width; ++x)
10543 {
10544 unsigned long pixel = XGetPixel (ximg, x, y);
10545 lookup_pixel_color (f, pixel);
10546 }
10547
10548 /* Record colors in the image. Free color table and XImage. */
10549 img->colors = colors_in_color_table (&img->ncolors);
10550 free_color_table ();
10551 XDestroyImage (ximg);
10552
10553#if 0 /* This doesn't seem to be the case. If we free the colors
10554 here, we get a BadAccess later in x_clear_image when
10555 freeing the colors. */
10556 /* We have allocated colors once, but Ghostscript has also
10557 allocated colors on behalf of us. So, to get the
10558 reference counts right, free them once. */
10559 if (img->ncolors)
462d5d40 10560 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
10561#endif
10562 }
10563 else
10564 image_error ("Cannot get X image of `%s'; colors will not be freed",
45158a91 10565 img->spec, Qnil);
333b20bb
GM
10566
10567 UNBLOCK_INPUT;
10568 }
ad18ffb1
GM
10569
10570 /* Now that we have the pixmap, compute mask and transform the
10571 image if requested. */
10572 BLOCK_INPUT;
10573 postprocess_image (f, img);
10574 UNBLOCK_INPUT;
333b20bb
GM
10575}
10576
10577
10578\f
10579/***********************************************************************
10580 Window properties
10581 ***********************************************************************/
10582
10583DEFUN ("x-change-window-property", Fx_change_window_property,
10584 Sx_change_window_property, 2, 3, 0,
7ee72033 10585 doc: /* Change window property PROP to VALUE on the X window of FRAME.
c061c855 10586PROP and VALUE must be strings. FRAME nil or omitted means use the
7ee72033
MB
10587selected frame. Value is VALUE. */)
10588 (prop, value, frame)
333b20bb
GM
10589 Lisp_Object frame, prop, value;
10590{
10591 struct frame *f = check_x_frame (frame);
10592 Atom prop_atom;
10593
b7826503
PJ
10594 CHECK_STRING (prop);
10595 CHECK_STRING (value);
333b20bb
GM
10596
10597 BLOCK_INPUT;
10598 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10599 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10600 prop_atom, XA_STRING, 8, PropModeReplace,
10601 XSTRING (value)->data, XSTRING (value)->size);
10602
10603 /* Make sure the property is set when we return. */
10604 XFlush (FRAME_X_DISPLAY (f));
10605 UNBLOCK_INPUT;
10606
10607 return value;
10608}
10609
10610
10611DEFUN ("x-delete-window-property", Fx_delete_window_property,
10612 Sx_delete_window_property, 1, 2, 0,
7ee72033
MB
10613 doc: /* Remove window property PROP from X window of FRAME.
10614FRAME nil or omitted means use the selected frame. Value is PROP. */)
10615 (prop, frame)
333b20bb
GM
10616 Lisp_Object prop, frame;
10617{
10618 struct frame *f = check_x_frame (frame);
10619 Atom prop_atom;
10620
b7826503 10621 CHECK_STRING (prop);
333b20bb
GM
10622 BLOCK_INPUT;
10623 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10624 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
10625
10626 /* Make sure the property is removed when we return. */
10627 XFlush (FRAME_X_DISPLAY (f));
10628 UNBLOCK_INPUT;
10629
10630 return prop;
10631}
10632
10633
10634DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
10635 1, 2, 0,
7ee72033 10636 doc: /* Value is the value of window property PROP on FRAME.
c061c855
GM
10637If FRAME is nil or omitted, use the selected frame. Value is nil
10638if FRAME hasn't a property with name PROP or if PROP has no string
7ee72033
MB
10639value. */)
10640 (prop, frame)
333b20bb
GM
10641 Lisp_Object prop, frame;
10642{
10643 struct frame *f = check_x_frame (frame);
10644 Atom prop_atom;
10645 int rc;
10646 Lisp_Object prop_value = Qnil;
10647 char *tmp_data = NULL;
10648 Atom actual_type;
10649 int actual_format;
10650 unsigned long actual_size, bytes_remaining;
10651
b7826503 10652 CHECK_STRING (prop);
333b20bb
GM
10653 BLOCK_INPUT;
10654 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10655 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10656 prop_atom, 0, 0, False, XA_STRING,
10657 &actual_type, &actual_format, &actual_size,
10658 &bytes_remaining, (unsigned char **) &tmp_data);
10659 if (rc == Success)
10660 {
10661 int size = bytes_remaining;
10662
10663 XFree (tmp_data);
10664 tmp_data = NULL;
10665
10666 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10667 prop_atom, 0, bytes_remaining,
10668 False, XA_STRING,
10669 &actual_type, &actual_format,
10670 &actual_size, &bytes_remaining,
10671 (unsigned char **) &tmp_data);
4c8c7926 10672 if (rc == Success && tmp_data)
333b20bb
GM
10673 prop_value = make_string (tmp_data, size);
10674
10675 XFree (tmp_data);
10676 }
10677
10678 UNBLOCK_INPUT;
10679 return prop_value;
10680}
10681
10682
10683\f
10684/***********************************************************************
10685 Busy cursor
10686 ***********************************************************************/
10687
4ae9a85e 10688/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 10689 an hourglass cursor on all frames. */
333b20bb 10690
0af913d7 10691static struct atimer *hourglass_atimer;
333b20bb 10692
0af913d7 10693/* Non-zero means an hourglass cursor is currently shown. */
333b20bb 10694
0af913d7 10695static int hourglass_shown_p;
333b20bb 10696
0af913d7 10697/* Number of seconds to wait before displaying an hourglass cursor. */
333b20bb 10698
0af913d7 10699static Lisp_Object Vhourglass_delay;
333b20bb 10700
0af913d7 10701/* Default number of seconds to wait before displaying an hourglass
4ae9a85e
GM
10702 cursor. */
10703
0af913d7 10704#define DEFAULT_HOURGLASS_DELAY 1
4ae9a85e
GM
10705
10706/* Function prototypes. */
10707
0af913d7
GM
10708static void show_hourglass P_ ((struct atimer *));
10709static void hide_hourglass P_ ((void));
4ae9a85e
GM
10710
10711
0af913d7 10712/* Cancel a currently active hourglass timer, and start a new one. */
4ae9a85e
GM
10713
10714void
0af913d7 10715start_hourglass ()
333b20bb 10716{
4ae9a85e 10717 EMACS_TIME delay;
3caa99d3 10718 int secs, usecs = 0;
4ae9a85e 10719
0af913d7 10720 cancel_hourglass ();
4ae9a85e 10721
0af913d7
GM
10722 if (INTEGERP (Vhourglass_delay)
10723 && XINT (Vhourglass_delay) > 0)
10724 secs = XFASTINT (Vhourglass_delay);
10725 else if (FLOATP (Vhourglass_delay)
10726 && XFLOAT_DATA (Vhourglass_delay) > 0)
3caa99d3
GM
10727 {
10728 Lisp_Object tem;
0af913d7 10729 tem = Ftruncate (Vhourglass_delay, Qnil);
3caa99d3 10730 secs = XFASTINT (tem);
0af913d7 10731 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
3caa99d3 10732 }
4ae9a85e 10733 else
0af913d7 10734 secs = DEFAULT_HOURGLASS_DELAY;
4ae9a85e 10735
3caa99d3 10736 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
10737 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
10738 show_hourglass, NULL);
4ae9a85e
GM
10739}
10740
10741
0af913d7 10742/* Cancel the hourglass cursor timer if active, hide a busy cursor if
4ae9a85e
GM
10743 shown. */
10744
10745void
0af913d7 10746cancel_hourglass ()
4ae9a85e 10747{
0af913d7 10748 if (hourglass_atimer)
99f01f62 10749 {
0af913d7
GM
10750 cancel_atimer (hourglass_atimer);
10751 hourglass_atimer = NULL;
99f01f62
GM
10752 }
10753
0af913d7
GM
10754 if (hourglass_shown_p)
10755 hide_hourglass ();
4ae9a85e
GM
10756}
10757
10758
0af913d7
GM
10759/* Timer function of hourglass_atimer. TIMER is equal to
10760 hourglass_atimer.
4ae9a85e 10761
0af913d7
GM
10762 Display an hourglass pointer on all frames by mapping the frames'
10763 hourglass_window. Set the hourglass_p flag in the frames'
10764 output_data.x structure to indicate that an hourglass cursor is
10765 shown on the frames. */
4ae9a85e
GM
10766
10767static void
0af913d7 10768show_hourglass (timer)
4ae9a85e
GM
10769 struct atimer *timer;
10770{
10771 /* The timer implementation will cancel this timer automatically
0af913d7 10772 after this function has run. Set hourglass_atimer to null
4ae9a85e 10773 so that we know the timer doesn't have to be canceled. */
0af913d7 10774 hourglass_atimer = NULL;
4ae9a85e 10775
0af913d7 10776 if (!hourglass_shown_p)
333b20bb
GM
10777 {
10778 Lisp_Object rest, frame;
4ae9a85e
GM
10779
10780 BLOCK_INPUT;
10781
333b20bb 10782 FOR_EACH_FRAME (rest, frame)
5f7a1890
GM
10783 {
10784 struct frame *f = XFRAME (frame);
10785
10786 if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
10787 {
10788 Display *dpy = FRAME_X_DISPLAY (f);
10789
10790#ifdef USE_X_TOOLKIT
10791 if (f->output_data.x->widget)
10792#else
10793 if (FRAME_OUTER_WINDOW (f))
10794#endif
10795 {
0af913d7 10796 f->output_data.x->hourglass_p = 1;
4ae9a85e 10797
0af913d7 10798 if (!f->output_data.x->hourglass_window)
5f7a1890
GM
10799 {
10800 unsigned long mask = CWCursor;
10801 XSetWindowAttributes attrs;
4ae9a85e 10802
0af913d7 10803 attrs.cursor = f->output_data.x->hourglass_cursor;
4ae9a85e 10804
0af913d7 10805 f->output_data.x->hourglass_window
5f7a1890
GM
10806 = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
10807 0, 0, 32000, 32000, 0, 0,
10808 InputOnly,
10809 CopyFromParent,
10810 mask, &attrs);
10811 }
4ae9a85e 10812
0af913d7 10813 XMapRaised (dpy, f->output_data.x->hourglass_window);
5f7a1890
GM
10814 XFlush (dpy);
10815 }
10816 }
10817 }
333b20bb 10818
0af913d7 10819 hourglass_shown_p = 1;
4ae9a85e
GM
10820 UNBLOCK_INPUT;
10821 }
333b20bb
GM
10822}
10823
10824
0af913d7
GM
10825/* Hide the hourglass pointer on all frames, if it is currently
10826 shown. */
333b20bb 10827
4ae9a85e 10828static void
0af913d7 10829hide_hourglass ()
4ae9a85e 10830{
0af913d7 10831 if (hourglass_shown_p)
333b20bb 10832 {
4ae9a85e
GM
10833 Lisp_Object rest, frame;
10834
10835 BLOCK_INPUT;
10836 FOR_EACH_FRAME (rest, frame)
333b20bb 10837 {
4ae9a85e
GM
10838 struct frame *f = XFRAME (frame);
10839
10840 if (FRAME_X_P (f)
10841 /* Watch out for newly created frames. */
0af913d7 10842 && f->output_data.x->hourglass_window)
4ae9a85e 10843 {
0af913d7
GM
10844 XUnmapWindow (FRAME_X_DISPLAY (f),
10845 f->output_data.x->hourglass_window);
10846 /* Sync here because XTread_socket looks at the
10847 hourglass_p flag that is reset to zero below. */
4ae9a85e 10848 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 10849 f->output_data.x->hourglass_p = 0;
4ae9a85e 10850 }
333b20bb 10851 }
333b20bb 10852
0af913d7 10853 hourglass_shown_p = 0;
4ae9a85e
GM
10854 UNBLOCK_INPUT;
10855 }
333b20bb
GM
10856}
10857
10858
10859\f
10860/***********************************************************************
10861 Tool tips
10862 ***********************************************************************/
10863
10864static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
275841bf 10865 Lisp_Object, Lisp_Object));
06d62053 10866static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
ab452f99 10867 Lisp_Object, int, int, int *, int *));
333b20bb 10868
44b5a125 10869/* The frame of a currently visible tooltip. */
333b20bb 10870
44b5a125 10871Lisp_Object tip_frame;
333b20bb
GM
10872
10873/* If non-nil, a timer started that hides the last tooltip when it
10874 fires. */
10875
10876Lisp_Object tip_timer;
10877Window tip_window;
10878
06d62053
GM
10879/* If non-nil, a vector of 3 elements containing the last args
10880 with which x-show-tip was called. See there. */
10881
10882Lisp_Object last_show_tip_args;
10883
d63931a2
GM
10884/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
10885
10886Lisp_Object Vx_max_tooltip_size;
10887
eaf1eea9
GM
10888
10889static Lisp_Object
10890unwind_create_tip_frame (frame)
10891 Lisp_Object frame;
10892{
c844a81a
GM
10893 Lisp_Object deleted;
10894
10895 deleted = unwind_create_frame (frame);
10896 if (EQ (deleted, Qt))
10897 {
10898 tip_window = None;
10899 tip_frame = Qnil;
10900 }
10901
10902 return deleted;
eaf1eea9
GM
10903}
10904
10905
333b20bb 10906/* Create a frame for a tooltip on the display described by DPYINFO.
275841bf
GM
10907 PARMS is a list of frame parameters. TEXT is the string to
10908 display in the tip frame. Value is the frame.
eaf1eea9
GM
10909
10910 Note that functions called here, esp. x_default_parameter can
10911 signal errors, for instance when a specified color name is
10912 undefined. We have to make sure that we're in a consistent state
10913 when this happens. */
333b20bb
GM
10914
10915static Lisp_Object
275841bf 10916x_create_tip_frame (dpyinfo, parms, text)
333b20bb 10917 struct x_display_info *dpyinfo;
275841bf 10918 Lisp_Object parms, text;
333b20bb
GM
10919{
10920 struct frame *f;
10921 Lisp_Object frame, tem;
10922 Lisp_Object name;
333b20bb
GM
10923 long window_prompting = 0;
10924 int width, height;
eaf1eea9 10925 int count = BINDING_STACK_SIZE ();
b6d7acec 10926 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb 10927 struct kboard *kb;
06d62053 10928 int face_change_count_before = face_change_count;
275841bf
GM
10929 Lisp_Object buffer;
10930 struct buffer *old_buffer;
333b20bb
GM
10931
10932 check_x ();
10933
10934 /* Use this general default value to start with until we know if
10935 this frame has a specified name. */
10936 Vx_resource_name = Vinvocation_name;
10937
10938#ifdef MULTI_KBOARD
10939 kb = dpyinfo->kboard;
10940#else
10941 kb = &the_only_kboard;
10942#endif
10943
10944 /* Get the name of the frame to use for resource lookup. */
10945 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10946 if (!STRINGP (name)
10947 && !EQ (name, Qunbound)
10948 && !NILP (name))
10949 error ("Invalid frame name--not a string or nil");
10950 Vx_resource_name = name;
10951
10952 frame = Qnil;
10953 GCPRO3 (parms, name, frame);
44b5a125 10954 f = make_frame (1);
333b20bb 10955 XSETFRAME (frame, f);
275841bf
GM
10956
10957 buffer = Fget_buffer_create (build_string (" *tip*"));
10958 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10959 old_buffer = current_buffer;
10960 set_buffer_internal_1 (XBUFFER (buffer));
d63931a2 10961 current_buffer->truncate_lines = Qnil;
275841bf
GM
10962 Ferase_buffer ();
10963 Finsert (1, &text);
10964 set_buffer_internal_1 (old_buffer);
10965
333b20bb 10966 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
8a1a7743 10967 record_unwind_protect (unwind_create_tip_frame, frame);
333b20bb 10968
eaf1eea9
GM
10969 /* By setting the output method, we're essentially saying that
10970 the frame is live, as per FRAME_LIVE_P. If we get a signal
10971 from this point on, x_destroy_window might screw up reference
10972 counts etc. */
333b20bb
GM
10973 f->output_method = output_x_window;
10974 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10975 bzero (f->output_data.x, sizeof (struct x_output));
10976 f->output_data.x->icon_bitmap = -1;
10977 f->output_data.x->fontset = -1;
61d461a8
GM
10978 f->output_data.x->scroll_bar_foreground_pixel = -1;
10979 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
10980#ifdef USE_TOOLKIT_SCROLL_BARS
10981 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
10982 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
10983#endif /* USE_TOOLKIT_SCROLL_BARS */
333b20bb
GM
10984 f->icon_name = Qnil;
10985 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 10986#if GLYPH_DEBUG
eaf1eea9
GM
10987 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
10988 dpyinfo_refcount = dpyinfo->reference_count;
10989#endif /* GLYPH_DEBUG */
333b20bb
GM
10990#ifdef MULTI_KBOARD
10991 FRAME_KBOARD (f) = kb;
10992#endif
10993 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10994 f->output_data.x->explicit_parent = 0;
10995
61d461a8
GM
10996 /* These colors will be set anyway later, but it's important
10997 to get the color reference counts right, so initialize them! */
10998 {
10999 Lisp_Object black;
11000 struct gcpro gcpro1;
11001
11002 black = build_string ("black");
11003 GCPRO1 (black);
11004 f->output_data.x->foreground_pixel
11005 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11006 f->output_data.x->background_pixel
11007 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11008 f->output_data.x->cursor_pixel
11009 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11010 f->output_data.x->cursor_foreground_pixel
11011 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11012 f->output_data.x->border_pixel
11013 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11014 f->output_data.x->mouse_pixel
11015 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11016 UNGCPRO;
11017 }
11018
333b20bb
GM
11019 /* Set the name; the functions to which we pass f expect the name to
11020 be set. */
11021 if (EQ (name, Qunbound) || NILP (name))
11022 {
11023 f->name = build_string (dpyinfo->x_id_name);
11024 f->explicit_name = 0;
11025 }
11026 else
11027 {
11028 f->name = name;
11029 f->explicit_name = 1;
11030 /* use the frame's title when getting resources for this frame. */
11031 specbind (Qx_resource_name, name);
11032 }
11033
eaf1eea9
GM
11034 /* Extract the window parameters from the supplied values that are
11035 needed to determine window geometry. */
333b20bb
GM
11036 {
11037 Lisp_Object font;
11038
11039 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
11040
11041 BLOCK_INPUT;
11042 /* First, try whatever font the caller has specified. */
11043 if (STRINGP (font))
11044 {
11045 tem = Fquery_fontset (font, Qnil);
11046 if (STRINGP (tem))
11047 font = x_new_fontset (f, XSTRING (tem)->data);
11048 else
11049 font = x_new_font (f, XSTRING (font)->data);
11050 }
11051
11052 /* Try out a font which we hope has bold and italic variations. */
11053 if (!STRINGP (font))
11054 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
11055 if (!STRINGP (font))
11056 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11057 if (! STRINGP (font))
11058 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11059 if (! STRINGP (font))
11060 /* This was formerly the first thing tried, but it finds too many fonts
11061 and takes too long. */
11062 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
11063 /* If those didn't work, look for something which will at least work. */
11064 if (! STRINGP (font))
11065 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
11066 UNBLOCK_INPUT;
11067 if (! STRINGP (font))
11068 font = build_string ("fixed");
11069
11070 x_default_parameter (f, parms, Qfont, font,
11071 "font", "Font", RES_TYPE_STRING);
11072 }
11073
11074 x_default_parameter (f, parms, Qborder_width, make_number (2),
11075 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
11076
11077 /* This defaults to 2 in order to match xterm. We recognize either
11078 internalBorderWidth or internalBorder (which is what xterm calls
11079 it). */
11080 if (NILP (Fassq (Qinternal_border_width, parms)))
11081 {
11082 Lisp_Object value;
11083
11084 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
11085 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
11086 if (! EQ (value, Qunbound))
11087 parms = Fcons (Fcons (Qinternal_border_width, value),
11088 parms);
11089 }
11090
11091 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
11092 "internalBorderWidth", "internalBorderWidth",
11093 RES_TYPE_NUMBER);
11094
11095 /* Also do the stuff which must be set before the window exists. */
11096 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
11097 "foreground", "Foreground", RES_TYPE_STRING);
11098 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
11099 "background", "Background", RES_TYPE_STRING);
11100 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
11101 "pointerColor", "Foreground", RES_TYPE_STRING);
11102 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
11103 "cursorColor", "Foreground", RES_TYPE_STRING);
11104 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
11105 "borderColor", "BorderColor", RES_TYPE_STRING);
11106
11107 /* Init faces before x_default_parameter is called for scroll-bar
11108 parameters because that function calls x_set_scroll_bar_width,
11109 which calls change_frame_size, which calls Fset_window_buffer,
11110 which runs hooks, which call Fvertical_motion. At the end, we
11111 end up in init_iterator with a null face cache, which should not
11112 happen. */
11113 init_frame_faces (f);
11114
11115 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
11116 window_prompting = x_figure_window_size (f, parms);
11117
11118 if (window_prompting & XNegative)
11119 {
11120 if (window_prompting & YNegative)
11121 f->output_data.x->win_gravity = SouthEastGravity;
11122 else
11123 f->output_data.x->win_gravity = NorthEastGravity;
11124 }
11125 else
11126 {
11127 if (window_prompting & YNegative)
11128 f->output_data.x->win_gravity = SouthWestGravity;
11129 else
11130 f->output_data.x->win_gravity = NorthWestGravity;
11131 }
11132
11133 f->output_data.x->size_hint_flags = window_prompting;
11134 {
11135 XSetWindowAttributes attrs;
11136 unsigned long mask;
11137
11138 BLOCK_INPUT;
c51d2b5e
GM
11139 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
11140 if (DoesSaveUnders (dpyinfo->screen))
11141 mask |= CWSaveUnder;
11142
9b2956e2
GM
11143 /* Window managers look at the override-redirect flag to determine
11144 whether or net to give windows a decoration (Xlib spec, chapter
333b20bb
GM
11145 3.2.8). */
11146 attrs.override_redirect = True;
11147 attrs.save_under = True;
11148 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
11149 /* Arrange for getting MapNotify and UnmapNotify events. */
11150 attrs.event_mask = StructureNotifyMask;
11151 tip_window
11152 = FRAME_X_WINDOW (f)
11153 = XCreateWindow (FRAME_X_DISPLAY (f),
11154 FRAME_X_DISPLAY_INFO (f)->root_window,
11155 /* x, y, width, height */
11156 0, 0, 1, 1,
11157 /* Border. */
11158 1,
11159 CopyFromParent, InputOutput, CopyFromParent,
11160 mask, &attrs);
11161 UNBLOCK_INPUT;
11162 }
11163
11164 x_make_gc (f);
11165
333b20bb
GM
11166 x_default_parameter (f, parms, Qauto_raise, Qnil,
11167 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11168 x_default_parameter (f, parms, Qauto_lower, Qnil,
11169 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11170 x_default_parameter (f, parms, Qcursor_type, Qbox,
11171 "cursorType", "CursorType", RES_TYPE_SYMBOL);
11172
11173 /* Dimensions, especially f->height, must be done via change_frame_size.
11174 Change will not be effected unless different from the current
11175 f->height. */
11176 width = f->width;
11177 height = f->height;
11178 f->height = 0;
11179 SET_FRAME_WIDTH (f, 0);
8938a4fb 11180 change_frame_size (f, height, width, 1, 0, 0);
333b20bb 11181
035d5114 11182 /* Set up faces after all frame parameters are known. This call
6801a572
GM
11183 also merges in face attributes specified for new frames.
11184
11185 Frame parameters may be changed if .Xdefaults contains
11186 specifications for the default font. For example, if there is an
11187 `Emacs.default.attributeBackground: pink', the `background-color'
11188 attribute of the frame get's set, which let's the internal border
11189 of the tooltip frame appear in pink. Prevent this. */
11190 {
11191 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
11192
11193 /* Set tip_frame here, so that */
11194 tip_frame = frame;
11195 call1 (Qface_set_after_frame_default, frame);
11196
11197 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
11198 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
11199 Qnil));
11200 }
035d5114 11201
333b20bb
GM
11202 f->no_split = 1;
11203
11204 UNGCPRO;
11205
11206 /* It is now ok to make the frame official even if we get an error
11207 below. And the frame needs to be on Vframe_list or making it
11208 visible won't work. */
11209 Vframe_list = Fcons (frame, Vframe_list);
11210
11211 /* Now that the frame is official, it counts as a reference to
11212 its display. */
11213 FRAME_X_DISPLAY_INFO (f)->reference_count++;
11214
06d62053
GM
11215 /* Setting attributes of faces of the tooltip frame from resources
11216 and similar will increment face_change_count, which leads to the
11217 clearing of all current matrices. Since this isn't necessary
11218 here, avoid it by resetting face_change_count to the value it
11219 had before we created the tip frame. */
11220 face_change_count = face_change_count_before;
11221
eaf1eea9 11222 /* Discard the unwind_protect. */
333b20bb
GM
11223 return unbind_to (count, frame);
11224}
11225
11226
06d62053
GM
11227/* Compute where to display tip frame F. PARMS is the list of frame
11228 parameters for F. DX and DY are specified offsets from the current
ab452f99
GM
11229 location of the mouse. WIDTH and HEIGHT are the width and height
11230 of the tooltip. Return coordinates relative to the root window of
11231 the display in *ROOT_X, and *ROOT_Y. */
06d62053
GM
11232
11233static void
ab452f99 11234compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
06d62053
GM
11235 struct frame *f;
11236 Lisp_Object parms, dx, dy;
ab452f99 11237 int width, height;
06d62053
GM
11238 int *root_x, *root_y;
11239{
11240 Lisp_Object left, top;
11241 int win_x, win_y;
11242 Window root, child;
11243 unsigned pmask;
11244
11245 /* User-specified position? */
11246 left = Fcdr (Fassq (Qleft, parms));
11247 top = Fcdr (Fassq (Qtop, parms));
11248
11249 /* Move the tooltip window where the mouse pointer is. Resize and
11250 show it. */
570d22b0 11251 if (!INTEGERP (left) || !INTEGERP (top))
ab452f99
GM
11252 {
11253 BLOCK_INPUT;
11254 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
11255 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
11256 UNBLOCK_INPUT;
11257 }
06d62053 11258
06d62053
GM
11259 if (INTEGERP (top))
11260 *root_y = XINT (top);
ab452f99
GM
11261 else if (*root_y + XINT (dy) - height < 0)
11262 *root_y -= XINT (dy);
11263 else
11264 {
11265 *root_y -= height;
11266 *root_y += XINT (dy);
11267 }
11268
11269 if (INTEGERP (left))
11270 *root_x = XINT (left);
d682d3df
RS
11271 else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width)
11272 /* It fits to the right of the pointer. */
11273 *root_x += XINT (dx);
11274 else if (width + XINT (dx) <= *root_x)
11275 /* It fits to the left of the pointer. */
ab452f99
GM
11276 *root_x -= width + XINT (dx);
11277 else
d682d3df
RS
11278 /* Put it left-justified on the screen--it ought to fit that way. */
11279 *root_x = 0;
06d62053
GM
11280}
11281
11282
0634ce98 11283DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
7ee72033 11284 doc: /* Show STRING in a "tooltip" window on frame FRAME.
c061c855
GM
11285A tooltip window is a small X window displaying a string.
11286
11287FRAME nil or omitted means use the selected frame.
11288
11289PARMS is an optional list of frame parameters which can be used to
11290change the tooltip's appearance.
11291
11292Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
11293means use the default timeout of 5 seconds.
11294
11295If the list of frame parameters PARAMS contains a `left' parameters,
11296the tooltip is displayed at that x-position. Otherwise it is
11297displayed at the mouse position, with offset DX added (default is 5 if
11298DX isn't specified). Likewise for the y-position; if a `top' frame
11299parameter is specified, it determines the y-position of the tooltip
11300window, otherwise it is displayed at the mouse position, with offset
11301DY added (default is -10).
11302
11303A tooltip's maximum size is specified by `x-max-tooltip-size'.
7ee72033
MB
11304Text larger than the specified size is clipped. */)
11305 (string, frame, parms, timeout, dx, dy)
0634ce98 11306 Lisp_Object string, frame, parms, timeout, dx, dy;
333b20bb
GM
11307{
11308 struct frame *f;
11309 struct window *w;
06d62053 11310 int root_x, root_y;
333b20bb
GM
11311 struct buffer *old_buffer;
11312 struct text_pos pos;
11313 int i, width, height;
393f2d14 11314 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
333b20bb 11315 int old_windows_or_buffers_changed = windows_or_buffers_changed;
06d62053 11316 int count = BINDING_STACK_SIZE ();
333b20bb
GM
11317
11318 specbind (Qinhibit_redisplay, Qt);
11319
393f2d14 11320 GCPRO4 (string, parms, frame, timeout);
333b20bb 11321
b7826503 11322 CHECK_STRING (string);
333b20bb
GM
11323 f = check_x_frame (frame);
11324 if (NILP (timeout))
11325 timeout = make_number (5);
11326 else
b7826503 11327 CHECK_NATNUM (timeout);
0634ce98
GM
11328
11329 if (NILP (dx))
11330 dx = make_number (5);
11331 else
b7826503 11332 CHECK_NUMBER (dx);
0634ce98
GM
11333
11334 if (NILP (dy))
12c67a7f 11335 dy = make_number (-10);
0634ce98 11336 else
b7826503 11337 CHECK_NUMBER (dy);
333b20bb 11338
06d62053
GM
11339 if (NILP (last_show_tip_args))
11340 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
11341
11342 if (!NILP (tip_frame))
11343 {
11344 Lisp_Object last_string = AREF (last_show_tip_args, 0);
11345 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
11346 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
11347
11348 if (EQ (frame, last_frame)
11349 && !NILP (Fequal (last_string, string))
11350 && !NILP (Fequal (last_parms, parms)))
11351 {
11352 struct frame *f = XFRAME (tip_frame);
11353
11354 /* Only DX and DY have changed. */
11355 if (!NILP (tip_timer))
ae782866
GM
11356 {
11357 Lisp_Object timer = tip_timer;
11358 tip_timer = Qnil;
11359 call1 (Qcancel_timer, timer);
11360 }
06d62053
GM
11361
11362 BLOCK_INPUT;
ab452f99
GM
11363 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
11364 PIXEL_HEIGHT (f), &root_x, &root_y);
06d62053 11365 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11366 root_x, root_y);
06d62053
GM
11367 UNBLOCK_INPUT;
11368 goto start_timer;
11369 }
11370 }
11371
333b20bb
GM
11372 /* Hide a previous tip, if any. */
11373 Fx_hide_tip ();
11374
06d62053
GM
11375 ASET (last_show_tip_args, 0, string);
11376 ASET (last_show_tip_args, 1, frame);
11377 ASET (last_show_tip_args, 2, parms);
11378
333b20bb
GM
11379 /* Add default values to frame parameters. */
11380 if (NILP (Fassq (Qname, parms)))
11381 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
11382 if (NILP (Fassq (Qinternal_border_width, parms)))
11383 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
11384 if (NILP (Fassq (Qborder_width, parms)))
11385 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
11386 if (NILP (Fassq (Qborder_color, parms)))
11387 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
11388 if (NILP (Fassq (Qbackground_color, parms)))
11389 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
11390 parms);
11391
11392 /* Create a frame for the tooltip, and record it in the global
11393 variable tip_frame. */
275841bf 11394 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
44b5a125 11395 f = XFRAME (frame);
333b20bb 11396
d63931a2 11397 /* Set up the frame's root window. */
333b20bb
GM
11398 w = XWINDOW (FRAME_ROOT_WINDOW (f));
11399 w->left = w->top = make_number (0);
d63931a2
GM
11400
11401 if (CONSP (Vx_max_tooltip_size)
11402 && INTEGERP (XCAR (Vx_max_tooltip_size))
11403 && XINT (XCAR (Vx_max_tooltip_size)) > 0
11404 && INTEGERP (XCDR (Vx_max_tooltip_size))
11405 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
11406 {
11407 w->width = XCAR (Vx_max_tooltip_size);
11408 w->height = XCDR (Vx_max_tooltip_size);
11409 }
11410 else
11411 {
11412 w->width = make_number (80);
11413 w->height = make_number (40);
11414 }
11415
11416 f->window_width = XINT (w->width);
333b20bb
GM
11417 adjust_glyphs (f);
11418 w->pseudo_window_p = 1;
11419
11420 /* Display the tooltip text in a temporary buffer. */
333b20bb 11421 old_buffer = current_buffer;
275841bf 11422 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
d63931a2 11423 current_buffer->truncate_lines = Qnil;
333b20bb
GM
11424 clear_glyph_matrix (w->desired_matrix);
11425 clear_glyph_matrix (w->current_matrix);
11426 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
11427 try_window (FRAME_ROOT_WINDOW (f), pos);
11428
11429 /* Compute width and height of the tooltip. */
11430 width = height = 0;
11431 for (i = 0; i < w->desired_matrix->nrows; ++i)
11432 {
11433 struct glyph_row *row = &w->desired_matrix->rows[i];
11434 struct glyph *last;
11435 int row_width;
11436
11437 /* Stop at the first empty row at the end. */
11438 if (!row->enabled_p || !row->displays_text_p)
11439 break;
11440
d7bf0342
GM
11441 /* Let the row go over the full width of the frame. */
11442 row->full_width_p = 1;
333b20bb 11443
e3130015 11444 /* There's a glyph at the end of rows that is used to place
333b20bb
GM
11445 the cursor there. Don't include the width of this glyph. */
11446 if (row->used[TEXT_AREA])
11447 {
11448 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
11449 row_width = row->pixel_width - last->pixel_width;
11450 }
11451 else
11452 row_width = row->pixel_width;
11453
11454 height += row->height;
11455 width = max (width, row_width);
11456 }
11457
11458 /* Add the frame's internal border to the width and height the X
11459 window should have. */
11460 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11461 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11462
11463 /* Move the tooltip window where the mouse pointer is. Resize and
11464 show it. */
ab452f99 11465 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
0634ce98 11466
0634ce98 11467 BLOCK_INPUT;
333b20bb 11468 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11469 root_x, root_y, width, height);
333b20bb
GM
11470 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11471 UNBLOCK_INPUT;
06d62053 11472
333b20bb
GM
11473 /* Draw into the window. */
11474 w->must_be_updated_p = 1;
11475 update_single_window (w, 1);
11476
11477 /* Restore original current buffer. */
11478 set_buffer_internal_1 (old_buffer);
11479 windows_or_buffers_changed = old_windows_or_buffers_changed;
11480
06d62053 11481 start_timer:
333b20bb
GM
11482 /* Let the tip disappear after timeout seconds. */
11483 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
11484 intern ("x-hide-tip"));
a744a2ec
DL
11485
11486 UNGCPRO;
333b20bb
GM
11487 return unbind_to (count, Qnil);
11488}
11489
11490
11491DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
7ee72033
MB
11492 doc: /* Hide the current tooltip window, if there is any.
11493Value is t if tooltip was open, nil otherwise. */)
11494 ()
333b20bb 11495{
44b5a125 11496 int count;
c0006262
GM
11497 Lisp_Object deleted, frame, timer;
11498 struct gcpro gcpro1, gcpro2;
44b5a125
GM
11499
11500 /* Return quickly if nothing to do. */
c0006262 11501 if (NILP (tip_timer) && NILP (tip_frame))
44b5a125 11502 return Qnil;
333b20bb 11503
c0006262
GM
11504 frame = tip_frame;
11505 timer = tip_timer;
11506 GCPRO2 (frame, timer);
11507 tip_frame = tip_timer = deleted = Qnil;
11508
44b5a125 11509 count = BINDING_STACK_SIZE ();
333b20bb 11510 specbind (Qinhibit_redisplay, Qt);
44b5a125 11511 specbind (Qinhibit_quit, Qt);
333b20bb 11512
c0006262 11513 if (!NILP (timer))
ae782866 11514 call1 (Qcancel_timer, timer);
333b20bb 11515
c0006262 11516 if (FRAMEP (frame))
333b20bb 11517 {
44b5a125
GM
11518 Fdelete_frame (frame, Qnil);
11519 deleted = Qt;
f6c44811
GM
11520
11521#ifdef USE_LUCID
11522 /* Bloodcurdling hack alert: The Lucid menu bar widget's
11523 redisplay procedure is not called when a tip frame over menu
11524 items is unmapped. Redisplay the menu manually... */
11525 {
11526 struct frame *f = SELECTED_FRAME ();
11527 Widget w = f->output_data.x->menubar_widget;
11528 extern void xlwmenu_redisplay P_ ((Widget));
9180dc8c 11529
f6c44811 11530 if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
dbc64aa7 11531 && w != NULL)
f6c44811
GM
11532 {
11533 BLOCK_INPUT;
11534 xlwmenu_redisplay (w);
11535 UNBLOCK_INPUT;
11536 }
11537 }
11538#endif /* USE_LUCID */
333b20bb
GM
11539 }
11540
c0006262 11541 UNGCPRO;
44b5a125 11542 return unbind_to (count, deleted);
333b20bb
GM
11543}
11544
11545
11546\f
11547/***********************************************************************
11548 File selection dialog
11549 ***********************************************************************/
11550
11551#ifdef USE_MOTIF
11552
11553/* Callback for "OK" and "Cancel" on file selection dialog. */
11554
11555static void
11556file_dialog_cb (widget, client_data, call_data)
11557 Widget widget;
11558 XtPointer call_data, client_data;
11559{
11560 int *result = (int *) client_data;
11561 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
11562 *result = cb->reason;
11563}
11564
11565
a779d213
GM
11566/* Callback for unmapping a file selection dialog. This is used to
11567 capture the case where a dialog is closed via a window manager's
11568 closer button, for example. Using a XmNdestroyCallback didn't work
11569 in this case. */
11570
11571static void
11572file_dialog_unmap_cb (widget, client_data, call_data)
11573 Widget widget;
11574 XtPointer call_data, client_data;
11575{
11576 int *result = (int *) client_data;
11577 *result = XmCR_CANCEL;
11578}
11579
11580
333b20bb 11581DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
7ee72033 11582 doc: /* Read file name, prompting with PROMPT in directory DIR.
c061c855
GM
11583Use a file selection dialog.
11584Select DEFAULT-FILENAME in the dialog's file selection box, if
11585specified. Don't let the user enter a file name in the file
7ee72033
MB
11586selection dialog's entry field, if MUSTMATCH is non-nil. */)
11587 (prompt, dir, default_filename, mustmatch)
333b20bb
GM
11588 Lisp_Object prompt, dir, default_filename, mustmatch;
11589{
11590 int result;
0fe92f72 11591 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
11592 Lisp_Object file = Qnil;
11593 Widget dialog, text, list, help;
11594 Arg al[10];
11595 int ac = 0;
11596 extern XtAppContext Xt_app_con;
333b20bb 11597 XmString dir_xmstring, pattern_xmstring;
333b20bb
GM
11598 int count = specpdl_ptr - specpdl;
11599 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
11600
11601 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
11602 CHECK_STRING (prompt);
11603 CHECK_STRING (dir);
333b20bb
GM
11604
11605 /* Prevent redisplay. */
11606 specbind (Qinhibit_redisplay, Qt);
11607
11608 BLOCK_INPUT;
11609
11610 /* Create the dialog with PROMPT as title, using DIR as initial
11611 directory and using "*" as pattern. */
11612 dir = Fexpand_file_name (dir, Qnil);
11613 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data);
11614 pattern_xmstring = XmStringCreateLocalized ("*");
11615
11616 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac;
11617 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
11618 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
11619 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
11620 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
11621 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
11622 "fsb", al, ac);
11623 XmStringFree (dir_xmstring);
11624 XmStringFree (pattern_xmstring);
11625
11626 /* Add callbacks for OK and Cancel. */
11627 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
11628 (XtPointer) &result);
11629 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
11630 (XtPointer) &result);
a779d213
GM
11631 XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
11632 (XtPointer) &result);
333b20bb
GM
11633
11634 /* Disable the help button since we can't display help. */
11635 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
11636 XtSetSensitive (help, False);
11637
11638 /* Mark OK button as default. */
11639 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
11640 XmNshowAsDefault, True, NULL);
11641
11642 /* If MUSTMATCH is non-nil, disable the file entry field of the
11643 dialog, so that the user must select a file from the files list
11644 box. We can't remove it because we wouldn't have a way to get at
11645 the result file name, then. */
11646 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
11647 if (!NILP (mustmatch))
11648 {
11649 Widget label;
11650 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
11651 XtSetSensitive (text, False);
11652 XtSetSensitive (label, False);
11653 }
11654
11655 /* Manage the dialog, so that list boxes get filled. */
11656 XtManageChild (dialog);
11657
11658 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
11659 must include the path for this to work. */
11660 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
11661 if (STRINGP (default_filename))
11662 {
11663 XmString default_xmstring;
11664 int item_pos;
11665
11666 default_xmstring
11667 = XmStringCreateLocalized (XSTRING (default_filename)->data);
11668
11669 if (!XmListItemExists (list, default_xmstring))
11670 {
11671 /* Add a new item if DEFAULT_FILENAME is not in the list. */
11672 XmListAddItem (list, default_xmstring, 0);
11673 item_pos = 0;
11674 }
11675 else
11676 item_pos = XmListItemPos (list, default_xmstring);
11677 XmStringFree (default_xmstring);
11678
11679 /* Select the item and scroll it into view. */
11680 XmListSelectPos (list, item_pos, True);
11681 XmListSetPos (list, item_pos);
11682 }
11683
563b384d
GM
11684 /* Process events until the user presses Cancel or OK. Block
11685 and unblock input here so that we get a chance of processing
11686 expose events. */
11687 UNBLOCK_INPUT;
03100098 11688 result = 0;
a779d213 11689 while (result == 0)
563b384d
GM
11690 {
11691 BLOCK_INPUT;
11692 XtAppProcessEvent (Xt_app_con, XtIMAll);
11693 UNBLOCK_INPUT;
11694 }
11695 BLOCK_INPUT;
03100098 11696
333b20bb
GM
11697 /* Get the result. */
11698 if (result == XmCR_OK)
11699 {
11700 XmString text;
11701 String data;
11702
d1670063 11703 XtVaGetValues (dialog, XmNtextString, &text, NULL);
333b20bb
GM
11704 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
11705 XmStringFree (text);
11706 file = build_string (data);
11707 XtFree (data);
11708 }
11709 else
11710 file = Qnil;
11711
11712 /* Clean up. */
11713 XtUnmanageChild (dialog);
11714 XtDestroyWidget (dialog);
11715 UNBLOCK_INPUT;
11716 UNGCPRO;
11717
11718 /* Make "Cancel" equivalent to C-g. */
11719 if (NILP (file))
11720 Fsignal (Qquit, Qnil);
11721
11722 return unbind_to (count, file);
11723}
11724
11725#endif /* USE_MOTIF */
11726
333b20bb
GM
11727
11728\f
82bab41c
GM
11729/***********************************************************************
11730 Keyboard
11731 ***********************************************************************/
11732
11733#ifdef HAVE_XKBGETKEYBOARD
11734#include <X11/XKBlib.h>
11735#include <X11/keysym.h>
11736#endif
11737
11738DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
11739 Sx_backspace_delete_keys_p, 0, 1, 0,
7ee72033 11740 doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME.
c061c855
GM
11741FRAME nil means use the selected frame.
11742Value is t if we know that both keys are present, and are mapped to the
7ee72033
MB
11743usual X keysyms. */)
11744 (frame)
82bab41c
GM
11745 Lisp_Object frame;
11746{
11747#ifdef HAVE_XKBGETKEYBOARD
11748 XkbDescPtr kb;
11749 struct frame *f = check_x_frame (frame);
11750 Display *dpy = FRAME_X_DISPLAY (f);
11751 Lisp_Object have_keys;
46f6a258 11752 int major, minor, op, event, error;
82bab41c
GM
11753
11754 BLOCK_INPUT;
46f6a258
GM
11755
11756 /* Check library version in case we're dynamically linked. */
11757 major = XkbMajorVersion;
11758 minor = XkbMinorVersion;
11759 if (!XkbLibraryVersion (&major, &minor))
c1efd260
GM
11760 {
11761 UNBLOCK_INPUT;
11762 return Qnil;
11763 }
46f6a258
GM
11764
11765 /* Check that the server supports XKB. */
11766 major = XkbMajorVersion;
11767 minor = XkbMinorVersion;
11768 if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
c1efd260
GM
11769 {
11770 UNBLOCK_INPUT;
11771 return Qnil;
11772 }
46f6a258
GM
11773
11774 have_keys = Qnil;
c1efd260 11775 kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
82bab41c
GM
11776 if (kb)
11777 {
11778 int delete_keycode = 0, backspace_keycode = 0, i;
c1efd260
GM
11779
11780 if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
82bab41c 11781 {
c1efd260
GM
11782 for (i = kb->min_key_code;
11783 (i < kb->max_key_code
11784 && (delete_keycode == 0 || backspace_keycode == 0));
11785 ++i)
11786 {
d63931a2
GM
11787 /* The XKB symbolic key names can be seen most easily in
11788 the PS file generated by `xkbprint -label name
11789 $DISPLAY'. */
c1efd260
GM
11790 if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
11791 delete_keycode = i;
11792 else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
11793 backspace_keycode = i;
11794 }
11795
11796 XkbFreeNames (kb, 0, True);
82bab41c
GM
11797 }
11798
c1efd260 11799 XkbFreeClientMap (kb, 0, True);
82bab41c
GM
11800
11801 if (delete_keycode
11802 && backspace_keycode
11803 && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
11804 && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
11805 have_keys = Qt;
11806 }
11807 UNBLOCK_INPUT;
11808 return have_keys;
11809#else /* not HAVE_XKBGETKEYBOARD */
11810 return Qnil;
11811#endif /* not HAVE_XKBGETKEYBOARD */
11812}
11813
11814
11815\f
333b20bb
GM
11816/***********************************************************************
11817 Initialization
11818 ***********************************************************************/
11819
11820void
11821syms_of_xfns ()
11822{
11823 /* This is zero if not using X windows. */
11824 x_in_use = 0;
11825
11826 /* The section below is built by the lisp expression at the top of the file,
11827 just above where these variables are declared. */
11828 /*&&& init symbols here &&&*/
11829 Qauto_raise = intern ("auto-raise");
11830 staticpro (&Qauto_raise);
11831 Qauto_lower = intern ("auto-lower");
11832 staticpro (&Qauto_lower);
11833 Qbar = intern ("bar");
dbc4e1c1 11834 staticpro (&Qbar);
f9942c9e
JB
11835 Qborder_color = intern ("border-color");
11836 staticpro (&Qborder_color);
11837 Qborder_width = intern ("border-width");
11838 staticpro (&Qborder_width);
dbc4e1c1
JB
11839 Qbox = intern ("box");
11840 staticpro (&Qbox);
f9942c9e
JB
11841 Qcursor_color = intern ("cursor-color");
11842 staticpro (&Qcursor_color);
dbc4e1c1
JB
11843 Qcursor_type = intern ("cursor-type");
11844 staticpro (&Qcursor_type);
f9942c9e
JB
11845 Qgeometry = intern ("geometry");
11846 staticpro (&Qgeometry);
f9942c9e
JB
11847 Qicon_left = intern ("icon-left");
11848 staticpro (&Qicon_left);
11849 Qicon_top = intern ("icon-top");
11850 staticpro (&Qicon_top);
11851 Qicon_type = intern ("icon-type");
11852 staticpro (&Qicon_type);
80534dd6
KH
11853 Qicon_name = intern ("icon-name");
11854 staticpro (&Qicon_name);
f9942c9e
JB
11855 Qinternal_border_width = intern ("internal-border-width");
11856 staticpro (&Qinternal_border_width);
11857 Qleft = intern ("left");
11858 staticpro (&Qleft);
1ab3d87e
RS
11859 Qright = intern ("right");
11860 staticpro (&Qright);
f9942c9e
JB
11861 Qmouse_color = intern ("mouse-color");
11862 staticpro (&Qmouse_color);
baaed68e
JB
11863 Qnone = intern ("none");
11864 staticpro (&Qnone);
f9942c9e
JB
11865 Qparent_id = intern ("parent-id");
11866 staticpro (&Qparent_id);
4701395c
KH
11867 Qscroll_bar_width = intern ("scroll-bar-width");
11868 staticpro (&Qscroll_bar_width);
8af1d7ca
JB
11869 Qsuppress_icon = intern ("suppress-icon");
11870 staticpro (&Qsuppress_icon);
01f1ba30 11871 Qundefined_color = intern ("undefined-color");
f9942c9e 11872 staticpro (&Qundefined_color);
a3c87d4e
JB
11873 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
11874 staticpro (&Qvertical_scroll_bars);
49795535
JB
11875 Qvisibility = intern ("visibility");
11876 staticpro (&Qvisibility);
f9942c9e
JB
11877 Qwindow_id = intern ("window-id");
11878 staticpro (&Qwindow_id);
2cbebefb
RS
11879 Qouter_window_id = intern ("outer-window-id");
11880 staticpro (&Qouter_window_id);
f9942c9e
JB
11881 Qx_frame_parameter = intern ("x-frame-parameter");
11882 staticpro (&Qx_frame_parameter);
9ef48a9d
RS
11883 Qx_resource_name = intern ("x-resource-name");
11884 staticpro (&Qx_resource_name);
4fe1de12
RS
11885 Quser_position = intern ("user-position");
11886 staticpro (&Quser_position);
11887 Quser_size = intern ("user-size");
11888 staticpro (&Quser_size);
333b20bb
GM
11889 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
11890 staticpro (&Qscroll_bar_foreground);
11891 Qscroll_bar_background = intern ("scroll-bar-background");
11892 staticpro (&Qscroll_bar_background);
d62c8769
GM
11893 Qscreen_gamma = intern ("screen-gamma");
11894 staticpro (&Qscreen_gamma);
563b67aa
GM
11895 Qline_spacing = intern ("line-spacing");
11896 staticpro (&Qline_spacing);
7c7ff7f5
GM
11897 Qcenter = intern ("center");
11898 staticpro (&Qcenter);
96db09e4
KH
11899 Qcompound_text = intern ("compound-text");
11900 staticpro (&Qcompound_text);
ae782866
GM
11901 Qcancel_timer = intern ("cancel-timer");
11902 staticpro (&Qcancel_timer);
ea0a1f53
GM
11903 Qwait_for_wm = intern ("wait-for-wm");
11904 staticpro (&Qwait_for_wm);
49d41073
EZ
11905 Qfullscreen = intern ("fullscreen");
11906 staticpro (&Qfullscreen);
11907 Qfullwidth = intern ("fullwidth");
11908 staticpro (&Qfullwidth);
11909 Qfullheight = intern ("fullheight");
11910 staticpro (&Qfullheight);
11911 Qfullboth = intern ("fullboth");
11912 staticpro (&Qfullboth);
f9942c9e
JB
11913 /* This is the end of symbol initialization. */
11914
58cad5ed
KH
11915 /* Text property `display' should be nonsticky by default. */
11916 Vtext_property_default_nonsticky
11917 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
11918
11919
333b20bb
GM
11920 Qlaplace = intern ("laplace");
11921 staticpro (&Qlaplace);
4a8e312c
GM
11922 Qemboss = intern ("emboss");
11923 staticpro (&Qemboss);
11924 Qedge_detection = intern ("edge-detection");
11925 staticpro (&Qedge_detection);
11926 Qheuristic = intern ("heuristic");
11927 staticpro (&Qheuristic);
11928 QCmatrix = intern (":matrix");
11929 staticpro (&QCmatrix);
11930 QCcolor_adjustment = intern (":color-adjustment");
11931 staticpro (&QCcolor_adjustment);
11932 QCmask = intern (":mask");
11933 staticpro (&QCmask);
11934
a367641f
RS
11935 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
11936 staticpro (&Qface_set_after_frame_default);
11937
01f1ba30
JB
11938 Fput (Qundefined_color, Qerror_conditions,
11939 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
11940 Fput (Qundefined_color, Qerror_message,
11941 build_string ("Undefined color"));
11942
f9942c9e
JB
11943 init_x_parm_symbols ();
11944
7ee72033
MB
11945 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
11946 doc: /* Non-nil means always draw a cross over disabled images.
c061c855
GM
11947Disabled images are those having an `:conversion disabled' property.
11948A cross is always drawn on black & white displays. */);
14819cb3
GM
11949 cross_disabled_images = 0;
11950
7ee72033
MB
11951 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
11952 doc: /* List of directories to search for bitmap files for X. */);
e241c09b 11953 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 11954
7ee72033
MB
11955 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
11956 doc: /* The shape of the pointer when over text.
c061c855
GM
11957Changing the value does not affect existing frames
11958unless you set the mouse color. */);
01f1ba30
JB
11959 Vx_pointer_shape = Qnil;
11960
7ee72033
MB
11961 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
11962 doc: /* The name Emacs uses to look up X resources.
c061c855
GM
11963`x-get-resource' uses this as the first component of the instance name
11964when requesting resource values.
11965Emacs initially sets `x-resource-name' to the name under which Emacs
11966was invoked, or to the value specified with the `-name' or `-rn'
11967switches, if present.
11968
11969It may be useful to bind this variable locally around a call
11970to `x-get-resource'. See also the variable `x-resource-class'. */);
d387c960 11971 Vx_resource_name = Qnil;
ac63d3d6 11972
7ee72033
MB
11973 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
11974 doc: /* The class Emacs uses to look up X resources.
c061c855
GM
11975`x-get-resource' uses this as the first component of the instance class
11976when requesting resource values.
11977
11978Emacs initially sets `x-resource-class' to "Emacs".
11979
11980Setting this variable permanently is not a reasonable thing to do,
11981but binding this variable locally around a call to `x-get-resource'
11982is a reasonable practice. See also the variable `x-resource-name'. */);
498e9ac3
RS
11983 Vx_resource_class = build_string (EMACS_CLASS);
11984
ca0ecbf5 11985#if 0 /* This doesn't really do anything. */
7ee72033
MB
11986 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
11987 doc: /* The shape of the pointer when not over text.
c061c855
GM
11988This variable takes effect when you create a new frame
11989or when you set the mouse color. */);
af01ef26 11990#endif
01f1ba30
JB
11991 Vx_nontext_pointer_shape = Qnil;
11992
7ee72033
MB
11993 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
11994 doc: /* The shape of the pointer when Emacs is busy.
c061c855
GM
11995This variable takes effect when you create a new frame
11996or when you set the mouse color. */);
0af913d7 11997 Vx_hourglass_pointer_shape = Qnil;
333b20bb 11998
7ee72033
MB
11999 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
12000 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 12001 display_hourglass_p = 1;
333b20bb 12002
7ee72033
MB
12003 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
12004 doc: /* *Seconds to wait before displaying an hourglass pointer.
c061c855 12005Value must be an integer or float. */);
0af913d7 12006 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
4ae9a85e 12007
ca0ecbf5 12008#if 0 /* This doesn't really do anything. */
7ee72033
MB
12009 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
12010 doc: /* The shape of the pointer when over the mode line.
c061c855
GM
12011This variable takes effect when you create a new frame
12012or when you set the mouse color. */);
af01ef26 12013#endif
01f1ba30
JB
12014 Vx_mode_pointer_shape = Qnil;
12015
d3b06468 12016 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
7ee72033
MB
12017 &Vx_sensitive_text_pointer_shape,
12018 doc: /* The shape of the pointer when over mouse-sensitive text.
c061c855
GM
12019This variable takes effect when you create a new frame
12020or when you set the mouse color. */);
ca0ecbf5 12021 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 12022
8fb4ec9c 12023 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
7ee72033
MB
12024 &Vx_window_horizontal_drag_shape,
12025 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
c061c855
GM
12026This variable takes effect when you create a new frame
12027or when you set the mouse color. */);
8fb4ec9c
GM
12028 Vx_window_horizontal_drag_shape = Qnil;
12029
7ee72033
MB
12030 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
12031 doc: /* A string indicating the foreground color of the cursor box. */);
01f1ba30
JB
12032 Vx_cursor_fore_pixel = Qnil;
12033
7ee72033
MB
12034 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
12035 doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS).
c061c855 12036Text larger than this is clipped. */);
d63931a2
GM
12037 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
12038
7ee72033
MB
12039 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
12040 doc: /* Non-nil if no X window manager is in use.
c061c855
GM
12041Emacs doesn't try to figure this out; this is always nil
12042unless you set it to something else. */);
2d38195d
RS
12043 /* We don't have any way to find this out, so set it to nil
12044 and maybe the user would like to set it to t. */
12045 Vx_no_window_manager = Qnil;
1d3dac41 12046
942ea06d 12047 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
7ee72033
MB
12048 &Vx_pixel_size_width_font_regexp,
12049 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
c061c855
GM
12050
12051Since Emacs gets width of a font matching with this regexp from
12052PIXEL_SIZE field of the name, font finding mechanism gets faster for
12053such a font. This is especially effective for such large fonts as
12054Chinese, Japanese, and Korean. */);
942ea06d
KH
12055 Vx_pixel_size_width_font_regexp = Qnil;
12056
7ee72033
MB
12057 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
12058 doc: /* Time after which cached images are removed from the cache.
c061c855
GM
12059When an image has not been displayed this many seconds, remove it
12060from the image cache. Value must be an integer or nil with nil
12061meaning don't clear the cache. */);
fcf431dc 12062 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb 12063
1d3dac41 12064#ifdef USE_X_TOOLKIT
6f3f6a8d 12065 Fprovide (intern ("x-toolkit"), Qnil);
5b827abb 12066#ifdef USE_MOTIF
6f3f6a8d 12067 Fprovide (intern ("motif"), Qnil);
fc2cdd9a 12068
7ee72033
MB
12069 DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
12070 doc: /* Version info for LessTif/Motif. */);
fc2cdd9a
GM
12071 Vmotif_version_string = build_string (XmVERSION_STRING);
12072#endif /* USE_MOTIF */
12073#endif /* USE_X_TOOLKIT */
01f1ba30 12074
01f1ba30 12075 defsubr (&Sx_get_resource);
333b20bb
GM
12076
12077 /* X window properties. */
12078 defsubr (&Sx_change_window_property);
12079 defsubr (&Sx_delete_window_property);
12080 defsubr (&Sx_window_property);
12081
2d764c78 12082 defsubr (&Sxw_display_color_p);
d0c9d219 12083 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
12084 defsubr (&Sxw_color_defined_p);
12085 defsubr (&Sxw_color_values);
9d317b2c 12086 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
12087 defsubr (&Sx_server_vendor);
12088 defsubr (&Sx_server_version);
12089 defsubr (&Sx_display_pixel_width);
12090 defsubr (&Sx_display_pixel_height);
12091 defsubr (&Sx_display_mm_width);
12092 defsubr (&Sx_display_mm_height);
12093 defsubr (&Sx_display_screens);
12094 defsubr (&Sx_display_planes);
12095 defsubr (&Sx_display_color_cells);
12096 defsubr (&Sx_display_visual_class);
12097 defsubr (&Sx_display_backing_store);
12098 defsubr (&Sx_display_save_under);
8af1d7ca 12099 defsubr (&Sx_parse_geometry);
f676886a 12100 defsubr (&Sx_create_frame);
01f1ba30 12101 defsubr (&Sx_open_connection);
08a90d6a
RS
12102 defsubr (&Sx_close_connection);
12103 defsubr (&Sx_display_list);
01f1ba30 12104 defsubr (&Sx_synchronize);
3decc1e7 12105 defsubr (&Sx_focus_frame);
82bab41c
GM
12106 defsubr (&Sx_backspace_delete_keys_p);
12107
942ea06d
KH
12108 /* Setting callback functions for fontset handler. */
12109 get_font_info_func = x_get_font_info;
333b20bb
GM
12110
12111#if 0 /* This function pointer doesn't seem to be used anywhere.
12112 And the pointer assigned has the wrong type, anyway. */
942ea06d 12113 list_fonts_func = x_list_fonts;
333b20bb
GM
12114#endif
12115
942ea06d 12116 load_font_func = x_load_font;
bc1958c4 12117 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
12118 query_font_func = x_query_font;
12119 set_frame_fontset_func = x_set_font;
12120 check_window_system_func = check_x;
333b20bb
GM
12121
12122 /* Images. */
12123 Qxbm = intern ("xbm");
12124 staticpro (&Qxbm);
12125 QCtype = intern (":type");
12126 staticpro (&QCtype);
d2dc8167
GM
12127 QCconversion = intern (":conversion");
12128 staticpro (&QCconversion);
333b20bb
GM
12129 QCheuristic_mask = intern (":heuristic-mask");
12130 staticpro (&QCheuristic_mask);
12131 QCcolor_symbols = intern (":color-symbols");
12132 staticpro (&QCcolor_symbols);
333b20bb
GM
12133 QCascent = intern (":ascent");
12134 staticpro (&QCascent);
12135 QCmargin = intern (":margin");
12136 staticpro (&QCmargin);
12137 QCrelief = intern (":relief");
12138 staticpro (&QCrelief);
fcf431dc
GM
12139 Qpostscript = intern ("postscript");
12140 staticpro (&Qpostscript);
333b20bb
GM
12141 QCloader = intern (":loader");
12142 staticpro (&QCloader);
12143 QCbounding_box = intern (":bounding-box");
12144 staticpro (&QCbounding_box);
12145 QCpt_width = intern (":pt-width");
12146 staticpro (&QCpt_width);
12147 QCpt_height = intern (":pt-height");
12148 staticpro (&QCpt_height);
3ccff1e3
GM
12149 QCindex = intern (":index");
12150 staticpro (&QCindex);
333b20bb
GM
12151 Qpbm = intern ("pbm");
12152 staticpro (&Qpbm);
12153
12154#if HAVE_XPM
12155 Qxpm = intern ("xpm");
12156 staticpro (&Qxpm);
12157#endif
12158
12159#if HAVE_JPEG
12160 Qjpeg = intern ("jpeg");
12161 staticpro (&Qjpeg);
12162#endif
12163
12164#if HAVE_TIFF
12165 Qtiff = intern ("tiff");
12166 staticpro (&Qtiff);
12167#endif
12168
12169#if HAVE_GIF
12170 Qgif = intern ("gif");
12171 staticpro (&Qgif);
12172#endif
12173
12174#if HAVE_PNG
12175 Qpng = intern ("png");
12176 staticpro (&Qpng);
12177#endif
12178
12179 defsubr (&Sclear_image_cache);
42677916 12180 defsubr (&Simage_size);
b243755a 12181 defsubr (&Simage_mask_p);
333b20bb 12182
0af913d7
GM
12183 hourglass_atimer = NULL;
12184 hourglass_shown_p = 0;
333b20bb
GM
12185
12186 defsubr (&Sx_show_tip);
12187 defsubr (&Sx_hide_tip);
333b20bb 12188 tip_timer = Qnil;
44b5a125
GM
12189 staticpro (&tip_timer);
12190 tip_frame = Qnil;
12191 staticpro (&tip_frame);
333b20bb 12192
06d62053
GM
12193 last_show_tip_args = Qnil;
12194 staticpro (&last_show_tip_args);
12195
333b20bb
GM
12196#ifdef USE_MOTIF
12197 defsubr (&Sx_file_dialog);
12198#endif
12199}
12200
12201
12202void
12203init_xfns ()
12204{
12205 image_types = NULL;
12206 Vimage_types = Qnil;
12207
12208 define_image_type (&xbm_type);
12209 define_image_type (&gs_type);
12210 define_image_type (&pbm_type);
12211
12212#if HAVE_XPM
12213 define_image_type (&xpm_type);
12214#endif
12215
12216#if HAVE_JPEG
12217 define_image_type (&jpeg_type);
12218#endif
12219
12220#if HAVE_TIFF
12221 define_image_type (&tiff_type);
12222#endif
12223
12224#if HAVE_GIF
12225 define_image_type (&gif_type);
12226#endif
12227
12228#if HAVE_PNG
12229 define_image_type (&png_type);
12230#endif
01f1ba30
JB
12231}
12232
12233#endif /* HAVE_X_WINDOWS */