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