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