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