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