* w32fns.c (validate_x_resource_name): Use SSET.
[bpt/emacs.git] / src / xfns.c
CommitLineData
01f1ba30 1/* Functions for the X window system.
edf36fe6 2 Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
333b20bb 3 Free Software Foundation.
01f1ba30
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
1113d9db 9the Free Software Foundation; either version 2, or (at your option)
01f1ba30
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
01f1ba30 21
c389a86d 22#include <config.h>
68c45bf0 23#include <signal.h>
333b20bb 24#include <stdio.h>
d62c8769 25#include <math.h>
c389a86d 26
3ecaf7e5
RS
27#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
30
40e6f148 31/* This makes the fields of a Display accessible, in Xlib header files. */
333b20bb 32
40e6f148
RS
33#define XLIB_ILLEGAL_ACCESS
34
01f1ba30
JB
35#include "lisp.h"
36#include "xterm.h"
f676886a 37#include "frame.h"
01f1ba30
JB
38#include "window.h"
39#include "buffer.h"
58cad5ed 40#include "intervals.h"
01f1ba30 41#include "dispextern.h"
1f98fa48 42#include "keyboard.h"
9ac0d9e0 43#include "blockinput.h"
57bda87a 44#include <epaths.h>
942ea06d 45#include "charset.h"
96db09e4 46#include "coding.h"
942ea06d 47#include "fontset.h"
333b20bb
GM
48#include "systime.h"
49#include "termhooks.h"
4ae9a85e 50#include "atimer.h"
01f1ba30
JB
51
52#ifdef HAVE_X_WINDOWS
67ba84d1 53
67ba84d1 54#include <ctype.h>
63cec32f
GM
55#include <sys/types.h>
56#include <sys/stat.h>
01f1ba30 57
0a93081c 58#ifndef VMS
0505a740 59#if 1 /* Used to be #ifdef EMACS_BITMAP_FILES, but this should always work. */
ef493a27
RS
60#include "bitmaps/gray.xbm"
61#else
dbc4e1c1 62#include <X11/bitmaps/gray>
ef493a27 63#endif
0a93081c
JB
64#else
65#include "[.bitmaps]gray.xbm"
66#endif
dbc4e1c1 67
9ef48a9d
RS
68#ifdef USE_X_TOOLKIT
69#include <X11/Shell.h>
70
398ffa92 71#ifndef USE_MOTIF
9ef48a9d
RS
72#include <X11/Xaw/Paned.h>
73#include <X11/Xaw/Label.h>
398ffa92 74#endif /* USE_MOTIF */
9ef48a9d
RS
75
76#ifdef USG
77#undef USG /* ####KLUDGE for Solaris 2.2 and up */
78#include <X11/Xos.h>
79#define USG
80#else
81#include <X11/Xos.h>
82#endif
83
84#include "widget.h"
85
86#include "../lwlib/lwlib.h"
87
333b20bb
GM
88#ifdef USE_MOTIF
89#include <Xm/Xm.h>
90#include <Xm/DialogS.h>
91#include <Xm/FileSB.h>
92#endif
93
3b882b1d
RS
94/* Do the EDITRES protocol if running X11R5
95 Exception: HP-UX (at least version A.09.05) has X11R5 without EditRes */
333b20bb 96
3b882b1d 97#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
6c32dd68 98#define HACK_EDITRES
b9dc4443 99extern void _XEditResCheckMessages ();
6c32dd68
PR
100#endif /* R5 + Athena */
101
333b20bb
GM
102/* Unique id counter for widgets created by the Lucid Widget Library. */
103
6c32dd68
PR
104extern LWLIB_ID widget_id_tick;
105
e3881aa0 106#ifdef USE_LUCID
82c90203 107/* This is part of a kludge--see lwlib/xlwmenu.c. */
03e2c340 108extern XFontStruct *xlwmenu_default_font;
e3881aa0 109#endif
9ef48a9d 110
6bc20398 111extern void free_frame_menubar ();
d62c8769 112extern double atof ();
333b20bb 113
fc2cdd9a
GM
114#ifdef USE_MOTIF
115
116/* LessTif/Motif version info. */
117
118static Lisp_Object Vmotif_version_string;
119
120#endif /* USE_MOTIF */
121
9ef48a9d
RS
122#endif /* USE_X_TOOLKIT */
123
9d317b2c
RS
124#ifdef HAVE_X11R4
125#define MAXREQUEST(dpy) (XMaxRequestSize (dpy))
126#else
127#define MAXREQUEST(dpy) ((dpy)->max_request_size)
128#endif
129
333b20bb
GM
130/* The gray bitmap `bitmaps/gray'. This is done because xterm.c uses
131 it, and including `bitmaps/gray' more than once is a problem when
132 config.h defines `static' as an empty replacement string. */
133
134int gray_bitmap_width = gray_width;
135int gray_bitmap_height = gray_height;
62906360 136char *gray_bitmap_bits = gray_bits;
333b20bb 137
498e9ac3 138/* The name we're using in resource queries. Most often "emacs". */
333b20bb 139
d387c960 140Lisp_Object Vx_resource_name;
ac63d3d6 141
498e9ac3
RS
142/* The application class we're using in resource queries.
143 Normally "Emacs". */
333b20bb 144
498e9ac3
RS
145Lisp_Object Vx_resource_class;
146
0af913d7 147/* Non-zero means we're allowed to display an hourglass cursor. */
333b20bb 148
0af913d7 149int display_hourglass_p;
333b20bb 150
01f1ba30 151/* The background and shape of the mouse pointer, and shape when not
b9dc4443 152 over text or in the modeline. */
333b20bb 153
01f1ba30 154Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 155Lisp_Object Vx_hourglass_pointer_shape;
333b20bb 156
ca0ecbf5 157/* The shape when over mouse-sensitive text. */
333b20bb 158
ca0ecbf5 159Lisp_Object Vx_sensitive_text_pointer_shape;
01f1ba30 160
8fb4ec9c
GM
161/* If non-nil, the pointer shape to indicate that windows can be
162 dragged horizontally. */
163
164Lisp_Object Vx_window_horizontal_drag_shape;
165
b9dc4443 166/* Color of chars displayed in cursor box. */
333b20bb 167
01f1ba30
JB
168Lisp_Object Vx_cursor_fore_pixel;
169
b9dc4443 170/* Nonzero if using X. */
333b20bb 171
b9dc4443 172static int x_in_use;
01f1ba30 173
b9dc4443 174/* Non nil if no window manager is in use. */
333b20bb 175
01f1ba30
JB
176Lisp_Object Vx_no_window_manager;
177
f1c7b5a6 178/* Search path for bitmap files. */
333b20bb 179
f1c7b5a6
RS
180Lisp_Object Vx_bitmap_file_path;
181
942ea06d 182/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
333b20bb 183
942ea06d
KH
184Lisp_Object Vx_pixel_size_width_font_regexp;
185
f9942c9e
JB
186Lisp_Object Qauto_raise;
187Lisp_Object Qauto_lower;
a9653085 188Lisp_Object Qbar, Qhbar;
f9942c9e
JB
189Lisp_Object Qborder_color;
190Lisp_Object Qborder_width;
dbc4e1c1 191Lisp_Object Qbox;
f9942c9e 192Lisp_Object Qcursor_color;
dbc4e1c1 193Lisp_Object Qcursor_type;
f9942c9e 194Lisp_Object Qgeometry;
f9942c9e
JB
195Lisp_Object Qicon_left;
196Lisp_Object Qicon_top;
197Lisp_Object Qicon_type;
80534dd6 198Lisp_Object Qicon_name;
f9942c9e
JB
199Lisp_Object Qinternal_border_width;
200Lisp_Object Qleft;
1ab3d87e 201Lisp_Object Qright;
f9942c9e 202Lisp_Object Qmouse_color;
baaed68e 203Lisp_Object Qnone;
2cbebefb 204Lisp_Object Qouter_window_id;
f9942c9e 205Lisp_Object Qparent_id;
4701395c 206Lisp_Object Qscroll_bar_width;
8af1d7ca 207Lisp_Object Qsuppress_icon;
333b20bb 208extern Lisp_Object Qtop;
01f1ba30 209Lisp_Object Qundefined_color;
a3c87d4e 210Lisp_Object Qvertical_scroll_bars;
49795535 211Lisp_Object Qvisibility;
f9942c9e 212Lisp_Object Qwindow_id;
f676886a 213Lisp_Object Qx_frame_parameter;
9ef48a9d 214Lisp_Object Qx_resource_name;
4fe1de12
RS
215Lisp_Object Quser_position;
216Lisp_Object Quser_size;
0cafb359 217extern Lisp_Object Qdisplay;
333b20bb 218Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
7c7ff7f5 219Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
ae782866 220Lisp_Object Qcompound_text, Qcancel_timer;
ea0a1f53 221Lisp_Object Qwait_for_wm;
49d41073
EZ
222Lisp_Object Qfullscreen;
223Lisp_Object Qfullwidth;
224Lisp_Object Qfullheight;
225Lisp_Object Qfullboth;
01f1ba30 226
b9dc4443 227/* The below are defined in frame.c. */
333b20bb 228
baaed68e 229extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
c2304e02 230extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
9ea173e8 231extern Lisp_Object Qtool_bar_lines;
f9942c9e 232
01f1ba30
JB
233extern Lisp_Object Vwindow_system_version;
234
a367641f 235Lisp_Object Qface_set_after_frame_default;
333b20bb 236
f1d2ce7f 237#if GLYPH_DEBUG
eaf1eea9
GM
238int image_cache_refcount, dpyinfo_refcount;
239#endif
240
241
01f1ba30 242\f
11ae94fe 243/* Error if we are not connected to X. */
333b20bb 244
7fc9de26 245void
11ae94fe
RS
246check_x ()
247{
b9dc4443 248 if (! x_in_use)
11ae94fe
RS
249 error ("X windows are not in use or not initialized");
250}
251
1c59f5df
RS
252/* Nonzero if we can use mouse menus.
253 You should not call this unless HAVE_MENUS is defined. */
75cc8ee5
RS
254
255int
1c59f5df 256have_menus_p ()
75cc8ee5 257{
b9dc4443
RS
258 return x_in_use;
259}
260
261/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
262 and checking validity for X. */
263
264FRAME_PTR
265check_x_frame (frame)
266 Lisp_Object frame;
267{
268 FRAME_PTR f;
269
270 if (NILP (frame))
0fe92f72 271 frame = selected_frame;
b7826503 272 CHECK_LIVE_FRAME (frame);
0fe92f72 273 f = XFRAME (frame);
b9dc4443 274 if (! FRAME_X_P (f))
1c59f5df 275 error ("Non-X frame used");
b9dc4443 276 return f;
75cc8ee5
RS
277}
278
b9dc4443
RS
279/* Let the user specify an X display with a frame.
280 nil stands for the selected frame--or, if that is not an X frame,
281 the first X display on the list. */
282
283static struct x_display_info *
284check_x_display_info (frame)
285 Lisp_Object frame;
286{
8ec8a5ec
GM
287 struct x_display_info *dpyinfo = NULL;
288
b9dc4443
RS
289 if (NILP (frame))
290 {
0fe92f72
GM
291 struct frame *sf = XFRAME (selected_frame);
292
293 if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
8ec8a5ec 294 dpyinfo = FRAME_X_DISPLAY_INFO (sf);
b9dc4443 295 else if (x_display_list != 0)
8ec8a5ec 296 dpyinfo = x_display_list;
b9dc4443
RS
297 else
298 error ("X windows are not in use or not initialized");
299 }
300 else if (STRINGP (frame))
8ec8a5ec 301 dpyinfo = x_display_info_for_name (frame);
b9dc4443
RS
302 else
303 {
ba4c10fd 304 FRAME_PTR f = check_x_frame (frame);
8ec8a5ec 305 dpyinfo = FRAME_X_DISPLAY_INFO (f);
b9dc4443 306 }
8ec8a5ec
GM
307
308 return dpyinfo;
b9dc4443 309}
333b20bb 310
b9dc4443 311\f
f676886a
JB
312/* Return the Emacs frame-object corresponding to an X window.
313 It could be the frame's main window or an icon window. */
01f1ba30 314
34ca5317 315/* This function can be called during GC, so use GC_xxx type test macros. */
bcb2db92 316
f676886a 317struct frame *
2d271e2e
KH
318x_window_to_frame (dpyinfo, wdesc)
319 struct x_display_info *dpyinfo;
01f1ba30
JB
320 int wdesc;
321{
f676886a
JB
322 Lisp_Object tail, frame;
323 struct frame *f;
01f1ba30 324
8e713be6 325 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
01f1ba30 326 {
8e713be6 327 frame = XCAR (tail);
34ca5317 328 if (!GC_FRAMEP (frame))
01f1ba30 329 continue;
f676886a 330 f = XFRAME (frame);
2d764c78 331 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
2d271e2e 332 continue;
0af913d7 333 if (f->output_data.x->hourglass_window == wdesc)
17cbbf95 334 return f;
9ef48a9d 335#ifdef USE_X_TOOLKIT
7556890b
RS
336 if ((f->output_data.x->edit_widget
337 && XtWindow (f->output_data.x->edit_widget) == wdesc)
333b20bb
GM
338 /* A tooltip frame? */
339 || (!f->output_data.x->edit_widget
340 && FRAME_X_WINDOW (f) == wdesc)
7556890b 341 || f->output_data.x->icon_desc == wdesc)
9ef48a9d
RS
342 return f;
343#else /* not USE_X_TOOLKIT */
fe24a618 344 if (FRAME_X_WINDOW (f) == wdesc
7556890b 345 || f->output_data.x->icon_desc == wdesc)
f676886a 346 return f;
9ef48a9d
RS
347#endif /* not USE_X_TOOLKIT */
348 }
349 return 0;
350}
351
352#ifdef USE_X_TOOLKIT
353/* Like x_window_to_frame but also compares the window with the widget's
354 windows. */
355
356struct frame *
2d271e2e
KH
357x_any_window_to_frame (dpyinfo, wdesc)
358 struct x_display_info *dpyinfo;
9ef48a9d
RS
359 int wdesc;
360{
361 Lisp_Object tail, frame;
17cbbf95 362 struct frame *f, *found;
7556890b 363 struct x_output *x;
9ef48a9d 364
17cbbf95
GM
365 found = NULL;
366 for (tail = Vframe_list; GC_CONSP (tail) && !found; tail = XCDR (tail))
9ef48a9d 367 {
8e713be6 368 frame = XCAR (tail);
34ca5317 369 if (!GC_FRAMEP (frame))
9ef48a9d 370 continue;
17cbbf95 371
9ef48a9d 372 f = XFRAME (frame);
17cbbf95 373 if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo)
333b20bb 374 {
17cbbf95
GM
375 /* This frame matches if the window is any of its widgets. */
376 x = f->output_data.x;
0af913d7 377 if (x->hourglass_window == wdesc)
17cbbf95
GM
378 found = f;
379 else if (x->widget)
380 {
381 if (wdesc == XtWindow (x->widget)
382 || wdesc == XtWindow (x->column_widget)
383 || wdesc == XtWindow (x->edit_widget))
384 found = f;
385 /* Match if the window is this frame's menubar. */
386 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
387 found = f;
388 }
389 else if (FRAME_X_WINDOW (f) == wdesc)
390 /* A tooltip frame. */
391 found = f;
333b20bb 392 }
01f1ba30 393 }
17cbbf95
GM
394
395 return found;
01f1ba30 396}
5e65b9ab 397
5fbc3f3a
KH
398/* Likewise, but exclude the menu bar widget. */
399
400struct frame *
401x_non_menubar_window_to_frame (dpyinfo, wdesc)
402 struct x_display_info *dpyinfo;
403 int wdesc;
404{
405 Lisp_Object tail, frame;
406 struct frame *f;
7556890b 407 struct x_output *x;
5fbc3f3a 408
8e713be6 409 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
5fbc3f3a 410 {
8e713be6 411 frame = XCAR (tail);
5fbc3f3a
KH
412 if (!GC_FRAMEP (frame))
413 continue;
414 f = XFRAME (frame);
2d764c78 415 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
5fbc3f3a 416 continue;
7556890b 417 x = f->output_data.x;
5fbc3f3a 418 /* This frame matches if the window is any of its widgets. */
0af913d7 419 if (x->hourglass_window == wdesc)
17cbbf95
GM
420 return f;
421 else if (x->widget)
333b20bb
GM
422 {
423 if (wdesc == XtWindow (x->widget)
424 || wdesc == XtWindow (x->column_widget)
425 || wdesc == XtWindow (x->edit_widget))
426 return f;
427 }
428 else if (FRAME_X_WINDOW (f) == wdesc)
429 /* A tooltip frame. */
5fbc3f3a
KH
430 return f;
431 }
432 return 0;
433}
434
fd3a3022
RS
435/* Likewise, but consider only the menu bar widget. */
436
437struct frame *
438x_menubar_window_to_frame (dpyinfo, wdesc)
439 struct x_display_info *dpyinfo;
440 int wdesc;
441{
442 Lisp_Object tail, frame;
443 struct frame *f;
7556890b 444 struct x_output *x;
fd3a3022 445
8e713be6 446 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
fd3a3022 447 {
8e713be6 448 frame = XCAR (tail);
fd3a3022
RS
449 if (!GC_FRAMEP (frame))
450 continue;
451 f = XFRAME (frame);
2d764c78 452 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
fd3a3022 453 continue;
7556890b 454 x = f->output_data.x;
fd3a3022 455 /* Match if the window is this frame's menubar. */
333b20bb
GM
456 if (x->menubar_widget
457 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
fd3a3022
RS
458 return f;
459 }
460 return 0;
461}
462
5e65b9ab
RS
463/* Return the frame whose principal (outermost) window is WDESC.
464 If WDESC is some other (smaller) window, we return 0. */
465
466struct frame *
2d271e2e
KH
467x_top_window_to_frame (dpyinfo, wdesc)
468 struct x_display_info *dpyinfo;
5e65b9ab
RS
469 int wdesc;
470{
471 Lisp_Object tail, frame;
472 struct frame *f;
7556890b 473 struct x_output *x;
5e65b9ab 474
8e713be6 475 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
5e65b9ab 476 {
8e713be6 477 frame = XCAR (tail);
34ca5317 478 if (!GC_FRAMEP (frame))
5e65b9ab
RS
479 continue;
480 f = XFRAME (frame);
2d764c78 481 if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
2d271e2e 482 continue;
7556890b 483 x = f->output_data.x;
333b20bb
GM
484
485 if (x->widget)
486 {
487 /* This frame matches if the window is its topmost widget. */
488 if (wdesc == XtWindow (x->widget))
489 return f;
7a994728
KH
490#if 0 /* I don't know why it did this,
491 but it seems logically wrong,
492 and it causes trouble for MapNotify events. */
333b20bb
GM
493 /* Match if the window is this frame's menubar. */
494 if (x->menubar_widget
495 && wdesc == XtWindow (x->menubar_widget))
496 return f;
7a994728 497#endif
333b20bb
GM
498 }
499 else if (FRAME_X_WINDOW (f) == wdesc)
500 /* Tooltip frame. */
501 return f;
5e65b9ab
RS
502 }
503 return 0;
504}
9ef48a9d 505#endif /* USE_X_TOOLKIT */
01f1ba30 506
01f1ba30 507\f
203c1d73
RS
508
509/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
510 id, which is just an int that this section returns. Bitmaps are
511 reference counted so they can be shared among frames.
512
513 Bitmap indices are guaranteed to be > 0, so a negative number can
514 be used to indicate no bitmap.
515
516 If you use x_create_bitmap_from_data, then you must keep track of
517 the bitmaps yourself. That is, creating a bitmap from the same
b9dc4443 518 data more than once will not be caught. */
203c1d73
RS
519
520
f1c7b5a6
RS
521/* Functions to access the contents of a bitmap, given an id. */
522
523int
524x_bitmap_height (f, id)
525 FRAME_PTR f;
526 int id;
527{
08a90d6a 528 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
f1c7b5a6
RS
529}
530
531int
532x_bitmap_width (f, id)
533 FRAME_PTR f;
534 int id;
535{
08a90d6a 536 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
f1c7b5a6
RS
537}
538
539int
540x_bitmap_pixmap (f, id)
541 FRAME_PTR f;
542 int id;
543{
08a90d6a 544 return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
f1c7b5a6
RS
545}
546
547
203c1d73
RS
548/* Allocate a new bitmap record. Returns index of new record. */
549
550static int
08a90d6a
RS
551x_allocate_bitmap_record (f)
552 FRAME_PTR f;
203c1d73 553{
08a90d6a
RS
554 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
555 int i;
556
557 if (dpyinfo->bitmaps == NULL)
203c1d73 558 {
08a90d6a
RS
559 dpyinfo->bitmaps_size = 10;
560 dpyinfo->bitmaps
561 = (struct x_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
562 dpyinfo->bitmaps_last = 1;
203c1d73
RS
563 return 1;
564 }
565
08a90d6a
RS
566 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
567 return ++dpyinfo->bitmaps_last;
203c1d73 568
08a90d6a
RS
569 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
570 if (dpyinfo->bitmaps[i].refcount == 0)
571 return i + 1;
203c1d73 572
08a90d6a
RS
573 dpyinfo->bitmaps_size *= 2;
574 dpyinfo->bitmaps
575 = (struct x_bitmap_record *) xrealloc (dpyinfo->bitmaps,
576 dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record));
577 return ++dpyinfo->bitmaps_last;
203c1d73
RS
578}
579
580/* Add one reference to the reference count of the bitmap with id ID. */
581
582void
f1c7b5a6
RS
583x_reference_bitmap (f, id)
584 FRAME_PTR f;
203c1d73
RS
585 int id;
586{
08a90d6a 587 ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
203c1d73
RS
588}
589
590/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
591
592int
593x_create_bitmap_from_data (f, bits, width, height)
594 struct frame *f;
595 char *bits;
596 unsigned int width, height;
597{
08a90d6a 598 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
203c1d73
RS
599 Pixmap bitmap;
600 int id;
601
b9dc4443 602 bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
203c1d73
RS
603 bits, width, height);
604
605 if (! bitmap)
606 return -1;
607
08a90d6a
RS
608 id = x_allocate_bitmap_record (f);
609 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
610 dpyinfo->bitmaps[id - 1].file = NULL;
611 dpyinfo->bitmaps[id - 1].refcount = 1;
612 dpyinfo->bitmaps[id - 1].depth = 1;
613 dpyinfo->bitmaps[id - 1].height = height;
614 dpyinfo->bitmaps[id - 1].width = width;
203c1d73
RS
615
616 return id;
617}
618
619/* Create bitmap from file FILE for frame F. */
620
621int
622x_create_bitmap_from_file (f, file)
623 struct frame *f;
f1c7b5a6 624 Lisp_Object file;
203c1d73 625{
08a90d6a 626 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
203c1d73
RS
627 unsigned int width, height;
628 Pixmap bitmap;
629 int xhot, yhot, result, id;
f1c7b5a6
RS
630 Lisp_Object found;
631 int fd;
632 char *filename;
203c1d73
RS
633
634 /* Look for an existing bitmap with the same name. */
08a90d6a 635 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
203c1d73 636 {
08a90d6a
RS
637 if (dpyinfo->bitmaps[id].refcount
638 && dpyinfo->bitmaps[id].file
d5db4077 639 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
203c1d73 640 {
08a90d6a 641 ++dpyinfo->bitmaps[id].refcount;
203c1d73
RS
642 return id + 1;
643 }
644 }
645
f1c7b5a6 646 /* Search bitmap-file-path for the file, if appropriate. */
de2413e9 647 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
f1c7b5a6
RS
648 if (fd < 0)
649 return -1;
68c45bf0 650 emacs_close (fd);
f1c7b5a6 651
d5db4077 652 filename = (char *) SDATA (found);
f1c7b5a6 653
b9dc4443 654 result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f1c7b5a6 655 filename, &width, &height, &bitmap, &xhot, &yhot);
203c1d73
RS
656 if (result != BitmapSuccess)
657 return -1;
658
08a90d6a
RS
659 id = x_allocate_bitmap_record (f);
660 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
661 dpyinfo->bitmaps[id - 1].refcount = 1;
9f2a85b2 662 dpyinfo->bitmaps[id - 1].file
d5db4077 663 = (char *) xmalloc (SBYTES (file) + 1);
08a90d6a
RS
664 dpyinfo->bitmaps[id - 1].depth = 1;
665 dpyinfo->bitmaps[id - 1].height = height;
666 dpyinfo->bitmaps[id - 1].width = width;
d5db4077 667 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
203c1d73
RS
668
669 return id;
670}
671
672/* Remove reference to bitmap with id number ID. */
673
968b1234 674void
f1c7b5a6
RS
675x_destroy_bitmap (f, id)
676 FRAME_PTR f;
203c1d73
RS
677 int id;
678{
08a90d6a
RS
679 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
680
203c1d73
RS
681 if (id > 0)
682 {
08a90d6a
RS
683 --dpyinfo->bitmaps[id - 1].refcount;
684 if (dpyinfo->bitmaps[id - 1].refcount == 0)
203c1d73 685 {
ed662bdd 686 BLOCK_INPUT;
08a90d6a
RS
687 XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].pixmap);
688 if (dpyinfo->bitmaps[id - 1].file)
203c1d73 689 {
333b20bb 690 xfree (dpyinfo->bitmaps[id - 1].file);
08a90d6a 691 dpyinfo->bitmaps[id - 1].file = NULL;
203c1d73 692 }
ed662bdd 693 UNBLOCK_INPUT;
203c1d73
RS
694 }
695 }
696}
697
08a90d6a 698/* Free all the bitmaps for the display specified by DPYINFO. */
203c1d73 699
08a90d6a
RS
700static void
701x_destroy_all_bitmaps (dpyinfo)
702 struct x_display_info *dpyinfo;
203c1d73 703{
08a90d6a
RS
704 int i;
705 for (i = 0; i < dpyinfo->bitmaps_last; i++)
706 if (dpyinfo->bitmaps[i].refcount > 0)
707 {
708 XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].pixmap);
709 if (dpyinfo->bitmaps[i].file)
333b20bb 710 xfree (dpyinfo->bitmaps[i].file);
08a90d6a
RS
711 }
712 dpyinfo->bitmaps_last = 0;
203c1d73
RS
713}
714\f
f676886a 715/* Connect the frame-parameter names for X frames
01f1ba30
JB
716 to the ways of passing the parameter values to the window system.
717
718 The name of a parameter, as a Lisp symbol,
f676886a 719 has an `x-frame-parameter' property which is an integer in Lisp
9fb026ab 720 that is an index in this table. */
01f1ba30 721
f676886a 722struct x_frame_parm_table
01f1ba30
JB
723{
724 char *name;
d62c8769 725 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
01f1ba30
JB
726};
727
eaf1eea9
GM
728static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
729static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
52de7ce9 730static void x_change_window_heights P_ ((Lisp_Object, int));
14819cb3 731static void x_disable_image P_ ((struct frame *, struct image *));
d62c8769 732void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
563b67aa 733static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
ea0a1f53 734static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object));
49d41073 735static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
d62c8769
GM
736void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
737void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
738void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
739void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
740void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
741void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
742void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
b3ba0aa8 743static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
d62c8769
GM
744void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
745void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
746void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
747 Lisp_Object));
748void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
749void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
750void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
751void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
752 Lisp_Object));
753void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
754void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
755void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
756void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
757void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
9ea173e8 758void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
333b20bb
GM
759void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
760 Lisp_Object));
761void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
762 Lisp_Object));
763static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
764 Lisp_Object,
765 Lisp_Object,
766 char *, char *,
767 int));
d62c8769 768static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
4a8e312c
GM
769static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
770 Lisp_Object));
b243755a
GM
771static void init_color_table P_ ((void));
772static void free_color_table P_ ((void));
773static unsigned long *colors_in_color_table P_ ((int *n));
774static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
775static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
776
777
01f1ba30 778
f676886a 779static struct x_frame_parm_table x_frame_parms[] =
01f1ba30 780{
9908a324
PJ
781 {"auto-raise", x_set_autoraise},
782 {"auto-lower", x_set_autolower},
783 {"background-color", x_set_background_color},
784 {"border-color", x_set_border_color},
785 {"border-width", x_set_border_width},
786 {"cursor-color", x_set_cursor_color},
787 {"cursor-type", x_set_cursor_type},
788 {"font", x_set_font},
789 {"foreground-color", x_set_foreground_color},
790 {"icon-name", x_set_icon_name},
791 {"icon-type", x_set_icon_type},
792 {"internal-border-width", x_set_internal_border_width},
793 {"menu-bar-lines", x_set_menu_bar_lines},
794 {"mouse-color", x_set_mouse_color},
795 {"name", x_explicitly_set_name},
796 {"scroll-bar-width", x_set_scroll_bar_width},
797 {"title", x_set_title},
798 {"unsplittable", x_set_unsplittable},
799 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
800 {"visibility", x_set_visibility},
801 {"tool-bar-lines", x_set_tool_bar_lines},
802 {"scroll-bar-foreground", x_set_scroll_bar_foreground},
803 {"scroll-bar-background", x_set_scroll_bar_background},
804 {"screen-gamma", x_set_screen_gamma},
805 {"line-spacing", x_set_line_spacing},
806 {"left-fringe", x_set_fringe_width},
807 {"right-fringe", x_set_fringe_width},
49d41073
EZ
808 {"wait-for-wm", x_set_wait_for_wm},
809 {"fullscreen", x_set_fullscreen},
810
01f1ba30
JB
811};
812
f676886a 813/* Attach the `x-frame-parameter' properties to
01f1ba30
JB
814 the Lisp symbol names of parameters relevant to X. */
815
201d8c78 816void
01f1ba30
JB
817init_x_parm_symbols ()
818{
819 int i;
820
d043f1a4 821 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
f676886a 822 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
01f1ba30
JB
823 make_number (i));
824}
825\f
49d41073
EZ
826
827/* Really try to move where we want to be in case of fullscreen. Some WMs
828 moves the window where we tell them. Some (mwm, twm) moves the outer
829 window manager window there instead.
830 Try to compensate for those WM here. */
831static void
832x_fullscreen_move (f, new_top, new_left)
833 struct frame *f;
834 int new_top;
835 int new_left;
836{
837 if (new_top != f->output_data.x->top_pos
838 || new_left != f->output_data.x->left_pos)
839 {
840 int move_x = new_left + f->output_data.x->x_pixels_outer_diff;
841 int move_y = new_top + f->output_data.x->y_pixels_outer_diff;
842
843 f->output_data.x->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
844 x_set_offset (f, move_x, move_y, 1);
845 }
846}
847
e8cc313b 848/* Change the parameters of frame F as specified by ALIST.
64362cd4
GM
849 If a parameter is not specially recognized, do nothing special;
850 otherwise call the `x_set_...' function for that parameter.
851 Except for certain geometry properties, always call store_frame_param
852 to store the new value in the parameter alist. */
d043f1a4 853
f9942c9e
JB
854void
855x_set_frame_parameters (f, alist)
856 FRAME_PTR f;
857 Lisp_Object alist;
858{
859 Lisp_Object tail;
860
861 /* If both of these parameters are present, it's more efficient to
862 set them both at once. So we wait until we've looked at the
863 entire list before we set them. */
e4f79258 864 int width, height;
f9942c9e
JB
865
866 /* Same here. */
867 Lisp_Object left, top;
f9942c9e 868
a59e4f3d
RS
869 /* Same with these. */
870 Lisp_Object icon_left, icon_top;
871
f5e70acd
RS
872 /* Record in these vectors all the parms specified. */
873 Lisp_Object *parms;
874 Lisp_Object *values;
a797a73d 875 int i, p;
e1d962d7 876 int left_no_change = 0, top_no_change = 0;
a59e4f3d 877 int icon_left_no_change = 0, icon_top_no_change = 0;
5f9338d5 878 int fullscreen_is_being_set = 0;
203c1d73 879
7589a1d9
RS
880 struct gcpro gcpro1, gcpro2;
881
f5e70acd
RS
882 i = 0;
883 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
884 i++;
885
886 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
887 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
f9942c9e 888
f5e70acd
RS
889 /* Extract parm names and values into those vectors. */
890
891 i = 0;
f9942c9e
JB
892 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
893 {
333b20bb 894 Lisp_Object elt;
f9942c9e
JB
895
896 elt = Fcar (tail);
f5e70acd
RS
897 parms[i] = Fcar (elt);
898 values[i] = Fcdr (elt);
899 i++;
900 }
7589a1d9
RS
901 /* TAIL and ALIST are not used again below here. */
902 alist = tail = Qnil;
903
904 GCPRO2 (*parms, *values);
905 gcpro1.nvars = i;
906 gcpro2.nvars = i;
f5e70acd 907
7589a1d9
RS
908 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
909 because their values appear in VALUES and strings are not valid. */
e4f79258 910 top = left = Qunbound;
a59e4f3d 911 icon_left = icon_top = Qunbound;
f9942c9e 912
e4f79258
RS
913 /* Provide default values for HEIGHT and WIDTH. */
914 if (FRAME_NEW_WIDTH (f))
915 width = FRAME_NEW_WIDTH (f);
916 else
917 width = FRAME_WIDTH (f);
918
919 if (FRAME_NEW_HEIGHT (f))
920 height = FRAME_NEW_HEIGHT (f);
921 else
922 height = FRAME_HEIGHT (f);
923
a797a73d
GV
924 /* Process foreground_color and background_color before anything else.
925 They are independent of other properties, but other properties (e.g.,
926 cursor_color) are dependent upon them. */
b3ba0aa8 927 /* Process default font as well, since fringe widths depends on it. */
49d41073 928 /* Also, process fullscreen, width and height depend upon that */
a797a73d
GV
929 for (p = 0; p < i; p++)
930 {
931 Lisp_Object prop, val;
932
933 prop = parms[p];
934 val = values[p];
b3ba0aa8
KS
935 if (EQ (prop, Qforeground_color)
936 || EQ (prop, Qbackground_color)
49d41073
EZ
937 || EQ (prop, Qfont)
938 || EQ (prop, Qfullscreen))
a797a73d
GV
939 {
940 register Lisp_Object param_index, old_value;
941
a797a73d 942 old_value = get_frame_param (f, prop);
f0b9a067 943 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
c7e609d5
MB
944
945 if (NILP (Fequal (val, old_value)))
946 {
947 store_frame_param (f, prop, val);
948
949 param_index = Fget (prop, Qx_frame_parameter);
950 if (NATNUMP (param_index)
951 && (XFASTINT (param_index)
952 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
953 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
954 }
a797a73d
GV
955 }
956 }
957
f5e70acd
RS
958 /* Now process them in reverse of specified order. */
959 for (i--; i >= 0; i--)
960 {
961 Lisp_Object prop, val;
962
963 prop = parms[i];
964 val = values[i];
965
e4f79258
RS
966 if (EQ (prop, Qwidth) && NUMBERP (val))
967 width = XFASTINT (val);
968 else if (EQ (prop, Qheight) && NUMBERP (val))
969 height = XFASTINT (val);
f5e70acd 970 else if (EQ (prop, Qtop))
f9942c9e 971 top = val;
f5e70acd 972 else if (EQ (prop, Qleft))
f9942c9e 973 left = val;
a59e4f3d
RS
974 else if (EQ (prop, Qicon_top))
975 icon_top = val;
976 else if (EQ (prop, Qicon_left))
977 icon_left = val;
b3ba0aa8
KS
978 else if (EQ (prop, Qforeground_color)
979 || EQ (prop, Qbackground_color)
49d41073
EZ
980 || EQ (prop, Qfont)
981 || EQ (prop, Qfullscreen))
a797a73d
GV
982 /* Processed above. */
983 continue;
f9942c9e
JB
984 else
985 {
98381190 986 register Lisp_Object param_index, old_value;
ea96210c 987
98381190 988 old_value = get_frame_param (f, prop);
c7e609d5 989
9f7e52b4 990 store_frame_param (f, prop, val);
c7e609d5 991
9f7e52b4
GM
992 param_index = Fget (prop, Qx_frame_parameter);
993 if (NATNUMP (param_index)
994 && (XFASTINT (param_index)
995 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
996 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
f9942c9e
JB
997 }
998 }
999
11378c41
RS
1000 /* Don't die if just one of these was set. */
1001 if (EQ (left, Qunbound))
e1d962d7
RS
1002 {
1003 left_no_change = 1;
7556890b
RS
1004 if (f->output_data.x->left_pos < 0)
1005 left = Fcons (Qplus, Fcons (make_number (f->output_data.x->left_pos), Qnil));
e1d962d7 1006 else
7556890b 1007 XSETINT (left, f->output_data.x->left_pos);
e1d962d7 1008 }
11378c41 1009 if (EQ (top, Qunbound))
e1d962d7
RS
1010 {
1011 top_no_change = 1;
7556890b
RS
1012 if (f->output_data.x->top_pos < 0)
1013 top = Fcons (Qplus, Fcons (make_number (f->output_data.x->top_pos), Qnil));
e1d962d7 1014 else
7556890b 1015 XSETINT (top, f->output_data.x->top_pos);
e1d962d7 1016 }
11378c41 1017
a59e4f3d
RS
1018 /* If one of the icon positions was not set, preserve or default it. */
1019 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
1020 {
1021 icon_left_no_change = 1;
1022 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
1023 if (NILP (icon_left))
1024 XSETINT (icon_left, 0);
1025 }
1026 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
1027 {
1028 icon_top_no_change = 1;
1029 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
1030 if (NILP (icon_top))
1031 XSETINT (icon_top, 0);
1032 }
1033
5f9338d5 1034 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
49d41073
EZ
1035 {
1036 /* If the frame is visible already and the fullscreen parameter is
1037 being set, it is too late to set WM manager hints to specify
1038 size and position.
1039 Here we first get the width, height and position that applies to
1040 fullscreen. We then move the frame to the appropriate
1041 position. Resize of the frame is taken care of in the code after
5f9338d5 1042 this if-statement. */
49d41073
EZ
1043 int new_left, new_top;
1044
1045 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
1046 x_fullscreen_move (f, new_top, new_left);
1047 }
1048
499ea23b 1049 /* Don't set these parameters unless they've been explicitly
d387c960
JB
1050 specified. The window might be mapped or resized while we're in
1051 this function, and we don't want to override that unless the lisp
1052 code has asked for it.
1053
1054 Don't set these parameters unless they actually differ from the
1055 window's current parameters; the window may not actually exist
1056 yet. */
f9942c9e
JB
1057 {
1058 Lisp_Object frame;
1059
1f11a5ca
RS
1060 check_frame_size (f, &height, &width);
1061
191ed777 1062 XSETFRAME (frame, f);
11378c41 1063
e4f79258
RS
1064 if (width != FRAME_WIDTH (f)
1065 || height != FRAME_HEIGHT (f)
d6f80ae9 1066 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
e4f79258 1067 Fset_frame_size (frame, make_number (width), make_number (height));
f10f0b79
RS
1068
1069 if ((!NILP (left) || !NILP (top))
e1d962d7 1070 && ! (left_no_change && top_no_change)
7556890b
RS
1071 && ! (NUMBERP (left) && XINT (left) == f->output_data.x->left_pos
1072 && NUMBERP (top) && XINT (top) == f->output_data.x->top_pos))
f10f0b79 1073 {
e1d962d7
RS
1074 int leftpos = 0;
1075 int toppos = 0;
f10f0b79
RS
1076
1077 /* Record the signs. */
7556890b 1078 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
e1d962d7 1079 if (EQ (left, Qminus))
7556890b 1080 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7
RS
1081 else if (INTEGERP (left))
1082 {
1083 leftpos = XINT (left);
1084 if (leftpos < 0)
7556890b 1085 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7 1086 }
8e713be6
KR
1087 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1088 && CONSP (XCDR (left))
1089 && INTEGERP (XCAR (XCDR (left))))
e1d962d7 1090 {
8e713be6 1091 leftpos = - XINT (XCAR (XCDR (left)));
7556890b 1092 f->output_data.x->size_hint_flags |= XNegative;
e1d962d7 1093 }
8e713be6
KR
1094 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1095 && CONSP (XCDR (left))
1096 && INTEGERP (XCAR (XCDR (left))))
e1d962d7 1097 {
8e713be6 1098 leftpos = XINT (XCAR (XCDR (left)));
e1d962d7
RS
1099 }
1100
1101 if (EQ (top, Qminus))
7556890b 1102 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7
RS
1103 else if (INTEGERP (top))
1104 {
1105 toppos = XINT (top);
1106 if (toppos < 0)
7556890b 1107 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7 1108 }
8e713be6
KR
1109 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1110 && CONSP (XCDR (top))
1111 && INTEGERP (XCAR (XCDR (top))))
e1d962d7 1112 {
8e713be6 1113 toppos = - XINT (XCAR (XCDR (top)));
7556890b 1114 f->output_data.x->size_hint_flags |= YNegative;
e1d962d7 1115 }
8e713be6
KR
1116 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1117 && CONSP (XCDR (top))
1118 && INTEGERP (XCAR (XCDR (top))))
e1d962d7 1119 {
8e713be6 1120 toppos = XINT (XCAR (XCDR (top)));
e1d962d7
RS
1121 }
1122
1123
1124 /* Store the numeric value of the position. */
7556890b
RS
1125 f->output_data.x->top_pos = toppos;
1126 f->output_data.x->left_pos = leftpos;
e1d962d7 1127
7556890b 1128 f->output_data.x->win_gravity = NorthWestGravity;
f10f0b79
RS
1129
1130 /* Actually set that position, and convert to absolute. */
f0e72e79 1131 x_set_offset (f, leftpos, toppos, -1);
f10f0b79 1132 }
a59e4f3d
RS
1133
1134 if ((!NILP (icon_left) || !NILP (icon_top))
1135 && ! (icon_left_no_change && icon_top_no_change))
1136 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
f9942c9e 1137 }
7589a1d9
RS
1138
1139 UNGCPRO;
f9942c9e 1140}
01f1ba30 1141
08a90d6a 1142/* Store the screen positions of frame F into XPTR and YPTR.
e9445337
RS
1143 These are the positions of the containing window manager window,
1144 not Emacs's own window. */
1145
1146void
1147x_real_positions (f, xptr, yptr)
1148 FRAME_PTR f;
1149 int *xptr, *yptr;
1150{
49d41073
EZ
1151 int win_x, win_y, outer_x, outer_y;
1152 int real_x = 0, real_y = 0;
1153 int had_errors = 0;
1154 Window win = f->output_data.x->parent_desc;
e9445337 1155
49d41073 1156 int count;
043835a3 1157
49d41073
EZ
1158 BLOCK_INPUT;
1159
1160 count = x_catch_errors (FRAME_X_DISPLAY (f));
043835a3 1161
49d41073
EZ
1162 if (win == FRAME_X_DISPLAY_INFO (f)->root_window)
1163 win = FRAME_OUTER_WINDOW (f);
1164
1165 /* This loop traverses up the containment tree until we hit the root
1166 window. Window managers may intersect many windows between our window
1167 and the root window. The window we find just before the root window
1168 should be the outer WM window. */
1169 for (;;)
e9445337 1170 {
49d41073
EZ
1171 Window wm_window, rootw;
1172 Window *tmp_children;
1173 unsigned int tmp_nchildren;
e7161ad9 1174 int success;
ca7bac79 1175
e7161ad9
RS
1176 success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
1177 &wm_window, &tmp_children, &tmp_nchildren);
08a90d6a 1178
49d41073 1179 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
08a90d6a 1180
e7161ad9
RS
1181 /* Don't free tmp_children if XQueryTree failed. */
1182 if (! success)
1183 break;
1184
1185 XFree ((char *) tmp_children);
1186
49d41073
EZ
1187 if (wm_window == rootw || had_errors)
1188 break;
08a90d6a 1189
49d41073
EZ
1190 win = wm_window;
1191 }
1192
1193 if (! had_errors)
1194 {
1195 int ign;
1196 Window child, rootw;
1197
1198 /* Get the real coordinates for the WM window upper left corner */
1199 XGetGeometry (FRAME_X_DISPLAY (f), win,
1200 &rootw, &real_x, &real_y, &ign, &ign, &ign, &ign);
1201
1202 /* Translate real coordinates to coordinates relative to our
1203 window. For our window, the upper left corner is 0, 0.
1204 Since the upper left corner of the WM window is outside
1205 our window, win_x and win_y will be negative:
1206
1207 ------------------ ---> x
1208 | title |
1209 | ----------------- v y
1210 | | our window
1211 */
8a07bba0 1212 XTranslateCoordinates (FRAME_X_DISPLAY (f),
e9445337 1213
8a07bba0 1214 /* From-window, to-window. */
8a07bba0 1215 FRAME_X_DISPLAY_INFO (f)->root_window,
49d41073 1216 FRAME_X_WINDOW (f),
e9445337 1217
8a07bba0 1218 /* From-position, to-position. */
49d41073 1219 real_x, real_y, &win_x, &win_y,
08a90d6a 1220
8a07bba0
RS
1221 /* Child of win. */
1222 &child);
e9445337 1223
49d41073 1224 if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
845e9d85 1225 {
49d41073
EZ
1226 outer_x = win_x;
1227 outer_y = win_y;
845e9d85 1228 }
49d41073
EZ
1229 else
1230 {
1231 XTranslateCoordinates (FRAME_X_DISPLAY (f),
ca7bac79 1232
49d41073
EZ
1233 /* From-window, to-window. */
1234 FRAME_X_DISPLAY_INFO (f)->root_window,
1235 FRAME_OUTER_WINDOW (f),
1236
1237 /* From-position, to-position. */
1238 real_x, real_y, &outer_x, &outer_y,
1239
1240 /* Child of win. */
1241 &child);
e9445337 1242 }
08a90d6a 1243
49d41073
EZ
1244 had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
1245 }
1246
1247 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
1248
1249 UNBLOCK_INPUT;
1250
1251 if (had_errors) return;
1252
1253 f->output_data.x->x_pixels_diff = -win_x;
1254 f->output_data.x->y_pixels_diff = -win_y;
1255 f->output_data.x->x_pixels_outer_diff = -outer_x;
1256 f->output_data.x->y_pixels_outer_diff = -outer_y;
1257
1258 *xptr = real_x;
1259 *yptr = real_y;
e9445337
RS
1260}
1261
f676886a 1262/* Insert a description of internally-recorded parameters of frame X
01f1ba30
JB
1263 into the parameter alist *ALISTPTR that is to be given to the user.
1264 Only parameters that are specific to the X window system
f676886a 1265 and whose values are not correctly recorded in the frame's
01f1ba30
JB
1266 param_alist need to be considered here. */
1267
968b1234 1268void
f676886a
JB
1269x_report_frame_params (f, alistptr)
1270 struct frame *f;
01f1ba30
JB
1271 Lisp_Object *alistptr;
1272{
1273 char buf[16];
9b002b8d
KH
1274 Lisp_Object tem;
1275
1276 /* Represent negative positions (off the top or left screen edge)
1277 in a way that Fmodify_frame_parameters will understand correctly. */
7556890b
RS
1278 XSETINT (tem, f->output_data.x->left_pos);
1279 if (f->output_data.x->left_pos >= 0)
9b002b8d
KH
1280 store_in_alist (alistptr, Qleft, tem);
1281 else
1282 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1283
7556890b
RS
1284 XSETINT (tem, f->output_data.x->top_pos);
1285 if (f->output_data.x->top_pos >= 0)
9b002b8d
KH
1286 store_in_alist (alistptr, Qtop, tem);
1287 else
1288 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
01f1ba30 1289
f9942c9e 1290 store_in_alist (alistptr, Qborder_width,
7556890b 1291 make_number (f->output_data.x->border_width));
f9942c9e 1292 store_in_alist (alistptr, Qinternal_border_width,
7556890b 1293 make_number (f->output_data.x->internal_border_width));
30bf44e0
KS
1294 store_in_alist (alistptr, Qleft_fringe,
1295 make_number (f->output_data.x->left_fringe_width));
1296 store_in_alist (alistptr, Qright_fringe,
1297 make_number (f->output_data.x->right_fringe_width));
99f7c77f
EZ
1298 store_in_alist (alistptr, Qscroll_bar_width,
1299 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1300 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1301 : 0));
7c118b57 1302 sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f));
f9942c9e 1303 store_in_alist (alistptr, Qwindow_id,
01f1ba30 1304 build_string (buf));
333b20bb
GM
1305#ifdef USE_X_TOOLKIT
1306 /* Tooltip frame may not have this widget. */
1307 if (f->output_data.x->widget)
1308#endif
1309 sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f));
2cbebefb
RS
1310 store_in_alist (alistptr, Qouter_window_id,
1311 build_string (buf));
f468da95 1312 store_in_alist (alistptr, Qicon_name, f->icon_name);
a8ccd803 1313 FRAME_SAMPLE_VISIBILITY (f);
d043f1a4
RS
1314 store_in_alist (alistptr, Qvisibility,
1315 (FRAME_VISIBLE_P (f) ? Qt
1316 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
34ae77b5 1317 store_in_alist (alistptr, Qdisplay,
8e713be6 1318 XCAR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
e4f79258 1319
8c239ac3
RS
1320 if (f->output_data.x->parent_desc == FRAME_X_DISPLAY_INFO (f)->root_window)
1321 tem = Qnil;
1322 else
1323 XSETFASTINT (tem, f->output_data.x->parent_desc);
1324 store_in_alist (alistptr, Qparent_id, tem);
01f1ba30
JB
1325}
1326\f
82978295 1327
d62c8769
GM
1328
1329/* Gamma-correct COLOR on frame F. */
1330
1331void
1332gamma_correct (f, color)
1333 struct frame *f;
1334 XColor *color;
1335{
1336 if (f->gamma)
1337 {
1338 color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5;
1339 color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5;
1340 color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5;
1341 }
1342}
1343
1344
7b746c38
GM
1345/* Decide if color named COLOR_NAME is valid for use on frame F. If
1346 so, return the RGB values in COLOR. If ALLOC_P is non-zero,
1347 allocate the color. Value is zero if COLOR_NAME is invalid, or
1348 no color could be allocated. */
e12d55b2 1349
01f1ba30 1350int
7b746c38
GM
1351x_defined_color (f, color_name, color, alloc_p)
1352 struct frame *f;
1353 char *color_name;
1354 XColor *color;
1355 int alloc_p;
01f1ba30 1356{
7b746c38
GM
1357 int success_p;
1358 Display *dpy = FRAME_X_DISPLAY (f);
1359 Colormap cmap = FRAME_X_COLORMAP (f);
01f1ba30
JB
1360
1361 BLOCK_INPUT;
7b746c38
GM
1362 success_p = XParseColor (dpy, cmap, color_name, color);
1363 if (success_p && alloc_p)
1364 success_p = x_alloc_nearest_color (f, cmap, color);
01f1ba30
JB
1365 UNBLOCK_INPUT;
1366
7b746c38 1367 return success_p;
01f1ba30
JB
1368}
1369
9b2956e2
GM
1370
1371/* Return the pixel color value for color COLOR_NAME on frame F. If F
1372 is a monochrome frame, return MONO_COLOR regardless of what ARG says.
1373 Signal an error if color can't be allocated. */
01f1ba30
JB
1374
1375int
9b2956e2 1376x_decode_color (f, color_name, mono_color)
b9dc4443 1377 FRAME_PTR f;
9b2956e2
GM
1378 Lisp_Object color_name;
1379 int mono_color;
01f1ba30 1380{
b9dc4443 1381 XColor cdef;
01f1ba30 1382
b7826503 1383 CHECK_STRING (color_name);
01f1ba30 1384
9b2956e2
GM
1385#if 0 /* Don't do this. It's wrong when we're not using the default
1386 colormap, it makes freeing difficult, and it's probably not
1387 an important optimization. */
d5db4077 1388 if (strcmp (SDATA (color_name), "black") == 0)
b9dc4443 1389 return BLACK_PIX_DEFAULT (f);
d5db4077 1390 else if (strcmp (SDATA (color_name), "white") == 0)
b9dc4443 1391 return WHITE_PIX_DEFAULT (f);
9b2956e2 1392#endif
01f1ba30 1393
9b2956e2 1394 /* Return MONO_COLOR for monochrome frames. */
b9dc4443 1395 if (FRAME_X_DISPLAY_INFO (f)->n_planes == 1)
9b2956e2 1396 return mono_color;
01f1ba30 1397
2d764c78 1398 /* x_defined_color is responsible for coping with failures
95626e11 1399 by looking for a near-miss. */
d5db4077 1400 if (x_defined_color (f, SDATA (color_name), &cdef, 1))
95626e11
RS
1401 return cdef.pixel;
1402
c301be26
GM
1403 Fsignal (Qerror, Fcons (build_string ("Undefined color"),
1404 Fcons (color_name, Qnil)));
1405 return 0;
01f1ba30 1406}
9b2956e2
GM
1407
1408
01f1ba30 1409\f
563b67aa
GM
1410/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1411 the previous value of that parameter, NEW_VALUE is the new value. */
1412
1413static void
1414x_set_line_spacing (f, new_value, old_value)
1415 struct frame *f;
1416 Lisp_Object new_value, old_value;
1417{
1418 if (NILP (new_value))
1419 f->extra_line_spacing = 0;
1420 else if (NATNUMP (new_value))
1421 f->extra_line_spacing = XFASTINT (new_value);
1422 else
1a948b17 1423 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
563b67aa
GM
1424 Fcons (new_value, Qnil)));
1425 if (FRAME_VISIBLE_P (f))
1426 redraw_frame (f);
1427}
1428
1429
ea0a1f53
GM
1430/* Change the `wait-for-wm' frame parameter of frame F. OLD_VALUE is
1431 the previous value of that parameter, NEW_VALUE is the new value.
1432 See also the comment of wait_for_wm in struct x_output. */
1433
1434static void
1435x_set_wait_for_wm (f, new_value, old_value)
1436 struct frame *f;
1437 Lisp_Object new_value, old_value;
1438{
1439 f->output_data.x->wait_for_wm = !NILP (new_value);
1440}
1441
1442
49d41073
EZ
1443/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
1444 the previous value of that parameter, NEW_VALUE is the new value. */
1445
1446static void
1447x_set_fullscreen (f, new_value, old_value)
1448 struct frame *f;
1449 Lisp_Object new_value, old_value;
1450{
1451 if (NILP (new_value))
1452 f->output_data.x->want_fullscreen = FULLSCREEN_NONE;
1453 else if (EQ (new_value, Qfullboth))
1454 f->output_data.x->want_fullscreen = FULLSCREEN_BOTH;
1455 else if (EQ (new_value, Qfullwidth))
1456 f->output_data.x->want_fullscreen = FULLSCREEN_WIDTH;
1457 else if (EQ (new_value, Qfullheight))
1458 f->output_data.x->want_fullscreen = FULLSCREEN_HEIGHT;
1459}
1460
1461
d62c8769 1462/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
ea0a1f53
GM
1463 the previous value of that parameter, NEW_VALUE is the new
1464 value. */
d62c8769
GM
1465
1466static void
1467x_set_screen_gamma (f, new_value, old_value)
1468 struct frame *f;
1469 Lisp_Object new_value, old_value;
1470{
1471 if (NILP (new_value))
1472 f->gamma = 0;
1473 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1474 /* The value 0.4545 is the normal viewing gamma. */
1475 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1476 else
1a948b17 1477 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
d62c8769
GM
1478 Fcons (new_value, Qnil)));
1479
1480 clear_face_cache (0);
1481}
1482
1483
f676886a 1484/* Functions called only from `x_set_frame_param'
01f1ba30
JB
1485 to set individual parameters.
1486
fe24a618 1487 If FRAME_X_WINDOW (f) is 0,
f676886a 1488 the frame is being created and its X-window does not exist yet.
01f1ba30
JB
1489 In that case, just record the parameter's new value
1490 in the standard place; do not attempt to change the window. */
1491
1492void
f676886a
JB
1493x_set_foreground_color (f, arg, oldval)
1494 struct frame *f;
01f1ba30
JB
1495 Lisp_Object arg, oldval;
1496{
09393d07
GM
1497 struct x_output *x = f->output_data.x;
1498 unsigned long fg, old_fg;
a76206dc 1499
09393d07
GM
1500 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1501 old_fg = x->foreground_pixel;
1502 x->foreground_pixel = fg;
a76206dc 1503
fe24a618 1504 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1505 {
09393d07 1506 Display *dpy = FRAME_X_DISPLAY (f);
36d42089 1507
09393d07
GM
1508 BLOCK_INPUT;
1509 XSetForeground (dpy, x->normal_gc, fg);
1510 XSetBackground (dpy, x->reverse_gc, fg);
36d42089 1511
09393d07
GM
1512 if (x->cursor_pixel == old_fg)
1513 {
1514 unload_color (f, x->cursor_pixel);
1515 x->cursor_pixel = x_copy_color (f, fg);
1516 XSetBackground (dpy, x->cursor_gc, x->cursor_pixel);
1517 }
1518
01f1ba30 1519 UNBLOCK_INPUT;
09393d07 1520
05c8abbe 1521 update_face_from_frame_parameter (f, Qforeground_color, arg);
09393d07 1522
179956b9 1523 if (FRAME_VISIBLE_P (f))
f676886a 1524 redraw_frame (f);
01f1ba30 1525 }
09393d07
GM
1526
1527 unload_color (f, old_fg);
01f1ba30
JB
1528}
1529
1530void
f676886a
JB
1531x_set_background_color (f, arg, oldval)
1532 struct frame *f;
01f1ba30
JB
1533 Lisp_Object arg, oldval;
1534{
09393d07
GM
1535 struct x_output *x = f->output_data.x;
1536 unsigned long bg;
01f1ba30 1537
09393d07
GM
1538 bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1539 unload_color (f, x->background_pixel);
1540 x->background_pixel = bg;
a76206dc 1541
fe24a618 1542 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1543 {
09393d07 1544 Display *dpy = FRAME_X_DISPLAY (f);
36d42089 1545
09393d07
GM
1546 BLOCK_INPUT;
1547 XSetBackground (dpy, x->normal_gc, bg);
1548 XSetForeground (dpy, x->reverse_gc, bg);
1549 XSetWindowBackground (dpy, FRAME_X_WINDOW (f), bg);
1550 XSetForeground (dpy, x->cursor_gc, bg);
1551
f76e0368
GM
1552#ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with
1553 toolkit scroll bars. */
1554 {
1555 Lisp_Object bar;
1556 for (bar = FRAME_SCROLL_BARS (f);
1557 !NILP (bar);
1558 bar = XSCROLL_BAR (bar)->next)
1559 {
1560 Window window = SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar));
1561 XSetWindowBackground (dpy, window, bg);
1562 }
1563 }
1564#endif /* USE_TOOLKIT_SCROLL_BARS */
01f1ba30 1565
09393d07 1566 UNBLOCK_INPUT;
05c8abbe 1567 update_face_from_frame_parameter (f, Qbackground_color, arg);
ea96210c 1568
179956b9 1569 if (FRAME_VISIBLE_P (f))
f676886a 1570 redraw_frame (f);
01f1ba30
JB
1571 }
1572}
1573
1574void
f676886a
JB
1575x_set_mouse_color (f, arg, oldval)
1576 struct frame *f;
01f1ba30
JB
1577 Lisp_Object arg, oldval;
1578{
09393d07
GM
1579 struct x_output *x = f->output_data.x;
1580 Display *dpy = FRAME_X_DISPLAY (f);
95f80c78 1581 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
0af913d7 1582 Cursor hourglass_cursor, horizontal_drag_cursor;
1dc6cfa6 1583 int count;
51a1d2d8 1584 unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
09393d07 1585 unsigned long mask_color = x->background_pixel;
a76206dc 1586
51a1d2d8 1587 /* Don't let pointers be invisible. */
09393d07 1588 if (mask_color == pixel)
bcf26b38
GM
1589 {
1590 x_free_colors (f, &pixel, 1);
09393d07 1591 pixel = x_copy_color (f, x->foreground_pixel);
bcf26b38 1592 }
a76206dc 1593
09393d07
GM
1594 unload_color (f, x->mouse_pixel);
1595 x->mouse_pixel = pixel;
01f1ba30
JB
1596
1597 BLOCK_INPUT;
fe24a618 1598
eb8c3be9 1599 /* It's not okay to crash if the user selects a screwy cursor. */
09393d07 1600 count = x_catch_errors (dpy);
fe24a618 1601
09393d07 1602 if (!NILP (Vx_pointer_shape))
01f1ba30 1603 {
b7826503 1604 CHECK_NUMBER (Vx_pointer_shape);
09393d07 1605 cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
01f1ba30
JB
1606 }
1607 else
09393d07
GM
1608 cursor = XCreateFontCursor (dpy, XC_xterm);
1609 x_check_errors (dpy, "bad text pointer cursor: %s");
01f1ba30 1610
09393d07 1611 if (!NILP (Vx_nontext_pointer_shape))
01f1ba30 1612 {
b7826503 1613 CHECK_NUMBER (Vx_nontext_pointer_shape);
09393d07
GM
1614 nontext_cursor
1615 = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
01f1ba30
JB
1616 }
1617 else
09393d07
GM
1618 nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
1619 x_check_errors (dpy, "bad nontext pointer cursor: %s");
01f1ba30 1620
09393d07 1621 if (!NILP (Vx_hourglass_pointer_shape))
333b20bb 1622 {
b7826503 1623 CHECK_NUMBER (Vx_hourglass_pointer_shape);
09393d07
GM
1624 hourglass_cursor
1625 = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
333b20bb
GM
1626 }
1627 else
09393d07
GM
1628 hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
1629 x_check_errors (dpy, "bad hourglass pointer cursor: %s");
333b20bb 1630
09393d07
GM
1631 x_check_errors (dpy, "bad nontext pointer cursor: %s");
1632 if (!NILP (Vx_mode_pointer_shape))
01f1ba30 1633 {
b7826503 1634 CHECK_NUMBER (Vx_mode_pointer_shape);
09393d07 1635 mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
01f1ba30
JB
1636 }
1637 else
09393d07
GM
1638 mode_cursor = XCreateFontCursor (dpy, XC_xterm);
1639 x_check_errors (dpy, "bad modeline pointer cursor: %s");
95f80c78 1640
09393d07 1641 if (!NILP (Vx_sensitive_text_pointer_shape))
95f80c78 1642 {
b7826503 1643 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ca0ecbf5 1644 cross_cursor
09393d07 1645 = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
95f80c78
FP
1646 }
1647 else
5d449b17 1648 cross_cursor = XCreateFontCursor (dpy, XC_hand2);
01f1ba30 1649
8fb4ec9c
GM
1650 if (!NILP (Vx_window_horizontal_drag_shape))
1651 {
b7826503 1652 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
8fb4ec9c 1653 horizontal_drag_cursor
09393d07 1654 = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
8fb4ec9c
GM
1655 }
1656 else
1657 horizontal_drag_cursor
09393d07 1658 = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
8fb4ec9c 1659
fe24a618 1660 /* Check and report errors with the above calls. */
09393d07
GM
1661 x_check_errors (dpy, "can't set cursor shape: %s");
1662 x_uncatch_errors (dpy, count);
fe24a618 1663
01f1ba30
JB
1664 {
1665 XColor fore_color, back_color;
1666
09393d07 1667 fore_color.pixel = x->mouse_pixel;
a31fedb7 1668 x_query_color (f, &fore_color);
01f1ba30 1669 back_color.pixel = mask_color;
a31fedb7
GM
1670 x_query_color (f, &back_color);
1671
09393d07
GM
1672 XRecolorCursor (dpy, cursor, &fore_color, &back_color);
1673 XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
1674 XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
1675 XRecolorCursor (dpy, cross_cursor, &fore_color, &back_color);
1676 XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
1677 XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
01f1ba30 1678 }
01f1ba30 1679
fe24a618 1680 if (FRAME_X_WINDOW (f) != 0)
09393d07
GM
1681 XDefineCursor (dpy, FRAME_X_WINDOW (f), cursor);
1682
1683 if (cursor != x->text_cursor
1684 && x->text_cursor != 0)
1685 XFreeCursor (dpy, x->text_cursor);
1686 x->text_cursor = cursor;
1687
1688 if (nontext_cursor != x->nontext_cursor
1689 && x->nontext_cursor != 0)
1690 XFreeCursor (dpy, x->nontext_cursor);
1691 x->nontext_cursor = nontext_cursor;
1692
1693 if (hourglass_cursor != x->hourglass_cursor
1694 && x->hourglass_cursor != 0)
1695 XFreeCursor (dpy, x->hourglass_cursor);
1696 x->hourglass_cursor = hourglass_cursor;
1697
1698 if (mode_cursor != x->modeline_cursor
1699 && x->modeline_cursor != 0)
1700 XFreeCursor (dpy, f->output_data.x->modeline_cursor);
1701 x->modeline_cursor = mode_cursor;
333b20bb 1702
09393d07
GM
1703 if (cross_cursor != x->cross_cursor
1704 && x->cross_cursor != 0)
1705 XFreeCursor (dpy, x->cross_cursor);
1706 x->cross_cursor = cross_cursor;
01f1ba30 1707
09393d07
GM
1708 if (horizontal_drag_cursor != x->horizontal_drag_cursor
1709 && x->horizontal_drag_cursor != 0)
1710 XFreeCursor (dpy, x->horizontal_drag_cursor);
1711 x->horizontal_drag_cursor = horizontal_drag_cursor;
8fb4ec9c 1712
09393d07 1713 XFlush (dpy);
01f1ba30 1714 UNBLOCK_INPUT;
05c8abbe
GM
1715
1716 update_face_from_frame_parameter (f, Qmouse_color, arg);
01f1ba30
JB
1717}
1718
1719void
f676886a
JB
1720x_set_cursor_color (f, arg, oldval)
1721 struct frame *f;
01f1ba30
JB
1722 Lisp_Object arg, oldval;
1723{
a76206dc 1724 unsigned long fore_pixel, pixel;
10168ebb 1725 int fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
09393d07 1726 struct x_output *x = f->output_data.x;
01f1ba30 1727
10168ebb
GM
1728 if (!NILP (Vx_cursor_fore_pixel))
1729 {
1730 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
1731 WHITE_PIX_DEFAULT (f));
1732 fore_pixel_allocated_p = 1;
1733 }
01f1ba30 1734 else
09393d07 1735 fore_pixel = x->background_pixel;
10168ebb 1736
a76206dc 1737 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
10168ebb 1738 pixel_allocated_p = 1;
a76206dc 1739
f9942c9e 1740 /* Make sure that the cursor color differs from the background color. */
09393d07 1741 if (pixel == x->background_pixel)
01f1ba30 1742 {
10168ebb
GM
1743 if (pixel_allocated_p)
1744 {
1745 x_free_colors (f, &pixel, 1);
1746 pixel_allocated_p = 0;
1747 }
1748
09393d07 1749 pixel = x->mouse_pixel;
a76206dc 1750 if (pixel == fore_pixel)
10168ebb
GM
1751 {
1752 if (fore_pixel_allocated_p)
1753 {
1754 x_free_colors (f, &fore_pixel, 1);
1755 fore_pixel_allocated_p = 0;
1756 }
09393d07 1757 fore_pixel = x->background_pixel;
10168ebb 1758 }
01f1ba30 1759 }
a76206dc 1760
09393d07 1761 unload_color (f, x->cursor_foreground_pixel);
10168ebb
GM
1762 if (!fore_pixel_allocated_p)
1763 fore_pixel = x_copy_color (f, fore_pixel);
09393d07 1764 x->cursor_foreground_pixel = fore_pixel;
01f1ba30 1765
09393d07 1766 unload_color (f, x->cursor_pixel);
10168ebb
GM
1767 if (!pixel_allocated_p)
1768 pixel = x_copy_color (f, pixel);
09393d07 1769 x->cursor_pixel = pixel;
a76206dc 1770
fe24a618 1771 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 1772 {
01f1ba30 1773 BLOCK_INPUT;
09393d07
GM
1774 XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
1775 XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);
01f1ba30 1776 UNBLOCK_INPUT;
01f1ba30 1777
179956b9 1778 if (FRAME_VISIBLE_P (f))
01f1ba30 1779 {
cedadcfa
RS
1780 x_update_cursor (f, 0);
1781 x_update_cursor (f, 1);
01f1ba30
JB
1782 }
1783 }
05c8abbe
GM
1784
1785 update_face_from_frame_parameter (f, Qcursor_color, arg);
01f1ba30 1786}
943b580d 1787\f
f676886a 1788/* Set the border-color of frame F to value described by ARG.
01f1ba30
JB
1789 ARG can be a string naming a color.
1790 The border-color is used for the border that is drawn by the X server.
1791 Note that this does not fully take effect if done before
f676886a 1792 F has an x-window; it must be redone when the window is created.
01f1ba30
JB
1793
1794 Note: this is done in two routines because of the way X10 works.
1795
1796 Note: under X11, this is normally the province of the window manager,
b9dc4443 1797 and so emacs' border colors may be overridden. */
01f1ba30
JB
1798
1799void
f676886a
JB
1800x_set_border_color (f, arg, oldval)
1801 struct frame *f;
01f1ba30
JB
1802 Lisp_Object arg, oldval;
1803{
01f1ba30
JB
1804 int pix;
1805
b7826503 1806 CHECK_STRING (arg);
b9dc4443 1807 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
f676886a 1808 x_set_border_pixel (f, pix);
05c8abbe 1809 update_face_from_frame_parameter (f, Qborder_color, arg);
01f1ba30
JB
1810}
1811
f676886a 1812/* Set the border-color of frame F to pixel value PIX.
01f1ba30 1813 Note that this does not fully take effect if done before
f676886a 1814 F has an x-window. */
01f1ba30 1815
968b1234 1816void
f676886a
JB
1817x_set_border_pixel (f, pix)
1818 struct frame *f;
01f1ba30
JB
1819 int pix;
1820{
a76206dc 1821 unload_color (f, f->output_data.x->border_pixel);
7556890b 1822 f->output_data.x->border_pixel = pix;
01f1ba30 1823
7556890b 1824 if (FRAME_X_WINDOW (f) != 0 && f->output_data.x->border_width > 0)
01f1ba30 1825 {
01f1ba30 1826 BLOCK_INPUT;
b9dc4443 1827 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
270958e8 1828 (unsigned long)pix);
01f1ba30
JB
1829 UNBLOCK_INPUT;
1830
179956b9 1831 if (FRAME_VISIBLE_P (f))
f676886a 1832 redraw_frame (f);
01f1ba30
JB
1833 }
1834}
1835
0d1469d6
GM
1836
1837/* Value is the internal representation of the specified cursor type
1838 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
1839 of the bar cursor. */
1840
1841enum text_cursor_kinds
1842x_specified_cursor_type (arg, width)
1843 Lisp_Object arg;
1844 int *width;
dbc4e1c1 1845{
0d1469d6
GM
1846 enum text_cursor_kinds type;
1847
dbc4e1c1 1848 if (EQ (arg, Qbar))
c3211206 1849 {
0d1469d6
GM
1850 type = BAR_CURSOR;
1851 *width = 2;
c3211206 1852 }
08ac8554
GM
1853 else if (CONSP (arg)
1854 && EQ (XCAR (arg), Qbar)
1855 && INTEGERP (XCDR (arg))
1856 && XINT (XCDR (arg)) >= 0)
c3211206 1857 {
0d1469d6
GM
1858 type = BAR_CURSOR;
1859 *width = XINT (XCDR (arg));
c3211206 1860 }
a9653085
EZ
1861 else if (EQ (arg, Qhbar))
1862 {
1863 type = HBAR_CURSOR;
1864 *width = 2;
1865 }
1866 else if (CONSP (arg)
1867 && EQ (XCAR (arg), Qhbar)
1868 && INTEGERP (XCDR (arg))
1869 && XINT (XCDR (arg)) >= 0)
1870 {
1871 type = HBAR_CURSOR;
1872 *width = XINT (XCDR (arg));
1873 }
08ac8554 1874 else if (NILP (arg))
0d1469d6 1875 type = NO_CURSOR;
dbc4e1c1 1876 else
c3211206
RS
1877 /* Treat anything unknown as "box cursor".
1878 It was bad to signal an error; people have trouble fixing
1879 .Xdefaults with Emacs, when it has something bad in it. */
0d1469d6
GM
1880 type = FILLED_BOX_CURSOR;
1881
1882 return type;
1883}
1884
1885void
1886x_set_cursor_type (f, arg, oldval)
1887 FRAME_PTR f;
1888 Lisp_Object arg, oldval;
1889{
1890 int width;
1891
1892 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
1893 f->output_data.x->cursor_width = width;
dbc4e1c1 1894
75691005
RS
1895 /* Make sure the cursor gets redrawn. */
1896 cursor_type_changed = 1;
dbc4e1c1 1897}
943b580d 1898\f
01f1ba30 1899void
f676886a
JB
1900x_set_icon_type (f, arg, oldval)
1901 struct frame *f;
01f1ba30
JB
1902 Lisp_Object arg, oldval;
1903{
01f1ba30
JB
1904 int result;
1905
203c1d73
RS
1906 if (STRINGP (arg))
1907 {
1908 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1909 return;
1910 }
1911 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
01f1ba30
JB
1912 return;
1913
1914 BLOCK_INPUT;
265a9e55 1915 if (NILP (arg))
80534dd6 1916 result = x_text_icon (f,
d5db4077 1917 (char *) SDATA ((!NILP (f->icon_name)
f468da95 1918 ? f->icon_name
d5db4077 1919 : f->name)));
f1c7b5a6
RS
1920 else
1921 result = x_bitmap_icon (f, arg);
01f1ba30
JB
1922
1923 if (result)
1924 {
01f1ba30 1925 UNBLOCK_INPUT;
0fb53770 1926 error ("No icon window available");
01f1ba30
JB
1927 }
1928
b9dc4443 1929 XFlush (FRAME_X_DISPLAY (f));
01f1ba30
JB
1930 UNBLOCK_INPUT;
1931}
1932
f1c7b5a6 1933/* Return non-nil if frame F wants a bitmap icon. */
0fb53770 1934
f1c7b5a6 1935Lisp_Object
0fb53770
RS
1936x_icon_type (f)
1937 FRAME_PTR f;
1938{
1939 Lisp_Object tem;
1940
1941 tem = assq_no_quit (Qicon_type, f->param_alist);
f1c7b5a6 1942 if (CONSP (tem))
8e713be6 1943 return XCDR (tem);
f1c7b5a6
RS
1944 else
1945 return Qnil;
0fb53770
RS
1946}
1947
80534dd6
KH
1948void
1949x_set_icon_name (f, arg, oldval)
1950 struct frame *f;
1951 Lisp_Object arg, oldval;
1952{
80534dd6
KH
1953 int result;
1954
1955 if (STRINGP (arg))
1956 {
1957 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1958 return;
1959 }
1960 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
1961 return;
1962
f468da95 1963 f->icon_name = arg;
80534dd6 1964
7556890b 1965 if (f->output_data.x->icon_bitmap != 0)
80534dd6
KH
1966 return;
1967
1968 BLOCK_INPUT;
1969
1970 result = x_text_icon (f,
d5db4077
KR
1971 (char *) SDATA ((!NILP (f->icon_name)
1972 ? f->icon_name
1973 : !NILP (f->title)
1974 ? f->title
1975 : f->name)));
80534dd6
KH
1976
1977 if (result)
1978 {
1979 UNBLOCK_INPUT;
1980 error ("No icon window available");
1981 }
1982
80534dd6
KH
1983 XFlush (FRAME_X_DISPLAY (f));
1984 UNBLOCK_INPUT;
1985}
943b580d 1986\f
01f1ba30 1987void
f676886a
JB
1988x_set_font (f, arg, oldval)
1989 struct frame *f;
01f1ba30
JB
1990 Lisp_Object arg, oldval;
1991{
ea96210c 1992 Lisp_Object result;
942ea06d 1993 Lisp_Object fontset_name;
a367641f 1994 Lisp_Object frame;
57c5889c 1995 int old_fontset = f->output_data.x->fontset;
01f1ba30 1996
b7826503 1997 CHECK_STRING (arg);
01f1ba30 1998
49965a29 1999 fontset_name = Fquery_fontset (arg, Qnil);
942ea06d 2000
01f1ba30 2001 BLOCK_INPUT;
942ea06d 2002 result = (STRINGP (fontset_name)
d5db4077
KR
2003 ? x_new_fontset (f, SDATA (fontset_name))
2004 : x_new_font (f, SDATA (arg)));
01f1ba30
JB
2005 UNBLOCK_INPUT;
2006
ea96210c 2007 if (EQ (result, Qnil))
d5db4077 2008 error ("Font `%s' is not defined", SDATA (arg));
ea96210c 2009 else if (EQ (result, Qt))
26e18ed9 2010 error ("The characters of the given font have varying widths");
ea96210c
JB
2011 else if (STRINGP (result))
2012 {
57c5889c
GM
2013 if (STRINGP (fontset_name))
2014 {
2015 /* Fontset names are built from ASCII font names, so the
2016 names may be equal despite there was a change. */
2017 if (old_fontset == f->output_data.x->fontset)
2018 return;
2019 }
2020 else if (!NILP (Fequal (result, oldval)))
1d090605 2021 return;
57c5889c 2022
ea96210c 2023 store_frame_param (f, Qfont, result);
333b20bb 2024 recompute_basic_faces (f);
ea96210c
JB
2025 }
2026 else
2027 abort ();
a367641f 2028
8938a4fb 2029 do_pending_window_change (0);
95aa0336 2030
333b20bb
GM
2031 /* Don't call `face-set-after-frame-default' when faces haven't been
2032 initialized yet. This is the case when called from
2033 Fx_create_frame. In that case, the X widget or window doesn't
2034 exist either, and we can end up in x_report_frame_params with a
2035 null widget which gives a segfault. */
2036 if (FRAME_FACE_CACHE (f))
2037 {
2038 XSETFRAME (frame, f);
2039 call1 (Qface_set_after_frame_default, frame);
2040 }
01f1ba30
JB
2041}
2042
b3ba0aa8
KS
2043static void
2044x_set_fringe_width (f, new_value, old_value)
2045 struct frame *f;
2046 Lisp_Object new_value, old_value;
2047{
2048 x_compute_fringe_widths (f, 1);
2049}
2050
01f1ba30 2051void
f676886a
JB
2052x_set_border_width (f, arg, oldval)
2053 struct frame *f;
01f1ba30
JB
2054 Lisp_Object arg, oldval;
2055{
b7826503 2056 CHECK_NUMBER (arg);
01f1ba30 2057
7556890b 2058 if (XINT (arg) == f->output_data.x->border_width)
01f1ba30
JB
2059 return;
2060
fe24a618 2061 if (FRAME_X_WINDOW (f) != 0)
01f1ba30
JB
2062 error ("Cannot change the border width of a window");
2063
7556890b 2064 f->output_data.x->border_width = XINT (arg);
01f1ba30
JB
2065}
2066
2067void
f676886a
JB
2068x_set_internal_border_width (f, arg, oldval)
2069 struct frame *f;
01f1ba30
JB
2070 Lisp_Object arg, oldval;
2071{
7556890b 2072 int old = f->output_data.x->internal_border_width;
01f1ba30 2073
b7826503 2074 CHECK_NUMBER (arg);
7556890b
RS
2075 f->output_data.x->internal_border_width = XINT (arg);
2076 if (f->output_data.x->internal_border_width < 0)
2077 f->output_data.x->internal_border_width = 0;
01f1ba30 2078
d3b06468 2079#ifdef USE_X_TOOLKIT
2a8a07d4 2080 if (f->output_data.x->edit_widget)
968b1234 2081 widget_store_internal_border (f->output_data.x->edit_widget);
d3b06468 2082#endif
2a8a07d4 2083
7556890b 2084 if (f->output_data.x->internal_border_width == old)
01f1ba30
JB
2085 return;
2086
fe24a618 2087 if (FRAME_X_WINDOW (f) != 0)
01f1ba30 2088 {
363f7e15 2089 x_set_window_size (f, 0, f->width, f->height);
f676886a 2090 SET_FRAME_GARBAGED (f);
8938a4fb 2091 do_pending_window_change (0);
01f1ba30 2092 }
ea42193a
GM
2093 else
2094 SET_FRAME_GARBAGED (f);
01f1ba30
JB
2095}
2096
d043f1a4
RS
2097void
2098x_set_visibility (f, value, oldval)
2099 struct frame *f;
2100 Lisp_Object value, oldval;
2101{
2102 Lisp_Object frame;
191ed777 2103 XSETFRAME (frame, f);
d043f1a4
RS
2104
2105 if (NILP (value))
363f7e15 2106 Fmake_frame_invisible (frame, Qt);
49795535 2107 else if (EQ (value, Qicon))
d043f1a4 2108 Ficonify_frame (frame);
49795535
JB
2109 else
2110 Fmake_frame_visible (frame);
d043f1a4 2111}
52de7ce9 2112
943b580d 2113\f
52de7ce9
GM
2114/* Change window heights in windows rooted in WINDOW by N lines. */
2115
d043f1a4 2116static void
52de7ce9 2117x_change_window_heights (window, n)
d043f1a4
RS
2118 Lisp_Object window;
2119 int n;
2120{
47c0f58b 2121 struct window *w = XWINDOW (window);
d043f1a4 2122
e33f7330
KH
2123 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2124 XSETFASTINT (w->height, XFASTINT (w->height) - n);
d043f1a4 2125
4336c705
GM
2126 if (INTEGERP (w->orig_top))
2127 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2128 if (INTEGERP (w->orig_height))
2129 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2130
47c0f58b
RS
2131 /* Handle just the top child in a vertical split. */
2132 if (!NILP (w->vchild))
52de7ce9 2133 x_change_window_heights (w->vchild, n);
d043f1a4 2134
47c0f58b
RS
2135 /* Adjust all children in a horizontal split. */
2136 for (window = w->hchild; !NILP (window); window = w->next)
2137 {
2138 w = XWINDOW (window);
52de7ce9 2139 x_change_window_heights (window, n);
d043f1a4
RS
2140 }
2141}
2142
2143void
2144x_set_menu_bar_lines (f, value, oldval)
2145 struct frame *f;
2146 Lisp_Object value, oldval;
2147{
2148 int nlines;
b6d7acec 2149#ifndef USE_X_TOOLKIT
d043f1a4 2150 int olines = FRAME_MENU_BAR_LINES (f);
b6d7acec 2151#endif
d043f1a4 2152
f64ba6ea
JB
2153 /* Right now, menu bars don't work properly in minibuf-only frames;
2154 most of the commands try to apply themselves to the minibuffer
333b20bb 2155 frame itself, and get an error because you can't switch buffers
f64ba6ea 2156 in or split the minibuffer window. */
519066d2 2157 if (FRAME_MINIBUF_ONLY_P (f))
f64ba6ea
JB
2158 return;
2159
6a5e54e2 2160 if (INTEGERP (value))
d043f1a4
RS
2161 nlines = XINT (value);
2162 else
2163 nlines = 0;
2164
3d09b6be
RS
2165 /* Make sure we redisplay all windows in this frame. */
2166 windows_or_buffers_changed++;
2167
9ef48a9d
RS
2168#ifdef USE_X_TOOLKIT
2169 FRAME_MENU_BAR_LINES (f) = 0;
2170 if (nlines)
0d8ef3f4
RS
2171 {
2172 FRAME_EXTERNAL_MENU_BAR (f) = 1;
97a1ff91 2173 if (FRAME_X_P (f) && f->output_data.x->menubar_widget == 0)
0d8ef3f4
RS
2174 /* Make sure next redisplay shows the menu bar. */
2175 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt;
2176 }
9ef48a9d
RS
2177 else
2178 {
6bc20398
FP
2179 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2180 free_frame_menubar (f);
9ef48a9d 2181 FRAME_EXTERNAL_MENU_BAR (f) = 0;
97a1ff91
RS
2182 if (FRAME_X_P (f))
2183 f->output_data.x->menubar_widget = 0;
9ef48a9d
RS
2184 }
2185#else /* not USE_X_TOOLKIT */
d043f1a4 2186 FRAME_MENU_BAR_LINES (f) = nlines;
52de7ce9 2187 x_change_window_heights (f->root_window, nlines - olines);
9ef48a9d 2188#endif /* not USE_X_TOOLKIT */
333b20bb
GM
2189 adjust_glyphs (f);
2190}
2191
2192
2193/* Set the number of lines used for the tool bar of frame F to VALUE.
2194 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2195 is the old number of tool bar lines. This function changes the
2196 height of all windows on frame F to match the new tool bar height.
2197 The frame's height doesn't change. */
2198
2199void
9ea173e8 2200x_set_tool_bar_lines (f, value, oldval)
333b20bb
GM
2201 struct frame *f;
2202 Lisp_Object value, oldval;
2203{
52de7ce9
GM
2204 int delta, nlines, root_height;
2205 Lisp_Object root_window;
333b20bb 2206
e870b7ba
GM
2207 /* Treat tool bars like menu bars. */
2208 if (FRAME_MINIBUF_ONLY_P (f))
2209 return;
2210
333b20bb
GM
2211 /* Use VALUE only if an integer >= 0. */
2212 if (INTEGERP (value) && XINT (value) >= 0)
2213 nlines = XFASTINT (value);
2214 else
2215 nlines = 0;
2216
2217 /* Make sure we redisplay all windows in this frame. */
2218 ++windows_or_buffers_changed;
2219
9ea173e8 2220 delta = nlines - FRAME_TOOL_BAR_LINES (f);
52de7ce9
GM
2221
2222 /* Don't resize the tool-bar to more than we have room for. */
2223 root_window = FRAME_ROOT_WINDOW (f);
2224 root_height = XINT (XWINDOW (root_window)->height);
2225 if (root_height - delta < 1)
2226 {
2227 delta = root_height - 1;
2228 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2229 }
2230
9ea173e8 2231 FRAME_TOOL_BAR_LINES (f) = nlines;
52de7ce9 2232 x_change_window_heights (root_window, delta);
333b20bb 2233 adjust_glyphs (f);
ccba751c
GM
2234
2235 /* We also have to make sure that the internal border at the top of
2236 the frame, below the menu bar or tool bar, is redrawn when the
2237 tool bar disappears. This is so because the internal border is
2238 below the tool bar if one is displayed, but is below the menu bar
2239 if there isn't a tool bar. The tool bar draws into the area
2240 below the menu bar. */
2241 if (FRAME_X_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2242 {
2243 updating_frame = f;
2244 clear_frame ();
fb3cd89b 2245 clear_current_matrices (f);
ccba751c
GM
2246 updating_frame = NULL;
2247 }
b6f91066
GM
2248
2249 /* If the tool bar gets smaller, the internal border below it
2250 has to be cleared. It was formerly part of the display
2251 of the larger tool bar, and updating windows won't clear it. */
2252 if (delta < 0)
2253 {
2254 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2255 int width = PIXEL_WIDTH (f);
2256 int y = nlines * CANON_Y_UNIT (f);
2257
2258 BLOCK_INPUT;
161d30fd
GM
2259 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2260 0, y, width, height, False);
b6f91066 2261 UNBLOCK_INPUT;
ddc24747
GM
2262
2263 if (WINDOWP (f->tool_bar_window))
2264 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
b6f91066 2265 }
333b20bb
GM
2266}
2267
2268
2269/* Set the foreground color for scroll bars on frame F to VALUE.
2270 VALUE should be a string, a color name. If it isn't a string or
2271 isn't a valid color name, do nothing. OLDVAL is the old value of
2272 the frame parameter. */
2273
2274void
2275x_set_scroll_bar_foreground (f, value, oldval)
2276 struct frame *f;
2277 Lisp_Object value, oldval;
2278{
2279 unsigned long pixel;
2280
2281 if (STRINGP (value))
2282 pixel = x_decode_color (f, value, BLACK_PIX_DEFAULT (f));
2283 else
2284 pixel = -1;
2285
2286 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
2287 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
2288
2289 f->output_data.x->scroll_bar_foreground_pixel = pixel;
2290 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2291 {
2292 /* Remove all scroll bars because they have wrong colors. */
2293 if (condemn_scroll_bars_hook)
2294 (*condemn_scroll_bars_hook) (f);
2295 if (judge_scroll_bars_hook)
2296 (*judge_scroll_bars_hook) (f);
05c8abbe
GM
2297
2298 update_face_from_frame_parameter (f, Qscroll_bar_foreground, value);
333b20bb
GM
2299 redraw_frame (f);
2300 }
2301}
2302
2303
2304/* Set the background color for scroll bars on frame F to VALUE VALUE
2305 should be a string, a color name. If it isn't a string or isn't a
2306 valid color name, do nothing. OLDVAL is the old value of the frame
2307 parameter. */
2308
2309void
2310x_set_scroll_bar_background (f, value, oldval)
2311 struct frame *f;
2312 Lisp_Object value, oldval;
2313{
2314 unsigned long pixel;
2315
2316 if (STRINGP (value))
2317 pixel = x_decode_color (f, value, WHITE_PIX_DEFAULT (f));
2318 else
2319 pixel = -1;
2320
2321 if (f->output_data.x->scroll_bar_background_pixel != -1)
2322 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
2323
f15340b7
MB
2324#ifdef USE_TOOLKIT_SCROLL_BARS
2325 /* Scrollbar shadow colors. */
2326 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
2327 {
2328 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
2329 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
2330 }
2331 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
2332 {
2333 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
2334 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
2335 }
2336#endif /* USE_TOOLKIT_SCROLL_BARS */
2337
333b20bb
GM
2338 f->output_data.x->scroll_bar_background_pixel = pixel;
2339 if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f))
2340 {
2341 /* Remove all scroll bars because they have wrong colors. */
2342 if (condemn_scroll_bars_hook)
2343 (*condemn_scroll_bars_hook) (f);
2344 if (judge_scroll_bars_hook)
2345 (*judge_scroll_bars_hook) (f);
2346
05c8abbe 2347 update_face_from_frame_parameter (f, Qscroll_bar_background, value);
333b20bb
GM
2348 redraw_frame (f);
2349 }
d043f1a4 2350}
333b20bb 2351
943b580d 2352\f
3a258507 2353/* Encode Lisp string STRING as a text in a format appropriate for
96db09e4
KH
2354 XICCC (X Inter Client Communication Conventions).
2355
2356 If STRING contains only ASCII characters, do no conversion and
2357 return the string data of STRING. Otherwise, encode the text by
2358 CODING_SYSTEM, and return a newly allocated memory area which
2359 should be freed by `xfree' by a caller.
2360
37323f34
EZ
2361 SELECTIONP non-zero means the string is being encoded for an X
2362 selection, so it is safe to run pre-write conversions (which
2363 may run Lisp code).
2364
96db09e4
KH
2365 Store the byte length of resulting text in *TEXT_BYTES.
2366
d60660d6 2367 If the text contains only ASCII and Latin-1, store 1 in *STRING_P,
96db09e4 2368 which means that the `encoding' of the result can be `STRING'.
d60660d6 2369 Otherwise store 0 in *STRINGP, which means that the `encoding' of
96db09e4
KH
2370 the result should be `COMPOUND_TEXT'. */
2371
2372unsigned char *
37323f34 2373x_encode_text (string, coding_system, selectionp, text_bytes, stringp)
96db09e4 2374 Lisp_Object string, coding_system;
d60660d6 2375 int *text_bytes, *stringp;
37323f34 2376 int selectionp;
96db09e4 2377{
d5db4077
KR
2378 unsigned char *str = SDATA (string);
2379 int chars = SCHARS (string);
2380 int bytes = SBYTES (string);
96db09e4
KH
2381 int charset_info;
2382 int bufsize;
2383 unsigned char *buf;
2384 struct coding_system coding;
43dc73f1 2385 extern Lisp_Object Qcompound_text_with_extensions;
96db09e4
KH
2386
2387 charset_info = find_charset_in_text (str, chars, bytes, NULL, Qnil);
2388 if (charset_info == 0)
2389 {
2390 /* No multibyte character in OBJ. We need not encode it. */
2391 *text_bytes = bytes;
d60660d6 2392 *stringp = 1;
96db09e4
KH
2393 return str;
2394 }
2395
2396 setup_coding_system (coding_system, &coding);
37323f34
EZ
2397 if (selectionp
2398 && SYMBOLP (coding.pre_write_conversion)
2399 && !NILP (Ffboundp (coding.pre_write_conversion)))
2400 {
2401 string = run_pre_post_conversion_on_str (string, &coding, 1);
d5db4077
KR
2402 str = SDATA (string);
2403 chars = SCHARS (string);
2404 bytes = SBYTES (string);
37323f34 2405 }
96db09e4
KH
2406 coding.src_multibyte = 1;
2407 coding.dst_multibyte = 0;
2408 coding.mode |= CODING_MODE_LAST_BLOCK;
d60660d6
KH
2409 if (coding.type == coding_type_iso2022)
2410 coding.flags |= CODING_FLAG_ISO_SAFE;
35bc5887
KH
2411 /* We suppress producing escape sequences for composition. */
2412 coding.composing = COMPOSITION_DISABLED;
96db09e4
KH
2413 bufsize = encoding_buffer_size (&coding, bytes);
2414 buf = (unsigned char *) xmalloc (bufsize);
2415 encode_coding (&coding, str, buf, bytes, bufsize);
2416 *text_bytes = coding.produced;
43dc73f1
EZ
2417 *stringp = (charset_info == 1
2418 || (!EQ (coding_system, Qcompound_text)
2419 && !EQ (coding_system, Qcompound_text_with_extensions)));
96db09e4
KH
2420 return buf;
2421}
2422
2423\f
75f9d625 2424/* Change the name of frame F to NAME. If NAME is nil, set F's name to
f945b920
JB
2425 x_id_name.
2426
2427 If EXPLICIT is non-zero, that indicates that lisp code is setting the
75f9d625
DM
2428 name; if NAME is a string, set F's name to NAME and set
2429 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
f945b920
JB
2430
2431 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2432 suggesting a new name, which lisp code should override; if
2433 F->explicit_name is set, ignore the new name; otherwise, set it. */
2434
2435void
2436x_set_name (f, name, explicit)
2437 struct frame *f;
2438 Lisp_Object name;
2439 int explicit;
2440{
2441 /* Make sure that requests from lisp code override requests from
2442 Emacs redisplay code. */
2443 if (explicit)
2444 {
2445 /* If we're switching from explicit to implicit, we had better
2446 update the mode lines and thereby update the title. */
2447 if (f->explicit_name && NILP (name))
cf177271 2448 update_mode_lines = 1;
f945b920
JB
2449
2450 f->explicit_name = ! NILP (name);
2451 }
2452 else if (f->explicit_name)
2453 return;
2454
2455 /* If NAME is nil, set the name to the x_id_name. */
2456 if (NILP (name))
f10f0b79
RS
2457 {
2458 /* Check for no change needed in this very common case
2459 before we do any consing. */
08a90d6a 2460 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->x_id_name,
d5db4077 2461 SDATA (f->name)))
f10f0b79 2462 return;
08a90d6a 2463 name = build_string (FRAME_X_DISPLAY_INFO (f)->x_id_name);
f10f0b79 2464 }
62265f1c 2465 else
b7826503 2466 CHECK_STRING (name);
01f1ba30 2467
f945b920
JB
2468 /* Don't change the name if it's already NAME. */
2469 if (! NILP (Fstring_equal (name, f->name)))
daa37602
JB
2470 return;
2471
943b580d
RS
2472 f->name = name;
2473
2474 /* For setting the frame title, the title parameter should override
2475 the name parameter. */
2476 if (! NILP (f->title))
2477 name = f->title;
2478
fe24a618 2479 if (FRAME_X_WINDOW (f))
01f1ba30 2480 {
01f1ba30 2481 BLOCK_INPUT;
fe24a618
JB
2482#ifdef HAVE_X11R4
2483 {
80534dd6 2484 XTextProperty text, icon;
d60660d6 2485 int bytes, stringp;
11270583 2486 Lisp_Object coding_system;
80534dd6 2487
11270583
KH
2488 coding_system = Vlocale_coding_system;
2489 if (NILP (coding_system))
2490 coding_system = Qcompound_text;
37323f34 2491 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2492 text.encoding = (stringp ? XA_STRING
96db09e4 2493 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
fe24a618 2494 text.format = 8;
96db09e4 2495 text.nitems = bytes;
80534dd6 2496
96db09e4
KH
2497 if (NILP (f->icon_name))
2498 {
2499 icon = text;
2500 }
2501 else
2502 {
37323f34 2503 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2504 &bytes, &stringp);
2505 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2506 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2507 icon.format = 8;
2508 icon.nitems = bytes;
2509 }
9ef48a9d 2510#ifdef USE_X_TOOLKIT
b9dc4443 2511 XSetWMName (FRAME_X_DISPLAY (f),
7556890b
RS
2512 XtWindow (f->output_data.x->widget), &text);
2513 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
80534dd6 2514 &icon);
9ef48a9d 2515#else /* not USE_X_TOOLKIT */
b9dc4443 2516 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
80534dd6 2517 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
9ef48a9d 2518#endif /* not USE_X_TOOLKIT */
96db09e4 2519 if (!NILP (f->icon_name)
d5db4077 2520 && icon.value != SDATA (f->icon_name))
96db09e4 2521 xfree (icon.value);
d5db4077 2522 if (text.value != SDATA (name))
96db09e4 2523 xfree (text.value);
fe24a618 2524 }
9ef48a9d 2525#else /* not HAVE_X11R4 */
b9dc4443 2526 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 2527 SDATA (name));
b9dc4443 2528 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 2529 SDATA (name));
9ef48a9d 2530#endif /* not HAVE_X11R4 */
01f1ba30
JB
2531 UNBLOCK_INPUT;
2532 }
f945b920
JB
2533}
2534
2535/* This function should be called when the user's lisp code has
2536 specified a name for the frame; the name will override any set by the
2537 redisplay code. */
2538void
2539x_explicitly_set_name (f, arg, oldval)
2540 FRAME_PTR f;
2541 Lisp_Object arg, oldval;
2542{
2543 x_set_name (f, arg, 1);
2544}
2545
2546/* This function should be called by Emacs redisplay code to set the
2547 name; names set this way will never override names set by the user's
2548 lisp code. */
25250031 2549void
f945b920
JB
2550x_implicitly_set_name (f, arg, oldval)
2551 FRAME_PTR f;
2552 Lisp_Object arg, oldval;
2553{
2554 x_set_name (f, arg, 0);
01f1ba30 2555}
943b580d
RS
2556\f
2557/* Change the title of frame F to NAME.
2558 If NAME is nil, use the frame name as the title.
01f1ba30 2559
943b580d
RS
2560 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2561 name; if NAME is a string, set F's name to NAME and set
2562 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2563
2564 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2565 suggesting a new name, which lisp code should override; if
2566 F->explicit_name is set, ignore the new name; otherwise, set it. */
2567
2568void
d62c8769 2569x_set_title (f, name, old_name)
943b580d 2570 struct frame *f;
d62c8769 2571 Lisp_Object name, old_name;
943b580d
RS
2572{
2573 /* Don't change the title if it's already NAME. */
2574 if (EQ (name, f->title))
2575 return;
2576
2577 update_mode_lines = 1;
2578
2579 f->title = name;
2580
2581 if (NILP (name))
2582 name = f->name;
beb403b3 2583 else
b7826503 2584 CHECK_STRING (name);
943b580d
RS
2585
2586 if (FRAME_X_WINDOW (f))
2587 {
2588 BLOCK_INPUT;
2589#ifdef HAVE_X11R4
2590 {
2591 XTextProperty text, icon;
d60660d6 2592 int bytes, stringp;
11270583 2593 Lisp_Object coding_system;
943b580d 2594
11270583
KH
2595 coding_system = Vlocale_coding_system;
2596 if (NILP (coding_system))
2597 coding_system = Qcompound_text;
37323f34 2598 text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
d60660d6 2599 text.encoding = (stringp ? XA_STRING
96db09e4 2600 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
943b580d 2601 text.format = 8;
96db09e4 2602 text.nitems = bytes;
943b580d 2603
96db09e4
KH
2604 if (NILP (f->icon_name))
2605 {
2606 icon = text;
2607 }
2608 else
2609 {
37323f34 2610 icon.value = x_encode_text (f->icon_name, coding_system, 0,
d60660d6
KH
2611 &bytes, &stringp);
2612 icon.encoding = (stringp ? XA_STRING
96db09e4
KH
2613 : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
2614 icon.format = 8;
2615 icon.nitems = bytes;
2616 }
943b580d
RS
2617#ifdef USE_X_TOOLKIT
2618 XSetWMName (FRAME_X_DISPLAY (f),
2619 XtWindow (f->output_data.x->widget), &text);
2620 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
2621 &icon);
2622#else /* not USE_X_TOOLKIT */
2623 XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
2624 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
2625#endif /* not USE_X_TOOLKIT */
96db09e4 2626 if (!NILP (f->icon_name)
d5db4077 2627 && icon.value != SDATA (f->icon_name))
96db09e4 2628 xfree (icon.value);
d5db4077 2629 if (text.value != SDATA (name))
96db09e4 2630 xfree (text.value);
943b580d
RS
2631 }
2632#else /* not HAVE_X11R4 */
2633 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 2634 SDATA (name));
943b580d 2635 XStoreName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 2636 SDATA (name));
943b580d
RS
2637#endif /* not HAVE_X11R4 */
2638 UNBLOCK_INPUT;
2639 }
2640}
2641\f
01f1ba30 2642void
f676886a
JB
2643x_set_autoraise (f, arg, oldval)
2644 struct frame *f;
01f1ba30
JB
2645 Lisp_Object arg, oldval;
2646{
f676886a 2647 f->auto_raise = !EQ (Qnil, arg);
01f1ba30
JB
2648}
2649
2650void
f676886a
JB
2651x_set_autolower (f, arg, oldval)
2652 struct frame *f;
01f1ba30
JB
2653 Lisp_Object arg, oldval;
2654{
f676886a 2655 f->auto_lower = !EQ (Qnil, arg);
01f1ba30 2656}
179956b9 2657
eac358ef
KH
2658void
2659x_set_unsplittable (f, arg, oldval)
2660 struct frame *f;
2661 Lisp_Object arg, oldval;
2662{
2663 f->no_split = !NILP (arg);
2664}
2665
179956b9 2666void
a3c87d4e 2667x_set_vertical_scroll_bars (f, arg, oldval)
179956b9
JB
2668 struct frame *f;
2669 Lisp_Object arg, oldval;
2670{
1ab3d87e
RS
2671 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2672 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2673 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2674 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
179956b9 2675 {
1ab3d87e
RS
2676 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2677 = (NILP (arg)
2678 ? vertical_scroll_bar_none
2679 : EQ (Qright, arg)
2680 ? vertical_scroll_bar_right
2681 : vertical_scroll_bar_left);
179956b9 2682
cf177271
JB
2683 /* We set this parameter before creating the X window for the
2684 frame, so we can get the geometry right from the start.
2685 However, if the window hasn't been created yet, we shouldn't
2686 call x_set_window_size. */
2687 if (FRAME_X_WINDOW (f))
363f7e15 2688 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2689 do_pending_window_change (0);
179956b9
JB
2690 }
2691}
4701395c
KH
2692
2693void
2694x_set_scroll_bar_width (f, arg, oldval)
2695 struct frame *f;
2696 Lisp_Object arg, oldval;
2697{
a672c74d
RS
2698 int wid = FONT_WIDTH (f->output_data.x->font);
2699
dff9a538
KH
2700 if (NILP (arg))
2701 {
c6e9d03b
GM
2702#ifdef USE_TOOLKIT_SCROLL_BARS
2703 /* A minimum width of 14 doesn't look good for toolkit scroll bars. */
333b20bb
GM
2704 int width = 16 + 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM;
2705 FRAME_SCROLL_BAR_COLS (f) = (width + wid - 1) / wid;
2706 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = width;
2707#else
2708 /* Make the actual width at least 14 pixels and a multiple of a
2709 character width. */
a672c74d 2710 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
333b20bb
GM
2711
2712 /* Use all of that space (aside from required margins) for the
2713 scroll bar. */
dff9a538 2714 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
333b20bb 2715#endif
a672c74d 2716
a90ab372
RS
2717 if (FRAME_X_WINDOW (f))
2718 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
8938a4fb 2719 do_pending_window_change (0);
dff9a538
KH
2720 }
2721 else if (INTEGERP (arg) && XINT (arg) > 0
2722 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
4701395c 2723 {
09d8c7ac
RS
2724 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
2725 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
0a26b136 2726
4701395c
KH
2727 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2728 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
2729 if (FRAME_X_WINDOW (f))
2730 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2731 }
dca97592 2732
8938a4fb 2733 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
333b20bb
GM
2734 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2735 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
4701395c 2736}
333b20bb
GM
2737
2738
01f1ba30 2739\f
f676886a 2740/* Subroutines of creating an X frame. */
01f1ba30 2741
b7975ee4
KH
2742/* Make sure that Vx_resource_name is set to a reasonable value.
2743 Fix it up, or set it to `emacs' if it is too hopeless. */
2744
d387c960
JB
2745static void
2746validate_x_resource_name ()
2747{
333b20bb 2748 int len = 0;
0e78b377
RS
2749 /* Number of valid characters in the resource name. */
2750 int good_count = 0;
2751 /* Number of invalid characters in the resource name. */
2752 int bad_count = 0;
2753 Lisp_Object new;
2754 int i;
2755
498e9ac3
RS
2756 if (!STRINGP (Vx_resource_class))
2757 Vx_resource_class = build_string (EMACS_CLASS);
2758
cf204347
RS
2759 if (STRINGP (Vx_resource_name))
2760 {
d5db4077 2761 unsigned char *p = SDATA (Vx_resource_name);
cf204347
RS
2762 int i;
2763
d5db4077 2764 len = SBYTES (Vx_resource_name);
0e78b377
RS
2765
2766 /* Only letters, digits, - and _ are valid in resource names.
2767 Count the valid characters and count the invalid ones. */
cf204347
RS
2768 for (i = 0; i < len; i++)
2769 {
2770 int c = p[i];
2771 if (! ((c >= 'a' && c <= 'z')
2772 || (c >= 'A' && c <= 'Z')
2773 || (c >= '0' && c <= '9')
2774 || c == '-' || c == '_'))
0e78b377
RS
2775 bad_count++;
2776 else
2777 good_count++;
cf204347
RS
2778 }
2779 }
2780 else
0e78b377
RS
2781 /* Not a string => completely invalid. */
2782 bad_count = 5, good_count = 0;
2783
2784 /* If name is valid already, return. */
2785 if (bad_count == 0)
2786 return;
2787
2788 /* If name is entirely invalid, or nearly so, use `emacs'. */
2789 if (good_count == 0
2790 || (good_count == 1 && bad_count > 0))
2791 {
b7975ee4 2792 Vx_resource_name = build_string ("emacs");
0e78b377
RS
2793 return;
2794 }
2795
2796 /* Name is partly valid. Copy it and replace the invalid characters
2797 with underscores. */
2798
2799 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2800
2801 for (i = 0; i < len; i++)
2802 {
d5db4077 2803 int c = SREF (new, i);
0e78b377
RS
2804 if (! ((c >= 'a' && c <= 'z')
2805 || (c >= 'A' && c <= 'Z')
2806 || (c >= '0' && c <= '9')
2807 || c == '-' || c == '_'))
d5db4077 2808 SREF (new, i) = '_';
0e78b377 2809 }
d387c960
JB
2810}
2811
2812
01f1ba30 2813extern char *x_get_string_resource ();
01f1ba30 2814
cf177271 2815DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
03265352 2816 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
c061c855
GM
2817This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2818class, where INSTANCE is the name under which Emacs was invoked, or
2819the name specified by the `-name' or `-rn' command-line arguments.
2820
2821The optional arguments COMPONENT and SUBCLASS add to the key and the
2822class, respectively. You must specify both of them or neither.
2823If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
7ee72033
MB
2824and the class is `Emacs.CLASS.SUBCLASS'. */)
2825 (attribute, class, component, subclass)
cf177271 2826 Lisp_Object attribute, class, component, subclass;
01f1ba30
JB
2827{
2828 register char *value;
2829 char *name_key;
2830 char *class_key;
2831
11ae94fe
RS
2832 check_x ();
2833
b7826503
PJ
2834 CHECK_STRING (attribute);
2835 CHECK_STRING (class);
cf177271 2836
8fabe6f4 2837 if (!NILP (component))
b7826503 2838 CHECK_STRING (component);
8fabe6f4 2839 if (!NILP (subclass))
b7826503 2840 CHECK_STRING (subclass);
8fabe6f4
RS
2841 if (NILP (component) != NILP (subclass))
2842 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2843
d387c960
JB
2844 validate_x_resource_name ();
2845
b7975ee4
KH
2846 /* Allocate space for the components, the dots which separate them,
2847 and the final '\0'. Make them big enough for the worst case. */
d5db4077 2848 name_key = (char *) alloca (SBYTES (Vx_resource_name)
b7975ee4 2849 + (STRINGP (component)
d5db4077
KR
2850 ? SBYTES (component) : 0)
2851 + SBYTES (attribute)
b7975ee4
KH
2852 + 3);
2853
d5db4077
KR
2854 class_key = (char *) alloca (SBYTES (Vx_resource_class)
2855 + SBYTES (class)
b7975ee4 2856 + (STRINGP (subclass)
d5db4077 2857 ? SBYTES (subclass) : 0)
b7975ee4
KH
2858 + 3);
2859
2860 /* Start with emacs.FRAMENAME for the name (the specific one)
2861 and with `Emacs' for the class key (the general one). */
d5db4077
KR
2862 strcpy (name_key, SDATA (Vx_resource_name));
2863 strcpy (class_key, SDATA (Vx_resource_class));
b7975ee4
KH
2864
2865 strcat (class_key, ".");
d5db4077 2866 strcat (class_key, SDATA (class));
b7975ee4
KH
2867
2868 if (!NILP (component))
01f1ba30 2869 {
b7975ee4 2870 strcat (class_key, ".");
d5db4077 2871 strcat (class_key, SDATA (subclass));
b7975ee4
KH
2872
2873 strcat (name_key, ".");
d5db4077 2874 strcat (name_key, SDATA (component));
01f1ba30
JB
2875 }
2876
b7975ee4 2877 strcat (name_key, ".");
d5db4077 2878 strcat (name_key, SDATA (attribute));
b7975ee4 2879
b9dc4443
RS
2880 value = x_get_string_resource (check_x_display_info (Qnil)->xrdb,
2881 name_key, class_key);
01f1ba30
JB
2882
2883 if (value != (char *) 0)
2884 return build_string (value);
2885 else
2886 return Qnil;
2887}
2888
abb4b7ec
RS
2889/* Get an X resource, like Fx_get_resource, but for display DPYINFO. */
2890
333b20bb 2891Lisp_Object
abb4b7ec
RS
2892display_x_get_resource (dpyinfo, attribute, class, component, subclass)
2893 struct x_display_info *dpyinfo;
2894 Lisp_Object attribute, class, component, subclass;
2895{
2896 register char *value;
2897 char *name_key;
2898 char *class_key;
2899
b7826503
PJ
2900 CHECK_STRING (attribute);
2901 CHECK_STRING (class);
abb4b7ec
RS
2902
2903 if (!NILP (component))
b7826503 2904 CHECK_STRING (component);
abb4b7ec 2905 if (!NILP (subclass))
b7826503 2906 CHECK_STRING (subclass);
abb4b7ec
RS
2907 if (NILP (component) != NILP (subclass))
2908 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2909
2910 validate_x_resource_name ();
2911
2912 /* Allocate space for the components, the dots which separate them,
2913 and the final '\0'. Make them big enough for the worst case. */
d5db4077 2914 name_key = (char *) alloca (SBYTES (Vx_resource_name)
abb4b7ec 2915 + (STRINGP (component)
d5db4077
KR
2916 ? SBYTES (component) : 0)
2917 + SBYTES (attribute)
abb4b7ec
RS
2918 + 3);
2919
d5db4077
KR
2920 class_key = (char *) alloca (SBYTES (Vx_resource_class)
2921 + SBYTES (class)
abb4b7ec 2922 + (STRINGP (subclass)
d5db4077 2923 ? SBYTES (subclass) : 0)
abb4b7ec
RS
2924 + 3);
2925
2926 /* Start with emacs.FRAMENAME for the name (the specific one)
2927 and with `Emacs' for the class key (the general one). */
d5db4077
KR
2928 strcpy (name_key, SDATA (Vx_resource_name));
2929 strcpy (class_key, SDATA (Vx_resource_class));
abb4b7ec
RS
2930
2931 strcat (class_key, ".");
d5db4077 2932 strcat (class_key, SDATA (class));
abb4b7ec
RS
2933
2934 if (!NILP (component))
2935 {
2936 strcat (class_key, ".");
d5db4077 2937 strcat (class_key, SDATA (subclass));
abb4b7ec
RS
2938
2939 strcat (name_key, ".");
d5db4077 2940 strcat (name_key, SDATA (component));
abb4b7ec
RS
2941 }
2942
2943 strcat (name_key, ".");
d5db4077 2944 strcat (name_key, SDATA (attribute));
abb4b7ec
RS
2945
2946 value = x_get_string_resource (dpyinfo->xrdb, name_key, class_key);
2947
2948 if (value != (char *) 0)
2949 return build_string (value);
2950 else
2951 return Qnil;
2952}
2953
3402e1a4
RS
2954/* Used when C code wants a resource value. */
2955
2956char *
2957x_get_resource_string (attribute, class)
2958 char *attribute, *class;
2959{
3402e1a4
RS
2960 char *name_key;
2961 char *class_key;
0fe92f72 2962 struct frame *sf = SELECTED_FRAME ();
3402e1a4
RS
2963
2964 /* Allocate space for the components, the dots which separate them,
2965 and the final '\0'. */
d5db4077 2966 name_key = (char *) alloca (SBYTES (Vinvocation_name)
3402e1a4
RS
2967 + strlen (attribute) + 2);
2968 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2969 + strlen (class) + 2);
2970
2971 sprintf (name_key, "%s.%s",
d5db4077 2972 SDATA (Vinvocation_name),
3402e1a4
RS
2973 attribute);
2974 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2975
0fe92f72 2976 return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
b9dc4443 2977 name_key, class_key);
3402e1a4
RS
2978}
2979
60fb3ee1
JB
2980/* Types we might convert a resource string into. */
2981enum resource_types
333b20bb
GM
2982{
2983 RES_TYPE_NUMBER,
d62c8769 2984 RES_TYPE_FLOAT,
333b20bb
GM
2985 RES_TYPE_BOOLEAN,
2986 RES_TYPE_STRING,
2987 RES_TYPE_SYMBOL
2988};
60fb3ee1 2989
01f1ba30 2990/* Return the value of parameter PARAM.
60fb3ee1 2991
f676886a 2992 First search ALIST, then Vdefault_frame_alist, then the X defaults
cf177271 2993 database, using ATTRIBUTE as the attribute name and CLASS as its class.
60fb3ee1
JB
2994
2995 Convert the resource to the type specified by desired_type.
2996
f9942c9e
JB
2997 If no default is specified, return Qunbound. If you call
2998 x_get_arg, make sure you deal with Qunbound in a reasonable way,
a59e4f3d 2999 and don't let it get stored in any Lisp-visible variables! */
01f1ba30
JB
3000
3001static Lisp_Object
abb4b7ec
RS
3002x_get_arg (dpyinfo, alist, param, attribute, class, type)
3003 struct x_display_info *dpyinfo;
3c254570 3004 Lisp_Object alist, param;
60fb3ee1 3005 char *attribute;
cf177271 3006 char *class;
60fb3ee1 3007 enum resource_types type;
01f1ba30
JB
3008{
3009 register Lisp_Object tem;
3010
3011 tem = Fassq (param, alist);
3012 if (EQ (tem, Qnil))
f676886a 3013 tem = Fassq (param, Vdefault_frame_alist);
f9942c9e 3014 if (EQ (tem, Qnil))
01f1ba30 3015 {
60fb3ee1 3016
f9942c9e 3017 if (attribute)
60fb3ee1 3018 {
abb4b7ec
RS
3019 tem = display_x_get_resource (dpyinfo,
3020 build_string (attribute),
3021 build_string (class),
3022 Qnil, Qnil);
f9942c9e
JB
3023
3024 if (NILP (tem))
3025 return Qunbound;
3026
3027 switch (type)
3028 {
333b20bb 3029 case RES_TYPE_NUMBER:
d5db4077 3030 return make_number (atoi (SDATA (tem)));
f9942c9e 3031
d62c8769 3032 case RES_TYPE_FLOAT:
d5db4077 3033 return make_float (atof (SDATA (tem)));
d62c8769 3034
333b20bb 3035 case RES_TYPE_BOOLEAN:
f9942c9e 3036 tem = Fdowncase (tem);
d5db4077
KR
3037 if (!strcmp (SDATA (tem), "on")
3038 || !strcmp (SDATA (tem), "true"))
f9942c9e
JB
3039 return Qt;
3040 else
3041 return Qnil;
3042
333b20bb 3043 case RES_TYPE_STRING:
f9942c9e
JB
3044 return tem;
3045
333b20bb 3046 case RES_TYPE_SYMBOL:
49795535
JB
3047 /* As a special case, we map the values `true' and `on'
3048 to Qt, and `false' and `off' to Qnil. */
3049 {
98381190
KH
3050 Lisp_Object lower;
3051 lower = Fdowncase (tem);
d5db4077
KR
3052 if (!strcmp (SDATA (lower), "on")
3053 || !strcmp (SDATA (lower), "true"))
49795535 3054 return Qt;
d5db4077
KR
3055 else if (!strcmp (SDATA (lower), "off")
3056 || !strcmp (SDATA (lower), "false"))
49795535
JB
3057 return Qnil;
3058 else
89032215 3059 return Fintern (tem, Qnil);
49795535 3060 }
f945b920 3061
f9942c9e
JB
3062 default:
3063 abort ();
3064 }
60fb3ee1 3065 }
f9942c9e
JB
3066 else
3067 return Qunbound;
01f1ba30
JB
3068 }
3069 return Fcdr (tem);
3070}
3071
e4f79258
RS
3072/* Like x_get_arg, but also record the value in f->param_alist. */
3073
3074static Lisp_Object
3075x_get_and_record_arg (f, alist, param, attribute, class, type)
3076 struct frame *f;
3077 Lisp_Object alist, param;
3078 char *attribute;
3079 char *class;
3080 enum resource_types type;
3081{
3082 Lisp_Object value;
3083
abb4b7ec
RS
3084 value = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, param,
3085 attribute, class, type);
e4f79258
RS
3086 if (! NILP (value))
3087 store_frame_param (f, param, value);
3088
3089 return value;
3090}
3091
f676886a 3092/* Record in frame F the specified or default value according to ALIST
e8cc313b
KH
3093 of the parameter named PROP (a Lisp symbol).
3094 If no value is specified for PROP, look for an X default for XPROP
f676886a 3095 on the frame named NAME.
01f1ba30
JB
3096 If that is not found either, use the value DEFLT. */
3097
3098static Lisp_Object
cf177271 3099x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
f676886a 3100 struct frame *f;
01f1ba30 3101 Lisp_Object alist;
f9942c9e 3102 Lisp_Object prop;
01f1ba30
JB
3103 Lisp_Object deflt;
3104 char *xprop;
cf177271 3105 char *xclass;
60fb3ee1 3106 enum resource_types type;
01f1ba30 3107{
01f1ba30
JB
3108 Lisp_Object tem;
3109
abb4b7ec 3110 tem = x_get_arg (FRAME_X_DISPLAY_INFO (f), alist, prop, xprop, xclass, type);
f9942c9e 3111 if (EQ (tem, Qunbound))
01f1ba30 3112 tem = deflt;
f9942c9e 3113 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
01f1ba30
JB
3114 return tem;
3115}
333b20bb
GM
3116
3117
3118/* Record in frame F the specified or default value according to ALIST
3119 of the parameter named PROP (a Lisp symbol). If no value is
3120 specified for PROP, look for an X default for XPROP on the frame
3121 named NAME. If that is not found either, use the value DEFLT. */
3122
3123static Lisp_Object
3124x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass,
3125 foreground_p)
3126 struct frame *f;
3127 Lisp_Object alist;
3128 Lisp_Object prop;
3129 char *xprop;
3130 char *xclass;
3131 int foreground_p;
3132{
3133 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3134 Lisp_Object tem;
3135
3136 tem = x_get_arg (dpyinfo, alist, prop, xprop, xclass, RES_TYPE_STRING);
3137 if (EQ (tem, Qunbound))
3138 {
3139#ifdef USE_TOOLKIT_SCROLL_BARS
3140
3141 /* See if an X resource for the scroll bar color has been
3142 specified. */
3143 tem = display_x_get_resource (dpyinfo,
3144 build_string (foreground_p
3145 ? "foreground"
3146 : "background"),
c0ec53ad 3147 empty_string,
333b20bb 3148 build_string ("verticalScrollBar"),
c0ec53ad 3149 empty_string);
333b20bb
GM
3150 if (!STRINGP (tem))
3151 {
3152 /* If nothing has been specified, scroll bars will use a
3153 toolkit-dependent default. Because these defaults are
3154 difficult to get at without actually creating a scroll
3155 bar, use nil to indicate that no color has been
3156 specified. */
3157 tem = Qnil;
3158 }
3159
3160#else /* not USE_TOOLKIT_SCROLL_BARS */
3161
3162 tem = Qnil;
3163
3164#endif /* not USE_TOOLKIT_SCROLL_BARS */
3165 }
3166
3167 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3168 return tem;
3169}
3170
3171
01f1ba30 3172\f
8af1d7ca 3173DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
7ee72033 3174 doc: /* Parse an X-style geometry string STRING.
c061c855
GM
3175Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3176The properties returned may include `top', `left', `height', and `width'.
3177The value of `left' or `top' may be an integer,
3178or a list (+ N) meaning N pixels relative to top/left corner,
7ee72033
MB
3179or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3180 (string)
a6605e5c 3181 Lisp_Object string;
01f1ba30
JB
3182{
3183 int geometry, x, y;
3184 unsigned int width, height;
f83f10ba 3185 Lisp_Object result;
01f1ba30 3186
b7826503 3187 CHECK_STRING (string);
01f1ba30 3188
d5db4077 3189 geometry = XParseGeometry ((char *) SDATA (string),
01f1ba30
JB
3190 &x, &y, &width, &height);
3191
f83f10ba
RS
3192#if 0
3193 if (!!(geometry & XValue) != !!(geometry & YValue))
3194 error ("Must specify both x and y position, or neither");
3195#endif
3196
3197 result = Qnil;
3198 if (geometry & XValue)
01f1ba30 3199 {
f83f10ba
RS
3200 Lisp_Object element;
3201
e1d962d7
RS
3202 if (x >= 0 && (geometry & XNegative))
3203 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3204 else if (x < 0 && ! (geometry & XNegative))
3205 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
f83f10ba
RS
3206 else
3207 element = Fcons (Qleft, make_number (x));
3208 result = Fcons (element, result);
3209 }
3210
3211 if (geometry & YValue)
3212 {
3213 Lisp_Object element;
3214
e1d962d7
RS
3215 if (y >= 0 && (geometry & YNegative))
3216 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3217 else if (y < 0 && ! (geometry & YNegative))
3218 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
f83f10ba
RS
3219 else
3220 element = Fcons (Qtop, make_number (y));
3221 result = Fcons (element, result);
01f1ba30 3222 }
f83f10ba
RS
3223
3224 if (geometry & WidthValue)
3225 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3226 if (geometry & HeightValue)
3227 result = Fcons (Fcons (Qheight, make_number (height)), result);
3228
3229 return result;
01f1ba30
JB
3230}
3231
01f1ba30 3232/* Calculate the desired size and position of this window,
f83f10ba 3233 and return the flags saying which aspects were specified.
8fc2766b
RS
3234
3235 This function does not make the coordinates positive. */
01f1ba30
JB
3236
3237#define DEFAULT_ROWS 40
3238#define DEFAULT_COLS 80
3239
f9942c9e 3240static int
f676886a
JB
3241x_figure_window_size (f, parms)
3242 struct frame *f;
01f1ba30
JB
3243 Lisp_Object parms;
3244{
4fe1de12 3245 register Lisp_Object tem0, tem1, tem2;
01f1ba30 3246 long window_prompting = 0;
abb4b7ec 3247 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
3248
3249 /* Default values if we fall through.
3250 Actually, if that happens we should get
b9dc4443 3251 window manager prompting. */
1ab3d87e 3252 SET_FRAME_WIDTH (f, DEFAULT_COLS);
f676886a 3253 f->height = DEFAULT_ROWS;
bd0b85c3
RS
3254 /* Window managers expect that if program-specified
3255 positions are not (0,0), they're intentional, not defaults. */
7556890b
RS
3256 f->output_data.x->top_pos = 0;
3257 f->output_data.x->left_pos = 0;
01f1ba30 3258
333b20bb
GM
3259 tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3260 tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3261 tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3262 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3263 {
f83f10ba
RS
3264 if (!EQ (tem0, Qunbound))
3265 {
b7826503 3266 CHECK_NUMBER (tem0);
f83f10ba
RS
3267 f->height = XINT (tem0);
3268 }
3269 if (!EQ (tem1, Qunbound))
3270 {
b7826503 3271 CHECK_NUMBER (tem1);
1ab3d87e 3272 SET_FRAME_WIDTH (f, XINT (tem1));
f83f10ba
RS
3273 }
3274 if (!NILP (tem2) && !EQ (tem2, Qunbound))
4fe1de12
RS
3275 window_prompting |= USSize;
3276 else
3277 window_prompting |= PSize;
01f1ba30 3278 }
01f1ba30 3279
7556890b 3280 f->output_data.x->vertical_scroll_bar_extra
a444c70b
KH
3281 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3282 ? 0
7556890b 3283 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
b3ba0aa8
KS
3284
3285 x_compute_fringe_widths (f, 0);
3286
7556890b
RS
3287 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3288 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
01f1ba30 3289
333b20bb
GM
3290 tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3291 tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3292 tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
f83f10ba 3293 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
01f1ba30 3294 {
f83f10ba
RS
3295 if (EQ (tem0, Qminus))
3296 {
7556890b 3297 f->output_data.x->top_pos = 0;
f83f10ba
RS
3298 window_prompting |= YNegative;
3299 }
8e713be6
KR
3300 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3301 && CONSP (XCDR (tem0))
3302 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3303 {
8e713be6 3304 f->output_data.x->top_pos = - XINT (XCAR (XCDR (tem0)));
e1d962d7
RS
3305 window_prompting |= YNegative;
3306 }
8e713be6
KR
3307 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3308 && CONSP (XCDR (tem0))
3309 && INTEGERP (XCAR (XCDR (tem0))))
e1d962d7 3310 {
8e713be6 3311 f->output_data.x->top_pos = XINT (XCAR (XCDR (tem0)));
e1d962d7 3312 }
f83f10ba 3313 else if (EQ (tem0, Qunbound))
7556890b 3314 f->output_data.x->top_pos = 0;
f83f10ba
RS
3315 else
3316 {
b7826503 3317 CHECK_NUMBER (tem0);
7556890b
RS
3318 f->output_data.x->top_pos = XINT (tem0);
3319 if (f->output_data.x->top_pos < 0)
f83f10ba
RS
3320 window_prompting |= YNegative;
3321 }
3322
3323 if (EQ (tem1, Qminus))
3324 {
7556890b 3325 f->output_data.x->left_pos = 0;
f83f10ba
RS
3326 window_prompting |= XNegative;
3327 }
8e713be6
KR
3328 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3329 && CONSP (XCDR (tem1))
3330 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3331 {
8e713be6 3332 f->output_data.x->left_pos = - XINT (XCAR (XCDR (tem1)));
e1d962d7
RS
3333 window_prompting |= XNegative;
3334 }
8e713be6
KR
3335 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3336 && CONSP (XCDR (tem1))
3337 && INTEGERP (XCAR (XCDR (tem1))))
e1d962d7 3338 {
8e713be6 3339 f->output_data.x->left_pos = XINT (XCAR (XCDR (tem1)));
e1d962d7 3340 }
f83f10ba 3341 else if (EQ (tem1, Qunbound))
7556890b 3342 f->output_data.x->left_pos = 0;
f83f10ba
RS
3343 else
3344 {
b7826503 3345 CHECK_NUMBER (tem1);
7556890b
RS
3346 f->output_data.x->left_pos = XINT (tem1);
3347 if (f->output_data.x->left_pos < 0)
f83f10ba
RS
3348 window_prompting |= XNegative;
3349 }
3350
c3724dc2 3351 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
4fe1de12
RS
3352 window_prompting |= USPosition;
3353 else
3354 window_prompting |= PPosition;
01f1ba30 3355 }
f83f10ba 3356
49d41073
EZ
3357 if (f->output_data.x->want_fullscreen != FULLSCREEN_NONE)
3358 {
3359 int left, top;
3360 int width, height;
3361
3362 /* It takes both for some WM:s to place it where we want */
3363 window_prompting = USPosition | PPosition;
3364 x_fullscreen_adjust (f, &width, &height, &top, &left);
3365 f->width = width;
3366 f->height = height;
3367 f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3368 f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3369 f->output_data.x->left_pos = left;
3370 f->output_data.x->top_pos = top;
3371 }
3372
739f2f53 3373 return window_prompting;
01f1ba30
JB
3374}
3375
f58534a3
RS
3376#if !defined (HAVE_X11R4) && !defined (HAVE_XSETWMPROTOCOLS)
3377
3378Status
3379XSetWMProtocols (dpy, w, protocols, count)
3380 Display *dpy;
3381 Window w;
3382 Atom *protocols;
3383 int count;
3384{
3385 Atom prop;
3386 prop = XInternAtom (dpy, "WM_PROTOCOLS", False);
3387 if (prop == None) return False;
3388 XChangeProperty (dpy, w, prop, XA_ATOM, 32, PropModeReplace,
3389 (unsigned char *) protocols, count);
3390 return True;
3391}
9ef48a9d
RS
3392#endif /* not HAVE_X11R4 && not HAVE_XSETWMPROTOCOLS */
3393\f
3394#ifdef USE_X_TOOLKIT
3395
8e3d10a9
RS
3396/* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS,
3397 WM_DELETE_WINDOW, and WM_SAVE_YOURSELF, then add them. (They may
59aa6c90
RS
3398 already be present because of the toolkit (Motif adds some of them,
3399 for example, but Xt doesn't). */
9ef48a9d
RS
3400
3401static void
b9dc4443
RS
3402hack_wm_protocols (f, widget)
3403 FRAME_PTR f;
9ef48a9d
RS
3404 Widget widget;
3405{
3406 Display *dpy = XtDisplay (widget);
3407 Window w = XtWindow (widget);
3408 int need_delete = 1;
3409 int need_focus = 1;
59aa6c90 3410 int need_save = 1;
9ef48a9d
RS
3411
3412 BLOCK_INPUT;
3413 {
3414 Atom type, *atoms = 0;
3415 int format = 0;
3416 unsigned long nitems = 0;
3417 unsigned long bytes_after;
3418
270958e8
KH
3419 if ((XGetWindowProperty (dpy, w,
3420 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
34d5ae1e 3421 (long)0, (long)100, False, XA_ATOM,
270958e8
KH
3422 &type, &format, &nitems, &bytes_after,
3423 (unsigned char **) &atoms)
3424 == Success)
9ef48a9d
RS
3425 && format == 32 && type == XA_ATOM)
3426 while (nitems > 0)
3427 {
3428 nitems--;
b9dc4443
RS
3429 if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window)
3430 need_delete = 0;
3431 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus)
3432 need_focus = 0;
3433 else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself)
3434 need_save = 0;
9ef48a9d
RS
3435 }
3436 if (atoms) XFree ((char *) atoms);
3437 }
3438 {
3439 Atom props [10];
3440 int count = 0;
b9dc4443
RS
3441 if (need_delete)
3442 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
3443 if (need_focus)
3444 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus;
3445 if (need_save)
3446 props[count++] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
9ef48a9d 3447 if (count)
b9dc4443
RS
3448 XChangeProperty (dpy, w, FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3449 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3450 (unsigned char *) props, count);
3451 }
3452 UNBLOCK_INPUT;
3453}
3454#endif
86779fac
GM
3455
3456
5a7df7d7
GM
3457\f
3458/* Support routines for XIC (X Input Context). */
86779fac 3459
5a7df7d7
GM
3460#ifdef HAVE_X_I18N
3461
3462static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
3463static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
3464
3465
3466/* Supported XIM styles, ordered by preferenc. */
3467
3468static XIMStyle supported_xim_styles[] =
3469{
3470 XIMPreeditPosition | XIMStatusArea,
3471 XIMPreeditPosition | XIMStatusNothing,
3472 XIMPreeditPosition | XIMStatusNone,
3473 XIMPreeditNothing | XIMStatusArea,
3474 XIMPreeditNothing | XIMStatusNothing,
3475 XIMPreeditNothing | XIMStatusNone,
3476 XIMPreeditNone | XIMStatusArea,
3477 XIMPreeditNone | XIMStatusNothing,
3478 XIMPreeditNone | XIMStatusNone,
3479 0,
3480};
3481
3482
3483/* Create an X fontset on frame F with base font name
3484 BASE_FONTNAME.. */
3485
3486static XFontSet
3487xic_create_xfontset (f, base_fontname)
86779fac 3488 struct frame *f;
5a7df7d7 3489 char *base_fontname;
86779fac 3490{
5a7df7d7
GM
3491 XFontSet xfs;
3492 char **missing_list;
3493 int missing_count;
3494 char *def_string;
86779fac 3495
5a7df7d7
GM
3496 xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
3497 base_fontname, &missing_list,
3498 &missing_count, &def_string);
3499 if (missing_list)
3500 XFreeStringList (missing_list);
3501
3502 /* No need to free def_string. */
3503 return xfs;
3504}
3505
3506
3507/* Value is the best input style, given user preferences USER (already
3508 checked to be supported by Emacs), and styles supported by the
3509 input method XIM. */
3510
3511static XIMStyle
3512best_xim_style (user, xim)
3513 XIMStyles *user;
3514 XIMStyles *xim;
3515{
3516 int i, j;
3517
3518 for (i = 0; i < user->count_styles; ++i)
3519 for (j = 0; j < xim->count_styles; ++j)
3520 if (user->supported_styles[i] == xim->supported_styles[j])
3521 return user->supported_styles[i];
3522
3523 /* Return the default style. */
3524 return XIMPreeditNothing | XIMStatusNothing;
3525}
3526
3527/* Create XIC for frame F. */
3528
5df79d3d
GM
3529static XIMStyle xic_style;
3530
5a7df7d7
GM
3531void
3532create_frame_xic (f)
3533 struct frame *f;
3534{
5a7df7d7
GM
3535 XIM xim;
3536 XIC xic = NULL;
3537 XFontSet xfs = NULL;
86779fac 3538
5a7df7d7
GM
3539 if (FRAME_XIC (f))
3540 return;
3541
3542 xim = FRAME_X_XIM (f);
3543 if (xim)
3544 {
d9d57cb2
DL
3545 XRectangle s_area;
3546 XPoint spot;
5a7df7d7
GM
3547 XVaNestedList preedit_attr;
3548 XVaNestedList status_attr;
3549 char *base_fontname;
3550 int fontset;
3551
d9d57cb2
DL
3552 s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
3553 spot.x = 0; spot.y = 1;
5a7df7d7
GM
3554 /* Create X fontset. */
3555 fontset = FRAME_FONTSET (f);
3556 if (fontset < 0)
3557 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3558 else
3559 {
6ecb43ce
KH
3560 /* Determine the base fontname from the ASCII font name of
3561 FONTSET. */
d5db4077 3562 char *ascii_font = (char *) SDATA (fontset_ascii (fontset));
6ecb43ce 3563 char *p = ascii_font;
5a7df7d7 3564 int i;
6ecb43ce
KH
3565
3566 for (i = 0; *p; p++)
3567 if (*p == '-') i++;
3568 if (i != 14)
3569 /* As the font name doesn't conform to XLFD, we can't
3570 modify it to get a suitable base fontname for the
3571 frame. */
3572 base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
3573 else
3574 {
3575 int len = strlen (ascii_font) + 1;
8ec8a5ec 3576 char *p1 = NULL;
6ecb43ce
KH
3577
3578 for (i = 0, p = ascii_font; i < 8; p++)
3579 {
3580 if (*p == '-')
3581 {
3582 i++;
3583 if (i == 3)
3584 p1 = p + 1;
3585 }
3586 }
3587 base_fontname = (char *) alloca (len);
3588 bzero (base_fontname, len);
3589 strcpy (base_fontname, "-*-*-");
3590 bcopy (p1, base_fontname + 5, p - p1);
3591 strcat (base_fontname, "*-*-*-*-*-*-*");
3592 }
5a7df7d7
GM
3593 }
3594 xfs = xic_create_xfontset (f, base_fontname);
86779fac 3595
5a7df7d7
GM
3596 /* Determine XIC style. */
3597 if (xic_style == 0)
3598 {
3599 XIMStyles supported_list;
3600 supported_list.count_styles = (sizeof supported_xim_styles
3601 / sizeof supported_xim_styles[0]);
3602 supported_list.supported_styles = supported_xim_styles;
3603 xic_style = best_xim_style (&supported_list,
3604 FRAME_X_XIM_STYLES (f));
3605 }
86779fac 3606
5a7df7d7
GM
3607 preedit_attr = XVaCreateNestedList (0,
3608 XNFontSet, xfs,
3609 XNForeground,
3610 FRAME_FOREGROUND_PIXEL (f),
3611 XNBackground,
3612 FRAME_BACKGROUND_PIXEL (f),
3613 (xic_style & XIMPreeditPosition
3614 ? XNSpotLocation
3615 : NULL),
3616 &spot,
3617 NULL);
3618 status_attr = XVaCreateNestedList (0,
3619 XNArea,
3620 &s_area,
3621 XNFontSet,
3622 xfs,
3623 XNForeground,
3624 FRAME_FOREGROUND_PIXEL (f),
3625 XNBackground,
3626 FRAME_BACKGROUND_PIXEL (f),
3627 NULL);
3628
3629 xic = XCreateIC (xim,
3630 XNInputStyle, xic_style,
3631 XNClientWindow, FRAME_X_WINDOW(f),
3632 XNFocusWindow, FRAME_X_WINDOW(f),
3633 XNStatusAttributes, status_attr,
3634 XNPreeditAttributes, preedit_attr,
3635 NULL);
3636 XFree (preedit_attr);
3637 XFree (status_attr);
3638 }
3639
3640 FRAME_XIC (f) = xic;
3641 FRAME_XIC_STYLE (f) = xic_style;
3642 FRAME_XIC_FONTSET (f) = xfs;
86779fac
GM
3643}
3644
5a7df7d7
GM
3645
3646/* Destroy XIC and free XIC fontset of frame F, if any. */
3647
3648void
3649free_frame_xic (f)
3650 struct frame *f;
3651{
3652 if (FRAME_XIC (f) == NULL)
3653 return;
3654
3655 XDestroyIC (FRAME_XIC (f));
3656 if (FRAME_XIC_FONTSET (f))
3657 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3658
3659 FRAME_XIC (f) = NULL;
3660 FRAME_XIC_FONTSET (f) = NULL;
3661}
3662
3663
3664/* Place preedit area for XIC of window W's frame to specified
3665 pixel position X/Y. X and Y are relative to window W. */
3666
3667void
3668xic_set_preeditarea (w, x, y)
3669 struct window *w;
3670 int x, y;
3671{
3672 struct frame *f = XFRAME (w->frame);
3673 XVaNestedList attr;
3674 XPoint spot;
3675
3676 spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
3677 spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
3678 attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
3679 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3680 XFree (attr);
3681}
3682
3683
3684/* Place status area for XIC in bottom right corner of frame F.. */
3685
3686void
3687xic_set_statusarea (f)
3688 struct frame *f;
3689{
3690 XIC xic = FRAME_XIC (f);
3691 XVaNestedList attr;
3692 XRectangle area;
3693 XRectangle *needed;
3694
3695 /* Negotiate geometry of status area. If input method has existing
3696 status area, use its current size. */
3697 area.x = area.y = area.width = area.height = 0;
3698 attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
3699 XSetICValues (xic, XNStatusAttributes, attr, NULL);
3700 XFree (attr);
3701
3702 attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
3703 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3704 XFree (attr);
3705
3706 if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
3707 {
3708 attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
3709 XGetICValues (xic, XNStatusAttributes, attr, NULL);
3710 XFree (attr);
3711 }
3712
3713 area.width = needed->width;
3714 area.height = needed->height;
3715 area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
3716 area.y = (PIXEL_HEIGHT (f) - area.height
3717 - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
3718 XFree (needed);
3719
3720 attr = XVaCreateNestedList (0, XNArea, &area, NULL);
3721 XSetICValues(xic, XNStatusAttributes, attr, NULL);
3722 XFree (attr);
3723}
3724
3725
3726/* Set X fontset for XIC of frame F, using base font name
3727 BASE_FONTNAME. Called when a new Emacs fontset is chosen. */
3728
3729void
3730xic_set_xfontset (f, base_fontname)
3731 struct frame *f;
3732 char *base_fontname;
3733{
3734 XVaNestedList attr;
3735 XFontSet xfs;
3736
3737 xfs = xic_create_xfontset (f, base_fontname);
3738
3739 attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
3740 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
3741 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
3742 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
3743 XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
3744 XFree (attr);
3745
3746 if (FRAME_XIC_FONTSET (f))
3747 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
3748 FRAME_XIC_FONTSET (f) = xfs;
3749}
3750
3751#endif /* HAVE_X_I18N */
3752
3753
9ef48a9d 3754\f
8fc2766b
RS
3755#ifdef USE_X_TOOLKIT
3756
3757/* Create and set up the X widget for frame F. */
f58534a3 3758
01f1ba30 3759static void
a7f7d550
FP
3760x_window (f, window_prompting, minibuffer_only)
3761 struct frame *f;
3762 long window_prompting;
3763 int minibuffer_only;
01f1ba30 3764{
9ef48a9d 3765 XClassHint class_hints;
31ac8d8c
FP
3766 XSetWindowAttributes attributes;
3767 unsigned long attribute_mask;
9ef48a9d
RS
3768 Widget shell_widget;
3769 Widget pane_widget;
6c32dd68 3770 Widget frame_widget;
9ef48a9d
RS
3771 Arg al [25];
3772 int ac;
3773
3774 BLOCK_INPUT;
3775
b7975ee4
KH
3776 /* Use the resource name as the top-level widget name
3777 for looking up resources. Make a non-Lisp copy
3778 for the window manager, so GC relocation won't bother it.
3779
3780 Elsewhere we specify the window name for the window manager. */
3781
cca176a0 3782 {
d5db4077 3783 char *str = (char *) SDATA (Vx_resource_name);
b7975ee4 3784 f->namebuf = (char *) xmalloc (strlen (str) + 1);
cca176a0
KH
3785 strcpy (f->namebuf, str);
3786 }
9ef48a9d
RS
3787
3788 ac = 0;
3789 XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
3790 XtSetArg (al[ac], XtNinput, 1); ac++;
97787173 3791 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
7556890b 3792 XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
9b2956e2
GM
3793 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3794 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3795 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
cca176a0 3796 shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
7a994728 3797 applicationShellWidgetClass,
82c90203 3798 FRAME_X_DISPLAY (f), al, ac);
9ef48a9d 3799
7556890b 3800 f->output_data.x->widget = shell_widget;
9ef48a9d
RS
3801 /* maybe_set_screen_title_format (shell_widget); */
3802
6c32dd68
PR
3803 pane_widget = lw_create_widget ("main", "pane", widget_id_tick++,
3804 (widget_value *) NULL,
3805 shell_widget, False,
3806 (lw_callback) NULL,
3807 (lw_callback) NULL,
b6e11efd 3808 (lw_callback) NULL,
6c32dd68 3809 (lw_callback) NULL);
9ef48a9d 3810
9b2956e2
GM
3811 ac = 0;
3812 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3813 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3814 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3815 XtSetValues (pane_widget, al, ac);
7556890b 3816 f->output_data.x->column_widget = pane_widget;
a7f7d550 3817
9ef48a9d 3818 /* mappedWhenManaged to false tells to the paned window to not map/unmap
5e65b9ab 3819 the emacs screen when changing menubar. This reduces flickering. */
9ef48a9d
RS
3820
3821 ac = 0;
3822 XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
3823 XtSetArg (al[ac], XtNshowGrip, 0); ac++;
3824 XtSetArg (al[ac], XtNallowResize, 1); ac++;
3825 XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
3826 XtSetArg (al[ac], XtNemacsFrame, f); ac++;
9b2956e2
GM
3827 XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
3828 XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
3829 XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
3830 frame_widget = XtCreateWidget (f->namebuf, emacsFrameClass, pane_widget,
3831 al, ac);
9ef48a9d 3832
7556890b 3833 f->output_data.x->edit_widget = frame_widget;
9ef48a9d 3834
6c32dd68 3835 XtManageChild (frame_widget);
a7f7d550
FP
3836
3837 /* Do some needed geometry management. */
3838 {
3839 int len;
3840 char *tem, shell_position[32];
3841 Arg al[2];
3842 int ac = 0;
5031cc10 3843 int extra_borders = 0;
8fc2766b 3844 int menubar_size
7556890b
RS
3845 = (f->output_data.x->menubar_widget
3846 ? (f->output_data.x->menubar_widget->core.height
3847 + f->output_data.x->menubar_widget->core.border_width)
8fc2766b 3848 : 0);
a7f7d550 3849
f7008aff
RS
3850#if 0 /* Experimentally, we now get the right results
3851 for -geometry -0-0 without this. 24 Aug 96, rms. */
01cbdba5
RS
3852 if (FRAME_EXTERNAL_MENU_BAR (f))
3853 {
dd254b21 3854 Dimension ibw = 0;
01cbdba5
RS
3855 XtVaGetValues (pane_widget, XtNinternalBorderWidth, &ibw, NULL);
3856 menubar_size += ibw;
3857 }
f7008aff 3858#endif
01cbdba5 3859
7556890b 3860 f->output_data.x->menubar_height = menubar_size;
00983aba 3861
440b0bfd 3862#ifndef USE_LUCID
5031cc10
KH
3863 /* Motif seems to need this amount added to the sizes
3864 specified for the shell widget. The Athena/Lucid widgets don't.
3865 Both conclusions reached experimentally. -- rms. */
440b0bfd
RS
3866 XtVaGetValues (f->output_data.x->edit_widget, XtNinternalBorderWidth,
3867 &extra_borders, NULL);
3868 extra_borders *= 2;
3869#endif
5031cc10 3870
97787173
RS
3871 /* Convert our geometry parameters into a geometry string
3872 and specify it.
3873 Note that we do not specify here whether the position
3874 is a user-specified or program-specified one.
3875 We pass that information later, in x_wm_set_size_hints. */
3876 {
7556890b 3877 int left = f->output_data.x->left_pos;
97787173 3878 int xneg = window_prompting & XNegative;
7556890b 3879 int top = f->output_data.x->top_pos;
97787173
RS
3880 int yneg = window_prompting & YNegative;
3881 if (xneg)
3882 left = -left;
3883 if (yneg)
3884 top = -top;
c760f47e
KH
3885
3886 if (window_prompting & USPosition)
5031cc10
KH
3887 sprintf (shell_position, "=%dx%d%c%d%c%d",
3888 PIXEL_WIDTH (f) + extra_borders,
3889 PIXEL_HEIGHT (f) + menubar_size + extra_borders,
c760f47e
KH
3890 (xneg ? '-' : '+'), left,
3891 (yneg ? '-' : '+'), top);
3892 else
5031cc10
KH
3893 sprintf (shell_position, "=%dx%d",
3894 PIXEL_WIDTH (f) + extra_borders,
3895 PIXEL_HEIGHT (f) + menubar_size + extra_borders);
97787173
RS
3896 }
3897
a7f7d550 3898 len = strlen (shell_position) + 1;
77110caa
RS
3899 /* We don't free this because we don't know whether
3900 it is safe to free it while the frame exists.
3901 It isn't worth the trouble of arranging to free it
3902 when the frame is deleted. */
a7f7d550
FP
3903 tem = (char *) xmalloc (len);
3904 strncpy (tem, shell_position, len);
3905 XtSetArg (al[ac], XtNgeometry, tem); ac++;
3906 XtSetValues (shell_widget, al, ac);
3907 }
3908
9ef48a9d
RS
3909 XtManageChild (pane_widget);
3910 XtRealizeWidget (shell_widget);
3911
6c32dd68 3912 FRAME_X_WINDOW (f) = XtWindow (frame_widget);
9ef48a9d
RS
3913
3914 validate_x_resource_name ();
b7975ee4 3915
d5db4077
KR
3916 class_hints.res_name = (char *) SDATA (Vx_resource_name);
3917 class_hints.res_class = (char *) SDATA (Vx_resource_class);
b9dc4443 3918 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
5a7df7d7
GM
3919
3920#ifdef HAVE_X_I18N
3921 FRAME_XIC (f) = NULL;
4bd777b8 3922#ifdef USE_XIM
5a7df7d7 3923 create_frame_xic (f);
4bd777b8 3924#endif
5a7df7d7 3925#endif
64d16748 3926
7556890b
RS
3927 f->output_data.x->wm_hints.input = True;
3928 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 3929 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3930 &f->output_data.x->wm_hints);
b8228beb 3931
c4ec904f 3932 hack_wm_protocols (f, shell_widget);
9ef48a9d 3933
6c32dd68
PR
3934#ifdef HACK_EDITRES
3935 XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0);
3936#endif
3937
9ef48a9d 3938 /* Do a stupid property change to force the server to generate a
333b20bb 3939 PropertyNotify event so that the event_stream server timestamp will
9ef48a9d
RS
3940 be initialized to something relevant to the time we created the window.
3941 */
6c32dd68 3942 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
b9dc4443
RS
3943 FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols,
3944 XA_ATOM, 32, PropModeAppend,
9ef48a9d
RS
3945 (unsigned char*) NULL, 0);
3946
5a7df7d7 3947 /* Make all the standard events reach the Emacs frame. */
31ac8d8c 3948 attributes.event_mask = STANDARD_EVENT_SET;
5a7df7d7
GM
3949
3950#ifdef HAVE_X_I18N
3951 if (FRAME_XIC (f))
3952 {
3953 /* XIM server might require some X events. */
3954 unsigned long fevent = NoEventMask;
3955 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
3956 attributes.event_mask |= fevent;
3957 }
3958#endif /* HAVE_X_I18N */
3959
31ac8d8c
FP
3960 attribute_mask = CWEventMask;
3961 XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
3962 attribute_mask, &attributes);
3963
6c32dd68 3964 XtMapWidget (frame_widget);
9ef48a9d 3965
8fc2766b
RS
3966 /* x_set_name normally ignores requests to set the name if the
3967 requested name is the same as the current name. This is the one
3968 place where that assumption isn't correct; f->name is set, but
3969 the X server hasn't been told. */
3970 {
3971 Lisp_Object name;
3972 int explicit = f->explicit_name;
3973
3974 f->explicit_name = 0;
3975 name = f->name;
3976 f->name = Qnil;
3977 x_set_name (f, name, explicit);
3978 }
3979
b9dc4443 3980 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 3981 f->output_data.x->text_cursor);
8fc2766b
RS
3982
3983 UNBLOCK_INPUT;
3984
495fa05e
GM
3985 /* This is a no-op, except under Motif. Make sure main areas are
3986 set to something reasonable, in case we get an error later. */
3987 lw_set_main_areas (pane_widget, 0, frame_widget);
8fc2766b
RS
3988}
3989
9ef48a9d
RS
3990#else /* not USE_X_TOOLKIT */
3991
8fc2766b
RS
3992/* Create and set up the X window for frame F. */
3993
201d8c78 3994void
8fc2766b
RS
3995x_window (f)
3996 struct frame *f;
3997
3998{
3999 XClassHint class_hints;
4000 XSetWindowAttributes attributes;
4001 unsigned long attribute_mask;
4002
7556890b
RS
4003 attributes.background_pixel = f->output_data.x->background_pixel;
4004 attributes.border_pixel = f->output_data.x->border_pixel;
01f1ba30
JB
4005 attributes.bit_gravity = StaticGravity;
4006 attributes.backing_store = NotUseful;
4007 attributes.save_under = True;
4008 attributes.event_mask = STANDARD_EVENT_SET;
9b2956e2
GM
4009 attributes.colormap = FRAME_X_COLORMAP (f);
4010 attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
4011 | CWColormap);
01f1ba30
JB
4012
4013 BLOCK_INPUT;
fe24a618 4014 FRAME_X_WINDOW (f)
b9dc4443 4015 = XCreateWindow (FRAME_X_DISPLAY (f),
7556890b
RS
4016 f->output_data.x->parent_desc,
4017 f->output_data.x->left_pos,
4018 f->output_data.x->top_pos,
f676886a 4019 PIXEL_WIDTH (f), PIXEL_HEIGHT (f),
7556890b 4020 f->output_data.x->border_width,
01f1ba30
JB
4021 CopyFromParent, /* depth */
4022 InputOutput, /* class */
383d6ffc 4023 FRAME_X_VISUAL (f),
01f1ba30 4024 attribute_mask, &attributes);
5a7df7d7
GM
4025
4026#ifdef HAVE_X_I18N
4bd777b8 4027#ifdef USE_XIM
5a7df7d7
GM
4028 create_frame_xic (f);
4029 if (FRAME_XIC (f))
4030 {
4031 /* XIM server might require some X events. */
4032 unsigned long fevent = NoEventMask;
4033 XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
4034 attributes.event_mask |= fevent;
4035 attribute_mask = CWEventMask;
4036 XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4037 attribute_mask, &attributes);
4038 }
4bd777b8 4039#endif
5a7df7d7
GM
4040#endif /* HAVE_X_I18N */
4041
d387c960 4042 validate_x_resource_name ();
b7975ee4 4043
d5db4077
KR
4044 class_hints.res_name = (char *) SDATA (Vx_resource_name);
4045 class_hints.res_class = (char *) SDATA (Vx_resource_class);
b9dc4443 4046 XSetClassHint (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &class_hints);
01f1ba30 4047
00983aba
KH
4048 /* The menubar is part of the ordinary display;
4049 it does not count in addition to the height of the window. */
7556890b 4050 f->output_data.x->menubar_height = 0;
00983aba 4051
179956b9
JB
4052 /* This indicates that we use the "Passive Input" input model.
4053 Unless we do this, we don't get the Focus{In,Out} events that we
4054 need to draw the cursor correctly. Accursed bureaucrats.
b9dc4443 4055 XWhipsAndChains (FRAME_X_DISPLAY (f), IronMaiden, &TheRack); */
179956b9 4056
7556890b
RS
4057 f->output_data.x->wm_hints.input = True;
4058 f->output_data.x->wm_hints.flags |= InputHint;
b9dc4443 4059 XSetWMHints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4060 &f->output_data.x->wm_hints);
6d078211 4061 f->output_data.x->wm_hints.icon_pixmap = None;
179956b9 4062
032e4ebe
RS
4063 /* Request "save yourself" and "delete window" commands from wm. */
4064 {
4065 Atom protocols[2];
b9dc4443
RS
4066 protocols[0] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window;
4067 protocols[1] = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself;
4068 XSetWMProtocols (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), protocols, 2);
032e4ebe 4069 }
9ef48a9d 4070
e373f201
JB
4071 /* x_set_name normally ignores requests to set the name if the
4072 requested name is the same as the current name. This is the one
4073 place where that assumption isn't correct; f->name is set, but
4074 the X server hasn't been told. */
4075 {
98381190 4076 Lisp_Object name;
cf177271 4077 int explicit = f->explicit_name;
e373f201 4078
cf177271 4079 f->explicit_name = 0;
98381190
KH
4080 name = f->name;
4081 f->name = Qnil;
cf177271 4082 x_set_name (f, name, explicit);
e373f201
JB
4083 }
4084
b9dc4443 4085 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4086 f->output_data.x->text_cursor);
9ef48a9d 4087
01f1ba30
JB
4088 UNBLOCK_INPUT;
4089
fe24a618 4090 if (FRAME_X_WINDOW (f) == 0)
9ef48a9d 4091 error ("Unable to create window");
01f1ba30
JB
4092}
4093
8fc2766b
RS
4094#endif /* not USE_X_TOOLKIT */
4095
01f1ba30
JB
4096/* Handle the icon stuff for this window. Perhaps later we might
4097 want an x_set_icon_position which can be called interactively as
b9dc4443 4098 well. */
01f1ba30
JB
4099
4100static void
f676886a
JB
4101x_icon (f, parms)
4102 struct frame *f;
01f1ba30
JB
4103 Lisp_Object parms;
4104{
f9942c9e 4105 Lisp_Object icon_x, icon_y;
abb4b7ec 4106 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
01f1ba30
JB
4107
4108 /* Set the position of the icon. Note that twm groups all
b9dc4443 4109 icons in an icon window. */
333b20bb
GM
4110 icon_x = x_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4111 icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
f9942c9e 4112 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
01f1ba30 4113 {
b7826503
PJ
4114 CHECK_NUMBER (icon_x);
4115 CHECK_NUMBER (icon_y);
01f1ba30 4116 }
f9942c9e 4117 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
01f1ba30 4118 error ("Both left and top icon corners of icon must be specified");
01f1ba30 4119
f9942c9e
JB
4120 BLOCK_INPUT;
4121
fe24a618
JB
4122 if (! EQ (icon_x, Qunbound))
4123 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
f9942c9e 4124
01f1ba30 4125 /* Start up iconic or window? */
49795535 4126 x_wm_set_window_state
333b20bb
GM
4127 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL),
4128 Qicon)
49795535
JB
4129 ? IconicState
4130 : NormalState));
01f1ba30 4131
d5db4077 4132 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
f468da95 4133 ? f->icon_name
d5db4077 4134 : f->name)));
80534dd6 4135
01f1ba30
JB
4136 UNBLOCK_INPUT;
4137}
4138
b243755a 4139/* Make the GCs needed for this window, setting the
01f1ba30
JB
4140 background, border and mouse colors; also create the
4141 mouse cursor and the gray border tile. */
4142
f945b920
JB
4143static char cursor_bits[] =
4144 {
4145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4149 };
4150
01f1ba30 4151static void
f676886a
JB
4152x_make_gc (f)
4153 struct frame *f;
01f1ba30
JB
4154{
4155 XGCValues gc_values;
01f1ba30 4156
6afb1d07
JB
4157 BLOCK_INPUT;
4158
b243755a 4159 /* Create the GCs of this frame.
9ef48a9d 4160 Note that many default values are used. */
01f1ba30
JB
4161
4162 /* Normal video */
7556890b
RS
4163 gc_values.font = f->output_data.x->font->fid;
4164 gc_values.foreground = f->output_data.x->foreground_pixel;
4165 gc_values.background = f->output_data.x->background_pixel;
9ef48a9d 4166 gc_values.line_width = 0; /* Means 1 using fast algorithm. */
959e647d
GM
4167 f->output_data.x->normal_gc
4168 = XCreateGC (FRAME_X_DISPLAY (f),
4169 FRAME_X_WINDOW (f),
4170 GCLineWidth | GCFont | GCForeground | GCBackground,
4171 &gc_values);
01f1ba30 4172
b9dc4443 4173 /* Reverse video style. */
7556890b
RS
4174 gc_values.foreground = f->output_data.x->background_pixel;
4175 gc_values.background = f->output_data.x->foreground_pixel;
959e647d
GM
4176 f->output_data.x->reverse_gc
4177 = XCreateGC (FRAME_X_DISPLAY (f),
4178 FRAME_X_WINDOW (f),
4179 GCFont | GCForeground | GCBackground | GCLineWidth,
4180 &gc_values);
01f1ba30 4181
9ef48a9d 4182 /* Cursor has cursor-color background, background-color foreground. */
7556890b
RS
4183 gc_values.foreground = f->output_data.x->background_pixel;
4184 gc_values.background = f->output_data.x->cursor_pixel;
01f1ba30
JB
4185 gc_values.fill_style = FillOpaqueStippled;
4186 gc_values.stipple
b9dc4443
RS
4187 = XCreateBitmapFromData (FRAME_X_DISPLAY (f),
4188 FRAME_X_DISPLAY_INFO (f)->root_window,
01f1ba30 4189 cursor_bits, 16, 16);
7556890b 4190 f->output_data.x->cursor_gc
b9dc4443 4191 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
01f1ba30 4192 (GCFont | GCForeground | GCBackground
ac1f48a4 4193 | GCFillStyle /* | GCStipple */ | GCLineWidth),
01f1ba30
JB
4194 &gc_values);
4195
333b20bb
GM
4196 /* Reliefs. */
4197 f->output_data.x->white_relief.gc = 0;
4198 f->output_data.x->black_relief.gc = 0;
4199
01f1ba30 4200 /* Create the gray border tile used when the pointer is not in
f676886a 4201 the frame. Since this depends on the frame's pixel values,
9ef48a9d 4202 this must be done on a per-frame basis. */
7556890b 4203 f->output_data.x->border_tile
d043f1a4 4204 = (XCreatePixmapFromBitmapData
b9dc4443 4205 (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
d043f1a4 4206 gray_bits, gray_width, gray_height,
7556890b
RS
4207 f->output_data.x->foreground_pixel,
4208 f->output_data.x->background_pixel,
ab452f99 4209 DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f))));
6afb1d07
JB
4210
4211 UNBLOCK_INPUT;
01f1ba30 4212}
01f1ba30 4213
959e647d
GM
4214
4215/* Free what was was allocated in x_make_gc. */
4216
4217void
4218x_free_gcs (f)
4219 struct frame *f;
4220{
4221 Display *dpy = FRAME_X_DISPLAY (f);
4222
4223 BLOCK_INPUT;
4224
4225 if (f->output_data.x->normal_gc)
4226 {
4227 XFreeGC (dpy, f->output_data.x->normal_gc);
4228 f->output_data.x->normal_gc = 0;
4229 }
4230
4231 if (f->output_data.x->reverse_gc)
4232 {
4233 XFreeGC (dpy, f->output_data.x->reverse_gc);
4234 f->output_data.x->reverse_gc = 0;
4235 }
4236
4237 if (f->output_data.x->cursor_gc)
4238 {
4239 XFreeGC (dpy, f->output_data.x->cursor_gc);
4240 f->output_data.x->cursor_gc = 0;
4241 }
4242
4243 if (f->output_data.x->border_tile)
4244 {
4245 XFreePixmap (dpy, f->output_data.x->border_tile);
4246 f->output_data.x->border_tile = 0;
4247 }
4248
4249 UNBLOCK_INPUT;
4250}
4251
4252
eaf1eea9
GM
4253/* Handler for signals raised during x_create_frame and
4254 x_create_top_frame. FRAME is the frame which is partially
4255 constructed. */
4256
4257static Lisp_Object
4258unwind_create_frame (frame)
4259 Lisp_Object frame;
4260{
4261 struct frame *f = XFRAME (frame);
4262
4263 /* If frame is ``official'', nothing to do. */
4264 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4265 {
f1d2ce7f 4266#if GLYPH_DEBUG
eaf1eea9
GM
4267 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
4268#endif
4269
4270 x_free_frame_resources (f);
4271
4272 /* Check that reference counts are indeed correct. */
4273 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4274 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a 4275 return Qt;
eaf1eea9
GM
4276 }
4277
4278 return Qnil;
4279}
4280
4281
f676886a 4282DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
01f1ba30 4283 1, 1, 0,
7ee72033 4284 doc: /* Make a new X window, which is called a "frame" in Emacs terms.
c061c855
GM
4285Returns an Emacs frame object.
4286ALIST is an alist of frame parameters.
4287If the parameters specify that the frame should not have a minibuffer,
4288and do not specify a specific minibuffer window to use,
4289then `default-minibuffer-frame' must be a frame whose minibuffer can
4290be shared by the new frame.
4291
7ee72033
MB
4292This function is an internal primitive--use `make-frame' instead. */)
4293 (parms)
01f1ba30
JB
4294 Lisp_Object parms;
4295{
f676886a 4296 struct frame *f;
2365c027 4297 Lisp_Object frame, tem;
01f1ba30
JB
4298 Lisp_Object name;
4299 int minibuffer_only = 0;
4300 long window_prompting = 0;
4301 int width, height;
331379bf 4302 int count = SPECPDL_INDEX ();
ecaca587 4303 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
b9dc4443 4304 Lisp_Object display;
333b20bb 4305 struct x_display_info *dpyinfo = NULL;
a59e4f3d 4306 Lisp_Object parent;
e557f19d 4307 struct kboard *kb;
01f1ba30 4308
11ae94fe 4309 check_x ();
01f1ba30 4310
b7975ee4
KH
4311 /* Use this general default value to start with
4312 until we know if this frame has a specified name. */
4313 Vx_resource_name = Vinvocation_name;
4314
333b20bb 4315 display = x_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING);
b9dc4443
RS
4316 if (EQ (display, Qunbound))
4317 display = Qnil;
4318 dpyinfo = check_x_display_info (display);
e557f19d
KH
4319#ifdef MULTI_KBOARD
4320 kb = dpyinfo->kboard;
4321#else
4322 kb = &the_only_kboard;
4323#endif
b9dc4443 4324
333b20bb 4325 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
6a5e54e2 4326 if (!STRINGP (name)
cf177271
JB
4327 && ! EQ (name, Qunbound)
4328 && ! NILP (name))
08a90d6a 4329 error ("Invalid frame name--not a string or nil");
01f1ba30 4330
b7975ee4
KH
4331 if (STRINGP (name))
4332 Vx_resource_name = name;
4333
a59e4f3d 4334 /* See if parent window is specified. */
333b20bb 4335 parent = x_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
a59e4f3d
RS
4336 if (EQ (parent, Qunbound))
4337 parent = Qnil;
4338 if (! NILP (parent))
b7826503 4339 CHECK_NUMBER (parent);
a59e4f3d 4340
ecaca587
RS
4341 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4342 /* No need to protect DISPLAY because that's not used after passing
4343 it to make_frame_without_minibuffer. */
4344 frame = Qnil;
4345 GCPRO4 (parms, parent, name, frame);
333b20bb
GM
4346 tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
4347 RES_TYPE_SYMBOL);
f9942c9e 4348 if (EQ (tem, Qnone) || NILP (tem))
2526c290 4349 f = make_frame_without_minibuffer (Qnil, kb, display);
f9942c9e 4350 else if (EQ (tem, Qonly))
01f1ba30 4351 {
f676886a 4352 f = make_minibuffer_frame ();
01f1ba30
JB
4353 minibuffer_only = 1;
4354 }
6a5e54e2 4355 else if (WINDOWP (tem))
2526c290 4356 f = make_frame_without_minibuffer (tem, kb, display);
f9942c9e
JB
4357 else
4358 f = make_frame (1);
01f1ba30 4359
ecaca587
RS
4360 XSETFRAME (frame, f);
4361
a3c87d4e
JB
4362 /* Note that X Windows does support scroll bars. */
4363 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
179956b9 4364
08a90d6a 4365 f->output_method = output_x_window;
7556890b
RS
4366 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
4367 bzero (f->output_data.x, sizeof (struct x_output));
4368 f->output_data.x->icon_bitmap = -1;
0ecca023 4369 f->output_data.x->fontset = -1;
333b20bb
GM
4370 f->output_data.x->scroll_bar_foreground_pixel = -1;
4371 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
4372#ifdef USE_TOOLKIT_SCROLL_BARS
4373 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
4374 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
4375#endif /* USE_TOOLKIT_SCROLL_BARS */
eaf1eea9 4376 record_unwind_protect (unwind_create_frame, frame);
08a90d6a 4377
f468da95 4378 f->icon_name
333b20bb
GM
4379 = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
4380 RES_TYPE_STRING);
f468da95
RS
4381 if (! STRINGP (f->icon_name))
4382 f->icon_name = Qnil;
80534dd6 4383
08a90d6a 4384 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 4385#if GLYPH_DEBUG
eaf1eea9
GM
4386 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
4387 dpyinfo_refcount = dpyinfo->reference_count;
4388#endif /* GLYPH_DEBUG */
73410c76 4389#ifdef MULTI_KBOARD
e557f19d 4390 FRAME_KBOARD (f) = kb;
73410c76 4391#endif
08a90d6a 4392
9b2956e2
GM
4393 /* These colors will be set anyway later, but it's important
4394 to get the color reference counts right, so initialize them! */
4395 {
4396 Lisp_Object black;
4397 struct gcpro gcpro1;
cefecbcf
GM
4398
4399 /* Function x_decode_color can signal an error. Make
4400 sure to initialize color slots so that we won't try
4401 to free colors we haven't allocated. */
4402 f->output_data.x->foreground_pixel = -1;
4403 f->output_data.x->background_pixel = -1;
4404 f->output_data.x->cursor_pixel = -1;
4405 f->output_data.x->cursor_foreground_pixel = -1;
4406 f->output_data.x->border_pixel = -1;
4407 f->output_data.x->mouse_pixel = -1;
9b2956e2
GM
4408
4409 black = build_string ("black");
4410 GCPRO1 (black);
4411 f->output_data.x->foreground_pixel
4412 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4413 f->output_data.x->background_pixel
4414 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4415 f->output_data.x->cursor_pixel
4416 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4417 f->output_data.x->cursor_foreground_pixel
4418 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4419 f->output_data.x->border_pixel
4420 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4421 f->output_data.x->mouse_pixel
4422 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
4423 UNGCPRO;
4424 }
4425
a59e4f3d
RS
4426 /* Specify the parent under which to make this X window. */
4427
4428 if (!NILP (parent))
4429 {
8c239ac3 4430 f->output_data.x->parent_desc = (Window) XFASTINT (parent);
7556890b 4431 f->output_data.x->explicit_parent = 1;
a59e4f3d
RS
4432 }
4433 else
4434 {
7556890b
RS
4435 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
4436 f->output_data.x->explicit_parent = 0;
a59e4f3d
RS
4437 }
4438
cf177271
JB
4439 /* Set the name; the functions to which we pass f expect the name to
4440 be set. */
4441 if (EQ (name, Qunbound) || NILP (name))
4442 {
08a90d6a 4443 f->name = build_string (dpyinfo->x_id_name);
cf177271
JB
4444 f->explicit_name = 0;
4445 }
4446 else
4447 {
4448 f->name = name;
4449 f->explicit_name = 1;
9ef48a9d
RS
4450 /* use the frame's title when getting resources for this frame. */
4451 specbind (Qx_resource_name, name);
cf177271 4452 }
01f1ba30 4453
01f1ba30
JB
4454 /* Extract the window parameters from the supplied values
4455 that are needed to determine window geometry. */
d387c960
JB
4456 {
4457 Lisp_Object font;
4458
333b20bb 4459 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
2ee3abaa 4460
6817eab4 4461 BLOCK_INPUT;
e5e548e3
RS
4462 /* First, try whatever font the caller has specified. */
4463 if (STRINGP (font))
942ea06d 4464 {
49965a29 4465 tem = Fquery_fontset (font, Qnil);
477f8642 4466 if (STRINGP (tem))
d5db4077 4467 font = x_new_fontset (f, SDATA (tem));
942ea06d 4468 else
d5db4077 4469 font = x_new_font (f, SDATA (font));
942ea06d 4470 }
333b20bb 4471
e5e548e3 4472 /* Try out a font which we hope has bold and italic variations. */
333b20bb
GM
4473 if (!STRINGP (font))
4474 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
e5e548e3 4475 if (!STRINGP (font))
a6ac02af 4476 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3 4477 if (! STRINGP (font))
a6ac02af 4478 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
e5e548e3
RS
4479 if (! STRINGP (font))
4480 /* This was formerly the first thing tried, but it finds too many fonts
4481 and takes too long. */
4482 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
4483 /* If those didn't work, look for something which will at least work. */
4484 if (! STRINGP (font))
a6ac02af 4485 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
6817eab4
JB
4486 UNBLOCK_INPUT;
4487 if (! STRINGP (font))
e5e548e3
RS
4488 font = build_string ("fixed");
4489
477f8642 4490 x_default_parameter (f, parms, Qfont, font,
333b20bb 4491 "font", "Font", RES_TYPE_STRING);
d387c960 4492 }
9ef48a9d 4493
e3881aa0 4494#ifdef USE_LUCID
82c90203
RS
4495 /* Prevent lwlib/xlwmenu.c from crashing because of a bug
4496 whereby it fails to get any font. */
7556890b 4497 xlwmenu_default_font = f->output_data.x->font;
dd254b21 4498#endif
82c90203 4499
cf177271 4500 x_default_parameter (f, parms, Qborder_width, make_number (2),
333b20bb
GM
4501 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
4502
4e397688 4503 /* This defaults to 1 in order to match xterm. We recognize either
ddf768c3
JB
4504 internalBorderWidth or internalBorder (which is what xterm calls
4505 it). */
4506 if (NILP (Fassq (Qinternal_border_width, parms)))
4507 {
4508 Lisp_Object value;
4509
abb4b7ec 4510 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
333b20bb 4511 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
ddf768c3
JB
4512 if (! EQ (value, Qunbound))
4513 parms = Fcons (Fcons (Qinternal_border_width, value),
4514 parms);
4515 }
dca97592 4516 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
333b20bb
GM
4517 "internalBorderWidth", "internalBorderWidth",
4518 RES_TYPE_NUMBER);
1ab3d87e 4519 x_default_parameter (f, parms, Qvertical_scroll_bars, Qleft,
333b20bb
GM
4520 "verticalScrollBars", "ScrollBars",
4521 RES_TYPE_SYMBOL);
01f1ba30 4522
b9dc4443 4523 /* Also do the stuff which must be set before the window exists. */
cf177271 4524 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
333b20bb 4525 "foreground", "Foreground", RES_TYPE_STRING);
cf177271 4526 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
0b60fc91 4527 "background", "Background", RES_TYPE_STRING);
cf177271 4528 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
333b20bb 4529 "pointerColor", "Foreground", RES_TYPE_STRING);
cf177271 4530 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
333b20bb 4531 "cursorColor", "Foreground", RES_TYPE_STRING);
cf177271 4532 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
333b20bb 4533 "borderColor", "BorderColor", RES_TYPE_STRING);
d62c8769
GM
4534 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
4535 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
563b67aa
GM
4536 x_default_parameter (f, parms, Qline_spacing, Qnil,
4537 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
b3ba0aa8
KS
4538 x_default_parameter (f, parms, Qleft_fringe, Qnil,
4539 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4540 x_default_parameter (f, parms, Qright_fringe, Qnil,
4541 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
333b20bb
GM
4542
4543 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
4544 "scrollBarForeground",
4545 "ScrollBarForeground", 1);
4546 x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
4547 "scrollBarBackground",
4548 "ScrollBarBackground", 0);
4549
4550 /* Init faces before x_default_parameter is called for scroll-bar
4551 parameters because that function calls x_set_scroll_bar_width,
4552 which calls change_frame_size, which calls Fset_window_buffer,
4553 which runs hooks, which call Fvertical_motion. At the end, we
4554 end up in init_iterator with a null face cache, which should not
4555 happen. */
4556 init_frame_faces (f);
4557
c7bcb20d 4558 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
333b20bb 4559 "menuBar", "MenuBar", RES_TYPE_NUMBER);
e33455ca 4560 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
333b20bb 4561 "toolBar", "ToolBar", RES_TYPE_NUMBER);
79873d50 4562 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
333b20bb
GM
4563 "bufferPredicate", "BufferPredicate",
4564 RES_TYPE_SYMBOL);
c2304e02 4565 x_default_parameter (f, parms, Qtitle, Qnil,
333b20bb 4566 "title", "Title", RES_TYPE_STRING);
ea0a1f53
GM
4567 x_default_parameter (f, parms, Qwait_for_wm, Qt,
4568 "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
49d41073
EZ
4569 x_default_parameter (f, parms, Qfullscreen, Qnil,
4570 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
90eb1019 4571
7556890b 4572 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
35f59f6b
GM
4573
4574 /* Add the tool-bar height to the initial frame height so that the
4575 user gets a text display area of the size he specified with -g or
4576 via .Xdefaults. Later changes of the tool-bar height don't
4577 change the frame size. This is done so that users can create
4578 tall Emacs frames without having to guess how tall the tool-bar
4579 will get. */
4580 if (FRAME_TOOL_BAR_LINES (f))
4581 {
4582 int margin, relief, bar_height;
4583
8ed86491 4584 relief = (tool_bar_button_relief >= 0
35f59f6b
GM
4585 ? tool_bar_button_relief
4586 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
4587
4588 if (INTEGERP (Vtool_bar_button_margin)
4589 && XINT (Vtool_bar_button_margin) > 0)
4590 margin = XFASTINT (Vtool_bar_button_margin);
4591 else if (CONSP (Vtool_bar_button_margin)
4592 && INTEGERP (XCDR (Vtool_bar_button_margin))
4593 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
4594 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
4595 else
4596 margin = 0;
4597
4598 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
4599 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
4600 }
4601
4602 /* Compute the size of the X window. */
f676886a 4603 window_prompting = x_figure_window_size (f, parms);
01f1ba30 4604
f83f10ba 4605 if (window_prompting & XNegative)
2365c027 4606 {
f83f10ba 4607 if (window_prompting & YNegative)
7556890b 4608 f->output_data.x->win_gravity = SouthEastGravity;
f83f10ba 4609 else
7556890b 4610 f->output_data.x->win_gravity = NorthEastGravity;
f83f10ba
RS
4611 }
4612 else
4613 {
4614 if (window_prompting & YNegative)
7556890b 4615 f->output_data.x->win_gravity = SouthWestGravity;
f83f10ba 4616 else
7556890b 4617 f->output_data.x->win_gravity = NorthWestGravity;
2365c027
RS
4618 }
4619
7556890b 4620 f->output_data.x->size_hint_flags = window_prompting;
38d22040 4621
495fa05e
GM
4622 tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4623 f->no_split = minibuffer_only || EQ (tem, Qt);
4624
6a1bcd01 4625 /* Create the X widget or window. */
a7f7d550
FP
4626#ifdef USE_X_TOOLKIT
4627 x_window (f, window_prompting, minibuffer_only);
4628#else
f676886a 4629 x_window (f);
a7f7d550 4630#endif
495fa05e 4631
f676886a
JB
4632 x_icon (f, parms);
4633 x_make_gc (f);
01f1ba30 4634
495fa05e
GM
4635 /* Now consider the frame official. */
4636 FRAME_X_DISPLAY_INFO (f)->reference_count++;
4637 Vframe_list = Fcons (frame, Vframe_list);
4638
f9942c9e
JB
4639 /* We need to do this after creating the X window, so that the
4640 icon-creation functions can say whose icon they're describing. */
cf177271 4641 x_default_parameter (f, parms, Qicon_type, Qnil,
333b20bb 4642 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
f9942c9e 4643
cf177271 4644 x_default_parameter (f, parms, Qauto_raise, Qnil,
333b20bb 4645 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
cf177271 4646 x_default_parameter (f, parms, Qauto_lower, Qnil,
333b20bb 4647 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
dbc4e1c1 4648 x_default_parameter (f, parms, Qcursor_type, Qbox,
333b20bb 4649 "cursorType", "CursorType", RES_TYPE_SYMBOL);
28d7281d
GM
4650 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4651 "scrollBarWidth", "ScrollBarWidth",
4652 RES_TYPE_NUMBER);
f9942c9e 4653
f676886a 4654 /* Dimensions, especially f->height, must be done via change_frame_size.
01f1ba30 4655 Change will not be effected unless different from the current
b9dc4443 4656 f->height. */
f676886a
JB
4657 width = f->width;
4658 height = f->height;
6a1bcd01 4659
1ab3d87e
RS
4660 f->height = 0;
4661 SET_FRAME_WIDTH (f, 0);
8938a4fb 4662 change_frame_size (f, height, width, 1, 0, 0);
d043f1a4 4663
4a967a9b
GM
4664 /* Set up faces after all frame parameters are known. This call
4665 also merges in face attributes specified for new frames. If we
4666 don't do this, the `menu' face for instance won't have the right
4667 colors, and the menu bar won't appear in the specified colors for
4668 new frames. */
4669 call1 (Qface_set_after_frame_default, frame);
4670
495fa05e
GM
4671#ifdef USE_X_TOOLKIT
4672 /* Create the menu bar. */
4673 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4674 {
4675 /* If this signals an error, we haven't set size hints for the
4676 frame and we didn't make it visible. */
4677 initialize_frame_menubar (f);
4678
4679 /* This is a no-op, except under Motif where it arranges the
4680 main window for the widgets on it. */
4681 lw_set_main_areas (f->output_data.x->column_widget,
4682 f->output_data.x->menubar_widget,
4683 f->output_data.x->edit_widget);
4684 }
4685#endif /* USE_X_TOOLKIT */
4686
4687 /* Tell the server what size and position, etc, we want, and how
4688 badly we want them. This should be done after we have the menu
4689 bar so that its size can be taken into account. */
01f1ba30 4690 BLOCK_INPUT;
7989f084 4691 x_wm_set_size_hint (f, window_prompting, 0);
01f1ba30
JB
4692 UNBLOCK_INPUT;
4693
495fa05e
GM
4694 /* Make the window appear on the frame and enable display, unless
4695 the caller says not to. However, with explicit parent, Emacs
4696 cannot control visibility, so don't try. */
7556890b 4697 if (! f->output_data.x->explicit_parent)
a59e4f3d
RS
4698 {
4699 Lisp_Object visibility;
49795535 4700
333b20bb
GM
4701 visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
4702 RES_TYPE_SYMBOL);
a59e4f3d
RS
4703 if (EQ (visibility, Qunbound))
4704 visibility = Qt;
49795535 4705
a59e4f3d
RS
4706 if (EQ (visibility, Qicon))
4707 x_iconify_frame (f);
4708 else if (! NILP (visibility))
4709 x_make_frame_visible (f);
4710 else
4711 /* Must have been Qnil. */
4712 ;
4713 }
01f1ba30 4714
495fa05e 4715 UNGCPRO;
9e57df62
GM
4716
4717 /* Make sure windows on this frame appear in calls to next-window
4718 and similar functions. */
4719 Vwindow_list = Qnil;
4720
9ef48a9d 4721 return unbind_to (count, frame);
01f1ba30
JB
4722}
4723
eaf1eea9 4724
0d17d282
KH
4725/* FRAME is used only to get a handle on the X display. We don't pass the
4726 display info directly because we're called from frame.c, which doesn't
4727 know about that structure. */
e4f79258 4728
87498171 4729Lisp_Object
0d17d282
KH
4730x_get_focus_frame (frame)
4731 struct frame *frame;
87498171 4732{
0d17d282 4733 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (frame);
87498171 4734 Lisp_Object xfocus;
0d17d282 4735 if (! dpyinfo->x_focus_frame)
87498171
KH
4736 return Qnil;
4737
0d17d282 4738 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
87498171
KH
4739 return xfocus;
4740}
f0614854 4741
3decc1e7
GM
4742
4743/* In certain situations, when the window manager follows a
4744 click-to-focus policy, there seems to be no way around calling
4745 XSetInputFocus to give another frame the input focus .
4746
4747 In an ideal world, XSetInputFocus should generally be avoided so
4748 that applications don't interfere with the window manager's focus
4749 policy. But I think it's okay to use when it's clearly done
4750 following a user-command. */
4751
4752DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
7ee72033
MB
4753 doc: /* Set the input focus to FRAME.
4754FRAME nil means use the selected frame. */)
4755 (frame)
3decc1e7
GM
4756 Lisp_Object frame;
4757{
4758 struct frame *f = check_x_frame (frame);
4759 Display *dpy = FRAME_X_DISPLAY (f);
4760 int count;
4761
4762 BLOCK_INPUT;
4763 count = x_catch_errors (dpy);
4764 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4765 RevertToParent, CurrentTime);
4766 x_uncatch_errors (dpy, count);
4767 UNBLOCK_INPUT;
4768
4769 return Qnil;
4770}
4771
f0614854 4772\f
2d764c78 4773DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7ee72033
MB
4774 doc: /* Internal function called by `color-defined-p', which see. */)
4775 (color, frame)
b9dc4443 4776 Lisp_Object color, frame;
e12d55b2 4777{
b9dc4443
RS
4778 XColor foo;
4779 FRAME_PTR f = check_x_frame (frame);
e12d55b2 4780
b7826503 4781 CHECK_STRING (color);
b9dc4443 4782
d5db4077 4783 if (x_defined_color (f, SDATA (color), &foo, 0))
e12d55b2
RS
4784 return Qt;
4785 else
4786 return Qnil;
4787}
4788
2d764c78 4789DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7ee72033
MB
4790 doc: /* Internal function called by `color-values', which see. */)
4791 (color, frame)
b9dc4443 4792 Lisp_Object color, frame;
01f1ba30 4793{
b9dc4443
RS
4794 XColor foo;
4795 FRAME_PTR f = check_x_frame (frame);
4796
b7826503 4797 CHECK_STRING (color);
01f1ba30 4798
d5db4077 4799 if (x_defined_color (f, SDATA (color), &foo, 0))
57c82a63
RS
4800 {
4801 Lisp_Object rgb[3];
4802
4803 rgb[0] = make_number (foo.red);
4804 rgb[1] = make_number (foo.green);
4805 rgb[2] = make_number (foo.blue);
4806 return Flist (3, rgb);
4807 }
01f1ba30
JB
4808 else
4809 return Qnil;
4810}
4811
2d764c78 4812DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7ee72033
MB
4813 doc: /* Internal function called by `display-color-p', which see. */)
4814 (display)
08a90d6a 4815 Lisp_Object display;
01f1ba30 4816{
08a90d6a 4817 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 4818
b9dc4443 4819 if (dpyinfo->n_planes <= 2)
01f1ba30
JB
4820 return Qnil;
4821
b9dc4443 4822 switch (dpyinfo->visual->class)
01f1ba30
JB
4823 {
4824 case StaticColor:
4825 case PseudoColor:
4826 case TrueColor:
4827 case DirectColor:
4828 return Qt;
4829
4830 default:
4831 return Qnil;
4832 }
4833}
4834
d0c9d219 4835DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
c061c855 4836 0, 1, 0,
7ee72033 4837 doc: /* Return t if the X display supports shades of gray.
c061c855
GM
4838Note that color displays do support shades of gray.
4839The optional argument DISPLAY specifies which display to ask about.
4840DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4841If omitted or nil, that stands for the selected frame's display. */)
4842 (display)
08a90d6a 4843 Lisp_Object display;
d0c9d219 4844{
08a90d6a 4845 struct x_display_info *dpyinfo = check_x_display_info (display);
d0c9d219 4846
ae6b58f9 4847 if (dpyinfo->n_planes <= 1)
b9dc4443
RS
4848 return Qnil;
4849
ae6b58f9
RS
4850 switch (dpyinfo->visual->class)
4851 {
4852 case StaticColor:
4853 case PseudoColor:
4854 case TrueColor:
4855 case DirectColor:
4856 case StaticGray:
4857 case GrayScale:
4858 return Qt;
4859
4860 default:
4861 return Qnil;
4862 }
d0c9d219
RS
4863}
4864
41beb8fc 4865DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
c061c855 4866 0, 1, 0,
7ee72033 4867 doc: /* Returns the width in pixels of the X display DISPLAY.
c061c855
GM
4868The optional argument DISPLAY specifies which display to ask about.
4869DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4870If omitted or nil, that stands for the selected frame's display. */)
4871 (display)
08a90d6a 4872 Lisp_Object display;
41beb8fc 4873{
08a90d6a 4874 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4875
4876 return make_number (dpyinfo->width);
41beb8fc
RS
4877}
4878
4879DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
c061c855 4880 Sx_display_pixel_height, 0, 1, 0,
7ee72033 4881 doc: /* Returns the height in pixels of the X display DISPLAY.
c061c855
GM
4882The optional argument DISPLAY specifies which display to ask about.
4883DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4884If omitted or nil, that stands for the selected frame's display. */)
4885 (display)
08a90d6a 4886 Lisp_Object display;
41beb8fc 4887{
08a90d6a 4888 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4889
4890 return make_number (dpyinfo->height);
41beb8fc
RS
4891}
4892
4893DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
c061c855 4894 0, 1, 0,
7ee72033 4895 doc: /* Returns the number of bitplanes of the X display DISPLAY.
c061c855
GM
4896The optional argument DISPLAY specifies which display to ask about.
4897DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4898If omitted or nil, that stands for the selected frame's display. */)
4899 (display)
08a90d6a 4900 Lisp_Object display;
41beb8fc 4901{
08a90d6a 4902 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4903
4904 return make_number (dpyinfo->n_planes);
41beb8fc
RS
4905}
4906
4907DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
c061c855 4908 0, 1, 0,
7ee72033 4909 doc: /* Returns the number of color cells of the X display DISPLAY.
c061c855
GM
4910The optional argument DISPLAY specifies which display to ask about.
4911DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4912If omitted or nil, that stands for the selected frame's display. */)
4913 (display)
08a90d6a 4914 Lisp_Object display;
41beb8fc 4915{
08a90d6a 4916 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4917
4918 return make_number (DisplayCells (dpyinfo->display,
4919 XScreenNumberOfScreen (dpyinfo->screen)));
41beb8fc
RS
4920}
4921
9d317b2c
RS
4922DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4923 Sx_server_max_request_size,
c061c855 4924 0, 1, 0,
7ee72033 4925 doc: /* Returns the maximum request size of the X server of display DISPLAY.
c061c855
GM
4926The optional argument DISPLAY specifies which display to ask about.
4927DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4928If omitted or nil, that stands for the selected frame's display. */)
4929 (display)
08a90d6a 4930 Lisp_Object display;
9d317b2c 4931{
08a90d6a 4932 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4933
4934 return make_number (MAXREQUEST (dpyinfo->display));
9d317b2c
RS
4935}
4936
41beb8fc 4937DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7ee72033 4938 doc: /* Returns the vendor ID string of the X server of display DISPLAY.
c061c855
GM
4939The optional argument DISPLAY specifies which display to ask about.
4940DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4941If omitted or nil, that stands for the selected frame's display. */)
4942 (display)
08a90d6a 4943 Lisp_Object display;
41beb8fc 4944{
08a90d6a 4945 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4946 char *vendor = ServerVendor (dpyinfo->display);
4947
41beb8fc
RS
4948 if (! vendor) vendor = "";
4949 return build_string (vendor);
4950}
4951
4952DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7ee72033 4953 doc: /* Returns the version numbers of the X server of display DISPLAY.
c061c855
GM
4954The value is a list of three integers: the major and minor
4955version numbers of the X Protocol in use, and the vendor-specific release
4956number. See also the function `x-server-vendor'.
4957
4958The optional argument DISPLAY specifies which display to ask about.
4959DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4960If omitted or nil, that stands for the selected frame's display. */)
4961 (display)
08a90d6a 4962 Lisp_Object display;
41beb8fc 4963{
08a90d6a 4964 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443 4965 Display *dpy = dpyinfo->display;
11ae94fe 4966
41beb8fc
RS
4967 return Fcons (make_number (ProtocolVersion (dpy)),
4968 Fcons (make_number (ProtocolRevision (dpy)),
4969 Fcons (make_number (VendorRelease (dpy)), Qnil)));
4970}
4971
4972DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7ee72033 4973 doc: /* Return the number of screens on the X server of display DISPLAY.
c061c855
GM
4974The optional argument DISPLAY specifies which display to ask about.
4975DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4976If omitted or nil, that stands for the selected frame's display. */)
4977 (display)
08a90d6a 4978 Lisp_Object display;
41beb8fc 4979{
08a90d6a 4980 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4981
4982 return make_number (ScreenCount (dpyinfo->display));
41beb8fc
RS
4983}
4984
4985DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7ee72033 4986 doc: /* Return the height in millimeters of the X display DISPLAY.
c061c855
GM
4987The optional argument DISPLAY specifies which display to ask about.
4988DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
4989If omitted or nil, that stands for the selected frame's display. */)
4990 (display)
08a90d6a 4991 Lisp_Object display;
41beb8fc 4992{
08a90d6a 4993 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
4994
4995 return make_number (HeightMMOfScreen (dpyinfo->screen));
41beb8fc
RS
4996}
4997
4998DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7ee72033 4999 doc: /* Return the width in millimeters of the X display DISPLAY.
c061c855
GM
5000The optional argument DISPLAY specifies which display to ask about.
5001DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5002If omitted or nil, that stands for the selected frame's display. */)
5003 (display)
08a90d6a 5004 Lisp_Object display;
41beb8fc 5005{
08a90d6a 5006 struct x_display_info *dpyinfo = check_x_display_info (display);
b9dc4443
RS
5007
5008 return make_number (WidthMMOfScreen (dpyinfo->screen));
41beb8fc
RS
5009}
5010
5011DEFUN ("x-display-backing-store", Fx_display_backing_store,
c061c855 5012 Sx_display_backing_store, 0, 1, 0,
7ee72033 5013 doc: /* Returns an indication of whether X display DISPLAY does backing store.
c061c855
GM
5014The value may be `always', `when-mapped', or `not-useful'.
5015The optional argument DISPLAY specifies which display to ask about.
5016DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5017If omitted or nil, that stands for the selected frame's display. */)
5018 (display)
08a90d6a 5019 Lisp_Object display;
41beb8fc 5020{
08a90d6a 5021 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5022 Lisp_Object result;
11ae94fe 5023
b9dc4443 5024 switch (DoesBackingStore (dpyinfo->screen))
41beb8fc
RS
5025 {
5026 case Always:
8ec8a5ec
GM
5027 result = intern ("always");
5028 break;
41beb8fc
RS
5029
5030 case WhenMapped:
8ec8a5ec
GM
5031 result = intern ("when-mapped");
5032 break;
41beb8fc
RS
5033
5034 case NotUseful:
8ec8a5ec
GM
5035 result = intern ("not-useful");
5036 break;
41beb8fc
RS
5037
5038 default:
5039 error ("Strange value for BackingStore parameter of screen");
8ec8a5ec 5040 result = Qnil;
41beb8fc 5041 }
8ec8a5ec
GM
5042
5043 return result;
41beb8fc
RS
5044}
5045
5046DEFUN ("x-display-visual-class", Fx_display_visual_class,
c061c855 5047 Sx_display_visual_class, 0, 1, 0,
7ee72033 5048 doc: /* Return the visual class of the X display DISPLAY.
c061c855
GM
5049The value is one of the symbols `static-gray', `gray-scale',
5050`static-color', `pseudo-color', `true-color', or `direct-color'.
5051
5052The optional argument DISPLAY specifies which display to ask about.
5053DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5054If omitted or nil, that stands for the selected frame's display. */)
5055 (display)
08a90d6a 5056 Lisp_Object display;
41beb8fc 5057{
08a90d6a 5058 struct x_display_info *dpyinfo = check_x_display_info (display);
8ec8a5ec 5059 Lisp_Object result;
11ae94fe 5060
b9dc4443 5061 switch (dpyinfo->visual->class)
41beb8fc 5062 {
8ec8a5ec
GM
5063 case StaticGray:
5064 result = intern ("static-gray");
5065 break;
5066 case GrayScale:
5067 result = intern ("gray-scale");
5068 break;
5069 case StaticColor:
5070 result = intern ("static-color");
5071 break;
5072 case PseudoColor:
5073 result = intern ("pseudo-color");
5074 break;
5075 case TrueColor:
5076 result = intern ("true-color");
5077 break;
5078 case DirectColor:
5079 result = intern ("direct-color");
5080 break;
41beb8fc
RS
5081 default:
5082 error ("Display has an unknown visual class");
8ec8a5ec 5083 result = Qnil;
41beb8fc 5084 }
8ec8a5ec
GM
5085
5086 return result;
41beb8fc
RS
5087}
5088
5089DEFUN ("x-display-save-under", Fx_display_save_under,
c061c855 5090 Sx_display_save_under, 0, 1, 0,
7ee72033 5091 doc: /* Returns t if the X display DISPLAY supports the save-under feature.
c061c855
GM
5092The optional argument DISPLAY specifies which display to ask about.
5093DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5094If omitted or nil, that stands for the selected frame's display. */)
5095 (display)
08a90d6a 5096 Lisp_Object display;
41beb8fc 5097{
08a90d6a 5098 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5099
b9dc4443 5100 if (DoesSaveUnders (dpyinfo->screen) == True)
41beb8fc
RS
5101 return Qt;
5102 else
5103 return Qnil;
5104}
5105\f
b9dc4443 5106int
55caf99c
RS
5107x_pixel_width (f)
5108 register struct frame *f;
01f1ba30 5109{
55caf99c 5110 return PIXEL_WIDTH (f);
01f1ba30
JB
5111}
5112
b9dc4443 5113int
55caf99c
RS
5114x_pixel_height (f)
5115 register struct frame *f;
01f1ba30 5116{
55caf99c
RS
5117 return PIXEL_HEIGHT (f);
5118}
5119
b9dc4443 5120int
55caf99c
RS
5121x_char_width (f)
5122 register struct frame *f;
5123{
7556890b 5124 return FONT_WIDTH (f->output_data.x->font);
55caf99c
RS
5125}
5126
b9dc4443 5127int
55caf99c
RS
5128x_char_height (f)
5129 register struct frame *f;
5130{
7556890b 5131 return f->output_data.x->line_height;
01f1ba30 5132}
b9dc4443
RS
5133
5134int
f03f2489
RS
5135x_screen_planes (f)
5136 register struct frame *f;
b9dc4443 5137{
f03f2489 5138 return FRAME_X_DISPLAY_INFO (f)->n_planes;
b9dc4443 5139}
01f1ba30 5140
a6ad00c0
GM
5141
5142\f
5143/************************************************************************
5144 X Displays
5145 ************************************************************************/
5146
01f1ba30 5147\f
a6ad00c0
GM
5148/* Mapping visual names to visuals. */
5149
5150static struct visual_class
5151{
5152 char *name;
5153 int class;
5154}
5155visual_classes[] =
5156{
5157 {"StaticGray", StaticGray},
5158 {"GrayScale", GrayScale},
5159 {"StaticColor", StaticColor},
5160 {"PseudoColor", PseudoColor},
5161 {"TrueColor", TrueColor},
5162 {"DirectColor", DirectColor},
9908a324 5163 {NULL, 0}
a6ad00c0
GM
5164};
5165
5166
404daac1 5167#ifndef HAVE_XSCREENNUMBEROFSCREEN
a6ad00c0
GM
5168
5169/* Value is the screen number of screen SCR. This is a substitute for
5170 the X function with the same name when that doesn't exist. */
5171
404daac1
RS
5172int
5173XScreenNumberOfScreen (scr)
5174 register Screen *scr;
5175{
a6ad00c0
GM
5176 Display *dpy = scr->display;
5177 int i;
3df34fdb 5178
a6ad00c0 5179 for (i = 0; i < dpy->nscreens; ++i)
fbd5ceb2 5180 if (scr == dpy->screens + i)
a6ad00c0 5181 break;
404daac1 5182
a6ad00c0 5183 return i;
404daac1 5184}
a6ad00c0 5185
404daac1
RS
5186#endif /* not HAVE_XSCREENNUMBEROFSCREEN */
5187
01f1ba30 5188
a6ad00c0
GM
5189/* Select the visual that should be used on display DPYINFO. Set
5190 members of DPYINFO appropriately. Called from x_term_init. */
fe24a618 5191
a6ad00c0
GM
5192void
5193select_visual (dpyinfo)
5194 struct x_display_info *dpyinfo;
5195{
5196 Display *dpy = dpyinfo->display;
5197 Screen *screen = dpyinfo->screen;
5198 Lisp_Object value;
fe24a618 5199
a6ad00c0
GM
5200 /* See if a visual is specified. */
5201 value = display_x_get_resource (dpyinfo,
5202 build_string ("visualClass"),
5203 build_string ("VisualClass"),
5204 Qnil, Qnil);
5205 if (STRINGP (value))
5206 {
5207 /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
5208 of `PseudoColor', `TrueColor' etc. and DEPTH is the color
5209 depth, a decimal number. NAME is compared with case ignored. */
d5db4077 5210 char *s = (char *) alloca (SBYTES (value) + 1);
a6ad00c0
GM
5211 char *dash;
5212 int i, class = -1;
5213 XVisualInfo vinfo;
5214
d5db4077 5215 strcpy (s, SDATA (value));
a6ad00c0
GM
5216 dash = index (s, '-');
5217 if (dash)
5218 {
5219 dpyinfo->n_planes = atoi (dash + 1);
5220 *dash = '\0';
5221 }
5222 else
5223 /* We won't find a matching visual with depth 0, so that
5224 an error will be printed below. */
5225 dpyinfo->n_planes = 0;
f0614854 5226
a6ad00c0
GM
5227 /* Determine the visual class. */
5228 for (i = 0; visual_classes[i].name; ++i)
5229 if (xstricmp (s, visual_classes[i].name) == 0)
5230 {
5231 class = visual_classes[i].class;
5232 break;
5233 }
01f1ba30 5234
a6ad00c0
GM
5235 /* Look up a matching visual for the specified class. */
5236 if (class == -1
5237 || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
5238 dpyinfo->n_planes, class, &vinfo))
d5db4077 5239 fatal ("Invalid visual specification `%s'", SDATA (value));
a6ad00c0
GM
5240
5241 dpyinfo->visual = vinfo.visual;
5242 }
01f1ba30
JB
5243 else
5244 {
a6ad00c0
GM
5245 int n_visuals;
5246 XVisualInfo *vinfo, vinfo_template;
5247
5248 dpyinfo->visual = DefaultVisualOfScreen (screen);
5249
5250#ifdef HAVE_X11R4
5251 vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
5252#else
5253 vinfo_template.visualid = dpyinfo->visual->visualid;
5254#endif
5255 vinfo_template.screen = XScreenNumberOfScreen (screen);
5256 vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
5257 &vinfo_template, &n_visuals);
5258 if (n_visuals != 1)
5259 fatal ("Can't get proper X visual info");
5260
94ac875b 5261 dpyinfo->n_planes = vinfo->depth;
a6ad00c0
GM
5262 XFree ((char *) vinfo);
5263 }
01f1ba30 5264}
01f1ba30 5265
a6ad00c0 5266
b9dc4443
RS
5267/* Return the X display structure for the display named NAME.
5268 Open a new connection if necessary. */
5269
5270struct x_display_info *
5271x_display_info_for_name (name)
5272 Lisp_Object name;
5273{
08a90d6a 5274 Lisp_Object names;
b9dc4443
RS
5275 struct x_display_info *dpyinfo;
5276
b7826503 5277 CHECK_STRING (name);
b9dc4443 5278
806048df
RS
5279 if (! EQ (Vwindow_system, intern ("x")))
5280 error ("Not using X Windows");
5281
08a90d6a
RS
5282 for (dpyinfo = x_display_list, names = x_display_name_list;
5283 dpyinfo;
8e713be6 5284 dpyinfo = dpyinfo->next, names = XCDR (names))
b9dc4443
RS
5285 {
5286 Lisp_Object tem;
8e713be6 5287 tem = Fstring_equal (XCAR (XCAR (names)), name);
08a90d6a 5288 if (!NILP (tem))
b9dc4443
RS
5289 return dpyinfo;
5290 }
5291
b7975ee4
KH
5292 /* Use this general default value to start with. */
5293 Vx_resource_name = Vinvocation_name;
5294
b9dc4443
RS
5295 validate_x_resource_name ();
5296
9b207e8e 5297 dpyinfo = x_term_init (name, (char *)0,
d5db4077 5298 (char *) SDATA (Vx_resource_name));
b9dc4443 5299
08a90d6a 5300 if (dpyinfo == 0)
d5db4077 5301 error ("Cannot connect to X server %s", SDATA (name));
08a90d6a 5302
b9dc4443
RS
5303 x_in_use = 1;
5304 XSETFASTINT (Vwindow_system_version, 11);
5305
5306 return dpyinfo;
5307}
5308
a6ad00c0 5309
01f1ba30 5310DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
c061c855 5311 1, 3, 0,
7ee72033 5312 doc: /* Open a connection to an X server.
c061c855
GM
5313DISPLAY is the name of the display to connect to.
5314Optional second arg XRM-STRING is a string of resources in xrdb format.
5315If the optional third arg MUST-SUCCEED is non-nil,
7ee72033
MB
5316terminate Emacs if we can't open the connection. */)
5317 (display, xrm_string, must_succeed)
08a90d6a 5318 Lisp_Object display, xrm_string, must_succeed;
01f1ba30 5319{
01f1ba30 5320 unsigned char *xrm_option;
b9dc4443 5321 struct x_display_info *dpyinfo;
01f1ba30 5322
b7826503 5323 CHECK_STRING (display);
d387c960 5324 if (! NILP (xrm_string))
b7826503 5325 CHECK_STRING (xrm_string);
01f1ba30 5326
806048df
RS
5327 if (! EQ (Vwindow_system, intern ("x")))
5328 error ("Not using X Windows");
5329
d387c960 5330 if (! NILP (xrm_string))
d5db4077 5331 xrm_option = (unsigned char *) SDATA (xrm_string);
01f1ba30
JB
5332 else
5333 xrm_option = (unsigned char *) 0;
d387c960
JB
5334
5335 validate_x_resource_name ();
5336
e1b1bee8 5337 /* This is what opens the connection and sets x_current_display.
b9dc4443
RS
5338 This also initializes many symbols, such as those used for input. */
5339 dpyinfo = x_term_init (display, xrm_option,
d5db4077 5340 (char *) SDATA (Vx_resource_name));
f1c16f36 5341
08a90d6a
RS
5342 if (dpyinfo == 0)
5343 {
5344 if (!NILP (must_succeed))
10ffbc14
GM
5345 fatal ("Cannot connect to X server %s.\n\
5346Check the DISPLAY environment variable or use `-d'.\n\
5347Also use the `xhost' program to verify that it is set to permit\n\
1b4ec1c8 5348connections from your machine.\n",
d5db4077 5349 SDATA (display));
08a90d6a 5350 else
d5db4077 5351 error ("Cannot connect to X server %s", SDATA (display));
08a90d6a
RS
5352 }
5353
b9dc4443 5354 x_in_use = 1;
01f1ba30 5355
b9dc4443 5356 XSETFASTINT (Vwindow_system_version, 11);
01f1ba30
JB
5357 return Qnil;
5358}
5359
08a90d6a
RS
5360DEFUN ("x-close-connection", Fx_close_connection,
5361 Sx_close_connection, 1, 1, 0,
7ee72033 5362 doc: /* Close the connection to DISPLAY's X server.
c061c855 5363For DISPLAY, specify either a frame or a display name (a string).
7ee72033
MB
5364If DISPLAY is nil, that stands for the selected frame's display. */)
5365 (display)
c061c855 5366 Lisp_Object display;
01f1ba30 5367{
08a90d6a 5368 struct x_display_info *dpyinfo = check_x_display_info (display);
08a90d6a 5369 int i;
3457bc6e 5370
08a90d6a
RS
5371 if (dpyinfo->reference_count > 0)
5372 error ("Display still has frames on it");
01f1ba30 5373
08a90d6a
RS
5374 BLOCK_INPUT;
5375 /* Free the fonts in the font table. */
5376 for (i = 0; i < dpyinfo->n_fonts; i++)
333b20bb
GM
5377 if (dpyinfo->font_table[i].name)
5378 {
6ecb43ce
KH
5379 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
5380 xfree (dpyinfo->font_table[i].full_name);
333b20bb 5381 xfree (dpyinfo->font_table[i].name);
333b20bb
GM
5382 XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
5383 }
5384
08a90d6a
RS
5385 x_destroy_all_bitmaps (dpyinfo);
5386 XSetCloseDownMode (dpyinfo->display, DestroyAll);
82c90203
RS
5387
5388#ifdef USE_X_TOOLKIT
5389 XtCloseDisplay (dpyinfo->display);
5390#else
08a90d6a 5391 XCloseDisplay (dpyinfo->display);
82c90203 5392#endif
08a90d6a
RS
5393
5394 x_delete_display (dpyinfo);
5395 UNBLOCK_INPUT;
3457bc6e 5396
01f1ba30
JB
5397 return Qnil;
5398}
5399
08a90d6a 5400DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7ee72033
MB
5401 doc: /* Return the list of display names that Emacs has connections to. */)
5402 ()
08a90d6a
RS
5403{
5404 Lisp_Object tail, result;
5405
5406 result = Qnil;
8e713be6
KR
5407 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
5408 result = Fcons (XCAR (XCAR (tail)), result);
08a90d6a
RS
5409
5410 return result;
5411}
5412
5413DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7ee72033 5414 doc: /* If ON is non-nil, report X errors as soon as the erring request is made.
c061c855
GM
5415If ON is nil, allow buffering of requests.
5416Turning on synchronization prohibits the Xlib routines from buffering
5417requests and seriously degrades performance, but makes debugging much
5418easier.
5419The optional second argument DISPLAY specifies which display to act on.
5420DISPLAY should be either a frame or a display name (a string).
7ee72033
MB
5421If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
5422 (on, display)
08a90d6a 5423 Lisp_Object display, on;
01f1ba30 5424{
08a90d6a 5425 struct x_display_info *dpyinfo = check_x_display_info (display);
11ae94fe 5426
b9dc4443 5427 XSynchronize (dpyinfo->display, !EQ (on, Qnil));
01f1ba30
JB
5428
5429 return Qnil;
5430}
5431
b9dc4443 5432/* Wait for responses to all X commands issued so far for frame F. */
6b7b1820
RS
5433
5434void
b9dc4443
RS
5435x_sync (f)
5436 FRAME_PTR f;
6b7b1820 5437{
4e87f4d2 5438 BLOCK_INPUT;
b9dc4443 5439 XSync (FRAME_X_DISPLAY (f), False);
4e87f4d2 5440 UNBLOCK_INPUT;
6b7b1820 5441}
333b20bb 5442
01f1ba30 5443\f
333b20bb
GM
5444/***********************************************************************
5445 Image types
5446 ***********************************************************************/
f1c16f36 5447
333b20bb
GM
5448/* Value is the number of elements of vector VECTOR. */
5449
5450#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
5451
5452/* List of supported image types. Use define_image_type to add new
5453 types. Use lookup_image_type to find a type for a given symbol. */
5454
5455static struct image_type *image_types;
5456
333b20bb
GM
5457/* The symbol `image' which is the car of the lists used to represent
5458 images in Lisp. */
5459
5460extern Lisp_Object Qimage;
5461
5462/* The symbol `xbm' which is used as the type symbol for XBM images. */
5463
5464Lisp_Object Qxbm;
5465
5466/* Keywords. */
5467
0fe92f72 5468extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
5469extern Lisp_Object QCdata, QCtype;
5470Lisp_Object QCascent, QCmargin, QCrelief;
d2dc8167 5471Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4a8e312c 5472Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
333b20bb
GM
5473
5474/* Other symbols. */
5475
4a8e312c 5476Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
333b20bb
GM
5477
5478/* Time in seconds after which images should be removed from the cache
5479 if not displayed. */
5480
fcf431dc 5481Lisp_Object Vimage_cache_eviction_delay;
333b20bb
GM
5482
5483/* Function prototypes. */
5484
5485static void define_image_type P_ ((struct image_type *type));
5486static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
5487static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
5488static void x_laplace P_ ((struct frame *, struct image *));
4a8e312c 5489static void x_emboss P_ ((struct frame *, struct image *));
45158a91
GM
5490static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
5491 Lisp_Object));
333b20bb
GM
5492
5493
5494/* Define a new image type from TYPE. This adds a copy of TYPE to
5495 image_types and adds the symbol *TYPE->type to Vimage_types. */
5496
5497static void
5498define_image_type (type)
5499 struct image_type *type;
5500{
5501 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
5502 The initialized data segment is read-only. */
5503 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
5504 bcopy (type, p, sizeof *p);
5505 p->next = image_types;
5506 image_types = p;
5507 Vimage_types = Fcons (*p->type, Vimage_types);
5508}
5509
5510
5511/* Look up image type SYMBOL, and return a pointer to its image_type
5512 structure. Value is null if SYMBOL is not a known image type. */
5513
5514static INLINE struct image_type *
5515lookup_image_type (symbol)
5516 Lisp_Object symbol;
5517{
5518 struct image_type *type;
5519
5520 for (type = image_types; type; type = type->next)
5521 if (EQ (symbol, *type->type))
5522 break;
5523
5524 return type;
5525}
5526
5527
5528/* Value is non-zero if OBJECT is a valid Lisp image specification. A
5529 valid image specification is a list whose car is the symbol
5530 `image', and whose rest is a property list. The property list must
5531 contain a value for key `:type'. That value must be the name of a
5532 supported image type. The rest of the property list depends on the
5533 image type. */
5534
5535int
5536valid_image_p (object)
5537 Lisp_Object object;
5538{
5539 int valid_p = 0;
5540
5541 if (CONSP (object) && EQ (XCAR (object), Qimage))
5542 {
1783ffa2
GM
5543 Lisp_Object tem;
5544
5545 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
5546 if (EQ (XCAR (tem), QCtype))
5547 {
5548 tem = XCDR (tem);
5549 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
5550 {
5551 struct image_type *type;
5552 type = lookup_image_type (XCAR (tem));
5553 if (type)
5554 valid_p = type->valid_p (object);
5555 }
5556
5557 break;
5558 }
333b20bb
GM
5559 }
5560
5561 return valid_p;
5562}
5563
5564
7ab1745f
GM
5565/* Log error message with format string FORMAT and argument ARG.
5566 Signaling an error, e.g. when an image cannot be loaded, is not a
5567 good idea because this would interrupt redisplay, and the error
5568 message display would lead to another redisplay. This function
5569 therefore simply displays a message. */
333b20bb
GM
5570
5571static void
5572image_error (format, arg1, arg2)
5573 char *format;
5574 Lisp_Object arg1, arg2;
5575{
7ab1745f 5576 add_to_log (format, arg1, arg2);
333b20bb
GM
5577}
5578
5579
5580\f
5581/***********************************************************************
5582 Image specifications
5583 ***********************************************************************/
5584
5585enum image_value_type
5586{
5587 IMAGE_DONT_CHECK_VALUE_TYPE,
5588 IMAGE_STRING_VALUE,
6f1be3b9 5589 IMAGE_STRING_OR_NIL_VALUE,
333b20bb
GM
5590 IMAGE_SYMBOL_VALUE,
5591 IMAGE_POSITIVE_INTEGER_VALUE,
3ed61e75 5592 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
333b20bb 5593 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7c7ff7f5 5594 IMAGE_ASCENT_VALUE,
333b20bb
GM
5595 IMAGE_INTEGER_VALUE,
5596 IMAGE_FUNCTION_VALUE,
5597 IMAGE_NUMBER_VALUE,
5598 IMAGE_BOOL_VALUE
5599};
5600
5601/* Structure used when parsing image specifications. */
5602
5603struct image_keyword
5604{
5605 /* Name of keyword. */
5606 char *name;
5607
5608 /* The type of value allowed. */
5609 enum image_value_type type;
5610
5611 /* Non-zero means key must be present. */
5612 int mandatory_p;
5613
5614 /* Used to recognize duplicate keywords in a property list. */
5615 int count;
5616
5617 /* The value that was found. */
5618 Lisp_Object value;
5619};
5620
5621
bfd2209f
GM
5622static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
5623 int, Lisp_Object));
333b20bb
GM
5624static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
5625
5626
5627/* Parse image spec SPEC according to KEYWORDS. A valid image spec
5628 has the format (image KEYWORD VALUE ...). One of the keyword/
5629 value pairs must be `:type TYPE'. KEYWORDS is a vector of
5630 image_keywords structures of size NKEYWORDS describing other
bfd2209f 5631 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
333b20bb
GM
5632
5633static int
bfd2209f 5634parse_image_spec (spec, keywords, nkeywords, type)
333b20bb
GM
5635 Lisp_Object spec;
5636 struct image_keyword *keywords;
5637 int nkeywords;
5638 Lisp_Object type;
333b20bb
GM
5639{
5640 int i;
5641 Lisp_Object plist;
5642
5643 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
5644 return 0;
5645
5646 plist = XCDR (spec);
5647 while (CONSP (plist))
5648 {
5649 Lisp_Object key, value;
5650
5651 /* First element of a pair must be a symbol. */
5652 key = XCAR (plist);
5653 plist = XCDR (plist);
5654 if (!SYMBOLP (key))
5655 return 0;
5656
5657 /* There must follow a value. */
5658 if (!CONSP (plist))
5659 return 0;
5660 value = XCAR (plist);
5661 plist = XCDR (plist);
5662
5663 /* Find key in KEYWORDS. Error if not found. */
5664 for (i = 0; i < nkeywords; ++i)
d5db4077 5665 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
333b20bb
GM
5666 break;
5667
5668 if (i == nkeywords)
bfd2209f 5669 continue;
333b20bb
GM
5670
5671 /* Record that we recognized the keyword. If a keywords
5672 was found more than once, it's an error. */
5673 keywords[i].value = value;
5674 ++keywords[i].count;
5675
5676 if (keywords[i].count > 1)
5677 return 0;
5678
5679 /* Check type of value against allowed type. */
5680 switch (keywords[i].type)
5681 {
5682 case IMAGE_STRING_VALUE:
5683 if (!STRINGP (value))
5684 return 0;
5685 break;
5686
6f1be3b9
GM
5687 case IMAGE_STRING_OR_NIL_VALUE:
5688 if (!STRINGP (value) && !NILP (value))
5689 return 0;
5690 break;
5691
333b20bb
GM
5692 case IMAGE_SYMBOL_VALUE:
5693 if (!SYMBOLP (value))
5694 return 0;
5695 break;
5696
5697 case IMAGE_POSITIVE_INTEGER_VALUE:
5698 if (!INTEGERP (value) || XINT (value) <= 0)
5699 return 0;
5700 break;
5701
3ed61e75
GM
5702 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
5703 if (INTEGERP (value) && XINT (value) >= 0)
5704 break;
5705 if (CONSP (value)
5706 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
5707 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
5708 break;
5709 return 0;
5710
7c7ff7f5
GM
5711 case IMAGE_ASCENT_VALUE:
5712 if (SYMBOLP (value) && EQ (value, Qcenter))
5713 break;
5714 else if (INTEGERP (value)
5715 && XINT (value) >= 0
5716 && XINT (value) <= 100)
5717 break;
5718 return 0;
5719
333b20bb
GM
5720 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
5721 if (!INTEGERP (value) || XINT (value) < 0)
5722 return 0;
5723 break;
5724
5725 case IMAGE_DONT_CHECK_VALUE_TYPE:
5726 break;
5727
5728 case IMAGE_FUNCTION_VALUE:
5729 value = indirect_function (value);
5730 if (SUBRP (value)
5731 || COMPILEDP (value)
5732 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
5733 break;
5734 return 0;
5735
5736 case IMAGE_NUMBER_VALUE:
5737 if (!INTEGERP (value) && !FLOATP (value))
5738 return 0;
5739 break;
5740
5741 case IMAGE_INTEGER_VALUE:
5742 if (!INTEGERP (value))
5743 return 0;
5744 break;
5745
5746 case IMAGE_BOOL_VALUE:
5747 if (!NILP (value) && !EQ (value, Qt))
5748 return 0;
5749 break;
5750
5751 default:
5752 abort ();
5753 break;
5754 }
5755
5756 if (EQ (key, QCtype) && !EQ (type, value))
5757 return 0;
5758 }
5759
5760 /* Check that all mandatory fields are present. */
5761 for (i = 0; i < nkeywords; ++i)
5762 if (keywords[i].mandatory_p && keywords[i].count == 0)
5763 return 0;
5764
5765 return NILP (plist);
5766}
5767
5768
5769/* Return the value of KEY in image specification SPEC. Value is nil
5770 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
5771 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
5772
5773static Lisp_Object
5774image_spec_value (spec, key, found)
5775 Lisp_Object spec, key;
5776 int *found;
5777{
5778 Lisp_Object tail;
5779
5780 xassert (valid_image_p (spec));
5781
5782 for (tail = XCDR (spec);
5783 CONSP (tail) && CONSP (XCDR (tail));
5784 tail = XCDR (XCDR (tail)))
5785 {
5786 if (EQ (XCAR (tail), key))
5787 {
5788 if (found)
5789 *found = 1;
5790 return XCAR (XCDR (tail));
5791 }
5792 }
5793
5794 if (found)
5795 *found = 0;
5796 return Qnil;
5797}
5798
5799
42677916 5800DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
7ee72033 5801 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
c061c855
GM
5802PIXELS non-nil means return the size in pixels, otherwise return the
5803size in canonical character units.
5804FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5805or omitted means use the selected frame. */)
5806 (spec, pixels, frame)
42677916
GM
5807 Lisp_Object spec, pixels, frame;
5808{
5809 Lisp_Object size;
5810
5811 size = Qnil;
5812 if (valid_image_p (spec))
5813 {
5814 struct frame *f = check_x_frame (frame);
83676598 5815 int id = lookup_image (f, spec);
42677916 5816 struct image *img = IMAGE_FROM_ID (f, id);
3ed61e75
GM
5817 int width = img->width + 2 * img->hmargin;
5818 int height = img->height + 2 * img->vmargin;
42677916
GM
5819
5820 if (NILP (pixels))
5821 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
5822 make_float ((double) height / CANON_Y_UNIT (f)));
5823 else
5824 size = Fcons (make_number (width), make_number (height));
5825 }
5826 else
5827 error ("Invalid image specification");
5828
5829 return size;
5830}
5831
333b20bb 5832
b243755a 5833DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
7ee72033 5834 doc: /* Return t if image SPEC has a mask bitmap.
c061c855 5835FRAME is the frame on which the image will be displayed. FRAME nil
7ee72033
MB
5836or omitted means use the selected frame. */)
5837 (spec, frame)
b243755a
GM
5838 Lisp_Object spec, frame;
5839{
5840 Lisp_Object mask;
5841
5842 mask = Qnil;
5843 if (valid_image_p (spec))
5844 {
5845 struct frame *f = check_x_frame (frame);
83676598 5846 int id = lookup_image (f, spec);
b243755a
GM
5847 struct image *img = IMAGE_FROM_ID (f, id);
5848 if (img->mask)
5849 mask = Qt;
5850 }
5851 else
5852 error ("Invalid image specification");
5853
5854 return mask;
5855}
5856
5857
333b20bb
GM
5858\f
5859/***********************************************************************
5860 Image type independent image structures
5861 ***********************************************************************/
5862
5863static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
5864static void free_image P_ ((struct frame *f, struct image *img));
5865
5866
5867/* Allocate and return a new image structure for image specification
5868 SPEC. SPEC has a hash value of HASH. */
5869
5870static struct image *
5871make_image (spec, hash)
5872 Lisp_Object spec;
5873 unsigned hash;
5874{
5875 struct image *img = (struct image *) xmalloc (sizeof *img);
5876
5877 xassert (valid_image_p (spec));
5878 bzero (img, sizeof *img);
5879 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
5880 xassert (img->type != NULL);
5881 img->spec = spec;
5882 img->data.lisp_val = Qnil;
5883 img->ascent = DEFAULT_IMAGE_ASCENT;
5884 img->hash = hash;
5885 return img;
5886}
5887
5888
5889/* Free image IMG which was used on frame F, including its resources. */
5890
5891static void
5892free_image (f, img)
5893 struct frame *f;
5894 struct image *img;
5895{
5896 if (img)
5897 {
5898 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5899
5900 /* Remove IMG from the hash table of its cache. */
5901 if (img->prev)
5902 img->prev->next = img->next;
5903 else
5904 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
5905
5906 if (img->next)
5907 img->next->prev = img->prev;
5908
5909 c->images[img->id] = NULL;
5910
5911 /* Free resources, then free IMG. */
5912 img->type->free (f, img);
5913 xfree (img);
5914 }
5915}
5916
5917
5918/* Prepare image IMG for display on frame F. Must be called before
5919 drawing an image. */
5920
5921void
5922prepare_image_for_display (f, img)
5923 struct frame *f;
5924 struct image *img;
5925{
5926 EMACS_TIME t;
5927
5928 /* We're about to display IMG, so set its timestamp to `now'. */
5929 EMACS_GET_TIME (t);
5930 img->timestamp = EMACS_SECS (t);
5931
5932 /* If IMG doesn't have a pixmap yet, load it now, using the image
5933 type dependent loader function. */
dd00328a 5934 if (img->pixmap == None && !img->load_failed_p)
209061be 5935 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
5936}
5937
5938
7c7ff7f5
GM
5939/* Value is the number of pixels for the ascent of image IMG when
5940 drawn in face FACE. */
5941
5942int
5943image_ascent (img, face)
5944 struct image *img;
5945 struct face *face;
5946{
3ed61e75 5947 int height = img->height + img->vmargin;
7c7ff7f5
GM
5948 int ascent;
5949
5950 if (img->ascent == CENTERED_IMAGE_ASCENT)
5951 {
5952 if (face->font)
3694cb3f
MB
5953 /* This expression is arranged so that if the image can't be
5954 exactly centered, it will be moved slightly up. This is
5955 because a typical font is `top-heavy' (due to the presence
5956 uppercase letters), so the image placement should err towards
5957 being top-heavy too. It also just generally looks better. */
5958 ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
7c7ff7f5
GM
5959 else
5960 ascent = height / 2;
5961 }
5962 else
5963 ascent = height * img->ascent / 100.0;
5964
5965 return ascent;
5966}
5967
f20a3b7a
MB
5968\f
5969/* Image background colors. */
5970
5971static unsigned long
5972four_corners_best (ximg, width, height)
5973 XImage *ximg;
5974 unsigned long width, height;
5975{
b350c2e5
GM
5976 unsigned long corners[4], best;
5977 int i, best_count;
f20a3b7a 5978
b350c2e5
GM
5979 /* Get the colors at the corners of ximg. */
5980 corners[0] = XGetPixel (ximg, 0, 0);
5981 corners[1] = XGetPixel (ximg, width - 1, 0);
5982 corners[2] = XGetPixel (ximg, width - 1, height - 1);
5983 corners[3] = XGetPixel (ximg, 0, height - 1);
f20a3b7a 5984
b350c2e5
GM
5985 /* Choose the most frequently found color as background. */
5986 for (i = best_count = 0; i < 4; ++i)
5987 {
5988 int j, n;
f20a3b7a 5989
b350c2e5
GM
5990 for (j = n = 0; j < 4; ++j)
5991 if (corners[i] == corners[j])
5992 ++n;
f20a3b7a 5993
b350c2e5
GM
5994 if (n > best_count)
5995 best = corners[i], best_count = n;
5996 }
f20a3b7a 5997
b350c2e5 5998 return best;
f20a3b7a
MB
5999}
6000
6001/* Return the `background' field of IMG. If IMG doesn't have one yet,
6002 it is guessed heuristically. If non-zero, XIMG is an existing XImage
6003 object to use for the heuristic. */
6004
6005unsigned long
6006image_background (img, f, ximg)
6007 struct image *img;
6008 struct frame *f;
6009 XImage *ximg;
6010{
6011 if (! img->background_valid)
6012 /* IMG doesn't have a background yet, try to guess a reasonable value. */
6013 {
6014 int free_ximg = !ximg;
6015
6016 if (! ximg)
6017 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
6018 0, 0, img->width, img->height, ~0, ZPixmap);
6019
6020 img->background = four_corners_best (ximg, img->width, img->height);
6021
6022 if (free_ximg)
6023 XDestroyImage (ximg);
6024
6025 img->background_valid = 1;
6026 }
6027
6028 return img->background;
6029}
6030
6031/* Return the `background_transparent' field of IMG. If IMG doesn't
6032 have one yet, it is guessed heuristically. If non-zero, MASK is an
6033 existing XImage object to use for the heuristic. */
6034
6035int
6036image_background_transparent (img, f, mask)
6037 struct image *img;
6038 struct frame *f;
6039 XImage *mask;
6040{
6041 if (! img->background_transparent_valid)
6042 /* IMG doesn't have a background yet, try to guess a reasonable value. */
6043 {
6044 if (img->mask)
6045 {
6046 int free_mask = !mask;
6047
6048 if (! mask)
6049 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
6050 0, 0, img->width, img->height, ~0, ZPixmap);
6051
6052 img->background_transparent
6053 = !four_corners_best (mask, img->width, img->height);
6054
6055 if (free_mask)
6056 XDestroyImage (mask);
6057 }
6058 else
6059 img->background_transparent = 0;
6060
6061 img->background_transparent_valid = 1;
6062 }
6063
6064 return img->background_transparent;
6065}
7c7ff7f5 6066
333b20bb
GM
6067\f
6068/***********************************************************************
6069 Helper functions for X image types
6070 ***********************************************************************/
6071
dd00328a
GM
6072static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
6073 int, int));
333b20bb
GM
6074static void x_clear_image P_ ((struct frame *f, struct image *img));
6075static unsigned long x_alloc_image_color P_ ((struct frame *f,
6076 struct image *img,
6077 Lisp_Object color_name,
6078 unsigned long dflt));
6079
dd00328a
GM
6080
6081/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
6082 free the pixmap if any. MASK_P non-zero means clear the mask
6083 pixmap if any. COLORS_P non-zero means free colors allocated for
6084 the image, if any. */
333b20bb
GM
6085
6086static void
dd00328a 6087x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
333b20bb
GM
6088 struct frame *f;
6089 struct image *img;
dd00328a 6090 int pixmap_p, mask_p, colors_p;
333b20bb 6091{
dd00328a 6092 if (pixmap_p && img->pixmap)
333b20bb 6093 {
333b20bb 6094 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 6095 img->pixmap = None;
f20a3b7a 6096 img->background_valid = 0;
f4779de9
GM
6097 }
6098
dd00328a 6099 if (mask_p && img->mask)
f4779de9
GM
6100 {
6101 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 6102 img->mask = None;
f20a3b7a 6103 img->background_transparent_valid = 0;
333b20bb
GM
6104 }
6105
dd00328a 6106 if (colors_p && img->ncolors)
333b20bb 6107 {
462d5d40 6108 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
6109 xfree (img->colors);
6110 img->colors = NULL;
6111 img->ncolors = 0;
6112 }
dd00328a
GM
6113}
6114
6115/* Free X resources of image IMG which is used on frame F. */
6116
6117static void
6118x_clear_image (f, img)
6119 struct frame *f;
6120 struct image *img;
6121{
6122 BLOCK_INPUT;
6123 x_clear_image_1 (f, img, 1, 1, 1);
f4779de9 6124 UNBLOCK_INPUT;
333b20bb
GM
6125}
6126
6127
6128/* Allocate color COLOR_NAME for image IMG on frame F. If color
6129 cannot be allocated, use DFLT. Add a newly allocated color to
6130 IMG->colors, so that it can be freed again. Value is the pixel
6131 color. */
6132
6133static unsigned long
6134x_alloc_image_color (f, img, color_name, dflt)
6135 struct frame *f;
6136 struct image *img;
6137 Lisp_Object color_name;
6138 unsigned long dflt;
6139{
6140 XColor color;
6141 unsigned long result;
6142
6143 xassert (STRINGP (color_name));
6144
d5db4077 6145 if (x_defined_color (f, SDATA (color_name), &color, 1))
333b20bb
GM
6146 {
6147 /* This isn't called frequently so we get away with simply
6148 reallocating the color vector to the needed size, here. */
6149 ++img->ncolors;
6150 img->colors =
6151 (unsigned long *) xrealloc (img->colors,
6152 img->ncolors * sizeof *img->colors);
6153 img->colors[img->ncolors - 1] = color.pixel;
6154 result = color.pixel;
6155 }
6156 else
6157 result = dflt;
6158
6159 return result;
6160}
6161
6162
6163\f
6164/***********************************************************************
6165 Image Cache
6166 ***********************************************************************/
6167
6168static void cache_image P_ ((struct frame *f, struct image *img));
ad18ffb1 6169static void postprocess_image P_ ((struct frame *, struct image *));
333b20bb
GM
6170
6171
6172/* Return a new, initialized image cache that is allocated from the
6173 heap. Call free_image_cache to free an image cache. */
6174
6175struct image_cache *
6176make_image_cache ()
6177{
6178 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
6179 int size;
6180
6181 bzero (c, sizeof *c);
6182 c->size = 50;
6183 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
6184 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
6185 c->buckets = (struct image **) xmalloc (size);
6186 bzero (c->buckets, size);
6187 return c;
6188}
6189
6190
6191/* Free image cache of frame F. Be aware that X frames share images
6192 caches. */
6193
6194void
6195free_image_cache (f)
6196 struct frame *f;
6197{
6198 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6199 if (c)
6200 {
6201 int i;
6202
6203 /* Cache should not be referenced by any frame when freed. */
6204 xassert (c->refcount == 0);
6205
6206 for (i = 0; i < c->used; ++i)
6207 free_image (f, c->images[i]);
6208 xfree (c->images);
333b20bb 6209 xfree (c->buckets);
e3130015 6210 xfree (c);
333b20bb
GM
6211 FRAME_X_IMAGE_CACHE (f) = NULL;
6212 }
6213}
6214
6215
6216/* Clear image cache of frame F. FORCE_P non-zero means free all
6217 images. FORCE_P zero means clear only images that haven't been
6218 displayed for some time. Should be called from time to time to
6219 reduce the number of loaded images. If image-eviction-seconds is
6220 non-nil, this frees images in the cache which weren't displayed for
6221 at least that many seconds. */
6222
6223void
6224clear_image_cache (f, force_p)
6225 struct frame *f;
6226 int force_p;
6227{
6228 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6229
83676598 6230 if (c && INTEGERP (Vimage_cache_eviction_delay))
333b20bb
GM
6231 {
6232 EMACS_TIME t;
6233 unsigned long old;
f4779de9 6234 int i, nfreed;
333b20bb
GM
6235
6236 EMACS_GET_TIME (t);
fcf431dc 6237 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
f4779de9
GM
6238
6239 /* Block input so that we won't be interrupted by a SIGIO
6240 while being in an inconsistent state. */
6241 BLOCK_INPUT;
333b20bb 6242
f4779de9 6243 for (i = nfreed = 0; i < c->used; ++i)
333b20bb
GM
6244 {
6245 struct image *img = c->images[i];
6246 if (img != NULL
f4779de9 6247 && (force_p || img->timestamp < old))
333b20bb
GM
6248 {
6249 free_image (f, img);
f4779de9 6250 ++nfreed;
333b20bb
GM
6251 }
6252 }
6253
6254 /* We may be clearing the image cache because, for example,
6255 Emacs was iconified for a longer period of time. In that
6256 case, current matrices may still contain references to
6257 images freed above. So, clear these matrices. */
f4779de9 6258 if (nfreed)
333b20bb 6259 {
f4779de9
GM
6260 Lisp_Object tail, frame;
6261
6262 FOR_EACH_FRAME (tail, frame)
6263 {
6264 struct frame *f = XFRAME (frame);
6265 if (FRAME_X_P (f)
6266 && FRAME_X_IMAGE_CACHE (f) == c)
83676598 6267 clear_current_matrices (f);
f4779de9
GM
6268 }
6269
333b20bb
GM
6270 ++windows_or_buffers_changed;
6271 }
f4779de9
GM
6272
6273 UNBLOCK_INPUT;
333b20bb
GM
6274 }
6275}
6276
6277
6278DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6279 0, 1, 0,
7ee72033 6280 doc: /* Clear the image cache of FRAME.
c061c855 6281FRAME nil or omitted means use the selected frame.
7ee72033
MB
6282FRAME t means clear the image caches of all frames. */)
6283 (frame)
333b20bb
GM
6284 Lisp_Object frame;
6285{
6286 if (EQ (frame, Qt))
6287 {
6288 Lisp_Object tail;
6289
6290 FOR_EACH_FRAME (tail, frame)
6291 if (FRAME_X_P (XFRAME (frame)))
6292 clear_image_cache (XFRAME (frame), 1);
6293 }
6294 else
6295 clear_image_cache (check_x_frame (frame), 1);
6296
6297 return Qnil;
6298}
6299
6300
ad18ffb1
GM
6301/* Compute masks and transform image IMG on frame F, as specified
6302 by the image's specification, */
6303
6304static void
6305postprocess_image (f, img)
6306 struct frame *f;
6307 struct image *img;
6308{
6309 /* Manipulation of the image's mask. */
6310 if (img->pixmap)
6311 {
6312 Lisp_Object conversion, spec;
6313 Lisp_Object mask;
6314
6315 spec = img->spec;
6316
6317 /* `:heuristic-mask t'
6318 `:mask heuristic'
6319 means build a mask heuristically.
6320 `:heuristic-mask (R G B)'
6321 `:mask (heuristic (R G B))'
6322 means build a mask from color (R G B) in the
6323 image.
6324 `:mask nil'
6325 means remove a mask, if any. */
6326
6327 mask = image_spec_value (spec, QCheuristic_mask, NULL);
6328 if (!NILP (mask))
6329 x_build_heuristic_mask (f, img, mask);
6330 else
6331 {
6332 int found_p;
6333
6334 mask = image_spec_value (spec, QCmask, &found_p);
6335
6336 if (EQ (mask, Qheuristic))
6337 x_build_heuristic_mask (f, img, Qt);
6338 else if (CONSP (mask)
6339 && EQ (XCAR (mask), Qheuristic))
6340 {
6341 if (CONSP (XCDR (mask)))
6342 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
6343 else
6344 x_build_heuristic_mask (f, img, XCDR (mask));
6345 }
6346 else if (NILP (mask) && found_p && img->mask)
6347 {
6348 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
6349 img->mask = None;
6350 }
6351 }
6352
6353
6354 /* Should we apply an image transformation algorithm? */
6355 conversion = image_spec_value (spec, QCconversion, NULL);
6356 if (EQ (conversion, Qdisabled))
6357 x_disable_image (f, img);
6358 else if (EQ (conversion, Qlaplace))
6359 x_laplace (f, img);
6360 else if (EQ (conversion, Qemboss))
6361 x_emboss (f, img);
6362 else if (CONSP (conversion)
6363 && EQ (XCAR (conversion), Qedge_detection))
6364 {
6365 Lisp_Object tem;
6366 tem = XCDR (conversion);
6367 if (CONSP (tem))
6368 x_edge_detection (f, img,
6369 Fplist_get (tem, QCmatrix),
6370 Fplist_get (tem, QCcolor_adjustment));
6371 }
6372 }
6373}
6374
6375
333b20bb 6376/* Return the id of image with Lisp specification SPEC on frame F.
83676598 6377 SPEC must be a valid Lisp image specification (see valid_image_p). */
333b20bb
GM
6378
6379int
83676598 6380lookup_image (f, spec)
333b20bb
GM
6381 struct frame *f;
6382 Lisp_Object spec;
6383{
6384 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6385 struct image *img;
6386 int i;
6387 unsigned hash;
6388 struct gcpro gcpro1;
4f7ca1f1 6389 EMACS_TIME now;
333b20bb
GM
6390
6391 /* F must be a window-system frame, and SPEC must be a valid image
6392 specification. */
6393 xassert (FRAME_WINDOW_P (f));
6394 xassert (valid_image_p (spec));
6395
6396 GCPRO1 (spec);
6397
6398 /* Look up SPEC in the hash table of the image cache. */
6399 hash = sxhash (spec, 0);
6400 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6401
6402 for (img = c->buckets[i]; img; img = img->next)
6403 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6404 break;
6405
6406 /* If not found, create a new image and cache it. */
6407 if (img == NULL)
6408 {
ad18ffb1
GM
6409 extern Lisp_Object Qpostscript;
6410
28c7826c 6411 BLOCK_INPUT;
333b20bb
GM
6412 img = make_image (spec, hash);
6413 cache_image (f, img);
83676598 6414 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
6415
6416 /* If we can't load the image, and we don't have a width and
6417 height, use some arbitrary width and height so that we can
6418 draw a rectangle for it. */
83676598 6419 if (img->load_failed_p)
333b20bb
GM
6420 {
6421 Lisp_Object value;
6422
6423 value = image_spec_value (spec, QCwidth, NULL);
6424 img->width = (INTEGERP (value)
6425 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6426 value = image_spec_value (spec, QCheight, NULL);
6427 img->height = (INTEGERP (value)
6428 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6429 }
6430 else
6431 {
6432 /* Handle image type independent image attributes
f20a3b7a
MB
6433 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
6434 `:background COLOR'. */
6435 Lisp_Object ascent, margin, relief, bg;
333b20bb
GM
6436
6437 ascent = image_spec_value (spec, QCascent, NULL);
6438 if (INTEGERP (ascent))
6439 img->ascent = XFASTINT (ascent);
7c7ff7f5
GM
6440 else if (EQ (ascent, Qcenter))
6441 img->ascent = CENTERED_IMAGE_ASCENT;
333b20bb
GM
6442
6443 margin = image_spec_value (spec, QCmargin, NULL);
6444 if (INTEGERP (margin) && XINT (margin) >= 0)
3ed61e75
GM
6445 img->vmargin = img->hmargin = XFASTINT (margin);
6446 else if (CONSP (margin) && INTEGERP (XCAR (margin))
6447 && INTEGERP (XCDR (margin)))
6448 {
6449 if (XINT (XCAR (margin)) > 0)
6450 img->hmargin = XFASTINT (XCAR (margin));
6451 if (XINT (XCDR (margin)) > 0)
6452 img->vmargin = XFASTINT (XCDR (margin));
6453 }
333b20bb
GM
6454
6455 relief = image_spec_value (spec, QCrelief, NULL);
6456 if (INTEGERP (relief))
6457 {
6458 img->relief = XINT (relief);
3ed61e75
GM
6459 img->hmargin += abs (img->relief);
6460 img->vmargin += abs (img->relief);
333b20bb
GM
6461 }
6462
f20a3b7a
MB
6463 if (! img->background_valid)
6464 {
6465 bg = image_spec_value (img->spec, QCbackground, NULL);
6466 if (!NILP (bg))
6467 {
6468 img->background
6469 = x_alloc_image_color (f, img, bg,
6470 FRAME_BACKGROUND_PIXEL (f));
6471 img->background_valid = 1;
6472 }
6473 }
6474
ad18ffb1
GM
6475 /* Do image transformations and compute masks, unless we
6476 don't have the image yet. */
6477 if (!EQ (*img->type->type, Qpostscript))
6478 postprocess_image (f, img);
333b20bb 6479 }
dd00328a 6480
28c7826c
GM
6481 UNBLOCK_INPUT;
6482 xassert (!interrupt_input_blocked);
333b20bb
GM
6483 }
6484
4f7ca1f1
GM
6485 /* We're using IMG, so set its timestamp to `now'. */
6486 EMACS_GET_TIME (now);
6487 img->timestamp = EMACS_SECS (now);
6488
333b20bb
GM
6489 UNGCPRO;
6490
6491 /* Value is the image id. */
6492 return img->id;
6493}
6494
6495
6496/* Cache image IMG in the image cache of frame F. */
6497
6498static void
6499cache_image (f, img)
6500 struct frame *f;
6501 struct image *img;
6502{
6503 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6504 int i;
6505
6506 /* Find a free slot in c->images. */
6507 for (i = 0; i < c->used; ++i)
6508 if (c->images[i] == NULL)
6509 break;
6510
6511 /* If no free slot found, maybe enlarge c->images. */
6512 if (i == c->used && c->used == c->size)
6513 {
6514 c->size *= 2;
6515 c->images = (struct image **) xrealloc (c->images,
6516 c->size * sizeof *c->images);
6517 }
6518
6519 /* Add IMG to c->images, and assign IMG an id. */
6520 c->images[i] = img;
6521 img->id = i;
6522 if (i == c->used)
6523 ++c->used;
6524
6525 /* Add IMG to the cache's hash table. */
6526 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6527 img->next = c->buckets[i];
6528 if (img->next)
6529 img->next->prev = img;
6530 img->prev = NULL;
6531 c->buckets[i] = img;
6532}
6533
6534
6535/* Call FN on every image in the image cache of frame F. Used to mark
6536 Lisp Objects in the image cache. */
6537
6538void
6539forall_images_in_image_cache (f, fn)
6540 struct frame *f;
6541 void (*fn) P_ ((struct image *img));
6542{
6543 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6544 {
6545 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6546 if (c)
6547 {
6548 int i;
6549 for (i = 0; i < c->used; ++i)
6550 if (c->images[i])
6551 fn (c->images[i]);
6552 }
6553 }
6554}
6555
6556
6557\f
6558/***********************************************************************
6559 X support code
6560 ***********************************************************************/
6561
45158a91
GM
6562static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
6563 XImage **, Pixmap *));
333b20bb
GM
6564static void x_destroy_x_image P_ ((XImage *));
6565static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6566
6567
6568/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6569 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6570 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6571 via xmalloc. Print error messages via image_error if an error
45158a91 6572 occurs. Value is non-zero if successful. */
333b20bb
GM
6573
6574static int
45158a91 6575x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
333b20bb 6576 struct frame *f;
333b20bb
GM
6577 int width, height, depth;
6578 XImage **ximg;
6579 Pixmap *pixmap;
6580{
6581 Display *display = FRAME_X_DISPLAY (f);
6582 Screen *screen = FRAME_X_SCREEN (f);
6583 Window window = FRAME_X_WINDOW (f);
6584
6585 xassert (interrupt_input_blocked);
6586
6587 if (depth <= 0)
6588 depth = DefaultDepthOfScreen (screen);
6589 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6590 depth, ZPixmap, 0, NULL, width, height,
6591 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6592 if (*ximg == NULL)
6593 {
45158a91 6594 image_error ("Unable to allocate X image", Qnil, Qnil);
333b20bb
GM
6595 return 0;
6596 }
6597
6598 /* Allocate image raster. */
6599 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6600
6601 /* Allocate a pixmap of the same size. */
6602 *pixmap = XCreatePixmap (display, window, width, height, depth);
dd00328a 6603 if (*pixmap == None)
333b20bb
GM
6604 {
6605 x_destroy_x_image (*ximg);
6606 *ximg = NULL;
45158a91 6607 image_error ("Unable to create X pixmap", Qnil, Qnil);
333b20bb
GM
6608 return 0;
6609 }
6610
6611 return 1;
6612}
6613
6614
6615/* Destroy XImage XIMG. Free XIMG->data. */
6616
6617static void
6618x_destroy_x_image (ximg)
6619 XImage *ximg;
6620{
6621 xassert (interrupt_input_blocked);
6622 if (ximg)
6623 {
6624 xfree (ximg->data);
6625 ximg->data = NULL;
6626 XDestroyImage (ximg);
6627 }
6628}
6629
6630
6631/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6632 are width and height of both the image and pixmap. */
6633
ea6b19ca 6634static void
333b20bb
GM
6635x_put_x_image (f, ximg, pixmap, width, height)
6636 struct frame *f;
6637 XImage *ximg;
6638 Pixmap pixmap;
6639{
6640 GC gc;
6641
6642 xassert (interrupt_input_blocked);
6643 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6644 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6645 XFreeGC (FRAME_X_DISPLAY (f), gc);
6646}
6647
6648
6649\f
6650/***********************************************************************
5be6c3b0 6651 File Handling
333b20bb
GM
6652 ***********************************************************************/
6653
6654static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5be6c3b0
GM
6655static char *slurp_file P_ ((char *, int *));
6656
333b20bb
GM
6657
6658/* Find image file FILE. Look in data-directory, then
6659 x-bitmap-file-path. Value is the full name of the file found, or
6660 nil if not found. */
6661
6662static Lisp_Object
6663x_find_image_file (file)
6664 Lisp_Object file;
6665{
6666 Lisp_Object file_found, search_path;
6667 struct gcpro gcpro1, gcpro2;
6668 int fd;
6669
6670 file_found = Qnil;
6671 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6672 GCPRO2 (file_found, search_path);
6673
6674 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 6675 fd = openp (search_path, file, Qnil, &file_found, Qnil);
333b20bb 6676
939d6465 6677 if (fd == -1)
333b20bb
GM
6678 file_found = Qnil;
6679 else
6680 close (fd);
6681
6682 UNGCPRO;
6683 return file_found;
6684}
6685
6686
5be6c3b0
GM
6687/* Read FILE into memory. Value is a pointer to a buffer allocated
6688 with xmalloc holding FILE's contents. Value is null if an error
b243755a 6689 occurred. *SIZE is set to the size of the file. */
5be6c3b0
GM
6690
6691static char *
6692slurp_file (file, size)
6693 char *file;
6694 int *size;
6695{
6696 FILE *fp = NULL;
6697 char *buf = NULL;
6698 struct stat st;
6699
6700 if (stat (file, &st) == 0
6701 && (fp = fopen (file, "r")) != NULL
6702 && (buf = (char *) xmalloc (st.st_size),
6703 fread (buf, 1, st.st_size, fp) == st.st_size))
6704 {
6705 *size = st.st_size;
6706 fclose (fp);
6707 }
6708 else
6709 {
6710 if (fp)
6711 fclose (fp);
6712 if (buf)
6713 {
6714 xfree (buf);
6715 buf = NULL;
6716 }
6717 }
6718
6719 return buf;
6720}
6721
6722
333b20bb
GM
6723\f
6724/***********************************************************************
6725 XBM images
6726 ***********************************************************************/
6727
5be6c3b0 6728static int xbm_scan P_ ((char **, char *, char *, int *));
333b20bb 6729static int xbm_load P_ ((struct frame *f, struct image *img));
5be6c3b0
GM
6730static int xbm_load_image P_ ((struct frame *f, struct image *img,
6731 char *, char *));
333b20bb 6732static int xbm_image_p P_ ((Lisp_Object object));
5be6c3b0
GM
6733static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
6734 unsigned char **));
6735static int xbm_file_p P_ ((Lisp_Object));
333b20bb
GM
6736
6737
6738/* Indices of image specification fields in xbm_format, below. */
6739
6740enum xbm_keyword_index
6741{
6742 XBM_TYPE,
6743 XBM_FILE,
6744 XBM_WIDTH,
6745 XBM_HEIGHT,
6746 XBM_DATA,
6747 XBM_FOREGROUND,
6748 XBM_BACKGROUND,
6749 XBM_ASCENT,
6750 XBM_MARGIN,
6751 XBM_RELIEF,
6752 XBM_ALGORITHM,
6753 XBM_HEURISTIC_MASK,
4a8e312c 6754 XBM_MASK,
333b20bb
GM
6755 XBM_LAST
6756};
6757
6758/* Vector of image_keyword structures describing the format
6759 of valid XBM image specifications. */
6760
6761static struct image_keyword xbm_format[XBM_LAST] =
6762{
6763 {":type", IMAGE_SYMBOL_VALUE, 1},
6764 {":file", IMAGE_STRING_VALUE, 0},
6765 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6766 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6767 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
6768 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
6769 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
7c7ff7f5 6770 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 6771 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 6772 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 6773 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c
GM
6774 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6775 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
333b20bb
GM
6776};
6777
6778/* Structure describing the image type XBM. */
6779
6780static struct image_type xbm_type =
6781{
6782 &Qxbm,
6783 xbm_image_p,
6784 xbm_load,
6785 x_clear_image,
6786 NULL
6787};
6788
6789/* Tokens returned from xbm_scan. */
6790
6791enum xbm_token
6792{
6793 XBM_TK_IDENT = 256,
6794 XBM_TK_NUMBER
6795};
6796
6797
6798/* Return non-zero if OBJECT is a valid XBM-type image specification.
6799 A valid specification is a list starting with the symbol `image'
6800 The rest of the list is a property list which must contain an
6801 entry `:type xbm..
6802
6803 If the specification specifies a file to load, it must contain
6804 an entry `:file FILENAME' where FILENAME is a string.
6805
6806 If the specification is for a bitmap loaded from memory it must
6807 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6808 WIDTH and HEIGHT are integers > 0. DATA may be:
6809
6810 1. a string large enough to hold the bitmap data, i.e. it must
6811 have a size >= (WIDTH + 7) / 8 * HEIGHT
6812
6813 2. a bool-vector of size >= WIDTH * HEIGHT
6814
6815 3. a vector of strings or bool-vectors, one for each line of the
6816 bitmap.
6817
5be6c3b0
GM
6818 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
6819 may not be specified in this case because they are defined in the
6820 XBM file.
6821
333b20bb
GM
6822 Both the file and data forms may contain the additional entries
6823 `:background COLOR' and `:foreground COLOR'. If not present,
6824 foreground and background of the frame on which the image is
e3130015 6825 displayed is used. */
333b20bb
GM
6826
6827static int
6828xbm_image_p (object)
6829 Lisp_Object object;
6830{
6831 struct image_keyword kw[XBM_LAST];
6832
6833 bcopy (xbm_format, kw, sizeof kw);
bfd2209f 6834 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
333b20bb
GM
6835 return 0;
6836
6837 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6838
6839 if (kw[XBM_FILE].count)
6840 {
6841 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6842 return 0;
6843 }
5be6c3b0
GM
6844 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
6845 {
6846 /* In-memory XBM file. */
6847 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
6848 return 0;
6849 }
333b20bb
GM
6850 else
6851 {
6852 Lisp_Object data;
6853 int width, height;
6854
6855 /* Entries for `:width', `:height' and `:data' must be present. */
6856 if (!kw[XBM_WIDTH].count
6857 || !kw[XBM_HEIGHT].count
6858 || !kw[XBM_DATA].count)
6859 return 0;
6860
6861 data = kw[XBM_DATA].value;
6862 width = XFASTINT (kw[XBM_WIDTH].value);
6863 height = XFASTINT (kw[XBM_HEIGHT].value);
6864
6865 /* Check type of data, and width and height against contents of
6866 data. */
6867 if (VECTORP (data))
6868 {
6869 int i;
6870
6871 /* Number of elements of the vector must be >= height. */
6872 if (XVECTOR (data)->size < height)
6873 return 0;
6874
6875 /* Each string or bool-vector in data must be large enough
6876 for one line of the image. */
6877 for (i = 0; i < height; ++i)
6878 {
6879 Lisp_Object elt = XVECTOR (data)->contents[i];
6880
6881 if (STRINGP (elt))
6882 {
d5db4077 6883 if (SCHARS (elt)
333b20bb
GM
6884 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6885 return 0;
6886 }
6887 else if (BOOL_VECTOR_P (elt))
6888 {
6889 if (XBOOL_VECTOR (elt)->size < width)
6890 return 0;
6891 }
6892 else
6893 return 0;
6894 }
6895 }
6896 else if (STRINGP (data))
6897 {
d5db4077 6898 if (SCHARS (data)
333b20bb
GM
6899 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6900 return 0;
6901 }
6902 else if (BOOL_VECTOR_P (data))
6903 {
6904 if (XBOOL_VECTOR (data)->size < width * height)
6905 return 0;
6906 }
6907 else
6908 return 0;
6909 }
6910
333b20bb
GM
6911 return 1;
6912}
6913
6914
6915/* Scan a bitmap file. FP is the stream to read from. Value is
6916 either an enumerator from enum xbm_token, or a character for a
6917 single-character token, or 0 at end of file. If scanning an
6918 identifier, store the lexeme of the identifier in SVAL. If
6919 scanning a number, store its value in *IVAL. */
6920
6921static int
5be6c3b0
GM
6922xbm_scan (s, end, sval, ival)
6923 char **s, *end;
333b20bb
GM
6924 char *sval;
6925 int *ival;
6926{
6927 int c;
0a695da7
GM
6928
6929 loop:
333b20bb
GM
6930
6931 /* Skip white space. */
5be6c3b0 6932 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
6933 ;
6934
5be6c3b0 6935 if (*s >= end)
333b20bb
GM
6936 c = 0;
6937 else if (isdigit (c))
6938 {
6939 int value = 0, digit;
6940
5be6c3b0 6941 if (c == '0' && *s < end)
333b20bb 6942 {
5be6c3b0 6943 c = *(*s)++;
333b20bb
GM
6944 if (c == 'x' || c == 'X')
6945 {
5be6c3b0 6946 while (*s < end)
333b20bb 6947 {
5be6c3b0 6948 c = *(*s)++;
333b20bb
GM
6949 if (isdigit (c))
6950 digit = c - '0';
6951 else if (c >= 'a' && c <= 'f')
6952 digit = c - 'a' + 10;
6953 else if (c >= 'A' && c <= 'F')
6954 digit = c - 'A' + 10;
6955 else
6956 break;
6957 value = 16 * value + digit;
6958 }
6959 }
6960 else if (isdigit (c))
6961 {
6962 value = c - '0';
5be6c3b0
GM
6963 while (*s < end
6964 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6965 value = 8 * value + c - '0';
6966 }
6967 }
6968 else
6969 {
6970 value = c - '0';
5be6c3b0
GM
6971 while (*s < end
6972 && (c = *(*s)++, isdigit (c)))
333b20bb
GM
6973 value = 10 * value + c - '0';
6974 }
6975
5be6c3b0
GM
6976 if (*s < end)
6977 *s = *s - 1;
333b20bb
GM
6978 *ival = value;
6979 c = XBM_TK_NUMBER;
6980 }
6981 else if (isalpha (c) || c == '_')
6982 {
6983 *sval++ = c;
5be6c3b0
GM
6984 while (*s < end
6985 && (c = *(*s)++, (isalnum (c) || c == '_')))
333b20bb
GM
6986 *sval++ = c;
6987 *sval = 0;
5be6c3b0
GM
6988 if (*s < end)
6989 *s = *s - 1;
333b20bb
GM
6990 c = XBM_TK_IDENT;
6991 }
0a695da7
GM
6992 else if (c == '/' && **s == '*')
6993 {
6994 /* C-style comment. */
6995 ++*s;
6996 while (**s && (**s != '*' || *(*s + 1) != '/'))
6997 ++*s;
6998 if (**s)
6999 {
7000 *s += 2;
7001 goto loop;
7002 }
7003 }
333b20bb
GM
7004
7005 return c;
7006}
7007
7008
7009/* Replacement for XReadBitmapFileData which isn't available under old
5be6c3b0
GM
7010 X versions. CONTENTS is a pointer to a buffer to parse; END is the
7011 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
7012 the image. Return in *DATA the bitmap data allocated with xmalloc.
7013 Value is non-zero if successful. DATA null means just test if
b243755a 7014 CONTENTS looks like an in-memory XBM file. */
333b20bb
GM
7015
7016static int
5be6c3b0
GM
7017xbm_read_bitmap_data (contents, end, width, height, data)
7018 char *contents, *end;
333b20bb
GM
7019 int *width, *height;
7020 unsigned char **data;
7021{
5be6c3b0 7022 char *s = contents;
333b20bb
GM
7023 char buffer[BUFSIZ];
7024 int padding_p = 0;
7025 int v10 = 0;
7026 int bytes_per_line, i, nbytes;
7027 unsigned char *p;
7028 int value;
7029 int LA1;
7030
7031#define match() \
5be6c3b0 7032 LA1 = xbm_scan (&s, end, buffer, &value)
333b20bb
GM
7033
7034#define expect(TOKEN) \
7035 if (LA1 != (TOKEN)) \
7036 goto failure; \
7037 else \
7038 match ()
7039
7040#define expect_ident(IDENT) \
7041 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
7042 match (); \
7043 else \
7044 goto failure
7045
333b20bb 7046 *width = *height = -1;
5be6c3b0
GM
7047 if (data)
7048 *data = NULL;
7049 LA1 = xbm_scan (&s, end, buffer, &value);
333b20bb
GM
7050
7051 /* Parse defines for width, height and hot-spots. */
7052 while (LA1 == '#')
7053 {
333b20bb
GM
7054 match ();
7055 expect_ident ("define");
7056 expect (XBM_TK_IDENT);
7057
7058 if (LA1 == XBM_TK_NUMBER);
7059 {
7060 char *p = strrchr (buffer, '_');
7061 p = p ? p + 1 : buffer;
7062 if (strcmp (p, "width") == 0)
7063 *width = value;
7064 else if (strcmp (p, "height") == 0)
7065 *height = value;
7066 }
7067 expect (XBM_TK_NUMBER);
7068 }
7069
7070 if (*width < 0 || *height < 0)
7071 goto failure;
5be6c3b0
GM
7072 else if (data == NULL)
7073 goto success;
333b20bb
GM
7074
7075 /* Parse bits. Must start with `static'. */
7076 expect_ident ("static");
7077 if (LA1 == XBM_TK_IDENT)
7078 {
7079 if (strcmp (buffer, "unsigned") == 0)
7080 {
7081 match ();
7082 expect_ident ("char");
7083 }
7084 else if (strcmp (buffer, "short") == 0)
7085 {
7086 match ();
7087 v10 = 1;
7088 if (*width % 16 && *width % 16 < 9)
7089 padding_p = 1;
7090 }
7091 else if (strcmp (buffer, "char") == 0)
7092 match ();
7093 else
7094 goto failure;
7095 }
7096 else
7097 goto failure;
7098
7099 expect (XBM_TK_IDENT);
7100 expect ('[');
7101 expect (']');
7102 expect ('=');
7103 expect ('{');
7104
7105 bytes_per_line = (*width + 7) / 8 + padding_p;
7106 nbytes = bytes_per_line * *height;
7107 p = *data = (char *) xmalloc (nbytes);
7108
7109 if (v10)
7110 {
333b20bb
GM
7111 for (i = 0; i < nbytes; i += 2)
7112 {
7113 int val = value;
7114 expect (XBM_TK_NUMBER);
7115
7116 *p++ = val;
7117 if (!padding_p || ((i + 2) % bytes_per_line))
7118 *p++ = value >> 8;
7119
7120 if (LA1 == ',' || LA1 == '}')
7121 match ();
7122 else
7123 goto failure;
7124 }
7125 }
7126 else
7127 {
7128 for (i = 0; i < nbytes; ++i)
7129 {
7130 int val = value;
7131 expect (XBM_TK_NUMBER);
7132
7133 *p++ = val;
7134
7135 if (LA1 == ',' || LA1 == '}')
7136 match ();
7137 else
7138 goto failure;
7139 }
7140 }
7141
5be6c3b0 7142 success:
333b20bb
GM
7143 return 1;
7144
7145 failure:
7146
5be6c3b0 7147 if (data && *data)
333b20bb
GM
7148 {
7149 xfree (*data);
7150 *data = NULL;
7151 }
7152 return 0;
7153
7154#undef match
7155#undef expect
7156#undef expect_ident
7157}
7158
7159
5be6c3b0
GM
7160/* Load XBM image IMG which will be displayed on frame F from buffer
7161 CONTENTS. END is the end of the buffer. Value is non-zero if
7162 successful. */
333b20bb
GM
7163
7164static int
5be6c3b0 7165xbm_load_image (f, img, contents, end)
333b20bb
GM
7166 struct frame *f;
7167 struct image *img;
5be6c3b0 7168 char *contents, *end;
333b20bb
GM
7169{
7170 int rc;
7171 unsigned char *data;
7172 int success_p = 0;
333b20bb 7173
5be6c3b0 7174 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
333b20bb
GM
7175 if (rc)
7176 {
7177 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7178 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7179 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7180 Lisp_Object value;
7181
7182 xassert (img->width > 0 && img->height > 0);
7183
7184 /* Get foreground and background colors, maybe allocate colors. */
7185 value = image_spec_value (img->spec, QCforeground, NULL);
7186 if (!NILP (value))
7187 foreground = x_alloc_image_color (f, img, value, foreground);
333b20bb
GM
7188 value = image_spec_value (img->spec, QCbackground, NULL);
7189 if (!NILP (value))
f20a3b7a
MB
7190 {
7191 background = x_alloc_image_color (f, img, value, background);
7192 img->background = background;
7193 img->background_valid = 1;
7194 }
333b20bb 7195
333b20bb
GM
7196 img->pixmap
7197 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7198 FRAME_X_WINDOW (f),
7199 data,
7200 img->width, img->height,
7201 foreground, background,
7202 depth);
7203 xfree (data);
7204
dd00328a 7205 if (img->pixmap == None)
333b20bb
GM
7206 {
7207 x_clear_image (f, img);
5be6c3b0 7208 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
7209 }
7210 else
7211 success_p = 1;
333b20bb
GM
7212 }
7213 else
45158a91 7214 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
333b20bb 7215
333b20bb
GM
7216 return success_p;
7217}
7218
7219
5be6c3b0
GM
7220/* Value is non-zero if DATA looks like an in-memory XBM file. */
7221
7222static int
7223xbm_file_p (data)
7224 Lisp_Object data;
7225{
7226 int w, h;
7227 return (STRINGP (data)
d5db4077
KR
7228 && xbm_read_bitmap_data (SDATA (data),
7229 (SDATA (data)
7230 + SBYTES (data)),
5be6c3b0
GM
7231 &w, &h, NULL));
7232}
7233
7234
333b20bb
GM
7235/* Fill image IMG which is used on frame F with pixmap data. Value is
7236 non-zero if successful. */
7237
7238static int
7239xbm_load (f, img)
7240 struct frame *f;
7241 struct image *img;
7242{
7243 int success_p = 0;
7244 Lisp_Object file_name;
7245
7246 xassert (xbm_image_p (img->spec));
7247
7248 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7249 file_name = image_spec_value (img->spec, QCfile, NULL);
7250 if (STRINGP (file_name))
5be6c3b0
GM
7251 {
7252 Lisp_Object file;
7253 char *contents;
7254 int size;
7255 struct gcpro gcpro1;
7256
7257 file = x_find_image_file (file_name);
7258 GCPRO1 (file);
7259 if (!STRINGP (file))
7260 {
7261 image_error ("Cannot find image file `%s'", file_name, Qnil);
7262 UNGCPRO;
7263 return 0;
7264 }
7265
d5db4077 7266 contents = slurp_file (SDATA (file), &size);
5be6c3b0
GM
7267 if (contents == NULL)
7268 {
7269 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
7270 UNGCPRO;
7271 return 0;
7272 }
7273
7274 success_p = xbm_load_image (f, img, contents, contents + size);
7275 UNGCPRO;
7276 }
333b20bb
GM
7277 else
7278 {
7279 struct image_keyword fmt[XBM_LAST];
7280 Lisp_Object data;
7281 int depth;
7282 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7283 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7284 char *bits;
9b207e8e 7285 int parsed_p;
5be6c3b0
GM
7286 int in_memory_file_p = 0;
7287
7288 /* See if data looks like an in-memory XBM file. */
7289 data = image_spec_value (img->spec, QCdata, NULL);
7290 in_memory_file_p = xbm_file_p (data);
333b20bb 7291
5be6c3b0 7292 /* Parse the image specification. */
333b20bb 7293 bcopy (xbm_format, fmt, sizeof fmt);
bfd2209f 7294 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
333b20bb
GM
7295 xassert (parsed_p);
7296
7297 /* Get specified width, and height. */
5be6c3b0
GM
7298 if (!in_memory_file_p)
7299 {
7300 img->width = XFASTINT (fmt[XBM_WIDTH].value);
7301 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
7302 xassert (img->width > 0 && img->height > 0);
7303 }
333b20bb 7304
333b20bb 7305 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
7306 if (fmt[XBM_FOREGROUND].count
7307 && STRINGP (fmt[XBM_FOREGROUND].value))
333b20bb
GM
7308 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
7309 foreground);
6f1be3b9
GM
7310 if (fmt[XBM_BACKGROUND].count
7311 && STRINGP (fmt[XBM_BACKGROUND].value))
333b20bb
GM
7312 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
7313 background);
7314
5be6c3b0 7315 if (in_memory_file_p)
d5db4077
KR
7316 success_p = xbm_load_image (f, img, SDATA (data),
7317 (SDATA (data)
7318 + SBYTES (data)));
5be6c3b0 7319 else
333b20bb 7320 {
5be6c3b0
GM
7321 if (VECTORP (data))
7322 {
7323 int i;
7324 char *p;
7325 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
333b20bb 7326
5be6c3b0
GM
7327 p = bits = (char *) alloca (nbytes * img->height);
7328 for (i = 0; i < img->height; ++i, p += nbytes)
7329 {
7330 Lisp_Object line = XVECTOR (data)->contents[i];
7331 if (STRINGP (line))
d5db4077 7332 bcopy (SDATA (line), p, nbytes);
5be6c3b0
GM
7333 else
7334 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
7335 }
7336 }
7337 else if (STRINGP (data))
d5db4077 7338 bits = SDATA (data);
5be6c3b0
GM
7339 else
7340 bits = XBOOL_VECTOR (data)->data;
7341
7342 /* Create the pixmap. */
7343 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7344 img->pixmap
7345 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7346 FRAME_X_WINDOW (f),
7347 bits,
7348 img->width, img->height,
7349 foreground, background,
7350 depth);
7351 if (img->pixmap)
7352 success_p = 1;
7353 else
333b20bb 7354 {
5be6c3b0
GM
7355 image_error ("Unable to create pixmap for XBM image `%s'",
7356 img->spec, Qnil);
7357 x_clear_image (f, img);
333b20bb
GM
7358 }
7359 }
333b20bb
GM
7360 }
7361
7362 return success_p;
7363}
7364
7365
7366\f
7367/***********************************************************************
7368 XPM images
7369 ***********************************************************************/
7370
7371#if HAVE_XPM
7372
7373static int xpm_image_p P_ ((Lisp_Object object));
7374static int xpm_load P_ ((struct frame *f, struct image *img));
7375static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
7376
7377#include "X11/xpm.h"
7378
7379/* The symbol `xpm' identifying XPM-format images. */
7380
7381Lisp_Object Qxpm;
7382
7383/* Indices of image specification fields in xpm_format, below. */
7384
7385enum xpm_keyword_index
7386{
7387 XPM_TYPE,
7388 XPM_FILE,
7389 XPM_DATA,
7390 XPM_ASCENT,
7391 XPM_MARGIN,
7392 XPM_RELIEF,
7393 XPM_ALGORITHM,
7394 XPM_HEURISTIC_MASK,
4a8e312c 7395 XPM_MASK,
333b20bb 7396 XPM_COLOR_SYMBOLS,
f20a3b7a 7397 XPM_BACKGROUND,
333b20bb
GM
7398 XPM_LAST
7399};
7400
7401/* Vector of image_keyword structures describing the format
7402 of valid XPM image specifications. */
7403
7404static struct image_keyword xpm_format[XPM_LAST] =
7405{
7406 {":type", IMAGE_SYMBOL_VALUE, 1},
7407 {":file", IMAGE_STRING_VALUE, 0},
7408 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 7409 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 7410 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 7411 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 7412 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 7413 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 7414 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
7415 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7416 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
7417};
7418
7419/* Structure describing the image type XBM. */
7420
7421static struct image_type xpm_type =
7422{
7423 &Qxpm,
7424 xpm_image_p,
7425 xpm_load,
7426 x_clear_image,
7427 NULL
7428};
7429
7430
b243755a
GM
7431/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
7432 functions for allocating image colors. Our own functions handle
7433 color allocation failures more gracefully than the ones on the XPM
7434 lib. */
7435
7436#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
7437#define ALLOC_XPM_COLORS
7438#endif
7439
7440#ifdef ALLOC_XPM_COLORS
7441
f72c62ad 7442static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
b243755a
GM
7443static void xpm_free_color_cache P_ ((void));
7444static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
f72c62ad
GM
7445static int xpm_color_bucket P_ ((char *));
7446static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
7447 XColor *, int));
b243755a
GM
7448
7449/* An entry in a hash table used to cache color definitions of named
7450 colors. This cache is necessary to speed up XPM image loading in
7451 case we do color allocations ourselves. Without it, we would need
7452 a call to XParseColor per pixel in the image. */
7453
7454struct xpm_cached_color
7455{
7456 /* Next in collision chain. */
7457 struct xpm_cached_color *next;
7458
7459 /* Color definition (RGB and pixel color). */
7460 XColor color;
7461
7462 /* Color name. */
7463 char name[1];
7464};
7465
7466/* The hash table used for the color cache, and its bucket vector
7467 size. */
7468
7469#define XPM_COLOR_CACHE_BUCKETS 1001
7470struct xpm_cached_color **xpm_color_cache;
7471
b243755a
GM
7472/* Initialize the color cache. */
7473
7474static void
f72c62ad
GM
7475xpm_init_color_cache (f, attrs)
7476 struct frame *f;
7477 XpmAttributes *attrs;
b243755a
GM
7478{
7479 size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
7480 xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
7481 memset (xpm_color_cache, 0, nbytes);
7482 init_color_table ();
f72c62ad
GM
7483
7484 if (attrs->valuemask & XpmColorSymbols)
7485 {
7486 int i;
7487 XColor color;
7488
7489 for (i = 0; i < attrs->numsymbols; ++i)
7490 if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7491 attrs->colorsymbols[i].value, &color))
7492 {
7493 color.pixel = lookup_rgb_color (f, color.red, color.green,
7494 color.blue);
7495 xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
7496 }
7497 }
b243755a
GM
7498}
7499
7500
7501/* Free the color cache. */
7502
7503static void
7504xpm_free_color_cache ()
7505{
7506 struct xpm_cached_color *p, *next;
7507 int i;
7508
7509 for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
7510 for (p = xpm_color_cache[i]; p; p = next)
7511 {
7512 next = p->next;
7513 xfree (p);
7514 }
7515
7516 xfree (xpm_color_cache);
7517 xpm_color_cache = NULL;
7518 free_color_table ();
7519}
7520
7521
f72c62ad
GM
7522/* Return the bucket index for color named COLOR_NAME in the color
7523 cache. */
7524
7525static int
7526xpm_color_bucket (color_name)
7527 char *color_name;
7528{
7529 unsigned h = 0;
7530 char *s;
7531
7532 for (s = color_name; *s; ++s)
7533 h = (h << 2) ^ *s;
7534 return h %= XPM_COLOR_CACHE_BUCKETS;
7535}
7536
7537
7538/* On frame F, cache values COLOR for color with name COLOR_NAME.
7539 BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
7540 entry added. */
7541
7542static struct xpm_cached_color *
7543xpm_cache_color (f, color_name, color, bucket)
7544 struct frame *f;
7545 char *color_name;
7546 XColor *color;
7547 int bucket;
7548{
7549 size_t nbytes;
7550 struct xpm_cached_color *p;
7551
7552 if (bucket < 0)
7553 bucket = xpm_color_bucket (color_name);
7554
7555 nbytes = sizeof *p + strlen (color_name);
7556 p = (struct xpm_cached_color *) xmalloc (nbytes);
7557 strcpy (p->name, color_name);
7558 p->color = *color;
7559 p->next = xpm_color_cache[bucket];
7560 xpm_color_cache[bucket] = p;
7561 return p;
7562}
7563
7564
b243755a
GM
7565/* Look up color COLOR_NAME for frame F in the color cache. If found,
7566 return the cached definition in *COLOR. Otherwise, make a new
7567 entry in the cache and allocate the color. Value is zero if color
7568 allocation failed. */
7569
7570static int
7571xpm_lookup_color (f, color_name, color)
7572 struct frame *f;
7573 char *color_name;
7574 XColor *color;
7575{
b243755a 7576 struct xpm_cached_color *p;
83676598 7577 int h = xpm_color_bucket (color_name);
b243755a
GM
7578
7579 for (p = xpm_color_cache[h]; p; p = p->next)
7580 if (strcmp (p->name, color_name) == 0)
7581 break;
7582
7583 if (p != NULL)
7584 *color = p->color;
7585 else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
7586 color_name, color))
7587 {
b243755a
GM
7588 color->pixel = lookup_rgb_color (f, color->red, color->green,
7589 color->blue);
f72c62ad 7590 p = xpm_cache_color (f, color_name, color, h);
b243755a 7591 }
f72c62ad 7592
b243755a
GM
7593 return p != NULL;
7594}
7595
7596
7597/* Callback for allocating color COLOR_NAME. Called from the XPM lib.
7598 CLOSURE is a pointer to the frame on which we allocate the
7599 color. Return in *COLOR the allocated color. Value is non-zero
7600 if successful. */
7601
7602static int
7603xpm_alloc_color (dpy, cmap, color_name, color, closure)
7604 Display *dpy;
7605 Colormap cmap;
7606 char *color_name;
7607 XColor *color;
7608 void *closure;
7609{
7610 return xpm_lookup_color ((struct frame *) closure, color_name, color);
7611}
7612
7613
7614/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE
7615 is a pointer to the frame on which we allocate the color. Value is
7616 non-zero if successful. */
7617
7618static int
7619xpm_free_colors (dpy, cmap, pixels, npixels, closure)
7620 Display *dpy;
7621 Colormap cmap;
7622 Pixel *pixels;
7623 int npixels;
7624 void *closure;
7625{
7626 return 1;
7627}
7628
7629#endif /* ALLOC_XPM_COLORS */
7630
7631
333b20bb
GM
7632/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7633 for XPM images. Such a list must consist of conses whose car and
7634 cdr are strings. */
7635
7636static int
7637xpm_valid_color_symbols_p (color_symbols)
7638 Lisp_Object color_symbols;
7639{
7640 while (CONSP (color_symbols))
7641 {
7642 Lisp_Object sym = XCAR (color_symbols);
7643 if (!CONSP (sym)
7644 || !STRINGP (XCAR (sym))
7645 || !STRINGP (XCDR (sym)))
7646 break;
7647 color_symbols = XCDR (color_symbols);
7648 }
7649
7650 return NILP (color_symbols);
7651}
7652
7653
7654/* Value is non-zero if OBJECT is a valid XPM image specification. */
7655
7656static int
7657xpm_image_p (object)
7658 Lisp_Object object;
7659{
7660 struct image_keyword fmt[XPM_LAST];
7661 bcopy (xpm_format, fmt, sizeof fmt);
bfd2209f 7662 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
333b20bb
GM
7663 /* Either `:file' or `:data' must be present. */
7664 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7665 /* Either no `:color-symbols' or it's a list of conses
7666 whose car and cdr are strings. */
7667 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7c7ff7f5 7668 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
333b20bb
GM
7669}
7670
7671
7672/* Load image IMG which will be displayed on frame F. Value is
7673 non-zero if successful. */
7674
7675static int
7676xpm_load (f, img)
7677 struct frame *f;
7678 struct image *img;
7679{
9b207e8e 7680 int rc;
333b20bb
GM
7681 XpmAttributes attrs;
7682 Lisp_Object specified_file, color_symbols;
7683
7684 /* Configure the XPM lib. Use the visual of frame F. Allocate
7685 close colors. Return colors allocated. */
7686 bzero (&attrs, sizeof attrs);
9b2956e2
GM
7687 attrs.visual = FRAME_X_VISUAL (f);
7688 attrs.colormap = FRAME_X_COLORMAP (f);
333b20bb 7689 attrs.valuemask |= XpmVisual;
9b2956e2 7690 attrs.valuemask |= XpmColormap;
b243755a
GM
7691
7692#ifdef ALLOC_XPM_COLORS
7693 /* Allocate colors with our own functions which handle
7694 failing color allocation more gracefully. */
7695 attrs.color_closure = f;
7696 attrs.alloc_color = xpm_alloc_color;
7697 attrs.free_colors = xpm_free_colors;
7698 attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
7699#else /* not ALLOC_XPM_COLORS */
7700 /* Let the XPM lib allocate colors. */
333b20bb 7701 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 7702#ifdef XpmAllocCloseColors
333b20bb
GM
7703 attrs.alloc_close_colors = 1;
7704 attrs.valuemask |= XpmAllocCloseColors;
b243755a 7705#else /* not XpmAllocCloseColors */
e4c082be
RS
7706 attrs.closeness = 600;
7707 attrs.valuemask |= XpmCloseness;
b243755a
GM
7708#endif /* not XpmAllocCloseColors */
7709#endif /* ALLOC_XPM_COLORS */
333b20bb
GM
7710
7711 /* If image specification contains symbolic color definitions, add
7712 these to `attrs'. */
7713 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7714 if (CONSP (color_symbols))
7715 {
7716 Lisp_Object tail;
7717 XpmColorSymbol *xpm_syms;
7718 int i, size;
7719
7720 attrs.valuemask |= XpmColorSymbols;
7721
7722 /* Count number of symbols. */
7723 attrs.numsymbols = 0;
7724 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7725 ++attrs.numsymbols;
7726
7727 /* Allocate an XpmColorSymbol array. */
7728 size = attrs.numsymbols * sizeof *xpm_syms;
7729 xpm_syms = (XpmColorSymbol *) alloca (size);
7730 bzero (xpm_syms, size);
7731 attrs.colorsymbols = xpm_syms;
7732
7733 /* Fill the color symbol array. */
7734 for (tail = color_symbols, i = 0;
7735 CONSP (tail);
7736 ++i, tail = XCDR (tail))
7737 {
7738 Lisp_Object name = XCAR (XCAR (tail));
7739 Lisp_Object color = XCDR (XCAR (tail));
d5db4077
KR
7740 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
7741 strcpy (xpm_syms[i].name, SDATA (name));
7742 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
7743 strcpy (xpm_syms[i].value, SDATA (color));
333b20bb
GM
7744 }
7745 }
7746
7747 /* Create a pixmap for the image, either from a file, or from a
7748 string buffer containing data in the same format as an XPM file. */
b243755a 7749#ifdef ALLOC_XPM_COLORS
f72c62ad 7750 xpm_init_color_cache (f, &attrs);
b243755a
GM
7751#endif
7752
333b20bb
GM
7753 specified_file = image_spec_value (img->spec, QCfile, NULL);
7754 if (STRINGP (specified_file))
7755 {
7756 Lisp_Object file = x_find_image_file (specified_file);
7757 if (!STRINGP (file))
7758 {
45158a91 7759 image_error ("Cannot find image file `%s'", specified_file, Qnil);
333b20bb
GM
7760 return 0;
7761 }
7762
7763 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 7764 SDATA (file), &img->pixmap, &img->mask,
333b20bb
GM
7765 &attrs);
7766 }
7767 else
7768 {
7769 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7770 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
d5db4077 7771 SDATA (buffer),
333b20bb
GM
7772 &img->pixmap, &img->mask,
7773 &attrs);
7774 }
333b20bb
GM
7775
7776 if (rc == XpmSuccess)
7777 {
b243755a
GM
7778#ifdef ALLOC_XPM_COLORS
7779 img->colors = colors_in_color_table (&img->ncolors);
7780#else /* not ALLOC_XPM_COLORS */
f47a9ec4
KR
7781 int i;
7782
333b20bb
GM
7783 img->ncolors = attrs.nalloc_pixels;
7784 img->colors = (unsigned long *) xmalloc (img->ncolors
7785 * sizeof *img->colors);
7786 for (i = 0; i < attrs.nalloc_pixels; ++i)
3b4ae1cc
GM
7787 {
7788 img->colors[i] = attrs.alloc_pixels[i];
7789#ifdef DEBUG_X_COLORS
7790 register_color (img->colors[i]);
7791#endif
7792 }
b243755a 7793#endif /* not ALLOC_XPM_COLORS */
333b20bb
GM
7794
7795 img->width = attrs.width;
7796 img->height = attrs.height;
7797 xassert (img->width > 0 && img->height > 0);
7798
7799 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
333b20bb 7800 XpmFreeAttributes (&attrs);
333b20bb
GM
7801 }
7802 else
7803 {
7804 switch (rc)
7805 {
7806 case XpmOpenFailed:
7807 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7808 break;
7809
7810 case XpmFileInvalid:
7811 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7812 break;
7813
7814 case XpmNoMemory:
7815 image_error ("Out of memory (%s)", img->spec, Qnil);
7816 break;
7817
7818 case XpmColorFailed:
7819 image_error ("Color allocation error (%s)", img->spec, Qnil);
7820 break;
7821
7822 default:
7823 image_error ("Unknown error (%s)", img->spec, Qnil);
7824 break;
7825 }
7826 }
7827
b243755a
GM
7828#ifdef ALLOC_XPM_COLORS
7829 xpm_free_color_cache ();
7830#endif
333b20bb
GM
7831 return rc == XpmSuccess;
7832}
7833
7834#endif /* HAVE_XPM != 0 */
7835
7836\f
7837/***********************************************************************
7838 Color table
7839 ***********************************************************************/
7840
7841/* An entry in the color table mapping an RGB color to a pixel color. */
7842
7843struct ct_color
7844{
7845 int r, g, b;
7846 unsigned long pixel;
7847
7848 /* Next in color table collision list. */
7849 struct ct_color *next;
7850};
7851
7852/* The bucket vector size to use. Must be prime. */
7853
7854#define CT_SIZE 101
7855
7856/* Value is a hash of the RGB color given by R, G, and B. */
7857
7858#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7859
7860/* The color hash table. */
7861
7862struct ct_color **ct_table;
7863
7864/* Number of entries in the color table. */
7865
7866int ct_colors_allocated;
7867
333b20bb
GM
7868/* Initialize the color table. */
7869
7870static void
7871init_color_table ()
7872{
7873 int size = CT_SIZE * sizeof (*ct_table);
7874 ct_table = (struct ct_color **) xmalloc (size);
7875 bzero (ct_table, size);
7876 ct_colors_allocated = 0;
7877}
7878
7879
7880/* Free memory associated with the color table. */
7881
7882static void
7883free_color_table ()
7884{
7885 int i;
7886 struct ct_color *p, *next;
7887
7888 for (i = 0; i < CT_SIZE; ++i)
7889 for (p = ct_table[i]; p; p = next)
7890 {
7891 next = p->next;
7892 xfree (p);
7893 }
7894
7895 xfree (ct_table);
7896 ct_table = NULL;
7897}
7898
7899
7900/* Value is a pixel color for RGB color R, G, B on frame F. If an
7901 entry for that color already is in the color table, return the
7902 pixel color of that entry. Otherwise, allocate a new color for R,
7903 G, B, and make an entry in the color table. */
7904
7905static unsigned long
7906lookup_rgb_color (f, r, g, b)
7907 struct frame *f;
7908 int r, g, b;
7909{
7910 unsigned hash = CT_HASH_RGB (r, g, b);
7911 int i = hash % CT_SIZE;
7912 struct ct_color *p;
7913
7914 for (p = ct_table[i]; p; p = p->next)
7915 if (p->r == r && p->g == g && p->b == b)
7916 break;
7917
7918 if (p == NULL)
7919 {
7920 XColor color;
7921 Colormap cmap;
7922 int rc;
7923
7924 color.red = r;
7925 color.green = g;
7926 color.blue = b;
7927
9b2956e2 7928 cmap = FRAME_X_COLORMAP (f);
d62c8769 7929 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7930
7931 if (rc)
7932 {
7933 ++ct_colors_allocated;
7934
7935 p = (struct ct_color *) xmalloc (sizeof *p);
7936 p->r = r;
7937 p->g = g;
7938 p->b = b;
7939 p->pixel = color.pixel;
7940 p->next = ct_table[i];
7941 ct_table[i] = p;
7942 }
7943 else
7944 return FRAME_FOREGROUND_PIXEL (f);
7945 }
7946
7947 return p->pixel;
7948}
7949
7950
7951/* Look up pixel color PIXEL which is used on frame F in the color
7952 table. If not already present, allocate it. Value is PIXEL. */
7953
7954static unsigned long
7955lookup_pixel_color (f, pixel)
7956 struct frame *f;
7957 unsigned long pixel;
7958{
7959 int i = pixel % CT_SIZE;
7960 struct ct_color *p;
7961
7962 for (p = ct_table[i]; p; p = p->next)
7963 if (p->pixel == pixel)
7964 break;
7965
7966 if (p == NULL)
7967 {
7968 XColor color;
7969 Colormap cmap;
7970 int rc;
7971
9b2956e2 7972 cmap = FRAME_X_COLORMAP (f);
333b20bb 7973 color.pixel = pixel;
a31fedb7 7974 x_query_color (f, &color);
d62c8769 7975 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7976
7977 if (rc)
7978 {
7979 ++ct_colors_allocated;
7980
7981 p = (struct ct_color *) xmalloc (sizeof *p);
7982 p->r = color.red;
7983 p->g = color.green;
7984 p->b = color.blue;
7985 p->pixel = pixel;
7986 p->next = ct_table[i];
7987 ct_table[i] = p;
7988 }
7989 else
7990 return FRAME_FOREGROUND_PIXEL (f);
7991 }
7992
7993 return p->pixel;
7994}
7995
7996
7997/* Value is a vector of all pixel colors contained in the color table,
7998 allocated via xmalloc. Set *N to the number of colors. */
7999
8000static unsigned long *
8001colors_in_color_table (n)
8002 int *n;
8003{
8004 int i, j;
8005 struct ct_color *p;
8006 unsigned long *colors;
8007
8008 if (ct_colors_allocated == 0)
8009 {
8010 *n = 0;
8011 colors = NULL;
8012 }
8013 else
8014 {
8015 colors = (unsigned long *) xmalloc (ct_colors_allocated
8016 * sizeof *colors);
8017 *n = ct_colors_allocated;
8018
8019 for (i = j = 0; i < CT_SIZE; ++i)
8020 for (p = ct_table[i]; p; p = p->next)
8021 colors[j++] = p->pixel;
8022 }
8023
8024 return colors;
8025}
8026
8027
8028\f
8029/***********************************************************************
8030 Algorithms
8031 ***********************************************************************/
8032
4a8e312c
GM
8033static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
8034static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
8035static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
8036
d2dc8167 8037/* Non-zero means draw a cross on images having `:conversion
14819cb3
GM
8038 disabled'. */
8039
8040int cross_disabled_images;
8041
4a8e312c
GM
8042/* Edge detection matrices for different edge-detection
8043 strategies. */
8044
8045static int emboss_matrix[9] = {
8046 /* x - 1 x x + 1 */
8047 2, -1, 0, /* y - 1 */
8048 -1, 0, 1, /* y */
8049 0, 1, -2 /* y + 1 */
8050};
333b20bb 8051
4a8e312c
GM
8052static int laplace_matrix[9] = {
8053 /* x - 1 x x + 1 */
8054 1, 0, 0, /* y - 1 */
8055 0, 0, 0, /* y */
8056 0, 0, -1 /* y + 1 */
8057};
333b20bb 8058
14819cb3
GM
8059/* Value is the intensity of the color whose red/green/blue values
8060 are R, G, and B. */
8061
8062#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
8063
333b20bb 8064
4a8e312c
GM
8065/* On frame F, return an array of XColor structures describing image
8066 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
8067 non-zero means also fill the red/green/blue members of the XColor
8068 structures. Value is a pointer to the array of XColors structures,
8069 allocated with xmalloc; it must be freed by the caller. */
8070
8071static XColor *
8072x_to_xcolors (f, img, rgb_p)
333b20bb 8073 struct frame *f;
4a8e312c
GM
8074 struct image *img;
8075 int rgb_p;
333b20bb 8076{
4a8e312c
GM
8077 int x, y;
8078 XColor *colors, *p;
8079 XImage *ximg;
333b20bb 8080
4a8e312c
GM
8081 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
8082
8083 /* Get the X image IMG->pixmap. */
8084 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8085 0, 0, img->width, img->height, ~0, ZPixmap);
333b20bb 8086
4a8e312c
GM
8087 /* Fill the `pixel' members of the XColor array. I wished there
8088 were an easy and portable way to circumvent XGetPixel. */
8089 p = colors;
8090 for (y = 0; y < img->height; ++y)
8091 {
8092 XColor *row = p;
8093
8094 for (x = 0; x < img->width; ++x, ++p)
8095 p->pixel = XGetPixel (ximg, x, y);
8096
8097 if (rgb_p)
a31fedb7 8098 x_query_colors (f, row, img->width);
4a8e312c
GM
8099 }
8100
8101 XDestroyImage (ximg);
4a8e312c 8102 return colors;
333b20bb
GM
8103}
8104
8105
4a8e312c
GM
8106/* Create IMG->pixmap from an array COLORS of XColor structures, whose
8107 RGB members are set. F is the frame on which this all happens.
8108 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
333b20bb
GM
8109
8110static void
4a8e312c 8111x_from_xcolors (f, img, colors)
333b20bb 8112 struct frame *f;
4a8e312c
GM
8113 struct image *img;
8114 XColor *colors;
333b20bb 8115{
4a8e312c
GM
8116 int x, y;
8117 XImage *oimg;
8118 Pixmap pixmap;
8119 XColor *p;
8120
4a8e312c 8121 init_color_table ();
333b20bb 8122
4a8e312c
GM
8123 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
8124 &oimg, &pixmap);
8125 p = colors;
8126 for (y = 0; y < img->height; ++y)
8127 for (x = 0; x < img->width; ++x, ++p)
8128 {
8129 unsigned long pixel;
8130 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
8131 XPutPixel (oimg, x, y, pixel);
8132 }
8133
8134 xfree (colors);
dd00328a 8135 x_clear_image_1 (f, img, 1, 0, 1);
4a8e312c
GM
8136
8137 x_put_x_image (f, oimg, pixmap, img->width, img->height);
8138 x_destroy_x_image (oimg);
8139 img->pixmap = pixmap;
8140 img->colors = colors_in_color_table (&img->ncolors);
8141 free_color_table ();
333b20bb
GM
8142}
8143
8144
4a8e312c
GM
8145/* On frame F, perform edge-detection on image IMG.
8146
8147 MATRIX is a nine-element array specifying the transformation
8148 matrix. See emboss_matrix for an example.
8149
8150 COLOR_ADJUST is a color adjustment added to each pixel of the
8151 outgoing image. */
333b20bb
GM
8152
8153static void
4a8e312c 8154x_detect_edges (f, img, matrix, color_adjust)
333b20bb
GM
8155 struct frame *f;
8156 struct image *img;
4a8e312c 8157 int matrix[9], color_adjust;
333b20bb 8158{
4a8e312c
GM
8159 XColor *colors = x_to_xcolors (f, img, 1);
8160 XColor *new, *p;
8161 int x, y, i, sum;
333b20bb 8162
4a8e312c
GM
8163 for (i = sum = 0; i < 9; ++i)
8164 sum += abs (matrix[i]);
333b20bb 8165
4a8e312c 8166#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
333b20bb 8167
4a8e312c 8168 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
333b20bb 8169
4a8e312c
GM
8170 for (y = 0; y < img->height; ++y)
8171 {
8172 p = COLOR (new, 0, y);
8173 p->red = p->green = p->blue = 0xffff/2;
8174 p = COLOR (new, img->width - 1, y);
8175 p->red = p->green = p->blue = 0xffff/2;
8176 }
8177
8178 for (x = 1; x < img->width - 1; ++x)
8179 {
8180 p = COLOR (new, x, 0);
8181 p->red = p->green = p->blue = 0xffff/2;
8182 p = COLOR (new, x, img->height - 1);
8183 p->red = p->green = p->blue = 0xffff/2;
8184 }
333b20bb 8185
4a8e312c 8186 for (y = 1; y < img->height - 1; ++y)
333b20bb 8187 {
4a8e312c
GM
8188 p = COLOR (new, 1, y);
8189
8190 for (x = 1; x < img->width - 1; ++x, ++p)
8191 {
14819cb3 8192 int r, g, b, y1, x1;
4a8e312c
GM
8193
8194 r = g = b = i = 0;
8195 for (y1 = y - 1; y1 < y + 2; ++y1)
8196 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
8197 if (matrix[i])
8198 {
8199 XColor *t = COLOR (colors, x1, y1);
8200 r += matrix[i] * t->red;
8201 g += matrix[i] * t->green;
8202 b += matrix[i] * t->blue;
8203 }
333b20bb 8204
4a8e312c
GM
8205 r = (r / sum + color_adjust) & 0xffff;
8206 g = (g / sum + color_adjust) & 0xffff;
8207 b = (b / sum + color_adjust) & 0xffff;
14819cb3 8208 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
333b20bb 8209 }
333b20bb
GM
8210 }
8211
4a8e312c
GM
8212 xfree (colors);
8213 x_from_xcolors (f, img, new);
333b20bb 8214
4a8e312c
GM
8215#undef COLOR
8216}
8217
8218
8219/* Perform the pre-defined `emboss' edge-detection on image IMG
8220 on frame F. */
8221
8222static void
8223x_emboss (f, img)
8224 struct frame *f;
8225 struct image *img;
8226{
8227 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
8228}
8229
8230
8231/* Perform the pre-defined `laplace' edge-detection on image IMG
8232 on frame F. */
8233
8234static void
8235x_laplace (f, img)
8236 struct frame *f;
8237 struct image *img;
8238{
8239 x_detect_edges (f, img, laplace_matrix, 45000);
8240}
8241
8242
8243/* Perform edge-detection on image IMG on frame F, with specified
8244 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
8245
8246 MATRIX must be either
8247
8248 - a list of at least 9 numbers in row-major form
8249 - a vector of at least 9 numbers
8250
8251 COLOR_ADJUST nil means use a default; otherwise it must be a
8252 number. */
8253
8254static void
8255x_edge_detection (f, img, matrix, color_adjust)
8256 struct frame *f;
8257 struct image *img;
8258 Lisp_Object matrix, color_adjust;
8259{
8260 int i = 0;
8261 int trans[9];
333b20bb 8262
4a8e312c
GM
8263 if (CONSP (matrix))
8264 {
8265 for (i = 0;
8266 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
8267 ++i, matrix = XCDR (matrix))
8268 trans[i] = XFLOATINT (XCAR (matrix));
8269 }
8270 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
8271 {
8272 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
8273 trans[i] = XFLOATINT (AREF (matrix, i));
8274 }
333b20bb 8275
4a8e312c
GM
8276 if (NILP (color_adjust))
8277 color_adjust = make_number (0xffff / 2);
333b20bb 8278
4a8e312c
GM
8279 if (i == 9 && NUMBERP (color_adjust))
8280 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
333b20bb
GM
8281}
8282
8283
14819cb3
GM
8284/* Transform image IMG on frame F so that it looks disabled. */
8285
8286static void
8287x_disable_image (f, img)
8288 struct frame *f;
8289 struct image *img;
8290{
8291 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
dd00328a 8292
14819cb3
GM
8293 if (dpyinfo->n_planes >= 2)
8294 {
8295 /* Color (or grayscale). Convert to gray, and equalize. Just
8296 drawing such images with a stipple can look very odd, so
8297 we're using this method instead. */
8298 XColor *colors = x_to_xcolors (f, img, 1);
8299 XColor *p, *end;
8300 const int h = 15000;
8301 const int l = 30000;
8302
8303 for (p = colors, end = colors + img->width * img->height;
8304 p < end;
8305 ++p)
8306 {
8307 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
8308 int i2 = (0xffff - h - l) * i / 0xffff + l;
8309 p->red = p->green = p->blue = i2;
8310 }
8311
8312 x_from_xcolors (f, img, colors);
8313 }
8314
8315 /* Draw a cross over the disabled image, if we must or if we
8316 should. */
8317 if (dpyinfo->n_planes < 2 || cross_disabled_images)
8318 {
8319 Display *dpy = FRAME_X_DISPLAY (f);
8320 GC gc;
8321
14819cb3
GM
8322 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
8323 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
8324 XDrawLine (dpy, img->pixmap, gc, 0, 0,
8325 img->width - 1, img->height - 1);
8326 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
8327 img->width - 1, 0);
8328 XFreeGC (dpy, gc);
8329
8330 if (img->mask)
8331 {
8332 gc = XCreateGC (dpy, img->mask, 0, NULL);
8333 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
8334 XDrawLine (dpy, img->mask, gc, 0, 0,
8335 img->width - 1, img->height - 1);
8336 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
8337 img->width - 1, 0);
8338 XFreeGC (dpy, gc);
8339 }
14819cb3
GM
8340 }
8341}
8342
8343
333b20bb
GM
8344/* Build a mask for image IMG which is used on frame F. FILE is the
8345 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
8346 determine the background color of IMG. If it is a list '(R G B)',
8347 with R, G, and B being integers >= 0, take that as the color of the
8348 background. Otherwise, determine the background color of IMG
8349 heuristically. Value is non-zero if successful. */
333b20bb
GM
8350
8351static int
45158a91 8352x_build_heuristic_mask (f, img, how)
333b20bb 8353 struct frame *f;
333b20bb
GM
8354 struct image *img;
8355 Lisp_Object how;
8356{
8357 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 8358 XImage *ximg, *mask_img;
f20a3b7a 8359 int x, y, rc, use_img_background;
8ec8a5ec 8360 unsigned long bg = 0;
333b20bb 8361
4a8e312c
GM
8362 if (img->mask)
8363 {
8364 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
dd00328a 8365 img->mask = None;
f20a3b7a 8366 img->background_transparent_valid = 0;
4a8e312c 8367 }
dd00328a 8368
333b20bb 8369 /* Create an image and pixmap serving as mask. */
45158a91 8370 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
333b20bb
GM
8371 &mask_img, &img->mask);
8372 if (!rc)
28c7826c 8373 return 0;
333b20bb
GM
8374
8375 /* Get the X image of IMG->pixmap. */
8376 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
8377 ~0, ZPixmap);
8378
fcf431dc 8379 /* Determine the background color of ximg. If HOW is `(R G B)'
f20a3b7a
MB
8380 take that as color. Otherwise, use the image's background color. */
8381 use_img_background = 1;
fcf431dc
GM
8382
8383 if (CONSP (how))
8384 {
cac1daf0 8385 int rgb[3], i;
fcf431dc 8386
cac1daf0 8387 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
fcf431dc
GM
8388 {
8389 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
8390 how = XCDR (how);
8391 }
8392
8393 if (i == 3 && NILP (how))
8394 {
8395 char color_name[30];
fcf431dc 8396 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
053b3256
GM
8397 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
8398 use_img_background = 0;
fcf431dc
GM
8399 }
8400 }
8401
f20a3b7a 8402 if (use_img_background)
43f7c3ea 8403 bg = four_corners_best (ximg, img->width, img->height);
333b20bb
GM
8404
8405 /* Set all bits in mask_img to 1 whose color in ximg is different
8406 from the background color bg. */
8407 for (y = 0; y < img->height; ++y)
8408 for (x = 0; x < img->width; ++x)
8409 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
8410
f20a3b7a
MB
8411 /* Fill in the background_transparent field while we have the mask handy. */
8412 image_background_transparent (img, f, mask_img);
8413
333b20bb
GM
8414 /* Put mask_img into img->mask. */
8415 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8416 x_destroy_x_image (mask_img);
8417 XDestroyImage (ximg);
8418
333b20bb
GM
8419 return 1;
8420}
8421
8422
8423\f
8424/***********************************************************************
8425 PBM (mono, gray, color)
8426 ***********************************************************************/
8427
8428static int pbm_image_p P_ ((Lisp_Object object));
8429static int pbm_load P_ ((struct frame *f, struct image *img));
63cec32f 8430static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
333b20bb
GM
8431
8432/* The symbol `pbm' identifying images of this type. */
8433
8434Lisp_Object Qpbm;
8435
8436/* Indices of image specification fields in gs_format, below. */
8437
8438enum pbm_keyword_index
8439{
8440 PBM_TYPE,
8441 PBM_FILE,
63cec32f 8442 PBM_DATA,
333b20bb
GM
8443 PBM_ASCENT,
8444 PBM_MARGIN,
8445 PBM_RELIEF,
8446 PBM_ALGORITHM,
8447 PBM_HEURISTIC_MASK,
4a8e312c 8448 PBM_MASK,
be0b1fac
GM
8449 PBM_FOREGROUND,
8450 PBM_BACKGROUND,
333b20bb
GM
8451 PBM_LAST
8452};
8453
8454/* Vector of image_keyword structures describing the format
8455 of valid user-defined image specifications. */
8456
8457static struct image_keyword pbm_format[PBM_LAST] =
8458{
8459 {":type", IMAGE_SYMBOL_VALUE, 1},
63cec32f
GM
8460 {":file", IMAGE_STRING_VALUE, 0},
8461 {":data", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8462 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8463 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8464 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8465 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8466 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
be0b1fac 8467 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6f1be3b9
GM
8468 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8469 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8470};
8471
8472/* Structure describing the image type `pbm'. */
8473
8474static struct image_type pbm_type =
8475{
8476 &Qpbm,
8477 pbm_image_p,
8478 pbm_load,
8479 x_clear_image,
8480 NULL
8481};
8482
8483
8484/* Return non-zero if OBJECT is a valid PBM image specification. */
8485
8486static int
8487pbm_image_p (object)
8488 Lisp_Object object;
8489{
8490 struct image_keyword fmt[PBM_LAST];
8491
8492 bcopy (pbm_format, fmt, sizeof fmt);
8493
7c7ff7f5 8494 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
333b20bb 8495 return 0;
63cec32f
GM
8496
8497 /* Must specify either :data or :file. */
8498 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
333b20bb
GM
8499}
8500
8501
63cec32f
GM
8502/* Scan a decimal number from *S and return it. Advance *S while
8503 reading the number. END is the end of the string. Value is -1 at
8504 end of input. */
333b20bb
GM
8505
8506static int
63cec32f
GM
8507pbm_scan_number (s, end)
8508 unsigned char **s, *end;
333b20bb 8509{
8ec8a5ec 8510 int c = 0, val = -1;
333b20bb 8511
63cec32f 8512 while (*s < end)
333b20bb
GM
8513 {
8514 /* Skip white-space. */
63cec32f 8515 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
8516 ;
8517
8518 if (c == '#')
8519 {
8520 /* Skip comment to end of line. */
63cec32f 8521 while (*s < end && (c = *(*s)++, c != '\n'))
333b20bb
GM
8522 ;
8523 }
8524 else if (isdigit (c))
8525 {
8526 /* Read decimal number. */
8527 val = c - '0';
63cec32f 8528 while (*s < end && (c = *(*s)++, isdigit (c)))
333b20bb
GM
8529 val = 10 * val + c - '0';
8530 break;
8531 }
8532 else
8533 break;
8534 }
8535
8536 return val;
8537}
8538
8539
8540/* Load PBM image IMG for use on frame F. */
8541
8542static int
8543pbm_load (f, img)
8544 struct frame *f;
8545 struct image *img;
8546{
333b20bb 8547 int raw_p, x, y;
b6d7acec 8548 int width, height, max_color_idx = 0;
333b20bb
GM
8549 XImage *ximg;
8550 Lisp_Object file, specified_file;
8551 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
8552 struct gcpro gcpro1;
63cec32f
GM
8553 unsigned char *contents = NULL;
8554 unsigned char *end, *p;
8555 int size;
333b20bb
GM
8556
8557 specified_file = image_spec_value (img->spec, QCfile, NULL);
63cec32f 8558 file = Qnil;
333b20bb 8559 GCPRO1 (file);
333b20bb 8560
63cec32f 8561 if (STRINGP (specified_file))
333b20bb 8562 {
63cec32f
GM
8563 file = x_find_image_file (specified_file);
8564 if (!STRINGP (file))
8565 {
8566 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8567 UNGCPRO;
8568 return 0;
8569 }
333b20bb 8570
d5db4077 8571 contents = slurp_file (SDATA (file), &size);
63cec32f
GM
8572 if (contents == NULL)
8573 {
8574 image_error ("Error reading `%s'", file, Qnil);
8575 UNGCPRO;
8576 return 0;
8577 }
8578
8579 p = contents;
8580 end = contents + size;
8581 }
8582 else
333b20bb 8583 {
63cec32f
GM
8584 Lisp_Object data;
8585 data = image_spec_value (img->spec, QCdata, NULL);
d5db4077
KR
8586 p = SDATA (data);
8587 end = p + SBYTES (data);
333b20bb
GM
8588 }
8589
63cec32f
GM
8590 /* Check magic number. */
8591 if (end - p < 2 || *p++ != 'P')
333b20bb 8592 {
45158a91 8593 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f
GM
8594 error:
8595 xfree (contents);
333b20bb
GM
8596 UNGCPRO;
8597 return 0;
8598 }
8599
63cec32f 8600 switch (*p++)
333b20bb
GM
8601 {
8602 case '1':
8603 raw_p = 0, type = PBM_MONO;
8604 break;
8605
8606 case '2':
8607 raw_p = 0, type = PBM_GRAY;
8608 break;
8609
8610 case '3':
8611 raw_p = 0, type = PBM_COLOR;
8612 break;
8613
8614 case '4':
8615 raw_p = 1, type = PBM_MONO;
8616 break;
8617
8618 case '5':
8619 raw_p = 1, type = PBM_GRAY;
8620 break;
8621
8622 case '6':
8623 raw_p = 1, type = PBM_COLOR;
8624 break;
8625
8626 default:
45158a91 8627 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f 8628 goto error;
333b20bb
GM
8629 }
8630
8631 /* Read width, height, maximum color-component. Characters
8632 starting with `#' up to the end of a line are ignored. */
63cec32f
GM
8633 width = pbm_scan_number (&p, end);
8634 height = pbm_scan_number (&p, end);
333b20bb
GM
8635
8636 if (type != PBM_MONO)
8637 {
63cec32f 8638 max_color_idx = pbm_scan_number (&p, end);
333b20bb
GM
8639 if (raw_p && max_color_idx > 255)
8640 max_color_idx = 255;
8641 }
8642
63cec32f
GM
8643 if (width < 0
8644 || height < 0
333b20bb 8645 || (type != PBM_MONO && max_color_idx < 0))
63cec32f 8646 goto error;
333b20bb 8647
45158a91 8648 if (!x_create_x_image_and_pixmap (f, width, height, 0,
333b20bb 8649 &ximg, &img->pixmap))
28c7826c 8650 goto error;
333b20bb
GM
8651
8652 /* Initialize the color hash table. */
8653 init_color_table ();
8654
8655 if (type == PBM_MONO)
8656 {
8657 int c = 0, g;
be0b1fac
GM
8658 struct image_keyword fmt[PBM_LAST];
8659 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
8660 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
8661
8662 /* Parse the image specification. */
8663 bcopy (pbm_format, fmt, sizeof fmt);
8664 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
8665
8666 /* Get foreground and background colors, maybe allocate colors. */
6f1be3b9
GM
8667 if (fmt[PBM_FOREGROUND].count
8668 && STRINGP (fmt[PBM_FOREGROUND].value))
be0b1fac 8669 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
6f1be3b9
GM
8670 if (fmt[PBM_BACKGROUND].count
8671 && STRINGP (fmt[PBM_BACKGROUND].value))
f20a3b7a
MB
8672 {
8673 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
8674 img->background = bg;
8675 img->background_valid = 1;
8676 }
333b20bb
GM
8677
8678 for (y = 0; y < height; ++y)
8679 for (x = 0; x < width; ++x)
8680 {
8681 if (raw_p)
8682 {
8683 if ((x & 7) == 0)
63cec32f 8684 c = *p++;
333b20bb
GM
8685 g = c & 0x80;
8686 c <<= 1;
8687 }
8688 else
63cec32f 8689 g = pbm_scan_number (&p, end);
333b20bb 8690
be0b1fac 8691 XPutPixel (ximg, x, y, g ? fg : bg);
333b20bb
GM
8692 }
8693 }
8694 else
8695 {
8696 for (y = 0; y < height; ++y)
8697 for (x = 0; x < width; ++x)
8698 {
8699 int r, g, b;
8700
8701 if (type == PBM_GRAY)
63cec32f 8702 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
333b20bb
GM
8703 else if (raw_p)
8704 {
63cec32f
GM
8705 r = *p++;
8706 g = *p++;
8707 b = *p++;
333b20bb
GM
8708 }
8709 else
8710 {
63cec32f
GM
8711 r = pbm_scan_number (&p, end);
8712 g = pbm_scan_number (&p, end);
8713 b = pbm_scan_number (&p, end);
333b20bb
GM
8714 }
8715
8716 if (r < 0 || g < 0 || b < 0)
8717 {
333b20bb
GM
8718 xfree (ximg->data);
8719 ximg->data = NULL;
8720 XDestroyImage (ximg);
45158a91
GM
8721 image_error ("Invalid pixel value in image `%s'",
8722 img->spec, Qnil);
63cec32f 8723 goto error;
333b20bb
GM
8724 }
8725
8726 /* RGB values are now in the range 0..max_color_idx.
8727 Scale this to the range 0..0xffff supported by X. */
8728 r = (double) r * 65535 / max_color_idx;
8729 g = (double) g * 65535 / max_color_idx;
8730 b = (double) b * 65535 / max_color_idx;
8731 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8732 }
8733 }
8734
333b20bb
GM
8735 /* Store in IMG->colors the colors allocated for the image, and
8736 free the color table. */
8737 img->colors = colors_in_color_table (&img->ncolors);
8738 free_color_table ();
f20a3b7a
MB
8739
8740 /* Maybe fill in the background field while we have ximg handy. */
8741 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
8742 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
8743
8744 /* Put the image into a pixmap. */
8745 x_put_x_image (f, ximg, img->pixmap, width, height);
8746 x_destroy_x_image (ximg);
333b20bb
GM
8747
8748 img->width = width;
8749 img->height = height;
8750
8751 UNGCPRO;
63cec32f 8752 xfree (contents);
333b20bb
GM
8753 return 1;
8754}
8755
8756
8757\f
8758/***********************************************************************
8759 PNG
8760 ***********************************************************************/
8761
8762#if HAVE_PNG
8763
8764#include <png.h>
8765
8766/* Function prototypes. */
8767
8768static int png_image_p P_ ((Lisp_Object object));
8769static int png_load P_ ((struct frame *f, struct image *img));
8770
8771/* The symbol `png' identifying images of this type. */
8772
8773Lisp_Object Qpng;
8774
8775/* Indices of image specification fields in png_format, below. */
8776
8777enum png_keyword_index
8778{
8779 PNG_TYPE,
63448a4d 8780 PNG_DATA,
333b20bb
GM
8781 PNG_FILE,
8782 PNG_ASCENT,
8783 PNG_MARGIN,
8784 PNG_RELIEF,
8785 PNG_ALGORITHM,
8786 PNG_HEURISTIC_MASK,
4a8e312c 8787 PNG_MASK,
f20a3b7a 8788 PNG_BACKGROUND,
333b20bb
GM
8789 PNG_LAST
8790};
8791
8792/* Vector of image_keyword structures describing the format
8793 of valid user-defined image specifications. */
8794
8795static struct image_keyword png_format[PNG_LAST] =
8796{
8797 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8798 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8799 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 8800 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 8801 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 8802 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 8803 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 8804 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 8805 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a 8806 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
8807};
8808
06482119 8809/* Structure describing the image type `png'. */
333b20bb
GM
8810
8811static struct image_type png_type =
8812{
8813 &Qpng,
8814 png_image_p,
8815 png_load,
8816 x_clear_image,
8817 NULL
8818};
8819
8820
8821/* Return non-zero if OBJECT is a valid PNG image specification. */
8822
8823static int
8824png_image_p (object)
8825 Lisp_Object object;
8826{
8827 struct image_keyword fmt[PNG_LAST];
8828 bcopy (png_format, fmt, sizeof fmt);
8829
7c7ff7f5 8830 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
333b20bb 8831 return 0;
63448a4d 8832
63cec32f
GM
8833 /* Must specify either the :data or :file keyword. */
8834 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
333b20bb
GM
8835}
8836
8837
8838/* Error and warning handlers installed when the PNG library
8839 is initialized. */
8840
8841static void
8842my_png_error (png_ptr, msg)
8843 png_struct *png_ptr;
8844 char *msg;
8845{
8846 xassert (png_ptr != NULL);
8847 image_error ("PNG error: %s", build_string (msg), Qnil);
8848 longjmp (png_ptr->jmpbuf, 1);
8849}
8850
8851
8852static void
8853my_png_warning (png_ptr, msg)
8854 png_struct *png_ptr;
8855 char *msg;
8856{
8857 xassert (png_ptr != NULL);
8858 image_error ("PNG warning: %s", build_string (msg), Qnil);
8859}
8860
5ad6a5fb
GM
8861/* Memory source for PNG decoding. */
8862
63448a4d
WP
8863struct png_memory_storage
8864{
5ad6a5fb
GM
8865 unsigned char *bytes; /* The data */
8866 size_t len; /* How big is it? */
8867 int index; /* Where are we? */
63448a4d
WP
8868};
8869
5ad6a5fb
GM
8870
8871/* Function set as reader function when reading PNG image from memory.
8872 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8873 bytes from the input to DATA. */
8874
63448a4d 8875static void
5ad6a5fb
GM
8876png_read_from_memory (png_ptr, data, length)
8877 png_structp png_ptr;
8878 png_bytep data;
8879 png_size_t length;
63448a4d 8880{
5ad6a5fb
GM
8881 struct png_memory_storage *tbr
8882 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
63448a4d 8883
5ad6a5fb
GM
8884 if (length > tbr->len - tbr->index)
8885 png_error (png_ptr, "Read error");
8886
8887 bcopy (tbr->bytes + tbr->index, data, length);
8888 tbr->index = tbr->index + length;
63448a4d 8889}
333b20bb
GM
8890
8891/* Load PNG image IMG for use on frame F. Value is non-zero if
8892 successful. */
8893
8894static int
8895png_load (f, img)
8896 struct frame *f;
8897 struct image *img;
8898{
8899 Lisp_Object file, specified_file;
63448a4d 8900 Lisp_Object specified_data;
b6d7acec 8901 int x, y, i;
333b20bb
GM
8902 XImage *ximg, *mask_img = NULL;
8903 struct gcpro gcpro1;
8904 png_struct *png_ptr = NULL;
8905 png_info *info_ptr = NULL, *end_info = NULL;
8ec8a5ec 8906 FILE *volatile fp = NULL;
333b20bb 8907 png_byte sig[8];
8ec8a5ec
GM
8908 png_byte * volatile pixels = NULL;
8909 png_byte ** volatile rows = NULL;
333b20bb
GM
8910 png_uint_32 width, height;
8911 int bit_depth, color_type, interlace_type;
8912 png_byte channels;
8913 png_uint_32 row_bytes;
8914 int transparent_p;
333b20bb
GM
8915 double screen_gamma, image_gamma;
8916 int intent;
63448a4d 8917 struct png_memory_storage tbr; /* Data to be read */
333b20bb
GM
8918
8919 /* Find out what file to load. */
8920 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8921 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8922 file = Qnil;
8923 GCPRO1 (file);
333b20bb 8924
63448a4d 8925 if (NILP (specified_data))
5ad6a5fb
GM
8926 {
8927 file = x_find_image_file (specified_file);
8928 if (!STRINGP (file))
63448a4d 8929 {
45158a91 8930 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
8931 UNGCPRO;
8932 return 0;
8933 }
333b20bb 8934
5ad6a5fb 8935 /* Open the image file. */
d5db4077 8936 fp = fopen (SDATA (file), "rb");
5ad6a5fb
GM
8937 if (!fp)
8938 {
45158a91 8939 image_error ("Cannot open image file `%s'", file, Qnil);
5ad6a5fb
GM
8940 UNGCPRO;
8941 fclose (fp);
8942 return 0;
8943 }
63448a4d 8944
5ad6a5fb
GM
8945 /* Check PNG signature. */
8946 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8947 || !png_check_sig (sig, sizeof sig))
8948 {
45158a91 8949 image_error ("Not a PNG file: `%s'", file, Qnil);
5ad6a5fb
GM
8950 UNGCPRO;
8951 fclose (fp);
8952 return 0;
63448a4d 8953 }
5ad6a5fb 8954 }
63448a4d 8955 else
5ad6a5fb
GM
8956 {
8957 /* Read from memory. */
d5db4077
KR
8958 tbr.bytes = SDATA (specified_data);
8959 tbr.len = SBYTES (specified_data);
5ad6a5fb 8960 tbr.index = 0;
63448a4d 8961
5ad6a5fb
GM
8962 /* Check PNG signature. */
8963 if (tbr.len < sizeof sig
8964 || !png_check_sig (tbr.bytes, sizeof sig))
8965 {
45158a91 8966 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5ad6a5fb
GM
8967 UNGCPRO;
8968 return 0;
63448a4d 8969 }
333b20bb 8970
5ad6a5fb
GM
8971 /* Need to skip past the signature. */
8972 tbr.bytes += sizeof (sig);
8973 }
8974
333b20bb
GM
8975 /* Initialize read and info structs for PNG lib. */
8976 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8977 my_png_error, my_png_warning);
8978 if (!png_ptr)
8979 {
63448a4d 8980 if (fp) fclose (fp);
333b20bb
GM
8981 UNGCPRO;
8982 return 0;
8983 }
8984
8985 info_ptr = png_create_info_struct (png_ptr);
8986 if (!info_ptr)
8987 {
8988 png_destroy_read_struct (&png_ptr, NULL, NULL);
63448a4d 8989 if (fp) fclose (fp);
333b20bb
GM
8990 UNGCPRO;
8991 return 0;
8992 }
8993
8994 end_info = png_create_info_struct (png_ptr);
8995 if (!end_info)
8996 {
8997 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
63448a4d 8998 if (fp) fclose (fp);
333b20bb
GM
8999 UNGCPRO;
9000 return 0;
9001 }
9002
9003 /* Set error jump-back. We come back here when the PNG library
9004 detects an error. */
9005 if (setjmp (png_ptr->jmpbuf))
9006 {
9007 error:
9008 if (png_ptr)
9009 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9010 xfree (pixels);
9011 xfree (rows);
63448a4d 9012 if (fp) fclose (fp);
333b20bb
GM
9013 UNGCPRO;
9014 return 0;
9015 }
9016
9017 /* Read image info. */
63448a4d 9018 if (!NILP (specified_data))
5ad6a5fb 9019 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
63448a4d 9020 else
5ad6a5fb 9021 png_init_io (png_ptr, fp);
63448a4d 9022
333b20bb
GM
9023 png_set_sig_bytes (png_ptr, sizeof sig);
9024 png_read_info (png_ptr, info_ptr);
9025 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
9026 &interlace_type, NULL, NULL);
9027
9028 /* If image contains simply transparency data, we prefer to
9029 construct a clipping mask. */
9030 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
9031 transparent_p = 1;
9032 else
9033 transparent_p = 0;
9034
9035 /* This function is easier to write if we only have to handle
9036 one data format: RGB or RGBA with 8 bits per channel. Let's
9037 transform other formats into that format. */
9038
9039 /* Strip more than 8 bits per channel. */
9040 if (bit_depth == 16)
9041 png_set_strip_16 (png_ptr);
9042
9043 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
9044 if available. */
9045 png_set_expand (png_ptr);
9046
9047 /* Convert grayscale images to RGB. */
9048 if (color_type == PNG_COLOR_TYPE_GRAY
9049 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9050 png_set_gray_to_rgb (png_ptr);
9051
d4405ed7 9052 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
333b20bb
GM
9053
9054 /* Tell the PNG lib to handle gamma correction for us. */
9055
6c1aa34d 9056#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
333b20bb 9057 if (png_get_sRGB (png_ptr, info_ptr, &intent))
d4405ed7
RS
9058 /* The libpng documentation says this is right in this case. */
9059 png_set_gamma (png_ptr, screen_gamma, 0.45455);
6c1aa34d
GM
9060 else
9061#endif
9062 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
333b20bb
GM
9063 /* Image contains gamma information. */
9064 png_set_gamma (png_ptr, screen_gamma, image_gamma);
9065 else
d4405ed7
RS
9066 /* Use the standard default for the image gamma. */
9067 png_set_gamma (png_ptr, screen_gamma, 0.45455);
333b20bb
GM
9068
9069 /* Handle alpha channel by combining the image with a background
9070 color. Do this only if a real alpha channel is supplied. For
9071 simple transparency, we prefer a clipping mask. */
9072 if (!transparent_p)
9073 {
f20a3b7a
MB
9074 png_color_16 *image_bg;
9075 Lisp_Object specified_bg
9076 = image_spec_value (img->spec, QCbackground, NULL);
9077
f2f0a644 9078 if (STRINGP (specified_bg))
f20a3b7a
MB
9079 /* The user specified `:background', use that. */
9080 {
9081 XColor color;
d5db4077 9082 if (x_defined_color (f, SDATA (specified_bg), &color, 0))
f20a3b7a
MB
9083 {
9084 png_color_16 user_bg;
9085
9086 bzero (&user_bg, sizeof user_bg);
9087 user_bg.red = color.red;
9088 user_bg.green = color.green;
9089 user_bg.blue = color.blue;
333b20bb 9090
f20a3b7a
MB
9091 png_set_background (png_ptr, &user_bg,
9092 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9093 }
9094 }
9095 else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
333b20bb
GM
9096 /* Image contains a background color with which to
9097 combine the image. */
f20a3b7a 9098 png_set_background (png_ptr, image_bg,
333b20bb
GM
9099 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
9100 else
9101 {
9102 /* Image does not contain a background color with which
9103 to combine the image data via an alpha channel. Use
9104 the frame's background instead. */
9105 XColor color;
9106 Colormap cmap;
9107 png_color_16 frame_background;
9108
9b2956e2 9109 cmap = FRAME_X_COLORMAP (f);
333b20bb 9110 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a31fedb7 9111 x_query_color (f, &color);
333b20bb
GM
9112
9113 bzero (&frame_background, sizeof frame_background);
9114 frame_background.red = color.red;
9115 frame_background.green = color.green;
9116 frame_background.blue = color.blue;
9117
9118 png_set_background (png_ptr, &frame_background,
9119 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9120 }
9121 }
9122
9123 /* Update info structure. */
9124 png_read_update_info (png_ptr, info_ptr);
9125
9126 /* Get number of channels. Valid values are 1 for grayscale images
9127 and images with a palette, 2 for grayscale images with transparency
9128 information (alpha channel), 3 for RGB images, and 4 for RGB
9129 images with alpha channel, i.e. RGBA. If conversions above were
9130 sufficient we should only have 3 or 4 channels here. */
9131 channels = png_get_channels (png_ptr, info_ptr);
9132 xassert (channels == 3 || channels == 4);
9133
9134 /* Number of bytes needed for one row of the image. */
9135 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
9136
9137 /* Allocate memory for the image. */
9138 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
9139 rows = (png_byte **) xmalloc (height * sizeof *rows);
9140 for (i = 0; i < height; ++i)
9141 rows[i] = pixels + i * row_bytes;
9142
9143 /* Read the entire image. */
9144 png_read_image (png_ptr, rows);
9145 png_read_end (png_ptr, info_ptr);
5ad6a5fb
GM
9146 if (fp)
9147 {
9148 fclose (fp);
9149 fp = NULL;
9150 }
333b20bb 9151
333b20bb 9152 /* Create the X image and pixmap. */
45158a91 9153 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
333b20bb 9154 &img->pixmap))
28c7826c 9155 goto error;
333b20bb
GM
9156
9157 /* Create an image and pixmap serving as mask if the PNG image
9158 contains an alpha channel. */
9159 if (channels == 4
9160 && !transparent_p
45158a91 9161 && !x_create_x_image_and_pixmap (f, width, height, 1,
333b20bb
GM
9162 &mask_img, &img->mask))
9163 {
9164 x_destroy_x_image (ximg);
9165 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
dd00328a 9166 img->pixmap = None;
333b20bb
GM
9167 goto error;
9168 }
9169
9170 /* Fill the X image and mask from PNG data. */
9171 init_color_table ();
9172
9173 for (y = 0; y < height; ++y)
9174 {
9175 png_byte *p = rows[y];
9176
9177 for (x = 0; x < width; ++x)
9178 {
9179 unsigned r, g, b;
9180
9181 r = *p++ << 8;
9182 g = *p++ << 8;
9183 b = *p++ << 8;
9184 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9185
9186 /* An alpha channel, aka mask channel, associates variable
9187 transparency with an image. Where other image formats
9188 support binary transparency---fully transparent or fully
9189 opaque---PNG allows up to 254 levels of partial transparency.
9190 The PNG library implements partial transparency by combining
9191 the image with a specified background color.
9192
9193 I'm not sure how to handle this here nicely: because the
9194 background on which the image is displayed may change, for
9195 real alpha channel support, it would be necessary to create
9196 a new image for each possible background.
9197
9198 What I'm doing now is that a mask is created if we have
9199 boolean transparency information. Otherwise I'm using
9200 the frame's background color to combine the image with. */
9201
9202 if (channels == 4)
9203 {
9204 if (mask_img)
9205 XPutPixel (mask_img, x, y, *p > 0);
9206 ++p;
9207 }
9208 }
9209 }
9210
f20a3b7a
MB
9211 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9212 /* Set IMG's background color from the PNG image, unless the user
9213 overrode it. */
9214 {
9215 png_color_16 *bg;
9216 if (png_get_bKGD (png_ptr, info_ptr, &bg))
9217 {
f2f0a644 9218 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
f20a3b7a
MB
9219 img->background_valid = 1;
9220 }
9221 }
9222
333b20bb
GM
9223 /* Remember colors allocated for this image. */
9224 img->colors = colors_in_color_table (&img->ncolors);
9225 free_color_table ();
9226
9227 /* Clean up. */
9228 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9229 xfree (rows);
9230 xfree (pixels);
9231
9232 img->width = width;
9233 img->height = height;
9234
f20a3b7a
MB
9235 /* Maybe fill in the background field while we have ximg handy. */
9236 IMAGE_BACKGROUND (img, f, ximg);
9237
333b20bb
GM
9238 /* Put the image into the pixmap, then free the X image and its buffer. */
9239 x_put_x_image (f, ximg, img->pixmap, width, height);
9240 x_destroy_x_image (ximg);
9241
9242 /* Same for the mask. */
9243 if (mask_img)
9244 {
f20a3b7a
MB
9245 /* Fill in the background_transparent field while we have the mask
9246 handy. */
9247 image_background_transparent (img, f, mask_img);
9248
333b20bb
GM
9249 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9250 x_destroy_x_image (mask_img);
9251 }
9252
333b20bb
GM
9253 UNGCPRO;
9254 return 1;
9255}
9256
9257#endif /* HAVE_PNG != 0 */
9258
9259
9260\f
9261/***********************************************************************
9262 JPEG
9263 ***********************************************************************/
9264
9265#if HAVE_JPEG
9266
ba06aba4
GM
9267/* Work around a warning about HAVE_STDLIB_H being redefined in
9268 jconfig.h. */
9269#ifdef HAVE_STDLIB_H
9270#define HAVE_STDLIB_H_1
9271#undef HAVE_STDLIB_H
9272#endif /* HAVE_STLIB_H */
9273
333b20bb
GM
9274#include <jpeglib.h>
9275#include <jerror.h>
9276#include <setjmp.h>
9277
ba06aba4
GM
9278#ifdef HAVE_STLIB_H_1
9279#define HAVE_STDLIB_H 1
9280#endif
9281
333b20bb
GM
9282static int jpeg_image_p P_ ((Lisp_Object object));
9283static int jpeg_load P_ ((struct frame *f, struct image *img));
9284
9285/* The symbol `jpeg' identifying images of this type. */
9286
9287Lisp_Object Qjpeg;
9288
9289/* Indices of image specification fields in gs_format, below. */
9290
9291enum jpeg_keyword_index
9292{
9293 JPEG_TYPE,
8e39770a 9294 JPEG_DATA,
333b20bb
GM
9295 JPEG_FILE,
9296 JPEG_ASCENT,
9297 JPEG_MARGIN,
9298 JPEG_RELIEF,
9299 JPEG_ALGORITHM,
9300 JPEG_HEURISTIC_MASK,
4a8e312c 9301 JPEG_MASK,
f20a3b7a 9302 JPEG_BACKGROUND,
333b20bb
GM
9303 JPEG_LAST
9304};
9305
9306/* Vector of image_keyword structures describing the format
9307 of valid user-defined image specifications. */
9308
9309static struct image_keyword jpeg_format[JPEG_LAST] =
9310{
9311 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9312 {":data", IMAGE_STRING_VALUE, 0},
8e39770a 9313 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9314 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9315 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9316 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9317 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9318 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9319 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9320 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9321};
9322
9323/* Structure describing the image type `jpeg'. */
9324
9325static struct image_type jpeg_type =
9326{
9327 &Qjpeg,
9328 jpeg_image_p,
9329 jpeg_load,
9330 x_clear_image,
9331 NULL
9332};
9333
9334
9335/* Return non-zero if OBJECT is a valid JPEG image specification. */
9336
9337static int
9338jpeg_image_p (object)
9339 Lisp_Object object;
9340{
9341 struct image_keyword fmt[JPEG_LAST];
9342
9343 bcopy (jpeg_format, fmt, sizeof fmt);
9344
7c7ff7f5 9345 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
333b20bb 9346 return 0;
8e39770a 9347
63cec32f
GM
9348 /* Must specify either the :data or :file keyword. */
9349 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
333b20bb
GM
9350}
9351
8e39770a 9352
333b20bb
GM
9353struct my_jpeg_error_mgr
9354{
9355 struct jpeg_error_mgr pub;
9356 jmp_buf setjmp_buffer;
9357};
9358
e3130015 9359
333b20bb
GM
9360static void
9361my_error_exit (cinfo)
9362 j_common_ptr cinfo;
9363{
9364 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
9365 longjmp (mgr->setjmp_buffer, 1);
9366}
9367
e3130015 9368
8e39770a
GM
9369/* Init source method for JPEG data source manager. Called by
9370 jpeg_read_header() before any data is actually read. See
9371 libjpeg.doc from the JPEG lib distribution. */
9372
9373static void
9374our_init_source (cinfo)
9375 j_decompress_ptr cinfo;
9376{
9377}
9378
9379
9380/* Fill input buffer method for JPEG data source manager. Called
9381 whenever more data is needed. We read the whole image in one step,
9382 so this only adds a fake end of input marker at the end. */
9383
9384static boolean
9385our_fill_input_buffer (cinfo)
9386 j_decompress_ptr cinfo;
9387{
9388 /* Insert a fake EOI marker. */
9389 struct jpeg_source_mgr *src = cinfo->src;
9390 static JOCTET buffer[2];
9391
9392 buffer[0] = (JOCTET) 0xFF;
9393 buffer[1] = (JOCTET) JPEG_EOI;
9394
9395 src->next_input_byte = buffer;
9396 src->bytes_in_buffer = 2;
9397 return TRUE;
9398}
9399
9400
9401/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
9402 is the JPEG data source manager. */
9403
9404static void
9405our_skip_input_data (cinfo, num_bytes)
9406 j_decompress_ptr cinfo;
9407 long num_bytes;
9408{
9409 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
9410
9411 if (src)
9412 {
9413 if (num_bytes > src->bytes_in_buffer)
5ad6a5fb 9414 ERREXIT (cinfo, JERR_INPUT_EOF);
8e39770a
GM
9415
9416 src->bytes_in_buffer -= num_bytes;
9417 src->next_input_byte += num_bytes;
9418 }
9419}
9420
9421
9422/* Method to terminate data source. Called by
9423 jpeg_finish_decompress() after all data has been processed. */
9424
9425static void
9426our_term_source (cinfo)
9427 j_decompress_ptr cinfo;
9428{
9429}
9430
9431
9432/* Set up the JPEG lib for reading an image from DATA which contains
9433 LEN bytes. CINFO is the decompression info structure created for
9434 reading the image. */
9435
9436static void
9437jpeg_memory_src (cinfo, data, len)
9438 j_decompress_ptr cinfo;
9439 JOCTET *data;
9440 unsigned int len;
9441{
9442 struct jpeg_source_mgr *src;
9443
9444 if (cinfo->src == NULL)
9445 {
9446 /* First time for this JPEG object? */
9447 cinfo->src = (struct jpeg_source_mgr *)
9448 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
9449 sizeof (struct jpeg_source_mgr));
9450 src = (struct jpeg_source_mgr *) cinfo->src;
9451 src->next_input_byte = data;
9452 }
9453
9454 src = (struct jpeg_source_mgr *) cinfo->src;
9455 src->init_source = our_init_source;
9456 src->fill_input_buffer = our_fill_input_buffer;
9457 src->skip_input_data = our_skip_input_data;
9458 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
9459 src->term_source = our_term_source;
9460 src->bytes_in_buffer = len;
9461 src->next_input_byte = data;
9462}
9463
5ad6a5fb 9464
333b20bb
GM
9465/* Load image IMG for use on frame F. Patterned after example.c
9466 from the JPEG lib. */
9467
9468static int
9469jpeg_load (f, img)
9470 struct frame *f;
9471 struct image *img;
9472{
9473 struct jpeg_decompress_struct cinfo;
9474 struct my_jpeg_error_mgr mgr;
9475 Lisp_Object file, specified_file;
8e39770a 9476 Lisp_Object specified_data;
8ec8a5ec 9477 FILE * volatile fp = NULL;
333b20bb
GM
9478 JSAMPARRAY buffer;
9479 int row_stride, x, y;
9480 XImage *ximg = NULL;
b6d7acec 9481 int rc;
333b20bb
GM
9482 unsigned long *colors;
9483 int width, height;
9484 struct gcpro gcpro1;
9485
9486 /* Open the JPEG file. */
9487 specified_file = image_spec_value (img->spec, QCfile, NULL);
8e39770a 9488 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9489 file = Qnil;
9490 GCPRO1 (file);
8e39770a 9491
8e39770a 9492 if (NILP (specified_data))
333b20bb 9493 {
8e39770a 9494 file = x_find_image_file (specified_file);
8e39770a
GM
9495 if (!STRINGP (file))
9496 {
45158a91 9497 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8e39770a
GM
9498 UNGCPRO;
9499 return 0;
9500 }
333b20bb 9501
d5db4077 9502 fp = fopen (SDATA (file), "r");
8e39770a
GM
9503 if (fp == NULL)
9504 {
9505 image_error ("Cannot open `%s'", file, Qnil);
9506 UNGCPRO;
9507 return 0;
9508 }
333b20bb
GM
9509 }
9510
5ad6a5fb
GM
9511 /* Customize libjpeg's error handling to call my_error_exit when an
9512 error is detected. This function will perform a longjmp. */
333b20bb 9513 cinfo.err = jpeg_std_error (&mgr.pub);
14358466 9514 mgr.pub.error_exit = my_error_exit;
333b20bb
GM
9515
9516 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
9517 {
5ad6a5fb
GM
9518 if (rc == 1)
9519 {
9520 /* Called from my_error_exit. Display a JPEG error. */
9521 char buffer[JMSG_LENGTH_MAX];
9522 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
45158a91 9523 image_error ("Error reading JPEG image `%s': %s", img->spec,
5ad6a5fb
GM
9524 build_string (buffer));
9525 }
333b20bb
GM
9526
9527 /* Close the input file and destroy the JPEG object. */
5ad6a5fb 9528 if (fp)
8ec8a5ec 9529 fclose ((FILE *) fp);
333b20bb
GM
9530 jpeg_destroy_decompress (&cinfo);
9531
5ad6a5fb
GM
9532 /* If we already have an XImage, free that. */
9533 x_destroy_x_image (ximg);
333b20bb 9534
5ad6a5fb
GM
9535 /* Free pixmap and colors. */
9536 x_clear_image (f, img);
333b20bb 9537
5ad6a5fb
GM
9538 UNGCPRO;
9539 return 0;
333b20bb
GM
9540 }
9541
9542 /* Create the JPEG decompression object. Let it read from fp.
63448a4d 9543 Read the JPEG image header. */
333b20bb 9544 jpeg_create_decompress (&cinfo);
8e39770a
GM
9545
9546 if (NILP (specified_data))
8ec8a5ec 9547 jpeg_stdio_src (&cinfo, (FILE *) fp);
8e39770a 9548 else
d5db4077
KR
9549 jpeg_memory_src (&cinfo, SDATA (specified_data),
9550 SBYTES (specified_data));
63448a4d 9551
333b20bb
GM
9552 jpeg_read_header (&cinfo, TRUE);
9553
9554 /* Customize decompression so that color quantization will be used.
63448a4d 9555 Start decompression. */
333b20bb
GM
9556 cinfo.quantize_colors = TRUE;
9557 jpeg_start_decompress (&cinfo);
9558 width = img->width = cinfo.output_width;
9559 height = img->height = cinfo.output_height;
9560
333b20bb 9561 /* Create X image and pixmap. */
45158a91 9562 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
28c7826c 9563 longjmp (mgr.setjmp_buffer, 2);
333b20bb
GM
9564
9565 /* Allocate colors. When color quantization is used,
5ad6a5fb
GM
9566 cinfo.actual_number_of_colors has been set with the number of
9567 colors generated, and cinfo.colormap is a two-dimensional array
9568 of color indices in the range 0..cinfo.actual_number_of_colors.
9569 No more than 255 colors will be generated. */
333b20bb 9570 {
5ad6a5fb
GM
9571 int i, ir, ig, ib;
9572
9573 if (cinfo.out_color_components > 2)
9574 ir = 0, ig = 1, ib = 2;
9575 else if (cinfo.out_color_components > 1)
9576 ir = 0, ig = 1, ib = 0;
9577 else
9578 ir = 0, ig = 0, ib = 0;
9579
9580 /* Use the color table mechanism because it handles colors that
9581 cannot be allocated nicely. Such colors will be replaced with
9582 a default color, and we don't have to care about which colors
9583 can be freed safely, and which can't. */
9584 init_color_table ();
9585 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
9586 * sizeof *colors);
333b20bb 9587
5ad6a5fb
GM
9588 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
9589 {
9590 /* Multiply RGB values with 255 because X expects RGB values
9591 in the range 0..0xffff. */
9592 int r = cinfo.colormap[ir][i] << 8;
9593 int g = cinfo.colormap[ig][i] << 8;
9594 int b = cinfo.colormap[ib][i] << 8;
9595 colors[i] = lookup_rgb_color (f, r, g, b);
9596 }
333b20bb 9597
5ad6a5fb
GM
9598 /* Remember those colors actually allocated. */
9599 img->colors = colors_in_color_table (&img->ncolors);
9600 free_color_table ();
333b20bb
GM
9601 }
9602
9603 /* Read pixels. */
9604 row_stride = width * cinfo.output_components;
9605 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
5ad6a5fb 9606 row_stride, 1);
333b20bb
GM
9607 for (y = 0; y < height; ++y)
9608 {
5ad6a5fb
GM
9609 jpeg_read_scanlines (&cinfo, buffer, 1);
9610 for (x = 0; x < cinfo.output_width; ++x)
9611 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
333b20bb
GM
9612 }
9613
9614 /* Clean up. */
9615 jpeg_finish_decompress (&cinfo);
9616 jpeg_destroy_decompress (&cinfo);
5ad6a5fb 9617 if (fp)
8ec8a5ec 9618 fclose ((FILE *) fp);
f20a3b7a
MB
9619
9620 /* Maybe fill in the background field while we have ximg handy. */
9621 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9622 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9623
9624 /* Put the image into the pixmap. */
9625 x_put_x_image (f, ximg, img->pixmap, width, height);
9626 x_destroy_x_image (ximg);
333b20bb
GM
9627 UNGCPRO;
9628 return 1;
9629}
9630
9631#endif /* HAVE_JPEG */
9632
9633
9634\f
9635/***********************************************************************
9636 TIFF
9637 ***********************************************************************/
9638
9639#if HAVE_TIFF
9640
cf4790ad 9641#include <tiffio.h>
333b20bb
GM
9642
9643static int tiff_image_p P_ ((Lisp_Object object));
9644static int tiff_load P_ ((struct frame *f, struct image *img));
9645
9646/* The symbol `tiff' identifying images of this type. */
9647
9648Lisp_Object Qtiff;
9649
9650/* Indices of image specification fields in tiff_format, below. */
9651
9652enum tiff_keyword_index
9653{
9654 TIFF_TYPE,
63448a4d 9655 TIFF_DATA,
333b20bb
GM
9656 TIFF_FILE,
9657 TIFF_ASCENT,
9658 TIFF_MARGIN,
9659 TIFF_RELIEF,
9660 TIFF_ALGORITHM,
9661 TIFF_HEURISTIC_MASK,
4a8e312c 9662 TIFF_MASK,
f20a3b7a 9663 TIFF_BACKGROUND,
333b20bb
GM
9664 TIFF_LAST
9665};
9666
9667/* Vector of image_keyword structures describing the format
9668 of valid user-defined image specifications. */
9669
9670static struct image_keyword tiff_format[TIFF_LAST] =
9671{
9672 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9673 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9674 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 9675 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 9676 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 9677 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 9678 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 9679 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
9680 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9681 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
9682};
9683
9684/* Structure describing the image type `tiff'. */
9685
9686static struct image_type tiff_type =
9687{
9688 &Qtiff,
9689 tiff_image_p,
9690 tiff_load,
9691 x_clear_image,
9692 NULL
9693};
9694
9695
9696/* Return non-zero if OBJECT is a valid TIFF image specification. */
9697
9698static int
9699tiff_image_p (object)
9700 Lisp_Object object;
9701{
9702 struct image_keyword fmt[TIFF_LAST];
9703 bcopy (tiff_format, fmt, sizeof fmt);
9704
7c7ff7f5 9705 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
333b20bb 9706 return 0;
5ad6a5fb 9707
63cec32f
GM
9708 /* Must specify either the :data or :file keyword. */
9709 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
333b20bb
GM
9710}
9711
5ad6a5fb
GM
9712
9713/* Reading from a memory buffer for TIFF images Based on the PNG
9714 memory source, but we have to provide a lot of extra functions.
9715 Blah.
63448a4d
WP
9716
9717 We really only need to implement read and seek, but I am not
9718 convinced that the TIFF library is smart enough not to destroy
9719 itself if we only hand it the function pointers we need to
5ad6a5fb
GM
9720 override. */
9721
9722typedef struct
9723{
63448a4d
WP
9724 unsigned char *bytes;
9725 size_t len;
9726 int index;
5ad6a5fb
GM
9727}
9728tiff_memory_source;
63448a4d 9729
e3130015 9730
5ad6a5fb
GM
9731static size_t
9732tiff_read_from_memory (data, buf, size)
9733 thandle_t data;
9734 tdata_t buf;
9735 tsize_t size;
63448a4d 9736{
5ad6a5fb 9737 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9738
9739 if (size > src->len - src->index)
5ad6a5fb
GM
9740 return (size_t) -1;
9741 bcopy (src->bytes + src->index, buf, size);
63448a4d
WP
9742 src->index += size;
9743 return size;
9744}
9745
e3130015 9746
5ad6a5fb
GM
9747static size_t
9748tiff_write_from_memory (data, buf, size)
9749 thandle_t data;
9750 tdata_t buf;
9751 tsize_t size;
63448a4d
WP
9752{
9753 return (size_t) -1;
9754}
9755
e3130015 9756
5ad6a5fb
GM
9757static toff_t
9758tiff_seek_in_memory (data, off, whence)
9759 thandle_t data;
9760 toff_t off;
9761 int whence;
63448a4d 9762{
5ad6a5fb 9763 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9764 int idx;
9765
9766 switch (whence)
5ad6a5fb
GM
9767 {
9768 case SEEK_SET: /* Go from beginning of source. */
9769 idx = off;
9770 break;
9771
9772 case SEEK_END: /* Go from end of source. */
9773 idx = src->len + off;
9774 break;
9775
9776 case SEEK_CUR: /* Go from current position. */
9777 idx = src->index + off;
9778 break;
9779
9780 default: /* Invalid `whence'. */
9781 return -1;
9782 }
9783
9784 if (idx > src->len || idx < 0)
9785 return -1;
9786
63448a4d
WP
9787 src->index = idx;
9788 return src->index;
9789}
9790
e3130015 9791
5ad6a5fb
GM
9792static int
9793tiff_close_memory (data)
9794 thandle_t data;
63448a4d
WP
9795{
9796 /* NOOP */
5ad6a5fb 9797 return 0;
63448a4d
WP
9798}
9799
e3130015 9800
5ad6a5fb
GM
9801static int
9802tiff_mmap_memory (data, pbase, psize)
9803 thandle_t data;
9804 tdata_t *pbase;
9805 toff_t *psize;
63448a4d
WP
9806{
9807 /* It is already _IN_ memory. */
5ad6a5fb 9808 return 0;
63448a4d
WP
9809}
9810
e3130015 9811
5ad6a5fb
GM
9812static void
9813tiff_unmap_memory (data, base, size)
9814 thandle_t data;
9815 tdata_t base;
9816 toff_t size;
63448a4d
WP
9817{
9818 /* We don't need to do this. */
63448a4d
WP
9819}
9820
e3130015 9821
5ad6a5fb
GM
9822static toff_t
9823tiff_size_of_memory (data)
9824 thandle_t data;
63448a4d 9825{
5ad6a5fb 9826 return ((tiff_memory_source *) data)->len;
63448a4d 9827}
333b20bb 9828
e3130015 9829
c6892044
GM
9830static void
9831tiff_error_handler (title, format, ap)
9832 const char *title, *format;
9833 va_list ap;
9834{
9835 char buf[512];
9836 int len;
9837
9838 len = sprintf (buf, "TIFF error: %s ", title);
9839 vsprintf (buf + len, format, ap);
9840 add_to_log (buf, Qnil, Qnil);
9841}
9842
9843
9844static void
9845tiff_warning_handler (title, format, ap)
9846 const char *title, *format;
9847 va_list ap;
9848{
9849 char buf[512];
9850 int len;
9851
9852 len = sprintf (buf, "TIFF warning: %s ", title);
9853 vsprintf (buf + len, format, ap);
9854 add_to_log (buf, Qnil, Qnil);
9855}
9856
9857
333b20bb
GM
9858/* Load TIFF image IMG for use on frame F. Value is non-zero if
9859 successful. */
9860
9861static int
9862tiff_load (f, img)
9863 struct frame *f;
9864 struct image *img;
9865{
9866 Lisp_Object file, specified_file;
63448a4d 9867 Lisp_Object specified_data;
333b20bb
GM
9868 TIFF *tiff;
9869 int width, height, x, y;
9870 uint32 *buf;
9871 int rc;
9872 XImage *ximg;
9873 struct gcpro gcpro1;
63448a4d 9874 tiff_memory_source memsrc;
333b20bb
GM
9875
9876 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9877 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9878 file = Qnil;
9879 GCPRO1 (file);
63448a4d 9880
c6892044
GM
9881 TIFFSetErrorHandler (tiff_error_handler);
9882 TIFFSetWarningHandler (tiff_warning_handler);
9883
63448a4d 9884 if (NILP (specified_data))
5ad6a5fb
GM
9885 {
9886 /* Read from a file */
9887 file = x_find_image_file (specified_file);
9888 if (!STRINGP (file))
63448a4d 9889 {
45158a91 9890 image_error ("Cannot find image file `%s'", file, Qnil);
5ad6a5fb
GM
9891 UNGCPRO;
9892 return 0;
9893 }
63448a4d 9894
5ad6a5fb 9895 /* Try to open the image file. */
d5db4077 9896 tiff = TIFFOpen (SDATA (file), "r");
5ad6a5fb
GM
9897 if (tiff == NULL)
9898 {
9899 image_error ("Cannot open `%s'", file, Qnil);
9900 UNGCPRO;
9901 return 0;
63448a4d 9902 }
5ad6a5fb 9903 }
63448a4d 9904 else
5ad6a5fb
GM
9905 {
9906 /* Memory source! */
d5db4077
KR
9907 memsrc.bytes = SDATA (specified_data);
9908 memsrc.len = SBYTES (specified_data);
5ad6a5fb
GM
9909 memsrc.index = 0;
9910
9911 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9912 (TIFFReadWriteProc) tiff_read_from_memory,
9913 (TIFFReadWriteProc) tiff_write_from_memory,
9914 tiff_seek_in_memory,
9915 tiff_close_memory,
9916 tiff_size_of_memory,
9917 tiff_mmap_memory,
9918 tiff_unmap_memory);
9919
9920 if (!tiff)
63448a4d 9921 {
45158a91 9922 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
5ad6a5fb
GM
9923 UNGCPRO;
9924 return 0;
63448a4d 9925 }
5ad6a5fb 9926 }
333b20bb
GM
9927
9928 /* Get width and height of the image, and allocate a raster buffer
9929 of width x height 32-bit values. */
9930 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9931 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9932 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9933
9934 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9935 TIFFClose (tiff);
9936 if (!rc)
9937 {
45158a91 9938 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
333b20bb
GM
9939 xfree (buf);
9940 UNGCPRO;
9941 return 0;
9942 }
9943
333b20bb 9944 /* Create the X image and pixmap. */
45158a91 9945 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9946 {
333b20bb
GM
9947 xfree (buf);
9948 UNGCPRO;
9949 return 0;
9950 }
9951
9952 /* Initialize the color table. */
9953 init_color_table ();
9954
9955 /* Process the pixel raster. Origin is in the lower-left corner. */
9956 for (y = 0; y < height; ++y)
9957 {
9958 uint32 *row = buf + y * width;
9959
9960 for (x = 0; x < width; ++x)
9961 {
9962 uint32 abgr = row[x];
9963 int r = TIFFGetR (abgr) << 8;
9964 int g = TIFFGetG (abgr) << 8;
9965 int b = TIFFGetB (abgr) << 8;
9966 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9967 }
9968 }
9969
9970 /* Remember the colors allocated for the image. Free the color table. */
9971 img->colors = colors_in_color_table (&img->ncolors);
9972 free_color_table ();
f20a3b7a
MB
9973
9974 img->width = width;
9975 img->height = height;
9976
9977 /* Maybe fill in the background field while we have ximg handy. */
9978 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
9979 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
9980
9981 /* Put the image into the pixmap, then free the X image and its buffer. */
9982 x_put_x_image (f, ximg, img->pixmap, width, height);
9983 x_destroy_x_image (ximg);
9984 xfree (buf);
333b20bb
GM
9985
9986 UNGCPRO;
9987 return 1;
9988}
9989
9990#endif /* HAVE_TIFF != 0 */
9991
9992
9993\f
9994/***********************************************************************
9995 GIF
9996 ***********************************************************************/
9997
9998#if HAVE_GIF
9999
10000#include <gif_lib.h>
10001
10002static int gif_image_p P_ ((Lisp_Object object));
10003static int gif_load P_ ((struct frame *f, struct image *img));
10004
10005/* The symbol `gif' identifying images of this type. */
10006
10007Lisp_Object Qgif;
10008
10009/* Indices of image specification fields in gif_format, below. */
10010
10011enum gif_keyword_index
10012{
10013 GIF_TYPE,
63448a4d 10014 GIF_DATA,
333b20bb
GM
10015 GIF_FILE,
10016 GIF_ASCENT,
10017 GIF_MARGIN,
10018 GIF_RELIEF,
10019 GIF_ALGORITHM,
10020 GIF_HEURISTIC_MASK,
4a8e312c 10021 GIF_MASK,
333b20bb 10022 GIF_IMAGE,
f20a3b7a 10023 GIF_BACKGROUND,
333b20bb
GM
10024 GIF_LAST
10025};
10026
10027/* Vector of image_keyword structures describing the format
10028 of valid user-defined image specifications. */
10029
10030static struct image_keyword gif_format[GIF_LAST] =
10031{
10032 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 10033 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 10034 {":file", IMAGE_STRING_VALUE, 0},
7c7ff7f5 10035 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10036 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10037 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10038 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
333b20bb 10039 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10040 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f2f0a644 10041 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
f20a3b7a 10042 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10043};
10044
10045/* Structure describing the image type `gif'. */
10046
10047static struct image_type gif_type =
10048{
10049 &Qgif,
10050 gif_image_p,
10051 gif_load,
10052 x_clear_image,
10053 NULL
10054};
10055
e3130015 10056
333b20bb
GM
10057/* Return non-zero if OBJECT is a valid GIF image specification. */
10058
10059static int
10060gif_image_p (object)
10061 Lisp_Object object;
10062{
10063 struct image_keyword fmt[GIF_LAST];
10064 bcopy (gif_format, fmt, sizeof fmt);
10065
7c7ff7f5 10066 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
333b20bb 10067 return 0;
5ad6a5fb 10068
63cec32f
GM
10069 /* Must specify either the :data or :file keyword. */
10070 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
333b20bb
GM
10071}
10072
e3130015 10073
63448a4d
WP
10074/* Reading a GIF image from memory
10075 Based on the PNG memory stuff to a certain extent. */
10076
5ad6a5fb
GM
10077typedef struct
10078{
63448a4d
WP
10079 unsigned char *bytes;
10080 size_t len;
10081 int index;
5ad6a5fb
GM
10082}
10083gif_memory_source;
63448a4d 10084
e3130015 10085
f036834a
GM
10086/* Make the current memory source available to gif_read_from_memory.
10087 It's done this way because not all versions of libungif support
10088 a UserData field in the GifFileType structure. */
10089static gif_memory_source *current_gif_memory_src;
10090
5ad6a5fb
GM
10091static int
10092gif_read_from_memory (file, buf, len)
10093 GifFileType *file;
10094 GifByteType *buf;
10095 int len;
63448a4d 10096{
f036834a 10097 gif_memory_source *src = current_gif_memory_src;
63448a4d 10098
5ad6a5fb
GM
10099 if (len > src->len - src->index)
10100 return -1;
63448a4d 10101
5ad6a5fb 10102 bcopy (src->bytes + src->index, buf, len);
63448a4d
WP
10103 src->index += len;
10104 return len;
10105}
333b20bb 10106
5ad6a5fb 10107
333b20bb
GM
10108/* Load GIF image IMG for use on frame F. Value is non-zero if
10109 successful. */
10110
10111static int
10112gif_load (f, img)
10113 struct frame *f;
10114 struct image *img;
10115{
10116 Lisp_Object file, specified_file;
63448a4d 10117 Lisp_Object specified_data;
333b20bb
GM
10118 int rc, width, height, x, y, i;
10119 XImage *ximg;
10120 ColorMapObject *gif_color_map;
10121 unsigned long pixel_colors[256];
10122 GifFileType *gif;
10123 struct gcpro gcpro1;
10124 Lisp_Object image;
10125 int ino, image_left, image_top, image_width, image_height;
63448a4d 10126 gif_memory_source memsrc;
9b784e96 10127 unsigned char *raster;
333b20bb
GM
10128
10129 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 10130 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
10131 file = Qnil;
10132 GCPRO1 (file);
63448a4d
WP
10133
10134 if (NILP (specified_data))
5ad6a5fb
GM
10135 {
10136 file = x_find_image_file (specified_file);
10137 if (!STRINGP (file))
63448a4d 10138 {
45158a91 10139 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
10140 UNGCPRO;
10141 return 0;
10142 }
333b20bb 10143
5ad6a5fb 10144 /* Open the GIF file. */
d5db4077 10145 gif = DGifOpenFileName (SDATA (file));
5ad6a5fb
GM
10146 if (gif == NULL)
10147 {
10148 image_error ("Cannot open `%s'", file, Qnil);
10149 UNGCPRO;
10150 return 0;
63448a4d 10151 }
5ad6a5fb 10152 }
63448a4d 10153 else
5ad6a5fb
GM
10154 {
10155 /* Read from memory! */
f036834a 10156 current_gif_memory_src = &memsrc;
d5db4077
KR
10157 memsrc.bytes = SDATA (specified_data);
10158 memsrc.len = SBYTES (specified_data);
5ad6a5fb 10159 memsrc.index = 0;
63448a4d 10160
5ad6a5fb
GM
10161 gif = DGifOpen(&memsrc, gif_read_from_memory);
10162 if (!gif)
10163 {
45158a91 10164 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
5ad6a5fb
GM
10165 UNGCPRO;
10166 return 0;
63448a4d 10167 }
5ad6a5fb 10168 }
333b20bb
GM
10169
10170 /* Read entire contents. */
10171 rc = DGifSlurp (gif);
10172 if (rc == GIF_ERROR)
10173 {
45158a91 10174 image_error ("Error reading `%s'", img->spec, Qnil);
333b20bb
GM
10175 DGifCloseFile (gif);
10176 UNGCPRO;
10177 return 0;
10178 }
10179
3ccff1e3 10180 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
10181 ino = INTEGERP (image) ? XFASTINT (image) : 0;
10182 if (ino >= gif->ImageCount)
10183 {
45158a91
GM
10184 image_error ("Invalid image number `%s' in image `%s'",
10185 image, img->spec);
333b20bb
GM
10186 DGifCloseFile (gif);
10187 UNGCPRO;
10188 return 0;
10189 }
10190
c7f07c4c
PJ
10191 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
10192 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
333b20bb 10193
333b20bb 10194 /* Create the X image and pixmap. */
45158a91 10195 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 10196 {
333b20bb
GM
10197 DGifCloseFile (gif);
10198 UNGCPRO;
10199 return 0;
10200 }
10201
10202 /* Allocate colors. */
10203 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
10204 if (!gif_color_map)
10205 gif_color_map = gif->SColorMap;
10206 init_color_table ();
10207 bzero (pixel_colors, sizeof pixel_colors);
10208
10209 for (i = 0; i < gif_color_map->ColorCount; ++i)
10210 {
10211 int r = gif_color_map->Colors[i].Red << 8;
10212 int g = gif_color_map->Colors[i].Green << 8;
10213 int b = gif_color_map->Colors[i].Blue << 8;
10214 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
10215 }
10216
10217 img->colors = colors_in_color_table (&img->ncolors);
10218 free_color_table ();
10219
10220 /* Clear the part of the screen image that are not covered by
10221 the image from the GIF file. Full animated GIF support
10222 requires more than can be done here (see the gif89 spec,
10223 disposal methods). Let's simply assume that the part
10224 not covered by a sub-image is in the frame's background color. */
10225 image_top = gif->SavedImages[ino].ImageDesc.Top;
10226 image_left = gif->SavedImages[ino].ImageDesc.Left;
10227 image_width = gif->SavedImages[ino].ImageDesc.Width;
10228 image_height = gif->SavedImages[ino].ImageDesc.Height;
10229
10230 for (y = 0; y < image_top; ++y)
10231 for (x = 0; x < width; ++x)
10232 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10233
10234 for (y = image_top + image_height; y < height; ++y)
10235 for (x = 0; x < width; ++x)
10236 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10237
10238 for (y = image_top; y < image_top + image_height; ++y)
10239 {
10240 for (x = 0; x < image_left; ++x)
10241 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10242 for (x = image_left + image_width; x < width; ++x)
10243 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10244 }
10245
9b784e96
GM
10246 /* Read the GIF image into the X image. We use a local variable
10247 `raster' here because RasterBits below is a char *, and invites
10248 problems with bytes >= 0x80. */
10249 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
10250
333b20bb
GM
10251 if (gif->SavedImages[ino].ImageDesc.Interlace)
10252 {
10253 static int interlace_start[] = {0, 4, 2, 1};
10254 static int interlace_increment[] = {8, 8, 4, 2};
9b207e8e 10255 int pass;
06482119
GM
10256 int row = interlace_start[0];
10257
10258 pass = 0;
333b20bb 10259
06482119 10260 for (y = 0; y < image_height; y++)
333b20bb 10261 {
06482119
GM
10262 if (row >= image_height)
10263 {
10264 row = interlace_start[++pass];
10265 while (row >= image_height)
10266 row = interlace_start[++pass];
10267 }
10268
10269 for (x = 0; x < image_width; x++)
10270 {
9b784e96 10271 int i = raster[(y * image_width) + x];
06482119
GM
10272 XPutPixel (ximg, x + image_left, row + image_top,
10273 pixel_colors[i]);
10274 }
10275
10276 row += interlace_increment[pass];
333b20bb
GM
10277 }
10278 }
10279 else
10280 {
10281 for (y = 0; y < image_height; ++y)
10282 for (x = 0; x < image_width; ++x)
10283 {
9b784e96 10284 int i = raster[y * image_width + x];
333b20bb
GM
10285 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
10286 }
10287 }
10288
10289 DGifCloseFile (gif);
f20a3b7a
MB
10290
10291 /* Maybe fill in the background field while we have ximg handy. */
10292 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10293 IMAGE_BACKGROUND (img, f, ximg);
333b20bb
GM
10294
10295 /* Put the image into the pixmap, then free the X image and its buffer. */
10296 x_put_x_image (f, ximg, img->pixmap, width, height);
10297 x_destroy_x_image (ximg);
333b20bb
GM
10298
10299 UNGCPRO;
10300 return 1;
10301}
10302
10303#endif /* HAVE_GIF != 0 */
10304
10305
10306\f
10307/***********************************************************************
10308 Ghostscript
10309 ***********************************************************************/
10310
10311static int gs_image_p P_ ((Lisp_Object object));
10312static int gs_load P_ ((struct frame *f, struct image *img));
10313static void gs_clear_image P_ ((struct frame *f, struct image *img));
10314
fcf431dc 10315/* The symbol `postscript' identifying images of this type. */
333b20bb 10316
fcf431dc 10317Lisp_Object Qpostscript;
333b20bb
GM
10318
10319/* Keyword symbols. */
10320
10321Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
10322
10323/* Indices of image specification fields in gs_format, below. */
10324
10325enum gs_keyword_index
10326{
10327 GS_TYPE,
10328 GS_PT_WIDTH,
10329 GS_PT_HEIGHT,
10330 GS_FILE,
10331 GS_LOADER,
10332 GS_BOUNDING_BOX,
10333 GS_ASCENT,
10334 GS_MARGIN,
10335 GS_RELIEF,
10336 GS_ALGORITHM,
10337 GS_HEURISTIC_MASK,
4a8e312c 10338 GS_MASK,
f20a3b7a 10339 GS_BACKGROUND,
333b20bb
GM
10340 GS_LAST
10341};
10342
10343/* Vector of image_keyword structures describing the format
10344 of valid user-defined image specifications. */
10345
10346static struct image_keyword gs_format[GS_LAST] =
10347{
10348 {":type", IMAGE_SYMBOL_VALUE, 1},
10349 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10350 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
10351 {":file", IMAGE_STRING_VALUE, 1},
10352 {":loader", IMAGE_FUNCTION_VALUE, 0},
10353 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
7c7ff7f5 10354 {":ascent", IMAGE_ASCENT_VALUE, 0},
3ed61e75 10355 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
333b20bb 10356 {":relief", IMAGE_INTEGER_VALUE, 0},
d2dc8167 10357 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4a8e312c 10358 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
f20a3b7a
MB
10359 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10360 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
333b20bb
GM
10361};
10362
10363/* Structure describing the image type `ghostscript'. */
10364
10365static struct image_type gs_type =
10366{
fcf431dc 10367 &Qpostscript,
333b20bb
GM
10368 gs_image_p,
10369 gs_load,
10370 gs_clear_image,
10371 NULL
10372};
10373
10374
10375/* Free X resources of Ghostscript image IMG which is used on frame F. */
10376
10377static void
10378gs_clear_image (f, img)
10379 struct frame *f;
10380 struct image *img;
10381{
10382 /* IMG->data.ptr_val may contain a recorded colormap. */
10383 xfree (img->data.ptr_val);
10384 x_clear_image (f, img);
10385}
10386
10387
10388/* Return non-zero if OBJECT is a valid Ghostscript image
10389 specification. */
10390
10391static int
10392gs_image_p (object)
10393 Lisp_Object object;
10394{
10395 struct image_keyword fmt[GS_LAST];
10396 Lisp_Object tem;
10397 int i;
10398
10399 bcopy (gs_format, fmt, sizeof fmt);
10400
7c7ff7f5 10401 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
333b20bb
GM
10402 return 0;
10403
10404 /* Bounding box must be a list or vector containing 4 integers. */
10405 tem = fmt[GS_BOUNDING_BOX].value;
10406 if (CONSP (tem))
10407 {
10408 for (i = 0; i < 4; ++i, tem = XCDR (tem))
10409 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
10410 return 0;
10411 if (!NILP (tem))
10412 return 0;
10413 }
10414 else if (VECTORP (tem))
10415 {
10416 if (XVECTOR (tem)->size != 4)
10417 return 0;
10418 for (i = 0; i < 4; ++i)
10419 if (!INTEGERP (XVECTOR (tem)->contents[i]))
10420 return 0;
10421 }
10422 else
10423 return 0;
10424
10425 return 1;
10426}
10427
10428
10429/* Load Ghostscript image IMG for use on frame F. Value is non-zero
10430 if successful. */
10431
10432static int
10433gs_load (f, img)
10434 struct frame *f;
10435 struct image *img;
10436{
10437 char buffer[100];
10438 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
10439 struct gcpro gcpro1, gcpro2;
10440 Lisp_Object frame;
10441 double in_width, in_height;
10442 Lisp_Object pixel_colors = Qnil;
10443
10444 /* Compute pixel size of pixmap needed from the given size in the
10445 image specification. Sizes in the specification are in pt. 1 pt
10446 = 1/72 in, xdpi and ydpi are stored in the frame's X display
10447 info. */
10448 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
10449 in_width = XFASTINT (pt_width) / 72.0;
10450 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
10451 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
10452 in_height = XFASTINT (pt_height) / 72.0;
10453 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
10454
10455 /* Create the pixmap. */
dd00328a 10456 xassert (img->pixmap == None);
333b20bb
GM
10457 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10458 img->width, img->height,
10459 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
333b20bb
GM
10460
10461 if (!img->pixmap)
10462 {
45158a91 10463 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
10464 return 0;
10465 }
10466
10467 /* Call the loader to fill the pixmap. It returns a process object
10468 if successful. We do not record_unwind_protect here because
10469 other places in redisplay like calling window scroll functions
10470 don't either. Let the Lisp loader use `unwind-protect' instead. */
10471 GCPRO2 (window_and_pixmap_id, pixel_colors);
10472
10473 sprintf (buffer, "%lu %lu",
10474 (unsigned long) FRAME_X_WINDOW (f),
10475 (unsigned long) img->pixmap);
10476 window_and_pixmap_id = build_string (buffer);
10477
10478 sprintf (buffer, "%lu %lu",
10479 FRAME_FOREGROUND_PIXEL (f),
10480 FRAME_BACKGROUND_PIXEL (f));
10481 pixel_colors = build_string (buffer);
10482
10483 XSETFRAME (frame, f);
10484 loader = image_spec_value (img->spec, QCloader, NULL);
10485 if (NILP (loader))
10486 loader = intern ("gs-load-image");
10487
10488 img->data.lisp_val = call6 (loader, frame, img->spec,
10489 make_number (img->width),
10490 make_number (img->height),
10491 window_and_pixmap_id,
10492 pixel_colors);
10493 UNGCPRO;
10494 return PROCESSP (img->data.lisp_val);
10495}
10496
10497
10498/* Kill the Ghostscript process that was started to fill PIXMAP on
10499 frame F. Called from XTread_socket when receiving an event
10500 telling Emacs that Ghostscript has finished drawing. */
10501
10502void
10503x_kill_gs_process (pixmap, f)
10504 Pixmap pixmap;
10505 struct frame *f;
10506{
10507 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
10508 int class, i;
10509 struct image *img;
10510
10511 /* Find the image containing PIXMAP. */
10512 for (i = 0; i < c->used; ++i)
10513 if (c->images[i]->pixmap == pixmap)
10514 break;
10515
daba7643
GM
10516 /* Should someone in between have cleared the image cache, for
10517 instance, give up. */
10518 if (i == c->used)
10519 return;
10520
333b20bb
GM
10521 /* Kill the GS process. We should have found PIXMAP in the image
10522 cache and its image should contain a process object. */
333b20bb
GM
10523 img = c->images[i];
10524 xassert (PROCESSP (img->data.lisp_val));
10525 Fkill_process (img->data.lisp_val, Qnil);
10526 img->data.lisp_val = Qnil;
10527
10528 /* On displays with a mutable colormap, figure out the colors
10529 allocated for the image by looking at the pixels of an XImage for
10530 img->pixmap. */
383d6ffc 10531 class = FRAME_X_VISUAL (f)->class;
333b20bb
GM
10532 if (class != StaticColor && class != StaticGray && class != TrueColor)
10533 {
10534 XImage *ximg;
10535
10536 BLOCK_INPUT;
10537
10538 /* Try to get an XImage for img->pixmep. */
10539 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10540 0, 0, img->width, img->height, ~0, ZPixmap);
10541 if (ximg)
10542 {
10543 int x, y;
10544
10545 /* Initialize the color table. */
10546 init_color_table ();
10547
10548 /* For each pixel of the image, look its color up in the
10549 color table. After having done so, the color table will
10550 contain an entry for each color used by the image. */
10551 for (y = 0; y < img->height; ++y)
10552 for (x = 0; x < img->width; ++x)
10553 {
10554 unsigned long pixel = XGetPixel (ximg, x, y);
10555 lookup_pixel_color (f, pixel);
10556 }
10557
10558 /* Record colors in the image. Free color table and XImage. */
10559 img->colors = colors_in_color_table (&img->ncolors);
10560 free_color_table ();
10561 XDestroyImage (ximg);
10562
10563#if 0 /* This doesn't seem to be the case. If we free the colors
10564 here, we get a BadAccess later in x_clear_image when
10565 freeing the colors. */
10566 /* We have allocated colors once, but Ghostscript has also
10567 allocated colors on behalf of us. So, to get the
10568 reference counts right, free them once. */
10569 if (img->ncolors)
462d5d40 10570 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
10571#endif
10572 }
10573 else
10574 image_error ("Cannot get X image of `%s'; colors will not be freed",
45158a91 10575 img->spec, Qnil);
333b20bb
GM
10576
10577 UNBLOCK_INPUT;
10578 }
ad18ffb1
GM
10579
10580 /* Now that we have the pixmap, compute mask and transform the
10581 image if requested. */
10582 BLOCK_INPUT;
10583 postprocess_image (f, img);
10584 UNBLOCK_INPUT;
333b20bb
GM
10585}
10586
10587
10588\f
10589/***********************************************************************
10590 Window properties
10591 ***********************************************************************/
10592
10593DEFUN ("x-change-window-property", Fx_change_window_property,
10594 Sx_change_window_property, 2, 3, 0,
7ee72033 10595 doc: /* Change window property PROP to VALUE on the X window of FRAME.
c061c855 10596PROP and VALUE must be strings. FRAME nil or omitted means use the
7ee72033
MB
10597selected frame. Value is VALUE. */)
10598 (prop, value, frame)
333b20bb
GM
10599 Lisp_Object frame, prop, value;
10600{
10601 struct frame *f = check_x_frame (frame);
10602 Atom prop_atom;
10603
b7826503
PJ
10604 CHECK_STRING (prop);
10605 CHECK_STRING (value);
333b20bb
GM
10606
10607 BLOCK_INPUT;
d5db4077 10608 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
333b20bb
GM
10609 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10610 prop_atom, XA_STRING, 8, PropModeReplace,
d5db4077 10611 SDATA (value), SCHARS (value));
333b20bb
GM
10612
10613 /* Make sure the property is set when we return. */
10614 XFlush (FRAME_X_DISPLAY (f));
10615 UNBLOCK_INPUT;
10616
10617 return value;
10618}
10619
10620
10621DEFUN ("x-delete-window-property", Fx_delete_window_property,
10622 Sx_delete_window_property, 1, 2, 0,
7ee72033
MB
10623 doc: /* Remove window property PROP from X window of FRAME.
10624FRAME nil or omitted means use the selected frame. Value is PROP. */)
10625 (prop, frame)
333b20bb
GM
10626 Lisp_Object prop, frame;
10627{
10628 struct frame *f = check_x_frame (frame);
10629 Atom prop_atom;
10630
b7826503 10631 CHECK_STRING (prop);
333b20bb 10632 BLOCK_INPUT;
d5db4077 10633 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
333b20bb
GM
10634 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
10635
10636 /* Make sure the property is removed when we return. */
10637 XFlush (FRAME_X_DISPLAY (f));
10638 UNBLOCK_INPUT;
10639
10640 return prop;
10641}
10642
10643
10644DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
10645 1, 2, 0,
7ee72033 10646 doc: /* Value is the value of window property PROP on FRAME.
c061c855
GM
10647If FRAME is nil or omitted, use the selected frame. Value is nil
10648if FRAME hasn't a property with name PROP or if PROP has no string
7ee72033
MB
10649value. */)
10650 (prop, frame)
333b20bb
GM
10651 Lisp_Object prop, frame;
10652{
10653 struct frame *f = check_x_frame (frame);
10654 Atom prop_atom;
10655 int rc;
10656 Lisp_Object prop_value = Qnil;
10657 char *tmp_data = NULL;
10658 Atom actual_type;
10659 int actual_format;
10660 unsigned long actual_size, bytes_remaining;
10661
b7826503 10662 CHECK_STRING (prop);
333b20bb 10663 BLOCK_INPUT;
d5db4077 10664 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
333b20bb
GM
10665 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10666 prop_atom, 0, 0, False, XA_STRING,
10667 &actual_type, &actual_format, &actual_size,
10668 &bytes_remaining, (unsigned char **) &tmp_data);
10669 if (rc == Success)
10670 {
10671 int size = bytes_remaining;
10672
10673 XFree (tmp_data);
10674 tmp_data = NULL;
10675
10676 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10677 prop_atom, 0, bytes_remaining,
10678 False, XA_STRING,
10679 &actual_type, &actual_format,
10680 &actual_size, &bytes_remaining,
10681 (unsigned char **) &tmp_data);
4c8c7926 10682 if (rc == Success && tmp_data)
333b20bb
GM
10683 prop_value = make_string (tmp_data, size);
10684
10685 XFree (tmp_data);
10686 }
10687
10688 UNBLOCK_INPUT;
10689 return prop_value;
10690}
10691
10692
10693\f
10694/***********************************************************************
10695 Busy cursor
10696 ***********************************************************************/
10697
4ae9a85e 10698/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 10699 an hourglass cursor on all frames. */
333b20bb 10700
0af913d7 10701static struct atimer *hourglass_atimer;
333b20bb 10702
0af913d7 10703/* Non-zero means an hourglass cursor is currently shown. */
333b20bb 10704
0af913d7 10705static int hourglass_shown_p;
333b20bb 10706
0af913d7 10707/* Number of seconds to wait before displaying an hourglass cursor. */
333b20bb 10708
0af913d7 10709static Lisp_Object Vhourglass_delay;
333b20bb 10710
0af913d7 10711/* Default number of seconds to wait before displaying an hourglass
4ae9a85e
GM
10712 cursor. */
10713
0af913d7 10714#define DEFAULT_HOURGLASS_DELAY 1
4ae9a85e
GM
10715
10716/* Function prototypes. */
10717
0af913d7
GM
10718static void show_hourglass P_ ((struct atimer *));
10719static void hide_hourglass P_ ((void));
4ae9a85e
GM
10720
10721
0af913d7 10722/* Cancel a currently active hourglass timer, and start a new one. */
4ae9a85e
GM
10723
10724void
0af913d7 10725start_hourglass ()
333b20bb 10726{
4ae9a85e 10727 EMACS_TIME delay;
3caa99d3 10728 int secs, usecs = 0;
4ae9a85e 10729
0af913d7 10730 cancel_hourglass ();
4ae9a85e 10731
0af913d7
GM
10732 if (INTEGERP (Vhourglass_delay)
10733 && XINT (Vhourglass_delay) > 0)
10734 secs = XFASTINT (Vhourglass_delay);
10735 else if (FLOATP (Vhourglass_delay)
10736 && XFLOAT_DATA (Vhourglass_delay) > 0)
3caa99d3
GM
10737 {
10738 Lisp_Object tem;
0af913d7 10739 tem = Ftruncate (Vhourglass_delay, Qnil);
3caa99d3 10740 secs = XFASTINT (tem);
0af913d7 10741 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
3caa99d3 10742 }
4ae9a85e 10743 else
0af913d7 10744 secs = DEFAULT_HOURGLASS_DELAY;
4ae9a85e 10745
3caa99d3 10746 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
10747 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
10748 show_hourglass, NULL);
4ae9a85e
GM
10749}
10750
10751
0af913d7 10752/* Cancel the hourglass cursor timer if active, hide a busy cursor if
4ae9a85e
GM
10753 shown. */
10754
10755void
0af913d7 10756cancel_hourglass ()
4ae9a85e 10757{
0af913d7 10758 if (hourglass_atimer)
99f01f62 10759 {
0af913d7
GM
10760 cancel_atimer (hourglass_atimer);
10761 hourglass_atimer = NULL;
99f01f62
GM
10762 }
10763
0af913d7
GM
10764 if (hourglass_shown_p)
10765 hide_hourglass ();
4ae9a85e
GM
10766}
10767
10768
0af913d7
GM
10769/* Timer function of hourglass_atimer. TIMER is equal to
10770 hourglass_atimer.
4ae9a85e 10771
0af913d7
GM
10772 Display an hourglass pointer on all frames by mapping the frames'
10773 hourglass_window. Set the hourglass_p flag in the frames'
10774 output_data.x structure to indicate that an hourglass cursor is
10775 shown on the frames. */
4ae9a85e
GM
10776
10777static void
0af913d7 10778show_hourglass (timer)
4ae9a85e
GM
10779 struct atimer *timer;
10780{
10781 /* The timer implementation will cancel this timer automatically
0af913d7 10782 after this function has run. Set hourglass_atimer to null
4ae9a85e 10783 so that we know the timer doesn't have to be canceled. */
0af913d7 10784 hourglass_atimer = NULL;
4ae9a85e 10785
0af913d7 10786 if (!hourglass_shown_p)
333b20bb
GM
10787 {
10788 Lisp_Object rest, frame;
4ae9a85e
GM
10789
10790 BLOCK_INPUT;
10791
333b20bb 10792 FOR_EACH_FRAME (rest, frame)
5f7a1890
GM
10793 {
10794 struct frame *f = XFRAME (frame);
10795
10796 if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
10797 {
10798 Display *dpy = FRAME_X_DISPLAY (f);
10799
10800#ifdef USE_X_TOOLKIT
10801 if (f->output_data.x->widget)
10802#else
10803 if (FRAME_OUTER_WINDOW (f))
10804#endif
10805 {
0af913d7 10806 f->output_data.x->hourglass_p = 1;
4ae9a85e 10807
0af913d7 10808 if (!f->output_data.x->hourglass_window)
5f7a1890
GM
10809 {
10810 unsigned long mask = CWCursor;
10811 XSetWindowAttributes attrs;
4ae9a85e 10812
0af913d7 10813 attrs.cursor = f->output_data.x->hourglass_cursor;
4ae9a85e 10814
0af913d7 10815 f->output_data.x->hourglass_window
5f7a1890
GM
10816 = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
10817 0, 0, 32000, 32000, 0, 0,
10818 InputOnly,
10819 CopyFromParent,
10820 mask, &attrs);
10821 }
4ae9a85e 10822
0af913d7 10823 XMapRaised (dpy, f->output_data.x->hourglass_window);
5f7a1890
GM
10824 XFlush (dpy);
10825 }
10826 }
10827 }
333b20bb 10828
0af913d7 10829 hourglass_shown_p = 1;
4ae9a85e
GM
10830 UNBLOCK_INPUT;
10831 }
333b20bb
GM
10832}
10833
10834
0af913d7
GM
10835/* Hide the hourglass pointer on all frames, if it is currently
10836 shown. */
333b20bb 10837
4ae9a85e 10838static void
0af913d7 10839hide_hourglass ()
4ae9a85e 10840{
0af913d7 10841 if (hourglass_shown_p)
333b20bb 10842 {
4ae9a85e
GM
10843 Lisp_Object rest, frame;
10844
10845 BLOCK_INPUT;
10846 FOR_EACH_FRAME (rest, frame)
333b20bb 10847 {
4ae9a85e
GM
10848 struct frame *f = XFRAME (frame);
10849
10850 if (FRAME_X_P (f)
10851 /* Watch out for newly created frames. */
0af913d7 10852 && f->output_data.x->hourglass_window)
4ae9a85e 10853 {
0af913d7
GM
10854 XUnmapWindow (FRAME_X_DISPLAY (f),
10855 f->output_data.x->hourglass_window);
10856 /* Sync here because XTread_socket looks at the
10857 hourglass_p flag that is reset to zero below. */
4ae9a85e 10858 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 10859 f->output_data.x->hourglass_p = 0;
4ae9a85e 10860 }
333b20bb 10861 }
333b20bb 10862
0af913d7 10863 hourglass_shown_p = 0;
4ae9a85e
GM
10864 UNBLOCK_INPUT;
10865 }
333b20bb
GM
10866}
10867
10868
10869\f
10870/***********************************************************************
10871 Tool tips
10872 ***********************************************************************/
10873
10874static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
275841bf 10875 Lisp_Object, Lisp_Object));
06d62053 10876static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
ab452f99 10877 Lisp_Object, int, int, int *, int *));
333b20bb 10878
44b5a125 10879/* The frame of a currently visible tooltip. */
333b20bb 10880
44b5a125 10881Lisp_Object tip_frame;
333b20bb
GM
10882
10883/* If non-nil, a timer started that hides the last tooltip when it
10884 fires. */
10885
10886Lisp_Object tip_timer;
10887Window tip_window;
10888
06d62053
GM
10889/* If non-nil, a vector of 3 elements containing the last args
10890 with which x-show-tip was called. See there. */
10891
10892Lisp_Object last_show_tip_args;
10893
d63931a2
GM
10894/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
10895
10896Lisp_Object Vx_max_tooltip_size;
10897
eaf1eea9
GM
10898
10899static Lisp_Object
10900unwind_create_tip_frame (frame)
10901 Lisp_Object frame;
10902{
c844a81a
GM
10903 Lisp_Object deleted;
10904
10905 deleted = unwind_create_frame (frame);
10906 if (EQ (deleted, Qt))
10907 {
10908 tip_window = None;
10909 tip_frame = Qnil;
10910 }
10911
10912 return deleted;
eaf1eea9
GM
10913}
10914
10915
333b20bb 10916/* Create a frame for a tooltip on the display described by DPYINFO.
275841bf
GM
10917 PARMS is a list of frame parameters. TEXT is the string to
10918 display in the tip frame. Value is the frame.
eaf1eea9
GM
10919
10920 Note that functions called here, esp. x_default_parameter can
10921 signal errors, for instance when a specified color name is
10922 undefined. We have to make sure that we're in a consistent state
10923 when this happens. */
333b20bb
GM
10924
10925static Lisp_Object
275841bf 10926x_create_tip_frame (dpyinfo, parms, text)
333b20bb 10927 struct x_display_info *dpyinfo;
275841bf 10928 Lisp_Object parms, text;
333b20bb
GM
10929{
10930 struct frame *f;
10931 Lisp_Object frame, tem;
10932 Lisp_Object name;
333b20bb
GM
10933 long window_prompting = 0;
10934 int width, height;
331379bf 10935 int count = SPECPDL_INDEX ();
b6d7acec 10936 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb 10937 struct kboard *kb;
06d62053 10938 int face_change_count_before = face_change_count;
275841bf
GM
10939 Lisp_Object buffer;
10940 struct buffer *old_buffer;
333b20bb
GM
10941
10942 check_x ();
10943
10944 /* Use this general default value to start with until we know if
10945 this frame has a specified name. */
10946 Vx_resource_name = Vinvocation_name;
10947
10948#ifdef MULTI_KBOARD
10949 kb = dpyinfo->kboard;
10950#else
10951 kb = &the_only_kboard;
10952#endif
10953
10954 /* Get the name of the frame to use for resource lookup. */
10955 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10956 if (!STRINGP (name)
10957 && !EQ (name, Qunbound)
10958 && !NILP (name))
10959 error ("Invalid frame name--not a string or nil");
10960 Vx_resource_name = name;
10961
10962 frame = Qnil;
10963 GCPRO3 (parms, name, frame);
44b5a125 10964 f = make_frame (1);
333b20bb 10965 XSETFRAME (frame, f);
275841bf
GM
10966
10967 buffer = Fget_buffer_create (build_string (" *tip*"));
10968 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10969 old_buffer = current_buffer;
10970 set_buffer_internal_1 (XBUFFER (buffer));
d63931a2 10971 current_buffer->truncate_lines = Qnil;
275841bf
GM
10972 Ferase_buffer ();
10973 Finsert (1, &text);
10974 set_buffer_internal_1 (old_buffer);
10975
333b20bb 10976 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
8a1a7743 10977 record_unwind_protect (unwind_create_tip_frame, frame);
333b20bb 10978
eaf1eea9
GM
10979 /* By setting the output method, we're essentially saying that
10980 the frame is live, as per FRAME_LIVE_P. If we get a signal
10981 from this point on, x_destroy_window might screw up reference
10982 counts etc. */
333b20bb
GM
10983 f->output_method = output_x_window;
10984 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10985 bzero (f->output_data.x, sizeof (struct x_output));
10986 f->output_data.x->icon_bitmap = -1;
10987 f->output_data.x->fontset = -1;
61d461a8
GM
10988 f->output_data.x->scroll_bar_foreground_pixel = -1;
10989 f->output_data.x->scroll_bar_background_pixel = -1;
f15340b7
MB
10990#ifdef USE_TOOLKIT_SCROLL_BARS
10991 f->output_data.x->scroll_bar_top_shadow_pixel = -1;
10992 f->output_data.x->scroll_bar_bottom_shadow_pixel = -1;
10993#endif /* USE_TOOLKIT_SCROLL_BARS */
333b20bb
GM
10994 f->icon_name = Qnil;
10995 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
f1d2ce7f 10996#if GLYPH_DEBUG
eaf1eea9
GM
10997 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
10998 dpyinfo_refcount = dpyinfo->reference_count;
10999#endif /* GLYPH_DEBUG */
333b20bb
GM
11000#ifdef MULTI_KBOARD
11001 FRAME_KBOARD (f) = kb;
11002#endif
11003 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
11004 f->output_data.x->explicit_parent = 0;
11005
61d461a8
GM
11006 /* These colors will be set anyway later, but it's important
11007 to get the color reference counts right, so initialize them! */
11008 {
11009 Lisp_Object black;
11010 struct gcpro gcpro1;
11011
11012 black = build_string ("black");
11013 GCPRO1 (black);
11014 f->output_data.x->foreground_pixel
11015 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11016 f->output_data.x->background_pixel
11017 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11018 f->output_data.x->cursor_pixel
11019 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11020 f->output_data.x->cursor_foreground_pixel
11021 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11022 f->output_data.x->border_pixel
11023 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11024 f->output_data.x->mouse_pixel
11025 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
11026 UNGCPRO;
11027 }
11028
333b20bb
GM
11029 /* Set the name; the functions to which we pass f expect the name to
11030 be set. */
11031 if (EQ (name, Qunbound) || NILP (name))
11032 {
11033 f->name = build_string (dpyinfo->x_id_name);
11034 f->explicit_name = 0;
11035 }
11036 else
11037 {
11038 f->name = name;
11039 f->explicit_name = 1;
11040 /* use the frame's title when getting resources for this frame. */
11041 specbind (Qx_resource_name, name);
11042 }
11043
eaf1eea9
GM
11044 /* Extract the window parameters from the supplied values that are
11045 needed to determine window geometry. */
333b20bb
GM
11046 {
11047 Lisp_Object font;
11048
11049 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
11050
11051 BLOCK_INPUT;
11052 /* First, try whatever font the caller has specified. */
11053 if (STRINGP (font))
11054 {
11055 tem = Fquery_fontset (font, Qnil);
11056 if (STRINGP (tem))
d5db4077 11057 font = x_new_fontset (f, SDATA (tem));
333b20bb 11058 else
d5db4077 11059 font = x_new_font (f, SDATA (font));
333b20bb
GM
11060 }
11061
11062 /* Try out a font which we hope has bold and italic variations. */
11063 if (!STRINGP (font))
11064 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
11065 if (!STRINGP (font))
11066 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11067 if (! STRINGP (font))
11068 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11069 if (! STRINGP (font))
11070 /* This was formerly the first thing tried, but it finds too many fonts
11071 and takes too long. */
11072 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
11073 /* If those didn't work, look for something which will at least work. */
11074 if (! STRINGP (font))
11075 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
11076 UNBLOCK_INPUT;
11077 if (! STRINGP (font))
11078 font = build_string ("fixed");
11079
11080 x_default_parameter (f, parms, Qfont, font,
11081 "font", "Font", RES_TYPE_STRING);
11082 }
11083
11084 x_default_parameter (f, parms, Qborder_width, make_number (2),
11085 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
11086
11087 /* This defaults to 2 in order to match xterm. We recognize either
11088 internalBorderWidth or internalBorder (which is what xterm calls
11089 it). */
11090 if (NILP (Fassq (Qinternal_border_width, parms)))
11091 {
11092 Lisp_Object value;
11093
11094 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
11095 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
11096 if (! EQ (value, Qunbound))
11097 parms = Fcons (Fcons (Qinternal_border_width, value),
11098 parms);
11099 }
11100
11101 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
11102 "internalBorderWidth", "internalBorderWidth",
11103 RES_TYPE_NUMBER);
11104
11105 /* Also do the stuff which must be set before the window exists. */
11106 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
11107 "foreground", "Foreground", RES_TYPE_STRING);
11108 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
11109 "background", "Background", RES_TYPE_STRING);
11110 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
11111 "pointerColor", "Foreground", RES_TYPE_STRING);
11112 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
11113 "cursorColor", "Foreground", RES_TYPE_STRING);
11114 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
11115 "borderColor", "BorderColor", RES_TYPE_STRING);
11116
11117 /* Init faces before x_default_parameter is called for scroll-bar
11118 parameters because that function calls x_set_scroll_bar_width,
11119 which calls change_frame_size, which calls Fset_window_buffer,
11120 which runs hooks, which call Fvertical_motion. At the end, we
11121 end up in init_iterator with a null face cache, which should not
11122 happen. */
11123 init_frame_faces (f);
11124
11125 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
11126 window_prompting = x_figure_window_size (f, parms);
11127
11128 if (window_prompting & XNegative)
11129 {
11130 if (window_prompting & YNegative)
11131 f->output_data.x->win_gravity = SouthEastGravity;
11132 else
11133 f->output_data.x->win_gravity = NorthEastGravity;
11134 }
11135 else
11136 {
11137 if (window_prompting & YNegative)
11138 f->output_data.x->win_gravity = SouthWestGravity;
11139 else
11140 f->output_data.x->win_gravity = NorthWestGravity;
11141 }
11142
11143 f->output_data.x->size_hint_flags = window_prompting;
11144 {
11145 XSetWindowAttributes attrs;
11146 unsigned long mask;
11147
11148 BLOCK_INPUT;
c51d2b5e
GM
11149 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
11150 if (DoesSaveUnders (dpyinfo->screen))
11151 mask |= CWSaveUnder;
11152
9b2956e2
GM
11153 /* Window managers look at the override-redirect flag to determine
11154 whether or net to give windows a decoration (Xlib spec, chapter
333b20bb
GM
11155 3.2.8). */
11156 attrs.override_redirect = True;
11157 attrs.save_under = True;
11158 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
11159 /* Arrange for getting MapNotify and UnmapNotify events. */
11160 attrs.event_mask = StructureNotifyMask;
11161 tip_window
11162 = FRAME_X_WINDOW (f)
11163 = XCreateWindow (FRAME_X_DISPLAY (f),
11164 FRAME_X_DISPLAY_INFO (f)->root_window,
11165 /* x, y, width, height */
11166 0, 0, 1, 1,
11167 /* Border. */
11168 1,
11169 CopyFromParent, InputOutput, CopyFromParent,
11170 mask, &attrs);
11171 UNBLOCK_INPUT;
11172 }
11173
11174 x_make_gc (f);
11175
333b20bb
GM
11176 x_default_parameter (f, parms, Qauto_raise, Qnil,
11177 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11178 x_default_parameter (f, parms, Qauto_lower, Qnil,
11179 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11180 x_default_parameter (f, parms, Qcursor_type, Qbox,
11181 "cursorType", "CursorType", RES_TYPE_SYMBOL);
11182
11183 /* Dimensions, especially f->height, must be done via change_frame_size.
11184 Change will not be effected unless different from the current
11185 f->height. */
11186 width = f->width;
11187 height = f->height;
11188 f->height = 0;
11189 SET_FRAME_WIDTH (f, 0);
8938a4fb 11190 change_frame_size (f, height, width, 1, 0, 0);
333b20bb 11191
035d5114 11192 /* Set up faces after all frame parameters are known. This call
6801a572
GM
11193 also merges in face attributes specified for new frames.
11194
11195 Frame parameters may be changed if .Xdefaults contains
11196 specifications for the default font. For example, if there is an
11197 `Emacs.default.attributeBackground: pink', the `background-color'
11198 attribute of the frame get's set, which let's the internal border
11199 of the tooltip frame appear in pink. Prevent this. */
11200 {
11201 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
11202
11203 /* Set tip_frame here, so that */
11204 tip_frame = frame;
11205 call1 (Qface_set_after_frame_default, frame);
11206
11207 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
11208 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
11209 Qnil));
11210 }
035d5114 11211
333b20bb
GM
11212 f->no_split = 1;
11213
11214 UNGCPRO;
11215
11216 /* It is now ok to make the frame official even if we get an error
11217 below. And the frame needs to be on Vframe_list or making it
11218 visible won't work. */
11219 Vframe_list = Fcons (frame, Vframe_list);
11220
11221 /* Now that the frame is official, it counts as a reference to
11222 its display. */
11223 FRAME_X_DISPLAY_INFO (f)->reference_count++;
11224
06d62053
GM
11225 /* Setting attributes of faces of the tooltip frame from resources
11226 and similar will increment face_change_count, which leads to the
11227 clearing of all current matrices. Since this isn't necessary
11228 here, avoid it by resetting face_change_count to the value it
11229 had before we created the tip frame. */
11230 face_change_count = face_change_count_before;
11231
eaf1eea9 11232 /* Discard the unwind_protect. */
333b20bb
GM
11233 return unbind_to (count, frame);
11234}
11235
11236
06d62053
GM
11237/* Compute where to display tip frame F. PARMS is the list of frame
11238 parameters for F. DX and DY are specified offsets from the current
ab452f99
GM
11239 location of the mouse. WIDTH and HEIGHT are the width and height
11240 of the tooltip. Return coordinates relative to the root window of
11241 the display in *ROOT_X, and *ROOT_Y. */
06d62053
GM
11242
11243static void
ab452f99 11244compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
06d62053
GM
11245 struct frame *f;
11246 Lisp_Object parms, dx, dy;
ab452f99 11247 int width, height;
06d62053
GM
11248 int *root_x, *root_y;
11249{
11250 Lisp_Object left, top;
11251 int win_x, win_y;
11252 Window root, child;
11253 unsigned pmask;
11254
11255 /* User-specified position? */
11256 left = Fcdr (Fassq (Qleft, parms));
11257 top = Fcdr (Fassq (Qtop, parms));
11258
11259 /* Move the tooltip window where the mouse pointer is. Resize and
11260 show it. */
570d22b0 11261 if (!INTEGERP (left) || !INTEGERP (top))
ab452f99
GM
11262 {
11263 BLOCK_INPUT;
11264 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
11265 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
11266 UNBLOCK_INPUT;
11267 }
06d62053 11268
06d62053
GM
11269 if (INTEGERP (top))
11270 *root_y = XINT (top);
ab452f99
GM
11271 else if (*root_y + XINT (dy) - height < 0)
11272 *root_y -= XINT (dy);
11273 else
11274 {
11275 *root_y -= height;
11276 *root_y += XINT (dy);
11277 }
11278
11279 if (INTEGERP (left))
11280 *root_x = XINT (left);
d682d3df
RS
11281 else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width)
11282 /* It fits to the right of the pointer. */
11283 *root_x += XINT (dx);
11284 else if (width + XINT (dx) <= *root_x)
11285 /* It fits to the left of the pointer. */
ab452f99
GM
11286 *root_x -= width + XINT (dx);
11287 else
d682d3df
RS
11288 /* Put it left-justified on the screen--it ought to fit that way. */
11289 *root_x = 0;
06d62053
GM
11290}
11291
11292
0634ce98 11293DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
7ee72033 11294 doc: /* Show STRING in a "tooltip" window on frame FRAME.
c061c855
GM
11295A tooltip window is a small X window displaying a string.
11296
11297FRAME nil or omitted means use the selected frame.
11298
11299PARMS is an optional list of frame parameters which can be used to
11300change the tooltip's appearance.
11301
11302Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
11303means use the default timeout of 5 seconds.
11304
11305If the list of frame parameters PARAMS contains a `left' parameters,
11306the tooltip is displayed at that x-position. Otherwise it is
11307displayed at the mouse position, with offset DX added (default is 5 if
11308DX isn't specified). Likewise for the y-position; if a `top' frame
11309parameter is specified, it determines the y-position of the tooltip
11310window, otherwise it is displayed at the mouse position, with offset
11311DY added (default is -10).
11312
11313A tooltip's maximum size is specified by `x-max-tooltip-size'.
7ee72033
MB
11314Text larger than the specified size is clipped. */)
11315 (string, frame, parms, timeout, dx, dy)
0634ce98 11316 Lisp_Object string, frame, parms, timeout, dx, dy;
333b20bb
GM
11317{
11318 struct frame *f;
11319 struct window *w;
06d62053 11320 int root_x, root_y;
333b20bb
GM
11321 struct buffer *old_buffer;
11322 struct text_pos pos;
11323 int i, width, height;
393f2d14 11324 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
333b20bb 11325 int old_windows_or_buffers_changed = windows_or_buffers_changed;
331379bf 11326 int count = SPECPDL_INDEX ();
333b20bb
GM
11327
11328 specbind (Qinhibit_redisplay, Qt);
11329
393f2d14 11330 GCPRO4 (string, parms, frame, timeout);
333b20bb 11331
b7826503 11332 CHECK_STRING (string);
333b20bb
GM
11333 f = check_x_frame (frame);
11334 if (NILP (timeout))
11335 timeout = make_number (5);
11336 else
b7826503 11337 CHECK_NATNUM (timeout);
0634ce98
GM
11338
11339 if (NILP (dx))
11340 dx = make_number (5);
11341 else
b7826503 11342 CHECK_NUMBER (dx);
0634ce98
GM
11343
11344 if (NILP (dy))
12c67a7f 11345 dy = make_number (-10);
0634ce98 11346 else
b7826503 11347 CHECK_NUMBER (dy);
333b20bb 11348
06d62053
GM
11349 if (NILP (last_show_tip_args))
11350 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
11351
11352 if (!NILP (tip_frame))
11353 {
11354 Lisp_Object last_string = AREF (last_show_tip_args, 0);
11355 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
11356 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
11357
11358 if (EQ (frame, last_frame)
11359 && !NILP (Fequal (last_string, string))
11360 && !NILP (Fequal (last_parms, parms)))
11361 {
11362 struct frame *f = XFRAME (tip_frame);
11363
11364 /* Only DX and DY have changed. */
11365 if (!NILP (tip_timer))
ae782866
GM
11366 {
11367 Lisp_Object timer = tip_timer;
11368 tip_timer = Qnil;
11369 call1 (Qcancel_timer, timer);
11370 }
06d62053
GM
11371
11372 BLOCK_INPUT;
ab452f99
GM
11373 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
11374 PIXEL_HEIGHT (f), &root_x, &root_y);
06d62053 11375 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11376 root_x, root_y);
06d62053
GM
11377 UNBLOCK_INPUT;
11378 goto start_timer;
11379 }
11380 }
11381
333b20bb
GM
11382 /* Hide a previous tip, if any. */
11383 Fx_hide_tip ();
11384
06d62053
GM
11385 ASET (last_show_tip_args, 0, string);
11386 ASET (last_show_tip_args, 1, frame);
11387 ASET (last_show_tip_args, 2, parms);
11388
333b20bb
GM
11389 /* Add default values to frame parameters. */
11390 if (NILP (Fassq (Qname, parms)))
11391 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
11392 if (NILP (Fassq (Qinternal_border_width, parms)))
11393 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
11394 if (NILP (Fassq (Qborder_width, parms)))
11395 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
11396 if (NILP (Fassq (Qborder_color, parms)))
11397 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
11398 if (NILP (Fassq (Qbackground_color, parms)))
11399 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
11400 parms);
11401
11402 /* Create a frame for the tooltip, and record it in the global
11403 variable tip_frame. */
275841bf 11404 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
44b5a125 11405 f = XFRAME (frame);
333b20bb 11406
d63931a2 11407 /* Set up the frame's root window. */
333b20bb
GM
11408 w = XWINDOW (FRAME_ROOT_WINDOW (f));
11409 w->left = w->top = make_number (0);
d63931a2
GM
11410
11411 if (CONSP (Vx_max_tooltip_size)
11412 && INTEGERP (XCAR (Vx_max_tooltip_size))
11413 && XINT (XCAR (Vx_max_tooltip_size)) > 0
11414 && INTEGERP (XCDR (Vx_max_tooltip_size))
11415 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
11416 {
11417 w->width = XCAR (Vx_max_tooltip_size);
11418 w->height = XCDR (Vx_max_tooltip_size);
11419 }
11420 else
11421 {
11422 w->width = make_number (80);
11423 w->height = make_number (40);
11424 }
11425
11426 f->window_width = XINT (w->width);
333b20bb
GM
11427 adjust_glyphs (f);
11428 w->pseudo_window_p = 1;
11429
11430 /* Display the tooltip text in a temporary buffer. */
333b20bb 11431 old_buffer = current_buffer;
275841bf 11432 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
d63931a2 11433 current_buffer->truncate_lines = Qnil;
333b20bb
GM
11434 clear_glyph_matrix (w->desired_matrix);
11435 clear_glyph_matrix (w->current_matrix);
11436 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
11437 try_window (FRAME_ROOT_WINDOW (f), pos);
11438
11439 /* Compute width and height of the tooltip. */
11440 width = height = 0;
11441 for (i = 0; i < w->desired_matrix->nrows; ++i)
11442 {
11443 struct glyph_row *row = &w->desired_matrix->rows[i];
11444 struct glyph *last;
11445 int row_width;
11446
11447 /* Stop at the first empty row at the end. */
11448 if (!row->enabled_p || !row->displays_text_p)
11449 break;
11450
d7bf0342
GM
11451 /* Let the row go over the full width of the frame. */
11452 row->full_width_p = 1;
333b20bb 11453
e3130015 11454 /* There's a glyph at the end of rows that is used to place
333b20bb
GM
11455 the cursor there. Don't include the width of this glyph. */
11456 if (row->used[TEXT_AREA])
11457 {
11458 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
11459 row_width = row->pixel_width - last->pixel_width;
11460 }
11461 else
11462 row_width = row->pixel_width;
11463
11464 height += row->height;
11465 width = max (width, row_width);
11466 }
11467
11468 /* Add the frame's internal border to the width and height the X
11469 window should have. */
11470 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11471 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11472
11473 /* Move the tooltip window where the mouse pointer is. Resize and
11474 show it. */
ab452f99 11475 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
0634ce98 11476
0634ce98 11477 BLOCK_INPUT;
333b20bb 11478 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
ab452f99 11479 root_x, root_y, width, height);
333b20bb
GM
11480 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11481 UNBLOCK_INPUT;
06d62053 11482
333b20bb
GM
11483 /* Draw into the window. */
11484 w->must_be_updated_p = 1;
11485 update_single_window (w, 1);
11486
11487 /* Restore original current buffer. */
11488 set_buffer_internal_1 (old_buffer);
11489 windows_or_buffers_changed = old_windows_or_buffers_changed;
11490
06d62053 11491 start_timer:
333b20bb
GM
11492 /* Let the tip disappear after timeout seconds. */
11493 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
11494 intern ("x-hide-tip"));
a744a2ec
DL
11495
11496 UNGCPRO;
333b20bb
GM
11497 return unbind_to (count, Qnil);
11498}
11499
11500
11501DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
7ee72033
MB
11502 doc: /* Hide the current tooltip window, if there is any.
11503Value is t if tooltip was open, nil otherwise. */)
11504 ()
333b20bb 11505{
44b5a125 11506 int count;
c0006262
GM
11507 Lisp_Object deleted, frame, timer;
11508 struct gcpro gcpro1, gcpro2;
44b5a125
GM
11509
11510 /* Return quickly if nothing to do. */
c0006262 11511 if (NILP (tip_timer) && NILP (tip_frame))
44b5a125 11512 return Qnil;
333b20bb 11513
c0006262
GM
11514 frame = tip_frame;
11515 timer = tip_timer;
11516 GCPRO2 (frame, timer);
11517 tip_frame = tip_timer = deleted = Qnil;
11518
331379bf 11519 count = SPECPDL_INDEX ();
333b20bb 11520 specbind (Qinhibit_redisplay, Qt);
44b5a125 11521 specbind (Qinhibit_quit, Qt);
333b20bb 11522
c0006262 11523 if (!NILP (timer))
ae782866 11524 call1 (Qcancel_timer, timer);
333b20bb 11525
c0006262 11526 if (FRAMEP (frame))
333b20bb 11527 {
44b5a125
GM
11528 Fdelete_frame (frame, Qnil);
11529 deleted = Qt;
f6c44811
GM
11530
11531#ifdef USE_LUCID
11532 /* Bloodcurdling hack alert: The Lucid menu bar widget's
11533 redisplay procedure is not called when a tip frame over menu
11534 items is unmapped. Redisplay the menu manually... */
11535 {
11536 struct frame *f = SELECTED_FRAME ();
11537 Widget w = f->output_data.x->menubar_widget;
11538 extern void xlwmenu_redisplay P_ ((Widget));
9180dc8c 11539
f6c44811 11540 if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
dbc64aa7 11541 && w != NULL)
f6c44811
GM
11542 {
11543 BLOCK_INPUT;
11544 xlwmenu_redisplay (w);
11545 UNBLOCK_INPUT;
11546 }
11547 }
11548#endif /* USE_LUCID */
333b20bb
GM
11549 }
11550
c0006262 11551 UNGCPRO;
44b5a125 11552 return unbind_to (count, deleted);
333b20bb
GM
11553}
11554
11555
11556\f
11557/***********************************************************************
11558 File selection dialog
11559 ***********************************************************************/
11560
11561#ifdef USE_MOTIF
11562
11563/* Callback for "OK" and "Cancel" on file selection dialog. */
11564
11565static void
11566file_dialog_cb (widget, client_data, call_data)
11567 Widget widget;
11568 XtPointer call_data, client_data;
11569{
11570 int *result = (int *) client_data;
11571 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
11572 *result = cb->reason;
11573}
11574
11575
a779d213
GM
11576/* Callback for unmapping a file selection dialog. This is used to
11577 capture the case where a dialog is closed via a window manager's
11578 closer button, for example. Using a XmNdestroyCallback didn't work
11579 in this case. */
11580
11581static void
11582file_dialog_unmap_cb (widget, client_data, call_data)
11583 Widget widget;
11584 XtPointer call_data, client_data;
11585{
11586 int *result = (int *) client_data;
11587 *result = XmCR_CANCEL;
11588}
11589
11590
333b20bb 11591DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
7ee72033 11592 doc: /* Read file name, prompting with PROMPT in directory DIR.
c061c855
GM
11593Use a file selection dialog.
11594Select DEFAULT-FILENAME in the dialog's file selection box, if
11595specified. Don't let the user enter a file name in the file
7ee72033
MB
11596selection dialog's entry field, if MUSTMATCH is non-nil. */)
11597 (prompt, dir, default_filename, mustmatch)
333b20bb
GM
11598 Lisp_Object prompt, dir, default_filename, mustmatch;
11599{
11600 int result;
0fe92f72 11601 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
11602 Lisp_Object file = Qnil;
11603 Widget dialog, text, list, help;
11604 Arg al[10];
11605 int ac = 0;
11606 extern XtAppContext Xt_app_con;
333b20bb 11607 XmString dir_xmstring, pattern_xmstring;
65b21658 11608 int count = SPECPDL_INDEX ();
333b20bb
GM
11609 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
11610
11611 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
11612 CHECK_STRING (prompt);
11613 CHECK_STRING (dir);
333b20bb
GM
11614
11615 /* Prevent redisplay. */
11616 specbind (Qinhibit_redisplay, Qt);
11617
11618 BLOCK_INPUT;
11619
11620 /* Create the dialog with PROMPT as title, using DIR as initial
11621 directory and using "*" as pattern. */
11622 dir = Fexpand_file_name (dir, Qnil);
d5db4077 11623 dir_xmstring = XmStringCreateLocalized (SDATA (dir));
333b20bb
GM
11624 pattern_xmstring = XmStringCreateLocalized ("*");
11625
d5db4077 11626 XtSetArg (al[ac], XmNtitle, SDATA (prompt)); ++ac;
333b20bb
GM
11627 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
11628 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
11629 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
11630 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
11631 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
11632 "fsb", al, ac);
11633 XmStringFree (dir_xmstring);
11634 XmStringFree (pattern_xmstring);
11635
11636 /* Add callbacks for OK and Cancel. */
11637 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
11638 (XtPointer) &result);
11639 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
11640 (XtPointer) &result);
a779d213
GM
11641 XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
11642 (XtPointer) &result);
333b20bb
GM
11643
11644 /* Disable the help button since we can't display help. */
11645 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
11646 XtSetSensitive (help, False);
11647
11648 /* Mark OK button as default. */
11649 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
11650 XmNshowAsDefault, True, NULL);
11651
11652 /* If MUSTMATCH is non-nil, disable the file entry field of the
11653 dialog, so that the user must select a file from the files list
11654 box. We can't remove it because we wouldn't have a way to get at
11655 the result file name, then. */
11656 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
11657 if (!NILP (mustmatch))
11658 {
11659 Widget label;
11660 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
11661 XtSetSensitive (text, False);
11662 XtSetSensitive (label, False);
11663 }
11664
11665 /* Manage the dialog, so that list boxes get filled. */
11666 XtManageChild (dialog);
11667
11668 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
11669 must include the path for this to work. */
11670 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
11671 if (STRINGP (default_filename))
11672 {
11673 XmString default_xmstring;
11674 int item_pos;
11675
11676 default_xmstring
d5db4077 11677 = XmStringCreateLocalized (SDATA (default_filename));
333b20bb
GM
11678
11679 if (!XmListItemExists (list, default_xmstring))
11680 {
11681 /* Add a new item if DEFAULT_FILENAME is not in the list. */
11682 XmListAddItem (list, default_xmstring, 0);
11683 item_pos = 0;
11684 }
11685 else
11686 item_pos = XmListItemPos (list, default_xmstring);
11687 XmStringFree (default_xmstring);
11688
11689 /* Select the item and scroll it into view. */
11690 XmListSelectPos (list, item_pos, True);
11691 XmListSetPos (list, item_pos);
11692 }
11693
563b384d
GM
11694 /* Process events until the user presses Cancel or OK. Block
11695 and unblock input here so that we get a chance of processing
11696 expose events. */
11697 UNBLOCK_INPUT;
03100098 11698 result = 0;
a779d213 11699 while (result == 0)
563b384d
GM
11700 {
11701 BLOCK_INPUT;
11702 XtAppProcessEvent (Xt_app_con, XtIMAll);
11703 UNBLOCK_INPUT;
11704 }
11705 BLOCK_INPUT;
03100098 11706
333b20bb
GM
11707 /* Get the result. */
11708 if (result == XmCR_OK)
11709 {
11710 XmString text;
11711 String data;
11712
d1670063 11713 XtVaGetValues (dialog, XmNtextString, &text, NULL);
333b20bb
GM
11714 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
11715 XmStringFree (text);
11716 file = build_string (data);
11717 XtFree (data);
11718 }
11719 else
11720 file = Qnil;
11721
11722 /* Clean up. */
11723 XtUnmanageChild (dialog);
11724 XtDestroyWidget (dialog);
11725 UNBLOCK_INPUT;
11726 UNGCPRO;
11727
11728 /* Make "Cancel" equivalent to C-g. */
11729 if (NILP (file))
11730 Fsignal (Qquit, Qnil);
11731
11732 return unbind_to (count, file);
11733}
11734
11735#endif /* USE_MOTIF */
11736
333b20bb
GM
11737
11738\f
82bab41c
GM
11739/***********************************************************************
11740 Keyboard
11741 ***********************************************************************/
11742
11743#ifdef HAVE_XKBGETKEYBOARD
11744#include <X11/XKBlib.h>
11745#include <X11/keysym.h>
11746#endif
11747
11748DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
11749 Sx_backspace_delete_keys_p, 0, 1, 0,
7ee72033 11750 doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME.
c061c855
GM
11751FRAME nil means use the selected frame.
11752Value is t if we know that both keys are present, and are mapped to the
7ee72033
MB
11753usual X keysyms. */)
11754 (frame)
82bab41c
GM
11755 Lisp_Object frame;
11756{
11757#ifdef HAVE_XKBGETKEYBOARD
11758 XkbDescPtr kb;
11759 struct frame *f = check_x_frame (frame);
11760 Display *dpy = FRAME_X_DISPLAY (f);
11761 Lisp_Object have_keys;
46f6a258 11762 int major, minor, op, event, error;
82bab41c
GM
11763
11764 BLOCK_INPUT;
46f6a258
GM
11765
11766 /* Check library version in case we're dynamically linked. */
11767 major = XkbMajorVersion;
11768 minor = XkbMinorVersion;
11769 if (!XkbLibraryVersion (&major, &minor))
c1efd260
GM
11770 {
11771 UNBLOCK_INPUT;
11772 return Qnil;
11773 }
46f6a258
GM
11774
11775 /* Check that the server supports XKB. */
11776 major = XkbMajorVersion;
11777 minor = XkbMinorVersion;
11778 if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
c1efd260
GM
11779 {
11780 UNBLOCK_INPUT;
11781 return Qnil;
11782 }
46f6a258
GM
11783
11784 have_keys = Qnil;
c1efd260 11785 kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
82bab41c
GM
11786 if (kb)
11787 {
11788 int delete_keycode = 0, backspace_keycode = 0, i;
c1efd260
GM
11789
11790 if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
82bab41c 11791 {
c1efd260
GM
11792 for (i = kb->min_key_code;
11793 (i < kb->max_key_code
11794 && (delete_keycode == 0 || backspace_keycode == 0));
11795 ++i)
11796 {
d63931a2
GM
11797 /* The XKB symbolic key names can be seen most easily in
11798 the PS file generated by `xkbprint -label name
11799 $DISPLAY'. */
c1efd260
GM
11800 if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
11801 delete_keycode = i;
11802 else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
11803 backspace_keycode = i;
11804 }
11805
11806 XkbFreeNames (kb, 0, True);
82bab41c
GM
11807 }
11808
c1efd260 11809 XkbFreeClientMap (kb, 0, True);
82bab41c
GM
11810
11811 if (delete_keycode
11812 && backspace_keycode
11813 && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
11814 && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
11815 have_keys = Qt;
11816 }
11817 UNBLOCK_INPUT;
11818 return have_keys;
11819#else /* not HAVE_XKBGETKEYBOARD */
11820 return Qnil;
11821#endif /* not HAVE_XKBGETKEYBOARD */
11822}
11823
11824
11825\f
333b20bb
GM
11826/***********************************************************************
11827 Initialization
11828 ***********************************************************************/
11829
11830void
11831syms_of_xfns ()
11832{
11833 /* This is zero if not using X windows. */
11834 x_in_use = 0;
11835
11836 /* The section below is built by the lisp expression at the top of the file,
11837 just above where these variables are declared. */
11838 /*&&& init symbols here &&&*/
11839 Qauto_raise = intern ("auto-raise");
11840 staticpro (&Qauto_raise);
11841 Qauto_lower = intern ("auto-lower");
11842 staticpro (&Qauto_lower);
11843 Qbar = intern ("bar");
dbc4e1c1 11844 staticpro (&Qbar);
a9653085
EZ
11845 Qhbar = intern ("hbar");
11846 staticpro (&Qhbar);
f9942c9e
JB
11847 Qborder_color = intern ("border-color");
11848 staticpro (&Qborder_color);
11849 Qborder_width = intern ("border-width");
11850 staticpro (&Qborder_width);
dbc4e1c1
JB
11851 Qbox = intern ("box");
11852 staticpro (&Qbox);
f9942c9e
JB
11853 Qcursor_color = intern ("cursor-color");
11854 staticpro (&Qcursor_color);
dbc4e1c1
JB
11855 Qcursor_type = intern ("cursor-type");
11856 staticpro (&Qcursor_type);
f9942c9e
JB
11857 Qgeometry = intern ("geometry");
11858 staticpro (&Qgeometry);
f9942c9e
JB
11859 Qicon_left = intern ("icon-left");
11860 staticpro (&Qicon_left);
11861 Qicon_top = intern ("icon-top");
11862 staticpro (&Qicon_top);
11863 Qicon_type = intern ("icon-type");
11864 staticpro (&Qicon_type);
80534dd6
KH
11865 Qicon_name = intern ("icon-name");
11866 staticpro (&Qicon_name);
f9942c9e
JB
11867 Qinternal_border_width = intern ("internal-border-width");
11868 staticpro (&Qinternal_border_width);
11869 Qleft = intern ("left");
11870 staticpro (&Qleft);
1ab3d87e
RS
11871 Qright = intern ("right");
11872 staticpro (&Qright);
f9942c9e
JB
11873 Qmouse_color = intern ("mouse-color");
11874 staticpro (&Qmouse_color);
baaed68e
JB
11875 Qnone = intern ("none");
11876 staticpro (&Qnone);
f9942c9e
JB
11877 Qparent_id = intern ("parent-id");
11878 staticpro (&Qparent_id);
4701395c
KH
11879 Qscroll_bar_width = intern ("scroll-bar-width");
11880 staticpro (&Qscroll_bar_width);
8af1d7ca
JB
11881 Qsuppress_icon = intern ("suppress-icon");
11882 staticpro (&Qsuppress_icon);
01f1ba30 11883 Qundefined_color = intern ("undefined-color");
f9942c9e 11884 staticpro (&Qundefined_color);
a3c87d4e
JB
11885 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
11886 staticpro (&Qvertical_scroll_bars);
49795535
JB
11887 Qvisibility = intern ("visibility");
11888 staticpro (&Qvisibility);
f9942c9e
JB
11889 Qwindow_id = intern ("window-id");
11890 staticpro (&Qwindow_id);
2cbebefb
RS
11891 Qouter_window_id = intern ("outer-window-id");
11892 staticpro (&Qouter_window_id);
f9942c9e
JB
11893 Qx_frame_parameter = intern ("x-frame-parameter");
11894 staticpro (&Qx_frame_parameter);
9ef48a9d
RS
11895 Qx_resource_name = intern ("x-resource-name");
11896 staticpro (&Qx_resource_name);
4fe1de12
RS
11897 Quser_position = intern ("user-position");
11898 staticpro (&Quser_position);
11899 Quser_size = intern ("user-size");
11900 staticpro (&Quser_size);
333b20bb
GM
11901 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
11902 staticpro (&Qscroll_bar_foreground);
11903 Qscroll_bar_background = intern ("scroll-bar-background");
11904 staticpro (&Qscroll_bar_background);
d62c8769
GM
11905 Qscreen_gamma = intern ("screen-gamma");
11906 staticpro (&Qscreen_gamma);
563b67aa
GM
11907 Qline_spacing = intern ("line-spacing");
11908 staticpro (&Qline_spacing);
7c7ff7f5
GM
11909 Qcenter = intern ("center");
11910 staticpro (&Qcenter);
96db09e4
KH
11911 Qcompound_text = intern ("compound-text");
11912 staticpro (&Qcompound_text);
ae782866
GM
11913 Qcancel_timer = intern ("cancel-timer");
11914 staticpro (&Qcancel_timer);
ea0a1f53
GM
11915 Qwait_for_wm = intern ("wait-for-wm");
11916 staticpro (&Qwait_for_wm);
49d41073
EZ
11917 Qfullscreen = intern ("fullscreen");
11918 staticpro (&Qfullscreen);
11919 Qfullwidth = intern ("fullwidth");
11920 staticpro (&Qfullwidth);
11921 Qfullheight = intern ("fullheight");
11922 staticpro (&Qfullheight);
11923 Qfullboth = intern ("fullboth");
11924 staticpro (&Qfullboth);
f9942c9e
JB
11925 /* This is the end of symbol initialization. */
11926
58cad5ed
KH
11927 /* Text property `display' should be nonsticky by default. */
11928 Vtext_property_default_nonsticky
11929 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
11930
11931
333b20bb
GM
11932 Qlaplace = intern ("laplace");
11933 staticpro (&Qlaplace);
4a8e312c
GM
11934 Qemboss = intern ("emboss");
11935 staticpro (&Qemboss);
11936 Qedge_detection = intern ("edge-detection");
11937 staticpro (&Qedge_detection);
11938 Qheuristic = intern ("heuristic");
11939 staticpro (&Qheuristic);
11940 QCmatrix = intern (":matrix");
11941 staticpro (&QCmatrix);
11942 QCcolor_adjustment = intern (":color-adjustment");
11943 staticpro (&QCcolor_adjustment);
11944 QCmask = intern (":mask");
11945 staticpro (&QCmask);
11946
a367641f
RS
11947 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
11948 staticpro (&Qface_set_after_frame_default);
11949
01f1ba30
JB
11950 Fput (Qundefined_color, Qerror_conditions,
11951 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
11952 Fput (Qundefined_color, Qerror_message,
11953 build_string ("Undefined color"));
11954
f9942c9e
JB
11955 init_x_parm_symbols ();
11956
7ee72033
MB
11957 DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
11958 doc: /* Non-nil means always draw a cross over disabled images.
c061c855
GM
11959Disabled images are those having an `:conversion disabled' property.
11960A cross is always drawn on black & white displays. */);
14819cb3
GM
11961 cross_disabled_images = 0;
11962
7ee72033
MB
11963 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
11964 doc: /* List of directories to search for bitmap files for X. */);
e241c09b 11965 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 11966
7ee72033
MB
11967 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
11968 doc: /* The shape of the pointer when over text.
c061c855
GM
11969Changing the value does not affect existing frames
11970unless you set the mouse color. */);
01f1ba30
JB
11971 Vx_pointer_shape = Qnil;
11972
7ee72033
MB
11973 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
11974 doc: /* The name Emacs uses to look up X resources.
c061c855
GM
11975`x-get-resource' uses this as the first component of the instance name
11976when requesting resource values.
11977Emacs initially sets `x-resource-name' to the name under which Emacs
11978was invoked, or to the value specified with the `-name' or `-rn'
11979switches, if present.
11980
11981It may be useful to bind this variable locally around a call
11982to `x-get-resource'. See also the variable `x-resource-class'. */);
d387c960 11983 Vx_resource_name = Qnil;
ac63d3d6 11984
7ee72033
MB
11985 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
11986 doc: /* The class Emacs uses to look up X resources.
c061c855
GM
11987`x-get-resource' uses this as the first component of the instance class
11988when requesting resource values.
11989
11990Emacs initially sets `x-resource-class' to "Emacs".
11991
11992Setting this variable permanently is not a reasonable thing to do,
11993but binding this variable locally around a call to `x-get-resource'
11994is a reasonable practice. See also the variable `x-resource-name'. */);
498e9ac3
RS
11995 Vx_resource_class = build_string (EMACS_CLASS);
11996
ca0ecbf5 11997#if 0 /* This doesn't really do anything. */
7ee72033
MB
11998 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
11999 doc: /* The shape of the pointer when not over text.
c061c855
GM
12000This variable takes effect when you create a new frame
12001or when you set the mouse color. */);
af01ef26 12002#endif
01f1ba30
JB
12003 Vx_nontext_pointer_shape = Qnil;
12004
7ee72033
MB
12005 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
12006 doc: /* The shape of the pointer when Emacs is busy.
c061c855
GM
12007This variable takes effect when you create a new frame
12008or when you set the mouse color. */);
0af913d7 12009 Vx_hourglass_pointer_shape = Qnil;
333b20bb 12010
7ee72033
MB
12011 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
12012 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 12013 display_hourglass_p = 1;
333b20bb 12014
7ee72033
MB
12015 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
12016 doc: /* *Seconds to wait before displaying an hourglass pointer.
c061c855 12017Value must be an integer or float. */);
0af913d7 12018 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
4ae9a85e 12019
ca0ecbf5 12020#if 0 /* This doesn't really do anything. */
7ee72033
MB
12021 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
12022 doc: /* The shape of the pointer when over the mode line.
c061c855
GM
12023This variable takes effect when you create a new frame
12024or when you set the mouse color. */);
af01ef26 12025#endif
01f1ba30
JB
12026 Vx_mode_pointer_shape = Qnil;
12027
d3b06468 12028 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
7ee72033
MB
12029 &Vx_sensitive_text_pointer_shape,
12030 doc: /* The shape of the pointer when over mouse-sensitive text.
c061c855
GM
12031This variable takes effect when you create a new frame
12032or when you set the mouse color. */);
ca0ecbf5 12033 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 12034
8fb4ec9c 12035 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
7ee72033
MB
12036 &Vx_window_horizontal_drag_shape,
12037 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
c061c855
GM
12038This variable takes effect when you create a new frame
12039or when you set the mouse color. */);
8fb4ec9c
GM
12040 Vx_window_horizontal_drag_shape = Qnil;
12041
7ee72033
MB
12042 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
12043 doc: /* A string indicating the foreground color of the cursor box. */);
01f1ba30
JB
12044 Vx_cursor_fore_pixel = Qnil;
12045
7ee72033
MB
12046 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
12047 doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS).
c061c855 12048Text larger than this is clipped. */);
d63931a2
GM
12049 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
12050
7ee72033
MB
12051 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
12052 doc: /* Non-nil if no X window manager is in use.
c061c855
GM
12053Emacs doesn't try to figure this out; this is always nil
12054unless you set it to something else. */);
2d38195d
RS
12055 /* We don't have any way to find this out, so set it to nil
12056 and maybe the user would like to set it to t. */
12057 Vx_no_window_manager = Qnil;
1d3dac41 12058
942ea06d 12059 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
7ee72033
MB
12060 &Vx_pixel_size_width_font_regexp,
12061 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
c061c855
GM
12062
12063Since Emacs gets width of a font matching with this regexp from
12064PIXEL_SIZE field of the name, font finding mechanism gets faster for
12065such a font. This is especially effective for such large fonts as
12066Chinese, Japanese, and Korean. */);
942ea06d
KH
12067 Vx_pixel_size_width_font_regexp = Qnil;
12068
7ee72033
MB
12069 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
12070 doc: /* Time after which cached images are removed from the cache.
c061c855
GM
12071When an image has not been displayed this many seconds, remove it
12072from the image cache. Value must be an integer or nil with nil
12073meaning don't clear the cache. */);
fcf431dc 12074 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb 12075
1d3dac41 12076#ifdef USE_X_TOOLKIT
6f3f6a8d 12077 Fprovide (intern ("x-toolkit"), Qnil);
5b827abb 12078#ifdef USE_MOTIF
6f3f6a8d 12079 Fprovide (intern ("motif"), Qnil);
fc2cdd9a 12080
7ee72033
MB
12081 DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
12082 doc: /* Version info for LessTif/Motif. */);
fc2cdd9a
GM
12083 Vmotif_version_string = build_string (XmVERSION_STRING);
12084#endif /* USE_MOTIF */
12085#endif /* USE_X_TOOLKIT */
01f1ba30 12086
01f1ba30 12087 defsubr (&Sx_get_resource);
333b20bb
GM
12088
12089 /* X window properties. */
12090 defsubr (&Sx_change_window_property);
12091 defsubr (&Sx_delete_window_property);
12092 defsubr (&Sx_window_property);
12093
2d764c78 12094 defsubr (&Sxw_display_color_p);
d0c9d219 12095 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
12096 defsubr (&Sxw_color_defined_p);
12097 defsubr (&Sxw_color_values);
9d317b2c 12098 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
12099 defsubr (&Sx_server_vendor);
12100 defsubr (&Sx_server_version);
12101 defsubr (&Sx_display_pixel_width);
12102 defsubr (&Sx_display_pixel_height);
12103 defsubr (&Sx_display_mm_width);
12104 defsubr (&Sx_display_mm_height);
12105 defsubr (&Sx_display_screens);
12106 defsubr (&Sx_display_planes);
12107 defsubr (&Sx_display_color_cells);
12108 defsubr (&Sx_display_visual_class);
12109 defsubr (&Sx_display_backing_store);
12110 defsubr (&Sx_display_save_under);
8af1d7ca 12111 defsubr (&Sx_parse_geometry);
f676886a 12112 defsubr (&Sx_create_frame);
01f1ba30 12113 defsubr (&Sx_open_connection);
08a90d6a
RS
12114 defsubr (&Sx_close_connection);
12115 defsubr (&Sx_display_list);
01f1ba30 12116 defsubr (&Sx_synchronize);
3decc1e7 12117 defsubr (&Sx_focus_frame);
82bab41c
GM
12118 defsubr (&Sx_backspace_delete_keys_p);
12119
942ea06d
KH
12120 /* Setting callback functions for fontset handler. */
12121 get_font_info_func = x_get_font_info;
333b20bb
GM
12122
12123#if 0 /* This function pointer doesn't seem to be used anywhere.
12124 And the pointer assigned has the wrong type, anyway. */
942ea06d 12125 list_fonts_func = x_list_fonts;
333b20bb
GM
12126#endif
12127
942ea06d 12128 load_font_func = x_load_font;
bc1958c4 12129 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
12130 query_font_func = x_query_font;
12131 set_frame_fontset_func = x_set_font;
12132 check_window_system_func = check_x;
333b20bb
GM
12133
12134 /* Images. */
12135 Qxbm = intern ("xbm");
12136 staticpro (&Qxbm);
d2dc8167
GM
12137 QCconversion = intern (":conversion");
12138 staticpro (&QCconversion);
333b20bb
GM
12139 QCheuristic_mask = intern (":heuristic-mask");
12140 staticpro (&QCheuristic_mask);
12141 QCcolor_symbols = intern (":color-symbols");
12142 staticpro (&QCcolor_symbols);
333b20bb
GM
12143 QCascent = intern (":ascent");
12144 staticpro (&QCascent);
12145 QCmargin = intern (":margin");
12146 staticpro (&QCmargin);
12147 QCrelief = intern (":relief");
12148 staticpro (&QCrelief);
fcf431dc
GM
12149 Qpostscript = intern ("postscript");
12150 staticpro (&Qpostscript);
333b20bb
GM
12151 QCloader = intern (":loader");
12152 staticpro (&QCloader);
12153 QCbounding_box = intern (":bounding-box");
12154 staticpro (&QCbounding_box);
12155 QCpt_width = intern (":pt-width");
12156 staticpro (&QCpt_width);
12157 QCpt_height = intern (":pt-height");
12158 staticpro (&QCpt_height);
3ccff1e3
GM
12159 QCindex = intern (":index");
12160 staticpro (&QCindex);
333b20bb
GM
12161 Qpbm = intern ("pbm");
12162 staticpro (&Qpbm);
12163
12164#if HAVE_XPM
12165 Qxpm = intern ("xpm");
12166 staticpro (&Qxpm);
12167#endif
12168
12169#if HAVE_JPEG
12170 Qjpeg = intern ("jpeg");
12171 staticpro (&Qjpeg);
12172#endif
12173
12174#if HAVE_TIFF
12175 Qtiff = intern ("tiff");
12176 staticpro (&Qtiff);
12177#endif
12178
12179#if HAVE_GIF
12180 Qgif = intern ("gif");
12181 staticpro (&Qgif);
12182#endif
12183
12184#if HAVE_PNG
12185 Qpng = intern ("png");
12186 staticpro (&Qpng);
12187#endif
12188
12189 defsubr (&Sclear_image_cache);
42677916 12190 defsubr (&Simage_size);
b243755a 12191 defsubr (&Simage_mask_p);
333b20bb 12192
0af913d7
GM
12193 hourglass_atimer = NULL;
12194 hourglass_shown_p = 0;
333b20bb
GM
12195
12196 defsubr (&Sx_show_tip);
12197 defsubr (&Sx_hide_tip);
333b20bb 12198 tip_timer = Qnil;
44b5a125
GM
12199 staticpro (&tip_timer);
12200 tip_frame = Qnil;
12201 staticpro (&tip_frame);
333b20bb 12202
06d62053
GM
12203 last_show_tip_args = Qnil;
12204 staticpro (&last_show_tip_args);
12205
333b20bb
GM
12206#ifdef USE_MOTIF
12207 defsubr (&Sx_file_dialog);
12208#endif
12209}
12210
12211
12212void
12213init_xfns ()
12214{
12215 image_types = NULL;
12216 Vimage_types = Qnil;
12217
12218 define_image_type (&xbm_type);
12219 define_image_type (&gs_type);
12220 define_image_type (&pbm_type);
12221
12222#if HAVE_XPM
12223 define_image_type (&xpm_type);
12224#endif
12225
12226#if HAVE_JPEG
12227 define_image_type (&jpeg_type);
12228#endif
12229
12230#if HAVE_TIFF
12231 define_image_type (&tiff_type);
12232#endif
12233
12234#if HAVE_GIF
12235 define_image_type (&gif_type);
12236#endif
12237
12238#if HAVE_PNG
12239 define_image_type (&png_type);
12240#endif
01f1ba30
JB
12241}
12242
12243#endif /* HAVE_X_WINDOWS */