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