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