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