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