(tags): Include ../lwlib/TAGS in TAGS.
[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
GM
5799Lisp_Object QCtype, QCdata, QCascent, QCmargin, QCrelief;
5800extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
333b20bb 5801Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
bfd2209f 5802Lisp_Object QCindex;
333b20bb
GM
5803
5804/* Other symbols. */
5805
5806Lisp_Object Qlaplace;
5807
5808/* Time in seconds after which images should be removed from the cache
5809 if not displayed. */
5810
fcf431dc 5811Lisp_Object Vimage_cache_eviction_delay;
333b20bb
GM
5812
5813/* Function prototypes. */
5814
5815static void define_image_type P_ ((struct image_type *type));
5816static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
5817static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
5818static void x_laplace P_ ((struct frame *, struct image *));
45158a91
GM
5819static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
5820 Lisp_Object));
333b20bb
GM
5821
5822
5823/* Define a new image type from TYPE. This adds a copy of TYPE to
5824 image_types and adds the symbol *TYPE->type to Vimage_types. */
5825
5826static void
5827define_image_type (type)
5828 struct image_type *type;
5829{
5830 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
5831 The initialized data segment is read-only. */
5832 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
5833 bcopy (type, p, sizeof *p);
5834 p->next = image_types;
5835 image_types = p;
5836 Vimage_types = Fcons (*p->type, Vimage_types);
5837}
5838
5839
5840/* Look up image type SYMBOL, and return a pointer to its image_type
5841 structure. Value is null if SYMBOL is not a known image type. */
5842
5843static INLINE struct image_type *
5844lookup_image_type (symbol)
5845 Lisp_Object symbol;
5846{
5847 struct image_type *type;
5848
5849 for (type = image_types; type; type = type->next)
5850 if (EQ (symbol, *type->type))
5851 break;
5852
5853 return type;
5854}
5855
5856
5857/* Value is non-zero if OBJECT is a valid Lisp image specification. A
5858 valid image specification is a list whose car is the symbol
5859 `image', and whose rest is a property list. The property list must
5860 contain a value for key `:type'. That value must be the name of a
5861 supported image type. The rest of the property list depends on the
5862 image type. */
5863
5864int
5865valid_image_p (object)
5866 Lisp_Object object;
5867{
5868 int valid_p = 0;
5869
5870 if (CONSP (object) && EQ (XCAR (object), Qimage))
5871 {
5872 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
5873 struct image_type *type = lookup_image_type (symbol);
5874
5875 if (type)
5876 valid_p = type->valid_p (object);
5877 }
5878
5879 return valid_p;
5880}
5881
5882
7ab1745f
GM
5883/* Log error message with format string FORMAT and argument ARG.
5884 Signaling an error, e.g. when an image cannot be loaded, is not a
5885 good idea because this would interrupt redisplay, and the error
5886 message display would lead to another redisplay. This function
5887 therefore simply displays a message. */
333b20bb
GM
5888
5889static void
5890image_error (format, arg1, arg2)
5891 char *format;
5892 Lisp_Object arg1, arg2;
5893{
7ab1745f 5894 add_to_log (format, arg1, arg2);
333b20bb
GM
5895}
5896
5897
5898\f
5899/***********************************************************************
5900 Image specifications
5901 ***********************************************************************/
5902
5903enum image_value_type
5904{
5905 IMAGE_DONT_CHECK_VALUE_TYPE,
5906 IMAGE_STRING_VALUE,
5907 IMAGE_SYMBOL_VALUE,
5908 IMAGE_POSITIVE_INTEGER_VALUE,
5909 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
5910 IMAGE_INTEGER_VALUE,
5911 IMAGE_FUNCTION_VALUE,
5912 IMAGE_NUMBER_VALUE,
5913 IMAGE_BOOL_VALUE
5914};
5915
5916/* Structure used when parsing image specifications. */
5917
5918struct image_keyword
5919{
5920 /* Name of keyword. */
5921 char *name;
5922
5923 /* The type of value allowed. */
5924 enum image_value_type type;
5925
5926 /* Non-zero means key must be present. */
5927 int mandatory_p;
5928
5929 /* Used to recognize duplicate keywords in a property list. */
5930 int count;
5931
5932 /* The value that was found. */
5933 Lisp_Object value;
5934};
5935
5936
bfd2209f
GM
5937static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
5938 int, Lisp_Object));
333b20bb
GM
5939static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
5940
5941
5942/* Parse image spec SPEC according to KEYWORDS. A valid image spec
5943 has the format (image KEYWORD VALUE ...). One of the keyword/
5944 value pairs must be `:type TYPE'. KEYWORDS is a vector of
5945 image_keywords structures of size NKEYWORDS describing other
bfd2209f 5946 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
333b20bb
GM
5947
5948static int
bfd2209f 5949parse_image_spec (spec, keywords, nkeywords, type)
333b20bb
GM
5950 Lisp_Object spec;
5951 struct image_keyword *keywords;
5952 int nkeywords;
5953 Lisp_Object type;
333b20bb
GM
5954{
5955 int i;
5956 Lisp_Object plist;
5957
5958 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
5959 return 0;
5960
5961 plist = XCDR (spec);
5962 while (CONSP (plist))
5963 {
5964 Lisp_Object key, value;
5965
5966 /* First element of a pair must be a symbol. */
5967 key = XCAR (plist);
5968 plist = XCDR (plist);
5969 if (!SYMBOLP (key))
5970 return 0;
5971
5972 /* There must follow a value. */
5973 if (!CONSP (plist))
5974 return 0;
5975 value = XCAR (plist);
5976 plist = XCDR (plist);
5977
5978 /* Find key in KEYWORDS. Error if not found. */
5979 for (i = 0; i < nkeywords; ++i)
5980 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
5981 break;
5982
5983 if (i == nkeywords)
bfd2209f 5984 continue;
333b20bb
GM
5985
5986 /* Record that we recognized the keyword. If a keywords
5987 was found more than once, it's an error. */
5988 keywords[i].value = value;
5989 ++keywords[i].count;
5990
5991 if (keywords[i].count > 1)
5992 return 0;
5993
5994 /* Check type of value against allowed type. */
5995 switch (keywords[i].type)
5996 {
5997 case IMAGE_STRING_VALUE:
5998 if (!STRINGP (value))
5999 return 0;
6000 break;
6001
6002 case IMAGE_SYMBOL_VALUE:
6003 if (!SYMBOLP (value))
6004 return 0;
6005 break;
6006
6007 case IMAGE_POSITIVE_INTEGER_VALUE:
6008 if (!INTEGERP (value) || XINT (value) <= 0)
6009 return 0;
6010 break;
6011
6012 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
6013 if (!INTEGERP (value) || XINT (value) < 0)
6014 return 0;
6015 break;
6016
6017 case IMAGE_DONT_CHECK_VALUE_TYPE:
6018 break;
6019
6020 case IMAGE_FUNCTION_VALUE:
6021 value = indirect_function (value);
6022 if (SUBRP (value)
6023 || COMPILEDP (value)
6024 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
6025 break;
6026 return 0;
6027
6028 case IMAGE_NUMBER_VALUE:
6029 if (!INTEGERP (value) && !FLOATP (value))
6030 return 0;
6031 break;
6032
6033 case IMAGE_INTEGER_VALUE:
6034 if (!INTEGERP (value))
6035 return 0;
6036 break;
6037
6038 case IMAGE_BOOL_VALUE:
6039 if (!NILP (value) && !EQ (value, Qt))
6040 return 0;
6041 break;
6042
6043 default:
6044 abort ();
6045 break;
6046 }
6047
6048 if (EQ (key, QCtype) && !EQ (type, value))
6049 return 0;
6050 }
6051
6052 /* Check that all mandatory fields are present. */
6053 for (i = 0; i < nkeywords; ++i)
6054 if (keywords[i].mandatory_p && keywords[i].count == 0)
6055 return 0;
6056
6057 return NILP (plist);
6058}
6059
6060
6061/* Return the value of KEY in image specification SPEC. Value is nil
6062 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
6063 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
6064
6065static Lisp_Object
6066image_spec_value (spec, key, found)
6067 Lisp_Object spec, key;
6068 int *found;
6069{
6070 Lisp_Object tail;
6071
6072 xassert (valid_image_p (spec));
6073
6074 for (tail = XCDR (spec);
6075 CONSP (tail) && CONSP (XCDR (tail));
6076 tail = XCDR (XCDR (tail)))
6077 {
6078 if (EQ (XCAR (tail), key))
6079 {
6080 if (found)
6081 *found = 1;
6082 return XCAR (XCDR (tail));
6083 }
6084 }
6085
6086 if (found)
6087 *found = 0;
6088 return Qnil;
6089}
6090
6091
6092
6093\f
6094/***********************************************************************
6095 Image type independent image structures
6096 ***********************************************************************/
6097
6098static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
6099static void free_image P_ ((struct frame *f, struct image *img));
6100
6101
6102/* Allocate and return a new image structure for image specification
6103 SPEC. SPEC has a hash value of HASH. */
6104
6105static struct image *
6106make_image (spec, hash)
6107 Lisp_Object spec;
6108 unsigned hash;
6109{
6110 struct image *img = (struct image *) xmalloc (sizeof *img);
6111
6112 xassert (valid_image_p (spec));
6113 bzero (img, sizeof *img);
6114 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
6115 xassert (img->type != NULL);
6116 img->spec = spec;
6117 img->data.lisp_val = Qnil;
6118 img->ascent = DEFAULT_IMAGE_ASCENT;
6119 img->hash = hash;
6120 return img;
6121}
6122
6123
6124/* Free image IMG which was used on frame F, including its resources. */
6125
6126static void
6127free_image (f, img)
6128 struct frame *f;
6129 struct image *img;
6130{
6131 if (img)
6132 {
6133 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6134
6135 /* Remove IMG from the hash table of its cache. */
6136 if (img->prev)
6137 img->prev->next = img->next;
6138 else
6139 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
6140
6141 if (img->next)
6142 img->next->prev = img->prev;
6143
6144 c->images[img->id] = NULL;
6145
6146 /* Free resources, then free IMG. */
6147 img->type->free (f, img);
6148 xfree (img);
6149 }
6150}
6151
6152
6153/* Prepare image IMG for display on frame F. Must be called before
6154 drawing an image. */
6155
6156void
6157prepare_image_for_display (f, img)
6158 struct frame *f;
6159 struct image *img;
6160{
6161 EMACS_TIME t;
6162
6163 /* We're about to display IMG, so set its timestamp to `now'. */
6164 EMACS_GET_TIME (t);
6165 img->timestamp = EMACS_SECS (t);
6166
6167 /* If IMG doesn't have a pixmap yet, load it now, using the image
6168 type dependent loader function. */
209061be
GM
6169 if (img->pixmap == 0 && !img->load_failed_p)
6170 img->load_failed_p = img->type->load (f, img) == 0;
333b20bb
GM
6171}
6172
6173
6174\f
6175/***********************************************************************
6176 Helper functions for X image types
6177 ***********************************************************************/
6178
6179static void x_clear_image P_ ((struct frame *f, struct image *img));
6180static unsigned long x_alloc_image_color P_ ((struct frame *f,
6181 struct image *img,
6182 Lisp_Object color_name,
6183 unsigned long dflt));
6184
6185/* Free X resources of image IMG which is used on frame F. */
6186
6187static void
6188x_clear_image (f, img)
6189 struct frame *f;
6190 struct image *img;
6191{
6192 if (img->pixmap)
6193 {
6194 BLOCK_INPUT;
6195 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
6196 img->pixmap = 0;
6197 UNBLOCK_INPUT;
6198 }
6199
6200 if (img->ncolors)
6201 {
462d5d40
GM
6202 BLOCK_INPUT;
6203 x_free_colors (f, img->colors, img->ncolors);
6204 UNBLOCK_INPUT;
333b20bb
GM
6205
6206 xfree (img->colors);
6207 img->colors = NULL;
6208 img->ncolors = 0;
6209 }
6210}
6211
6212
6213/* Allocate color COLOR_NAME for image IMG on frame F. If color
6214 cannot be allocated, use DFLT. Add a newly allocated color to
6215 IMG->colors, so that it can be freed again. Value is the pixel
6216 color. */
6217
6218static unsigned long
6219x_alloc_image_color (f, img, color_name, dflt)
6220 struct frame *f;
6221 struct image *img;
6222 Lisp_Object color_name;
6223 unsigned long dflt;
6224{
6225 XColor color;
6226 unsigned long result;
6227
6228 xassert (STRINGP (color_name));
6229
2d764c78 6230 if (x_defined_color (f, XSTRING (color_name)->data, &color, 1))
333b20bb
GM
6231 {
6232 /* This isn't called frequently so we get away with simply
6233 reallocating the color vector to the needed size, here. */
6234 ++img->ncolors;
6235 img->colors =
6236 (unsigned long *) xrealloc (img->colors,
6237 img->ncolors * sizeof *img->colors);
6238 img->colors[img->ncolors - 1] = color.pixel;
6239 result = color.pixel;
6240 }
6241 else
6242 result = dflt;
6243
6244 return result;
6245}
6246
6247
6248\f
6249/***********************************************************************
6250 Image Cache
6251 ***********************************************************************/
6252
6253static void cache_image P_ ((struct frame *f, struct image *img));
6254
6255
6256/* Return a new, initialized image cache that is allocated from the
6257 heap. Call free_image_cache to free an image cache. */
6258
6259struct image_cache *
6260make_image_cache ()
6261{
6262 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
6263 int size;
6264
6265 bzero (c, sizeof *c);
6266 c->size = 50;
6267 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
6268 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
6269 c->buckets = (struct image **) xmalloc (size);
6270 bzero (c->buckets, size);
6271 return c;
6272}
6273
6274
6275/* Free image cache of frame F. Be aware that X frames share images
6276 caches. */
6277
6278void
6279free_image_cache (f)
6280 struct frame *f;
6281{
6282 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6283 if (c)
6284 {
6285 int i;
6286
6287 /* Cache should not be referenced by any frame when freed. */
6288 xassert (c->refcount == 0);
6289
6290 for (i = 0; i < c->used; ++i)
6291 free_image (f, c->images[i]);
6292 xfree (c->images);
6293 xfree (c);
6294 xfree (c->buckets);
6295 FRAME_X_IMAGE_CACHE (f) = NULL;
6296 }
6297}
6298
6299
6300/* Clear image cache of frame F. FORCE_P non-zero means free all
6301 images. FORCE_P zero means clear only images that haven't been
6302 displayed for some time. Should be called from time to time to
6303 reduce the number of loaded images. If image-eviction-seconds is
6304 non-nil, this frees images in the cache which weren't displayed for
6305 at least that many seconds. */
6306
6307void
6308clear_image_cache (f, force_p)
6309 struct frame *f;
6310 int force_p;
6311{
6312 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6313
fcf431dc 6314 if (c && INTEGERP (Vimage_cache_eviction_delay))
333b20bb
GM
6315 {
6316 EMACS_TIME t;
6317 unsigned long old;
6318 int i, any_freed_p = 0;
6319
6320 EMACS_GET_TIME (t);
fcf431dc 6321 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
333b20bb
GM
6322
6323 for (i = 0; i < c->used; ++i)
6324 {
6325 struct image *img = c->images[i];
6326 if (img != NULL
6327 && (force_p
6328 || (img->timestamp > old)))
6329 {
6330 free_image (f, img);
6331 any_freed_p = 1;
6332 }
6333 }
6334
6335 /* We may be clearing the image cache because, for example,
6336 Emacs was iconified for a longer period of time. In that
6337 case, current matrices may still contain references to
6338 images freed above. So, clear these matrices. */
6339 if (any_freed_p)
6340 {
6341 clear_current_matrices (f);
6342 ++windows_or_buffers_changed;
6343 }
6344 }
6345}
6346
6347
6348DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
6349 0, 1, 0,
6350 "Clear the image cache of FRAME.\n\
6351FRAME nil or omitted means use the selected frame.\n\
6352FRAME t means clear the image caches of all frames.")
6353 (frame)
6354 Lisp_Object frame;
6355{
6356 if (EQ (frame, Qt))
6357 {
6358 Lisp_Object tail;
6359
6360 FOR_EACH_FRAME (tail, frame)
6361 if (FRAME_X_P (XFRAME (frame)))
6362 clear_image_cache (XFRAME (frame), 1);
6363 }
6364 else
6365 clear_image_cache (check_x_frame (frame), 1);
6366
6367 return Qnil;
6368}
6369
6370
6371/* Return the id of image with Lisp specification SPEC on frame F.
6372 SPEC must be a valid Lisp image specification (see valid_image_p). */
6373
6374int
6375lookup_image (f, spec)
6376 struct frame *f;
6377 Lisp_Object spec;
6378{
6379 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6380 struct image *img;
6381 int i;
6382 unsigned hash;
6383 struct gcpro gcpro1;
4f7ca1f1 6384 EMACS_TIME now;
333b20bb
GM
6385
6386 /* F must be a window-system frame, and SPEC must be a valid image
6387 specification. */
6388 xassert (FRAME_WINDOW_P (f));
6389 xassert (valid_image_p (spec));
6390
6391 GCPRO1 (spec);
6392
6393 /* Look up SPEC in the hash table of the image cache. */
6394 hash = sxhash (spec, 0);
6395 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
6396
6397 for (img = c->buckets[i]; img; img = img->next)
6398 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
6399 break;
6400
6401 /* If not found, create a new image and cache it. */
6402 if (img == NULL)
6403 {
333b20bb
GM
6404 img = make_image (spec, hash);
6405 cache_image (f, img);
209061be
GM
6406 img->load_failed_p = img->type->load (f, img) == 0;
6407 xassert (!interrupt_input_blocked);
333b20bb
GM
6408
6409 /* If we can't load the image, and we don't have a width and
6410 height, use some arbitrary width and height so that we can
6411 draw a rectangle for it. */
209061be 6412 if (img->load_failed_p)
333b20bb
GM
6413 {
6414 Lisp_Object value;
6415
6416 value = image_spec_value (spec, QCwidth, NULL);
6417 img->width = (INTEGERP (value)
6418 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
6419 value = image_spec_value (spec, QCheight, NULL);
6420 img->height = (INTEGERP (value)
6421 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
6422 }
6423 else
6424 {
6425 /* Handle image type independent image attributes
6426 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
6427 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
6428 Lisp_Object file;
6429
6430 ascent = image_spec_value (spec, QCascent, NULL);
6431 if (INTEGERP (ascent))
6432 img->ascent = XFASTINT (ascent);
6433
6434 margin = image_spec_value (spec, QCmargin, NULL);
6435 if (INTEGERP (margin) && XINT (margin) >= 0)
6436 img->margin = XFASTINT (margin);
6437
6438 relief = image_spec_value (spec, QCrelief, NULL);
6439 if (INTEGERP (relief))
6440 {
6441 img->relief = XINT (relief);
6442 img->margin += abs (img->relief);
6443 }
6444
6445 /* Should we apply a Laplace edge-detection algorithm? */
6446 algorithm = image_spec_value (spec, QCalgorithm, NULL);
6447 if (img->pixmap && EQ (algorithm, Qlaplace))
6448 x_laplace (f, img);
6449
6450 /* Should we built a mask heuristically? */
6451 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
6452 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
45158a91 6453 x_build_heuristic_mask (f, img, heuristic_mask);
333b20bb
GM
6454 }
6455 }
6456
4f7ca1f1
GM
6457 /* We're using IMG, so set its timestamp to `now'. */
6458 EMACS_GET_TIME (now);
6459 img->timestamp = EMACS_SECS (now);
6460
333b20bb
GM
6461 UNGCPRO;
6462
6463 /* Value is the image id. */
6464 return img->id;
6465}
6466
6467
6468/* Cache image IMG in the image cache of frame F. */
6469
6470static void
6471cache_image (f, img)
6472 struct frame *f;
6473 struct image *img;
6474{
6475 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6476 int i;
6477
6478 /* Find a free slot in c->images. */
6479 for (i = 0; i < c->used; ++i)
6480 if (c->images[i] == NULL)
6481 break;
6482
6483 /* If no free slot found, maybe enlarge c->images. */
6484 if (i == c->used && c->used == c->size)
6485 {
6486 c->size *= 2;
6487 c->images = (struct image **) xrealloc (c->images,
6488 c->size * sizeof *c->images);
6489 }
6490
6491 /* Add IMG to c->images, and assign IMG an id. */
6492 c->images[i] = img;
6493 img->id = i;
6494 if (i == c->used)
6495 ++c->used;
6496
6497 /* Add IMG to the cache's hash table. */
6498 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
6499 img->next = c->buckets[i];
6500 if (img->next)
6501 img->next->prev = img;
6502 img->prev = NULL;
6503 c->buckets[i] = img;
6504}
6505
6506
6507/* Call FN on every image in the image cache of frame F. Used to mark
6508 Lisp Objects in the image cache. */
6509
6510void
6511forall_images_in_image_cache (f, fn)
6512 struct frame *f;
6513 void (*fn) P_ ((struct image *img));
6514{
6515 if (FRAME_LIVE_P (f) && FRAME_X_P (f))
6516 {
6517 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
6518 if (c)
6519 {
6520 int i;
6521 for (i = 0; i < c->used; ++i)
6522 if (c->images[i])
6523 fn (c->images[i]);
6524 }
6525 }
6526}
6527
6528
6529\f
6530/***********************************************************************
6531 X support code
6532 ***********************************************************************/
6533
45158a91
GM
6534static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
6535 XImage **, Pixmap *));
333b20bb
GM
6536static void x_destroy_x_image P_ ((XImage *));
6537static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
6538
6539
6540/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
6541 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
6542 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
6543 via xmalloc. Print error messages via image_error if an error
45158a91 6544 occurs. Value is non-zero if successful. */
333b20bb
GM
6545
6546static int
45158a91 6547x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
333b20bb 6548 struct frame *f;
333b20bb
GM
6549 int width, height, depth;
6550 XImage **ximg;
6551 Pixmap *pixmap;
6552{
6553 Display *display = FRAME_X_DISPLAY (f);
6554 Screen *screen = FRAME_X_SCREEN (f);
6555 Window window = FRAME_X_WINDOW (f);
6556
6557 xassert (interrupt_input_blocked);
6558
6559 if (depth <= 0)
6560 depth = DefaultDepthOfScreen (screen);
6561 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
6562 depth, ZPixmap, 0, NULL, width, height,
6563 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
6564 if (*ximg == NULL)
6565 {
45158a91 6566 image_error ("Unable to allocate X image", Qnil, Qnil);
333b20bb
GM
6567 return 0;
6568 }
6569
6570 /* Allocate image raster. */
6571 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
6572
6573 /* Allocate a pixmap of the same size. */
6574 *pixmap = XCreatePixmap (display, window, width, height, depth);
6575 if (*pixmap == 0)
6576 {
6577 x_destroy_x_image (*ximg);
6578 *ximg = NULL;
45158a91 6579 image_error ("Unable to create X pixmap", Qnil, Qnil);
333b20bb
GM
6580 return 0;
6581 }
6582
6583 return 1;
6584}
6585
6586
6587/* Destroy XImage XIMG. Free XIMG->data. */
6588
6589static void
6590x_destroy_x_image (ximg)
6591 XImage *ximg;
6592{
6593 xassert (interrupt_input_blocked);
6594 if (ximg)
6595 {
6596 xfree (ximg->data);
6597 ximg->data = NULL;
6598 XDestroyImage (ximg);
6599 }
6600}
6601
6602
6603/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
6604 are width and height of both the image and pixmap. */
6605
ea6b19ca 6606static void
333b20bb
GM
6607x_put_x_image (f, ximg, pixmap, width, height)
6608 struct frame *f;
6609 XImage *ximg;
6610 Pixmap pixmap;
6611{
6612 GC gc;
6613
6614 xassert (interrupt_input_blocked);
6615 gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
6616 XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
6617 XFreeGC (FRAME_X_DISPLAY (f), gc);
6618}
6619
6620
6621\f
6622/***********************************************************************
6623 Searching files
6624 ***********************************************************************/
6625
6626static Lisp_Object x_find_image_file P_ ((Lisp_Object));
6627
6628/* Find image file FILE. Look in data-directory, then
6629 x-bitmap-file-path. Value is the full name of the file found, or
6630 nil if not found. */
6631
6632static Lisp_Object
6633x_find_image_file (file)
6634 Lisp_Object file;
6635{
6636 Lisp_Object file_found, search_path;
6637 struct gcpro gcpro1, gcpro2;
6638 int fd;
6639
6640 file_found = Qnil;
6641 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
6642 GCPRO2 (file_found, search_path);
6643
6644 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
6645 fd = openp (search_path, file, "", &file_found, 0);
6646
6647 if (fd < 0)
6648 file_found = Qnil;
6649 else
6650 close (fd);
6651
6652 UNGCPRO;
6653 return file_found;
6654}
6655
6656
6657\f
6658/***********************************************************************
6659 XBM images
6660 ***********************************************************************/
6661
6662static int xbm_load P_ ((struct frame *f, struct image *img));
6663static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
6664 Lisp_Object file));
6665static int xbm_image_p P_ ((Lisp_Object object));
6666static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
6667 unsigned char **));
333b20bb
GM
6668
6669
6670/* Indices of image specification fields in xbm_format, below. */
6671
6672enum xbm_keyword_index
6673{
6674 XBM_TYPE,
6675 XBM_FILE,
6676 XBM_WIDTH,
6677 XBM_HEIGHT,
6678 XBM_DATA,
6679 XBM_FOREGROUND,
6680 XBM_BACKGROUND,
6681 XBM_ASCENT,
6682 XBM_MARGIN,
6683 XBM_RELIEF,
6684 XBM_ALGORITHM,
6685 XBM_HEURISTIC_MASK,
6686 XBM_LAST
6687};
6688
6689/* Vector of image_keyword structures describing the format
6690 of valid XBM image specifications. */
6691
6692static struct image_keyword xbm_format[XBM_LAST] =
6693{
6694 {":type", IMAGE_SYMBOL_VALUE, 1},
6695 {":file", IMAGE_STRING_VALUE, 0},
6696 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6697 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6698 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6699 {":foreground", IMAGE_STRING_VALUE, 0},
6700 {":background", IMAGE_STRING_VALUE, 0},
6701 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6702 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
6703 {":relief", IMAGE_INTEGER_VALUE, 0},
6704 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6705 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6706};
6707
6708/* Structure describing the image type XBM. */
6709
6710static struct image_type xbm_type =
6711{
6712 &Qxbm,
6713 xbm_image_p,
6714 xbm_load,
6715 x_clear_image,
6716 NULL
6717};
6718
6719/* Tokens returned from xbm_scan. */
6720
6721enum xbm_token
6722{
6723 XBM_TK_IDENT = 256,
6724 XBM_TK_NUMBER
6725};
6726
6727
6728/* Return non-zero if OBJECT is a valid XBM-type image specification.
6729 A valid specification is a list starting with the symbol `image'
6730 The rest of the list is a property list which must contain an
6731 entry `:type xbm..
6732
6733 If the specification specifies a file to load, it must contain
6734 an entry `:file FILENAME' where FILENAME is a string.
6735
6736 If the specification is for a bitmap loaded from memory it must
6737 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
6738 WIDTH and HEIGHT are integers > 0. DATA may be:
6739
6740 1. a string large enough to hold the bitmap data, i.e. it must
6741 have a size >= (WIDTH + 7) / 8 * HEIGHT
6742
6743 2. a bool-vector of size >= WIDTH * HEIGHT
6744
6745 3. a vector of strings or bool-vectors, one for each line of the
6746 bitmap.
6747
6748 Both the file and data forms may contain the additional entries
6749 `:background COLOR' and `:foreground COLOR'. If not present,
6750 foreground and background of the frame on which the image is
6751 displayed, is used. */
6752
6753static int
6754xbm_image_p (object)
6755 Lisp_Object object;
6756{
6757 struct image_keyword kw[XBM_LAST];
6758
6759 bcopy (xbm_format, kw, sizeof kw);
bfd2209f 6760 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
333b20bb
GM
6761 return 0;
6762
6763 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
6764
6765 if (kw[XBM_FILE].count)
6766 {
6767 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
6768 return 0;
6769 }
6770 else
6771 {
6772 Lisp_Object data;
6773 int width, height;
6774
6775 /* Entries for `:width', `:height' and `:data' must be present. */
6776 if (!kw[XBM_WIDTH].count
6777 || !kw[XBM_HEIGHT].count
6778 || !kw[XBM_DATA].count)
6779 return 0;
6780
6781 data = kw[XBM_DATA].value;
6782 width = XFASTINT (kw[XBM_WIDTH].value);
6783 height = XFASTINT (kw[XBM_HEIGHT].value);
6784
6785 /* Check type of data, and width and height against contents of
6786 data. */
6787 if (VECTORP (data))
6788 {
6789 int i;
6790
6791 /* Number of elements of the vector must be >= height. */
6792 if (XVECTOR (data)->size < height)
6793 return 0;
6794
6795 /* Each string or bool-vector in data must be large enough
6796 for one line of the image. */
6797 for (i = 0; i < height; ++i)
6798 {
6799 Lisp_Object elt = XVECTOR (data)->contents[i];
6800
6801 if (STRINGP (elt))
6802 {
6803 if (XSTRING (elt)->size
6804 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
6805 return 0;
6806 }
6807 else if (BOOL_VECTOR_P (elt))
6808 {
6809 if (XBOOL_VECTOR (elt)->size < width)
6810 return 0;
6811 }
6812 else
6813 return 0;
6814 }
6815 }
6816 else if (STRINGP (data))
6817 {
6818 if (XSTRING (data)->size
6819 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
6820 return 0;
6821 }
6822 else if (BOOL_VECTOR_P (data))
6823 {
6824 if (XBOOL_VECTOR (data)->size < width * height)
6825 return 0;
6826 }
6827 else
6828 return 0;
6829 }
6830
6831 /* Baseline must be a value between 0 and 100 (a percentage). */
6832 if (kw[XBM_ASCENT].count
6833 && XFASTINT (kw[XBM_ASCENT].value) > 100)
6834 return 0;
6835
6836 return 1;
6837}
6838
6839
6840/* Scan a bitmap file. FP is the stream to read from. Value is
6841 either an enumerator from enum xbm_token, or a character for a
6842 single-character token, or 0 at end of file. If scanning an
6843 identifier, store the lexeme of the identifier in SVAL. If
6844 scanning a number, store its value in *IVAL. */
6845
6846static int
6847xbm_scan (fp, sval, ival)
6848 FILE *fp;
6849 char *sval;
6850 int *ival;
6851{
6852 int c;
6853
6854 /* Skip white space. */
6855 while ((c = fgetc (fp)) != EOF && isspace (c))
6856 ;
6857
6858 if (c == EOF)
6859 c = 0;
6860 else if (isdigit (c))
6861 {
6862 int value = 0, digit;
6863
6864 if (c == '0')
6865 {
6866 c = fgetc (fp);
6867 if (c == 'x' || c == 'X')
6868 {
6869 while ((c = fgetc (fp)) != EOF)
6870 {
6871 if (isdigit (c))
6872 digit = c - '0';
6873 else if (c >= 'a' && c <= 'f')
6874 digit = c - 'a' + 10;
6875 else if (c >= 'A' && c <= 'F')
6876 digit = c - 'A' + 10;
6877 else
6878 break;
6879 value = 16 * value + digit;
6880 }
6881 }
6882 else if (isdigit (c))
6883 {
6884 value = c - '0';
6885 while ((c = fgetc (fp)) != EOF
6886 && isdigit (c))
6887 value = 8 * value + c - '0';
6888 }
6889 }
6890 else
6891 {
6892 value = c - '0';
6893 while ((c = fgetc (fp)) != EOF
6894 && isdigit (c))
6895 value = 10 * value + c - '0';
6896 }
6897
6898 if (c != EOF)
6899 ungetc (c, fp);
6900 *ival = value;
6901 c = XBM_TK_NUMBER;
6902 }
6903 else if (isalpha (c) || c == '_')
6904 {
6905 *sval++ = c;
6906 while ((c = fgetc (fp)) != EOF
6907 && (isalnum (c) || c == '_'))
6908 *sval++ = c;
6909 *sval = 0;
6910 if (c != EOF)
6911 ungetc (c, fp);
6912 c = XBM_TK_IDENT;
6913 }
6914
6915 return c;
6916}
6917
6918
6919/* Replacement for XReadBitmapFileData which isn't available under old
6920 X versions. FILE is the name of the bitmap file to read. Set
6921 *WIDTH and *HEIGHT to the width and height of the image. Return in
6922 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
6923 successful. */
6924
6925static int
6926xbm_read_bitmap_file_data (file, width, height, data)
6927 char *file;
6928 int *width, *height;
6929 unsigned char **data;
6930{
6931 FILE *fp;
6932 char buffer[BUFSIZ];
6933 int padding_p = 0;
6934 int v10 = 0;
6935 int bytes_per_line, i, nbytes;
6936 unsigned char *p;
6937 int value;
6938 int LA1;
6939
6940#define match() \
6941 LA1 = xbm_scan (fp, buffer, &value)
6942
6943#define expect(TOKEN) \
6944 if (LA1 != (TOKEN)) \
6945 goto failure; \
6946 else \
6947 match ()
6948
6949#define expect_ident(IDENT) \
6950 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
6951 match (); \
6952 else \
6953 goto failure
6954
6955 fp = fopen (file, "r");
6956 if (fp == NULL)
6957 return 0;
6958
6959 *width = *height = -1;
6960 *data = NULL;
6961 LA1 = xbm_scan (fp, buffer, &value);
6962
6963 /* Parse defines for width, height and hot-spots. */
6964 while (LA1 == '#')
6965 {
333b20bb
GM
6966 match ();
6967 expect_ident ("define");
6968 expect (XBM_TK_IDENT);
6969
6970 if (LA1 == XBM_TK_NUMBER);
6971 {
6972 char *p = strrchr (buffer, '_');
6973 p = p ? p + 1 : buffer;
6974 if (strcmp (p, "width") == 0)
6975 *width = value;
6976 else if (strcmp (p, "height") == 0)
6977 *height = value;
6978 }
6979 expect (XBM_TK_NUMBER);
6980 }
6981
6982 if (*width < 0 || *height < 0)
6983 goto failure;
6984
6985 /* Parse bits. Must start with `static'. */
6986 expect_ident ("static");
6987 if (LA1 == XBM_TK_IDENT)
6988 {
6989 if (strcmp (buffer, "unsigned") == 0)
6990 {
6991 match ();
6992 expect_ident ("char");
6993 }
6994 else if (strcmp (buffer, "short") == 0)
6995 {
6996 match ();
6997 v10 = 1;
6998 if (*width % 16 && *width % 16 < 9)
6999 padding_p = 1;
7000 }
7001 else if (strcmp (buffer, "char") == 0)
7002 match ();
7003 else
7004 goto failure;
7005 }
7006 else
7007 goto failure;
7008
7009 expect (XBM_TK_IDENT);
7010 expect ('[');
7011 expect (']');
7012 expect ('=');
7013 expect ('{');
7014
7015 bytes_per_line = (*width + 7) / 8 + padding_p;
7016 nbytes = bytes_per_line * *height;
7017 p = *data = (char *) xmalloc (nbytes);
7018
7019 if (v10)
7020 {
7021
7022 for (i = 0; i < nbytes; i += 2)
7023 {
7024 int val = value;
7025 expect (XBM_TK_NUMBER);
7026
7027 *p++ = val;
7028 if (!padding_p || ((i + 2) % bytes_per_line))
7029 *p++ = value >> 8;
7030
7031 if (LA1 == ',' || LA1 == '}')
7032 match ();
7033 else
7034 goto failure;
7035 }
7036 }
7037 else
7038 {
7039 for (i = 0; i < nbytes; ++i)
7040 {
7041 int val = value;
7042 expect (XBM_TK_NUMBER);
7043
7044 *p++ = val;
7045
7046 if (LA1 == ',' || LA1 == '}')
7047 match ();
7048 else
7049 goto failure;
7050 }
7051 }
7052
7053 fclose (fp);
7054 return 1;
7055
7056 failure:
7057
7058 fclose (fp);
7059 if (*data)
7060 {
7061 xfree (*data);
7062 *data = NULL;
7063 }
7064 return 0;
7065
7066#undef match
7067#undef expect
7068#undef expect_ident
7069}
7070
7071
7072/* Load XBM image IMG which will be displayed on frame F from file
7073 SPECIFIED_FILE. Value is non-zero if successful. */
7074
7075static int
7076xbm_load_image_from_file (f, img, specified_file)
7077 struct frame *f;
7078 struct image *img;
7079 Lisp_Object specified_file;
7080{
7081 int rc;
7082 unsigned char *data;
7083 int success_p = 0;
7084 Lisp_Object file;
7085 struct gcpro gcpro1;
7086
7087 xassert (STRINGP (specified_file));
7088 file = Qnil;
7089 GCPRO1 (file);
7090
7091 file = x_find_image_file (specified_file);
7092 if (!STRINGP (file))
7093 {
45158a91 7094 image_error ("Cannot find image file `%s'", specified_file, Qnil);
333b20bb
GM
7095 UNGCPRO;
7096 return 0;
7097 }
7098
7099 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
7100 &img->height, &data);
7101 if (rc)
7102 {
7103 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7104 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7105 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7106 Lisp_Object value;
7107
7108 xassert (img->width > 0 && img->height > 0);
7109
7110 /* Get foreground and background colors, maybe allocate colors. */
7111 value = image_spec_value (img->spec, QCforeground, NULL);
7112 if (!NILP (value))
7113 foreground = x_alloc_image_color (f, img, value, foreground);
7114
7115 value = image_spec_value (img->spec, QCbackground, NULL);
7116 if (!NILP (value))
7117 background = x_alloc_image_color (f, img, value, background);
7118
7119 BLOCK_INPUT;
7120 img->pixmap
7121 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7122 FRAME_X_WINDOW (f),
7123 data,
7124 img->width, img->height,
7125 foreground, background,
7126 depth);
7127 xfree (data);
7128
7129 if (img->pixmap == 0)
7130 {
7131 x_clear_image (f, img);
7132 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
7133 }
7134 else
7135 success_p = 1;
7136
7137 UNBLOCK_INPUT;
7138 }
7139 else
45158a91 7140 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
333b20bb
GM
7141
7142 UNGCPRO;
7143 return success_p;
7144}
7145
7146
7147/* Fill image IMG which is used on frame F with pixmap data. Value is
7148 non-zero if successful. */
7149
7150static int
7151xbm_load (f, img)
7152 struct frame *f;
7153 struct image *img;
7154{
7155 int success_p = 0;
7156 Lisp_Object file_name;
7157
7158 xassert (xbm_image_p (img->spec));
7159
7160 /* If IMG->spec specifies a file name, create a non-file spec from it. */
7161 file_name = image_spec_value (img->spec, QCfile, NULL);
7162 if (STRINGP (file_name))
7163 success_p = xbm_load_image_from_file (f, img, file_name);
7164 else
7165 {
7166 struct image_keyword fmt[XBM_LAST];
7167 Lisp_Object data;
7168 int depth;
7169 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
7170 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
7171 char *bits;
7172 int parsed_p;
7173
7174 /* Parse the list specification. */
7175 bcopy (xbm_format, fmt, sizeof fmt);
bfd2209f 7176 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
333b20bb
GM
7177 xassert (parsed_p);
7178
7179 /* Get specified width, and height. */
7180 img->width = XFASTINT (fmt[XBM_WIDTH].value);
7181 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
7182 xassert (img->width > 0 && img->height > 0);
7183
7184 BLOCK_INPUT;
7185
7186 if (fmt[XBM_ASCENT].count)
7187 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
7188
7189 /* Get foreground and background colors, maybe allocate colors. */
7190 if (fmt[XBM_FOREGROUND].count)
7191 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
7192 foreground);
7193 if (fmt[XBM_BACKGROUND].count)
7194 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
7195 background);
7196
7197 /* Set bits to the bitmap image data. */
7198 data = fmt[XBM_DATA].value;
7199 if (VECTORP (data))
7200 {
7201 int i;
7202 char *p;
7203 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
7204
7205 p = bits = (char *) alloca (nbytes * img->height);
7206 for (i = 0; i < img->height; ++i, p += nbytes)
7207 {
7208 Lisp_Object line = XVECTOR (data)->contents[i];
7209 if (STRINGP (line))
7210 bcopy (XSTRING (line)->data, p, nbytes);
7211 else
7212 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
7213 }
7214 }
7215 else if (STRINGP (data))
7216 bits = XSTRING (data)->data;
7217 else
7218 bits = XBOOL_VECTOR (data)->data;
7219
7220 /* Create the pixmap. */
7221 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
7222 img->pixmap
7223 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
7224 FRAME_X_WINDOW (f),
7225 bits,
7226 img->width, img->height,
7227 foreground, background,
7228 depth);
7229 if (img->pixmap)
7230 success_p = 1;
7231 else
7232 {
45158a91
GM
7233 image_error ("Unable to create pixmap for XBM image `%s'",
7234 img->spec, Qnil);
333b20bb
GM
7235 x_clear_image (f, img);
7236 }
7237
7238 UNBLOCK_INPUT;
7239 }
7240
7241 return success_p;
7242}
7243
7244
7245\f
7246/***********************************************************************
7247 XPM images
7248 ***********************************************************************/
7249
7250#if HAVE_XPM
7251
7252static int xpm_image_p P_ ((Lisp_Object object));
7253static int xpm_load P_ ((struct frame *f, struct image *img));
7254static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
7255
7256#include "X11/xpm.h"
7257
7258/* The symbol `xpm' identifying XPM-format images. */
7259
7260Lisp_Object Qxpm;
7261
7262/* Indices of image specification fields in xpm_format, below. */
7263
7264enum xpm_keyword_index
7265{
7266 XPM_TYPE,
7267 XPM_FILE,
7268 XPM_DATA,
7269 XPM_ASCENT,
7270 XPM_MARGIN,
7271 XPM_RELIEF,
7272 XPM_ALGORITHM,
7273 XPM_HEURISTIC_MASK,
7274 XPM_COLOR_SYMBOLS,
7275 XPM_LAST
7276};
7277
7278/* Vector of image_keyword structures describing the format
7279 of valid XPM image specifications. */
7280
7281static struct image_keyword xpm_format[XPM_LAST] =
7282{
7283 {":type", IMAGE_SYMBOL_VALUE, 1},
7284 {":file", IMAGE_STRING_VALUE, 0},
7285 {":data", IMAGE_STRING_VALUE, 0},
7286 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7287 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7288 {":relief", IMAGE_INTEGER_VALUE, 0},
7289 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7290 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7291 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7292};
7293
7294/* Structure describing the image type XBM. */
7295
7296static struct image_type xpm_type =
7297{
7298 &Qxpm,
7299 xpm_image_p,
7300 xpm_load,
7301 x_clear_image,
7302 NULL
7303};
7304
7305
7306/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
7307 for XPM images. Such a list must consist of conses whose car and
7308 cdr are strings. */
7309
7310static int
7311xpm_valid_color_symbols_p (color_symbols)
7312 Lisp_Object color_symbols;
7313{
7314 while (CONSP (color_symbols))
7315 {
7316 Lisp_Object sym = XCAR (color_symbols);
7317 if (!CONSP (sym)
7318 || !STRINGP (XCAR (sym))
7319 || !STRINGP (XCDR (sym)))
7320 break;
7321 color_symbols = XCDR (color_symbols);
7322 }
7323
7324 return NILP (color_symbols);
7325}
7326
7327
7328/* Value is non-zero if OBJECT is a valid XPM image specification. */
7329
7330static int
7331xpm_image_p (object)
7332 Lisp_Object object;
7333{
7334 struct image_keyword fmt[XPM_LAST];
7335 bcopy (xpm_format, fmt, sizeof fmt);
bfd2209f 7336 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
333b20bb
GM
7337 /* Either `:file' or `:data' must be present. */
7338 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
7339 /* Either no `:color-symbols' or it's a list of conses
7340 whose car and cdr are strings. */
7341 && (fmt[XPM_COLOR_SYMBOLS].count == 0
7342 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
7343 && (fmt[XPM_ASCENT].count == 0
7344 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
7345}
7346
7347
7348/* Load image IMG which will be displayed on frame F. Value is
7349 non-zero if successful. */
7350
7351static int
7352xpm_load (f, img)
7353 struct frame *f;
7354 struct image *img;
7355{
7356 int rc, i;
7357 XpmAttributes attrs;
7358 Lisp_Object specified_file, color_symbols;
7359
7360 /* Configure the XPM lib. Use the visual of frame F. Allocate
7361 close colors. Return colors allocated. */
7362 bzero (&attrs, sizeof attrs);
9b2956e2
GM
7363 attrs.visual = FRAME_X_VISUAL (f);
7364 attrs.colormap = FRAME_X_COLORMAP (f);
333b20bb 7365 attrs.valuemask |= XpmVisual;
9b2956e2 7366 attrs.valuemask |= XpmColormap;
333b20bb 7367 attrs.valuemask |= XpmReturnAllocPixels;
e4c082be 7368#ifdef XpmAllocCloseColors
333b20bb
GM
7369 attrs.alloc_close_colors = 1;
7370 attrs.valuemask |= XpmAllocCloseColors;
e4c082be
RS
7371#else
7372 attrs.closeness = 600;
7373 attrs.valuemask |= XpmCloseness;
7374#endif
333b20bb
GM
7375
7376 /* If image specification contains symbolic color definitions, add
7377 these to `attrs'. */
7378 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
7379 if (CONSP (color_symbols))
7380 {
7381 Lisp_Object tail;
7382 XpmColorSymbol *xpm_syms;
7383 int i, size;
7384
7385 attrs.valuemask |= XpmColorSymbols;
7386
7387 /* Count number of symbols. */
7388 attrs.numsymbols = 0;
7389 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
7390 ++attrs.numsymbols;
7391
7392 /* Allocate an XpmColorSymbol array. */
7393 size = attrs.numsymbols * sizeof *xpm_syms;
7394 xpm_syms = (XpmColorSymbol *) alloca (size);
7395 bzero (xpm_syms, size);
7396 attrs.colorsymbols = xpm_syms;
7397
7398 /* Fill the color symbol array. */
7399 for (tail = color_symbols, i = 0;
7400 CONSP (tail);
7401 ++i, tail = XCDR (tail))
7402 {
7403 Lisp_Object name = XCAR (XCAR (tail));
7404 Lisp_Object color = XCDR (XCAR (tail));
7405 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
7406 strcpy (xpm_syms[i].name, XSTRING (name)->data);
7407 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
7408 strcpy (xpm_syms[i].value, XSTRING (color)->data);
7409 }
7410 }
7411
7412 /* Create a pixmap for the image, either from a file, or from a
7413 string buffer containing data in the same format as an XPM file. */
7414 BLOCK_INPUT;
7415 specified_file = image_spec_value (img->spec, QCfile, NULL);
7416 if (STRINGP (specified_file))
7417 {
7418 Lisp_Object file = x_find_image_file (specified_file);
7419 if (!STRINGP (file))
7420 {
45158a91 7421 image_error ("Cannot find image file `%s'", specified_file, Qnil);
209061be 7422 UNBLOCK_INPUT;
333b20bb
GM
7423 return 0;
7424 }
7425
7426 rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7427 XSTRING (file)->data, &img->pixmap, &img->mask,
7428 &attrs);
7429 }
7430 else
7431 {
7432 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
7433 rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7434 XSTRING (buffer)->data,
7435 &img->pixmap, &img->mask,
7436 &attrs);
7437 }
7438 UNBLOCK_INPUT;
7439
7440 if (rc == XpmSuccess)
7441 {
7442 /* Remember allocated colors. */
7443 img->ncolors = attrs.nalloc_pixels;
7444 img->colors = (unsigned long *) xmalloc (img->ncolors
7445 * sizeof *img->colors);
7446 for (i = 0; i < attrs.nalloc_pixels; ++i)
7447 img->colors[i] = attrs.alloc_pixels[i];
7448
7449 img->width = attrs.width;
7450 img->height = attrs.height;
7451 xassert (img->width > 0 && img->height > 0);
7452
7453 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
7454 BLOCK_INPUT;
7455 XpmFreeAttributes (&attrs);
7456 UNBLOCK_INPUT;
7457 }
7458 else
7459 {
7460 switch (rc)
7461 {
7462 case XpmOpenFailed:
7463 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
7464 break;
7465
7466 case XpmFileInvalid:
7467 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
7468 break;
7469
7470 case XpmNoMemory:
7471 image_error ("Out of memory (%s)", img->spec, Qnil);
7472 break;
7473
7474 case XpmColorFailed:
7475 image_error ("Color allocation error (%s)", img->spec, Qnil);
7476 break;
7477
7478 default:
7479 image_error ("Unknown error (%s)", img->spec, Qnil);
7480 break;
7481 }
7482 }
7483
7484 return rc == XpmSuccess;
7485}
7486
7487#endif /* HAVE_XPM != 0 */
7488
7489\f
7490/***********************************************************************
7491 Color table
7492 ***********************************************************************/
7493
7494/* An entry in the color table mapping an RGB color to a pixel color. */
7495
7496struct ct_color
7497{
7498 int r, g, b;
7499 unsigned long pixel;
7500
7501 /* Next in color table collision list. */
7502 struct ct_color *next;
7503};
7504
7505/* The bucket vector size to use. Must be prime. */
7506
7507#define CT_SIZE 101
7508
7509/* Value is a hash of the RGB color given by R, G, and B. */
7510
7511#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
7512
7513/* The color hash table. */
7514
7515struct ct_color **ct_table;
7516
7517/* Number of entries in the color table. */
7518
7519int ct_colors_allocated;
7520
7521/* Function prototypes. */
7522
7523static void init_color_table P_ ((void));
7524static void free_color_table P_ ((void));
7525static unsigned long *colors_in_color_table P_ ((int *n));
7526static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
7527static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
7528
7529
7530/* Initialize the color table. */
7531
7532static void
7533init_color_table ()
7534{
7535 int size = CT_SIZE * sizeof (*ct_table);
7536 ct_table = (struct ct_color **) xmalloc (size);
7537 bzero (ct_table, size);
7538 ct_colors_allocated = 0;
7539}
7540
7541
7542/* Free memory associated with the color table. */
7543
7544static void
7545free_color_table ()
7546{
7547 int i;
7548 struct ct_color *p, *next;
7549
7550 for (i = 0; i < CT_SIZE; ++i)
7551 for (p = ct_table[i]; p; p = next)
7552 {
7553 next = p->next;
7554 xfree (p);
7555 }
7556
7557 xfree (ct_table);
7558 ct_table = NULL;
7559}
7560
7561
7562/* Value is a pixel color for RGB color R, G, B on frame F. If an
7563 entry for that color already is in the color table, return the
7564 pixel color of that entry. Otherwise, allocate a new color for R,
7565 G, B, and make an entry in the color table. */
7566
7567static unsigned long
7568lookup_rgb_color (f, r, g, b)
7569 struct frame *f;
7570 int r, g, b;
7571{
7572 unsigned hash = CT_HASH_RGB (r, g, b);
7573 int i = hash % CT_SIZE;
7574 struct ct_color *p;
7575
7576 for (p = ct_table[i]; p; p = p->next)
7577 if (p->r == r && p->g == g && p->b == b)
7578 break;
7579
7580 if (p == NULL)
7581 {
7582 XColor color;
7583 Colormap cmap;
7584 int rc;
7585
7586 color.red = r;
7587 color.green = g;
7588 color.blue = b;
7589
7590 BLOCK_INPUT;
9b2956e2 7591 cmap = FRAME_X_COLORMAP (f);
d62c8769 7592 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7593 UNBLOCK_INPUT;
7594
7595 if (rc)
7596 {
7597 ++ct_colors_allocated;
7598
7599 p = (struct ct_color *) xmalloc (sizeof *p);
7600 p->r = r;
7601 p->g = g;
7602 p->b = b;
7603 p->pixel = color.pixel;
7604 p->next = ct_table[i];
7605 ct_table[i] = p;
7606 }
7607 else
7608 return FRAME_FOREGROUND_PIXEL (f);
7609 }
7610
7611 return p->pixel;
7612}
7613
7614
7615/* Look up pixel color PIXEL which is used on frame F in the color
7616 table. If not already present, allocate it. Value is PIXEL. */
7617
7618static unsigned long
7619lookup_pixel_color (f, pixel)
7620 struct frame *f;
7621 unsigned long pixel;
7622{
7623 int i = pixel % CT_SIZE;
7624 struct ct_color *p;
7625
7626 for (p = ct_table[i]; p; p = p->next)
7627 if (p->pixel == pixel)
7628 break;
7629
7630 if (p == NULL)
7631 {
7632 XColor color;
7633 Colormap cmap;
7634 int rc;
7635
7636 BLOCK_INPUT;
7637
9b2956e2 7638 cmap = FRAME_X_COLORMAP (f);
333b20bb
GM
7639 color.pixel = pixel;
7640 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
d62c8769 7641 rc = x_alloc_nearest_color (f, cmap, &color);
333b20bb
GM
7642 UNBLOCK_INPUT;
7643
7644 if (rc)
7645 {
7646 ++ct_colors_allocated;
7647
7648 p = (struct ct_color *) xmalloc (sizeof *p);
7649 p->r = color.red;
7650 p->g = color.green;
7651 p->b = color.blue;
7652 p->pixel = pixel;
7653 p->next = ct_table[i];
7654 ct_table[i] = p;
7655 }
7656 else
7657 return FRAME_FOREGROUND_PIXEL (f);
7658 }
7659
7660 return p->pixel;
7661}
7662
7663
7664/* Value is a vector of all pixel colors contained in the color table,
7665 allocated via xmalloc. Set *N to the number of colors. */
7666
7667static unsigned long *
7668colors_in_color_table (n)
7669 int *n;
7670{
7671 int i, j;
7672 struct ct_color *p;
7673 unsigned long *colors;
7674
7675 if (ct_colors_allocated == 0)
7676 {
7677 *n = 0;
7678 colors = NULL;
7679 }
7680 else
7681 {
7682 colors = (unsigned long *) xmalloc (ct_colors_allocated
7683 * sizeof *colors);
7684 *n = ct_colors_allocated;
7685
7686 for (i = j = 0; i < CT_SIZE; ++i)
7687 for (p = ct_table[i]; p; p = p->next)
7688 colors[j++] = p->pixel;
7689 }
7690
7691 return colors;
7692}
7693
7694
7695\f
7696/***********************************************************************
7697 Algorithms
7698 ***********************************************************************/
7699
7700static void x_laplace_write_row P_ ((struct frame *, long *,
7701 int, XImage *, int));
7702static void x_laplace_read_row P_ ((struct frame *, Colormap,
7703 XColor *, int, XImage *, int));
7704
7705
7706/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
7707 frame we operate on, CMAP is the color-map in effect, and WIDTH is
7708 the width of one row in the image. */
7709
7710static void
7711x_laplace_read_row (f, cmap, colors, width, ximg, y)
7712 struct frame *f;
7713 Colormap cmap;
7714 XColor *colors;
7715 int width;
7716 XImage *ximg;
7717 int y;
7718{
7719 int x;
7720
7721 for (x = 0; x < width; ++x)
7722 colors[x].pixel = XGetPixel (ximg, x, y);
7723
7724 XQueryColors (FRAME_X_DISPLAY (f), cmap, colors, width);
7725}
7726
7727
7728/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
7729 containing the pixel colors to write. F is the frame we are
7730 working on. */
7731
7732static void
7733x_laplace_write_row (f, pixels, width, ximg, y)
7734 struct frame *f;
7735 long *pixels;
7736 int width;
7737 XImage *ximg;
7738 int y;
7739{
7740 int x;
7741
7742 for (x = 0; x < width; ++x)
7743 XPutPixel (ximg, x, y, pixels[x]);
7744}
7745
7746
7747/* Transform image IMG which is used on frame F with a Laplace
7748 edge-detection algorithm. The result is an image that can be used
7749 to draw disabled buttons, for example. */
7750
7751static void
7752x_laplace (f, img)
7753 struct frame *f;
7754 struct image *img;
7755{
9b2956e2 7756 Colormap cmap = FRAME_X_COLORMAP (f);
333b20bb
GM
7757 XImage *ximg, *oimg;
7758 XColor *in[3];
7759 long *out;
7760 Pixmap pixmap;
7761 int x, y, i;
7762 long pixel;
7763 int in_y, out_y, rc;
7764 int mv2 = 45000;
7765
7766 BLOCK_INPUT;
7767
7768 /* Get the X image IMG->pixmap. */
7769 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
7770 0, 0, img->width, img->height, ~0, ZPixmap);
7771
7772 /* Allocate 3 input rows, and one output row of colors. */
7773 for (i = 0; i < 3; ++i)
7774 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
7775 out = (long *) alloca (img->width * sizeof (long));
7776
7777 /* Create an X image for output. */
45158a91 7778 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
333b20bb
GM
7779 &oimg, &pixmap);
7780
7781 /* Fill first two rows. */
7782 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
7783 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
7784 in_y = 2;
7785
7786 /* Write first row, all zeros. */
7787 init_color_table ();
7788 pixel = lookup_rgb_color (f, 0, 0, 0);
7789 for (x = 0; x < img->width; ++x)
7790 out[x] = pixel;
7791 x_laplace_write_row (f, out, img->width, oimg, 0);
7792 out_y = 1;
7793
7794 for (y = 2; y < img->height; ++y)
7795 {
7796 int rowa = y % 3;
7797 int rowb = (y + 2) % 3;
7798
7799 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
7800
7801 for (x = 0; x < img->width - 2; ++x)
7802 {
7803 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
7804 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
7805 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
7806
7807 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
7808 b & 0xffff);
7809 }
7810
7811 x_laplace_write_row (f, out, img->width, oimg, out_y++);
7812 }
7813
7814 /* Write last line, all zeros. */
7815 for (x = 0; x < img->width; ++x)
7816 out[x] = pixel;
7817 x_laplace_write_row (f, out, img->width, oimg, out_y);
7818
7819 /* Free the input image, and free resources of IMG. */
7820 XDestroyImage (ximg);
7821 x_clear_image (f, img);
7822
7823 /* Put the output image into pixmap, and destroy it. */
7824 x_put_x_image (f, oimg, pixmap, img->width, img->height);
7825 x_destroy_x_image (oimg);
7826
7827 /* Remember new pixmap and colors in IMG. */
7828 img->pixmap = pixmap;
7829 img->colors = colors_in_color_table (&img->ncolors);
7830 free_color_table ();
7831
7832 UNBLOCK_INPUT;
7833}
7834
7835
7836/* Build a mask for image IMG which is used on frame F. FILE is the
7837 name of an image file, for error messages. HOW determines how to
fcf431dc
GM
7838 determine the background color of IMG. If it is a list '(R G B)',
7839 with R, G, and B being integers >= 0, take that as the color of the
7840 background. Otherwise, determine the background color of IMG
7841 heuristically. Value is non-zero if successful. */
333b20bb
GM
7842
7843static int
45158a91 7844x_build_heuristic_mask (f, img, how)
333b20bb 7845 struct frame *f;
333b20bb
GM
7846 struct image *img;
7847 Lisp_Object how;
7848{
7849 Display *dpy = FRAME_X_DISPLAY (f);
333b20bb 7850 XImage *ximg, *mask_img;
fcf431dc 7851 int x, y, rc, look_at_corners_p;
333b20bb
GM
7852 unsigned long bg;
7853
7854 BLOCK_INPUT;
7855
7856 /* Create an image and pixmap serving as mask. */
45158a91 7857 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
333b20bb
GM
7858 &mask_img, &img->mask);
7859 if (!rc)
7860 {
7861 UNBLOCK_INPUT;
7862 return 0;
7863 }
7864
7865 /* Get the X image of IMG->pixmap. */
7866 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
7867 ~0, ZPixmap);
7868
fcf431dc
GM
7869 /* Determine the background color of ximg. If HOW is `(R G B)'
7870 take that as color. Otherwise, try to determine the color
7871 heuristically. */
7872 look_at_corners_p = 1;
7873
7874 if (CONSP (how))
7875 {
7876 int rgb[3], i = 0;
7877
7878 while (i < 3
7879 && CONSP (how)
7880 && NATNUMP (XCAR (how)))
7881 {
7882 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
7883 how = XCDR (how);
7884 }
7885
7886 if (i == 3 && NILP (how))
7887 {
7888 char color_name[30];
7889 XColor exact, color;
7890 Colormap cmap;
7891
7892 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
7893
9b2956e2 7894 cmap = FRAME_X_COLORMAP (f);
fcf431dc
GM
7895 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
7896 {
7897 bg = color.pixel;
7898 look_at_corners_p = 0;
7899 }
7900 }
7901 }
7902
7903 if (look_at_corners_p)
333b20bb
GM
7904 {
7905 unsigned long corners[4];
7906 int i, best_count;
7907
7908 /* Get the colors at the corners of ximg. */
7909 corners[0] = XGetPixel (ximg, 0, 0);
7910 corners[1] = XGetPixel (ximg, img->width - 1, 0);
7911 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
7912 corners[3] = XGetPixel (ximg, 0, img->height - 1);
7913
7914 /* Choose the most frequently found color as background. */
7915 for (i = best_count = 0; i < 4; ++i)
7916 {
7917 int j, n;
7918
7919 for (j = n = 0; j < 4; ++j)
7920 if (corners[i] == corners[j])
7921 ++n;
7922
7923 if (n > best_count)
7924 bg = corners[i], best_count = n;
7925 }
7926 }
7927
7928 /* Set all bits in mask_img to 1 whose color in ximg is different
7929 from the background color bg. */
7930 for (y = 0; y < img->height; ++y)
7931 for (x = 0; x < img->width; ++x)
7932 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
7933
7934 /* Put mask_img into img->mask. */
7935 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7936 x_destroy_x_image (mask_img);
7937 XDestroyImage (ximg);
7938
7939 UNBLOCK_INPUT;
7940 return 1;
7941}
7942
7943
7944\f
7945/***********************************************************************
7946 PBM (mono, gray, color)
7947 ***********************************************************************/
7948
7949static int pbm_image_p P_ ((Lisp_Object object));
7950static int pbm_load P_ ((struct frame *f, struct image *img));
63cec32f 7951static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
333b20bb
GM
7952
7953/* The symbol `pbm' identifying images of this type. */
7954
7955Lisp_Object Qpbm;
7956
7957/* Indices of image specification fields in gs_format, below. */
7958
7959enum pbm_keyword_index
7960{
7961 PBM_TYPE,
7962 PBM_FILE,
63cec32f 7963 PBM_DATA,
333b20bb
GM
7964 PBM_ASCENT,
7965 PBM_MARGIN,
7966 PBM_RELIEF,
7967 PBM_ALGORITHM,
7968 PBM_HEURISTIC_MASK,
7969 PBM_LAST
7970};
7971
7972/* Vector of image_keyword structures describing the format
7973 of valid user-defined image specifications. */
7974
7975static struct image_keyword pbm_format[PBM_LAST] =
7976{
7977 {":type", IMAGE_SYMBOL_VALUE, 1},
63cec32f
GM
7978 {":file", IMAGE_STRING_VALUE, 0},
7979 {":data", IMAGE_STRING_VALUE, 0},
333b20bb
GM
7980 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7981 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7982 {":relief", IMAGE_INTEGER_VALUE, 0},
7983 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7984 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7985};
7986
7987/* Structure describing the image type `pbm'. */
7988
7989static struct image_type pbm_type =
7990{
7991 &Qpbm,
7992 pbm_image_p,
7993 pbm_load,
7994 x_clear_image,
7995 NULL
7996};
7997
7998
7999/* Return non-zero if OBJECT is a valid PBM image specification. */
8000
8001static int
8002pbm_image_p (object)
8003 Lisp_Object object;
8004{
8005 struct image_keyword fmt[PBM_LAST];
8006
8007 bcopy (pbm_format, fmt, sizeof fmt);
8008
bfd2209f 8009 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
333b20bb
GM
8010 || (fmt[PBM_ASCENT].count
8011 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
8012 return 0;
63cec32f
GM
8013
8014 /* Must specify either :data or :file. */
8015 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
333b20bb
GM
8016}
8017
8018
63cec32f
GM
8019/* Scan a decimal number from *S and return it. Advance *S while
8020 reading the number. END is the end of the string. Value is -1 at
8021 end of input. */
333b20bb
GM
8022
8023static int
63cec32f
GM
8024pbm_scan_number (s, end)
8025 unsigned char **s, *end;
333b20bb
GM
8026{
8027 int c, val = -1;
8028
63cec32f 8029 while (*s < end)
333b20bb
GM
8030 {
8031 /* Skip white-space. */
63cec32f 8032 while (*s < end && (c = *(*s)++, isspace (c)))
333b20bb
GM
8033 ;
8034
8035 if (c == '#')
8036 {
8037 /* Skip comment to end of line. */
63cec32f 8038 while (*s < end && (c = *(*s)++, c != '\n'))
333b20bb
GM
8039 ;
8040 }
8041 else if (isdigit (c))
8042 {
8043 /* Read decimal number. */
8044 val = c - '0';
63cec32f 8045 while (*s < end && (c = *(*s)++, isdigit (c)))
333b20bb
GM
8046 val = 10 * val + c - '0';
8047 break;
8048 }
8049 else
8050 break;
8051 }
8052
8053 return val;
8054}
8055
8056
63cec32f
GM
8057/* Read FILE into memory. Value is a pointer to a buffer allocated
8058 with xmalloc holding FILE's contents. Value is null if an error
8059 occured. *SIZE is set to the size of the file. */
8060
8061static char *
8062pbm_read_file (file, size)
8063 Lisp_Object file;
8064 int *size;
8065{
8066 FILE *fp = NULL;
8067 char *buf = NULL;
8068 struct stat st;
8069
8070 if (stat (XSTRING (file)->data, &st) == 0
8071 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
8072 && (buf = (char *) xmalloc (st.st_size),
8073 fread (buf, 1, st.st_size, fp) == st.st_size))
8074 {
8075 *size = st.st_size;
8076 fclose (fp);
8077 }
8078 else
8079 {
8080 if (fp)
8081 fclose (fp);
8082 if (buf)
8083 {
8084 xfree (buf);
8085 buf = NULL;
8086 }
8087 }
8088
8089 return buf;
8090}
8091
8092
333b20bb
GM
8093/* Load PBM image IMG for use on frame F. */
8094
8095static int
8096pbm_load (f, img)
8097 struct frame *f;
8098 struct image *img;
8099{
333b20bb 8100 int raw_p, x, y;
b6d7acec 8101 int width, height, max_color_idx = 0;
333b20bb
GM
8102 XImage *ximg;
8103 Lisp_Object file, specified_file;
8104 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
8105 struct gcpro gcpro1;
63cec32f
GM
8106 unsigned char *contents = NULL;
8107 unsigned char *end, *p;
8108 int size;
333b20bb
GM
8109
8110 specified_file = image_spec_value (img->spec, QCfile, NULL);
63cec32f 8111 file = Qnil;
333b20bb 8112 GCPRO1 (file);
333b20bb 8113
63cec32f 8114 if (STRINGP (specified_file))
333b20bb 8115 {
63cec32f
GM
8116 file = x_find_image_file (specified_file);
8117 if (!STRINGP (file))
8118 {
8119 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8120 UNGCPRO;
8121 return 0;
8122 }
333b20bb 8123
63cec32f
GM
8124 contents = pbm_read_file (file, &size);
8125 if (contents == NULL)
8126 {
8127 image_error ("Error reading `%s'", file, Qnil);
8128 UNGCPRO;
8129 return 0;
8130 }
8131
8132 p = contents;
8133 end = contents + size;
8134 }
8135 else
333b20bb 8136 {
63cec32f
GM
8137 Lisp_Object data;
8138 data = image_spec_value (img->spec, QCdata, NULL);
8139 p = XSTRING (data)->data;
8140 end = p + STRING_BYTES (XSTRING (data));
333b20bb
GM
8141 }
8142
63cec32f
GM
8143 /* Check magic number. */
8144 if (end - p < 2 || *p++ != 'P')
333b20bb 8145 {
45158a91 8146 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f
GM
8147 error:
8148 xfree (contents);
333b20bb
GM
8149 UNGCPRO;
8150 return 0;
8151 }
8152
63cec32f 8153 switch (*p++)
333b20bb
GM
8154 {
8155 case '1':
8156 raw_p = 0, type = PBM_MONO;
8157 break;
8158
8159 case '2':
8160 raw_p = 0, type = PBM_GRAY;
8161 break;
8162
8163 case '3':
8164 raw_p = 0, type = PBM_COLOR;
8165 break;
8166
8167 case '4':
8168 raw_p = 1, type = PBM_MONO;
8169 break;
8170
8171 case '5':
8172 raw_p = 1, type = PBM_GRAY;
8173 break;
8174
8175 case '6':
8176 raw_p = 1, type = PBM_COLOR;
8177 break;
8178
8179 default:
45158a91 8180 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
63cec32f 8181 goto error;
333b20bb
GM
8182 }
8183
8184 /* Read width, height, maximum color-component. Characters
8185 starting with `#' up to the end of a line are ignored. */
63cec32f
GM
8186 width = pbm_scan_number (&p, end);
8187 height = pbm_scan_number (&p, end);
333b20bb
GM
8188
8189 if (type != PBM_MONO)
8190 {
63cec32f 8191 max_color_idx = pbm_scan_number (&p, end);
333b20bb
GM
8192 if (raw_p && max_color_idx > 255)
8193 max_color_idx = 255;
8194 }
8195
63cec32f
GM
8196 if (width < 0
8197 || height < 0
333b20bb 8198 || (type != PBM_MONO && max_color_idx < 0))
63cec32f 8199 goto error;
333b20bb
GM
8200
8201 BLOCK_INPUT;
45158a91 8202 if (!x_create_x_image_and_pixmap (f, width, height, 0,
333b20bb
GM
8203 &ximg, &img->pixmap))
8204 {
333b20bb 8205 UNBLOCK_INPUT;
63cec32f 8206 goto error;
333b20bb
GM
8207 }
8208
8209 /* Initialize the color hash table. */
8210 init_color_table ();
8211
8212 if (type == PBM_MONO)
8213 {
8214 int c = 0, g;
8215
8216 for (y = 0; y < height; ++y)
8217 for (x = 0; x < width; ++x)
8218 {
8219 if (raw_p)
8220 {
8221 if ((x & 7) == 0)
63cec32f 8222 c = *p++;
333b20bb
GM
8223 g = c & 0x80;
8224 c <<= 1;
8225 }
8226 else
63cec32f 8227 g = pbm_scan_number (&p, end);
333b20bb
GM
8228
8229 XPutPixel (ximg, x, y, (g
8230 ? FRAME_FOREGROUND_PIXEL (f)
8231 : FRAME_BACKGROUND_PIXEL (f)));
8232 }
8233 }
8234 else
8235 {
8236 for (y = 0; y < height; ++y)
8237 for (x = 0; x < width; ++x)
8238 {
8239 int r, g, b;
8240
8241 if (type == PBM_GRAY)
63cec32f 8242 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
333b20bb
GM
8243 else if (raw_p)
8244 {
63cec32f
GM
8245 r = *p++;
8246 g = *p++;
8247 b = *p++;
333b20bb
GM
8248 }
8249 else
8250 {
63cec32f
GM
8251 r = pbm_scan_number (&p, end);
8252 g = pbm_scan_number (&p, end);
8253 b = pbm_scan_number (&p, end);
333b20bb
GM
8254 }
8255
8256 if (r < 0 || g < 0 || b < 0)
8257 {
333b20bb
GM
8258 xfree (ximg->data);
8259 ximg->data = NULL;
8260 XDestroyImage (ximg);
8261 UNBLOCK_INPUT;
45158a91
GM
8262 image_error ("Invalid pixel value in image `%s'",
8263 img->spec, Qnil);
63cec32f 8264 goto error;
333b20bb
GM
8265 }
8266
8267 /* RGB values are now in the range 0..max_color_idx.
8268 Scale this to the range 0..0xffff supported by X. */
8269 r = (double) r * 65535 / max_color_idx;
8270 g = (double) g * 65535 / max_color_idx;
8271 b = (double) b * 65535 / max_color_idx;
8272 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8273 }
8274 }
8275
333b20bb
GM
8276 /* Store in IMG->colors the colors allocated for the image, and
8277 free the color table. */
8278 img->colors = colors_in_color_table (&img->ncolors);
8279 free_color_table ();
8280
8281 /* Put the image into a pixmap. */
8282 x_put_x_image (f, ximg, img->pixmap, width, height);
8283 x_destroy_x_image (ximg);
8284 UNBLOCK_INPUT;
8285
8286 img->width = width;
8287 img->height = height;
8288
8289 UNGCPRO;
63cec32f 8290 xfree (contents);
333b20bb
GM
8291 return 1;
8292}
8293
8294
8295\f
8296/***********************************************************************
8297 PNG
8298 ***********************************************************************/
8299
8300#if HAVE_PNG
8301
8302#include <png.h>
8303
8304/* Function prototypes. */
8305
8306static int png_image_p P_ ((Lisp_Object object));
8307static int png_load P_ ((struct frame *f, struct image *img));
8308
8309/* The symbol `png' identifying images of this type. */
8310
8311Lisp_Object Qpng;
8312
8313/* Indices of image specification fields in png_format, below. */
8314
8315enum png_keyword_index
8316{
8317 PNG_TYPE,
63448a4d 8318 PNG_DATA,
333b20bb
GM
8319 PNG_FILE,
8320 PNG_ASCENT,
8321 PNG_MARGIN,
8322 PNG_RELIEF,
8323 PNG_ALGORITHM,
8324 PNG_HEURISTIC_MASK,
8325 PNG_LAST
8326};
8327
8328/* Vector of image_keyword structures describing the format
8329 of valid user-defined image specifications. */
8330
8331static struct image_keyword png_format[PNG_LAST] =
8332{
8333 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8334 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 8335 {":file", IMAGE_STRING_VALUE, 0},
333b20bb
GM
8336 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8337 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8338 {":relief", IMAGE_INTEGER_VALUE, 0},
8339 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8340 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8341};
8342
06482119 8343/* Structure describing the image type `png'. */
333b20bb
GM
8344
8345static struct image_type png_type =
8346{
8347 &Qpng,
8348 png_image_p,
8349 png_load,
8350 x_clear_image,
8351 NULL
8352};
8353
8354
8355/* Return non-zero if OBJECT is a valid PNG image specification. */
8356
8357static int
8358png_image_p (object)
8359 Lisp_Object object;
8360{
8361 struct image_keyword fmt[PNG_LAST];
8362 bcopy (png_format, fmt, sizeof fmt);
8363
bfd2209f 8364 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
333b20bb
GM
8365 || (fmt[PNG_ASCENT].count
8366 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
8367 return 0;
63448a4d 8368
63cec32f
GM
8369 /* Must specify either the :data or :file keyword. */
8370 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
333b20bb
GM
8371}
8372
8373
8374/* Error and warning handlers installed when the PNG library
8375 is initialized. */
8376
8377static void
8378my_png_error (png_ptr, msg)
8379 png_struct *png_ptr;
8380 char *msg;
8381{
8382 xassert (png_ptr != NULL);
8383 image_error ("PNG error: %s", build_string (msg), Qnil);
8384 longjmp (png_ptr->jmpbuf, 1);
8385}
8386
8387
8388static void
8389my_png_warning (png_ptr, msg)
8390 png_struct *png_ptr;
8391 char *msg;
8392{
8393 xassert (png_ptr != NULL);
8394 image_error ("PNG warning: %s", build_string (msg), Qnil);
8395}
8396
5ad6a5fb
GM
8397/* Memory source for PNG decoding. */
8398
63448a4d
WP
8399struct png_memory_storage
8400{
5ad6a5fb
GM
8401 unsigned char *bytes; /* The data */
8402 size_t len; /* How big is it? */
8403 int index; /* Where are we? */
63448a4d
WP
8404};
8405
5ad6a5fb
GM
8406
8407/* Function set as reader function when reading PNG image from memory.
8408 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
8409 bytes from the input to DATA. */
8410
63448a4d 8411static void
5ad6a5fb
GM
8412png_read_from_memory (png_ptr, data, length)
8413 png_structp png_ptr;
8414 png_bytep data;
8415 png_size_t length;
63448a4d 8416{
5ad6a5fb
GM
8417 struct png_memory_storage *tbr
8418 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
63448a4d 8419
5ad6a5fb
GM
8420 if (length > tbr->len - tbr->index)
8421 png_error (png_ptr, "Read error");
8422
8423 bcopy (tbr->bytes + tbr->index, data, length);
8424 tbr->index = tbr->index + length;
63448a4d 8425}
333b20bb
GM
8426
8427/* Load PNG image IMG for use on frame F. Value is non-zero if
8428 successful. */
8429
8430static int
8431png_load (f, img)
8432 struct frame *f;
8433 struct image *img;
8434{
8435 Lisp_Object file, specified_file;
63448a4d 8436 Lisp_Object specified_data;
b6d7acec 8437 int x, y, i;
333b20bb
GM
8438 XImage *ximg, *mask_img = NULL;
8439 struct gcpro gcpro1;
8440 png_struct *png_ptr = NULL;
8441 png_info *info_ptr = NULL, *end_info = NULL;
63448a4d 8442 FILE *fp = NULL;
333b20bb
GM
8443 png_byte sig[8];
8444 png_byte *pixels = NULL;
8445 png_byte **rows = NULL;
8446 png_uint_32 width, height;
8447 int bit_depth, color_type, interlace_type;
8448 png_byte channels;
8449 png_uint_32 row_bytes;
8450 int transparent_p;
8451 char *gamma_str;
8452 double screen_gamma, image_gamma;
8453 int intent;
63448a4d 8454 struct png_memory_storage tbr; /* Data to be read */
333b20bb
GM
8455
8456 /* Find out what file to load. */
8457 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 8458 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8459 file = Qnil;
8460 GCPRO1 (file);
333b20bb 8461
63448a4d 8462 if (NILP (specified_data))
5ad6a5fb
GM
8463 {
8464 file = x_find_image_file (specified_file);
8465 if (!STRINGP (file))
63448a4d 8466 {
45158a91 8467 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
8468 UNGCPRO;
8469 return 0;
8470 }
333b20bb 8471
5ad6a5fb
GM
8472 /* Open the image file. */
8473 fp = fopen (XSTRING (file)->data, "rb");
8474 if (!fp)
8475 {
45158a91 8476 image_error ("Cannot open image file `%s'", file, Qnil);
5ad6a5fb
GM
8477 UNGCPRO;
8478 fclose (fp);
8479 return 0;
8480 }
63448a4d 8481
5ad6a5fb
GM
8482 /* Check PNG signature. */
8483 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
8484 || !png_check_sig (sig, sizeof sig))
8485 {
45158a91 8486 image_error ("Not a PNG file: `%s'", file, Qnil);
5ad6a5fb
GM
8487 UNGCPRO;
8488 fclose (fp);
8489 return 0;
63448a4d 8490 }
5ad6a5fb 8491 }
63448a4d 8492 else
5ad6a5fb
GM
8493 {
8494 /* Read from memory. */
8495 tbr.bytes = XSTRING (specified_data)->data;
8496 tbr.len = STRING_BYTES (XSTRING (specified_data));
8497 tbr.index = 0;
63448a4d 8498
5ad6a5fb
GM
8499 /* Check PNG signature. */
8500 if (tbr.len < sizeof sig
8501 || !png_check_sig (tbr.bytes, sizeof sig))
8502 {
45158a91 8503 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
5ad6a5fb
GM
8504 UNGCPRO;
8505 return 0;
63448a4d 8506 }
333b20bb 8507
5ad6a5fb
GM
8508 /* Need to skip past the signature. */
8509 tbr.bytes += sizeof (sig);
8510 }
8511
333b20bb
GM
8512 /* Initialize read and info structs for PNG lib. */
8513 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
8514 my_png_error, my_png_warning);
8515 if (!png_ptr)
8516 {
63448a4d 8517 if (fp) fclose (fp);
333b20bb
GM
8518 UNGCPRO;
8519 return 0;
8520 }
8521
8522 info_ptr = png_create_info_struct (png_ptr);
8523 if (!info_ptr)
8524 {
8525 png_destroy_read_struct (&png_ptr, NULL, NULL);
63448a4d 8526 if (fp) fclose (fp);
333b20bb
GM
8527 UNGCPRO;
8528 return 0;
8529 }
8530
8531 end_info = png_create_info_struct (png_ptr);
8532 if (!end_info)
8533 {
8534 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
63448a4d 8535 if (fp) fclose (fp);
333b20bb
GM
8536 UNGCPRO;
8537 return 0;
8538 }
8539
8540 /* Set error jump-back. We come back here when the PNG library
8541 detects an error. */
8542 if (setjmp (png_ptr->jmpbuf))
8543 {
8544 error:
8545 if (png_ptr)
8546 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8547 xfree (pixels);
8548 xfree (rows);
63448a4d 8549 if (fp) fclose (fp);
333b20bb
GM
8550 UNGCPRO;
8551 return 0;
8552 }
8553
8554 /* Read image info. */
63448a4d 8555 if (!NILP (specified_data))
5ad6a5fb 8556 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
63448a4d 8557 else
5ad6a5fb 8558 png_init_io (png_ptr, fp);
63448a4d 8559
333b20bb
GM
8560 png_set_sig_bytes (png_ptr, sizeof sig);
8561 png_read_info (png_ptr, info_ptr);
8562 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
8563 &interlace_type, NULL, NULL);
8564
8565 /* If image contains simply transparency data, we prefer to
8566 construct a clipping mask. */
8567 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
8568 transparent_p = 1;
8569 else
8570 transparent_p = 0;
8571
8572 /* This function is easier to write if we only have to handle
8573 one data format: RGB or RGBA with 8 bits per channel. Let's
8574 transform other formats into that format. */
8575
8576 /* Strip more than 8 bits per channel. */
8577 if (bit_depth == 16)
8578 png_set_strip_16 (png_ptr);
8579
8580 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
8581 if available. */
8582 png_set_expand (png_ptr);
8583
8584 /* Convert grayscale images to RGB. */
8585 if (color_type == PNG_COLOR_TYPE_GRAY
8586 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8587 png_set_gray_to_rgb (png_ptr);
8588
8589 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
8590 gamma_str = getenv ("SCREEN_GAMMA");
8591 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
8592
8593 /* Tell the PNG lib to handle gamma correction for us. */
8594
6c1aa34d 8595#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
333b20bb
GM
8596 if (png_get_sRGB (png_ptr, info_ptr, &intent))
8597 /* There is a special chunk in the image specifying the gamma. */
8598 png_set_sRGB (png_ptr, info_ptr, intent);
6c1aa34d
GM
8599 else
8600#endif
8601 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
333b20bb
GM
8602 /* Image contains gamma information. */
8603 png_set_gamma (png_ptr, screen_gamma, image_gamma);
8604 else
8605 /* Use a default of 0.5 for the image gamma. */
8606 png_set_gamma (png_ptr, screen_gamma, 0.5);
8607
8608 /* Handle alpha channel by combining the image with a background
8609 color. Do this only if a real alpha channel is supplied. For
8610 simple transparency, we prefer a clipping mask. */
8611 if (!transparent_p)
8612 {
8613 png_color_16 *image_background;
8614
8615 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
8616 /* Image contains a background color with which to
8617 combine the image. */
8618 png_set_background (png_ptr, image_background,
8619 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
8620 else
8621 {
8622 /* Image does not contain a background color with which
8623 to combine the image data via an alpha channel. Use
8624 the frame's background instead. */
8625 XColor color;
8626 Colormap cmap;
8627 png_color_16 frame_background;
8628
8629 BLOCK_INPUT;
9b2956e2 8630 cmap = FRAME_X_COLORMAP (f);
333b20bb
GM
8631 color.pixel = FRAME_BACKGROUND_PIXEL (f);
8632 XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
8633 UNBLOCK_INPUT;
8634
8635 bzero (&frame_background, sizeof frame_background);
8636 frame_background.red = color.red;
8637 frame_background.green = color.green;
8638 frame_background.blue = color.blue;
8639
8640 png_set_background (png_ptr, &frame_background,
8641 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
8642 }
8643 }
8644
8645 /* Update info structure. */
8646 png_read_update_info (png_ptr, info_ptr);
8647
8648 /* Get number of channels. Valid values are 1 for grayscale images
8649 and images with a palette, 2 for grayscale images with transparency
8650 information (alpha channel), 3 for RGB images, and 4 for RGB
8651 images with alpha channel, i.e. RGBA. If conversions above were
8652 sufficient we should only have 3 or 4 channels here. */
8653 channels = png_get_channels (png_ptr, info_ptr);
8654 xassert (channels == 3 || channels == 4);
8655
8656 /* Number of bytes needed for one row of the image. */
8657 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
8658
8659 /* Allocate memory for the image. */
8660 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
8661 rows = (png_byte **) xmalloc (height * sizeof *rows);
8662 for (i = 0; i < height; ++i)
8663 rows[i] = pixels + i * row_bytes;
8664
8665 /* Read the entire image. */
8666 png_read_image (png_ptr, rows);
8667 png_read_end (png_ptr, info_ptr);
5ad6a5fb
GM
8668 if (fp)
8669 {
8670 fclose (fp);
8671 fp = NULL;
8672 }
333b20bb
GM
8673
8674 BLOCK_INPUT;
8675
8676 /* Create the X image and pixmap. */
45158a91 8677 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
333b20bb
GM
8678 &img->pixmap))
8679 {
8680 UNBLOCK_INPUT;
8681 goto error;
8682 }
8683
8684 /* Create an image and pixmap serving as mask if the PNG image
8685 contains an alpha channel. */
8686 if (channels == 4
8687 && !transparent_p
45158a91 8688 && !x_create_x_image_and_pixmap (f, width, height, 1,
333b20bb
GM
8689 &mask_img, &img->mask))
8690 {
8691 x_destroy_x_image (ximg);
8692 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8693 img->pixmap = 0;
8694 UNBLOCK_INPUT;
8695 goto error;
8696 }
8697
8698 /* Fill the X image and mask from PNG data. */
8699 init_color_table ();
8700
8701 for (y = 0; y < height; ++y)
8702 {
8703 png_byte *p = rows[y];
8704
8705 for (x = 0; x < width; ++x)
8706 {
8707 unsigned r, g, b;
8708
8709 r = *p++ << 8;
8710 g = *p++ << 8;
8711 b = *p++ << 8;
8712 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
8713
8714 /* An alpha channel, aka mask channel, associates variable
8715 transparency with an image. Where other image formats
8716 support binary transparency---fully transparent or fully
8717 opaque---PNG allows up to 254 levels of partial transparency.
8718 The PNG library implements partial transparency by combining
8719 the image with a specified background color.
8720
8721 I'm not sure how to handle this here nicely: because the
8722 background on which the image is displayed may change, for
8723 real alpha channel support, it would be necessary to create
8724 a new image for each possible background.
8725
8726 What I'm doing now is that a mask is created if we have
8727 boolean transparency information. Otherwise I'm using
8728 the frame's background color to combine the image with. */
8729
8730 if (channels == 4)
8731 {
8732 if (mask_img)
8733 XPutPixel (mask_img, x, y, *p > 0);
8734 ++p;
8735 }
8736 }
8737 }
8738
8739 /* Remember colors allocated for this image. */
8740 img->colors = colors_in_color_table (&img->ncolors);
8741 free_color_table ();
8742
8743 /* Clean up. */
8744 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
8745 xfree (rows);
8746 xfree (pixels);
8747
8748 img->width = width;
8749 img->height = height;
8750
8751 /* Put the image into the pixmap, then free the X image and its buffer. */
8752 x_put_x_image (f, ximg, img->pixmap, width, height);
8753 x_destroy_x_image (ximg);
8754
8755 /* Same for the mask. */
8756 if (mask_img)
8757 {
8758 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
8759 x_destroy_x_image (mask_img);
8760 }
8761
8762 UNBLOCK_INPUT;
8763 UNGCPRO;
8764 return 1;
8765}
8766
8767#endif /* HAVE_PNG != 0 */
8768
8769
8770\f
8771/***********************************************************************
8772 JPEG
8773 ***********************************************************************/
8774
8775#if HAVE_JPEG
8776
ba06aba4
GM
8777/* Work around a warning about HAVE_STDLIB_H being redefined in
8778 jconfig.h. */
8779#ifdef HAVE_STDLIB_H
8780#define HAVE_STDLIB_H_1
8781#undef HAVE_STDLIB_H
8782#endif /* HAVE_STLIB_H */
8783
333b20bb
GM
8784#include <jpeglib.h>
8785#include <jerror.h>
8786#include <setjmp.h>
8787
ba06aba4
GM
8788#ifdef HAVE_STLIB_H_1
8789#define HAVE_STDLIB_H 1
8790#endif
8791
333b20bb
GM
8792static int jpeg_image_p P_ ((Lisp_Object object));
8793static int jpeg_load P_ ((struct frame *f, struct image *img));
8794
8795/* The symbol `jpeg' identifying images of this type. */
8796
8797Lisp_Object Qjpeg;
8798
8799/* Indices of image specification fields in gs_format, below. */
8800
8801enum jpeg_keyword_index
8802{
8803 JPEG_TYPE,
8e39770a 8804 JPEG_DATA,
333b20bb
GM
8805 JPEG_FILE,
8806 JPEG_ASCENT,
8807 JPEG_MARGIN,
8808 JPEG_RELIEF,
8809 JPEG_ALGORITHM,
8810 JPEG_HEURISTIC_MASK,
8811 JPEG_LAST
8812};
8813
8814/* Vector of image_keyword structures describing the format
8815 of valid user-defined image specifications. */
8816
8817static struct image_keyword jpeg_format[JPEG_LAST] =
8818{
8819 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 8820 {":data", IMAGE_STRING_VALUE, 0},
8e39770a 8821 {":file", IMAGE_STRING_VALUE, 0},
333b20bb
GM
8822 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8823 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8824 {":relief", IMAGE_INTEGER_VALUE, 0},
8825 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8826 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8827};
8828
8829/* Structure describing the image type `jpeg'. */
8830
8831static struct image_type jpeg_type =
8832{
8833 &Qjpeg,
8834 jpeg_image_p,
8835 jpeg_load,
8836 x_clear_image,
8837 NULL
8838};
8839
8840
8841/* Return non-zero if OBJECT is a valid JPEG image specification. */
8842
8843static int
8844jpeg_image_p (object)
8845 Lisp_Object object;
8846{
8847 struct image_keyword fmt[JPEG_LAST];
8848
8849 bcopy (jpeg_format, fmt, sizeof fmt);
8850
bfd2209f 8851 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
333b20bb 8852 || (fmt[JPEG_ASCENT].count
5ad6a5fb 8853 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
333b20bb 8854 return 0;
8e39770a 8855
63cec32f
GM
8856 /* Must specify either the :data or :file keyword. */
8857 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
333b20bb
GM
8858}
8859
8e39770a 8860
333b20bb
GM
8861struct my_jpeg_error_mgr
8862{
8863 struct jpeg_error_mgr pub;
8864 jmp_buf setjmp_buffer;
8865};
8866
8867static void
8868my_error_exit (cinfo)
8869 j_common_ptr cinfo;
8870{
8871 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
8872 longjmp (mgr->setjmp_buffer, 1);
8873}
8874
8e39770a
GM
8875/* Init source method for JPEG data source manager. Called by
8876 jpeg_read_header() before any data is actually read. See
8877 libjpeg.doc from the JPEG lib distribution. */
8878
8879static void
8880our_init_source (cinfo)
8881 j_decompress_ptr cinfo;
8882{
8883}
8884
8885
8886/* Fill input buffer method for JPEG data source manager. Called
8887 whenever more data is needed. We read the whole image in one step,
8888 so this only adds a fake end of input marker at the end. */
8889
8890static boolean
8891our_fill_input_buffer (cinfo)
8892 j_decompress_ptr cinfo;
8893{
8894 /* Insert a fake EOI marker. */
8895 struct jpeg_source_mgr *src = cinfo->src;
8896 static JOCTET buffer[2];
8897
8898 buffer[0] = (JOCTET) 0xFF;
8899 buffer[1] = (JOCTET) JPEG_EOI;
8900
8901 src->next_input_byte = buffer;
8902 src->bytes_in_buffer = 2;
8903 return TRUE;
8904}
8905
8906
8907/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
8908 is the JPEG data source manager. */
8909
8910static void
8911our_skip_input_data (cinfo, num_bytes)
8912 j_decompress_ptr cinfo;
8913 long num_bytes;
8914{
8915 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
8916
8917 if (src)
8918 {
8919 if (num_bytes > src->bytes_in_buffer)
5ad6a5fb 8920 ERREXIT (cinfo, JERR_INPUT_EOF);
8e39770a
GM
8921
8922 src->bytes_in_buffer -= num_bytes;
8923 src->next_input_byte += num_bytes;
8924 }
8925}
8926
8927
8928/* Method to terminate data source. Called by
8929 jpeg_finish_decompress() after all data has been processed. */
8930
8931static void
8932our_term_source (cinfo)
8933 j_decompress_ptr cinfo;
8934{
8935}
8936
8937
8938/* Set up the JPEG lib for reading an image from DATA which contains
8939 LEN bytes. CINFO is the decompression info structure created for
8940 reading the image. */
8941
8942static void
8943jpeg_memory_src (cinfo, data, len)
8944 j_decompress_ptr cinfo;
8945 JOCTET *data;
8946 unsigned int len;
8947{
8948 struct jpeg_source_mgr *src;
8949
8950 if (cinfo->src == NULL)
8951 {
8952 /* First time for this JPEG object? */
8953 cinfo->src = (struct jpeg_source_mgr *)
8954 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
8955 sizeof (struct jpeg_source_mgr));
8956 src = (struct jpeg_source_mgr *) cinfo->src;
8957 src->next_input_byte = data;
8958 }
8959
8960 src = (struct jpeg_source_mgr *) cinfo->src;
8961 src->init_source = our_init_source;
8962 src->fill_input_buffer = our_fill_input_buffer;
8963 src->skip_input_data = our_skip_input_data;
8964 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
8965 src->term_source = our_term_source;
8966 src->bytes_in_buffer = len;
8967 src->next_input_byte = data;
8968}
8969
5ad6a5fb 8970
333b20bb
GM
8971/* Load image IMG for use on frame F. Patterned after example.c
8972 from the JPEG lib. */
8973
8974static int
8975jpeg_load (f, img)
8976 struct frame *f;
8977 struct image *img;
8978{
8979 struct jpeg_decompress_struct cinfo;
8980 struct my_jpeg_error_mgr mgr;
8981 Lisp_Object file, specified_file;
8e39770a
GM
8982 Lisp_Object specified_data;
8983 FILE *fp = NULL;
333b20bb
GM
8984 JSAMPARRAY buffer;
8985 int row_stride, x, y;
8986 XImage *ximg = NULL;
b6d7acec 8987 int rc;
333b20bb
GM
8988 unsigned long *colors;
8989 int width, height;
8990 struct gcpro gcpro1;
8991
8992 /* Open the JPEG file. */
8993 specified_file = image_spec_value (img->spec, QCfile, NULL);
8e39770a 8994 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
8995 file = Qnil;
8996 GCPRO1 (file);
8e39770a 8997
8e39770a 8998 if (NILP (specified_data))
333b20bb 8999 {
8e39770a 9000 file = x_find_image_file (specified_file);
8e39770a
GM
9001 if (!STRINGP (file))
9002 {
45158a91 9003 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8e39770a
GM
9004 UNGCPRO;
9005 return 0;
9006 }
333b20bb 9007
8e39770a
GM
9008 fp = fopen (XSTRING (file)->data, "r");
9009 if (fp == NULL)
9010 {
9011 image_error ("Cannot open `%s'", file, Qnil);
9012 UNGCPRO;
9013 return 0;
9014 }
333b20bb
GM
9015 }
9016
5ad6a5fb
GM
9017 /* Customize libjpeg's error handling to call my_error_exit when an
9018 error is detected. This function will perform a longjmp. */
333b20bb
GM
9019 mgr.pub.error_exit = my_error_exit;
9020 cinfo.err = jpeg_std_error (&mgr.pub);
9021
9022 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
9023 {
5ad6a5fb
GM
9024 if (rc == 1)
9025 {
9026 /* Called from my_error_exit. Display a JPEG error. */
9027 char buffer[JMSG_LENGTH_MAX];
9028 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
45158a91 9029 image_error ("Error reading JPEG image `%s': %s", img->spec,
5ad6a5fb
GM
9030 build_string (buffer));
9031 }
333b20bb
GM
9032
9033 /* Close the input file and destroy the JPEG object. */
5ad6a5fb
GM
9034 if (fp)
9035 fclose (fp);
333b20bb
GM
9036 jpeg_destroy_decompress (&cinfo);
9037
5ad6a5fb 9038 BLOCK_INPUT;
333b20bb 9039
5ad6a5fb
GM
9040 /* If we already have an XImage, free that. */
9041 x_destroy_x_image (ximg);
333b20bb 9042
5ad6a5fb
GM
9043 /* Free pixmap and colors. */
9044 x_clear_image (f, img);
333b20bb 9045
5ad6a5fb
GM
9046 UNBLOCK_INPUT;
9047 UNGCPRO;
9048 return 0;
333b20bb
GM
9049 }
9050
9051 /* Create the JPEG decompression object. Let it read from fp.
63448a4d 9052 Read the JPEG image header. */
333b20bb 9053 jpeg_create_decompress (&cinfo);
8e39770a
GM
9054
9055 if (NILP (specified_data))
9056 jpeg_stdio_src (&cinfo, fp);
9057 else
9058 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
9059 STRING_BYTES (XSTRING (specified_data)));
63448a4d 9060
333b20bb
GM
9061 jpeg_read_header (&cinfo, TRUE);
9062
9063 /* Customize decompression so that color quantization will be used.
63448a4d 9064 Start decompression. */
333b20bb
GM
9065 cinfo.quantize_colors = TRUE;
9066 jpeg_start_decompress (&cinfo);
9067 width = img->width = cinfo.output_width;
9068 height = img->height = cinfo.output_height;
9069
9070 BLOCK_INPUT;
9071
9072 /* Create X image and pixmap. */
45158a91 9073 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb 9074 {
5ad6a5fb
GM
9075 UNBLOCK_INPUT;
9076 longjmp (mgr.setjmp_buffer, 2);
333b20bb
GM
9077 }
9078
9079 /* Allocate colors. When color quantization is used,
5ad6a5fb
GM
9080 cinfo.actual_number_of_colors has been set with the number of
9081 colors generated, and cinfo.colormap is a two-dimensional array
9082 of color indices in the range 0..cinfo.actual_number_of_colors.
9083 No more than 255 colors will be generated. */
333b20bb 9084 {
5ad6a5fb
GM
9085 int i, ir, ig, ib;
9086
9087 if (cinfo.out_color_components > 2)
9088 ir = 0, ig = 1, ib = 2;
9089 else if (cinfo.out_color_components > 1)
9090 ir = 0, ig = 1, ib = 0;
9091 else
9092 ir = 0, ig = 0, ib = 0;
9093
9094 /* Use the color table mechanism because it handles colors that
9095 cannot be allocated nicely. Such colors will be replaced with
9096 a default color, and we don't have to care about which colors
9097 can be freed safely, and which can't. */
9098 init_color_table ();
9099 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
9100 * sizeof *colors);
333b20bb 9101
5ad6a5fb
GM
9102 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
9103 {
9104 /* Multiply RGB values with 255 because X expects RGB values
9105 in the range 0..0xffff. */
9106 int r = cinfo.colormap[ir][i] << 8;
9107 int g = cinfo.colormap[ig][i] << 8;
9108 int b = cinfo.colormap[ib][i] << 8;
9109 colors[i] = lookup_rgb_color (f, r, g, b);
9110 }
333b20bb 9111
5ad6a5fb
GM
9112 /* Remember those colors actually allocated. */
9113 img->colors = colors_in_color_table (&img->ncolors);
9114 free_color_table ();
333b20bb
GM
9115 }
9116
9117 /* Read pixels. */
9118 row_stride = width * cinfo.output_components;
9119 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
5ad6a5fb 9120 row_stride, 1);
333b20bb
GM
9121 for (y = 0; y < height; ++y)
9122 {
5ad6a5fb
GM
9123 jpeg_read_scanlines (&cinfo, buffer, 1);
9124 for (x = 0; x < cinfo.output_width; ++x)
9125 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
333b20bb
GM
9126 }
9127
9128 /* Clean up. */
9129 jpeg_finish_decompress (&cinfo);
9130 jpeg_destroy_decompress (&cinfo);
5ad6a5fb
GM
9131 if (fp)
9132 fclose (fp);
333b20bb
GM
9133
9134 /* Put the image into the pixmap. */
9135 x_put_x_image (f, ximg, img->pixmap, width, height);
9136 x_destroy_x_image (ximg);
9137 UNBLOCK_INPUT;
9138 UNGCPRO;
9139 return 1;
9140}
9141
9142#endif /* HAVE_JPEG */
9143
9144
9145\f
9146/***********************************************************************
9147 TIFF
9148 ***********************************************************************/
9149
9150#if HAVE_TIFF
9151
cf4790ad 9152#include <tiffio.h>
333b20bb
GM
9153
9154static int tiff_image_p P_ ((Lisp_Object object));
9155static int tiff_load P_ ((struct frame *f, struct image *img));
9156
9157/* The symbol `tiff' identifying images of this type. */
9158
9159Lisp_Object Qtiff;
9160
9161/* Indices of image specification fields in tiff_format, below. */
9162
9163enum tiff_keyword_index
9164{
9165 TIFF_TYPE,
63448a4d 9166 TIFF_DATA,
333b20bb
GM
9167 TIFF_FILE,
9168 TIFF_ASCENT,
9169 TIFF_MARGIN,
9170 TIFF_RELIEF,
9171 TIFF_ALGORITHM,
9172 TIFF_HEURISTIC_MASK,
9173 TIFF_LAST
9174};
9175
9176/* Vector of image_keyword structures describing the format
9177 of valid user-defined image specifications. */
9178
9179static struct image_keyword tiff_format[TIFF_LAST] =
9180{
9181 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9182 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9183 {":file", IMAGE_STRING_VALUE, 0},
333b20bb
GM
9184 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9185 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9186 {":relief", IMAGE_INTEGER_VALUE, 0},
9187 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9188 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9189};
9190
9191/* Structure describing the image type `tiff'. */
9192
9193static struct image_type tiff_type =
9194{
9195 &Qtiff,
9196 tiff_image_p,
9197 tiff_load,
9198 x_clear_image,
9199 NULL
9200};
9201
9202
9203/* Return non-zero if OBJECT is a valid TIFF image specification. */
9204
9205static int
9206tiff_image_p (object)
9207 Lisp_Object object;
9208{
9209 struct image_keyword fmt[TIFF_LAST];
9210 bcopy (tiff_format, fmt, sizeof fmt);
9211
bfd2209f 9212 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
333b20bb
GM
9213 || (fmt[TIFF_ASCENT].count
9214 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
9215 return 0;
5ad6a5fb 9216
63cec32f
GM
9217 /* Must specify either the :data or :file keyword. */
9218 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
333b20bb
GM
9219}
9220
5ad6a5fb
GM
9221
9222/* Reading from a memory buffer for TIFF images Based on the PNG
9223 memory source, but we have to provide a lot of extra functions.
9224 Blah.
63448a4d
WP
9225
9226 We really only need to implement read and seek, but I am not
9227 convinced that the TIFF library is smart enough not to destroy
9228 itself if we only hand it the function pointers we need to
5ad6a5fb
GM
9229 override. */
9230
9231typedef struct
9232{
63448a4d
WP
9233 unsigned char *bytes;
9234 size_t len;
9235 int index;
5ad6a5fb
GM
9236}
9237tiff_memory_source;
63448a4d 9238
5ad6a5fb
GM
9239static size_t
9240tiff_read_from_memory (data, buf, size)
9241 thandle_t data;
9242 tdata_t buf;
9243 tsize_t size;
63448a4d 9244{
5ad6a5fb 9245 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9246
9247 if (size > src->len - src->index)
5ad6a5fb
GM
9248 return (size_t) -1;
9249 bcopy (src->bytes + src->index, buf, size);
63448a4d
WP
9250 src->index += size;
9251 return size;
9252}
9253
5ad6a5fb
GM
9254static size_t
9255tiff_write_from_memory (data, buf, size)
9256 thandle_t data;
9257 tdata_t buf;
9258 tsize_t size;
63448a4d
WP
9259{
9260 return (size_t) -1;
9261}
9262
5ad6a5fb
GM
9263static toff_t
9264tiff_seek_in_memory (data, off, whence)
9265 thandle_t data;
9266 toff_t off;
9267 int whence;
63448a4d 9268{
5ad6a5fb 9269 tiff_memory_source *src = (tiff_memory_source *) data;
63448a4d
WP
9270 int idx;
9271
9272 switch (whence)
5ad6a5fb
GM
9273 {
9274 case SEEK_SET: /* Go from beginning of source. */
9275 idx = off;
9276 break;
9277
9278 case SEEK_END: /* Go from end of source. */
9279 idx = src->len + off;
9280 break;
9281
9282 case SEEK_CUR: /* Go from current position. */
9283 idx = src->index + off;
9284 break;
9285
9286 default: /* Invalid `whence'. */
9287 return -1;
9288 }
9289
9290 if (idx > src->len || idx < 0)
9291 return -1;
9292
63448a4d
WP
9293 src->index = idx;
9294 return src->index;
9295}
9296
5ad6a5fb
GM
9297static int
9298tiff_close_memory (data)
9299 thandle_t data;
63448a4d
WP
9300{
9301 /* NOOP */
5ad6a5fb 9302 return 0;
63448a4d
WP
9303}
9304
5ad6a5fb
GM
9305static int
9306tiff_mmap_memory (data, pbase, psize)
9307 thandle_t data;
9308 tdata_t *pbase;
9309 toff_t *psize;
63448a4d
WP
9310{
9311 /* It is already _IN_ memory. */
5ad6a5fb 9312 return 0;
63448a4d
WP
9313}
9314
5ad6a5fb
GM
9315static void
9316tiff_unmap_memory (data, base, size)
9317 thandle_t data;
9318 tdata_t base;
9319 toff_t size;
63448a4d
WP
9320{
9321 /* We don't need to do this. */
63448a4d
WP
9322}
9323
5ad6a5fb
GM
9324static toff_t
9325tiff_size_of_memory (data)
9326 thandle_t data;
63448a4d 9327{
5ad6a5fb 9328 return ((tiff_memory_source *) data)->len;
63448a4d 9329}
333b20bb
GM
9330
9331/* Load TIFF image IMG for use on frame F. Value is non-zero if
9332 successful. */
9333
9334static int
9335tiff_load (f, img)
9336 struct frame *f;
9337 struct image *img;
9338{
9339 Lisp_Object file, specified_file;
63448a4d 9340 Lisp_Object specified_data;
333b20bb
GM
9341 TIFF *tiff;
9342 int width, height, x, y;
9343 uint32 *buf;
9344 int rc;
9345 XImage *ximg;
9346 struct gcpro gcpro1;
63448a4d 9347 tiff_memory_source memsrc;
333b20bb
GM
9348
9349 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9350 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9351 file = Qnil;
9352 GCPRO1 (file);
63448a4d
WP
9353
9354 if (NILP (specified_data))
5ad6a5fb
GM
9355 {
9356 /* Read from a file */
9357 file = x_find_image_file (specified_file);
9358 if (!STRINGP (file))
63448a4d 9359 {
45158a91 9360 image_error ("Cannot find image file `%s'", file, Qnil);
5ad6a5fb
GM
9361 UNGCPRO;
9362 return 0;
9363 }
63448a4d 9364
5ad6a5fb
GM
9365 /* Try to open the image file. */
9366 tiff = TIFFOpen (XSTRING (file)->data, "r");
9367 if (tiff == NULL)
9368 {
9369 image_error ("Cannot open `%s'", file, Qnil);
9370 UNGCPRO;
9371 return 0;
63448a4d 9372 }
5ad6a5fb 9373 }
63448a4d 9374 else
5ad6a5fb
GM
9375 {
9376 /* Memory source! */
9377 memsrc.bytes = XSTRING (specified_data)->data;
9378 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9379 memsrc.index = 0;
9380
9381 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
9382 (TIFFReadWriteProc) tiff_read_from_memory,
9383 (TIFFReadWriteProc) tiff_write_from_memory,
9384 tiff_seek_in_memory,
9385 tiff_close_memory,
9386 tiff_size_of_memory,
9387 tiff_mmap_memory,
9388 tiff_unmap_memory);
9389
9390 if (!tiff)
63448a4d 9391 {
45158a91 9392 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
5ad6a5fb
GM
9393 UNGCPRO;
9394 return 0;
63448a4d 9395 }
5ad6a5fb 9396 }
333b20bb
GM
9397
9398 /* Get width and height of the image, and allocate a raster buffer
9399 of width x height 32-bit values. */
9400 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
9401 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
9402 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
9403
9404 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
9405 TIFFClose (tiff);
9406 if (!rc)
9407 {
45158a91 9408 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
333b20bb
GM
9409 xfree (buf);
9410 UNGCPRO;
9411 return 0;
9412 }
9413
9414 BLOCK_INPUT;
9415
9416 /* Create the X image and pixmap. */
45158a91 9417 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb
GM
9418 {
9419 UNBLOCK_INPUT;
9420 xfree (buf);
9421 UNGCPRO;
9422 return 0;
9423 }
9424
9425 /* Initialize the color table. */
9426 init_color_table ();
9427
9428 /* Process the pixel raster. Origin is in the lower-left corner. */
9429 for (y = 0; y < height; ++y)
9430 {
9431 uint32 *row = buf + y * width;
9432
9433 for (x = 0; x < width; ++x)
9434 {
9435 uint32 abgr = row[x];
9436 int r = TIFFGetR (abgr) << 8;
9437 int g = TIFFGetG (abgr) << 8;
9438 int b = TIFFGetB (abgr) << 8;
9439 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
9440 }
9441 }
9442
9443 /* Remember the colors allocated for the image. Free the color table. */
9444 img->colors = colors_in_color_table (&img->ncolors);
9445 free_color_table ();
9446
9447 /* Put the image into the pixmap, then free the X image and its buffer. */
9448 x_put_x_image (f, ximg, img->pixmap, width, height);
9449 x_destroy_x_image (ximg);
9450 xfree (buf);
9451 UNBLOCK_INPUT;
9452
9453 img->width = width;
9454 img->height = height;
9455
9456 UNGCPRO;
9457 return 1;
9458}
9459
9460#endif /* HAVE_TIFF != 0 */
9461
9462
9463\f
9464/***********************************************************************
9465 GIF
9466 ***********************************************************************/
9467
9468#if HAVE_GIF
9469
9470#include <gif_lib.h>
9471
9472static int gif_image_p P_ ((Lisp_Object object));
9473static int gif_load P_ ((struct frame *f, struct image *img));
9474
9475/* The symbol `gif' identifying images of this type. */
9476
9477Lisp_Object Qgif;
9478
9479/* Indices of image specification fields in gif_format, below. */
9480
9481enum gif_keyword_index
9482{
9483 GIF_TYPE,
63448a4d 9484 GIF_DATA,
333b20bb
GM
9485 GIF_FILE,
9486 GIF_ASCENT,
9487 GIF_MARGIN,
9488 GIF_RELIEF,
9489 GIF_ALGORITHM,
9490 GIF_HEURISTIC_MASK,
9491 GIF_IMAGE,
9492 GIF_LAST
9493};
9494
9495/* Vector of image_keyword structures describing the format
9496 of valid user-defined image specifications. */
9497
9498static struct image_keyword gif_format[GIF_LAST] =
9499{
9500 {":type", IMAGE_SYMBOL_VALUE, 1},
5ad6a5fb 9501 {":data", IMAGE_STRING_VALUE, 0},
63448a4d 9502 {":file", IMAGE_STRING_VALUE, 0},
333b20bb
GM
9503 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9504 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9505 {":relief", IMAGE_INTEGER_VALUE, 0},
9506 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9507 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9508 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
9509};
9510
9511/* Structure describing the image type `gif'. */
9512
9513static struct image_type gif_type =
9514{
9515 &Qgif,
9516 gif_image_p,
9517 gif_load,
9518 x_clear_image,
9519 NULL
9520};
9521
333b20bb
GM
9522/* Return non-zero if OBJECT is a valid GIF image specification. */
9523
9524static int
9525gif_image_p (object)
9526 Lisp_Object object;
9527{
9528 struct image_keyword fmt[GIF_LAST];
9529 bcopy (gif_format, fmt, sizeof fmt);
9530
bfd2209f 9531 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
333b20bb
GM
9532 || (fmt[GIF_ASCENT].count
9533 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
9534 return 0;
5ad6a5fb 9535
63cec32f
GM
9536 /* Must specify either the :data or :file keyword. */
9537 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
333b20bb
GM
9538}
9539
63448a4d
WP
9540/* Reading a GIF image from memory
9541 Based on the PNG memory stuff to a certain extent. */
9542
5ad6a5fb
GM
9543typedef struct
9544{
63448a4d
WP
9545 unsigned char *bytes;
9546 size_t len;
9547 int index;
5ad6a5fb
GM
9548}
9549gif_memory_source;
63448a4d 9550
f036834a
GM
9551/* Make the current memory source available to gif_read_from_memory.
9552 It's done this way because not all versions of libungif support
9553 a UserData field in the GifFileType structure. */
9554static gif_memory_source *current_gif_memory_src;
9555
5ad6a5fb
GM
9556static int
9557gif_read_from_memory (file, buf, len)
9558 GifFileType *file;
9559 GifByteType *buf;
9560 int len;
63448a4d 9561{
f036834a 9562 gif_memory_source *src = current_gif_memory_src;
63448a4d 9563
5ad6a5fb
GM
9564 if (len > src->len - src->index)
9565 return -1;
63448a4d 9566
5ad6a5fb 9567 bcopy (src->bytes + src->index, buf, len);
63448a4d
WP
9568 src->index += len;
9569 return len;
9570}
333b20bb 9571
5ad6a5fb 9572
333b20bb
GM
9573/* Load GIF image IMG for use on frame F. Value is non-zero if
9574 successful. */
9575
9576static int
9577gif_load (f, img)
9578 struct frame *f;
9579 struct image *img;
9580{
9581 Lisp_Object file, specified_file;
63448a4d 9582 Lisp_Object specified_data;
333b20bb
GM
9583 int rc, width, height, x, y, i;
9584 XImage *ximg;
9585 ColorMapObject *gif_color_map;
9586 unsigned long pixel_colors[256];
9587 GifFileType *gif;
9588 struct gcpro gcpro1;
9589 Lisp_Object image;
9590 int ino, image_left, image_top, image_width, image_height;
63448a4d 9591 gif_memory_source memsrc;
9b784e96 9592 unsigned char *raster;
333b20bb
GM
9593
9594 specified_file = image_spec_value (img->spec, QCfile, NULL);
63448a4d 9595 specified_data = image_spec_value (img->spec, QCdata, NULL);
5ad6a5fb
GM
9596 file = Qnil;
9597 GCPRO1 (file);
63448a4d
WP
9598
9599 if (NILP (specified_data))
5ad6a5fb
GM
9600 {
9601 file = x_find_image_file (specified_file);
9602 if (!STRINGP (file))
63448a4d 9603 {
45158a91 9604 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5ad6a5fb
GM
9605 UNGCPRO;
9606 return 0;
9607 }
333b20bb 9608
5ad6a5fb
GM
9609 /* Open the GIF file. */
9610 gif = DGifOpenFileName (XSTRING (file)->data);
9611 if (gif == NULL)
9612 {
9613 image_error ("Cannot open `%s'", file, Qnil);
9614 UNGCPRO;
9615 return 0;
63448a4d 9616 }
5ad6a5fb 9617 }
63448a4d 9618 else
5ad6a5fb
GM
9619 {
9620 /* Read from memory! */
f036834a 9621 current_gif_memory_src = &memsrc;
5ad6a5fb
GM
9622 memsrc.bytes = XSTRING (specified_data)->data;
9623 memsrc.len = STRING_BYTES (XSTRING (specified_data));
9624 memsrc.index = 0;
63448a4d 9625
5ad6a5fb
GM
9626 gif = DGifOpen(&memsrc, gif_read_from_memory);
9627 if (!gif)
9628 {
45158a91 9629 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
5ad6a5fb
GM
9630 UNGCPRO;
9631 return 0;
63448a4d 9632 }
5ad6a5fb 9633 }
333b20bb
GM
9634
9635 /* Read entire contents. */
9636 rc = DGifSlurp (gif);
9637 if (rc == GIF_ERROR)
9638 {
45158a91 9639 image_error ("Error reading `%s'", img->spec, Qnil);
333b20bb
GM
9640 DGifCloseFile (gif);
9641 UNGCPRO;
9642 return 0;
9643 }
9644
3ccff1e3 9645 image = image_spec_value (img->spec, QCindex, NULL);
333b20bb
GM
9646 ino = INTEGERP (image) ? XFASTINT (image) : 0;
9647 if (ino >= gif->ImageCount)
9648 {
45158a91
GM
9649 image_error ("Invalid image number `%s' in image `%s'",
9650 image, img->spec);
333b20bb
GM
9651 DGifCloseFile (gif);
9652 UNGCPRO;
9653 return 0;
9654 }
9655
9656 width = img->width = gif->SWidth;
9657 height = img->height = gif->SHeight;
9658
9659 BLOCK_INPUT;
9660
9661 /* Create the X image and pixmap. */
45158a91 9662 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
333b20bb
GM
9663 {
9664 UNBLOCK_INPUT;
9665 DGifCloseFile (gif);
9666 UNGCPRO;
9667 return 0;
9668 }
9669
9670 /* Allocate colors. */
9671 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
9672 if (!gif_color_map)
9673 gif_color_map = gif->SColorMap;
9674 init_color_table ();
9675 bzero (pixel_colors, sizeof pixel_colors);
9676
9677 for (i = 0; i < gif_color_map->ColorCount; ++i)
9678 {
9679 int r = gif_color_map->Colors[i].Red << 8;
9680 int g = gif_color_map->Colors[i].Green << 8;
9681 int b = gif_color_map->Colors[i].Blue << 8;
9682 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
9683 }
9684
9685 img->colors = colors_in_color_table (&img->ncolors);
9686 free_color_table ();
9687
9688 /* Clear the part of the screen image that are not covered by
9689 the image from the GIF file. Full animated GIF support
9690 requires more than can be done here (see the gif89 spec,
9691 disposal methods). Let's simply assume that the part
9692 not covered by a sub-image is in the frame's background color. */
9693 image_top = gif->SavedImages[ino].ImageDesc.Top;
9694 image_left = gif->SavedImages[ino].ImageDesc.Left;
9695 image_width = gif->SavedImages[ino].ImageDesc.Width;
9696 image_height = gif->SavedImages[ino].ImageDesc.Height;
9697
9698 for (y = 0; y < image_top; ++y)
9699 for (x = 0; x < width; ++x)
9700 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9701
9702 for (y = image_top + image_height; y < height; ++y)
9703 for (x = 0; x < width; ++x)
9704 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9705
9706 for (y = image_top; y < image_top + image_height; ++y)
9707 {
9708 for (x = 0; x < image_left; ++x)
9709 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9710 for (x = image_left + image_width; x < width; ++x)
9711 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
9712 }
9713
9b784e96
GM
9714 /* Read the GIF image into the X image. We use a local variable
9715 `raster' here because RasterBits below is a char *, and invites
9716 problems with bytes >= 0x80. */
9717 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
9718
333b20bb
GM
9719 if (gif->SavedImages[ino].ImageDesc.Interlace)
9720 {
9721 static int interlace_start[] = {0, 4, 2, 1};
9722 static int interlace_increment[] = {8, 8, 4, 2};
9723 int pass, inc;
06482119
GM
9724 int row = interlace_start[0];
9725
9726 pass = 0;
333b20bb 9727
06482119 9728 for (y = 0; y < image_height; y++)
333b20bb 9729 {
06482119
GM
9730 if (row >= image_height)
9731 {
9732 row = interlace_start[++pass];
9733 while (row >= image_height)
9734 row = interlace_start[++pass];
9735 }
9736
9737 for (x = 0; x < image_width; x++)
9738 {
9b784e96 9739 int i = raster[(y * image_width) + x];
06482119
GM
9740 XPutPixel (ximg, x + image_left, row + image_top,
9741 pixel_colors[i]);
9742 }
9743
9744 row += interlace_increment[pass];
333b20bb
GM
9745 }
9746 }
9747 else
9748 {
9749 for (y = 0; y < image_height; ++y)
9750 for (x = 0; x < image_width; ++x)
9751 {
9b784e96 9752 int i = raster[y * image_width + x];
333b20bb
GM
9753 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
9754 }
9755 }
9756
9757 DGifCloseFile (gif);
9758
9759 /* Put the image into the pixmap, then free the X image and its buffer. */
9760 x_put_x_image (f, ximg, img->pixmap, width, height);
9761 x_destroy_x_image (ximg);
9762 UNBLOCK_INPUT;
9763
9764 UNGCPRO;
9765 return 1;
9766}
9767
9768#endif /* HAVE_GIF != 0 */
9769
9770
9771\f
9772/***********************************************************************
9773 Ghostscript
9774 ***********************************************************************/
9775
9776static int gs_image_p P_ ((Lisp_Object object));
9777static int gs_load P_ ((struct frame *f, struct image *img));
9778static void gs_clear_image P_ ((struct frame *f, struct image *img));
9779
fcf431dc 9780/* The symbol `postscript' identifying images of this type. */
333b20bb 9781
fcf431dc 9782Lisp_Object Qpostscript;
333b20bb
GM
9783
9784/* Keyword symbols. */
9785
9786Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
9787
9788/* Indices of image specification fields in gs_format, below. */
9789
9790enum gs_keyword_index
9791{
9792 GS_TYPE,
9793 GS_PT_WIDTH,
9794 GS_PT_HEIGHT,
9795 GS_FILE,
9796 GS_LOADER,
9797 GS_BOUNDING_BOX,
9798 GS_ASCENT,
9799 GS_MARGIN,
9800 GS_RELIEF,
9801 GS_ALGORITHM,
9802 GS_HEURISTIC_MASK,
9803 GS_LAST
9804};
9805
9806/* Vector of image_keyword structures describing the format
9807 of valid user-defined image specifications. */
9808
9809static struct image_keyword gs_format[GS_LAST] =
9810{
9811 {":type", IMAGE_SYMBOL_VALUE, 1},
9812 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9813 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
9814 {":file", IMAGE_STRING_VALUE, 1},
9815 {":loader", IMAGE_FUNCTION_VALUE, 0},
9816 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
9817 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9818 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9819 {":relief", IMAGE_INTEGER_VALUE, 0},
9820 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9821 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9822};
9823
9824/* Structure describing the image type `ghostscript'. */
9825
9826static struct image_type gs_type =
9827{
fcf431dc 9828 &Qpostscript,
333b20bb
GM
9829 gs_image_p,
9830 gs_load,
9831 gs_clear_image,
9832 NULL
9833};
9834
9835
9836/* Free X resources of Ghostscript image IMG which is used on frame F. */
9837
9838static void
9839gs_clear_image (f, img)
9840 struct frame *f;
9841 struct image *img;
9842{
9843 /* IMG->data.ptr_val may contain a recorded colormap. */
9844 xfree (img->data.ptr_val);
9845 x_clear_image (f, img);
9846}
9847
9848
9849/* Return non-zero if OBJECT is a valid Ghostscript image
9850 specification. */
9851
9852static int
9853gs_image_p (object)
9854 Lisp_Object object;
9855{
9856 struct image_keyword fmt[GS_LAST];
9857 Lisp_Object tem;
9858 int i;
9859
9860 bcopy (gs_format, fmt, sizeof fmt);
9861
bfd2209f 9862 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
333b20bb
GM
9863 || (fmt[GS_ASCENT].count
9864 && XFASTINT (fmt[GS_ASCENT].value) > 100))
9865 return 0;
9866
9867 /* Bounding box must be a list or vector containing 4 integers. */
9868 tem = fmt[GS_BOUNDING_BOX].value;
9869 if (CONSP (tem))
9870 {
9871 for (i = 0; i < 4; ++i, tem = XCDR (tem))
9872 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
9873 return 0;
9874 if (!NILP (tem))
9875 return 0;
9876 }
9877 else if (VECTORP (tem))
9878 {
9879 if (XVECTOR (tem)->size != 4)
9880 return 0;
9881 for (i = 0; i < 4; ++i)
9882 if (!INTEGERP (XVECTOR (tem)->contents[i]))
9883 return 0;
9884 }
9885 else
9886 return 0;
9887
9888 return 1;
9889}
9890
9891
9892/* Load Ghostscript image IMG for use on frame F. Value is non-zero
9893 if successful. */
9894
9895static int
9896gs_load (f, img)
9897 struct frame *f;
9898 struct image *img;
9899{
9900 char buffer[100];
9901 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
9902 struct gcpro gcpro1, gcpro2;
9903 Lisp_Object frame;
9904 double in_width, in_height;
9905 Lisp_Object pixel_colors = Qnil;
9906
9907 /* Compute pixel size of pixmap needed from the given size in the
9908 image specification. Sizes in the specification are in pt. 1 pt
9909 = 1/72 in, xdpi and ydpi are stored in the frame's X display
9910 info. */
9911 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
9912 in_width = XFASTINT (pt_width) / 72.0;
9913 img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
9914 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
9915 in_height = XFASTINT (pt_height) / 72.0;
9916 img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
9917
9918 /* Create the pixmap. */
9919 BLOCK_INPUT;
9920 xassert (img->pixmap == 0);
9921 img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9922 img->width, img->height,
9923 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
9924 UNBLOCK_INPUT;
9925
9926 if (!img->pixmap)
9927 {
45158a91 9928 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
333b20bb
GM
9929 return 0;
9930 }
9931
9932 /* Call the loader to fill the pixmap. It returns a process object
9933 if successful. We do not record_unwind_protect here because
9934 other places in redisplay like calling window scroll functions
9935 don't either. Let the Lisp loader use `unwind-protect' instead. */
9936 GCPRO2 (window_and_pixmap_id, pixel_colors);
9937
9938 sprintf (buffer, "%lu %lu",
9939 (unsigned long) FRAME_X_WINDOW (f),
9940 (unsigned long) img->pixmap);
9941 window_and_pixmap_id = build_string (buffer);
9942
9943 sprintf (buffer, "%lu %lu",
9944 FRAME_FOREGROUND_PIXEL (f),
9945 FRAME_BACKGROUND_PIXEL (f));
9946 pixel_colors = build_string (buffer);
9947
9948 XSETFRAME (frame, f);
9949 loader = image_spec_value (img->spec, QCloader, NULL);
9950 if (NILP (loader))
9951 loader = intern ("gs-load-image");
9952
9953 img->data.lisp_val = call6 (loader, frame, img->spec,
9954 make_number (img->width),
9955 make_number (img->height),
9956 window_and_pixmap_id,
9957 pixel_colors);
9958 UNGCPRO;
9959 return PROCESSP (img->data.lisp_val);
9960}
9961
9962
9963/* Kill the Ghostscript process that was started to fill PIXMAP on
9964 frame F. Called from XTread_socket when receiving an event
9965 telling Emacs that Ghostscript has finished drawing. */
9966
9967void
9968x_kill_gs_process (pixmap, f)
9969 Pixmap pixmap;
9970 struct frame *f;
9971{
9972 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9973 int class, i;
9974 struct image *img;
9975
9976 /* Find the image containing PIXMAP. */
9977 for (i = 0; i < c->used; ++i)
9978 if (c->images[i]->pixmap == pixmap)
9979 break;
9980
9981 /* Kill the GS process. We should have found PIXMAP in the image
9982 cache and its image should contain a process object. */
9983 xassert (i < c->used);
9984 img = c->images[i];
9985 xassert (PROCESSP (img->data.lisp_val));
9986 Fkill_process (img->data.lisp_val, Qnil);
9987 img->data.lisp_val = Qnil;
9988
9989 /* On displays with a mutable colormap, figure out the colors
9990 allocated for the image by looking at the pixels of an XImage for
9991 img->pixmap. */
9992 class = FRAME_X_DISPLAY_INFO (f)->visual->class;
9993 if (class != StaticColor && class != StaticGray && class != TrueColor)
9994 {
9995 XImage *ximg;
9996
9997 BLOCK_INPUT;
9998
9999 /* Try to get an XImage for img->pixmep. */
10000 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10001 0, 0, img->width, img->height, ~0, ZPixmap);
10002 if (ximg)
10003 {
10004 int x, y;
10005
10006 /* Initialize the color table. */
10007 init_color_table ();
10008
10009 /* For each pixel of the image, look its color up in the
10010 color table. After having done so, the color table will
10011 contain an entry for each color used by the image. */
10012 for (y = 0; y < img->height; ++y)
10013 for (x = 0; x < img->width; ++x)
10014 {
10015 unsigned long pixel = XGetPixel (ximg, x, y);
10016 lookup_pixel_color (f, pixel);
10017 }
10018
10019 /* Record colors in the image. Free color table and XImage. */
10020 img->colors = colors_in_color_table (&img->ncolors);
10021 free_color_table ();
10022 XDestroyImage (ximg);
10023
10024#if 0 /* This doesn't seem to be the case. If we free the colors
10025 here, we get a BadAccess later in x_clear_image when
10026 freeing the colors. */
10027 /* We have allocated colors once, but Ghostscript has also
10028 allocated colors on behalf of us. So, to get the
10029 reference counts right, free them once. */
10030 if (img->ncolors)
462d5d40 10031 x_free_colors (f, img->colors, img->ncolors);
333b20bb
GM
10032#endif
10033 }
10034 else
10035 image_error ("Cannot get X image of `%s'; colors will not be freed",
45158a91 10036 img->spec, Qnil);
333b20bb
GM
10037
10038 UNBLOCK_INPUT;
10039 }
10040}
10041
10042
10043\f
10044/***********************************************************************
10045 Window properties
10046 ***********************************************************************/
10047
10048DEFUN ("x-change-window-property", Fx_change_window_property,
10049 Sx_change_window_property, 2, 3, 0,
10050 "Change window property PROP to VALUE on the X window of FRAME.\n\
10051PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
10052selected frame. Value is VALUE.")
10053 (prop, value, frame)
10054 Lisp_Object frame, prop, value;
10055{
10056 struct frame *f = check_x_frame (frame);
10057 Atom prop_atom;
10058
10059 CHECK_STRING (prop, 1);
10060 CHECK_STRING (value, 2);
10061
10062 BLOCK_INPUT;
10063 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10064 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10065 prop_atom, XA_STRING, 8, PropModeReplace,
10066 XSTRING (value)->data, XSTRING (value)->size);
10067
10068 /* Make sure the property is set when we return. */
10069 XFlush (FRAME_X_DISPLAY (f));
10070 UNBLOCK_INPUT;
10071
10072 return value;
10073}
10074
10075
10076DEFUN ("x-delete-window-property", Fx_delete_window_property,
10077 Sx_delete_window_property, 1, 2, 0,
10078 "Remove window property PROP from X window of FRAME.\n\
10079FRAME nil or omitted means use the selected frame. Value is PROP.")
10080 (prop, frame)
10081 Lisp_Object prop, frame;
10082{
10083 struct frame *f = check_x_frame (frame);
10084 Atom prop_atom;
10085
10086 CHECK_STRING (prop, 1);
10087 BLOCK_INPUT;
10088 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10089 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
10090
10091 /* Make sure the property is removed when we return. */
10092 XFlush (FRAME_X_DISPLAY (f));
10093 UNBLOCK_INPUT;
10094
10095 return prop;
10096}
10097
10098
10099DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
10100 1, 2, 0,
10101 "Value is the value of window property PROP on FRAME.\n\
10102If FRAME is nil or omitted, use the selected frame. Value is nil\n\
10103if FRAME hasn't a property with name PROP or if PROP has no string\n\
10104value.")
10105 (prop, frame)
10106 Lisp_Object prop, frame;
10107{
10108 struct frame *f = check_x_frame (frame);
10109 Atom prop_atom;
10110 int rc;
10111 Lisp_Object prop_value = Qnil;
10112 char *tmp_data = NULL;
10113 Atom actual_type;
10114 int actual_format;
10115 unsigned long actual_size, bytes_remaining;
10116
10117 CHECK_STRING (prop, 1);
10118 BLOCK_INPUT;
10119 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
10120 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10121 prop_atom, 0, 0, False, XA_STRING,
10122 &actual_type, &actual_format, &actual_size,
10123 &bytes_remaining, (unsigned char **) &tmp_data);
10124 if (rc == Success)
10125 {
10126 int size = bytes_remaining;
10127
10128 XFree (tmp_data);
10129 tmp_data = NULL;
10130
10131 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10132 prop_atom, 0, bytes_remaining,
10133 False, XA_STRING,
10134 &actual_type, &actual_format,
10135 &actual_size, &bytes_remaining,
10136 (unsigned char **) &tmp_data);
10137 if (rc == Success)
10138 prop_value = make_string (tmp_data, size);
10139
10140 XFree (tmp_data);
10141 }
10142
10143 UNBLOCK_INPUT;
10144 return prop_value;
10145}
10146
10147
10148\f
10149/***********************************************************************
10150 Busy cursor
10151 ***********************************************************************/
10152
4ae9a85e
GM
10153/* If non-null, an asynchronous timer that, when it expires, displays
10154 a busy cursor on all frames. */
333b20bb 10155
4ae9a85e 10156static struct atimer *busy_cursor_atimer;
333b20bb 10157
4ae9a85e 10158/* Non-zero means a busy cursor is currently shown. */
333b20bb 10159
4ae9a85e 10160static int busy_cursor_shown_p;
333b20bb 10161
4ae9a85e 10162/* Number of seconds to wait before displaying a busy cursor. */
333b20bb 10163
4ae9a85e 10164static Lisp_Object Vbusy_cursor_delay;
333b20bb 10165
4ae9a85e
GM
10166/* Default number of seconds to wait before displaying a busy
10167 cursor. */
10168
10169#define DEFAULT_BUSY_CURSOR_DELAY 1
10170
10171/* Function prototypes. */
10172
10173static void show_busy_cursor P_ ((struct atimer *));
10174static void hide_busy_cursor P_ ((void));
10175
10176
10177/* Cancel a currently active busy-cursor timer, and start a new one. */
10178
10179void
10180start_busy_cursor ()
333b20bb 10181{
4ae9a85e 10182 EMACS_TIME delay;
3caa99d3 10183 int secs, usecs = 0;
4ae9a85e
GM
10184
10185 cancel_busy_cursor ();
10186
10187 if (INTEGERP (Vbusy_cursor_delay)
10188 && XINT (Vbusy_cursor_delay) > 0)
10189 secs = XFASTINT (Vbusy_cursor_delay);
3caa99d3
GM
10190 else if (FLOATP (Vbusy_cursor_delay)
10191 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
10192 {
10193 Lisp_Object tem;
10194 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
10195 secs = XFASTINT (tem);
10196 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
10197 }
4ae9a85e
GM
10198 else
10199 secs = DEFAULT_BUSY_CURSOR_DELAY;
10200
3caa99d3 10201 EMACS_SET_SECS_USECS (delay, secs, usecs);
4ae9a85e
GM
10202 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
10203 show_busy_cursor, NULL);
10204}
10205
10206
10207/* Cancel the busy cursor timer if active, hide a busy cursor if
10208 shown. */
10209
10210void
10211cancel_busy_cursor ()
10212{
10213 if (busy_cursor_atimer)
99f01f62
GM
10214 {
10215 cancel_atimer (busy_cursor_atimer);
10216 busy_cursor_atimer = NULL;
10217 }
10218
4ae9a85e
GM
10219 if (busy_cursor_shown_p)
10220 hide_busy_cursor ();
10221}
10222
10223
10224/* Timer function of busy_cursor_atimer. TIMER is equal to
10225 busy_cursor_atimer.
10226
10227 Display a busy cursor on all frames by mapping the frames'
10228 busy_window. Set the busy_p flag in the frames' output_data.x
10229 structure to indicate that a busy cursor is shown on the
10230 frames. */
10231
10232static void
10233show_busy_cursor (timer)
10234 struct atimer *timer;
10235{
10236 /* The timer implementation will cancel this timer automatically
10237 after this function has run. Set busy_cursor_atimer to null
10238 so that we know the timer doesn't have to be canceled. */
10239 busy_cursor_atimer = NULL;
10240
10241 if (!busy_cursor_shown_p)
333b20bb
GM
10242 {
10243 Lisp_Object rest, frame;
4ae9a85e
GM
10244
10245 BLOCK_INPUT;
10246
333b20bb
GM
10247 FOR_EACH_FRAME (rest, frame)
10248 if (FRAME_X_P (XFRAME (frame)))
10249 {
10250 struct frame *f = XFRAME (frame);
4ae9a85e 10251
333b20bb 10252 f->output_data.x->busy_p = 1;
4ae9a85e 10253
333b20bb
GM
10254 if (!f->output_data.x->busy_window)
10255 {
10256 unsigned long mask = CWCursor;
10257 XSetWindowAttributes attrs;
4ae9a85e 10258
333b20bb 10259 attrs.cursor = f->output_data.x->busy_cursor;
4ae9a85e 10260
333b20bb
GM
10261 f->output_data.x->busy_window
10262 = XCreateWindow (FRAME_X_DISPLAY (f),
10263 FRAME_OUTER_WINDOW (f),
10264 0, 0, 32000, 32000, 0, 0,
dc6f74cf
GM
10265 InputOnly,
10266 CopyFromParent,
333b20bb
GM
10267 mask, &attrs);
10268 }
4ae9a85e 10269
333b20bb 10270 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
4ae9a85e 10271 XFlush (FRAME_X_DISPLAY (f));
333b20bb 10272 }
333b20bb 10273
4ae9a85e
GM
10274 busy_cursor_shown_p = 1;
10275 UNBLOCK_INPUT;
10276 }
333b20bb
GM
10277}
10278
10279
4ae9a85e 10280/* Hide the busy cursor on all frames, if it is currently shown. */
333b20bb 10281
4ae9a85e
GM
10282static void
10283hide_busy_cursor ()
10284{
10285 if (busy_cursor_shown_p)
333b20bb 10286 {
4ae9a85e
GM
10287 Lisp_Object rest, frame;
10288
10289 BLOCK_INPUT;
10290 FOR_EACH_FRAME (rest, frame)
333b20bb 10291 {
4ae9a85e
GM
10292 struct frame *f = XFRAME (frame);
10293
10294 if (FRAME_X_P (f)
10295 /* Watch out for newly created frames. */
10296 && f->output_data.x->busy_window)
10297 {
10298 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
10299 /* Sync here because XTread_socket looks at the busy_p flag
10300 that is reset to zero below. */
10301 XSync (FRAME_X_DISPLAY (f), False);
10302 f->output_data.x->busy_p = 0;
10303 }
333b20bb 10304 }
333b20bb 10305
4ae9a85e
GM
10306 busy_cursor_shown_p = 0;
10307 UNBLOCK_INPUT;
10308 }
333b20bb
GM
10309}
10310
10311
10312\f
10313/***********************************************************************
10314 Tool tips
10315 ***********************************************************************/
10316
10317static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
10318 Lisp_Object));
10319
10320/* The frame of a currently visible tooltip, or null. */
10321
10322struct frame *tip_frame;
10323
10324/* If non-nil, a timer started that hides the last tooltip when it
10325 fires. */
10326
10327Lisp_Object tip_timer;
10328Window tip_window;
10329
10330/* Create a frame for a tooltip on the display described by DPYINFO.
10331 PARMS is a list of frame parameters. Value is the frame. */
10332
10333static Lisp_Object
10334x_create_tip_frame (dpyinfo, parms)
10335 struct x_display_info *dpyinfo;
10336 Lisp_Object parms;
10337{
10338 struct frame *f;
10339 Lisp_Object frame, tem;
10340 Lisp_Object name;
333b20bb
GM
10341 long window_prompting = 0;
10342 int width, height;
10343 int count = specpdl_ptr - specpdl;
b6d7acec 10344 struct gcpro gcpro1, gcpro2, gcpro3;
333b20bb
GM
10345 struct kboard *kb;
10346
10347 check_x ();
10348
10349 /* Use this general default value to start with until we know if
10350 this frame has a specified name. */
10351 Vx_resource_name = Vinvocation_name;
10352
10353#ifdef MULTI_KBOARD
10354 kb = dpyinfo->kboard;
10355#else
10356 kb = &the_only_kboard;
10357#endif
10358
10359 /* Get the name of the frame to use for resource lookup. */
10360 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
10361 if (!STRINGP (name)
10362 && !EQ (name, Qunbound)
10363 && !NILP (name))
10364 error ("Invalid frame name--not a string or nil");
10365 Vx_resource_name = name;
10366
10367 frame = Qnil;
10368 GCPRO3 (parms, name, frame);
10369 tip_frame = f = make_frame (1);
10370 XSETFRAME (frame, f);
10371 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
10372
10373 f->output_method = output_x_window;
10374 f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
10375 bzero (f->output_data.x, sizeof (struct x_output));
10376 f->output_data.x->icon_bitmap = -1;
10377 f->output_data.x->fontset = -1;
10378 f->icon_name = Qnil;
10379 FRAME_X_DISPLAY_INFO (f) = dpyinfo;
10380#ifdef MULTI_KBOARD
10381 FRAME_KBOARD (f) = kb;
10382#endif
10383 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10384 f->output_data.x->explicit_parent = 0;
10385
10386 /* Set the name; the functions to which we pass f expect the name to
10387 be set. */
10388 if (EQ (name, Qunbound) || NILP (name))
10389 {
10390 f->name = build_string (dpyinfo->x_id_name);
10391 f->explicit_name = 0;
10392 }
10393 else
10394 {
10395 f->name = name;
10396 f->explicit_name = 1;
10397 /* use the frame's title when getting resources for this frame. */
10398 specbind (Qx_resource_name, name);
10399 }
10400
10401 /* Create fontsets from `global_fontset_alist' before handling fonts. */
8e713be6
KR
10402 for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCDR (tem))
10403 fs_register_fontset (f, XCAR (tem));
333b20bb
GM
10404
10405 /* Extract the window parameters from the supplied values
10406 that are needed to determine window geometry. */
10407 {
10408 Lisp_Object font;
10409
10410 font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
10411
10412 BLOCK_INPUT;
10413 /* First, try whatever font the caller has specified. */
10414 if (STRINGP (font))
10415 {
10416 tem = Fquery_fontset (font, Qnil);
10417 if (STRINGP (tem))
10418 font = x_new_fontset (f, XSTRING (tem)->data);
10419 else
10420 font = x_new_font (f, XSTRING (font)->data);
10421 }
10422
10423 /* Try out a font which we hope has bold and italic variations. */
10424 if (!STRINGP (font))
10425 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
10426 if (!STRINGP (font))
10427 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
10428 if (! STRINGP (font))
10429 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
10430 if (! STRINGP (font))
10431 /* This was formerly the first thing tried, but it finds too many fonts
10432 and takes too long. */
10433 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
10434 /* If those didn't work, look for something which will at least work. */
10435 if (! STRINGP (font))
10436 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
10437 UNBLOCK_INPUT;
10438 if (! STRINGP (font))
10439 font = build_string ("fixed");
10440
10441 x_default_parameter (f, parms, Qfont, font,
10442 "font", "Font", RES_TYPE_STRING);
10443 }
10444
10445 x_default_parameter (f, parms, Qborder_width, make_number (2),
10446 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
10447
10448 /* This defaults to 2 in order to match xterm. We recognize either
10449 internalBorderWidth or internalBorder (which is what xterm calls
10450 it). */
10451 if (NILP (Fassq (Qinternal_border_width, parms)))
10452 {
10453 Lisp_Object value;
10454
10455 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
10456 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
10457 if (! EQ (value, Qunbound))
10458 parms = Fcons (Fcons (Qinternal_border_width, value),
10459 parms);
10460 }
10461
10462 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
10463 "internalBorderWidth", "internalBorderWidth",
10464 RES_TYPE_NUMBER);
10465
10466 /* Also do the stuff which must be set before the window exists. */
10467 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
10468 "foreground", "Foreground", RES_TYPE_STRING);
10469 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
10470 "background", "Background", RES_TYPE_STRING);
10471 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
10472 "pointerColor", "Foreground", RES_TYPE_STRING);
10473 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
10474 "cursorColor", "Foreground", RES_TYPE_STRING);
10475 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
10476 "borderColor", "BorderColor", RES_TYPE_STRING);
10477
10478 /* Init faces before x_default_parameter is called for scroll-bar
10479 parameters because that function calls x_set_scroll_bar_width,
10480 which calls change_frame_size, which calls Fset_window_buffer,
10481 which runs hooks, which call Fvertical_motion. At the end, we
10482 end up in init_iterator with a null face cache, which should not
10483 happen. */
10484 init_frame_faces (f);
10485
10486 f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
10487 window_prompting = x_figure_window_size (f, parms);
10488
10489 if (window_prompting & XNegative)
10490 {
10491 if (window_prompting & YNegative)
10492 f->output_data.x->win_gravity = SouthEastGravity;
10493 else
10494 f->output_data.x->win_gravity = NorthEastGravity;
10495 }
10496 else
10497 {
10498 if (window_prompting & YNegative)
10499 f->output_data.x->win_gravity = SouthWestGravity;
10500 else
10501 f->output_data.x->win_gravity = NorthWestGravity;
10502 }
10503
10504 f->output_data.x->size_hint_flags = window_prompting;
10505 {
10506 XSetWindowAttributes attrs;
10507 unsigned long mask;
10508
10509 BLOCK_INPUT;
10510 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
9b2956e2
GM
10511 /* Window managers look at the override-redirect flag to determine
10512 whether or net to give windows a decoration (Xlib spec, chapter
333b20bb
GM
10513 3.2.8). */
10514 attrs.override_redirect = True;
10515 attrs.save_under = True;
10516 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
10517 /* Arrange for getting MapNotify and UnmapNotify events. */
10518 attrs.event_mask = StructureNotifyMask;
10519 tip_window
10520 = FRAME_X_WINDOW (f)
10521 = XCreateWindow (FRAME_X_DISPLAY (f),
10522 FRAME_X_DISPLAY_INFO (f)->root_window,
10523 /* x, y, width, height */
10524 0, 0, 1, 1,
10525 /* Border. */
10526 1,
10527 CopyFromParent, InputOutput, CopyFromParent,
10528 mask, &attrs);
10529 UNBLOCK_INPUT;
10530 }
10531
10532 x_make_gc (f);
10533
333b20bb
GM
10534 x_default_parameter (f, parms, Qauto_raise, Qnil,
10535 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10536 x_default_parameter (f, parms, Qauto_lower, Qnil,
10537 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
10538 x_default_parameter (f, parms, Qcursor_type, Qbox,
10539 "cursorType", "CursorType", RES_TYPE_SYMBOL);
10540
10541 /* Dimensions, especially f->height, must be done via change_frame_size.
10542 Change will not be effected unless different from the current
10543 f->height. */
10544 width = f->width;
10545 height = f->height;
10546 f->height = 0;
10547 SET_FRAME_WIDTH (f, 0);
8938a4fb 10548 change_frame_size (f, height, width, 1, 0, 0);
333b20bb
GM
10549
10550 f->no_split = 1;
10551
10552 UNGCPRO;
10553
10554 /* It is now ok to make the frame official even if we get an error
10555 below. And the frame needs to be on Vframe_list or making it
10556 visible won't work. */
10557 Vframe_list = Fcons (frame, Vframe_list);
10558
10559 /* Now that the frame is official, it counts as a reference to
10560 its display. */
10561 FRAME_X_DISPLAY_INFO (f)->reference_count++;
10562
10563 return unbind_to (count, frame);
10564}
10565
10566
10567DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
e82d09c9
GM
10568 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
10569A tooltip window is a small X window displaying STRING at\n\
10570the current mouse position.\n\
333b20bb
GM
10571FRAME nil or omitted means use the selected frame.\n\
10572PARMS is an optional list of frame parameters which can be\n\
10573used to change the tooltip's appearance.\n\
10574Automatically hide the tooltip after TIMEOUT seconds.\n\
10575TIMEOUT nil means use the default timeout of 5 seconds.")
10576 (string, frame, parms, timeout)
68c45bf0 10577 Lisp_Object string, frame, parms, timeout;
333b20bb
GM
10578{
10579 struct frame *f;
10580 struct window *w;
10581 Window root, child;
333b20bb
GM
10582 Lisp_Object buffer;
10583 struct buffer *old_buffer;
10584 struct text_pos pos;
10585 int i, width, height;
10586 int root_x, root_y, win_x, win_y;
10587 unsigned pmask;
393f2d14 10588 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
333b20bb
GM
10589 int old_windows_or_buffers_changed = windows_or_buffers_changed;
10590 int count = specpdl_ptr - specpdl;
10591
10592 specbind (Qinhibit_redisplay, Qt);
10593
393f2d14 10594 GCPRO4 (string, parms, frame, timeout);
333b20bb
GM
10595
10596 CHECK_STRING (string, 0);
10597 f = check_x_frame (frame);
10598 if (NILP (timeout))
10599 timeout = make_number (5);
10600 else
10601 CHECK_NATNUM (timeout, 2);
10602
10603 /* Hide a previous tip, if any. */
10604 Fx_hide_tip ();
10605
10606 /* Add default values to frame parameters. */
10607 if (NILP (Fassq (Qname, parms)))
10608 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
10609 if (NILP (Fassq (Qinternal_border_width, parms)))
10610 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
10611 if (NILP (Fassq (Qborder_width, parms)))
10612 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
10613 if (NILP (Fassq (Qborder_color, parms)))
10614 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
10615 if (NILP (Fassq (Qbackground_color, parms)))
10616 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
10617 parms);
10618
10619 /* Create a frame for the tooltip, and record it in the global
10620 variable tip_frame. */
10621 frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms);
10622 tip_frame = f = XFRAME (frame);
10623
10624 /* Set up the frame's root window. Currently we use a size of 80
10625 columns x 40 lines. If someone wants to show a larger tip, he
10626 will loose. I don't think this is a realistic case. */
10627 w = XWINDOW (FRAME_ROOT_WINDOW (f));
10628 w->left = w->top = make_number (0);
10629 w->width = 80;
10630 w->height = 40;
10631 adjust_glyphs (f);
10632 w->pseudo_window_p = 1;
10633
10634 /* Display the tooltip text in a temporary buffer. */
10635 buffer = Fget_buffer_create (build_string (" *tip*"));
10636 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
10637 old_buffer = current_buffer;
10638 set_buffer_internal_1 (XBUFFER (buffer));
10639 Ferase_buffer ();
10640 Finsert (make_number (1), &string);
10641 clear_glyph_matrix (w->desired_matrix);
10642 clear_glyph_matrix (w->current_matrix);
10643 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
10644 try_window (FRAME_ROOT_WINDOW (f), pos);
10645
10646 /* Compute width and height of the tooltip. */
10647 width = height = 0;
10648 for (i = 0; i < w->desired_matrix->nrows; ++i)
10649 {
10650 struct glyph_row *row = &w->desired_matrix->rows[i];
10651 struct glyph *last;
10652 int row_width;
10653
10654 /* Stop at the first empty row at the end. */
10655 if (!row->enabled_p || !row->displays_text_p)
10656 break;
10657
d7bf0342
GM
10658 /* Let the row go over the full width of the frame. */
10659 row->full_width_p = 1;
333b20bb
GM
10660
10661 /* There's a glyph at the end of rows that is use to place
10662 the cursor there. Don't include the width of this glyph. */
10663 if (row->used[TEXT_AREA])
10664 {
10665 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
10666 row_width = row->pixel_width - last->pixel_width;
10667 }
10668 else
10669 row_width = row->pixel_width;
10670
10671 height += row->height;
10672 width = max (width, row_width);
10673 }
10674
10675 /* Add the frame's internal border to the width and height the X
10676 window should have. */
10677 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
10678 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
10679
10680 /* Move the tooltip window where the mouse pointer is. Resize and
10681 show it. */
10682 BLOCK_INPUT;
10683 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
10684 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
10685 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10686 root_x + 5, root_y - height - 5, width, height);
10687 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
10688 UNBLOCK_INPUT;
10689
10690 /* Draw into the window. */
10691 w->must_be_updated_p = 1;
10692 update_single_window (w, 1);
10693
10694 /* Restore original current buffer. */
10695 set_buffer_internal_1 (old_buffer);
10696 windows_or_buffers_changed = old_windows_or_buffers_changed;
10697
10698 /* Let the tip disappear after timeout seconds. */
10699 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
10700 intern ("x-hide-tip"));
a744a2ec
DL
10701
10702 UNGCPRO;
333b20bb
GM
10703 return unbind_to (count, Qnil);
10704}
10705
10706
10707DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
e82d09c9 10708 "Hide the current tooltip window, if there is any.\n\
333b20bb
GM
10709Value is t is tooltip was open, nil otherwise.")
10710 ()
10711{
10712 int count = specpdl_ptr - specpdl;
10713 int deleted_p = 0;
10714
10715 specbind (Qinhibit_redisplay, Qt);
10716
10717 if (!NILP (tip_timer))
10718 {
10719 call1 (intern ("cancel-timer"), tip_timer);
10720 tip_timer = Qnil;
10721 }
10722
10723 if (tip_frame)
10724 {
10725 Lisp_Object frame;
10726
10727 XSETFRAME (frame, tip_frame);
10728 Fdelete_frame (frame, Qt);
10729 tip_frame = NULL;
10730 deleted_p = 1;
10731 }
10732
10733 return unbind_to (count, deleted_p ? Qt : Qnil);
10734}
10735
10736
10737\f
10738/***********************************************************************
10739 File selection dialog
10740 ***********************************************************************/
10741
10742#ifdef USE_MOTIF
10743
10744/* Callback for "OK" and "Cancel" on file selection dialog. */
10745
10746static void
10747file_dialog_cb (widget, client_data, call_data)
10748 Widget widget;
10749 XtPointer call_data, client_data;
10750{
10751 int *result = (int *) client_data;
10752 XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
10753 *result = cb->reason;
10754}
10755
10756
10757DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
10758 "Read file name, prompting with PROMPT in directory DIR.\n\
10759Use a file selection dialog.\n\
10760Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
10761specified. Don't let the user enter a file name in the file\n\
10762selection dialog's entry field, if MUSTMATCH is non-nil.")
10763 (prompt, dir, default_filename, mustmatch)
10764 Lisp_Object prompt, dir, default_filename, mustmatch;
10765{
10766 int result;
0fe92f72 10767 struct frame *f = SELECTED_FRAME ();
333b20bb
GM
10768 Lisp_Object file = Qnil;
10769 Widget dialog, text, list, help;
10770 Arg al[10];
10771 int ac = 0;
10772 extern XtAppContext Xt_app_con;
10773 char *title;
10774 XmString dir_xmstring, pattern_xmstring;
10775 int popup_activated_flag;
10776 int count = specpdl_ptr - specpdl;
10777 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
10778
10779 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
10780 CHECK_STRING (prompt, 0);
10781 CHECK_STRING (dir, 1);
10782
10783 /* Prevent redisplay. */
10784 specbind (Qinhibit_redisplay, Qt);
10785
10786 BLOCK_INPUT;
10787
10788 /* Create the dialog with PROMPT as title, using DIR as initial
10789 directory and using "*" as pattern. */
10790 dir = Fexpand_file_name (dir, Qnil);
10791 dir_xmstring = XmStringCreateLocalized (XSTRING (dir)->data);
10792 pattern_xmstring = XmStringCreateLocalized ("*");
10793
10794 XtSetArg (al[ac], XmNtitle, XSTRING (prompt)->data); ++ac;
10795 XtSetArg (al[ac], XmNdirectory, dir_xmstring); ++ac;
10796 XtSetArg (al[ac], XmNpattern, pattern_xmstring); ++ac;
10797 XtSetArg (al[ac], XmNresizePolicy, XmRESIZE_GROW); ++ac;
10798 XtSetArg (al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); ++ac;
10799 dialog = XmCreateFileSelectionDialog (f->output_data.x->widget,
10800 "fsb", al, ac);
10801 XmStringFree (dir_xmstring);
10802 XmStringFree (pattern_xmstring);
10803
10804 /* Add callbacks for OK and Cancel. */
10805 XtAddCallback (dialog, XmNokCallback, file_dialog_cb,
10806 (XtPointer) &result);
10807 XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
10808 (XtPointer) &result);
10809
10810 /* Disable the help button since we can't display help. */
10811 help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
10812 XtSetSensitive (help, False);
10813
10814 /* Mark OK button as default. */
10815 XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON),
10816 XmNshowAsDefault, True, NULL);
10817
10818 /* If MUSTMATCH is non-nil, disable the file entry field of the
10819 dialog, so that the user must select a file from the files list
10820 box. We can't remove it because we wouldn't have a way to get at
10821 the result file name, then. */
10822 text = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT);
10823 if (!NILP (mustmatch))
10824 {
10825 Widget label;
10826 label = XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL);
10827 XtSetSensitive (text, False);
10828 XtSetSensitive (label, False);
10829 }
10830
10831 /* Manage the dialog, so that list boxes get filled. */
10832 XtManageChild (dialog);
10833
10834 /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME
10835 must include the path for this to work. */
10836 list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST);
10837 if (STRINGP (default_filename))
10838 {
10839 XmString default_xmstring;
10840 int item_pos;
10841
10842 default_xmstring
10843 = XmStringCreateLocalized (XSTRING (default_filename)->data);
10844
10845 if (!XmListItemExists (list, default_xmstring))
10846 {
10847 /* Add a new item if DEFAULT_FILENAME is not in the list. */
10848 XmListAddItem (list, default_xmstring, 0);
10849 item_pos = 0;
10850 }
10851 else
10852 item_pos = XmListItemPos (list, default_xmstring);
10853 XmStringFree (default_xmstring);
10854
10855 /* Select the item and scroll it into view. */
10856 XmListSelectPos (list, item_pos, True);
10857 XmListSetPos (list, item_pos);
10858 }
10859
10860 /* Process all events until the user presses Cancel or OK. */
10861 for (result = 0; result == 0;)
10862 {
10863 XEvent event;
10864 Widget widget, parent;
10865
10866 XtAppNextEvent (Xt_app_con, &event);
10867
10868 /* See if the receiver of the event is one of the widgets of
10869 the file selection dialog. If so, dispatch it. If not,
10870 discard it. */
10871 widget = XtWindowToWidget (event.xany.display, event.xany.window);
10872 parent = widget;
10873 while (parent && parent != dialog)
10874 parent = XtParent (parent);
10875
10876 if (parent == dialog
10877 || (event.type == Expose
10878 && !process_expose_from_menu (event)))
10879 XtDispatchEvent (&event);
10880 }
10881
10882 /* Get the result. */
10883 if (result == XmCR_OK)
10884 {
10885 XmString text;
10886 String data;
10887
10888 XtVaGetValues (dialog, XmNtextString, &text, 0);
10889 XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
10890 XmStringFree (text);
10891 file = build_string (data);
10892 XtFree (data);
10893 }
10894 else
10895 file = Qnil;
10896
10897 /* Clean up. */
10898 XtUnmanageChild (dialog);
10899 XtDestroyWidget (dialog);
10900 UNBLOCK_INPUT;
10901 UNGCPRO;
10902
10903 /* Make "Cancel" equivalent to C-g. */
10904 if (NILP (file))
10905 Fsignal (Qquit, Qnil);
10906
10907 return unbind_to (count, file);
10908}
10909
10910#endif /* USE_MOTIF */
10911
10912\f
10913/***********************************************************************
10914 Tests
10915 ***********************************************************************/
10916
10917#if GLYPH_DEBUG
10918
10919DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
10920 "Value is non-nil if SPEC is a valid image specification.")
10921 (spec)
10922 Lisp_Object spec;
10923{
10924 return valid_image_p (spec) ? Qt : Qnil;
10925}
10926
10927
10928DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
10929 (spec)
10930 Lisp_Object spec;
10931{
10932 int id = -1;
10933
10934 if (valid_image_p (spec))
0fe92f72 10935 id = lookup_image (SELECTED_FRAME (), spec);
333b20bb
GM
10936
10937 debug_print (spec);
10938 return make_number (id);
10939}
10940
10941#endif /* GLYPH_DEBUG != 0 */
10942
10943
10944\f
10945/***********************************************************************
10946 Initialization
10947 ***********************************************************************/
10948
10949void
10950syms_of_xfns ()
10951{
10952 /* This is zero if not using X windows. */
10953 x_in_use = 0;
10954
10955 /* The section below is built by the lisp expression at the top of the file,
10956 just above where these variables are declared. */
10957 /*&&& init symbols here &&&*/
10958 Qauto_raise = intern ("auto-raise");
10959 staticpro (&Qauto_raise);
10960 Qauto_lower = intern ("auto-lower");
10961 staticpro (&Qauto_lower);
10962 Qbar = intern ("bar");
dbc4e1c1 10963 staticpro (&Qbar);
f9942c9e
JB
10964 Qborder_color = intern ("border-color");
10965 staticpro (&Qborder_color);
10966 Qborder_width = intern ("border-width");
10967 staticpro (&Qborder_width);
dbc4e1c1
JB
10968 Qbox = intern ("box");
10969 staticpro (&Qbox);
f9942c9e
JB
10970 Qcursor_color = intern ("cursor-color");
10971 staticpro (&Qcursor_color);
dbc4e1c1
JB
10972 Qcursor_type = intern ("cursor-type");
10973 staticpro (&Qcursor_type);
f9942c9e
JB
10974 Qgeometry = intern ("geometry");
10975 staticpro (&Qgeometry);
f9942c9e
JB
10976 Qicon_left = intern ("icon-left");
10977 staticpro (&Qicon_left);
10978 Qicon_top = intern ("icon-top");
10979 staticpro (&Qicon_top);
10980 Qicon_type = intern ("icon-type");
10981 staticpro (&Qicon_type);
80534dd6
KH
10982 Qicon_name = intern ("icon-name");
10983 staticpro (&Qicon_name);
f9942c9e
JB
10984 Qinternal_border_width = intern ("internal-border-width");
10985 staticpro (&Qinternal_border_width);
10986 Qleft = intern ("left");
10987 staticpro (&Qleft);
1ab3d87e
RS
10988 Qright = intern ("right");
10989 staticpro (&Qright);
f9942c9e
JB
10990 Qmouse_color = intern ("mouse-color");
10991 staticpro (&Qmouse_color);
baaed68e
JB
10992 Qnone = intern ("none");
10993 staticpro (&Qnone);
f9942c9e
JB
10994 Qparent_id = intern ("parent-id");
10995 staticpro (&Qparent_id);
4701395c
KH
10996 Qscroll_bar_width = intern ("scroll-bar-width");
10997 staticpro (&Qscroll_bar_width);
8af1d7ca
JB
10998 Qsuppress_icon = intern ("suppress-icon");
10999 staticpro (&Qsuppress_icon);
01f1ba30 11000 Qundefined_color = intern ("undefined-color");
f9942c9e 11001 staticpro (&Qundefined_color);
a3c87d4e
JB
11002 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
11003 staticpro (&Qvertical_scroll_bars);
49795535
JB
11004 Qvisibility = intern ("visibility");
11005 staticpro (&Qvisibility);
f9942c9e
JB
11006 Qwindow_id = intern ("window-id");
11007 staticpro (&Qwindow_id);
2cbebefb
RS
11008 Qouter_window_id = intern ("outer-window-id");
11009 staticpro (&Qouter_window_id);
f9942c9e
JB
11010 Qx_frame_parameter = intern ("x-frame-parameter");
11011 staticpro (&Qx_frame_parameter);
9ef48a9d
RS
11012 Qx_resource_name = intern ("x-resource-name");
11013 staticpro (&Qx_resource_name);
4fe1de12
RS
11014 Quser_position = intern ("user-position");
11015 staticpro (&Quser_position);
11016 Quser_size = intern ("user-size");
11017 staticpro (&Quser_size);
333b20bb
GM
11018 Qscroll_bar_foreground = intern ("scroll-bar-foreground");
11019 staticpro (&Qscroll_bar_foreground);
11020 Qscroll_bar_background = intern ("scroll-bar-background");
11021 staticpro (&Qscroll_bar_background);
d62c8769
GM
11022 Qscreen_gamma = intern ("screen-gamma");
11023 staticpro (&Qscreen_gamma);
f9942c9e
JB
11024 /* This is the end of symbol initialization. */
11025
58cad5ed
KH
11026 /* Text property `display' should be nonsticky by default. */
11027 Vtext_property_default_nonsticky
11028 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
11029
11030
333b20bb
GM
11031 Qlaplace = intern ("laplace");
11032 staticpro (&Qlaplace);
11033
a367641f
RS
11034 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
11035 staticpro (&Qface_set_after_frame_default);
11036
01f1ba30
JB
11037 Fput (Qundefined_color, Qerror_conditions,
11038 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
11039 Fput (Qundefined_color, Qerror_message,
11040 build_string ("Undefined color"));
11041
f9942c9e
JB
11042 init_x_parm_symbols ();
11043
f1c7b5a6
RS
11044 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
11045 "List of directories to search for bitmap files for X.");
e241c09b 11046 Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
f1c7b5a6 11047
16ae08a9 11048 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
d387c960 11049 "The shape of the pointer when over text.\n\
af01ef26
RS
11050Changing the value does not affect existing frames\n\
11051unless you set the mouse color.");
01f1ba30
JB
11052 Vx_pointer_shape = Qnil;
11053
d387c960 11054 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
498e9ac3 11055 "The name Emacs uses to look up X resources.\n\
d387c960
JB
11056`x-get-resource' uses this as the first component of the instance name\n\
11057when requesting resource values.\n\
11058Emacs initially sets `x-resource-name' to the name under which Emacs\n\
11059was invoked, or to the value specified with the `-name' or `-rn'\n\
498e9ac3
RS
11060switches, if present.\n\
11061\n\
11062It may be useful to bind this variable locally around a call\n\
11063to `x-get-resource'. See also the variable `x-resource-class'.");
d387c960 11064 Vx_resource_name = Qnil;
ac63d3d6 11065
498e9ac3
RS
11066 DEFVAR_LISP ("x-resource-class", &Vx_resource_class,
11067 "The class Emacs uses to look up X resources.\n\
11068`x-get-resource' uses this as the first component of the instance class\n\
11069when requesting resource values.\n\
11070Emacs initially sets `x-resource-class' to \"Emacs\".\n\
11071\n\
11072Setting this variable permanently is not a reasonable thing to do,\n\
11073but binding this variable locally around a call to `x-get-resource'\n\
333b20bb 11074is a reasonable practice. See also the variable `x-resource-name'.");
498e9ac3
RS
11075 Vx_resource_class = build_string (EMACS_CLASS);
11076
ca0ecbf5 11077#if 0 /* This doesn't really do anything. */
d3b06468 11078 DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape,
ca0ecbf5
RS
11079 "The shape of the pointer when not over text.\n\
11080This variable takes effect when you create a new frame\n\
11081or when you set the mouse color.");
af01ef26 11082#endif
01f1ba30
JB
11083 Vx_nontext_pointer_shape = Qnil;
11084
333b20bb
GM
11085 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
11086 "The shape of the pointer when Emacs is busy.\n\
11087This variable takes effect when you create a new frame\n\
11088or when you set the mouse color.");
11089 Vx_busy_pointer_shape = Qnil;
11090
11091 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
11092 "Non-zero means Emacs displays a busy cursor on window systems.");
11093 display_busy_cursor_p = 1;
11094
4ae9a85e
GM
11095 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
11096 "*Seconds to wait before displaying a busy-cursor.\n\
3caa99d3 11097Value must be an integer or float.");
4ae9a85e
GM
11098 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
11099
ca0ecbf5 11100#if 0 /* This doesn't really do anything. */
d3b06468 11101 DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
ca0ecbf5
RS
11102 "The shape of the pointer when over the mode line.\n\
11103This variable takes effect when you create a new frame\n\
11104or when you set the mouse color.");
af01ef26 11105#endif
01f1ba30
JB
11106 Vx_mode_pointer_shape = Qnil;
11107
d3b06468 11108 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ca0ecbf5
RS
11109 &Vx_sensitive_text_pointer_shape,
11110 "The shape of the pointer when over mouse-sensitive text.\n\
11111This variable takes effect when you create a new frame\n\
11112or when you set the mouse color.");
11113 Vx_sensitive_text_pointer_shape = Qnil;
95f80c78 11114
01f1ba30
JB
11115 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
11116 "A string indicating the foreground color of the cursor box.");
11117 Vx_cursor_fore_pixel = Qnil;
11118
01f1ba30 11119 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
2d38195d
RS
11120 "Non-nil if no X window manager is in use.\n\
11121Emacs doesn't try to figure this out; this is always nil\n\
11122unless you set it to something else.");
11123 /* We don't have any way to find this out, so set it to nil
11124 and maybe the user would like to set it to t. */
11125 Vx_no_window_manager = Qnil;
1d3dac41 11126
942ea06d
KH
11127 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
11128 &Vx_pixel_size_width_font_regexp,
11129 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
11130\n\
dcc13cda 11131Since Emacs gets width of a font matching with this regexp from\n\
942ea06d
KH
11132PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
11133such a font. This is especially effective for such large fonts as\n\
11134Chinese, Japanese, and Korean.");
11135 Vx_pixel_size_width_font_regexp = Qnil;
11136
fcf431dc 11137 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
333b20bb
GM
11138 "Time after which cached images are removed from the cache.\n\
11139When an image has not been displayed this many seconds, remove it\n\
11140from the image cache. Value must be an integer or nil with nil\n\
11141meaning don't clear the cache.");
fcf431dc 11142 Vimage_cache_eviction_delay = make_number (30 * 60);
333b20bb
GM
11143
11144 DEFVAR_LISP ("image-types", &Vimage_types,
11145 "List of supported image types.\n\
11146Each element of the list is a symbol for a supported image type.");
11147 Vimage_types = Qnil;
11148
1d3dac41 11149#ifdef USE_X_TOOLKIT
f1d238ef 11150 Fprovide (intern ("x-toolkit"));
1d3dac41 11151#endif
5b827abb
KH
11152#ifdef USE_MOTIF
11153 Fprovide (intern ("motif"));
11154#endif
01f1ba30 11155
01f1ba30 11156 defsubr (&Sx_get_resource);
333b20bb
GM
11157
11158 /* X window properties. */
11159 defsubr (&Sx_change_window_property);
11160 defsubr (&Sx_delete_window_property);
11161 defsubr (&Sx_window_property);
11162
85ffea93 11163#if 0
01f1ba30
JB
11164 defsubr (&Sx_draw_rectangle);
11165 defsubr (&Sx_erase_rectangle);
11166 defsubr (&Sx_contour_region);
11167 defsubr (&Sx_uncontour_region);
85ffea93 11168#endif
2d764c78 11169 defsubr (&Sxw_display_color_p);
d0c9d219 11170 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
11171 defsubr (&Sxw_color_defined_p);
11172 defsubr (&Sxw_color_values);
9d317b2c 11173 defsubr (&Sx_server_max_request_size);
41beb8fc
RS
11174 defsubr (&Sx_server_vendor);
11175 defsubr (&Sx_server_version);
11176 defsubr (&Sx_display_pixel_width);
11177 defsubr (&Sx_display_pixel_height);
11178 defsubr (&Sx_display_mm_width);
11179 defsubr (&Sx_display_mm_height);
11180 defsubr (&Sx_display_screens);
11181 defsubr (&Sx_display_planes);
11182 defsubr (&Sx_display_color_cells);
11183 defsubr (&Sx_display_visual_class);
11184 defsubr (&Sx_display_backing_store);
11185 defsubr (&Sx_display_save_under);
01567351 11186#if 0
9d04a87a
RS
11187 defsubr (&Sx_rebind_key);
11188 defsubr (&Sx_rebind_keys);
01f1ba30 11189 defsubr (&Sx_track_pointer);
01f1ba30
JB
11190 defsubr (&Sx_grab_pointer);
11191 defsubr (&Sx_ungrab_pointer);
01f1ba30 11192#endif
8af1d7ca 11193 defsubr (&Sx_parse_geometry);
f676886a 11194 defsubr (&Sx_create_frame);
06ef7355 11195#if 0
01f1ba30 11196 defsubr (&Sx_horizontal_line);
06ef7355 11197#endif
01f1ba30 11198 defsubr (&Sx_open_connection);
08a90d6a
RS
11199 defsubr (&Sx_close_connection);
11200 defsubr (&Sx_display_list);
01f1ba30 11201 defsubr (&Sx_synchronize);
942ea06d
KH
11202
11203 /* Setting callback functions for fontset handler. */
11204 get_font_info_func = x_get_font_info;
333b20bb
GM
11205
11206#if 0 /* This function pointer doesn't seem to be used anywhere.
11207 And the pointer assigned has the wrong type, anyway. */
942ea06d 11208 list_fonts_func = x_list_fonts;
333b20bb
GM
11209#endif
11210
942ea06d 11211 load_font_func = x_load_font;
bc1958c4 11212 find_ccl_program_func = x_find_ccl_program;
942ea06d
KH
11213 query_font_func = x_query_font;
11214 set_frame_fontset_func = x_set_font;
11215 check_window_system_func = check_x;
333b20bb
GM
11216
11217 /* Images. */
11218 Qxbm = intern ("xbm");
11219 staticpro (&Qxbm);
11220 QCtype = intern (":type");
11221 staticpro (&QCtype);
333b20bb
GM
11222 QCalgorithm = intern (":algorithm");
11223 staticpro (&QCalgorithm);
11224 QCheuristic_mask = intern (":heuristic-mask");
11225 staticpro (&QCheuristic_mask);
11226 QCcolor_symbols = intern (":color-symbols");
11227 staticpro (&QCcolor_symbols);
11228 QCdata = intern (":data");
11229 staticpro (&QCdata);
11230 QCascent = intern (":ascent");
11231 staticpro (&QCascent);
11232 QCmargin = intern (":margin");
11233 staticpro (&QCmargin);
11234 QCrelief = intern (":relief");
11235 staticpro (&QCrelief);
fcf431dc
GM
11236 Qpostscript = intern ("postscript");
11237 staticpro (&Qpostscript);
333b20bb
GM
11238 QCloader = intern (":loader");
11239 staticpro (&QCloader);
11240 QCbounding_box = intern (":bounding-box");
11241 staticpro (&QCbounding_box);
11242 QCpt_width = intern (":pt-width");
11243 staticpro (&QCpt_width);
11244 QCpt_height = intern (":pt-height");
11245 staticpro (&QCpt_height);
3ccff1e3
GM
11246 QCindex = intern (":index");
11247 staticpro (&QCindex);
333b20bb
GM
11248 Qpbm = intern ("pbm");
11249 staticpro (&Qpbm);
11250
11251#if HAVE_XPM
11252 Qxpm = intern ("xpm");
11253 staticpro (&Qxpm);
11254#endif
11255
11256#if HAVE_JPEG
11257 Qjpeg = intern ("jpeg");
11258 staticpro (&Qjpeg);
11259#endif
11260
11261#if HAVE_TIFF
11262 Qtiff = intern ("tiff");
11263 staticpro (&Qtiff);
11264#endif
11265
11266#if HAVE_GIF
11267 Qgif = intern ("gif");
11268 staticpro (&Qgif);
11269#endif
11270
11271#if HAVE_PNG
11272 Qpng = intern ("png");
11273 staticpro (&Qpng);
11274#endif
11275
11276 defsubr (&Sclear_image_cache);
11277
11278#if GLYPH_DEBUG
11279 defsubr (&Simagep);
11280 defsubr (&Slookup_image);
11281#endif
11282
4ae9a85e
GM
11283 busy_cursor_atimer = NULL;
11284 busy_cursor_shown_p = 0;
333b20bb
GM
11285
11286 defsubr (&Sx_show_tip);
11287 defsubr (&Sx_hide_tip);
11288 staticpro (&tip_timer);
11289 tip_timer = Qnil;
11290
11291#ifdef USE_MOTIF
11292 defsubr (&Sx_file_dialog);
11293#endif
11294}
11295
11296
11297void
11298init_xfns ()
11299{
11300 image_types = NULL;
11301 Vimage_types = Qnil;
11302
11303 define_image_type (&xbm_type);
11304 define_image_type (&gs_type);
11305 define_image_type (&pbm_type);
11306
11307#if HAVE_XPM
11308 define_image_type (&xpm_type);
11309#endif
11310
11311#if HAVE_JPEG
11312 define_image_type (&jpeg_type);
11313#endif
11314
11315#if HAVE_TIFF
11316 define_image_type (&tiff_type);
11317#endif
11318
11319#if HAVE_GIF
11320 define_image_type (&gif_type);
11321#endif
11322
11323#if HAVE_PNG
11324 define_image_type (&png_type);
11325#endif
01f1ba30
JB
11326}
11327
11328#endif /* HAVE_X_WINDOWS */