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