(png_load): Set screen_gamma based on f->gamma.
[bpt/emacs.git] / src / xfns.c
CommitLineData
01f1ba30 1/* Functions for the X window system.
edf36fe6 2 Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
333b20bb 3 Free Software Foundation.
01f1ba30
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
1113d9db 9the Free Software Foundation; either version 2, or (at your option)
01f1ba30
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
01f1ba30 21
c389a86d 22#include <config.h>
68c45bf0 23#include <signal.h>
333b20bb 24#include <stdio.h>
d62c8769 25#include <math.h>
c389a86d 26
3ecaf7e5
RS
27#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
30
40e6f148 31/* This makes the fields of a Display accessible, in Xlib header files. */
333b20bb 32
40e6f148
RS
33#define XLIB_ILLEGAL_ACCESS
34
01f1ba30
JB
35#include "lisp.h"
36#include "xterm.h"
f676886a 37#include "frame.h"
01f1ba30
JB
38#include "window.h"
39#include "buffer.h"
58cad5ed 40#include "intervals.h"
01f1ba30 41#include "dispextern.h"
1f98fa48 42#include "keyboard.h"
9ac0d9e0 43#include "blockinput.h"
57bda87a 44#include <epaths.h>
942ea06d 45#include "charset.h"
96db09e4 46#include "coding.h"
942ea06d 47#include "fontset.h"
333b20bb
GM
48#include "systime.h"
49#include "termhooks.h"
4ae9a85e 50#include "atimer.h"
01f1ba30
JB
51
52#ifdef HAVE_X_WINDOWS
67ba84d1 53
67ba84d1 54#include <ctype.h>
63cec32f
GM
55#include <sys/types.h>
56#include <sys/stat.h>
01f1ba30 57
0a93081c 58#ifndef VMS
0505a740 59#if 1 /* Used to be #ifdef EMACS_BITMAP_FILES, but this should always work. */
ef493a27
RS
60#include "bitmaps/gray.xbm"
61#else
dbc4e1c1 62#include <X11/bitmaps/gray>
ef493a27 63#endif
0a93081c
JB
64#else
65#include "[.bitmaps]gray.xbm"
66#endif
dbc4e1c1 67
9ef48a9d
RS
68#ifdef USE_X_TOOLKIT
69#include <X11/Shell.h>
70
398ffa92 71#ifndef USE_MOTIF
9ef48a9d
RS
72#include <X11/Xaw/Paned.h>
73#include <X11/Xaw/Label.h>
398ffa92 74#endif /* USE_MOTIF */
9ef48a9d
RS
75
76#ifdef USG
77#undef USG /* ####KLUDGE for Solaris 2.2 and up */
78#include <X11/Xos.h>
79#define USG
80#else
81#include <X11/Xos.h>
82#endif
83
84#include "widget.h"
85
86#include "../lwlib/lwlib.h"
87
333b20bb
GM
88#ifdef USE_MOTIF
89#include <Xm/Xm.h>
90#include <Xm/DialogS.h>
91#include <Xm/FileSB.h>
92#endif
93
3b882b1d
RS
94/* Do the EDITRES protocol if running X11R5
95 Exception: HP-UX (at least version A.09.05) has X11R5 without EditRes */
333b20bb 96
3b882b1d 97#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
6c32dd68 98#define HACK_EDITRES
b9dc4443 99extern void _XEditResCheckMessages ();
6c32dd68
PR
100#endif /* R5 + Athena */
101
333b20bb
GM
102/* Unique id counter for widgets created by the Lucid Widget Library. */
103
6c32dd68
PR
104extern LWLIB_ID widget_id_tick;
105
e3881aa0 106#ifdef USE_LUCID
82c90203 107/* This is part of a kludge--see lwlib/xlwmenu.c. */
03e2c340 108extern XFontStruct *xlwmenu_default_font;
e3881aa0 109#endif
9ef48a9d 110
6bc20398 111extern void free_frame_menubar ();
d62c8769 112extern double atof ();
333b20bb 113
fc2cdd9a
GM
114#ifdef USE_MOTIF
115
116/* LessTif/Motif version info. */
117
118static Lisp_Object Vmotif_version_string;
119
120#endif /* USE_MOTIF */
121
9ef48a9d
RS
122#endif /* USE_X_TOOLKIT */
123
9d317b2c
RS
124#ifdef HAVE_X11R4
125#define MAXREQUEST(dpy) (XMaxRequestSize (dpy))
126#else
127#define MAXREQUEST(dpy) ((dpy)->max_request_size)
128#endif
129
333b20bb
GM
130/* The gray bitmap `bitmaps/gray'. This is done because xterm.c uses
131 it, and including `bitmaps/gray' more than once is a problem when
132 config.h defines `static' as an empty replacement string. */
133
134int gray_bitmap_width = gray_width;
135int gray_bitmap_height = gray_height;
62906360 136char *gray_bitmap_bits = gray_bits;
333b20bb 137
498e9ac3 138/* The name we're using in resource queries. Most often "emacs". */
333b20bb 139
d387c960 140Lisp_Object Vx_resource_name;
ac63d3d6 141
498e9ac3
RS
142/* The application class we're using in resource queries.
143 Normally "Emacs". */
333b20bb 144
498e9ac3
RS
145Lisp_Object Vx_resource_class;
146
0af913d7 147/* Non-zero means we're allowed to display an hourglass cursor. */
333b20bb 148
0af913d7 149int display_hourglass_p;
333b20bb 150
01f1ba30 151/* The background and shape of the mouse pointer, and shape when not
b9dc4443 152 over text or in the modeline. */
333b20bb 153
01f1ba30 154Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 155Lisp_Object Vx_hourglass_pointer_shape;
333b20bb 156
ca0ecbf5 157/* The shape when over mouse-sensitive text. */
333b20bb 158
ca0ecbf5 159Lisp_Object Vx_sensitive_text_pointer_shape;
01f1ba30 160
8fb4ec9c
GM
161/* If non-nil, the pointer shape to indicate that windows can be
162 dragged horizontally. */
163
164Lisp_Object Vx_window_horizontal_drag_shape;
165
b9dc4443 166/* Color of chars displayed in cursor box. */
333b20bb 167
01f1ba30
JB
168Lisp_Object Vx_cursor_fore_pixel;
169
b9dc4443 170/* Nonzero if using X. */
333b20bb 171
b9dc4443 172static int x_in_use;
01f1ba30 173
b9dc4443 174/* Non nil if no window manager is in use. */
333b20bb 175
01f1ba30
JB
176Lisp_Object Vx_no_window_manager;
177
f1c7b5a6 178/* Search path for bitmap files. */
333b20bb 179
f1c7b5a6
RS
180Lisp_Object Vx_bitmap_file_path;
181
942ea06d 182/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
333b20bb 183
942ea06d
KH
184Lisp_Object Vx_pixel_size_width_font_regexp;
185
f9942c9e
JB
186Lisp_Object Qauto_raise;
187Lisp_Object Qauto_lower;
dbc4e1c1 188Lisp_Object Qbar;
f9942c9e
JB
189Lisp_Object Qborder_color;
190Lisp_Object Qborder_width;
dbc4e1c1 191Lisp_Object Qbox;
f9942c9e 192Lisp_Object Qcursor_color;
dbc4e1c1 193Lisp_Object Qcursor_type;
f9942c9e 194Lisp_Object Qgeometry;
f9942c9e
JB
195Lisp_Object Qicon_left;
196Lisp_Object Qicon_top;
197Lisp_Object Qicon_type;
80534dd6 198Lisp_Object Qicon_name;
f9942c9e
JB
199Lisp_Object Qinternal_border_width;
200Lisp_Object Qleft;
1ab3d87e 201Lisp_Object Qright;
f9942c9e 202Lisp_Object Qmouse_color;
baaed68e 203Lisp_Object Qnone;
2cbebefb 204Lisp_Object Qouter_window_id;
f9942c9e 205Lisp_Object Qparent_id;
4701395c 206Lisp_Object Qscroll_bar_width;
8af1d7ca 207Lisp_Object Qsuppress_icon;
333b20bb 208extern Lisp_Object Qtop;
01f1ba30 209Lisp_Object Qundefined_color;
a3c87d4e 210Lisp_Object Qvertical_scroll_bars;
49795535 211Lisp_Object Qvisibility;
f9942c9e 212Lisp_Object Qwindow_id;
f676886a 213Lisp_Object Qx_frame_parameter;
9ef48a9d 214Lisp_Object Qx_resource_name;
4fe1de12
RS
215Lisp_Object Quser_position;
216Lisp_Object Quser_size;
0cafb359 217extern Lisp_Object Qdisplay;
333b20bb 218Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
7c7ff7f5 219Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
ae782866 220Lisp_Object Qcompound_text, Qcancel_timer;
ea0a1f53 221Lisp_Object Qwait_for_wm;
49d41073
EZ
222Lisp_Object Qfullscreen;
223Lisp_Object Qfullwidth;
224Lisp_Object Qfullheight;
225Lisp_Object Qfullboth;
01f1ba30 226
b9dc4443 227/* The below are defined in frame.c. */
333b20bb 228
baaed68e 229extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
c2304e02 230extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
9ea173e8 231extern Lisp_Object Qtool_bar_lines;
f9942c9e 232
01f1ba30
JB
233extern Lisp_Object Vwindow_system_version;
234
a367641f 235Lisp_Object Qface_set_after_frame_default;
333b20bb 236
f1d2ce7f 237#if GLYPH_DEBUG
eaf1eea9
GM
238int image_cache_refcount, dpyinfo_refcount;
239#endif
240
241
01f1ba30 242\f
11ae94fe 243/* Error if we are not connected to X. */
333b20bb 244
7fc9de26 245void
11ae94fe
RS
246check_x ()
247{
b9dc4443 248 if (! x_in_use)
11ae94fe
RS
249 error ("X windows are not in use or not initialized");
250}
251
1c59f5df
RS
252/* Nonzero if we can use mouse menus.
253 You should not call this unless HAVE_MENUS is defined. */
75cc8ee5
RS
254
255int
1c59f5df 256have_menus_p ()
75cc8ee5 257{
b9dc4443
RS
258 return x_in_use;
259}
260
261/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
262 and checking validity for X. */
263
264FRAME_PTR
265check_x_frame (frame)
266 Lisp_Object frame;
267{
268 FRAME_PTR f;
269
270 if (NILP (frame))
0fe92f72 271 frame = selected_frame;
b7826503 272 CHECK_LIVE_FRAME (frame);
0fe92f72 273 f = XFRAME (frame);
b9dc4443 274 if (! FRAME_X_P (f))
1c59f5df 275 error ("Non-X frame used");
b9dc4443 276 return f;
75cc8ee5
RS
277}
278
b9dc4443
RS
279/* Let the user specify an X display with a frame.
280 nil stands for the selected frame--or, if that is not an X frame,
281 the first X display on the list. */
282
283static struct x_display_info *
284check_x_display_info (frame)
285 Lisp_Object frame;
286{
8ec8a5ec
GM
287 struct x_display_info *dpyinfo = NULL;
288
b9dc4443
RS
289 if (NILP (frame))
290 {
0fe92f72
GM
291 struct frame *sf = XFRAME (selected_frame);
292
293 if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
8ec8a5ec 294 dpyinfo = FRAME_X_DISPLAY_INFO (sf);
b9dc4443 295 else if (x_display_list != 0)
8ec8a5ec 296 dpyinfo = x_display_list;
b9dc4443
RS
297 else
298 error ("X windows are not in use or not initialized");
299 }
300 else if (STRINGP (frame))
8ec8a5ec 301 dpyinfo = x_display_info_for_name (frame);
b9dc4443
RS
302 else
303 {
304 FRAME_PTR f;
305
b7826503 306 CHECK_LIVE_FRAME (frame);
b9dc4443
RS
307 f = XFRAME (frame);
308 if (! FRAME_X_P (f))
1c59f5df 309 error ("Non-X frame used");
8ec8a5ec 310 dpyinfo = FRAME_X_DISPLAY_INFO (f);
b9dc4443 311 }
8ec8a5ec
GM
312
313 return dpyinfo;
b9dc4443 314}
333b20bb 315
b9dc4443 316\f
f676886a
JB
317/* Return the Emacs frame-object corresponding to an X window.
318 It could be the frame's main window or an icon window. */
01f1ba30 319
34ca5317 320/* This function can be called during GC, so use GC_xxx type test macros. */
bcb2db92 321
f676886a 322struct frame *
2d271e2e
KH
323x_window_to_frame (dpyinfo, wdesc)
324 struct x_display_info *dpyinfo;
01f1ba30
JB
325 int wdesc;
326{
f676886a
JB
327 Lisp_Object tail, frame;
328 struct frame *f;
01f1ba30 329
8e713be6 330 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
01f1ba30 331 {
8e713be6 332 frame = XCAR (tail);
34ca5317 333 if (!GC_FRAMEP (frame))
01f1ba30 334 continue;
f676886a 335 f = XFRAME (frame);
2d764c78 336 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
2d271e2e 337 continue;
0af913d7 338 if (f->output_data.x->hourglass_window == wdesc)
17cbbf95 339 return f;
9ef48a9d 340#ifdef USE_X_TOOLKIT
7556890b
RS
341 if ((f->output_data.x->edit_widget
342 && XtWindow (f->output_data.x->edit_widget) == wdesc)
333b20bb
GM
343 /* A tooltip frame? */
344 || (!f->output_data.x->edit_widget
345 && FRAME_X_WINDOW (f) == wdesc)
7556890b 346 || f->output_data.x->icon_desc == wdesc)
9ef48a9d
RS
347 return f;
348#else /* not USE_X_TOOLKIT */
fe24a618 349 if (FRAME_X_WINDOW (f) == wdesc
7556890b 350 || f->output_data.x->icon_desc == wdesc)
f676886a 351 return f;
9ef48a9d
RS
352#endif /* not USE_X_TOOLKIT */
353 }
354 return 0;
355}
356
357#ifdef USE_X_TOOLKIT
358/* Like x_window_to_frame but also compares the window with the widget's
359 windows. */
360
361struct frame *
2d271e2e
KH
362x_any_window_to_frame (dpyinfo, wdesc)
363 struct x_display_info *dpyinfo;
9ef48a9d
RS
364 int wdesc;
365{
366 Lisp_Object tail, frame;
17cbbf95 367 struct frame *f, *found;
7556890b 368 struct x_output *x;
9ef48a9d 369
17cbbf95
GM
370 found = NULL;
371 for (tail = Vframe_list; GC_CONSP (tail) && !found; tail = XCDR (tail))
9ef48a9d 372 {
8e713be6 373 frame = XCAR (tail);
34ca5317 374 if (!GC_FRAMEP (frame))
9ef48a9d 375 continue;
17cbbf95 376
9ef48a9d 377 f = XFRAME (frame);
17cbbf95 378 if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo)
333b20bb 379 {
17cbbf95
GM
380 /* This frame matches if the window is any of its widgets. */
381 x = f->output_data.x;
0af913d7 382 if (x->hourglass_window == wdesc)
17cbbf95
GM
383 found = f;
384 else if (x->widget)
385 {
386 if (wdesc == XtWindow (x->widget)
387 || wdesc == XtWindow (x->column_widget)
388 || wdesc == XtWindow (x->edit_widget))
389 found = f;
390 /* Match if the window is this frame's menubar. */
391 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
392 found = f;
393 }
394 else if (FRAME_X_WINDOW (f) == wdesc)
395 /* A tooltip frame. */
396 found = f;
333b20bb 397 }
01f1ba30 398 }
17cbbf95
GM
399
400 return found;
01f1ba30 401}
5e65b9ab 402
5fbc3f3a
KH
403/* Likewise, but exclude the menu bar widget. */
404
405struct frame *
406x_non_menubar_window_to_frame (dpyinfo, wdesc)
407 struct x_display_info *dpyinfo;
408 int wdesc;
409{
410 Lisp_Object tail, frame;
411 struct frame *f;
7556890b 412 struct x_output *x;
5fbc3f3a 413
8e713be6 414 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
5fbc3f3a 415 {
8e713be6 416 frame = XCAR (tail);
5fbc3f3a
KH
417 if (!GC_FRAMEP (frame))
418 continue;
419 f = XFRAME (frame);
2d764c78 420 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
5fbc3f3a 421 continue;
7556890b 422 x = f->output_data.x;
5fbc3f3a 423 /* This frame matches if the window is any of its widgets. */
0af913d7 424 if (x->hourglass_window == wdesc)
17cbbf95
GM
425 return f;
426 else if (x->widget)
333b20bb
GM
427 {
428 if (wdesc == XtWindow (x->widget)
429 || wdesc == XtWindow (x->column_widget)
430 || wdesc == XtWindow (x->edit_widget))
431 return f;
432 }
433 else if (FRAME_X_WINDOW (f) == wdesc)
434 /* A tooltip frame. */
5fbc3f3a
KH
435 return f;
436 }
437 return 0;
438}
439
fd3a3022
RS
440/* Likewise, but consider only the menu bar widget. */
441
442struct frame *
443x_menubar_window_to_frame (dpyinfo, wdesc)
444 struct x_display_info *dpyinfo;
445 int wdesc;
446{
447 Lisp_Object tail, frame;
448 struct frame *f;
7556890b 449 struct x_output *x;
fd3a3022 450
8e713be6 451 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
fd3a3022 452 {
8e713be6 453 frame = XCAR (tail);
fd3a3022
RS
454 if (!GC_FRAMEP (frame))
455 continue;
456 f = XFRAME (frame);
2d764c78 457 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
fd3a3022 458 continue;
7556890b 459 x = f->output_data.x;
fd3a3022 460 /* Match if the window is this frame's menubar. */
333b20bb
GM
461 if (x->menubar_widget
462 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
fd3a3022
RS
463 return f;
464 }
465 return 0;
466}
467
5e65b9ab
RS
468/* Return the frame whose principal (outermost) window is WDESC.
469 If WDESC is some other (smaller) window, we return 0. */
470
471struct frame *
2d271e2e
KH
472x_top_window_to_frame (dpyinfo, wdesc)
473 struct x_display_info *dpyinfo;
5e65b9ab
RS
474 int wdesc;
475{
476 Lisp_Object tail, frame;
477 struct frame *f;
7556890b 478 struct x_output *x;
5e65b9ab 479
8e713be6 480 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
5e65b9ab 481 {
8e713be6 482 frame = XCAR (tail);
34ca5317 483 if (!GC_FRAMEP (frame))
5e65b9ab
RS
484 continue;
485 f = XFRAME (frame);
2d764c78 486 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
2d271e2e 487 continue;
7556890b 488 x = f->output_data.x;
333b20bb
GM
489
490 if (x->widget)
491 {
492 /* This frame matches if the window is its topmost widget. */
493 if (wdesc == XtWindow (x->widget))
494 return f;
7a994728
KH
495#if 0 /* I don't know why it did this,
496 but it seems logically wrong,
497 and it causes trouble for MapNotify events. */
333b20bb
GM
498 /* Match if the window is this frame's menubar. */
499 if (x->menubar_widget
500 && wdesc == XtWindow (x->menubar_widget))
501 return f;
7a994728 502#endif
333b20bb
GM
503 }
504 else if (FRAME_X_WINDOW (f) == wdesc)
505 /* Tooltip frame. */
506 return f;
5e65b9ab
RS
507 }
508 return 0;
509}
9ef48a9d 510#endif /* USE_X_TOOLKIT */
01f1ba30 511
01f1ba30 512\f
203c1d73
RS
513
514/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
515 id, which is just an int that this section returns. Bitmaps are
516 reference counted so they can be shared among frames.
517
518 Bitmap indices are guaranteed to be > 0, so a negative number can
519 be used to indicate no bitmap.
520
521 If you use x_create_bitmap_from_data, then you must keep track of
522 the bitmaps yourself. That is, creating a bitmap from the same
b9dc4443 523 data more than once will not be caught. */
203c1d73
RS
524
525
f1c7b5a6
RS
526/* Functions to access the contents of a bitmap, given an id. */
527
528int
529x_bitmap_height (f, id)
530 FRAME_PTR f;
531 int id;
532{
08a90d6a 533 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
f1c7b5a6
RS
534}
535
536int
537x_bitmap_width (f, id)
538 FRAME_PTR f;
539 int id;
540{
08a90d6a 541 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
f1c7b5a6
RS
542}
543
544int
545x_bitmap_pixmap (f, id)
546 FRAME_PTR f;
547 int id;
548{
08a90d6a 549 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
f1c7b5a6
RS
550}
551
552
203c1d73
RS
553/* Allocate a new bitmap record. Returns index of new record. */
554
555static int
08a90d6a
RS
556x_allocate_bitmap_record (f)
557 FRAME_PTR f;
203c1d73 558{
08a90d6a
RS
559 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
560 int i;
561
562 if (dpyinfo->bitmaps == NULL)
203c1d73 563 {
08a90d6a
RS
564 dpyinfo->bitmaps_size = 10;
565 dpyinfo->bitmaps
566 = (struct x_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
567 dpyinfo->bitmaps_last = 1;
203c1d73
RS
568 return 1;
569 }
570
08a90d6a
RS
571 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
572 return ++dpyinfo->bitmaps_last;
203c1d73 573
08a90d6a
RS
574 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
575 if (dpyinfo->bitmaps[i].refcount == 0)
576 return i + 1;
203c1d73 577
08a90d6a
RS
578 dpyinfo->bitmaps_size *= 2;
579 dpyinfo->bitmaps
580 = (struct x_bitmap_record *) xrealloc (dpyinfo->bitmaps,
581 dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
582 return ++dpyinfo->bitmaps_last;
203c1d73
RS
583}
584
585/* Add one reference to the reference count of the bitmap with id ID. */
586
587void
f1c7b5a6
RS
588x_reference_bitmap (f, id)
589 FRAME_PTR f;
203c1d73
RS
590 int id;
591{
08a90d6a 592 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
203c1d73
RS
593}
594
595/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
596
597int
598x_create_bitmap_from_data (f, bits, width, height)
599 struct frame *f;
600 char *bits;
601 unsigned int width, height;
602{
08a90d6a 603 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
203c1d73
RS
604 Pixmap bitmap;
605 int id;
606
b9dc4443 607 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
203c1d73
RS
608 bits, width, height);
609
610 if (! bitmap)
611 return -1;
612
08a90d6a
RS
613 id = x_allocate_bitmap_record (f);
614 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
615 dpyinfo->bitmaps[id - 1].file = NULL;
616 dpyinfo->bitmaps[id - 1].refcount = 1;
617 dpyinfo->bitmaps[id - 1].depth = 1;
618 dpyinfo->bitmaps[id - 1].height = height;
619 dpyinfo->bitmaps[id - 1].width = width;
203c1d73
RS
620
621 return id;
622}
623
624/* Create bitmap from file FILE for frame F. */
625
626int
627x_create_bitmap_from_file (f, file)
628 struct frame *f;
f1c7b5a6 629 Lisp_Object file;
203c1d73 630{
08a90d6a 631 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
203c1d73
RS
632 unsigned int width, height;
633 Pixmap bitmap;
634 int xhot, yhot, result, id;
f1c7b5a6
RS
635 Lisp_Object found;
636 int fd;
637 char *filename;
203c1d73
RS
638
639 /* Look for an existing bitmap with the same name. */
08a90d6a 640 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
203c1d73 641 {
08a90d6a
RS
642 if (dpyinfo->bitmaps[id].refcount
643 && dpyinfo->bitmaps[id].file
644 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
203c1d73 645 {
08a90d6a 646 ++dpyinfo->bitmaps[id].refcount;
203c1d73
RS
647 return id + 1;
648 }
649 }
650
f1c7b5a6 651 /* Search bitmap-file-path for the file, if appropriate. */
c0ec53ad 652 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
f1c7b5a6
RS
653 if (fd < 0)
654 return -1;
68c45bf0 655 emacs_close (fd);
f1c7b5a6
RS
656
657 filename = (char *) XSTRING (found)->data;
658
b9dc4443 659 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f1c7b5a6 660 filename, &width, &height, &bitmap, &xhot, &yhot);
203c1d73
RS
661 if (result != BitmapSuccess)
662 return -1;
663
08a90d6a
RS
664 id = x_allocate_bitmap_record (f);
665 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
666 dpyinfo->bitmaps[id - 1].refcount = 1;
9f2a85b2 667 dpyinfo->bitmaps[id - 1].file
fc932ac6 668 = (char *) xmalloc (STRING_BYTES (XSTRING (file)) + 1);
08a90d6a
RS
669 dpyinfo->bitmaps[id - 1].depth = 1;
670 dpyinfo->bitmaps[id - 1].height = height;
671 dpyinfo->bitmaps[id - 1].width = width;
672 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
203c1d73
RS
673
674 return id;
675}
676
677/* Remove reference to bitmap with id number ID. */
678
968b1234 679void
f1c7b5a6
RS
680x_destroy_bitmap (f, id)
681 FRAME_PTR f;
203c1d73
RS
682 int id;
683{
08a90d6a
RS
684 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
685
203c1d73
RS
686 if (id > 0)
687 {
08a90d6a
RS
688 --dpyinfo->bitmaps[id - 1].refcount;
689 if (dpyinfo->bitmaps[id - 1].refcount == 0)
203c1d73 690 {
ed662bdd 691 BLOCK_INPUT;
08a90d6a
RS
692 XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].pixmap);
693 if (dpyinfo->bitmaps[id - 1].file)
203c1d73 694 {
333b20bb 695 xfree (dpyinfo->bitmaps[id - 1].file);
08a90d6a 696 dpyinfo->bitmaps[id - 1].file = NULL;
203c1d73 697 }
ed662bdd 698 UNBLOCK_INPUT;
203c1d73
RS
699 }
700 }
701}
702
08a90d6a 703/* Free all the bitmaps for the display specified by DPYINFO. */
203c1d73 704
08a90d6a
RS
705static void
706x_destroy_all_bitmaps (dpyinfo)
707 struct x_display_info *dpyinfo;
203c1d73 708{
08a90d6a
RS
709 int i;
710 for (i = 0; i < dpyinfo->bitmaps_last; i++)
711 if (dpyinfo->bitmaps[i].refcount > 0)
712 {
713 XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].pixmap);
714 if (dpyinfo->bitmaps[i].file)
333b20bb 715 xfree (dpyinfo->bitmaps[i].file);
08a90d6a
RS
716 }
717 dpyinfo->bitmaps_last = 0;
203c1d73
RS
718}
719\f
f676886a 720/* Connect the frame-parameter names for X frames
01f1ba30
JB
721 to the ways of passing the parameter values to the window system.
722
723 The name of a parameter, as a Lisp symbol,
f676886a 724 has an `x-frame-parameter' property which is an integer in Lisp
9fb026ab 725 that is an index in this table. */
01f1ba30 726
f676886a 727struct x_frame_parm_table
01f1ba30
JB
728{
729 char *name;
d62c8769 730 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
01f1ba30
JB
731};
732
eaf1eea9
GM
733static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
734static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
52de7ce9 735static void x_change_window_heights P_ ((Lisp_Object, int));
14819cb3 736static void x_disable_image P_ ((struct frame *, struct image *));
d62c8769 737void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
563b67aa 738static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
ea0a1f53 739static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object));
49d41073 740static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
d62c8769
GM
741void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
742void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
743void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
744void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
745void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
746void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
747void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
b3ba0aa8 748static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
d62c8769
GM
749void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
750void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
751void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
752 Lisp_Object));
753void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
754void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
755void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
756void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
757 Lisp_Object));
758void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
759void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
760void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
761void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
762void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
9ea173e8 763void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
333b20bb
GM
764void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
765 Lisp_Object));
766void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
767 Lisp_Object));
768static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
769 Lisp_Object,
770 Lisp_Object,
771 char *, char *,
772 int));
d62c8769 773static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
4a8e312c
GM
774static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
775 Lisp_Object));
b243755a
GM
776static void init_color_table P_ ((void));
777static void free_color_table P_ ((void));
778static unsigned long *colors_in_color_table P_ ((int *n));
779static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
780static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
781
782
01f1ba30 783
f676886a 784static struct x_frame_parm_table x_frame_parms[] =
01f1ba30 785{
9908a324
PJ
786 {"auto-raise", x_set_autoraise},
787 {"auto-lower", x_set_autolower},
788 {"background-color", x_set_background_color},
789 {"border-color", x_set_border_color},
790 {"border-width", x_set_border_width},
791 {"cursor-color", x_set_cursor_color},
792 {"cursor-type", x_set_cursor_type},
793 {"font", x_set_font},
794 {"foreground-color", x_set_foreground_color},
795 {"icon-name", x_set_icon_name},
796 {"icon-type", x_set_icon_type},
797 {"internal-border-width", x_set_internal_border_width},
798 {"menu-bar-lines", x_set_menu_bar_lines},
799 {"mouse-color", x_set_mouse_color},
800 {"name", x_explicitly_set_name},
801 {"scroll-bar-width", x_set_scroll_bar_width},
802 {"title", x_set_title},
803 {"unsplittable", x_set_unsplittable},
804 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
805 {"visibility", x_set_visibility},
806 {"tool-bar-lines", x_set_tool_bar_lines},
807 {"scroll-bar-foreground", x_set_scroll_bar_foreground},
808 {"scroll-bar-background", x_set_scroll_bar_background},
809 {"screen-gamma", x_set_screen_gamma},
810 {"line-spacing", x_set_line_spacing},
811 {"left-fringe", x_set_fringe_width},
812 {"right-fringe", x_set_fringe_width},
49d41073
EZ
813 {"wait-for-wm", x_set_wait_for_wm},
814 {"fullscreen", x_set_fullscreen},
815
01f1ba30
JB
816};
817
f676886a 818/* Attach the `x-frame-parameter' properties to
01f1ba30
JB
819 the Lisp symbol names of parameters relevant to X. */
820
201d8c78 821void
01f1ba30
JB
822init_x_parm_symbols ()
823{
824 int i;
825
d043f1a4 826 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
f676886a 827 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
01f1ba30
JB
828 make_number (i));
829}
830\f
49d41073
EZ
831
832/* Really try to move where we want to be in case of fullscreen. Some WMs
833 moves the window where we tell them. Some (mwm, twm) moves the outer
834 window manager window there instead.
835 Try to compensate for those WM here. */
836static void
837x_fullscreen_move (f, new_top, new_left)
838 struct frame *f;
839 int new_top;
840 int new_left;
841{
842 if (new_top != f->output_data.x->top_pos
843 || new_left != f->output_data.x->left_pos)
844 {
845 int move_x = new_left + f->output_data.x->x_pixels_outer_diff;
846 int move_y = new_top + f->output_data.x->y_pixels_outer_diff;
847
848 f->output_data.x->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
849 x_set_offset (f, move_x, move_y, 1);
850 }
851}
852
e8cc313b 853/* Change the parameters of frame F as specified by ALIST.
64362cd4
GM
854 If a parameter is not specially recognized, do nothing special;
855 otherwise call the `x_set_...' function for that parameter.
856 Except for certain geometry properties, always call store_frame_param
857 to store the new value in the parameter alist. */
d043f1a4 858
f9942c9e
JB
859void
860x_set_frame_parameters (f, alist)
861 FRAME_PTR f;
862 Lisp_Object alist;
863{
864 Lisp_Object tail;
865
866 /* If both of these parameters are present, it's more efficient to
867 set them both at once. So we wait until we've looked at the
868 entire list before we set them. */
e4f79258 869 int width, height;
f9942c9e
JB
870
871 /* Same here. */
872 Lisp_Object left, top;
f9942c9e 873
a59e4f3d
RS
874 /* Same with these. */
875 Lisp_Object icon_left, icon_top;
876
f5e70acd
RS
877 /* Record in these vectors all the parms specified. */
878 Lisp_Object *parms;
879 Lisp_Object *values;
a797a73d 880 int i, p;
e1d962d7 881 int left_no_change = 0, top_no_change = 0;
a59e4f3d 882 int icon_left_no_change = 0, icon_top_no_change = 0;
5f9338d5 883 int fullscreen_is_being_set = 0;
203c1d73 884
7589a1d9
RS
885 struct gcpro gcpro1, gcpro2;
886
f5e70acd
RS
887 i = 0;
888 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
889 i++;
890
891 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
892 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
f9942c9e 893
f5e70acd
RS
894 /* Extract parm names and values into those vectors. */
895
896 i = 0;
f9942c9e
JB
897 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
898 {
333b20bb 899 Lisp_Object elt;
f9942c9e
JB
900
901 elt = Fcar (tail);
f5e70acd
RS
902 parms[i] = Fcar (elt);
903 values[i] = Fcdr (elt);
904 i++;
905 }
7589a1d9
RS
906 /* TAIL and ALIST are not used again below here. */
907 alist = tail = Qnil;
908
909 GCPRO2 (*parms, *values);
910 gcpro1.nvars = i;
911 gcpro2.nvars = i;
f5e70acd 912
7589a1d9
RS
913 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
914 because their values appear in VALUES and strings are not valid. */
e4f79258 915 top = left = Qunbound;
a59e4f3d 916 icon_left = icon_top = Qunbound;
f9942c9e 917
e4f79258
RS
918 /* Provide default values for HEIGHT and WIDTH. */
919 if (FRAME_NEW_WIDTH (f))
920 width = FRAME_NEW_WIDTH (f);
921 else
922 width = FRAME_WIDTH (f);
923
924 if (FRAME_NEW_HEIGHT (f))
925 height = FRAME_NEW_HEIGHT (f);
926 else
927 height = FRAME_HEIGHT (f);
928
a797a73d
GV
929 /* Process foreground_color and background_color before anything else.
930 They are independent of other properties, but other properties (e.g.,
931 cursor_color) are dependent upon them. */
b3ba0aa8 932 /* Process default font as well, since fringe widths depends on it. */
49d41073 933 /* Also, process fullscreen, width and height depend upon that */
a797a73d
GV
934 for (p = 0; p < i; p++)
935 {
936 Lisp_Object prop, val;
937
938 prop = parms[p];
939 val = values[p];
b3ba0aa8
KS
940 if (EQ (prop, Qforeground_color)
941 || EQ (prop, Qbackground_color)
49d41073
EZ
942 || EQ (prop, Qfont)
943 || EQ (prop, Qfullscreen))
a797a73d
GV
944 {
945 register Lisp_Object param_index, old_value;
946
a797a73d 947 old_value = get_frame_param (f, prop);
f0b9a067 948 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
c7e609d5
MB
949
950 if (NILP (Fequal (val, old_value)))
951 {
952 store_frame_param (f, prop, val);
953
954 param_index = Fget (prop, Qx_frame_parameter);
955 if (NATNUMP (param_index)
956 && (XFASTINT (param_index)
957 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
958 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
959 }
a797a73d
GV
960 }
961 }
962
f5e70acd
RS
963 /* Now process them in reverse of specified order. */
964 for (i--; i >= 0; i--)
965 {
966 Lisp_Object prop, val;
967
968 prop = parms[i];
969 val = values[i];
970
e4f79258
RS
971 if (EQ (prop, Qwidth) && NUMBERP (val))
972 width = XFASTINT (val);
973 else if (EQ (prop, Qheight) && NUMBERP (val))
974 height = XFASTINT (val);
f5e70acd 975 else if (EQ (prop, Qtop))
f9942c9e 976 top = val;
f5e70acd 977 else if (EQ (prop, Qleft))
f9942c9e 978 left = val;
a59e4f3d
RS
979 else if (EQ (prop, Qicon_top))
980 icon_top = val;
981 else if (EQ (prop, Qicon_left))
982 icon_left = val;
b3ba0aa8
KS
983 else if (EQ (prop, Qforeground_color)
984 || EQ (prop, Qbackground_color)
49d41073
EZ
985 || EQ (prop, Qfont)
986 || EQ (prop, Qfullscreen))
a797a73d
GV
987 /* Processed above. */
988 continue;
f9942c9e
JB
989 else
990 {
98381190 991 register Lisp_Object param_index, old_value;
ea96210c 992
98381190 993 old_value = get_frame_param (f, prop);
c7e609d5 994
9f7e52b4 995 store_frame_param (f, prop, val);
c7e609d5 996
9f7e52b4
GM
997 param_index = Fget (prop, Qx_frame_parameter);
998 if (NATNUMP (param_index)
999 && (XFASTINT (param_index)
1000 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
1001 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
f9942c9e
JB
1002 }
1003 }
1004
11378c41
RS
1005 /* Don't die if just one of these was set. */
1006 if (EQ (left, Qunbound))
e1d962d7
RS
1007 {
1008 left_no_change = 1;
7556890b
RS
1009 if (f->output_data.x->left_pos < 0)
1010 left = Fcons (Qplus, Fcons (make_number (f->output_data.x->left_pos), Qnil));
e1d962d7 1011 else
7556890b 1012 XSETINT (left, f->output_data.x->left_pos);
e1d962d7 1013 }
11378c41 1014 if (EQ (top, Qunbound))
e1d962d7
RS
1015 {
1016 top_no_change = 1;
7556890b
RS
1017 if (f->output_data.x->top_pos < 0)
1018 top = Fcons (Qplus, Fcons (make_number (f->output_data.x->top_pos), Qnil));
e1d962d7 1019 else
7556890b 1020 XSETINT (top, f->output_data.x->top_pos);
e1d962d7 1021 }
11378c41 1022
a59e4f3d
RS
1023 /* If one of the icon positions was not set, preserve or default it. */
1024 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
1025 {
1026 icon_left_no_change = 1;
1027 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
1028 if (NILP (icon_left))
1029 XSETINT (icon_left, 0);
1030 }
1031 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
1032 {
1033 icon_top_no_change = 1;
1034 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
1035 if (NILP (icon_top))
1036 XSETINT (icon_top, 0);
1037 }
1038
5f9338d5 1039 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
49d41073
EZ
1040 {
1041 /* If the frame is visible already and the fullscreen parameter is
1042 being set, it is too late to set WM manager hints to specify
1043 size and position.
1044 Here we first get the width, height and position that applies to
1045 fullscreen. We then move the frame to the appropriate
1046 position. Resize of the frame is taken care of in the code after
5f9338d5 1047 this if-statement. */
49d41073
EZ
1048 int new_left, new_top;
1049
1050 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
1051 x_fullscreen_move (f, new_top, new_left);
1052 }
1053
499ea23b 1054 /* Don't set these parameters unless they've been explicitly
d387c960
JB
1055 specified. The window might be mapped or resized while we're in
1056 this function, and we don't want to override that unless the lisp
1057 code has asked for it.
1058
1059 Don't set these parameters unless they actually differ from the
1060 window's current parameters; the window may not actually exist
1061 yet. */
f9942c9e
JB
1062 {
1063 Lisp_Object frame;
1064
1f11a5ca
RS
1065 check_frame_size (f, &height, &width);
1066
191ed777 1067 XSETFRAME (frame, f);
11378c41 1068
e4f79258
RS
1069 if (width != FRAME_WIDTH (f)
1070 || height != FRAME_HEIGHT (f)
d6f80ae9 1071 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
e4f79258 1072 Fset_frame_size (frame, make_number (width), make_number (height));
f10f0b79
RS
1073
1074 if ((!NILP (left) || !NILP (top))
e1d962d7 1075 && ! (left_no_change && top_no_change)
7556890b
RS
1076 && ! (NUMBERP (left) && XINT (left) == f->output_data.x->left_pos
1077 && NUMBERP (top) && XINT (top) == f->output_data.x->top_pos))
f10f0b79 1078 {
e1d962d7
RS
1079 int leftpos = 0;
1080 int toppos = 0;
f10f0b79
RS
1081
1082 /* Record the signs. */
7556890b 1083 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
e1d962d7 1084 if (EQ (left, Qminus))
7556890b 1085 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7
RS
1086 else if (INTEGERP (left))
1087 {
1088 leftpos = XINT (left);
1089 if (leftpos < 0)
7556890b 1090 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7 1091 }
8e713be6
KR
1092 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1093 && CONSP (XCDR (left))
1094 && INTEGERP (XCAR (XCDR (left))))
e1d962d7 1095 {
8e713be6 1096 leftpos = - XINT (XCAR (XCDR (left)));
7556890b 1097 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7 1098 }
8e713be6
KR
1099 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1100 && CONSP (XCDR (left))
1101 && INTEGERP (XCAR (XCDR (left))))
e1d962d7 1102 {
8e713be6 1103 leftpos = XINT (XCAR (XCDR (left)));
e1d962d7
RS
1104 }
1105
1106 if (EQ (top, Qminus))
7556890b 1107 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7
RS
1108 else if (INTEGERP (top))
1109 {
1110 toppos = XINT (top);
1111 if (toppos < 0)
7556890b 1112 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7 1113 }
8e713be6
KR
1114 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1115 && CONSP (XCDR (top))
1116 && INTEGERP (XCAR (XCDR (top))))
e1d962d7 1117 {
8e713be6 1118 toppos = - XINT (XCAR (XCDR (top)));
7556890b 1119 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7 1120 }
8e713be6
KR
1121 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1122 && CONSP (XCDR (top))
1123 && INTEGERP (XCAR (XCDR (top))))
e1d962d7 1124 {
8e713be6 1125 toppos = XINT (XCAR (XCDR (top)));
e1d962d7
RS
1126 }
1127
1128
1129 /* Store the numeric value of the position. */
7556890b
RS
1130 f->output_data.x->top_pos = toppos;
1131 f->output_data.x->left_pos = leftpos;
e1d962d7 1132
7556890b 1133 f->output_data.x->win_gravity = NorthWestGravity;
f10f0b79
RS
1134
1135 /* Actually set that position, and convert to absolute. */
f0e72e79 1136 x_set_offset (f, leftpos, toppos, -1);
f10f0b79 1137 }
a59e4f3d
RS
1138
1139 if ((!NILP (icon_left) || !NILP (icon_top))
1140 && ! (icon_left_no_change && icon_top_no_change))
1141 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
f9942c9e 1142 }
7589a1d9
RS
1143
1144 UNGCPRO;
f9942c9e 1145}
01f1ba30 1146
08a90d6a 1147/* Store the screen positions of frame F into XPTR and YPTR.
e9445337
RS
1148 These are the positions of the containing window manager window,
1149 not Emacs's own window. */
1150
1151void
1152x_real_positions (f, xptr, yptr)
1153 FRAME_PTR f;
1154 int *xptr, *yptr;
1155{
49d41073
EZ
1156 int win_x, win_y, outer_x, outer_y;
1157 int real_x = 0, real_y = 0;
1158 int had_errors = 0;
1159 Window win = f->output_data.x->parent_desc;
e9445337 1160
49d41073 1161 int count;
043835a3 1162
49d41073
EZ
1163 BLOCK_INPUT;
1164
1165 count = x_catch_errors (FRAME_X_DISPLAY (f));
043835a3 1166
49d41073
EZ
1167 if (win == FRAME_X_DISPLAY_INFO (f)->root_window)
1168 win = FRAME_OUTER_WINDOW (f);
1169
1170 /* This loop traverses up the containment tree until we hit the root
1171 window. Window managers may intersect many windows between our window
1172 and the root window. The window we find just before the root window
1173 should be the outer WM window. */
1174 for (;;)
e9445337 1175 {
49d41073
EZ
1176 Window wm_window, rootw;
1177 Window *tmp_children;
1178 unsigned int tmp_nchildren;
ca7bac79 1179
49d41073
EZ
1180 XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
1181 &wm_window, &tmp_children, &tmp_nchildren);
72dc3bc7 1182 XFree ((char *) tmp_children);
08a90d6a 1183
49d41073 1184 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
08a90d6a 1185
49d41073
EZ
1186 if (wm_window == rootw || had_errors)
1187 break;
08a90d6a 1188
49d41073
EZ
1189 win = wm_window;
1190 }
1191
1192 if (! had_errors)
1193 {
1194 int ign;
1195 Window child, rootw;
1196
1197 /* Get the real coordinates for the WM window upper left corner */
1198 XGetGeometry (FRAME_X_DISPLAY (f), win,
1199 &rootw, &real_x, &real_y, &ign, &ign, &ign, &ign);
1200
1201 /* Translate real coordinates to coordinates relative to our
1202 window. For our window, the upper left corner is 0, 0.
1203 Since the upper left corner of the WM window is outside
1204 our window, win_x and win_y will be negative:
1205
1206 ------------------ ---> x
1207 | title |
1208 | ----------------- v y
1209 | | our window
1210 */
8a07bba0 1211 XTranslateCoordinates (FRAME_X_DISPLAY (f),
e9445337 1212
8a07bba0 1213 /* From-window, to-window. */
8a07bba0 1214 FRAME_X_DISPLAY_INFO (f)->root_window,
49d41073 1215 FRAME_X_WINDOW (f),
e9445337 1216
8a07bba0 1217 /* From-position, to-position. */
49d41073 1218 real_x, real_y, &win_x, &win_y,
08a90d6a 1219
8a07bba0
RS
1220 /* Child of win. */
1221 &child);
e9445337 1222
49d41073 1223 if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
845e9d85 1224 {
49d41073
EZ
1225 outer_x = win_x;
1226 outer_y = win_y;
845e9d85 1227 }
49d41073
EZ
1228 else
1229 {
1230 XTranslateCoordinates (FRAME_X_DISPLAY (f),
ca7bac79 1231
49d41073
EZ
1232 /* From-window, to-window. */
1233 FRAME_X_DISPLAY_INFO (f)->root_window,
1234 FRAME_OUTER_WINDOW (f),
1235
1236 /* From-position, to-position. */
1237 real_x, real_y, &outer_x, &outer_y,
1238
1239 /* Child of win. */
1240 &child);
e9445337 1241 }
08a90d6a 1242
49d41073
EZ
1243 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
1244 }
1245
1246 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
1247
1248 UNBLOCK_INPUT;
1249
1250 if (had_errors) return;
1251
1252 f->output_data.x->x_pixels_diff = -win_x;
1253 f->output_data.x->y_pixels_diff = -win_y;
1254 f->output_data.x->x_pixels_outer_diff = -outer_x;
1255 f->output_data.x->y_pixels_outer_diff = -outer_y;
1256
1257 *xptr = real_x;
1258 *yptr = real_y;
e9445337
RS
1259}
1260
f676886a 1261/* Insert a description of internally-recorded parameters of frame X
01f1ba30
JB
1262 into the parameter alist *ALISTPTR that is to be given to the user.
1263 Only parameters that are specific to the X window system
f676886a 1264 and whose values are not correctly recorded in the frame's
01f1ba30
JB
1265 param_alist need to be considered here. */
1266
968b1234 1267void
f676886a
JB
1268x_report_frame_params (f, alistptr)
1269 struct frame *f;
01f1ba30
JB
1270 Lisp_Object *alistptr;
1271{
1272 char buf[16];
9b002b8d
KH
1273 Lisp_Object tem;
1274
1275 /* Represent negative positions (off the top or left screen edge)
1276 in a way that Fmodify_frame_parameters will understand correctly. */
7556890b
RS
1277 XSETINT (tem, f->output_data.x->left_pos);
1278 if (f->output_data.x->left_pos >= 0)
9b002b8d
KH
1279 store_in_alist (alistptr, Qleft, tem);
1280 else
1281 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1282
7556890b
RS
1283 XSETINT (tem, f->output_data.x->top_pos);
1284 if (f->output_data.x->top_pos >= 0)
9b002b8d
KH
1285 store_in_alist (alistptr, Qtop, tem);
1286 else
1287 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
01f1ba30 1288
f9942c9e 1289 store_in_alist (alistptr, Qborder_width,
7556890b 1290 make_number (f->output_data.x->border_width));
f9942c9e 1291 store_in_alist (alistptr, Qinternal_border_width,
7556890b 1292 make_number (f->output_data.x->internal_border_width));
30bf44e0
KS
1293 store_in_alist (alistptr, Qleft_fringe,
1294 make_number (f->output_data.x->left_fringe_width));
1295 store_in_alist (alistptr, Qright_fringe,
1296 make_number (f->output_data.x->right_fringe_width));
99f7c77f
EZ
1297 store_in_alist (alistptr, Qscroll_bar_width,
1298 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1299 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1300 : 0));
7c118b57 1301 sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f));
f9942c9e 1302 store_in_alist (alistptr, Qwindow_id,
01f1ba30 1303 build_string (buf));
333b20bb
GM
1304#ifdef USE_X_TOOLKIT
1305 /* Tooltip frame may not have this widget. */
1306 if (f->output_data.x->widget)
1307#endif
1308 sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f));
2cbebefb
RS
1309 store_in_alist (alistptr, Qouter_window_id,
1310 build_string (buf));
f468da95 1311 store_in_alist (alistptr, Qicon_name, f->icon_name);
a8ccd803 1312 FRAME_SAMPLE_VISIBILITY (f);
d043f1a4
RS
1313 store_in_alist (alistptr, Qvisibility,
1314 (FRAME_VISIBLE_P (f) ? Qt
1315 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
34ae77b5 1316 store_in_alist (alistptr, Qdisplay,
8e713be6 1317 XCAR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
e4f79258 1318
8c239ac3
RS
1319 if (f->output_data.x->parent_desc == FRAME_X_DISPLAY_INFO (f)->root_window)
1320 tem = Qnil;
1321 else
1322 XSETFASTINT (tem, f->output_data.x->parent_desc);
1323 store_in_alist (alistptr, Qparent_id, tem);
01f1ba30
JB
1324}
1325\f
82978295 1326
d62c8769
GM
1327
1328/* Gamma-correct COLOR on frame F. */
1329
1330void
1331gamma_correct (f, color)
1332 struct frame *f;
1333 XColor *color;
1334{
1335 if (f->gamma)
1336 {
1337 color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5;
1338 color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5;
1339 color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5;
1340 }
1341}
1342
1343
7b746c38
GM
1344/* Decide if color named COLOR_NAME is valid for use on frame F. If
1345 so, return the RGB values in COLOR. If ALLOC_P is non-zero,
1346 allocate the color. Value is zero if COLOR_NAME is invalid, or
1347 no color could be allocated. */
e12d55b2 1348
01f1ba30 1349int
7b746c38
GM
1350x_defined_color (f, color_name, color, alloc_p)
1351 struct frame *f;
1352 char *color_name;
1353 XColor *color;
1354 int alloc_p;
01f1ba30 1355{
7b746c38
GM
1356 int success_p;
1357 Display *dpy = FRAME_X_DISPLAY (f);
1358 Colormap cmap = FRAME_X_COLORMAP (f);
01f1ba30
JB
1359
1360 BLOCK_INPUT;
7b746c38
GM
1361 success_p = XParseColor (dpy, cmap, color_name, color);
1362 if (success_p && alloc_p)
1363 success_p = x_alloc_nearest_color (f, cmap, color);
01f1ba30
JB
1364 UNBLOCK_INPUT;
1365
7b746c38 1366 return success_p;
01f1ba30
JB
1367}
1368
9b2956e2
GM
1369
1370/* Return the pixel color value for color COLOR_NAME on frame F. If F
1371 is a monochrome frame, return MONO_COLOR regardless of what ARG says.
1372 Signal an error if color can't be allocated. */
01f1ba30
JB
1373
1374int
9b2956e2 1375x_decode_color (f, color_name, mono_color)
b9dc4443 1376 FRAME_PTR f;
9b2956e2
GM
1377 Lisp_Object color_name;
1378 int mono_color;
01f1ba30 1379{
b9dc4443 1380 XColor cdef;
01f1ba30 1381
b7826503 1382 CHECK_STRING (color_name);
01f1ba30 1383
9b2956e2
GM
1384#if 0 /* Don't do this. It's wrong when we're not using the default
1385 colormap, it makes freeing difficult, and it's probably not
1386 an important optimization. */
1387 if (strcmp (XSTRING (color_name)->data, "black") == 0)
b9dc4443 1388 return BLACK_PIX_DEFAULT (f);
9b2956e2 1389 else if (strcmp (XSTRING (color_name)->data, "white") == 0)
b9dc4443 1390 return WHITE_PIX_DEFAULT (f);
9b2956e2 1391#endif
01f1ba30 1392
9b2956e2 1393 /* Return MONO_COLOR for monochrome frames. */
b9dc4443 1394 if (FRAME_X_DISPLAY_INFO (f)->n_planes == 1)
9b2956e2 1395 return mono_color;
01f1ba30 1396
2d764c78 1397 /* x_defined_color is responsible for coping with failures
95626e11 1398 by looking for a near-miss. */
9b2956e2 1399 if (x_defined_color (f, XSTRING (color_name)->data, &cdef, 1))
95626e11
RS
1400 return cdef.pixel;
1401
c301be26
GM
1402 Fsignal (Qerror, Fcons (build_string ("Undefined color"),
1403 Fcons (color_name, Qnil)));
1404 return 0;
01f1ba30 1405}
9b2956e2
GM
1406
1407
01f1ba30 1408\f
563b67aa
GM
1409/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1410 the previous value of that parameter, NEW_VALUE is the new value. */
1411
1412static void
1413x_set_line_spacing (f, new_value, old_value)
1414 struct frame *f;
1415 Lisp_Object new_value, old_value;
1416{
1417 if (NILP (new_value))
1418 f->extra_line_spacing = 0;
1419 else if (NATNUMP (new_value))
1420 f->extra_line_spacing = XFASTINT (new_value);
1421 else
1a948b17 1422 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
563b67aa
GM
1423 Fcons (new_value, Qnil)));
1424 if (FRAME_VISIBLE_P (f))
1425 redraw_frame (f);
1426}
1427
1428
ea0a1f53
GM
1429/* Change the `wait-for-wm' frame parameter of frame F. OLD_VALUE is
1430 the previous value of that parameter, NEW_VALUE is the new value.
1431 See also the comment of wait_for_wm in struct x_output. */
1432
1433static void
1434x_set_wait_for_wm (f, new_value, old_value)
1435 struct frame *f;
1436 Lisp_Object new_value, old_value;
1437{
1438 f->output_data.x->wait_for_wm = !NILP (new_value);
1439}
1440
1441
49d41073
EZ
1442/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
1443 the previous value of that parameter, NEW_VALUE is the new value. */
1444
1445static void
1446x_set_fullscreen (f, new_value, old_value)
1447 struct frame *f;
1448 Lisp_Object new_value, old_value;
1449{
1450 if (NILP (new_value))
1451 f->output_data.x->want_fullscreen = FULLSCREEN_NONE;
1452 else if (EQ (new_value, Qfullboth))
1453 f->output_data.x->want_fullscreen = FULLSCREEN_BOTH;
1454 else if (EQ (new_value, Qfullwidth))
1455 f->output_data.x->want_fullscreen = FULLSCREEN_WIDTH;
1456 else if (EQ (new_value, Qfullheight))
1457 f->output_data.x->want_fullscreen = FULLSCREEN_HEIGHT;
1458}
1459
1460
d62c8769 1461/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
ea0a1f53
GM
1462 the previous value of that parameter, NEW_VALUE is the new
1463 value. */
d62c8769
GM
1464
1465static void
1466x_set_screen_gamma (f, new_value, old_value)
1467 struct frame *f;
1468 Lisp_Object new_value, old_value;
1469{
1470 if (NILP (new_value))
1471 f->gamma = 0;
1472 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1473 /* The value 0.4545 is the normal viewing gamma. */
1474 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1475 else
1a948b17 1476 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
d62c8769
GM
1477 Fcons (new_value, Qnil)));
1478
1479 clear_face_cache (0);
1480}
1481
1482
f676886a 1483/* Functions called only from `x_set_frame_param'
01f1ba30
JB
1484 to set individual parameters.
1485
fe24a618 1486 If FRAME_X_WINDOW (f) is 0,
f676886a 1487 the frame is being created and its X-window does not exist yet.
01f1ba30
JB
1488 In that case, just record the parameter's new value
1489 in the standard place; do not attempt to change the window. */
1490
1491void
f676886a
JB
1492x_set_foreground_color (f, arg, oldval)
1493 struct frame *f;
01f1ba30
JB
1494 Lisp_Object arg, oldval;
1495{
09393d07
GM
1496 struct x_output *x = f->output_data.x;
1497 unsigned long fg, old_fg;
a76206dc 1498
09393d07
GM
1499 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1500 old_fg = x->foreground_pixel;
1501 x->foreground_pixel = fg;
a76206dc 1502
fe24a618 1503 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1504 {
09393d07 1505 Display *dpy = FRAME_X_DISPLAY (f);
36d42089 1506
09393d07
GM
1507 BLOCK_INPUT;
1508 XSetForeground (dpy, x->normal_gc, fg);
1509 XSetBackground (dpy, x->reverse_gc, fg);
36d42089 1510
09393d07
GM
1511 if (x->cursor_pixel == old_fg)
1512 {
1513 unload_color (f, x->cursor_pixel);
1514 x->cursor_pixel = x_copy_color (f, fg);
1515 XSetBackground (dpy, x->cursor_gc, x->cursor_pixel);
1516 }
1517
01f1ba30 1518 UNBLOCK_INPUT;
09393d07 1519
05c8abbe 1520 update_face_from_frame_parameter (f, Qforeground_color, arg);
09393d07 1521
179956b9 1522 if (FRAME_VISIBLE_P (f))
f676886a 1523 redraw_frame (f);
01f1ba30 1524 }
09393d07
GM
1525
1526 unload_color (f, old_fg);
01f1ba30
JB
1527}
1528
1529void
f676886a
JB
1530x_set_background_color (f, arg, oldval)
1531 struct frame *f;
01f1ba30
JB
1532 Lisp_Object arg, oldval;
1533{
09393d07
GM
1534 struct x_output *x = f->output_data.x;
1535 unsigned long bg;
01f1ba30 1536
09393d07
GM
1537 bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1538 unload_color (f, x->background_pixel);
1539 x->background_pixel = bg;
a76206dc 1540
fe24a618 1541 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1542 {
09393d07 1543 Display *dpy = FRAME_X_DISPLAY (f);
36d42089 1544
09393d07
GM
1545 BLOCK_INPUT;
1546 XSetBackground (dpy, x->normal_gc, bg);
1547 XSetForeground (dpy, x->reverse_gc, bg);
1548 XSetWindowBackground (dpy, FRAME_X_WINDOW (f), bg);
1549 XSetForeground (dpy, x->cursor_gc, bg);
1550
f76e0368
GM
1551#ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with
1552 toolkit scroll bars. */
1553 {
1554 Lisp_Object bar;
1555 for (bar = FRAME_SCROLL_BARS (f);
1556 !NILP (bar);
1557 bar = XSCROLL_BAR (bar)->next)
1558 {
1559 Window window = SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar));
1560 XSetWindowBackground (dpy, window, bg);
1561 }
1562 }
1563#endif /* USE_TOOLKIT_SCROLL_BARS */
01f1ba30 1564
09393d07 1565 UNBLOCK_INPUT;
05c8abbe 1566 update_face_from_frame_parameter (f, Qbackground_color, arg);
ea96210c 1567
179956b9 1568 if (FRAME_VISIBLE_P (f))
f676886a 1569 redraw_frame (f);
01f1ba30
JB
1570 }
1571}
1572
1573void
f676886a
JB
1574x_set_mouse_color (f, arg, oldval)
1575 struct frame *f;
01f1ba30
JB
1576 Lisp_Object arg, oldval;
1577{
09393d07
GM
1578 struct x_output *x = f->output_data.x;
1579 Display *dpy = FRAME_X_DISPLAY (f);
95f80c78 1580 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
0af913d7 1581 Cursor hourglass_cursor, horizontal_drag_cursor;
1dc6cfa6 1582 int count;
51a1d2d8 1583 unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
09393d07 1584 unsigned long mask_color = x->background_pixel;
a76206dc 1585
51a1d2d8 1586 /* Don't let pointers be invisible. */
09393d07 1587 if (mask_color == pixel)
bcf26b38
GM
1588 {
1589 x_free_colors (f, &pixel, 1);
09393d07 1590 pixel = x_copy_color (f, x->foreground_pixel);
bcf26b38 1591 }
a76206dc 1592
09393d07
GM
1593 unload_color (f, x->mouse_pixel);
1594 x->mouse_pixel = pixel;
01f1ba30
JB
1595
1596 BLOCK_INPUT;
fe24a618 1597
eb8c3be9 1598 /* It's not okay to crash if the user selects a screwy cursor. */
09393d07 1599 count = x_catch_errors (dpy);
fe24a618 1600
09393d07 1601 if (!NILP (Vx_pointer_shape))
01f1ba30 1602 {
b7826503 1603 CHECK_NUMBER (Vx_pointer_shape);
09393d07 1604 cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
01f1ba30
JB
1605 }
1606 else
09393d07
GM
1607 cursor = XCreateFontCursor (dpy, XC_xterm);
1608 x_check_errors (dpy, "bad text pointer cursor: %s");
01f1ba30 1609
09393d07 1610 if (!NILP (Vx_nontext_pointer_shape))
01f1ba30 1611 {
b7826503 1612 CHECK_NUMBER (Vx_nontext_pointer_shape);
09393d07
GM
1613 nontext_cursor
1614 = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
01f1ba30
JB
1615 }
1616 else
09393d07
GM
1617 nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
1618 x_check_errors (dpy, "bad nontext pointer cursor: %s");
01f1ba30 1619
09393d07 1620 if (!NILP (Vx_hourglass_pointer_shape))
333b20bb 1621 {
b7826503 1622 CHECK_NUMBER (Vx_hourglass_pointer_shape);
09393d07
GM
1623 hourglass_cursor
1624 = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
333b20bb
GM
1625 }
1626 else
09393d07
GM
1627 hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
1628 x_check_errors (dpy, "bad hourglass pointer cursor: %s");
333b20bb 1629
09393d07
GM
1630 x_check_errors (dpy, "bad nontext pointer cursor: %s");
1631 if (!NILP (Vx_mode_pointer_shape))
01f1ba30 1632 {
b7826503 1633 CHECK_NUMBER (Vx_mode_pointer_shape);
09393d07 1634 mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
01f1ba30
JB
1635 }
1636 else
09393d07
GM
1637 mode_cursor = XCreateFontCursor (dpy, XC_xterm);
1638 x_check_errors (dpy, "bad modeline pointer cursor: %s");
95f80c78 1639
09393d07 1640 if (!NILP (Vx_sensitive_text_pointer_shape))
95f80c78 1641 {
b7826503 1642 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ca0ecbf5 1643 cross_cursor
09393d07 1644 = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
95f80c78
FP
1645 }
1646 else
09393d07 1647 cross_cursor = XCreateFontCursor (dpy, XC_crosshair);
01f1ba30 1648
8fb4ec9c
GM
1649 if (!NILP (Vx_window_horizontal_drag_shape))
1650 {
b7826503 1651 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
8fb4ec9c 1652 horizontal_drag_cursor
09393d07 1653 = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
8fb4ec9c
GM
1654 }
1655 else
1656 horizontal_drag_cursor
09393d07 1657 = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
8fb4ec9c 1658
fe24a618 1659 /* Check and report errors with the above calls. */
09393d07
GM
1660 x_check_errors (dpy, "can't set cursor shape: %s");
1661 x_uncatch_errors (dpy, count);
fe24a618 1662
01f1ba30
JB
1663 {
1664 XColor fore_color, back_color;
1665
09393d07 1666 fore_color.pixel = x->mouse_pixel;
a31fedb7 1667 x_query_color (f, &fore_color);
01f1ba30 1668 back_color.pixel = mask_color;
a31fedb7
GM
1669 x_query_color (f, &back_color);
1670
09393d07
GM
1671 XRecolorCursor (dpy, cursor, &fore_color, &back_color);
1672 XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
1673 XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
1674 XRecolorCursor (dpy, cross_cursor, &fore_color, &back_color);
1675 XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
1676 XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
01f1ba30 1677 }
01f1ba30 1678
fe24a618 1679 if (FRAME_X_WINDOW (f) != 0)
09393d07
GM
1680 XDefineCursor (dpy, FRAME_X_WINDOW (f), cursor);
1681
1682 if (cursor != x->text_cursor
1683 && x->text_cursor != 0)
1684 XFreeCursor (dpy, x->text_cursor);
1685 x->text_cursor = cursor;
1686
1687 if (nontext_cursor != x->nontext_cursor
1688 && x->nontext_cursor != 0)
1689 XFreeCursor (dpy, x->nontext_cursor);
1690 x->nontext_cursor = nontext_cursor;
1691
1692 if (hourglass_cursor != x->hourglass_cursor
1693 && x->hourglass_cursor != 0)
1694 XFreeCursor (dpy, x->hourglass_cursor);
1695 x->hourglass_cursor = hourglass_cursor;
1696
1697 if (mode_cursor != x->modeline_cursor
1698 && x->modeline_cursor != 0)
1699 XFreeCursor (dpy, f->output_data.x->modeline_cursor);
1700 x->modeline_cursor = mode_cursor;
333b20bb 1701
09393d07
GM
1702 if (cross_cursor != x->cross_cursor
1703 && x->cross_cursor != 0)
1704 XFreeCursor (dpy, x->cross_cursor);
1705 x->cross_cursor = cross_cursor;
01f1ba30 1706
09393d07
GM
1707 if (horizontal_drag_cursor != x->horizontal_drag_cursor
1708 && x->horizontal_drag_cursor != 0)
1709 XFreeCursor (dpy, x->horizontal_drag_cursor);
1710 x->horizontal_drag_cursor = horizontal_drag_cursor;
8fb4ec9c 1711
09393d07 1712 XFlush (dpy);
01f1ba30 1713 UNBLOCK_INPUT;
05c8abbe
GM
1714
1715 update_face_from_frame_parameter (f, Qmouse_color, arg);
01f1ba30
JB
1716}
1717
1718void
f676886a
JB
1719x_set_cursor_color (f, arg, oldval)
1720 struct frame *f;
01f1ba30
JB
1721 Lisp_Object arg, oldval;
1722{
a76206dc 1723 unsigned long fore_pixel, pixel;
10168ebb 1724 int fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
09393d07 1725 struct x_output *x = f->output_data.x;
01f1ba30 1726
10168ebb
GM
1727 if (!NILP (Vx_cursor_fore_pixel))
1728 {
1729 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
1730 WHITE_PIX_DEFAULT (f));
1731 fore_pixel_allocated_p = 1;
1732 }
01f1ba30 1733 else
09393d07 1734 fore_pixel = x->background_pixel;
10168ebb 1735
a76206dc 1736 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
10168ebb 1737 pixel_allocated_p = 1;
a76206dc 1738
f9942c9e 1739 /* Make sure that the cursor color differs from the background color. */
09393d07 1740 if (pixel == x->background_pixel)
01f1ba30 1741 {
10168ebb
GM
1742 if (pixel_allocated_p)
1743 {
1744 x_free_colors (f, &pixel, 1);
1745 pixel_allocated_p = 0;
1746 }
1747
09393d07 1748 pixel = x->mouse_pixel;
a76206dc 1749 if (pixel == fore_pixel)
10168ebb
GM
1750 {
1751 if (fore_pixel_allocated_p)
1752 {
1753 x_free_colors (f, &fore_pixel, 1);
1754 fore_pixel_allocated_p = 0;
1755 }
09393d07 1756 fore_pixel = x->background_pixel;
10168ebb 1757 }
01f1ba30 1758 }
a76206dc 1759
09393d07 1760 unload_color (f, x->cursor_foreground_pixel);
10168ebb
GM
1761 if (!fore_pixel_allocated_p)
1762 fore_pixel = x_copy_color (f, fore_pixel);
09393d07 1763 x->cursor_foreground_pixel = fore_pixel;
01f1ba30 1764
09393d07 1765 unload_color (f, x->cursor_pixel);
10168ebb
GM
1766 if (!pixel_allocated_p)
1767 pixel = x_copy_color (f, pixel);
09393d07 1768 x->cursor_pixel = pixel;
a76206dc 1769
fe24a618 1770 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1771 {
01f1ba30 1772 BLOCK_INPUT;
09393d07
GM
1773 XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
1774 XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);
01f1ba30 1775 UNBLOCK_INPUT;
01f1ba30 1776
179956b9 1777 if (FRAME_VISIBLE_P (f))
01f1ba30 1778 {
cedadcfa
RS
1779 x_update_cursor (f, 0);
1780 x_update_cursor (f, 1);
01f1ba30
JB
1781 }
1782 }
05c8abbe
GM
1783
1784 update_face_from_frame_parameter (f, Qcursor_color, arg);
01f1ba30 1785}
943b580d 1786\f
f676886a 1787/* Set the border-color of frame F to value described by ARG.
01f1ba30
JB
1788 ARG can be a string naming a color.
1789 The border-color is used for the border that is drawn by the X server.
1790 Note that this does not fully take effect if done before
f676886a 1791 F has an x-window; it must be redone when the window is created.
01f1ba30
JB
1792
1793 Note: this is done in two routines because of the way X10 works.
1794
1795 Note: under X11, this is normally the province of the window manager,
b9dc4443 1796 and so emacs' border colors may be overridden. */
01f1ba30
JB
1797
1798void
f676886a
JB
1799x_set_border_color (f, arg, oldval)
1800 struct frame *f;
01f1ba30
JB
1801 Lisp_Object arg, oldval;
1802{
01f1ba30
JB
1803 int pix;
1804
b7826503 1805 CHECK_STRING (arg);
b9dc4443 1806 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
f676886a 1807 x_set_border_pixel (f, pix);
05c8abbe 1808 update_face_from_frame_parameter (f, Qborder_color, arg);
01f1ba30
JB
1809}
1810
f676886a 1811/* Set the border-color of frame F to pixel value PIX.
01f1ba30 1812 Note that this does not fully take effect if done before
f676886a 1813 F has an x-window. */
01f1ba30 1814
968b1234 1815void
f676886a
JB
1816x_set_border_pixel (f, pix)
1817 struct frame *f;
01f1ba30
JB
1818 int pix;
1819{
a76206dc 1820 unload_color (f, f->output_data.x->border_pixel);
7556890b 1821 f->output_data.x->border_pixel = pix;
01f1ba30 1822
7556890b 1823 if (FRAME_X_WINDOW (f) != 0 && f->output_data.x->border_width > 0)
01f1ba30 1824 {
01f1ba30 1825 BLOCK_INPUT;
b9dc4443 1826 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
270958e8 1827 (unsigned long)pix);
01f1ba30
JB
1828 UNBLOCK_INPUT;
1829
179956b9 1830 if (FRAME_VISIBLE_P (f))
f676886a 1831 redraw_frame (f);
01f1ba30
JB
1832 }
1833}
1834
0d1469d6
GM
1835
1836/* Value is the internal representation of the specified cursor type
1837 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
1838 of the bar cursor. */
1839
1840enum text_cursor_kinds
1841x_specified_cursor_type (arg, width)
1842 Lisp_Object arg;
1843 int *width;
dbc4e1c1 1844{
0d1469d6
GM
1845 enum text_cursor_kinds type;
1846
dbc4e1c1 1847 if (EQ (arg, Qbar))
c3211206 1848 {
0d1469d6
GM
1849 type = BAR_CURSOR;
1850 *width = 2;
c3211206 1851 }
08ac8554
GM
1852 else if (CONSP (arg)
1853 && EQ (XCAR (arg), Qbar)
1854 && INTEGERP (XCDR (arg))
1855 && XINT (XCDR (arg)) >= 0)
c3211206 1856 {
0d1469d6
GM
1857 type = BAR_CURSOR;
1858 *width = XINT (XCDR (arg));
c3211206 1859 }
08ac8554 1860 else if (NILP (arg))
0d1469d6 1861 type = NO_CURSOR;
dbc4e1c1 1862 else
c3211206
RS
1863 /* Treat anything unknown as "box cursor".
1864 It was bad to signal an error; people have trouble fixing
1865 .Xdefaults with Emacs, when it has something bad in it. */
0d1469d6
GM
1866 type = FILLED_BOX_CURSOR;
1867
1868 return type;
1869}
1870
1871void
1872x_set_cursor_type (f, arg, oldval)
1873 FRAME_PTR f;
1874 Lisp_Object arg, oldval;
1875{
1876 int width;
1877
1878 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
1879 f->output_data.x->cursor_width = width;
dbc4e1c1
JB
1880
1881 /* Make sure the cursor gets redrawn. This is overkill, but how
1882 often do people change cursor types? */
1883 update_mode_lines++;
1884}
943b580d 1885\f
01f1ba30 1886void
f676886a
JB
1887x_set_icon_type (f, arg, oldval)
1888 struct frame *f;
01f1ba30
JB
1889 Lisp_Object arg, oldval;
1890{
01f1ba30
JB
1891 int result;
1892
203c1d73
RS
1893 if (STRINGP (arg))
1894 {
1895 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1896 return;
1897 }
1898 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
01f1ba30
JB
1899 return;
1900
1901 BLOCK_INPUT;
265a9e55 1902 if (NILP (arg))
80534dd6 1903 result = x_text_icon (f,
f468da95
RS
1904 (char *) XSTRING ((!NILP (f->icon_name)
1905 ? f->icon_name
80534dd6 1906 : f->name))->data);
f1c7b5a6
RS
1907 else
1908 result = x_bitmap_icon (f, arg);
01f1ba30
JB
1909
1910 if (result)
1911 {
01f1ba30 1912 UNBLOCK_INPUT;
0fb53770 1913 error ("No icon window available");
01f1ba30
JB
1914 }
1915
b9dc4443 1916 XFlush (FRAME_X_DISPLAY (f));
01f1ba30
JB
1917 UNBLOCK_INPUT;
1918}
1919
f1c7b5a6 1920/* Return non-nil if frame F wants a bitmap icon. */
0fb53770 1921
f1c7b5a6 1922Lisp_Object
0fb53770
RS
1923x_icon_type (f)
1924 FRAME_PTR f;
1925{
1926 Lisp_Object tem;
1927
1928 tem = assq_no_quit (Qicon_type, f->param_alist);
f1c7b5a6 1929 if (CONSP (tem))
8e713be6 1930 return XCDR (tem);
f1c7b5a6
RS
1931 else
1932 return Qnil;
0fb53770
RS
1933}
1934
80534dd6
KH
1935void
1936x_set_icon_name (f, arg, oldval)
1937 struct frame *f;
1938 Lisp_Object arg, oldval;
1939{
80534dd6
KH
1940 int result;
1941
1942 if (STRINGP (arg))
1943 {
1944 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1945 return;
1946 }
1947 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
1948 return;
1949
f468da95 1950 f->icon_name = arg;
80534dd6 1951
7556890b 1952 if (f->output_data.x->icon_bitmap != 0)
80534dd6
KH
1953 return;
1954
1955 BLOCK_INPUT;
1956
1957 result = x_text_icon (f,
f468da95
RS
1958 (char *) XSTRING ((!NILP (f->icon_name)
1959 ? f->icon_name
943b580d
RS
1960 : !NILP (f->title)
1961 ? f->title
80534dd6
KH
1962 : f->name))->data);
1963
1964 if (result)
1965 {
1966 UNBLOCK_INPUT;
1967 error ("No icon window available");
1968 }
1969
80534dd6
KH
1970 XFlush (FRAME_X_DISPLAY (f));
1971 UNBLOCK_INPUT;
1972}
943b580d 1973\f
01f1ba30 1974void
f676886a
JB
1975x_set_font (f, arg, oldval)
1976 struct frame *f;
01f1ba30
JB
1977 Lisp_Object arg, oldval;
1978{
ea96210c 1979 Lisp_Object result;
942ea06d 1980 Lisp_Object fontset_name;
a367641f 1981 Lisp_Object frame;
57c5889c 1982 int old_fontset = f->output_data.x->fontset;
01f1ba30 1983
b7826503 1984 CHECK_STRING (arg);
01f1ba30 1985
49965a29 1986 fontset_name = Fquery_fontset (arg, Qnil);
942ea06d 1987
01f1ba30 1988 BLOCK_INPUT;
942ea06d
KH
1989 result = (STRINGP (fontset_name)
1990 ? x_new_fontset (f, XSTRING (fontset_name)->data)
1991 : x_new_font (f, XSTRING (arg)->data));
01f1ba30
JB
1992 UNBLOCK_INPUT;
1993
ea96210c 1994 if (EQ (result, Qnil))
1c59f5df 1995 error ("Font `%s' is not defined", XSTRING (arg)->data);
ea96210c 1996 else if (EQ (result, Qt))
26e18ed9 1997 error ("The characters of the given font have varying widths");
ea96210c
JB
1998 else if (STRINGP (result))
1999 {
57c5889c
GM
2000 if (STRINGP (fontset_name))
2001 {
2002 /* Fontset names are built from ASCII font names, so the
2003 names may be equal despite there was a change. */
2004 if (old_fontset == f->output_data.x->fontset)
2005 return;
2006 }
2007 else if (!NILP (Fequal (result, oldval)))
1d090605 2008 return;
57c5889c 2009
ea96210c 2010 store_frame_param (f, Qfont, result);
333b20bb 2011 recompute_basic_faces (f);
ea96210c
JB
2012 }
2013 else
2014 abort ();
a367641f 2015
8938a4fb 2016 do_pending_window_change (0);
95aa0336 2017
333b20bb
GM
2018 /* Don't call `face-set-after-frame-default' when faces haven't been
2019 initialized yet. This is the case when called from
2020 Fx_create_frame. In that case, the X widget or window doesn't
2021 exist either, and we can end up in x_report_frame_params with a
2022 null widget which gives a segfault. */
2023 if (FRAME_FACE_CACHE (f))
2024 {
2025 XSETFRAME (frame, f);
2026 call1 (Qface_set_after_frame_default, frame);
2027 }
01f1ba30
JB
2028}
2029
b3ba0aa8
KS
2030static void
2031x_set_fringe_width (f, new_value, old_value)
2032 struct frame *f;
2033 Lisp_Object new_value, old_value;
2034{
2035 x_compute_fringe_widths (f, 1);
2036}
2037
01f1ba30 2038void
f676886a
JB
2039x_set_border_width (f, arg, oldval)
2040 struct frame *f;
01f1ba30
JB
2041 Lisp_Object arg, oldval;
2042{
b7826503 2043 CHECK_NUMBER (arg);
01f1ba30 2044
7556890b 2045 if (XINT (arg) == f->output_data.x->border_width)
01f1ba30
JB
2046 return;
2047
fe24a618 2048 if (FRAME_X_WINDOW (f) != 0)
01f1ba30
JB
2049 error ("Cannot change the border width of a window");
2050
7556890b 2051 f->output_data.x->border_width = XINT (arg);
01f1ba30
JB
2052}
2053
2054void
f676886a
JB
2055x_set_internal_border_width (f, arg, oldval)
2056 struct frame *f;
01f1ba30
JB
2057 Lisp_Object arg, oldval;
2058{
7556890b 2059 int old = f->output_data.x->internal_border_width;
01f1ba30 2060
b7826503 2061 CHECK_NUMBER (arg);
7556890b
RS
2062 f->output_data.x->internal_border_width = XINT (arg);
2063 if (f->output_data.x->internal_border_width < 0)
2064 f->output_data.x->internal_border_width = 0;
01f1ba30 2065
d3b06468 2066#ifdef USE_X_TOOLKIT
2a8a07d4 2067 if (f->output_data.x->edit_widget)
968b1234 2068 widget_store_internal_border (f->output_data.x->edit_widget);
d3b06468 2069#endif
2a8a07d4 2070
7556890b 2071 if (f->output_data.x->internal_border_width == old)
01f1ba30
JB
2072 return;
2073
fe24a618 2074 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 2075 {
363f7e15 2076 x_set_window_size (f, 0, f->width, f->height);
f676886a 2077 SET_FRAME_GARBAGED (f);
8938a4fb 2078 do_pending_window_change (0);
01f1ba30 2079 }
ea42193a
GM
2080 else
2081 SET_FRAME_GARBAGED (f);
01f1ba30
JB
2082}
2083
d043f1a4
RS
2084void
2085x_set_visibility (f, value, oldval)
2086 struct frame *f;
2087 Lisp_Object value, oldval;
2088{
2089 Lisp_Object frame;
191ed777 2090 XSETFRAME (frame, f);
d043f1a4
RS
2091
2092 if (NILP (value))
363f7e15 2093 Fmake_frame_invisible (frame, Qt);
49795535 2094 else if (EQ (value, Qicon))
d043f1a4 2095 Ficonify_frame (frame);
49795535
JB
2096 else
2097 Fmake_frame_visible (frame);
d043f1a4 2098}
52de7ce9 2099
943b580d 2100\f
52de7ce9
GM
2101/* Change window heights in windows rooted in WINDOW by N lines. */
2102
d043f1a4 2103static void
52de7ce9 2104x_change_window_heights (window, n)
d043f1a4
RS
2105 Lisp_Object window;
2106 int n;
2107{
47c0f58b 2108 struct window *w = XWINDOW (window);
d043f1a4 2109
e33f7330
KH
2110 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2111 XSETFASTINT (w->height, XFASTINT (w->height) - n);
d043f1a4 2112
4336c705
GM
2113 if (INTEGERP (w->orig_top))
2114 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2115 if (INTEGERP (w->orig_height))
2116 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2117
47c0f58b
RS
2118 /* Handle just the top child in a vertical split. */
2119 if (!NILP (w->vchild))
52de7ce9 2120 x_change_window_heights (w->vchild, n);
d043f1a4 2121
47c0f58b
RS
2122 /* Adjust all children in a horizontal split. */
2123 for (window = w->hchild; !NILP (window); window = w->next)
2124 {
2125 w = XWINDOW (window);
52de7ce9 2126 x_change_window_heights (window, n);
d043f1a4
RS
2127 }
2128}
2129
2130void
2131x_set_menu_bar_lines (f, value, oldval)
2132 struct frame *f;
2133 Lisp_Object value, oldval;
2134{
2135 int nlines;
b6d7acec 2136#ifndef USE_X_TOOLKIT
d043f1a4 2137 int olines = FRAME_MENU_BAR_LINES (f);
b6d7acec 2138#endif
d043f1a4 2139
f64ba6ea
JB
2140 /* Right now, menu bars don't work properly in minibuf-only frames;
2141 most of the commands try to apply themselves to the minibuffer
333b20bb 2142 frame itself, and get an error because you can't switch buffers
f64ba6ea 2143 in or split the minibuffer window. */
519066d2 2144 if (FRAME_MINIBUF_ONLY_P (f))
f64ba6ea
JB
2145 return;
2146
6a5e54e2 2147 if (INTEGERP (value))
d043f1a4
RS
2148 nlines = XINT (value);
2149 else
2150 nlines = 0;
2151
3d09b6be
RS
2152 /* Make sure we redisplay all windows in this frame. */
2153 windows_or_buffers_changed++;
2154
9ef48a9d
RS
2155#ifdef USE_X_TOOLKIT
2156 FRAME_MENU_BAR_LINES (f) = 0;
2157 if (nlines)
0d8ef3f4
RS
2158 {
2159 FRAME_EXTERNAL_MENU_BAR (f) = 1;
97a1ff91 2160 if (FRAME_X_P (f) && f->output_data.x->menubar_widget == 0)
0d8ef3f4
RS
2161 /* Make sure next redisplay shows the menu bar. */
2162 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt;
2163 }
9ef48a9d
RS
2164 else
2165 {
6bc20398
FP
2166 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2167 free_frame_menubar (f);
9ef48a9d 2168 FRAME_EXTERNAL_MENU_BAR (f) = 0;
97a1ff91
RS
2169 if (FRAME_X_P (f))
2170 f->output_data.x->menubar_widget = 0;
9ef48a9d
RS
2171 }
2172#else /* not USE_X_TOOLKIT */
d043f1a4 2173 FRAME_MENU_BAR_LINES (f) = nlines;
52de7ce9 2174 x_change_window_heights (f->root_window, nlines - olines);
9ef48a9d 2175#endif /* not USE_X_TOOLKIT */
333b20bb
GM
2176 adjust_glyphs (f);
2177}
2178
2179
2180/* Set the number of lines used for the tool bar of frame F to VALUE.
2181 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2182 is the old number of tool bar lines. This function changes the
2183 height of all windows on frame F to match the new tool bar height.
2184 The frame's height doesn't change. */
2185
2186void
9ea173e8 2187x_set_tool_bar_lines (f, value, oldval)
333b20bb
GM
2188 struct frame *f;
2189 Lisp_Object value, oldval;
2190{
52de7ce9
GM
2191 int delta, nlines, root_height;
2192 Lisp_Object root_window;
333b20bb 2193
e870b7ba
GM
2194 /* Treat tool bars like menu bars. */
2195 if (FRAME_MINIBUF_ONLY_P (f))
2196 return;
2197
333b20bb
GM
2198 /* Use VALUE only if an integer >= 0. */
2199 if (INTEGERP (value) && XINT (value) >= 0)
2200 nlines = XFASTINT (value);
2201 else
2202 nlines = 0;
2203
2204 /* Make sure we redisplay all windows in this frame. */
2205 ++windows_or_buffers_changed;
2206
9ea173e8 2207 delta = nlines - FRAME_TOOL_BAR_LINES (f);
52de7ce9
GM
2208
2209 /* Don't resize the tool-bar to more than we have room for. */
2210 root_window = FRAME_ROOT_WINDOW (f);
2211 root_height = XINT (XWINDOW (root_window)->height);
2212 if (root_height - delta < 1)
2213 {
2214 delta = root_height - 1;
2215 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2216 }
2217
9ea173e8 2218 FRAME_TOOL_BAR_LINES (f) = nlines;
52de7ce9 2219 x_change_window_heights (root_window, delta);
333b20bb 2220 adjust_glyphs (f);
ccba751c
GM
2221
2222 /* We also have to make sure that the internal border at the top of
2223 the frame, below the menu bar or tool bar, is redrawn when the
2224 tool bar disappears. This is so because the internal border is
2225 below the tool bar if one is displayed, but is below the menu bar
2226 if there isn't a tool bar. The tool bar draws into the area
2227 below the menu bar. */
2228 if (FRAME_X_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2229 {
2230 updating_frame = f;
2231 clear_frame ();
fb3cd89b 2232 clear_current_matrices (f);
ccba751c
GM
2233 updating_frame = NULL;
2234 }
b6f91066
GM
2235
2236 /* If the tool bar gets smaller, the internal border below it
2237 has to be cleared. It was formerly part of the display
2238 of the larger tool bar, and updating windows won't clear it. */
2239 if (delta < 0)
2240 {
2241 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2242 int width = PIXEL_WIDTH (f);
2243 int y = nlines * CANON_Y_UNIT (f);
2244
2245 BLOCK_INPUT;
161d30fd
GM
2246 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2247 0, y, width, height, False);
b6f91066 2248 UNBLOCK_INPUT;
ddc24747
GM
2249
2250 if (WINDOWP (f->tool_bar_window))
2251 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
b6f91066 2252 }
333b20bb
GM
2253}
2254
2255
2256/* Set the foreground color for scroll bars on frame F to VALUE.
2257 VALUE should be a string, a color name. If it isn't a string or
2258 isn't a valid color name, do nothing. OLDVAL is the old value of
2259 the frame parameter. */
2260
2261void
2262x_set_scroll_bar_foreground (f, value, oldval)
2263 struct frame *f;
2264 Lisp_Object value, oldval;
2265{
2266 unsigned long pixel;
2267
2268 if (STRINGP (value))
2269 pixel = x_decode_color (f, value, BLACK_PIX_DEFAULT (f));
2270 else
2271 pixel = -1;
2272
2273 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
2274 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
2275
2276 f->output_data.x->scroll_bar_foreground_pixel = pixel;
2277 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2278 {
2279 /* Remove all scroll bars because they have wrong colors. */
2280 if (condemn_scroll_bars_hook)
2281 (*condemn_scroll_bars_hook) (f);
2282 if (judge_scroll_bars_hook)
2283 (*judge_scroll_bars_hook) (f);
05c8abbe
GM
2284
2285 update_face_from_frame_parameter (f, Qscroll_bar_foreground, value);
333b20bb
GM
2286 redraw_frame (f);
2287 }
2288}
2289
2290
2291/* Set the background color for scroll bars on frame F to VALUE VALUE
2292 should be a string, a color name. If it isn't a string or isn't a
2293 valid color name, do nothing. OLDVAL is the old value of the frame
2294 parameter. */
2295
2296void
2297x_set_scroll_bar_background (f, value, oldval)
2298 struct frame *f;
2299 Lisp_Object value, oldval;
2300{
2301 unsigned long pixel;
2302
2303 if (STRINGP (value))
2304 pixel = x_decode_color (f, value, WHITE_PIX_DEFAULT (f));
2305 else
2306 pixel = -1;
2307
2308 if (f->output_data.x->scroll_bar_background_pixel != -1)
2309 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
2310
f15340b7
MB
2311#ifdef USE_TOOLKIT_SCROLL_BARS
2312 /* Scrollbar shadow colors. */
2313 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
2314 {
2315 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
2316 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
2317 }
2318 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
2319 {
2320 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
2321 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
2322 }
2323#endif /* USE_TOOLKIT_SCROLL_BARS */
2324
333b20bb
GM
2325 f->output_data.x->scroll_bar_background_pixel = pixel;
2326 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2327 {
2328 /* Remove all scroll bars because they have wrong colors. */
2329 if (condemn_scroll_bars_hook)
2330 (*condemn_scroll_bars_hook) (f);
2331 if (judge_scroll_bars_hook)
2332 (*judge_scroll_bars_hook) (f);
2333
05c8abbe 2334 update_face_from_frame_parameter (f, Qscroll_bar_background, value);
333b20bb
GM
2335 redraw_frame (f);
2336 }
d043f1a4 2337}
333b20bb 2338
943b580d 2339\f
3a258507 2340/* Encode Lisp string STRING as a text in a format appropriate for
96db09e4
KH
2341 XICCC (X Inter Client Communication Conventions).
2342
2343 If STRING contains only ASCII characters, do no conversion and
2344 return the string data of STRING. Otherwise, encode the text by
2345 CODING_SYSTEM, and return a newly allocated memory area which
2346 should be freed by `xfree' by a caller.
2347
37323f34
EZ
2348 SELECTIONP non-zero means the string is being encoded for an X
2349 selection, so it is safe to run pre-write conversions (which
2350 may run Lisp code).
2351
96db09e4
KH
2352 Store the byte length of resulting text in *TEXT_BYTES.
2353
d60660d6 2354 If the text contains only ASCII and Latin-1, store 1 in *STRING_P,
96db09e4 2355 which means that the `encoding' of the result can be `STRING'.
d60660d6 2356 Otherwise store 0 in *STRINGP, which means that the `encoding' of
96db09e4
KH
2357 the result should be `COMPOUND_TEXT'. */
2358
2359unsigned char *
37323f34 2360x_encode_text (string, coding_system, selectionp, text_bytes, stringp)
96db09e4 2361 Lisp_Object string, coding_system;
d60660d6 2362 int *text_bytes, *stringp;
37323f34 2363 int selectionp;
96db09e4
KH
2364{
2365 unsigned char *str = XSTRING (string)->data;
2366 int chars = XSTRING (string)->size;
2367 int bytes = STRING_BYTES (XSTRING (string));
2368 int charset_info;
2369 int bufsize;
2370 unsigned char *buf;
2371 struct coding_system coding;
2372
2373 charset_info = find_charset_in_text (str, chars, bytes, NULL, Qnil);
2374 if (charset_info == 0)
2375 {
2376 /* No multibyte character in OBJ. We need not encode it. */
2377 *text_bytes = bytes;
d60660d6 2378 *stringp = 1;
96db09e4
KH
2379 return str;
2380 }
2381
2382 setup_coding_system (coding_system, &coding);
37323f34
EZ
2383 if (selectionp
2384 && SYMBOLP (coding.pre_write_conversion)
2385 && !NILP (Ffboundp (coding.pre_write_conversion)))
2386 {
2387 string = run_pre_post_conversion_on_str (string, &coding, 1);
2388 str = XSTRING (string)->data;
2389 chars = XSTRING (string)->size;
2390 bytes = STRING_BYTES (XSTRING (string));
2391 }
96db09e4
KH
2392 coding.src_multibyte = 1;
2393 coding.dst_multibyte = 0;
2394 coding.mode |= CODING_MODE_LAST_BLOCK;
d60660d6
KH
2395 if (coding.type == coding_type_iso2022)
2396 coding.flags |= CODING_FLAG_ISO_SAFE;
35bc5887
KH
2397 /* We suppress producing escape sequences for composition. */
2398 coding.composing = COMPOSITION_DISABLED;
96db09e4
KH
2399 bufsize = encoding_buffer_size (&coding, bytes);
2400 buf = (unsigned char *) xmalloc (bufsize);
2401 encode_coding (&coding, str, buf, bytes, bufsize);
2402 *text_bytes = coding.produced;
d60660d6 2403 *stringp = (charset_info == 1 || !EQ (coding_system, Qcompound_text));
96db09e4
KH
2404 return buf;
2405}
2406
2407\f
75f9d625 2408/* Change the name of frame F to NAME. If NAME is nil, set F's name to
f945b920
JB
2409 x_id_name.
2410
2411 If EXPLICIT is non-zero, that indicates that lisp code is setting the
75f9d625
DM
2412 name; if NAME is a string, set F's name to NAME and set
2413 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
f945b920
JB
2414
2415 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2416 suggesting a new name, which lisp code should override; if
2417 F->explicit_name is set, ignore the new name; otherwise, set it. */
2418
2419void
2420x_set_name (f, name, explicit)
2421 struct frame *f;
2422 Lisp_Object name;
2423 int explicit;
2424{
2425 /* Make sure that requests from lisp code override requests from
2426 Emacs redisplay code. */
2427 if (explicit)
2428 {
2429 /* If we're switching from explicit to implicit, we had better
2430 update the mode lines and thereby update the title. */
2431 if (f->explicit_name && NILP (name))
cf177271 2432 update_mode_lines = 1;
f945b920
JB
2433
2434 f->explicit_name = ! NILP (name);
2435 }
2436 else if (f->explicit_name)
2437 return;
2438
2439 /* If NAME is nil, set the name to the x_id_name. */
2440 if (NILP (name))
f10f0b79
RS
2441 {
2442 /* Check for no change needed in this very common case
2443 before we do any consing. */
08a90d6a
RS
2444 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->x_id_name,
2445 XSTRING (f->name)->data))
f10f0b79 2446 return;
08a90d6a 2447 name = build_string (FRAME_X_DISPLAY_INFO (f)->x_id_name);
f10f0b79 2448 }
62265f1c 2449 else
b7826503 2450 CHECK_STRING (name);
01f1ba30 2451
f945b920
JB
2452 /* Don't change the name if it's already NAME. */
2453 if (! NILP (Fstring_equal (name, f->name)))
daa37602
JB
2454 return;
2455
943b580d
RS
2456 f->name = name;
2457
2458 /* For setting the frame title, the title parameter should override
2459 the name parameter. */
2460 if (! NILP (f->title))
2461 name = f->title;
2462
fe24a618 2463 if (FRAME_X_WINDOW (f))
01f1ba30 2464 {
01f1ba30 2465 BLOCK_INPUT;
fe24a618
JB
2466#ifdef HAVE_X11R4
2467 {
80534dd6 2468 XTextProperty text, icon;
d60660d6 2469 int bytes, stringp;
11270583 2470 Lisp_Object coding_system;
80534dd6 2471
11270583
KH
2472 coding_system = Vlocale_coding_system;
2473 if (NILP (coding_system))
2474 coding_system = Qcompound_text;
37323f34 2475 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2476 text.encoding = (stringp ? XA_STRING
96db09e4 2477 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
fe24a618 2478 text.format = 8;
96db09e4 2479 text.nitems = bytes;
80534dd6 2480
96db09e4
KH
2481 if (NILP (f->icon_name))
2482 {
2483 icon = text;
2484 }
2485 else
2486 {
37323f34 2487 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2488 &bytes, &stringp);
2489 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2490 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2491 icon.format = 8;
2492 icon.nitems = bytes;
2493 }
9ef48a9d 2494#ifdef USE_X_TOOLKIT
b9dc4443 2495 XSetWMName (FRAME_X_DISPLAY (f),
7556890b
RS
2496 XtWindow (f->output_data.x->widget), &text);
2497 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
80534dd6 2498 &icon);
9ef48a9d 2499#else /* not USE_X_TOOLKIT */
b9dc4443 2500 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
80534dd6 2501 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
9ef48a9d 2502#endif /* not USE_X_TOOLKIT */
96db09e4
KH
2503 if (!NILP (f->icon_name)
2504 && icon.value != XSTRING (f->icon_name)->data)
2505 xfree (icon.value);
2506 if (text.value != XSTRING (name)->data)
2507 xfree (text.value);
fe24a618 2508 }
9ef48a9d 2509#else /* not HAVE_X11R4 */
b9dc4443 2510 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
fe24a618 2511 XSTRING (name)->data);
b9dc4443 2512 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
fe24a618 2513 XSTRING (name)->data);
9ef48a9d 2514#endif /* not HAVE_X11R4 */
01f1ba30
JB
2515 UNBLOCK_INPUT;
2516 }
f945b920
JB
2517}
2518
2519/* This function should be called when the user's lisp code has
2520 specified a name for the frame; the name will override any set by the
2521 redisplay code. */
2522void
2523x_explicitly_set_name (f, arg, oldval)
2524 FRAME_PTR f;
2525 Lisp_Object arg, oldval;
2526{
2527 x_set_name (f, arg, 1);
2528}
2529
2530/* This function should be called by Emacs redisplay code to set the
2531 name; names set this way will never override names set by the user's
2532 lisp code. */
25250031 2533void
f945b920
JB
2534x_implicitly_set_name (f, arg, oldval)
2535 FRAME_PTR f;
2536 Lisp_Object arg, oldval;
2537{
2538 x_set_name (f, arg, 0);
01f1ba30 2539}
943b580d
RS
2540\f
2541/* Change the title of frame F to NAME.
2542 If NAME is nil, use the frame name as the title.
01f1ba30 2543
943b580d
RS
2544 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2545 name; if NAME is a string, set F's name to NAME and set
2546 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2547
2548 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2549 suggesting a new name, which lisp code should override; if
2550 F->explicit_name is set, ignore the new name; otherwise, set it. */
2551
2552void
d62c8769 2553x_set_title (f, name, old_name)
943b580d 2554 struct frame *f;
d62c8769 2555 Lisp_Object name, old_name;
943b580d
RS
2556{
2557 /* Don't change the title if it's already NAME. */
2558 if (EQ (name, f->title))
2559 return;
2560
2561 update_mode_lines = 1;
2562
2563 f->title = name;
2564
2565 if (NILP (name))
2566 name = f->name;
beb403b3 2567 else
b7826503 2568 CHECK_STRING (name);
943b580d
RS
2569
2570 if (FRAME_X_WINDOW (f))
2571 {
2572 BLOCK_INPUT;
2573#ifdef HAVE_X11R4
2574 {
2575 XTextProperty text, icon;
d60660d6 2576 int bytes, stringp;
11270583 2577 Lisp_Object coding_system;
943b580d 2578
11270583
KH
2579 coding_system = Vlocale_coding_system;
2580 if (NILP (coding_system))
2581 coding_system = Qcompound_text;
37323f34 2582 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2583 text.encoding = (stringp ? XA_STRING
96db09e4 2584 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
943b580d 2585 text.format = 8;
96db09e4 2586 text.nitems = bytes;
943b580d 2587
96db09e4
KH
2588 if (NILP (f->icon_name))
2589 {
2590 icon = text;
2591 }
2592 else
2593 {
37323f34 2594 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2595 &bytes, &stringp);
2596 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2597 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2598 icon.format = 8;
2599 icon.nitems = bytes;
2600 }
943b580d
RS
2601#ifdef USE_X_TOOLKIT
2602 XSetWMName (FRAME_X_DISPLAY (f),
2603 XtWindow (f->output_data.x->widget), &text);
2604 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
2605 &icon);
2606#else /* not USE_X_TOOLKIT */
2607 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
2608 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
2609#endif /* not USE_X_TOOLKIT */
96db09e4
KH
2610 if (!NILP (f->icon_name)
2611 && icon.value != XSTRING (f->icon_name)->data)
2612 xfree (icon.value);
2613 if (text.value != XSTRING (name)->data)
2614 xfree (text.value);
943b580d
RS
2615 }
2616#else /* not HAVE_X11R4 */
2617 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2618 XSTRING (name)->data);
2619 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2620 XSTRING (name)->data);
2621#endif /* not HAVE_X11R4 */
2622 UNBLOCK_INPUT;
2623 }
2624}
2625\f
01f1ba30 2626void
f676886a
JB
2627x_set_autoraise (f, arg, oldval)
2628 struct frame *f;
01f1ba30
JB
2629 Lisp_Object arg, oldval;
2630{
f676886a 2631 f->auto_raise = !EQ (Qnil, arg);
01f1ba30
JB
2632}
2633
2634void
f676886a
JB
2635x_set_autolower (f, arg, oldval)
2636 struct frame *f;
01f1ba30
JB
2637 Lisp_Object arg, oldval;
2638{
f676886a 2639 f->auto_lower = !EQ (Qnil, arg);
01f1ba30 2640}
179956b9 2641
eac358ef
KH
2642void
2643x_set_unsplittable (f, arg, oldval)
2644 struct frame *f;
2645 Lisp_Object arg, oldval;
2646{
2647 f->no_split = !NILP (arg);
2648}
2649
179956b9 2650void
a3c87d4e 2651x_set_vertical_scroll_bars (f, arg, oldval)
179956b9
JB
2652 struct frame *f;
2653 Lisp_Object arg, oldval;
2654{
1ab3d87e
RS
2655 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2656 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2657 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2658 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
179956b9 2659 {
1ab3d87e
RS
2660 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2661 = (NILP (arg)
2662 ? vertical_scroll_bar_none
2663 : EQ (Qright, arg)
2664 ? vertical_scroll_bar_right
2665 : vertical_scroll_bar_left);
179956b9 2666
cf177271
JB
2667 /* We set this parameter before creating the X window for the
2668 frame, so we can get the geometry right from the start.
2669 However, if the window hasn't been created yet, we shouldn't
2670 call x_set_window_size. */
2671 if (FRAME_X_WINDOW (f))
363f7e15 2672 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2673 do_pending_window_change (0);
179956b9
JB
2674 }
2675}
4701395c
KH
2676
2677void
2678x_set_scroll_bar_width (f, arg, oldval)
2679 struct frame *f;
2680 Lisp_Object arg, oldval;
2681{
a672c74d
RS
2682 int wid = FONT_WIDTH (f->output_data.x->font);
2683
dff9a538
KH
2684 if (NILP (arg))
2685 {
c6e9d03b
GM
2686#ifdef USE_TOOLKIT_SCROLL_BARS
2687 /* A minimum width of 14 doesn't look good for toolkit scroll bars. */
333b20bb
GM
2688 int width = 16 + 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM;
2689 FRAME_SCROLL_BAR_COLS (f) = (width + wid - 1) / wid;
2690 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = width;
2691#else
2692 /* Make the actual width at least 14 pixels and a multiple of a
2693 character width. */
a672c74d 2694 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
333b20bb
GM
2695
2696 /* Use all of that space (aside from required margins) for the
2697 scroll bar. */
dff9a538 2698 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
333b20bb 2699#endif
a672c74d 2700
a90ab372
RS
2701 if (FRAME_X_WINDOW (f))
2702 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2703 do_pending_window_change (0);
dff9a538
KH
2704 }
2705 else if (INTEGERP (arg) && XINT (arg) > 0
2706 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
4701395c 2707 {
09d8c7ac
RS
2708 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
2709 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
0a26b136 2710
4701395c
KH
2711 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2712 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
2713 if (FRAME_X_WINDOW (f))
2714 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2715 }
dca97592 2716
8938a4fb 2717 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
333b20bb
GM
2718 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2719 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
4701395c 2720}
333b20bb
GM
2721
2722
01f1ba30 2723\f
f676886a 2724/* Subroutines of creating an X frame. */
01f1ba30 2725
b7975ee4
KH
2726/* Make sure that Vx_resource_name is set to a reasonable value.
2727 Fix it up, or set it to `emacs' if it is too hopeless. */
2728
d387c960
JB
2729static void
2730validate_x_resource_name ()
2731{
333b20bb 2732 int len = 0;
0e78b377
RS
2733 /* Number of valid characters in the resource name. */
2734 int good_count = 0;
2735 /* Number of invalid characters in the resource name. */
2736 int bad_count = 0;
2737 Lisp_Object new;
2738 int i;
2739
498e9ac3
RS
2740 if (!STRINGP (Vx_resource_class))
2741 Vx_resource_class = build_string (EMACS_CLASS);
2742
cf204347
RS
2743 if (STRINGP (Vx_resource_name))
2744 {
cf204347
RS
2745 unsigned char *p = XSTRING (Vx_resource_name)->data;
2746 int i;
2747
fc932ac6 2748 len = STRING_BYTES (XSTRING (Vx_resource_name));
0e78b377
RS
2749
2750 /* Only letters, digits, - and _ are valid in resource names.
2751 Count the valid characters and count the invalid ones. */
cf204347
RS
2752 for (i = 0; i < len; i++)
2753 {
2754 int c = p[i];
2755 if (! ((c >= 'a' && c <= 'z')
2756 || (c >= 'A' && c <= 'Z')
2757 || (c >= '0' && c <= '9')
2758 || c == '-' || c == '_'))
0e78b377
RS
2759 bad_count++;
2760 else
2761 good_count++;
cf204347
RS
2762 }
2763 }
2764 else
0e78b377
RS
2765 /* Not a string => completely invalid. */
2766 bad_count = 5, good_count = 0;
2767
2768 /* If name is valid already, return. */
2769 if (bad_count == 0)
2770 return;
2771
2772 /* If name is entirely invalid, or nearly so, use `emacs'. */
2773 if (good_count == 0
2774 || (good_count == 1 && bad_count > 0))
2775 {
b7975ee4 2776 Vx_resource_name = build_string ("emacs");
0e78b377
RS
2777 return;
2778 }
2779
2780 /* Name is partly valid. Copy it and replace the invalid characters
2781 with underscores. */
2782
2783 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2784
2785 for (i = 0; i < len; i++)
2786 {
2787 int c = XSTRING (new)->data[i];
2788 if (! ((c >= 'a' && c <= 'z')
2789 || (c >= 'A' && c <= 'Z')
2790 || (c >= '0' && c <= '9')
2791 || c == '-' || c == '_'))
2792 XSTRING (new)->data[i] = '_';
2793 }
d387c960
JB
2794}
2795
2796
01f1ba30 2797extern char *x_get_string_resource ();
01f1ba30 2798
cf177271 2799DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
03265352 2800 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
c061c855
GM
2801This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2802class, where INSTANCE is the name under which Emacs was invoked, or
2803the name specified by the `-name' or `-rn' command-line arguments.
2804
2805The optional arguments COMPONENT and SUBCLASS add to the key and the
2806class, respectively. You must specify both of them or neither.
2807If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
7ee72033
MB
2808and the class is `Emacs.CLASS.SUBCLASS'. */)
2809 (attribute, class, component, subclass)
cf177271 2810 Lisp_Object attribute, class, component, subclass;
01f1ba30
JB
2811{
2812 register char *value;
2813 char *name_key;
2814 char *class_key;
2815
11ae94fe
RS
2816 check_x ();
2817
b7826503
PJ
2818 CHECK_STRING (attribute);
2819 CHECK_STRING (class);
cf177271 2820
8fabe6f4 2821 if (!NILP (component))
b7826503 2822 CHECK_STRING (component);
8fabe6f4 2823 if (!NILP (subclass))
b7826503 2824 CHECK_STRING (subclass);
8fabe6f4
RS
2825 if (NILP (component) != NILP (subclass))
2826 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2827
d387c960
JB
2828 validate_x_resource_name ();
2829
b7975ee4
KH
2830 /* Allocate space for the components, the dots which separate them,
2831 and the final '\0'. Make them big enough for the worst case. */
fc932ac6 2832 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
b7975ee4 2833 + (STRINGP (component)
fc932ac6
RS
2834 ? STRING_BYTES (XSTRING (component)) : 0)
2835 + STRING_BYTES (XSTRING (attribute))
b7975ee4
KH
2836 + 3);
2837
fc932ac6
RS
2838 class_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_class))
2839 + STRING_BYTES (XSTRING (class))
b7975ee4 2840 + (STRINGP (subclass)
fc932ac6 2841 ? STRING_BYTES (XSTRING (subclass)) : 0)
b7975ee4
KH
2842 + 3);
2843
2844 /* Start with emacs.FRAMENAME for the name (the specific one)
2845 and with `Emacs' for the class key (the general one). */
2846 strcpy (name_key, XSTRING (Vx_resource_name)->data);
498e9ac3 2847 strcpy (class_key, XSTRING (Vx_resource_class)->data);
b7975ee4
KH
2848
2849 strcat (class_key, ".");
2850 strcat (class_key, XSTRING (class)->data);
2851
2852 if (!NILP (component))
01f1ba30 2853 {
b7975ee4
KH
2854 strcat (class_key, ".");
2855 strcat (class_key, XSTRING (subclass)->data);
2856
2857 strcat (name_key, ".");
2858 strcat (name_key, XSTRING (component)->data);
01f1ba30
JB
2859 }
2860
b7975ee4
KH
2861 strcat (name_key, ".");
2862 strcat (name_key, XSTRING (attribute)->data);
2863
b9dc4443
RS
2864 value = x_get_string_resource (check_x_display_info (Qnil)->xrdb,
2865 name_key, class_key);
01f1ba30
JB
2866
2867 if (value != (char *) 0)
2868 return build_string (value);
2869 else
2870 return Qnil;
2871}
2872
abb4b7ec
RS
2873/* Get an X resource, like Fx_get_resource, but for display DPYINFO. */
2874
333b20bb 2875Lisp_Object
abb4b7ec
RS
2876display_x_get_resource (dpyinfo, attribute, class, component, subclass)
2877 struct x_display_info *dpyinfo;
2878 Lisp_Object attribute, class, component, subclass;
2879{
2880 register char *value;
2881 char *name_key;
2882 char *class_key;
2883
b7826503
PJ
2884 CHECK_STRING (attribute);
2885 CHECK_STRING (class);
abb4b7ec
RS
2886
2887 if (!NILP (component))
b7826503 2888 CHECK_STRING (component);
abb4b7ec 2889 if (!NILP (subclass))
b7826503 2890 CHECK_STRING (subclass);
abb4b7ec
RS
2891 if (NILP (component) != NILP (subclass))
2892 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2893
2894 validate_x_resource_name ();
2895
2896 /* Allocate space for the components, the dots which separate them,
2897 and the final '\0'. Make them big enough for the worst case. */
fc932ac6 2898 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
abb4b7ec 2899 + (STRINGP (component)
fc932ac6
RS
2900 ? STRING_BYTES (XSTRING (component)) : 0)
2901 + STRING_BYTES (XSTRING (attribute))
abb4b7ec
RS
2902 + 3);
2903
fc932ac6
RS
2904 class_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_class))
2905 + STRING_BYTES (XSTRING (class))
abb4b7ec 2906 + (STRINGP (subclass)
fc932ac6 2907 ? STRING_BYTES (XSTRING (subclass)) : 0)
abb4b7ec
RS
2908 + 3);
2909
2910 /* Start with emacs.FRAMENAME for the name (the specific one)
2911 and with `Emacs' for the class key (the general one). */
2912 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2913 strcpy (class_key, XSTRING (Vx_resource_class)->data);
2914
2915 strcat (class_key, ".");
2916 strcat (class_key, XSTRING (class)->data);
2917
2918 if (!NILP (component))
2919 {
2920 strcat (class_key, ".");
2921 strcat (class_key, XSTRING (subclass)->data);
2922
2923 strcat (name_key, ".");
2924 strcat (name_key, XSTRING (component)->data);
2925 }
2926
2927 strcat (name_key, ".");
2928 strcat (name_key, XSTRING (attribute)->data);
2929
2930 value = x_get_string_resource (dpyinfo->xrdb, name_key, class_key);
2931
2932 if (value != (char *) 0)
2933 return build_string (value);
2934 else
2935 return Qnil;
2936}
2937
3402e1a4
RS
2938/* Used when C code wants a resource value. */
2939
2940char *
2941x_get_resource_string (attribute, class)
2942 char *attribute, *class;
2943{
3402e1a4
RS
2944 char *name_key;
2945 char *class_key;
0fe92f72 2946 struct frame *sf = SELECTED_FRAME ();
3402e1a4
RS
2947
2948 /* Allocate space for the components, the dots which separate them,
2949 and the final '\0'. */
fc932ac6 2950 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3402e1a4
RS
2951 + strlen (attribute) + 2);
2952 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2953 + strlen (class) + 2);
2954
2955 sprintf (name_key, "%s.%s",
2956 XSTRING (Vinvocation_name)->data,
2957 attribute);
2958 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2959
0fe92f72 2960 return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
b9dc4443 2961 name_key, class_key);
3402e1a4
RS
2962}
2963
60fb3ee1
JB
2964/* Types we might convert a resource string into. */
2965enum resource_types
333b20bb
GM
2966{
2967 RES_TYPE_NUMBER,
d62c8769 2968 RES_TYPE_FLOAT,
333b20bb
GM
2969 RES_TYPE_BOOLEAN,
2970 RES_TYPE_STRING,
2971 RES_TYPE_SYMBOL
2972};
60fb3ee1 2973
01f1ba30 2974/* Return the value of parameter PARAM.
60fb3ee1 2975
f676886a 2976 First search ALIST, then Vdefault_frame_alist, then the X defaults
cf177271 2977 database, using ATTRIBUTE as the attribute name and CLASS as its class.
60fb3ee1
JB
2978
2979 Convert the resource to the type specified by desired_type.
2980
f9942c9e
JB
2981 If no default is specified, return Qunbound. If you call
2982 x_get_arg, make sure you deal with Qunbound in a reasonable way,
a59e4f3d 2983 and don't let it get stored in any Lisp-visible variables! */
01f1ba30
JB
2984
2985static Lisp_Object
abb4b7ec
RS
2986x_get_arg (dpyinfo, alist, param, attribute, class, type)
2987 struct x_display_info *dpyinfo;
3c254570 2988 Lisp_Object alist, param;
60fb3ee1 2989 char *attribute;
cf177271 2990 char *class;
60fb3ee1 2991 enum resource_types type;
01f1ba30
JB
2992{
2993 register Lisp_Object tem;
2994
2995 tem = Fassq (param, alist);
2996 if (EQ (tem, Qnil))
f676886a 2997 tem = Fassq (param, Vdefault_frame_alist);
f9942c9e 2998 if (EQ (tem, Qnil))
01f1ba30 2999 {
60fb3ee1 3000
f9942c9e 3001 if (attribute)
60fb3ee1 3002 {
abb4b7ec
RS
3003 tem = display_x_get_resource (dpyinfo,
3004 build_string (attribute),
3005 build_string (class),
3006 Qnil, Qnil);
f9942c9e
JB
3007
3008 if (NILP (tem))
3009 return Qunbound;
3010
3011 switch (type)
3012 {
333b20bb 3013 case RES_TYPE_NUMBER:
f9942c9e
JB
3014 return make_number (atoi (XSTRING (tem)->data));
3015
d62c8769
GM
3016 case RES_TYPE_FLOAT:
3017 return make_float (atof (XSTRING (tem)->data));
3018
333b20bb 3019 case RES_TYPE_BOOLEAN:
f9942c9e
JB
3020 tem = Fdowncase (tem);
3021 if (!strcmp (XSTRING (tem)->data, "on")
3022 || !strcmp (XSTRING (tem)->data, "true"))
3023 return Qt;
3024 else
3025 return Qnil;
3026
333b20bb 3027 case RES_TYPE_STRING:
f9942c9e
JB
3028 return tem;
3029
333b20bb 3030 case RES_TYPE_SYMBOL:
49795535
JB
3031 /* As a special case, we map the values `true' and `on'
3032 to Qt, and `false' and `off' to Qnil. */
3033 {
98381190
KH
3034 Lisp_Object lower;
3035 lower = Fdowncase (tem);
26ae6b61
KH
3036 if (!strcmp (XSTRING (lower)->data, "on")
3037 || !strcmp (XSTRING (lower)->data, "true"))
49795535 3038 return Qt;
26ae6b61
KH
3039 else if (!strcmp (XSTRING (lower)->data, "off")
3040 || !strcmp (XSTRING (lower)->data, "false"))
49795535
JB
3041 return Qnil;
3042 else
89032215 3043 return Fintern (tem, Qnil);
49795535 3044 }
f945b920 3045
f9942c9e
JB
3046 default:
3047 abort ();
3048 }
60fb3ee1 3049 }
f9942c9e
JB
3050 else
3051 return Qunbound;
01f1ba30
JB
3052 }
3053 return Fcdr (tem);
3054}
3055
e4f79258
RS
3056/* Like x_get_arg, but also record the value in f->param_alist. */
3057
3058static Lisp_Object
3059x_get_and_record_arg (f, alist, param, attribute, class, type)
3060 struct frame *f;
3061 Lisp_Object alist, param;
3062 char *attribute;
3063 char *class;
3064 enum resource_types type;
3065{
3066 Lisp_Object value;
3067
abb4b7ec
RS
3068 value = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, param,
3069 attribute, class, type);
e4f79258
RS
3070 if (! NILP (value))
3071 store_frame_param (f, param, value);
3072
3073 return value;
3074}
3075
f676886a 3076/* Record in frame F the specified or default value according to ALIST
e8cc313b
KH
3077 of the parameter named PROP (a Lisp symbol).
3078 If no value is specified for PROP, look for an X default for XPROP
f676886a 3079 on the frame named NAME.
01f1ba30
JB
3080 If that is not found either, use the value DEFLT. */
3081
3082static Lisp_Object
cf177271 3083x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
f676886a 3084 struct frame *f;
01f1ba30 3085 Lisp_Object alist;
f9942c9e 3086 Lisp_Object prop;
01f1ba30
JB
3087 Lisp_Object deflt;
3088 char *xprop;
cf177271 3089 char *xclass;
60fb3ee1 3090 enum resource_types type;
01f1ba30 3091{
01f1ba30
JB
3092 Lisp_Object tem;
3093
abb4b7ec 3094 tem = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, prop, xprop, xclass, type);
f9942c9e 3095 if (EQ (tem, Qunbound))
01f1ba30 3096 tem = deflt;
f9942c9e 3097 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
01f1ba30
JB
3098 return tem;
3099}
333b20bb
GM
3100
3101
3102/* Record in frame F the specified or default value according to ALIST
3103 of the parameter named PROP (a Lisp symbol). If no value is
3104 specified for PROP, look for an X default for XPROP on the frame
3105 named NAME. If that is not found either, use the value DEFLT. */
3106
3107static Lisp_Object
3108x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass,
3109 foreground_p)
3110 struct frame *f;
3111 Lisp_Object alist;
3112 Lisp_Object prop;
3113 char *xprop;
3114 char *xclass;
3115 int foreground_p;
3116{
3117 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3118 Lisp_Object tem;
3119
3120 tem = x_get_arg (dpyinfo, alist, prop, xprop, xclass, RES_TYPE_STRING);
3121 if (EQ (tem, Qunbound))
3122 {
3123#ifdef USE_TOOLKIT_SCROLL_BARS
3124
3125 /* See if an X resource for the scroll bar color has been
3126 specified. */
3127 tem = display_x_get_resource (dpyinfo,
3128 build_string (foreground_p
3129 ? "foreground"
3130 : "background"),
c0ec53ad 3131 empty_string,
333b20bb 3132 build_string ("verticalScrollBar"),
c0ec53ad 3133 empty_string);
333b20bb
GM
3134 if (!STRINGP (tem))
3135 {
3136 /* If nothing has been specified, scroll bars will use a
3137 toolkit-dependent default. Because these defaults are
3138 difficult to get at without actually creating a scroll
3139 bar, use nil to indicate that no color has been
3140 specified. */
3141 tem = Qnil;
3142 }
3143
3144#else /* not USE_TOOLKIT_SCROLL_BARS */
3145
3146 tem = Qnil;
3147
3148#endif /* not USE_TOOLKIT_SCROLL_BARS */
3149 }
3150
3151 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3152 return tem;
3153}
3154
3155
01f1ba30 3156\f
8af1d7ca 3157DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
7ee72033 3158 doc: /* Parse an X-style geometry string STRING.
c061c855
GM
3159Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3160The properties returned may include `top', `left', `height', and `width'.
3161The value of `left' or `top' may be an integer,
3162or a list (+ N) meaning N pixels relative to top/left corner,
7ee72033
MB
3163or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3164 (string)
a6605e5c 3165 Lisp_Object string;
01f1ba30
JB
3166{
3167 int geometry, x, y;
3168 unsigned int width, height;
f83f10ba 3169 Lisp_Object result;
01f1ba30 3170
b7826503 3171 CHECK_STRING (string);
01f1ba30
JB
3172
3173 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3174 &x, &y, &width, &height);
3175
f83f10ba
RS
3176#if 0
3177 if (!!(geometry & XValue) != !!(geometry & YValue))
3178 error ("Must specify both x and y position, or neither");
3179#endif
3180
3181 result = Qnil;
3182 if (geometry & XValue)
01f1ba30 3183 {
f83f10ba
RS
3184 Lisp_Object element;
3185
e1d962d7
RS
3186 if (x >= 0 && (geometry & XNegative))
3187 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3188 else if (x < 0 && ! (geometry & XNegative))
3189 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
f83f10ba
RS
3190 else
3191 element = Fcons (Qleft, make_number (x));
3192 result = Fcons (element, result);
3193 }
3194
3195 if (geometry & YValue)
3196 {
3197 Lisp_Object element;
3198
e1d962d7
RS
3199 if (y >= 0 && (geometry & YNegative))
3200 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3201 else if (y < 0 && ! (geometry & YNegative))
3202 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
f83f10ba
RS
3203 else
3204 element = Fcons (Qtop, make_number (y));
3205 result = Fcons (element, result);
01f1ba30 3206 }
f83f10ba
RS
3207
3208 if (geometry & WidthValue)
3209 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3210 if (geometry & HeightValue)
3211 result = Fcons (Fcons (Qheight, make_number (height)), result);
3212
3213 return result;
01f1ba30
JB
3214}
3215
01f1ba30 3216/* Calculate the desired size and position of this window,
f83f10ba 3217 and return the flags saying which aspects were specified.
8fc2766b
RS
3218
3219 This function does not make the coordinates positive. */
01f1ba30
JB
3220
3221#define DEFAULT_ROWS 40
3222#define DEFAULT_COLS 80
3223
f9942c9e 3224static int
f676886a
JB
3225x_figure_window_size (f, parms)
3226 struct frame *f;
01f1ba30
JB
3227 Lisp_Object parms;
3228{
4fe1de12 3229 register Lisp_Object tem0, tem1, tem2;
01f1ba30 3230 long window_prompting = 0;
abb4b7ec 3231 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
3232
3233 /* Default values if we fall through.
3234 Actually, if that happens we should get
b9dc4443 3235 window manager prompting. */
1ab3d87e 3236 SET_FRAME_WIDTH (f, DEFAULT_COLS);
f676886a 3237 f->height = DEFAULT_ROWS;
bd0b85c3
RS
3238 /* Window managers expect that if program-specified
3239 positions are not (0,0), they're intentional, not defaults. */
7556890b
RS
3240 f->output_data.x->top_pos = 0;
3241 f->output_data.x->left_pos = 0;
01f1ba30 3242
333b20bb
GM
3243 tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3244 tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3245 tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3246 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3247 {
f83f10ba
RS
3248 if (!EQ (tem0, Qunbound))
3249 {
b7826503 3250 CHECK_NUMBER (tem0);
f83f10ba
RS
3251 f->height = XINT (tem0);
3252 }
3253 if (!EQ (tem1, Qunbound))
3254 {
b7826503 3255 CHECK_NUMBER (tem1);
1ab3d87e 3256 SET_FRAME_WIDTH (f, XINT (tem1));
f83f10ba
RS
3257 }
3258 if (!NILP (tem2) && !EQ (tem2, Qunbound))
4fe1de12
RS
3259 window_prompting |= USSize;
3260 else
3261 window_prompting |= PSize;
01f1ba30 3262 }
01f1ba30 3263
7556890b 3264 f->output_data.x->vertical_scroll_bar_extra
a444c70b
KH
3265 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3266 ? 0
7556890b 3267 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
b3ba0aa8
KS
3268
3269 x_compute_fringe_widths (f, 0);
3270
7556890b
RS
3271 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3272 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
01f1ba30 3273
333b20bb
GM
3274 tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3275 tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3276 tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3277 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3278 {
f83f10ba
RS
3279 if (EQ (tem0, Qminus))
3280 {
7556890b 3281 f->output_data.x->top_pos = 0;
f83f10ba
RS
3282 window_prompting |= YNegative;
3283 }
8e713be6
KR
3284 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3285 && CONSP (XCDR (tem0))
3286 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3287 {
8e713be6 3288 f->output_data.x->top_pos = - XINT (XCAR (XCDR (tem0)));
e1d962d7
RS
3289 window_prompting |= YNegative;
3290 }
8e713be6
KR
3291 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3292 && CONSP (XCDR (tem0))
3293 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3294 {
8e713be6 3295 f->output_data.x->top_pos = XINT (XCAR (XCDR (tem0)));
e1d962d7 3296 }
f83f10ba 3297 else if (EQ (tem0, Qunbound))
7556890b 3298 f->output_data.x->top_pos = 0;
f83f10ba
RS
3299 else
3300 {
b7826503 3301 CHECK_NUMBER (tem0);
7556890b
RS
3302 f->output_data.x->top_pos = XINT (tem0);
3303 if (f->output_data.x->top_pos < 0)
f83f10ba
RS
3304 window_prompting |= YNegative;
3305 }
3306
3307 if (EQ (tem1, Qminus))
3308 {
7556890b 3309 f->output_data.x->left_pos = 0;
f83f10ba
RS
3310 window_prompting |= XNegative;
3311 }
8e713be6
KR
3312 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3313 && CONSP (XCDR (tem1))
3314 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3315 {
8e713be6 3316 f->output_data.x->left_pos = - XINT (XCAR (XCDR (tem1)));
e1d962d7
RS
3317 window_prompting |= XNegative;
3318 }
8e713be6
KR
3319 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3320 && CONSP (XCDR (tem1))
3321 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3322 {
8e713be6 3323 f->output_data.x->left_pos = XINT (XCAR (XCDR (tem1)));
e1d962d7 3324 }
f83f10ba 3325 else if (EQ (tem1, Qunbound))
7556890b 3326 f->output_data.x->left_pos = 0;
f83f10ba
RS
3327 else
3328 {
b7826503 3329 CHECK_NUMBER (tem1);
7556890b
RS
3330 f->output_data.x->left_pos = XINT (tem1);
3331 if (f->output_data.x->left_pos < 0)
f83f10ba
RS
3332 window_prompting |= XNegative;
3333 }
3334
c3724dc2 3335 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
4fe1de12
RS
3336 window_prompting |= USPosition;
3337 else
3338 window_prompting |= PPosition;
01f1ba30 3339 }
f83f10ba 3340
49d41073
EZ
3341 if (f->output_data.x->want_fullscreen != FULLSCREEN_NONE)
3342 {
3343 int left, top;
3344 int width, height;
3345
3346 /* It takes both for some WM:s to place it where we want */
3347 window_prompting = USPosition | PPosition;
3348 x_fullscreen_adjust (f, &width, &height, &top, &left);
3349 f->width = width;
3350 f->height = height;
3351 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3352 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3353 f->output_data.x->left_pos = left;
3354 f->output_data.x->top_pos = top;
3355 }
3356
739f2f53 3357 return window_prompting;
01f1ba30
JB
3358}
3359
f58534a3
RS
3360#if !defined (HAVE_X11R4) && !defined (HAVE_XSETWMPROTOCOLS)
3361
3362Status
3363XSetWMProtocols (dpy, w, protocols, count)
3364 Display *dpy;
3365 Window w;
3366 Atom *protocols;
3367 int count;
3368{
3369 Atom prop;
3370 prop = XInternAtom (dpy, "WM_PROTOCOLS", False);
3371 if (prop == None) return False;
3372 XChangeProperty (dpy, w, prop, XA_ATOM, 32, PropModeReplace,
3373 (unsigned char *) protocols, count);
3374 return True;
3375}
9ef48a9d
RS
3376#endif /* not HAVE_X11R4 && not HAVE_XSETWMPROTOCOLS */
3377\f
3378#ifdef USE_X_TOOLKIT
3379
8e3d10a9
RS
3380/* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS,
3381 WM_DELETE_WINDOW, and WM_SAVE_YOURSELF, then add them. (They may
59aa6c90
RS
3382 already be present because of the toolkit (Motif adds some of them,
3383 for example, but Xt doesn't). */
9ef48a9d
RS
3384
3385static void
b9dc4443
RS
3386hack_wm_protocols (f, widget)
3387 FRAME_PTR f;
9ef48a9d
RS
3388 Widget widget;
3389{
3390 Display *dpy = XtDisplay (widget);
3391 Window w = XtWindow (widget);
3392 int need_delete = 1;
3393 int need_focus = 1;
59aa6c90 3394 int need_save = 1;
9ef48a9d
RS
3395
3396 BLOCK_INPUT;
3397 {
3398 Atom type, *atoms = 0;
3399 int format = 0;
3400 unsigned long nitems = 0;
3401 unsigned long bytes_after;
3402
270958e8
KH
3403 if ((XGetWindowProperty (dpy, w,
3404 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
34d5ae1e 3405 (long)0, (long)100, False, XA_ATOM,
270958e8
KH
3406 &type, &format, &nitems, &bytes_after,
3407 (unsigned char **) &atoms)
3408 == Success)
9ef48a9d
RS
3409 && format == 32 && type == XA_ATOM)
3410 while (nitems > 0)
3411 {
3412 nitems--;
b9dc4443
RS
3413 if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window)
3414 need_delete = 0;
3415 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus)
3416 need_focus = 0;
3417 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself)
3418 need_save = 0;
9ef48a9d
RS
3419 }
3420 if (atoms) XFree ((char *) atoms);
3421 }
3422 {
3423 Atom props [10];
3424 int count = 0;
b9dc4443
RS
3425 if (need_delete)
3426 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
3427 if (need_focus)
3428 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus;
3429 if (need_save)
3430 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
9ef48a9d 3431 if (count)
b9dc4443
RS
3432 XChangeProperty (dpy, w, FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3433 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3434 (unsigned char *) props, count);
3435 }
3436 UNBLOCK_INPUT;
3437}
3438#endif
86779fac
GM
3439
3440
5a7df7d7
GM
3441\f
3442/* Support routines for XIC (X Input Context). */
86779fac 3443
5a7df7d7
GM
3444#ifdef HAVE_X_I18N
3445
3446static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
3447static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
3448
3449
3450/* Supported XIM styles, ordered by preferenc. */
3451
3452static XIMStyle supported_xim_styles[] =
3453{
3454 XIMPreeditPosition | XIMStatusArea,
3455 XIMPreeditPosition | XIMStatusNothing,
3456 XIMPreeditPosition | XIMStatusNone,
3457 XIMPreeditNothing | XIMStatusArea,
3458 XIMPreeditNothing | XIMStatusNothing,
3459 XIMPreeditNothing | XIMStatusNone,
3460 XIMPreeditNone | XIMStatusArea,
3461 XIMPreeditNone | XIMStatusNothing,
3462 XIMPreeditNone | XIMStatusNone,
3463 0,
3464};
3465
3466
3467/* Create an X fontset on frame F with base font name
3468 BASE_FONTNAME.. */
3469
3470static XFontSet
3471xic_create_xfontset (f, base_fontname)
86779fac 3472 struct frame *f;
5a7df7d7 3473 char *base_fontname;
86779fac 3474{
5a7df7d7
GM
3475 XFontSet xfs;
3476 char **missing_list;
3477 int missing_count;
3478 char *def_string;
86779fac 3479
5a7df7d7
GM
3480 xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
3481 base_fontname, &missing_list,
3482 &missing_count, &def_string);
3483 if (missing_list)
3484 XFreeStringList (missing_list);
3485
3486 /* No need to free def_string. */
3487 return xfs;
3488}
3489
3490
3491/* Value is the best input style, given user preferences USER (already
3492 checked to be supported by Emacs), and styles supported by the
3493 input method XIM. */
3494
3495static XIMStyle
3496best_xim_style (user, xim)
3497 XIMStyles *user;
3498 XIMStyles *xim;
3499{
3500 int i, j;
3501
3502 for (i = 0; i < user->count_styles; ++i)
3503 for (j = 0; j < xim->count_styles; ++j)
3504 if (user->supported_styles[i] == xim->supported_styles[j])
3505 return user->supported_styles[i];
3506
3507 /* Return the default style. */
3508 return XIMPreeditNothing | XIMStatusNothing;
3509}
3510
3511/* Create XIC for frame F. */
3512
5df79d3d
GM
3513static XIMStyle xic_style;
3514
5a7df7d7
GM
3515void
3516create_frame_xic (f)
3517 struct frame *f;
3518{
5a7df7d7
GM
3519 XIM xim;
3520 XIC xic = NULL;
3521 XFontSet xfs = NULL;
86779fac 3522
5a7df7d7
GM
3523 if (FRAME_XIC (f))
3524 return;
3525
3526 xim = FRAME_X_XIM (f);
3527 if (xim)
3528 {
d9d57cb2
DL
3529 XRectangle s_area;
3530 XPoint spot;
5a7df7d7
GM
3531 XVaNestedList preedit_attr;
3532 XVaNestedList status_attr;
3533 char *base_fontname;
3534 int fontset;
3535
d9d57cb2
DL
3536 s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
3537 spot.x = 0; spot.y = 1;
5a7df7d7
GM
3538 /* Create X fontset. */
3539 fontset = FRAME_FONTSET (f);
3540 if (fontset < 0)
3541 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3542 else
3543 {
6ecb43ce
KH
3544 /* Determine the base fontname from the ASCII font name of
3545 FONTSET. */
3546 char *ascii_font = (char *) XSTRING (fontset_ascii (fontset))->data;
3547 char *p = ascii_font;
5a7df7d7 3548 int i;
6ecb43ce
KH
3549
3550 for (i = 0; *p; p++)
3551 if (*p == '-') i++;
3552 if (i != 14)
3553 /* As the font name doesn't conform to XLFD, we can't
3554 modify it to get a suitable base fontname for the
3555 frame. */
3556 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3557 else
3558 {
3559 int len = strlen (ascii_font) + 1;
8ec8a5ec 3560 char *p1 = NULL;
6ecb43ce
KH
3561
3562 for (i = 0, p = ascii_font; i < 8; p++)
3563 {
3564 if (*p == '-')
3565 {
3566 i++;
3567 if (i == 3)
3568 p1 = p + 1;
3569 }
3570 }
3571 base_fontname = (char *) alloca (len);
3572 bzero (base_fontname, len);
3573 strcpy (base_fontname, "-*-*-");
3574 bcopy (p1, base_fontname + 5, p - p1);
3575 strcat (base_fontname, "*-*-*-*-*-*-*");
3576 }
5a7df7d7
GM
3577 }
3578 xfs = xic_create_xfontset (f, base_fontname);
86779fac 3579
5a7df7d7
GM
3580 /* Determine XIC style. */
3581 if (xic_style == 0)
3582 {
3583 XIMStyles supported_list;
3584 supported_list.count_styles = (sizeof supported_xim_styles
3585 / sizeof supported_xim_styles[0]);
3586 supported_list.supported_styles = supported_xim_styles;
3587 xic_style = best_xim_style (&supported_list,
3588 FRAME_X_XIM_STYLES (f));
3589 }
86779fac 3590
5a7df7d7
GM
3591 preedit_attr = XVaCreateNestedList (0,
3592 XNFontSet, xfs,
3593 XNForeground,
3594 FRAME_FOREGROUND_PIXEL (f),
3595 XNBackground,
3596 FRAME_BACKGROUND_PIXEL (f),
3597 (xic_style & XIMPreeditPosition
3598 ? XNSpotLocation
3599 : NULL),
3600 &spot,
3601 NULL);
3602 status_attr = XVaCreateNestedList (0,
3603 XNArea,
3604 &s_area,
3605 XNFontSet,
3606 xfs,
3607 XNForeground,
3608 FRAME_FOREGROUND_PIXEL (f),
3609 XNBackground,
3610 FRAME_BACKGROUND_PIXEL (f),
3611 NULL);
3612
3613 xic = XCreateIC (xim,
3614 XNInputStyle, xic_style,
3615 XNClientWindow, FRAME_X_WINDOW(f),
3616 XNFocusWindow, FRAME_X_WINDOW(f),
3617 XNStatusAttributes, status_attr,
3618 XNPreeditAttributes, preedit_attr,
3619 NULL);
3620 XFree (preedit_attr);
3621 XFree (status_attr);
3622 }
3623
3624 FRAME_XIC (f) = xic;
3625 FRAME_XIC_STYLE (f) = xic_style;
3626 FRAME_XIC_FONTSET (f) = xfs;
86779fac
GM
3627}
3628
5a7df7d7
GM
3629
3630/* Destroy XIC and free XIC fontset of frame F, if any. */
3631
3632void
3633free_frame_xic (f)
3634 struct frame *f;
3635{
3636 if (FRAME_XIC (f) == NULL)
3637 return;
3638
3639 XDestroyIC (FRAME_XIC (f));
3640 if (FRAME_XIC_FONTSET (f))
3641 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3642
3643 FRAME_XIC (f) = NULL;
3644 FRAME_XIC_FONTSET (f) = NULL;
3645}
3646
3647
3648/* Place preedit area for XIC of window W's frame to specified
3649 pixel position X/Y. X and Y are relative to window W. */
3650
3651void
3652xic_set_preeditarea (w, x, y)
3653 struct window *w;
3654 int x, y;
3655{
3656 struct frame *f = XFRAME (w->frame);
3657 XVaNestedList attr;
3658 XPoint spot;
3659
3660 spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
3661 spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
3662 attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
3663 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3664 XFree (attr);
3665}
3666
3667
3668/* Place status area for XIC in bottom right corner of frame F.. */
3669
3670void
3671xic_set_statusarea (f)
3672 struct frame *f;
3673{
3674 XIC xic = FRAME_XIC (f);
3675 XVaNestedList attr;
3676 XRectangle area;
3677 XRectangle *needed;
3678
3679 /* Negotiate geometry of status area. If input method has existing
3680 status area, use its current size. */
3681 area.x = area.y = area.width = area.height = 0;
3682 attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
3683 XSetICValues (xic, XNStatusAttributes, attr, NULL);
3684 XFree (attr);
3685
3686 attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
3687 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3688 XFree (attr);
3689
3690 if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
3691 {
3692 attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
3693 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3694 XFree (attr);
3695 }
3696
3697 area.width = needed->width;
3698 area.height = needed->height;
3699 area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
3700 area.y = (PIXEL_HEIGHT (f) - area.height
3701 - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
3702 XFree (needed);
3703
3704 attr = XVaCreateNestedList (0, XNArea, &area, NULL);
3705 XSetICValues(xic, XNStatusAttributes, attr, NULL);
3706 XFree (attr);
3707}
3708
3709
3710/* Set X fontset for XIC of frame F, using base font name
3711 BASE_FONTNAME. Called when a new Emacs fontset is chosen. */
3712
3713void
3714xic_set_xfontset (f, base_fontname)
3715 struct frame *f;
3716 char *base_fontname;
3717{
3718 XVaNestedList attr;
3719 XFontSet xfs;
3720
3721 xfs = xic_create_xfontset (f, base_fontname);
3722
3723 attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
3724 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
3725 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3726 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
3727 XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
3728 XFree (attr);
3729
3730 if (FRAME_XIC_FONTSET (f))
3731 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3732 FRAME_XIC_FONTSET (f) = xfs;
3733}
3734
3735#endif /* HAVE_X_I18N */
3736
3737
9ef48a9d 3738\f
8fc2766b
RS
3739#ifdef USE_X_TOOLKIT
3740
3741/* Create and set up the X widget for frame F. */
f58534a3 3742
01f1ba30 3743static void
a7f7d550
FP
3744x_window (f, window_prompting, minibuffer_only)
3745 struct frame *f;
3746 long window_prompting;
3747 int minibuffer_only;
01f1ba30 3748{
9ef48a9d 3749 XClassHint class_hints;
31ac8d8c
FP
3750 XSetWindowAttributes attributes;
3751 unsigned long attribute_mask;
9ef48a9d
RS
3752 Widget shell_widget;
3753 Widget pane_widget;
6c32dd68 3754 Widget frame_widget;
9ef48a9d
RS
3755 Arg al [25];
3756 int ac;
3757
3758 BLOCK_INPUT;
3759
b7975ee4
KH
3760 /* Use the resource name as the top-level widget name
3761 for looking up resources. Make a non-Lisp copy
3762 for the window manager, so GC relocation won't bother it.
3763
3764 Elsewhere we specify the window name for the window manager. */
3765
cca176a0 3766 {
b7975ee4
KH
3767 char *str = (char *) XSTRING (Vx_resource_name)->data;
3768 f->namebuf = (char *) xmalloc (strlen (str) + 1);
cca176a0
KH
3769 strcpy (f->namebuf, str);
3770 }
9ef48a9d
RS
3771
3772 ac = 0;
3773 XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
3774 XtSetArg (al[ac], XtNinput, 1); ac++;
97787173 3775 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
7556890b 3776 XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
9b2956e2
GM
3777 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3778 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3779 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
cca176a0 3780 shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
7a994728 3781 applicationShellWidgetClass,
82c90203 3782 FRAME_X_DISPLAY (f), al, ac);
9ef48a9d 3783
7556890b 3784 f->output_data.x->widget = shell_widget;
9ef48a9d
RS
3785 /* maybe_set_screen_title_format (shell_widget); */
3786
6c32dd68
PR
3787 pane_widget = lw_create_widget ("main", "pane", widget_id_tick++,
3788 (widget_value *) NULL,
3789 shell_widget, False,
3790 (lw_callback) NULL,
3791 (lw_callback) NULL,
b6e11efd 3792 (lw_callback) NULL,
6c32dd68 3793 (lw_callback) NULL);
9ef48a9d 3794
9b2956e2
GM
3795 ac = 0;
3796 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3797 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3798 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3799 XtSetValues (pane_widget, al, ac);
7556890b 3800 f->output_data.x->column_widget = pane_widget;
a7f7d550 3801
9ef48a9d 3802 /* mappedWhenManaged to false tells to the paned window to not map/unmap
5e65b9ab 3803 the emacs screen when changing menubar. This reduces flickering. */
9ef48a9d
RS
3804
3805 ac = 0;
3806 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
3807 XtSetArg (al[ac], XtNshowGrip, 0); ac++;
3808 XtSetArg (al[ac], XtNallowResize, 1); ac++;
3809 XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
3810 XtSetArg (al[ac], XtNemacsFrame, f); ac++;
9b2956e2
GM
3811 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3812 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3813 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3814 frame_widget = XtCreateWidget (f->namebuf, emacsFrameClass, pane_widget,
3815 al, ac);
9ef48a9d 3816
7556890b 3817 f->output_data.x->edit_widget = frame_widget;
9ef48a9d 3818
6c32dd68 3819 XtManageChild (frame_widget);
a7f7d550
FP
3820
3821 /* Do some needed geometry management. */
3822 {
3823 int len;
3824 char *tem, shell_position[32];
3825 Arg al[2];
3826 int ac = 0;
5031cc10 3827 int extra_borders = 0;
8fc2766b 3828 int menubar_size
7556890b
RS
3829 = (f->output_data.x->menubar_widget
3830 ? (f->output_data.x->menubar_widget->core.height
3831 + f->output_data.x->menubar_widget->core.border_width)
8fc2766b 3832 : 0);
a7f7d550 3833
f7008aff
RS
3834#if 0 /* Experimentally, we now get the right results
3835 for -geometry -0-0 without this. 24 Aug 96, rms. */
01cbdba5
RS
3836 if (FRAME_EXTERNAL_MENU_BAR (f))
3837 {
dd254b21 3838 Dimension ibw = 0;
01cbdba5
RS
3839 XtVaGetValues (pane_widget, XtNinternalBorderWidth, &ibw, NULL);
3840 menubar_size += ibw;
3841 }
f7008aff 3842#endif
01cbdba5 3843
7556890b 3844 f->output_data.x->menubar_height = menubar_size;
00983aba 3845
440b0bfd 3846#ifndef USE_LUCID
5031cc10
KH
3847 /* Motif seems to need this amount added to the sizes
3848 specified for the shell widget. The Athena/Lucid widgets don't.
3849 Both conclusions reached experimentally. -- rms. */
440b0bfd
RS
3850 XtVaGetValues (f->output_data.x->edit_widget, XtNinternalBorderWidth,
3851 &extra_borders, NULL);
3852 extra_borders *= 2;
3853#endif
5031cc10 3854
97787173
RS
3855 /* Convert our geometry parameters into a geometry string
3856 and specify it.
3857 Note that we do not specify here whether the position
3858 is a user-specified or program-specified one.
3859 We pass that information later, in x_wm_set_size_hints. */
3860 {
7556890b 3861 int left = f->output_data.x->left_pos;
97787173 3862 int xneg = window_prompting & XNegative;
7556890b 3863 int top = f->output_data.x->top_pos;
97787173
RS
3864 int yneg = window_prompting & YNegative;
3865 if (xneg)
3866 left = -left;
3867 if (yneg)
3868 top = -top;
c760f47e
KH
3869
3870 if (window_prompting & USPosition)
5031cc10
KH
3871 sprintf (shell_position, "=%dx%d%c%d%c%d",
3872 PIXEL_WIDTH (f) + extra_borders,
3873 PIXEL_HEIGHT (f) + menubar_size + extra_borders,
c760f47e
KH
3874 (xneg ? '-' : '+'), left,
3875 (yneg ? '-' : '+'), top);
3876 else
5031cc10
KH
3877 sprintf (shell_position, "=%dx%d",
3878 PIXEL_WIDTH (f) + extra_borders,
3879 PIXEL_HEIGHT (f) + menubar_size + extra_borders);
97787173
RS
3880 }
3881
a7f7d550 3882 len = strlen (shell_position) + 1;
77110caa
RS
3883 /* We don't free this because we don't know whether
3884 it is safe to free it while the frame exists.
3885 It isn't worth the trouble of arranging to free it
3886 when the frame is deleted. */
a7f7d550
FP
3887 tem = (char *) xmalloc (len);
3888 strncpy (tem, shell_position, len);
3889 XtSetArg (al[ac], XtNgeometry, tem); ac++;
3890 XtSetValues (shell_widget, al, ac);
3891 }
3892
9ef48a9d
RS
3893 XtManageChild (pane_widget);
3894 XtRealizeWidget (shell_widget);
3895
6c32dd68 3896 FRAME_X_WINDOW (f) = XtWindow (frame_widget);
9ef48a9d
RS
3897
3898 validate_x_resource_name ();
b7975ee4 3899
9ef48a9d 3900 class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
498e9ac3 3901 class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
b9dc4443 3902 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
5a7df7d7
GM
3903
3904#ifdef HAVE_X_I18N
3905 FRAME_XIC (f) = NULL;
4bd777b8 3906#ifdef USE_XIM
5a7df7d7 3907 create_frame_xic (f);
4bd777b8 3908#endif
5a7df7d7 3909#endif
64d16748 3910
7556890b
RS
3911 f->output_data.x->wm_hints.input = True;
3912 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 3913 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3914 &f->output_data.x->wm_hints);
b8228beb 3915
c4ec904f 3916 hack_wm_protocols (f, shell_widget);
9ef48a9d 3917
6c32dd68
PR
3918#ifdef HACK_EDITRES
3919 XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0);
3920#endif
3921
9ef48a9d 3922 /* Do a stupid property change to force the server to generate a
333b20bb 3923 PropertyNotify event so that the event_stream server timestamp will
9ef48a9d
RS
3924 be initialized to something relevant to the time we created the window.
3925 */
6c32dd68 3926 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
b9dc4443
RS
3927 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3928 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3929 (unsigned char*) NULL, 0);
3930
5a7df7d7 3931 /* Make all the standard events reach the Emacs frame. */
31ac8d8c 3932 attributes.event_mask = STANDARD_EVENT_SET;
5a7df7d7
GM
3933
3934#ifdef HAVE_X_I18N
3935 if (FRAME_XIC (f))
3936 {
3937 /* XIM server might require some X events. */
3938 unsigned long fevent = NoEventMask;
3939 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
3940 attributes.event_mask |= fevent;
3941 }
3942#endif /* HAVE_X_I18N */
3943
31ac8d8c
FP
3944 attribute_mask = CWEventMask;
3945 XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
3946 attribute_mask, &attributes);
3947
6c32dd68 3948 XtMapWidget (frame_widget);
9ef48a9d 3949
8fc2766b
RS
3950 /* x_set_name normally ignores requests to set the name if the
3951 requested name is the same as the current name. This is the one
3952 place where that assumption isn't correct; f->name is set, but
3953 the X server hasn't been told. */
3954 {
3955 Lisp_Object name;
3956 int explicit = f->explicit_name;
3957
3958 f->explicit_name = 0;
3959 name = f->name;
3960 f->name = Qnil;
3961 x_set_name (f, name, explicit);
3962 }
3963
b9dc4443 3964 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3965 f->output_data.x->text_cursor);
8fc2766b
RS
3966
3967 UNBLOCK_INPUT;
3968
495fa05e
GM
3969 /* This is a no-op, except under Motif. Make sure main areas are
3970 set to something reasonable, in case we get an error later. */
3971 lw_set_main_areas (pane_widget, 0, frame_widget);
8fc2766b
RS
3972}
3973
9ef48a9d
RS
3974#else /* not USE_X_TOOLKIT */
3975
8fc2766b
RS
3976/* Create and set up the X window for frame F. */
3977
201d8c78 3978void
8fc2766b
RS
3979x_window (f)
3980 struct frame *f;
3981
3982{
3983 XClassHint class_hints;
3984 XSetWindowAttributes attributes;
3985 unsigned long attribute_mask;
3986
7556890b
RS
3987 attributes.background_pixel = f->output_data.x->background_pixel;
3988 attributes.border_pixel = f->output_data.x->border_pixel;
01f1ba30
JB
3989 attributes.bit_gravity = StaticGravity;
3990 attributes.backing_store = NotUseful;
3991 attributes.save_under = True;
3992 attributes.event_mask = STANDARD_EVENT_SET;
9b2956e2
GM
3993 attributes.colormap = FRAME_X_COLORMAP (f);
3994 attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
3995 | CWColormap);
01f1ba30
JB
3996
3997 BLOCK_INPUT;
fe24a618 3998 FRAME_X_WINDOW (f)
b9dc4443 3999 = XCreateWindow (FRAME_X_DISPLAY (f),
7556890b
RS
4000 f->output_data.x->parent_desc,
4001 f->output_data.x->left_pos,
4002 f->output_data.x->top_pos,
f676886a 4003 PIXEL_WIDTH (f), PIXEL_HEIGHT (f),
7556890b 4004 f->output_data.x->border_width,
01f1ba30
JB
4005 CopyFromParent, /* depth */
4006 InputOutput, /* class */
383d6ffc 4007 FRAME_X_VISUAL (f),
01f1ba30 4008 attribute_mask, &attributes);
5a7df7d7
GM
4009
4010#ifdef HAVE_X_I18N
4bd777b8 4011#ifdef USE_XIM
5a7df7d7
GM
4012 create_frame_xic (f);
4013 if (FRAME_XIC (f))
4014 {
4015 /* XIM server might require some X events. */
4016 unsigned long fevent = NoEventMask;
4017 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
4018 attributes.event_mask |= fevent;
4019 attribute_mask = CWEventMask;
4020 XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4021 attribute_mask, &attributes);
4022 }
4bd777b8 4023#endif
5a7df7d7
GM
4024#endif /* HAVE_X_I18N */
4025
d387c960 4026 validate_x_resource_name ();
b7975ee4 4027
d387c960 4028 class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
498e9ac3 4029 class_hints.res_class = (char *) XSTRING (Vx_resource_class)->data;
b9dc4443 4030 XSetClassHint (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &class_hints);
01f1ba30 4031
00983aba
KH
4032 /* The menubar is part of the ordinary display;
4033 it does not count in addition to the height of the window. */
7556890b 4034 f->output_data.x->menubar_height = 0;
00983aba 4035
179956b9
JB
4036 /* This indicates that we use the "Passive Input" input model.
4037 Unless we do this, we don't get the Focus{In,Out} events that we
4038 need to draw the cursor correctly. Accursed bureaucrats.
b9dc4443 4039 XWhipsAndChains (FRAME_X_DISPLAY (f), IronMaiden, &TheRack); */
179956b9 4040
7556890b
RS
4041 f->output_data.x->wm_hints.input = True;
4042 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 4043 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4044 &f->output_data.x->wm_hints);
6d078211 4045 f->output_data.x->wm_hints.icon_pixmap = None;
179956b9 4046
032e4ebe
RS
4047 /* Request "save yourself" and "delete window" commands from wm. */
4048 {
4049 Atom protocols[2];
b9dc4443
RS
4050 protocols[0] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
4051 protocols[1] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
4052 XSetWMProtocols (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), protocols, 2);
032e4ebe 4053 }
9ef48a9d 4054
e373f201
JB
4055 /* x_set_name normally ignores requests to set the name if the
4056 requested name is the same as the current name. This is the one
4057 place where that assumption isn't correct; f->name is set, but
4058 the X server hasn't been told. */
4059 {
98381190 4060 Lisp_Object name;
cf177271 4061 int explicit = f->explicit_name;
e373f201 4062
cf177271 4063 f->explicit_name = 0;
98381190
KH
4064 name = f->name;
4065 f->name = Qnil;
cf177271 4066 x_set_name (f, name, explicit);
e373f201
JB
4067 }
4068
b9dc4443 4069 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4070 f->output_data.x->text_cursor);
9ef48a9d 4071
01f1ba30
JB
4072 UNBLOCK_INPUT;
4073
fe24a618 4074 if (FRAME_X_WINDOW (f) == 0)
9ef48a9d 4075 error ("Unable to create window");
01f1ba30
JB
4076}
4077
8fc2766b
RS
4078#endif /* not USE_X_TOOLKIT */
4079
01f1ba30
JB
4080/* Handle the icon stuff for this window. Perhaps later we might
4081 want an x_set_icon_position which can be called interactively as
b9dc4443 4082 well. */
01f1ba30
JB
4083
4084static void
f676886a
JB
4085x_icon (f, parms)
4086 struct frame *f;
01f1ba30
JB
4087 Lisp_Object parms;
4088{
f9942c9e 4089 Lisp_Object icon_x, icon_y;
abb4b7ec 4090 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
4091
4092 /* Set the position of the icon. Note that twm groups all
b9dc4443 4093 icons in an icon window. */
333b20bb
GM
4094 icon_x = x_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4095 icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
f9942c9e 4096 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
01f1ba30 4097 {
b7826503
PJ
4098 CHECK_NUMBER (icon_x);
4099 CHECK_NUMBER (icon_y);
01f1ba30 4100 }
f9942c9e 4101 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
01f1ba30 4102 error ("Both left and top icon corners of icon must be specified");
01f1ba30 4103
f9942c9e
JB
4104 BLOCK_INPUT;
4105
fe24a618
JB
4106 if (! EQ (icon_x, Qunbound))
4107 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
f9942c9e 4108
01f1ba30 4109 /* Start up iconic or window? */
49795535 4110 x_wm_set_window_state
333b20bb
GM
4111 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL),
4112 Qicon)
49795535
JB
4113 ? IconicState
4114 : NormalState));
01f1ba30 4115
f468da95
RS
4116 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4117 ? f->icon_name
4118 : f->name))->data);
80534dd6 4119
01f1ba30
JB
4120 UNBLOCK_INPUT;
4121}
4122
b243755a 4123/* Make the GCs needed for this window, setting the
01f1ba30
JB
4124 background, border and mouse colors; also create the
4125 mouse cursor and the gray border tile. */
4126
f945b920
JB
4127static char cursor_bits[] =
4128 {
4129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4133 };
4134
01f1ba30 4135static void
f676886a
JB
4136x_make_gc (f)
4137 struct frame *f;
01f1ba30
JB
4138{
4139 XGCValues gc_values;
01f1ba30 4140
6afb1d07
JB
4141 BLOCK_INPUT;
4142
b243755a 4143 /* Create the GCs of this frame.
9ef48a9d 4144 Note that many default values are used. */
01f1ba30
JB
4145
4146 /* Normal video */
7556890b
RS
4147 gc_values.font = f->output_data.x->font->fid;
4148 gc_values.foreground = f->output_data.x->foreground_pixel;
4149 gc_values.background = f->output_data.x->background_pixel;
9ef48a9d 4150 gc_values.line_width = 0; /* Means 1 using fast algorithm. */
959e647d
GM
4151 f->output_data.x->normal_gc
4152 = XCreateGC (FRAME_X_DISPLAY (f),
4153 FRAME_X_WINDOW (f),
4154 GCLineWidth | GCFont | GCForeground | GCBackground,
4155 &gc_values);
01f1ba30 4156
b9dc4443 4157 /* Reverse video style. */
7556890b
RS
4158 gc_values.foreground = f->output_data.x->background_pixel;
4159 gc_values.background = f->output_data.x->foreground_pixel;
959e647d
GM
4160 f->output_data.x->reverse_gc
4161 = XCreateGC (FRAME_X_DISPLAY (f),
4162 FRAME_X_WINDOW (f),
4163 GCFont | GCForeground | GCBackground | GCLineWidth,
4164 &gc_values);
01f1ba30 4165
9ef48a9d 4166 /* Cursor has cursor-color background, background-color foreground. */
7556890b
RS
4167 gc_values.foreground = f->output_data.x->background_pixel;
4168 gc_values.background = f->output_data.x->cursor_pixel;
01f1ba30
JB
4169 gc_values.fill_style = FillOpaqueStippled;
4170 gc_values.stipple
b9dc4443
RS
4171 = XCreateBitmapFromData (FRAME_X_DISPLAY (f),
4172 FRAME_X_DISPLAY_INFO (f)->root_window,
01f1ba30 4173 cursor_bits, 16, 16);
7556890b 4174 f->output_data.x->cursor_gc
b9dc4443 4175 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
01f1ba30 4176 (GCFont | GCForeground | GCBackground
ac1f48a4 4177 | GCFillStyle /* | GCStipple */ | GCLineWidth),
01f1ba30
JB
4178 &gc_values);
4179
333b20bb
GM
4180 /* Reliefs. */
4181 f->output_data.x->white_relief.gc = 0;
4182 f->output_data.x->black_relief.gc = 0;
4183
01f1ba30 4184 /* Create the gray border tile used when the pointer is not in
f676886a 4185 the frame. Since this depends on the frame's pixel values,
9ef48a9d 4186 this must be done on a per-frame basis. */
7556890b 4187 f->output_data.x->border_tile
d043f1a4 4188 = (XCreatePixmapFromBitmapData
b9dc4443 4189 (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
d043f1a4 4190 gray_bits, gray_width, gray_height,
7556890b
RS
4191 f->output_data.x->foreground_pixel,
4192 f->output_data.x->background_pixel,
ab452f99 4193 DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f))));
6afb1d07
JB
4194
4195 UNBLOCK_INPUT;
01f1ba30 4196}
01f1ba30 4197
959e647d
GM
4198
4199/* Free what was was allocated in x_make_gc. */
4200
4201void
4202x_free_gcs (f)
4203 struct frame *f;
4204{
4205 Display *dpy = FRAME_X_DISPLAY (f);
4206
4207 BLOCK_INPUT;
4208
4209 if (f->output_data.x->normal_gc)
4210 {
4211 XFreeGC (dpy, f->output_data.x->normal_gc);
4212 f->output_data.x->normal_gc = 0;
4213 }
4214
4215 if (f->output_data.x->reverse_gc)
4216 {
4217 XFreeGC (dpy, f->output_data.x->reverse_gc);
4218 f->output_data.x->reverse_gc = 0;
4219 }
4220
4221 if (f->output_data.x->cursor_gc)
4222 {
4223 XFreeGC (dpy, f->output_data.x->cursor_gc);
4224 f->output_data.x->cursor_gc = 0;
4225 }
4226
4227 if (f->output_data.x->border_tile)
4228 {
4229 XFreePixmap (dpy, f->output_data.x->border_tile);
4230 f->output_data.x->border_tile = 0;
4231 }
4232
4233 UNBLOCK_INPUT;
4234}
4235
4236
eaf1eea9
GM
4237/* Handler for signals raised during x_create_frame and
4238 x_create_top_frame. FRAME is the frame which is partially
4239 constructed. */
4240
4241static Lisp_Object
4242unwind_create_frame (frame)
4243 Lisp_Object frame;
4244{
4245 struct frame *f = XFRAME (frame);
4246
4247 /* If frame is ``official'', nothing to do. */
4248 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4249 {
f1d2ce7f 4250#if GLYPH_DEBUG
eaf1eea9
GM
4251 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4252#endif
4253
4254 x_free_frame_resources (f);
4255
4256 /* Check that reference counts are indeed correct. */
4257 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4258 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a 4259 return Qt;
eaf1eea9
GM
4260 }
4261
4262 return Qnil;
4263}
4264
4265
f676886a 4266DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
01f1ba30 4267 1, 1, 0,
7ee72033 4268 doc: /* Make a new X window, which is called a "frame" in Emacs terms.
c061c855
GM
4269Returns an Emacs frame object.
4270ALIST is an alist of frame parameters.
4271If the parameters specify that the frame should not have a minibuffer,
4272and do not specify a specific minibuffer window to use,
4273then `default-minibuffer-frame' must be a frame whose minibuffer can
4274be shared by the new frame.
4275
7ee72033
MB
4276This function is an internal primitive--use `make-frame' instead. */)
4277 (parms)
01f1ba30
JB
4278 Lisp_Object parms;
4279{
f676886a 4280 struct frame *f;
2365c027 4281 Lisp_Object frame, tem;
01f1ba30
JB
4282 Lisp_Object name;
4283 int minibuffer_only = 0;
4284 long window_prompting = 0;
4285 int width, height;
eaf1eea9 4286 int count = BINDING_STACK_SIZE ();
ecaca587 4287 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
b9dc4443 4288 Lisp_Object display;
333b20bb 4289 struct x_display_info *dpyinfo = NULL;
a59e4f3d 4290 Lisp_Object parent;
e557f19d 4291 struct kboard *kb;
01f1ba30 4292
11ae94fe 4293 check_x ();
01f1ba30 4294
b7975ee4
KH
4295 /* Use this general default value to start with
4296 until we know if this frame has a specified name. */
4297 Vx_resource_name = Vinvocation_name;
4298
333b20bb 4299 display = x_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING);
b9dc4443
RS
4300 if (EQ (display, Qunbound))
4301 display = Qnil;
4302 dpyinfo = check_x_display_info (display);
e557f19d
KH
4303#ifdef MULTI_KBOARD
4304 kb = dpyinfo->kboard;
4305#else
4306 kb = &the_only_kboard;
4307#endif
b9dc4443 4308
333b20bb 4309 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
6a5e54e2 4310 if (!STRINGP (name)
cf177271
JB
4311 && ! EQ (name, Qunbound)
4312 && ! NILP (name))
08a90d6a 4313 error ("Invalid frame name--not a string or nil");
01f1ba30 4314
b7975ee4
KH
4315 if (STRINGP (name))
4316 Vx_resource_name = name;
4317
a59e4f3d 4318 /* See if parent window is specified. */
333b20bb 4319 parent = x_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
a59e4f3d
RS
4320 if (EQ (parent, Qunbound))
4321 parent = Qnil;
4322 if (! NILP (parent))
b7826503 4323 CHECK_NUMBER (parent);
a59e4f3d 4324
ecaca587
RS
4325 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4326 /* No need to protect DISPLAY because that's not used after passing
4327 it to make_frame_without_minibuffer. */
4328 frame = Qnil;
4329 GCPRO4 (parms, parent, name, frame);
333b20bb
GM
4330 tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
4331 RES_TYPE_SYMBOL);
f9942c9e 4332 if (EQ (tem, Qnone) || NILP (tem))
2526c290 4333 f = make_frame_without_minibuffer (Qnil, kb, display);
f9942c9e 4334 else if (EQ (tem, Qonly))
01f1ba30 4335 {
f676886a 4336 f = make_minibuffer_frame ();
01f1ba30
JB
4337 minibuffer_only = 1;
4338 }
6a5e54e2 4339 else if (WINDOWP (tem))
2526c290 4340 f = make_frame_without_minibuffer (tem, kb, display);
f9942c9e
JB
4341 else
4342 f = make_frame (1);
01f1ba30 4343
ecaca587
RS
4344 XSETFRAME (frame, f);
4345
a3c87d4e
JB
4346 /* Note that X Windows does support scroll bars. */
4347 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
179956b9 4348
08a90d6a 4349 f->output_method = output_x_window;
7556890b
RS
4350 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
4351 bzero (f->output_data.x, sizeof (struct x_output));
4352 f->output_data.x->icon_bitmap = -1;
0ecca023 4353 f->output_data.x->fontset = -1;
333b20bb
GM
4354 f->output_data.x->scroll_bar_foreground_pixel = -1;
4355 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
4356#ifdef USE_TOOLKIT_SCROLL_BARS
4357 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
4358 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
4359#endif /* USE_TOOLKIT_SCROLL_BARS */
eaf1eea9 4360 record_unwind_protect (unwind_create_frame, frame);
08a90d6a 4361
f468da95 4362 f->icon_name
333b20bb
GM
4363 = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
4364 RES_TYPE_STRING);
f468da95
RS
4365 if (! STRINGP (f->icon_name))
4366 f->icon_name = Qnil;
80534dd6 4367
08a90d6a 4368 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 4369#if GLYPH_DEBUG
eaf1eea9
GM
4370 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
4371 dpyinfo_refcount = dpyinfo->reference_count;
4372#endif /* GLYPH_DEBUG */
73410c76 4373#ifdef MULTI_KBOARD
e557f19d 4374 FRAME_KBOARD (f) = kb;
73410c76 4375#endif
08a90d6a 4376
9b2956e2
GM
4377 /* These colors will be set anyway later, but it's important
4378 to get the color reference counts right, so initialize them! */
4379 {
4380 Lisp_Object black;
4381 struct gcpro gcpro1;
cefecbcf
GM
4382
4383 /* Function x_decode_color can signal an error. Make
4384 sure to initialize color slots so that we won't try
4385 to free colors we haven't allocated. */
4386 f->output_data.x->foreground_pixel = -1;
4387 f->output_data.x->background_pixel = -1;
4388 f->output_data.x->cursor_pixel = -1;
4389 f->output_data.x->cursor_foreground_pixel = -1;
4390 f->output_data.x->border_pixel = -1;
4391 f->output_data.x->mouse_pixel = -1;
9b2956e2
GM
4392
4393 black = build_string ("black");
4394 GCPRO1 (black);
4395 f->output_data.x->foreground_pixel
4396 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4397 f->output_data.x->background_pixel
4398 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4399 f->output_data.x->cursor_pixel
4400 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4401 f->output_data.x->cursor_foreground_pixel
4402 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4403 f->output_data.x->border_pixel
4404 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4405 f->output_data.x->mouse_pixel
4406 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4407 UNGCPRO;
4408 }
4409
a59e4f3d
RS
4410 /* Specify the parent under which to make this X window. */
4411
4412 if (!NILP (parent))
4413 {
8c239ac3 4414 f->output_data.x->parent_desc = (Window) XFASTINT (parent);
7556890b 4415 f->output_data.x->explicit_parent = 1;
a59e4f3d
RS
4416 }
4417 else
4418 {
7556890b
RS
4419 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
4420 f->output_data.x->explicit_parent = 0;
a59e4f3d
RS
4421 }
4422
cf177271
JB
4423 /* Set the name; the functions to which we pass f expect the name to
4424 be set. */
4425 if (EQ (name, Qunbound) || NILP (name))
4426 {
08a90d6a 4427 f->name = build_string (dpyinfo->x_id_name);
cf177271
JB
4428 f->explicit_name = 0;
4429 }
4430 else
4431 {
4432 f->name = name;
4433 f->explicit_name = 1;
9ef48a9d
RS
4434 /* use the frame's title when getting resources for this frame. */
4435 specbind (Qx_resource_name, name);
cf177271 4436 }
01f1ba30 4437
01f1ba30
JB
4438 /* Extract the window parameters from the supplied values
4439 that are needed to determine window geometry. */
d387c960
JB
4440 {
4441 Lisp_Object font;
4442
333b20bb 4443 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
2ee3abaa 4444
6817eab4 4445 BLOCK_INPUT;
e5e548e3
RS
4446 /* First, try whatever font the caller has specified. */
4447 if (STRINGP (font))
942ea06d 4448 {
49965a29 4449 tem = Fquery_fontset (font, Qnil);
477f8642
KH
4450 if (STRINGP (tem))
4451 font = x_new_fontset (f, XSTRING (tem)->data);
942ea06d
KH
4452 else
4453 font = x_new_font (f, XSTRING (font)->data);
4454 }
333b20bb 4455
e5e548e3 4456 /* Try out a font which we hope has bold and italic variations. */
333b20bb
GM
4457 if (!STRINGP (font))
4458 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
e5e548e3 4459 if (!STRINGP (font))
a6ac02af 4460 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3 4461 if (! STRINGP (font))
a6ac02af 4462 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3
RS
4463 if (! STRINGP (font))
4464 /* This was formerly the first thing tried, but it finds too many fonts
4465 and takes too long. */
4466 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
4467 /* If those didn't work, look for something which will at least work. */
4468 if (! STRINGP (font))
a6ac02af 4469 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
6817eab4
JB
4470 UNBLOCK_INPUT;
4471 if (! STRINGP (font))
e5e548e3
RS
4472 font = build_string ("fixed");
4473
477f8642 4474 x_default_parameter (f, parms, Qfont, font,
333b20bb 4475 "font", "Font", RES_TYPE_STRING);
d387c960 4476 }
9ef48a9d 4477
e3881aa0 4478#ifdef USE_LUCID
82c90203
RS
4479 /* Prevent lwlib/xlwmenu.c from crashing because of a bug
4480 whereby it fails to get any font. */
7556890b 4481 xlwmenu_default_font = f->output_data.x->font;
dd254b21 4482#endif
82c90203 4483
cf177271 4484 x_default_parameter (f, parms, Qborder_width, make_number (2),
333b20bb
GM
4485 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
4486
4e397688 4487 /* This defaults to 1 in order to match xterm. We recognize either
ddf768c3
JB
4488 internalBorderWidth or internalBorder (which is what xterm calls
4489 it). */
4490 if (NILP (Fassq (Qinternal_border_width, parms)))
4491 {
4492 Lisp_Object value;
4493
abb4b7ec 4494 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
333b20bb 4495 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
ddf768c3
JB
4496 if (! EQ (value, Qunbound))
4497 parms = Fcons (Fcons (Qinternal_border_width, value),
4498 parms);
4499 }
dca97592 4500 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
333b20bb
GM
4501 "internalBorderWidth", "internalBorderWidth",
4502 RES_TYPE_NUMBER);
1ab3d87e 4503 x_default_parameter (f, parms, Qvertical_scroll_bars, Qleft,
333b20bb
GM
4504 "verticalScrollBars", "ScrollBars",
4505 RES_TYPE_SYMBOL);
01f1ba30 4506
b9dc4443 4507 /* Also do the stuff which must be set before the window exists. */
cf177271 4508 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
333b20bb 4509 "foreground", "Foreground", RES_TYPE_STRING);
cf177271 4510 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
0b60fc91 4511 "background", "Background", RES_TYPE_STRING);
cf177271 4512 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
333b20bb 4513 "pointerColor", "Foreground", RES_TYPE_STRING);
cf177271 4514 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
333b20bb 4515 "cursorColor", "Foreground", RES_TYPE_STRING);
cf177271 4516 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
333b20bb 4517 "borderColor", "BorderColor", RES_TYPE_STRING);
d62c8769
GM
4518 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
4519 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
563b67aa
GM
4520 x_default_parameter (f, parms, Qline_spacing, Qnil,
4521 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
b3ba0aa8
KS
4522 x_default_parameter (f, parms, Qleft_fringe, Qnil,
4523 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4524 x_default_parameter (f, parms, Qright_fringe, Qnil,
4525 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
333b20bb
GM
4526
4527 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
4528 "scrollBarForeground",
4529 "ScrollBarForeground", 1);
4530 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
4531 "scrollBarBackground",
4532 "ScrollBarBackground", 0);
4533
4534 /* Init faces before x_default_parameter is called for scroll-bar
4535 parameters because that function calls x_set_scroll_bar_width,
4536 which calls change_frame_size, which calls Fset_window_buffer,
4537 which runs hooks, which call Fvertical_motion. At the end, we
4538 end up in init_iterator with a null face cache, which should not
4539 happen. */
4540 init_frame_faces (f);
4541
c7bcb20d 4542 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
333b20bb 4543 "menuBar", "MenuBar", RES_TYPE_NUMBER);
e33455ca 4544 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
333b20bb 4545 "toolBar", "ToolBar", RES_TYPE_NUMBER);
79873d50 4546 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
333b20bb
GM
4547 "bufferPredicate", "BufferPredicate",
4548 RES_TYPE_SYMBOL);
c2304e02 4549 x_default_parameter (f, parms, Qtitle, Qnil,
333b20bb 4550 "title", "Title", RES_TYPE_STRING);
ea0a1f53
GM
4551 x_default_parameter (f, parms, Qwait_for_wm, Qt,
4552 "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
49d41073
EZ
4553 x_default_parameter (f, parms, Qfullscreen, Qnil,
4554 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
90eb1019 4555
7556890b 4556 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
35f59f6b
GM
4557
4558 /* Add the tool-bar height to the initial frame height so that the
4559 user gets a text display area of the size he specified with -g or
4560 via .Xdefaults. Later changes of the tool-bar height don't
4561 change the frame size. This is done so that users can create
4562 tall Emacs frames without having to guess how tall the tool-bar
4563 will get. */
4564 if (FRAME_TOOL_BAR_LINES (f))
4565 {
4566 int margin, relief, bar_height;
4567
8ed86491 4568 relief = (tool_bar_button_relief >= 0
35f59f6b
GM
4569 ? tool_bar_button_relief
4570 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
4571
4572 if (INTEGERP (Vtool_bar_button_margin)
4573 && XINT (Vtool_bar_button_margin) > 0)
4574 margin = XFASTINT (Vtool_bar_button_margin);
4575 else if (CONSP (Vtool_bar_button_margin)
4576 && INTEGERP (XCDR (Vtool_bar_button_margin))
4577 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
4578 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
4579 else
4580 margin = 0;
4581
4582 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
4583 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
4584 }
4585
4586 /* Compute the size of the X window. */
f676886a 4587 window_prompting = x_figure_window_size (f, parms);
01f1ba30 4588
f83f10ba 4589 if (window_prompting & XNegative)
2365c027 4590 {
f83f10ba 4591 if (window_prompting & YNegative)
7556890b 4592 f->output_data.x->win_gravity = SouthEastGravity;
f83f10ba 4593 else
7556890b 4594 f->output_data.x->win_gravity = NorthEastGravity;
f83f10ba
RS
4595 }
4596 else
4597 {
4598 if (window_prompting & YNegative)
7556890b 4599 f->output_data.x->win_gravity = SouthWestGravity;
f83f10ba 4600 else
7556890b 4601 f->output_data.x->win_gravity = NorthWestGravity;
2365c027
RS
4602 }
4603
7556890b 4604 f->output_data.x->size_hint_flags = window_prompting;
38d22040 4605
495fa05e
GM
4606 tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4607 f->no_split = minibuffer_only || EQ (tem, Qt);
4608
6a1bcd01 4609 /* Create the X widget or window. */
a7f7d550
FP
4610#ifdef USE_X_TOOLKIT
4611 x_window (f, window_prompting, minibuffer_only);
4612#else
f676886a 4613 x_window (f);
a7f7d550 4614#endif
495fa05e 4615
f676886a
JB
4616 x_icon (f, parms);
4617 x_make_gc (f);
01f1ba30 4618
495fa05e
GM
4619 /* Now consider the frame official. */
4620 FRAME_X_DISPLAY_INFO (f)->reference_count++;
4621 Vframe_list = Fcons (frame, Vframe_list);
4622
f9942c9e
JB
4623 /* We need to do this after creating the X window, so that the
4624 icon-creation functions can say whose icon they're describing. */
cf177271 4625 x_default_parameter (f, parms, Qicon_type, Qnil,
333b20bb 4626 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
f9942c9e 4627
cf177271 4628 x_default_parameter (f, parms, Qauto_raise, Qnil,
333b20bb 4629 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
cf177271 4630 x_default_parameter (f, parms, Qauto_lower, Qnil,
333b20bb 4631 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
dbc4e1c1 4632 x_default_parameter (f, parms, Qcursor_type, Qbox,
333b20bb 4633 "cursorType", "CursorType", RES_TYPE_SYMBOL);
28d7281d
GM
4634 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4635 "scrollBarWidth", "ScrollBarWidth",
4636 RES_TYPE_NUMBER);
f9942c9e 4637
f676886a 4638 /* Dimensions, especially f->height, must be done via change_frame_size.
01f1ba30 4639 Change will not be effected unless different from the current
b9dc4443 4640 f->height. */
f676886a
JB
4641 width = f->width;
4642 height = f->height;
6a1bcd01 4643
1ab3d87e
RS
4644 f->height = 0;
4645 SET_FRAME_WIDTH (f, 0);
8938a4fb 4646 change_frame_size (f, height, width, 1, 0, 0);
d043f1a4 4647
4a967a9b
GM
4648 /* Set up faces after all frame parameters are known. This call
4649 also merges in face attributes specified for new frames. If we
4650 don't do this, the `menu' face for instance won't have the right
4651 colors, and the menu bar won't appear in the specified colors for
4652 new frames. */
4653 call1 (Qface_set_after_frame_default, frame);
4654
495fa05e
GM
4655#ifdef USE_X_TOOLKIT
4656 /* Create the menu bar. */
4657 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4658 {
4659 /* If this signals an error, we haven't set size hints for the
4660 frame and we didn't make it visible. */
4661 initialize_frame_menubar (f);
4662
4663 /* This is a no-op, except under Motif where it arranges the
4664 main window for the widgets on it. */
4665 lw_set_main_areas (f->output_data.x->column_widget,
4666 f->output_data.x->menubar_widget,
4667 f->output_data.x->edit_widget);
4668 }
4669#endif /* USE_X_TOOLKIT */
4670
4671 /* Tell the server what size and position, etc, we want, and how
4672 badly we want them. This should be done after we have the menu
4673 bar so that its size can be taken into account. */
01f1ba30 4674 BLOCK_INPUT;
7989f084 4675 x_wm_set_size_hint (f, window_prompting, 0);
01f1ba30
JB
4676 UNBLOCK_INPUT;
4677
495fa05e
GM
4678 /* Make the window appear on the frame and enable display, unless
4679 the caller says not to. However, with explicit parent, Emacs
4680 cannot control visibility, so don't try. */
7556890b 4681 if (! f->output_data.x->explicit_parent)
a59e4f3d
RS
4682 {
4683 Lisp_Object visibility;
49795535 4684
333b20bb
GM
4685 visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
4686 RES_TYPE_SYMBOL);
a59e4f3d
RS
4687 if (EQ (visibility, Qunbound))
4688 visibility = Qt;
49795535 4689
a59e4f3d
RS
4690 if (EQ (visibility, Qicon))
4691 x_iconify_frame (f);
4692 else if (! NILP (visibility))
4693 x_make_frame_visible (f);
4694 else
4695 /* Must have been Qnil. */
4696 ;
4697 }
01f1ba30 4698
495fa05e 4699 UNGCPRO;
9e57df62
GM
4700
4701 /* Make sure windows on this frame appear in calls to next-window
4702 and similar functions. */
4703 Vwindow_list = Qnil;
4704
9ef48a9d 4705 return unbind_to (count, frame);
01f1ba30
JB
4706}
4707
eaf1eea9 4708
0d17d282
KH
4709/* FRAME is used only to get a handle on the X display. We don't pass the
4710 display info directly because we're called from frame.c, which doesn't
4711 know about that structure. */
e4f79258 4712
87498171 4713Lisp_Object
0d17d282
KH
4714x_get_focus_frame (frame)
4715 struct frame *frame;
87498171 4716{
0d17d282 4717 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (frame);
87498171 4718 Lisp_Object xfocus;
0d17d282 4719 if (! dpyinfo->x_focus_frame)
87498171
KH
4720 return Qnil;
4721
0d17d282 4722 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
87498171
KH
4723 return xfocus;
4724}
f0614854 4725
3decc1e7
GM
4726
4727/* In certain situations, when the window manager follows a
4728 click-to-focus policy, there seems to be no way around calling
4729 XSetInputFocus to give another frame the input focus .
4730
4731 In an ideal world, XSetInputFocus should generally be avoided so
4732 that applications don't interfere with the window manager's focus
4733 policy. But I think it's okay to use when it's clearly done
4734 following a user-command. */
4735
4736DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
7ee72033
MB
4737 doc: /* Set the input focus to FRAME.
4738FRAME nil means use the selected frame. */)
4739 (frame)
3decc1e7
GM
4740 Lisp_Object frame;
4741{
4742 struct frame *f = check_x_frame (frame);
4743 Display *dpy = FRAME_X_DISPLAY (f);
4744 int count;
4745
4746 BLOCK_INPUT;
4747 count = x_catch_errors (dpy);
4748 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4749 RevertToParent, CurrentTime);
4750 x_uncatch_errors (dpy, count);
4751 UNBLOCK_INPUT;
4752
4753 return Qnil;
4754}
4755
f0614854 4756\f
2d764c78 4757DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7ee72033
MB
4758 doc: /* Internal function called by `color-defined-p', which see. */)
4759 (color, frame)
b9dc4443 4760 Lisp_Object color, frame;
e12d55b2 4761{
b9dc4443
RS
4762 XColor foo;
4763 FRAME_PTR f = check_x_frame (frame);
e12d55b2 4764
b7826503 4765 CHECK_STRING (color);
b9dc4443 4766
2d764c78 4767 if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
e12d55b2
RS
4768 return Qt;
4769 else
4770 return Qnil;
4771}
4772
2d764c78 4773DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7ee72033
MB
4774 doc: /* Internal function called by `color-values', which see. */)
4775 (color, frame)
b9dc4443 4776 Lisp_Object color, frame;
01f1ba30 4777{
b9dc4443
RS
4778 XColor foo;
4779 FRAME_PTR f = check_x_frame (frame);
4780
b7826503 4781 CHECK_STRING (color);
01f1ba30 4782
2d764c78 4783 if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
57c82a63
RS
4784 {
4785 Lisp_Object rgb[3];
4786
4787 rgb[0] = make_number (foo.red);
4788 rgb[1] = make_number (foo.green);
4789 rgb[2] = make_number (foo.blue);
4790 return Flist (3, rgb);
4791 }
01f1ba30
JB
4792 else
4793 return Qnil;
4794}
4795
2d764c78 4796DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7ee72033
MB
4797 doc: /* Internal function called by `display-color-p', which see. */)
4798 (display)
08a90d6a 4799 Lisp_Object display;
01f1ba30 4800{
08a90d6a 4801 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 4802
b9dc4443 4803 if (dpyinfo->n_planes <= 2)
01f1ba30
JB
4804 return Qnil;
4805
b9dc4443 4806 switch (dpyinfo->visual->class)
01f1ba30
JB
4807 {
4808 case StaticColor:
4809 case PseudoColor:
4810 case TrueColor:
4811 case DirectColor:
4812 return Qt;
4813
4814 default:
4815 return Qnil;
4816 }
4817}
4818
d0c9d219 4819DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
c061c855 4820 0, 1, 0,
7ee72033 4821 doc: /* Return t if the X display supports shades of gray.
c061c855
GM
4822Note that color displays do support shades of gray.
4823The optional argument DISPLAY specifies which display to ask about.
4824DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4825If omitted or nil, that stands for the selected frame's display. */)
4826 (display)
08a90d6a 4827 Lisp_Object display;
d0c9d219 4828{
08a90d6a 4829 struct x_display_info *dpyinfo = check_x_display_info (display);
d0c9d219 4830
ae6b58f9 4831 if (dpyinfo->n_planes <= 1)
b9dc4443
RS
4832 return Qnil;
4833
ae6b58f9
RS
4834 switch (dpyinfo->visual->class)
4835 {
4836 case StaticColor:
4837 case PseudoColor:
4838 case TrueColor:
4839 case DirectColor:
4840 case StaticGray:
4841 case GrayScale:
4842 return Qt;
4843
4844 default:
4845 return Qnil;
4846 }
d0c9d219
RS
4847}
4848
41beb8fc 4849DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
c061c855 4850 0, 1, 0,
7ee72033 4851 doc: /* Returns the width in pixels of the X display DISPLAY.
c061c855
GM
4852The optional argument DISPLAY specifies which display to ask about.
4853DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4854If omitted or nil, that stands for the selected frame's display. */)
4855 (display)
08a90d6a 4856 Lisp_Object display;
41beb8fc 4857{
08a90d6a 4858 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4859
4860 return make_number (dpyinfo->width);
41beb8fc
RS
4861}
4862
4863DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
c061c855 4864 Sx_display_pixel_height, 0, 1, 0,
7ee72033 4865 doc: /* Returns the height in pixels of the X display DISPLAY.
c061c855
GM
4866The optional argument DISPLAY specifies which display to ask about.
4867DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4868If omitted or nil, that stands for the selected frame's display. */)
4869 (display)
08a90d6a 4870 Lisp_Object display;
41beb8fc 4871{
08a90d6a 4872 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4873
4874 return make_number (dpyinfo->height);
41beb8fc
RS
4875}
4876
4877DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
c061c855 4878 0, 1, 0,
7ee72033 4879 doc: /* Returns the number of bitplanes of the X display DISPLAY.
c061c855
GM
4880The optional argument DISPLAY specifies which display to ask about.
4881DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4882If omitted or nil, that stands for the selected frame's display. */)
4883 (display)
08a90d6a 4884 Lisp_Object display;
41beb8fc 4885{
08a90d6a 4886 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4887
4888 return make_number (dpyinfo->n_planes);
41beb8fc
RS
4889}
4890
4891DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
c061c855 4892 0, 1, 0,
7ee72033 4893 doc: /* Returns the number of color cells of the X display DISPLAY.
c061c855
GM
4894The optional argument DISPLAY specifies which display to ask about.
4895DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4896If omitted or nil, that stands for the selected frame's display. */)
4897 (display)
08a90d6a 4898 Lisp_Object display;
41beb8fc 4899{
08a90d6a 4900 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4901
4902 return make_number (DisplayCells (dpyinfo->display,
4903 XScreenNumberOfScreen (dpyinfo->screen)));
41beb8fc
RS
4904}
4905
9d317b2c
RS
4906DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4907 Sx_server_max_request_size,
c061c855 4908 0, 1, 0,
7ee72033 4909 doc: /* Returns the maximum request size of the X server of display DISPLAY.
c061c855
GM
4910The optional argument DISPLAY specifies which display to ask about.
4911DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4912If omitted or nil, that stands for the selected frame's display. */)
4913 (display)
08a90d6a 4914 Lisp_Object display;
9d317b2c 4915{
08a90d6a 4916 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4917
4918 return make_number (MAXREQUEST (dpyinfo->display));
9d317b2c
RS
4919}
4920
41beb8fc 4921DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7ee72033 4922 doc: /* Returns the vendor ID string of the X server of display DISPLAY.
c061c855
GM
4923The optional argument DISPLAY specifies which display to ask about.
4924DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4925If omitted or nil, that stands for the selected frame's display. */)
4926 (display)
08a90d6a 4927 Lisp_Object display;
41beb8fc 4928{
08a90d6a 4929 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4930 char *vendor = ServerVendor (dpyinfo->display);
4931
41beb8fc
RS
4932 if (! vendor) vendor = "";
4933 return build_string (vendor);
4934}
4935
4936DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7ee72033 4937 doc: /* Returns the version numbers of the X server of display DISPLAY.
c061c855
GM
4938The value is a list of three integers: the major and minor
4939version numbers of the X Protocol in use, and the vendor-specific release
4940number. See also the function `x-server-vendor'.
4941
4942The optional argument DISPLAY specifies which display to ask about.
4943DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4944If omitted or nil, that stands for the selected frame's display. */)
4945 (display)
08a90d6a 4946 Lisp_Object display;
41beb8fc 4947{
08a90d6a 4948 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443 4949 Display *dpy = dpyinfo->display;
11ae94fe 4950
41beb8fc
RS
4951 return Fcons (make_number (ProtocolVersion (dpy)),
4952 Fcons (make_number (ProtocolRevision (dpy)),
4953 Fcons (make_number (VendorRelease (dpy)), Qnil)));
4954}
4955
4956DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7ee72033 4957 doc: /* Return the number of screens on the X server of display DISPLAY.
c061c855
GM
4958The optional argument DISPLAY specifies which display to ask about.
4959DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4960If omitted or nil, that stands for the selected frame's display. */)
4961 (display)
08a90d6a 4962 Lisp_Object display;
41beb8fc 4963{
08a90d6a 4964 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4965
4966 return make_number (ScreenCount (dpyinfo->display));
41beb8fc
RS
4967}
4968
4969DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7ee72033 4970 doc: /* Return the height in millimeters of the X display DISPLAY.
c061c855
GM
4971The optional argument DISPLAY specifies which display to ask about.
4972DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4973If omitted or nil, that stands for the selected frame's display. */)
4974 (display)
08a90d6a 4975 Lisp_Object display;
41beb8fc 4976{
08a90d6a 4977 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4978
4979 return make_number (HeightMMOfScreen (dpyinfo->screen));
41beb8fc
RS
4980}
4981
4982DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7ee72033 4983 doc: /* Return the width in millimeters of the X display DISPLAY.
c061c855
GM
4984The optional argument DISPLAY specifies which display to ask about.
4985DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4986If omitted or nil, that stands for the selected frame's display. */)
4987 (display)
08a90d6a 4988 Lisp_Object display;
41beb8fc 4989{
08a90d6a 4990 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4991
4992 return make_number (WidthMMOfScreen (dpyinfo->screen));
41beb8fc
RS
4993}
4994
4995DEFUN ("x-display-backing-store", Fx_display_backing_store,
c061c855 4996 Sx_display_backing_store, 0, 1, 0,
7ee72033 4997 doc: /* Returns an indication of whether X display DISPLAY does backing store.
c061c855
GM
4998The value may be `always', `when-mapped', or `not-useful'.
4999The optional argument DISPLAY specifies which display to ask about.
5000DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5001If omitted or nil, that stands for the selected frame's display. */)
5002 (display)
08a90d6a 5003 Lisp_Object display;
41beb8fc 5004{
08a90d6a 5005 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5006 Lisp_Object result;
11ae94fe 5007
b9dc4443 5008 switch (DoesBackingStore (dpyinfo->screen))
41beb8fc
RS
5009 {
5010 case Always:
8ec8a5ec
GM
5011 result = intern ("always");
5012 break;
41beb8fc
RS
5013
5014 case WhenMapped:
8ec8a5ec
GM
5015 result = intern ("when-mapped");
5016 break;
41beb8fc
RS
5017
5018 case NotUseful:
8ec8a5ec
GM
5019 result = intern ("not-useful");
5020 break;
41beb8fc
RS
5021
5022 default:
5023 error ("Strange value for BackingStore parameter of screen");
8ec8a5ec 5024 result = Qnil;
41beb8fc 5025 }
8ec8a5ec
GM
5026
5027 return result;
41beb8fc
RS
5028}
5029
5030DEFUN ("x-display-visual-class", Fx_display_visual_class,
c061c855 5031 Sx_display_visual_class, 0, 1, 0,
7ee72033 5032 doc: /* Return the visual class of the X display DISPLAY.
c061c855
GM
5033The value is one of the symbols `static-gray', `gray-scale',
5034`static-color', `pseudo-color', `true-color', or `direct-color'.
5035
5036The optional argument DISPLAY specifies which display to ask about.
5037DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5038If omitted or nil, that stands for the selected frame's display. */)
5039 (display)
08a90d6a 5040 Lisp_Object display;
41beb8fc 5041{
08a90d6a 5042 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5043 Lisp_Object result;
11ae94fe 5044
b9dc4443 5045 switch (dpyinfo->visual->class)
41beb8fc 5046 {
8ec8a5ec
GM
5047 case StaticGray:
5048 result = intern ("static-gray");
5049 break;
5050 case GrayScale:
5051 result = intern ("gray-scale");
5052 break;
5053 case StaticColor:
5054 result = intern ("static-color");
5055 break;
5056 case PseudoColor:
5057 result = intern ("pseudo-color");
5058 break;
5059 case TrueColor:
5060 result = intern ("true-color");
5061 break;
5062 case DirectColor:
5063 result = intern ("direct-color");
5064 break;
41beb8fc
RS
5065 default:
5066 error ("Display has an unknown visual class");
8ec8a5ec 5067 result = Qnil;
41beb8fc 5068 }
8ec8a5ec
GM
5069
5070 return result;
41beb8fc
RS
5071}
5072
5073DEFUN ("x-display-save-under", Fx_display_save_under,
c061c855 5074 Sx_display_save_under, 0, 1, 0,
7ee72033 5075 doc: /* Returns t if the X display DISPLAY supports the save-under feature.
c061c855
GM
5076The optional argument DISPLAY specifies which display to ask about.
5077DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5078If omitted or nil, that stands for the selected frame's display. */)
5079 (display)
08a90d6a 5080 Lisp_Object display;
41beb8fc 5081{
08a90d6a 5082 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5083
b9dc4443 5084 if (DoesSaveUnders (dpyinfo->screen) == True)
41beb8fc
RS
5085 return Qt;
5086 else
5087 return Qnil;
5088}
5089\f
b9dc4443 5090int
55caf99c
RS
5091x_pixel_width (f)
5092 register struct frame *f;
01f1ba30 5093{
55caf99c 5094 return PIXEL_WIDTH (f);
01f1ba30
JB
5095}
5096
b9dc4443 5097int
55caf99c
RS
5098x_pixel_height (f)
5099 register struct frame *f;
01f1ba30 5100{
55caf99c
RS
5101 return PIXEL_HEIGHT (f);
5102}
5103
b9dc4443 5104int
55caf99c
RS
5105x_char_width (f)
5106 register struct frame *f;
5107{
7556890b 5108 return FONT_WIDTH (f->output_data.x->font);
55caf99c
RS
5109}
5110
b9dc4443 5111int
55caf99c
RS
5112x_char_height (f)
5113 register struct frame *f;
5114{
7556890b 5115 return f->output_data.x->line_height;
01f1ba30 5116}
b9dc4443
RS
5117
5118int
f03f2489
RS
5119x_screen_planes (f)
5120 register struct frame *f;
b9dc4443 5121{
f03f2489 5122 return FRAME_X_DISPLAY_INFO (f)->n_planes;
b9dc4443 5123}
01f1ba30 5124
a6ad00c0
GM
5125
5126\f
5127/************************************************************************
5128 X Displays
5129 ************************************************************************/
5130
01f1ba30 5131\f
a6ad00c0
GM
5132/* Mapping visual names to visuals. */
5133
5134static struct visual_class
5135{
5136 char *name;
5137 int class;
5138}
5139visual_classes[] =
5140{
5141 {"StaticGray", StaticGray},
5142 {"GrayScale", GrayScale},
5143 {"StaticColor", StaticColor},
5144 {"PseudoColor", PseudoColor},
5145 {"TrueColor", TrueColor},
5146 {"DirectColor", DirectColor},
9908a324 5147 {NULL, 0}
a6ad00c0
GM
5148};
5149
5150
404daac1 5151#ifndef HAVE_XSCREENNUMBEROFSCREEN
a6ad00c0
GM
5152
5153/* Value is the screen number of screen SCR. This is a substitute for
5154 the X function with the same name when that doesn't exist. */
5155
404daac1
RS
5156int
5157XScreenNumberOfScreen (scr)
5158 register Screen *scr;
5159{
a6ad00c0
GM
5160 Display *dpy = scr->display;
5161 int i;
3df34fdb 5162
a6ad00c0 5163 for (i = 0; i < dpy->nscreens; ++i)
fbd5ceb2 5164 if (scr == dpy->screens + i)
a6ad00c0 5165 break;
404daac1 5166
a6ad00c0 5167 return i;
404daac1 5168}
a6ad00c0 5169
404daac1
RS
5170#endif /* not HAVE_XSCREENNUMBEROFSCREEN */
5171
01f1ba30 5172
a6ad00c0
GM
5173/* Select the visual that should be used on display DPYINFO. Set
5174 members of DPYINFO appropriately. Called from x_term_init. */
fe24a618 5175
a6ad00c0
GM
5176void
5177select_visual (dpyinfo)
5178 struct x_display_info *dpyinfo;
5179{
5180 Display *dpy = dpyinfo->display;
5181 Screen *screen = dpyinfo->screen;
5182 Lisp_Object value;
fe24a618 5183
a6ad00c0
GM
5184 /* See if a visual is specified. */
5185 value = display_x_get_resource (dpyinfo,
5186 build_string ("visualClass"),
5187 build_string ("VisualClass"),
5188 Qnil, Qnil);
5189 if (STRINGP (value))
5190 {
5191 /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
5192 of `PseudoColor', `TrueColor' etc. and DEPTH is the color
5193 depth, a decimal number. NAME is compared with case ignored. */
5194 char *s = (char *) alloca (STRING_BYTES (XSTRING (value)) + 1);
5195 char *dash;
5196 int i, class = -1;
5197 XVisualInfo vinfo;
5198
5199 strcpy (s, XSTRING (value)->data);
5200 dash = index (s, '-');
5201 if (dash)
5202 {
5203 dpyinfo->n_planes = atoi (dash + 1);
5204 *dash = '\0';
5205 }
5206 else
5207 /* We won't find a matching visual with depth 0, so that
5208 an error will be printed below. */
5209 dpyinfo->n_planes = 0;
f0614854 5210
a6ad00c0
GM
5211 /* Determine the visual class. */
5212 for (i = 0; visual_classes[i].name; ++i)
5213 if (xstricmp (s, visual_classes[i].name) == 0)
5214 {
5215 class = visual_classes[i].class;
5216 break;
5217 }
01f1ba30 5218
a6ad00c0
GM
5219 /* Look up a matching visual for the specified class. */
5220 if (class == -1
5221 || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
5222 dpyinfo->n_planes, class, &vinfo))
5223 fatal ("Invalid visual specification `%s'", XSTRING (value)->data);
5224
5225 dpyinfo->visual = vinfo.visual;
5226 }
01f1ba30
JB
5227 else
5228 {
a6ad00c0
GM
5229 int n_visuals;
5230 XVisualInfo *vinfo, vinfo_template;
5231
5232 dpyinfo->visual = DefaultVisualOfScreen (screen);
5233
5234#ifdef HAVE_X11R4
5235 vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
5236#else
5237 vinfo_template.visualid = dpyinfo->visual->visualid;
5238#endif
5239 vinfo_template.screen = XScreenNumberOfScreen (screen);
5240 vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
5241 &vinfo_template, &n_visuals);
5242 if (n_visuals != 1)
5243 fatal ("Can't get proper X visual info");
5244
94ac875b 5245 dpyinfo->n_planes = vinfo->depth;
a6ad00c0
GM
5246 XFree ((char *) vinfo);
5247 }
01f1ba30 5248}
01f1ba30 5249
a6ad00c0 5250
b9dc4443
RS
5251/* Return the X display structure for the display named NAME.
5252 Open a new connection if necessary. */
5253
5254struct x_display_info *
5255x_display_info_for_name (name)
5256 Lisp_Object name;
5257{
08a90d6a 5258 Lisp_Object names;
b9dc4443
RS
5259 struct x_display_info *dpyinfo;
5260
b7826503 5261 CHECK_STRING (name);
b9dc4443 5262
806048df
RS
5263 if (! EQ (Vwindow_system, intern ("x")))
5264 error ("Not using X Windows");
5265
08a90d6a
RS
5266 for (dpyinfo = x_display_list, names = x_display_name_list;
5267 dpyinfo;
8e713be6 5268 dpyinfo = dpyinfo->next, names = XCDR (names))
b9dc4443
RS
5269 {
5270 Lisp_Object tem;
8e713be6 5271 tem = Fstring_equal (XCAR (XCAR (names)), name);
08a90d6a 5272 if (!NILP (tem))
b9dc4443
RS
5273 return dpyinfo;
5274 }
5275
b7975ee4
KH
5276 /* Use this general default value to start with. */
5277 Vx_resource_name = Vinvocation_name;
5278
b9dc4443
RS
5279 validate_x_resource_name ();
5280
9b207e8e 5281 dpyinfo = x_term_init (name, (char *)0,
b7975ee4 5282 (char *) XSTRING (Vx_resource_name)->data);
b9dc4443 5283
08a90d6a 5284 if (dpyinfo == 0)
1b4ec1c8 5285 error ("Cannot connect to X server %s", XSTRING (name)->data);
08a90d6a 5286
b9dc4443
RS
5287 x_in_use = 1;
5288 XSETFASTINT (Vwindow_system_version, 11);
5289
5290 return dpyinfo;
5291}
5292
a6ad00c0 5293
01f1ba30 5294DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
c061c855 5295 1, 3, 0,
7ee72033 5296 doc: /* Open a connection to an X server.
c061c855
GM
5297DISPLAY is the name of the display to connect to.
5298Optional second arg XRM-STRING is a string of resources in xrdb format.
5299If the optional third arg MUST-SUCCEED is non-nil,
7ee72033
MB
5300terminate Emacs if we can't open the connection. */)
5301 (display, xrm_string, must_succeed)
08a90d6a 5302 Lisp_Object display, xrm_string, must_succeed;
01f1ba30 5303{
01f1ba30 5304 unsigned char *xrm_option;
b9dc4443 5305 struct x_display_info *dpyinfo;
01f1ba30 5306
b7826503 5307 CHECK_STRING (display);
d387c960 5308 if (! NILP (xrm_string))
b7826503 5309 CHECK_STRING (xrm_string);
01f1ba30 5310
806048df
RS
5311 if (! EQ (Vwindow_system, intern ("x")))
5312 error ("Not using X Windows");
5313
d387c960
JB
5314 if (! NILP (xrm_string))
5315 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
01f1ba30
JB
5316 else
5317 xrm_option = (unsigned char *) 0;
d387c960
JB
5318
5319 validate_x_resource_name ();
5320
e1b1bee8 5321 /* This is what opens the connection and sets x_current_display.
b9dc4443
RS
5322 This also initializes many symbols, such as those used for input. */
5323 dpyinfo = x_term_init (display, xrm_option,
b7975ee4 5324 (char *) XSTRING (Vx_resource_name)->data);
f1c16f36 5325
08a90d6a
RS
5326 if (dpyinfo == 0)
5327 {
5328 if (!NILP (must_succeed))
10ffbc14
GM
5329 fatal ("Cannot connect to X server %s.\n\
5330Check the DISPLAY environment variable or use `-d'.\n\
5331Also use the `xhost' program to verify that it is set to permit\n\
1b4ec1c8 5332connections from your machine.\n",
08a90d6a
RS
5333 XSTRING (display)->data);
5334 else
1b4ec1c8 5335 error ("Cannot connect to X server %s", XSTRING (display)->data);
08a90d6a
RS
5336 }
5337
b9dc4443 5338 x_in_use = 1;
01f1ba30 5339
b9dc4443 5340 XSETFASTINT (Vwindow_system_version, 11);
01f1ba30
JB
5341 return Qnil;
5342}
5343
08a90d6a
RS
5344DEFUN ("x-close-connection", Fx_close_connection,
5345 Sx_close_connection, 1, 1, 0,
7ee72033 5346 doc: /* Close the connection to DISPLAY's X server.
c061c855 5347For DISPLAY, specify either a frame or a display name (a string).
7ee72033
MB
5348If DISPLAY is nil, that stands for the selected frame's display. */)
5349 (display)
c061c855 5350 Lisp_Object display;
01f1ba30 5351{
08a90d6a 5352 struct x_display_info *dpyinfo = check_x_display_info (display);
08a90d6a 5353 int i;
3457bc6e 5354
08a90d6a
RS
5355 if (dpyinfo->reference_count > 0)
5356 error ("Display still has frames on it");
01f1ba30 5357
08a90d6a
RS
5358 BLOCK_INPUT;
5359 /* Free the fonts in the font table. */
5360 for (i = 0; i < dpyinfo->n_fonts; i++)
333b20bb
GM
5361 if (dpyinfo->font_table[i].name)
5362 {
6ecb43ce
KH
5363 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
5364 xfree (dpyinfo->font_table[i].full_name);
333b20bb 5365 xfree (dpyinfo->font_table[i].name);
333b20bb
GM
5366 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
5367 }
5368
08a90d6a
RS
5369 x_destroy_all_bitmaps (dpyinfo);
5370 XSetCloseDownMode (dpyinfo->display, DestroyAll);
82c90203
RS
5371
5372#ifdef USE_X_TOOLKIT
5373 XtCloseDisplay (dpyinfo->display);
5374#else
08a90d6a 5375 XCloseDisplay (dpyinfo->display);
82c90203 5376#endif
08a90d6a
RS
5377
5378 x_delete_display (dpyinfo);
5379 UNBLOCK_INPUT;
3457bc6e 5380
01f1ba30
JB
5381 return Qnil;
5382}
5383
08a90d6a 5384DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7ee72033
MB
5385 doc: /* Return the list of display names that Emacs has connections to. */)
5386 ()
08a90d6a
RS
5387{
5388 Lisp_Object tail, result;
5389
5390 result = Qnil;
8e713be6
KR
5391 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
5392 result = Fcons (XCAR (XCAR (tail)), result);
08a90d6a
RS
5393
5394 return result;
5395}
5396
5397DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7ee72033 5398 doc: /* If ON is non-nil, report X errors as soon as the erring request is made.
c061c855
GM
5399If ON is nil, allow buffering of requests.
5400Turning on synchronization prohibits the Xlib routines from buffering
5401requests and seriously degrades performance, but makes debugging much
5402easier.
5403The optional second argument DISPLAY specifies which display to act on.
5404DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5405If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
5406 (on, display)
08a90d6a 5407 Lisp_Object display, on;
01f1ba30 5408{
08a90d6a 5409 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5410
b9dc4443 5411 XSynchronize (dpyinfo->display, !EQ (on, Qnil));
01f1ba30
JB
5412
5413 return Qnil;
5414}
5415
b9dc4443 5416/* Wait for responses to all X commands issued so far for frame F. */
6b7b1820
RS
5417
5418void
b9dc4443
RS
5419x_sync (f)
5420 FRAME_PTR f;
6b7b1820 5421{
4e87f4d2 5422 BLOCK_INPUT;
b9dc4443 5423 XSync (FRAME_X_DISPLAY (f), False);
4e87f4d2 5424 UNBLOCK_INPUT;
6b7b1820 5425}
333b20bb 5426
01f1ba30 5427\f
333b20bb
GM
5428/***********************************************************************
5429 Image types
5430 ***********************************************************************/
f1c16f36 5431
333b20bb
GM
5432/* Value is the number of elements of vector VECTOR. */
5433
5434#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
5435
5436/* List of supported image types. Use define_image_type to add new
5437 types. Use lookup_image_type to find a type for a given symbol. */
5438
5439static struct image_type *image_types;
5440
333b20bb
GM
5441/* The symbol `image' which is the car of the lists used to represent
5442 images in Lisp. */
5443
5444extern Lisp_Object Qimage;
5445
5446/* The symbol `xbm' which is used as the type symbol for XBM images. */
5447
5448Lisp_Object Qxbm;
5449
5450/* Keywords. */
5451
0fe92f72 5452extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
90ebdb19
GM
5453extern Lisp_Object QCdata;
5454Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
d2dc8167 5455Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4a8e312c 5456Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
333b20bb
GM
5457
5458/* Other symbols. */
5459
4a8e312c 5460Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
333b20bb
GM
5461
5462/* Time in seconds after which images should be removed from the cache
5463 if not displayed. */
5464
fcf431dc 5465Lisp_Object Vimage_cache_eviction_delay;
333b20bb
GM
5466
5467/* Function prototypes. */
5468
5469static void define_image_type P_ ((struct image_type *type));
5470static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
5471static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
5472static void x_laplace P_ ((struct frame *, struct image *));
4a8e312c 5473static void x_emboss P_ ((struct frame *, struct image *));
45158a91
GM
5474static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
5475 Lisp_Object));
333b20bb
GM
5476
5477
5478/* Define a new image type from TYPE. This adds a copy of TYPE to
5479 image_types and adds the symbol *TYPE->type to Vimage_types. */
5480
5481static void
5482define_image_type (type)
5483 struct image_type *type;
5484{
5485 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
5486 The initialized data segment is read-only. */
5487 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
5488 bcopy (type, p, sizeof *p);
5489 p->next = image_types;
5490 image_types = p;
5491 Vimage_types = Fcons (*p->type, Vimage_types);
5492}
5493
5494
5495/* Look up image type SYMBOL, and return a pointer to its image_type
5496 structure. Value is null if SYMBOL is not a known image type. */
5497
5498static INLINE struct image_type *
5499lookup_image_type (symbol)
5500 Lisp_Object symbol;
5501{
5502 struct image_type *type;
5503
5504 for (type = image_types; type; type = type->next)
5505 if (EQ (symbol, *type->type))
5506 break;
5507
5508 return type;
5509}
5510
5511
5512/* Value is non-zero if OBJECT is a valid Lisp image specification. A
5513 valid image specification is a list whose car is the symbol
5514 `image', and whose rest is a property list. The property list must
5515 contain a value for key `:type'. That value must be the name of a
5516 supported image type. The rest of the property list depends on the
5517 image type. */
5518
5519int
5520valid_image_p (object)
5521 Lisp_Object object;
5522{
5523 int valid_p = 0;
5524
5525 if (CONSP (object) && EQ (XCAR (object), Qimage))
5526 {
1783ffa2
GM
5527 Lisp_Object tem;
5528
5529 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
5530 if (EQ (XCAR (tem), QCtype))
5531 {
5532 tem = XCDR (tem);
5533 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
5534 {
5535 struct image_type *type;
5536 type = lookup_image_type (XCAR (tem));
5537 if (type)
5538 valid_p = type->valid_p (object);
5539 }
5540
5541 break;
5542 }
333b20bb
GM
5543 }
5544
5545 return valid_p;
5546}
5547
5548
7ab1745f
GM
5549/* Log error message with format string FORMAT and argument ARG.
5550 Signaling an error, e.g. when an image cannot be loaded, is not a
5551 good idea because this would interrupt redisplay, and the error
5552 message display would lead to another redisplay. This function
5553 therefore simply displays a message. */
333b20bb
GM
5554
5555static void
5556image_error (format, arg1, arg2)
5557 char *format;
5558 Lisp_Object arg1, arg2;
5559{
7ab1745f 5560 add_to_log (format, arg1, arg2);
333b20bb
GM
5561}
5562
5563
5564\f
5565/***********************************************************************
5566 Image specifications
5567 ***********************************************************************/
5568
5569enum image_value_type
5570{
5571 IMAGE_DONT_CHECK_VALUE_TYPE,
5572 IMAGE_STRING_VALUE,
6f1be3b9 5573 IMAGE_STRING_OR_NIL_VALUE,
333b20bb
GM
5574 IMAGE_SYMBOL_VALUE,
5575 IMAGE_POSITIVE_INTEGER_VALUE,
3ed61e75 5576 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
333b20bb 5577 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7c7ff7f5 5578 IMAGE_ASCENT_VALUE,
333b20bb
GM
5579 IMAGE_INTEGER_VALUE,
5580 IMAGE_FUNCTION_VALUE,
5581 IMAGE_NUMBER_VALUE,
5582 IMAGE_BOOL_VALUE
5583};
5584
5585/* Structure used when parsing image specifications. */
5586
5587struct image_keyword
5588{
5589 /* Name of keyword. */
5590 char *name;
5591
5592 /* The type of value allowed. */
5593 enum image_value_type type;
5594
5595 /* Non-zero means key must be present. */
5596 int mandatory_p;
5597
5598 /* Used to recognize duplicate keywords in a property list. */
5599 int count;
5600
5601 /* The value that was found. */
5602 Lisp_Object value;
5603};
5604
5605
bfd2209f
GM
5606static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
5607 int, Lisp_Object));
333b20bb
GM
5608static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
5609
5610
5611/* Parse image spec SPEC according to KEYWORDS. A valid image spec
5612 has the format (image KEYWORD VALUE ...). One of the keyword/
5613 value pairs must be `:type TYPE'. KEYWORDS is a vector of
5614 image_keywords structures of size NKEYWORDS describing other
bfd2209f 5615 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
333b20bb
GM
5616
5617static int
bfd2209f 5618parse_image_spec (spec, keywords, nkeywords, type)
333b20bb
GM
5619 Lisp_Object spec;
5620 struct image_keyword *keywords;
5621 int nkeywords;
5622 Lisp_Object type;
333b20bb
GM
5623{
5624 int i;
5625 Lisp_Object plist;
5626
5627 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
5628 return 0;
5629
5630 plist = XCDR (spec);
5631 while (CONSP (plist))
5632 {
5633 Lisp_Object key, value;
5634
5635 /* First element of a pair must be a symbol. */
5636 key = XCAR (plist);
5637 plist = XCDR (plist);
5638 if (!SYMBOLP (key))
5639 return 0;
5640
5641 /* There must follow a value. */
5642 if (!CONSP (plist))
5643 return 0;
5644 value = XCAR (plist);
5645 plist = XCDR (plist);
5646
5647 /* Find key in KEYWORDS. Error if not found. */
5648 for (i = 0; i < nkeywords; ++i)
5649 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
5650 break;
5651
5652 if (i == nkeywords)
bfd2209f 5653 continue;
333b20bb
GM
5654
5655 /* Record that we recognized the keyword. If a keywords
5656 was found more than once, it's an error. */
5657 keywords[i].value = value;
5658 ++keywords[i].count;
5659
5660 if (keywords[i].count > 1)
5661 return 0;
5662
5663 /* Check type of value against allowed type. */
5664 switch (keywords[i].type)
5665 {
5666 case IMAGE_STRING_VALUE:
5667 if (!STRINGP (value))
5668 return 0;
5669 break;
5670
6f1be3b9
GM
5671 case IMAGE_STRING_OR_NIL_VALUE:
5672 if (!STRINGP (value) && !NILP (value))
5673 return 0;
5674 break;
5675
333b20bb
GM
5676 case IMAGE_SYMBOL_VALUE:
5677 if (!SYMBOLP (value))
5678 return 0;
5679 break;
5680
5681 case IMAGE_POSITIVE_INTEGER_VALUE:
5682 if (!INTEGERP (value) || XINT (value) <= 0)
5683 return 0;
5684 break;
5685
3ed61e75
GM
5686 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
5687 if (INTEGERP (value) && XINT (value) >= 0)
5688 break;
5689 if (CONSP (value)
5690 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
5691 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
5692 break;
5693 return 0;
5694
7c7ff7f5
GM
5695 case IMAGE_ASCENT_VALUE:
5696 if (SYMBOLP (value) && EQ (value, Qcenter))
5697 break;
5698 else if (INTEGERP (value)
5699 && XINT (value) >= 0
5700 && XINT (value) <= 100)
5701 break;
5702 return 0;
5703
333b20bb
GM
5704 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
5705 if (!INTEGERP (value) || XINT (value) < 0)
5706 return 0;
5707 break;
5708
5709 case IMAGE_DONT_CHECK_VALUE_TYPE:
5710 break;
5711
5712 case IMAGE_FUNCTION_VALUE:
5713 value = indirect_function (value);
5714 if (SUBRP (value)
5715 || COMPILEDP (value)
5716 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
5717 break;
5718 return 0;
5719
5720 case IMAGE_NUMBER_VALUE:
5721 if (!INTEGERP (value) && !FLOATP (value))
5722 return 0;
5723 break;
5724
5725 case IMAGE_INTEGER_VALUE:
5726 if (!INTEGERP (value))
5727 return 0;
5728 break;
5729
5730 case IMAGE_BOOL_VALUE:
5731 if (!NILP (value) && !EQ (value, Qt))
5732 return 0;
5733 break;
5734
5735 default:
5736 abort ();
5737 break;
5738 }
5739
5740 if (EQ (key, QCtype) && !EQ (type, value))
5741 return 0;
5742 }
5743
5744 /* Check that all mandatory fields are present. */
5745 for (i = 0; i < nkeywords; ++i)
5746 if (keywords[i].mandatory_p && keywords[i].count == 0)
5747 return 0;
5748
5749 return NILP (plist);
5750}
5751
5752
5753/* Return the value of KEY in image specification SPEC. Value is nil
5754 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
5755 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
5756
5757static Lisp_Object
5758image_spec_value (spec, key, found)
5759 Lisp_Object spec, key;
5760 int *found;
5761{
5762 Lisp_Object tail;
5763
5764 xassert (valid_image_p (spec));
5765
5766 for (tail = XCDR (spec);
5767 CONSP (tail) && CONSP (XCDR (tail));
5768 tail = XCDR (XCDR (tail)))
5769 {
5770 if (EQ (XCAR (tail), key))
5771 {
5772 if (found)
5773 *found = 1;
5774 return XCAR (XCDR (tail));
5775 }
5776 }
5777
5778 if (found)
5779 *found = 0;
5780 return Qnil;
5781}
5782
5783
42677916 5784DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
7ee72033 5785 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
c061c855
GM
5786PIXELS non-nil means return the size in pixels, otherwise return the
5787size in canonical character units.
5788FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5789or omitted means use the selected frame. */)
5790 (spec, pixels, frame)
42677916
GM
5791 Lisp_Object spec, pixels, frame;
5792{
5793 Lisp_Object size;
5794
5795 size = Qnil;
5796 if (valid_image_p (spec))
5797 {
5798 struct frame *f = check_x_frame (frame);
83676598 5799 int id = lookup_image (f, spec);
42677916 5800 struct image *img = IMAGE_FROM_ID (f, id);
3ed61e75
GM
5801 int width = img->width + 2 * img->hmargin;
5802 int height = img->height + 2 * img->vmargin;
42677916
GM
5803
5804 if (NILP (pixels))
5805 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
5806 make_float ((double) height / CANON_Y_UNIT (f)));
5807 else
5808 size = Fcons (make_number (width), make_number (height));
5809 }
5810 else
5811 error ("Invalid image specification");
5812
5813 return size;
5814}
5815
333b20bb 5816
b243755a 5817DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
7ee72033 5818 doc: /* Return t if image SPEC has a mask bitmap.
c061c855 5819FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5820or omitted means use the selected frame. */)
5821 (spec, frame)
b243755a
GM
5822 Lisp_Object spec, frame;
5823{
5824 Lisp_Object mask;
5825
5826 mask = Qnil;
5827 if (valid_image_p (spec))
5828 {
5829 struct frame *f = check_x_frame (frame);
83676598 5830 int id = lookup_image (f, spec);
b243755a
GM
5831 struct image *img = IMAGE_FROM_ID (f, id);
5832 if (img->mask)
5833 mask = Qt;
5834 }
5835 else
5836 error ("Invalid image specification");
5837
5838 return mask;
5839}
5840
5841
333b20bb
GM
5842\f
5843/***********************************************************************
5844 Image type independent image structures
5845 ***********************************************************************/
5846
5847static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
5848static void free_image P_ ((struct frame *f, struct image *img));
5849
5850
5851/* Allocate and return a new image structure for image specification
5852 SPEC. SPEC has a hash value of HASH. */
5853
5854static struct image *
5855make_image (spec, hash)
5856 Lisp_Object spec;
5857 unsigned hash;
5858{
5859 struct image *img = (struct image *) xmalloc (sizeof *img);
5860
5861 xassert (valid_image_p (spec));
5862 bzero (img, sizeof *img);
5863 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
5864 xassert (img->type != NULL);
5865 img->spec = spec;
5866 img->data.lisp_val = Qnil;
5867 img->ascent = DEFAULT_IMAGE_ASCENT;
5868 img->hash = hash;
5869 return img;
5870}
5871
5872
5873/* Free image IMG which was used on frame F, including its resources. */
5874
5875static void
5876free_image (f, img)
5877 struct frame *f;
5878 struct image *img;
5879{
5880 if (img)
5881 {
5882 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5883
5884 /* Remove IMG from the hash table of its cache. */
5885 if (img->prev)
5886 img->prev->next = img->next;
5887 else
5888 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
5889
5890 if (img->next)
5891 img->next->prev = img->prev;
5892
5893 c->images[img->id] = NULL;
5894
5895 /* Free resources, then free IMG. */
5896 img->type->free (f, img);
5897 xfree (img);
5898 }
5899}
5900
5901
5902/* Prepare image IMG for display on frame F. Must be called before
5903 drawing an image. */
5904
5905void
5906prepare_image_for_display (f, img)
5907 struct frame *f;
5908 struct image *img;
5909{
5910 EMACS_TIME t;
5911
5912 /* We're about to display IMG, so set its timestamp to `now'. */
5913 EMACS_GET_TIME (t);
5914 img->timestamp = EMACS_SECS (t);
5915
5916 /* If IMG doesn't have a pixmap yet, load it now, using the image
5917 type dependent loader function. */
dd00328a 5918 if (img->pixmap == None && !img->load_failed_p)
209061be 5919 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
5920}
5921
5922
7c7ff7f5
GM
5923/* Value is the number of pixels for the ascent of image IMG when
5924 drawn in face FACE. */
5925
5926int
5927image_ascent (img, face)
5928 struct image *img;
5929 struct face *face;
5930{
3ed61e75 5931 int height = img->height + img->vmargin;
7c7ff7f5
GM
5932 int ascent;
5933
5934 if (img->ascent == CENTERED_IMAGE_ASCENT)
5935 {
5936 if (face->font)
3694cb3f
MB
5937 /* This expression is arranged so that if the image can't be
5938 exactly centered, it will be moved slightly up. This is
5939 because a typical font is `top-heavy' (due to the presence
5940 uppercase letters), so the image placement should err towards
5941 being top-heavy too. It also just generally looks better. */
5942 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
7c7ff7f5
GM
5943 else
5944 ascent = height / 2;
5945 }
5946 else
5947 ascent = height * img->ascent / 100.0;
5948
5949 return ascent;
5950}
5951
f20a3b7a
MB
5952\f
5953/* Image background colors. */
5954
5955static unsigned long
5956four_corners_best (ximg, width, height)
5957 XImage *ximg;
5958 unsigned long width, height;
5959{
b350c2e5
GM
5960 unsigned long corners[4], best;
5961 int i, best_count;
f20a3b7a 5962
b350c2e5
GM
5963 /* Get the colors at the corners of ximg. */
5964 corners[0] = XGetPixel (ximg, 0, 0);
5965 corners[1] = XGetPixel (ximg, width - 1, 0);
5966 corners[2] = XGetPixel (ximg, width - 1, height - 1);
5967 corners[3] = XGetPixel (ximg, 0, height - 1);
f20a3b7a 5968
b350c2e5
GM
5969 /* Choose the most frequently found color as background. */
5970 for (i = best_count = 0; i < 4; ++i)
5971 {
5972 int j, n;
f20a3b7a 5973
b350c2e5
GM
5974 for (j = n = 0; j < 4; ++j)
5975 if (corners[i] == corners[j])
5976 ++n;
f20a3b7a 5977
b350c2e5
GM
5978 if (n > best_count)
5979 best = corners[i], best_count = n;
5980 }
f20a3b7a 5981
b350c2e5 5982 return best;
f20a3b7a
MB
5983}
5984
5985/* Return the `background' field of IMG. If IMG doesn't have one yet,
5986 it is guessed heuristically. If non-zero, XIMG is an existing XImage
5987 object to use for the heuristic. */
5988
5989unsigned long
5990image_background (img, f, ximg)
5991 struct image *img;
5992 struct frame *f;
5993 XImage *ximg;
5994{
5995 if (! img->background_valid)
5996 /* IMG doesn't have a background yet, try to guess a reasonable value. */
5997 {
5998 int free_ximg = !ximg;
5999
6000 if (! ximg)
6001 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
6002 0, 0, img->width, img->height, ~0, ZPixmap);
6003
6004 img->background = four_corners_best (ximg, img->width, img->height);
6005
6006 if (free_ximg)
6007 XDestroyImage (ximg);
6008
6009 img->background_valid = 1;
6010 }
6011
6012 return img->background;
6013}
6014
6015/* Return the `background_transparent' field of IMG. If IMG doesn't
6016 have one yet, it is guessed heuristically. If non-zero, MASK is an
6017 existing XImage object to use for the heuristic. */
6018
6019int
6020image_background_transparent (img, f, mask)
6021 struct image *img;
6022 struct frame *f;
6023 XImage *mask;
6024{
6025 if (! img->background_transparent_valid)
6026 /* IMG doesn't have a background yet, try to guess a reasonable value. */
6027 {
6028 if (img->mask)
6029 {
6030 int free_mask = !mask;
6031
6032 if (! mask)
6033 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
6034 0, 0, img->width, img->height, ~0, ZPixmap);
6035
6036 img->background_transparent
6037 = !four_corners_best (mask, img->width, img->height);
6038
6039 if (free_mask)
6040 XDestroyImage (mask);
6041 }
6042 else
6043 img->background_transparent = 0;
6044
6045 img->background_transparent_valid = 1;
6046 }
6047
6048 return img->background_transparent;
6049}
7c7ff7f5 6050
333b20bb
GM
6051\f
6052/***********************************************************************
6053 Helper functions for X image types
6054 ***********************************************************************/
6055
dd00328a
GM
6056static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
6057 int, int));
333b20bb
GM
6058static void x_clear_image P_ ((struct frame *f, struct image *img));
6059static unsigned long x_alloc_image_color P_ ((struct frame *f,
6060 struct image *img,
6061 Lisp_Object color_name,
6062 unsigned long dflt));
6063
dd00328a
GM
6064
6065/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
6066 free the pixmap if any. MASK_P non-zero means clear the mask
6067 pixmap if any. COLORS_P non-zero means free colors allocated for
6068 the image, if any. */
333b20bb
GM
6069
6070static void
dd00328a 6071x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
333b20bb
GM
6072 struct frame *f;
6073 struct image *img;
dd00328a 6074 int pixmap_p, mask_p, colors_p;
333b20bb 6075{
dd00328a 6076 if (pixmap_p && img->pixmap)
333b20bb 6077 {
333b20bb 6078 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 6079 img->pixmap = None;
f20a3b7a 6080 img->background_valid = 0;
f4779de9
GM
6081 }
6082
dd00328a 6083 if (mask_p && img->mask)
f4779de9
GM
6084 {
6085 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 6086 img->mask = None;
f20a3b7a 6087 img->background_transparent_valid = 0;
333b20bb
GM
6088 }
6089
dd00328a 6090 if (colors_p && img->ncolors)
333b20bb 6091 {
462d5d40 6092 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
6093 xfree (img->colors);
6094 img->colors = NULL;
6095 img->ncolors = 0;
6096 }
dd00328a
GM
6097}
6098
6099/* Free X resources of image IMG which is used on frame F. */
6100
6101static void
6102x_clear_image (f, img)
6103 struct frame *f;
6104 struct image *img;
6105{
6106 BLOCK_INPUT;
6107 x_clear_image_1 (f, img, 1, 1, 1);
f4779de9 6108 UNBLOCK_INPUT;
333b20bb
GM
6109}
6110
6111
6112/* Allocate color COLOR_NAME for image IMG on frame F. If color
6113 cannot be allocated, use DFLT. Add a newly allocated color to
6114 IMG->colors, so that it can be freed again. Value is the pixel
6115 color. */
6116
6117static unsigned long
6118x_alloc_image_color (f, img, color_name, dflt)
6119 struct frame *f;
6120 struct image *img;
6121 Lisp_Object color_name;
6122 unsigned long dflt;
6123{
6124 XColor color;
6125 unsigned long result;
6126
6127 xassert (STRINGP (color_name));
6128
2d764c78 6129 if (x_defined_color (f, XSTRING (color_name)->data, &color, 1))
333b20bb
GM
6130 {
6131 /* This isn't called frequently so we get away with simply
6132 reallocating the color vector to the needed size, here. */
6133 ++img->ncolors;
6134 img->colors =
6135 (unsigned long *) xrealloc (img->colors,
6136 img->ncolors * sizeof *img->colors);
6137 img->colors[img->ncolors - 1] = color.pixel;
6138 result = color.pixel;
6139 }
6140 else
6141 result = dflt;
6142
6143 return result;
6144}
6145
6146
6147\f
6148/***********************************************************************
6149 Image Cache
6150 ***********************************************************************/
6151
6152static void cache_image P_ ((struct frame *f, struct image *img));
ad18ffb1 6153static void postprocess_image P_ ((struct frame *, struct image *));
333b20bb
GM
6154
6155
6156/* Return a new, initialized image cache that is allocated from the
6157 heap. Call free_image_cache to free an image cache. */
6158
6159struct image_cache *
6160make_image_cache ()
6161{
6162 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
6163 int size;
6164
6165 bzero (c, sizeof *c);
6166 c->size = 50;
6167 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
6168 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
6169 c->buckets = (struct image **) xmalloc (size);
6170 bzero (c->buckets, size);
6171 return c;
6172}
6173
6174
6175/* Free image cache of frame F. Be aware that X frames share images
6176 caches. */
6177
6178void
6179free_image_cache (f)
6180 struct frame *f;
6181{
6182 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6183 if (c)
6184 {
6185 int i;
6186
6187 /* Cache should not be referenced by any frame when freed. */
6188 xassert (c->refcount == 0);
6189
6190 for (i = 0; i < c->used; ++i)
6191 free_image (f, c->images[i]);
6192 xfree (c->images);
333b20bb 6193 xfree (c->buckets);
e3130015 6194 xfree (c);
333b20bb
GM
6195 FRAME_X_IMAGE_CACHE (f) = NULL;
6196 }
6197}
6198
6199
6200/* Clear image cache of frame F. FORCE_P non-zero means free all
6201 images. FORCE_P zero means clear only images that haven't been
6202 displayed for some time. Should be called from time to time to
6203 reduce the number of loaded images. If image-eviction-seconds is
6204 non-nil, this frees images in the cache which weren't displayed for
6205 at least that many seconds. */
6206
6207void
6208clear_image_cache (f, force_p)
6209 struct frame *f;
6210 int force_p;
6211{
6212 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6213
83676598 6214 if (c && INTEGERP (Vimage_cache_eviction_delay))
333b20bb
GM
6215 {
6216 EMACS_TIME t;
6217 unsigned long old;
f4779de9 6218 int i, nfreed;
333b20bb
GM
6219
6220 EMACS_GET_TIME (t);
fcf431dc 6221 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
f4779de9
GM
6222
6223 /* Block input so that we won't be interrupted by a SIGIO
6224 while being in an inconsistent state. */
6225 BLOCK_INPUT;
333b20bb 6226
f4779de9 6227 for (i = nfreed = 0; i < c->used; ++i)
333b20bb
GM
6228 {
6229 struct image *img = c->images[i];
6230 if (img != NULL
f4779de9 6231 && (force_p || img->timestamp < old))
333b20bb
GM
6232 {
6233 free_image (f, img);
f4779de9 6234 ++nfreed;
333b20bb
GM
6235 }
6236 }
6237
6238 /* We may be clearing the image cache because, for example,
6239 Emacs was iconified for a longer period of time. In that
6240 case, current matrices may still contain references to
6241 images freed above. So, clear these matrices. */
f4779de9 6242 if (nfreed)
333b20bb 6243 {
f4779de9
GM
6244 Lisp_Object tail, frame;
6245
6246 FOR_EACH_FRAME (tail, frame)
6247 {
6248 struct frame *f = XFRAME (frame);
6249 if (FRAME_X_P (f)
6250 && FRAME_X_IMAGE_CACHE (f) == c)
83676598 6251 clear_current_matrices (f);
f4779de9
GM
6252 }
6253
333b20bb
GM
6254 ++windows_or_buffers_changed;
6255 }
f4779de9
GM
6256
6257 UNBLOCK_INPUT;
333b20bb
GM
6258 }
6259}
6260
6261
6262DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6263 0, 1, 0,
7ee72033 6264 doc: /* Clear the image cache of FRAME.
c061c855 6265FRAME nil or omitted means use the selected frame.
7ee72033
MB
6266FRAME t means clear the image caches of all frames. */)
6267 (frame)
333b20bb
GM
6268 Lisp_Object frame;
6269{
6270 if (EQ (frame, Qt))
6271 {
6272 Lisp_Object tail;
6273
6274 FOR_EACH_FRAME (tail, frame)
6275 if (FRAME_X_P (XFRAME (frame)))
6276 clear_image_cache (XFRAME (frame), 1);
6277 }
6278 else
6279 clear_image_cache (check_x_frame (frame), 1);
6280
6281 return Qnil;
6282}
6283
6284
ad18ffb1
GM
6285/* Compute masks and transform image IMG on frame F, as specified
6286 by the image's specification, */
6287
6288static void
6289postprocess_image (f, img)
6290 struct frame *f;
6291 struct image *img;
6292{
6293 /* Manipulation of the image's mask. */
6294 if (img->pixmap)
6295 {
6296 Lisp_Object conversion, spec;
6297 Lisp_Object mask;
6298
6299 spec = img->spec;
6300
6301 /* `:heuristic-mask t'
6302 `:mask heuristic'
6303 means build a mask heuristically.
6304 `:heuristic-mask (R G B)'
6305 `:mask (heuristic (R G B))'
6306 means build a mask from color (R G B) in the
6307 image.
6308 `:mask nil'
6309 means remove a mask, if any. */
6310
6311 mask = image_spec_value (spec, QCheuristic_mask, NULL);
6312 if (!NILP (mask))
6313 x_build_heuristic_mask (f, img, mask);
6314 else
6315 {
6316 int found_p;
6317
6318 mask = image_spec_value (spec, QCmask, &found_p);
6319
6320 if (EQ (mask, Qheuristic))
6321 x_build_heuristic_mask (f, img, Qt);
6322 else if (CONSP (mask)
6323 && EQ (XCAR (mask), Qheuristic))
6324 {
6325 if (CONSP (XCDR (mask)))
6326 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
6327 else
6328 x_build_heuristic_mask (f, img, XCDR (mask));
6329 }
6330 else if (NILP (mask) && found_p && img->mask)
6331 {
6332 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6333 img->mask = None;
6334 }
6335 }
6336
6337
6338 /* Should we apply an image transformation algorithm? */
6339 conversion = image_spec_value (spec, QCconversion, NULL);
6340 if (EQ (conversion, Qdisabled))
6341 x_disable_image (f, img);
6342 else if (EQ (conversion, Qlaplace))
6343 x_laplace (f, img);
6344 else if (EQ (conversion, Qemboss))
6345 x_emboss (f, img);
6346 else if (CONSP (conversion)
6347 && EQ (XCAR (conversion), Qedge_detection))
6348 {
6349 Lisp_Object tem;
6350 tem = XCDR (conversion);
6351 if (CONSP (tem))
6352 x_edge_detection (f, img,
6353 Fplist_get (tem, QCmatrix),
6354 Fplist_get (tem, QCcolor_adjustment));
6355 }
6356 }
6357}
6358
6359
333b20bb 6360/* Return the id of image with Lisp specification SPEC on frame F.
83676598 6361 SPEC must be a valid Lisp image specification (see valid_image_p). */
333b20bb
GM
6362
6363int
83676598 6364lookup_image (f, spec)
333b20bb
GM
6365 struct frame *f;
6366 Lisp_Object spec;
6367{
6368 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6369 struct image *img;
6370 int i;
6371 unsigned hash;
6372 struct gcpro gcpro1;
4f7ca1f1 6373 EMACS_TIME now;
333b20bb
GM
6374
6375 /* F must be a window-system frame, and SPEC must be a valid image
6376 specification. */
6377 xassert (FRAME_WINDOW_P (f));
6378 xassert (valid_image_p (spec));
6379
6380 GCPRO1 (spec);
6381
6382 /* Look up SPEC in the hash table of the image cache. */
6383 hash = sxhash (spec, 0);
6384 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6385
6386 for (img = c->buckets[i]; img; img = img->next)
6387 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6388 break;
6389
6390 /* If not found, create a new image and cache it. */
6391 if (img == NULL)
6392 {
ad18ffb1
GM
6393 extern Lisp_Object Qpostscript;
6394
28c7826c 6395 BLOCK_INPUT;
333b20bb
GM
6396 img = make_image (spec, hash);
6397 cache_image (f, img);
83676598 6398 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
6399
6400 /* If we can't load the image, and we don't have a width and
6401 height, use some arbitrary width and height so that we can
6402 draw a rectangle for it. */
83676598 6403 if (img->load_failed_p)
333b20bb
GM
6404 {
6405 Lisp_Object value;
6406
6407 value = image_spec_value (spec, QCwidth, NULL);
6408 img->width = (INTEGERP (value)
6409 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6410 value = image_spec_value (spec, QCheight, NULL);
6411 img->height = (INTEGERP (value)
6412 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6413 }
6414 else
6415 {
6416 /* Handle image type independent image attributes
f20a3b7a
MB
6417 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
6418 `:background COLOR'. */
6419 Lisp_Object ascent, margin, relief, bg;
333b20bb
GM
6420
6421 ascent = image_spec_value (spec, QCascent, NULL);
6422 if (INTEGERP (ascent))
6423 img->ascent = XFASTINT (ascent);
7c7ff7f5
GM
6424 else if (EQ (ascent, Qcenter))
6425 img->ascent = CENTERED_IMAGE_ASCENT;
333b20bb
GM
6426
6427 margin = image_spec_value (spec, QCmargin, NULL);
6428 if (INTEGERP (margin) && XINT (margin) >= 0)
3ed61e75
GM
6429 img->vmargin = img->hmargin = XFASTINT (margin);
6430 else if (CONSP (margin) && INTEGERP (XCAR (margin))
6431 && INTEGERP (XCDR (margin)))
6432 {
6433 if (XINT (XCAR (margin)) > 0)
6434 img->hmargin = XFASTINT (XCAR (margin));
6435 if (XINT (XCDR (margin)) > 0)
6436 img->vmargin = XFASTINT (XCDR (margin));
6437 }
333b20bb
GM
6438
6439 relief = image_spec_value (spec, QCrelief, NULL);
6440 if (INTEGERP (relief))
6441 {
6442 img->relief = XINT (relief);
3ed61e75
GM
6443 img->hmargin += abs (img->relief);
6444 img->vmargin += abs (img->relief);
333b20bb
GM
6445 }
6446
f20a3b7a
MB
6447 if (! img->background_valid)
6448 {
6449 bg = image_spec_value (img->spec, QCbackground, NULL);
6450 if (!NILP (bg))
6451 {
6452 img->background
6453 = x_alloc_image_color (f, img, bg,
6454 FRAME_BACKGROUND_PIXEL (f));
6455 img->background_valid = 1;
6456 }
6457 }
6458
ad18ffb1
GM
6459 /* Do image transformations and compute masks, unless we
6460 don't have the image yet. */
6461 if (!EQ (*img->type->type, Qpostscript))
6462 postprocess_image (f, img);
333b20bb 6463 }
dd00328a 6464
28c7826c
GM
6465 UNBLOCK_INPUT;
6466 xassert (!interrupt_input_blocked);
333b20bb
GM
6467 }
6468
4f7ca1f1
GM
6469 /* We're using IMG, so set its timestamp to `now'. */
6470 EMACS_GET_TIME (now);
6471 img->timestamp = EMACS_SECS (now);
6472
333b20bb
GM
6473 UNGCPRO;
6474
6475 /* Value is the image id. */
6476 return img->id;
6477}
6478
6479
6480/* Cache image IMG in the image cache of frame F. */
6481
6482static void
6483cache_image (f, img)
6484 struct frame *f;
6485 struct image *img;
6486{
6487 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6488 int i;
6489
6490 /* Find a free slot in c->images. */
6491 for (i = 0; i < c->used; ++i)
6492 if (c->images[i] == NULL)
6493 break;
6494
6495 /* If no free slot found, maybe enlarge c->images. */
6496 if (i == c->used && c->used == c->size)
6497 {
6498 c->size *= 2;
6499 c->images = (struct image **) xrealloc (c->images,
6500 c->size * sizeof *c->images);
6501 }
6502
6503 /* Add IMG to c->images, and assign IMG an id. */
6504 c->images[i] = img;
6505 img->id = i;
6506 if (i == c->used)
6507 ++c->used;
6508
6509 /* Add IMG to the cache's hash table. */
6510 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6511 img->next = c->buckets[i];
6512 if (img->next)
6513 img->next->prev = img;
6514 img->prev = NULL;
6515 c->buckets[i] = img;
6516}
6517
6518
6519/* Call FN on every image in the image cache of frame F. Used to mark
6520 Lisp Objects in the image cache. */
6521
6522void
6523forall_images_in_image_cache (f, fn)
6524 struct frame *f;
6525 void (*fn) P_ ((struct image *img));
6526{
6527 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6528 {
6529 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6530 if (c)
6531 {
6532 int i;
6533 for (i = 0; i < c->used; ++i)
6534 if (c->images[i])
6535 fn (c->images[i]);
6536 }
6537 }
6538}
6539
6540
6541\f
6542/***********************************************************************
6543 X support code
6544 ***********************************************************************/
6545
45158a91
GM
6546static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
6547 XImage **, Pixmap *));
333b20bb
GM
6548static void x_destroy_x_image P_ ((XImage *));
6549static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6550
6551
6552/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6553 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6554 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6555 via xmalloc. Print error messages via image_error if an error
45158a91 6556 occurs. Value is non-zero if successful. */
333b20bb
GM
6557
6558static int
45158a91 6559x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
333b20bb 6560 struct frame *f;
333b20bb
GM
6561 int width, height, depth;
6562 XImage **ximg;
6563 Pixmap *pixmap;
6564{
6565 Display *display = FRAME_X_DISPLAY (f);
6566 Screen *screen = FRAME_X_SCREEN (f);
6567 Window window = FRAME_X_WINDOW (f);
6568
6569 xassert (interrupt_input_blocked);
6570
6571 if (depth <= 0)
6572 depth = DefaultDepthOfScreen (screen);
6573 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6574 depth, ZPixmap, 0, NULL, width, height,
6575 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6576 if (*ximg == NULL)
6577 {
45158a91 6578 image_error ("Unable to allocate X image", Qnil, Qnil);
333b20bb
GM
6579 return 0;
6580 }
6581
6582 /* Allocate image raster. */
6583 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6584
6585 /* Allocate a pixmap of the same size. */
6586 *pixmap = XCreatePixmap (display, window, width, height, depth);
dd00328a 6587 if (*pixmap == None)
333b20bb
GM
6588 {
6589 x_destroy_x_image (*ximg);
6590 *ximg = NULL;
45158a91 6591 image_error ("Unable to create X pixmap", Qnil, Qnil);
333b20bb
GM
6592 return 0;
6593 }
6594
6595 return 1;
6596}
6597
6598
6599/* Destroy XImage XIMG. Free XIMG->data. */
6600
6601static void
6602x_destroy_x_image (ximg)
6603 XImage *ximg;
6604{
6605 xassert (interrupt_input_blocked);
6606 if (ximg)
6607 {
6608 xfree (ximg->data);
6609 ximg->data = NULL;
6610 XDestroyImage (ximg);
6611 }
6612}
6613
6614
6615/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6616 are width and height of both the image and pixmap. */
6617
ea6b19ca 6618static void
333b20bb
GM
6619x_put_x_image (f, ximg, pixmap, width, height)
6620 struct frame *f;
6621 XImage *ximg;
6622 Pixmap pixmap;
6623{
6624 GC gc;
6625
6626 xassert (interrupt_input_blocked);
6627 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6628 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6629 XFreeGC (FRAME_X_DISPLAY (f), gc);
6630}
6631
6632
6633\f
6634/***********************************************************************
5be6c3b0 6635 File Handling
333b20bb
GM
6636 ***********************************************************************/
6637
6638static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5be6c3b0
GM
6639static char *slurp_file P_ ((char *, int *));
6640
333b20bb
GM
6641
6642/* Find image file FILE. Look in data-directory, then
6643 x-bitmap-file-path. Value is the full name of the file found, or
6644 nil if not found. */
6645
6646static Lisp_Object
6647x_find_image_file (file)
6648 Lisp_Object file;
6649{
6650 Lisp_Object file_found, search_path;
6651 struct gcpro gcpro1, gcpro2;
6652 int fd;
6653
6654 file_found = Qnil;
6655 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6656 GCPRO2 (file_found, search_path);
6657
6658 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 6659 fd = openp (search_path, file, Qnil, &file_found, 0);
333b20bb 6660
939d6465 6661 if (fd == -1)
333b20bb
GM
6662 file_found = Qnil;
6663 else
6664 close (fd);
6665
6666 UNGCPRO;
6667 return file_found;
6668}
6669
6670
5be6c3b0
GM
6671/* Read FILE into memory. Value is a pointer to a buffer allocated
6672 with xmalloc holding FILE's contents. Value is null if an error
b243755a 6673 occurred. *SIZE is set to the size of the file. */
5be6c3b0
GM
6674
6675static char *
6676slurp_file (file, size)
6677 char *file;
6678 int *size;
6679{
6680 FILE *fp = NULL;
6681 char *buf = NULL;
6682 struct stat st;
6683
6684 if (stat (file, &st) == 0
6685 && (fp = fopen (file, "r")) != NULL
6686 && (buf = (char *) xmalloc (st.st_size),
6687 fread (buf, 1, st.st_size, fp) == st.st_size))
6688 {
6689 *size = st.st_size;
6690 fclose (fp);
6691 }
6692 else
6693 {
6694 if (fp)
6695 fclose (fp);
6696 if (buf)
6697 {
6698 xfree (buf);
6699 buf = NULL;
6700 }
6701 }
6702
6703 return buf;
6704}
6705
6706
333b20bb
GM
6707\f
6708/***********************************************************************
6709 XBM images
6710 ***********************************************************************/
6711
5be6c3b0 6712static int xbm_scan P_ ((char **, char *, char *, int *));
333b20bb 6713static int xbm_load P_ ((struct frame *f, struct image *img));
5be6c3b0
GM
6714static int xbm_load_image P_ ((struct frame *f, struct image *img,
6715 char *, char *));
333b20bb 6716static int xbm_image_p P_ ((Lisp_Object object));
5be6c3b0
GM
6717static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
6718 unsigned char **));
6719static int xbm_file_p P_ ((Lisp_Object));
333b20bb
GM
6720
6721
6722/* Indices of image specification fields in xbm_format, below. */
6723
6724enum xbm_keyword_index
6725{
6726 XBM_TYPE,
6727 XBM_FILE,
6728 XBM_WIDTH,
6729 XBM_HEIGHT,
6730 XBM_DATA,
6731 XBM_FOREGROUND,
6732 XBM_BACKGROUND,
6733 XBM_ASCENT,
6734 XBM_MARGIN,
6735 XBM_RELIEF,
6736 XBM_ALGORITHM,
6737 XBM_HEURISTIC_MASK,
4a8e312c 6738 XBM_MASK,
333b20bb
GM
6739 XBM_LAST
6740};
6741
6742/* Vector of image_keyword structures describing the format
6743 of valid XBM image specifications. */
6744
6745static struct image_keyword xbm_format[XBM_LAST] =
6746{
6747 {":type", IMAGE_SYMBOL_VALUE, 1},
6748 {":file", IMAGE_STRING_VALUE, 0},
6749 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6750 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6751 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
6752 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6753 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
7c7ff7f5 6754 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 6755 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 6756 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 6757 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
6758 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6759 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
6760};
6761
6762/* Structure describing the image type XBM. */
6763
6764static struct image_type xbm_type =
6765{
6766 &Qxbm,
6767 xbm_image_p,
6768 xbm_load,
6769 x_clear_image,
6770 NULL
6771};
6772
6773/* Tokens returned from xbm_scan. */
6774
6775enum xbm_token
6776{
6777 XBM_TK_IDENT = 256,
6778 XBM_TK_NUMBER
6779};
6780
6781
6782/* Return non-zero if OBJECT is a valid XBM-type image specification.
6783 A valid specification is a list starting with the symbol `image'
6784 The rest of the list is a property list which must contain an
6785 entry `:type xbm..
6786
6787 If the specification specifies a file to load, it must contain
6788 an entry `:file FILENAME' where FILENAME is a string.
6789
6790 If the specification is for a bitmap loaded from memory it must
6791 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6792 WIDTH and HEIGHT are integers > 0. DATA may be:
6793
6794 1. a string large enough to hold the bitmap data, i.e. it must
6795 have a size >= (WIDTH + 7) / 8 * HEIGHT
6796
6797 2. a bool-vector of size >= WIDTH * HEIGHT
6798
6799 3. a vector of strings or bool-vectors, one for each line of the
6800 bitmap.
6801
5be6c3b0
GM
6802 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
6803 may not be specified in this case because they are defined in the
6804 XBM file.
6805
333b20bb
GM
6806 Both the file and data forms may contain the additional entries
6807 `:background COLOR' and `:foreground COLOR'. If not present,
6808 foreground and background of the frame on which the image is
e3130015 6809 displayed is used. */
333b20bb
GM
6810
6811static int
6812xbm_image_p (object)
6813 Lisp_Object object;
6814{
6815 struct image_keyword kw[XBM_LAST];
6816
6817 bcopy (xbm_format, kw, sizeof kw);
bfd2209f 6818 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
333b20bb
GM
6819 return 0;
6820
6821 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6822
6823 if (kw[XBM_FILE].count)
6824 {
6825 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6826 return 0;
6827 }
5be6c3b0
GM
6828 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
6829 {
6830 /* In-memory XBM file. */
6831 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
6832 return 0;
6833 }
333b20bb
GM
6834 else
6835 {
6836 Lisp_Object data;
6837 int width, height;
6838
6839 /* Entries for `:width', `:height' and `:data' must be present. */
6840 if (!kw[XBM_WIDTH].count
6841 || !kw[XBM_HEIGHT].count
6842 || !kw[XBM_DATA].count)
6843 return 0;
6844
6845 data = kw[XBM_DATA].value;
6846 width = XFASTINT (kw[XBM_WIDTH].value);
6847 height = XFASTINT (kw[XBM_HEIGHT].value);
6848
6849 /* Check type of data, and width and height against contents of
6850 data. */
6851 if (VECTORP (data))
6852 {
6853 int i;
6854
6855 /* Number of elements of the vector must be >= height. */
6856 if (XVECTOR (data)->size < height)
6857 return 0;
6858
6859 /* Each string or bool-vector in data must be large enough
6860 for one line of the image. */
6861 for (i = 0; i < height; ++i)
6862 {
6863 Lisp_Object elt = XVECTOR (data)->contents[i];
6864
6865 if (STRINGP (elt))
6866 {
6867 if (XSTRING (elt)->size
6868 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6869 return 0;
6870 }
6871 else if (BOOL_VECTOR_P (elt))
6872 {
6873 if (XBOOL_VECTOR (elt)->size < width)
6874 return 0;
6875 }
6876 else
6877 return 0;
6878 }
6879 }
6880 else if (STRINGP (data))
6881 {
6882 if (XSTRING (data)->size
6883 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6884 return 0;
6885 }
6886 else if (BOOL_VECTOR_P (data))
6887 {
6888 if (XBOOL_VECTOR (data)->size < width * height)
6889 return 0;
6890 }
6891 else
6892 return 0;
6893 }
6894
333b20bb
GM
6895 return 1;
6896}
6897
6898
6899/* Scan a bitmap file. FP is the stream to read from. Value is
6900 either an enumerator from enum xbm_token, or a character for a
6901 single-character token, or 0 at end of file. If scanning an
6902 identifier, store the lexeme of the identifier in SVAL. If
6903 scanning a number, store its value in *IVAL. */
6904
6905static int
5be6c3b0
GM
6906xbm_scan (s, end, sval, ival)
6907 char **s, *end;
333b20bb
GM
6908 char *sval;
6909 int *ival;
6910{
6911 int c;
0a695da7
GM
6912
6913 loop:
333b20bb
GM
6914
6915 /* Skip white space. */
5be6c3b0 6916 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
6917 ;
6918
5be6c3b0 6919 if (*s >= end)
333b20bb
GM
6920 c = 0;
6921 else if (isdigit (c))
6922 {
6923 int value = 0, digit;
6924
5be6c3b0 6925 if (c == '0' && *s < end)
333b20bb 6926 {
5be6c3b0 6927 c = *(*s)++;
333b20bb
GM
6928 if (c == 'x' || c == 'X')
6929 {
5be6c3b0 6930 while (*s < end)
333b20bb 6931 {
5be6c3b0 6932 c = *(*s)++;
333b20bb
GM
6933 if (isdigit (c))
6934 digit = c - '0';
6935 else if (c >= 'a' && c <= 'f')
6936 digit = c - 'a' + 10;
6937 else if (c >= 'A' && c <= 'F')
6938 digit = c - 'A' + 10;
6939 else
6940 break;
6941 value = 16 * value + digit;
6942 }
6943 }
6944 else if (isdigit (c))
6945 {
6946 value = c - '0';
5be6c3b0
GM
6947 while (*s < end
6948 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6949 value = 8 * value + c - '0';
6950 }
6951 }
6952 else
6953 {
6954 value = c - '0';
5be6c3b0
GM
6955 while (*s < end
6956 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6957 value = 10 * value + c - '0';
6958 }
6959
5be6c3b0
GM
6960 if (*s < end)
6961 *s = *s - 1;
333b20bb
GM
6962 *ival = value;
6963 c = XBM_TK_NUMBER;
6964 }
6965 else if (isalpha (c) || c == '_')
6966 {
6967 *sval++ = c;
5be6c3b0
GM
6968 while (*s < end
6969 && (c = *(*s)++, (isalnum (c) || c == '_')))
333b20bb
GM
6970 *sval++ = c;
6971 *sval = 0;
5be6c3b0
GM
6972 if (*s < end)
6973 *s = *s - 1;
333b20bb
GM
6974 c = XBM_TK_IDENT;
6975 }
0a695da7
GM
6976 else if (c == '/' && **s == '*')
6977 {
6978 /* C-style comment. */
6979 ++*s;
6980 while (**s && (**s != '*' || *(*s + 1) != '/'))
6981 ++*s;
6982 if (**s)
6983 {
6984 *s += 2;
6985 goto loop;
6986 }
6987 }
333b20bb
GM
6988
6989 return c;
6990}
6991
6992
6993/* Replacement for XReadBitmapFileData which isn't available under old
5be6c3b0
GM
6994 X versions. CONTENTS is a pointer to a buffer to parse; END is the
6995 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
6996 the image. Return in *DATA the bitmap data allocated with xmalloc.
6997 Value is non-zero if successful. DATA null means just test if
b243755a 6998 CONTENTS looks like an in-memory XBM file. */
333b20bb
GM
6999
7000static int
5be6c3b0
GM
7001xbm_read_bitmap_data (contents, end, width, height, data)
7002 char *contents, *end;
333b20bb
GM
7003 int *width, *height;
7004 unsigned char **data;
7005{
5be6c3b0 7006 char *s = contents;
333b20bb
GM
7007 char buffer[BUFSIZ];
7008 int padding_p = 0;
7009 int v10 = 0;
7010 int bytes_per_line, i, nbytes;
7011 unsigned char *p;
7012 int value;
7013 int LA1;
7014
7015#define match() \
5be6c3b0 7016 LA1 = xbm_scan (&s, end, buffer, &value)
333b20bb
GM
7017
7018#define expect(TOKEN) \
7019 if (LA1 != (TOKEN)) \
7020 goto failure; \
7021 else \
7022 match ()
7023
7024#define expect_ident(IDENT) \
7025 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
7026 match (); \
7027 else \
7028 goto failure
7029
333b20bb 7030 *width = *height = -1;
5be6c3b0
GM
7031 if (data)
7032 *data = NULL;
7033 LA1 = xbm_scan (&s, end, buffer, &value);
333b20bb
GM
7034
7035 /* Parse defines for width, height and hot-spots. */
7036 while (LA1 == '#')
7037 {
333b20bb
GM
7038 match ();
7039 expect_ident ("define");
7040 expect (XBM_TK_IDENT);
7041
7042 if (LA1 == XBM_TK_NUMBER);
7043 {
7044 char *p = strrchr (buffer, '_');
7045 p = p ? p + 1 : buffer;
7046 if (strcmp (p, "width") == 0)
7047 *width = value;
7048 else if (strcmp (p, "height") == 0)
7049 *height = value;
7050 }
7051 expect (XBM_TK_NUMBER);
7052 }
7053
7054 if (*width < 0 || *height < 0)
7055 goto failure;
5be6c3b0
GM
7056 else if (data == NULL)
7057 goto success;
333b20bb
GM
7058
7059 /* Parse bits. Must start with `static'. */
7060 expect_ident ("static");
7061 if (LA1 == XBM_TK_IDENT)
7062 {
7063 if (strcmp (buffer, "unsigned") == 0)
7064 {
7065 match ();
7066 expect_ident ("char");
7067 }
7068 else if (strcmp (buffer, "short") == 0)
7069 {
7070 match ();
7071 v10 = 1;
7072 if (*width % 16 && *width % 16 < 9)
7073 padding_p = 1;
7074 }
7075 else if (strcmp (buffer, "char") == 0)
7076 match ();
7077 else
7078 goto failure;
7079 }
7080 else
7081 goto failure;
7082
7083 expect (XBM_TK_IDENT);
7084 expect ('[');
7085 expect (']');
7086 expect ('=');
7087 expect ('{');
7088
7089 bytes_per_line = (*width + 7) / 8 + padding_p;
7090 nbytes = bytes_per_line * *height;
7091 p = *data = (char *) xmalloc (nbytes);
7092
7093 if (v10)
7094 {
333b20bb
GM
7095 for (i = 0; i < nbytes; i += 2)
7096 {
7097 int val = value;
7098 expect (XBM_TK_NUMBER);
7099
7100 *p++ = val;
7101 if (!padding_p || ((i + 2) % bytes_per_line))
7102 *p++ = value >> 8;
7103
7104 if (LA1 == ',' || LA1 == '}')
7105 match ();
7106 else
7107 goto failure;
7108 }
7109 }
7110 else
7111 {
7112 for (i = 0; i < nbytes; ++i)
7113 {
7114 int val = value;
7115 expect (XBM_TK_NUMBER);
7116
7117 *p++ = val;
7118
7119 if (LA1 == ',' || LA1 == '}')
7120 match ();
7121 else
7122 goto failure;
7123 }
7124 }
7125
5be6c3b0 7126 success:
333b20bb
GM
7127 return 1;
7128
7129 failure:
7130
5be6c3b0 7131 if (data && *data)
333b20bb
GM
7132 {
7133 xfree (*data);
7134 *data = NULL;
7135 }
7136 return 0;
7137
7138#undef match
7139#undef expect
7140#undef expect_ident
7141}
7142
7143
5be6c3b0
GM
7144/* Load XBM image IMG which will be displayed on frame F from buffer
7145 CONTENTS. END is the end of the buffer. Value is non-zero if
7146 successful. */
333b20bb
GM
7147
7148static int
5be6c3b0 7149xbm_load_image (f, img, contents, end)
333b20bb
GM
7150 struct frame *f;
7151 struct image *img;
5be6c3b0 7152 char *contents, *end;
333b20bb
GM
7153{
7154 int rc;
7155 unsigned char *data;
7156 int success_p = 0;
333b20bb 7157
5be6c3b0 7158 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
333b20bb
GM
7159 if (rc)
7160 {
7161 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7162 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7163 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7164 Lisp_Object value;
7165
7166 xassert (img->width > 0 && img->height > 0);
7167
7168 /* Get foreground and background colors, maybe allocate colors. */
7169 value = image_spec_value (img->spec, QCforeground, NULL);
7170 if (!NILP (value))
7171 foreground = x_alloc_image_color (f, img, value, foreground);
333b20bb
GM
7172 value = image_spec_value (img->spec, QCbackground, NULL);
7173 if (!NILP (value))
f20a3b7a
MB
7174 {
7175 background = x_alloc_image_color (f, img, value, background);
7176 img->background = background;
7177 img->background_valid = 1;
7178 }
333b20bb 7179
333b20bb
GM
7180 img->pixmap
7181 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7182 FRAME_X_WINDOW (f),
7183 data,
7184 img->width, img->height,
7185 foreground, background,
7186 depth);
7187 xfree (data);
7188
dd00328a 7189 if (img->pixmap == None)
333b20bb
GM
7190 {
7191 x_clear_image (f, img);
5be6c3b0 7192 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
7193 }
7194 else
7195 success_p = 1;
333b20bb
GM
7196 }
7197 else
45158a91 7198 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
333b20bb 7199
333b20bb
GM
7200 return success_p;
7201}
7202
7203
5be6c3b0
GM
7204/* Value is non-zero if DATA looks like an in-memory XBM file. */
7205
7206static int
7207xbm_file_p (data)
7208 Lisp_Object data;
7209{
7210 int w, h;
7211 return (STRINGP (data)
7212 && xbm_read_bitmap_data (XSTRING (data)->data,
7213 (XSTRING (data)->data
7214 + STRING_BYTES (XSTRING (data))),
7215 &w, &h, NULL));
7216}
7217
7218
333b20bb
GM
7219/* Fill image IMG which is used on frame F with pixmap data. Value is
7220 non-zero if successful. */
7221
7222static int
7223xbm_load (f, img)
7224 struct frame *f;
7225 struct image *img;
7226{
7227 int success_p = 0;
7228 Lisp_Object file_name;
7229
7230 xassert (xbm_image_p (img->spec));
7231
7232 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7233 file_name = image_spec_value (img->spec, QCfile, NULL);
7234 if (STRINGP (file_name))
5be6c3b0
GM
7235 {
7236 Lisp_Object file;
7237 char *contents;
7238 int size;
7239 struct gcpro gcpro1;
7240
7241 file = x_find_image_file (file_name);
7242 GCPRO1 (file);
7243 if (!STRINGP (file))
7244 {
7245 image_error ("Cannot find image file `%s'", file_name, Qnil);
7246 UNGCPRO;
7247 return 0;
7248 }
7249
7250 contents = slurp_file (XSTRING (file)->data, &size);
7251 if (contents == NULL)
7252 {
7253 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7254 UNGCPRO;
7255 return 0;
7256 }
7257
7258 success_p = xbm_load_image (f, img, contents, contents + size);
7259 UNGCPRO;
7260 }
333b20bb
GM
7261 else
7262 {
7263 struct image_keyword fmt[XBM_LAST];
7264 Lisp_Object data;
7265 int depth;
7266 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7267 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7268 char *bits;
9b207e8e 7269 int parsed_p;
5be6c3b0
GM
7270 int in_memory_file_p = 0;
7271
7272 /* See if data looks like an in-memory XBM file. */
7273 data = image_spec_value (img->spec, QCdata, NULL);
7274 in_memory_file_p = xbm_file_p (data);
333b20bb 7275
5be6c3b0 7276 /* Parse the image specification. */
333b20bb 7277 bcopy (xbm_format, fmt, sizeof fmt);
bfd2209f 7278 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
333b20bb
GM
7279 xassert (parsed_p);
7280
7281 /* Get specified width, and height. */
5be6c3b0
GM
7282 if (!in_memory_file_p)
7283 {
7284 img->width = XFASTINT (fmt[XBM_WIDTH].value);
7285 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
7286 xassert (img->width > 0 && img->height > 0);
7287 }
333b20bb 7288
333b20bb 7289 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
7290 if (fmt[XBM_FOREGROUND].count
7291 && STRINGP (fmt[XBM_FOREGROUND].value))
333b20bb
GM
7292 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
7293 foreground);
6f1be3b9
GM
7294 if (fmt[XBM_BACKGROUND].count
7295 && STRINGP (fmt[XBM_BACKGROUND].value))
333b20bb
GM
7296 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
7297 background);
7298
5be6c3b0
GM
7299 if (in_memory_file_p)
7300 success_p = xbm_load_image (f, img, XSTRING (data)->data,
7301 (XSTRING (data)->data
7302 + STRING_BYTES (XSTRING (data))));
7303 else
333b20bb 7304 {
5be6c3b0
GM
7305 if (VECTORP (data))
7306 {
7307 int i;
7308 char *p;
7309 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
333b20bb 7310
5be6c3b0
GM
7311 p = bits = (char *) alloca (nbytes * img->height);
7312 for (i = 0; i < img->height; ++i, p += nbytes)
7313 {
7314 Lisp_Object line = XVECTOR (data)->contents[i];
7315 if (STRINGP (line))
7316 bcopy (XSTRING (line)->data, p, nbytes);
7317 else
7318 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
7319 }
7320 }
7321 else if (STRINGP (data))
7322 bits = XSTRING (data)->data;
7323 else
7324 bits = XBOOL_VECTOR (data)->data;
7325
7326 /* Create the pixmap. */
7327 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7328 img->pixmap
7329 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7330 FRAME_X_WINDOW (f),
7331 bits,
7332 img->width, img->height,
7333 foreground, background,
7334 depth);
7335 if (img->pixmap)
7336 success_p = 1;
7337 else
333b20bb 7338 {
5be6c3b0
GM
7339 image_error ("Unable to create pixmap for XBM image `%s'",
7340 img->spec, Qnil);
7341 x_clear_image (f, img);
333b20bb
GM
7342 }
7343 }
333b20bb
GM
7344 }
7345
7346 return success_p;
7347}
7348
7349
7350\f
7351/***********************************************************************
7352 XPM images
7353 ***********************************************************************/
7354
7355#if HAVE_XPM
7356
7357static int xpm_image_p P_ ((Lisp_Object object));
7358static int xpm_load P_ ((struct frame *f, struct image *img));
7359static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
7360
7361#include "X11/xpm.h"
7362
7363/* The symbol `xpm' identifying XPM-format images. */
7364
7365Lisp_Object Qxpm;
7366
7367/* Indices of image specification fields in xpm_format, below. */
7368
7369enum xpm_keyword_index
7370{
7371 XPM_TYPE,
7372 XPM_FILE,
7373 XPM_DATA,
7374 XPM_ASCENT,
7375 XPM_MARGIN,
7376 XPM_RELIEF,
7377 XPM_ALGORITHM,
7378 XPM_HEURISTIC_MASK,
4a8e312c 7379 XPM_MASK,
333b20bb 7380 XPM_COLOR_SYMBOLS,
f20a3b7a 7381 XPM_BACKGROUND,
333b20bb
GM
7382 XPM_LAST
7383};
7384
7385/* Vector of image_keyword structures describing the format
7386 of valid XPM image specifications. */
7387
7388static struct image_keyword xpm_format[XPM_LAST] =
7389{
7390 {":type", IMAGE_SYMBOL_VALUE, 1},
7391 {":file", IMAGE_STRING_VALUE, 0},
7392 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 7393 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 7394 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 7395 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 7396 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 7397 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 7398 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
7399 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7400 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
7401};
7402
7403/* Structure describing the image type XBM. */
7404
7405static struct image_type xpm_type =
7406{
7407 &Qxpm,
7408 xpm_image_p,
7409 xpm_load,
7410 x_clear_image,
7411 NULL
7412};
7413
7414
b243755a
GM
7415/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
7416 functions for allocating image colors. Our own functions handle
7417 color allocation failures more gracefully than the ones on the XPM
7418 lib. */
7419
7420#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
7421#define ALLOC_XPM_COLORS
7422#endif
7423
7424#ifdef ALLOC_XPM_COLORS
7425
f72c62ad 7426static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
b243755a
GM
7427static void xpm_free_color_cache P_ ((void));
7428static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
f72c62ad
GM
7429static int xpm_color_bucket P_ ((char *));
7430static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
7431 XColor *, int));
b243755a
GM
7432
7433/* An entry in a hash table used to cache color definitions of named
7434 colors. This cache is necessary to speed up XPM image loading in
7435 case we do color allocations ourselves. Without it, we would need
7436 a call to XParseColor per pixel in the image. */
7437
7438struct xpm_cached_color
7439{
7440 /* Next in collision chain. */
7441 struct xpm_cached_color *next;
7442
7443 /* Color definition (RGB and pixel color). */
7444 XColor color;
7445
7446 /* Color name. */
7447 char name[1];
7448};
7449
7450/* The hash table used for the color cache, and its bucket vector
7451 size. */
7452
7453#define XPM_COLOR_CACHE_BUCKETS 1001
7454struct xpm_cached_color **xpm_color_cache;
7455
b243755a
GM
7456/* Initialize the color cache. */
7457
7458static void
f72c62ad
GM
7459xpm_init_color_cache (f, attrs)
7460 struct frame *f;
7461 XpmAttributes *attrs;
b243755a
GM
7462{
7463 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
7464 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
7465 memset (xpm_color_cache, 0, nbytes);
7466 init_color_table ();
f72c62ad
GM
7467
7468 if (attrs->valuemask & XpmColorSymbols)
7469 {
7470 int i;
7471 XColor color;
7472
7473 for (i = 0; i < attrs->numsymbols; ++i)
7474 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7475 attrs->colorsymbols[i].value, &color))
7476 {
7477 color.pixel = lookup_rgb_color (f, color.red, color.green,
7478 color.blue);
7479 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
7480 }
7481 }
b243755a
GM
7482}
7483
7484
7485/* Free the color cache. */
7486
7487static void
7488xpm_free_color_cache ()
7489{
7490 struct xpm_cached_color *p, *next;
7491 int i;
7492
7493 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
7494 for (p = xpm_color_cache[i]; p; p = next)
7495 {
7496 next = p->next;
7497 xfree (p);
7498 }
7499
7500 xfree (xpm_color_cache);
7501 xpm_color_cache = NULL;
7502 free_color_table ();
7503}
7504
7505
f72c62ad
GM
7506/* Return the bucket index for color named COLOR_NAME in the color
7507 cache. */
7508
7509static int
7510xpm_color_bucket (color_name)
7511 char *color_name;
7512{
7513 unsigned h = 0;
7514 char *s;
7515
7516 for (s = color_name; *s; ++s)
7517 h = (h << 2) ^ *s;
7518 return h %= XPM_COLOR_CACHE_BUCKETS;
7519}
7520
7521
7522/* On frame F, cache values COLOR for color with name COLOR_NAME.
7523 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
7524 entry added. */
7525
7526static struct xpm_cached_color *
7527xpm_cache_color (f, color_name, color, bucket)
7528 struct frame *f;
7529 char *color_name;
7530 XColor *color;
7531 int bucket;
7532{
7533 size_t nbytes;
7534 struct xpm_cached_color *p;
7535
7536 if (bucket < 0)
7537 bucket = xpm_color_bucket (color_name);
7538
7539 nbytes = sizeof *p + strlen (color_name);
7540 p = (struct xpm_cached_color *) xmalloc (nbytes);
7541 strcpy (p->name, color_name);
7542 p->color = *color;
7543 p->next = xpm_color_cache[bucket];
7544 xpm_color_cache[bucket] = p;
7545 return p;
7546}
7547
7548
b243755a
GM
7549/* Look up color COLOR_NAME for frame F in the color cache. If found,
7550 return the cached definition in *COLOR. Otherwise, make a new
7551 entry in the cache and allocate the color. Value is zero if color
7552 allocation failed. */
7553
7554static int
7555xpm_lookup_color (f, color_name, color)
7556 struct frame *f;
7557 char *color_name;
7558 XColor *color;
7559{
b243755a 7560 struct xpm_cached_color *p;
83676598 7561 int h = xpm_color_bucket (color_name);
b243755a
GM
7562
7563 for (p = xpm_color_cache[h]; p; p = p->next)
7564 if (strcmp (p->name, color_name) == 0)
7565 break;
7566
7567 if (p != NULL)
7568 *color = p->color;
7569 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7570 color_name, color))
7571 {
b243755a
GM
7572 color->pixel = lookup_rgb_color (f, color->red, color->green,
7573 color->blue);
f72c62ad 7574 p = xpm_cache_color (f, color_name, color, h);
b243755a 7575 }
f72c62ad 7576
b243755a
GM
7577 return p != NULL;
7578}
7579
7580
7581/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
7582 CLOSURE is a pointer to the frame on which we allocate the
7583 color. Return in *COLOR the allocated color. Value is non-zero
7584 if successful. */
7585
7586static int
7587xpm_alloc_color (dpy, cmap, color_name, color, closure)
7588 Display *dpy;
7589 Colormap cmap;
7590 char *color_name;
7591 XColor *color;
7592 void *closure;
7593{
7594 return xpm_lookup_color ((struct frame *) closure, color_name, color);
7595}
7596
7597
7598/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
7599 is a pointer to the frame on which we allocate the color. Value is
7600 non-zero if successful. */
7601
7602static int
7603xpm_free_colors (dpy, cmap, pixels, npixels, closure)
7604 Display *dpy;
7605 Colormap cmap;
7606 Pixel *pixels;
7607 int npixels;
7608 void *closure;
7609{
7610 return 1;
7611}
7612
7613#endif /* ALLOC_XPM_COLORS */
7614
7615
333b20bb
GM
7616/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7617 for XPM images. Such a list must consist of conses whose car and
7618 cdr are strings. */
7619
7620static int
7621xpm_valid_color_symbols_p (color_symbols)
7622 Lisp_Object color_symbols;
7623{
7624 while (CONSP (color_symbols))
7625 {
7626 Lisp_Object sym = XCAR (color_symbols);
7627 if (!CONSP (sym)
7628 || !STRINGP (XCAR (sym))
7629 || !STRINGP (XCDR (sym)))
7630 break;
7631 color_symbols = XCDR (color_symbols);
7632 }
7633
7634 return NILP (color_symbols);
7635}
7636
7637
7638/* Value is non-zero if OBJECT is a valid XPM image specification. */
7639
7640static int
7641xpm_image_p (object)
7642 Lisp_Object object;
7643{
7644 struct image_keyword fmt[XPM_LAST];
7645 bcopy (xpm_format, fmt, sizeof fmt);
bfd2209f 7646 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
333b20bb
GM
7647 /* Either `:file' or `:data' must be present. */
7648 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7649 /* Either no `:color-symbols' or it's a list of conses
7650 whose car and cdr are strings. */
7651 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7c7ff7f5 7652 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
333b20bb
GM
7653}
7654
7655
7656/* Load image IMG which will be displayed on frame F. Value is
7657 non-zero if successful. */
7658
7659static int
7660xpm_load (f, img)
7661 struct frame *f;
7662 struct image *img;
7663{
9b207e8e 7664 int rc;
333b20bb
GM
7665 XpmAttributes attrs;
7666 Lisp_Object specified_file, color_symbols;
7667
7668 /* Configure the XPM lib. Use the visual of frame F. Allocate
7669 close colors. Return colors allocated. */
7670 bzero (&attrs, sizeof attrs);
9b2956e2
GM
7671 attrs.visual = FRAME_X_VISUAL (f);
7672 attrs.colormap = FRAME_X_COLORMAP (f);
333b20bb 7673 attrs.valuemask |= XpmVisual;
9b2956e2 7674 attrs.valuemask |= XpmColormap;
b243755a
GM
7675
7676#ifdef ALLOC_XPM_COLORS
7677 /* Allocate colors with our own functions which handle
7678 failing color allocation more gracefully. */
7679 attrs.color_closure = f;
7680 attrs.alloc_color = xpm_alloc_color;
7681 attrs.free_colors = xpm_free_colors;
7682 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
7683#else /* not ALLOC_XPM_COLORS */
7684 /* Let the XPM lib allocate colors. */
333b20bb 7685 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 7686#ifdef XpmAllocCloseColors
333b20bb
GM
7687 attrs.alloc_close_colors = 1;
7688 attrs.valuemask |= XpmAllocCloseColors;
b243755a 7689#else /* not XpmAllocCloseColors */
e4c082be
RS
7690 attrs.closeness = 600;
7691 attrs.valuemask |= XpmCloseness;
b243755a
GM
7692#endif /* not XpmAllocCloseColors */
7693#endif /* ALLOC_XPM_COLORS */
333b20bb
GM
7694
7695 /* If image specification contains symbolic color definitions, add
7696 these to `attrs'. */
7697 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7698 if (CONSP (color_symbols))
7699 {
7700 Lisp_Object tail;
7701 XpmColorSymbol *xpm_syms;
7702 int i, size;
7703
7704 attrs.valuemask |= XpmColorSymbols;
7705
7706 /* Count number of symbols. */
7707 attrs.numsymbols = 0;
7708 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7709 ++attrs.numsymbols;
7710
7711 /* Allocate an XpmColorSymbol array. */
7712 size = attrs.numsymbols * sizeof *xpm_syms;
7713 xpm_syms = (XpmColorSymbol *) alloca (size);
7714 bzero (xpm_syms, size);
7715 attrs.colorsymbols = xpm_syms;
7716
7717 /* Fill the color symbol array. */
7718 for (tail = color_symbols, i = 0;
7719 CONSP (tail);
7720 ++i, tail = XCDR (tail))
7721 {
7722 Lisp_Object name = XCAR (XCAR (tail));
7723 Lisp_Object color = XCDR (XCAR (tail));
7724 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
7725 strcpy (xpm_syms[i].name, XSTRING (name)->data);
7726 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
7727 strcpy (xpm_syms[i].value, XSTRING (color)->data);
7728 }
7729 }
7730
7731 /* Create a pixmap for the image, either from a file, or from a
7732 string buffer containing data in the same format as an XPM file. */
b243755a 7733#ifdef ALLOC_XPM_COLORS
f72c62ad 7734 xpm_init_color_cache (f, &attrs);
b243755a
GM
7735#endif
7736
333b20bb
GM
7737 specified_file = image_spec_value (img->spec, QCfile, NULL);
7738 if (STRINGP (specified_file))
7739 {
7740 Lisp_Object file = x_find_image_file (specified_file);
7741 if (!STRINGP (file))
7742 {
45158a91 7743 image_error ("Cannot find image file `%s'", specified_file, Qnil);
333b20bb
GM
7744 return 0;
7745 }
7746
7747 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7748 XSTRING (file)->data, &img->pixmap, &img->mask,
7749 &attrs);
7750 }
7751 else
7752 {
7753 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7754 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7755 XSTRING (buffer)->data,
7756 &img->pixmap, &img->mask,
7757 &attrs);
7758 }
333b20bb
GM
7759
7760 if (rc == XpmSuccess)
7761 {
b243755a
GM
7762#ifdef ALLOC_XPM_COLORS
7763 img->colors = colors_in_color_table (&img->ncolors);
7764#else /* not ALLOC_XPM_COLORS */
f47a9ec4
KR
7765 int i;
7766
333b20bb
GM
7767 img->ncolors = attrs.nalloc_pixels;
7768 img->colors = (unsigned long *) xmalloc (img->ncolors
7769 * sizeof *img->colors);
7770 for (i = 0; i < attrs.nalloc_pixels; ++i)
3b4ae1cc
GM
7771 {
7772 img->colors[i] = attrs.alloc_pixels[i];
7773#ifdef DEBUG_X_COLORS
7774 register_color (img->colors[i]);
7775#endif
7776 }
b243755a 7777#endif /* not ALLOC_XPM_COLORS */
333b20bb
GM
7778
7779 img->width = attrs.width;
7780 img->height = attrs.height;
7781 xassert (img->width > 0 && img->height > 0);
7782
7783 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
333b20bb 7784 XpmFreeAttributes (&attrs);
333b20bb
GM
7785 }
7786 else
7787 {
7788 switch (rc)
7789 {
7790 case XpmOpenFailed:
7791 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7792 break;
7793
7794 case XpmFileInvalid:
7795 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7796 break;
7797
7798 case XpmNoMemory:
7799 image_error ("Out of memory (%s)", img->spec, Qnil);
7800 break;
7801
7802 case XpmColorFailed:
7803 image_error ("Color allocation error (%s)", img->spec, Qnil);
7804 break;
7805
7806 default:
7807 image_error ("Unknown error (%s)", img->spec, Qnil);
7808 break;
7809 }
7810 }
7811
b243755a
GM
7812#ifdef ALLOC_XPM_COLORS
7813 xpm_free_color_cache ();
7814#endif
333b20bb
GM
7815 return rc == XpmSuccess;
7816}
7817
7818#endif /* HAVE_XPM != 0 */
7819
7820\f
7821/***********************************************************************
7822 Color table
7823 ***********************************************************************/
7824
7825/* An entry in the color table mapping an RGB color to a pixel color. */
7826
7827struct ct_color
7828{
7829 int r, g, b;
7830 unsigned long pixel;
7831
7832 /* Next in color table collision list. */
7833 struct ct_color *next;
7834};
7835
7836/* The bucket vector size to use. Must be prime. */
7837
7838#define CT_SIZE 101
7839
7840/* Value is a hash of the RGB color given by R, G, and B. */
7841
7842#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7843
7844/* The color hash table. */
7845
7846struct ct_color **ct_table;
7847
7848/* Number of entries in the color table. */
7849
7850int ct_colors_allocated;
7851
333b20bb
GM
7852/* Initialize the color table. */
7853
7854static void
7855init_color_table ()
7856{
7857 int size = CT_SIZE * sizeof (*ct_table);
7858 ct_table = (struct ct_color **) xmalloc (size);
7859 bzero (ct_table, size);
7860 ct_colors_allocated = 0;
7861}
7862
7863
7864/* Free memory associated with the color table. */
7865
7866static void
7867free_color_table ()
7868{
7869 int i;
7870 struct ct_color *p, *next;
7871
7872 for (i = 0; i < CT_SIZE; ++i)
7873 for (p = ct_table[i]; p; p = next)
7874 {
7875 next = p->next;
7876 xfree (p);
7877 }
7878
7879 xfree (ct_table);
7880 ct_table = NULL;
7881}
7882
7883
7884/* Value is a pixel color for RGB color R, G, B on frame F. If an
7885 entry for that color already is in the color table, return the
7886 pixel color of that entry. Otherwise, allocate a new color for R,
7887 G, B, and make an entry in the color table. */
7888
7889static unsigned long
7890lookup_rgb_color (f, r, g, b)
7891 struct frame *f;
7892 int r, g, b;
7893{
7894 unsigned hash = CT_HASH_RGB (r, g, b);
7895 int i = hash % CT_SIZE;
7896 struct ct_color *p;
7897
7898 for (p = ct_table[i]; p; p = p->next)
7899 if (p->r == r && p->g == g && p->b == b)
7900 break;
7901
7902 if (p == NULL)
7903 {
7904 XColor color;
7905 Colormap cmap;
7906 int rc;
7907
7908 color.red = r;
7909 color.green = g;
7910 color.blue = b;
7911
9b2956e2 7912 cmap = FRAME_X_COLORMAP (f);
d62c8769 7913 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7914
7915 if (rc)
7916 {
7917 ++ct_colors_allocated;
7918
7919 p = (struct ct_color *) xmalloc (sizeof *p);
7920 p->r = r;
7921 p->g = g;
7922 p->b = b;
7923 p->pixel = color.pixel;
7924 p->next = ct_table[i];
7925 ct_table[i] = p;
7926 }
7927 else
7928 return FRAME_FOREGROUND_PIXEL (f);
7929 }
7930
7931 return p->pixel;
7932}
7933
7934
7935/* Look up pixel color PIXEL which is used on frame F in the color
7936 table. If not already present, allocate it. Value is PIXEL. */
7937
7938static unsigned long
7939lookup_pixel_color (f, pixel)
7940 struct frame *f;
7941 unsigned long pixel;
7942{
7943 int i = pixel % CT_SIZE;
7944 struct ct_color *p;
7945
7946 for (p = ct_table[i]; p; p = p->next)
7947 if (p->pixel == pixel)
7948 break;
7949
7950 if (p == NULL)
7951 {
7952 XColor color;
7953 Colormap cmap;
7954 int rc;
7955
9b2956e2 7956 cmap = FRAME_X_COLORMAP (f);
333b20bb 7957 color.pixel = pixel;
a31fedb7 7958 x_query_color (f, &color);
d62c8769 7959 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7960
7961 if (rc)
7962 {
7963 ++ct_colors_allocated;
7964
7965 p = (struct ct_color *) xmalloc (sizeof *p);
7966 p->r = color.red;
7967 p->g = color.green;
7968 p->b = color.blue;
7969 p->pixel = pixel;
7970 p->next = ct_table[i];
7971 ct_table[i] = p;
7972 }
7973 else
7974 return FRAME_FOREGROUND_PIXEL (f);
7975 }
7976
7977 return p->pixel;
7978}
7979
7980
7981/* Value is a vector of all pixel colors contained in the color table,
7982 allocated via xmalloc. Set *N to the number of colors. */
7983
7984static unsigned long *
7985colors_in_color_table (n)
7986 int *n;
7987{
7988 int i, j;
7989 struct ct_color *p;
7990 unsigned long *colors;
7991
7992 if (ct_colors_allocated == 0)
7993 {
7994 *n = 0;
7995 colors = NULL;
7996 }
7997 else
7998 {
7999 colors = (unsigned long *) xmalloc (ct_colors_allocated
8000 * sizeof *colors);
8001 *n = ct_colors_allocated;
8002
8003 for (i = j = 0; i < CT_SIZE; ++i)
8004 for (p = ct_table[i]; p; p = p->next)
8005 colors[j++] = p->pixel;
8006 }
8007
8008 return colors;
8009}
8010
8011
8012\f
8013/***********************************************************************
8014 Algorithms
8015 ***********************************************************************/
8016
4a8e312c
GM
8017static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
8018static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
8019static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
8020
d2dc8167 8021/* Non-zero means draw a cross on images having `:conversion
14819cb3
GM
8022 disabled'. */
8023
8024int cross_disabled_images;
8025
4a8e312c
GM
8026/* Edge detection matrices for different edge-detection
8027 strategies. */
8028
8029static int emboss_matrix[9] = {
8030 /* x - 1 x x + 1 */
8031 2, -1, 0, /* y - 1 */
8032 -1, 0, 1, /* y */
8033 0, 1, -2 /* y + 1 */
8034};
333b20bb 8035
4a8e312c
GM
8036static int laplace_matrix[9] = {
8037 /* x - 1 x x + 1 */
8038 1, 0, 0, /* y - 1 */
8039 0, 0, 0, /* y */
8040 0, 0, -1 /* y + 1 */
8041};
333b20bb 8042
14819cb3
GM
8043/* Value is the intensity of the color whose red/green/blue values
8044 are R, G, and B. */
8045
8046#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
8047
333b20bb 8048
4a8e312c
GM
8049/* On frame F, return an array of XColor structures describing image
8050 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
8051 non-zero means also fill the red/green/blue members of the XColor
8052 structures. Value is a pointer to the array of XColors structures,
8053 allocated with xmalloc; it must be freed by the caller. */
8054
8055static XColor *
8056x_to_xcolors (f, img, rgb_p)
333b20bb 8057 struct frame *f;
4a8e312c
GM
8058 struct image *img;
8059 int rgb_p;
333b20bb 8060{
4a8e312c
GM
8061 int x, y;
8062 XColor *colors, *p;
8063 XImage *ximg;
333b20bb 8064
4a8e312c
GM
8065 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
8066
8067 /* Get the X image IMG->pixmap. */
8068 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8069 0, 0, img->width, img->height, ~0, ZPixmap);
333b20bb 8070
4a8e312c
GM
8071 /* Fill the `pixel' members of the XColor array. I wished there
8072 were an easy and portable way to circumvent XGetPixel. */
8073 p = colors;
8074 for (y = 0; y < img->height; ++y)
8075 {
8076 XColor *row = p;
8077
8078 for (x = 0; x < img->width; ++x, ++p)
8079 p->pixel = XGetPixel (ximg, x, y);
8080
8081 if (rgb_p)
a31fedb7 8082 x_query_colors (f, row, img->width);
4a8e312c
GM
8083 }
8084
8085 XDestroyImage (ximg);
4a8e312c 8086 return colors;
333b20bb
GM
8087}
8088
8089
4a8e312c
GM
8090/* Create IMG->pixmap from an array COLORS of XColor structures, whose
8091 RGB members are set. F is the frame on which this all happens.
8092 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
333b20bb
GM
8093
8094static void
4a8e312c 8095x_from_xcolors (f, img, colors)
333b20bb 8096 struct frame *f;
4a8e312c
GM
8097 struct image *img;
8098 XColor *colors;
333b20bb 8099{
4a8e312c
GM
8100 int x, y;
8101 XImage *oimg;
8102 Pixmap pixmap;
8103 XColor *p;
8104
4a8e312c 8105 init_color_table ();
333b20bb 8106
4a8e312c
GM
8107 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
8108 &oimg, &pixmap);
8109 p = colors;
8110 for (y = 0; y < img->height; ++y)
8111 for (x = 0; x < img->width; ++x, ++p)
8112 {
8113 unsigned long pixel;
8114 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
8115 XPutPixel (oimg, x, y, pixel);
8116 }
8117
8118 xfree (colors);
dd00328a 8119 x_clear_image_1 (f, img, 1, 0, 1);
4a8e312c
GM
8120
8121 x_put_x_image (f, oimg, pixmap, img->width, img->height);
8122 x_destroy_x_image (oimg);
8123 img->pixmap = pixmap;
8124 img->colors = colors_in_color_table (&img->ncolors);
8125 free_color_table ();
333b20bb
GM
8126}
8127
8128
4a8e312c
GM
8129/* On frame F, perform edge-detection on image IMG.
8130
8131 MATRIX is a nine-element array specifying the transformation
8132 matrix. See emboss_matrix for an example.
8133
8134 COLOR_ADJUST is a color adjustment added to each pixel of the
8135 outgoing image. */
333b20bb
GM
8136
8137static void
4a8e312c 8138x_detect_edges (f, img, matrix, color_adjust)
333b20bb
GM
8139 struct frame *f;
8140 struct image *img;
4a8e312c 8141 int matrix[9], color_adjust;
333b20bb 8142{
4a8e312c
GM
8143 XColor *colors = x_to_xcolors (f, img, 1);
8144 XColor *new, *p;
8145 int x, y, i, sum;
333b20bb 8146
4a8e312c
GM
8147 for (i = sum = 0; i < 9; ++i)
8148 sum += abs (matrix[i]);
333b20bb 8149
4a8e312c 8150#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
333b20bb 8151
4a8e312c 8152 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
333b20bb 8153
4a8e312c
GM
8154 for (y = 0; y < img->height; ++y)
8155 {
8156 p = COLOR (new, 0, y);
8157 p->red = p->green = p->blue = 0xffff/2;
8158 p = COLOR (new, img->width - 1, y);
8159 p->red = p->green = p->blue = 0xffff/2;
8160 }
8161
8162 for (x = 1; x < img->width - 1; ++x)
8163 {
8164 p = COLOR (new, x, 0);
8165 p->red = p->green = p->blue = 0xffff/2;
8166 p = COLOR (new, x, img->height - 1);
8167 p->red = p->green = p->blue = 0xffff/2;
8168 }
333b20bb 8169
4a8e312c 8170 for (y = 1; y < img->height - 1; ++y)
333b20bb 8171 {
4a8e312c
GM
8172 p = COLOR (new, 1, y);
8173
8174 for (x = 1; x < img->width - 1; ++x, ++p)
8175 {
14819cb3 8176 int r, g, b, y1, x1;
4a8e312c
GM
8177
8178 r = g = b = i = 0;
8179 for (y1 = y - 1; y1 < y + 2; ++y1)
8180 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
8181 if (matrix[i])
8182 {
8183 XColor *t = COLOR (colors, x1, y1);
8184 r += matrix[i] * t->red;
8185 g += matrix[i] * t->green;
8186 b += matrix[i] * t->blue;
8187 }
333b20bb 8188
4a8e312c
GM
8189 r = (r / sum + color_adjust) & 0xffff;
8190 g = (g / sum + color_adjust) & 0xffff;
8191 b = (b / sum + color_adjust) & 0xffff;
14819cb3 8192 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
333b20bb 8193 }
333b20bb
GM
8194 }
8195
4a8e312c
GM
8196 xfree (colors);
8197 x_from_xcolors (f, img, new);
333b20bb 8198
4a8e312c
GM
8199#undef COLOR
8200}
8201
8202
8203/* Perform the pre-defined `emboss' edge-detection on image IMG
8204 on frame F. */
8205
8206static void
8207x_emboss (f, img)
8208 struct frame *f;
8209 struct image *img;
8210{
8211 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
8212}
8213
8214
8215/* Perform the pre-defined `laplace' edge-detection on image IMG
8216 on frame F. */
8217
8218static void
8219x_laplace (f, img)
8220 struct frame *f;
8221 struct image *img;
8222{
8223 x_detect_edges (f, img, laplace_matrix, 45000);
8224}
8225
8226
8227/* Perform edge-detection on image IMG on frame F, with specified
8228 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
8229
8230 MATRIX must be either
8231
8232 - a list of at least 9 numbers in row-major form
8233 - a vector of at least 9 numbers
8234
8235 COLOR_ADJUST nil means use a default; otherwise it must be a
8236 number. */
8237
8238static void
8239x_edge_detection (f, img, matrix, color_adjust)
8240 struct frame *f;
8241 struct image *img;
8242 Lisp_Object matrix, color_adjust;
8243{
8244 int i = 0;
8245 int trans[9];
333b20bb 8246
4a8e312c
GM
8247 if (CONSP (matrix))
8248 {
8249 for (i = 0;
8250 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
8251 ++i, matrix = XCDR (matrix))
8252 trans[i] = XFLOATINT (XCAR (matrix));
8253 }
8254 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
8255 {
8256 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
8257 trans[i] = XFLOATINT (AREF (matrix, i));
8258 }
333b20bb 8259
4a8e312c
GM
8260 if (NILP (color_adjust))
8261 color_adjust = make_number (0xffff / 2);
333b20bb 8262
4a8e312c
GM
8263 if (i == 9 && NUMBERP (color_adjust))
8264 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
333b20bb
GM
8265}
8266
8267
14819cb3
GM
8268/* Transform image IMG on frame F so that it looks disabled. */
8269
8270static void
8271x_disable_image (f, img)
8272 struct frame *f;
8273 struct image *img;
8274{
8275 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
dd00328a 8276
14819cb3
GM
8277 if (dpyinfo->n_planes >= 2)
8278 {
8279 /* Color (or grayscale). Convert to gray, and equalize. Just
8280 drawing such images with a stipple can look very odd, so
8281 we're using this method instead. */
8282 XColor *colors = x_to_xcolors (f, img, 1);
8283 XColor *p, *end;
8284 const int h = 15000;
8285 const int l = 30000;
8286
8287 for (p = colors, end = colors + img->width * img->height;
8288 p < end;
8289 ++p)
8290 {
8291 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
8292 int i2 = (0xffff - h - l) * i / 0xffff + l;
8293 p->red = p->green = p->blue = i2;
8294 }
8295
8296 x_from_xcolors (f, img, colors);
8297 }
8298
8299 /* Draw a cross over the disabled image, if we must or if we
8300 should. */
8301 if (dpyinfo->n_planes < 2 || cross_disabled_images)
8302 {
8303 Display *dpy = FRAME_X_DISPLAY (f);
8304 GC gc;
8305
14819cb3
GM
8306 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
8307 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
8308 XDrawLine (dpy, img->pixmap, gc, 0, 0,
8309 img->width - 1, img->height - 1);
8310 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
8311 img->width - 1, 0);
8312 XFreeGC (dpy, gc);
8313
8314 if (img->mask)
8315 {
8316 gc = XCreateGC (dpy, img->mask, 0, NULL);
8317 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
8318 XDrawLine (dpy, img->mask, gc, 0, 0,
8319 img->width - 1, img->height - 1);
8320 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
8321 img->width - 1, 0);
8322 XFreeGC (dpy, gc);
8323 }
14819cb3
GM
8324 }
8325}
8326
8327
333b20bb
GM
8328/* Build a mask for image IMG which is used on frame F. FILE is the
8329 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
8330 determine the background color of IMG. If it is a list '(R G B)',
8331 with R, G, and B being integers >= 0, take that as the color of the
8332 background. Otherwise, determine the background color of IMG
8333 heuristically. Value is non-zero if successful. */
333b20bb
GM
8334
8335static int
45158a91 8336x_build_heuristic_mask (f, img, how)
333b20bb 8337 struct frame *f;
333b20bb
GM
8338 struct image *img;
8339 Lisp_Object how;
8340{
8341 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 8342 XImage *ximg, *mask_img;
f20a3b7a 8343 int x, y, rc, use_img_background;
8ec8a5ec 8344 unsigned long bg = 0;
333b20bb 8345
4a8e312c
GM
8346 if (img->mask)
8347 {
8348 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 8349 img->mask = None;
f20a3b7a 8350 img->background_transparent_valid = 0;
4a8e312c 8351 }
dd00328a 8352
333b20bb 8353 /* Create an image and pixmap serving as mask. */
45158a91 8354 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
333b20bb
GM
8355 &mask_img, &img->mask);
8356 if (!rc)
28c7826c 8357 return 0;
333b20bb
GM
8358
8359 /* Get the X image of IMG->pixmap. */
8360 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
8361 ~0, ZPixmap);
8362
fcf431dc 8363 /* Determine the background color of ximg. If HOW is `(R G B)'
f20a3b7a
MB
8364 take that as color. Otherwise, use the image's background color. */
8365 use_img_background = 1;
fcf431dc
GM
8366
8367 if (CONSP (how))
8368 {
cac1daf0 8369 int rgb[3], i;
fcf431dc 8370
cac1daf0 8371 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
fcf431dc
GM
8372 {
8373 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
8374 how = XCDR (how);
8375 }
8376
8377 if (i == 3 && NILP (how))
8378 {
8379 char color_name[30];
fcf431dc 8380 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
053b3256
GM
8381 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
8382 use_img_background = 0;
fcf431dc
GM
8383 }
8384 }
8385
f20a3b7a 8386 if (use_img_background)
43f7c3ea 8387 bg = four_corners_best (ximg, img->width, img->height);
333b20bb
GM
8388
8389 /* Set all bits in mask_img to 1 whose color in ximg is different
8390 from the background color bg. */
8391 for (y = 0; y < img->height; ++y)
8392 for (x = 0; x < img->width; ++x)
8393 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
8394
f20a3b7a
MB
8395 /* Fill in the background_transparent field while we have the mask handy. */
8396 image_background_transparent (img, f, mask_img);
8397
333b20bb
GM
8398 /* Put mask_img into img->mask. */
8399 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8400 x_destroy_x_image (mask_img);
8401 XDestroyImage (ximg);
8402
333b20bb
GM
8403 return 1;
8404}
8405
8406
8407\f
8408/***********************************************************************
8409 PBM (mono, gray, color)
8410 ***********************************************************************/
8411
8412static int pbm_image_p P_ ((Lisp_Object object));
8413static int pbm_load P_ ((struct frame *f, struct image *img));
63cec32f 8414static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
333b20bb
GM
8415
8416/* The symbol `pbm' identifying images of this type. */
8417
8418Lisp_Object Qpbm;
8419
8420/* Indices of image specification fields in gs_format, below. */
8421
8422enum pbm_keyword_index
8423{
8424 PBM_TYPE,
8425 PBM_FILE,
63cec32f 8426 PBM_DATA,
333b20bb
GM
8427 PBM_ASCENT,
8428 PBM_MARGIN,
8429 PBM_RELIEF,
8430 PBM_ALGORITHM,
8431 PBM_HEURISTIC_MASK,
4a8e312c 8432 PBM_MASK,
be0b1fac
GM
8433 PBM_FOREGROUND,
8434 PBM_BACKGROUND,
333b20bb
GM
8435 PBM_LAST
8436};
8437
8438/* Vector of image_keyword structures describing the format
8439 of valid user-defined image specifications. */
8440
8441static struct image_keyword pbm_format[PBM_LAST] =
8442{
8443 {":type", IMAGE_SYMBOL_VALUE, 1},
63cec32f
GM
8444 {":file", IMAGE_STRING_VALUE, 0},
8445 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8446 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8447 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8448 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8449 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8450 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
be0b1fac 8451 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
8452 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8453 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8454};
8455
8456/* Structure describing the image type `pbm'. */
8457
8458static struct image_type pbm_type =
8459{
8460 &Qpbm,
8461 pbm_image_p,
8462 pbm_load,
8463 x_clear_image,
8464 NULL
8465};
8466
8467
8468/* Return non-zero if OBJECT is a valid PBM image specification. */
8469
8470static int
8471pbm_image_p (object)
8472 Lisp_Object object;
8473{
8474 struct image_keyword fmt[PBM_LAST];
8475
8476 bcopy (pbm_format, fmt, sizeof fmt);
8477
7c7ff7f5 8478 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
333b20bb 8479 return 0;
63cec32f
GM
8480
8481 /* Must specify either :data or :file. */
8482 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
333b20bb
GM
8483}
8484
8485
63cec32f
GM
8486/* Scan a decimal number from *S and return it. Advance *S while
8487 reading the number. END is the end of the string. Value is -1 at
8488 end of input. */
333b20bb
GM
8489
8490static int
63cec32f
GM
8491pbm_scan_number (s, end)
8492 unsigned char **s, *end;
333b20bb 8493{
8ec8a5ec 8494 int c = 0, val = -1;
333b20bb 8495
63cec32f 8496 while (*s < end)
333b20bb
GM
8497 {
8498 /* Skip white-space. */
63cec32f 8499 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
8500 ;
8501
8502 if (c == '#')
8503 {
8504 /* Skip comment to end of line. */
63cec32f 8505 while (*s < end && (c = *(*s)++, c != '\n'))
333b20bb
GM
8506 ;
8507 }
8508 else if (isdigit (c))
8509 {
8510 /* Read decimal number. */
8511 val = c - '0';
63cec32f 8512 while (*s < end && (c = *(*s)++, isdigit (c)))
333b20bb
GM
8513 val = 10 * val + c - '0';
8514 break;
8515 }
8516 else
8517 break;
8518 }
8519
8520 return val;
8521}
8522
8523
8524/* Load PBM image IMG for use on frame F. */
8525
8526static int
8527pbm_load (f, img)
8528 struct frame *f;
8529 struct image *img;
8530{
333b20bb 8531 int raw_p, x, y;
b6d7acec 8532 int width, height, max_color_idx = 0;
333b20bb
GM
8533 XImage *ximg;
8534 Lisp_Object file, specified_file;
8535 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
8536 struct gcpro gcpro1;
63cec32f
GM
8537 unsigned char *contents = NULL;
8538 unsigned char *end, *p;
8539 int size;
333b20bb
GM
8540
8541 specified_file = image_spec_value (img->spec, QCfile, NULL);
63cec32f 8542 file = Qnil;
333b20bb 8543 GCPRO1 (file);
333b20bb 8544
63cec32f 8545 if (STRINGP (specified_file))
333b20bb 8546 {
63cec32f
GM
8547 file = x_find_image_file (specified_file);
8548 if (!STRINGP (file))
8549 {
8550 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8551 UNGCPRO;
8552 return 0;
8553 }
333b20bb 8554
5be6c3b0 8555 contents = slurp_file (XSTRING (file)->data, &size);
63cec32f
GM
8556 if (contents == NULL)
8557 {
8558 image_error ("Error reading `%s'", file, Qnil);
8559 UNGCPRO;
8560 return 0;
8561 }
8562
8563 p = contents;
8564 end = contents + size;
8565 }
8566 else
333b20bb 8567 {
63cec32f
GM
8568 Lisp_Object data;
8569 data = image_spec_value (img->spec, QCdata, NULL);
8570 p = XSTRING (data)->data;
8571 end = p + STRING_BYTES (XSTRING (data));
333b20bb
GM
8572 }
8573
63cec32f
GM
8574 /* Check magic number. */
8575 if (end - p < 2 || *p++ != 'P')
333b20bb 8576 {
45158a91 8577 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f
GM
8578 error:
8579 xfree (contents);
333b20bb
GM
8580 UNGCPRO;
8581 return 0;
8582 }
8583
63cec32f 8584 switch (*p++)
333b20bb
GM
8585 {
8586 case '1':
8587 raw_p = 0, type = PBM_MONO;
8588 break;
8589
8590 case '2':
8591 raw_p = 0, type = PBM_GRAY;
8592 break;
8593
8594 case '3':
8595 raw_p = 0, type = PBM_COLOR;
8596 break;
8597
8598 case '4':
8599 raw_p = 1, type = PBM_MONO;
8600 break;
8601
8602 case '5':
8603 raw_p = 1, type = PBM_GRAY;
8604 break;
8605
8606 case '6':
8607 raw_p = 1, type = PBM_COLOR;
8608 break;
8609
8610 default:
45158a91 8611 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f 8612 goto error;
333b20bb
GM
8613 }
8614
8615 /* Read width, height, maximum color-component. Characters
8616 starting with `#' up to the end of a line are ignored. */
63cec32f
GM
8617 width = pbm_scan_number (&p, end);
8618 height = pbm_scan_number (&p, end);
333b20bb
GM
8619
8620 if (type != PBM_MONO)
8621 {
63cec32f 8622 max_color_idx = pbm_scan_number (&p, end);
333b20bb
GM
8623 if (raw_p && max_color_idx > 255)
8624 max_color_idx = 255;
8625 }
8626
63cec32f
GM
8627 if (width < 0
8628 || height < 0
333b20bb 8629 || (type != PBM_MONO && max_color_idx < 0))
63cec32f 8630 goto error;
333b20bb 8631
45158a91 8632 if (!x_create_x_image_and_pixmap (f, width, height, 0,
333b20bb 8633 &ximg, &img->pixmap))
28c7826c 8634 goto error;
333b20bb
GM
8635
8636 /* Initialize the color hash table. */
8637 init_color_table ();
8638
8639 if (type == PBM_MONO)
8640 {
8641 int c = 0, g;
be0b1fac
GM
8642 struct image_keyword fmt[PBM_LAST];
8643 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
8644 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
8645
8646 /* Parse the image specification. */
8647 bcopy (pbm_format, fmt, sizeof fmt);
8648 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
8649
8650 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
8651 if (fmt[PBM_FOREGROUND].count
8652 && STRINGP (fmt[PBM_FOREGROUND].value))
be0b1fac 8653 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
6f1be3b9
GM
8654 if (fmt[PBM_BACKGROUND].count
8655 && STRINGP (fmt[PBM_BACKGROUND].value))
f20a3b7a
MB
8656 {
8657 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
8658 img->background = bg;
8659 img->background_valid = 1;
8660 }
333b20bb
GM
8661
8662 for (y = 0; y < height; ++y)
8663 for (x = 0; x < width; ++x)
8664 {
8665 if (raw_p)
8666 {
8667 if ((x & 7) == 0)
63cec32f 8668 c = *p++;
333b20bb
GM
8669 g = c & 0x80;
8670 c <<= 1;
8671 }
8672 else
63cec32f 8673 g = pbm_scan_number (&p, end);
333b20bb 8674
be0b1fac 8675 XPutPixel (ximg, x, y, g ? fg : bg);
333b20bb
GM
8676 }
8677 }
8678 else
8679 {
8680 for (y = 0; y < height; ++y)
8681 for (x = 0; x < width; ++x)
8682 {
8683 int r, g, b;
8684
8685 if (type == PBM_GRAY)
63cec32f 8686 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
333b20bb
GM
8687 else if (raw_p)
8688 {
63cec32f
GM
8689 r = *p++;
8690 g = *p++;
8691 b = *p++;
333b20bb
GM
8692 }
8693 else
8694 {
63cec32f
GM
8695 r = pbm_scan_number (&p, end);
8696 g = pbm_scan_number (&p, end);
8697 b = pbm_scan_number (&p, end);
333b20bb
GM
8698 }
8699
8700 if (r < 0 || g < 0 || b < 0)
8701 {
333b20bb
GM
8702 xfree (ximg->data);
8703 ximg->data = NULL;
8704 XDestroyImage (ximg);
45158a91
GM
8705 image_error ("Invalid pixel value in image `%s'",
8706 img->spec, Qnil);
63cec32f 8707 goto error;
333b20bb
GM
8708 }
8709
8710 /* RGB values are now in the range 0..max_color_idx.
8711 Scale this to the range 0..0xffff supported by X. */
8712 r = (double) r * 65535 / max_color_idx;
8713 g = (double) g * 65535 / max_color_idx;
8714 b = (double) b * 65535 / max_color_idx;
8715 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8716 }
8717 }
8718
333b20bb
GM
8719 /* Store in IMG->colors the colors allocated for the image, and
8720 free the color table. */
8721 img->colors = colors_in_color_table (&img->ncolors);
8722 free_color_table ();
f20a3b7a
MB
8723
8724 /* Maybe fill in the background field while we have ximg handy. */
8725 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8726 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
8727
8728 /* Put the image into a pixmap. */
8729 x_put_x_image (f, ximg, img->pixmap, width, height);
8730 x_destroy_x_image (ximg);
333b20bb
GM
8731
8732 img->width = width;
8733 img->height = height;
8734
8735 UNGCPRO;
63cec32f 8736 xfree (contents);
333b20bb
GM
8737 return 1;
8738}
8739
8740
8741\f
8742/***********************************************************************
8743 PNG
8744 ***********************************************************************/
8745
8746#if HAVE_PNG
8747
8748#include <png.h>
8749
8750/* Function prototypes. */
8751
8752static int png_image_p P_ ((Lisp_Object object));
8753static int png_load P_ ((struct frame *f, struct image *img));
8754
8755/* The symbol `png' identifying images of this type. */
8756
8757Lisp_Object Qpng;
8758
8759/* Indices of image specification fields in png_format, below. */
8760
8761enum png_keyword_index
8762{
8763 PNG_TYPE,
63448a4d 8764 PNG_DATA,
333b20bb
GM
8765 PNG_FILE,
8766 PNG_ASCENT,
8767 PNG_MARGIN,
8768 PNG_RELIEF,
8769 PNG_ALGORITHM,
8770 PNG_HEURISTIC_MASK,
4a8e312c 8771 PNG_MASK,
f20a3b7a 8772 PNG_BACKGROUND,
333b20bb
GM
8773 PNG_LAST
8774};
8775
8776/* Vector of image_keyword structures describing the format
8777 of valid user-defined image specifications. */
8778
8779static struct image_keyword png_format[PNG_LAST] =
8780{
8781 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8782 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8783 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8784 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8785 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8786 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8787 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8788 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 8789 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a 8790 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8791};
8792
06482119 8793/* Structure describing the image type `png'. */
333b20bb
GM
8794
8795static struct image_type png_type =
8796{
8797 &Qpng,
8798 png_image_p,
8799 png_load,
8800 x_clear_image,
8801 NULL
8802};
8803
8804
8805/* Return non-zero if OBJECT is a valid PNG image specification. */
8806
8807static int
8808png_image_p (object)
8809 Lisp_Object object;
8810{
8811 struct image_keyword fmt[PNG_LAST];
8812 bcopy (png_format, fmt, sizeof fmt);
8813
7c7ff7f5 8814 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
333b20bb 8815 return 0;
63448a4d 8816
63cec32f
GM
8817 /* Must specify either the :data or :file keyword. */
8818 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
333b20bb
GM
8819}
8820
8821
8822/* Error and warning handlers installed when the PNG library
8823 is initialized. */
8824
8825static void
8826my_png_error (png_ptr, msg)
8827 png_struct *png_ptr;
8828 char *msg;
8829{
8830 xassert (png_ptr != NULL);
8831 image_error ("PNG error: %s", build_string (msg), Qnil);
8832 longjmp (png_ptr->jmpbuf, 1);
8833}
8834
8835
8836static void
8837my_png_warning (png_ptr, msg)
8838 png_struct *png_ptr;
8839 char *msg;
8840{
8841 xassert (png_ptr != NULL);
8842 image_error ("PNG warning: %s", build_string (msg), Qnil);
8843}
8844
5ad6a5fb
GM
8845/* Memory source for PNG decoding. */
8846
63448a4d
WP
8847struct png_memory_storage
8848{
5ad6a5fb
GM
8849 unsigned char *bytes; /* The data */
8850 size_t len; /* How big is it? */
8851 int index; /* Where are we? */
63448a4d
WP
8852};
8853
5ad6a5fb
GM
8854
8855/* Function set as reader function when reading PNG image from memory.
8856 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8857 bytes from the input to DATA. */
8858
63448a4d 8859static void
5ad6a5fb
GM
8860png_read_from_memory (png_ptr, data, length)
8861 png_structp png_ptr;
8862 png_bytep data;
8863 png_size_t length;
63448a4d 8864{
5ad6a5fb
GM
8865 struct png_memory_storage *tbr
8866 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
63448a4d 8867
5ad6a5fb
GM
8868 if (length > tbr->len - tbr->index)
8869 png_error (png_ptr, "Read error");
8870
8871 bcopy (tbr->bytes + tbr->index, data, length);
8872 tbr->index = tbr->index + length;
63448a4d 8873}
333b20bb
GM
8874
8875/* Load PNG image IMG for use on frame F. Value is non-zero if
8876 successful. */
8877
8878static int
8879png_load (f, img)
8880 struct frame *f;
8881 struct image *img;
8882{
8883 Lisp_Object file, specified_file;
63448a4d 8884 Lisp_Object specified_data;
b6d7acec 8885 int x, y, i;
333b20bb
GM
8886 XImage *ximg, *mask_img = NULL;
8887 struct gcpro gcpro1;
8888 png_struct *png_ptr = NULL;
8889 png_info *info_ptr = NULL, *end_info = NULL;
8ec8a5ec 8890 FILE *volatile fp = NULL;
333b20bb 8891 png_byte sig[8];
8ec8a5ec
GM
8892 png_byte * volatile pixels = NULL;
8893 png_byte ** volatile rows = NULL;
333b20bb
GM
8894 png_uint_32 width, height;
8895 int bit_depth, color_type, interlace_type;
8896 png_byte channels;
8897 png_uint_32 row_bytes;
8898 int transparent_p;
8899 char *gamma_str;
8900 double screen_gamma, image_gamma;
8901 int intent;
63448a4d 8902 struct png_memory_storage tbr; /* Data to be read */
333b20bb
GM
8903
8904 /* Find out what file to load. */
8905 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8906 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8907 file = Qnil;
8908 GCPRO1 (file);
333b20bb 8909
63448a4d 8910 if (NILP (specified_data))
5ad6a5fb
GM
8911 {
8912 file = x_find_image_file (specified_file);
8913 if (!STRINGP (file))
63448a4d 8914 {
45158a91 8915 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
8916 UNGCPRO;
8917 return 0;
8918 }
333b20bb 8919
5ad6a5fb
GM
8920 /* Open the image file. */
8921 fp = fopen (XSTRING (file)->data, "rb");
8922 if (!fp)
8923 {
45158a91 8924 image_error ("Cannot open image file `%s'", file, Qnil);
5ad6a5fb
GM
8925 UNGCPRO;
8926 fclose (fp);
8927 return 0;
8928 }
63448a4d 8929
5ad6a5fb
GM
8930 /* Check PNG signature. */
8931 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8932 || !png_check_sig (sig, sizeof sig))
8933 {
45158a91 8934 image_error ("Not a PNG file: `%s'", file, Qnil);
5ad6a5fb
GM
8935 UNGCPRO;
8936 fclose (fp);
8937 return 0;
63448a4d 8938 }
5ad6a5fb 8939 }
63448a4d 8940 else
5ad6a5fb
GM
8941 {
8942 /* Read from memory. */
8943 tbr.bytes = XSTRING (specified_data)->data;
8944 tbr.len = STRING_BYTES (XSTRING (specified_data));
8945 tbr.index = 0;
63448a4d 8946
5ad6a5fb
GM
8947 /* Check PNG signature. */
8948 if (tbr.len < sizeof sig
8949 || !png_check_sig (tbr.bytes, sizeof sig))
8950 {
45158a91 8951 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5ad6a5fb
GM
8952 UNGCPRO;
8953 return 0;
63448a4d 8954 }
333b20bb 8955
5ad6a5fb
GM
8956 /* Need to skip past the signature. */
8957 tbr.bytes += sizeof (sig);
8958 }
8959
333b20bb
GM
8960 /* Initialize read and info structs for PNG lib. */
8961 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8962 my_png_error, my_png_warning);
8963 if (!png_ptr)
8964 {
63448a4d 8965 if (fp) fclose (fp);
333b20bb
GM
8966 UNGCPRO;
8967 return 0;
8968 }
8969
8970 info_ptr = png_create_info_struct (png_ptr);
8971 if (!info_ptr)
8972 {
8973 png_destroy_read_struct (&png_ptr, NULL, NULL);
63448a4d 8974 if (fp) fclose (fp);
333b20bb
GM
8975 UNGCPRO;
8976 return 0;
8977 }
8978
8979 end_info = png_create_info_struct (png_ptr);
8980 if (!end_info)
8981 {
8982 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
63448a4d 8983 if (fp) fclose (fp);
333b20bb
GM
8984 UNGCPRO;
8985 return 0;
8986 }
8987
8988 /* Set error jump-back. We come back here when the PNG library
8989 detects an error. */
8990 if (setjmp (png_ptr->jmpbuf))
8991 {
8992 error:
8993 if (png_ptr)
8994 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8995 xfree (pixels);
8996 xfree (rows);
63448a4d 8997 if (fp) fclose (fp);
333b20bb
GM
8998 UNGCPRO;
8999 return 0;
9000 }
9001
9002 /* Read image info. */
63448a4d 9003 if (!NILP (specified_data))
5ad6a5fb 9004 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
63448a4d 9005 else
5ad6a5fb 9006 png_init_io (png_ptr, fp);
63448a4d 9007
333b20bb
GM
9008 png_set_sig_bytes (png_ptr, sizeof sig);
9009 png_read_info (png_ptr, info_ptr);
9010 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
9011 &interlace_type, NULL, NULL);
9012
9013 /* If image contains simply transparency data, we prefer to
9014 construct a clipping mask. */
9015 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
9016 transparent_p = 1;
9017 else
9018 transparent_p = 0;
9019
9020 /* This function is easier to write if we only have to handle
9021 one data format: RGB or RGBA with 8 bits per channel. Let's
9022 transform other formats into that format. */
9023
9024 /* Strip more than 8 bits per channel. */
9025 if (bit_depth == 16)
9026 png_set_strip_16 (png_ptr);
9027
9028 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
9029 if available. */
9030 png_set_expand (png_ptr);
9031
9032 /* Convert grayscale images to RGB. */
9033 if (color_type == PNG_COLOR_TYPE_GRAY
9034 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9035 png_set_gray_to_rgb (png_ptr);
9036
d4405ed7 9037 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
333b20bb
GM
9038
9039 /* Tell the PNG lib to handle gamma correction for us. */
9040
6c1aa34d 9041#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
333b20bb 9042 if (png_get_sRGB (png_ptr, info_ptr, &intent))
d4405ed7
RS
9043 /* The libpng documentation says this is right in this case. */
9044 png_set_gamma (png_ptr, screen_gamma, 0.45455);
6c1aa34d
GM
9045 else
9046#endif
9047 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
333b20bb
GM
9048 /* Image contains gamma information. */
9049 png_set_gamma (png_ptr, screen_gamma, image_gamma);
9050 else
d4405ed7
RS
9051 /* Use the standard default for the image gamma. */
9052 png_set_gamma (png_ptr, screen_gamma, 0.45455);
333b20bb
GM
9053
9054 /* Handle alpha channel by combining the image with a background
9055 color. Do this only if a real alpha channel is supplied. For
9056 simple transparency, we prefer a clipping mask. */
9057 if (!transparent_p)
9058 {
f20a3b7a
MB
9059 png_color_16 *image_bg;
9060 Lisp_Object specified_bg
9061 = image_spec_value (img->spec, QCbackground, NULL);
9062
f2f0a644 9063 if (STRINGP (specified_bg))
f20a3b7a
MB
9064 /* The user specified `:background', use that. */
9065 {
9066 XColor color;
f2f0a644 9067 if (x_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
f20a3b7a
MB
9068 {
9069 png_color_16 user_bg;
9070
9071 bzero (&user_bg, sizeof user_bg);
9072 user_bg.red = color.red;
9073 user_bg.green = color.green;
9074 user_bg.blue = color.blue;
333b20bb 9075
f20a3b7a
MB
9076 png_set_background (png_ptr, &user_bg,
9077 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9078 }
9079 }
9080 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
333b20bb
GM
9081 /* Image contains a background color with which to
9082 combine the image. */
f20a3b7a 9083 png_set_background (png_ptr, image_bg,
333b20bb
GM
9084 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
9085 else
9086 {
9087 /* Image does not contain a background color with which
9088 to combine the image data via an alpha channel. Use
9089 the frame's background instead. */
9090 XColor color;
9091 Colormap cmap;
9092 png_color_16 frame_background;
9093
9b2956e2 9094 cmap = FRAME_X_COLORMAP (f);
333b20bb 9095 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a31fedb7 9096 x_query_color (f, &color);
333b20bb
GM
9097
9098 bzero (&frame_background, sizeof frame_background);
9099 frame_background.red = color.red;
9100 frame_background.green = color.green;
9101 frame_background.blue = color.blue;
9102
9103 png_set_background (png_ptr, &frame_background,
9104 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9105 }
9106 }
9107
9108 /* Update info structure. */
9109 png_read_update_info (png_ptr, info_ptr);
9110
9111 /* Get number of channels. Valid values are 1 for grayscale images
9112 and images with a palette, 2 for grayscale images with transparency
9113 information (alpha channel), 3 for RGB images, and 4 for RGB
9114 images with alpha channel, i.e. RGBA. If conversions above were
9115 sufficient we should only have 3 or 4 channels here. */
9116 channels = png_get_channels (png_ptr, info_ptr);
9117 xassert (channels == 3 || channels == 4);
9118
9119 /* Number of bytes needed for one row of the image. */
9120 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
9121
9122 /* Allocate memory for the image. */
9123 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
9124 rows = (png_byte **) xmalloc (height * sizeof *rows);
9125 for (i = 0; i < height; ++i)
9126 rows[i] = pixels + i * row_bytes;
9127
9128 /* Read the entire image. */
9129 png_read_image (png_ptr, rows);
9130 png_read_end (png_ptr, info_ptr);
5ad6a5fb
GM
9131 if (fp)
9132 {
9133 fclose (fp);
9134 fp = NULL;
9135 }
333b20bb 9136
333b20bb 9137 /* Create the X image and pixmap. */
45158a91 9138 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
333b20bb 9139 &img->pixmap))
28c7826c 9140 goto error;
333b20bb
GM
9141
9142 /* Create an image and pixmap serving as mask if the PNG image
9143 contains an alpha channel. */
9144 if (channels == 4
9145 && !transparent_p
45158a91 9146 && !x_create_x_image_and_pixmap (f, width, height, 1,
333b20bb
GM
9147 &mask_img, &img->mask))
9148 {
9149 x_destroy_x_image (ximg);
9150 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 9151 img->pixmap = None;
333b20bb
GM
9152 goto error;
9153 }
9154
9155 /* Fill the X image and mask from PNG data. */
9156 init_color_table ();
9157
9158 for (y = 0; y < height; ++y)
9159 {
9160 png_byte *p = rows[y];
9161
9162 for (x = 0; x < width; ++x)
9163 {
9164 unsigned r, g, b;
9165
9166 r = *p++ << 8;
9167 g = *p++ << 8;
9168 b = *p++ << 8;
9169 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9170
9171 /* An alpha channel, aka mask channel, associates variable
9172 transparency with an image. Where other image formats
9173 support binary transparency---fully transparent or fully
9174 opaque---PNG allows up to 254 levels of partial transparency.
9175 The PNG library implements partial transparency by combining
9176 the image with a specified background color.
9177
9178 I'm not sure how to handle this here nicely: because the
9179 background on which the image is displayed may change, for
9180 real alpha channel support, it would be necessary to create
9181 a new image for each possible background.
9182
9183 What I'm doing now is that a mask is created if we have
9184 boolean transparency information. Otherwise I'm using
9185 the frame's background color to combine the image with. */
9186
9187 if (channels == 4)
9188 {
9189 if (mask_img)
9190 XPutPixel (mask_img, x, y, *p > 0);
9191 ++p;
9192 }
9193 }
9194 }
9195
f20a3b7a
MB
9196 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9197 /* Set IMG's background color from the PNG image, unless the user
9198 overrode it. */
9199 {
9200 png_color_16 *bg;
9201 if (png_get_bKGD (png_ptr, info_ptr, &bg))
9202 {
f2f0a644 9203 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
f20a3b7a
MB
9204 img->background_valid = 1;
9205 }
9206 }
9207
333b20bb
GM
9208 /* Remember colors allocated for this image. */
9209 img->colors = colors_in_color_table (&img->ncolors);
9210 free_color_table ();
9211
9212 /* Clean up. */
9213 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9214 xfree (rows);
9215 xfree (pixels);
9216
9217 img->width = width;
9218 img->height = height;
9219
f20a3b7a
MB
9220 /* Maybe fill in the background field while we have ximg handy. */
9221 IMAGE_BACKGROUND (img, f, ximg);
9222
333b20bb
GM
9223 /* Put the image into the pixmap, then free the X image and its buffer. */
9224 x_put_x_image (f, ximg, img->pixmap, width, height);
9225 x_destroy_x_image (ximg);
9226
9227 /* Same for the mask. */
9228 if (mask_img)
9229 {
f20a3b7a
MB
9230 /* Fill in the background_transparent field while we have the mask
9231 handy. */
9232 image_background_transparent (img, f, mask_img);
9233
333b20bb
GM
9234 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9235 x_destroy_x_image (mask_img);
9236 }
9237
333b20bb
GM
9238 UNGCPRO;
9239 return 1;
9240}
9241
9242#endif /* HAVE_PNG != 0 */
9243
9244
9245\f
9246/***********************************************************************
9247 JPEG
9248 ***********************************************************************/
9249
9250#if HAVE_JPEG
9251
ba06aba4
GM
9252/* Work around a warning about HAVE_STDLIB_H being redefined in
9253 jconfig.h. */
9254#ifdef HAVE_STDLIB_H
9255#define HAVE_STDLIB_H_1
9256#undef HAVE_STDLIB_H
9257#endif /* HAVE_STLIB_H */
9258
333b20bb
GM
9259#include <jpeglib.h>
9260#include <jerror.h>
9261#include <setjmp.h>
9262
ba06aba4
GM
9263#ifdef HAVE_STLIB_H_1
9264#define HAVE_STDLIB_H 1
9265#endif
9266
333b20bb
GM
9267static int jpeg_image_p P_ ((Lisp_Object object));
9268static int jpeg_load P_ ((struct frame *f, struct image *img));
9269
9270/* The symbol `jpeg' identifying images of this type. */
9271
9272Lisp_Object Qjpeg;
9273
9274/* Indices of image specification fields in gs_format, below. */
9275
9276enum jpeg_keyword_index
9277{
9278 JPEG_TYPE,
8e39770a 9279 JPEG_DATA,
333b20bb
GM
9280 JPEG_FILE,
9281 JPEG_ASCENT,
9282 JPEG_MARGIN,
9283 JPEG_RELIEF,
9284 JPEG_ALGORITHM,
9285 JPEG_HEURISTIC_MASK,
4a8e312c 9286 JPEG_MASK,
f20a3b7a 9287 JPEG_BACKGROUND,
333b20bb
GM
9288 JPEG_LAST
9289};
9290
9291/* Vector of image_keyword structures describing the format
9292 of valid user-defined image specifications. */
9293
9294static struct image_keyword jpeg_format[JPEG_LAST] =
9295{
9296 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9297 {":data", IMAGE_STRING_VALUE, 0},
8e39770a 9298 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9299 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9300 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9301 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9302 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9303 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9304 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9305 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9306};
9307
9308/* Structure describing the image type `jpeg'. */
9309
9310static struct image_type jpeg_type =
9311{
9312 &Qjpeg,
9313 jpeg_image_p,
9314 jpeg_load,
9315 x_clear_image,
9316 NULL
9317};
9318
9319
9320/* Return non-zero if OBJECT is a valid JPEG image specification. */
9321
9322static int
9323jpeg_image_p (object)
9324 Lisp_Object object;
9325{
9326 struct image_keyword fmt[JPEG_LAST];
9327
9328 bcopy (jpeg_format, fmt, sizeof fmt);
9329
7c7ff7f5 9330 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
333b20bb 9331 return 0;
8e39770a 9332
63cec32f
GM
9333 /* Must specify either the :data or :file keyword. */
9334 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
333b20bb
GM
9335}
9336
8e39770a 9337
333b20bb
GM
9338struct my_jpeg_error_mgr
9339{
9340 struct jpeg_error_mgr pub;
9341 jmp_buf setjmp_buffer;
9342};
9343
e3130015 9344
333b20bb
GM
9345static void
9346my_error_exit (cinfo)
9347 j_common_ptr cinfo;
9348{
9349 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
9350 longjmp (mgr->setjmp_buffer, 1);
9351}
9352
e3130015 9353
8e39770a
GM
9354/* Init source method for JPEG data source manager. Called by
9355 jpeg_read_header() before any data is actually read. See
9356 libjpeg.doc from the JPEG lib distribution. */
9357
9358static void
9359our_init_source (cinfo)
9360 j_decompress_ptr cinfo;
9361{
9362}
9363
9364
9365/* Fill input buffer method for JPEG data source manager. Called
9366 whenever more data is needed. We read the whole image in one step,
9367 so this only adds a fake end of input marker at the end. */
9368
9369static boolean
9370our_fill_input_buffer (cinfo)
9371 j_decompress_ptr cinfo;
9372{
9373 /* Insert a fake EOI marker. */
9374 struct jpeg_source_mgr *src = cinfo->src;
9375 static JOCTET buffer[2];
9376
9377 buffer[0] = (JOCTET) 0xFF;
9378 buffer[1] = (JOCTET) JPEG_EOI;
9379
9380 src->next_input_byte = buffer;
9381 src->bytes_in_buffer = 2;
9382 return TRUE;
9383}
9384
9385
9386/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
9387 is the JPEG data source manager. */
9388
9389static void
9390our_skip_input_data (cinfo, num_bytes)
9391 j_decompress_ptr cinfo;
9392 long num_bytes;
9393{
9394 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
9395
9396 if (src)
9397 {
9398 if (num_bytes > src->bytes_in_buffer)
5ad6a5fb 9399 ERREXIT (cinfo, JERR_INPUT_EOF);
8e39770a
GM
9400
9401 src->bytes_in_buffer -= num_bytes;
9402 src->next_input_byte += num_bytes;
9403 }
9404}
9405
9406
9407/* Method to terminate data source. Called by
9408 jpeg_finish_decompress() after all data has been processed. */
9409
9410static void
9411our_term_source (cinfo)
9412 j_decompress_ptr cinfo;
9413{
9414}
9415
9416
9417/* Set up the JPEG lib for reading an image from DATA which contains
9418 LEN bytes. CINFO is the decompression info structure created for
9419 reading the image. */
9420
9421static void
9422jpeg_memory_src (cinfo, data, len)
9423 j_decompress_ptr cinfo;
9424 JOCTET *data;
9425 unsigned int len;
9426{
9427 struct jpeg_source_mgr *src;
9428
9429 if (cinfo->src == NULL)
9430 {
9431 /* First time for this JPEG object? */
9432 cinfo->src = (struct jpeg_source_mgr *)
9433 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
9434 sizeof (struct jpeg_source_mgr));
9435 src = (struct jpeg_source_mgr *) cinfo->src;
9436 src->next_input_byte = data;
9437 }
9438
9439 src = (struct jpeg_source_mgr *) cinfo->src;
9440 src->init_source = our_init_source;
9441 src->fill_input_buffer = our_fill_input_buffer;
9442 src->skip_input_data = our_skip_input_data;
9443 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
9444 src->term_source = our_term_source;
9445 src->bytes_in_buffer = len;
9446 src->next_input_byte = data;
9447}
9448
5ad6a5fb 9449
333b20bb
GM
9450/* Load image IMG for use on frame F. Patterned after example.c
9451 from the JPEG lib. */
9452
9453static int
9454jpeg_load (f, img)
9455 struct frame *f;
9456 struct image *img;
9457{
9458 struct jpeg_decompress_struct cinfo;
9459 struct my_jpeg_error_mgr mgr;
9460 Lisp_Object file, specified_file;
8e39770a 9461 Lisp_Object specified_data;
8ec8a5ec 9462 FILE * volatile fp = NULL;
333b20bb
GM
9463 JSAMPARRAY buffer;
9464 int row_stride, x, y;
9465 XImage *ximg = NULL;
b6d7acec 9466 int rc;
333b20bb
GM
9467 unsigned long *colors;
9468 int width, height;
9469 struct gcpro gcpro1;
9470
9471 /* Open the JPEG file. */
9472 specified_file = image_spec_value (img->spec, QCfile, NULL);
8e39770a 9473 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9474 file = Qnil;
9475 GCPRO1 (file);
8e39770a 9476
8e39770a 9477 if (NILP (specified_data))
333b20bb 9478 {
8e39770a 9479 file = x_find_image_file (specified_file);
8e39770a
GM
9480 if (!STRINGP (file))
9481 {
45158a91 9482 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8e39770a
GM
9483 UNGCPRO;
9484 return 0;
9485 }
333b20bb 9486
8e39770a
GM
9487 fp = fopen (XSTRING (file)->data, "r");
9488 if (fp == NULL)
9489 {
9490 image_error ("Cannot open `%s'", file, Qnil);
9491 UNGCPRO;
9492 return 0;
9493 }
333b20bb
GM
9494 }
9495
5ad6a5fb
GM
9496 /* Customize libjpeg's error handling to call my_error_exit when an
9497 error is detected. This function will perform a longjmp. */
333b20bb 9498 cinfo.err = jpeg_std_error (&mgr.pub);
14358466 9499 mgr.pub.error_exit = my_error_exit;
333b20bb
GM
9500
9501 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
9502 {
5ad6a5fb
GM
9503 if (rc == 1)
9504 {
9505 /* Called from my_error_exit. Display a JPEG error. */
9506 char buffer[JMSG_LENGTH_MAX];
9507 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
45158a91 9508 image_error ("Error reading JPEG image `%s': %s", img->spec,
5ad6a5fb
GM
9509 build_string (buffer));
9510 }
333b20bb
GM
9511
9512 /* Close the input file and destroy the JPEG object. */
5ad6a5fb 9513 if (fp)
8ec8a5ec 9514 fclose ((FILE *) fp);
333b20bb
GM
9515 jpeg_destroy_decompress (&cinfo);
9516
5ad6a5fb
GM
9517 /* If we already have an XImage, free that. */
9518 x_destroy_x_image (ximg);
333b20bb 9519
5ad6a5fb
GM
9520 /* Free pixmap and colors. */
9521 x_clear_image (f, img);
333b20bb 9522
5ad6a5fb
GM
9523 UNGCPRO;
9524 return 0;
333b20bb
GM
9525 }
9526
9527 /* Create the JPEG decompression object. Let it read from fp.
63448a4d 9528 Read the JPEG image header. */
333b20bb 9529 jpeg_create_decompress (&cinfo);
8e39770a
GM
9530
9531 if (NILP (specified_data))
8ec8a5ec 9532 jpeg_stdio_src (&cinfo, (FILE *) fp);
8e39770a
GM
9533 else
9534 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
9535 STRING_BYTES (XSTRING (specified_data)));
63448a4d 9536
333b20bb
GM
9537 jpeg_read_header (&cinfo, TRUE);
9538
9539 /* Customize decompression so that color quantization will be used.
63448a4d 9540 Start decompression. */
333b20bb
GM
9541 cinfo.quantize_colors = TRUE;
9542 jpeg_start_decompress (&cinfo);
9543 width = img->width = cinfo.output_width;
9544 height = img->height = cinfo.output_height;
9545
333b20bb 9546 /* Create X image and pixmap. */
45158a91 9547 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
28c7826c 9548 longjmp (mgr.setjmp_buffer, 2);
333b20bb
GM
9549
9550 /* Allocate colors. When color quantization is used,
5ad6a5fb
GM
9551 cinfo.actual_number_of_colors has been set with the number of
9552 colors generated, and cinfo.colormap is a two-dimensional array
9553 of color indices in the range 0..cinfo.actual_number_of_colors.
9554 No more than 255 colors will be generated. */
333b20bb 9555 {
5ad6a5fb
GM
9556 int i, ir, ig, ib;
9557
9558 if (cinfo.out_color_components > 2)
9559 ir = 0, ig = 1, ib = 2;
9560 else if (cinfo.out_color_components > 1)
9561 ir = 0, ig = 1, ib = 0;
9562 else
9563 ir = 0, ig = 0, ib = 0;
9564
9565 /* Use the color table mechanism because it handles colors that
9566 cannot be allocated nicely. Such colors will be replaced with
9567 a default color, and we don't have to care about which colors
9568 can be freed safely, and which can't. */
9569 init_color_table ();
9570 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
9571 * sizeof *colors);
333b20bb 9572
5ad6a5fb
GM
9573 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
9574 {
9575 /* Multiply RGB values with 255 because X expects RGB values
9576 in the range 0..0xffff. */
9577 int r = cinfo.colormap[ir][i] << 8;
9578 int g = cinfo.colormap[ig][i] << 8;
9579 int b = cinfo.colormap[ib][i] << 8;
9580 colors[i] = lookup_rgb_color (f, r, g, b);
9581 }
333b20bb 9582
5ad6a5fb
GM
9583 /* Remember those colors actually allocated. */
9584 img->colors = colors_in_color_table (&img->ncolors);
9585 free_color_table ();
333b20bb
GM
9586 }
9587
9588 /* Read pixels. */
9589 row_stride = width * cinfo.output_components;
9590 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
5ad6a5fb 9591 row_stride, 1);
333b20bb
GM
9592 for (y = 0; y < height; ++y)
9593 {
5ad6a5fb
GM
9594 jpeg_read_scanlines (&cinfo, buffer, 1);
9595 for (x = 0; x < cinfo.output_width; ++x)
9596 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
333b20bb
GM
9597 }
9598
9599 /* Clean up. */
9600 jpeg_finish_decompress (&cinfo);
9601 jpeg_destroy_decompress (&cinfo);
5ad6a5fb 9602 if (fp)
8ec8a5ec 9603 fclose ((FILE *) fp);
f20a3b7a
MB
9604
9605 /* Maybe fill in the background field while we have ximg handy. */
9606 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9607 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9608
9609 /* Put the image into the pixmap. */
9610 x_put_x_image (f, ximg, img->pixmap, width, height);
9611 x_destroy_x_image (ximg);
333b20bb
GM
9612 UNGCPRO;
9613 return 1;
9614}
9615
9616#endif /* HAVE_JPEG */
9617
9618
9619\f
9620/***********************************************************************
9621 TIFF
9622 ***********************************************************************/
9623
9624#if HAVE_TIFF
9625
cf4790ad 9626#include <tiffio.h>
333b20bb
GM
9627
9628static int tiff_image_p P_ ((Lisp_Object object));
9629static int tiff_load P_ ((struct frame *f, struct image *img));
9630
9631/* The symbol `tiff' identifying images of this type. */
9632
9633Lisp_Object Qtiff;
9634
9635/* Indices of image specification fields in tiff_format, below. */
9636
9637enum tiff_keyword_index
9638{
9639 TIFF_TYPE,
63448a4d 9640 TIFF_DATA,
333b20bb
GM
9641 TIFF_FILE,
9642 TIFF_ASCENT,
9643 TIFF_MARGIN,
9644 TIFF_RELIEF,
9645 TIFF_ALGORITHM,
9646 TIFF_HEURISTIC_MASK,
4a8e312c 9647 TIFF_MASK,
f20a3b7a 9648 TIFF_BACKGROUND,
333b20bb
GM
9649 TIFF_LAST
9650};
9651
9652/* Vector of image_keyword structures describing the format
9653 of valid user-defined image specifications. */
9654
9655static struct image_keyword tiff_format[TIFF_LAST] =
9656{
9657 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9658 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9659 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9660 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9661 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9662 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9663 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9664 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9665 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9666 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9667};
9668
9669/* Structure describing the image type `tiff'. */
9670
9671static struct image_type tiff_type =
9672{
9673 &Qtiff,
9674 tiff_image_p,
9675 tiff_load,
9676 x_clear_image,
9677 NULL
9678};
9679
9680
9681/* Return non-zero if OBJECT is a valid TIFF image specification. */
9682
9683static int
9684tiff_image_p (object)
9685 Lisp_Object object;
9686{
9687 struct image_keyword fmt[TIFF_LAST];
9688 bcopy (tiff_format, fmt, sizeof fmt);
9689
7c7ff7f5 9690 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
333b20bb 9691 return 0;
5ad6a5fb 9692
63cec32f
GM
9693 /* Must specify either the :data or :file keyword. */
9694 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
333b20bb
GM
9695}
9696
5ad6a5fb
GM
9697
9698/* Reading from a memory buffer for TIFF images Based on the PNG
9699 memory source, but we have to provide a lot of extra functions.
9700 Blah.
63448a4d
WP
9701
9702 We really only need to implement read and seek, but I am not
9703 convinced that the TIFF library is smart enough not to destroy
9704 itself if we only hand it the function pointers we need to
5ad6a5fb
GM
9705 override. */
9706
9707typedef struct
9708{
63448a4d
WP
9709 unsigned char *bytes;
9710 size_t len;
9711 int index;
5ad6a5fb
GM
9712}
9713tiff_memory_source;
63448a4d 9714
e3130015 9715
5ad6a5fb
GM
9716static size_t
9717tiff_read_from_memory (data, buf, size)
9718 thandle_t data;
9719 tdata_t buf;
9720 tsize_t size;
63448a4d 9721{
5ad6a5fb 9722 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9723
9724 if (size > src->len - src->index)
5ad6a5fb
GM
9725 return (size_t) -1;
9726 bcopy (src->bytes + src->index, buf, size);
63448a4d
WP
9727 src->index += size;
9728 return size;
9729}
9730
e3130015 9731
5ad6a5fb
GM
9732static size_t
9733tiff_write_from_memory (data, buf, size)
9734 thandle_t data;
9735 tdata_t buf;
9736 tsize_t size;
63448a4d
WP
9737{
9738 return (size_t) -1;
9739}
9740
e3130015 9741
5ad6a5fb
GM
9742static toff_t
9743tiff_seek_in_memory (data, off, whence)
9744 thandle_t data;
9745 toff_t off;
9746 int whence;
63448a4d 9747{
5ad6a5fb 9748 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9749 int idx;
9750
9751 switch (whence)
5ad6a5fb
GM
9752 {
9753 case SEEK_SET: /* Go from beginning of source. */
9754 idx = off;
9755 break;
9756
9757 case SEEK_END: /* Go from end of source. */
9758 idx = src->len + off;
9759 break;
9760
9761 case SEEK_CUR: /* Go from current position. */
9762 idx = src->index + off;
9763 break;
9764
9765 default: /* Invalid `whence'. */
9766 return -1;
9767 }
9768
9769 if (idx > src->len || idx < 0)
9770 return -1;
9771
63448a4d
WP
9772 src->index = idx;
9773 return src->index;
9774}
9775
e3130015 9776
5ad6a5fb
GM
9777static int
9778tiff_close_memory (data)
9779 thandle_t data;
63448a4d
WP
9780{
9781 /* NOOP */
5ad6a5fb 9782 return 0;
63448a4d
WP
9783}
9784
e3130015 9785
5ad6a5fb
GM
9786static int
9787tiff_mmap_memory (data, pbase, psize)
9788 thandle_t data;
9789 tdata_t *pbase;
9790 toff_t *psize;
63448a4d
WP
9791{
9792 /* It is already _IN_ memory. */
5ad6a5fb 9793 return 0;
63448a4d
WP
9794}
9795
e3130015 9796
5ad6a5fb
GM
9797static void
9798tiff_unmap_memory (data, base, size)
9799 thandle_t data;
9800 tdata_t base;
9801 toff_t size;
63448a4d
WP
9802{
9803 /* We don't need to do this. */
63448a4d
WP
9804}
9805
e3130015 9806
5ad6a5fb
GM
9807static toff_t
9808tiff_size_of_memory (data)
9809 thandle_t data;
63448a4d 9810{
5ad6a5fb 9811 return ((tiff_memory_source *) data)->len;
63448a4d 9812}
333b20bb 9813
e3130015 9814
c6892044
GM
9815static void
9816tiff_error_handler (title, format, ap)
9817 const char *title, *format;
9818 va_list ap;
9819{
9820 char buf[512];
9821 int len;
9822
9823 len = sprintf (buf, "TIFF error: %s ", title);
9824 vsprintf (buf + len, format, ap);
9825 add_to_log (buf, Qnil, Qnil);
9826}
9827
9828
9829static void
9830tiff_warning_handler (title, format, ap)
9831 const char *title, *format;
9832 va_list ap;
9833{
9834 char buf[512];
9835 int len;
9836
9837 len = sprintf (buf, "TIFF warning: %s ", title);
9838 vsprintf (buf + len, format, ap);
9839 add_to_log (buf, Qnil, Qnil);
9840}
9841
9842
333b20bb
GM
9843/* Load TIFF image IMG for use on frame F. Value is non-zero if
9844 successful. */
9845
9846static int
9847tiff_load (f, img)
9848 struct frame *f;
9849 struct image *img;
9850{
9851 Lisp_Object file, specified_file;
63448a4d 9852 Lisp_Object specified_data;
333b20bb
GM
9853 TIFF *tiff;
9854 int width, height, x, y;
9855 uint32 *buf;
9856 int rc;
9857 XImage *ximg;
9858 struct gcpro gcpro1;
63448a4d 9859 tiff_memory_source memsrc;
333b20bb
GM
9860
9861 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9862 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9863 file = Qnil;
9864 GCPRO1 (file);
63448a4d 9865
c6892044
GM
9866 TIFFSetErrorHandler (tiff_error_handler);
9867 TIFFSetWarningHandler (tiff_warning_handler);
9868
63448a4d 9869 if (NILP (specified_data))
5ad6a5fb
GM
9870 {
9871 /* Read from a file */
9872 file = x_find_image_file (specified_file);
9873 if (!STRINGP (file))
63448a4d 9874 {
45158a91 9875 image_error ("Cannot find image file `%s'", file, Qnil);
5ad6a5fb
GM
9876 UNGCPRO;
9877 return 0;
9878 }
63448a4d 9879
5ad6a5fb
GM
9880 /* Try to open the image file. */
9881 tiff = TIFFOpen (XSTRING (file)->data, "r");
9882 if (tiff == NULL)
9883 {
9884 image_error ("Cannot open `%s'", file, Qnil);
9885 UNGCPRO;
9886 return 0;
63448a4d 9887 }
5ad6a5fb 9888 }
63448a4d 9889 else
5ad6a5fb
GM
9890 {
9891 /* Memory source! */
9892 memsrc.bytes = XSTRING (specified_data)->data;
9893 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9894 memsrc.index = 0;
9895
9896 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9897 (TIFFReadWriteProc) tiff_read_from_memory,
9898 (TIFFReadWriteProc) tiff_write_from_memory,
9899 tiff_seek_in_memory,
9900 tiff_close_memory,
9901 tiff_size_of_memory,
9902 tiff_mmap_memory,
9903 tiff_unmap_memory);
9904
9905 if (!tiff)
63448a4d 9906 {
45158a91 9907 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
5ad6a5fb
GM
9908 UNGCPRO;
9909 return 0;
63448a4d 9910 }
5ad6a5fb 9911 }
333b20bb
GM
9912
9913 /* Get width and height of the image, and allocate a raster buffer
9914 of width x height 32-bit values. */
9915 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9916 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9917 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9918
9919 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9920 TIFFClose (tiff);
9921 if (!rc)
9922 {
45158a91 9923 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
333b20bb
GM
9924 xfree (buf);
9925 UNGCPRO;
9926 return 0;
9927 }
9928
333b20bb 9929 /* Create the X image and pixmap. */
45158a91 9930 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9931 {
333b20bb
GM
9932 xfree (buf);
9933 UNGCPRO;
9934 return 0;
9935 }
9936
9937 /* Initialize the color table. */
9938 init_color_table ();
9939
9940 /* Process the pixel raster. Origin is in the lower-left corner. */
9941 for (y = 0; y < height; ++y)
9942 {
9943 uint32 *row = buf + y * width;
9944
9945 for (x = 0; x < width; ++x)
9946 {
9947 uint32 abgr = row[x];
9948 int r = TIFFGetR (abgr) << 8;
9949 int g = TIFFGetG (abgr) << 8;
9950 int b = TIFFGetB (abgr) << 8;
9951 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9952 }
9953 }
9954
9955 /* Remember the colors allocated for the image. Free the color table. */
9956 img->colors = colors_in_color_table (&img->ncolors);
9957 free_color_table ();
f20a3b7a
MB
9958
9959 img->width = width;
9960 img->height = height;
9961
9962 /* Maybe fill in the background field while we have ximg handy. */
9963 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9964 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9965
9966 /* Put the image into the pixmap, then free the X image and its buffer. */
9967 x_put_x_image (f, ximg, img->pixmap, width, height);
9968 x_destroy_x_image (ximg);
9969 xfree (buf);
333b20bb
GM
9970
9971 UNGCPRO;
9972 return 1;
9973}
9974
9975#endif /* HAVE_TIFF != 0 */
9976
9977
9978\f
9979/***********************************************************************
9980 GIF
9981 ***********************************************************************/
9982
9983#if HAVE_GIF
9984
9985#include <gif_lib.h>
9986
9987static int gif_image_p P_ ((Lisp_Object object));
9988static int gif_load P_ ((struct frame *f, struct image *img));
9989
9990/* The symbol `gif' identifying images of this type. */
9991
9992Lisp_Object Qgif;
9993
9994/* Indices of image specification fields in gif_format, below. */
9995
9996enum gif_keyword_index
9997{
9998 GIF_TYPE,
63448a4d 9999 GIF_DATA,
333b20bb
GM
10000 GIF_FILE,
10001 GIF_ASCENT,
10002 GIF_MARGIN,
10003 GIF_RELIEF,
10004 GIF_ALGORITHM,
10005 GIF_HEURISTIC_MASK,
4a8e312c 10006 GIF_MASK,
333b20bb 10007 GIF_IMAGE,
f20a3b7a 10008 GIF_BACKGROUND,
333b20bb
GM
10009 GIF_LAST
10010};
10011
10012/* Vector of image_keyword structures describing the format
10013 of valid user-defined image specifications. */
10014
10015static struct image_keyword gif_format[GIF_LAST] =
10016{
10017 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 10018 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 10019 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 10020 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10021 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10022 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10023 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 10024 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10025 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 10026 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
f20a3b7a 10027 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10028};
10029
10030/* Structure describing the image type `gif'. */
10031
10032static struct image_type gif_type =
10033{
10034 &Qgif,
10035 gif_image_p,
10036 gif_load,
10037 x_clear_image,
10038 NULL
10039};
10040
e3130015 10041
333b20bb
GM
10042/* Return non-zero if OBJECT is a valid GIF image specification. */
10043
10044static int
10045gif_image_p (object)
10046 Lisp_Object object;
10047{
10048 struct image_keyword fmt[GIF_LAST];
10049 bcopy (gif_format, fmt, sizeof fmt);
10050
7c7ff7f5 10051 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
333b20bb 10052 return 0;
5ad6a5fb 10053
63cec32f
GM
10054 /* Must specify either the :data or :file keyword. */
10055 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
333b20bb
GM
10056}
10057
e3130015 10058
63448a4d
WP
10059/* Reading a GIF image from memory
10060 Based on the PNG memory stuff to a certain extent. */
10061
5ad6a5fb
GM
10062typedef struct
10063{
63448a4d
WP
10064 unsigned char *bytes;
10065 size_t len;
10066 int index;
5ad6a5fb
GM
10067}
10068gif_memory_source;
63448a4d 10069
e3130015 10070
f036834a
GM
10071/* Make the current memory source available to gif_read_from_memory.
10072 It's done this way because not all versions of libungif support
10073 a UserData field in the GifFileType structure. */
10074static gif_memory_source *current_gif_memory_src;
10075
5ad6a5fb
GM
10076static int
10077gif_read_from_memory (file, buf, len)
10078 GifFileType *file;
10079 GifByteType *buf;
10080 int len;
63448a4d 10081{
f036834a 10082 gif_memory_source *src = current_gif_memory_src;
63448a4d 10083
5ad6a5fb
GM
10084 if (len > src->len - src->index)
10085 return -1;
63448a4d 10086
5ad6a5fb 10087 bcopy (src->bytes + src->index, buf, len);
63448a4d
WP
10088 src->index += len;
10089 return len;
10090}
333b20bb 10091
5ad6a5fb 10092
333b20bb
GM
10093/* Load GIF image IMG for use on frame F. Value is non-zero if
10094 successful. */
10095
10096static int
10097gif_load (f, img)
10098 struct frame *f;
10099 struct image *img;
10100{
10101 Lisp_Object file, specified_file;
63448a4d 10102 Lisp_Object specified_data;
333b20bb
GM
10103 int rc, width, height, x, y, i;
10104 XImage *ximg;
10105 ColorMapObject *gif_color_map;
10106 unsigned long pixel_colors[256];
10107 GifFileType *gif;
10108 struct gcpro gcpro1;
10109 Lisp_Object image;
10110 int ino, image_left, image_top, image_width, image_height;
63448a4d 10111 gif_memory_source memsrc;
9b784e96 10112 unsigned char *raster;
333b20bb
GM
10113
10114 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 10115 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
10116 file = Qnil;
10117 GCPRO1 (file);
63448a4d
WP
10118
10119 if (NILP (specified_data))
5ad6a5fb
GM
10120 {
10121 file = x_find_image_file (specified_file);
10122 if (!STRINGP (file))
63448a4d 10123 {
45158a91 10124 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
10125 UNGCPRO;
10126 return 0;
10127 }
333b20bb 10128
5ad6a5fb
GM
10129 /* Open the GIF file. */
10130 gif = DGifOpenFileName (XSTRING (file)->data);
10131 if (gif == NULL)
10132 {
10133 image_error ("Cannot open `%s'", file, Qnil);
10134 UNGCPRO;
10135 return 0;
63448a4d 10136 }
5ad6a5fb 10137 }
63448a4d 10138 else
5ad6a5fb
GM
10139 {
10140 /* Read from memory! */
f036834a 10141 current_gif_memory_src = &memsrc;
5ad6a5fb
GM
10142 memsrc.bytes = XSTRING (specified_data)->data;
10143 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10144 memsrc.index = 0;
63448a4d 10145
5ad6a5fb
GM
10146 gif = DGifOpen(&memsrc, gif_read_from_memory);
10147 if (!gif)
10148 {
45158a91 10149 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
5ad6a5fb
GM
10150 UNGCPRO;
10151 return 0;
63448a4d 10152 }
5ad6a5fb 10153 }
333b20bb
GM
10154
10155 /* Read entire contents. */
10156 rc = DGifSlurp (gif);
10157 if (rc == GIF_ERROR)
10158 {
45158a91 10159 image_error ("Error reading `%s'", img->spec, Qnil);
333b20bb
GM
10160 DGifCloseFile (gif);
10161 UNGCPRO;
10162 return 0;
10163 }
10164
3ccff1e3 10165 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
10166 ino = INTEGERP (image) ? XFASTINT (image) : 0;
10167 if (ino >= gif->ImageCount)
10168 {
45158a91
GM
10169 image_error ("Invalid image number `%s' in image `%s'",
10170 image, img->spec);
333b20bb
GM
10171 DGifCloseFile (gif);
10172 UNGCPRO;
10173 return 0;
10174 }
10175
c7f07c4c
PJ
10176 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
10177 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
333b20bb 10178
333b20bb 10179 /* Create the X image and pixmap. */
45158a91 10180 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 10181 {
333b20bb
GM
10182 DGifCloseFile (gif);
10183 UNGCPRO;
10184 return 0;
10185 }
10186
10187 /* Allocate colors. */
10188 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
10189 if (!gif_color_map)
10190 gif_color_map = gif->SColorMap;
10191 init_color_table ();
10192 bzero (pixel_colors, sizeof pixel_colors);
10193
10194 for (i = 0; i < gif_color_map->ColorCount; ++i)
10195 {
10196 int r = gif_color_map->Colors[i].Red << 8;
10197 int g = gif_color_map->Colors[i].Green << 8;
10198 int b = gif_color_map->Colors[i].Blue << 8;
10199 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
10200 }
10201
10202 img->colors = colors_in_color_table (&img->ncolors);
10203 free_color_table ();
10204
10205 /* Clear the part of the screen image that are not covered by
10206 the image from the GIF file. Full animated GIF support
10207 requires more than can be done here (see the gif89 spec,
10208 disposal methods). Let's simply assume that the part
10209 not covered by a sub-image is in the frame's background color. */
10210 image_top = gif->SavedImages[ino].ImageDesc.Top;
10211 image_left = gif->SavedImages[ino].ImageDesc.Left;
10212 image_width = gif->SavedImages[ino].ImageDesc.Width;
10213 image_height = gif->SavedImages[ino].ImageDesc.Height;
10214
10215 for (y = 0; y < image_top; ++y)
10216 for (x = 0; x < width; ++x)
10217 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10218
10219 for (y = image_top + image_height; y < height; ++y)
10220 for (x = 0; x < width; ++x)
10221 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10222
10223 for (y = image_top; y < image_top + image_height; ++y)
10224 {
10225 for (x = 0; x < image_left; ++x)
10226 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10227 for (x = image_left + image_width; x < width; ++x)
10228 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10229 }
10230
9b784e96
GM
10231 /* Read the GIF image into the X image. We use a local variable
10232 `raster' here because RasterBits below is a char *, and invites
10233 problems with bytes >= 0x80. */
10234 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
10235
333b20bb
GM
10236 if (gif->SavedImages[ino].ImageDesc.Interlace)
10237 {
10238 static int interlace_start[] = {0, 4, 2, 1};
10239 static int interlace_increment[] = {8, 8, 4, 2};
9b207e8e 10240 int pass;
06482119
GM
10241 int row = interlace_start[0];
10242
10243 pass = 0;
333b20bb 10244
06482119 10245 for (y = 0; y < image_height; y++)
333b20bb 10246 {
06482119
GM
10247 if (row >= image_height)
10248 {
10249 row = interlace_start[++pass];
10250 while (row >= image_height)
10251 row = interlace_start[++pass];
10252 }
10253
10254 for (x = 0; x < image_width; x++)
10255 {
9b784e96 10256 int i = raster[(y * image_width) + x];
06482119
GM
10257 XPutPixel (ximg, x + image_left, row + image_top,
10258 pixel_colors[i]);
10259 }
10260
10261 row += interlace_increment[pass];
333b20bb
GM
10262 }
10263 }
10264 else
10265 {
10266 for (y = 0; y < image_height; ++y)
10267 for (x = 0; x < image_width; ++x)
10268 {
9b784e96 10269 int i = raster[y * image_width + x];
333b20bb
GM
10270 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
10271 }
10272 }
10273
10274 DGifCloseFile (gif);
f20a3b7a
MB
10275
10276 /* Maybe fill in the background field while we have ximg handy. */
10277 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10278 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
10279
10280 /* Put the image into the pixmap, then free the X image and its buffer. */
10281 x_put_x_image (f, ximg, img->pixmap, width, height);
10282 x_destroy_x_image (ximg);
333b20bb
GM
10283
10284 UNGCPRO;
10285 return 1;
10286}
10287
10288#endif /* HAVE_GIF != 0 */
10289
10290
10291\f
10292/***********************************************************************
10293 Ghostscript
10294 ***********************************************************************/
10295
10296static int gs_image_p P_ ((Lisp_Object object));
10297static int gs_load P_ ((struct frame *f, struct image *img));
10298static void gs_clear_image P_ ((struct frame *f, struct image *img));
10299
fcf431dc 10300/* The symbol `postscript' identifying images of this type. */
333b20bb 10301
fcf431dc 10302Lisp_Object Qpostscript;
333b20bb
GM
10303
10304/* Keyword symbols. */
10305
10306Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
10307
10308/* Indices of image specification fields in gs_format, below. */
10309
10310enum gs_keyword_index
10311{
10312 GS_TYPE,
10313 GS_PT_WIDTH,
10314 GS_PT_HEIGHT,
10315 GS_FILE,
10316 GS_LOADER,
10317 GS_BOUNDING_BOX,
10318 GS_ASCENT,
10319 GS_MARGIN,
10320 GS_RELIEF,
10321 GS_ALGORITHM,
10322 GS_HEURISTIC_MASK,
4a8e312c 10323 GS_MASK,
f20a3b7a 10324 GS_BACKGROUND,
333b20bb
GM
10325 GS_LAST
10326};
10327
10328/* Vector of image_keyword structures describing the format
10329 of valid user-defined image specifications. */
10330
10331static struct image_keyword gs_format[GS_LAST] =
10332{
10333 {":type", IMAGE_SYMBOL_VALUE, 1},
10334 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10335 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10336 {":file", IMAGE_STRING_VALUE, 1},
10337 {":loader", IMAGE_FUNCTION_VALUE, 0},
10338 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7c7ff7f5 10339 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10340 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10341 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10342 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10343 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
10344 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10345 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10346};
10347
10348/* Structure describing the image type `ghostscript'. */
10349
10350static struct image_type gs_type =
10351{
fcf431dc 10352 &Qpostscript,
333b20bb
GM
10353 gs_image_p,
10354 gs_load,
10355 gs_clear_image,
10356 NULL
10357};
10358
10359
10360/* Free X resources of Ghostscript image IMG which is used on frame F. */
10361
10362static void
10363gs_clear_image (f, img)
10364 struct frame *f;
10365 struct image *img;
10366{
10367 /* IMG->data.ptr_val may contain a recorded colormap. */
10368 xfree (img->data.ptr_val);
10369 x_clear_image (f, img);
10370}
10371
10372
10373/* Return non-zero if OBJECT is a valid Ghostscript image
10374 specification. */
10375
10376static int
10377gs_image_p (object)
10378 Lisp_Object object;
10379{
10380 struct image_keyword fmt[GS_LAST];
10381 Lisp_Object tem;
10382 int i;
10383
10384 bcopy (gs_format, fmt, sizeof fmt);
10385
7c7ff7f5 10386 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
333b20bb
GM
10387 return 0;
10388
10389 /* Bounding box must be a list or vector containing 4 integers. */
10390 tem = fmt[GS_BOUNDING_BOX].value;
10391 if (CONSP (tem))
10392 {
10393 for (i = 0; i < 4; ++i, tem = XCDR (tem))
10394 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
10395 return 0;
10396 if (!NILP (tem))
10397 return 0;
10398 }
10399 else if (VECTORP (tem))
10400 {
10401 if (XVECTOR (tem)->size != 4)
10402 return 0;
10403 for (i = 0; i < 4; ++i)
10404 if (!INTEGERP (XVECTOR (tem)->contents[i]))
10405 return 0;
10406 }
10407 else
10408 return 0;
10409
10410 return 1;
10411}
10412
10413
10414/* Load Ghostscript image IMG for use on frame F. Value is non-zero
10415 if successful. */
10416
10417static int
10418gs_load (f, img)
10419 struct frame *f;
10420 struct image *img;
10421{
10422 char buffer[100];
10423 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
10424 struct gcpro gcpro1, gcpro2;
10425 Lisp_Object frame;
10426 double in_width, in_height;
10427 Lisp_Object pixel_colors = Qnil;
10428
10429 /* Compute pixel size of pixmap needed from the given size in the
10430 image specification. Sizes in the specification are in pt. 1 pt
10431 = 1/72 in, xdpi and ydpi are stored in the frame's X display
10432 info. */
10433 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
10434 in_width = XFASTINT (pt_width) / 72.0;
10435 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
10436 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
10437 in_height = XFASTINT (pt_height) / 72.0;
10438 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
10439
10440 /* Create the pixmap. */
dd00328a 10441 xassert (img->pixmap == None);
333b20bb
GM
10442 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10443 img->width, img->height,
10444 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
333b20bb
GM
10445
10446 if (!img->pixmap)
10447 {
45158a91 10448 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
10449 return 0;
10450 }
10451
10452 /* Call the loader to fill the pixmap. It returns a process object
10453 if successful. We do not record_unwind_protect here because
10454 other places in redisplay like calling window scroll functions
10455 don't either. Let the Lisp loader use `unwind-protect' instead. */
10456 GCPRO2 (window_and_pixmap_id, pixel_colors);
10457
10458 sprintf (buffer, "%lu %lu",
10459 (unsigned long) FRAME_X_WINDOW (f),
10460 (unsigned long) img->pixmap);
10461 window_and_pixmap_id = build_string (buffer);
10462
10463 sprintf (buffer, "%lu %lu",
10464 FRAME_FOREGROUND_PIXEL (f),
10465 FRAME_BACKGROUND_PIXEL (f));
10466 pixel_colors = build_string (buffer);
10467
10468 XSETFRAME (frame, f);
10469 loader = image_spec_value (img->spec, QCloader, NULL);
10470 if (NILP (loader))
10471 loader = intern ("gs-load-image");
10472
10473 img->data.lisp_val = call6 (loader, frame, img->spec,
10474 make_number (img->width),
10475 make_number (img->height),
10476 window_and_pixmap_id,
10477 pixel_colors);
10478 UNGCPRO;
10479 return PROCESSP (img->data.lisp_val);
10480}
10481
10482
10483/* Kill the Ghostscript process that was started to fill PIXMAP on
10484 frame F. Called from XTread_socket when receiving an event
10485 telling Emacs that Ghostscript has finished drawing. */
10486
10487void
10488x_kill_gs_process (pixmap, f)
10489 Pixmap pixmap;
10490 struct frame *f;
10491{
10492 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
10493 int class, i;
10494 struct image *img;
10495
10496 /* Find the image containing PIXMAP. */
10497 for (i = 0; i < c->used; ++i)
10498 if (c->images[i]->pixmap == pixmap)
10499 break;
10500
daba7643
GM
10501 /* Should someone in between have cleared the image cache, for
10502 instance, give up. */
10503 if (i == c->used)
10504 return;
10505
333b20bb
GM
10506 /* Kill the GS process. We should have found PIXMAP in the image
10507 cache and its image should contain a process object. */
333b20bb
GM
10508 img = c->images[i];
10509 xassert (PROCESSP (img->data.lisp_val));
10510 Fkill_process (img->data.lisp_val, Qnil);
10511 img->data.lisp_val = Qnil;
10512
10513 /* On displays with a mutable colormap, figure out the colors
10514 allocated for the image by looking at the pixels of an XImage for
10515 img->pixmap. */
383d6ffc 10516 class = FRAME_X_VISUAL (f)->class;
333b20bb
GM
10517 if (class != StaticColor && class != StaticGray && class != TrueColor)
10518 {
10519 XImage *ximg;
10520
10521 BLOCK_INPUT;
10522
10523 /* Try to get an XImage for img->pixmep. */
10524 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10525 0, 0, img->width, img->height, ~0, ZPixmap);
10526 if (ximg)
10527 {
10528 int x, y;
10529
10530 /* Initialize the color table. */
10531 init_color_table ();
10532
10533 /* For each pixel of the image, look its color up in the
10534 color table. After having done so, the color table will
10535 contain an entry for each color used by the image. */
10536 for (y = 0; y < img->height; ++y)
10537 for (x = 0; x < img->width; ++x)
10538 {
10539 unsigned long pixel = XGetPixel (ximg, x, y);
10540 lookup_pixel_color (f, pixel);
10541 }
10542
10543 /* Record colors in the image. Free color table and XImage. */
10544 img->colors = colors_in_color_table (&img->ncolors);
10545 free_color_table ();
10546 XDestroyImage (ximg);
10547
10548#if 0 /* This doesn't seem to be the case. If we free the colors
10549 here, we get a BadAccess later in x_clear_image when
10550 freeing the colors. */
10551 /* We have allocated colors once, but Ghostscript has also
10552 allocated colors on behalf of us. So, to get the
10553 reference counts right, free them once. */
10554 if (img->ncolors)
462d5d40 10555 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
10556#endif
10557 }
10558 else
10559 image_error ("Cannot get X image of `%s'; colors will not be freed",
45158a91 10560 img->spec, Qnil);
333b20bb
GM
10561
10562 UNBLOCK_INPUT;
10563 }
ad18ffb1
GM
10564
10565 /* Now that we have the pixmap, compute mask and transform the
10566 image if requested. */
10567 BLOCK_INPUT;
10568 postprocess_image (f, img);
10569 UNBLOCK_INPUT;
333b20bb
GM
10570}
10571
10572
10573\f
10574/***********************************************************************
10575 Window properties
10576 ***********************************************************************/
10577
10578DEFUN ("x-change-window-property", Fx_change_window_property,
10579 Sx_change_window_property, 2, 3, 0,
7ee72033 10580 doc: /* Change window property PROP to VALUE on the X window of FRAME.
c061c855 10581PROP and VALUE must be strings. FRAME nil or omitted means use the
7ee72033
MB
10582selected frame. Value is VALUE. */)
10583 (prop, value, frame)
333b20bb
GM
10584 Lisp_Object frame, prop, value;
10585{
10586 struct frame *f = check_x_frame (frame);
10587 Atom prop_atom;
10588
b7826503
PJ
10589 CHECK_STRING (prop);
10590 CHECK_STRING (value);
333b20bb
GM
10591
10592 BLOCK_INPUT;
10593 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10594 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10595 prop_atom, XA_STRING, 8, PropModeReplace,
10596 XSTRING (value)->data, XSTRING (value)->size);
10597
10598 /* Make sure the property is set when we return. */
10599 XFlush (FRAME_X_DISPLAY (f));
10600 UNBLOCK_INPUT;
10601
10602 return value;
10603}
10604
10605
10606DEFUN ("x-delete-window-property", Fx_delete_window_property,
10607 Sx_delete_window_property, 1, 2, 0,
7ee72033
MB
10608 doc: /* Remove window property PROP from X window of FRAME.
10609FRAME nil or omitted means use the selected frame. Value is PROP. */)
10610 (prop, frame)
333b20bb
GM
10611 Lisp_Object prop, frame;
10612{
10613 struct frame *f = check_x_frame (frame);
10614 Atom prop_atom;
10615
b7826503 10616 CHECK_STRING (prop);
333b20bb
GM
10617 BLOCK_INPUT;
10618 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10619 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
10620
10621 /* Make sure the property is removed when we return. */
10622 XFlush (FRAME_X_DISPLAY (f));
10623 UNBLOCK_INPUT;
10624
10625 return prop;
10626}
10627
10628
10629DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
10630 1, 2, 0,
7ee72033 10631 doc: /* Value is the value of window property PROP on FRAME.
c061c855
GM
10632If FRAME is nil or omitted, use the selected frame. Value is nil
10633if FRAME hasn't a property with name PROP or if PROP has no string
7ee72033
MB
10634value. */)
10635 (prop, frame)
333b20bb
GM
10636 Lisp_Object prop, frame;
10637{
10638 struct frame *f = check_x_frame (frame);
10639 Atom prop_atom;
10640 int rc;
10641 Lisp_Object prop_value = Qnil;
10642 char *tmp_data = NULL;
10643 Atom actual_type;
10644 int actual_format;
10645 unsigned long actual_size, bytes_remaining;
10646
b7826503 10647 CHECK_STRING (prop);
333b20bb
GM
10648 BLOCK_INPUT;
10649 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10650 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10651 prop_atom, 0, 0, False, XA_STRING,
10652 &actual_type, &actual_format, &actual_size,
10653 &bytes_remaining, (unsigned char **) &tmp_data);
10654 if (rc == Success)
10655 {
10656 int size = bytes_remaining;
10657
10658 XFree (tmp_data);
10659 tmp_data = NULL;
10660
10661 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10662 prop_atom, 0, bytes_remaining,
10663 False, XA_STRING,
10664 &actual_type, &actual_format,
10665 &actual_size, &bytes_remaining,
10666 (unsigned char **) &tmp_data);
4c8c7926 10667 if (rc == Success && tmp_data)
333b20bb
GM
10668 prop_value = make_string (tmp_data, size);
10669
10670 XFree (tmp_data);
10671 }
10672
10673 UNBLOCK_INPUT;
10674 return prop_value;
10675}
10676
10677
10678\f
10679/***********************************************************************
10680 Busy cursor
10681 ***********************************************************************/
10682
4ae9a85e 10683/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 10684 an hourglass cursor on all frames. */
333b20bb 10685
0af913d7 10686static struct atimer *hourglass_atimer;
333b20bb 10687
0af913d7 10688/* Non-zero means an hourglass cursor is currently shown. */
333b20bb 10689
0af913d7 10690static int hourglass_shown_p;
333b20bb 10691
0af913d7 10692/* Number of seconds to wait before displaying an hourglass cursor. */
333b20bb 10693
0af913d7 10694static Lisp_Object Vhourglass_delay;
333b20bb 10695
0af913d7 10696/* Default number of seconds to wait before displaying an hourglass
4ae9a85e
GM
10697 cursor. */
10698
0af913d7 10699#define DEFAULT_HOURGLASS_DELAY 1
4ae9a85e
GM
10700
10701/* Function prototypes. */
10702
0af913d7
GM
10703static void show_hourglass P_ ((struct atimer *));
10704static void hide_hourglass P_ ((void));
4ae9a85e
GM
10705
10706
0af913d7 10707/* Cancel a currently active hourglass timer, and start a new one. */
4ae9a85e
GM
10708
10709void
0af913d7 10710start_hourglass ()
333b20bb 10711{
4ae9a85e 10712 EMACS_TIME delay;
3caa99d3 10713 int secs, usecs = 0;
4ae9a85e 10714
0af913d7 10715 cancel_hourglass ();
4ae9a85e 10716
0af913d7
GM
10717 if (INTEGERP (Vhourglass_delay)
10718 && XINT (Vhourglass_delay) > 0)
10719 secs = XFASTINT (Vhourglass_delay);
10720 else if (FLOATP (Vhourglass_delay)
10721 && XFLOAT_DATA (Vhourglass_delay) > 0)
3caa99d3
GM
10722 {
10723 Lisp_Object tem;
0af913d7 10724 tem = Ftruncate (Vhourglass_delay, Qnil);
3caa99d3 10725 secs = XFASTINT (tem);
0af913d7 10726 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
3caa99d3 10727 }
4ae9a85e 10728 else
0af913d7 10729 secs = DEFAULT_HOURGLASS_DELAY;
4ae9a85e 10730
3caa99d3 10731 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
10732 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
10733 show_hourglass, NULL);
4ae9a85e
GM
10734}
10735
10736
0af913d7 10737/* Cancel the hourglass cursor timer if active, hide a busy cursor if
4ae9a85e
GM
10738 shown. */
10739
10740void
0af913d7 10741cancel_hourglass ()
4ae9a85e 10742{
0af913d7 10743 if (hourglass_atimer)
99f01f62 10744 {
0af913d7
GM
10745 cancel_atimer (hourglass_atimer);
10746 hourglass_atimer = NULL;
99f01f62
GM
10747 }
10748
0af913d7
GM
10749 if (hourglass_shown_p)
10750 hide_hourglass ();
4ae9a85e
GM
10751}
10752
10753
0af913d7
GM
10754/* Timer function of hourglass_atimer. TIMER is equal to
10755 hourglass_atimer.
4ae9a85e 10756
0af913d7
GM
10757 Display an hourglass pointer on all frames by mapping the frames'
10758 hourglass_window. Set the hourglass_p flag in the frames'
10759 output_data.x structure to indicate that an hourglass cursor is
10760 shown on the frames. */
4ae9a85e
GM
10761
10762static void
0af913d7 10763show_hourglass (timer)
4ae9a85e
GM
10764 struct atimer *timer;
10765{
10766 /* The timer implementation will cancel this timer automatically
0af913d7 10767 after this function has run. Set hourglass_atimer to null
4ae9a85e 10768 so that we know the timer doesn't have to be canceled. */
0af913d7 10769 hourglass_atimer = NULL;
4ae9a85e 10770
0af913d7 10771 if (!hourglass_shown_p)
333b20bb
GM
10772 {
10773 Lisp_Object rest, frame;
4ae9a85e
GM
10774
10775 BLOCK_INPUT;
10776
333b20bb 10777 FOR_EACH_FRAME (rest, frame)
5f7a1890
GM
10778 {
10779 struct frame *f = XFRAME (frame);
10780
10781 if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
10782 {
10783 Display *dpy = FRAME_X_DISPLAY (f);
10784
10785#ifdef USE_X_TOOLKIT
10786 if (f->output_data.x->widget)
10787#else
10788 if (FRAME_OUTER_WINDOW (f))
10789#endif
10790 {
0af913d7 10791 f->output_data.x->hourglass_p = 1;
4ae9a85e 10792
0af913d7 10793 if (!f->output_data.x->hourglass_window)
5f7a1890
GM
10794 {
10795 unsigned long mask = CWCursor;
10796 XSetWindowAttributes attrs;
4ae9a85e 10797
0af913d7 10798 attrs.cursor = f->output_data.x->hourglass_cursor;
4ae9a85e 10799
0af913d7 10800 f->output_data.x->hourglass_window
5f7a1890
GM
10801 = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
10802 0, 0, 32000, 32000, 0, 0,
10803 InputOnly,
10804 CopyFromParent,
10805 mask, &attrs);
10806 }
4ae9a85e 10807
0af913d7 10808 XMapRaised (dpy, f->output_data.x->hourglass_window);
5f7a1890
GM
10809 XFlush (dpy);
10810 }
10811 }
10812 }
333b20bb 10813
0af913d7 10814 hourglass_shown_p = 1;
4ae9a85e
GM
10815 UNBLOCK_INPUT;
10816 }
333b20bb
GM
10817}
10818
10819
0af913d7
GM
10820/* Hide the hourglass pointer on all frames, if it is currently
10821 shown. */
333b20bb 10822
4ae9a85e 10823static void
0af913d7 10824hide_hourglass ()
4ae9a85e 10825{
0af913d7 10826 if (hourglass_shown_p)
333b20bb 10827 {
4ae9a85e
GM
10828 Lisp_Object rest, frame;
10829
10830 BLOCK_INPUT;
10831 FOR_EACH_FRAME (rest, frame)
333b20bb 10832 {
4ae9a85e
GM
10833 struct frame *f = XFRAME (frame);
10834
10835 if (FRAME_X_P (f)
10836 /* Watch out for newly created frames. */
0af913d7 10837 && f->output_data.x->hourglass_window)
4ae9a85e 10838 {
0af913d7
GM
10839 XUnmapWindow (FRAME_X_DISPLAY (f),
10840 f->output_data.x->hourglass_window);
10841 /* Sync here because XTread_socket looks at the
10842 hourglass_p flag that is reset to zero below. */
4ae9a85e 10843 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 10844 f->output_data.x->hourglass_p = 0;
4ae9a85e 10845 }
333b20bb 10846 }
333b20bb 10847
0af913d7 10848 hourglass_shown_p = 0;
4ae9a85e
GM
10849 UNBLOCK_INPUT;
10850 }
333b20bb
GM
10851}
10852
10853
10854\f
10855/***********************************************************************
10856 Tool tips
10857 ***********************************************************************/
10858
10859static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
275841bf 10860 Lisp_Object, Lisp_Object));
06d62053 10861static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
ab452f99 10862 Lisp_Object, int, int, int *, int *));
333b20bb 10863
44b5a125 10864/* The frame of a currently visible tooltip. */
333b20bb 10865
44b5a125 10866Lisp_Object tip_frame;
333b20bb
GM
10867
10868/* If non-nil, a timer started that hides the last tooltip when it
10869 fires. */
10870
10871Lisp_Object tip_timer;
10872Window tip_window;
10873
06d62053
GM
10874/* If non-nil, a vector of 3 elements containing the last args
10875 with which x-show-tip was called. See there. */
10876
10877Lisp_Object last_show_tip_args;
10878
d63931a2
GM
10879/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
10880
10881Lisp_Object Vx_max_tooltip_size;
10882
eaf1eea9
GM
10883
10884static Lisp_Object
10885unwind_create_tip_frame (frame)
10886 Lisp_Object frame;
10887{
c844a81a
GM
10888 Lisp_Object deleted;
10889
10890 deleted = unwind_create_frame (frame);
10891 if (EQ (deleted, Qt))
10892 {
10893 tip_window = None;
10894 tip_frame = Qnil;
10895 }
10896
10897 return deleted;
eaf1eea9
GM
10898}
10899
10900
333b20bb 10901/* Create a frame for a tooltip on the display described by DPYINFO.
275841bf
GM
10902 PARMS is a list of frame parameters. TEXT is the string to
10903 display in the tip frame. Value is the frame.
eaf1eea9
GM
10904
10905 Note that functions called here, esp. x_default_parameter can
10906 signal errors, for instance when a specified color name is
10907 undefined. We have to make sure that we're in a consistent state
10908 when this happens. */
333b20bb
GM
10909
10910static Lisp_Object
275841bf 10911x_create_tip_frame (dpyinfo, parms, text)
333b20bb 10912 struct x_display_info *dpyinfo;
275841bf 10913 Lisp_Object parms, text;
333b20bb
GM
10914{
10915 struct frame *f;
10916 Lisp_Object frame, tem;
10917 Lisp_Object name;
333b20bb
GM
10918 long window_prompting = 0;
10919 int width, height;
eaf1eea9 10920 int count = BINDING_STACK_SIZE ();
b6d7acec 10921 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb 10922 struct kboard *kb;
06d62053 10923 int face_change_count_before = face_change_count;
275841bf
GM
10924 Lisp_Object buffer;
10925 struct buffer *old_buffer;
333b20bb
GM
10926
10927 check_x ();
10928
10929 /* Use this general default value to start with until we know if
10930 this frame has a specified name. */
10931 Vx_resource_name = Vinvocation_name;
10932
10933#ifdef MULTI_KBOARD
10934 kb = dpyinfo->kboard;
10935#else
10936 kb = &the_only_kboard;
10937#endif
10938
10939 /* Get the name of the frame to use for resource lookup. */
10940 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10941 if (!STRINGP (name)
10942 && !EQ (name, Qunbound)
10943 && !NILP (name))
10944 error ("Invalid frame name--not a string or nil");
10945 Vx_resource_name = name;
10946
10947 frame = Qnil;
10948 GCPRO3 (parms, name, frame);
44b5a125 10949 f = make_frame (1);
333b20bb 10950 XSETFRAME (frame, f);
275841bf
GM
10951
10952 buffer = Fget_buffer_create (build_string (" *tip*"));
10953 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10954 old_buffer = current_buffer;
10955 set_buffer_internal_1 (XBUFFER (buffer));
d63931a2 10956 current_buffer->truncate_lines = Qnil;
275841bf
GM
10957 Ferase_buffer ();
10958 Finsert (1, &text);
10959 set_buffer_internal_1 (old_buffer);
10960
333b20bb 10961 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
8a1a7743 10962 record_unwind_protect (unwind_create_tip_frame, frame);
333b20bb 10963
eaf1eea9
GM
10964 /* By setting the output method, we're essentially saying that
10965 the frame is live, as per FRAME_LIVE_P. If we get a signal
10966 from this point on, x_destroy_window might screw up reference
10967 counts etc. */
333b20bb
GM
10968 f->output_method = output_x_window;
10969 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10970 bzero (f->output_data.x, sizeof (struct x_output));
10971 f->output_data.x->icon_bitmap = -1;
10972 f->output_data.x->fontset = -1;
61d461a8
GM
10973 f->output_data.x->scroll_bar_foreground_pixel = -1;
10974 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
10975#ifdef USE_TOOLKIT_SCROLL_BARS
10976 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
10977 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
10978#endif /* USE_TOOLKIT_SCROLL_BARS */
333b20bb
GM
10979 f->icon_name = Qnil;
10980 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 10981#if GLYPH_DEBUG
eaf1eea9
GM
10982 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
10983 dpyinfo_refcount = dpyinfo->reference_count;
10984#endif /* GLYPH_DEBUG */
333b20bb
GM
10985#ifdef MULTI_KBOARD
10986 FRAME_KBOARD (f) = kb;
10987#endif
10988 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10989 f->output_data.x->explicit_parent = 0;
10990
61d461a8
GM
10991 /* These colors will be set anyway later, but it's important
10992 to get the color reference counts right, so initialize them! */
10993 {
10994 Lisp_Object black;
10995 struct gcpro gcpro1;
10996
10997 black = build_string ("black");
10998 GCPRO1 (black);
10999 f->output_data.x->foreground_pixel
11000 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11001 f->output_data.x->background_pixel
11002 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11003 f->output_data.x->cursor_pixel
11004 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11005 f->output_data.x->cursor_foreground_pixel
11006 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11007 f->output_data.x->border_pixel
11008 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11009 f->output_data.x->mouse_pixel
11010 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11011 UNGCPRO;
11012 }
11013
333b20bb
GM
11014 /* Set the name; the functions to which we pass f expect the name to
11015 be set. */
11016 if (EQ (name, Qunbound) || NILP (name))
11017 {
11018 f->name = build_string (dpyinfo->x_id_name);
11019 f->explicit_name = 0;
11020 }
11021 else
11022 {
11023 f->name = name;
11024 f->explicit_name = 1;
11025 /* use the frame's title when getting resources for this frame. */
11026 specbind (Qx_resource_name, name);
11027 }
11028
eaf1eea9
GM
11029 /* Extract the window parameters from the supplied values that are
11030 needed to determine window geometry. */
333b20bb
GM
11031 {
11032 Lisp_Object font;
11033
11034 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
11035
11036 BLOCK_INPUT;
11037 /* First, try whatever font the caller has specified. */
11038 if (STRINGP (font))
11039 {
11040 tem = Fquery_fontset (font, Qnil);
11041 if (STRINGP (tem))
11042 font = x_new_fontset (f, XSTRING (tem)->data);
11043 else
11044 font = x_new_font (f, XSTRING (font)->data);
11045 }
11046
11047 /* Try out a font which we hope has bold and italic variations. */
11048 if (!STRINGP (font))
11049 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
11050 if (!STRINGP (font))
11051 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11052 if (! STRINGP (font))
11053 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11054 if (! STRINGP (font))
11055 /* This was formerly the first thing tried, but it finds too many fonts
11056 and takes too long. */
11057 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
11058 /* If those didn't work, look for something which will at least work. */
11059 if (! STRINGP (font))
11060 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
11061 UNBLOCK_INPUT;
11062 if (! STRINGP (font))
11063 font = build_string ("fixed");
11064
11065 x_default_parameter (f, parms, Qfont, font,
11066 "font", "Font", RES_TYPE_STRING);
11067 }
11068
11069 x_default_parameter (f, parms, Qborder_width, make_number (2),
11070 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
11071
11072 /* This defaults to 2 in order to match xterm. We recognize either
11073 internalBorderWidth or internalBorder (which is what xterm calls
11074 it). */
11075 if (NILP (Fassq (Qinternal_border_width, parms)))
11076 {
11077 Lisp_Object value;
11078
11079 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
11080 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
11081 if (! EQ (value, Qunbound))
11082 parms = Fcons (Fcons (Qinternal_border_width, value),
11083 parms);
11084 }
11085
11086 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
11087 "internalBorderWidth", "internalBorderWidth",
11088 RES_TYPE_NUMBER);
11089
11090 /* Also do the stuff which must be set before the window exists. */
11091 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
11092 "foreground", "Foreground", RES_TYPE_STRING);
11093 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
11094 "background", "Background", RES_TYPE_STRING);
11095 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
11096 "pointerColor", "Foreground", RES_TYPE_STRING);
11097 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
11098 "cursorColor", "Foreground", RES_TYPE_STRING);
11099 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
11100 "borderColor", "BorderColor", RES_TYPE_STRING);
11101
11102 /* Init faces before x_default_parameter is called for scroll-bar
11103 parameters because that function calls x_set_scroll_bar_width,
11104 which calls change_frame_size, which calls Fset_window_buffer,
11105 which runs hooks, which call Fvertical_motion. At the end, we
11106 end up in init_iterator with a null face cache, which should not
11107 happen. */
11108 init_frame_faces (f);
11109
11110 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
11111 window_prompting = x_figure_window_size (f, parms);
11112
11113 if (window_prompting & XNegative)
11114 {
11115 if (window_prompting & YNegative)
11116 f->output_data.x->win_gravity = SouthEastGravity;
11117 else
11118 f->output_data.x->win_gravity = NorthEastGravity;
11119 }
11120 else
11121 {
11122 if (window_prompting & YNegative)
11123 f->output_data.x->win_gravity = SouthWestGravity;
11124 else
11125 f->output_data.x->win_gravity = NorthWestGravity;
11126 }
11127
11128 f->output_data.x->size_hint_flags = window_prompting;
11129 {
11130 XSetWindowAttributes attrs;
11131 unsigned long mask;
11132
11133 BLOCK_INPUT;
c51d2b5e
GM
11134 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
11135 if (DoesSaveUnders (dpyinfo->screen))
11136 mask |= CWSaveUnder;
11137
9b2956e2
GM
11138 /* Window managers look at the override-redirect flag to determine
11139 whether or net to give windows a decoration (Xlib spec, chapter
333b20bb
GM
11140 3.2.8). */
11141 attrs.override_redirect = True;
11142 attrs.save_under = True;
11143 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
11144 /* Arrange for getting MapNotify and UnmapNotify events. */
11145 attrs.event_mask = StructureNotifyMask;
11146 tip_window
11147 = FRAME_X_WINDOW (f)
11148 = XCreateWindow (FRAME_X_DISPLAY (f),
11149 FRAME_X_DISPLAY_INFO (f)->root_window,
11150 /* x, y, width, height */
11151 0, 0, 1, 1,
11152 /* Border. */
11153 1,
11154 CopyFromParent, InputOutput, CopyFromParent,
11155 mask, &attrs);
11156 UNBLOCK_INPUT;
11157 }
11158
11159 x_make_gc (f);
11160
333b20bb
GM
11161 x_default_parameter (f, parms, Qauto_raise, Qnil,
11162 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11163 x_default_parameter (f, parms, Qauto_lower, Qnil,
11164 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11165 x_default_parameter (f, parms, Qcursor_type, Qbox,
11166 "cursorType", "CursorType", RES_TYPE_SYMBOL);
11167
11168 /* Dimensions, especially f->height, must be done via change_frame_size.
11169 Change will not be effected unless different from the current
11170 f->height. */
11171 width = f->width;
11172 height = f->height;
11173 f->height = 0;
11174 SET_FRAME_WIDTH (f, 0);
8938a4fb 11175 change_frame_size (f, height, width, 1, 0, 0);
333b20bb 11176
035d5114 11177 /* Set up faces after all frame parameters are known. This call
6801a572
GM
11178 also merges in face attributes specified for new frames.
11179
11180 Frame parameters may be changed if .Xdefaults contains
11181 specifications for the default font. For example, if there is an
11182 `Emacs.default.attributeBackground: pink', the `background-color'
11183 attribute of the frame get's set, which let's the internal border
11184 of the tooltip frame appear in pink. Prevent this. */
11185 {
11186 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
11187
11188 /* Set tip_frame here, so that */
11189 tip_frame = frame;
11190 call1 (Qface_set_after_frame_default, frame);
11191
11192 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
11193 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
11194 Qnil));
11195 }
035d5114 11196
333b20bb
GM
11197 f->no_split = 1;
11198
11199 UNGCPRO;
11200
11201 /* It is now ok to make the frame official even if we get an error
11202 below. And the frame needs to be on Vframe_list or making it
11203 visible won't work. */
11204 Vframe_list = Fcons (frame, Vframe_list);
11205
11206 /* Now that the frame is official, it counts as a reference to
11207 its display. */
11208 FRAME_X_DISPLAY_INFO (f)->reference_count++;
11209
06d62053
GM
11210 /* Setting attributes of faces of the tooltip frame from resources
11211 and similar will increment face_change_count, which leads to the
11212 clearing of all current matrices. Since this isn't necessary
11213 here, avoid it by resetting face_change_count to the value it
11214 had before we created the tip frame. */
11215 face_change_count = face_change_count_before;
11216
eaf1eea9 11217 /* Discard the unwind_protect. */
333b20bb
GM
11218 return unbind_to (count, frame);
11219}
11220
11221
06d62053
GM
11222/* Compute where to display tip frame F. PARMS is the list of frame
11223 parameters for F. DX and DY are specified offsets from the current
ab452f99
GM
11224 location of the mouse. WIDTH and HEIGHT are the width and height
11225 of the tooltip. Return coordinates relative to the root window of
11226 the display in *ROOT_X, and *ROOT_Y. */
06d62053
GM
11227
11228static void
ab452f99 11229compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
06d62053
GM
11230 struct frame *f;
11231 Lisp_Object parms, dx, dy;
ab452f99 11232 int width, height;
06d62053
GM
11233 int *root_x, *root_y;
11234{
11235 Lisp_Object left, top;
11236 int win_x, win_y;
11237 Window root, child;
11238 unsigned pmask;
11239
11240 /* User-specified position? */
11241 left = Fcdr (Fassq (Qleft, parms));
11242 top = Fcdr (Fassq (Qtop, parms));
11243
11244 /* Move the tooltip window where the mouse pointer is. Resize and
11245 show it. */
570d22b0 11246 if (!INTEGERP (left) || !INTEGERP (top))
ab452f99
GM
11247 {
11248 BLOCK_INPUT;
11249 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
11250 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
11251 UNBLOCK_INPUT;
11252 }
06d62053 11253
06d62053
GM
11254 if (INTEGERP (top))
11255 *root_y = XINT (top);
ab452f99
GM
11256 else if (*root_y + XINT (dy) - height < 0)
11257 *root_y -= XINT (dy);
11258 else
11259 {
11260 *root_y -= height;
11261 *root_y += XINT (dy);
11262 }
11263
11264 if (INTEGERP (left))
11265 *root_x = XINT (left);
d682d3df
RS
11266 else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width)
11267 /* It fits to the right of the pointer. */
11268 *root_x += XINT (dx);
11269 else if (width + XINT (dx) <= *root_x)
11270 /* It fits to the left of the pointer. */
ab452f99
GM
11271 *root_x -= width + XINT (dx);
11272 else
d682d3df
RS
11273 /* Put it left-justified on the screen--it ought to fit that way. */
11274 *root_x = 0;
06d62053
GM
11275}
11276
11277
0634ce98 11278DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
7ee72033 11279 doc: /* Show STRING in a "tooltip" window on frame FRAME.
c061c855
GM
11280A tooltip window is a small X window displaying a string.
11281
11282FRAME nil or omitted means use the selected frame.
11283
11284PARMS is an optional list of frame parameters which can be used to
11285change the tooltip's appearance.
11286
11287Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
11288means use the default timeout of 5 seconds.
11289
11290If the list of frame parameters PARAMS contains a `left' parameters,
11291the tooltip is displayed at that x-position. Otherwise it is
11292displayed at the mouse position, with offset DX added (default is 5 if
11293DX isn't specified). Likewise for the y-position; if a `top' frame
11294parameter is specified, it determines the y-position of the tooltip
11295window, otherwise it is displayed at the mouse position, with offset
11296DY added (default is -10).
11297
11298A tooltip's maximum size is specified by `x-max-tooltip-size'.
7ee72033
MB
11299Text larger than the specified size is clipped. */)
11300 (string, frame, parms, timeout, dx, dy)
0634ce98 11301 Lisp_Object string, frame, parms, timeout, dx, dy;
333b20bb
GM
11302{
11303 struct frame *f;
11304 struct window *w;
06d62053 11305 int root_x, root_y;
333b20bb
GM
11306 struct buffer *old_buffer;
11307 struct text_pos pos;
11308 int i, width, height;
393f2d14 11309 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
333b20bb 11310 int old_windows_or_buffers_changed = windows_or_buffers_changed;
06d62053 11311 int count = BINDING_STACK_SIZE ();
333b20bb
GM
11312
11313 specbind (Qinhibit_redisplay, Qt);
11314
393f2d14 11315 GCPRO4 (string, parms, frame, timeout);
333b20bb 11316
b7826503 11317 CHECK_STRING (string);
333b20bb
GM
11318 f = check_x_frame (frame);
11319 if (NILP (timeout))
11320 timeout = make_number (5);
11321 else
b7826503 11322 CHECK_NATNUM (timeout);
0634ce98
GM
11323
11324 if (NILP (dx))
11325 dx = make_number (5);
11326 else
b7826503 11327 CHECK_NUMBER (dx);
0634ce98
GM
11328
11329 if (NILP (dy))
12c67a7f 11330 dy = make_number (-10);
0634ce98 11331 else
b7826503 11332 CHECK_NUMBER (dy);
333b20bb 11333
06d62053
GM
11334 if (NILP (last_show_tip_args))
11335 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
11336
11337 if (!NILP (tip_frame))
11338 {
11339 Lisp_Object last_string = AREF (last_show_tip_args, 0);
11340 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
11341 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
11342
11343 if (EQ (frame, last_frame)
11344 && !NILP (Fequal (last_string, string))
11345 && !NILP (Fequal (last_parms, parms)))
11346 {
11347 struct frame *f = XFRAME (tip_frame);
11348
11349 /* Only DX and DY have changed. */
11350 if (!NILP (tip_timer))
ae782866
GM
11351 {
11352 Lisp_Object timer = tip_timer;
11353 tip_timer = Qnil;
11354 call1 (Qcancel_timer, timer);
11355 }
06d62053
GM
11356
11357 BLOCK_INPUT;
ab452f99
GM
11358 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
11359 PIXEL_HEIGHT (f), &root_x, &root_y);
06d62053 11360 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11361 root_x, root_y);
06d62053
GM
11362 UNBLOCK_INPUT;
11363 goto start_timer;
11364 }
11365 }
11366
333b20bb
GM
11367 /* Hide a previous tip, if any. */
11368 Fx_hide_tip ();
11369
06d62053
GM
11370 ASET (last_show_tip_args, 0, string);
11371 ASET (last_show_tip_args, 1, frame);
11372 ASET (last_show_tip_args, 2, parms);
11373
333b20bb
GM
11374 /* Add default values to frame parameters. */
11375 if (NILP (Fassq (Qname, parms)))
11376 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
11377 if (NILP (Fassq (Qinternal_border_width, parms)))
11378 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
11379 if (NILP (Fassq (Qborder_width, parms)))
11380 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
11381 if (NILP (Fassq (Qborder_color, parms)))
11382 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
11383 if (NILP (Fassq (Qbackground_color, parms)))
11384 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
11385 parms);
11386
11387 /* Create a frame for the tooltip, and record it in the global
11388 variable tip_frame. */
275841bf 11389 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
44b5a125 11390 f = XFRAME (frame);
333b20bb 11391
d63931a2 11392 /* Set up the frame's root window. */
333b20bb
GM
11393 w = XWINDOW (FRAME_ROOT_WINDOW (f));
11394 w->left = w->top = make_number (0);
d63931a2
GM
11395
11396 if (CONSP (Vx_max_tooltip_size)
11397 && INTEGERP (XCAR (Vx_max_tooltip_size))
11398 && XINT (XCAR (Vx_max_tooltip_size)) > 0
11399 && INTEGERP (XCDR (Vx_max_tooltip_size))
11400 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
11401 {
11402 w->width = XCAR (Vx_max_tooltip_size);
11403 w->height = XCDR (Vx_max_tooltip_size);
11404 }
11405 else
11406 {
11407 w->width = make_number (80);
11408 w->height = make_number (40);
11409 }
11410
11411 f->window_width = XINT (w->width);
333b20bb
GM
11412 adjust_glyphs (f);
11413 w->pseudo_window_p = 1;
11414
11415 /* Display the tooltip text in a temporary buffer. */
333b20bb 11416 old_buffer = current_buffer;
275841bf 11417 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
d63931a2 11418 current_buffer->truncate_lines = Qnil;
333b20bb
GM
11419 clear_glyph_matrix (w->desired_matrix);
11420 clear_glyph_matrix (w->current_matrix);
11421 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
11422 try_window (FRAME_ROOT_WINDOW (f), pos);
11423
11424 /* Compute width and height of the tooltip. */
11425 width = height = 0;
11426 for (i = 0; i < w->desired_matrix->nrows; ++i)
11427 {
11428 struct glyph_row *row = &w->desired_matrix->rows[i];
11429 struct glyph *last;
11430 int row_width;
11431
11432 /* Stop at the first empty row at the end. */
11433 if (!row->enabled_p || !row->displays_text_p)
11434 break;
11435
d7bf0342
GM
11436 /* Let the row go over the full width of the frame. */
11437 row->full_width_p = 1;
333b20bb 11438
e3130015 11439 /* There's a glyph at the end of rows that is used to place
333b20bb
GM
11440 the cursor there. Don't include the width of this glyph. */
11441 if (row->used[TEXT_AREA])
11442 {
11443 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
11444 row_width = row->pixel_width - last->pixel_width;
11445 }
11446 else
11447 row_width = row->pixel_width;
11448
11449 height += row->height;
11450 width = max (width, row_width);
11451 }
11452
11453 /* Add the frame's internal border to the width and height the X
11454 window should have. */
11455 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11456 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11457
11458 /* Move the tooltip window where the mouse pointer is. Resize and
11459 show it. */
ab452f99 11460 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
0634ce98 11461
0634ce98 11462 BLOCK_INPUT;
333b20bb 11463 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11464 root_x, root_y, width, height);
333b20bb
GM
11465 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11466 UNBLOCK_INPUT;
06d62053 11467
333b20bb
GM
11468 /* Draw into the window. */
11469 w->must_be_updated_p = 1;
11470 update_single_window (w, 1);
11471
11472 /* Restore original current buffer. */
11473 set_buffer_internal_1 (old_buffer);
11474 windows_or_buffers_changed = old_windows_or_buffers_changed;
11475
06d62053 11476 start_timer:
333b20bb
GM
11477 /* Let the tip disappear after timeout seconds. */
11478 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
11479 intern ("x-hide-tip"));
a744a2ec
DL
11480
11481 UNGCPRO;
333b20bb
GM
11482 return unbind_to (count, Qnil);
11483}
11484
11485
11486DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
7ee72033
MB
11487 doc: /* Hide the current tooltip window, if there is any.
11488Value is t if tooltip was open, nil otherwise. */)
11489 ()
333b20bb 11490{
44b5a125 11491 int count;
c0006262
GM
11492 Lisp_Object deleted, frame, timer;
11493 struct gcpro gcpro1, gcpro2;
44b5a125
GM
11494
11495 /* Return quickly if nothing to do. */
c0006262 11496 if (NILP (tip_timer) && NILP (tip_frame))
44b5a125 11497 return Qnil;
333b20bb 11498
c0006262
GM
11499 frame = tip_frame;
11500 timer = tip_timer;
11501 GCPRO2 (frame, timer);
11502 tip_frame = tip_timer = deleted = Qnil;
11503
44b5a125 11504 count = BINDING_STACK_SIZE ();
333b20bb 11505 specbind (Qinhibit_redisplay, Qt);
44b5a125 11506 specbind (Qinhibit_quit, Qt);
333b20bb 11507
c0006262 11508 if (!NILP (timer))
ae782866 11509 call1 (Qcancel_timer, timer);
333b20bb 11510
c0006262 11511 if (FRAMEP (frame))
333b20bb 11512 {
44b5a125
GM
11513 Fdelete_frame (frame, Qnil);
11514 deleted = Qt;
f6c44811
GM
11515
11516#ifdef USE_LUCID
11517 /* Bloodcurdling hack alert: The Lucid menu bar widget's
11518 redisplay procedure is not called when a tip frame over menu
11519 items is unmapped. Redisplay the menu manually... */
11520 {
11521 struct frame *f = SELECTED_FRAME ();
11522 Widget w = f->output_data.x->menubar_widget;
11523 extern void xlwmenu_redisplay P_ ((Widget));
9180dc8c 11524
f6c44811 11525 if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
dbc64aa7 11526 && w != NULL)
f6c44811
GM
11527 {
11528 BLOCK_INPUT;
11529 xlwmenu_redisplay (w);
11530 UNBLOCK_INPUT;
11531 }
11532 }
11533#endif /* USE_LUCID */
333b20bb
GM
11534 }
11535
c0006262 11536 UNGCPRO;
44b5a125 11537 return unbind_to (count, deleted);
333b20bb
GM
11538}
11539
11540
11541\f
11542/***********************************************************************
11543 File selection dialog
11544 ***********************************************************************/
11545
11546#ifdef USE_MOTIF
11547
11548/* Callback for "OK" and "Cancel" on file selection dialog. */
11549
11550static void
11551file_dialog_cb (widget, client_data, call_data)
11552 Widget widget;
11553 XtPointer call_data, client_data;
11554{
11555 int *result = (int *) client_data;
11556 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
11557 *result = cb->reason;
11558}
11559
11560
a779d213
GM
11561/* Callback for unmapping a file selection dialog. This is used to
11562 capture the case where a dialog is closed via a window manager's
11563 closer button, for example. Using a XmNdestroyCallback didn't work
11564 in this case. */
11565
11566static void
11567file_dialog_unmap_cb (widget, client_data, call_data)
11568 Widget widget;
11569 XtPointer call_data, client_data;
11570{
11571 int *result = (int *) client_data;
11572 *result = XmCR_CANCEL;
11573}
11574
11575
333b20bb 11576DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
7ee72033 11577 doc: /* Read file name, prompting with PROMPT in directory DIR.
c061c855
GM
11578Use a file selection dialog.
11579Select DEFAULT-FILENAME in the dialog's file selection box, if
11580specified. Don't let the user enter a file name in the file
7ee72033
MB
11581selection dialog's entry field, if MUSTMATCH is non-nil. */)
11582 (prompt, dir, default_filename, mustmatch)
333b20bb
GM
11583 Lisp_Object prompt, dir, default_filename, mustmatch;
11584{
11585 int result;
0fe92f72 11586 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
11587 Lisp_Object file = Qnil;
11588 Widget dialog, text, list, help;
11589 Arg al[10];
11590 int ac = 0;
11591 extern XtAppContext Xt_app_con;
333b20bb 11592 XmString dir_xmstring, pattern_xmstring;
333b20bb
GM
11593 int count = specpdl_ptr - specpdl;
11594 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
11595
11596 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
11597 CHECK_STRING (prompt);
11598 CHECK_STRING (dir);
333b20bb
GM
11599
11600 /* Prevent redisplay. */
11601 specbind (Qinhibit_redisplay, Qt);
11602
11603 BLOCK_INPUT;
11604
11605 /* Create the dialog with PROMPT as title, using DIR as initial
11606 directory and using "*" as pattern. */
11607 dir = Fexpand_file_name (dir, Qnil);
11608 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data);
11609 pattern_xmstring = XmStringCreateLocalized ("*");
11610
11611 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac;
11612 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
11613 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
11614 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
11615 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
11616 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
11617 "fsb", al, ac);
11618 XmStringFree (dir_xmstring);
11619 XmStringFree (pattern_xmstring);
11620
11621 /* Add callbacks for OK and Cancel. */
11622 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
11623 (XtPointer) &result);
11624 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
11625 (XtPointer) &result);
a779d213
GM
11626 XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
11627 (XtPointer) &result);
333b20bb
GM
11628
11629 /* Disable the help button since we can't display help. */
11630 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
11631 XtSetSensitive (help, False);
11632
11633 /* Mark OK button as default. */
11634 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
11635 XmNshowAsDefault, True, NULL);
11636
11637 /* If MUSTMATCH is non-nil, disable the file entry field of the
11638 dialog, so that the user must select a file from the files list
11639 box. We can't remove it because we wouldn't have a way to get at
11640 the result file name, then. */
11641 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
11642 if (!NILP (mustmatch))
11643 {
11644 Widget label;
11645 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
11646 XtSetSensitive (text, False);
11647 XtSetSensitive (label, False);
11648 }
11649
11650 /* Manage the dialog, so that list boxes get filled. */
11651 XtManageChild (dialog);
11652
11653 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
11654 must include the path for this to work. */
11655 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
11656 if (STRINGP (default_filename))
11657 {
11658 XmString default_xmstring;
11659 int item_pos;
11660
11661 default_xmstring
11662 = XmStringCreateLocalized (XSTRING (default_filename)->data);
11663
11664 if (!XmListItemExists (list, default_xmstring))
11665 {
11666 /* Add a new item if DEFAULT_FILENAME is not in the list. */
11667 XmListAddItem (list, default_xmstring, 0);
11668 item_pos = 0;
11669 }
11670 else
11671 item_pos = XmListItemPos (list, default_xmstring);
11672 XmStringFree (default_xmstring);
11673
11674 /* Select the item and scroll it into view. */
11675 XmListSelectPos (list, item_pos, True);
11676 XmListSetPos (list, item_pos);
11677 }
11678
563b384d
GM
11679 /* Process events until the user presses Cancel or OK. Block
11680 and unblock input here so that we get a chance of processing
11681 expose events. */
11682 UNBLOCK_INPUT;
03100098 11683 result = 0;
a779d213 11684 while (result == 0)
563b384d
GM
11685 {
11686 BLOCK_INPUT;
11687 XtAppProcessEvent (Xt_app_con, XtIMAll);
11688 UNBLOCK_INPUT;
11689 }
11690 BLOCK_INPUT;
03100098 11691
333b20bb
GM
11692 /* Get the result. */
11693 if (result == XmCR_OK)
11694 {
11695 XmString text;
11696 String data;
11697
d1670063 11698 XtVaGetValues (dialog, XmNtextString, &text, NULL);
333b20bb
GM
11699 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
11700 XmStringFree (text);
11701 file = build_string (data);
11702 XtFree (data);
11703 }
11704 else
11705 file = Qnil;
11706
11707 /* Clean up. */
11708 XtUnmanageChild (dialog);
11709 XtDestroyWidget (dialog);
11710 UNBLOCK_INPUT;
11711 UNGCPRO;
11712
11713 /* Make "Cancel" equivalent to C-g. */
11714 if (NILP (file))
11715 Fsignal (Qquit, Qnil);
11716
11717 return unbind_to (count, file);
11718}
11719
11720#endif /* USE_MOTIF */
11721
333b20bb
GM
11722
11723\f
82bab41c
GM
11724/***********************************************************************
11725 Keyboard
11726 ***********************************************************************/
11727
11728#ifdef HAVE_XKBGETKEYBOARD
11729#include <X11/XKBlib.h>
11730#include <X11/keysym.h>
11731#endif
11732
11733DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
11734 Sx_backspace_delete_keys_p, 0, 1, 0,
7ee72033 11735 doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME.
c061c855
GM
11736FRAME nil means use the selected frame.
11737Value is t if we know that both keys are present, and are mapped to the
7ee72033
MB
11738usual X keysyms. */)
11739 (frame)
82bab41c
GM
11740 Lisp_Object frame;
11741{
11742#ifdef HAVE_XKBGETKEYBOARD
11743 XkbDescPtr kb;
11744 struct frame *f = check_x_frame (frame);
11745 Display *dpy = FRAME_X_DISPLAY (f);
11746 Lisp_Object have_keys;
46f6a258 11747 int major, minor, op, event, error;
82bab41c
GM
11748
11749 BLOCK_INPUT;
46f6a258
GM
11750
11751 /* Check library version in case we're dynamically linked. */
11752 major = XkbMajorVersion;
11753 minor = XkbMinorVersion;
11754 if (!XkbLibraryVersion (&major, &minor))
c1efd260
GM
11755 {
11756 UNBLOCK_INPUT;
11757 return Qnil;
11758 }
46f6a258
GM
11759
11760 /* Check that the server supports XKB. */
11761 major = XkbMajorVersion;
11762 minor = XkbMinorVersion;
11763 if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
c1efd260
GM
11764 {
11765 UNBLOCK_INPUT;
11766 return Qnil;
11767 }
46f6a258
GM
11768
11769 have_keys = Qnil;
c1efd260 11770 kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
82bab41c
GM
11771 if (kb)
11772 {
11773 int delete_keycode = 0, backspace_keycode = 0, i;
c1efd260
GM
11774
11775 if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
82bab41c 11776 {
c1efd260
GM
11777 for (i = kb->min_key_code;
11778 (i < kb->max_key_code
11779 && (delete_keycode == 0 || backspace_keycode == 0));
11780 ++i)
11781 {
d63931a2
GM
11782 /* The XKB symbolic key names can be seen most easily in
11783 the PS file generated by `xkbprint -label name
11784 $DISPLAY'. */
c1efd260
GM
11785 if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
11786 delete_keycode = i;
11787 else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
11788 backspace_keycode = i;
11789 }
11790
11791 XkbFreeNames (kb, 0, True);
82bab41c
GM
11792 }
11793
c1efd260 11794 XkbFreeClientMap (kb, 0, True);
82bab41c
GM
11795
11796 if (delete_keycode
11797 && backspace_keycode
11798 && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
11799 && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
11800 have_keys = Qt;
11801 }
11802 UNBLOCK_INPUT;
11803 return have_keys;
11804#else /* not HAVE_XKBGETKEYBOARD */
11805 return Qnil;
11806#endif /* not HAVE_XKBGETKEYBOARD */
11807}
11808
11809
11810\f
333b20bb
GM
11811/***********************************************************************
11812 Initialization
11813 ***********************************************************************/
11814
11815void
11816syms_of_xfns ()
11817{
11818 /* This is zero if not using X windows. */
11819 x_in_use = 0;
11820
11821 /* The section below is built by the lisp expression at the top of the file,
11822 just above where these variables are declared. */
11823 /*&&& init symbols here &&&*/
11824 Qauto_raise = intern ("auto-raise");
11825 staticpro (&Qauto_raise);
11826 Qauto_lower = intern ("auto-lower");
11827 staticpro (&Qauto_lower);
11828 Qbar = intern ("bar");
dbc4e1c1 11829 staticpro (&Qbar);
f9942c9e
JB
11830 Qborder_color = intern ("border-color");
11831 staticpro (&Qborder_color);
11832 Qborder_width = intern ("border-width");
11833 staticpro (&Qborder_width);
dbc4e1c1
JB
11834 Qbox = intern ("box");
11835 staticpro (&Qbox);
f9942c9e
JB
11836 Qcursor_color = intern ("cursor-color");
11837 staticpro (&Qcursor_color);
dbc4e1c1
JB
11838 Qcursor_type = intern ("cursor-type");
11839 staticpro (&Qcursor_type);
f9942c9e
JB
11840 Qgeometry = intern ("geometry");
11841 staticpro (&Qgeometry);
f9942c9e
JB
11842 Qicon_left = intern ("icon-left");
11843 staticpro (&Qicon_left);
11844 Qicon_top = intern ("icon-top");
11845 staticpro (&Qicon_top);
11846 Qicon_type = intern ("icon-type");
11847 staticpro (&Qicon_type);
80534dd6
KH
11848 Qicon_name = intern ("icon-name");
11849 staticpro (&Qicon_name);
f9942c9e
JB
11850 Qinternal_border_width = intern ("internal-border-width");
11851 staticpro (&Qinternal_border_width);
11852 Qleft = intern ("left");
11853 staticpro (&Qleft);
1ab3d87e
RS
11854 Qright = intern ("right");
11855 staticpro (&Qright);
f9942c9e
JB
11856 Qmouse_color = intern ("mouse-color");
11857 staticpro (&Qmouse_color);
baaed68e
JB
11858 Qnone = intern ("none");
11859 staticpro (&Qnone);
f9942c9e
JB
11860 Qparent_id = intern ("parent-id");
11861 staticpro (&Qparent_id);
4701395c
KH
11862 Qscroll_bar_width = intern ("scroll-bar-width");
11863 staticpro (&Qscroll_bar_width);
8af1d7ca
JB
11864 Qsuppress_icon = intern ("suppress-icon");
11865 staticpro (&Qsuppress_icon);
01f1ba30 11866 Qundefined_color = intern ("undefined-color");
f9942c9e 11867 staticpro (&Qundefined_color);
a3c87d4e
JB
11868 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
11869 staticpro (&Qvertical_scroll_bars);
49795535
JB
11870 Qvisibility = intern ("visibility");
11871 staticpro (&Qvisibility);
f9942c9e
JB
11872 Qwindow_id = intern ("window-id");
11873 staticpro (&Qwindow_id);
2cbebefb
RS
11874 Qouter_window_id = intern ("outer-window-id");
11875 staticpro (&Qouter_window_id);
f9942c9e
JB
11876 Qx_frame_parameter = intern ("x-frame-parameter");
11877 staticpro (&Qx_frame_parameter);
9ef48a9d
RS
11878 Qx_resource_name = intern ("x-resource-name");
11879 staticpro (&Qx_resource_name);
4fe1de12
RS
11880 Quser_position = intern ("user-position");
11881 staticpro (&Quser_position);
11882 Quser_size = intern ("user-size");
11883 staticpro (&Quser_size);
333b20bb
GM
11884 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
11885 staticpro (&Qscroll_bar_foreground);
11886 Qscroll_bar_background = intern ("scroll-bar-background");
11887 staticpro (&Qscroll_bar_background);
d62c8769
GM
11888 Qscreen_gamma = intern ("screen-gamma");
11889 staticpro (&Qscreen_gamma);
563b67aa
GM
11890 Qline_spacing = intern ("line-spacing");
11891 staticpro (&Qline_spacing);
7c7ff7f5
GM
11892 Qcenter = intern ("center");
11893 staticpro (&Qcenter);
96db09e4
KH
11894 Qcompound_text = intern ("compound-text");
11895 staticpro (&Qcompound_text);
ae782866
GM
11896 Qcancel_timer = intern ("cancel-timer");
11897 staticpro (&Qcancel_timer);
ea0a1f53
GM
11898 Qwait_for_wm = intern ("wait-for-wm");
11899 staticpro (&Qwait_for_wm);
49d41073
EZ
11900 Qfullscreen = intern ("fullscreen");
11901 staticpro (&Qfullscreen);
11902 Qfullwidth = intern ("fullwidth");
11903 staticpro (&Qfullwidth);
11904 Qfullheight = intern ("fullheight");
11905 staticpro (&Qfullheight);
11906 Qfullboth = intern ("fullboth");
11907 staticpro (&Qfullboth);
f9942c9e
JB
11908 /* This is the end of symbol initialization. */
11909
58cad5ed
KH
11910 /* Text property `display' should be nonsticky by default. */
11911 Vtext_property_default_nonsticky
11912 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
11913
11914
333b20bb
GM
11915 Qlaplace = intern ("laplace");
11916 staticpro (&Qlaplace);
4a8e312c
GM
11917 Qemboss = intern ("emboss");
11918 staticpro (&Qemboss);
11919 Qedge_detection = intern ("edge-detection");
11920 staticpro (&Qedge_detection);
11921 Qheuristic = intern ("heuristic");
11922 staticpro (&Qheuristic);
11923 QCmatrix = intern (":matrix");
11924 staticpro (&QCmatrix);
11925 QCcolor_adjustment = intern (":color-adjustment");
11926 staticpro (&QCcolor_adjustment);
11927 QCmask = intern (":mask");
11928 staticpro (&QCmask);
11929
a367641f
RS
11930 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
11931 staticpro (&Qface_set_after_frame_default);
11932
01f1ba30
JB
11933 Fput (Qundefined_color, Qerror_conditions,
11934 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
11935 Fput (Qundefined_color, Qerror_message,
11936 build_string ("Undefined color"));
11937
f9942c9e
JB
11938 init_x_parm_symbols ();
11939
7ee72033
MB
11940 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
11941 doc: /* Non-nil means always draw a cross over disabled images.
c061c855
GM
11942Disabled images are those having an `:conversion disabled' property.
11943A cross is always drawn on black & white displays. */);
14819cb3
GM
11944 cross_disabled_images = 0;
11945
7ee72033
MB
11946 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
11947 doc: /* List of directories to search for bitmap files for X. */);
e241c09b 11948 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 11949
7ee72033
MB
11950 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
11951 doc: /* The shape of the pointer when over text.
c061c855
GM
11952Changing the value does not affect existing frames
11953unless you set the mouse color. */);
01f1ba30
JB
11954 Vx_pointer_shape = Qnil;
11955
7ee72033
MB
11956 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
11957 doc: /* The name Emacs uses to look up X resources.
c061c855
GM
11958`x-get-resource' uses this as the first component of the instance name
11959when requesting resource values.
11960Emacs initially sets `x-resource-name' to the name under which Emacs
11961was invoked, or to the value specified with the `-name' or `-rn'
11962switches, if present.
11963
11964It may be useful to bind this variable locally around a call
11965to `x-get-resource'. See also the variable `x-resource-class'. */);
d387c960 11966 Vx_resource_name = Qnil;
ac63d3d6 11967
7ee72033
MB
11968 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
11969 doc: /* The class Emacs uses to look up X resources.
c061c855
GM
11970`x-get-resource' uses this as the first component of the instance class
11971when requesting resource values.
11972
11973Emacs initially sets `x-resource-class' to "Emacs".
11974
11975Setting this variable permanently is not a reasonable thing to do,
11976but binding this variable locally around a call to `x-get-resource'
11977is a reasonable practice. See also the variable `x-resource-name'. */);
498e9ac3
RS
11978 Vx_resource_class = build_string (EMACS_CLASS);
11979
ca0ecbf5 11980#if 0 /* This doesn't really do anything. */
7ee72033
MB
11981 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
11982 doc: /* The shape of the pointer when not over text.
c061c855
GM
11983This variable takes effect when you create a new frame
11984or when you set the mouse color. */);
af01ef26 11985#endif
01f1ba30
JB
11986 Vx_nontext_pointer_shape = Qnil;
11987
7ee72033
MB
11988 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
11989 doc: /* The shape of the pointer when Emacs is busy.
c061c855
GM
11990This variable takes effect when you create a new frame
11991or when you set the mouse color. */);
0af913d7 11992 Vx_hourglass_pointer_shape = Qnil;
333b20bb 11993
7ee72033
MB
11994 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
11995 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 11996 display_hourglass_p = 1;
333b20bb 11997
7ee72033
MB
11998 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
11999 doc: /* *Seconds to wait before displaying an hourglass pointer.
c061c855 12000Value must be an integer or float. */);
0af913d7 12001 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
4ae9a85e 12002
ca0ecbf5 12003#if 0 /* This doesn't really do anything. */
7ee72033
MB
12004 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
12005 doc: /* The shape of the pointer when over the mode line.
c061c855
GM
12006This variable takes effect when you create a new frame
12007or when you set the mouse color. */);
af01ef26 12008#endif
01f1ba30
JB
12009 Vx_mode_pointer_shape = Qnil;
12010
d3b06468 12011 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
7ee72033
MB
12012 &Vx_sensitive_text_pointer_shape,
12013 doc: /* The shape of the pointer when over mouse-sensitive text.
c061c855
GM
12014This variable takes effect when you create a new frame
12015or when you set the mouse color. */);
ca0ecbf5 12016 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 12017
8fb4ec9c 12018 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
7ee72033
MB
12019 &Vx_window_horizontal_drag_shape,
12020 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
c061c855
GM
12021This variable takes effect when you create a new frame
12022or when you set the mouse color. */);
8fb4ec9c
GM
12023 Vx_window_horizontal_drag_shape = Qnil;
12024
7ee72033
MB
12025 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
12026 doc: /* A string indicating the foreground color of the cursor box. */);
01f1ba30
JB
12027 Vx_cursor_fore_pixel = Qnil;
12028
7ee72033
MB
12029 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
12030 doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS).
c061c855 12031Text larger than this is clipped. */);
d63931a2
GM
12032 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
12033
7ee72033
MB
12034 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
12035 doc: /* Non-nil if no X window manager is in use.
c061c855
GM
12036Emacs doesn't try to figure this out; this is always nil
12037unless you set it to something else. */);
2d38195d
RS
12038 /* We don't have any way to find this out, so set it to nil
12039 and maybe the user would like to set it to t. */
12040 Vx_no_window_manager = Qnil;
1d3dac41 12041
942ea06d 12042 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
7ee72033
MB
12043 &Vx_pixel_size_width_font_regexp,
12044 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
c061c855
GM
12045
12046Since Emacs gets width of a font matching with this regexp from
12047PIXEL_SIZE field of the name, font finding mechanism gets faster for
12048such a font. This is especially effective for such large fonts as
12049Chinese, Japanese, and Korean. */);
942ea06d
KH
12050 Vx_pixel_size_width_font_regexp = Qnil;
12051
7ee72033
MB
12052 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
12053 doc: /* Time after which cached images are removed from the cache.
c061c855
GM
12054When an image has not been displayed this many seconds, remove it
12055from the image cache. Value must be an integer or nil with nil
12056meaning don't clear the cache. */);
fcf431dc 12057 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb 12058
1d3dac41 12059#ifdef USE_X_TOOLKIT
6f3f6a8d 12060 Fprovide (intern ("x-toolkit"), Qnil);
5b827abb 12061#ifdef USE_MOTIF
6f3f6a8d 12062 Fprovide (intern ("motif"), Qnil);
fc2cdd9a 12063
7ee72033
MB
12064 DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
12065 doc: /* Version info for LessTif/Motif. */);
fc2cdd9a
GM
12066 Vmotif_version_string = build_string (XmVERSION_STRING);
12067#endif /* USE_MOTIF */
12068#endif /* USE_X_TOOLKIT */
01f1ba30 12069
01f1ba30 12070 defsubr (&Sx_get_resource);
333b20bb
GM
12071
12072 /* X window properties. */
12073 defsubr (&Sx_change_window_property);
12074 defsubr (&Sx_delete_window_property);
12075 defsubr (&Sx_window_property);
12076
2d764c78 12077 defsubr (&Sxw_display_color_p);
d0c9d219 12078 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
12079 defsubr (&Sxw_color_defined_p);
12080 defsubr (&Sxw_color_values);
9d317b2c 12081 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
12082 defsubr (&Sx_server_vendor);
12083 defsubr (&Sx_server_version);
12084 defsubr (&Sx_display_pixel_width);
12085 defsubr (&Sx_display_pixel_height);
12086 defsubr (&Sx_display_mm_width);
12087 defsubr (&Sx_display_mm_height);
12088 defsubr (&Sx_display_screens);
12089 defsubr (&Sx_display_planes);
12090 defsubr (&Sx_display_color_cells);
12091 defsubr (&Sx_display_visual_class);
12092 defsubr (&Sx_display_backing_store);
12093 defsubr (&Sx_display_save_under);
8af1d7ca 12094 defsubr (&Sx_parse_geometry);
f676886a 12095 defsubr (&Sx_create_frame);
01f1ba30 12096 defsubr (&Sx_open_connection);
08a90d6a
RS
12097 defsubr (&Sx_close_connection);
12098 defsubr (&Sx_display_list);
01f1ba30 12099 defsubr (&Sx_synchronize);
3decc1e7 12100 defsubr (&Sx_focus_frame);
82bab41c
GM
12101 defsubr (&Sx_backspace_delete_keys_p);
12102
942ea06d
KH
12103 /* Setting callback functions for fontset handler. */
12104 get_font_info_func = x_get_font_info;
333b20bb
GM
12105
12106#if 0 /* This function pointer doesn't seem to be used anywhere.
12107 And the pointer assigned has the wrong type, anyway. */
942ea06d 12108 list_fonts_func = x_list_fonts;
333b20bb
GM
12109#endif
12110
942ea06d 12111 load_font_func = x_load_font;
bc1958c4 12112 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
12113 query_font_func = x_query_font;
12114 set_frame_fontset_func = x_set_font;
12115 check_window_system_func = check_x;
333b20bb
GM
12116
12117 /* Images. */
12118 Qxbm = intern ("xbm");
12119 staticpro (&Qxbm);
12120 QCtype = intern (":type");
12121 staticpro (&QCtype);
d2dc8167
GM
12122 QCconversion = intern (":conversion");
12123 staticpro (&QCconversion);
333b20bb
GM
12124 QCheuristic_mask = intern (":heuristic-mask");
12125 staticpro (&QCheuristic_mask);
12126 QCcolor_symbols = intern (":color-symbols");
12127 staticpro (&QCcolor_symbols);
333b20bb
GM
12128 QCascent = intern (":ascent");
12129 staticpro (&QCascent);
12130 QCmargin = intern (":margin");
12131 staticpro (&QCmargin);
12132 QCrelief = intern (":relief");
12133 staticpro (&QCrelief);
fcf431dc
GM
12134 Qpostscript = intern ("postscript");
12135 staticpro (&Qpostscript);
333b20bb
GM
12136 QCloader = intern (":loader");
12137 staticpro (&QCloader);
12138 QCbounding_box = intern (":bounding-box");
12139 staticpro (&QCbounding_box);
12140 QCpt_width = intern (":pt-width");
12141 staticpro (&QCpt_width);
12142 QCpt_height = intern (":pt-height");
12143 staticpro (&QCpt_height);
3ccff1e3
GM
12144 QCindex = intern (":index");
12145 staticpro (&QCindex);
333b20bb
GM
12146 Qpbm = intern ("pbm");
12147 staticpro (&Qpbm);
12148
12149#if HAVE_XPM
12150 Qxpm = intern ("xpm");
12151 staticpro (&Qxpm);
12152#endif
12153
12154#if HAVE_JPEG
12155 Qjpeg = intern ("jpeg");
12156 staticpro (&Qjpeg);
12157#endif
12158
12159#if HAVE_TIFF
12160 Qtiff = intern ("tiff");
12161 staticpro (&Qtiff);
12162#endif
12163
12164#if HAVE_GIF
12165 Qgif = intern ("gif");
12166 staticpro (&Qgif);
12167#endif
12168
12169#if HAVE_PNG
12170 Qpng = intern ("png");
12171 staticpro (&Qpng);
12172#endif
12173
12174 defsubr (&Sclear_image_cache);
42677916 12175 defsubr (&Simage_size);
b243755a 12176 defsubr (&Simage_mask_p);
333b20bb 12177
0af913d7
GM
12178 hourglass_atimer = NULL;
12179 hourglass_shown_p = 0;
333b20bb
GM
12180
12181 defsubr (&Sx_show_tip);
12182 defsubr (&Sx_hide_tip);
333b20bb 12183 tip_timer = Qnil;
44b5a125
GM
12184 staticpro (&tip_timer);
12185 tip_frame = Qnil;
12186 staticpro (&tip_frame);
333b20bb 12187
06d62053
GM
12188 last_show_tip_args = Qnil;
12189 staticpro (&last_show_tip_args);
12190
333b20bb
GM
12191#ifdef USE_MOTIF
12192 defsubr (&Sx_file_dialog);
12193#endif
12194}
12195
12196
12197void
12198init_xfns ()
12199{
12200 image_types = NULL;
12201 Vimage_types = Qnil;
12202
12203 define_image_type (&xbm_type);
12204 define_image_type (&gs_type);
12205 define_image_type (&pbm_type);
12206
12207#if HAVE_XPM
12208 define_image_type (&xpm_type);
12209#endif
12210
12211#if HAVE_JPEG
12212 define_image_type (&jpeg_type);
12213#endif
12214
12215#if HAVE_TIFF
12216 define_image_type (&tiff_type);
12217#endif
12218
12219#if HAVE_GIF
12220 define_image_type (&gif_type);
12221#endif
12222
12223#if HAVE_PNG
12224 define_image_type (&png_type);
12225#endif
01f1ba30
JB
12226}
12227
12228#endif /* HAVE_X_WINDOWS */