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