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