(Frame_parameters): Makes the scroll-bar-width frame parameter have
[bpt/emacs.git] / src / w32fns.c
CommitLineData
e9e23e23 1/* Graphical user interface functions for the Microsoft W32 API.
a93f4566 2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
6fc2811b 3 Free Software Foundation, Inc.
ee78dc32
GV
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
9the Free Software Foundation; either version 2, or (at your option)
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. */
ee78dc32
GV
21
22/* Added by Kevin Gallo */
23
ee78dc32 24#include <config.h>
1edf84e7
GV
25
26#include <signal.h>
ee78dc32 27#include <stdio.h>
1edf84e7
GV
28#include <limits.h>
29#include <errno.h>
ee78dc32
GV
30
31#include "lisp.h"
4587b026 32#include "charset.h"
71eab8d1 33#include "dispextern.h"
ee78dc32 34#include "w32term.h"
c7501041 35#include "keyboard.h"
ee78dc32
GV
36#include "frame.h"
37#include "window.h"
38#include "buffer.h"
126f2e35 39#include "fontset.h"
6fc2811b 40#include "intervals.h"
ee78dc32 41#include "blockinput.h"
57bda87a 42#include "epaths.h"
489f9371 43#include "w32heap.h"
ee78dc32 44#include "termhooks.h"
4587b026 45#include "coding.h"
3545439c 46#include "ccl.h"
6fc2811b
JR
47#include "systime.h"
48
49#include "bitmaps/gray.xbm"
ee78dc32
GV
50
51#include <commdlg.h>
cb9e33d4 52#include <shellapi.h>
6fc2811b 53#include <ctype.h>
ee78dc32 54
ee78dc32 55extern void free_frame_menubar ();
9eb16b62 56extern void x_compute_fringe_widths P_ ((struct frame *, int));
6fc2811b 57extern double atof ();
9eb16b62
JR
58extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
59extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
60extern void w32_free_menu_strings P_ ((HWND));
61
5ac45f98 62extern int quit_char;
ee78dc32 63
6fc2811b
JR
64/* A definition of XColor for non-X frames. */
65#ifndef HAVE_X_WINDOWS
66typedef struct {
67 unsigned long pixel;
68 unsigned short red, green, blue;
69 char flags;
70 char pad;
71} XColor;
72#endif
73
ccc2d29c
GV
74extern char *lispy_function_keys[];
75
6fc2811b
JR
76/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
77 it, and including `bitmaps/gray' more than once is a problem when
78 config.h defines `static' as an empty replacement string. */
79
80int gray_bitmap_width = gray_width;
81int gray_bitmap_height = gray_height;
82unsigned char *gray_bitmap_bits = gray_bits;
83
ee78dc32 84/* The colormap for converting color names to RGB values */
fbd6baed 85Lisp_Object Vw32_color_map;
ee78dc32 86
da36a4d6 87/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 88Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 89
8c205c63
RS
90/* Non nil if alt key is translated to meta_modifier, nil if it is translated
91 to alt_modifier. */
fbd6baed 92Lisp_Object Vw32_alt_is_meta;
8c205c63 93
7d081355
AI
94/* If non-zero, the windows virtual key code for an alternative quit key. */
95Lisp_Object Vw32_quit_key;
96
ccc2d29c
GV
97/* Non nil if left window key events are passed on to Windows (this only
98 affects whether "tapping" the key opens the Start menu). */
99Lisp_Object Vw32_pass_lwindow_to_system;
100
101/* Non nil if right window key events are passed on to Windows (this
102 only affects whether "tapping" the key opens the Start menu). */
103Lisp_Object Vw32_pass_rwindow_to_system;
104
adcc3809
GV
105/* Virtual key code used to generate "phantom" key presses in order
106 to stop system from acting on Windows key events. */
107Lisp_Object Vw32_phantom_key_code;
108
ccc2d29c
GV
109/* Modifier associated with the left "Windows" key, or nil to act as a
110 normal key. */
111Lisp_Object Vw32_lwindow_modifier;
112
113/* Modifier associated with the right "Windows" key, or nil to act as a
114 normal key. */
115Lisp_Object Vw32_rwindow_modifier;
116
117/* Modifier associated with the "Apps" key, or nil to act as a normal
118 key. */
119Lisp_Object Vw32_apps_modifier;
120
121/* Value is nil if Num Lock acts as a function key. */
122Lisp_Object Vw32_enable_num_lock;
123
124/* Value is nil if Caps Lock acts as a function key. */
125Lisp_Object Vw32_enable_caps_lock;
126
127/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
128Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 129
7ce9aaca 130/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b
JR
131 and italic versions of fonts. */
132Lisp_Object Vw32_enable_synthesized_fonts;
5ac45f98
GV
133
134/* Enable palette management. */
fbd6baed 135Lisp_Object Vw32_enable_palette;
5ac45f98
GV
136
137/* Control how close left/right button down events must be to
138 be converted to a middle button down event. */
fbd6baed 139Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 140
84fb1139
KH
141/* Minimum interval between mouse movement (and scroll bar drag)
142 events that are passed on to the event loop. */
fbd6baed 143Lisp_Object Vw32_mouse_move_interval;
84fb1139 144
ee78dc32
GV
145/* The name we're using in resource queries. */
146Lisp_Object Vx_resource_name;
147
148/* Non nil if no window manager is in use. */
149Lisp_Object Vx_no_window_manager;
150
0af913d7 151/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 152
0af913d7 153int display_hourglass_p;
6fc2811b 154
ee78dc32
GV
155/* The background and shape of the mouse pointer, and shape when not
156 over text or in the modeline. */
dfff8a69 157
ee78dc32 158Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 159Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 160
ee78dc32 161/* The shape when over mouse-sensitive text. */
dfff8a69 162
ee78dc32
GV
163Lisp_Object Vx_sensitive_text_pointer_shape;
164
165/* Color of chars displayed in cursor box. */
dfff8a69 166
ee78dc32
GV
167Lisp_Object Vx_cursor_fore_pixel;
168
1edf84e7 169/* Nonzero if using Windows. */
dfff8a69 170
1edf84e7
GV
171static int w32_in_use;
172
ee78dc32 173/* Search path for bitmap files. */
dfff8a69 174
ee78dc32
GV
175Lisp_Object Vx_bitmap_file_path;
176
4587b026 177/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 178
4587b026
GV
179Lisp_Object Vx_pixel_size_width_font_regexp;
180
33d52f9c
GV
181/* Alist of bdf fonts and the files that define them. */
182Lisp_Object Vw32_bdf_filename_alist;
183
f46e6225 184/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
185int w32_strict_fontnames;
186
c0611964
AI
187/* A flag to control whether we should only repaint if GetUpdateRect
188 indicates there is an update region. */
189int w32_strict_painting;
190
dfff8a69
JR
191/* Associative list linking character set strings to Windows codepages. */
192Lisp_Object Vw32_charset_info_alist;
193
194/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
195#ifndef VIETNAMESE_CHARSET
196#define VIETNAMESE_CHARSET 163
197#endif
198
ee78dc32
GV
199Lisp_Object Qauto_raise;
200Lisp_Object Qauto_lower;
ee78dc32
GV
201Lisp_Object Qbar;
202Lisp_Object Qborder_color;
203Lisp_Object Qborder_width;
204Lisp_Object Qbox;
205Lisp_Object Qcursor_color;
206Lisp_Object Qcursor_type;
ee78dc32
GV
207Lisp_Object Qgeometry;
208Lisp_Object Qicon_left;
209Lisp_Object Qicon_top;
210Lisp_Object Qicon_type;
211Lisp_Object Qicon_name;
212Lisp_Object Qinternal_border_width;
213Lisp_Object Qleft;
1026b400 214Lisp_Object Qright;
ee78dc32
GV
215Lisp_Object Qmouse_color;
216Lisp_Object Qnone;
217Lisp_Object Qparent_id;
218Lisp_Object Qscroll_bar_width;
219Lisp_Object Qsuppress_icon;
ee78dc32
GV
220Lisp_Object Qundefined_color;
221Lisp_Object Qvertical_scroll_bars;
222Lisp_Object Qvisibility;
223Lisp_Object Qwindow_id;
224Lisp_Object Qx_frame_parameter;
225Lisp_Object Qx_resource_name;
226Lisp_Object Quser_position;
227Lisp_Object Quser_size;
6fc2811b 228Lisp_Object Qscreen_gamma;
dfff8a69
JR
229Lisp_Object Qline_spacing;
230Lisp_Object Qcenter;
dc220243 231Lisp_Object Qcancel_timer;
adcc3809
GV
232Lisp_Object Qhyper;
233Lisp_Object Qsuper;
234Lisp_Object Qmeta;
235Lisp_Object Qalt;
236Lisp_Object Qctrl;
237Lisp_Object Qcontrol;
238Lisp_Object Qshift;
239
dfff8a69
JR
240Lisp_Object Qw32_charset_ansi;
241Lisp_Object Qw32_charset_default;
242Lisp_Object Qw32_charset_symbol;
243Lisp_Object Qw32_charset_shiftjis;
767b1ff0 244Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
245Lisp_Object Qw32_charset_gb2312;
246Lisp_Object Qw32_charset_chinesebig5;
247Lisp_Object Qw32_charset_oem;
248
71eab8d1
AI
249#ifndef JOHAB_CHARSET
250#define JOHAB_CHARSET 130
251#endif
dfff8a69
JR
252#ifdef JOHAB_CHARSET
253Lisp_Object Qw32_charset_easteurope;
254Lisp_Object Qw32_charset_turkish;
255Lisp_Object Qw32_charset_baltic;
256Lisp_Object Qw32_charset_russian;
257Lisp_Object Qw32_charset_arabic;
258Lisp_Object Qw32_charset_greek;
259Lisp_Object Qw32_charset_hebrew;
767b1ff0 260Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
261Lisp_Object Qw32_charset_thai;
262Lisp_Object Qw32_charset_johab;
263Lisp_Object Qw32_charset_mac;
264#endif
265
266#ifdef UNICODE_CHARSET
267Lisp_Object Qw32_charset_unicode;
268#endif
269
6fc2811b
JR
270extern Lisp_Object Qtop;
271extern Lisp_Object Qdisplay;
272extern Lisp_Object Qtool_bar_lines;
273
5ac45f98
GV
274/* State variables for emulating a three button mouse. */
275#define LMOUSE 1
276#define MMOUSE 2
277#define RMOUSE 4
278
279static int button_state = 0;
fbd6baed 280static W32Msg saved_mouse_button_msg;
84fb1139 281static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 282static W32Msg saved_mouse_move_msg;
84fb1139
KH
283static unsigned mouse_move_timer;
284
9eb16b62
JR
285/* Window that is tracking the mouse. */
286static HWND track_mouse_window;
287FARPROC track_mouse_event_fn;
288
93fbe8b7
GV
289/* W95 mousewheel handler */
290unsigned int msh_mousewheel = 0;
291
84fb1139
KH
292#define MOUSE_BUTTON_ID 1
293#define MOUSE_MOVE_ID 2
5ac45f98 294
ee78dc32 295/* The below are defined in frame.c. */
dfff8a69 296
ee78dc32 297extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 298extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 299extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
300
301extern Lisp_Object Vwindow_system_version;
302
4b817373
RS
303Lisp_Object Qface_set_after_frame_default;
304
937e601e
AI
305#ifdef GLYPH_DEBUG
306int image_cache_refcount, dpyinfo_refcount;
307#endif
308
309
fbd6baed
GV
310/* From w32term.c. */
311extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 312extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 313
65906840
JR
314extern HWND w32_system_caret_hwnd;
315extern int w32_system_caret_width;
316extern int w32_system_caret_height;
317extern int w32_system_caret_x;
318extern int w32_system_caret_y;
319
ee78dc32 320\f
1edf84e7
GV
321/* Error if we are not connected to MS-Windows. */
322void
323check_w32 ()
324{
325 if (! w32_in_use)
326 error ("MS-Windows not in use or not initialized");
327}
328
329/* Nonzero if we can use mouse menus.
330 You should not call this unless HAVE_MENUS is defined. */
331
332int
333have_menus_p ()
334{
335 return w32_in_use;
336}
337
ee78dc32 338/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 339 and checking validity for W32. */
ee78dc32
GV
340
341FRAME_PTR
342check_x_frame (frame)
343 Lisp_Object frame;
344{
345 FRAME_PTR f;
346
347 if (NILP (frame))
6fc2811b 348 frame = selected_frame;
b7826503 349 CHECK_LIVE_FRAME (frame);
6fc2811b 350 f = XFRAME (frame);
fbd6baed
GV
351 if (! FRAME_W32_P (f))
352 error ("non-w32 frame used");
ee78dc32
GV
353 return f;
354}
355
356/* Let the user specify an display with a frame.
fbd6baed 357 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
358 the first display on the list. */
359
fbd6baed 360static struct w32_display_info *
ee78dc32
GV
361check_x_display_info (frame)
362 Lisp_Object frame;
363{
364 if (NILP (frame))
365 {
6fc2811b
JR
366 struct frame *sf = XFRAME (selected_frame);
367
368 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
369 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 370 else
fbd6baed 371 return &one_w32_display_info;
ee78dc32
GV
372 }
373 else if (STRINGP (frame))
374 return x_display_info_for_name (frame);
375 else
376 {
377 FRAME_PTR f;
378
b7826503 379 CHECK_LIVE_FRAME (frame);
ee78dc32 380 f = XFRAME (frame);
fbd6baed
GV
381 if (! FRAME_W32_P (f))
382 error ("non-w32 frame used");
383 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
384 }
385}
386\f
fbd6baed 387/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
388 It could be the frame's main window or an icon window. */
389
390/* This function can be called during GC, so use GC_xxx type test macros. */
391
392struct frame *
393x_window_to_frame (dpyinfo, wdesc)
fbd6baed 394 struct w32_display_info *dpyinfo;
ee78dc32
GV
395 HWND wdesc;
396{
397 Lisp_Object tail, frame;
398 struct frame *f;
399
8e713be6 400 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 401 {
8e713be6 402 frame = XCAR (tail);
ee78dc32
GV
403 if (!GC_FRAMEP (frame))
404 continue;
405 f = XFRAME (frame);
2d764c78 406 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 407 continue;
0af913d7 408 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
409 return f;
410
fbd6baed 411 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
412 return f;
413 }
414 return 0;
415}
416
417\f
418
419/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
420 id, which is just an int that this section returns. Bitmaps are
421 reference counted so they can be shared among frames.
422
423 Bitmap indices are guaranteed to be > 0, so a negative number can
424 be used to indicate no bitmap.
425
426 If you use x_create_bitmap_from_data, then you must keep track of
427 the bitmaps yourself. That is, creating a bitmap from the same
428 data more than once will not be caught. */
429
430
431/* Functions to access the contents of a bitmap, given an id. */
432
433int
434x_bitmap_height (f, id)
435 FRAME_PTR f;
436 int id;
437{
fbd6baed 438 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
439}
440
441int
442x_bitmap_width (f, id)
443 FRAME_PTR f;
444 int id;
445{
fbd6baed 446 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
447}
448
449int
450x_bitmap_pixmap (f, id)
451 FRAME_PTR f;
452 int id;
453{
fbd6baed 454 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
455}
456
457
458/* Allocate a new bitmap record. Returns index of new record. */
459
460static int
461x_allocate_bitmap_record (f)
462 FRAME_PTR f;
463{
fbd6baed 464 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
465 int i;
466
467 if (dpyinfo->bitmaps == NULL)
468 {
469 dpyinfo->bitmaps_size = 10;
470 dpyinfo->bitmaps
fbd6baed 471 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
472 dpyinfo->bitmaps_last = 1;
473 return 1;
474 }
475
476 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
477 return ++dpyinfo->bitmaps_last;
478
479 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
480 if (dpyinfo->bitmaps[i].refcount == 0)
481 return i + 1;
482
483 dpyinfo->bitmaps_size *= 2;
484 dpyinfo->bitmaps
fbd6baed
GV
485 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
486 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
487 return ++dpyinfo->bitmaps_last;
488}
489
490/* Add one reference to the reference count of the bitmap with id ID. */
491
492void
493x_reference_bitmap (f, id)
494 FRAME_PTR f;
495 int id;
496{
fbd6baed 497 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
498}
499
500/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
501
502int
503x_create_bitmap_from_data (f, bits, width, height)
504 struct frame *f;
505 char *bits;
506 unsigned int width, height;
507{
fbd6baed 508 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
509 Pixmap bitmap;
510 int id;
511
512 bitmap = CreateBitmap (width, height,
fbd6baed
GV
513 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
514 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
515 bits);
516
517 if (! bitmap)
518 return -1;
519
520 id = x_allocate_bitmap_record (f);
521 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
522 dpyinfo->bitmaps[id - 1].file = NULL;
523 dpyinfo->bitmaps[id - 1].hinst = NULL;
524 dpyinfo->bitmaps[id - 1].refcount = 1;
525 dpyinfo->bitmaps[id - 1].depth = 1;
526 dpyinfo->bitmaps[id - 1].height = height;
527 dpyinfo->bitmaps[id - 1].width = width;
528
529 return id;
530}
531
532/* Create bitmap from file FILE for frame F. */
533
534int
535x_create_bitmap_from_file (f, file)
536 struct frame *f;
537 Lisp_Object file;
538{
539 return -1;
767b1ff0 540#if 0 /* TODO : bitmap support */
fbd6baed 541 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 542 unsigned int width, height;
6fc2811b 543 HBITMAP bitmap;
ee78dc32
GV
544 int xhot, yhot, result, id;
545 Lisp_Object found;
546 int fd;
547 char *filename;
548 HINSTANCE hinst;
549
550 /* Look for an existing bitmap with the same name. */
551 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
552 {
553 if (dpyinfo->bitmaps[id].refcount
554 && dpyinfo->bitmaps[id].file
555 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
556 {
557 ++dpyinfo->bitmaps[id].refcount;
558 return id + 1;
559 }
560 }
561
562 /* Search bitmap-file-path for the file, if appropriate. */
c0ec53ad 563 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
ee78dc32
GV
564 if (fd < 0)
565 return -1;
6fc2811b 566 emacs_close (fd);
ee78dc32
GV
567
568 filename = (char *) XSTRING (found)->data;
569
570 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
571
572 if (hinst == NULL)
573 return -1;
574
575
fbd6baed 576 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
577 filename, &width, &height, &bitmap, &xhot, &yhot);
578 if (result != BitmapSuccess)
579 return -1;
580
581 id = x_allocate_bitmap_record (f);
582 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
583 dpyinfo->bitmaps[id - 1].refcount = 1;
584 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
585 dpyinfo->bitmaps[id - 1].depth = 1;
586 dpyinfo->bitmaps[id - 1].height = height;
587 dpyinfo->bitmaps[id - 1].width = width;
588 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
589
590 return id;
767b1ff0 591#endif /* TODO */
ee78dc32
GV
592}
593
594/* Remove reference to bitmap with id number ID. */
595
33d52f9c 596void
ee78dc32
GV
597x_destroy_bitmap (f, id)
598 FRAME_PTR f;
599 int id;
600{
fbd6baed 601 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
602
603 if (id > 0)
604 {
605 --dpyinfo->bitmaps[id - 1].refcount;
606 if (dpyinfo->bitmaps[id - 1].refcount == 0)
607 {
608 BLOCK_INPUT;
609 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
610 if (dpyinfo->bitmaps[id - 1].file)
611 {
6fc2811b 612 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
613 dpyinfo->bitmaps[id - 1].file = NULL;
614 }
615 UNBLOCK_INPUT;
616 }
617 }
618}
619
620/* Free all the bitmaps for the display specified by DPYINFO. */
621
622static void
623x_destroy_all_bitmaps (dpyinfo)
fbd6baed 624 struct w32_display_info *dpyinfo;
ee78dc32
GV
625{
626 int i;
627 for (i = 0; i < dpyinfo->bitmaps_last; i++)
628 if (dpyinfo->bitmaps[i].refcount > 0)
629 {
630 DeleteObject (dpyinfo->bitmaps[i].pixmap);
631 if (dpyinfo->bitmaps[i].file)
6fc2811b 632 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
633 }
634 dpyinfo->bitmaps_last = 0;
635}
636\f
fbd6baed 637/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
638 to the ways of passing the parameter values to the window system.
639
640 The name of a parameter, as a Lisp symbol,
641 has an `x-frame-parameter' property which is an integer in Lisp
642 but can be interpreted as an `enum x_frame_parm' in C. */
643
644enum x_frame_parm
645{
646 X_PARM_FOREGROUND_COLOR,
647 X_PARM_BACKGROUND_COLOR,
648 X_PARM_MOUSE_COLOR,
649 X_PARM_CURSOR_COLOR,
650 X_PARM_BORDER_COLOR,
651 X_PARM_ICON_TYPE,
652 X_PARM_FONT,
653 X_PARM_BORDER_WIDTH,
654 X_PARM_INTERNAL_BORDER_WIDTH,
655 X_PARM_NAME,
656 X_PARM_AUTORAISE,
657 X_PARM_AUTOLOWER,
658 X_PARM_VERT_SCROLL_BAR,
659 X_PARM_VISIBILITY,
660 X_PARM_MENU_BAR_LINES
661};
662
663
664struct x_frame_parm_table
665{
666 char *name;
6fc2811b 667 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
668};
669
ca56d953
JR
670BOOL my_show_window P_ ((struct frame *, HWND, int));
671void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
672static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
673static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
674static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 675/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 676void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 677static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
678void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
679void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
680void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
681void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
682void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
683void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
684void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
685void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 686static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
687void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
688void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
689 Lisp_Object));
690void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
691void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
692void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
693void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
694 Lisp_Object));
695void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
698void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
701static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
702static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
703 Lisp_Object));
ee78dc32
GV
704
705static struct x_frame_parm_table x_frame_parms[] =
706{
1edf84e7
GV
707 "auto-raise", x_set_autoraise,
708 "auto-lower", x_set_autolower,
ee78dc32 709 "background-color", x_set_background_color,
ee78dc32 710 "border-color", x_set_border_color,
1edf84e7
GV
711 "border-width", x_set_border_width,
712 "cursor-color", x_set_cursor_color,
ee78dc32 713 "cursor-type", x_set_cursor_type,
ee78dc32 714 "font", x_set_font,
1edf84e7
GV
715 "foreground-color", x_set_foreground_color,
716 "icon-name", x_set_icon_name,
717 "icon-type", x_set_icon_type,
ee78dc32 718 "internal-border-width", x_set_internal_border_width,
ee78dc32 719 "menu-bar-lines", x_set_menu_bar_lines,
1edf84e7
GV
720 "mouse-color", x_set_mouse_color,
721 "name", x_explicitly_set_name,
ee78dc32 722 "scroll-bar-width", x_set_scroll_bar_width,
1edf84e7 723 "title", x_set_title,
ee78dc32 724 "unsplittable", x_set_unsplittable,
1edf84e7
GV
725 "vertical-scroll-bars", x_set_vertical_scroll_bars,
726 "visibility", x_set_visibility,
6fc2811b 727 "tool-bar-lines", x_set_tool_bar_lines,
dfff8a69 728 "screen-gamma", x_set_screen_gamma,
41c1bdd9
KS
729 "line-spacing", x_set_line_spacing,
730 "left-fringe", x_set_fringe_width,
731 "right-fringe", x_set_fringe_width
732
ee78dc32
GV
733};
734
735/* Attach the `x-frame-parameter' properties to
fbd6baed 736 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 737
dfff8a69 738void
ee78dc32
GV
739init_x_parm_symbols ()
740{
741 int i;
742
743 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
744 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
745 make_number (i));
746}
747\f
dfff8a69 748/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
749 If a parameter is not specially recognized, do nothing;
750 otherwise call the `x_set_...' function for that parameter. */
751
752void
753x_set_frame_parameters (f, alist)
754 FRAME_PTR f;
755 Lisp_Object alist;
756{
757 Lisp_Object tail;
758
759 /* If both of these parameters are present, it's more efficient to
760 set them both at once. So we wait until we've looked at the
761 entire list before we set them. */
b839712d 762 int width, height;
ee78dc32
GV
763
764 /* Same here. */
765 Lisp_Object left, top;
766
767 /* Same with these. */
768 Lisp_Object icon_left, icon_top;
769
770 /* Record in these vectors all the parms specified. */
771 Lisp_Object *parms;
772 Lisp_Object *values;
a797a73d 773 int i, p;
ee78dc32
GV
774 int left_no_change = 0, top_no_change = 0;
775 int icon_left_no_change = 0, icon_top_no_change = 0;
776
5878523b
RS
777 struct gcpro gcpro1, gcpro2;
778
ee78dc32
GV
779 i = 0;
780 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
781 i++;
782
783 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
784 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
785
786 /* Extract parm names and values into those vectors. */
787
788 i = 0;
789 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
790 {
6fc2811b 791 Lisp_Object elt;
ee78dc32
GV
792
793 elt = Fcar (tail);
794 parms[i] = Fcar (elt);
795 values[i] = Fcdr (elt);
796 i++;
797 }
5878523b
RS
798 /* TAIL and ALIST are not used again below here. */
799 alist = tail = Qnil;
800
801 GCPRO2 (*parms, *values);
802 gcpro1.nvars = i;
803 gcpro2.nvars = i;
804
805 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
806 because their values appear in VALUES and strings are not valid. */
b839712d 807 top = left = Qunbound;
ee78dc32
GV
808 icon_left = icon_top = Qunbound;
809
b839712d 810 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
811 if (FRAME_NEW_WIDTH (f))
812 width = FRAME_NEW_WIDTH (f);
813 else
814 width = FRAME_WIDTH (f);
815
816 if (FRAME_NEW_HEIGHT (f))
817 height = FRAME_NEW_HEIGHT (f);
818 else
819 height = FRAME_HEIGHT (f);
b839712d 820
a797a73d
GV
821 /* Process foreground_color and background_color before anything else.
822 They are independent of other properties, but other properties (e.g.,
823 cursor_color) are dependent upon them. */
41c1bdd9 824 /* Process default font as well, since fringe widths depends on it. */
a797a73d
GV
825 for (p = 0; p < i; p++)
826 {
827 Lisp_Object prop, val;
828
829 prop = parms[p];
830 val = values[p];
41c1bdd9
KS
831 if (EQ (prop, Qforeground_color)
832 || EQ (prop, Qbackground_color)
833 || EQ (prop, Qfont))
a797a73d
GV
834 {
835 register Lisp_Object param_index, old_value;
836
a797a73d 837 old_value = get_frame_param (f, prop);
a05e2bae
JR
838
839 if (NILP (Fequal (val, old_value)))
840 {
841 store_frame_param (f, prop, val);
842
843 param_index = Fget (prop, Qx_frame_parameter);
844 if (NATNUMP (param_index)
845 && (XFASTINT (param_index)
846 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
847 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
848 }
a797a73d
GV
849 }
850 }
851
ee78dc32
GV
852 /* Now process them in reverse of specified order. */
853 for (i--; i >= 0; i--)
854 {
855 Lisp_Object prop, val;
856
857 prop = parms[i];
858 val = values[i];
859
b839712d
RS
860 if (EQ (prop, Qwidth) && NUMBERP (val))
861 width = XFASTINT (val);
862 else if (EQ (prop, Qheight) && NUMBERP (val))
863 height = XFASTINT (val);
ee78dc32
GV
864 else if (EQ (prop, Qtop))
865 top = val;
866 else if (EQ (prop, Qleft))
867 left = val;
868 else if (EQ (prop, Qicon_top))
869 icon_top = val;
870 else if (EQ (prop, Qicon_left))
871 icon_left = val;
41c1bdd9
KS
872 else if (EQ (prop, Qforeground_color)
873 || EQ (prop, Qbackground_color)
874 || EQ (prop, Qfont))
a797a73d
GV
875 /* Processed above. */
876 continue;
ee78dc32
GV
877 else
878 {
879 register Lisp_Object param_index, old_value;
880
ee78dc32 881 old_value = get_frame_param (f, prop);
a05e2bae 882
ee78dc32 883 store_frame_param (f, prop, val);
a05e2bae
JR
884
885 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
886 if (NATNUMP (param_index)
887 && (XFASTINT (param_index)
888 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 889 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
890 }
891 }
892
893 /* Don't die if just one of these was set. */
894 if (EQ (left, Qunbound))
895 {
896 left_no_change = 1;
fbd6baed
GV
897 if (f->output_data.w32->left_pos < 0)
898 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 899 else
fbd6baed 900 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
901 }
902 if (EQ (top, Qunbound))
903 {
904 top_no_change = 1;
fbd6baed
GV
905 if (f->output_data.w32->top_pos < 0)
906 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 907 else
fbd6baed 908 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
909 }
910
911 /* If one of the icon positions was not set, preserve or default it. */
912 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
913 {
914 icon_left_no_change = 1;
915 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
916 if (NILP (icon_left))
917 XSETINT (icon_left, 0);
918 }
919 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
920 {
921 icon_top_no_change = 1;
922 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
923 if (NILP (icon_top))
924 XSETINT (icon_top, 0);
925 }
926
ee78dc32
GV
927 /* Don't set these parameters unless they've been explicitly
928 specified. The window might be mapped or resized while we're in
929 this function, and we don't want to override that unless the lisp
930 code has asked for it.
931
932 Don't set these parameters unless they actually differ from the
933 window's current parameters; the window may not actually exist
934 yet. */
935 {
936 Lisp_Object frame;
937
938 check_frame_size (f, &height, &width);
939
940 XSETFRAME (frame, f);
941
dfff8a69
JR
942 if (width != FRAME_WIDTH (f)
943 || height != FRAME_HEIGHT (f)
944 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 945 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
946
947 if ((!NILP (left) || !NILP (top))
948 && ! (left_no_change && top_no_change)
fbd6baed
GV
949 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
950 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
951 {
952 int leftpos = 0;
953 int toppos = 0;
954
955 /* Record the signs. */
fbd6baed 956 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 957 if (EQ (left, Qminus))
fbd6baed 958 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
959 else if (INTEGERP (left))
960 {
961 leftpos = XINT (left);
962 if (leftpos < 0)
fbd6baed 963 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 964 }
8e713be6
KR
965 else if (CONSP (left) && EQ (XCAR (left), Qminus)
966 && CONSP (XCDR (left))
967 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 968 {
8e713be6 969 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 970 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 971 }
8e713be6
KR
972 else if (CONSP (left) && EQ (XCAR (left), Qplus)
973 && CONSP (XCDR (left))
974 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 975 {
8e713be6 976 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
977 }
978
979 if (EQ (top, Qminus))
fbd6baed 980 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
981 else if (INTEGERP (top))
982 {
983 toppos = XINT (top);
984 if (toppos < 0)
fbd6baed 985 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 986 }
8e713be6
KR
987 else if (CONSP (top) && EQ (XCAR (top), Qminus)
988 && CONSP (XCDR (top))
989 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 990 {
8e713be6 991 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 992 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 993 }
8e713be6
KR
994 else if (CONSP (top) && EQ (XCAR (top), Qplus)
995 && CONSP (XCDR (top))
996 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 997 {
8e713be6 998 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
999 }
1000
1001
1002 /* Store the numeric value of the position. */
fbd6baed
GV
1003 f->output_data.w32->top_pos = toppos;
1004 f->output_data.w32->left_pos = leftpos;
ee78dc32 1005
fbd6baed 1006 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1007
1008 /* Actually set that position, and convert to absolute. */
1009 x_set_offset (f, leftpos, toppos, -1);
1010 }
1011
1012 if ((!NILP (icon_left) || !NILP (icon_top))
1013 && ! (icon_left_no_change && icon_top_no_change))
1014 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1015 }
5878523b
RS
1016
1017 UNGCPRO;
ee78dc32
GV
1018}
1019
1020/* Store the screen positions of frame F into XPTR and YPTR.
1021 These are the positions of the containing window manager window,
1022 not Emacs's own window. */
1023
1024void
1025x_real_positions (f, xptr, yptr)
1026 FRAME_PTR f;
1027 int *xptr, *yptr;
1028{
1029 POINT pt;
3c190163
GV
1030
1031 {
1032 RECT rect;
ee78dc32 1033
fbd6baed
GV
1034 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1035 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 1036
3c190163
GV
1037 pt.x = rect.left;
1038 pt.y = rect.top;
1039 }
ee78dc32 1040
fbd6baed 1041 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
1042
1043 *xptr = pt.x;
1044 *yptr = pt.y;
1045}
1046
1047/* Insert a description of internally-recorded parameters of frame X
1048 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1049 Only parameters that are specific to W32
ee78dc32
GV
1050 and whose values are not correctly recorded in the frame's
1051 param_alist need to be considered here. */
1052
dfff8a69 1053void
ee78dc32
GV
1054x_report_frame_params (f, alistptr)
1055 struct frame *f;
1056 Lisp_Object *alistptr;
1057{
1058 char buf[16];
1059 Lisp_Object tem;
1060
1061 /* Represent negative positions (off the top or left screen edge)
1062 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1063 XSETINT (tem, f->output_data.w32->left_pos);
1064 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1065 store_in_alist (alistptr, Qleft, tem);
1066 else
1067 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1068
fbd6baed
GV
1069 XSETINT (tem, f->output_data.w32->top_pos);
1070 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1071 store_in_alist (alistptr, Qtop, tem);
1072 else
1073 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1074
1075 store_in_alist (alistptr, Qborder_width,
fbd6baed 1076 make_number (f->output_data.w32->border_width));
ee78dc32 1077 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1078 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1079 store_in_alist (alistptr, Qleft_fringe,
1080 make_number (f->output_data.w32->left_fringe_width));
1081 store_in_alist (alistptr, Qright_fringe,
1082 make_number (f->output_data.w32->right_fringe_width));
fbd6baed 1083 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1084 store_in_alist (alistptr, Qwindow_id,
1085 build_string (buf));
1086 store_in_alist (alistptr, Qicon_name, f->icon_name);
1087 FRAME_SAMPLE_VISIBILITY (f);
1088 store_in_alist (alistptr, Qvisibility,
1089 (FRAME_VISIBLE_P (f) ? Qt
1090 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1091 store_in_alist (alistptr, Qdisplay,
8e713be6 1092 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1093}
1094\f
1095
74e1aeec
JR
1096DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1097 Sw32_define_rgb_color, 4, 4, 0,
1098 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1099This adds or updates a named color to w32-color-map, making it
1100available for use. The original entry's RGB ref is returned, or nil
1101if the entry is new. */)
5ac45f98
GV
1102 (red, green, blue, name)
1103 Lisp_Object red, green, blue, name;
ee78dc32 1104{
5ac45f98
GV
1105 Lisp_Object rgb;
1106 Lisp_Object oldrgb = Qnil;
1107 Lisp_Object entry;
1108
b7826503
PJ
1109 CHECK_NUMBER (red);
1110 CHECK_NUMBER (green);
1111 CHECK_NUMBER (blue);
1112 CHECK_STRING (name);
ee78dc32 1113
5ac45f98 1114 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1115
5ac45f98 1116 BLOCK_INPUT;
ee78dc32 1117
fbd6baed
GV
1118 /* replace existing entry in w32-color-map or add new entry. */
1119 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1120 if (NILP (entry))
1121 {
1122 entry = Fcons (name, rgb);
fbd6baed 1123 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1124 }
1125 else
1126 {
1127 oldrgb = Fcdr (entry);
1128 Fsetcdr (entry, rgb);
1129 }
1130
1131 UNBLOCK_INPUT;
1132
1133 return (oldrgb);
ee78dc32
GV
1134}
1135
74e1aeec
JR
1136DEFUN ("w32-load-color-file", Fw32_load_color_file,
1137 Sw32_load_color_file, 1, 1, 0,
1138 doc: /* Create an alist of color entries from an external file.
1139Assign this value to w32-color-map to replace the existing color map.
1140
1141The file should define one named RGB color per line like so:
1142 R G B name
1143where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1144 (filename)
1145 Lisp_Object filename;
1146{
1147 FILE *fp;
1148 Lisp_Object cmap = Qnil;
1149 Lisp_Object abspath;
1150
b7826503 1151 CHECK_STRING (filename);
5ac45f98
GV
1152 abspath = Fexpand_file_name (filename, Qnil);
1153
1154 fp = fopen (XSTRING (filename)->data, "rt");
1155 if (fp)
1156 {
1157 char buf[512];
1158 int red, green, blue;
1159 int num;
1160
1161 BLOCK_INPUT;
1162
1163 while (fgets (buf, sizeof (buf), fp) != NULL) {
1164 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1165 {
1166 char *name = buf + num;
1167 num = strlen (name) - 1;
1168 if (name[num] == '\n')
1169 name[num] = 0;
1170 cmap = Fcons (Fcons (build_string (name),
1171 make_number (RGB (red, green, blue))),
1172 cmap);
1173 }
1174 }
1175 fclose (fp);
1176
1177 UNBLOCK_INPUT;
1178 }
1179
1180 return cmap;
1181}
ee78dc32 1182
fbd6baed 1183/* The default colors for the w32 color map */
ee78dc32
GV
1184typedef struct colormap_t
1185{
1186 char *name;
1187 COLORREF colorref;
1188} colormap_t;
1189
fbd6baed 1190colormap_t w32_color_map[] =
ee78dc32 1191{
1da8a614
GV
1192 {"snow" , PALETTERGB (255,250,250)},
1193 {"ghost white" , PALETTERGB (248,248,255)},
1194 {"GhostWhite" , PALETTERGB (248,248,255)},
1195 {"white smoke" , PALETTERGB (245,245,245)},
1196 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1197 {"gainsboro" , PALETTERGB (220,220,220)},
1198 {"floral white" , PALETTERGB (255,250,240)},
1199 {"FloralWhite" , PALETTERGB (255,250,240)},
1200 {"old lace" , PALETTERGB (253,245,230)},
1201 {"OldLace" , PALETTERGB (253,245,230)},
1202 {"linen" , PALETTERGB (250,240,230)},
1203 {"antique white" , PALETTERGB (250,235,215)},
1204 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1205 {"papaya whip" , PALETTERGB (255,239,213)},
1206 {"PapayaWhip" , PALETTERGB (255,239,213)},
1207 {"blanched almond" , PALETTERGB (255,235,205)},
1208 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1209 {"bisque" , PALETTERGB (255,228,196)},
1210 {"peach puff" , PALETTERGB (255,218,185)},
1211 {"PeachPuff" , PALETTERGB (255,218,185)},
1212 {"navajo white" , PALETTERGB (255,222,173)},
1213 {"NavajoWhite" , PALETTERGB (255,222,173)},
1214 {"moccasin" , PALETTERGB (255,228,181)},
1215 {"cornsilk" , PALETTERGB (255,248,220)},
1216 {"ivory" , PALETTERGB (255,255,240)},
1217 {"lemon chiffon" , PALETTERGB (255,250,205)},
1218 {"LemonChiffon" , PALETTERGB (255,250,205)},
1219 {"seashell" , PALETTERGB (255,245,238)},
1220 {"honeydew" , PALETTERGB (240,255,240)},
1221 {"mint cream" , PALETTERGB (245,255,250)},
1222 {"MintCream" , PALETTERGB (245,255,250)},
1223 {"azure" , PALETTERGB (240,255,255)},
1224 {"alice blue" , PALETTERGB (240,248,255)},
1225 {"AliceBlue" , PALETTERGB (240,248,255)},
1226 {"lavender" , PALETTERGB (230,230,250)},
1227 {"lavender blush" , PALETTERGB (255,240,245)},
1228 {"LavenderBlush" , PALETTERGB (255,240,245)},
1229 {"misty rose" , PALETTERGB (255,228,225)},
1230 {"MistyRose" , PALETTERGB (255,228,225)},
1231 {"white" , PALETTERGB (255,255,255)},
1232 {"black" , PALETTERGB ( 0, 0, 0)},
1233 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1234 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1235 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1236 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1237 {"dim gray" , PALETTERGB (105,105,105)},
1238 {"DimGray" , PALETTERGB (105,105,105)},
1239 {"dim grey" , PALETTERGB (105,105,105)},
1240 {"DimGrey" , PALETTERGB (105,105,105)},
1241 {"slate gray" , PALETTERGB (112,128,144)},
1242 {"SlateGray" , PALETTERGB (112,128,144)},
1243 {"slate grey" , PALETTERGB (112,128,144)},
1244 {"SlateGrey" , PALETTERGB (112,128,144)},
1245 {"light slate gray" , PALETTERGB (119,136,153)},
1246 {"LightSlateGray" , PALETTERGB (119,136,153)},
1247 {"light slate grey" , PALETTERGB (119,136,153)},
1248 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1249 {"gray" , PALETTERGB (190,190,190)},
1250 {"grey" , PALETTERGB (190,190,190)},
1251 {"light grey" , PALETTERGB (211,211,211)},
1252 {"LightGrey" , PALETTERGB (211,211,211)},
1253 {"light gray" , PALETTERGB (211,211,211)},
1254 {"LightGray" , PALETTERGB (211,211,211)},
1255 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1256 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1257 {"navy" , PALETTERGB ( 0, 0,128)},
1258 {"navy blue" , PALETTERGB ( 0, 0,128)},
1259 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1260 {"cornflower blue" , PALETTERGB (100,149,237)},
1261 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1262 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1263 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1264 {"slate blue" , PALETTERGB (106, 90,205)},
1265 {"SlateBlue" , PALETTERGB (106, 90,205)},
1266 {"medium slate blue" , PALETTERGB (123,104,238)},
1267 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1268 {"light slate blue" , PALETTERGB (132,112,255)},
1269 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1270 {"medium blue" , PALETTERGB ( 0, 0,205)},
1271 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1272 {"royal blue" , PALETTERGB ( 65,105,225)},
1273 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1274 {"blue" , PALETTERGB ( 0, 0,255)},
1275 {"dodger blue" , PALETTERGB ( 30,144,255)},
1276 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1277 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1278 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1279 {"sky blue" , PALETTERGB (135,206,235)},
1280 {"SkyBlue" , PALETTERGB (135,206,235)},
1281 {"light sky blue" , PALETTERGB (135,206,250)},
1282 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1283 {"steel blue" , PALETTERGB ( 70,130,180)},
1284 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1285 {"light steel blue" , PALETTERGB (176,196,222)},
1286 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1287 {"light blue" , PALETTERGB (173,216,230)},
1288 {"LightBlue" , PALETTERGB (173,216,230)},
1289 {"powder blue" , PALETTERGB (176,224,230)},
1290 {"PowderBlue" , PALETTERGB (176,224,230)},
1291 {"pale turquoise" , PALETTERGB (175,238,238)},
1292 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1293 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1294 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1295 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1296 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1297 {"turquoise" , PALETTERGB ( 64,224,208)},
1298 {"cyan" , PALETTERGB ( 0,255,255)},
1299 {"light cyan" , PALETTERGB (224,255,255)},
1300 {"LightCyan" , PALETTERGB (224,255,255)},
1301 {"cadet blue" , PALETTERGB ( 95,158,160)},
1302 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1303 {"medium aquamarine" , PALETTERGB (102,205,170)},
1304 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1305 {"aquamarine" , PALETTERGB (127,255,212)},
1306 {"dark green" , PALETTERGB ( 0,100, 0)},
1307 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1308 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1309 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1310 {"dark sea green" , PALETTERGB (143,188,143)},
1311 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1312 {"sea green" , PALETTERGB ( 46,139, 87)},
1313 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1314 {"medium sea green" , PALETTERGB ( 60,179,113)},
1315 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1316 {"light sea green" , PALETTERGB ( 32,178,170)},
1317 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1318 {"pale green" , PALETTERGB (152,251,152)},
1319 {"PaleGreen" , PALETTERGB (152,251,152)},
1320 {"spring green" , PALETTERGB ( 0,255,127)},
1321 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1322 {"lawn green" , PALETTERGB (124,252, 0)},
1323 {"LawnGreen" , PALETTERGB (124,252, 0)},
1324 {"green" , PALETTERGB ( 0,255, 0)},
1325 {"chartreuse" , PALETTERGB (127,255, 0)},
1326 {"medium spring green" , PALETTERGB ( 0,250,154)},
1327 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1328 {"green yellow" , PALETTERGB (173,255, 47)},
1329 {"GreenYellow" , PALETTERGB (173,255, 47)},
1330 {"lime green" , PALETTERGB ( 50,205, 50)},
1331 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1332 {"yellow green" , PALETTERGB (154,205, 50)},
1333 {"YellowGreen" , PALETTERGB (154,205, 50)},
1334 {"forest green" , PALETTERGB ( 34,139, 34)},
1335 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1336 {"olive drab" , PALETTERGB (107,142, 35)},
1337 {"OliveDrab" , PALETTERGB (107,142, 35)},
1338 {"dark khaki" , PALETTERGB (189,183,107)},
1339 {"DarkKhaki" , PALETTERGB (189,183,107)},
1340 {"khaki" , PALETTERGB (240,230,140)},
1341 {"pale goldenrod" , PALETTERGB (238,232,170)},
1342 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1343 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1344 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1345 {"light yellow" , PALETTERGB (255,255,224)},
1346 {"LightYellow" , PALETTERGB (255,255,224)},
1347 {"yellow" , PALETTERGB (255,255, 0)},
1348 {"gold" , PALETTERGB (255,215, 0)},
1349 {"light goldenrod" , PALETTERGB (238,221,130)},
1350 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1351 {"goldenrod" , PALETTERGB (218,165, 32)},
1352 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1353 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1354 {"rosy brown" , PALETTERGB (188,143,143)},
1355 {"RosyBrown" , PALETTERGB (188,143,143)},
1356 {"indian red" , PALETTERGB (205, 92, 92)},
1357 {"IndianRed" , PALETTERGB (205, 92, 92)},
1358 {"saddle brown" , PALETTERGB (139, 69, 19)},
1359 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1360 {"sienna" , PALETTERGB (160, 82, 45)},
1361 {"peru" , PALETTERGB (205,133, 63)},
1362 {"burlywood" , PALETTERGB (222,184,135)},
1363 {"beige" , PALETTERGB (245,245,220)},
1364 {"wheat" , PALETTERGB (245,222,179)},
1365 {"sandy brown" , PALETTERGB (244,164, 96)},
1366 {"SandyBrown" , PALETTERGB (244,164, 96)},
1367 {"tan" , PALETTERGB (210,180,140)},
1368 {"chocolate" , PALETTERGB (210,105, 30)},
1369 {"firebrick" , PALETTERGB (178,34, 34)},
1370 {"brown" , PALETTERGB (165,42, 42)},
1371 {"dark salmon" , PALETTERGB (233,150,122)},
1372 {"DarkSalmon" , PALETTERGB (233,150,122)},
1373 {"salmon" , PALETTERGB (250,128,114)},
1374 {"light salmon" , PALETTERGB (255,160,122)},
1375 {"LightSalmon" , PALETTERGB (255,160,122)},
1376 {"orange" , PALETTERGB (255,165, 0)},
1377 {"dark orange" , PALETTERGB (255,140, 0)},
1378 {"DarkOrange" , PALETTERGB (255,140, 0)},
1379 {"coral" , PALETTERGB (255,127, 80)},
1380 {"light coral" , PALETTERGB (240,128,128)},
1381 {"LightCoral" , PALETTERGB (240,128,128)},
1382 {"tomato" , PALETTERGB (255, 99, 71)},
1383 {"orange red" , PALETTERGB (255, 69, 0)},
1384 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1385 {"red" , PALETTERGB (255, 0, 0)},
1386 {"hot pink" , PALETTERGB (255,105,180)},
1387 {"HotPink" , PALETTERGB (255,105,180)},
1388 {"deep pink" , PALETTERGB (255, 20,147)},
1389 {"DeepPink" , PALETTERGB (255, 20,147)},
1390 {"pink" , PALETTERGB (255,192,203)},
1391 {"light pink" , PALETTERGB (255,182,193)},
1392 {"LightPink" , PALETTERGB (255,182,193)},
1393 {"pale violet red" , PALETTERGB (219,112,147)},
1394 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1395 {"maroon" , PALETTERGB (176, 48, 96)},
1396 {"medium violet red" , PALETTERGB (199, 21,133)},
1397 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1398 {"violet red" , PALETTERGB (208, 32,144)},
1399 {"VioletRed" , PALETTERGB (208, 32,144)},
1400 {"magenta" , PALETTERGB (255, 0,255)},
1401 {"violet" , PALETTERGB (238,130,238)},
1402 {"plum" , PALETTERGB (221,160,221)},
1403 {"orchid" , PALETTERGB (218,112,214)},
1404 {"medium orchid" , PALETTERGB (186, 85,211)},
1405 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1406 {"dark orchid" , PALETTERGB (153, 50,204)},
1407 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1408 {"dark violet" , PALETTERGB (148, 0,211)},
1409 {"DarkViolet" , PALETTERGB (148, 0,211)},
1410 {"blue violet" , PALETTERGB (138, 43,226)},
1411 {"BlueViolet" , PALETTERGB (138, 43,226)},
1412 {"purple" , PALETTERGB (160, 32,240)},
1413 {"medium purple" , PALETTERGB (147,112,219)},
1414 {"MediumPurple" , PALETTERGB (147,112,219)},
1415 {"thistle" , PALETTERGB (216,191,216)},
1416 {"gray0" , PALETTERGB ( 0, 0, 0)},
1417 {"grey0" , PALETTERGB ( 0, 0, 0)},
1418 {"dark grey" , PALETTERGB (169,169,169)},
1419 {"DarkGrey" , PALETTERGB (169,169,169)},
1420 {"dark gray" , PALETTERGB (169,169,169)},
1421 {"DarkGray" , PALETTERGB (169,169,169)},
1422 {"dark blue" , PALETTERGB ( 0, 0,139)},
1423 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1424 {"dark cyan" , PALETTERGB ( 0,139,139)},
1425 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1426 {"dark magenta" , PALETTERGB (139, 0,139)},
1427 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1428 {"dark red" , PALETTERGB (139, 0, 0)},
1429 {"DarkRed" , PALETTERGB (139, 0, 0)},
1430 {"light green" , PALETTERGB (144,238,144)},
1431 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1432};
1433
fbd6baed 1434DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1435 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1436 ()
1437{
1438 int i;
fbd6baed 1439 colormap_t *pc = w32_color_map;
ee78dc32
GV
1440 Lisp_Object cmap;
1441
1442 BLOCK_INPUT;
1443
1444 cmap = Qnil;
1445
fbd6baed 1446 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1447 pc++, i++)
1448 cmap = Fcons (Fcons (build_string (pc->name),
1449 make_number (pc->colorref)),
1450 cmap);
1451
1452 UNBLOCK_INPUT;
1453
1454 return (cmap);
1455}
ee78dc32
GV
1456
1457Lisp_Object
fbd6baed 1458w32_to_x_color (rgb)
ee78dc32
GV
1459 Lisp_Object rgb;
1460{
1461 Lisp_Object color;
1462
b7826503 1463 CHECK_NUMBER (rgb);
ee78dc32
GV
1464
1465 BLOCK_INPUT;
1466
fbd6baed 1467 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1468
1469 UNBLOCK_INPUT;
1470
1471 if (!NILP (color))
1472 return (Fcar (color));
1473 else
1474 return Qnil;
1475}
1476
5d7fed93
GV
1477COLORREF
1478w32_color_map_lookup (colorname)
1479 char *colorname;
1480{
1481 Lisp_Object tail, ret = Qnil;
1482
1483 BLOCK_INPUT;
1484
1485 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1486 {
1487 register Lisp_Object elt, tem;
1488
1489 elt = Fcar (tail);
1490 if (!CONSP (elt)) continue;
1491
1492 tem = Fcar (elt);
1493
1494 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1495 {
1496 ret = XUINT (Fcdr (elt));
1497 break;
1498 }
1499
1500 QUIT;
1501 }
1502
1503
1504 UNBLOCK_INPUT;
1505
1506 return ret;
1507}
1508
ee78dc32 1509COLORREF
fbd6baed 1510x_to_w32_color (colorname)
ee78dc32
GV
1511 char * colorname;
1512{
8edb0a6f
JR
1513 register Lisp_Object ret = Qnil;
1514
ee78dc32 1515 BLOCK_INPUT;
1edf84e7
GV
1516
1517 if (colorname[0] == '#')
1518 {
1519 /* Could be an old-style RGB Device specification. */
1520 char *color;
1521 int size;
1522 color = colorname + 1;
1523
1524 size = strlen(color);
1525 if (size == 3 || size == 6 || size == 9 || size == 12)
1526 {
1527 UINT colorval;
1528 int i, pos;
1529 pos = 0;
1530 size /= 3;
1531 colorval = 0;
1532
1533 for (i = 0; i < 3; i++)
1534 {
1535 char *end;
1536 char t;
1537 unsigned long value;
1538
1539 /* The check for 'x' in the following conditional takes into
1540 account the fact that strtol allows a "0x" in front of
1541 our numbers, and we don't. */
1542 if (!isxdigit(color[0]) || color[1] == 'x')
1543 break;
1544 t = color[size];
1545 color[size] = '\0';
1546 value = strtoul(color, &end, 16);
1547 color[size] = t;
1548 if (errno == ERANGE || end - color != size)
1549 break;
1550 switch (size)
1551 {
1552 case 1:
1553 value = value * 0x10;
1554 break;
1555 case 2:
1556 break;
1557 case 3:
1558 value /= 0x10;
1559 break;
1560 case 4:
1561 value /= 0x100;
1562 break;
1563 }
1564 colorval |= (value << pos);
1565 pos += 0x8;
1566 if (i == 2)
1567 {
1568 UNBLOCK_INPUT;
1569 return (colorval);
1570 }
1571 color = end;
1572 }
1573 }
1574 }
1575 else if (strnicmp(colorname, "rgb:", 4) == 0)
1576 {
1577 char *color;
1578 UINT colorval;
1579 int i, pos;
1580 pos = 0;
1581
1582 colorval = 0;
1583 color = colorname + 4;
1584 for (i = 0; i < 3; i++)
1585 {
1586 char *end;
1587 unsigned long value;
1588
1589 /* The check for 'x' in the following conditional takes into
1590 account the fact that strtol allows a "0x" in front of
1591 our numbers, and we don't. */
1592 if (!isxdigit(color[0]) || color[1] == 'x')
1593 break;
1594 value = strtoul(color, &end, 16);
1595 if (errno == ERANGE)
1596 break;
1597 switch (end - color)
1598 {
1599 case 1:
1600 value = value * 0x10 + value;
1601 break;
1602 case 2:
1603 break;
1604 case 3:
1605 value /= 0x10;
1606 break;
1607 case 4:
1608 value /= 0x100;
1609 break;
1610 default:
1611 value = ULONG_MAX;
1612 }
1613 if (value == ULONG_MAX)
1614 break;
1615 colorval |= (value << pos);
1616 pos += 0x8;
1617 if (i == 2)
1618 {
1619 if (*end != '\0')
1620 break;
1621 UNBLOCK_INPUT;
1622 return (colorval);
1623 }
1624 if (*end != '/')
1625 break;
1626 color = end + 1;
1627 }
1628 }
1629 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1630 {
1631 /* This is an RGB Intensity specification. */
1632 char *color;
1633 UINT colorval;
1634 int i, pos;
1635 pos = 0;
1636
1637 colorval = 0;
1638 color = colorname + 5;
1639 for (i = 0; i < 3; i++)
1640 {
1641 char *end;
1642 double value;
1643 UINT val;
1644
1645 value = strtod(color, &end);
1646 if (errno == ERANGE)
1647 break;
1648 if (value < 0.0 || value > 1.0)
1649 break;
1650 val = (UINT)(0x100 * value);
1651 /* We used 0x100 instead of 0xFF to give an continuous
1652 range between 0.0 and 1.0 inclusive. The next statement
1653 fixes the 1.0 case. */
1654 if (val == 0x100)
1655 val = 0xFF;
1656 colorval |= (val << pos);
1657 pos += 0x8;
1658 if (i == 2)
1659 {
1660 if (*end != '\0')
1661 break;
1662 UNBLOCK_INPUT;
1663 return (colorval);
1664 }
1665 if (*end != '/')
1666 break;
1667 color = end + 1;
1668 }
1669 }
1670 /* I am not going to attempt to handle any of the CIE color schemes
1671 or TekHVC, since I don't know the algorithms for conversion to
1672 RGB. */
f695b4b1
GV
1673
1674 /* If we fail to lookup the color name in w32_color_map, then check the
1675 colorname to see if it can be crudely approximated: If the X color
1676 ends in a number (e.g., "darkseagreen2"), strip the number and
1677 return the result of looking up the base color name. */
1678 ret = w32_color_map_lookup (colorname);
1679 if (NILP (ret))
ee78dc32 1680 {
f695b4b1 1681 int len = strlen (colorname);
ee78dc32 1682
f695b4b1
GV
1683 if (isdigit (colorname[len - 1]))
1684 {
8b77111c 1685 char *ptr, *approx = alloca (len + 1);
ee78dc32 1686
f695b4b1
GV
1687 strcpy (approx, colorname);
1688 ptr = &approx[len - 1];
1689 while (ptr > approx && isdigit (*ptr))
1690 *ptr-- = '\0';
ee78dc32 1691
f695b4b1 1692 ret = w32_color_map_lookup (approx);
ee78dc32 1693 }
ee78dc32
GV
1694 }
1695
1696 UNBLOCK_INPUT;
ee78dc32
GV
1697 return ret;
1698}
1699
5ac45f98
GV
1700
1701void
fbd6baed 1702w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1703{
fbd6baed 1704 struct w32_palette_entry * list;
5ac45f98
GV
1705 LOGPALETTE * log_palette;
1706 HPALETTE new_palette;
1707 int i;
1708
1709 /* don't bother trying to create palette if not supported */
fbd6baed 1710 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1711 return;
1712
1713 log_palette = (LOGPALETTE *)
1714 alloca (sizeof (LOGPALETTE) +
fbd6baed 1715 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1716 log_palette->palVersion = 0x300;
fbd6baed 1717 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1718
fbd6baed 1719 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1720 for (i = 0;
fbd6baed 1721 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1722 i++, list = list->next)
1723 log_palette->palPalEntry[i] = list->entry;
1724
1725 new_palette = CreatePalette (log_palette);
1726
1727 enter_crit ();
1728
fbd6baed
GV
1729 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1730 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1731 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1732
1733 /* Realize display palette and garbage all frames. */
1734 release_frame_dc (f, get_frame_dc (f));
1735
1736 leave_crit ();
1737}
1738
fbd6baed
GV
1739#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1740#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1741 do \
1742 { \
1743 pe.peRed = GetRValue (color); \
1744 pe.peGreen = GetGValue (color); \
1745 pe.peBlue = GetBValue (color); \
1746 pe.peFlags = 0; \
1747 } while (0)
1748
1749#if 0
1750/* Keep these around in case we ever want to track color usage. */
1751void
fbd6baed 1752w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1753{
fbd6baed 1754 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1755
fbd6baed 1756 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1757 return;
1758
1759 /* check if color is already mapped */
1760 while (list)
1761 {
fbd6baed 1762 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1763 {
1764 ++list->refcount;
1765 return;
1766 }
1767 list = list->next;
1768 }
1769
1770 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1771 list = (struct w32_palette_entry *)
1772 xmalloc (sizeof (struct w32_palette_entry));
1773 SET_W32_COLOR (list->entry, color);
5ac45f98 1774 list->refcount = 1;
fbd6baed
GV
1775 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1776 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1777 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1778
1779 /* set flag that palette must be regenerated */
fbd6baed 1780 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1781}
1782
1783void
fbd6baed 1784w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1785{
fbd6baed
GV
1786 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1787 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1788
fbd6baed 1789 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1790 return;
1791
1792 /* check if color is already mapped */
1793 while (list)
1794 {
fbd6baed 1795 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1796 {
1797 if (--list->refcount == 0)
1798 {
1799 *prev = list->next;
1800 xfree (list);
fbd6baed 1801 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1802 break;
1803 }
1804 else
1805 return;
1806 }
1807 prev = &list->next;
1808 list = list->next;
1809 }
1810
1811 /* set flag that palette must be regenerated */
fbd6baed 1812 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1813}
1814#endif
1815
6fc2811b
JR
1816
1817/* Gamma-correct COLOR on frame F. */
1818
1819void
1820gamma_correct (f, color)
1821 struct frame *f;
1822 COLORREF *color;
1823{
1824 if (f->gamma)
1825 {
1826 *color = PALETTERGB (
1827 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1828 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1829 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1830 }
1831}
1832
1833
ee78dc32
GV
1834/* Decide if color named COLOR is valid for the display associated with
1835 the selected frame; if so, return the rgb values in COLOR_DEF.
1836 If ALLOC is nonzero, allocate a new colormap cell. */
1837
1838int
6fc2811b 1839w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1840 FRAME_PTR f;
1841 char *color;
6fc2811b 1842 XColor *color_def;
ee78dc32
GV
1843 int alloc;
1844{
1845 register Lisp_Object tem;
6fc2811b 1846 COLORREF w32_color_ref;
3c190163 1847
fbd6baed 1848 tem = x_to_w32_color (color);
3c190163 1849
ee78dc32
GV
1850 if (!NILP (tem))
1851 {
d88c567c
JR
1852 if (f)
1853 {
1854 /* Apply gamma correction. */
1855 w32_color_ref = XUINT (tem);
1856 gamma_correct (f, &w32_color_ref);
1857 XSETINT (tem, w32_color_ref);
1858 }
9badad41
JR
1859
1860 /* Map this color to the palette if it is enabled. */
fbd6baed 1861 if (!NILP (Vw32_enable_palette))
5ac45f98 1862 {
fbd6baed 1863 struct w32_palette_entry * entry =
d88c567c 1864 one_w32_display_info.color_list;
fbd6baed 1865 struct w32_palette_entry ** prev =
d88c567c 1866 &one_w32_display_info.color_list;
5ac45f98
GV
1867
1868 /* check if color is already mapped */
1869 while (entry)
1870 {
fbd6baed 1871 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1872 break;
1873 prev = &entry->next;
1874 entry = entry->next;
1875 }
1876
1877 if (entry == NULL && alloc)
1878 {
1879 /* not already mapped, so add to list */
fbd6baed
GV
1880 entry = (struct w32_palette_entry *)
1881 xmalloc (sizeof (struct w32_palette_entry));
1882 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1883 entry->next = NULL;
1884 *prev = entry;
d88c567c 1885 one_w32_display_info.num_colors++;
5ac45f98
GV
1886
1887 /* set flag that palette must be regenerated */
d88c567c 1888 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1889 }
1890 }
1891 /* Ensure COLORREF value is snapped to nearest color in (default)
1892 palette by simulating the PALETTERGB macro. This works whether
1893 or not the display device has a palette. */
6fc2811b
JR
1894 w32_color_ref = XUINT (tem) | 0x2000000;
1895
6fc2811b
JR
1896 color_def->pixel = w32_color_ref;
1897 color_def->red = GetRValue (w32_color_ref);
1898 color_def->green = GetGValue (w32_color_ref);
1899 color_def->blue = GetBValue (w32_color_ref);
1900
ee78dc32 1901 return 1;
5ac45f98 1902 }
7fb46567 1903 else
3c190163
GV
1904 {
1905 return 0;
1906 }
ee78dc32
GV
1907}
1908
1909/* Given a string ARG naming a color, compute a pixel value from it
1910 suitable for screen F.
1911 If F is not a color screen, return DEF (default) regardless of what
1912 ARG says. */
1913
1914int
1915x_decode_color (f, arg, def)
1916 FRAME_PTR f;
1917 Lisp_Object arg;
1918 int def;
1919{
6fc2811b 1920 XColor cdef;
ee78dc32 1921
b7826503 1922 CHECK_STRING (arg);
ee78dc32
GV
1923
1924 if (strcmp (XSTRING (arg)->data, "black") == 0)
1925 return BLACK_PIX_DEFAULT (f);
1926 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1927 return WHITE_PIX_DEFAULT (f);
1928
fbd6baed 1929 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1930 return def;
1931
6fc2811b 1932 /* w32_defined_color is responsible for coping with failures
ee78dc32 1933 by looking for a near-miss. */
6fc2811b
JR
1934 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1935 return cdef.pixel;
ee78dc32
GV
1936
1937 /* defined_color failed; return an ultimate default. */
1938 return def;
1939}
1940\f
dfff8a69
JR
1941/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1942 the previous value of that parameter, NEW_VALUE is the new value. */
1943
1944static void
1945x_set_line_spacing (f, new_value, old_value)
1946 struct frame *f;
1947 Lisp_Object new_value, old_value;
1948{
1949 if (NILP (new_value))
1950 f->extra_line_spacing = 0;
1951 else if (NATNUMP (new_value))
1952 f->extra_line_spacing = XFASTINT (new_value);
1953 else
1a948b17 1954 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
1955 Fcons (new_value, Qnil)));
1956 if (FRAME_VISIBLE_P (f))
1957 redraw_frame (f);
1958}
1959
1960
6fc2811b
JR
1961/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1962 the previous value of that parameter, NEW_VALUE is the new value. */
1963
1964static void
1965x_set_screen_gamma (f, new_value, old_value)
1966 struct frame *f;
1967 Lisp_Object new_value, old_value;
1968{
1969 if (NILP (new_value))
1970 f->gamma = 0;
1971 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1972 /* The value 0.4545 is the normal viewing gamma. */
1973 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1974 else
1a948b17 1975 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
1976 Fcons (new_value, Qnil)));
1977
1978 clear_face_cache (0);
1979}
1980
1981
ee78dc32
GV
1982/* Functions called only from `x_set_frame_param'
1983 to set individual parameters.
1984
fbd6baed 1985 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1986 the frame is being created and its window does not exist yet.
1987 In that case, just record the parameter's new value
1988 in the standard place; do not attempt to change the window. */
1989
1990void
1991x_set_foreground_color (f, arg, oldval)
1992 struct frame *f;
1993 Lisp_Object arg, oldval;
1994{
3cf3436e
JR
1995 struct w32_output *x = f->output_data.w32;
1996 PIX_TYPE fg, old_fg;
1997
1998 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1999 old_fg = FRAME_FOREGROUND_PIXEL (f);
2000 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2001
fbd6baed 2002 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2003 {
3cf3436e
JR
2004 if (x->cursor_pixel == old_fg)
2005 x->cursor_pixel = fg;
2006
6fc2811b 2007 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2008 if (FRAME_VISIBLE_P (f))
2009 redraw_frame (f);
2010 }
2011}
2012
2013void
2014x_set_background_color (f, arg, oldval)
2015 struct frame *f;
2016 Lisp_Object arg, oldval;
2017{
6fc2811b 2018 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2019 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2020
fbd6baed 2021 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2022 {
6fc2811b
JR
2023 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2024 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2025
6fc2811b 2026 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2027
2028 if (FRAME_VISIBLE_P (f))
2029 redraw_frame (f);
2030 }
2031}
2032
2033void
2034x_set_mouse_color (f, arg, oldval)
2035 struct frame *f;
2036 Lisp_Object arg, oldval;
2037{
ee78dc32 2038 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2039 int count;
ee78dc32
GV
2040 int mask_color;
2041
2042 if (!EQ (Qnil, arg))
fbd6baed 2043 f->output_data.w32->mouse_pixel
ee78dc32 2044 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2045 mask_color = FRAME_BACKGROUND_PIXEL (f);
2046
2047 /* Don't let pointers be invisible. */
fbd6baed 2048 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2049 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2050 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2051
767b1ff0 2052#if 0 /* TODO : cursor changes */
ee78dc32
GV
2053 BLOCK_INPUT;
2054
2055 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2056 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2057
2058 if (!EQ (Qnil, Vx_pointer_shape))
2059 {
b7826503 2060 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2061 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2062 }
2063 else
fbd6baed
GV
2064 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2065 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2066
2067 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2068 {
b7826503 2069 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2070 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2071 XINT (Vx_nontext_pointer_shape));
2072 }
2073 else
fbd6baed
GV
2074 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2075 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2076
0af913d7 2077 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2078 {
b7826503 2079 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2080 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2081 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2082 }
2083 else
0af913d7 2084 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b
JR
2085 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2086
2087 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2088 if (!EQ (Qnil, Vx_mode_pointer_shape))
2089 {
b7826503 2090 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2091 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2092 XINT (Vx_mode_pointer_shape));
2093 }
2094 else
fbd6baed
GV
2095 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2096 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2097
2098 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2099 {
b7826503 2100 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2101 cross_cursor
fbd6baed 2102 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2103 XINT (Vx_sensitive_text_pointer_shape));
2104 }
2105 else
fbd6baed 2106 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2107
4694d762
JR
2108 if (!NILP (Vx_window_horizontal_drag_shape))
2109 {
b7826503 2110 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2111 horizontal_drag_cursor
2112 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2113 XINT (Vx_window_horizontal_drag_shape));
2114 }
2115 else
2116 horizontal_drag_cursor
2117 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2118
ee78dc32 2119 /* Check and report errors with the above calls. */
fbd6baed 2120 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2121 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2122
2123 {
2124 XColor fore_color, back_color;
2125
fbd6baed 2126 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2127 back_color.pixel = mask_color;
fbd6baed
GV
2128 XQueryColor (FRAME_W32_DISPLAY (f),
2129 DefaultColormap (FRAME_W32_DISPLAY (f),
2130 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2131 &fore_color);
fbd6baed
GV
2132 XQueryColor (FRAME_W32_DISPLAY (f),
2133 DefaultColormap (FRAME_W32_DISPLAY (f),
2134 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2135 &back_color);
fbd6baed 2136 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2137 &fore_color, &back_color);
fbd6baed 2138 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2139 &fore_color, &back_color);
fbd6baed 2140 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2141 &fore_color, &back_color);
fbd6baed 2142 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2143 &fore_color, &back_color);
0af913d7 2144 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2145 &fore_color, &back_color);
ee78dc32
GV
2146 }
2147
fbd6baed 2148 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2149 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2150
fbd6baed
GV
2151 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2152 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2153 f->output_data.w32->text_cursor = cursor;
2154
2155 if (nontext_cursor != f->output_data.w32->nontext_cursor
2156 && f->output_data.w32->nontext_cursor != 0)
2157 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2158 f->output_data.w32->nontext_cursor = nontext_cursor;
2159
0af913d7
GM
2160 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2161 && f->output_data.w32->hourglass_cursor != 0)
2162 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2163 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2164
fbd6baed
GV
2165 if (mode_cursor != f->output_data.w32->modeline_cursor
2166 && f->output_data.w32->modeline_cursor != 0)
2167 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2168 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2169
fbd6baed
GV
2170 if (cross_cursor != f->output_data.w32->cross_cursor
2171 && f->output_data.w32->cross_cursor != 0)
2172 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2173 f->output_data.w32->cross_cursor = cross_cursor;
2174
2175 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2176 UNBLOCK_INPUT;
6fc2811b
JR
2177
2178 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2179#endif /* TODO */
ee78dc32
GV
2180}
2181
70a0239a
JR
2182/* Defined in w32term.c. */
2183void x_update_cursor (struct frame *f, int on_p);
2184
ee78dc32
GV
2185void
2186x_set_cursor_color (f, arg, oldval)
2187 struct frame *f;
2188 Lisp_Object arg, oldval;
2189{
70a0239a 2190 unsigned long fore_pixel, pixel;
ee78dc32 2191
dfff8a69 2192 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2193 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2194 WHITE_PIX_DEFAULT (f));
ee78dc32 2195 else
6fc2811b 2196 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2197
6759f872 2198 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2199
2200 /* Make sure that the cursor color differs from the background color. */
70a0239a 2201 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2202 {
70a0239a
JR
2203 pixel = f->output_data.w32->mouse_pixel;
2204 if (pixel == fore_pixel)
6fc2811b 2205 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2206 }
70a0239a 2207
6fc2811b 2208 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
70a0239a 2209 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2210
fbd6baed 2211 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2212 {
2213 if (FRAME_VISIBLE_P (f))
2214 {
70a0239a
JR
2215 x_update_cursor (f, 0);
2216 x_update_cursor (f, 1);
ee78dc32
GV
2217 }
2218 }
6fc2811b
JR
2219
2220 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2221}
2222
33d52f9c
GV
2223/* Set the border-color of frame F to pixel value PIX.
2224 Note that this does not fully take effect if done before
2225 F has an window. */
2226void
2227x_set_border_pixel (f, pix)
2228 struct frame *f;
2229 int pix;
2230{
2231 f->output_data.w32->border_pixel = pix;
2232
2233 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2234 {
2235 if (FRAME_VISIBLE_P (f))
2236 redraw_frame (f);
2237 }
2238}
2239
ee78dc32
GV
2240/* Set the border-color of frame F to value described by ARG.
2241 ARG can be a string naming a color.
2242 The border-color is used for the border that is drawn by the server.
2243 Note that this does not fully take effect if done before
2244 F has a window; it must be redone when the window is created. */
2245
2246void
2247x_set_border_color (f, arg, oldval)
2248 struct frame *f;
2249 Lisp_Object arg, oldval;
2250{
ee78dc32
GV
2251 int pix;
2252
b7826503 2253 CHECK_STRING (arg);
ee78dc32 2254 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2255 x_set_border_pixel (f, pix);
6fc2811b 2256 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2257}
2258
dfff8a69
JR
2259/* Value is the internal representation of the specified cursor type
2260 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2261 of the bar cursor. */
2262
2263enum text_cursor_kinds
2264x_specified_cursor_type (arg, width)
2265 Lisp_Object arg;
2266 int *width;
ee78dc32 2267{
dfff8a69
JR
2268 enum text_cursor_kinds type;
2269
ee78dc32
GV
2270 if (EQ (arg, Qbar))
2271 {
dfff8a69
JR
2272 type = BAR_CURSOR;
2273 *width = 2;
ee78dc32 2274 }
dfff8a69
JR
2275 else if (CONSP (arg)
2276 && EQ (XCAR (arg), Qbar)
2277 && INTEGERP (XCDR (arg))
2278 && XINT (XCDR (arg)) >= 0)
ee78dc32 2279 {
dfff8a69
JR
2280 type = BAR_CURSOR;
2281 *width = XINT (XCDR (arg));
ee78dc32 2282 }
dfff8a69
JR
2283 else if (NILP (arg))
2284 type = NO_CURSOR;
ee78dc32
GV
2285 else
2286 /* Treat anything unknown as "box cursor".
2287 It was bad to signal an error; people have trouble fixing
2288 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2289 type = FILLED_BOX_CURSOR;
2290
2291 return type;
2292}
2293
2294void
2295x_set_cursor_type (f, arg, oldval)
2296 FRAME_PTR f;
2297 Lisp_Object arg, oldval;
2298{
2299 int width;
2300
2301 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2302 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2303
2304 /* Make sure the cursor gets redrawn. This is overkill, but how
2305 often do people change cursor types? */
2306 update_mode_lines++;
2307}
dfff8a69 2308\f
ee78dc32
GV
2309void
2310x_set_icon_type (f, arg, oldval)
2311 struct frame *f;
2312 Lisp_Object arg, oldval;
2313{
ee78dc32
GV
2314 int result;
2315
eb7576ce
GV
2316 if (NILP (arg) && NILP (oldval))
2317 return;
2318
2319 if (STRINGP (arg) && STRINGP (oldval)
2320 && EQ (Fstring_equal (oldval, arg), Qt))
2321 return;
2322
2323 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2324 return;
2325
2326 BLOCK_INPUT;
ee78dc32 2327
eb7576ce 2328 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2329 if (result)
2330 {
2331 UNBLOCK_INPUT;
2332 error ("No icon window available");
2333 }
2334
ee78dc32 2335 UNBLOCK_INPUT;
ee78dc32
GV
2336}
2337
2338/* Return non-nil if frame F wants a bitmap icon. */
2339
2340Lisp_Object
2341x_icon_type (f)
2342 FRAME_PTR f;
2343{
2344 Lisp_Object tem;
2345
2346 tem = assq_no_quit (Qicon_type, f->param_alist);
2347 if (CONSP (tem))
8e713be6 2348 return XCDR (tem);
ee78dc32
GV
2349 else
2350 return Qnil;
2351}
2352
2353void
2354x_set_icon_name (f, arg, oldval)
2355 struct frame *f;
2356 Lisp_Object arg, oldval;
2357{
ee78dc32
GV
2358 if (STRINGP (arg))
2359 {
2360 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2361 return;
2362 }
2363 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2364 return;
2365
2366 f->icon_name = arg;
2367
2368#if 0
fbd6baed 2369 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2370 return;
2371
2372 BLOCK_INPUT;
2373
2374 result = x_text_icon (f,
1edf84e7 2375 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2376 ? f->icon_name
1edf84e7
GV
2377 : !NILP (f->title)
2378 ? f->title
ee78dc32
GV
2379 : f->name))->data);
2380
2381 if (result)
2382 {
2383 UNBLOCK_INPUT;
2384 error ("No icon window available");
2385 }
2386
2387 /* If the window was unmapped (and its icon was mapped),
2388 the new icon is not mapped, so map the window in its stead. */
2389 if (FRAME_VISIBLE_P (f))
2390 {
2391#ifdef USE_X_TOOLKIT
fbd6baed 2392 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2393#endif
fbd6baed 2394 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2395 }
2396
fbd6baed 2397 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2398 UNBLOCK_INPUT;
2399#endif
2400}
2401
2402extern Lisp_Object x_new_font ();
4587b026 2403extern Lisp_Object x_new_fontset();
ee78dc32
GV
2404
2405void
2406x_set_font (f, arg, oldval)
2407 struct frame *f;
2408 Lisp_Object arg, oldval;
2409{
2410 Lisp_Object result;
4587b026 2411 Lisp_Object fontset_name;
4b817373 2412 Lisp_Object frame;
3cf3436e 2413 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2414
b7826503 2415 CHECK_STRING (arg);
ee78dc32 2416
4587b026
GV
2417 fontset_name = Fquery_fontset (arg, Qnil);
2418
ee78dc32 2419 BLOCK_INPUT;
4587b026
GV
2420 result = (STRINGP (fontset_name)
2421 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2422 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2423 UNBLOCK_INPUT;
2424
2425 if (EQ (result, Qnil))
dfff8a69 2426 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2427 else if (EQ (result, Qt))
dfff8a69 2428 error ("The characters of the given font have varying widths");
ee78dc32
GV
2429 else if (STRINGP (result))
2430 {
3cf3436e
JR
2431 if (STRINGP (fontset_name))
2432 {
2433 /* Fontset names are built from ASCII font names, so the
2434 names may be equal despite there was a change. */
2435 if (old_fontset == FRAME_FONTSET (f))
2436 return;
2437 }
2438 else if (!NILP (Fequal (result, oldval)))
dc220243 2439 return;
3cf3436e 2440
ee78dc32 2441 store_frame_param (f, Qfont, result);
6fc2811b 2442 recompute_basic_faces (f);
ee78dc32
GV
2443 }
2444 else
2445 abort ();
4b817373 2446
6fc2811b
JR
2447 do_pending_window_change (0);
2448
2449 /* Don't call `face-set-after-frame-default' when faces haven't been
2450 initialized yet. This is the case when called from
2451 Fx_create_frame. In that case, the X widget or window doesn't
2452 exist either, and we can end up in x_report_frame_params with a
2453 null widget which gives a segfault. */
2454 if (FRAME_FACE_CACHE (f))
2455 {
2456 XSETFRAME (frame, f);
2457 call1 (Qface_set_after_frame_default, frame);
2458 }
ee78dc32
GV
2459}
2460
41c1bdd9
KS
2461static void
2462x_set_fringe_width (f, new_value, old_value)
2463 struct frame *f;
2464 Lisp_Object new_value, old_value;
2465{
2466 x_compute_fringe_widths (f, 1);
2467}
2468
ee78dc32
GV
2469void
2470x_set_border_width (f, arg, oldval)
2471 struct frame *f;
2472 Lisp_Object arg, oldval;
2473{
b7826503 2474 CHECK_NUMBER (arg);
ee78dc32 2475
fbd6baed 2476 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2477 return;
2478
fbd6baed 2479 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2480 error ("Cannot change the border width of a window");
2481
fbd6baed 2482 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2483}
2484
2485void
2486x_set_internal_border_width (f, arg, oldval)
2487 struct frame *f;
2488 Lisp_Object arg, oldval;
2489{
fbd6baed 2490 int old = f->output_data.w32->internal_border_width;
ee78dc32 2491
b7826503 2492 CHECK_NUMBER (arg);
fbd6baed
GV
2493 f->output_data.w32->internal_border_width = XINT (arg);
2494 if (f->output_data.w32->internal_border_width < 0)
2495 f->output_data.w32->internal_border_width = 0;
ee78dc32 2496
fbd6baed 2497 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2498 return;
2499
fbd6baed 2500 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2501 {
ee78dc32 2502 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2503 SET_FRAME_GARBAGED (f);
6fc2811b 2504 do_pending_window_change (0);
ee78dc32 2505 }
a05e2bae
JR
2506 else
2507 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2508}
2509
2510void
2511x_set_visibility (f, value, oldval)
2512 struct frame *f;
2513 Lisp_Object value, oldval;
2514{
2515 Lisp_Object frame;
2516 XSETFRAME (frame, f);
2517
2518 if (NILP (value))
2519 Fmake_frame_invisible (frame, Qt);
2520 else if (EQ (value, Qicon))
2521 Ficonify_frame (frame);
2522 else
2523 Fmake_frame_visible (frame);
2524}
2525
a1258667
JR
2526\f
2527/* Change window heights in windows rooted in WINDOW by N lines. */
2528
2529static void
2530x_change_window_heights (window, n)
2531 Lisp_Object window;
2532 int n;
2533{
2534 struct window *w = XWINDOW (window);
2535
2536 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2537 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2538
2539 if (INTEGERP (w->orig_top))
2540 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2541 if (INTEGERP (w->orig_height))
2542 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2543
2544 /* Handle just the top child in a vertical split. */
2545 if (!NILP (w->vchild))
2546 x_change_window_heights (w->vchild, n);
2547
2548 /* Adjust all children in a horizontal split. */
2549 for (window = w->hchild; !NILP (window); window = w->next)
2550 {
2551 w = XWINDOW (window);
2552 x_change_window_heights (window, n);
2553 }
2554}
2555
ee78dc32
GV
2556void
2557x_set_menu_bar_lines (f, value, oldval)
2558 struct frame *f;
2559 Lisp_Object value, oldval;
2560{
2561 int nlines;
2562 int olines = FRAME_MENU_BAR_LINES (f);
2563
2564 /* Right now, menu bars don't work properly in minibuf-only frames;
2565 most of the commands try to apply themselves to the minibuffer
6fc2811b 2566 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2567 in or split the minibuffer window. */
2568 if (FRAME_MINIBUF_ONLY_P (f))
2569 return;
2570
2571 if (INTEGERP (value))
2572 nlines = XINT (value);
2573 else
2574 nlines = 0;
2575
2576 FRAME_MENU_BAR_LINES (f) = 0;
2577 if (nlines)
2578 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2579 else
2580 {
2581 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2582 free_frame_menubar (f);
2583 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2584
2585 /* Adjust the frame size so that the client (text) dimensions
2586 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2587 set correctly. */
2588 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2589 do_pending_window_change (0);
ee78dc32 2590 }
6fc2811b
JR
2591 adjust_glyphs (f);
2592}
2593
2594
2595/* Set the number of lines used for the tool bar of frame F to VALUE.
2596 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2597 is the old number of tool bar lines. This function changes the
2598 height of all windows on frame F to match the new tool bar height.
2599 The frame's height doesn't change. */
2600
2601void
2602x_set_tool_bar_lines (f, value, oldval)
2603 struct frame *f;
2604 Lisp_Object value, oldval;
2605{
36f8209a
JR
2606 int delta, nlines, root_height;
2607 Lisp_Object root_window;
6fc2811b 2608
dc220243
JR
2609 /* Treat tool bars like menu bars. */
2610 if (FRAME_MINIBUF_ONLY_P (f))
2611 return;
2612
6fc2811b
JR
2613 /* Use VALUE only if an integer >= 0. */
2614 if (INTEGERP (value) && XINT (value) >= 0)
2615 nlines = XFASTINT (value);
2616 else
2617 nlines = 0;
2618
2619 /* Make sure we redisplay all windows in this frame. */
2620 ++windows_or_buffers_changed;
2621
2622 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2623
2624 /* Don't resize the tool-bar to more than we have room for. */
2625 root_window = FRAME_ROOT_WINDOW (f);
2626 root_height = XINT (XWINDOW (root_window)->height);
2627 if (root_height - delta < 1)
2628 {
2629 delta = root_height - 1;
2630 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2631 }
2632
6fc2811b 2633 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2634 x_change_window_heights (root_window, delta);
6fc2811b 2635 adjust_glyphs (f);
36f8209a
JR
2636
2637 /* We also have to make sure that the internal border at the top of
2638 the frame, below the menu bar or tool bar, is redrawn when the
2639 tool bar disappears. This is so because the internal border is
2640 below the tool bar if one is displayed, but is below the menu bar
2641 if there isn't a tool bar. The tool bar draws into the area
2642 below the menu bar. */
2643 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2644 {
2645 updating_frame = f;
2646 clear_frame ();
2647 clear_current_matrices (f);
2648 updating_frame = NULL;
2649 }
2650
2651 /* If the tool bar gets smaller, the internal border below it
2652 has to be cleared. It was formerly part of the display
2653 of the larger tool bar, and updating windows won't clear it. */
2654 if (delta < 0)
2655 {
2656 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2657 int width = PIXEL_WIDTH (f);
2658 int y = nlines * CANON_Y_UNIT (f);
2659
2660 BLOCK_INPUT;
2661 {
2662 HDC hdc = get_frame_dc (f);
2663 w32_clear_area (f, hdc, 0, y, width, height);
2664 release_frame_dc (f, hdc);
2665 }
2666 UNBLOCK_INPUT;
3cf3436e
JR
2667
2668 if (WINDOWP (f->tool_bar_window))
2669 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2670 }
ee78dc32
GV
2671}
2672
6fc2811b 2673
ee78dc32 2674/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2675 w32_id_name.
ee78dc32
GV
2676
2677 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2678 name; if NAME is a string, set F's name to NAME and set
2679 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2680
2681 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2682 suggesting a new name, which lisp code should override; if
2683 F->explicit_name is set, ignore the new name; otherwise, set it. */
2684
2685void
2686x_set_name (f, name, explicit)
2687 struct frame *f;
2688 Lisp_Object name;
2689 int explicit;
2690{
2691 /* Make sure that requests from lisp code override requests from
2692 Emacs redisplay code. */
2693 if (explicit)
2694 {
2695 /* If we're switching from explicit to implicit, we had better
2696 update the mode lines and thereby update the title. */
2697 if (f->explicit_name && NILP (name))
2698 update_mode_lines = 1;
2699
2700 f->explicit_name = ! NILP (name);
2701 }
2702 else if (f->explicit_name)
2703 return;
2704
fbd6baed 2705 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2706 if (NILP (name))
2707 {
2708 /* Check for no change needed in this very common case
2709 before we do any consing. */
fbd6baed 2710 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2711 XSTRING (f->name)->data))
2712 return;
fbd6baed 2713 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2714 }
2715 else
b7826503 2716 CHECK_STRING (name);
ee78dc32
GV
2717
2718 /* Don't change the name if it's already NAME. */
2719 if (! NILP (Fstring_equal (name, f->name)))
2720 return;
2721
1edf84e7
GV
2722 f->name = name;
2723
2724 /* For setting the frame title, the title parameter should override
2725 the name parameter. */
2726 if (! NILP (f->title))
2727 name = f->title;
2728
fbd6baed 2729 if (FRAME_W32_WINDOW (f))
ee78dc32 2730 {
6fc2811b 2731 if (STRING_MULTIBYTE (name))
dfff8a69 2732 name = ENCODE_SYSTEM (name);
6fc2811b 2733
ee78dc32 2734 BLOCK_INPUT;
fbd6baed 2735 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2736 UNBLOCK_INPUT;
2737 }
ee78dc32
GV
2738}
2739
2740/* This function should be called when the user's lisp code has
2741 specified a name for the frame; the name will override any set by the
2742 redisplay code. */
2743void
2744x_explicitly_set_name (f, arg, oldval)
2745 FRAME_PTR f;
2746 Lisp_Object arg, oldval;
2747{
2748 x_set_name (f, arg, 1);
2749}
2750
2751/* This function should be called by Emacs redisplay code to set the
2752 name; names set this way will never override names set by the user's
2753 lisp code. */
2754void
2755x_implicitly_set_name (f, arg, oldval)
2756 FRAME_PTR f;
2757 Lisp_Object arg, oldval;
2758{
2759 x_set_name (f, arg, 0);
2760}
1edf84e7
GV
2761\f
2762/* Change the title of frame F to NAME.
2763 If NAME is nil, use the frame name as the title.
2764
2765 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2766 name; if NAME is a string, set F's name to NAME and set
2767 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2768
2769 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2770 suggesting a new name, which lisp code should override; if
2771 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2772
1edf84e7 2773void
6fc2811b 2774x_set_title (f, name, old_name)
1edf84e7 2775 struct frame *f;
6fc2811b 2776 Lisp_Object name, old_name;
1edf84e7
GV
2777{
2778 /* Don't change the title if it's already NAME. */
2779 if (EQ (name, f->title))
2780 return;
2781
2782 update_mode_lines = 1;
2783
2784 f->title = name;
2785
2786 if (NILP (name))
2787 name = f->name;
2788
2789 if (FRAME_W32_WINDOW (f))
2790 {
6fc2811b 2791 if (STRING_MULTIBYTE (name))
dfff8a69 2792 name = ENCODE_SYSTEM (name);
6fc2811b 2793
1edf84e7
GV
2794 BLOCK_INPUT;
2795 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2796 UNBLOCK_INPUT;
2797 }
2798}
2799\f
ee78dc32
GV
2800void
2801x_set_autoraise (f, arg, oldval)
2802 struct frame *f;
2803 Lisp_Object arg, oldval;
2804{
2805 f->auto_raise = !EQ (Qnil, arg);
2806}
2807
2808void
2809x_set_autolower (f, arg, oldval)
2810 struct frame *f;
2811 Lisp_Object arg, oldval;
2812{
2813 f->auto_lower = !EQ (Qnil, arg);
2814}
2815
2816void
2817x_set_unsplittable (f, arg, oldval)
2818 struct frame *f;
2819 Lisp_Object arg, oldval;
2820{
2821 f->no_split = !NILP (arg);
2822}
2823
2824void
2825x_set_vertical_scroll_bars (f, arg, oldval)
2826 struct frame *f;
2827 Lisp_Object arg, oldval;
2828{
1026b400
RS
2829 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2830 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2831 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2832 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2833 {
1026b400
RS
2834 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2835 vertical_scroll_bar_none :
87996783
GV
2836 /* Put scroll bars on the right by default, as is conventional
2837 on MS-Windows. */
2838 EQ (Qleft, arg)
2839 ? vertical_scroll_bar_left
2840 : vertical_scroll_bar_right;
ee78dc32
GV
2841
2842 /* We set this parameter before creating the window for the
2843 frame, so we can get the geometry right from the start.
2844 However, if the window hasn't been created yet, we shouldn't
2845 call x_set_window_size. */
fbd6baed 2846 if (FRAME_W32_WINDOW (f))
ee78dc32 2847 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2848 do_pending_window_change (0);
ee78dc32
GV
2849 }
2850}
2851
2852void
2853x_set_scroll_bar_width (f, arg, oldval)
2854 struct frame *f;
2855 Lisp_Object arg, oldval;
2856{
6fc2811b
JR
2857 int wid = FONT_WIDTH (f->output_data.w32->font);
2858
ee78dc32
GV
2859 if (NILP (arg))
2860 {
6fc2811b
JR
2861 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2862 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2863 wid - 1) / wid;
2864 if (FRAME_W32_WINDOW (f))
2865 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2866 do_pending_window_change (0);
ee78dc32
GV
2867 }
2868 else if (INTEGERP (arg) && XINT (arg) > 0
2869 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2870 {
ee78dc32 2871 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2872 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2873 + wid-1) / wid;
fbd6baed 2874 if (FRAME_W32_WINDOW (f))
ee78dc32 2875 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2876 do_pending_window_change (0);
ee78dc32 2877 }
6fc2811b
JR
2878 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2879 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2880 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2881}
2882\f
2883/* Subroutines of creating an frame. */
2884
2885/* Make sure that Vx_resource_name is set to a reasonable value.
2886 Fix it up, or set it to `emacs' if it is too hopeless. */
2887
2888static void
2889validate_x_resource_name ()
2890{
6fc2811b 2891 int len = 0;
ee78dc32
GV
2892 /* Number of valid characters in the resource name. */
2893 int good_count = 0;
2894 /* Number of invalid characters in the resource name. */
2895 int bad_count = 0;
2896 Lisp_Object new;
2897 int i;
2898
2899 if (STRINGP (Vx_resource_name))
2900 {
2901 unsigned char *p = XSTRING (Vx_resource_name)->data;
2902 int i;
2903
dfff8a69 2904 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2905
2906 /* Only letters, digits, - and _ are valid in resource names.
2907 Count the valid characters and count the invalid ones. */
2908 for (i = 0; i < len; i++)
2909 {
2910 int c = p[i];
2911 if (! ((c >= 'a' && c <= 'z')
2912 || (c >= 'A' && c <= 'Z')
2913 || (c >= '0' && c <= '9')
2914 || c == '-' || c == '_'))
2915 bad_count++;
2916 else
2917 good_count++;
2918 }
2919 }
2920 else
2921 /* Not a string => completely invalid. */
2922 bad_count = 5, good_count = 0;
2923
2924 /* If name is valid already, return. */
2925 if (bad_count == 0)
2926 return;
2927
2928 /* If name is entirely invalid, or nearly so, use `emacs'. */
2929 if (good_count == 0
2930 || (good_count == 1 && bad_count > 0))
2931 {
2932 Vx_resource_name = build_string ("emacs");
2933 return;
2934 }
2935
2936 /* Name is partly valid. Copy it and replace the invalid characters
2937 with underscores. */
2938
2939 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2940
2941 for (i = 0; i < len; i++)
2942 {
2943 int c = XSTRING (new)->data[i];
2944 if (! ((c >= 'a' && c <= 'z')
2945 || (c >= 'A' && c <= 'Z')
2946 || (c >= '0' && c <= '9')
2947 || c == '-' || c == '_'))
2948 XSTRING (new)->data[i] = '_';
2949 }
2950}
2951
2952
2953extern char *x_get_string_resource ();
2954
2955DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
2956 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
2957This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2958class, where INSTANCE is the name under which Emacs was invoked, or
2959the name specified by the `-name' or `-rn' command-line arguments.
2960
2961The optional arguments COMPONENT and SUBCLASS add to the key and the
2962class, respectively. You must specify both of them or neither.
2963If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
2964and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
2965 (attribute, class, component, subclass)
2966 Lisp_Object attribute, class, component, subclass;
2967{
2968 register char *value;
2969 char *name_key;
2970 char *class_key;
2971
b7826503
PJ
2972 CHECK_STRING (attribute);
2973 CHECK_STRING (class);
ee78dc32
GV
2974
2975 if (!NILP (component))
b7826503 2976 CHECK_STRING (component);
ee78dc32 2977 if (!NILP (subclass))
b7826503 2978 CHECK_STRING (subclass);
ee78dc32
GV
2979 if (NILP (component) != NILP (subclass))
2980 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2981
2982 validate_x_resource_name ();
2983
2984 /* Allocate space for the components, the dots which separate them,
2985 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 2986 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 2987 + (STRINGP (component)
dfff8a69
JR
2988 ? STRING_BYTES (XSTRING (component)) : 0)
2989 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
2990 + 3);
2991
2992 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 2993 + STRING_BYTES (XSTRING (class))
ee78dc32 2994 + (STRINGP (subclass)
dfff8a69 2995 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
2996 + 3);
2997
2998 /* Start with emacs.FRAMENAME for the name (the specific one)
2999 and with `Emacs' for the class key (the general one). */
3000 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3001 strcpy (class_key, EMACS_CLASS);
3002
3003 strcat (class_key, ".");
3004 strcat (class_key, XSTRING (class)->data);
3005
3006 if (!NILP (component))
3007 {
3008 strcat (class_key, ".");
3009 strcat (class_key, XSTRING (subclass)->data);
3010
3011 strcat (name_key, ".");
3012 strcat (name_key, XSTRING (component)->data);
3013 }
3014
3015 strcat (name_key, ".");
3016 strcat (name_key, XSTRING (attribute)->data);
3017
3018 value = x_get_string_resource (Qnil,
3019 name_key, class_key);
3020
3021 if (value != (char *) 0)
3022 return build_string (value);
3023 else
3024 return Qnil;
3025}
3026
3027/* Used when C code wants a resource value. */
3028
3029char *
3030x_get_resource_string (attribute, class)
3031 char *attribute, *class;
3032{
ee78dc32
GV
3033 char *name_key;
3034 char *class_key;
6fc2811b 3035 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3036
3037 /* Allocate space for the components, the dots which separate them,
3038 and the final '\0'. */
dfff8a69 3039 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3040 + strlen (attribute) + 2);
3041 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3042 + strlen (class) + 2);
3043
3044 sprintf (name_key, "%s.%s",
3045 XSTRING (Vinvocation_name)->data,
3046 attribute);
3047 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3048
6fc2811b 3049 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3050}
3051
3052/* Types we might convert a resource string into. */
3053enum resource_types
6fc2811b
JR
3054{
3055 RES_TYPE_NUMBER,
3056 RES_TYPE_FLOAT,
3057 RES_TYPE_BOOLEAN,
3058 RES_TYPE_STRING,
3059 RES_TYPE_SYMBOL
3060};
ee78dc32
GV
3061
3062/* Return the value of parameter PARAM.
3063
3064 First search ALIST, then Vdefault_frame_alist, then the X defaults
3065 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3066
3067 Convert the resource to the type specified by desired_type.
3068
3069 If no default is specified, return Qunbound. If you call
6fc2811b 3070 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3071 and don't let it get stored in any Lisp-visible variables! */
3072
3073static Lisp_Object
6fc2811b 3074w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3075 Lisp_Object alist, param;
3076 char *attribute;
3077 char *class;
3078 enum resource_types type;
3079{
3080 register Lisp_Object tem;
3081
3082 tem = Fassq (param, alist);
3083 if (EQ (tem, Qnil))
3084 tem = Fassq (param, Vdefault_frame_alist);
3085 if (EQ (tem, Qnil))
3086 {
3087
3088 if (attribute)
3089 {
3090 tem = Fx_get_resource (build_string (attribute),
3091 build_string (class),
3092 Qnil, Qnil);
3093
3094 if (NILP (tem))
3095 return Qunbound;
3096
3097 switch (type)
3098 {
6fc2811b 3099 case RES_TYPE_NUMBER:
ee78dc32
GV
3100 return make_number (atoi (XSTRING (tem)->data));
3101
6fc2811b
JR
3102 case RES_TYPE_FLOAT:
3103 return make_float (atof (XSTRING (tem)->data));
3104
3105 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3106 tem = Fdowncase (tem);
3107 if (!strcmp (XSTRING (tem)->data, "on")
3108 || !strcmp (XSTRING (tem)->data, "true"))
3109 return Qt;
3110 else
3111 return Qnil;
3112
6fc2811b 3113 case RES_TYPE_STRING:
ee78dc32
GV
3114 return tem;
3115
6fc2811b 3116 case RES_TYPE_SYMBOL:
ee78dc32
GV
3117 /* As a special case, we map the values `true' and `on'
3118 to Qt, and `false' and `off' to Qnil. */
3119 {
3120 Lisp_Object lower;
3121 lower = Fdowncase (tem);
3122 if (!strcmp (XSTRING (lower)->data, "on")
3123 || !strcmp (XSTRING (lower)->data, "true"))
3124 return Qt;
3125 else if (!strcmp (XSTRING (lower)->data, "off")
3126 || !strcmp (XSTRING (lower)->data, "false"))
3127 return Qnil;
3128 else
3129 return Fintern (tem, Qnil);
3130 }
3131
3132 default:
3133 abort ();
3134 }
3135 }
3136 else
3137 return Qunbound;
3138 }
3139 return Fcdr (tem);
3140}
3141
3142/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3143 of the parameter named PROP (a Lisp symbol).
3144 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3145 on the frame named NAME.
3146 If that is not found either, use the value DEFLT. */
3147
3148static Lisp_Object
3149x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3150 struct frame *f;
3151 Lisp_Object alist;
3152 Lisp_Object prop;
3153 Lisp_Object deflt;
3154 char *xprop;
3155 char *xclass;
3156 enum resource_types type;
3157{
3158 Lisp_Object tem;
3159
6fc2811b 3160 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3161 if (EQ (tem, Qunbound))
3162 tem = deflt;
3163 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3164 return tem;
3165}
3166\f
3167DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3168 doc: /* Parse an X-style geometry string STRING.
3169Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3170The properties returned may include `top', `left', `height', and `width'.
3171The value of `left' or `top' may be an integer,
3172or a list (+ N) meaning N pixels relative to top/left corner,
3173or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3174 (string)
3175 Lisp_Object string;
3176{
3177 int geometry, x, y;
3178 unsigned int width, height;
3179 Lisp_Object result;
3180
b7826503 3181 CHECK_STRING (string);
ee78dc32
GV
3182
3183 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3184 &x, &y, &width, &height);
3185
3186 result = Qnil;
3187 if (geometry & XValue)
3188 {
3189 Lisp_Object element;
3190
3191 if (x >= 0 && (geometry & XNegative))
3192 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3193 else if (x < 0 && ! (geometry & XNegative))
3194 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3195 else
3196 element = Fcons (Qleft, make_number (x));
3197 result = Fcons (element, result);
3198 }
3199
3200 if (geometry & YValue)
3201 {
3202 Lisp_Object element;
3203
3204 if (y >= 0 && (geometry & YNegative))
3205 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3206 else if (y < 0 && ! (geometry & YNegative))
3207 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3208 else
3209 element = Fcons (Qtop, make_number (y));
3210 result = Fcons (element, result);
3211 }
3212
3213 if (geometry & WidthValue)
3214 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3215 if (geometry & HeightValue)
3216 result = Fcons (Fcons (Qheight, make_number (height)), result);
3217
3218 return result;
3219}
3220
3221/* Calculate the desired size and position of this window,
3222 and return the flags saying which aspects were specified.
3223
3224 This function does not make the coordinates positive. */
3225
3226#define DEFAULT_ROWS 40
3227#define DEFAULT_COLS 80
3228
3229static int
3230x_figure_window_size (f, parms)
3231 struct frame *f;
3232 Lisp_Object parms;
3233{
3234 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3235 long window_prompting = 0;
3236
3237 /* Default values if we fall through.
3238 Actually, if that happens we should get
3239 window manager prompting. */
1026b400 3240 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3241 f->height = DEFAULT_ROWS;
3242 /* Window managers expect that if program-specified
3243 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3244 f->output_data.w32->top_pos = 0;
3245 f->output_data.w32->left_pos = 0;
ee78dc32 3246
35b41202
JR
3247 /* Ensure that old new_width and new_height will not override the
3248 values set here. */
3249 FRAME_NEW_WIDTH (f) = 0;
3250 FRAME_NEW_HEIGHT (f) = 0;
3251
6fc2811b
JR
3252 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3253 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3254 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3255 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3256 {
3257 if (!EQ (tem0, Qunbound))
3258 {
b7826503 3259 CHECK_NUMBER (tem0);
ee78dc32
GV
3260 f->height = XINT (tem0);
3261 }
3262 if (!EQ (tem1, Qunbound))
3263 {
b7826503 3264 CHECK_NUMBER (tem1);
1026b400 3265 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3266 }
3267 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3268 window_prompting |= USSize;
3269 else
3270 window_prompting |= PSize;
3271 }
3272
fbd6baed 3273 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3274 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3275 ? 0
3276 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3277 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3278 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
41c1bdd9 3279 x_compute_fringe_widths (f, 0);
fbd6baed
GV
3280 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3281 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3282
6fc2811b
JR
3283 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3284 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3285 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3286 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3287 {
3288 if (EQ (tem0, Qminus))
3289 {
fbd6baed 3290 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3291 window_prompting |= YNegative;
3292 }
8e713be6
KR
3293 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3294 && CONSP (XCDR (tem0))
3295 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3296 {
8e713be6 3297 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3298 window_prompting |= YNegative;
3299 }
8e713be6
KR
3300 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3301 && CONSP (XCDR (tem0))
3302 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3303 {
8e713be6 3304 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3305 }
3306 else if (EQ (tem0, Qunbound))
fbd6baed 3307 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3308 else
3309 {
b7826503 3310 CHECK_NUMBER (tem0);
fbd6baed
GV
3311 f->output_data.w32->top_pos = XINT (tem0);
3312 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3313 window_prompting |= YNegative;
3314 }
3315
3316 if (EQ (tem1, Qminus))
3317 {
fbd6baed 3318 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3319 window_prompting |= XNegative;
3320 }
8e713be6
KR
3321 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3322 && CONSP (XCDR (tem1))
3323 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3324 {
8e713be6 3325 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3326 window_prompting |= XNegative;
3327 }
8e713be6
KR
3328 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3329 && CONSP (XCDR (tem1))
3330 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3331 {
8e713be6 3332 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3333 }
3334 else if (EQ (tem1, Qunbound))
fbd6baed 3335 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3336 else
3337 {
b7826503 3338 CHECK_NUMBER (tem1);
fbd6baed
GV
3339 f->output_data.w32->left_pos = XINT (tem1);
3340 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3341 window_prompting |= XNegative;
3342 }
3343
3344 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3345 window_prompting |= USPosition;
3346 else
3347 window_prompting |= PPosition;
3348 }
3349
3350 return window_prompting;
3351}
3352
3353\f
3354
fbd6baed 3355extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3356
3357BOOL
fbd6baed 3358w32_init_class (hinst)
ee78dc32
GV
3359 HINSTANCE hinst;
3360{
3361 WNDCLASS wc;
3362
5ac45f98 3363 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3364 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3365 wc.cbClsExtra = 0;
3366 wc.cbWndExtra = WND_EXTRA_BYTES;
3367 wc.hInstance = hinst;
3368 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3369 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3370 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3371 wc.lpszMenuName = NULL;
3372 wc.lpszClassName = EMACS_CLASS;
3373
3374 return (RegisterClass (&wc));
3375}
3376
3377HWND
fbd6baed 3378w32_createscrollbar (f, bar)
ee78dc32
GV
3379 struct frame *f;
3380 struct scroll_bar * bar;
3381{
3382 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3383 /* Position and size of scroll bar. */
6fc2811b
JR
3384 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3385 XINT(bar->top),
3386 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3387 XINT(bar->height),
fbd6baed 3388 FRAME_W32_WINDOW (f),
ee78dc32
GV
3389 NULL,
3390 hinst,
3391 NULL));
3392}
3393
3394void
fbd6baed 3395w32_createwindow (f)
ee78dc32
GV
3396 struct frame *f;
3397{
3398 HWND hwnd;
1edf84e7
GV
3399 RECT rect;
3400
3401 rect.left = rect.top = 0;
3402 rect.right = PIXEL_WIDTH (f);
3403 rect.bottom = PIXEL_HEIGHT (f);
3404
3405 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3406 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3407
3408 /* Do first time app init */
3409
3410 if (!hprevinst)
3411 {
fbd6baed 3412 w32_init_class (hinst);
ee78dc32
GV
3413 }
3414
1edf84e7
GV
3415 FRAME_W32_WINDOW (f) = hwnd
3416 = CreateWindow (EMACS_CLASS,
3417 f->namebuf,
9ead1b60 3418 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3419 f->output_data.w32->left_pos,
3420 f->output_data.w32->top_pos,
3421 rect.right - rect.left,
3422 rect.bottom - rect.top,
3423 NULL,
3424 NULL,
3425 hinst,
3426 NULL);
3427
ee78dc32
GV
3428 if (hwnd)
3429 {
1edf84e7
GV
3430 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3431 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3432 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3433 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3434 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3435
cb9e33d4
RS
3436 /* Enable drag-n-drop. */
3437 DragAcceptFiles (hwnd, TRUE);
3438
5ac45f98
GV
3439 /* Do this to discard the default setting specified by our parent. */
3440 ShowWindow (hwnd, SW_HIDE);
3c190163 3441 }
3c190163
GV
3442}
3443
ee78dc32
GV
3444void
3445my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3446 W32Msg * wmsg;
ee78dc32
GV
3447 HWND hwnd;
3448 UINT msg;
3449 WPARAM wParam;
3450 LPARAM lParam;
3451{
3452 wmsg->msg.hwnd = hwnd;
3453 wmsg->msg.message = msg;
3454 wmsg->msg.wParam = wParam;
3455 wmsg->msg.lParam = lParam;
3456 wmsg->msg.time = GetMessageTime ();
3457
3458 post_msg (wmsg);
3459}
3460
e9e23e23 3461/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3462 between left and right keys as advertised. We test for this
3463 support dynamically, and set a flag when the support is absent. If
3464 absent, we keep track of the left and right control and alt keys
3465 ourselves. This is particularly necessary on keyboards that rely
3466 upon the AltGr key, which is represented as having the left control
3467 and right alt keys pressed. For these keyboards, we need to know
3468 when the left alt key has been pressed in addition to the AltGr key
3469 so that we can properly support M-AltGr-key sequences (such as M-@
3470 on Swedish keyboards). */
3471
3472#define EMACS_LCONTROL 0
3473#define EMACS_RCONTROL 1
3474#define EMACS_LMENU 2
3475#define EMACS_RMENU 3
3476
3477static int modifiers[4];
3478static int modifiers_recorded;
3479static int modifier_key_support_tested;
3480
3481static void
3482test_modifier_support (unsigned int wparam)
3483{
3484 unsigned int l, r;
3485
3486 if (wparam != VK_CONTROL && wparam != VK_MENU)
3487 return;
3488 if (wparam == VK_CONTROL)
3489 {
3490 l = VK_LCONTROL;
3491 r = VK_RCONTROL;
3492 }
3493 else
3494 {
3495 l = VK_LMENU;
3496 r = VK_RMENU;
3497 }
3498 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3499 modifiers_recorded = 1;
3500 else
3501 modifiers_recorded = 0;
3502 modifier_key_support_tested = 1;
3503}
3504
3505static void
3506record_keydown (unsigned int wparam, unsigned int lparam)
3507{
3508 int i;
3509
3510 if (!modifier_key_support_tested)
3511 test_modifier_support (wparam);
3512
3513 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3514 return;
3515
3516 if (wparam == VK_CONTROL)
3517 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3518 else
3519 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3520
3521 modifiers[i] = 1;
3522}
3523
3524static void
3525record_keyup (unsigned int wparam, unsigned int lparam)
3526{
3527 int i;
3528
3529 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3530 return;
3531
3532 if (wparam == VK_CONTROL)
3533 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3534 else
3535 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3536
3537 modifiers[i] = 0;
3538}
3539
da36a4d6
GV
3540/* Emacs can lose focus while a modifier key has been pressed. When
3541 it regains focus, be conservative and clear all modifiers since
3542 we cannot reconstruct the left and right modifier state. */
3543static void
3544reset_modifiers ()
3545{
8681157a
RS
3546 SHORT ctrl, alt;
3547
adcc3809
GV
3548 if (GetFocus () == NULL)
3549 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3550 return;
8681157a
RS
3551
3552 ctrl = GetAsyncKeyState (VK_CONTROL);
3553 alt = GetAsyncKeyState (VK_MENU);
3554
8681157a
RS
3555 if (!(ctrl & 0x08000))
3556 /* Clear any recorded control modifier state. */
3557 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3558
3559 if (!(alt & 0x08000))
3560 /* Clear any recorded alt modifier state. */
3561 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3562
adcc3809
GV
3563 /* Update the state of all modifier keys, because modifiers used in
3564 hot-key combinations can get stuck on if Emacs loses focus as a
3565 result of a hot-key being pressed. */
3566 {
3567 BYTE keystate[256];
3568
3569#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3570
3571 GetKeyboardState (keystate);
3572 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3573 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3574 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3575 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3576 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3577 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3578 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3579 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3580 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3581 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3582 SetKeyboardState (keystate);
3583 }
da36a4d6
GV
3584}
3585
7830e24b
RS
3586/* Synchronize modifier state with what is reported with the current
3587 keystroke. Even if we cannot distinguish between left and right
3588 modifier keys, we know that, if no modifiers are set, then neither
3589 the left or right modifier should be set. */
3590static void
3591sync_modifiers ()
3592{
3593 if (!modifiers_recorded)
3594 return;
3595
3596 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3597 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3598
3599 if (!(GetKeyState (VK_MENU) & 0x8000))
3600 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3601}
3602
a1a80b40
GV
3603static int
3604modifier_set (int vkey)
3605{
ccc2d29c 3606 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3607 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3608 if (!modifiers_recorded)
3609 return (GetKeyState (vkey) & 0x8000);
3610
3611 switch (vkey)
3612 {
3613 case VK_LCONTROL:
3614 return modifiers[EMACS_LCONTROL];
3615 case VK_RCONTROL:
3616 return modifiers[EMACS_RCONTROL];
3617 case VK_LMENU:
3618 return modifiers[EMACS_LMENU];
3619 case VK_RMENU:
3620 return modifiers[EMACS_RMENU];
a1a80b40
GV
3621 }
3622 return (GetKeyState (vkey) & 0x8000);
3623}
3624
ccc2d29c
GV
3625/* Convert between the modifier bits W32 uses and the modifier bits
3626 Emacs uses. */
3627
3628unsigned int
3629w32_key_to_modifier (int key)
3630{
3631 Lisp_Object key_mapping;
3632
3633 switch (key)
3634 {
3635 case VK_LWIN:
3636 key_mapping = Vw32_lwindow_modifier;
3637 break;
3638 case VK_RWIN:
3639 key_mapping = Vw32_rwindow_modifier;
3640 break;
3641 case VK_APPS:
3642 key_mapping = Vw32_apps_modifier;
3643 break;
3644 case VK_SCROLL:
3645 key_mapping = Vw32_scroll_lock_modifier;
3646 break;
3647 default:
3648 key_mapping = Qnil;
3649 }
3650
adcc3809
GV
3651 /* NB. This code runs in the input thread, asychronously to the lisp
3652 thread, so we must be careful to ensure access to lisp data is
3653 thread-safe. The following code is safe because the modifier
3654 variable values are updated atomically from lisp and symbols are
3655 not relocated by GC. Also, we don't have to worry about seeing GC
3656 markbits here. */
3657 if (EQ (key_mapping, Qhyper))
ccc2d29c 3658 return hyper_modifier;
adcc3809 3659 if (EQ (key_mapping, Qsuper))
ccc2d29c 3660 return super_modifier;
adcc3809 3661 if (EQ (key_mapping, Qmeta))
ccc2d29c 3662 return meta_modifier;
adcc3809 3663 if (EQ (key_mapping, Qalt))
ccc2d29c 3664 return alt_modifier;
adcc3809 3665 if (EQ (key_mapping, Qctrl))
ccc2d29c 3666 return ctrl_modifier;
adcc3809 3667 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3668 return ctrl_modifier;
adcc3809 3669 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3670 return shift_modifier;
3671
3672 /* Don't generate any modifier if not explicitly requested. */
3673 return 0;
3674}
3675
3676unsigned int
3677w32_get_modifiers ()
3678{
3679 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3680 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3681 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3682 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3683 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3684 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3685 (modifier_set (VK_MENU) ?
3686 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3687}
3688
a1a80b40
GV
3689/* We map the VK_* modifiers into console modifier constants
3690 so that we can use the same routines to handle both console
3691 and window input. */
3692
3693static int
ccc2d29c 3694construct_console_modifiers ()
a1a80b40
GV
3695{
3696 int mods;
3697
a1a80b40
GV
3698 mods = 0;
3699 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3700 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3701 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3702 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3703 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3704 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3705 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3706 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3707 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3708 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3709 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3710
3711 return mods;
3712}
3713
ccc2d29c
GV
3714static int
3715w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3716{
ccc2d29c
GV
3717 int mods;
3718
3719 /* Convert to emacs modifiers. */
3720 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3721
3722 return mods;
3723}
da36a4d6 3724
ccc2d29c
GV
3725unsigned int
3726map_keypad_keys (unsigned int virt_key, unsigned int extended)
3727{
3728 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3729 return virt_key;
da36a4d6 3730
ccc2d29c 3731 if (virt_key == VK_RETURN)
da36a4d6
GV
3732 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3733
ccc2d29c
GV
3734 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3735 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3736
3737 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3738 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3739
3740 if (virt_key == VK_CLEAR)
3741 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3742
3743 return virt_key;
3744}
3745
3746/* List of special key combinations which w32 would normally capture,
3747 but emacs should grab instead. Not directly visible to lisp, to
3748 simplify synchronization. Each item is an integer encoding a virtual
3749 key code and modifier combination to capture. */
3750Lisp_Object w32_grabbed_keys;
3751
3752#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3753#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3754#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3755#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3756
3757/* Register hot-keys for reserved key combinations when Emacs has
3758 keyboard focus, since this is the only way Emacs can receive key
3759 combinations like Alt-Tab which are used by the system. */
3760
3761static void
3762register_hot_keys (hwnd)
3763 HWND hwnd;
3764{
3765 Lisp_Object keylist;
3766
3767 /* Use GC_CONSP, since we are called asynchronously. */
3768 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3769 {
3770 Lisp_Object key = XCAR (keylist);
3771
3772 /* Deleted entries get set to nil. */
3773 if (!INTEGERP (key))
3774 continue;
3775
3776 RegisterHotKey (hwnd, HOTKEY_ID (key),
3777 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3778 }
3779}
3780
3781static void
3782unregister_hot_keys (hwnd)
3783 HWND hwnd;
3784{
3785 Lisp_Object keylist;
3786
3787 /* Use GC_CONSP, since we are called asynchronously. */
3788 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3789 {
3790 Lisp_Object key = XCAR (keylist);
3791
3792 if (!INTEGERP (key))
3793 continue;
3794
3795 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3796 }
3797}
3798
5ac45f98
GV
3799/* Main message dispatch loop. */
3800
1edf84e7
GV
3801static void
3802w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3803{
3804 MSG msg;
ccc2d29c
GV
3805 int result;
3806 HWND focus_window;
93fbe8b7
GV
3807
3808 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3809
5ac45f98
GV
3810 while (GetMessage (&msg, NULL, 0, 0))
3811 {
3812 if (msg.hwnd == NULL)
3813 {
3814 switch (msg.message)
3815 {
3ef68e6b
AI
3816 case WM_NULL:
3817 /* Produced by complete_deferred_msg; just ignore. */
3818 break;
5ac45f98 3819 case WM_EMACS_CREATEWINDOW:
fbd6baed 3820 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3821 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3822 abort ();
5ac45f98 3823 break;
dfdb4047
GV
3824 case WM_EMACS_SETLOCALE:
3825 SetThreadLocale (msg.wParam);
3826 /* Reply is not expected. */
3827 break;
ccc2d29c
GV
3828 case WM_EMACS_SETKEYBOARDLAYOUT:
3829 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3830 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3831 result, 0))
3832 abort ();
3833 break;
3834 case WM_EMACS_REGISTER_HOT_KEY:
3835 focus_window = GetFocus ();
3836 if (focus_window != NULL)
3837 RegisterHotKey (focus_window,
3838 HOTKEY_ID (msg.wParam),
3839 HOTKEY_MODIFIERS (msg.wParam),
3840 HOTKEY_VK_CODE (msg.wParam));
3841 /* Reply is not expected. */
3842 break;
3843 case WM_EMACS_UNREGISTER_HOT_KEY:
3844 focus_window = GetFocus ();
3845 if (focus_window != NULL)
3846 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3847 /* Mark item as erased. NB: this code must be
3848 thread-safe. The next line is okay because the cons
3849 cell is never made into garbage and is not relocated by
3850 GC. */
f3fbd155 3851 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3852 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3853 abort ();
3854 break;
adcc3809
GV
3855 case WM_EMACS_TOGGLE_LOCK_KEY:
3856 {
3857 int vk_code = (int) msg.wParam;
3858 int cur_state = (GetKeyState (vk_code) & 1);
3859 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3860
3861 /* NB: This code must be thread-safe. It is safe to
3862 call NILP because symbols are not relocated by GC,
3863 and pointer here is not touched by GC (so the markbit
3864 can't be set). Numbers are safe because they are
3865 immediate values. */
3866 if (NILP (new_state)
3867 || (NUMBERP (new_state)
8edb0a6f 3868 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3869 {
3870 one_w32_display_info.faked_key = vk_code;
3871
3872 keybd_event ((BYTE) vk_code,
3873 (BYTE) MapVirtualKey (vk_code, 0),
3874 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3875 keybd_event ((BYTE) vk_code,
3876 (BYTE) MapVirtualKey (vk_code, 0),
3877 KEYEVENTF_EXTENDEDKEY | 0, 0);
3878 keybd_event ((BYTE) vk_code,
3879 (BYTE) MapVirtualKey (vk_code, 0),
3880 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3881 cur_state = !cur_state;
3882 }
3883 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3884 cur_state, 0))
3885 abort ();
3886 }
3887 break;
1edf84e7 3888 default:
1edf84e7 3889 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3890 }
3891 }
3892 else
3893 {
3894 DispatchMessage (&msg);
3895 }
1edf84e7
GV
3896
3897 /* Exit nested loop when our deferred message has completed. */
3898 if (msg_buf->completed)
3899 break;
5ac45f98 3900 }
1edf84e7
GV
3901}
3902
3903deferred_msg * deferred_msg_head;
3904
3905static deferred_msg *
3906find_deferred_msg (HWND hwnd, UINT msg)
3907{
3908 deferred_msg * item;
3909
3910 /* Don't actually need synchronization for read access, since
3911 modification of single pointer is always atomic. */
3912 /* enter_crit (); */
3913
3914 for (item = deferred_msg_head; item != NULL; item = item->next)
3915 if (item->w32msg.msg.hwnd == hwnd
3916 && item->w32msg.msg.message == msg)
3917 break;
3918
3919 /* leave_crit (); */
3920
3921 return item;
3922}
3923
3924static LRESULT
3925send_deferred_msg (deferred_msg * msg_buf,
3926 HWND hwnd,
3927 UINT msg,
3928 WPARAM wParam,
3929 LPARAM lParam)
3930{
3931 /* Only input thread can send deferred messages. */
3932 if (GetCurrentThreadId () != dwWindowsThreadId)
3933 abort ();
3934
3935 /* It is an error to send a message that is already deferred. */
3936 if (find_deferred_msg (hwnd, msg) != NULL)
3937 abort ();
3938
3939 /* Enforced synchronization is not needed because this is the only
3940 function that alters deferred_msg_head, and the following critical
3941 section is guaranteed to only be serially reentered (since only the
3942 input thread can call us). */
3943
3944 /* enter_crit (); */
3945
3946 msg_buf->completed = 0;
3947 msg_buf->next = deferred_msg_head;
3948 deferred_msg_head = msg_buf;
3949 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3950
3951 /* leave_crit (); */
3952
3953 /* Start a new nested message loop to process other messages until
3954 this one is completed. */
3955 w32_msg_pump (msg_buf);
3956
3957 deferred_msg_head = msg_buf->next;
3958
3959 return msg_buf->result;
3960}
3961
3962void
3963complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3964{
3965 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3966
3967 if (msg_buf == NULL)
3ef68e6b
AI
3968 /* Message may have been cancelled, so don't abort(). */
3969 return;
1edf84e7
GV
3970
3971 msg_buf->result = result;
3972 msg_buf->completed = 1;
3973
3974 /* Ensure input thread is woken so it notices the completion. */
3975 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3976}
3977
3ef68e6b
AI
3978void
3979cancel_all_deferred_msgs ()
3980{
3981 deferred_msg * item;
3982
3983 /* Don't actually need synchronization for read access, since
3984 modification of single pointer is always atomic. */
3985 /* enter_crit (); */
3986
3987 for (item = deferred_msg_head; item != NULL; item = item->next)
3988 {
3989 item->result = 0;
3990 item->completed = 1;
3991 }
3992
3993 /* leave_crit (); */
3994
3995 /* Ensure input thread is woken so it notices the completion. */
3996 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3997}
1edf84e7
GV
3998
3999DWORD
4000w32_msg_worker (dw)
4001 DWORD dw;
4002{
4003 MSG msg;
4004 deferred_msg dummy_buf;
4005
4006 /* Ensure our message queue is created */
4007
4008 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 4009
1edf84e7
GV
4010 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4011 abort ();
4012
4013 memset (&dummy_buf, 0, sizeof (dummy_buf));
4014 dummy_buf.w32msg.msg.hwnd = NULL;
4015 dummy_buf.w32msg.msg.message = WM_NULL;
4016
4017 /* This is the inital message loop which should only exit when the
4018 application quits. */
4019 w32_msg_pump (&dummy_buf);
4020
4021 return 0;
5ac45f98
GV
4022}
4023
3ef68e6b
AI
4024static void
4025post_character_message (hwnd, msg, wParam, lParam, modifiers)
4026 HWND hwnd;
4027 UINT msg;
4028 WPARAM wParam;
4029 LPARAM lParam;
4030 DWORD modifiers;
4031
4032{
4033 W32Msg wmsg;
4034
4035 wmsg.dwModifiers = modifiers;
4036
4037 /* Detect quit_char and set quit-flag directly. Note that we
4038 still need to post a message to ensure the main thread will be
4039 woken up if blocked in sys_select(), but we do NOT want to post
4040 the quit_char message itself (because it will usually be as if
4041 the user had typed quit_char twice). Instead, we post a dummy
4042 message that has no particular effect. */
4043 {
4044 int c = wParam;
4045 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4046 c = make_ctrl_char (c) & 0377;
7d081355
AI
4047 if (c == quit_char
4048 || (wmsg.dwModifiers == 0 &&
4049 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4050 {
4051 Vquit_flag = Qt;
4052
4053 /* The choice of message is somewhat arbitrary, as long as
4054 the main thread handler just ignores it. */
4055 msg = WM_NULL;
4056
4057 /* Interrupt any blocking system calls. */
4058 signal_quit ();
4059
4060 /* As a safety precaution, forcibly complete any deferred
4061 messages. This is a kludge, but I don't see any particularly
4062 clean way to handle the situation where a deferred message is
4063 "dropped" in the lisp thread, and will thus never be
4064 completed, eg. by the user trying to activate the menubar
4065 when the lisp thread is busy, and then typing C-g when the
4066 menubar doesn't open promptly (with the result that the
4067 menubar never responds at all because the deferred
4068 WM_INITMENU message is never completed). Another problem
4069 situation is when the lisp thread calls SendMessage (to send
4070 a window manager command) when a message has been deferred;
4071 the lisp thread gets blocked indefinitely waiting for the
4072 deferred message to be completed, which itself is waiting for
4073 the lisp thread to respond.
4074
4075 Note that we don't want to block the input thread waiting for
4076 a reponse from the lisp thread (although that would at least
4077 solve the deadlock problem above), because we want to be able
4078 to receive C-g to interrupt the lisp thread. */
4079 cancel_all_deferred_msgs ();
4080 }
4081 }
4082
4083 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4084}
4085
ee78dc32
GV
4086/* Main window procedure */
4087
ee78dc32 4088LRESULT CALLBACK
fbd6baed 4089w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4090 HWND hwnd;
4091 UINT msg;
4092 WPARAM wParam;
4093 LPARAM lParam;
4094{
4095 struct frame *f;
fbd6baed
GV
4096 struct w32_display_info *dpyinfo = &one_w32_display_info;
4097 W32Msg wmsg;
84fb1139 4098 int windows_translate;
576ba81c 4099 int key;
84fb1139 4100
a6085637
KH
4101 /* Note that it is okay to call x_window_to_frame, even though we are
4102 not running in the main lisp thread, because frame deletion
4103 requires the lisp thread to synchronize with this thread. Thus, if
4104 a frame struct is returned, it can be used without concern that the
4105 lisp thread might make it disappear while we are using it.
4106
4107 NB. Walking the frame list in this thread is safe (as long as
4108 writes of Lisp_Object slots are atomic, which they are on Windows).
4109 Although delete-frame can destructively modify the frame list while
4110 we are walking it, a garbage collection cannot occur until after
4111 delete-frame has synchronized with this thread.
4112
4113 It is also safe to use functions that make GDI calls, such as
fbd6baed 4114 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4115 from the frame struct using get_frame_dc which is thread-aware. */
4116
ee78dc32
GV
4117 switch (msg)
4118 {
4119 case WM_ERASEBKGND:
a6085637
KH
4120 f = x_window_to_frame (dpyinfo, hwnd);
4121 if (f)
4122 {
9badad41 4123 HDC hdc = get_frame_dc (f);
a6085637 4124 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4125 w32_clear_rect (f, hdc, &wmsg.rect);
4126 release_frame_dc (f, hdc);
ce6059da
AI
4127
4128#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4129 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4130 f,
4131 wmsg.rect.left, wmsg.rect.top,
4132 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4133#endif /* W32_DEBUG_DISPLAY */
a6085637 4134 }
5ac45f98
GV
4135 return 1;
4136 case WM_PALETTECHANGED:
4137 /* ignore our own changes */
4138 if ((HWND)wParam != hwnd)
4139 {
a6085637
KH
4140 f = x_window_to_frame (dpyinfo, hwnd);
4141 if (f)
4142 /* get_frame_dc will realize our palette and force all
4143 frames to be redrawn if needed. */
4144 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4145 }
4146 return 0;
ee78dc32 4147 case WM_PAINT:
ce6059da 4148 {
55dcfc15
AI
4149 PAINTSTRUCT paintStruct;
4150 RECT update_rect;
4151
18f0b342
AI
4152 f = x_window_to_frame (dpyinfo, hwnd);
4153 if (f == 0)
4154 {
4155 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4156 return 0;
4157 }
4158
55dcfc15
AI
4159 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4160 fails. Apparently this can happen under some
4161 circumstances. */
c0611964 4162 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
4163 {
4164 enter_crit ();
4165 BeginPaint (hwnd, &paintStruct);
4166
c0611964
AI
4167 if (w32_strict_painting)
4168 /* The rectangles returned by GetUpdateRect and BeginPaint
4169 do not always match. GetUpdateRect seems to be the
4170 more reliable of the two. */
4171 wmsg.rect = update_rect;
4172 else
4173 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
4174
4175#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4176 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4177 f,
4178 wmsg.rect.left, wmsg.rect.top,
4179 wmsg.rect.right, wmsg.rect.bottom));
4180 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4181 update_rect.left, update_rect.top,
4182 update_rect.right, update_rect.bottom));
4183#endif
4184 EndPaint (hwnd, &paintStruct);
4185 leave_crit ();
4186
4187 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4188
4189 return 0;
4190 }
c0611964
AI
4191
4192 /* If GetUpdateRect returns 0 (meaning there is no update
4193 region), assume the whole window needs to be repainted. */
4194 GetClientRect(hwnd, &wmsg.rect);
4195 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4196 return 0;
ee78dc32 4197 }
a1a80b40 4198
ccc2d29c
GV
4199 case WM_INPUTLANGCHANGE:
4200 /* Inform lisp thread of keyboard layout changes. */
4201 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4202
4203 /* Clear dead keys in the keyboard state; for simplicity only
4204 preserve modifier key states. */
4205 {
4206 int i;
4207 BYTE keystate[256];
4208
4209 GetKeyboardState (keystate);
4210 for (i = 0; i < 256; i++)
4211 if (1
4212 && i != VK_SHIFT
4213 && i != VK_LSHIFT
4214 && i != VK_RSHIFT
4215 && i != VK_CAPITAL
4216 && i != VK_NUMLOCK
4217 && i != VK_SCROLL
4218 && i != VK_CONTROL
4219 && i != VK_LCONTROL
4220 && i != VK_RCONTROL
4221 && i != VK_MENU
4222 && i != VK_LMENU
4223 && i != VK_RMENU
4224 && i != VK_LWIN
4225 && i != VK_RWIN)
4226 keystate[i] = 0;
4227 SetKeyboardState (keystate);
4228 }
4229 goto dflt;
4230
4231 case WM_HOTKEY:
4232 /* Synchronize hot keys with normal input. */
4233 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4234 return (0);
4235
a1a80b40
GV
4236 case WM_KEYUP:
4237 case WM_SYSKEYUP:
4238 record_keyup (wParam, lParam);
4239 goto dflt;
4240
ee78dc32
GV
4241 case WM_KEYDOWN:
4242 case WM_SYSKEYDOWN:
ccc2d29c
GV
4243 /* Ignore keystrokes we fake ourself; see below. */
4244 if (dpyinfo->faked_key == wParam)
4245 {
4246 dpyinfo->faked_key = 0;
576ba81c
AI
4247 /* Make sure TranslateMessage sees them though (as long as
4248 they don't produce WM_CHAR messages). This ensures that
4249 indicator lights are toggled promptly on Windows 9x, for
4250 example. */
4251 if (lispy_function_keys[wParam] != 0)
4252 {
4253 windows_translate = 1;
4254 goto translate;
4255 }
4256 return 0;
ccc2d29c
GV
4257 }
4258
7830e24b
RS
4259 /* Synchronize modifiers with current keystroke. */
4260 sync_modifiers ();
a1a80b40 4261 record_keydown (wParam, lParam);
ccc2d29c 4262 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4263
4264 windows_translate = 0;
ccc2d29c
GV
4265
4266 switch (wParam)
4267 {
4268 case VK_LWIN:
4269 if (NILP (Vw32_pass_lwindow_to_system))
4270 {
4271 /* Prevent system from acting on keyup (which opens the
4272 Start menu if no other key was pressed) by simulating a
4273 press of Space which we will ignore. */
4274 if (GetAsyncKeyState (wParam) & 1)
4275 {
adcc3809 4276 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4277 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4278 else
576ba81c
AI
4279 key = VK_SPACE;
4280 dpyinfo->faked_key = key;
4281 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4282 }
4283 }
4284 if (!NILP (Vw32_lwindow_modifier))
4285 return 0;
4286 break;
4287 case VK_RWIN:
4288 if (NILP (Vw32_pass_rwindow_to_system))
4289 {
4290 if (GetAsyncKeyState (wParam) & 1)
4291 {
adcc3809 4292 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4293 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4294 else
576ba81c
AI
4295 key = VK_SPACE;
4296 dpyinfo->faked_key = key;
4297 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4298 }
4299 }
4300 if (!NILP (Vw32_rwindow_modifier))
4301 return 0;
4302 break;
576ba81c 4303 case VK_APPS:
ccc2d29c
GV
4304 if (!NILP (Vw32_apps_modifier))
4305 return 0;
4306 break;
4307 case VK_MENU:
4308 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4309 /* Prevent DefWindowProc from activating the menu bar if an
4310 Alt key is pressed and released by itself. */
ccc2d29c 4311 return 0;
84fb1139 4312 windows_translate = 1;
ccc2d29c
GV
4313 break;
4314 case VK_CAPITAL:
4315 /* Decide whether to treat as modifier or function key. */
4316 if (NILP (Vw32_enable_caps_lock))
4317 goto disable_lock_key;
adcc3809
GV
4318 windows_translate = 1;
4319 break;
ccc2d29c
GV
4320 case VK_NUMLOCK:
4321 /* Decide whether to treat as modifier or function key. */
4322 if (NILP (Vw32_enable_num_lock))
4323 goto disable_lock_key;
adcc3809
GV
4324 windows_translate = 1;
4325 break;
ccc2d29c
GV
4326 case VK_SCROLL:
4327 /* Decide whether to treat as modifier or function key. */
4328 if (NILP (Vw32_scroll_lock_modifier))
4329 goto disable_lock_key;
adcc3809
GV
4330 windows_translate = 1;
4331 break;
ccc2d29c 4332 disable_lock_key:
adcc3809
GV
4333 /* Ensure the appropriate lock key state (and indicator light)
4334 remains in the same state. We do this by faking another
4335 press of the relevant key. Apparently, this really is the
4336 only way to toggle the state of the indicator lights. */
4337 dpyinfo->faked_key = wParam;
4338 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4339 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4340 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4341 KEYEVENTF_EXTENDEDKEY | 0, 0);
4342 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4343 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4344 /* Ensure indicator lights are updated promptly on Windows 9x
4345 (TranslateMessage apparently does this), after forwarding
4346 input event. */
4347 post_character_message (hwnd, msg, wParam, lParam,
4348 w32_get_key_modifiers (wParam, lParam));
4349 windows_translate = 1;
ccc2d29c
GV
4350 break;
4351 case VK_CONTROL:
4352 case VK_SHIFT:
4353 case VK_PROCESSKEY: /* Generated by IME. */
4354 windows_translate = 1;
4355 break;
adcc3809
GV
4356 case VK_CANCEL:
4357 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4358 which is confusing for purposes of key binding; convert
4359 VK_CANCEL events into VK_PAUSE events. */
4360 wParam = VK_PAUSE;
4361 break;
4362 case VK_PAUSE:
4363 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4364 for purposes of key binding; convert these back into
4365 VK_NUMLOCK events, at least when we want to see NumLock key
4366 presses. (Note that there is never any possibility that
4367 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4368 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4369 wParam = VK_NUMLOCK;
4370 break;
ccc2d29c
GV
4371 default:
4372 /* If not defined as a function key, change it to a WM_CHAR message. */
4373 if (lispy_function_keys[wParam] == 0)
4374 {
adcc3809
GV
4375 DWORD modifiers = construct_console_modifiers ();
4376
ccc2d29c
GV
4377 if (!NILP (Vw32_recognize_altgr)
4378 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4379 {
4380 /* Always let TranslateMessage handle AltGr key chords;
4381 for some reason, ToAscii doesn't always process AltGr
4382 chords correctly. */
4383 windows_translate = 1;
4384 }
adcc3809 4385 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4386 {
adcc3809
GV
4387 /* Handle key chords including any modifiers other
4388 than shift directly, in order to preserve as much
4389 modifier information as possible. */
ccc2d29c
GV
4390 if ('A' <= wParam && wParam <= 'Z')
4391 {
4392 /* Don't translate modified alphabetic keystrokes,
4393 so the user doesn't need to constantly switch
4394 layout to type control or meta keystrokes when
4395 the normal layout translates alphabetic
4396 characters to non-ascii characters. */
4397 if (!modifier_set (VK_SHIFT))
4398 wParam += ('a' - 'A');
4399 msg = WM_CHAR;
4400 }
4401 else
4402 {
4403 /* Try to handle other keystrokes by determining the
4404 base character (ie. translating the base key plus
4405 shift modifier). */
4406 int add;
4407 int isdead = 0;
4408 KEY_EVENT_RECORD key;
4409
4410 key.bKeyDown = TRUE;
4411 key.wRepeatCount = 1;
4412 key.wVirtualKeyCode = wParam;
4413 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4414 key.uChar.AsciiChar = 0;
adcc3809 4415 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4416
4417 add = w32_kbd_patch_key (&key);
4418 /* 0 means an unrecognised keycode, negative means
4419 dead key. Ignore both. */
4420 while (--add >= 0)
4421 {
4422 /* Forward asciified character sequence. */
4423 post_character_message
4424 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4425 w32_get_key_modifiers (wParam, lParam));
4426 w32_kbd_patch_key (&key);
4427 }
4428 return 0;
4429 }
4430 }
4431 else
4432 {
4433 /* Let TranslateMessage handle everything else. */
4434 windows_translate = 1;
4435 }
4436 }
4437 }
a1a80b40 4438
adcc3809 4439 translate:
84fb1139
KH
4440 if (windows_translate)
4441 {
e9e23e23 4442 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4443
e9e23e23
GV
4444 windows_msg.time = GetMessageTime ();
4445 TranslateMessage (&windows_msg);
84fb1139
KH
4446 goto dflt;
4447 }
4448
ee78dc32
GV
4449 /* Fall through */
4450
4451 case WM_SYSCHAR:
4452 case WM_CHAR:
ccc2d29c
GV
4453 post_character_message (hwnd, msg, wParam, lParam,
4454 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4455 break;
da36a4d6 4456
5ac45f98
GV
4457 /* Simulate middle mouse button events when left and right buttons
4458 are used together, but only if user has two button mouse. */
ee78dc32 4459 case WM_LBUTTONDOWN:
5ac45f98 4460 case WM_RBUTTONDOWN:
7ce9aaca 4461 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4462 goto handle_plain_button;
4463
4464 {
4465 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4466 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4467
3cb20f4a
RS
4468 if (button_state & this)
4469 return 0;
5ac45f98
GV
4470
4471 if (button_state == 0)
4472 SetCapture (hwnd);
4473
4474 button_state |= this;
4475
4476 if (button_state & other)
4477 {
84fb1139 4478 if (mouse_button_timer)
5ac45f98 4479 {
84fb1139
KH
4480 KillTimer (hwnd, mouse_button_timer);
4481 mouse_button_timer = 0;
5ac45f98
GV
4482
4483 /* Generate middle mouse event instead. */
4484 msg = WM_MBUTTONDOWN;
4485 button_state |= MMOUSE;
4486 }
4487 else if (button_state & MMOUSE)
4488 {
4489 /* Ignore button event if we've already generated a
4490 middle mouse down event. This happens if the
4491 user releases and press one of the two buttons
4492 after we've faked a middle mouse event. */
4493 return 0;
4494 }
4495 else
4496 {
4497 /* Flush out saved message. */
84fb1139 4498 post_msg (&saved_mouse_button_msg);
5ac45f98 4499 }
fbd6baed 4500 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4501 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4502
4503 /* Clear message buffer. */
84fb1139 4504 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4505 }
4506 else
4507 {
4508 /* Hold onto message for now. */
84fb1139 4509 mouse_button_timer =
adcc3809
GV
4510 SetTimer (hwnd, MOUSE_BUTTON_ID,
4511 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4512 saved_mouse_button_msg.msg.hwnd = hwnd;
4513 saved_mouse_button_msg.msg.message = msg;
4514 saved_mouse_button_msg.msg.wParam = wParam;
4515 saved_mouse_button_msg.msg.lParam = lParam;
4516 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4517 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4518 }
4519 }
4520 return 0;
4521
ee78dc32 4522 case WM_LBUTTONUP:
5ac45f98 4523 case WM_RBUTTONUP:
7ce9aaca 4524 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4525 goto handle_plain_button;
4526
4527 {
4528 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4529 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4530
3cb20f4a
RS
4531 if ((button_state & this) == 0)
4532 return 0;
5ac45f98
GV
4533
4534 button_state &= ~this;
4535
4536 if (button_state & MMOUSE)
4537 {
4538 /* Only generate event when second button is released. */
4539 if ((button_state & other) == 0)
4540 {
4541 msg = WM_MBUTTONUP;
4542 button_state &= ~MMOUSE;
4543
4544 if (button_state) abort ();
4545 }
4546 else
4547 return 0;
4548 }
4549 else
4550 {
4551 /* Flush out saved message if necessary. */
84fb1139 4552 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4553 {
84fb1139 4554 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4555 }
4556 }
fbd6baed 4557 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4558 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4559
4560 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4561 saved_mouse_button_msg.msg.hwnd = 0;
4562 KillTimer (hwnd, mouse_button_timer);
4563 mouse_button_timer = 0;
5ac45f98
GV
4564
4565 if (button_state == 0)
4566 ReleaseCapture ();
4567 }
4568 return 0;
4569
ee78dc32
GV
4570 case WM_MBUTTONDOWN:
4571 case WM_MBUTTONUP:
5ac45f98 4572 handle_plain_button:
ee78dc32
GV
4573 {
4574 BOOL up;
1edf84e7 4575 int button;
ee78dc32 4576
1edf84e7 4577 if (parse_button (msg, &button, &up))
ee78dc32
GV
4578 {
4579 if (up) ReleaseCapture ();
4580 else SetCapture (hwnd);
1edf84e7
GV
4581 button = (button == 0) ? LMOUSE :
4582 ((button == 1) ? MMOUSE : RMOUSE);
4583 if (up)
4584 button_state &= ~button;
4585 else
4586 button_state |= button;
ee78dc32
GV
4587 }
4588 }
4589
fbd6baed 4590 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4591 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5ac45f98
GV
4592 return 0;
4593
5ac45f98 4594 case WM_MOUSEMOVE:
9eb16b62
JR
4595 /* If the mouse has just moved into the frame, start tracking
4596 it, so we will be notified when it leaves the frame. Mouse
4597 tracking only works under W98 and NT4 and later. On earlier
4598 versions, there is no way of telling when the mouse leaves the
4599 frame, so we just have to put up with help-echo and mouse
4600 highlighting remaining while the frame is not active. */
4601 if (track_mouse_event_fn && !track_mouse_window)
4602 {
4603 TRACKMOUSEEVENT tme;
4604 tme.cbSize = sizeof (tme);
4605 tme.dwFlags = TME_LEAVE;
4606 tme.hwndTrack = hwnd;
4607
4608 track_mouse_event_fn (&tme);
4609 track_mouse_window = hwnd;
4610 }
4611 case WM_VSCROLL:
fbd6baed 4612 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4613 || (msg == WM_MOUSEMOVE && button_state == 0))
4614 {
fbd6baed 4615 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4616 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4617 return 0;
4618 }
4619
4620 /* Hang onto mouse move and scroll messages for a bit, to avoid
4621 sending such events to Emacs faster than it can process them.
4622 If we get more events before the timer from the first message
4623 expires, we just replace the first message. */
4624
4625 if (saved_mouse_move_msg.msg.hwnd == 0)
4626 mouse_move_timer =
adcc3809
GV
4627 SetTimer (hwnd, MOUSE_MOVE_ID,
4628 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4629
4630 /* Hold onto message for now. */
4631 saved_mouse_move_msg.msg.hwnd = hwnd;
4632 saved_mouse_move_msg.msg.message = msg;
4633 saved_mouse_move_msg.msg.wParam = wParam;
4634 saved_mouse_move_msg.msg.lParam = lParam;
4635 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4636 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4637
4638 return 0;
4639
1edf84e7
GV
4640 case WM_MOUSEWHEEL:
4641 wmsg.dwModifiers = w32_get_modifiers ();
4642 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4643 return 0;
4644
cb9e33d4
RS
4645 case WM_DROPFILES:
4646 wmsg.dwModifiers = w32_get_modifiers ();
4647 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4648 return 0;
4649
84fb1139
KH
4650 case WM_TIMER:
4651 /* Flush out saved messages if necessary. */
4652 if (wParam == mouse_button_timer)
5ac45f98 4653 {
84fb1139
KH
4654 if (saved_mouse_button_msg.msg.hwnd)
4655 {
4656 post_msg (&saved_mouse_button_msg);
4657 saved_mouse_button_msg.msg.hwnd = 0;
4658 }
4659 KillTimer (hwnd, mouse_button_timer);
4660 mouse_button_timer = 0;
4661 }
4662 else if (wParam == mouse_move_timer)
4663 {
4664 if (saved_mouse_move_msg.msg.hwnd)
4665 {
4666 post_msg (&saved_mouse_move_msg);
4667 saved_mouse_move_msg.msg.hwnd = 0;
4668 }
4669 KillTimer (hwnd, mouse_move_timer);
4670 mouse_move_timer = 0;
5ac45f98 4671 }
5ac45f98 4672 return 0;
84fb1139
KH
4673
4674 case WM_NCACTIVATE:
4675 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4676 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4677 The only indication we get that something happened is receiving
4678 this message afterwards. So this is a good time to reset our
4679 keyboard modifiers' state. */
4680 reset_modifiers ();
4681 goto dflt;
da36a4d6 4682
1edf84e7 4683 case WM_INITMENU:
487163ac
AI
4684 button_state = 0;
4685 ReleaseCapture ();
1edf84e7
GV
4686 /* We must ensure menu bar is fully constructed and up to date
4687 before allowing user interaction with it. To achieve this
4688 we send this message to the lisp thread and wait for a
4689 reply (whose value is not actually needed) to indicate that
4690 the menu bar is now ready for use, so we can now return.
4691
4692 To remain responsive in the meantime, we enter a nested message
4693 loop that can process all other messages.
4694
4695 However, we skip all this if the message results from calling
4696 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4697 thread a message because it is blocked on us at this point. We
4698 set menubar_active before calling TrackPopupMenu to indicate
4699 this (there is no possibility of confusion with real menubar
4700 being active). */
4701
4702 f = x_window_to_frame (dpyinfo, hwnd);
4703 if (f
4704 && (f->output_data.w32->menubar_active
4705 /* We can receive this message even in the absence of a
4706 menubar (ie. when the system menu is activated) - in this
4707 case we do NOT want to forward the message, otherwise it
4708 will cause the menubar to suddenly appear when the user
4709 had requested it to be turned off! */
4710 || f->output_data.w32->menubar_widget == NULL))
4711 return 0;
4712
4713 {
4714 deferred_msg msg_buf;
4715
4716 /* Detect if message has already been deferred; in this case
4717 we cannot return any sensible value to ignore this. */
4718 if (find_deferred_msg (hwnd, msg) != NULL)
4719 abort ();
4720
4721 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4722 }
4723
4724 case WM_EXITMENULOOP:
4725 f = x_window_to_frame (dpyinfo, hwnd);
4726
9eb16b62
JR
4727 /* Free memory used by owner-drawn and help-echo strings. */
4728 w32_free_menu_strings (hwnd);
4729
1edf84e7
GV
4730 /* Indicate that menubar can be modified again. */
4731 if (f)
4732 f->output_data.w32->menubar_active = 0;
4733 goto dflt;
4734
126f2e35 4735 case WM_MENUSELECT:
4e3a1c61
JR
4736 /* Direct handling of help_echo in menus. Should be safe now
4737 that we generate the help_echo by placing a help event in the
4738 keyboard buffer. */
ca56d953 4739 {
ca56d953
JR
4740 HMENU menu = (HMENU) lParam;
4741 UINT menu_item = (UINT) LOWORD (wParam);
4742 UINT flags = (UINT) HIWORD (wParam);
4743
4e3a1c61 4744 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4745 }
126f2e35
JR
4746 return 0;
4747
87996783
GV
4748 case WM_MEASUREITEM:
4749 f = x_window_to_frame (dpyinfo, hwnd);
4750 if (f)
4751 {
4752 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4753
4754 if (pMis->CtlType == ODT_MENU)
4755 {
4756 /* Work out dimensions for popup menu titles. */
4757 char * title = (char *) pMis->itemData;
4758 HDC hdc = GetDC (hwnd);
4759 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4760 LOGFONT menu_logfont;
4761 HFONT old_font;
4762 SIZE size;
4763
4764 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4765 menu_logfont.lfWeight = FW_BOLD;
4766 menu_font = CreateFontIndirect (&menu_logfont);
4767 old_font = SelectObject (hdc, menu_font);
4768
dfff8a69
JR
4769 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4770 if (title)
4771 {
4772 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4773 pMis->itemWidth = size.cx;
4774 if (pMis->itemHeight < size.cy)
4775 pMis->itemHeight = size.cy;
4776 }
4777 else
4778 pMis->itemWidth = 0;
87996783
GV
4779
4780 SelectObject (hdc, old_font);
4781 DeleteObject (menu_font);
4782 ReleaseDC (hwnd, hdc);
4783 return TRUE;
4784 }
4785 }
4786 return 0;
4787
4788 case WM_DRAWITEM:
4789 f = x_window_to_frame (dpyinfo, hwnd);
4790 if (f)
4791 {
4792 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4793
4794 if (pDis->CtlType == ODT_MENU)
4795 {
4796 /* Draw popup menu title. */
4797 char * title = (char *) pDis->itemData;
212da13b
JR
4798 if (title)
4799 {
4800 HDC hdc = pDis->hDC;
4801 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4802 LOGFONT menu_logfont;
4803 HFONT old_font;
4804
4805 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4806 menu_logfont.lfWeight = FW_BOLD;
4807 menu_font = CreateFontIndirect (&menu_logfont);
4808 old_font = SelectObject (hdc, menu_font);
4809
4810 /* Always draw title as if not selected. */
4811 ExtTextOut (hdc,
4812 pDis->rcItem.left
4813 + GetSystemMetrics (SM_CXMENUCHECK),
4814 pDis->rcItem.top,
4815 ETO_OPAQUE, &pDis->rcItem,
4816 title, strlen (title), NULL);
4817
4818 SelectObject (hdc, old_font);
4819 DeleteObject (menu_font);
4820 }
87996783
GV
4821 return TRUE;
4822 }
4823 }
4824 return 0;
4825
1edf84e7
GV
4826#if 0
4827 /* Still not right - can't distinguish between clicks in the
4828 client area of the frame from clicks forwarded from the scroll
4829 bars - may have to hook WM_NCHITTEST to remember the mouse
4830 position and then check if it is in the client area ourselves. */
4831 case WM_MOUSEACTIVATE:
4832 /* Discard the mouse click that activates a frame, allowing the
4833 user to click anywhere without changing point (or worse!).
4834 Don't eat mouse clicks on scrollbars though!! */
4835 if (LOWORD (lParam) == HTCLIENT )
4836 return MA_ACTIVATEANDEAT;
4837 goto dflt;
4838#endif
4839
9eb16b62
JR
4840 case WM_MOUSELEAVE:
4841 /* No longer tracking mouse. */
4842 track_mouse_window = NULL;
4843
1edf84e7 4844 case WM_ACTIVATEAPP:
ccc2d29c 4845 case WM_ACTIVATE:
1edf84e7
GV
4846 case WM_WINDOWPOSCHANGED:
4847 case WM_SHOWWINDOW:
4848 /* Inform lisp thread that a frame might have just been obscured
4849 or exposed, so should recheck visibility of all frames. */
4850 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4851 goto dflt;
4852
da36a4d6 4853 case WM_SETFOCUS:
adcc3809
GV
4854 dpyinfo->faked_key = 0;
4855 reset_modifiers ();
ccc2d29c
GV
4856 register_hot_keys (hwnd);
4857 goto command;
8681157a 4858 case WM_KILLFOCUS:
ccc2d29c 4859 unregister_hot_keys (hwnd);
487163ac
AI
4860 button_state = 0;
4861 ReleaseCapture ();
65906840
JR
4862 /* Relinquish the system caret. */
4863 if (w32_system_caret_hwnd)
4864 {
4865 DestroyCaret ();
4866 w32_system_caret_hwnd = NULL;
4867 }
ee78dc32
GV
4868 case WM_MOVE:
4869 case WM_SIZE:
ee78dc32 4870 case WM_COMMAND:
ccc2d29c 4871 command:
fbd6baed 4872 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4873 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4874 goto dflt;
8847d890
RS
4875
4876 case WM_CLOSE:
fbd6baed 4877 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4878 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4879 return 0;
4880
ee78dc32 4881 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
4882 /* Don't restrict the sizing of tip frames. */
4883 if (hwnd == tip_window)
4884 return 0;
ee78dc32
GV
4885 {
4886 WINDOWPLACEMENT wp;
4887 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4888
4889 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4890 GetWindowPlacement (hwnd, &wp);
4891
1edf84e7 4892 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4893 {
4894 RECT rect;
4895 int wdiff;
4896 int hdiff;
1edf84e7
GV
4897 DWORD font_width;
4898 DWORD line_height;
4899 DWORD internal_border;
4900 DWORD scrollbar_extra;
ee78dc32
GV
4901 RECT wr;
4902
5ac45f98 4903 wp.length = sizeof(wp);
ee78dc32
GV
4904 GetWindowRect (hwnd, &wr);
4905
3c190163 4906 enter_crit ();
ee78dc32 4907
1edf84e7
GV
4908 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4909 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4910 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4911 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4912
3c190163 4913 leave_crit ();
ee78dc32
GV
4914
4915 memset (&rect, 0, sizeof (rect));
4916 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4917 GetMenu (hwnd) != NULL);
4918
1edf84e7
GV
4919 /* Force width and height of client area to be exact
4920 multiples of the character cell dimensions. */
4921 wdiff = (lppos->cx - (rect.right - rect.left)
4922 - 2 * internal_border - scrollbar_extra)
4923 % font_width;
4924 hdiff = (lppos->cy - (rect.bottom - rect.top)
4925 - 2 * internal_border)
4926 % line_height;
ee78dc32
GV
4927
4928 if (wdiff || hdiff)
4929 {
4930 /* For right/bottom sizing we can just fix the sizes.
4931 However for top/left sizing we will need to fix the X
4932 and Y positions as well. */
4933
4934 lppos->cx -= wdiff;
4935 lppos->cy -= hdiff;
4936
4937 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4938 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4939 {
4940 if (lppos->x != wr.left || lppos->y != wr.top)
4941 {
4942 lppos->x += wdiff;
4943 lppos->y += hdiff;
4944 }
4945 else
4946 {
4947 lppos->flags |= SWP_NOMOVE;
4948 }
4949 }
4950
1edf84e7 4951 return 0;
ee78dc32
GV
4952 }
4953 }
4954 }
ee78dc32
GV
4955
4956 goto dflt;
1edf84e7 4957
b1f918f8
GV
4958 case WM_GETMINMAXINFO:
4959 /* Hack to correct bug that allows Emacs frames to be resized
4960 below the Minimum Tracking Size. */
4961 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
4962 /* Hack to allow resizing the Emacs frame above the screen size.
4963 Note that Windows 9x limits coordinates to 16-bits. */
4964 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
4965 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
4966 return 0;
4967
1edf84e7
GV
4968 case WM_EMACS_CREATESCROLLBAR:
4969 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4970 (struct scroll_bar *) lParam);
4971
5ac45f98 4972 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4973 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4974
dfdb4047 4975 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4976 {
4977 HWND foreground_window;
4978 DWORD foreground_thread, retval;
4979
4980 /* On NT 5.0, and apparently Windows 98, it is necessary to
4981 attach to the thread that currently has focus in order to
4982 pull the focus away from it. */
4983 foreground_window = GetForegroundWindow ();
4984 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4985 if (!foreground_window
4986 || foreground_thread == GetCurrentThreadId ()
4987 || !AttachThreadInput (GetCurrentThreadId (),
4988 foreground_thread, TRUE))
4989 foreground_thread = 0;
4990
4991 retval = SetForegroundWindow ((HWND) wParam);
4992
4993 /* Detach from the previous foreground thread. */
4994 if (foreground_thread)
4995 AttachThreadInput (GetCurrentThreadId (),
4996 foreground_thread, FALSE);
4997
4998 return retval;
4999 }
dfdb4047 5000
5ac45f98
GV
5001 case WM_EMACS_SETWINDOWPOS:
5002 {
1edf84e7
GV
5003 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5004 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5005 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5006 }
1edf84e7 5007
ee78dc32 5008 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5009 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5010 return DestroyWindow ((HWND) wParam);
5011
65906840
JR
5012 case WM_EMACS_DESTROY_CARET:
5013 w32_system_caret_hwnd = NULL;
5014 return DestroyCaret ();
5015
5016 case WM_EMACS_TRACK_CARET:
5017 /* If there is currently no system caret, create one. */
5018 if (w32_system_caret_hwnd == NULL)
5019 {
5020 w32_system_caret_hwnd = hwnd;
5021 CreateCaret (hwnd, NULL, w32_system_caret_width,
5022 w32_system_caret_height);
5023 }
5024 return SetCaretPos (w32_system_caret_x, w32_system_caret_y);
5025
1edf84e7
GV
5026 case WM_EMACS_TRACKPOPUPMENU:
5027 {
5028 UINT flags;
5029 POINT *pos;
5030 int retval;
5031 pos = (POINT *)lParam;
5032 flags = TPM_CENTERALIGN;
5033 if (button_state & LMOUSE)
5034 flags |= TPM_LEFTBUTTON;
5035 else if (button_state & RMOUSE)
5036 flags |= TPM_RIGHTBUTTON;
5037
87996783
GV
5038 /* Remember we did a SetCapture on the initial mouse down event,
5039 so for safety, we make sure the capture is cancelled now. */
5040 ReleaseCapture ();
490822ff 5041 button_state = 0;
87996783 5042
1edf84e7
GV
5043 /* Use menubar_active to indicate that WM_INITMENU is from
5044 TrackPopupMenu below, and should be ignored. */
5045 f = x_window_to_frame (dpyinfo, hwnd);
5046 if (f)
5047 f->output_data.w32->menubar_active = 1;
5048
5049 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5050 0, hwnd, NULL))
5051 {
5052 MSG amsg;
5053 /* Eat any mouse messages during popupmenu */
5054 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5055 PM_REMOVE));
5056 /* Get the menu selection, if any */
5057 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5058 {
5059 retval = LOWORD (amsg.wParam);
5060 }
5061 else
5062 {
5063 retval = 0;
5064 }
1edf84e7
GV
5065 }
5066 else
5067 {
5068 retval = -1;
5069 }
5070
5071 return retval;
5072 }
5073
ee78dc32 5074 default:
93fbe8b7
GV
5075 /* Check for messages registered at runtime. */
5076 if (msg == msh_mousewheel)
5077 {
5078 wmsg.dwModifiers = w32_get_modifiers ();
5079 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5080 return 0;
5081 }
5082
ee78dc32
GV
5083 dflt:
5084 return DefWindowProc (hwnd, msg, wParam, lParam);
5085 }
5086
1edf84e7
GV
5087
5088 /* The most common default return code for handled messages is 0. */
5089 return 0;
ee78dc32
GV
5090}
5091
5092void
5093my_create_window (f)
5094 struct frame * f;
5095{
5096 MSG msg;
5097
1edf84e7
GV
5098 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5099 abort ();
ee78dc32
GV
5100 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5101}
5102
ca56d953
JR
5103
5104/* Create a tooltip window. Unlike my_create_window, we do not do this
5105 indirectly via the Window thread, as we do not need to process Window
5106 messages for the tooltip. Creating tooltips indirectly also creates
5107 deadlocks when tooltips are created for menu items. */
5108void
5109my_create_tip_window (f)
5110 struct frame *f;
5111{
bfd6edcc 5112 RECT rect;
ca56d953 5113
bfd6edcc
JR
5114 rect.left = rect.top = 0;
5115 rect.right = PIXEL_WIDTH (f);
5116 rect.bottom = PIXEL_HEIGHT (f);
5117
5118 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5119 FRAME_EXTERNAL_MENU_BAR (f));
5120
5121 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5122 = CreateWindow (EMACS_CLASS,
5123 f->namebuf,
5124 f->output_data.w32->dwStyle,
5125 f->output_data.w32->left_pos,
5126 f->output_data.w32->top_pos,
bfd6edcc
JR
5127 rect.right - rect.left,
5128 rect.bottom - rect.top,
ca56d953
JR
5129 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5130 NULL,
5131 hinst,
5132 NULL);
5133
bfd6edcc 5134 if (tip_window)
ca56d953 5135 {
bfd6edcc
JR
5136 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5137 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5138 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5139 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5140
5141 /* Tip frames have no scrollbars. */
5142 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5143
5144 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5145 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5146 }
5147}
5148
5149
fbd6baed 5150/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5151
5152static void
fbd6baed 5153w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5154 struct frame *f;
5155 long window_prompting;
5156 int minibuffer_only;
5157{
5158 BLOCK_INPUT;
5159
5160 /* Use the resource name as the top-level window name
5161 for looking up resources. Make a non-Lisp copy
5162 for the window manager, so GC relocation won't bother it.
5163
5164 Elsewhere we specify the window name for the window manager. */
5165
5166 {
5167 char *str = (char *) XSTRING (Vx_resource_name)->data;
5168 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5169 strcpy (f->namebuf, str);
5170 }
5171
5172 my_create_window (f);
5173
5174 validate_x_resource_name ();
5175
5176 /* x_set_name normally ignores requests to set the name if the
5177 requested name is the same as the current name. This is the one
5178 place where that assumption isn't correct; f->name is set, but
5179 the server hasn't been told. */
5180 {
5181 Lisp_Object name;
5182 int explicit = f->explicit_name;
5183
5184 f->explicit_name = 0;
5185 name = f->name;
5186 f->name = Qnil;
5187 x_set_name (f, name, explicit);
5188 }
5189
5190 UNBLOCK_INPUT;
5191
5192 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5193 initialize_frame_menubar (f);
5194
fbd6baed 5195 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5196 error ("Unable to create window");
5197}
5198
5199/* Handle the icon stuff for this window. Perhaps later we might
5200 want an x_set_icon_position which can be called interactively as
5201 well. */
5202
5203static void
5204x_icon (f, parms)
5205 struct frame *f;
5206 Lisp_Object parms;
5207{
5208 Lisp_Object icon_x, icon_y;
5209
e9e23e23 5210 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5211 icons in the tray. */
6fc2811b
JR
5212 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5213 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5214 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5215 {
b7826503
PJ
5216 CHECK_NUMBER (icon_x);
5217 CHECK_NUMBER (icon_y);
ee78dc32
GV
5218 }
5219 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5220 error ("Both left and top icon corners of icon must be specified");
5221
5222 BLOCK_INPUT;
5223
5224 if (! EQ (icon_x, Qunbound))
5225 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5226
1edf84e7
GV
5227#if 0 /* TODO */
5228 /* Start up iconic or window? */
5229 x_wm_set_window_state
6fc2811b 5230 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5231 ? IconicState
5232 : NormalState));
5233
5234 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5235 ? f->icon_name
5236 : f->name))->data);
5237#endif
5238
ee78dc32
GV
5239 UNBLOCK_INPUT;
5240}
5241
6fc2811b
JR
5242
5243static void
5244x_make_gc (f)
5245 struct frame *f;
5246{
5247 XGCValues gc_values;
5248
5249 BLOCK_INPUT;
5250
5251 /* Create the GC's of this frame.
5252 Note that many default values are used. */
5253
5254 /* Normal video */
5255 gc_values.font = f->output_data.w32->font;
5256
5257 /* Cursor has cursor-color background, background-color foreground. */
5258 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5259 gc_values.background = f->output_data.w32->cursor_pixel;
5260 f->output_data.w32->cursor_gc
5261 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5262 (GCFont | GCForeground | GCBackground),
5263 &gc_values);
5264
5265 /* Reliefs. */
5266 f->output_data.w32->white_relief.gc = 0;
5267 f->output_data.w32->black_relief.gc = 0;
5268
5269 UNBLOCK_INPUT;
5270}
5271
5272
937e601e
AI
5273/* Handler for signals raised during x_create_frame and
5274 x_create_top_frame. FRAME is the frame which is partially
5275 constructed. */
5276
5277static Lisp_Object
5278unwind_create_frame (frame)
5279 Lisp_Object frame;
5280{
5281 struct frame *f = XFRAME (frame);
5282
5283 /* If frame is ``official'', nothing to do. */
5284 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5285 {
5286#ifdef GLYPH_DEBUG
5287 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5288#endif
5289
5290 x_free_frame_resources (f);
5291
5292 /* Check that reference counts are indeed correct. */
5293 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5294 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5295
5296 return Qt;
937e601e
AI
5297 }
5298
5299 return Qnil;
5300}
5301
5302
ee78dc32
GV
5303DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5304 1, 1, 0,
74e1aeec
JR
5305 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5306Returns an Emacs frame object.
5307ALIST is an alist of frame parameters.
5308If the parameters specify that the frame should not have a minibuffer,
5309and do not specify a specific minibuffer window to use,
5310then `default-minibuffer-frame' must be a frame whose minibuffer can
5311be shared by the new frame.
5312
5313This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5314 (parms)
5315 Lisp_Object parms;
5316{
5317 struct frame *f;
5318 Lisp_Object frame, tem;
5319 Lisp_Object name;
5320 int minibuffer_only = 0;
5321 long window_prompting = 0;
5322 int width, height;
dc220243 5323 int count = BINDING_STACK_SIZE ();
1edf84e7 5324 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5325 Lisp_Object display;
6fc2811b 5326 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5327 Lisp_Object parent;
5328 struct kboard *kb;
5329
4587b026
GV
5330 check_w32 ();
5331
ee78dc32
GV
5332 /* Use this general default value to start with
5333 until we know if this frame has a specified name. */
5334 Vx_resource_name = Vinvocation_name;
5335
6fc2811b 5336 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5337 if (EQ (display, Qunbound))
5338 display = Qnil;
5339 dpyinfo = check_x_display_info (display);
5340#ifdef MULTI_KBOARD
5341 kb = dpyinfo->kboard;
5342#else
5343 kb = &the_only_kboard;
5344#endif
5345
6fc2811b 5346 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5347 if (!STRINGP (name)
5348 && ! EQ (name, Qunbound)
5349 && ! NILP (name))
5350 error ("Invalid frame name--not a string or nil");
5351
5352 if (STRINGP (name))
5353 Vx_resource_name = name;
5354
5355 /* See if parent window is specified. */
6fc2811b 5356 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5357 if (EQ (parent, Qunbound))
5358 parent = Qnil;
5359 if (! NILP (parent))
b7826503 5360 CHECK_NUMBER (parent);
ee78dc32 5361
1edf84e7
GV
5362 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5363 /* No need to protect DISPLAY because that's not used after passing
5364 it to make_frame_without_minibuffer. */
5365 frame = Qnil;
5366 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5367 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5368 RES_TYPE_SYMBOL);
ee78dc32
GV
5369 if (EQ (tem, Qnone) || NILP (tem))
5370 f = make_frame_without_minibuffer (Qnil, kb, display);
5371 else if (EQ (tem, Qonly))
5372 {
5373 f = make_minibuffer_frame ();
5374 minibuffer_only = 1;
5375 }
5376 else if (WINDOWP (tem))
5377 f = make_frame_without_minibuffer (tem, kb, display);
5378 else
5379 f = make_frame (1);
5380
1edf84e7
GV
5381 XSETFRAME (frame, f);
5382
ee78dc32
GV
5383 /* Note that Windows does support scroll bars. */
5384 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5385 /* By default, make scrollbars the system standard width. */
5386 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5387
fbd6baed 5388 f->output_method = output_w32;
6fc2811b
JR
5389 f->output_data.w32 =
5390 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5391 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5392 FRAME_FONTSET (f) = -1;
937e601e 5393 record_unwind_protect (unwind_create_frame, frame);
4587b026 5394
1edf84e7 5395 f->icon_name
6fc2811b 5396 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5397 if (! STRINGP (f->icon_name))
5398 f->icon_name = Qnil;
5399
fbd6baed 5400/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5401#ifdef MULTI_KBOARD
5402 FRAME_KBOARD (f) = kb;
5403#endif
5404
5405 /* Specify the parent under which to make this window. */
5406
5407 if (!NILP (parent))
5408 {
1660f34a 5409 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5410 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5411 }
5412 else
5413 {
fbd6baed
GV
5414 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5415 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5416 }
5417
ee78dc32
GV
5418 /* Set the name; the functions to which we pass f expect the name to
5419 be set. */
5420 if (EQ (name, Qunbound) || NILP (name))
5421 {
fbd6baed 5422 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5423 f->explicit_name = 0;
5424 }
5425 else
5426 {
5427 f->name = name;
5428 f->explicit_name = 1;
5429 /* use the frame's title when getting resources for this frame. */
5430 specbind (Qx_resource_name, name);
5431 }
5432
5433 /* Extract the window parameters from the supplied values
5434 that are needed to determine window geometry. */
5435 {
5436 Lisp_Object font;
5437
6fc2811b
JR
5438 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5439
ee78dc32
GV
5440 BLOCK_INPUT;
5441 /* First, try whatever font the caller has specified. */
5442 if (STRINGP (font))
4587b026
GV
5443 {
5444 tem = Fquery_fontset (font, Qnil);
5445 if (STRINGP (tem))
5446 font = x_new_fontset (f, XSTRING (tem)->data);
5447 else
1075afa9 5448 font = x_new_font (f, XSTRING (font)->data);
4587b026 5449 }
ee78dc32
GV
5450 /* Try out a font which we hope has bold and italic variations. */
5451 if (!STRINGP (font))
e39649be 5452 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5453 if (! STRINGP (font))
6fc2811b 5454 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5455 /* If those didn't work, look for something which will at least work. */
5456 if (! STRINGP (font))
6fc2811b 5457 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5458 UNBLOCK_INPUT;
5459 if (! STRINGP (font))
1edf84e7 5460 font = build_string ("Fixedsys");
ee78dc32
GV
5461
5462 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5463 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5464 }
5465
5466 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5467 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5468 /* This defaults to 2 in order to match xterm. We recognize either
5469 internalBorderWidth or internalBorder (which is what xterm calls
5470 it). */
5471 if (NILP (Fassq (Qinternal_border_width, parms)))
5472 {
5473 Lisp_Object value;
5474
6fc2811b 5475 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5476 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5477 if (! EQ (value, Qunbound))
5478 parms = Fcons (Fcons (Qinternal_border_width, value),
5479 parms);
5480 }
1edf84e7 5481 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5482 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5483 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5484 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5485 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5486
5487 /* Also do the stuff which must be set before the window exists. */
5488 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5489 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5490 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5491 "background", "Background", RES_TYPE_STRING);
ee78dc32 5492 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5493 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5494 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5495 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5496 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5497 "borderColor", "BorderColor", RES_TYPE_STRING);
5498 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5499 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5500 x_default_parameter (f, parms, Qline_spacing, Qnil,
5501 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5502 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5503 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5504 x_default_parameter (f, parms, Qright_fringe, Qnil,
5505 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5506
ee78dc32 5507
6fc2811b
JR
5508 /* Init faces before x_default_parameter is called for scroll-bar
5509 parameters because that function calls x_set_scroll_bar_width,
5510 which calls change_frame_size, which calls Fset_window_buffer,
5511 which runs hooks, which call Fvertical_motion. At the end, we
5512 end up in init_iterator with a null face cache, which should not
5513 happen. */
5514 init_frame_faces (f);
5515
ee78dc32 5516 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5517 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5518 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5519 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5520 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5521 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5522 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5523 "title", "Title", RES_TYPE_STRING);
ee78dc32 5524
fbd6baed
GV
5525 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5526 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5527
5528 /* Add the tool-bar height to the initial frame height so that the
5529 user gets a text display area of the size he specified with -g or
5530 via .Xdefaults. Later changes of the tool-bar height don't
5531 change the frame size. This is done so that users can create
5532 tall Emacs frames without having to guess how tall the tool-bar
5533 will get. */
5534 if (FRAME_TOOL_BAR_LINES (f))
5535 {
5536 int margin, relief, bar_height;
5537
a05e2bae 5538 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5539 ? tool_bar_button_relief
5540 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5541
5542 if (INTEGERP (Vtool_bar_button_margin)
5543 && XINT (Vtool_bar_button_margin) > 0)
5544 margin = XFASTINT (Vtool_bar_button_margin);
5545 else if (CONSP (Vtool_bar_button_margin)
5546 && INTEGERP (XCDR (Vtool_bar_button_margin))
5547 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5548 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5549 else
5550 margin = 0;
5551
5552 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5553 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5554 }
5555
ee78dc32
GV
5556 window_prompting = x_figure_window_size (f, parms);
5557
5558 if (window_prompting & XNegative)
5559 {
5560 if (window_prompting & YNegative)
fbd6baed 5561 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5562 else
fbd6baed 5563 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5564 }
5565 else
5566 {
5567 if (window_prompting & YNegative)
fbd6baed 5568 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5569 else
fbd6baed 5570 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5571 }
5572
fbd6baed 5573 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5574
6fc2811b
JR
5575 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5576 f->no_split = minibuffer_only || EQ (tem, Qt);
5577
fbd6baed 5578 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5579 x_icon (f, parms);
6fc2811b
JR
5580
5581 x_make_gc (f);
5582
5583 /* Now consider the frame official. */
5584 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5585 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5586
5587 /* We need to do this after creating the window, so that the
5588 icon-creation functions can say whose icon they're describing. */
5589 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5590 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5591
5592 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5593 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5594 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5595 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5596 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5597 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5598 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5599 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5600
5601 /* Dimensions, especially f->height, must be done via change_frame_size.
5602 Change will not be effected unless different from the current
5603 f->height. */
5604 width = f->width;
5605 height = f->height;
dc220243 5606
1026b400
RS
5607 f->height = 0;
5608 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5609 change_frame_size (f, height, width, 1, 0, 0);
5610
6fc2811b
JR
5611 /* Tell the server what size and position, etc, we want, and how
5612 badly we want them. This should be done after we have the menu
5613 bar so that its size can be taken into account. */
ee78dc32
GV
5614 BLOCK_INPUT;
5615 x_wm_set_size_hint (f, window_prompting, 0);
5616 UNBLOCK_INPUT;
5617
4694d762
JR
5618 /* Set up faces after all frame parameters are known. This call
5619 also merges in face attributes specified for new frames. If we
5620 don't do this, the `menu' face for instance won't have the right
5621 colors, and the menu bar won't appear in the specified colors for
5622 new frames. */
5623 call1 (Qface_set_after_frame_default, frame);
5624
6fc2811b
JR
5625 /* Make the window appear on the frame and enable display, unless
5626 the caller says not to. However, with explicit parent, Emacs
5627 cannot control visibility, so don't try. */
fbd6baed 5628 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5629 {
5630 Lisp_Object visibility;
5631
6fc2811b 5632 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5633 if (EQ (visibility, Qunbound))
5634 visibility = Qt;
5635
5636 if (EQ (visibility, Qicon))
5637 x_iconify_frame (f);
5638 else if (! NILP (visibility))
5639 x_make_frame_visible (f);
5640 else
5641 /* Must have been Qnil. */
5642 ;
5643 }
6fc2811b 5644 UNGCPRO;
9e57df62
GM
5645
5646 /* Make sure windows on this frame appear in calls to next-window
5647 and similar functions. */
5648 Vwindow_list = Qnil;
5649
ee78dc32
GV
5650 return unbind_to (count, frame);
5651}
5652
5653/* FRAME is used only to get a handle on the X display. We don't pass the
5654 display info directly because we're called from frame.c, which doesn't
5655 know about that structure. */
5656Lisp_Object
5657x_get_focus_frame (frame)
5658 struct frame *frame;
5659{
fbd6baed 5660 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5661 Lisp_Object xfocus;
fbd6baed 5662 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5663 return Qnil;
5664
fbd6baed 5665 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5666 return xfocus;
5667}
1edf84e7
GV
5668
5669DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5670 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5671 (frame)
5672 Lisp_Object frame;
5673{
5674 x_focus_on_frame (check_x_frame (frame));
5675 return Qnil;
5676}
5677
ee78dc32 5678\f
767b1ff0
JR
5679/* Return the charset portion of a font name. */
5680char * xlfd_charset_of_font (char * fontname)
5681{
5682 char *charset, *encoding;
5683
5684 encoding = strrchr(fontname, '-');
ceb12877 5685 if (!encoding || encoding == fontname)
767b1ff0
JR
5686 return NULL;
5687
478ea067
AI
5688 for (charset = encoding - 1; charset >= fontname; charset--)
5689 if (*charset == '-')
5690 break;
767b1ff0 5691
478ea067 5692 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5693 return NULL;
5694
5695 return charset + 1;
5696}
5697
33d52f9c
GV
5698struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5699 int size, char* filename);
8edb0a6f 5700static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5701static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5702 char * charset);
5703static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5704
8edb0a6f 5705static struct font_info *
33d52f9c 5706w32_load_system_font (f,fontname,size)
55dcfc15
AI
5707 struct frame *f;
5708 char * fontname;
5709 int size;
ee78dc32 5710{
4587b026
GV
5711 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5712 Lisp_Object font_names;
5713
4587b026
GV
5714 /* Get a list of all the fonts that match this name. Once we
5715 have a list of matching fonts, we compare them against the fonts
5716 we already have loaded by comparing names. */
5717 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5718
5719 if (!NILP (font_names))
3c190163 5720 {
4587b026
GV
5721 Lisp_Object tail;
5722 int i;
4587b026
GV
5723
5724 /* First check if any are already loaded, as that is cheaper
5725 than loading another one. */
5726 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5727 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5728 if (dpyinfo->font_table[i].name
5729 && (!strcmp (dpyinfo->font_table[i].name,
5730 XSTRING (XCAR (tail))->data)
5731 || !strcmp (dpyinfo->font_table[i].full_name,
5732 XSTRING (XCAR (tail))->data)))
4587b026 5733 return (dpyinfo->font_table + i);
6fc2811b 5734
8e713be6 5735 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5736 }
1075afa9 5737 else if (w32_strict_fontnames)
5ca0cd71
GV
5738 {
5739 /* If EnumFontFamiliesEx was available, we got a full list of
5740 fonts back so stop now to avoid the possibility of loading a
5741 random font. If we had to fall back to EnumFontFamilies, the
5742 list is incomplete, so continue whether the font we want was
5743 listed or not. */
5744 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5745 FARPROC enum_font_families_ex
1075afa9 5746 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5747 if (enum_font_families_ex)
5748 return NULL;
5749 }
4587b026
GV
5750
5751 /* Load the font and add it to the table. */
5752 {
767b1ff0 5753 char *full_name, *encoding, *charset;
4587b026
GV
5754 XFontStruct *font;
5755 struct font_info *fontp;
3c190163 5756 LOGFONT lf;
4587b026 5757 BOOL ok;
19c291d3 5758 int codepage;
6fc2811b 5759 int i;
5ac45f98 5760
4587b026 5761 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5762 return (NULL);
5ac45f98 5763
4587b026
GV
5764 if (!*lf.lfFaceName)
5765 /* If no name was specified for the font, we get a random font
5766 from CreateFontIndirect - this is not particularly
5767 desirable, especially since CreateFontIndirect does not
5768 fill out the missing name in lf, so we never know what we
5769 ended up with. */
5770 return NULL;
5771
3c190163 5772 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5773 bzero (font, sizeof (*font));
5ac45f98 5774
33d52f9c
GV
5775 /* Set bdf to NULL to indicate that this is a Windows font. */
5776 font->bdf = NULL;
5ac45f98 5777
3c190163 5778 BLOCK_INPUT;
5ac45f98
GV
5779
5780 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5781
1a292d24
AI
5782 if (font->hfont == NULL)
5783 {
5784 ok = FALSE;
5785 }
5786 else
5787 {
5788 HDC hdc;
5789 HANDLE oldobj;
19c291d3
AI
5790
5791 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5792
5793 hdc = GetDC (dpyinfo->root_window);
5794 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5795
1a292d24 5796 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5797 if (codepage == CP_UNICODE)
5798 font->double_byte_p = 1;
5799 else
8b77111c
AI
5800 {
5801 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5802 don't report themselves as double byte fonts, when
5803 patently they are. So instead of trusting
5804 GetFontLanguageInfo, we check the properties of the
5805 codepage directly, since that is ultimately what we are
5806 working from anyway. */
5807 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5808 CPINFO cpi = {0};
5809 GetCPInfo (codepage, &cpi);
5810 font->double_byte_p = cpi.MaxCharSize > 1;
5811 }
5c6682be 5812
1a292d24
AI
5813 SelectObject (hdc, oldobj);
5814 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5815 /* Fill out details in lf according to the font that was
5816 actually loaded. */
5817 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5818 lf.lfWidth = font->tm.tmAveCharWidth;
5819 lf.lfWeight = font->tm.tmWeight;
5820 lf.lfItalic = font->tm.tmItalic;
5821 lf.lfCharSet = font->tm.tmCharSet;
5822 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5823 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5824 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5825 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5826
5827 w32_cache_char_metrics (font);
1a292d24 5828 }
5ac45f98 5829
1a292d24 5830 UNBLOCK_INPUT;
5ac45f98 5831
4587b026
GV
5832 if (!ok)
5833 {
1a292d24
AI
5834 w32_unload_font (dpyinfo, font);
5835 return (NULL);
5836 }
ee78dc32 5837
6fc2811b
JR
5838 /* Find a free slot in the font table. */
5839 for (i = 0; i < dpyinfo->n_fonts; ++i)
5840 if (dpyinfo->font_table[i].name == NULL)
5841 break;
5842
5843 /* If no free slot found, maybe enlarge the font table. */
5844 if (i == dpyinfo->n_fonts
5845 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5846 {
6fc2811b
JR
5847 int sz;
5848 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5849 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5850 dpyinfo->font_table
6fc2811b 5851 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5852 }
5853
6fc2811b
JR
5854 fontp = dpyinfo->font_table + i;
5855 if (i == dpyinfo->n_fonts)
5856 ++dpyinfo->n_fonts;
4587b026
GV
5857
5858 /* Now fill in the slots of *FONTP. */
5859 BLOCK_INPUT;
5860 fontp->font = font;
6fc2811b 5861 fontp->font_idx = i;
4587b026
GV
5862 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5863 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5864
767b1ff0
JR
5865 charset = xlfd_charset_of_font (fontname);
5866
19c291d3
AI
5867 /* Cache the W32 codepage for a font. This makes w32_encode_char
5868 (called for every glyph during redisplay) much faster. */
5869 fontp->codepage = codepage;
5870
4587b026
GV
5871 /* Work out the font's full name. */
5872 full_name = (char *)xmalloc (100);
767b1ff0 5873 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
5874 fontp->full_name = full_name;
5875 else
5876 {
5877 /* If all else fails - just use the name we used to load it. */
5878 xfree (full_name);
5879 fontp->full_name = fontp->name;
5880 }
5881
5882 fontp->size = FONT_WIDTH (font);
5883 fontp->height = FONT_HEIGHT (font);
5884
5885 /* The slot `encoding' specifies how to map a character
5886 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
5887 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5888 (0:0x20..0x7F, 1:0xA0..0xFF,
5889 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 5890 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 5891 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
5892 which is never used by any charset. If mapping can't be
5893 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5894
5895 /* SJIS fonts need to be set to type 4, all others seem to work as
5896 type FONT_ENCODING_NOT_DECIDED. */
5897 encoding = strrchr (fontp->name, '-');
5898 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5899 fontp->encoding[1] = 4;
33d52f9c 5900 else
1c885fe1 5901 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5902
5903 /* The following three values are set to 0 under W32, which is
5904 what they get set to if XGetFontProperty fails under X. */
5905 fontp->baseline_offset = 0;
5906 fontp->relative_compose = 0;
33d52f9c 5907 fontp->default_ascent = 0;
4587b026 5908
6fc2811b
JR
5909 /* Set global flag fonts_changed_p to non-zero if the font loaded
5910 has a character with a smaller width than any other character
5911 before, or if the font loaded has a smalle>r height than any
5912 other font loaded before. If this happens, it will make a
5913 glyph matrix reallocation necessary. */
5914 fonts_changed_p = x_compute_min_glyph_bounds (f);
4587b026 5915 UNBLOCK_INPUT;
4587b026
GV
5916 return fontp;
5917 }
5918}
5919
33d52f9c
GV
5920/* Load font named FONTNAME of size SIZE for frame F, and return a
5921 pointer to the structure font_info while allocating it dynamically.
5922 If loading fails, return NULL. */
5923struct font_info *
5924w32_load_font (f,fontname,size)
5925struct frame *f;
5926char * fontname;
5927int size;
5928{
5929 Lisp_Object bdf_fonts;
5930 struct font_info *retval = NULL;
5931
8edb0a6f 5932 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
5933
5934 while (!retval && CONSP (bdf_fonts))
5935 {
5936 char *bdf_name, *bdf_file;
5937 Lisp_Object bdf_pair;
5938
8e713be6
KR
5939 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5940 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5941 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
5942
5943 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5944
8e713be6 5945 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
5946 }
5947
5948 if (retval)
5949 return retval;
5950
5951 return w32_load_system_font(f, fontname, size);
5952}
5953
5954
ee78dc32 5955void
fbd6baed
GV
5956w32_unload_font (dpyinfo, font)
5957 struct w32_display_info *dpyinfo;
ee78dc32
GV
5958 XFontStruct * font;
5959{
5960 if (font)
5961 {
c6be3860 5962 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
5963 if (font->bdf) w32_free_bdf_font (font->bdf);
5964
3c190163 5965 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5966 xfree (font);
5967 }
5968}
5969
fbd6baed 5970/* The font conversion stuff between x and w32 */
ee78dc32
GV
5971
5972/* X font string is as follows (from faces.el)
5973 * (let ((- "[-?]")
5974 * (foundry "[^-]+")
5975 * (family "[^-]+")
5976 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5977 * (weight\? "\\([^-]*\\)") ; 1
5978 * (slant "\\([ior]\\)") ; 2
5979 * (slant\? "\\([^-]?\\)") ; 2
5980 * (swidth "\\([^-]*\\)") ; 3
5981 * (adstyle "[^-]*") ; 4
5982 * (pixelsize "[0-9]+")
5983 * (pointsize "[0-9][0-9]+")
5984 * (resx "[0-9][0-9]+")
5985 * (resy "[0-9][0-9]+")
5986 * (spacing "[cmp?*]")
5987 * (avgwidth "[0-9]+")
5988 * (registry "[^-]+")
5989 * (encoding "[^-]+")
5990 * )
ee78dc32 5991 */
ee78dc32 5992
8edb0a6f 5993static LONG
fbd6baed 5994x_to_w32_weight (lpw)
ee78dc32
GV
5995 char * lpw;
5996{
5997 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
5998
5999 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6000 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6001 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6002 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6003 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6004 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6005 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6006 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6007 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6008 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6009 else
5ac45f98 6010 return FW_DONTCARE;
ee78dc32
GV
6011}
6012
5ac45f98 6013
8edb0a6f 6014static char *
fbd6baed 6015w32_to_x_weight (fnweight)
ee78dc32
GV
6016 int fnweight;
6017{
5ac45f98
GV
6018 if (fnweight >= FW_HEAVY) return "heavy";
6019 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6020 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6021 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6022 if (fnweight >= FW_MEDIUM) return "medium";
6023 if (fnweight >= FW_NORMAL) return "normal";
6024 if (fnweight >= FW_LIGHT) return "light";
6025 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6026 if (fnweight >= FW_THIN) return "thin";
6027 else
6028 return "*";
6029}
6030
8edb0a6f 6031static LONG
fbd6baed 6032x_to_w32_charset (lpcs)
5ac45f98
GV
6033 char * lpcs;
6034{
767b1ff0 6035 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6036 char *charset;
6037 int len = strlen (lpcs);
6038
6039 /* Support "*-#nnn" format for unknown charsets. */
6040 if (strncmp (lpcs, "*-#", 3) == 0)
6041 return atoi (lpcs + 3);
6042
6043 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6044 charset = alloca (len + 1);
6045 strcpy (charset, lpcs);
6046 lpcs = strchr (charset, '*');
6047 if (lpcs)
6048 *lpcs = 0;
4587b026 6049
dfff8a69
JR
6050 /* Look through w32-charset-info-alist for the character set.
6051 Format of each entry is
6052 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6053 */
8b77111c 6054 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6055
767b1ff0
JR
6056 if (NILP(this_entry))
6057 {
6058 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6059 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6060 return ANSI_CHARSET;
6061 else
6062 return DEFAULT_CHARSET;
6063 }
6064
6065 w32_charset = Fcar (Fcdr (this_entry));
6066
6067 // Translate Lisp symbol to number.
6068 if (w32_charset == Qw32_charset_ansi)
6069 return ANSI_CHARSET;
6070 if (w32_charset == Qw32_charset_symbol)
6071 return SYMBOL_CHARSET;
6072 if (w32_charset == Qw32_charset_shiftjis)
6073 return SHIFTJIS_CHARSET;
6074 if (w32_charset == Qw32_charset_hangeul)
6075 return HANGEUL_CHARSET;
6076 if (w32_charset == Qw32_charset_chinesebig5)
6077 return CHINESEBIG5_CHARSET;
6078 if (w32_charset == Qw32_charset_gb2312)
6079 return GB2312_CHARSET;
6080 if (w32_charset == Qw32_charset_oem)
6081 return OEM_CHARSET;
dfff8a69 6082#ifdef JOHAB_CHARSET
767b1ff0
JR
6083 if (w32_charset == Qw32_charset_johab)
6084 return JOHAB_CHARSET;
6085 if (w32_charset == Qw32_charset_easteurope)
6086 return EASTEUROPE_CHARSET;
6087 if (w32_charset == Qw32_charset_turkish)
6088 return TURKISH_CHARSET;
6089 if (w32_charset == Qw32_charset_baltic)
6090 return BALTIC_CHARSET;
6091 if (w32_charset == Qw32_charset_russian)
6092 return RUSSIAN_CHARSET;
6093 if (w32_charset == Qw32_charset_arabic)
6094 return ARABIC_CHARSET;
6095 if (w32_charset == Qw32_charset_greek)
6096 return GREEK_CHARSET;
6097 if (w32_charset == Qw32_charset_hebrew)
6098 return HEBREW_CHARSET;
6099 if (w32_charset == Qw32_charset_vietnamese)
6100 return VIETNAMESE_CHARSET;
6101 if (w32_charset == Qw32_charset_thai)
6102 return THAI_CHARSET;
6103 if (w32_charset == Qw32_charset_mac)
6104 return MAC_CHARSET;
dfff8a69 6105#endif /* JOHAB_CHARSET */
5ac45f98 6106#ifdef UNICODE_CHARSET
767b1ff0
JR
6107 if (w32_charset == Qw32_charset_unicode)
6108 return UNICODE_CHARSET;
5ac45f98 6109#endif
dfff8a69
JR
6110
6111 return DEFAULT_CHARSET;
5ac45f98
GV
6112}
6113
dfff8a69 6114
8edb0a6f 6115static char *
fbd6baed 6116w32_to_x_charset (fncharset)
5ac45f98
GV
6117 int fncharset;
6118{
5e905a57 6119 static char buf[32];
767b1ff0 6120 Lisp_Object charset_type;
1edf84e7 6121
5ac45f98
GV
6122 switch (fncharset)
6123 {
767b1ff0
JR
6124 case ANSI_CHARSET:
6125 /* Handle startup case of w32-charset-info-alist not
6126 being set up yet. */
6127 if (NILP(Vw32_charset_info_alist))
6128 return "iso8859-1";
6129 charset_type = Qw32_charset_ansi;
6130 break;
6131 case DEFAULT_CHARSET:
6132 charset_type = Qw32_charset_default;
6133 break;
6134 case SYMBOL_CHARSET:
6135 charset_type = Qw32_charset_symbol;
6136 break;
6137 case SHIFTJIS_CHARSET:
6138 charset_type = Qw32_charset_shiftjis;
6139 break;
6140 case HANGEUL_CHARSET:
6141 charset_type = Qw32_charset_hangeul;
6142 break;
6143 case GB2312_CHARSET:
6144 charset_type = Qw32_charset_gb2312;
6145 break;
6146 case CHINESEBIG5_CHARSET:
6147 charset_type = Qw32_charset_chinesebig5;
6148 break;
6149 case OEM_CHARSET:
6150 charset_type = Qw32_charset_oem;
6151 break;
4587b026
GV
6152
6153 /* More recent versions of Windows (95 and NT4.0) define more
6154 character sets. */
6155#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6156 case EASTEUROPE_CHARSET:
6157 charset_type = Qw32_charset_easteurope;
6158 break;
6159 case TURKISH_CHARSET:
6160 charset_type = Qw32_charset_turkish;
6161 break;
6162 case BALTIC_CHARSET:
6163 charset_type = Qw32_charset_baltic;
6164 break;
33d52f9c 6165 case RUSSIAN_CHARSET:
767b1ff0
JR
6166 charset_type = Qw32_charset_russian;
6167 break;
6168 case ARABIC_CHARSET:
6169 charset_type = Qw32_charset_arabic;
6170 break;
6171 case GREEK_CHARSET:
6172 charset_type = Qw32_charset_greek;
6173 break;
6174 case HEBREW_CHARSET:
6175 charset_type = Qw32_charset_hebrew;
6176 break;
6177 case VIETNAMESE_CHARSET:
6178 charset_type = Qw32_charset_vietnamese;
6179 break;
6180 case THAI_CHARSET:
6181 charset_type = Qw32_charset_thai;
6182 break;
6183 case MAC_CHARSET:
6184 charset_type = Qw32_charset_mac;
6185 break;
6186 case JOHAB_CHARSET:
6187 charset_type = Qw32_charset_johab;
6188 break;
4587b026
GV
6189#endif
6190
5ac45f98 6191#ifdef UNICODE_CHARSET
767b1ff0
JR
6192 case UNICODE_CHARSET:
6193 charset_type = Qw32_charset_unicode;
6194 break;
5ac45f98 6195#endif
767b1ff0
JR
6196 default:
6197 /* Encode numerical value of unknown charset. */
6198 sprintf (buf, "*-#%u", fncharset);
6199 return buf;
5ac45f98 6200 }
767b1ff0
JR
6201
6202 {
6203 Lisp_Object rest;
6204 char * best_match = NULL;
6205
6206 /* Look through w32-charset-info-alist for the character set.
6207 Prefer ISO codepages, and prefer lower numbers in the ISO
6208 range. Only return charsets for codepages which are installed.
6209
6210 Format of each entry is
6211 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6212 */
6213 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6214 {
6215 char * x_charset;
6216 Lisp_Object w32_charset;
6217 Lisp_Object codepage;
6218
6219 Lisp_Object this_entry = XCAR (rest);
6220
6221 /* Skip invalid entries in alist. */
6222 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6223 || !CONSP (XCDR (this_entry))
6224 || !SYMBOLP (XCAR (XCDR (this_entry))))
6225 continue;
6226
6227 x_charset = XSTRING (XCAR (this_entry))->data;
6228 w32_charset = XCAR (XCDR (this_entry));
6229 codepage = XCDR (XCDR (this_entry));
6230
6231 /* Look for Same charset and a valid codepage (or non-int
6232 which means ignore). */
6233 if (w32_charset == charset_type
6234 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6235 || IsValidCodePage (XINT (codepage))))
6236 {
6237 /* If we don't have a match already, then this is the
6238 best. */
6239 if (!best_match)
6240 best_match = x_charset;
6241 /* If this is an ISO codepage, and the best so far isn't,
6242 then this is better. */
6243 else if (stricmp (best_match, "iso") != 0
6244 && stricmp (x_charset, "iso") == 0)
6245 best_match = x_charset;
6246 /* If both are ISO8859 codepages, choose the one with the
6247 lowest number in the encoding field. */
6248 else if (stricmp (best_match, "iso8859-") == 0
6249 && stricmp (x_charset, "iso8859-") == 0)
6250 {
6251 int best_enc = atoi (best_match + 8);
6252 int this_enc = atoi (x_charset + 8);
6253 if (this_enc > 0 && this_enc < best_enc)
6254 best_match = x_charset;
6255 }
6256 }
6257 }
6258
6259 /* If no match, encode the numeric value. */
6260 if (!best_match)
6261 {
6262 sprintf (buf, "*-#%u", fncharset);
6263 return buf;
6264 }
6265
5e905a57
JR
6266 strncpy(buf, best_match, 31);
6267 buf[31] = '\0';
767b1ff0
JR
6268 return buf;
6269 }
ee78dc32
GV
6270}
6271
dfff8a69
JR
6272
6273/* Get the Windows codepage corresponding to the specified font. The
6274 charset info in the font name is used to look up
6275 w32-charset-to-codepage-alist. */
6276int
6277w32_codepage_for_font (char *fontname)
6278{
767b1ff0
JR
6279 Lisp_Object codepage, entry;
6280 char *charset_str, *charset, *end;
dfff8a69 6281
767b1ff0 6282 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6283 return CP_DEFAULT;
6284
767b1ff0
JR
6285 /* Extract charset part of font string. */
6286 charset = xlfd_charset_of_font (fontname);
6287
6288 if (!charset)
ceb12877 6289 return CP_UNKNOWN;
767b1ff0 6290
8b77111c 6291 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6292 strcpy (charset_str, charset);
6293
8b77111c 6294#if 0
dfff8a69
JR
6295 /* Remove leading "*-". */
6296 if (strncmp ("*-", charset_str, 2) == 0)
6297 charset = charset_str + 2;
6298 else
8b77111c 6299#endif
dfff8a69
JR
6300 charset = charset_str;
6301
6302 /* Stop match at wildcard (including preceding '-'). */
6303 if (end = strchr (charset, '*'))
6304 {
6305 if (end > charset && *(end-1) == '-')
6306 end--;
6307 *end = '\0';
6308 }
6309
767b1ff0
JR
6310 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6311 if (NILP (entry))
ceb12877 6312 return CP_UNKNOWN;
767b1ff0
JR
6313
6314 codepage = Fcdr (Fcdr (entry));
6315
6316 if (NILP (codepage))
6317 return CP_8BIT;
6318 else if (XFASTINT (codepage) == XFASTINT (Qt))
6319 return CP_UNICODE;
6320 else if (INTEGERP (codepage))
dfff8a69
JR
6321 return XINT (codepage);
6322 else
ceb12877 6323 return CP_UNKNOWN;
dfff8a69
JR
6324}
6325
6326
8edb0a6f 6327static BOOL
767b1ff0 6328w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6329 LOGFONT * lplogfont;
6330 char * lpxstr;
6331 int len;
767b1ff0 6332 char * specific_charset;
ee78dc32 6333{
6fc2811b 6334 char* fonttype;
f46e6225 6335 char *fontname;
3cb20f4a
RS
6336 char height_pixels[8];
6337 char height_dpi[8];
6338 char width_pixels[8];
4587b026 6339 char *fontname_dash;
d88c567c
JR
6340 int display_resy = one_w32_display_info.resy;
6341 int display_resx = one_w32_display_info.resx;
f46e6225
GV
6342 int bufsz;
6343 struct coding_system coding;
3cb20f4a
RS
6344
6345 if (!lpxstr) abort ();
ee78dc32 6346
3cb20f4a
RS
6347 if (!lplogfont)
6348 return FALSE;
6349
6fc2811b
JR
6350 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6351 fonttype = "raster";
6352 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6353 fonttype = "outline";
6354 else
6355 fonttype = "unknown";
6356
1fa3a200 6357 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6358 &coding);
aab5ac44
KH
6359 coding.src_multibyte = 0;
6360 coding.dst_multibyte = 1;
f46e6225
GV
6361 coding.mode |= CODING_MODE_LAST_BLOCK;
6362 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6363
6364 fontname = alloca(sizeof(*fontname) * bufsz);
6365 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6366 strlen(lplogfont->lfFaceName), bufsz - 1);
6367 *(fontname + coding.produced) = '\0';
4587b026
GV
6368
6369 /* Replace dashes with underscores so the dashes are not
f46e6225 6370 misinterpreted. */
4587b026
GV
6371 fontname_dash = fontname;
6372 while (fontname_dash = strchr (fontname_dash, '-'))
6373 *fontname_dash = '_';
6374
3cb20f4a 6375 if (lplogfont->lfHeight)
ee78dc32 6376 {
3cb20f4a
RS
6377 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6378 sprintf (height_dpi, "%u",
33d52f9c 6379 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6380 }
6381 else
ee78dc32 6382 {
3cb20f4a
RS
6383 strcpy (height_pixels, "*");
6384 strcpy (height_dpi, "*");
ee78dc32 6385 }
3cb20f4a
RS
6386 if (lplogfont->lfWidth)
6387 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6388 else
6389 strcpy (width_pixels, "*");
6390
6391 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6392 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6393 fonttype, /* foundry */
4587b026
GV
6394 fontname, /* family */
6395 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6396 lplogfont->lfItalic?'i':'r', /* slant */
6397 /* setwidth name */
6398 /* add style name */
6399 height_pixels, /* pixel size */
6400 height_dpi, /* point size */
33d52f9c
GV
6401 display_resx, /* resx */
6402 display_resy, /* resy */
4587b026
GV
6403 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6404 ? 'p' : 'c', /* spacing */
6405 width_pixels, /* avg width */
767b1ff0
JR
6406 specific_charset ? specific_charset
6407 : w32_to_x_charset (lplogfont->lfCharSet)
6408 /* charset registry and encoding */
3cb20f4a
RS
6409 );
6410
ee78dc32
GV
6411 lpxstr[len - 1] = 0; /* just to be sure */
6412 return (TRUE);
6413}
6414
8edb0a6f 6415static BOOL
fbd6baed 6416x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6417 char * lpxstr;
6418 LOGFONT * lplogfont;
6419{
f46e6225
GV
6420 struct coding_system coding;
6421
ee78dc32 6422 if (!lplogfont) return (FALSE);
f46e6225 6423
ee78dc32 6424 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6425
1a292d24 6426 /* Set default value for each field. */
771c47d5 6427#if 1
ee78dc32
GV
6428 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6429 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6430 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6431#else
6432 /* go for maximum quality */
6433 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6434 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6435 lplogfont->lfQuality = PROOF_QUALITY;
6436#endif
6437
1a292d24
AI
6438 lplogfont->lfCharSet = DEFAULT_CHARSET;
6439 lplogfont->lfWeight = FW_DONTCARE;
6440 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6441
5ac45f98
GV
6442 if (!lpxstr)
6443 return FALSE;
6444
6445 /* Provide a simple escape mechanism for specifying Windows font names
6446 * directly -- if font spec does not beginning with '-', assume this
6447 * format:
6448 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6449 */
ee78dc32 6450
5ac45f98
GV
6451 if (*lpxstr == '-')
6452 {
33d52f9c
GV
6453 int fields, tem;
6454 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6455 width[10], resy[10], remainder[50];
5ac45f98 6456 char * encoding;
d98c0337 6457 int dpi = one_w32_display_info.resy;
5ac45f98
GV
6458
6459 fields = sscanf (lpxstr,
8b77111c 6460 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6461 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6462 if (fields == EOF)
6463 return (FALSE);
6464
6465 /* In the general case when wildcards cover more than one field,
6466 we don't know which field is which, so don't fill any in.
6467 However, we need to cope with this particular form, which is
6468 generated by font_list_1 (invoked by try_font_list):
6469 "-raster-6x10-*-gb2312*-*"
6470 and make sure to correctly parse the charset field. */
6471 if (fields == 3)
6472 {
6473 fields = sscanf (lpxstr,
6474 "-%*[^-]-%49[^-]-*-%49s",
6475 name, remainder);
6476 }
6477 else if (fields < 9)
6478 {
6479 fields = 0;
6480 remainder[0] = 0;
6481 }
6fc2811b 6482
5ac45f98
GV
6483 if (fields > 0 && name[0] != '*')
6484 {
8ea3e054
RS
6485 int bufsize;
6486 unsigned char *buf;
6487
f46e6225 6488 setup_coding_system
1fa3a200 6489 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6490 coding.src_multibyte = 1;
6491 coding.dst_multibyte = 1;
8ea3e054
RS
6492 bufsize = encoding_buffer_size (&coding, strlen (name));
6493 buf = (unsigned char *) alloca (bufsize);
f46e6225 6494 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6495 encode_coding (&coding, name, buf, strlen (name), bufsize);
6496 if (coding.produced >= LF_FACESIZE)
6497 coding.produced = LF_FACESIZE - 1;
6498 buf[coding.produced] = 0;
6499 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6500 }
6501 else
6502 {
6fc2811b 6503 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6504 }
6505
6506 fields--;
6507
fbd6baed 6508 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6509
6510 fields--;
6511
c8874f14 6512 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6513
6514 fields--;
6515
6516 if (fields > 0 && pixels[0] != '*')
6517 lplogfont->lfHeight = atoi (pixels);
6518
6519 fields--;
5ac45f98 6520 fields--;
33d52f9c
GV
6521 if (fields > 0 && resy[0] != '*')
6522 {
6fc2811b 6523 tem = atoi (resy);
33d52f9c
GV
6524 if (tem > 0) dpi = tem;
6525 }
5ac45f98 6526
33d52f9c
GV
6527 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6528 lplogfont->lfHeight = atoi (height) * dpi / 720;
6529
6530 if (fields > 0)
5ac45f98
GV
6531 lplogfont->lfPitchAndFamily =
6532 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6533
6534 fields--;
6535
6536 if (fields > 0 && width[0] != '*')
6537 lplogfont->lfWidth = atoi (width) / 10;
6538
6539 fields--;
6540
4587b026 6541 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6542 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6543 {
5ac45f98
GV
6544 int len = strlen (remainder);
6545 if (len > 0 && remainder[len-1] == '-')
6546 remainder[len-1] = 0;
ee78dc32 6547 }
5ac45f98 6548 encoding = remainder;
8b77111c 6549#if 0
5ac45f98
GV
6550 if (strncmp (encoding, "*-", 2) == 0)
6551 encoding += 2;
8b77111c
AI
6552#endif
6553 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6554 }
6555 else
6556 {
6557 int fields;
6558 char name[100], height[10], width[10], weight[20];
a1a80b40 6559
5ac45f98
GV
6560 fields = sscanf (lpxstr,
6561 "%99[^:]:%9[^:]:%9[^:]:%19s",
6562 name, height, width, weight);
6563
6564 if (fields == EOF) return (FALSE);
6565
6566 if (fields > 0)
6567 {
6568 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6569 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6570 }
6571 else
6572 {
6573 lplogfont->lfFaceName[0] = 0;
6574 }
6575
6576 fields--;
6577
6578 if (fields > 0)
6579 lplogfont->lfHeight = atoi (height);
6580
6581 fields--;
6582
6583 if (fields > 0)
6584 lplogfont->lfWidth = atoi (width);
6585
6586 fields--;
6587
fbd6baed 6588 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6589 }
6590
6591 /* This makes TrueType fonts work better. */
6592 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6593
ee78dc32
GV
6594 return (TRUE);
6595}
6596
d88c567c
JR
6597/* Strip the pixel height and point height from the given xlfd, and
6598 return the pixel height. If no pixel height is specified, calculate
6599 one from the point height, or if that isn't defined either, return
6600 0 (which usually signifies a scalable font).
6601*/
8edb0a6f
JR
6602static int
6603xlfd_strip_height (char *fontname)
d88c567c 6604{
8edb0a6f 6605 int pixel_height, field_number;
d88c567c
JR
6606 char *read_from, *write_to;
6607
6608 xassert (fontname);
6609
6610 pixel_height = field_number = 0;
6611 write_to = NULL;
6612
6613 /* Look for height fields. */
6614 for (read_from = fontname; *read_from; read_from++)
6615 {
6616 if (*read_from == '-')
6617 {
6618 field_number++;
6619 if (field_number == 7) /* Pixel height. */
6620 {
6621 read_from++;
6622 write_to = read_from;
6623
6624 /* Find end of field. */
6625 for (;*read_from && *read_from != '-'; read_from++)
6626 ;
6627
6628 /* Split the fontname at end of field. */
6629 if (*read_from)
6630 {
6631 *read_from = '\0';
6632 read_from++;
6633 }
6634 pixel_height = atoi (write_to);
6635 /* Blank out field. */
6636 if (read_from > write_to)
6637 {
6638 *write_to = '-';
6639 write_to++;
6640 }
767b1ff0 6641 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6642 return now. */
6643 else
6644 return pixel_height;
6645
6646 /* If we got a pixel height, the point height can be
6647 ignored. Just blank it out and break now. */
6648 if (pixel_height)
6649 {
6650 /* Find end of point size field. */
6651 for (; *read_from && *read_from != '-'; read_from++)
6652 ;
6653
6654 if (*read_from)
6655 read_from++;
6656
6657 /* Blank out the point size field. */
6658 if (read_from > write_to)
6659 {
6660 *write_to = '-';
6661 write_to++;
6662 }
6663 else
6664 return pixel_height;
6665
6666 break;
6667 }
6668 /* If the point height is already blank, break now. */
6669 if (*read_from == '-')
6670 {
6671 read_from++;
6672 break;
6673 }
6674 }
6675 else if (field_number == 8)
6676 {
6677 /* If we didn't get a pixel height, try to get the point
6678 height and convert that. */
6679 int point_size;
6680 char *point_size_start = read_from++;
6681
6682 /* Find end of field. */
6683 for (; *read_from && *read_from != '-'; read_from++)
6684 ;
6685
6686 if (*read_from)
6687 {
6688 *read_from = '\0';
6689 read_from++;
6690 }
6691
6692 point_size = atoi (point_size_start);
6693
6694 /* Convert to pixel height. */
6695 pixel_height = point_size
6696 * one_w32_display_info.height_in / 720;
6697
6698 /* Blank out this field and break. */
6699 *write_to = '-';
6700 write_to++;
6701 break;
6702 }
6703 }
6704 }
6705
6706 /* Shift the rest of the font spec into place. */
6707 if (write_to && read_from > write_to)
6708 {
6709 for (; *read_from; read_from++, write_to++)
6710 *write_to = *read_from;
6711 *write_to = '\0';
6712 }
6713
6714 return pixel_height;
6715}
6716
6fc2811b 6717/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 6718static BOOL
6fc2811b
JR
6719w32_font_match (fontname, pattern)
6720 char * fontname;
6721 char * pattern;
ee78dc32 6722{
e7c72122 6723 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 6724 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6725 char *ptr;
ee78dc32 6726
d88c567c
JR
6727 /* Copy fontname so we can modify it during comparison. */
6728 strcpy (font_name_copy, fontname);
6729
6fc2811b
JR
6730 ptr = regex;
6731 *ptr++ = '^';
ee78dc32 6732
6fc2811b
JR
6733 /* Turn pattern into a regexp and do a regexp match. */
6734 for (; *pattern; pattern++)
6735 {
6736 if (*pattern == '?')
6737 *ptr++ = '.';
6738 else if (*pattern == '*')
6739 {
6740 *ptr++ = '.';
6741 *ptr++ = '*';
6742 }
33d52f9c 6743 else
6fc2811b 6744 *ptr++ = *pattern;
ee78dc32 6745 }
6fc2811b
JR
6746 *ptr = '$';
6747 *(ptr + 1) = '\0';
6748
d88c567c
JR
6749 /* Strip out font heights and compare them seperately, since
6750 rounding error can cause mismatches. This also allows a
6751 comparison between a font that declares only a pixel height and a
6752 pattern that declares the point height.
6753 */
6754 {
6755 int font_height, pattern_height;
6756
6757 font_height = xlfd_strip_height (font_name_copy);
6758 pattern_height = xlfd_strip_height (regex);
6759
6760 /* Compare now, and don't bother doing expensive regexp matching
6761 if the heights differ. */
6762 if (font_height && pattern_height && (font_height != pattern_height))
6763 return FALSE;
6764 }
6765
6fc2811b 6766 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 6767 font_name_copy) >= 0);
ee78dc32
GV
6768}
6769
5ca0cd71
GV
6770/* Callback functions, and a structure holding info they need, for
6771 listing system fonts on W32. We need one set of functions to do the
6772 job properly, but these don't work on NT 3.51 and earlier, so we
6773 have a second set which don't handle character sets properly to
6774 fall back on.
6775
6776 In both cases, there are two passes made. The first pass gets one
6777 font from each family, the second pass lists all the fonts from
6778 each family. */
6779
ee78dc32
GV
6780typedef struct enumfont_t
6781{
6782 HDC hdc;
6783 int numFonts;
3cb20f4a 6784 LOGFONT logfont;
ee78dc32
GV
6785 XFontStruct *size_ref;
6786 Lisp_Object *pattern;
ee78dc32
GV
6787 Lisp_Object *tail;
6788} enumfont_t;
6789
8edb0a6f 6790static int CALLBACK
ee78dc32
GV
6791enum_font_cb2 (lplf, lptm, FontType, lpef)
6792 ENUMLOGFONT * lplf;
6793 NEWTEXTMETRIC * lptm;
6794 int FontType;
6795 enumfont_t * lpef;
6796{
66895301
JR
6797 /* Ignore struck out and underlined versions of fonts. */
6798 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6799 return 1;
6800
6801 /* Only return fonts with names starting with @ if they were
6802 explicitly specified, since Microsoft uses an initial @ to
6803 denote fonts for vertical writing, without providing a more
6804 convenient way of identifying them. */
6805 if (lplf->elfLogFont.lfFaceName[0] == '@'
6806 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
6807 return 1;
6808
4587b026
GV
6809 /* Check that the character set matches if it was specified */
6810 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6811 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 6812 return 1;
4587b026 6813
ee78dc32
GV
6814 {
6815 char buf[100];
4587b026 6816 Lisp_Object width = Qnil;
767b1ff0 6817 char *charset = NULL;
ee78dc32 6818
6fc2811b
JR
6819 /* Truetype fonts do not report their true metrics until loaded */
6820 if (FontType != RASTER_FONTTYPE)
3cb20f4a 6821 {
6fc2811b
JR
6822 if (!NILP (*(lpef->pattern)))
6823 {
6824 /* Scalable fonts are as big as you want them to be. */
6825 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6826 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6827 width = make_number (lpef->logfont.lfWidth);
6828 }
6829 else
6830 {
6831 lplf->elfLogFont.lfHeight = 0;
6832 lplf->elfLogFont.lfWidth = 0;
6833 }
3cb20f4a 6834 }
6fc2811b 6835
f46e6225
GV
6836 /* Make sure the height used here is the same as everywhere
6837 else (ie character height, not cell height). */
6fc2811b
JR
6838 if (lplf->elfLogFont.lfHeight > 0)
6839 {
6840 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6841 if (FontType == RASTER_FONTTYPE)
6842 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6843 else
6844 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6845 }
4587b026 6846
767b1ff0
JR
6847 if (!NILP (*(lpef->pattern)))
6848 {
6849 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6850
6851 /* Ensure that charset is valid for this font. */
6852 if (charset
6853 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6854 charset = NULL;
6855 }
6856
6857 /* TODO: List all relevant charsets if charset not specified. */
6858 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
66895301 6859 return 1;
ee78dc32 6860
5ca0cd71
GV
6861 if (NILP (*(lpef->pattern))
6862 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 6863 {
4587b026 6864 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
8e713be6 6865 lpef->tail = &(XCDR (*lpef->tail));
ee78dc32
GV
6866 lpef->numFonts++;
6867 }
6868 }
6fc2811b 6869
5e905a57 6870 return 1;
ee78dc32
GV
6871}
6872
8edb0a6f 6873static int CALLBACK
ee78dc32
GV
6874enum_font_cb1 (lplf, lptm, FontType, lpef)
6875 ENUMLOGFONT * lplf;
6876 NEWTEXTMETRIC * lptm;
6877 int FontType;
6878 enumfont_t * lpef;
6879{
6880 return EnumFontFamilies (lpef->hdc,
6881 lplf->elfLogFont.lfFaceName,
6882 (FONTENUMPROC) enum_font_cb2,
6883 (LPARAM) lpef);
6884}
6885
6886
8edb0a6f 6887static int CALLBACK
5ca0cd71
GV
6888enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6889 ENUMLOGFONTEX * lplf;
6890 NEWTEXTMETRICEX * lptm;
6891 int font_type;
6892 enumfont_t * lpef;
6893{
6894 /* We are not interested in the extra info we get back from the 'Ex
6895 version - only the fact that we get character set variations
6896 enumerated seperately. */
6897 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6898 font_type, lpef);
6899}
6900
8edb0a6f 6901static int CALLBACK
5ca0cd71
GV
6902enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6903 ENUMLOGFONTEX * lplf;
6904 NEWTEXTMETRICEX * lptm;
6905 int font_type;
6906 enumfont_t * lpef;
6907{
6908 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6909 FARPROC enum_font_families_ex
6910 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6911 /* We don't really expect EnumFontFamiliesEx to disappear once we
6912 get here, so don't bother handling it gracefully. */
6913 if (enum_font_families_ex == NULL)
6914 error ("gdi32.dll has disappeared!");
6915 return enum_font_families_ex (lpef->hdc,
6916 &lplf->elfLogFont,
6917 (FONTENUMPROC) enum_fontex_cb2,
6918 (LPARAM) lpef, 0);
6919}
6920
4587b026
GV
6921/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6922 and xterm.c in Emacs 20.3) */
6923
8edb0a6f 6924static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6925{
6926 char *fontname, *ptnstr;
6927 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6928 int n_fonts = 0;
33d52f9c
GV
6929
6930 list = Vw32_bdf_filename_alist;
6931 ptnstr = XSTRING (pattern)->data;
6932
8e713be6 6933 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6934 {
8e713be6 6935 tem = XCAR (list);
33d52f9c 6936 if (CONSP (tem))
8e713be6 6937 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
6938 else if (STRINGP (tem))
6939 fontname = XSTRING (tem)->data;
6940 else
6941 continue;
6942
6943 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6944 {
8e713be6 6945 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6946 n_fonts++;
6947 if (n_fonts >= max_names)
6948 break;
6949 }
33d52f9c
GV
6950 }
6951
6952 return newlist;
6953}
6954
8edb0a6f
JR
6955static Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f,
6956 Lisp_Object pattern,
6957 int size, int max_names);
5ca0cd71 6958
4587b026
GV
6959/* Return a list of names of available fonts matching PATTERN on frame
6960 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6961 to be listed. Frame F NULL means we have not yet created any
6962 frame, which means we can't get proper size info, as we don't have
6963 a device context to use for GetTextMetrics.
6964 MAXNAMES sets a limit on how many fonts to match. */
6965
6966Lisp_Object
dc220243
JR
6967w32_list_fonts (f, pattern, size, maxnames)
6968 struct frame *f;
6969 Lisp_Object pattern;
6970 int size;
6971 int maxnames;
4587b026 6972{
6fc2811b 6973 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6974 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6975 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6976 int n_fonts = 0;
396594fe 6977
4587b026
GV
6978 patterns = Fassoc (pattern, Valternate_fontname_alist);
6979 if (NILP (patterns))
6980 patterns = Fcons (pattern, Qnil);
6981
8e713be6 6982 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6983 {
6984 enumfont_t ef;
767b1ff0 6985 int codepage;
4587b026 6986
8e713be6 6987 tpat = XCAR (patterns);
4587b026 6988
767b1ff0
JR
6989 if (!STRINGP (tpat))
6990 continue;
6991
6992 /* Avoid expensive EnumFontFamilies functions if we are not
6993 going to be able to output one of these anyway. */
6994 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6995 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
6996 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6997 && !IsValidCodePage(codepage))
767b1ff0
JR
6998 continue;
6999
4587b026
GV
7000 /* See if we cached the result for this particular query.
7001 The cache is an alist of the form:
7002 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7003 */
8e713be6 7004 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7005 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7006 {
7007 list = Fcdr_safe (list);
7008 /* We have a cached list. Don't have to get the list again. */
7009 goto label_cached;
7010 }
7011
7012 BLOCK_INPUT;
7013 /* At first, put PATTERN in the cache. */
7014 list = Qnil;
33d52f9c
GV
7015 ef.pattern = &tpat;
7016 ef.tail = &list;
4587b026 7017 ef.numFonts = 0;
33d52f9c 7018
5ca0cd71
GV
7019 /* Use EnumFontFamiliesEx where it is available, as it knows
7020 about character sets. Fall back to EnumFontFamilies for
7021 older versions of NT that don't support the 'Ex function. */
767b1ff0 7022 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7023 {
5ca0cd71
GV
7024 LOGFONT font_match_pattern;
7025 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7026 FARPROC enum_font_families_ex
7027 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7028
7029 /* We do our own pattern matching so we can handle wildcards. */
7030 font_match_pattern.lfFaceName[0] = 0;
7031 font_match_pattern.lfPitchAndFamily = 0;
7032 /* We can use the charset, because if it is a wildcard it will
7033 be DEFAULT_CHARSET anyway. */
7034 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7035
33d52f9c 7036 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7037
5ca0cd71
GV
7038 if (enum_font_families_ex)
7039 enum_font_families_ex (ef.hdc,
7040 &font_match_pattern,
7041 (FONTENUMPROC) enum_fontex_cb1,
7042 (LPARAM) &ef, 0);
7043 else
7044 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7045 (LPARAM)&ef);
4587b026 7046
33d52f9c 7047 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7048 }
7049
7050 UNBLOCK_INPUT;
7051
7052 /* Make a list of the fonts we got back.
7053 Store that in the font cache for the display. */
f3fbd155
KR
7054 XSETCDR (dpyinfo->name_list_element,
7055 Fcons (Fcons (tpat, list),
7056 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7057
7058 label_cached:
7059 if (NILP (list)) continue; /* Try the remaining alternatives. */
7060
7061 newlist = second_best = Qnil;
7062
7063 /* Make a list of the fonts that have the right width. */
8e713be6 7064 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7065 {
7066 int found_size;
8e713be6 7067 tem = XCAR (list);
4587b026
GV
7068
7069 if (!CONSP (tem))
7070 continue;
8e713be6 7071 if (NILP (XCAR (tem)))
4587b026
GV
7072 continue;
7073 if (!size)
7074 {
8e713be6 7075 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7076 n_fonts++;
7077 if (n_fonts >= maxnames)
7078 break;
7079 else
7080 continue;
4587b026 7081 }
8e713be6 7082 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7083 {
7084 /* Since we don't yet know the size of the font, we must
7085 load it and try GetTextMetrics. */
4587b026
GV
7086 W32FontStruct thisinfo;
7087 LOGFONT lf;
7088 HDC hdc;
7089 HANDLE oldobj;
7090
8e713be6 7091 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7092 continue;
7093
7094 BLOCK_INPUT;
33d52f9c 7095 thisinfo.bdf = NULL;
4587b026
GV
7096 thisinfo.hfont = CreateFontIndirect (&lf);
7097 if (thisinfo.hfont == NULL)
7098 continue;
7099
7100 hdc = GetDC (dpyinfo->root_window);
7101 oldobj = SelectObject (hdc, thisinfo.hfont);
7102 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7103 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7104 else
f3fbd155 7105 XSETCDR (tem, make_number (0));
4587b026
GV
7106 SelectObject (hdc, oldobj);
7107 ReleaseDC (dpyinfo->root_window, hdc);
7108 DeleteObject(thisinfo.hfont);
7109 UNBLOCK_INPUT;
7110 }
8e713be6 7111 found_size = XINT (XCDR (tem));
4587b026 7112 if (found_size == size)
5ca0cd71 7113 {
8e713be6 7114 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7115 n_fonts++;
7116 if (n_fonts >= maxnames)
7117 break;
7118 }
4587b026
GV
7119 /* keep track of the closest matching size in case
7120 no exact match is found. */
7121 else if (found_size > 0)
7122 {
7123 if (NILP (second_best))
7124 second_best = tem;
5ca0cd71 7125
4587b026
GV
7126 else if (found_size < size)
7127 {
8e713be6
KR
7128 if (XINT (XCDR (second_best)) > size
7129 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7130 second_best = tem;
7131 }
7132 else
7133 {
8e713be6
KR
7134 if (XINT (XCDR (second_best)) > size
7135 && XINT (XCDR (second_best)) >
4587b026
GV
7136 found_size)
7137 second_best = tem;
7138 }
7139 }
7140 }
7141
7142 if (!NILP (newlist))
7143 break;
7144 else if (!NILP (second_best))
7145 {
8e713be6 7146 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7147 break;
7148 }
7149 }
7150
33d52f9c 7151 /* Include any bdf fonts. */
5ca0cd71 7152 if (n_fonts < maxnames)
33d52f9c
GV
7153 {
7154 Lisp_Object combined[2];
5ca0cd71 7155 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7156 combined[1] = newlist;
7157 newlist = Fnconc(2, combined);
7158 }
7159
5ca0cd71
GV
7160 /* If we can't find a font that matches, check if Windows would be
7161 able to synthesize it from a different style. */
6fc2811b 7162 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
5ca0cd71
GV
7163 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
7164
4587b026
GV
7165 return newlist;
7166}
7167
8edb0a6f 7168static Lisp_Object
5ca0cd71
GV
7169w32_list_synthesized_fonts (f, pattern, size, max_names)
7170 FRAME_PTR f;
7171 Lisp_Object pattern;
7172 int size;
7173 int max_names;
7174{
7175 int fields;
7176 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
7177 char style[20], slant;
8edb0a6f 7178 Lisp_Object matches, tem, synthed_matches = Qnil;
5ca0cd71
GV
7179
7180 full_pattn = XSTRING (pattern)->data;
7181
8b77111c 7182 pattn_part2 = alloca (XSTRING (pattern)->size + 1);
5ca0cd71
GV
7183 /* Allow some space for wildcard expansion. */
7184 new_pattn = alloca (XSTRING (pattern)->size + 100);
7185
7186 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
7187 foundary, family, style, &slant, pattn_part2);
7188 if (fields == EOF || fields < 5)
7189 return Qnil;
7190
7191 /* If the style and slant are wildcards already there is no point
7192 checking again (and we don't want to keep recursing). */
7193 if (*style == '*' && slant == '*')
7194 return Qnil;
7195
7196 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
7197
7198 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
7199
8e713be6 7200 for ( ; CONSP (matches); matches = XCDR (matches))
5ca0cd71 7201 {
8e713be6 7202 tem = XCAR (matches);
5ca0cd71
GV
7203 if (!STRINGP (tem))
7204 continue;
7205
7206 full_pattn = XSTRING (tem)->data;
7207 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
7208 foundary, family, pattn_part2);
7209 if (fields == EOF || fields < 3)
7210 continue;
7211
7212 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
7213 slant, pattn_part2);
7214
7215 synthed_matches = Fcons (build_string (new_pattn),
7216 synthed_matches);
7217 }
7218
7219 return synthed_matches;
7220}
7221
7222
4587b026
GV
7223/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7224struct font_info *
7225w32_get_font_info (f, font_idx)
7226 FRAME_PTR f;
7227 int font_idx;
7228{
7229 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7230}
7231
7232
7233struct font_info*
7234w32_query_font (struct frame *f, char *fontname)
7235{
7236 int i;
7237 struct font_info *pfi;
7238
7239 pfi = FRAME_W32_FONT_TABLE (f);
7240
7241 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7242 {
7243 if (strcmp(pfi->name, fontname) == 0) return pfi;
7244 }
7245
7246 return NULL;
7247}
7248
7249/* Find a CCL program for a font specified by FONTP, and set the member
7250 `encoder' of the structure. */
7251
7252void
7253w32_find_ccl_program (fontp)
7254 struct font_info *fontp;
7255{
3545439c 7256 Lisp_Object list, elt;
4587b026 7257
8e713be6 7258 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7259 {
8e713be6 7260 elt = XCAR (list);
4587b026 7261 if (CONSP (elt)
8e713be6
KR
7262 && STRINGP (XCAR (elt))
7263 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7264 >= 0))
3545439c
KH
7265 break;
7266 }
7267 if (! NILP (list))
7268 {
17eedd00
KH
7269 struct ccl_program *ccl
7270 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7271
8e713be6 7272 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7273 xfree (ccl);
7274 else
7275 fontp->font_encoder = ccl;
4587b026
GV
7276 }
7277}
7278
7279\f
8edb0a6f
JR
7280/* Find BDF files in a specified directory. (use GCPRO when calling,
7281 as this calls lisp to get a directory listing). */
7282static Lisp_Object
7283w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7284{
7285 Lisp_Object filelist, list = Qnil;
7286 char fontname[100];
7287
7288 if (!STRINGP(directory))
7289 return Qnil;
7290
7291 filelist = Fdirectory_files (directory, Qt,
7292 build_string (".*\\.[bB][dD][fF]"), Qt);
7293
7294 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7295 {
7296 Lisp_Object filename = XCAR (filelist);
7297 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7298 store_in_alist (&list, build_string (fontname), filename);
7299 }
7300 return list;
7301}
7302
6fc2811b
JR
7303DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7304 1, 1, 0,
b3700ae7
JR
7305 doc: /* Return a list of BDF fonts in DIR.
7306The list is suitable for appending to w32-bdf-filename-alist. Fonts
7307which do not contain an xlfd description will not be included in the
7308list. DIR may be a list of directories. */)
6fc2811b
JR
7309 (directory)
7310 Lisp_Object directory;
7311{
7312 Lisp_Object list = Qnil;
7313 struct gcpro gcpro1, gcpro2;
ee78dc32 7314
6fc2811b
JR
7315 if (!CONSP (directory))
7316 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7317
6fc2811b 7318 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7319 {
6fc2811b
JR
7320 Lisp_Object pair[2];
7321 pair[0] = list;
7322 pair[1] = Qnil;
7323 GCPRO2 (directory, list);
7324 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7325 list = Fnconc( 2, pair );
7326 UNGCPRO;
7327 }
7328 return list;
7329}
ee78dc32 7330
6fc2811b
JR
7331\f
7332DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7333 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7334 (color, frame)
7335 Lisp_Object color, frame;
7336{
7337 XColor foo;
7338 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7339
b7826503 7340 CHECK_STRING (color);
ee78dc32 7341
6fc2811b
JR
7342 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7343 return Qt;
7344 else
7345 return Qnil;
7346}
ee78dc32 7347
2d764c78 7348DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7349 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7350 (color, frame)
7351 Lisp_Object color, frame;
7352{
6fc2811b 7353 XColor foo;
ee78dc32
GV
7354 FRAME_PTR f = check_x_frame (frame);
7355
b7826503 7356 CHECK_STRING (color);
ee78dc32 7357
6fc2811b 7358 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7359 {
7360 Lisp_Object rgb[3];
7361
6fc2811b
JR
7362 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7363 | GetRValue (foo.pixel));
7364 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7365 | GetGValue (foo.pixel));
7366 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7367 | GetBValue (foo.pixel));
ee78dc32
GV
7368 return Flist (3, rgb);
7369 }
7370 else
7371 return Qnil;
7372}
7373
2d764c78 7374DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7375 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7376 (display)
7377 Lisp_Object display;
7378{
fbd6baed 7379 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7380
7381 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7382 return Qnil;
7383
7384 return Qt;
7385}
7386
74e1aeec
JR
7387DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7388 Sx_display_grayscale_p, 0, 1, 0,
7389 doc: /* Return t if the X display supports shades of gray.
7390Note that color displays do support shades of gray.
7391The optional argument DISPLAY specifies which display to ask about.
7392DISPLAY should be either a frame or a display name (a string).
7393If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7394 (display)
7395 Lisp_Object display;
7396{
fbd6baed 7397 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7398
7399 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7400 return Qnil;
7401
7402 return Qt;
7403}
7404
74e1aeec
JR
7405DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7406 Sx_display_pixel_width, 0, 1, 0,
7407 doc: /* Returns the width in pixels of DISPLAY.
7408The optional argument DISPLAY specifies which display to ask about.
7409DISPLAY should be either a frame or a display name (a string).
7410If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7411 (display)
7412 Lisp_Object display;
7413{
fbd6baed 7414 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7415
7416 return make_number (dpyinfo->width);
7417}
7418
7419DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7420 Sx_display_pixel_height, 0, 1, 0,
7421 doc: /* Returns the height in pixels of DISPLAY.
7422The optional argument DISPLAY specifies which display to ask about.
7423DISPLAY should be either a frame or a display name (a string).
7424If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7425 (display)
7426 Lisp_Object display;
7427{
fbd6baed 7428 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7429
7430 return make_number (dpyinfo->height);
7431}
7432
7433DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7434 0, 1, 0,
7435 doc: /* Returns the number of bitplanes of DISPLAY.
7436The optional argument DISPLAY specifies which display to ask about.
7437DISPLAY should be either a frame or a display name (a string).
7438If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7439 (display)
7440 Lisp_Object display;
7441{
fbd6baed 7442 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7443
7444 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7445}
7446
7447DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7448 0, 1, 0,
7449 doc: /* Returns the number of color cells of DISPLAY.
7450The optional argument DISPLAY specifies which display to ask about.
7451DISPLAY should be either a frame or a display name (a string).
7452If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7453 (display)
7454 Lisp_Object display;
7455{
fbd6baed 7456 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7457 HDC hdc;
7458 int cap;
7459
5ac45f98
GV
7460 hdc = GetDC (dpyinfo->root_window);
7461 if (dpyinfo->has_palette)
7462 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7463 else
7464 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b
AI
7465
7466 if (cap < 0)
7467 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
ee78dc32
GV
7468
7469 ReleaseDC (dpyinfo->root_window, hdc);
7470
7471 return make_number (cap);
7472}
7473
7474DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7475 Sx_server_max_request_size,
74e1aeec
JR
7476 0, 1, 0,
7477 doc: /* Returns the maximum request size of the server of DISPLAY.
7478The optional argument DISPLAY specifies which display to ask about.
7479DISPLAY should be either a frame or a display name (a string).
7480If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7481 (display)
7482 Lisp_Object display;
7483{
fbd6baed 7484 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7485
7486 return make_number (1);
7487}
7488
7489DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7490 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7491The optional argument DISPLAY specifies which display to ask about.
7492DISPLAY should be either a frame or a display name (a string).
7493If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7494 (display)
7495 Lisp_Object display;
7496{
dfff8a69 7497 return build_string ("Microsoft Corp.");
ee78dc32
GV
7498}
7499
7500DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7501 doc: /* Returns the version numbers of the server of DISPLAY.
7502The value is a list of three integers: the major and minor
7503version numbers, and the vendor-specific release
7504number. See also the function `x-server-vendor'.
7505
7506The optional argument DISPLAY specifies which display to ask about.
7507DISPLAY should be either a frame or a display name (a string).
7508If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7509 (display)
7510 Lisp_Object display;
7511{
fbd6baed 7512 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7513 Fcons (make_number (w32_minor_version),
7514 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7515}
7516
7517DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7518 doc: /* Returns the number of screens on the server of DISPLAY.
7519The optional argument DISPLAY specifies which display to ask about.
7520DISPLAY should be either a frame or a display name (a string).
7521If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7522 (display)
7523 Lisp_Object display;
7524{
ee78dc32
GV
7525 return make_number (1);
7526}
7527
74e1aeec
JR
7528DEFUN ("x-display-mm-height", Fx_display_mm_height,
7529 Sx_display_mm_height, 0, 1, 0,
7530 doc: /* Returns the height in millimeters of DISPLAY.
7531The optional argument DISPLAY specifies which display to ask about.
7532DISPLAY should be either a frame or a display name (a string).
7533If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7534 (display)
7535 Lisp_Object display;
7536{
fbd6baed 7537 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7538 HDC hdc;
7539 int cap;
7540
5ac45f98 7541 hdc = GetDC (dpyinfo->root_window);
3c190163 7542
ee78dc32 7543 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7544
ee78dc32
GV
7545 ReleaseDC (dpyinfo->root_window, hdc);
7546
7547 return make_number (cap);
7548}
7549
7550DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7551 doc: /* Returns the width in millimeters of DISPLAY.
7552The optional argument DISPLAY specifies which display to ask about.
7553DISPLAY should be either a frame or a display name (a string).
7554If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7555 (display)
7556 Lisp_Object display;
7557{
fbd6baed 7558 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7559
7560 HDC hdc;
7561 int cap;
7562
5ac45f98 7563 hdc = GetDC (dpyinfo->root_window);
3c190163 7564
ee78dc32 7565 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7566
ee78dc32
GV
7567 ReleaseDC (dpyinfo->root_window, hdc);
7568
7569 return make_number (cap);
7570}
7571
7572DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7573 Sx_display_backing_store, 0, 1, 0,
7574 doc: /* Returns an indication of whether DISPLAY does backing store.
7575The value may be `always', `when-mapped', or `not-useful'.
7576The optional argument DISPLAY specifies which display to ask about.
7577DISPLAY should be either a frame or a display name (a string).
7578If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7579 (display)
7580 Lisp_Object display;
7581{
7582 return intern ("not-useful");
7583}
7584
7585DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7586 Sx_display_visual_class, 0, 1, 0,
7587 doc: /* Returns the visual class of DISPLAY.
7588The value is one of the symbols `static-gray', `gray-scale',
7589`static-color', `pseudo-color', `true-color', or `direct-color'.
7590
7591The optional argument DISPLAY specifies which display to ask about.
7592DISPLAY should be either a frame or a display name (a string).
7593If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7594 (display)
7595 Lisp_Object display;
7596{
fbd6baed 7597 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7598 Lisp_Object result = Qnil;
ee78dc32 7599
abf8c61b
AI
7600 if (dpyinfo->has_palette)
7601 result = intern ("pseudo-color");
7602 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7603 result = intern ("static-grey");
7604 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7605 result = intern ("static-color");
7606 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7607 result = intern ("true-color");
ee78dc32 7608
abf8c61b 7609 return result;
ee78dc32
GV
7610}
7611
7612DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7613 Sx_display_save_under, 0, 1, 0,
7614 doc: /* Returns t if DISPLAY supports the save-under feature.
7615The optional argument DISPLAY specifies which display to ask about.
7616DISPLAY should be either a frame or a display name (a string).
7617If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7618 (display)
7619 Lisp_Object display;
7620{
6fc2811b
JR
7621 return Qnil;
7622}
7623\f
7624int
7625x_pixel_width (f)
7626 register struct frame *f;
7627{
7628 return PIXEL_WIDTH (f);
7629}
7630
7631int
7632x_pixel_height (f)
7633 register struct frame *f;
7634{
7635 return PIXEL_HEIGHT (f);
7636}
7637
7638int
7639x_char_width (f)
7640 register struct frame *f;
7641{
7642 return FONT_WIDTH (f->output_data.w32->font);
7643}
7644
7645int
7646x_char_height (f)
7647 register struct frame *f;
7648{
7649 return f->output_data.w32->line_height;
7650}
7651
7652int
7653x_screen_planes (f)
7654 register struct frame *f;
7655{
7656 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7657}
7658\f
7659/* Return the display structure for the display named NAME.
7660 Open a new connection if necessary. */
7661
7662struct w32_display_info *
7663x_display_info_for_name (name)
7664 Lisp_Object name;
7665{
7666 Lisp_Object names;
7667 struct w32_display_info *dpyinfo;
7668
b7826503 7669 CHECK_STRING (name);
6fc2811b
JR
7670
7671 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7672 dpyinfo;
7673 dpyinfo = dpyinfo->next, names = XCDR (names))
7674 {
7675 Lisp_Object tem;
7676 tem = Fstring_equal (XCAR (XCAR (names)), name);
7677 if (!NILP (tem))
7678 return dpyinfo;
7679 }
7680
7681 /* Use this general default value to start with. */
7682 Vx_resource_name = Vinvocation_name;
7683
7684 validate_x_resource_name ();
7685
7686 dpyinfo = w32_term_init (name, (unsigned char *)0,
7687 (char *) XSTRING (Vx_resource_name)->data);
7688
7689 if (dpyinfo == 0)
7690 error ("Cannot connect to server %s", XSTRING (name)->data);
7691
7692 w32_in_use = 1;
7693 XSETFASTINT (Vwindow_system_version, 3);
7694
7695 return dpyinfo;
7696}
7697
7698DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
7699 1, 3, 0, doc: /* Open a connection to a server.
7700DISPLAY is the name of the display to connect to.
7701Optional second arg XRM-STRING is a string of resources in xrdb format.
7702If the optional third arg MUST-SUCCEED is non-nil,
7703terminate Emacs if we can't open the connection. */)
6fc2811b
JR
7704 (display, xrm_string, must_succeed)
7705 Lisp_Object display, xrm_string, must_succeed;
7706{
7707 unsigned char *xrm_option;
7708 struct w32_display_info *dpyinfo;
7709
74e1aeec
JR
7710 /* If initialization has already been done, return now to avoid
7711 overwriting critical parts of one_w32_display_info. */
7712 if (w32_in_use)
7713 return Qnil;
7714
b7826503 7715 CHECK_STRING (display);
6fc2811b 7716 if (! NILP (xrm_string))
b7826503 7717 CHECK_STRING (xrm_string);
6fc2811b
JR
7718
7719 if (! EQ (Vwindow_system, intern ("w32")))
7720 error ("Not using Microsoft Windows");
7721
7722 /* Allow color mapping to be defined externally; first look in user's
7723 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7724 {
7725 Lisp_Object color_file;
7726 struct gcpro gcpro1;
7727
7728 color_file = build_string("~/rgb.txt");
7729
7730 GCPRO1 (color_file);
7731
7732 if (NILP (Ffile_readable_p (color_file)))
7733 color_file =
7734 Fexpand_file_name (build_string ("rgb.txt"),
7735 Fsymbol_value (intern ("data-directory")));
7736
7737 Vw32_color_map = Fw32_load_color_file (color_file);
7738
7739 UNGCPRO;
7740 }
7741 if (NILP (Vw32_color_map))
7742 Vw32_color_map = Fw32_default_color_map ();
7743
7744 if (! NILP (xrm_string))
7745 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7746 else
7747 xrm_option = (unsigned char *) 0;
7748
7749 /* Use this general default value to start with. */
7750 /* First remove .exe suffix from invocation-name - it looks ugly. */
7751 {
7752 char basename[ MAX_PATH ], *str;
7753
7754 strcpy (basename, XSTRING (Vinvocation_name)->data);
7755 str = strrchr (basename, '.');
7756 if (str) *str = 0;
7757 Vinvocation_name = build_string (basename);
7758 }
7759 Vx_resource_name = Vinvocation_name;
7760
7761 validate_x_resource_name ();
7762
7763 /* This is what opens the connection and sets x_current_display.
7764 This also initializes many symbols, such as those used for input. */
7765 dpyinfo = w32_term_init (display, xrm_option,
7766 (char *) XSTRING (Vx_resource_name)->data);
7767
7768 if (dpyinfo == 0)
7769 {
7770 if (!NILP (must_succeed))
7771 fatal ("Cannot connect to server %s.\n",
7772 XSTRING (display)->data);
7773 else
7774 error ("Cannot connect to server %s", XSTRING (display)->data);
7775 }
7776
7777 w32_in_use = 1;
7778
7779 XSETFASTINT (Vwindow_system_version, 3);
7780 return Qnil;
7781}
7782
7783DEFUN ("x-close-connection", Fx_close_connection,
7784 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
7785 doc: /* Close the connection to DISPLAY's server.
7786For DISPLAY, specify either a frame or a display name (a string).
7787If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
7788 (display)
7789 Lisp_Object display;
7790{
7791 struct w32_display_info *dpyinfo = check_x_display_info (display);
7792 int i;
7793
7794 if (dpyinfo->reference_count > 0)
7795 error ("Display still has frames on it");
7796
7797 BLOCK_INPUT;
7798 /* Free the fonts in the font table. */
7799 for (i = 0; i < dpyinfo->n_fonts; i++)
7800 if (dpyinfo->font_table[i].name)
7801 {
126f2e35
JR
7802 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7803 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 7804 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
7805 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7806 }
7807 x_destroy_all_bitmaps (dpyinfo);
7808
7809 x_delete_display (dpyinfo);
7810 UNBLOCK_INPUT;
7811
7812 return Qnil;
7813}
7814
7815DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 7816 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
7817 ()
7818{
7819 Lisp_Object tail, result;
7820
7821 result = Qnil;
7822 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7823 result = Fcons (XCAR (XCAR (tail)), result);
7824
7825 return result;
7826}
7827
7828DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
7829 doc: /* This is a noop on W32 systems. */)
7830 (on, display)
7831 Lisp_Object display, on;
6fc2811b 7832{
6fc2811b
JR
7833 return Qnil;
7834}
7835
7836\f
7837\f
7838/***********************************************************************
7839 Image types
7840 ***********************************************************************/
7841
7842/* Value is the number of elements of vector VECTOR. */
7843
7844#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7845
7846/* List of supported image types. Use define_image_type to add new
7847 types. Use lookup_image_type to find a type for a given symbol. */
7848
7849static struct image_type *image_types;
7850
6fc2811b
JR
7851/* The symbol `image' which is the car of the lists used to represent
7852 images in Lisp. */
7853
7854extern Lisp_Object Qimage;
7855
7856/* The symbol `xbm' which is used as the type symbol for XBM images. */
7857
7858Lisp_Object Qxbm;
7859
7860/* Keywords. */
7861
6fc2811b 7862extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
7863extern Lisp_Object QCdata;
7864Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
a93f4566 7865Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 7866Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
7867
7868/* Other symbols. */
7869
3cf3436e 7870Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
7871
7872/* Time in seconds after which images should be removed from the cache
7873 if not displayed. */
7874
7875Lisp_Object Vimage_cache_eviction_delay;
7876
7877/* Function prototypes. */
7878
7879static void define_image_type P_ ((struct image_type *type));
7880static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7881static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7882static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 7883static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
7884static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7885 Lisp_Object));
7886
dfff8a69 7887
6fc2811b
JR
7888/* Define a new image type from TYPE. This adds a copy of TYPE to
7889 image_types and adds the symbol *TYPE->type to Vimage_types. */
7890
7891static void
7892define_image_type (type)
7893 struct image_type *type;
7894{
7895 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7896 The initialized data segment is read-only. */
7897 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7898 bcopy (type, p, sizeof *p);
7899 p->next = image_types;
7900 image_types = p;
7901 Vimage_types = Fcons (*p->type, Vimage_types);
7902}
7903
7904
7905/* Look up image type SYMBOL, and return a pointer to its image_type
7906 structure. Value is null if SYMBOL is not a known image type. */
7907
7908static INLINE struct image_type *
7909lookup_image_type (symbol)
7910 Lisp_Object symbol;
7911{
7912 struct image_type *type;
7913
7914 for (type = image_types; type; type = type->next)
7915 if (EQ (symbol, *type->type))
7916 break;
7917
7918 return type;
7919}
7920
7921
7922/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7923 valid image specification is a list whose car is the symbol
7924 `image', and whose rest is a property list. The property list must
7925 contain a value for key `:type'. That value must be the name of a
7926 supported image type. The rest of the property list depends on the
7927 image type. */
7928
7929int
7930valid_image_p (object)
7931 Lisp_Object object;
7932{
7933 int valid_p = 0;
7934
7935 if (CONSP (object) && EQ (XCAR (object), Qimage))
7936 {
3cf3436e
JR
7937 Lisp_Object tem;
7938
7939 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
7940 if (EQ (XCAR (tem), QCtype))
7941 {
7942 tem = XCDR (tem);
7943 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
7944 {
7945 struct image_type *type;
7946 type = lookup_image_type (XCAR (tem));
7947 if (type)
7948 valid_p = type->valid_p (object);
7949 }
7950
7951 break;
7952 }
6fc2811b
JR
7953 }
7954
7955 return valid_p;
7956}
7957
7958
7959/* Log error message with format string FORMAT and argument ARG.
7960 Signaling an error, e.g. when an image cannot be loaded, is not a
7961 good idea because this would interrupt redisplay, and the error
7962 message display would lead to another redisplay. This function
7963 therefore simply displays a message. */
7964
7965static void
7966image_error (format, arg1, arg2)
7967 char *format;
7968 Lisp_Object arg1, arg2;
7969{
7970 add_to_log (format, arg1, arg2);
7971}
7972
7973
7974\f
7975/***********************************************************************
7976 Image specifications
7977 ***********************************************************************/
7978
7979enum image_value_type
7980{
7981 IMAGE_DONT_CHECK_VALUE_TYPE,
7982 IMAGE_STRING_VALUE,
3cf3436e 7983 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
7984 IMAGE_SYMBOL_VALUE,
7985 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 7986 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 7987 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 7988 IMAGE_ASCENT_VALUE,
6fc2811b
JR
7989 IMAGE_INTEGER_VALUE,
7990 IMAGE_FUNCTION_VALUE,
7991 IMAGE_NUMBER_VALUE,
7992 IMAGE_BOOL_VALUE
7993};
7994
7995/* Structure used when parsing image specifications. */
7996
7997struct image_keyword
7998{
7999 /* Name of keyword. */
8000 char *name;
8001
8002 /* The type of value allowed. */
8003 enum image_value_type type;
8004
8005 /* Non-zero means key must be present. */
8006 int mandatory_p;
8007
8008 /* Used to recognize duplicate keywords in a property list. */
8009 int count;
8010
8011 /* The value that was found. */
8012 Lisp_Object value;
8013};
8014
8015
8016static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8017 int, Lisp_Object));
8018static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8019
8020
8021/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8022 has the format (image KEYWORD VALUE ...). One of the keyword/
8023 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8024 image_keywords structures of size NKEYWORDS describing other
8025 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8026
8027static int
8028parse_image_spec (spec, keywords, nkeywords, type)
8029 Lisp_Object spec;
8030 struct image_keyword *keywords;
8031 int nkeywords;
8032 Lisp_Object type;
8033{
8034 int i;
8035 Lisp_Object plist;
8036
8037 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8038 return 0;
8039
8040 plist = XCDR (spec);
8041 while (CONSP (plist))
8042 {
8043 Lisp_Object key, value;
8044
8045 /* First element of a pair must be a symbol. */
8046 key = XCAR (plist);
8047 plist = XCDR (plist);
8048 if (!SYMBOLP (key))
8049 return 0;
8050
8051 /* There must follow a value. */
8052 if (!CONSP (plist))
8053 return 0;
8054 value = XCAR (plist);
8055 plist = XCDR (plist);
8056
8057 /* Find key in KEYWORDS. Error if not found. */
8058 for (i = 0; i < nkeywords; ++i)
8059 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8060 break;
8061
8062 if (i == nkeywords)
8063 continue;
8064
8065 /* Record that we recognized the keyword. If a keywords
8066 was found more than once, it's an error. */
8067 keywords[i].value = value;
8068 ++keywords[i].count;
8069
8070 if (keywords[i].count > 1)
8071 return 0;
8072
8073 /* Check type of value against allowed type. */
8074 switch (keywords[i].type)
8075 {
8076 case IMAGE_STRING_VALUE:
8077 if (!STRINGP (value))
8078 return 0;
8079 break;
8080
3cf3436e
JR
8081 case IMAGE_STRING_OR_NIL_VALUE:
8082 if (!STRINGP (value) && !NILP (value))
8083 return 0;
8084 break;
8085
6fc2811b
JR
8086 case IMAGE_SYMBOL_VALUE:
8087 if (!SYMBOLP (value))
8088 return 0;
8089 break;
8090
8091 case IMAGE_POSITIVE_INTEGER_VALUE:
8092 if (!INTEGERP (value) || XINT (value) <= 0)
8093 return 0;
8094 break;
8095
8edb0a6f
JR
8096 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8097 if (INTEGERP (value) && XINT (value) >= 0)
8098 break;
8099 if (CONSP (value)
8100 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8101 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8102 break;
8103 return 0;
8104
dfff8a69
JR
8105 case IMAGE_ASCENT_VALUE:
8106 if (SYMBOLP (value) && EQ (value, Qcenter))
8107 break;
8108 else if (INTEGERP (value)
8109 && XINT (value) >= 0
8110 && XINT (value) <= 100)
8111 break;
8112 return 0;
8113
6fc2811b
JR
8114 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8115 if (!INTEGERP (value) || XINT (value) < 0)
8116 return 0;
8117 break;
8118
8119 case IMAGE_DONT_CHECK_VALUE_TYPE:
8120 break;
8121
8122 case IMAGE_FUNCTION_VALUE:
8123 value = indirect_function (value);
8124 if (SUBRP (value)
8125 || COMPILEDP (value)
8126 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8127 break;
8128 return 0;
8129
8130 case IMAGE_NUMBER_VALUE:
8131 if (!INTEGERP (value) && !FLOATP (value))
8132 return 0;
8133 break;
8134
8135 case IMAGE_INTEGER_VALUE:
8136 if (!INTEGERP (value))
8137 return 0;
8138 break;
8139
8140 case IMAGE_BOOL_VALUE:
8141 if (!NILP (value) && !EQ (value, Qt))
8142 return 0;
8143 break;
8144
8145 default:
8146 abort ();
8147 break;
8148 }
8149
8150 if (EQ (key, QCtype) && !EQ (type, value))
8151 return 0;
8152 }
8153
8154 /* Check that all mandatory fields are present. */
8155 for (i = 0; i < nkeywords; ++i)
8156 if (keywords[i].mandatory_p && keywords[i].count == 0)
8157 return 0;
8158
8159 return NILP (plist);
8160}
8161
8162
8163/* Return the value of KEY in image specification SPEC. Value is nil
8164 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8165 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8166
8167static Lisp_Object
8168image_spec_value (spec, key, found)
8169 Lisp_Object spec, key;
8170 int *found;
8171{
8172 Lisp_Object tail;
8173
8174 xassert (valid_image_p (spec));
8175
8176 for (tail = XCDR (spec);
8177 CONSP (tail) && CONSP (XCDR (tail));
8178 tail = XCDR (XCDR (tail)))
8179 {
8180 if (EQ (XCAR (tail), key))
8181 {
8182 if (found)
8183 *found = 1;
8184 return XCAR (XCDR (tail));
8185 }
8186 }
8187
8188 if (found)
8189 *found = 0;
8190 return Qnil;
8191}
8192
8193
8194
8195\f
8196/***********************************************************************
8197 Image type independent image structures
8198 ***********************************************************************/
8199
8200static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8201static void free_image P_ ((struct frame *f, struct image *img));
8202
8203
8204/* Allocate and return a new image structure for image specification
8205 SPEC. SPEC has a hash value of HASH. */
8206
8207static struct image *
8208make_image (spec, hash)
8209 Lisp_Object spec;
8210 unsigned hash;
8211{
8212 struct image *img = (struct image *) xmalloc (sizeof *img);
8213
8214 xassert (valid_image_p (spec));
8215 bzero (img, sizeof *img);
8216 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8217 xassert (img->type != NULL);
8218 img->spec = spec;
8219 img->data.lisp_val = Qnil;
8220 img->ascent = DEFAULT_IMAGE_ASCENT;
8221 img->hash = hash;
8222 return img;
8223}
8224
8225
8226/* Free image IMG which was used on frame F, including its resources. */
8227
8228static void
8229free_image (f, img)
8230 struct frame *f;
8231 struct image *img;
8232{
8233 if (img)
8234 {
8235 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8236
8237 /* Remove IMG from the hash table of its cache. */
8238 if (img->prev)
8239 img->prev->next = img->next;
8240 else
8241 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8242
8243 if (img->next)
8244 img->next->prev = img->prev;
8245
8246 c->images[img->id] = NULL;
8247
8248 /* Free resources, then free IMG. */
8249 img->type->free (f, img);
8250 xfree (img);
8251 }
8252}
8253
8254
8255/* Prepare image IMG for display on frame F. Must be called before
8256 drawing an image. */
8257
8258void
8259prepare_image_for_display (f, img)
8260 struct frame *f;
8261 struct image *img;
8262{
8263 EMACS_TIME t;
8264
8265 /* We're about to display IMG, so set its timestamp to `now'. */
8266 EMACS_GET_TIME (t);
8267 img->timestamp = EMACS_SECS (t);
8268
8269 /* If IMG doesn't have a pixmap yet, load it now, using the image
8270 type dependent loader function. */
8271 if (img->pixmap == 0 && !img->load_failed_p)
8272 img->load_failed_p = img->type->load (f, img) == 0;
8273}
8274
8275
dfff8a69
JR
8276/* Value is the number of pixels for the ascent of image IMG when
8277 drawn in face FACE. */
8278
8279int
8280image_ascent (img, face)
8281 struct image *img;
8282 struct face *face;
8283{
8edb0a6f 8284 int height = img->height + img->vmargin;
dfff8a69
JR
8285 int ascent;
8286
8287 if (img->ascent == CENTERED_IMAGE_ASCENT)
8288 {
8289 if (face->font)
8290 ascent = height / 2 - (FONT_DESCENT(face->font)
8291 - FONT_BASE(face->font)) / 2;
8292 else
8293 ascent = height / 2;
8294 }
8295 else
8296 ascent = height * img->ascent / 100.0;
8297
8298 return ascent;
8299}
8300
8301
6fc2811b 8302\f
a05e2bae
JR
8303/* Image background colors. */
8304
8305static unsigned long
8306four_corners_best (ximg, width, height)
8307 XImage *ximg;
8308 unsigned long width, height;
8309{
8310#if 0 /* TODO: Image support. */
8311 unsigned long corners[4], best;
8312 int i, best_count;
8313
8314 /* Get the colors at the corners of ximg. */
8315 corners[0] = XGetPixel (ximg, 0, 0);
8316 corners[1] = XGetPixel (ximg, width - 1, 0);
8317 corners[2] = XGetPixel (ximg, width - 1, height - 1);
8318 corners[3] = XGetPixel (ximg, 0, height - 1);
8319
8320 /* Choose the most frequently found color as background. */
8321 for (i = best_count = 0; i < 4; ++i)
8322 {
8323 int j, n;
8324
8325 for (j = n = 0; j < 4; ++j)
8326 if (corners[i] == corners[j])
8327 ++n;
8328
8329 if (n > best_count)
8330 best = corners[i], best_count = n;
8331 }
8332
8333 return best;
8334#else
8335 return 0;
8336#endif
8337}
8338
8339/* Return the `background' field of IMG. If IMG doesn't have one yet,
8340 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8341 object to use for the heuristic. */
8342
8343unsigned long
8344image_background (img, f, ximg)
8345 struct image *img;
8346 struct frame *f;
8347 XImage *ximg;
8348{
8349 if (! img->background_valid)
8350 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8351 {
8352#if 0 /* TODO: Image support. */
8353 int free_ximg = !ximg;
8354
8355 if (! ximg)
8356 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8357 0, 0, img->width, img->height, ~0, ZPixmap);
8358
8359 img->background = four_corners_best (ximg, img->width, img->height);
8360
8361 if (free_ximg)
8362 XDestroyImage (ximg);
8363
8364 img->background_valid = 1;
8365#endif
8366 }
8367
8368 return img->background;
8369}
8370
8371/* Return the `background_transparent' field of IMG. If IMG doesn't
8372 have one yet, it is guessed heuristically. If non-zero, MASK is an
8373 existing XImage object to use for the heuristic. */
8374
8375int
8376image_background_transparent (img, f, mask)
8377 struct image *img;
8378 struct frame *f;
8379 XImage *mask;
8380{
8381 if (! img->background_transparent_valid)
8382 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8383 {
8384#if 0 /* TODO: Image support. */
8385 if (img->mask)
8386 {
8387 int free_mask = !mask;
8388
8389 if (! mask)
8390 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8391 0, 0, img->width, img->height, ~0, ZPixmap);
8392
8393 img->background_transparent
8394 = !four_corners_best (mask, img->width, img->height);
8395
8396 if (free_mask)
8397 XDestroyImage (mask);
8398 }
8399 else
8400#endif
8401 img->background_transparent = 0;
8402
8403 img->background_transparent_valid = 1;
8404 }
8405
8406 return img->background_transparent;
8407}
8408
8409\f
6fc2811b
JR
8410/***********************************************************************
8411 Helper functions for X image types
8412 ***********************************************************************/
8413
a05e2bae
JR
8414static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8415 int, int));
6fc2811b
JR
8416static void x_clear_image P_ ((struct frame *f, struct image *img));
8417static unsigned long x_alloc_image_color P_ ((struct frame *f,
8418 struct image *img,
8419 Lisp_Object color_name,
8420 unsigned long dflt));
8421
a05e2bae
JR
8422
8423/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8424 free the pixmap if any. MASK_P non-zero means clear the mask
8425 pixmap if any. COLORS_P non-zero means free colors allocated for
8426 the image, if any. */
8427
8428static void
8429x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8430 struct frame *f;
8431 struct image *img;
8432 int pixmap_p, mask_p, colors_p;
8433{
9eb16b62 8434#if 0 /* TODO: W32 image support */
a05e2bae
JR
8435 if (pixmap_p && img->pixmap)
8436 {
8437 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8438 img->pixmap = None;
8439 img->background_valid = 0;
8440 }
8441
8442 if (mask_p && img->mask)
8443 {
8444 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8445 img->mask = None;
8446 img->background_transparent_valid = 0;
8447 }
8448
8449 if (colors_p && img->ncolors)
8450 {
8451 x_free_colors (f, img->colors, img->ncolors);
8452 xfree (img->colors);
8453 img->colors = NULL;
8454 img->ncolors = 0;
8455 }
8456#endif
8457}
8458
6fc2811b
JR
8459/* Free X resources of image IMG which is used on frame F. */
8460
8461static void
8462x_clear_image (f, img)
8463 struct frame *f;
8464 struct image *img;
8465{
767b1ff0 8466#if 0 /* TODO: W32 image support */
6fc2811b
JR
8467
8468 if (img->pixmap)
8469 {
8470 BLOCK_INPUT;
8471 XFreePixmap (NULL, img->pixmap);
8472 img->pixmap = 0;
8473 UNBLOCK_INPUT;
8474 }
8475
8476 if (img->ncolors)
8477 {
8478 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8479
8480 /* If display has an immutable color map, freeing colors is not
8481 necessary and some servers don't allow it. So don't do it. */
8482 if (class != StaticColor
8483 && class != StaticGray
8484 && class != TrueColor)
8485 {
8486 Colormap cmap;
8487 BLOCK_INPUT;
8488 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8489 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8490 img->ncolors, 0);
8491 UNBLOCK_INPUT;
8492 }
8493
8494 xfree (img->colors);
8495 img->colors = NULL;
8496 img->ncolors = 0;
8497 }
8498#endif
8499}
8500
8501
8502/* Allocate color COLOR_NAME for image IMG on frame F. If color
8503 cannot be allocated, use DFLT. Add a newly allocated color to
8504 IMG->colors, so that it can be freed again. Value is the pixel
8505 color. */
8506
8507static unsigned long
8508x_alloc_image_color (f, img, color_name, dflt)
8509 struct frame *f;
8510 struct image *img;
8511 Lisp_Object color_name;
8512 unsigned long dflt;
8513{
767b1ff0 8514#if 0 /* TODO: allocing colors. */
6fc2811b
JR
8515 XColor color;
8516 unsigned long result;
8517
8518 xassert (STRINGP (color_name));
8519
8520 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8521 {
8522 /* This isn't called frequently so we get away with simply
8523 reallocating the color vector to the needed size, here. */
8524 ++img->ncolors;
8525 img->colors =
8526 (unsigned long *) xrealloc (img->colors,
8527 img->ncolors * sizeof *img->colors);
8528 img->colors[img->ncolors - 1] = color.pixel;
8529 result = color.pixel;
8530 }
8531 else
8532 result = dflt;
8533 return result;
8534#endif
8535 return 0;
8536}
8537
8538
8539\f
8540/***********************************************************************
8541 Image Cache
8542 ***********************************************************************/
8543
8544static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8545static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8546
8547
8548/* Return a new, initialized image cache that is allocated from the
8549 heap. Call free_image_cache to free an image cache. */
8550
8551struct image_cache *
8552make_image_cache ()
8553{
8554 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8555 int size;
8556
8557 bzero (c, sizeof *c);
8558 c->size = 50;
8559 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8560 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8561 c->buckets = (struct image **) xmalloc (size);
8562 bzero (c->buckets, size);
8563 return c;
8564}
8565
8566
8567/* Free image cache of frame F. Be aware that X frames share images
8568 caches. */
8569
8570void
8571free_image_cache (f)
8572 struct frame *f;
8573{
8574 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8575 if (c)
8576 {
8577 int i;
8578
8579 /* Cache should not be referenced by any frame when freed. */
8580 xassert (c->refcount == 0);
8581
8582 for (i = 0; i < c->used; ++i)
8583 free_image (f, c->images[i]);
8584 xfree (c->images);
8585 xfree (c);
8586 xfree (c->buckets);
8587 FRAME_X_IMAGE_CACHE (f) = NULL;
8588 }
8589}
8590
8591
8592/* Clear image cache of frame F. FORCE_P non-zero means free all
8593 images. FORCE_P zero means clear only images that haven't been
8594 displayed for some time. Should be called from time to time to
dfff8a69
JR
8595 reduce the number of loaded images. If image-eviction-seconds is
8596 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8597 at least that many seconds. */
8598
8599void
8600clear_image_cache (f, force_p)
8601 struct frame *f;
8602 int force_p;
8603{
8604 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8605
8606 if (c && INTEGERP (Vimage_cache_eviction_delay))
8607 {
8608 EMACS_TIME t;
8609 unsigned long old;
8610 int i, any_freed_p = 0;
8611
8612 EMACS_GET_TIME (t);
8613 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8614
8615 for (i = 0; i < c->used; ++i)
8616 {
8617 struct image *img = c->images[i];
8618 if (img != NULL
8619 && (force_p
8620 || (img->timestamp > old)))
8621 {
8622 free_image (f, img);
8623 any_freed_p = 1;
8624 }
8625 }
8626
8627 /* We may be clearing the image cache because, for example,
8628 Emacs was iconified for a longer period of time. In that
8629 case, current matrices may still contain references to
8630 images freed above. So, clear these matrices. */
8631 if (any_freed_p)
8632 {
8633 clear_current_matrices (f);
8634 ++windows_or_buffers_changed;
8635 }
8636 }
8637}
8638
8639
8640DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8641 0, 1, 0,
74e1aeec
JR
8642 doc: /* Clear the image cache of FRAME.
8643FRAME nil or omitted means use the selected frame.
8644FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
8645 (frame)
8646 Lisp_Object frame;
8647{
8648 if (EQ (frame, Qt))
8649 {
8650 Lisp_Object tail;
8651
8652 FOR_EACH_FRAME (tail, frame)
8653 if (FRAME_W32_P (XFRAME (frame)))
8654 clear_image_cache (XFRAME (frame), 1);
8655 }
8656 else
8657 clear_image_cache (check_x_frame (frame), 1);
8658
8659 return Qnil;
8660}
8661
8662
3cf3436e
JR
8663/* Compute masks and transform image IMG on frame F, as specified
8664 by the image's specification, */
8665
8666static void
8667postprocess_image (f, img)
8668 struct frame *f;
8669 struct image *img;
8670{
8671#if 0 /* TODO: image support. */
8672 /* Manipulation of the image's mask. */
8673 if (img->pixmap)
8674 {
8675 Lisp_Object conversion, spec;
8676 Lisp_Object mask;
8677
8678 spec = img->spec;
8679
8680 /* `:heuristic-mask t'
8681 `:mask heuristic'
8682 means build a mask heuristically.
8683 `:heuristic-mask (R G B)'
8684 `:mask (heuristic (R G B))'
8685 means build a mask from color (R G B) in the
8686 image.
8687 `:mask nil'
8688 means remove a mask, if any. */
8689
8690 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8691 if (!NILP (mask))
8692 x_build_heuristic_mask (f, img, mask);
8693 else
8694 {
8695 int found_p;
8696
8697 mask = image_spec_value (spec, QCmask, &found_p);
8698
8699 if (EQ (mask, Qheuristic))
8700 x_build_heuristic_mask (f, img, Qt);
8701 else if (CONSP (mask)
8702 && EQ (XCAR (mask), Qheuristic))
8703 {
8704 if (CONSP (XCDR (mask)))
8705 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8706 else
8707 x_build_heuristic_mask (f, img, XCDR (mask));
8708 }
8709 else if (NILP (mask) && found_p && img->mask)
8710 {
8711 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8712 img->mask = NULL;
8713 }
8714 }
8715
8716
8717 /* Should we apply an image transformation algorithm? */
8718 conversion = image_spec_value (spec, QCconversion, NULL);
8719 if (EQ (conversion, Qdisabled))
8720 x_disable_image (f, img);
8721 else if (EQ (conversion, Qlaplace))
8722 x_laplace (f, img);
8723 else if (EQ (conversion, Qemboss))
8724 x_emboss (f, img);
8725 else if (CONSP (conversion)
8726 && EQ (XCAR (conversion), Qedge_detection))
8727 {
8728 Lisp_Object tem;
8729 tem = XCDR (conversion);
8730 if (CONSP (tem))
8731 x_edge_detection (f, img,
8732 Fplist_get (tem, QCmatrix),
8733 Fplist_get (tem, QCcolor_adjustment));
8734 }
8735 }
8736#endif
8737}
8738
8739
6fc2811b
JR
8740/* Return the id of image with Lisp specification SPEC on frame F.
8741 SPEC must be a valid Lisp image specification (see valid_image_p). */
8742
8743int
8744lookup_image (f, spec)
8745 struct frame *f;
8746 Lisp_Object spec;
8747{
8748 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8749 struct image *img;
8750 int i;
8751 unsigned hash;
8752 struct gcpro gcpro1;
8753 EMACS_TIME now;
8754
8755 /* F must be a window-system frame, and SPEC must be a valid image
8756 specification. */
8757 xassert (FRAME_WINDOW_P (f));
8758 xassert (valid_image_p (spec));
8759
8760 GCPRO1 (spec);
8761
8762 /* Look up SPEC in the hash table of the image cache. */
8763 hash = sxhash (spec, 0);
8764 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8765
8766 for (img = c->buckets[i]; img; img = img->next)
8767 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8768 break;
8769
8770 /* If not found, create a new image and cache it. */
8771 if (img == NULL)
8772 {
3cf3436e
JR
8773 extern Lisp_Object Qpostscript;
8774
8edb0a6f 8775 BLOCK_INPUT;
6fc2811b
JR
8776 img = make_image (spec, hash);
8777 cache_image (f, img);
8778 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
8779
8780 /* If we can't load the image, and we don't have a width and
8781 height, use some arbitrary width and height so that we can
8782 draw a rectangle for it. */
8783 if (img->load_failed_p)
8784 {
8785 Lisp_Object value;
8786
8787 value = image_spec_value (spec, QCwidth, NULL);
8788 img->width = (INTEGERP (value)
8789 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8790 value = image_spec_value (spec, QCheight, NULL);
8791 img->height = (INTEGERP (value)
8792 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8793 }
8794 else
8795 {
8796 /* Handle image type independent image attributes
a05e2bae
JR
8797 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
8798 `:background COLOR'. */
8799 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
8800
8801 ascent = image_spec_value (spec, QCascent, NULL);
8802 if (INTEGERP (ascent))
8803 img->ascent = XFASTINT (ascent);
dfff8a69
JR
8804 else if (EQ (ascent, Qcenter))
8805 img->ascent = CENTERED_IMAGE_ASCENT;
8806
6fc2811b
JR
8807 margin = image_spec_value (spec, QCmargin, NULL);
8808 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
8809 img->vmargin = img->hmargin = XFASTINT (margin);
8810 else if (CONSP (margin) && INTEGERP (XCAR (margin))
8811 && INTEGERP (XCDR (margin)))
8812 {
8813 if (XINT (XCAR (margin)) > 0)
8814 img->hmargin = XFASTINT (XCAR (margin));
8815 if (XINT (XCDR (margin)) > 0)
8816 img->vmargin = XFASTINT (XCDR (margin));
8817 }
6fc2811b
JR
8818
8819 relief = image_spec_value (spec, QCrelief, NULL);
8820 if (INTEGERP (relief))
8821 {
8822 img->relief = XINT (relief);
8edb0a6f
JR
8823 img->hmargin += abs (img->relief);
8824 img->vmargin += abs (img->relief);
6fc2811b
JR
8825 }
8826
a05e2bae
JR
8827 if (! img->background_valid)
8828 {
8829 bg = image_spec_value (img->spec, QCbackground, NULL);
8830 if (!NILP (bg))
8831 {
8832 img->background
8833 = x_alloc_image_color (f, img, bg,
8834 FRAME_BACKGROUND_PIXEL (f));
8835 img->background_valid = 1;
8836 }
8837 }
8838
3cf3436e
JR
8839 /* Do image transformations and compute masks, unless we
8840 don't have the image yet. */
8841 if (!EQ (*img->type->type, Qpostscript))
8842 postprocess_image (f, img);
6fc2811b 8843 }
3cf3436e 8844
8edb0a6f
JR
8845 UNBLOCK_INPUT;
8846 xassert (!interrupt_input_blocked);
6fc2811b
JR
8847 }
8848
8849 /* We're using IMG, so set its timestamp to `now'. */
8850 EMACS_GET_TIME (now);
8851 img->timestamp = EMACS_SECS (now);
8852
8853 UNGCPRO;
8854
8855 /* Value is the image id. */
8856 return img->id;
8857}
8858
8859
8860/* Cache image IMG in the image cache of frame F. */
8861
8862static void
8863cache_image (f, img)
8864 struct frame *f;
8865 struct image *img;
8866{
8867 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8868 int i;
8869
8870 /* Find a free slot in c->images. */
8871 for (i = 0; i < c->used; ++i)
8872 if (c->images[i] == NULL)
8873 break;
8874
8875 /* If no free slot found, maybe enlarge c->images. */
8876 if (i == c->used && c->used == c->size)
8877 {
8878 c->size *= 2;
8879 c->images = (struct image **) xrealloc (c->images,
8880 c->size * sizeof *c->images);
8881 }
8882
8883 /* Add IMG to c->images, and assign IMG an id. */
8884 c->images[i] = img;
8885 img->id = i;
8886 if (i == c->used)
8887 ++c->used;
8888
8889 /* Add IMG to the cache's hash table. */
8890 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8891 img->next = c->buckets[i];
8892 if (img->next)
8893 img->next->prev = img;
8894 img->prev = NULL;
8895 c->buckets[i] = img;
8896}
8897
8898
8899/* Call FN on every image in the image cache of frame F. Used to mark
8900 Lisp Objects in the image cache. */
8901
8902void
8903forall_images_in_image_cache (f, fn)
8904 struct frame *f;
8905 void (*fn) P_ ((struct image *img));
8906{
8907 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8908 {
8909 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8910 if (c)
8911 {
8912 int i;
8913 for (i = 0; i < c->used; ++i)
8914 if (c->images[i])
8915 fn (c->images[i]);
8916 }
8917 }
8918}
8919
8920
8921\f
8922/***********************************************************************
8923 W32 support code
8924 ***********************************************************************/
8925
767b1ff0 8926#if 0 /* TODO: W32 specific image code. */
6fc2811b
JR
8927
8928static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8929 XImage **, Pixmap *));
8930static void x_destroy_x_image P_ ((XImage *));
8931static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8932
8933
8934/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8935 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8936 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8937 via xmalloc. Print error messages via image_error if an error
8938 occurs. Value is non-zero if successful. */
8939
8940static int
8941x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8942 struct frame *f;
8943 int width, height, depth;
8944 XImage **ximg;
8945 Pixmap *pixmap;
8946{
767b1ff0 8947#if 0 /* TODO: Image support for W32 */
6fc2811b
JR
8948 Display *display = FRAME_W32_DISPLAY (f);
8949 Screen *screen = FRAME_X_SCREEN (f);
8950 Window window = FRAME_W32_WINDOW (f);
8951
8952 xassert (interrupt_input_blocked);
8953
8954 if (depth <= 0)
a05e2bae 8955 depth = one_w32_display_info.n_cbits;
6fc2811b
JR
8956 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8957 depth, ZPixmap, 0, NULL, width, height,
8958 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8959 if (*ximg == NULL)
8960 {
8961 image_error ("Unable to allocate X image", Qnil, Qnil);
8962 return 0;
8963 }
8964
8965 /* Allocate image raster. */
8966 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8967
8968 /* Allocate a pixmap of the same size. */
8969 *pixmap = XCreatePixmap (display, window, width, height, depth);
8970 if (*pixmap == 0)
8971 {
8972 x_destroy_x_image (*ximg);
8973 *ximg = NULL;
8974 image_error ("Unable to create X pixmap", Qnil, Qnil);
8975 return 0;
8976 }
8977#endif
8978 return 1;
8979}
8980
8981
8982/* Destroy XImage XIMG. Free XIMG->data. */
8983
8984static void
8985x_destroy_x_image (ximg)
8986 XImage *ximg;
8987{
8988 xassert (interrupt_input_blocked);
8989 if (ximg)
8990 {
8991 xfree (ximg->data);
8992 ximg->data = NULL;
8993 XDestroyImage (ximg);
8994 }
8995}
8996
8997
8998/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8999 are width and height of both the image and pixmap. */
9000
9001static void
9002x_put_x_image (f, ximg, pixmap, width, height)
9003 struct frame *f;
9004 XImage *ximg;
9005 Pixmap pixmap;
9006{
9007 GC gc;
9008
9009 xassert (interrupt_input_blocked);
9010 gc = XCreateGC (NULL, pixmap, 0, NULL);
9011 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9012 XFreeGC (NULL, gc);
9013}
9014
9015#endif
9016
9017\f
9018/***********************************************************************
3cf3436e 9019 File Handling
6fc2811b
JR
9020 ***********************************************************************/
9021
9022static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9023static char *slurp_file P_ ((char *, int *));
9024
6fc2811b
JR
9025
9026/* Find image file FILE. Look in data-directory, then
9027 x-bitmap-file-path. Value is the full name of the file found, or
9028 nil if not found. */
9029
9030static Lisp_Object
9031x_find_image_file (file)
9032 Lisp_Object file;
9033{
9034 Lisp_Object file_found, search_path;
9035 struct gcpro gcpro1, gcpro2;
9036 int fd;
9037
9038 file_found = Qnil;
9039 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9040 GCPRO2 (file_found, search_path);
9041
9042 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 9043 fd = openp (search_path, file, Qnil, &file_found, 0);
6fc2811b 9044
939d6465 9045 if (fd == -1)
6fc2811b
JR
9046 file_found = Qnil;
9047 else
9048 close (fd);
9049
9050 UNGCPRO;
9051 return file_found;
9052}
9053
9054
3cf3436e
JR
9055/* Read FILE into memory. Value is a pointer to a buffer allocated
9056 with xmalloc holding FILE's contents. Value is null if an error
9057 occurred. *SIZE is set to the size of the file. */
9058
9059static char *
9060slurp_file (file, size)
9061 char *file;
9062 int *size;
9063{
9064 FILE *fp = NULL;
9065 char *buf = NULL;
9066 struct stat st;
9067
9068 if (stat (file, &st) == 0
9069 && (fp = fopen (file, "r")) != NULL
9070 && (buf = (char *) xmalloc (st.st_size),
9071 fread (buf, 1, st.st_size, fp) == st.st_size))
9072 {
9073 *size = st.st_size;
9074 fclose (fp);
9075 }
9076 else
9077 {
9078 if (fp)
9079 fclose (fp);
9080 if (buf)
9081 {
9082 xfree (buf);
9083 buf = NULL;
9084 }
9085 }
9086
9087 return buf;
9088}
9089
9090
6fc2811b
JR
9091\f
9092/***********************************************************************
9093 XBM images
9094 ***********************************************************************/
9095
9096static int xbm_load P_ ((struct frame *f, struct image *img));
9097static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9098 Lisp_Object file));
9099static int xbm_image_p P_ ((Lisp_Object object));
9100static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9101 unsigned char **));
9102
9103
9104/* Indices of image specification fields in xbm_format, below. */
9105
9106enum xbm_keyword_index
9107{
9108 XBM_TYPE,
9109 XBM_FILE,
9110 XBM_WIDTH,
9111 XBM_HEIGHT,
9112 XBM_DATA,
9113 XBM_FOREGROUND,
9114 XBM_BACKGROUND,
9115 XBM_ASCENT,
9116 XBM_MARGIN,
9117 XBM_RELIEF,
9118 XBM_ALGORITHM,
9119 XBM_HEURISTIC_MASK,
a05e2bae 9120 XBM_MASK,
6fc2811b
JR
9121 XBM_LAST
9122};
9123
9124/* Vector of image_keyword structures describing the format
9125 of valid XBM image specifications. */
9126
9127static struct image_keyword xbm_format[XBM_LAST] =
9128{
9129 {":type", IMAGE_SYMBOL_VALUE, 1},
9130 {":file", IMAGE_STRING_VALUE, 0},
9131 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9132 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9133 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
9134 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9135 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6fc2811b 9136 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9137 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9138 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9139 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
9140 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9141};
9142
9143/* Structure describing the image type XBM. */
9144
9145static struct image_type xbm_type =
9146{
9147 &Qxbm,
9148 xbm_image_p,
9149 xbm_load,
9150 x_clear_image,
9151 NULL
9152};
9153
9154/* Tokens returned from xbm_scan. */
9155
9156enum xbm_token
9157{
9158 XBM_TK_IDENT = 256,
9159 XBM_TK_NUMBER
9160};
9161
9162
9163/* Return non-zero if OBJECT is a valid XBM-type image specification.
9164 A valid specification is a list starting with the symbol `image'
9165 The rest of the list is a property list which must contain an
9166 entry `:type xbm..
9167
9168 If the specification specifies a file to load, it must contain
9169 an entry `:file FILENAME' where FILENAME is a string.
9170
9171 If the specification is for a bitmap loaded from memory it must
9172 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9173 WIDTH and HEIGHT are integers > 0. DATA may be:
9174
9175 1. a string large enough to hold the bitmap data, i.e. it must
9176 have a size >= (WIDTH + 7) / 8 * HEIGHT
9177
9178 2. a bool-vector of size >= WIDTH * HEIGHT
9179
9180 3. a vector of strings or bool-vectors, one for each line of the
9181 bitmap.
9182
9183 Both the file and data forms may contain the additional entries
9184 `:background COLOR' and `:foreground COLOR'. If not present,
9185 foreground and background of the frame on which the image is
9186 displayed, is used. */
9187
9188static int
9189xbm_image_p (object)
9190 Lisp_Object object;
9191{
9192 struct image_keyword kw[XBM_LAST];
9193
9194 bcopy (xbm_format, kw, sizeof kw);
9195 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9196 return 0;
9197
9198 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9199
9200 if (kw[XBM_FILE].count)
9201 {
9202 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9203 return 0;
9204 }
9205 else
9206 {
9207 Lisp_Object data;
9208 int width, height;
9209
9210 /* Entries for `:width', `:height' and `:data' must be present. */
9211 if (!kw[XBM_WIDTH].count
9212 || !kw[XBM_HEIGHT].count
9213 || !kw[XBM_DATA].count)
9214 return 0;
9215
9216 data = kw[XBM_DATA].value;
9217 width = XFASTINT (kw[XBM_WIDTH].value);
9218 height = XFASTINT (kw[XBM_HEIGHT].value);
9219
9220 /* Check type of data, and width and height against contents of
9221 data. */
9222 if (VECTORP (data))
9223 {
9224 int i;
9225
9226 /* Number of elements of the vector must be >= height. */
9227 if (XVECTOR (data)->size < height)
9228 return 0;
9229
9230 /* Each string or bool-vector in data must be large enough
9231 for one line of the image. */
9232 for (i = 0; i < height; ++i)
9233 {
9234 Lisp_Object elt = XVECTOR (data)->contents[i];
9235
9236 if (STRINGP (elt))
9237 {
9238 if (XSTRING (elt)->size
9239 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9240 return 0;
9241 }
9242 else if (BOOL_VECTOR_P (elt))
9243 {
9244 if (XBOOL_VECTOR (elt)->size < width)
9245 return 0;
9246 }
9247 else
9248 return 0;
9249 }
9250 }
9251 else if (STRINGP (data))
9252 {
9253 if (XSTRING (data)->size
9254 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9255 return 0;
9256 }
9257 else if (BOOL_VECTOR_P (data))
9258 {
9259 if (XBOOL_VECTOR (data)->size < width * height)
9260 return 0;
9261 }
9262 else
9263 return 0;
9264 }
9265
9266 /* Baseline must be a value between 0 and 100 (a percentage). */
9267 if (kw[XBM_ASCENT].count
9268 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9269 return 0;
9270
9271 return 1;
9272}
9273
9274
9275/* Scan a bitmap file. FP is the stream to read from. Value is
9276 either an enumerator from enum xbm_token, or a character for a
9277 single-character token, or 0 at end of file. If scanning an
9278 identifier, store the lexeme of the identifier in SVAL. If
9279 scanning a number, store its value in *IVAL. */
9280
9281static int
3cf3436e
JR
9282xbm_scan (s, end, sval, ival)
9283 char **s, *end;
6fc2811b
JR
9284 char *sval;
9285 int *ival;
9286{
9287 int c;
3cf3436e
JR
9288
9289 loop:
9290
6fc2811b 9291 /* Skip white space. */
3cf3436e 9292 while (*s < end &&(c = *(*s)++, isspace (c)))
6fc2811b
JR
9293 ;
9294
3cf3436e 9295 if (*s >= end)
6fc2811b
JR
9296 c = 0;
9297 else if (isdigit (c))
9298 {
9299 int value = 0, digit;
9300
3cf3436e 9301 if (c == '0' && *s < end)
6fc2811b 9302 {
3cf3436e 9303 c = *(*s)++;
6fc2811b
JR
9304 if (c == 'x' || c == 'X')
9305 {
3cf3436e 9306 while (*s < end)
6fc2811b 9307 {
3cf3436e 9308 c = *(*s)++;
6fc2811b
JR
9309 if (isdigit (c))
9310 digit = c - '0';
9311 else if (c >= 'a' && c <= 'f')
9312 digit = c - 'a' + 10;
9313 else if (c >= 'A' && c <= 'F')
9314 digit = c - 'A' + 10;
9315 else
9316 break;
9317 value = 16 * value + digit;
9318 }
9319 }
9320 else if (isdigit (c))
9321 {
9322 value = c - '0';
3cf3436e
JR
9323 while (*s < end
9324 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9325 value = 8 * value + c - '0';
9326 }
9327 }
9328 else
9329 {
9330 value = c - '0';
3cf3436e
JR
9331 while (*s < end
9332 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9333 value = 10 * value + c - '0';
9334 }
9335
3cf3436e
JR
9336 if (*s < end)
9337 *s = *s - 1;
6fc2811b
JR
9338 *ival = value;
9339 c = XBM_TK_NUMBER;
9340 }
9341 else if (isalpha (c) || c == '_')
9342 {
9343 *sval++ = c;
3cf3436e
JR
9344 while (*s < end
9345 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9346 *sval++ = c;
9347 *sval = 0;
3cf3436e
JR
9348 if (*s < end)
9349 *s = *s - 1;
6fc2811b
JR
9350 c = XBM_TK_IDENT;
9351 }
3cf3436e
JR
9352 else if (c == '/' && **s == '*')
9353 {
9354 /* C-style comment. */
9355 ++*s;
9356 while (**s && (**s != '*' || *(*s + 1) != '/'))
9357 ++*s;
9358 if (**s)
9359 {
9360 *s += 2;
9361 goto loop;
9362 }
9363 }
6fc2811b
JR
9364
9365 return c;
9366}
9367
9368
9369/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9370 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9371 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9372 the image. Return in *DATA the bitmap data allocated with xmalloc.
9373 Value is non-zero if successful. DATA null means just test if
9374 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9375
9376static int
3cf3436e
JR
9377xbm_read_bitmap_data (contents, end, width, height, data)
9378 char *contents, *end;
6fc2811b
JR
9379 int *width, *height;
9380 unsigned char **data;
9381{
3cf3436e 9382 char *s = contents;
6fc2811b
JR
9383 char buffer[BUFSIZ];
9384 int padding_p = 0;
9385 int v10 = 0;
9386 int bytes_per_line, i, nbytes;
9387 unsigned char *p;
9388 int value;
9389 int LA1;
9390
9391#define match() \
3cf3436e 9392 LA1 = xbm_scan (contents, end, buffer, &value)
6fc2811b
JR
9393
9394#define expect(TOKEN) \
9395 if (LA1 != (TOKEN)) \
9396 goto failure; \
9397 else \
9398 match ()
9399
9400#define expect_ident(IDENT) \
9401 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9402 match (); \
9403 else \
9404 goto failure
9405
6fc2811b 9406 *width = *height = -1;
3cf3436e
JR
9407 if (data)
9408 *data = NULL;
9409 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9410
9411 /* Parse defines for width, height and hot-spots. */
9412 while (LA1 == '#')
9413 {
9414 match ();
9415 expect_ident ("define");
9416 expect (XBM_TK_IDENT);
9417
9418 if (LA1 == XBM_TK_NUMBER);
9419 {
9420 char *p = strrchr (buffer, '_');
9421 p = p ? p + 1 : buffer;
9422 if (strcmp (p, "width") == 0)
9423 *width = value;
9424 else if (strcmp (p, "height") == 0)
9425 *height = value;
9426 }
9427 expect (XBM_TK_NUMBER);
9428 }
9429
9430 if (*width < 0 || *height < 0)
9431 goto failure;
3cf3436e
JR
9432 else if (data == NULL)
9433 goto success;
6fc2811b
JR
9434
9435 /* Parse bits. Must start with `static'. */
9436 expect_ident ("static");
9437 if (LA1 == XBM_TK_IDENT)
9438 {
9439 if (strcmp (buffer, "unsigned") == 0)
9440 {
9441 match ();
9442 expect_ident ("char");
9443 }
9444 else if (strcmp (buffer, "short") == 0)
9445 {
9446 match ();
9447 v10 = 1;
9448 if (*width % 16 && *width % 16 < 9)
9449 padding_p = 1;
9450 }
9451 else if (strcmp (buffer, "char") == 0)
9452 match ();
9453 else
9454 goto failure;
9455 }
9456 else
9457 goto failure;
9458
9459 expect (XBM_TK_IDENT);
9460 expect ('[');
9461 expect (']');
9462 expect ('=');
9463 expect ('{');
9464
9465 bytes_per_line = (*width + 7) / 8 + padding_p;
9466 nbytes = bytes_per_line * *height;
9467 p = *data = (char *) xmalloc (nbytes);
9468
9469 if (v10)
9470 {
9471
9472 for (i = 0; i < nbytes; i += 2)
9473 {
9474 int val = value;
9475 expect (XBM_TK_NUMBER);
9476
9477 *p++ = val;
9478 if (!padding_p || ((i + 2) % bytes_per_line))
9479 *p++ = value >> 8;
9480
9481 if (LA1 == ',' || LA1 == '}')
9482 match ();
9483 else
9484 goto failure;
9485 }
9486 }
9487 else
9488 {
9489 for (i = 0; i < nbytes; ++i)
9490 {
9491 int val = value;
9492 expect (XBM_TK_NUMBER);
9493
9494 *p++ = val;
9495
9496 if (LA1 == ',' || LA1 == '}')
9497 match ();
9498 else
9499 goto failure;
9500 }
9501 }
9502
3cf3436e 9503 success:
6fc2811b
JR
9504 return 1;
9505
9506 failure:
3cf3436e
JR
9507
9508 if (data && *data)
6fc2811b
JR
9509 {
9510 xfree (*data);
9511 *data = NULL;
9512 }
9513 return 0;
9514
9515#undef match
9516#undef expect
9517#undef expect_ident
9518}
9519
9520
3cf3436e
JR
9521/* Load XBM image IMG which will be displayed on frame F from buffer
9522 CONTENTS. END is the end of the buffer. Value is non-zero if
9523 successful. */
6fc2811b
JR
9524
9525static int
3cf3436e 9526xbm_load_image (f, img, contents, end)
6fc2811b
JR
9527 struct frame *f;
9528 struct image *img;
3cf3436e 9529 char *contents, *end;
6fc2811b
JR
9530{
9531 int rc;
9532 unsigned char *data;
9533 int success_p = 0;
6fc2811b 9534
3cf3436e 9535 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
9536 if (rc)
9537 {
9538 int depth = one_w32_display_info.n_cbits;
9539 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9540 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9541 Lisp_Object value;
9542
9543 xassert (img->width > 0 && img->height > 0);
9544
9545 /* Get foreground and background colors, maybe allocate colors. */
9546 value = image_spec_value (img->spec, QCforeground, NULL);
9547 if (!NILP (value))
9548 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
9549 value = image_spec_value (img->spec, QCbackground, NULL);
9550 if (!NILP (value))
a05e2bae
JR
9551 {
9552 background = x_alloc_image_color (f, img, value, background);
9553 img->background = background;
9554 img->background_valid = 1;
9555 }
9556
767b1ff0 9557#if 0 /* TODO : Port image display to W32 */
6fc2811b
JR
9558 img->pixmap
9559 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9560 FRAME_W32_WINDOW (f),
9561 data,
9562 img->width, img->height,
9563 foreground, background,
9564 depth);
a05e2bae 9565#endif
6fc2811b
JR
9566 xfree (data);
9567
9568 if (img->pixmap == 0)
9569 {
9570 x_clear_image (f, img);
3cf3436e 9571 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
9572 }
9573 else
9574 success_p = 1;
6fc2811b
JR
9575 }
9576 else
9577 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9578
6fc2811b
JR
9579 return success_p;
9580}
9581
9582
3cf3436e
JR
9583/* Value is non-zero if DATA looks like an in-memory XBM file. */
9584
9585static int
9586xbm_file_p (data)
9587 Lisp_Object data;
9588{
9589 int w, h;
9590 return (STRINGP (data)
9591 && xbm_read_bitmap_data (XSTRING (data)->data,
9592 (XSTRING (data)->data
9593 + STRING_BYTES (XSTRING (data))),
9594 &w, &h, NULL));
9595}
9596
9597
6fc2811b
JR
9598/* Fill image IMG which is used on frame F with pixmap data. Value is
9599 non-zero if successful. */
9600
9601static int
9602xbm_load (f, img)
9603 struct frame *f;
9604 struct image *img;
9605{
9606 int success_p = 0;
9607 Lisp_Object file_name;
9608
9609 xassert (xbm_image_p (img->spec));
9610
9611 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9612 file_name = image_spec_value (img->spec, QCfile, NULL);
9613 if (STRINGP (file_name))
3cf3436e
JR
9614 {
9615 Lisp_Object file;
9616 char *contents;
9617 int size;
9618 struct gcpro gcpro1;
9619
9620 file = x_find_image_file (file_name);
9621 GCPRO1 (file);
9622 if (!STRINGP (file))
9623 {
9624 image_error ("Cannot find image file `%s'", file_name, Qnil);
9625 UNGCPRO;
9626 return 0;
9627 }
9628
9629 contents = slurp_file (XSTRING (file)->data, &size);
9630 if (contents == NULL)
9631 {
9632 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9633 UNGCPRO;
9634 return 0;
9635 }
9636
9637 success_p = xbm_load_image (f, img, contents, contents + size);
9638 UNGCPRO;
9639 }
6fc2811b
JR
9640 else
9641 {
9642 struct image_keyword fmt[XBM_LAST];
9643 Lisp_Object data;
9644 int depth;
9645 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9646 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9647 char *bits;
9648 int parsed_p;
3cf3436e
JR
9649 int in_memory_file_p = 0;
9650
9651 /* See if data looks like an in-memory XBM file. */
9652 data = image_spec_value (img->spec, QCdata, NULL);
9653 in_memory_file_p = xbm_file_p (data);
6fc2811b
JR
9654
9655 /* Parse the list specification. */
9656 bcopy (xbm_format, fmt, sizeof fmt);
9657 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9658 xassert (parsed_p);
9659
9660 /* Get specified width, and height. */
3cf3436e
JR
9661 if (!in_memory_file_p)
9662 {
9663 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9664 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9665 xassert (img->width > 0 && img->height > 0);
9666 }
6fc2811b 9667 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
9668 if (fmt[XBM_FOREGROUND].count
9669 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
9670 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9671 foreground);
3cf3436e
JR
9672 if (fmt[XBM_BACKGROUND].count
9673 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
9674 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9675 background);
9676
3cf3436e
JR
9677 if (in_memory_file_p)
9678 success_p = xbm_load_image (f, img, XSTRING (data)->data,
9679 (XSTRING (data)->data
9680 + STRING_BYTES (XSTRING (data))));
9681 else
6fc2811b 9682 {
3cf3436e
JR
9683 if (VECTORP (data))
9684 {
9685 int i;
9686 char *p;
9687 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 9688
3cf3436e
JR
9689 p = bits = (char *) alloca (nbytes * img->height);
9690 for (i = 0; i < img->height; ++i, p += nbytes)
9691 {
9692 Lisp_Object line = XVECTOR (data)->contents[i];
9693 if (STRINGP (line))
9694 bcopy (XSTRING (line)->data, p, nbytes);
9695 else
9696 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9697 }
9698 }
9699 else if (STRINGP (data))
9700 bits = XSTRING (data)->data;
9701 else
9702 bits = XBOOL_VECTOR (data)->data;
9703#ifdef TODO /* image support. */
9704 /* Create the pixmap. */
a05e2bae 9705 depth = one_w32_display_info.n_cbits;
3cf3436e
JR
9706 img->pixmap
9707 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
9708 FRAME_X_WINDOW (f),
9709 bits,
9710 img->width, img->height,
9711 foreground, background,
9712 depth);
9713#endif
9714 if (img->pixmap)
9715 success_p = 1;
9716 else
6fc2811b 9717 {
3cf3436e
JR
9718 image_error ("Unable to create pixmap for XBM image `%s'",
9719 img->spec, Qnil);
9720 x_clear_image (f, img);
6fc2811b
JR
9721 }
9722 }
6fc2811b
JR
9723 }
9724
9725 return success_p;
9726}
9727
9728
9729\f
9730/***********************************************************************
9731 XPM images
9732 ***********************************************************************/
9733
9734#if HAVE_XPM
9735
9736static int xpm_image_p P_ ((Lisp_Object object));
9737static int xpm_load P_ ((struct frame *f, struct image *img));
9738static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9739
9740#include "X11/xpm.h"
9741
9742/* The symbol `xpm' identifying XPM-format images. */
9743
9744Lisp_Object Qxpm;
9745
9746/* Indices of image specification fields in xpm_format, below. */
9747
9748enum xpm_keyword_index
9749{
9750 XPM_TYPE,
9751 XPM_FILE,
9752 XPM_DATA,
9753 XPM_ASCENT,
9754 XPM_MARGIN,
9755 XPM_RELIEF,
9756 XPM_ALGORITHM,
9757 XPM_HEURISTIC_MASK,
a05e2bae 9758 XPM_MASK,
6fc2811b 9759 XPM_COLOR_SYMBOLS,
a05e2bae 9760 XPM_BACKGROUND,
6fc2811b
JR
9761 XPM_LAST
9762};
9763
9764/* Vector of image_keyword structures describing the format
9765 of valid XPM image specifications. */
9766
9767static struct image_keyword xpm_format[XPM_LAST] =
9768{
9769 {":type", IMAGE_SYMBOL_VALUE, 1},
9770 {":file", IMAGE_STRING_VALUE, 0},
9771 {":data", IMAGE_STRING_VALUE, 0},
9772 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9773 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9774 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9775 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 9776 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
9777 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9778 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9779 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
9780};
9781
9782/* Structure describing the image type XBM. */
9783
9784static struct image_type xpm_type =
9785{
9786 &Qxpm,
9787 xpm_image_p,
9788 xpm_load,
9789 x_clear_image,
9790 NULL
9791};
9792
9793
9794/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9795 for XPM images. Such a list must consist of conses whose car and
9796 cdr are strings. */
9797
9798static int
9799xpm_valid_color_symbols_p (color_symbols)
9800 Lisp_Object color_symbols;
9801{
9802 while (CONSP (color_symbols))
9803 {
9804 Lisp_Object sym = XCAR (color_symbols);
9805 if (!CONSP (sym)
9806 || !STRINGP (XCAR (sym))
9807 || !STRINGP (XCDR (sym)))
9808 break;
9809 color_symbols = XCDR (color_symbols);
9810 }
9811
9812 return NILP (color_symbols);
9813}
9814
9815
9816/* Value is non-zero if OBJECT is a valid XPM image specification. */
9817
9818static int
9819xpm_image_p (object)
9820 Lisp_Object object;
9821{
9822 struct image_keyword fmt[XPM_LAST];
9823 bcopy (xpm_format, fmt, sizeof fmt);
9824 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9825 /* Either `:file' or `:data' must be present. */
9826 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9827 /* Either no `:color-symbols' or it's a list of conses
9828 whose car and cdr are strings. */
9829 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9830 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9831 && (fmt[XPM_ASCENT].count == 0
9832 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9833}
9834
9835
9836/* Load image IMG which will be displayed on frame F. Value is
9837 non-zero if successful. */
9838
9839static int
9840xpm_load (f, img)
9841 struct frame *f;
9842 struct image *img;
9843{
9844 int rc, i;
9845 XpmAttributes attrs;
9846 Lisp_Object specified_file, color_symbols;
9847
9848 /* Configure the XPM lib. Use the visual of frame F. Allocate
9849 close colors. Return colors allocated. */
9850 bzero (&attrs, sizeof attrs);
dfff8a69
JR
9851 attrs.visual = FRAME_X_VISUAL (f);
9852 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 9853 attrs.valuemask |= XpmVisual;
dfff8a69 9854 attrs.valuemask |= XpmColormap;
6fc2811b 9855 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 9856#ifdef XpmAllocCloseColors
6fc2811b
JR
9857 attrs.alloc_close_colors = 1;
9858 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
9859#else
9860 attrs.closeness = 600;
9861 attrs.valuemask |= XpmCloseness;
9862#endif
6fc2811b
JR
9863
9864 /* If image specification contains symbolic color definitions, add
9865 these to `attrs'. */
9866 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9867 if (CONSP (color_symbols))
9868 {
9869 Lisp_Object tail;
9870 XpmColorSymbol *xpm_syms;
9871 int i, size;
9872
9873 attrs.valuemask |= XpmColorSymbols;
9874
9875 /* Count number of symbols. */
9876 attrs.numsymbols = 0;
9877 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9878 ++attrs.numsymbols;
9879
9880 /* Allocate an XpmColorSymbol array. */
9881 size = attrs.numsymbols * sizeof *xpm_syms;
9882 xpm_syms = (XpmColorSymbol *) alloca (size);
9883 bzero (xpm_syms, size);
9884 attrs.colorsymbols = xpm_syms;
9885
9886 /* Fill the color symbol array. */
9887 for (tail = color_symbols, i = 0;
9888 CONSP (tail);
9889 ++i, tail = XCDR (tail))
9890 {
9891 Lisp_Object name = XCAR (XCAR (tail));
9892 Lisp_Object color = XCDR (XCAR (tail));
9893 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9894 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9895 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9896 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9897 }
9898 }
9899
9900 /* Create a pixmap for the image, either from a file, or from a
9901 string buffer containing data in the same format as an XPM file. */
9902 BLOCK_INPUT;
9903 specified_file = image_spec_value (img->spec, QCfile, NULL);
9904 if (STRINGP (specified_file))
9905 {
9906 Lisp_Object file = x_find_image_file (specified_file);
9907 if (!STRINGP (file))
9908 {
9909 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9910 UNBLOCK_INPUT;
9911 return 0;
9912 }
9913
9914 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9915 XSTRING (file)->data, &img->pixmap, &img->mask,
9916 &attrs);
9917 }
9918 else
9919 {
9920 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9921 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9922 XSTRING (buffer)->data,
9923 &img->pixmap, &img->mask,
9924 &attrs);
9925 }
9926 UNBLOCK_INPUT;
9927
9928 if (rc == XpmSuccess)
9929 {
9930 /* Remember allocated colors. */
9931 img->ncolors = attrs.nalloc_pixels;
9932 img->colors = (unsigned long *) xmalloc (img->ncolors
9933 * sizeof *img->colors);
9934 for (i = 0; i < attrs.nalloc_pixels; ++i)
9935 img->colors[i] = attrs.alloc_pixels[i];
9936
9937 img->width = attrs.width;
9938 img->height = attrs.height;
9939 xassert (img->width > 0 && img->height > 0);
9940
9941 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9942 BLOCK_INPUT;
9943 XpmFreeAttributes (&attrs);
9944 UNBLOCK_INPUT;
9945 }
9946 else
9947 {
9948 switch (rc)
9949 {
9950 case XpmOpenFailed:
9951 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9952 break;
9953
9954 case XpmFileInvalid:
9955 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9956 break;
9957
9958 case XpmNoMemory:
9959 image_error ("Out of memory (%s)", img->spec, Qnil);
9960 break;
9961
9962 case XpmColorFailed:
9963 image_error ("Color allocation error (%s)", img->spec, Qnil);
9964 break;
9965
9966 default:
9967 image_error ("Unknown error (%s)", img->spec, Qnil);
9968 break;
9969 }
9970 }
9971
9972 return rc == XpmSuccess;
9973}
9974
9975#endif /* HAVE_XPM != 0 */
9976
9977\f
767b1ff0 9978#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
9979/***********************************************************************
9980 Color table
9981 ***********************************************************************/
9982
9983/* An entry in the color table mapping an RGB color to a pixel color. */
9984
9985struct ct_color
9986{
9987 int r, g, b;
9988 unsigned long pixel;
9989
9990 /* Next in color table collision list. */
9991 struct ct_color *next;
9992};
9993
9994/* The bucket vector size to use. Must be prime. */
9995
9996#define CT_SIZE 101
9997
9998/* Value is a hash of the RGB color given by R, G, and B. */
9999
10000#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10001
10002/* The color hash table. */
10003
10004struct ct_color **ct_table;
10005
10006/* Number of entries in the color table. */
10007
10008int ct_colors_allocated;
10009
10010/* Function prototypes. */
10011
10012static void init_color_table P_ ((void));
10013static void free_color_table P_ ((void));
10014static unsigned long *colors_in_color_table P_ ((int *n));
10015static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10016static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10017
10018
10019/* Initialize the color table. */
10020
10021static void
10022init_color_table ()
10023{
10024 int size = CT_SIZE * sizeof (*ct_table);
10025 ct_table = (struct ct_color **) xmalloc (size);
10026 bzero (ct_table, size);
10027 ct_colors_allocated = 0;
10028}
10029
10030
10031/* Free memory associated with the color table. */
10032
10033static void
10034free_color_table ()
10035{
10036 int i;
10037 struct ct_color *p, *next;
10038
10039 for (i = 0; i < CT_SIZE; ++i)
10040 for (p = ct_table[i]; p; p = next)
10041 {
10042 next = p->next;
10043 xfree (p);
10044 }
10045
10046 xfree (ct_table);
10047 ct_table = NULL;
10048}
10049
10050
10051/* Value is a pixel color for RGB color R, G, B on frame F. If an
10052 entry for that color already is in the color table, return the
10053 pixel color of that entry. Otherwise, allocate a new color for R,
10054 G, B, and make an entry in the color table. */
10055
10056static unsigned long
10057lookup_rgb_color (f, r, g, b)
10058 struct frame *f;
10059 int r, g, b;
10060{
10061 unsigned hash = CT_HASH_RGB (r, g, b);
10062 int i = hash % CT_SIZE;
10063 struct ct_color *p;
10064
10065 for (p = ct_table[i]; p; p = p->next)
10066 if (p->r == r && p->g == g && p->b == b)
10067 break;
10068
10069 if (p == NULL)
10070 {
10071 COLORREF color;
10072 Colormap cmap;
10073 int rc;
10074
10075 color = PALETTERGB (r, g, b);
10076
10077 ++ct_colors_allocated;
10078
10079 p = (struct ct_color *) xmalloc (sizeof *p);
10080 p->r = r;
10081 p->g = g;
10082 p->b = b;
10083 p->pixel = color;
10084 p->next = ct_table[i];
10085 ct_table[i] = p;
10086 }
10087
10088 return p->pixel;
10089}
10090
10091
10092/* Look up pixel color PIXEL which is used on frame F in the color
10093 table. If not already present, allocate it. Value is PIXEL. */
10094
10095static unsigned long
10096lookup_pixel_color (f, pixel)
10097 struct frame *f;
10098 unsigned long pixel;
10099{
10100 int i = pixel % CT_SIZE;
10101 struct ct_color *p;
10102
10103 for (p = ct_table[i]; p; p = p->next)
10104 if (p->pixel == pixel)
10105 break;
10106
10107 if (p == NULL)
10108 {
10109 XColor color;
10110 Colormap cmap;
10111 int rc;
10112
10113 BLOCK_INPUT;
10114
10115 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10116 color.pixel = pixel;
10117 XQueryColor (NULL, cmap, &color);
10118 rc = x_alloc_nearest_color (f, cmap, &color);
10119 UNBLOCK_INPUT;
10120
10121 if (rc)
10122 {
10123 ++ct_colors_allocated;
10124
10125 p = (struct ct_color *) xmalloc (sizeof *p);
10126 p->r = color.red;
10127 p->g = color.green;
10128 p->b = color.blue;
10129 p->pixel = pixel;
10130 p->next = ct_table[i];
10131 ct_table[i] = p;
10132 }
10133 else
10134 return FRAME_FOREGROUND_PIXEL (f);
10135 }
10136 return p->pixel;
10137}
10138
10139
10140/* Value is a vector of all pixel colors contained in the color table,
10141 allocated via xmalloc. Set *N to the number of colors. */
10142
10143static unsigned long *
10144colors_in_color_table (n)
10145 int *n;
10146{
10147 int i, j;
10148 struct ct_color *p;
10149 unsigned long *colors;
10150
10151 if (ct_colors_allocated == 0)
10152 {
10153 *n = 0;
10154 colors = NULL;
10155 }
10156 else
10157 {
10158 colors = (unsigned long *) xmalloc (ct_colors_allocated
10159 * sizeof *colors);
10160 *n = ct_colors_allocated;
10161
10162 for (i = j = 0; i < CT_SIZE; ++i)
10163 for (p = ct_table[i]; p; p = p->next)
10164 colors[j++] = p->pixel;
10165 }
10166
10167 return colors;
10168}
10169
767b1ff0 10170#endif /* TODO */
6fc2811b
JR
10171
10172\f
10173/***********************************************************************
10174 Algorithms
10175 ***********************************************************************/
3cf3436e
JR
10176#if 0 /* TODO: image support. */
10177static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10178static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10179static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10180
10181/* Non-zero means draw a cross on images having `:conversion
10182 disabled'. */
6fc2811b 10183
3cf3436e 10184int cross_disabled_images;
6fc2811b 10185
3cf3436e
JR
10186/* Edge detection matrices for different edge-detection
10187 strategies. */
6fc2811b 10188
3cf3436e
JR
10189static int emboss_matrix[9] = {
10190 /* x - 1 x x + 1 */
10191 2, -1, 0, /* y - 1 */
10192 -1, 0, 1, /* y */
10193 0, 1, -2 /* y + 1 */
10194};
10195
10196static int laplace_matrix[9] = {
10197 /* x - 1 x x + 1 */
10198 1, 0, 0, /* y - 1 */
10199 0, 0, 0, /* y */
10200 0, 0, -1 /* y + 1 */
10201};
10202
10203/* Value is the intensity of the color whose red/green/blue values
10204 are R, G, and B. */
10205
10206#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10207
10208
10209/* On frame F, return an array of XColor structures describing image
10210 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10211 non-zero means also fill the red/green/blue members of the XColor
10212 structures. Value is a pointer to the array of XColors structures,
10213 allocated with xmalloc; it must be freed by the caller. */
10214
10215static XColor *
10216x_to_xcolors (f, img, rgb_p)
10217 struct frame *f;
10218 struct image *img;
10219 int rgb_p;
10220{
10221 int x, y;
10222 XColor *colors, *p;
10223 XImage *ximg;
10224
10225 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10226
10227 /* Get the X image IMG->pixmap. */
10228 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10229 0, 0, img->width, img->height, ~0, ZPixmap);
10230
10231 /* Fill the `pixel' members of the XColor array. I wished there
10232 were an easy and portable way to circumvent XGetPixel. */
10233 p = colors;
10234 for (y = 0; y < img->height; ++y)
10235 {
10236 XColor *row = p;
10237
10238 for (x = 0; x < img->width; ++x, ++p)
10239 p->pixel = XGetPixel (ximg, x, y);
10240
10241 if (rgb_p)
10242 x_query_colors (f, row, img->width);
10243 }
10244
10245 XDestroyImage (ximg);
10246 return colors;
10247}
10248
10249
10250/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10251 RGB members are set. F is the frame on which this all happens.
10252 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10253
10254static void
3cf3436e 10255x_from_xcolors (f, img, colors)
6fc2811b 10256 struct frame *f;
3cf3436e 10257 struct image *img;
6fc2811b 10258 XColor *colors;
6fc2811b 10259{
3cf3436e
JR
10260 int x, y;
10261 XImage *oimg;
10262 Pixmap pixmap;
10263 XColor *p;
10264
10265 init_color_table ();
10266
10267 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10268 &oimg, &pixmap);
10269 p = colors;
10270 for (y = 0; y < img->height; ++y)
10271 for (x = 0; x < img->width; ++x, ++p)
10272 {
10273 unsigned long pixel;
10274 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10275 XPutPixel (oimg, x, y, pixel);
10276 }
6fc2811b 10277
3cf3436e
JR
10278 xfree (colors);
10279 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10280
3cf3436e
JR
10281 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10282 x_destroy_x_image (oimg);
10283 img->pixmap = pixmap;
10284 img->colors = colors_in_color_table (&img->ncolors);
10285 free_color_table ();
6fc2811b
JR
10286}
10287
10288
3cf3436e
JR
10289/* On frame F, perform edge-detection on image IMG.
10290
10291 MATRIX is a nine-element array specifying the transformation
10292 matrix. See emboss_matrix for an example.
10293
10294 COLOR_ADJUST is a color adjustment added to each pixel of the
10295 outgoing image. */
6fc2811b
JR
10296
10297static void
3cf3436e 10298x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10299 struct frame *f;
3cf3436e
JR
10300 struct image *img;
10301 int matrix[9], color_adjust;
6fc2811b 10302{
3cf3436e
JR
10303 XColor *colors = x_to_xcolors (f, img, 1);
10304 XColor *new, *p;
10305 int x, y, i, sum;
10306
10307 for (i = sum = 0; i < 9; ++i)
10308 sum += abs (matrix[i]);
10309
10310#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10311
10312 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10313
10314 for (y = 0; y < img->height; ++y)
10315 {
10316 p = COLOR (new, 0, y);
10317 p->red = p->green = p->blue = 0xffff/2;
10318 p = COLOR (new, img->width - 1, y);
10319 p->red = p->green = p->blue = 0xffff/2;
10320 }
6fc2811b 10321
3cf3436e
JR
10322 for (x = 1; x < img->width - 1; ++x)
10323 {
10324 p = COLOR (new, x, 0);
10325 p->red = p->green = p->blue = 0xffff/2;
10326 p = COLOR (new, x, img->height - 1);
10327 p->red = p->green = p->blue = 0xffff/2;
10328 }
10329
10330 for (y = 1; y < img->height - 1; ++y)
10331 {
10332 p = COLOR (new, 1, y);
10333
10334 for (x = 1; x < img->width - 1; ++x, ++p)
10335 {
10336 int r, g, b, y1, x1;
10337
10338 r = g = b = i = 0;
10339 for (y1 = y - 1; y1 < y + 2; ++y1)
10340 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10341 if (matrix[i])
10342 {
10343 XColor *t = COLOR (colors, x1, y1);
10344 r += matrix[i] * t->red;
10345 g += matrix[i] * t->green;
10346 b += matrix[i] * t->blue;
10347 }
10348
10349 r = (r / sum + color_adjust) & 0xffff;
10350 g = (g / sum + color_adjust) & 0xffff;
10351 b = (b / sum + color_adjust) & 0xffff;
10352 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10353 }
10354 }
10355
10356 xfree (colors);
10357 x_from_xcolors (f, img, new);
10358
10359#undef COLOR
10360}
10361
10362
10363/* Perform the pre-defined `emboss' edge-detection on image IMG
10364 on frame F. */
10365
10366static void
10367x_emboss (f, img)
10368 struct frame *f;
10369 struct image *img;
10370{
10371 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10372}
3cf3436e 10373
6fc2811b
JR
10374
10375/* Transform image IMG which is used on frame F with a Laplace
10376 edge-detection algorithm. The result is an image that can be used
10377 to draw disabled buttons, for example. */
10378
10379static void
10380x_laplace (f, img)
10381 struct frame *f;
10382 struct image *img;
10383{
3cf3436e
JR
10384 x_detect_edges (f, img, laplace_matrix, 45000);
10385}
6fc2811b 10386
6fc2811b 10387
3cf3436e
JR
10388/* Perform edge-detection on image IMG on frame F, with specified
10389 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10390
3cf3436e 10391 MATRIX must be either
6fc2811b 10392
3cf3436e
JR
10393 - a list of at least 9 numbers in row-major form
10394 - a vector of at least 9 numbers
6fc2811b 10395
3cf3436e
JR
10396 COLOR_ADJUST nil means use a default; otherwise it must be a
10397 number. */
6fc2811b 10398
3cf3436e
JR
10399static void
10400x_edge_detection (f, img, matrix, color_adjust)
10401 struct frame *f;
10402 struct image *img;
10403 Lisp_Object matrix, color_adjust;
10404{
10405 int i = 0;
10406 int trans[9];
10407
10408 if (CONSP (matrix))
6fc2811b 10409 {
3cf3436e
JR
10410 for (i = 0;
10411 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10412 ++i, matrix = XCDR (matrix))
10413 trans[i] = XFLOATINT (XCAR (matrix));
10414 }
10415 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10416 {
10417 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10418 trans[i] = XFLOATINT (AREF (matrix, i));
10419 }
10420
10421 if (NILP (color_adjust))
10422 color_adjust = make_number (0xffff / 2);
10423
10424 if (i == 9 && NUMBERP (color_adjust))
10425 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10426}
10427
6fc2811b 10428
3cf3436e 10429/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10430
3cf3436e
JR
10431static void
10432x_disable_image (f, img)
10433 struct frame *f;
10434 struct image *img;
10435{
10436 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10437
10438 if (dpyinfo->n_planes >= 2)
10439 {
10440 /* Color (or grayscale). Convert to gray, and equalize. Just
10441 drawing such images with a stipple can look very odd, so
10442 we're using this method instead. */
10443 XColor *colors = x_to_xcolors (f, img, 1);
10444 XColor *p, *end;
10445 const int h = 15000;
10446 const int l = 30000;
10447
10448 for (p = colors, end = colors + img->width * img->height;
10449 p < end;
10450 ++p)
6fc2811b 10451 {
3cf3436e
JR
10452 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10453 int i2 = (0xffff - h - l) * i / 0xffff + l;
10454 p->red = p->green = p->blue = i2;
6fc2811b
JR
10455 }
10456
3cf3436e 10457 x_from_xcolors (f, img, colors);
6fc2811b
JR
10458 }
10459
3cf3436e
JR
10460 /* Draw a cross over the disabled image, if we must or if we
10461 should. */
10462 if (dpyinfo->n_planes < 2 || cross_disabled_images)
10463 {
10464 Display *dpy = FRAME_X_DISPLAY (f);
10465 GC gc;
6fc2811b 10466
3cf3436e
JR
10467 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10468 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10469 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10470 img->width - 1, img->height - 1);
10471 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10472 img->width - 1, 0);
10473 XFreeGC (dpy, gc);
6fc2811b 10474
3cf3436e
JR
10475 if (img->mask)
10476 {
10477 gc = XCreateGC (dpy, img->mask, 0, NULL);
10478 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10479 XDrawLine (dpy, img->mask, gc, 0, 0,
10480 img->width - 1, img->height - 1);
10481 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10482 img->width - 1, 0);
10483 XFreeGC (dpy, gc);
10484 }
10485 }
6fc2811b
JR
10486}
10487
10488
10489/* Build a mask for image IMG which is used on frame F. FILE is the
10490 name of an image file, for error messages. HOW determines how to
10491 determine the background color of IMG. If it is a list '(R G B)',
10492 with R, G, and B being integers >= 0, take that as the color of the
10493 background. Otherwise, determine the background color of IMG
10494 heuristically. Value is non-zero if successful. */
10495
10496static int
10497x_build_heuristic_mask (f, img, how)
10498 struct frame *f;
10499 struct image *img;
10500 Lisp_Object how;
10501{
6fc2811b
JR
10502 Display *dpy = FRAME_W32_DISPLAY (f);
10503 XImage *ximg, *mask_img;
a05e2bae
JR
10504 int x, y, rc, use_img_background;
10505 unsigned long bg = 0;
10506
10507 if (img->mask)
10508 {
10509 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10510 img->mask = None;
10511 img->background_transparent_valid = 0;
10512 }
6fc2811b 10513
6fc2811b
JR
10514 /* Create an image and pixmap serving as mask. */
10515 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10516 &mask_img, &img->mask);
10517 if (!rc)
a05e2bae 10518 return 0;
6fc2811b
JR
10519
10520 /* Get the X image of IMG->pixmap. */
10521 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10522 ~0, ZPixmap);
10523
10524 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
10525 take that as color. Otherwise, use the image's background color. */
10526 use_img_background = 1;
6fc2811b
JR
10527
10528 if (CONSP (how))
10529 {
a05e2bae 10530 int rgb[3], i;
6fc2811b 10531
a05e2bae 10532 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
10533 {
10534 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10535 how = XCDR (how);
10536 }
10537
10538 if (i == 3 && NILP (how))
10539 {
10540 char color_name[30];
6fc2811b 10541 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
10542 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10543 use_img_background = 0;
6fc2811b
JR
10544 }
10545 }
10546
a05e2bae
JR
10547 if (use_img_background)
10548 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
10549
10550 /* Set all bits in mask_img to 1 whose color in ximg is different
10551 from the background color bg. */
10552 for (y = 0; y < img->height; ++y)
10553 for (x = 0; x < img->width; ++x)
10554 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
10555
a05e2bae
JR
10556 /* Fill in the background_transparent field while we have the mask handy. */
10557 image_background_transparent (img, f, mask_img);
10558
6fc2811b
JR
10559 /* Put mask_img into img->mask. */
10560 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10561 x_destroy_x_image (mask_img);
10562 XDestroyImage (ximg);
6fc2811b
JR
10563
10564 return 1;
10565}
3cf3436e 10566#endif /* TODO */
6fc2811b
JR
10567
10568\f
10569/***********************************************************************
10570 PBM (mono, gray, color)
10571 ***********************************************************************/
10572#ifdef HAVE_PBM
10573
10574static int pbm_image_p P_ ((Lisp_Object object));
10575static int pbm_load P_ ((struct frame *f, struct image *img));
10576static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10577
10578/* The symbol `pbm' identifying images of this type. */
10579
10580Lisp_Object Qpbm;
10581
10582/* Indices of image specification fields in gs_format, below. */
10583
10584enum pbm_keyword_index
10585{
10586 PBM_TYPE,
10587 PBM_FILE,
10588 PBM_DATA,
10589 PBM_ASCENT,
10590 PBM_MARGIN,
10591 PBM_RELIEF,
10592 PBM_ALGORITHM,
10593 PBM_HEURISTIC_MASK,
a05e2bae
JR
10594 PBM_MASK,
10595 PBM_FOREGROUND,
10596 PBM_BACKGROUND,
6fc2811b
JR
10597 PBM_LAST
10598};
10599
10600/* Vector of image_keyword structures describing the format
10601 of valid user-defined image specifications. */
10602
10603static struct image_keyword pbm_format[PBM_LAST] =
10604{
10605 {":type", IMAGE_SYMBOL_VALUE, 1},
10606 {":file", IMAGE_STRING_VALUE, 0},
10607 {":data", IMAGE_STRING_VALUE, 0},
10608 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10609 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10610 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10611 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
10612 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10613 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10614 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10615 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10616};
10617
10618/* Structure describing the image type `pbm'. */
10619
10620static struct image_type pbm_type =
10621{
10622 &Qpbm,
10623 pbm_image_p,
10624 pbm_load,
10625 x_clear_image,
10626 NULL
10627};
10628
10629
10630/* Return non-zero if OBJECT is a valid PBM image specification. */
10631
10632static int
10633pbm_image_p (object)
10634 Lisp_Object object;
10635{
10636 struct image_keyword fmt[PBM_LAST];
10637
10638 bcopy (pbm_format, fmt, sizeof fmt);
10639
10640 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
10641 || (fmt[PBM_ASCENT].count
10642 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
10643 return 0;
10644
10645 /* Must specify either :data or :file. */
10646 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10647}
10648
10649
10650/* Scan a decimal number from *S and return it. Advance *S while
10651 reading the number. END is the end of the string. Value is -1 at
10652 end of input. */
10653
10654static int
10655pbm_scan_number (s, end)
10656 unsigned char **s, *end;
10657{
10658 int c, val = -1;
10659
10660 while (*s < end)
10661 {
10662 /* Skip white-space. */
10663 while (*s < end && (c = *(*s)++, isspace (c)))
10664 ;
10665
10666 if (c == '#')
10667 {
10668 /* Skip comment to end of line. */
10669 while (*s < end && (c = *(*s)++, c != '\n'))
10670 ;
10671 }
10672 else if (isdigit (c))
10673 {
10674 /* Read decimal number. */
10675 val = c - '0';
10676 while (*s < end && (c = *(*s)++, isdigit (c)))
10677 val = 10 * val + c - '0';
10678 break;
10679 }
10680 else
10681 break;
10682 }
10683
10684 return val;
10685}
10686
10687
10688/* Read FILE into memory. Value is a pointer to a buffer allocated
10689 with xmalloc holding FILE's contents. Value is null if an error
10690 occured. *SIZE is set to the size of the file. */
10691
10692static char *
10693pbm_read_file (file, size)
10694 Lisp_Object file;
10695 int *size;
10696{
10697 FILE *fp = NULL;
10698 char *buf = NULL;
10699 struct stat st;
10700
10701 if (stat (XSTRING (file)->data, &st) == 0
10702 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10703 && (buf = (char *) xmalloc (st.st_size),
10704 fread (buf, 1, st.st_size, fp) == st.st_size))
10705 {
10706 *size = st.st_size;
10707 fclose (fp);
10708 }
10709 else
10710 {
10711 if (fp)
10712 fclose (fp);
10713 if (buf)
10714 {
10715 xfree (buf);
10716 buf = NULL;
10717 }
10718 }
10719
10720 return buf;
10721}
10722
10723
10724/* Load PBM image IMG for use on frame F. */
10725
10726static int
10727pbm_load (f, img)
10728 struct frame *f;
10729 struct image *img;
10730{
10731 int raw_p, x, y;
10732 int width, height, max_color_idx = 0;
10733 XImage *ximg;
10734 Lisp_Object file, specified_file;
10735 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10736 struct gcpro gcpro1;
10737 unsigned char *contents = NULL;
10738 unsigned char *end, *p;
10739 int size;
10740
10741 specified_file = image_spec_value (img->spec, QCfile, NULL);
10742 file = Qnil;
10743 GCPRO1 (file);
10744
10745 if (STRINGP (specified_file))
10746 {
10747 file = x_find_image_file (specified_file);
10748 if (!STRINGP (file))
10749 {
10750 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10751 UNGCPRO;
10752 return 0;
10753 }
10754
3cf3436e 10755 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
10756 if (contents == NULL)
10757 {
10758 image_error ("Error reading `%s'", file, Qnil);
10759 UNGCPRO;
10760 return 0;
10761 }
10762
10763 p = contents;
10764 end = contents + size;
10765 }
10766 else
10767 {
10768 Lisp_Object data;
10769 data = image_spec_value (img->spec, QCdata, NULL);
10770 p = XSTRING (data)->data;
10771 end = p + STRING_BYTES (XSTRING (data));
10772 }
10773
10774 /* Check magic number. */
10775 if (end - p < 2 || *p++ != 'P')
10776 {
10777 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10778 error:
10779 xfree (contents);
10780 UNGCPRO;
10781 return 0;
10782 }
10783
6fc2811b
JR
10784 switch (*p++)
10785 {
10786 case '1':
10787 raw_p = 0, type = PBM_MONO;
10788 break;
10789
10790 case '2':
10791 raw_p = 0, type = PBM_GRAY;
10792 break;
10793
10794 case '3':
10795 raw_p = 0, type = PBM_COLOR;
10796 break;
10797
10798 case '4':
10799 raw_p = 1, type = PBM_MONO;
10800 break;
10801
10802 case '5':
10803 raw_p = 1, type = PBM_GRAY;
10804 break;
10805
10806 case '6':
10807 raw_p = 1, type = PBM_COLOR;
10808 break;
10809
10810 default:
10811 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10812 goto error;
10813 }
10814
10815 /* Read width, height, maximum color-component. Characters
10816 starting with `#' up to the end of a line are ignored. */
10817 width = pbm_scan_number (&p, end);
10818 height = pbm_scan_number (&p, end);
10819
10820 if (type != PBM_MONO)
10821 {
10822 max_color_idx = pbm_scan_number (&p, end);
10823 if (raw_p && max_color_idx > 255)
10824 max_color_idx = 255;
10825 }
10826
10827 if (width < 0
10828 || height < 0
10829 || (type != PBM_MONO && max_color_idx < 0))
10830 goto error;
10831
6fc2811b
JR
10832 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10833 &ximg, &img->pixmap))
3cf3436e
JR
10834 goto error;
10835
6fc2811b
JR
10836 /* Initialize the color hash table. */
10837 init_color_table ();
10838
10839 if (type == PBM_MONO)
10840 {
10841 int c = 0, g;
3cf3436e
JR
10842 struct image_keyword fmt[PBM_LAST];
10843 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
10844 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
10845
10846 /* Parse the image specification. */
10847 bcopy (pbm_format, fmt, sizeof fmt);
10848 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
10849
10850 /* Get foreground and background colors, maybe allocate colors. */
10851 if (fmt[PBM_FOREGROUND].count
10852 && STRINGP (fmt[PBM_FOREGROUND].value))
10853 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
10854 if (fmt[PBM_BACKGROUND].count
10855 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
10856 {
10857 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
10858 img->background = bg;
10859 img->background_valid = 1;
10860 }
10861
6fc2811b
JR
10862 for (y = 0; y < height; ++y)
10863 for (x = 0; x < width; ++x)
10864 {
10865 if (raw_p)
10866 {
10867 if ((x & 7) == 0)
10868 c = *p++;
10869 g = c & 0x80;
10870 c <<= 1;
10871 }
10872 else
10873 g = pbm_scan_number (&p, end);
10874
3cf3436e 10875 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
10876 }
10877 }
10878 else
10879 {
10880 for (y = 0; y < height; ++y)
10881 for (x = 0; x < width; ++x)
10882 {
10883 int r, g, b;
10884
10885 if (type == PBM_GRAY)
10886 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10887 else if (raw_p)
10888 {
10889 r = *p++;
10890 g = *p++;
10891 b = *p++;
10892 }
10893 else
10894 {
10895 r = pbm_scan_number (&p, end);
10896 g = pbm_scan_number (&p, end);
10897 b = pbm_scan_number (&p, end);
10898 }
10899
10900 if (r < 0 || g < 0 || b < 0)
10901 {
dfff8a69 10902 xfree (ximg->data);
6fc2811b
JR
10903 ximg->data = NULL;
10904 XDestroyImage (ximg);
6fc2811b
JR
10905 image_error ("Invalid pixel value in image `%s'",
10906 img->spec, Qnil);
10907 goto error;
10908 }
10909
10910 /* RGB values are now in the range 0..max_color_idx.
10911 Scale this to the range 0..0xffff supported by X. */
10912 r = (double) r * 65535 / max_color_idx;
10913 g = (double) g * 65535 / max_color_idx;
10914 b = (double) b * 65535 / max_color_idx;
10915 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10916 }
10917 }
10918
10919 /* Store in IMG->colors the colors allocated for the image, and
10920 free the color table. */
10921 img->colors = colors_in_color_table (&img->ncolors);
10922 free_color_table ();
10923
a05e2bae
JR
10924 /* Maybe fill in the background field while we have ximg handy. */
10925 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10926 IMAGE_BACKGROUND (img, f, ximg);
10927
6fc2811b
JR
10928 /* Put the image into a pixmap. */
10929 x_put_x_image (f, ximg, img->pixmap, width, height);
10930 x_destroy_x_image (ximg);
6fc2811b
JR
10931
10932 img->width = width;
10933 img->height = height;
10934
10935 UNGCPRO;
10936 xfree (contents);
10937 return 1;
10938}
10939#endif /* HAVE_PBM */
10940
10941\f
10942/***********************************************************************
10943 PNG
10944 ***********************************************************************/
10945
10946#if HAVE_PNG
10947
10948#include <png.h>
10949
10950/* Function prototypes. */
10951
10952static int png_image_p P_ ((Lisp_Object object));
10953static int png_load P_ ((struct frame *f, struct image *img));
10954
10955/* The symbol `png' identifying images of this type. */
10956
10957Lisp_Object Qpng;
10958
10959/* Indices of image specification fields in png_format, below. */
10960
10961enum png_keyword_index
10962{
10963 PNG_TYPE,
10964 PNG_DATA,
10965 PNG_FILE,
10966 PNG_ASCENT,
10967 PNG_MARGIN,
10968 PNG_RELIEF,
10969 PNG_ALGORITHM,
10970 PNG_HEURISTIC_MASK,
a05e2bae
JR
10971 PNG_MASK,
10972 PNG_BACKGROUND,
6fc2811b
JR
10973 PNG_LAST
10974};
10975
10976/* Vector of image_keyword structures describing the format
10977 of valid user-defined image specifications. */
10978
10979static struct image_keyword png_format[PNG_LAST] =
10980{
10981 {":type", IMAGE_SYMBOL_VALUE, 1},
10982 {":data", IMAGE_STRING_VALUE, 0},
10983 {":file", IMAGE_STRING_VALUE, 0},
10984 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10985 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10986 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10987 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10988 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10989 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10990 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10991};
10992
10993/* Structure describing the image type `png'. */
10994
10995static struct image_type png_type =
10996{
10997 &Qpng,
10998 png_image_p,
10999 png_load,
11000 x_clear_image,
11001 NULL
11002};
11003
11004
11005/* Return non-zero if OBJECT is a valid PNG image specification. */
11006
11007static int
11008png_image_p (object)
11009 Lisp_Object object;
11010{
11011 struct image_keyword fmt[PNG_LAST];
11012 bcopy (png_format, fmt, sizeof fmt);
11013
11014 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11015 || (fmt[PNG_ASCENT].count
11016 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11017 return 0;
11018
11019 /* Must specify either the :data or :file keyword. */
11020 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11021}
11022
11023
11024/* Error and warning handlers installed when the PNG library
11025 is initialized. */
11026
11027static void
11028my_png_error (png_ptr, msg)
11029 png_struct *png_ptr;
11030 char *msg;
11031{
11032 xassert (png_ptr != NULL);
11033 image_error ("PNG error: %s", build_string (msg), Qnil);
11034 longjmp (png_ptr->jmpbuf, 1);
11035}
11036
11037
11038static void
11039my_png_warning (png_ptr, msg)
11040 png_struct *png_ptr;
11041 char *msg;
11042{
11043 xassert (png_ptr != NULL);
11044 image_error ("PNG warning: %s", build_string (msg), Qnil);
11045}
11046
6fc2811b
JR
11047/* Memory source for PNG decoding. */
11048
11049struct png_memory_storage
11050{
11051 unsigned char *bytes; /* The data */
11052 size_t len; /* How big is it? */
11053 int index; /* Where are we? */
11054};
11055
11056
11057/* Function set as reader function when reading PNG image from memory.
11058 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11059 bytes from the input to DATA. */
11060
11061static void
11062png_read_from_memory (png_ptr, data, length)
11063 png_structp png_ptr;
11064 png_bytep data;
11065 png_size_t length;
11066{
11067 struct png_memory_storage *tbr
11068 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11069
11070 if (length > tbr->len - tbr->index)
11071 png_error (png_ptr, "Read error");
11072
11073 bcopy (tbr->bytes + tbr->index, data, length);
11074 tbr->index = tbr->index + length;
11075}
11076
6fc2811b
JR
11077/* Load PNG image IMG for use on frame F. Value is non-zero if
11078 successful. */
11079
11080static int
11081png_load (f, img)
11082 struct frame *f;
11083 struct image *img;
11084{
11085 Lisp_Object file, specified_file;
11086 Lisp_Object specified_data;
11087 int x, y, i;
11088 XImage *ximg, *mask_img = NULL;
11089 struct gcpro gcpro1;
11090 png_struct *png_ptr = NULL;
11091 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11092 FILE *volatile fp = NULL;
6fc2811b 11093 png_byte sig[8];
a05e2bae
JR
11094 png_byte *volatile pixels = NULL;
11095 png_byte **volatile rows = NULL;
6fc2811b
JR
11096 png_uint_32 width, height;
11097 int bit_depth, color_type, interlace_type;
11098 png_byte channels;
11099 png_uint_32 row_bytes;
11100 int transparent_p;
11101 char *gamma_str;
11102 double screen_gamma, image_gamma;
11103 int intent;
11104 struct png_memory_storage tbr; /* Data to be read */
11105
11106 /* Find out what file to load. */
11107 specified_file = image_spec_value (img->spec, QCfile, NULL);
11108 specified_data = image_spec_value (img->spec, QCdata, NULL);
11109 file = Qnil;
11110 GCPRO1 (file);
11111
11112 if (NILP (specified_data))
11113 {
11114 file = x_find_image_file (specified_file);
11115 if (!STRINGP (file))
11116 {
11117 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11118 UNGCPRO;
11119 return 0;
11120 }
11121
11122 /* Open the image file. */
11123 fp = fopen (XSTRING (file)->data, "rb");
11124 if (!fp)
11125 {
11126 image_error ("Cannot open image file `%s'", file, Qnil);
11127 UNGCPRO;
11128 fclose (fp);
11129 return 0;
11130 }
11131
11132 /* Check PNG signature. */
11133 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11134 || !png_check_sig (sig, sizeof sig))
11135 {
11136 image_error ("Not a PNG file:` %s'", file, Qnil);
11137 UNGCPRO;
11138 fclose (fp);
11139 return 0;
11140 }
11141 }
11142 else
11143 {
11144 /* Read from memory. */
11145 tbr.bytes = XSTRING (specified_data)->data;
11146 tbr.len = STRING_BYTES (XSTRING (specified_data));
11147 tbr.index = 0;
11148
11149 /* Check PNG signature. */
11150 if (tbr.len < sizeof sig
11151 || !png_check_sig (tbr.bytes, sizeof sig))
11152 {
11153 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11154 UNGCPRO;
11155 return 0;
11156 }
11157
11158 /* Need to skip past the signature. */
11159 tbr.bytes += sizeof (sig);
11160 }
11161
6fc2811b
JR
11162 /* Initialize read and info structs for PNG lib. */
11163 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11164 my_png_error, my_png_warning);
11165 if (!png_ptr)
11166 {
11167 if (fp) fclose (fp);
11168 UNGCPRO;
11169 return 0;
11170 }
11171
11172 info_ptr = png_create_info_struct (png_ptr);
11173 if (!info_ptr)
11174 {
11175 png_destroy_read_struct (&png_ptr, NULL, NULL);
11176 if (fp) fclose (fp);
11177 UNGCPRO;
11178 return 0;
11179 }
11180
11181 end_info = png_create_info_struct (png_ptr);
11182 if (!end_info)
11183 {
11184 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11185 if (fp) fclose (fp);
11186 UNGCPRO;
11187 return 0;
11188 }
11189
11190 /* Set error jump-back. We come back here when the PNG library
11191 detects an error. */
11192 if (setjmp (png_ptr->jmpbuf))
11193 {
11194 error:
11195 if (png_ptr)
11196 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11197 xfree (pixels);
11198 xfree (rows);
11199 if (fp) fclose (fp);
11200 UNGCPRO;
11201 return 0;
11202 }
11203
11204 /* Read image info. */
11205 if (!NILP (specified_data))
11206 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11207 else
11208 png_init_io (png_ptr, fp);
11209
11210 png_set_sig_bytes (png_ptr, sizeof sig);
11211 png_read_info (png_ptr, info_ptr);
11212 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11213 &interlace_type, NULL, NULL);
11214
11215 /* If image contains simply transparency data, we prefer to
11216 construct a clipping mask. */
11217 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11218 transparent_p = 1;
11219 else
11220 transparent_p = 0;
11221
11222 /* This function is easier to write if we only have to handle
11223 one data format: RGB or RGBA with 8 bits per channel. Let's
11224 transform other formats into that format. */
11225
11226 /* Strip more than 8 bits per channel. */
11227 if (bit_depth == 16)
11228 png_set_strip_16 (png_ptr);
11229
11230 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11231 if available. */
11232 png_set_expand (png_ptr);
11233
11234 /* Convert grayscale images to RGB. */
11235 if (color_type == PNG_COLOR_TYPE_GRAY
11236 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11237 png_set_gray_to_rgb (png_ptr);
11238
11239 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11240 gamma_str = getenv ("SCREEN_GAMMA");
11241 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11242
11243 /* Tell the PNG lib to handle gamma correction for us. */
11244
11245#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11246 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11247 /* There is a special chunk in the image specifying the gamma. */
11248 png_set_sRGB (png_ptr, info_ptr, intent);
11249 else
11250#endif
11251 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11252 /* Image contains gamma information. */
11253 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11254 else
11255 /* Use a default of 0.5 for the image gamma. */
11256 png_set_gamma (png_ptr, screen_gamma, 0.5);
11257
11258 /* Handle alpha channel by combining the image with a background
11259 color. Do this only if a real alpha channel is supplied. For
11260 simple transparency, we prefer a clipping mask. */
11261 if (!transparent_p)
11262 {
11263 png_color_16 *image_background;
a05e2bae
JR
11264 Lisp_Object specified_bg
11265 = image_spec_value (img->spec, QCbackground, NULL);
11266
11267
11268 if (STRINGP (specified_bg))
11269 /* The user specified `:background', use that. */
11270 {
11271 COLORREF color;
11272 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11273 {
11274 png_color_16 user_bg;
11275
11276 bzero (&user_bg, sizeof user_bg);
11277 user_bg.red = color.red;
11278 user_bg.green = color.green;
11279 user_bg.blue = color.blue;
6fc2811b 11280
a05e2bae
JR
11281 png_set_background (png_ptr, &user_bg,
11282 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11283 }
11284 }
11285 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11286 /* Image contains a background color with which to
11287 combine the image. */
11288 png_set_background (png_ptr, image_background,
11289 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11290 else
11291 {
11292 /* Image does not contain a background color with which
11293 to combine the image data via an alpha channel. Use
11294 the frame's background instead. */
11295 XColor color;
11296 Colormap cmap;
11297 png_color_16 frame_background;
11298
a05e2bae 11299 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11300 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11301 x_query_color (f, &color);
6fc2811b
JR
11302
11303 bzero (&frame_background, sizeof frame_background);
11304 frame_background.red = color.red;
11305 frame_background.green = color.green;
11306 frame_background.blue = color.blue;
11307
11308 png_set_background (png_ptr, &frame_background,
11309 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11310 }
11311 }
11312
11313 /* Update info structure. */
11314 png_read_update_info (png_ptr, info_ptr);
11315
11316 /* Get number of channels. Valid values are 1 for grayscale images
11317 and images with a palette, 2 for grayscale images with transparency
11318 information (alpha channel), 3 for RGB images, and 4 for RGB
11319 images with alpha channel, i.e. RGBA. If conversions above were
11320 sufficient we should only have 3 or 4 channels here. */
11321 channels = png_get_channels (png_ptr, info_ptr);
11322 xassert (channels == 3 || channels == 4);
11323
11324 /* Number of bytes needed for one row of the image. */
11325 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11326
11327 /* Allocate memory for the image. */
11328 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11329 rows = (png_byte **) xmalloc (height * sizeof *rows);
11330 for (i = 0; i < height; ++i)
11331 rows[i] = pixels + i * row_bytes;
11332
11333 /* Read the entire image. */
11334 png_read_image (png_ptr, rows);
11335 png_read_end (png_ptr, info_ptr);
11336 if (fp)
11337 {
11338 fclose (fp);
11339 fp = NULL;
11340 }
11341
6fc2811b
JR
11342 /* Create the X image and pixmap. */
11343 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11344 &img->pixmap))
a05e2bae 11345 goto error;
6fc2811b
JR
11346
11347 /* Create an image and pixmap serving as mask if the PNG image
11348 contains an alpha channel. */
11349 if (channels == 4
11350 && !transparent_p
11351 && !x_create_x_image_and_pixmap (f, width, height, 1,
11352 &mask_img, &img->mask))
11353 {
11354 x_destroy_x_image (ximg);
11355 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11356 img->pixmap = 0;
6fc2811b
JR
11357 goto error;
11358 }
11359
11360 /* Fill the X image and mask from PNG data. */
11361 init_color_table ();
11362
11363 for (y = 0; y < height; ++y)
11364 {
11365 png_byte *p = rows[y];
11366
11367 for (x = 0; x < width; ++x)
11368 {
11369 unsigned r, g, b;
11370
11371 r = *p++ << 8;
11372 g = *p++ << 8;
11373 b = *p++ << 8;
11374 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11375
11376 /* An alpha channel, aka mask channel, associates variable
11377 transparency with an image. Where other image formats
11378 support binary transparency---fully transparent or fully
11379 opaque---PNG allows up to 254 levels of partial transparency.
11380 The PNG library implements partial transparency by combining
11381 the image with a specified background color.
11382
11383 I'm not sure how to handle this here nicely: because the
11384 background on which the image is displayed may change, for
11385 real alpha channel support, it would be necessary to create
11386 a new image for each possible background.
11387
11388 What I'm doing now is that a mask is created if we have
11389 boolean transparency information. Otherwise I'm using
11390 the frame's background color to combine the image with. */
11391
11392 if (channels == 4)
11393 {
11394 if (mask_img)
11395 XPutPixel (mask_img, x, y, *p > 0);
11396 ++p;
11397 }
11398 }
11399 }
11400
a05e2bae
JR
11401 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11402 /* Set IMG's background color from the PNG image, unless the user
11403 overrode it. */
11404 {
11405 png_color_16 *bg;
11406 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11407 {
11408 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11409 img->background_valid = 1;
11410 }
11411 }
11412
6fc2811b
JR
11413 /* Remember colors allocated for this image. */
11414 img->colors = colors_in_color_table (&img->ncolors);
11415 free_color_table ();
11416
11417 /* Clean up. */
11418 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11419 xfree (rows);
11420 xfree (pixels);
11421
11422 img->width = width;
11423 img->height = height;
11424
a05e2bae
JR
11425 /* Maybe fill in the background field while we have ximg handy. */
11426 IMAGE_BACKGROUND (img, f, ximg);
11427
6fc2811b
JR
11428 /* Put the image into the pixmap, then free the X image and its buffer. */
11429 x_put_x_image (f, ximg, img->pixmap, width, height);
11430 x_destroy_x_image (ximg);
11431
11432 /* Same for the mask. */
11433 if (mask_img)
11434 {
a05e2bae
JR
11435 /* Fill in the background_transparent field while we have the mask
11436 handy. */
11437 image_background_transparent (img, f, mask_img);
11438
6fc2811b
JR
11439 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11440 x_destroy_x_image (mask_img);
11441 }
11442
6fc2811b
JR
11443 UNGCPRO;
11444 return 1;
11445}
11446
11447#endif /* HAVE_PNG != 0 */
11448
11449
11450\f
11451/***********************************************************************
11452 JPEG
11453 ***********************************************************************/
11454
11455#if HAVE_JPEG
11456
11457/* Work around a warning about HAVE_STDLIB_H being redefined in
11458 jconfig.h. */
11459#ifdef HAVE_STDLIB_H
11460#define HAVE_STDLIB_H_1
11461#undef HAVE_STDLIB_H
11462#endif /* HAVE_STLIB_H */
11463
11464#include <jpeglib.h>
11465#include <jerror.h>
11466#include <setjmp.h>
11467
11468#ifdef HAVE_STLIB_H_1
11469#define HAVE_STDLIB_H 1
11470#endif
11471
11472static int jpeg_image_p P_ ((Lisp_Object object));
11473static int jpeg_load P_ ((struct frame *f, struct image *img));
11474
11475/* The symbol `jpeg' identifying images of this type. */
11476
11477Lisp_Object Qjpeg;
11478
11479/* Indices of image specification fields in gs_format, below. */
11480
11481enum jpeg_keyword_index
11482{
11483 JPEG_TYPE,
11484 JPEG_DATA,
11485 JPEG_FILE,
11486 JPEG_ASCENT,
11487 JPEG_MARGIN,
11488 JPEG_RELIEF,
11489 JPEG_ALGORITHM,
11490 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11491 JPEG_MASK,
11492 JPEG_BACKGROUND,
6fc2811b
JR
11493 JPEG_LAST
11494};
11495
11496/* Vector of image_keyword structures describing the format
11497 of valid user-defined image specifications. */
11498
11499static struct image_keyword jpeg_format[JPEG_LAST] =
11500{
11501 {":type", IMAGE_SYMBOL_VALUE, 1},
11502 {":data", IMAGE_STRING_VALUE, 0},
11503 {":file", IMAGE_STRING_VALUE, 0},
11504 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11505 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11506 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11507 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11508 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11509 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11510 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11511};
11512
11513/* Structure describing the image type `jpeg'. */
11514
11515static struct image_type jpeg_type =
11516{
11517 &Qjpeg,
11518 jpeg_image_p,
11519 jpeg_load,
11520 x_clear_image,
11521 NULL
11522};
11523
11524
11525/* Return non-zero if OBJECT is a valid JPEG image specification. */
11526
11527static int
11528jpeg_image_p (object)
11529 Lisp_Object object;
11530{
11531 struct image_keyword fmt[JPEG_LAST];
11532
11533 bcopy (jpeg_format, fmt, sizeof fmt);
11534
11535 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11536 || (fmt[JPEG_ASCENT].count
11537 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11538 return 0;
11539
11540 /* Must specify either the :data or :file keyword. */
11541 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11542}
11543
11544
11545struct my_jpeg_error_mgr
11546{
11547 struct jpeg_error_mgr pub;
11548 jmp_buf setjmp_buffer;
11549};
11550
11551static void
11552my_error_exit (cinfo)
11553 j_common_ptr cinfo;
11554{
11555 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11556 longjmp (mgr->setjmp_buffer, 1);
11557}
11558
6fc2811b
JR
11559/* Init source method for JPEG data source manager. Called by
11560 jpeg_read_header() before any data is actually read. See
11561 libjpeg.doc from the JPEG lib distribution. */
11562
11563static void
11564our_init_source (cinfo)
11565 j_decompress_ptr cinfo;
11566{
11567}
11568
11569
11570/* Fill input buffer method for JPEG data source manager. Called
11571 whenever more data is needed. We read the whole image in one step,
11572 so this only adds a fake end of input marker at the end. */
11573
11574static boolean
11575our_fill_input_buffer (cinfo)
11576 j_decompress_ptr cinfo;
11577{
11578 /* Insert a fake EOI marker. */
11579 struct jpeg_source_mgr *src = cinfo->src;
11580 static JOCTET buffer[2];
11581
11582 buffer[0] = (JOCTET) 0xFF;
11583 buffer[1] = (JOCTET) JPEG_EOI;
11584
11585 src->next_input_byte = buffer;
11586 src->bytes_in_buffer = 2;
11587 return TRUE;
11588}
11589
11590
11591/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11592 is the JPEG data source manager. */
11593
11594static void
11595our_skip_input_data (cinfo, num_bytes)
11596 j_decompress_ptr cinfo;
11597 long num_bytes;
11598{
11599 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11600
11601 if (src)
11602 {
11603 if (num_bytes > src->bytes_in_buffer)
11604 ERREXIT (cinfo, JERR_INPUT_EOF);
11605
11606 src->bytes_in_buffer -= num_bytes;
11607 src->next_input_byte += num_bytes;
11608 }
11609}
11610
11611
11612/* Method to terminate data source. Called by
11613 jpeg_finish_decompress() after all data has been processed. */
11614
11615static void
11616our_term_source (cinfo)
11617 j_decompress_ptr cinfo;
11618{
11619}
11620
11621
11622/* Set up the JPEG lib for reading an image from DATA which contains
11623 LEN bytes. CINFO is the decompression info structure created for
11624 reading the image. */
11625
11626static void
11627jpeg_memory_src (cinfo, data, len)
11628 j_decompress_ptr cinfo;
11629 JOCTET *data;
11630 unsigned int len;
11631{
11632 struct jpeg_source_mgr *src;
11633
11634 if (cinfo->src == NULL)
11635 {
11636 /* First time for this JPEG object? */
11637 cinfo->src = (struct jpeg_source_mgr *)
11638 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11639 sizeof (struct jpeg_source_mgr));
11640 src = (struct jpeg_source_mgr *) cinfo->src;
11641 src->next_input_byte = data;
11642 }
11643
11644 src = (struct jpeg_source_mgr *) cinfo->src;
11645 src->init_source = our_init_source;
11646 src->fill_input_buffer = our_fill_input_buffer;
11647 src->skip_input_data = our_skip_input_data;
11648 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
11649 src->term_source = our_term_source;
11650 src->bytes_in_buffer = len;
11651 src->next_input_byte = data;
11652}
11653
11654
11655/* Load image IMG for use on frame F. Patterned after example.c
11656 from the JPEG lib. */
11657
11658static int
11659jpeg_load (f, img)
11660 struct frame *f;
11661 struct image *img;
11662{
11663 struct jpeg_decompress_struct cinfo;
11664 struct my_jpeg_error_mgr mgr;
11665 Lisp_Object file, specified_file;
11666 Lisp_Object specified_data;
a05e2bae 11667 FILE * volatile fp = NULL;
6fc2811b
JR
11668 JSAMPARRAY buffer;
11669 int row_stride, x, y;
11670 XImage *ximg = NULL;
11671 int rc;
11672 unsigned long *colors;
11673 int width, height;
11674 struct gcpro gcpro1;
11675
11676 /* Open the JPEG file. */
11677 specified_file = image_spec_value (img->spec, QCfile, NULL);
11678 specified_data = image_spec_value (img->spec, QCdata, NULL);
11679 file = Qnil;
11680 GCPRO1 (file);
11681
6fc2811b
JR
11682 if (NILP (specified_data))
11683 {
11684 file = x_find_image_file (specified_file);
11685 if (!STRINGP (file))
11686 {
11687 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11688 UNGCPRO;
11689 return 0;
11690 }
11691
11692 fp = fopen (XSTRING (file)->data, "r");
11693 if (fp == NULL)
11694 {
11695 image_error ("Cannot open `%s'", file, Qnil);
11696 UNGCPRO;
11697 return 0;
11698 }
11699 }
11700
11701 /* Customize libjpeg's error handling to call my_error_exit when an
11702 error is detected. This function will perform a longjmp. */
6fc2811b 11703 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 11704 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
11705
11706 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
11707 {
11708 if (rc == 1)
11709 {
11710 /* Called from my_error_exit. Display a JPEG error. */
11711 char buffer[JMSG_LENGTH_MAX];
11712 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11713 image_error ("Error reading JPEG image `%s': %s", img->spec,
11714 build_string (buffer));
11715 }
11716
11717 /* Close the input file and destroy the JPEG object. */
11718 if (fp)
11719 fclose (fp);
11720 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
11721
11722 /* If we already have an XImage, free that. */
11723 x_destroy_x_image (ximg);
11724
11725 /* Free pixmap and colors. */
11726 x_clear_image (f, img);
11727
6fc2811b
JR
11728 UNGCPRO;
11729 return 0;
11730 }
11731
11732 /* Create the JPEG decompression object. Let it read from fp.
11733 Read the JPEG image header. */
11734 jpeg_create_decompress (&cinfo);
11735
11736 if (NILP (specified_data))
11737 jpeg_stdio_src (&cinfo, fp);
11738 else
11739 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
11740 STRING_BYTES (XSTRING (specified_data)));
11741
11742 jpeg_read_header (&cinfo, TRUE);
11743
11744 /* Customize decompression so that color quantization will be used.
11745 Start decompression. */
11746 cinfo.quantize_colors = TRUE;
11747 jpeg_start_decompress (&cinfo);
11748 width = img->width = cinfo.output_width;
11749 height = img->height = cinfo.output_height;
11750
6fc2811b
JR
11751 /* Create X image and pixmap. */
11752 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11753 &img->pixmap))
a05e2bae 11754 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
11755
11756 /* Allocate colors. When color quantization is used,
11757 cinfo.actual_number_of_colors has been set with the number of
11758 colors generated, and cinfo.colormap is a two-dimensional array
11759 of color indices in the range 0..cinfo.actual_number_of_colors.
11760 No more than 255 colors will be generated. */
11761 {
11762 int i, ir, ig, ib;
11763
11764 if (cinfo.out_color_components > 2)
11765 ir = 0, ig = 1, ib = 2;
11766 else if (cinfo.out_color_components > 1)
11767 ir = 0, ig = 1, ib = 0;
11768 else
11769 ir = 0, ig = 0, ib = 0;
11770
11771 /* Use the color table mechanism because it handles colors that
11772 cannot be allocated nicely. Such colors will be replaced with
11773 a default color, and we don't have to care about which colors
11774 can be freed safely, and which can't. */
11775 init_color_table ();
11776 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11777 * sizeof *colors);
11778
11779 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11780 {
11781 /* Multiply RGB values with 255 because X expects RGB values
11782 in the range 0..0xffff. */
11783 int r = cinfo.colormap[ir][i] << 8;
11784 int g = cinfo.colormap[ig][i] << 8;
11785 int b = cinfo.colormap[ib][i] << 8;
11786 colors[i] = lookup_rgb_color (f, r, g, b);
11787 }
11788
11789 /* Remember those colors actually allocated. */
11790 img->colors = colors_in_color_table (&img->ncolors);
11791 free_color_table ();
11792 }
11793
11794 /* Read pixels. */
11795 row_stride = width * cinfo.output_components;
11796 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11797 row_stride, 1);
11798 for (y = 0; y < height; ++y)
11799 {
11800 jpeg_read_scanlines (&cinfo, buffer, 1);
11801 for (x = 0; x < cinfo.output_width; ++x)
11802 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11803 }
11804
11805 /* Clean up. */
11806 jpeg_finish_decompress (&cinfo);
11807 jpeg_destroy_decompress (&cinfo);
11808 if (fp)
11809 fclose (fp);
11810
a05e2bae
JR
11811 /* Maybe fill in the background field while we have ximg handy. */
11812 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11813 IMAGE_BACKGROUND (img, f, ximg);
11814
6fc2811b
JR
11815 /* Put the image into the pixmap. */
11816 x_put_x_image (f, ximg, img->pixmap, width, height);
11817 x_destroy_x_image (ximg);
11818 UNBLOCK_INPUT;
11819 UNGCPRO;
11820 return 1;
11821}
11822
11823#endif /* HAVE_JPEG */
11824
11825
11826\f
11827/***********************************************************************
11828 TIFF
11829 ***********************************************************************/
11830
11831#if HAVE_TIFF
11832
11833#include <tiffio.h>
11834
11835static int tiff_image_p P_ ((Lisp_Object object));
11836static int tiff_load P_ ((struct frame *f, struct image *img));
11837
11838/* The symbol `tiff' identifying images of this type. */
11839
11840Lisp_Object Qtiff;
11841
11842/* Indices of image specification fields in tiff_format, below. */
11843
11844enum tiff_keyword_index
11845{
11846 TIFF_TYPE,
11847 TIFF_DATA,
11848 TIFF_FILE,
11849 TIFF_ASCENT,
11850 TIFF_MARGIN,
11851 TIFF_RELIEF,
11852 TIFF_ALGORITHM,
11853 TIFF_HEURISTIC_MASK,
a05e2bae
JR
11854 TIFF_MASK,
11855 TIFF_BACKGROUND,
6fc2811b
JR
11856 TIFF_LAST
11857};
11858
11859/* Vector of image_keyword structures describing the format
11860 of valid user-defined image specifications. */
11861
11862static struct image_keyword tiff_format[TIFF_LAST] =
11863{
11864 {":type", IMAGE_SYMBOL_VALUE, 1},
11865 {":data", IMAGE_STRING_VALUE, 0},
11866 {":file", IMAGE_STRING_VALUE, 0},
11867 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11868 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11869 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11870 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11871 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11872 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11873 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11874};
11875
11876/* Structure describing the image type `tiff'. */
11877
11878static struct image_type tiff_type =
11879{
11880 &Qtiff,
11881 tiff_image_p,
11882 tiff_load,
11883 x_clear_image,
11884 NULL
11885};
11886
11887
11888/* Return non-zero if OBJECT is a valid TIFF image specification. */
11889
11890static int
11891tiff_image_p (object)
11892 Lisp_Object object;
11893{
11894 struct image_keyword fmt[TIFF_LAST];
11895 bcopy (tiff_format, fmt, sizeof fmt);
11896
11897 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11898 || (fmt[TIFF_ASCENT].count
11899 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11900 return 0;
11901
11902 /* Must specify either the :data or :file keyword. */
11903 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11904}
11905
11906
11907/* Reading from a memory buffer for TIFF images Based on the PNG
11908 memory source, but we have to provide a lot of extra functions.
11909 Blah.
11910
11911 We really only need to implement read and seek, but I am not
11912 convinced that the TIFF library is smart enough not to destroy
11913 itself if we only hand it the function pointers we need to
11914 override. */
11915
11916typedef struct
11917{
11918 unsigned char *bytes;
11919 size_t len;
11920 int index;
11921}
11922tiff_memory_source;
11923
11924static size_t
11925tiff_read_from_memory (data, buf, size)
11926 thandle_t data;
11927 tdata_t buf;
11928 tsize_t size;
11929{
11930 tiff_memory_source *src = (tiff_memory_source *) data;
11931
11932 if (size > src->len - src->index)
11933 return (size_t) -1;
11934 bcopy (src->bytes + src->index, buf, size);
11935 src->index += size;
11936 return size;
11937}
11938
11939static size_t
11940tiff_write_from_memory (data, buf, size)
11941 thandle_t data;
11942 tdata_t buf;
11943 tsize_t size;
11944{
11945 return (size_t) -1;
11946}
11947
11948static toff_t
11949tiff_seek_in_memory (data, off, whence)
11950 thandle_t data;
11951 toff_t off;
11952 int whence;
11953{
11954 tiff_memory_source *src = (tiff_memory_source *) data;
11955 int idx;
11956
11957 switch (whence)
11958 {
11959 case SEEK_SET: /* Go from beginning of source. */
11960 idx = off;
11961 break;
11962
11963 case SEEK_END: /* Go from end of source. */
11964 idx = src->len + off;
11965 break;
11966
11967 case SEEK_CUR: /* Go from current position. */
11968 idx = src->index + off;
11969 break;
11970
11971 default: /* Invalid `whence'. */
11972 return -1;
11973 }
11974
11975 if (idx > src->len || idx < 0)
11976 return -1;
11977
11978 src->index = idx;
11979 return src->index;
11980}
11981
11982static int
11983tiff_close_memory (data)
11984 thandle_t data;
11985{
11986 /* NOOP */
11987 return 0;
11988}
11989
11990static int
11991tiff_mmap_memory (data, pbase, psize)
11992 thandle_t data;
11993 tdata_t *pbase;
11994 toff_t *psize;
11995{
11996 /* It is already _IN_ memory. */
11997 return 0;
11998}
11999
12000static void
12001tiff_unmap_memory (data, base, size)
12002 thandle_t data;
12003 tdata_t base;
12004 toff_t size;
12005{
12006 /* We don't need to do this. */
12007}
12008
12009static toff_t
12010tiff_size_of_memory (data)
12011 thandle_t data;
12012{
12013 return ((tiff_memory_source *) data)->len;
12014}
12015
3cf3436e
JR
12016
12017static void
12018tiff_error_handler (title, format, ap)
12019 const char *title, *format;
12020 va_list ap;
12021{
12022 char buf[512];
12023 int len;
12024
12025 len = sprintf (buf, "TIFF error: %s ", title);
12026 vsprintf (buf + len, format, ap);
12027 add_to_log (buf, Qnil, Qnil);
12028}
12029
12030
12031static void
12032tiff_warning_handler (title, format, ap)
12033 const char *title, *format;
12034 va_list ap;
12035{
12036 char buf[512];
12037 int len;
12038
12039 len = sprintf (buf, "TIFF warning: %s ", title);
12040 vsprintf (buf + len, format, ap);
12041 add_to_log (buf, Qnil, Qnil);
12042}
12043
12044
6fc2811b
JR
12045/* Load TIFF image IMG for use on frame F. Value is non-zero if
12046 successful. */
12047
12048static int
12049tiff_load (f, img)
12050 struct frame *f;
12051 struct image *img;
12052{
12053 Lisp_Object file, specified_file;
12054 Lisp_Object specified_data;
12055 TIFF *tiff;
12056 int width, height, x, y;
12057 uint32 *buf;
12058 int rc;
12059 XImage *ximg;
12060 struct gcpro gcpro1;
12061 tiff_memory_source memsrc;
12062
12063 specified_file = image_spec_value (img->spec, QCfile, NULL);
12064 specified_data = image_spec_value (img->spec, QCdata, NULL);
12065 file = Qnil;
12066 GCPRO1 (file);
12067
3cf3436e
JR
12068 TIFFSetErrorHandler (tiff_error_handler);
12069 TIFFSetWarningHandler (tiff_warning_handler);
12070
6fc2811b
JR
12071 if (NILP (specified_data))
12072 {
12073 /* Read from a file */
12074 file = x_find_image_file (specified_file);
12075 if (!STRINGP (file))
3cf3436e
JR
12076 {
12077 image_error ("Cannot find image file `%s'", file, Qnil);
12078 UNGCPRO;
12079 return 0;
12080 }
12081
6fc2811b
JR
12082 /* Try to open the image file. */
12083 tiff = TIFFOpen (XSTRING (file)->data, "r");
12084 if (tiff == NULL)
3cf3436e
JR
12085 {
12086 image_error ("Cannot open `%s'", file, Qnil);
12087 UNGCPRO;
12088 return 0;
12089 }
6fc2811b
JR
12090 }
12091 else
12092 {
12093 /* Memory source! */
12094 memsrc.bytes = XSTRING (specified_data)->data;
12095 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12096 memsrc.index = 0;
12097
12098 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12099 (TIFFReadWriteProc) tiff_read_from_memory,
12100 (TIFFReadWriteProc) tiff_write_from_memory,
12101 tiff_seek_in_memory,
12102 tiff_close_memory,
12103 tiff_size_of_memory,
12104 tiff_mmap_memory,
12105 tiff_unmap_memory);
12106
12107 if (!tiff)
12108 {
12109 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12110 UNGCPRO;
12111 return 0;
12112 }
12113 }
12114
12115 /* Get width and height of the image, and allocate a raster buffer
12116 of width x height 32-bit values. */
12117 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12118 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12119 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12120
12121 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12122 TIFFClose (tiff);
12123 if (!rc)
12124 {
12125 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12126 xfree (buf);
12127 UNGCPRO;
12128 return 0;
12129 }
12130
6fc2811b
JR
12131 /* Create the X image and pixmap. */
12132 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12133 {
6fc2811b
JR
12134 xfree (buf);
12135 UNGCPRO;
12136 return 0;
12137 }
12138
12139 /* Initialize the color table. */
12140 init_color_table ();
12141
12142 /* Process the pixel raster. Origin is in the lower-left corner. */
12143 for (y = 0; y < height; ++y)
12144 {
12145 uint32 *row = buf + y * width;
12146
12147 for (x = 0; x < width; ++x)
12148 {
12149 uint32 abgr = row[x];
12150 int r = TIFFGetR (abgr) << 8;
12151 int g = TIFFGetG (abgr) << 8;
12152 int b = TIFFGetB (abgr) << 8;
12153 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12154 }
12155 }
12156
12157 /* Remember the colors allocated for the image. Free the color table. */
12158 img->colors = colors_in_color_table (&img->ncolors);
12159 free_color_table ();
12160
a05e2bae
JR
12161 img->width = width;
12162 img->height = height;
12163
12164 /* Maybe fill in the background field while we have ximg handy. */
12165 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12166 IMAGE_BACKGROUND (img, f, ximg);
12167
6fc2811b
JR
12168 /* Put the image into the pixmap, then free the X image and its buffer. */
12169 x_put_x_image (f, ximg, img->pixmap, width, height);
12170 x_destroy_x_image (ximg);
12171 xfree (buf);
6fc2811b
JR
12172
12173 UNGCPRO;
12174 return 1;
12175}
12176
12177#endif /* HAVE_TIFF != 0 */
12178
12179
12180\f
12181/***********************************************************************
12182 GIF
12183 ***********************************************************************/
12184
12185#if HAVE_GIF
12186
12187#include <gif_lib.h>
12188
12189static int gif_image_p P_ ((Lisp_Object object));
12190static int gif_load P_ ((struct frame *f, struct image *img));
12191
12192/* The symbol `gif' identifying images of this type. */
12193
12194Lisp_Object Qgif;
12195
12196/* Indices of image specification fields in gif_format, below. */
12197
12198enum gif_keyword_index
12199{
12200 GIF_TYPE,
12201 GIF_DATA,
12202 GIF_FILE,
12203 GIF_ASCENT,
12204 GIF_MARGIN,
12205 GIF_RELIEF,
12206 GIF_ALGORITHM,
12207 GIF_HEURISTIC_MASK,
a05e2bae 12208 GIF_MASK,
6fc2811b 12209 GIF_IMAGE,
a05e2bae 12210 GIF_BACKGROUND,
6fc2811b
JR
12211 GIF_LAST
12212};
12213
12214/* Vector of image_keyword structures describing the format
12215 of valid user-defined image specifications. */
12216
12217static struct image_keyword gif_format[GIF_LAST] =
12218{
12219 {":type", IMAGE_SYMBOL_VALUE, 1},
12220 {":data", IMAGE_STRING_VALUE, 0},
12221 {":file", IMAGE_STRING_VALUE, 0},
12222 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12223 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12224 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12225 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12226 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12227 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12228 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12229 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12230};
12231
12232/* Structure describing the image type `gif'. */
12233
12234static struct image_type gif_type =
12235{
12236 &Qgif,
12237 gif_image_p,
12238 gif_load,
12239 x_clear_image,
12240 NULL
12241};
12242
12243/* Return non-zero if OBJECT is a valid GIF image specification. */
12244
12245static int
12246gif_image_p (object)
12247 Lisp_Object object;
12248{
12249 struct image_keyword fmt[GIF_LAST];
12250 bcopy (gif_format, fmt, sizeof fmt);
12251
12252 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12253 || (fmt[GIF_ASCENT].count
12254 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12255 return 0;
12256
12257 /* Must specify either the :data or :file keyword. */
12258 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12259}
12260
12261/* Reading a GIF image from memory
12262 Based on the PNG memory stuff to a certain extent. */
12263
12264typedef struct
12265{
12266 unsigned char *bytes;
12267 size_t len;
12268 int index;
12269}
12270gif_memory_source;
12271
12272/* Make the current memory source available to gif_read_from_memory.
12273 It's done this way because not all versions of libungif support
12274 a UserData field in the GifFileType structure. */
12275static gif_memory_source *current_gif_memory_src;
12276
12277static int
12278gif_read_from_memory (file, buf, len)
12279 GifFileType *file;
12280 GifByteType *buf;
12281 int len;
12282{
12283 gif_memory_source *src = current_gif_memory_src;
12284
12285 if (len > src->len - src->index)
12286 return -1;
12287
12288 bcopy (src->bytes + src->index, buf, len);
12289 src->index += len;
12290 return len;
12291}
12292
12293
12294/* Load GIF image IMG for use on frame F. Value is non-zero if
12295 successful. */
12296
12297static int
12298gif_load (f, img)
12299 struct frame *f;
12300 struct image *img;
12301{
12302 Lisp_Object file, specified_file;
12303 Lisp_Object specified_data;
12304 int rc, width, height, x, y, i;
12305 XImage *ximg;
12306 ColorMapObject *gif_color_map;
12307 unsigned long pixel_colors[256];
12308 GifFileType *gif;
12309 struct gcpro gcpro1;
12310 Lisp_Object image;
12311 int ino, image_left, image_top, image_width, image_height;
12312 gif_memory_source memsrc;
12313 unsigned char *raster;
12314
12315 specified_file = image_spec_value (img->spec, QCfile, NULL);
12316 specified_data = image_spec_value (img->spec, QCdata, NULL);
12317 file = Qnil;
dfff8a69 12318 GCPRO1 (file);
6fc2811b
JR
12319
12320 if (NILP (specified_data))
12321 {
12322 file = x_find_image_file (specified_file);
6fc2811b
JR
12323 if (!STRINGP (file))
12324 {
12325 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12326 UNGCPRO;
12327 return 0;
12328 }
12329
12330 /* Open the GIF file. */
12331 gif = DGifOpenFileName (XSTRING (file)->data);
12332 if (gif == NULL)
12333 {
12334 image_error ("Cannot open `%s'", file, Qnil);
12335 UNGCPRO;
12336 return 0;
12337 }
12338 }
12339 else
12340 {
12341 /* Read from memory! */
12342 current_gif_memory_src = &memsrc;
12343 memsrc.bytes = XSTRING (specified_data)->data;
12344 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12345 memsrc.index = 0;
12346
12347 gif = DGifOpen(&memsrc, gif_read_from_memory);
12348 if (!gif)
12349 {
12350 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12351 UNGCPRO;
12352 return 0;
12353 }
12354 }
12355
12356 /* Read entire contents. */
12357 rc = DGifSlurp (gif);
12358 if (rc == GIF_ERROR)
12359 {
12360 image_error ("Error reading `%s'", img->spec, Qnil);
12361 DGifCloseFile (gif);
12362 UNGCPRO;
12363 return 0;
12364 }
12365
12366 image = image_spec_value (img->spec, QCindex, NULL);
12367 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12368 if (ino >= gif->ImageCount)
12369 {
12370 image_error ("Invalid image number `%s' in image `%s'",
12371 image, img->spec);
12372 DGifCloseFile (gif);
12373 UNGCPRO;
12374 return 0;
12375 }
12376
12377 width = img->width = gif->SWidth;
12378 height = img->height = gif->SHeight;
12379
6fc2811b
JR
12380 /* Create the X image and pixmap. */
12381 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12382 {
6fc2811b
JR
12383 DGifCloseFile (gif);
12384 UNGCPRO;
12385 return 0;
12386 }
12387
12388 /* Allocate colors. */
12389 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12390 if (!gif_color_map)
12391 gif_color_map = gif->SColorMap;
12392 init_color_table ();
12393 bzero (pixel_colors, sizeof pixel_colors);
12394
12395 for (i = 0; i < gif_color_map->ColorCount; ++i)
12396 {
12397 int r = gif_color_map->Colors[i].Red << 8;
12398 int g = gif_color_map->Colors[i].Green << 8;
12399 int b = gif_color_map->Colors[i].Blue << 8;
12400 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12401 }
12402
12403 img->colors = colors_in_color_table (&img->ncolors);
12404 free_color_table ();
12405
12406 /* Clear the part of the screen image that are not covered by
12407 the image from the GIF file. Full animated GIF support
12408 requires more than can be done here (see the gif89 spec,
12409 disposal methods). Let's simply assume that the part
12410 not covered by a sub-image is in the frame's background color. */
12411 image_top = gif->SavedImages[ino].ImageDesc.Top;
12412 image_left = gif->SavedImages[ino].ImageDesc.Left;
12413 image_width = gif->SavedImages[ino].ImageDesc.Width;
12414 image_height = gif->SavedImages[ino].ImageDesc.Height;
12415
12416 for (y = 0; y < image_top; ++y)
12417 for (x = 0; x < width; ++x)
12418 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12419
12420 for (y = image_top + image_height; y < height; ++y)
12421 for (x = 0; x < width; ++x)
12422 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12423
12424 for (y = image_top; y < image_top + image_height; ++y)
12425 {
12426 for (x = 0; x < image_left; ++x)
12427 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12428 for (x = image_left + image_width; x < width; ++x)
12429 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12430 }
12431
12432 /* Read the GIF image into the X image. We use a local variable
12433 `raster' here because RasterBits below is a char *, and invites
12434 problems with bytes >= 0x80. */
12435 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12436
12437 if (gif->SavedImages[ino].ImageDesc.Interlace)
12438 {
12439 static int interlace_start[] = {0, 4, 2, 1};
12440 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12441 int pass;
6fc2811b
JR
12442 int row = interlace_start[0];
12443
12444 pass = 0;
12445
12446 for (y = 0; y < image_height; y++)
12447 {
12448 if (row >= image_height)
12449 {
12450 row = interlace_start[++pass];
12451 while (row >= image_height)
12452 row = interlace_start[++pass];
12453 }
12454
12455 for (x = 0; x < image_width; x++)
12456 {
12457 int i = raster[(y * image_width) + x];
12458 XPutPixel (ximg, x + image_left, row + image_top,
12459 pixel_colors[i]);
12460 }
12461
12462 row += interlace_increment[pass];
12463 }
12464 }
12465 else
12466 {
12467 for (y = 0; y < image_height; ++y)
12468 for (x = 0; x < image_width; ++x)
12469 {
12470 int i = raster[y* image_width + x];
12471 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12472 }
12473 }
12474
12475 DGifCloseFile (gif);
a05e2bae
JR
12476
12477 /* Maybe fill in the background field while we have ximg handy. */
12478 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12479 IMAGE_BACKGROUND (img, f, ximg);
12480
6fc2811b
JR
12481 /* Put the image into the pixmap, then free the X image and its buffer. */
12482 x_put_x_image (f, ximg, img->pixmap, width, height);
12483 x_destroy_x_image (ximg);
6fc2811b
JR
12484
12485 UNGCPRO;
12486 return 1;
12487}
12488
12489#endif /* HAVE_GIF != 0 */
12490
12491
12492\f
12493/***********************************************************************
12494 Ghostscript
12495 ***********************************************************************/
12496
3cf3436e
JR
12497Lisp_Object Qpostscript;
12498
6fc2811b
JR
12499#ifdef HAVE_GHOSTSCRIPT
12500static int gs_image_p P_ ((Lisp_Object object));
12501static int gs_load P_ ((struct frame *f, struct image *img));
12502static void gs_clear_image P_ ((struct frame *f, struct image *img));
12503
12504/* The symbol `postscript' identifying images of this type. */
12505
6fc2811b
JR
12506/* Keyword symbols. */
12507
12508Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12509
12510/* Indices of image specification fields in gs_format, below. */
12511
12512enum gs_keyword_index
12513{
12514 GS_TYPE,
12515 GS_PT_WIDTH,
12516 GS_PT_HEIGHT,
12517 GS_FILE,
12518 GS_LOADER,
12519 GS_BOUNDING_BOX,
12520 GS_ASCENT,
12521 GS_MARGIN,
12522 GS_RELIEF,
12523 GS_ALGORITHM,
12524 GS_HEURISTIC_MASK,
a05e2bae
JR
12525 GS_MASK,
12526 GS_BACKGROUND,
6fc2811b
JR
12527 GS_LAST
12528};
12529
12530/* Vector of image_keyword structures describing the format
12531 of valid user-defined image specifications. */
12532
12533static struct image_keyword gs_format[GS_LAST] =
12534{
12535 {":type", IMAGE_SYMBOL_VALUE, 1},
12536 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12537 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12538 {":file", IMAGE_STRING_VALUE, 1},
12539 {":loader", IMAGE_FUNCTION_VALUE, 0},
12540 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12541 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12542 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12543 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12544 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12545 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12546 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12547 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12548};
12549
12550/* Structure describing the image type `ghostscript'. */
12551
12552static struct image_type gs_type =
12553{
12554 &Qpostscript,
12555 gs_image_p,
12556 gs_load,
12557 gs_clear_image,
12558 NULL
12559};
12560
12561
12562/* Free X resources of Ghostscript image IMG which is used on frame F. */
12563
12564static void
12565gs_clear_image (f, img)
12566 struct frame *f;
12567 struct image *img;
12568{
12569 /* IMG->data.ptr_val may contain a recorded colormap. */
12570 xfree (img->data.ptr_val);
12571 x_clear_image (f, img);
12572}
12573
12574
12575/* Return non-zero if OBJECT is a valid Ghostscript image
12576 specification. */
12577
12578static int
12579gs_image_p (object)
12580 Lisp_Object object;
12581{
12582 struct image_keyword fmt[GS_LAST];
12583 Lisp_Object tem;
12584 int i;
12585
12586 bcopy (gs_format, fmt, sizeof fmt);
12587
12588 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
12589 || (fmt[GS_ASCENT].count
12590 && XFASTINT (fmt[GS_ASCENT].value) > 100))
12591 return 0;
12592
12593 /* Bounding box must be a list or vector containing 4 integers. */
12594 tem = fmt[GS_BOUNDING_BOX].value;
12595 if (CONSP (tem))
12596 {
12597 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12598 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12599 return 0;
12600 if (!NILP (tem))
12601 return 0;
12602 }
12603 else if (VECTORP (tem))
12604 {
12605 if (XVECTOR (tem)->size != 4)
12606 return 0;
12607 for (i = 0; i < 4; ++i)
12608 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12609 return 0;
12610 }
12611 else
12612 return 0;
12613
12614 return 1;
12615}
12616
12617
12618/* Load Ghostscript image IMG for use on frame F. Value is non-zero
12619 if successful. */
12620
12621static int
12622gs_load (f, img)
12623 struct frame *f;
12624 struct image *img;
12625{
12626 char buffer[100];
12627 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12628 struct gcpro gcpro1, gcpro2;
12629 Lisp_Object frame;
12630 double in_width, in_height;
12631 Lisp_Object pixel_colors = Qnil;
12632
12633 /* Compute pixel size of pixmap needed from the given size in the
12634 image specification. Sizes in the specification are in pt. 1 pt
12635 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12636 info. */
12637 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12638 in_width = XFASTINT (pt_width) / 72.0;
12639 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12640 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12641 in_height = XFASTINT (pt_height) / 72.0;
12642 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12643
12644 /* Create the pixmap. */
12645 BLOCK_INPUT;
12646 xassert (img->pixmap == 0);
12647 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12648 img->width, img->height,
a05e2bae 12649 one_w32_display_info.n_cbits);
6fc2811b
JR
12650 UNBLOCK_INPUT;
12651
12652 if (!img->pixmap)
12653 {
12654 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12655 return 0;
12656 }
12657
12658 /* Call the loader to fill the pixmap. It returns a process object
12659 if successful. We do not record_unwind_protect here because
12660 other places in redisplay like calling window scroll functions
12661 don't either. Let the Lisp loader use `unwind-protect' instead. */
12662 GCPRO2 (window_and_pixmap_id, pixel_colors);
12663
12664 sprintf (buffer, "%lu %lu",
12665 (unsigned long) FRAME_W32_WINDOW (f),
12666 (unsigned long) img->pixmap);
12667 window_and_pixmap_id = build_string (buffer);
12668
12669 sprintf (buffer, "%lu %lu",
12670 FRAME_FOREGROUND_PIXEL (f),
12671 FRAME_BACKGROUND_PIXEL (f));
12672 pixel_colors = build_string (buffer);
12673
12674 XSETFRAME (frame, f);
12675 loader = image_spec_value (img->spec, QCloader, NULL);
12676 if (NILP (loader))
12677 loader = intern ("gs-load-image");
12678
12679 img->data.lisp_val = call6 (loader, frame, img->spec,
12680 make_number (img->width),
12681 make_number (img->height),
12682 window_and_pixmap_id,
12683 pixel_colors);
12684 UNGCPRO;
12685 return PROCESSP (img->data.lisp_val);
12686}
12687
12688
12689/* Kill the Ghostscript process that was started to fill PIXMAP on
12690 frame F. Called from XTread_socket when receiving an event
12691 telling Emacs that Ghostscript has finished drawing. */
12692
12693void
12694x_kill_gs_process (pixmap, f)
12695 Pixmap pixmap;
12696 struct frame *f;
12697{
12698 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
12699 int class, i;
12700 struct image *img;
12701
12702 /* Find the image containing PIXMAP. */
12703 for (i = 0; i < c->used; ++i)
12704 if (c->images[i]->pixmap == pixmap)
12705 break;
12706
3cf3436e
JR
12707 /* Should someone in between have cleared the image cache, for
12708 instance, give up. */
12709 if (i == c->used)
12710 return;
12711
6fc2811b
JR
12712 /* Kill the GS process. We should have found PIXMAP in the image
12713 cache and its image should contain a process object. */
6fc2811b
JR
12714 img = c->images[i];
12715 xassert (PROCESSP (img->data.lisp_val));
12716 Fkill_process (img->data.lisp_val, Qnil);
12717 img->data.lisp_val = Qnil;
12718
12719 /* On displays with a mutable colormap, figure out the colors
12720 allocated for the image by looking at the pixels of an XImage for
12721 img->pixmap. */
12722 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
12723 if (class != StaticColor && class != StaticGray && class != TrueColor)
12724 {
12725 XImage *ximg;
12726
12727 BLOCK_INPUT;
12728
12729 /* Try to get an XImage for img->pixmep. */
12730 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
12731 0, 0, img->width, img->height, ~0, ZPixmap);
12732 if (ximg)
12733 {
12734 int x, y;
12735
12736 /* Initialize the color table. */
12737 init_color_table ();
12738
12739 /* For each pixel of the image, look its color up in the
12740 color table. After having done so, the color table will
12741 contain an entry for each color used by the image. */
12742 for (y = 0; y < img->height; ++y)
12743 for (x = 0; x < img->width; ++x)
12744 {
12745 unsigned long pixel = XGetPixel (ximg, x, y);
12746 lookup_pixel_color (f, pixel);
12747 }
12748
12749 /* Record colors in the image. Free color table and XImage. */
12750 img->colors = colors_in_color_table (&img->ncolors);
12751 free_color_table ();
12752 XDestroyImage (ximg);
12753
12754#if 0 /* This doesn't seem to be the case. If we free the colors
12755 here, we get a BadAccess later in x_clear_image when
12756 freeing the colors. */
12757 /* We have allocated colors once, but Ghostscript has also
12758 allocated colors on behalf of us. So, to get the
12759 reference counts right, free them once. */
12760 if (img->ncolors)
3cf3436e 12761 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 12762 img->colors, img->ncolors, 0);
6fc2811b
JR
12763#endif
12764 }
12765 else
12766 image_error ("Cannot get X image of `%s'; colors will not be freed",
12767 img->spec, Qnil);
12768
12769 UNBLOCK_INPUT;
12770 }
3cf3436e
JR
12771
12772 /* Now that we have the pixmap, compute mask and transform the
12773 image if requested. */
12774 BLOCK_INPUT;
12775 postprocess_image (f, img);
12776 UNBLOCK_INPUT;
6fc2811b
JR
12777}
12778
12779#endif /* HAVE_GHOSTSCRIPT */
12780
12781\f
12782/***********************************************************************
12783 Window properties
12784 ***********************************************************************/
12785
12786DEFUN ("x-change-window-property", Fx_change_window_property,
12787 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
12788 doc: /* Change window property PROP to VALUE on the X window of FRAME.
12789PROP and VALUE must be strings. FRAME nil or omitted means use the
12790selected frame. Value is VALUE. */)
6fc2811b
JR
12791 (prop, value, frame)
12792 Lisp_Object frame, prop, value;
12793{
767b1ff0 12794#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12795 struct frame *f = check_x_frame (frame);
12796 Atom prop_atom;
12797
b7826503
PJ
12798 CHECK_STRING (prop);
12799 CHECK_STRING (value);
6fc2811b
JR
12800
12801 BLOCK_INPUT;
12802 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12803 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12804 prop_atom, XA_STRING, 8, PropModeReplace,
12805 XSTRING (value)->data, XSTRING (value)->size);
12806
12807 /* Make sure the property is set when we return. */
12808 XFlush (FRAME_W32_DISPLAY (f));
12809 UNBLOCK_INPUT;
12810
767b1ff0 12811#endif /* TODO */
6fc2811b
JR
12812
12813 return value;
12814}
12815
12816
12817DEFUN ("x-delete-window-property", Fx_delete_window_property,
12818 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
12819 doc: /* Remove window property PROP from X window of FRAME.
12820FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
12821 (prop, frame)
12822 Lisp_Object prop, frame;
12823{
767b1ff0 12824#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12825
12826 struct frame *f = check_x_frame (frame);
12827 Atom prop_atom;
12828
b7826503 12829 CHECK_STRING (prop);
6fc2811b
JR
12830 BLOCK_INPUT;
12831 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12832 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12833
12834 /* Make sure the property is removed when we return. */
12835 XFlush (FRAME_W32_DISPLAY (f));
12836 UNBLOCK_INPUT;
767b1ff0 12837#endif /* TODO */
6fc2811b
JR
12838
12839 return prop;
12840}
12841
12842
12843DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12844 1, 2, 0,
74e1aeec
JR
12845 doc: /* Value is the value of window property PROP on FRAME.
12846If FRAME is nil or omitted, use the selected frame. Value is nil
12847if FRAME hasn't a property with name PROP or if PROP has no string
12848value. */)
6fc2811b
JR
12849 (prop, frame)
12850 Lisp_Object prop, frame;
12851{
767b1ff0 12852#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12853
12854 struct frame *f = check_x_frame (frame);
12855 Atom prop_atom;
12856 int rc;
12857 Lisp_Object prop_value = Qnil;
12858 char *tmp_data = NULL;
12859 Atom actual_type;
12860 int actual_format;
12861 unsigned long actual_size, bytes_remaining;
12862
b7826503 12863 CHECK_STRING (prop);
6fc2811b
JR
12864 BLOCK_INPUT;
12865 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12866 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12867 prop_atom, 0, 0, False, XA_STRING,
12868 &actual_type, &actual_format, &actual_size,
12869 &bytes_remaining, (unsigned char **) &tmp_data);
12870 if (rc == Success)
12871 {
12872 int size = bytes_remaining;
12873
12874 XFree (tmp_data);
12875 tmp_data = NULL;
12876
12877 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12878 prop_atom, 0, bytes_remaining,
12879 False, XA_STRING,
12880 &actual_type, &actual_format,
12881 &actual_size, &bytes_remaining,
12882 (unsigned char **) &tmp_data);
12883 if (rc == Success)
12884 prop_value = make_string (tmp_data, size);
12885
12886 XFree (tmp_data);
12887 }
12888
12889 UNBLOCK_INPUT;
12890
12891 return prop_value;
12892
767b1ff0 12893#endif /* TODO */
6fc2811b
JR
12894 return Qnil;
12895}
12896
12897
12898\f
12899/***********************************************************************
12900 Busy cursor
12901 ***********************************************************************/
12902
f79e6790 12903/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 12904 an hourglass cursor on all frames. */
6fc2811b 12905
0af913d7 12906static struct atimer *hourglass_atimer;
6fc2811b 12907
0af913d7 12908/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 12909
0af913d7 12910static int hourglass_shown_p;
6fc2811b 12911
0af913d7 12912/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 12913
0af913d7 12914static Lisp_Object Vhourglass_delay;
6fc2811b 12915
0af913d7 12916/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
12917 cursor. */
12918
0af913d7 12919#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
12920
12921/* Function prototypes. */
12922
0af913d7
GM
12923static void show_hourglass P_ ((struct atimer *));
12924static void hide_hourglass P_ ((void));
f79e6790
JR
12925
12926
0af913d7 12927/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
12928
12929void
0af913d7 12930start_hourglass ()
f79e6790 12931{
767b1ff0 12932#if 0 /* TODO: cursor shape changes. */
f79e6790 12933 EMACS_TIME delay;
dfff8a69 12934 int secs, usecs = 0;
f79e6790 12935
0af913d7 12936 cancel_hourglass ();
f79e6790 12937
0af913d7
GM
12938 if (INTEGERP (Vhourglass_delay)
12939 && XINT (Vhourglass_delay) > 0)
12940 secs = XFASTINT (Vhourglass_delay);
12941 else if (FLOATP (Vhourglass_delay)
12942 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
12943 {
12944 Lisp_Object tem;
0af913d7 12945 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 12946 secs = XFASTINT (tem);
0af913d7 12947 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 12948 }
f79e6790 12949 else
0af913d7 12950 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 12951
dfff8a69 12952 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
12953 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
12954 show_hourglass, NULL);
f79e6790
JR
12955#endif
12956}
12957
12958
0af913d7
GM
12959/* Cancel the hourglass cursor timer if active, hide an hourglass
12960 cursor if shown. */
f79e6790
JR
12961
12962void
0af913d7 12963cancel_hourglass ()
f79e6790 12964{
0af913d7 12965 if (hourglass_atimer)
dfff8a69 12966 {
0af913d7
GM
12967 cancel_atimer (hourglass_atimer);
12968 hourglass_atimer = NULL;
dfff8a69
JR
12969 }
12970
0af913d7
GM
12971 if (hourglass_shown_p)
12972 hide_hourglass ();
f79e6790
JR
12973}
12974
12975
0af913d7
GM
12976/* Timer function of hourglass_atimer. TIMER is equal to
12977 hourglass_atimer.
f79e6790 12978
0af913d7
GM
12979 Display an hourglass cursor on all frames by mapping the frames'
12980 hourglass_window. Set the hourglass_p flag in the frames'
12981 output_data.x structure to indicate that an hourglass cursor is
12982 shown on the frames. */
f79e6790
JR
12983
12984static void
0af913d7 12985show_hourglass (timer)
f79e6790 12986 struct atimer *timer;
6fc2811b 12987{
767b1ff0 12988#if 0 /* TODO: cursor shape changes. */
f79e6790 12989 /* The timer implementation will cancel this timer automatically
0af913d7 12990 after this function has run. Set hourglass_atimer to null
f79e6790 12991 so that we know the timer doesn't have to be canceled. */
0af913d7 12992 hourglass_atimer = NULL;
f79e6790 12993
0af913d7 12994 if (!hourglass_shown_p)
6fc2811b
JR
12995 {
12996 Lisp_Object rest, frame;
f79e6790
JR
12997
12998 BLOCK_INPUT;
12999
6fc2811b 13000 FOR_EACH_FRAME (rest, frame)
dc220243 13001 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13002 {
13003 struct frame *f = XFRAME (frame);
f79e6790 13004
0af913d7 13005 f->output_data.w32->hourglass_p = 1;
f79e6790 13006
0af913d7 13007 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13008 {
13009 unsigned long mask = CWCursor;
13010 XSetWindowAttributes attrs;
f79e6790 13011
0af913d7 13012 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13013
0af913d7 13014 f->output_data.w32->hourglass_window
f79e6790 13015 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13016 FRAME_OUTER_WINDOW (f),
13017 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13018 InputOnly,
13019 CopyFromParent,
6fc2811b
JR
13020 mask, &attrs);
13021 }
f79e6790 13022
0af913d7
GM
13023 XMapRaised (FRAME_X_DISPLAY (f),
13024 f->output_data.w32->hourglass_window);
f79e6790 13025 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13026 }
6fc2811b 13027
0af913d7 13028 hourglass_shown_p = 1;
f79e6790
JR
13029 UNBLOCK_INPUT;
13030 }
13031#endif
6fc2811b
JR
13032}
13033
13034
0af913d7 13035/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13036
f79e6790 13037static void
0af913d7 13038hide_hourglass ()
f79e6790 13039{
767b1ff0 13040#if 0 /* TODO: cursor shape changes. */
0af913d7 13041 if (hourglass_shown_p)
6fc2811b 13042 {
f79e6790
JR
13043 Lisp_Object rest, frame;
13044
13045 BLOCK_INPUT;
13046 FOR_EACH_FRAME (rest, frame)
6fc2811b 13047 {
f79e6790
JR
13048 struct frame *f = XFRAME (frame);
13049
dc220243 13050 if (FRAME_W32_P (f)
f79e6790 13051 /* Watch out for newly created frames. */
0af913d7 13052 && f->output_data.x->hourglass_window)
f79e6790 13053 {
0af913d7
GM
13054 XUnmapWindow (FRAME_X_DISPLAY (f),
13055 f->output_data.x->hourglass_window);
13056 /* Sync here because XTread_socket looks at the
13057 hourglass_p flag that is reset to zero below. */
f79e6790 13058 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13059 f->output_data.x->hourglass_p = 0;
f79e6790 13060 }
6fc2811b 13061 }
6fc2811b 13062
0af913d7 13063 hourglass_shown_p = 0;
f79e6790
JR
13064 UNBLOCK_INPUT;
13065 }
13066#endif
6fc2811b
JR
13067}
13068
13069
13070\f
13071/***********************************************************************
13072 Tool tips
13073 ***********************************************************************/
13074
13075static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13076 Lisp_Object, Lisp_Object));
13077static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13078 Lisp_Object, int, int, int *, int *));
6fc2811b 13079
3cf3436e 13080/* The frame of a currently visible tooltip. */
6fc2811b 13081
937e601e 13082Lisp_Object tip_frame;
6fc2811b
JR
13083
13084/* If non-nil, a timer started that hides the last tooltip when it
13085 fires. */
13086
13087Lisp_Object tip_timer;
13088Window tip_window;
13089
3cf3436e
JR
13090/* If non-nil, a vector of 3 elements containing the last args
13091 with which x-show-tip was called. See there. */
13092
13093Lisp_Object last_show_tip_args;
13094
13095/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13096
13097Lisp_Object Vx_max_tooltip_size;
13098
13099
937e601e
AI
13100static Lisp_Object
13101unwind_create_tip_frame (frame)
13102 Lisp_Object frame;
13103{
c844a81a
GM
13104 Lisp_Object deleted;
13105
13106 deleted = unwind_create_frame (frame);
13107 if (EQ (deleted, Qt))
13108 {
13109 tip_window = NULL;
13110 tip_frame = Qnil;
13111 }
13112
13113 return deleted;
937e601e
AI
13114}
13115
13116
6fc2811b 13117/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13118 PARMS is a list of frame parameters. TEXT is the string to
13119 display in the tip frame. Value is the frame.
937e601e
AI
13120
13121 Note that functions called here, esp. x_default_parameter can
13122 signal errors, for instance when a specified color name is
13123 undefined. We have to make sure that we're in a consistent state
13124 when this happens. */
6fc2811b
JR
13125
13126static Lisp_Object
3cf3436e 13127x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13128 struct w32_display_info *dpyinfo;
3cf3436e 13129 Lisp_Object parms, text;
6fc2811b 13130{
6fc2811b
JR
13131 struct frame *f;
13132 Lisp_Object frame, tem;
13133 Lisp_Object name;
13134 long window_prompting = 0;
13135 int width, height;
dc220243 13136 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13137 struct gcpro gcpro1, gcpro2, gcpro3;
13138 struct kboard *kb;
3cf3436e
JR
13139 int face_change_count_before = face_change_count;
13140 Lisp_Object buffer;
13141 struct buffer *old_buffer;
6fc2811b 13142
ca56d953 13143 check_w32 ();
6fc2811b
JR
13144
13145 /* Use this general default value to start with until we know if
13146 this frame has a specified name. */
13147 Vx_resource_name = Vinvocation_name;
13148
13149#ifdef MULTI_KBOARD
13150 kb = dpyinfo->kboard;
13151#else
13152 kb = &the_only_kboard;
13153#endif
13154
13155 /* Get the name of the frame to use for resource lookup. */
13156 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13157 if (!STRINGP (name)
13158 && !EQ (name, Qunbound)
13159 && !NILP (name))
13160 error ("Invalid frame name--not a string or nil");
13161 Vx_resource_name = name;
13162
13163 frame = Qnil;
13164 GCPRO3 (parms, name, frame);
9eb16b62
JR
13165 /* Make a frame without minibuffer nor mode-line. */
13166 f = make_frame (0);
13167 f->wants_modeline = 0;
6fc2811b 13168 XSETFRAME (frame, f);
3cf3436e
JR
13169
13170 buffer = Fget_buffer_create (build_string (" *tip*"));
13171 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13172 old_buffer = current_buffer;
13173 set_buffer_internal_1 (XBUFFER (buffer));
13174 current_buffer->truncate_lines = Qnil;
13175 Ferase_buffer ();
13176 Finsert (1, &text);
13177 set_buffer_internal_1 (old_buffer);
13178
6fc2811b 13179 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13180 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13181
3cf3436e
JR
13182 /* By setting the output method, we're essentially saying that
13183 the frame is live, as per FRAME_LIVE_P. If we get a signal
13184 from this point on, x_destroy_window might screw up reference
13185 counts etc. */
d88c567c 13186 f->output_method = output_w32;
6fc2811b
JR
13187 f->output_data.w32 =
13188 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13189 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13190
13191 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13192 f->icon_name = Qnil;
13193
ca56d953 13194#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13195 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13196 dpyinfo_refcount = dpyinfo->reference_count;
13197#endif /* GLYPH_DEBUG */
6fc2811b
JR
13198#ifdef MULTI_KBOARD
13199 FRAME_KBOARD (f) = kb;
13200#endif
13201 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13202 f->output_data.w32->explicit_parent = 0;
13203
13204 /* Set the name; the functions to which we pass f expect the name to
13205 be set. */
13206 if (EQ (name, Qunbound) || NILP (name))
13207 {
ca56d953 13208 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13209 f->explicit_name = 0;
13210 }
13211 else
13212 {
13213 f->name = name;
13214 f->explicit_name = 1;
13215 /* use the frame's title when getting resources for this frame. */
13216 specbind (Qx_resource_name, name);
13217 }
13218
6fc2811b
JR
13219 /* Extract the window parameters from the supplied values
13220 that are needed to determine window geometry. */
13221 {
13222 Lisp_Object font;
13223
13224 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13225
13226 BLOCK_INPUT;
13227 /* First, try whatever font the caller has specified. */
13228 if (STRINGP (font))
13229 {
13230 tem = Fquery_fontset (font, Qnil);
13231 if (STRINGP (tem))
13232 font = x_new_fontset (f, XSTRING (tem)->data);
13233 else
13234 font = x_new_font (f, XSTRING (font)->data);
13235 }
13236
13237 /* Try out a font which we hope has bold and italic variations. */
13238 if (!STRINGP (font))
ca56d953 13239 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13240 if (! STRINGP (font))
ca56d953 13241 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13242 /* If those didn't work, look for something which will at least work. */
13243 if (! STRINGP (font))
ca56d953 13244 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13245 UNBLOCK_INPUT;
13246 if (! STRINGP (font))
ca56d953 13247 font = build_string ("Fixedsys");
6fc2811b
JR
13248
13249 x_default_parameter (f, parms, Qfont, font,
13250 "font", "Font", RES_TYPE_STRING);
13251 }
13252
13253 x_default_parameter (f, parms, Qborder_width, make_number (2),
13254 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13255 /* This defaults to 2 in order to match xterm. We recognize either
13256 internalBorderWidth or internalBorder (which is what xterm calls
13257 it). */
13258 if (NILP (Fassq (Qinternal_border_width, parms)))
13259 {
13260 Lisp_Object value;
13261
13262 value = w32_get_arg (parms, Qinternal_border_width,
13263 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13264 if (! EQ (value, Qunbound))
13265 parms = Fcons (Fcons (Qinternal_border_width, value),
13266 parms);
13267 }
bfd6edcc 13268 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13269 "internalBorderWidth", "internalBorderWidth",
13270 RES_TYPE_NUMBER);
13271
13272 /* Also do the stuff which must be set before the window exists. */
13273 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13274 "foreground", "Foreground", RES_TYPE_STRING);
13275 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13276 "background", "Background", RES_TYPE_STRING);
13277 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13278 "pointerColor", "Foreground", RES_TYPE_STRING);
13279 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13280 "cursorColor", "Foreground", RES_TYPE_STRING);
13281 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13282 "borderColor", "BorderColor", RES_TYPE_STRING);
13283
13284 /* Init faces before x_default_parameter is called for scroll-bar
13285 parameters because that function calls x_set_scroll_bar_width,
13286 which calls change_frame_size, which calls Fset_window_buffer,
13287 which runs hooks, which call Fvertical_motion. At the end, we
13288 end up in init_iterator with a null face cache, which should not
13289 happen. */
13290 init_frame_faces (f);
ca56d953
JR
13291
13292 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13293 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13294
6fc2811b
JR
13295 window_prompting = x_figure_window_size (f, parms);
13296
9eb16b62
JR
13297 /* No fringes on tip frame. */
13298 f->output_data.w32->fringes_extra = 0;
13299 f->output_data.w32->fringe_cols = 0;
13300 f->output_data.w32->left_fringe_width = 0;
13301 f->output_data.w32->right_fringe_width = 0;
13302
6fc2811b
JR
13303 if (window_prompting & XNegative)
13304 {
13305 if (window_prompting & YNegative)
13306 f->output_data.w32->win_gravity = SouthEastGravity;
13307 else
13308 f->output_data.w32->win_gravity = NorthEastGravity;
13309 }
13310 else
13311 {
13312 if (window_prompting & YNegative)
13313 f->output_data.w32->win_gravity = SouthWestGravity;
13314 else
13315 f->output_data.w32->win_gravity = NorthWestGravity;
13316 }
13317
13318 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13319
13320 BLOCK_INPUT;
13321 my_create_tip_window (f);
13322 UNBLOCK_INPUT;
6fc2811b
JR
13323
13324 x_make_gc (f);
13325
13326 x_default_parameter (f, parms, Qauto_raise, Qnil,
13327 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13328 x_default_parameter (f, parms, Qauto_lower, Qnil,
13329 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13330 x_default_parameter (f, parms, Qcursor_type, Qbox,
13331 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13332
13333 /* Dimensions, especially f->height, must be done via change_frame_size.
13334 Change will not be effected unless different from the current
13335 f->height. */
13336 width = f->width;
13337 height = f->height;
13338 f->height = 0;
13339 SET_FRAME_WIDTH (f, 0);
13340 change_frame_size (f, height, width, 1, 0, 0);
13341
3cf3436e
JR
13342 /* Set up faces after all frame parameters are known. This call
13343 also merges in face attributes specified for new frames.
13344
13345 Frame parameters may be changed if .Xdefaults contains
13346 specifications for the default font. For example, if there is an
13347 `Emacs.default.attributeBackground: pink', the `background-color'
13348 attribute of the frame get's set, which let's the internal border
13349 of the tooltip frame appear in pink. Prevent this. */
13350 {
13351 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13352
13353 /* Set tip_frame here, so that */
13354 tip_frame = frame;
13355 call1 (Qface_set_after_frame_default, frame);
13356
13357 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13358 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13359 Qnil));
13360 }
13361
6fc2811b
JR
13362 f->no_split = 1;
13363
13364 UNGCPRO;
13365
13366 /* It is now ok to make the frame official even if we get an error
13367 below. And the frame needs to be on Vframe_list or making it
13368 visible won't work. */
13369 Vframe_list = Fcons (frame, Vframe_list);
13370
13371 /* Now that the frame is official, it counts as a reference to
13372 its display. */
13373 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13374
3cf3436e
JR
13375 /* Setting attributes of faces of the tooltip frame from resources
13376 and similar will increment face_change_count, which leads to the
13377 clearing of all current matrices. Since this isn't necessary
13378 here, avoid it by resetting face_change_count to the value it
13379 had before we created the tip frame. */
13380 face_change_count = face_change_count_before;
13381
13382 /* Discard the unwind_protect. */
6fc2811b 13383 return unbind_to (count, frame);
ee78dc32
GV
13384}
13385
3cf3436e
JR
13386
13387/* Compute where to display tip frame F. PARMS is the list of frame
13388 parameters for F. DX and DY are specified offsets from the current
13389 location of the mouse. WIDTH and HEIGHT are the width and height
13390 of the tooltip. Return coordinates relative to the root window of
13391 the display in *ROOT_X, and *ROOT_Y. */
13392
13393static void
13394compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13395 struct frame *f;
13396 Lisp_Object parms, dx, dy;
13397 int width, height;
13398 int *root_x, *root_y;
13399{
3cf3436e 13400 Lisp_Object left, top;
3cf3436e
JR
13401
13402 /* User-specified position? */
13403 left = Fcdr (Fassq (Qleft, parms));
13404 top = Fcdr (Fassq (Qtop, parms));
13405
13406 /* Move the tooltip window where the mouse pointer is. Resize and
13407 show it. */
ca56d953 13408 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13409 {
ca56d953
JR
13410 POINT pt;
13411
3cf3436e 13412 BLOCK_INPUT;
ca56d953
JR
13413 GetCursorPos (&pt);
13414 *root_x = pt.x;
13415 *root_y = pt.y;
3cf3436e
JR
13416 UNBLOCK_INPUT;
13417 }
13418
13419 if (INTEGERP (top))
13420 *root_y = XINT (top);
13421 else if (*root_y + XINT (dy) - height < 0)
13422 *root_y -= XINT (dy);
13423 else
13424 {
13425 *root_y -= height;
13426 *root_y += XINT (dy);
13427 }
13428
13429 if (INTEGERP (left))
13430 *root_x = XINT (left);
bfd6edcc 13431 else if (*root_x + XINT (dx) + width > FRAME_W32_DISPLAY_INFO (f)->width)
3cf3436e
JR
13432 *root_x -= width + XINT (dx);
13433 else
13434 *root_x += XINT (dx);
3cf3436e
JR
13435}
13436
13437
71eab8d1 13438DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13439 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13440A tooltip window is a small window displaying a string.
13441
13442FRAME nil or omitted means use the selected frame.
13443
13444PARMS is an optional list of frame parameters which can be
13445used to change the tooltip's appearance.
13446
ca56d953
JR
13447Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13448means use the default timeout of 5 seconds.
74e1aeec 13449
ca56d953 13450If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13451the tooltip is displayed at that x-position. Otherwise it is
13452displayed at the mouse position, with offset DX added (default is 5 if
13453DX isn't specified). Likewise for the y-position; if a `top' frame
13454parameter is specified, it determines the y-position of the tooltip
13455window, otherwise it is displayed at the mouse position, with offset
13456DY added (default is -10).
13457
13458A tooltip's maximum size is specified by `x-max-tooltip-size'.
13459Text larger than the specified size is clipped. */)
71eab8d1
AI
13460 (string, frame, parms, timeout, dx, dy)
13461 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13462{
6fc2811b
JR
13463 struct frame *f;
13464 struct window *w;
3cf3436e 13465 int root_x, root_y;
6fc2811b
JR
13466 struct buffer *old_buffer;
13467 struct text_pos pos;
13468 int i, width, height;
6fc2811b
JR
13469 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13470 int old_windows_or_buffers_changed = windows_or_buffers_changed;
ca56d953 13471 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13472
13473 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13474
dfff8a69 13475 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13476
b7826503 13477 CHECK_STRING (string);
6fc2811b
JR
13478 f = check_x_frame (frame);
13479 if (NILP (timeout))
13480 timeout = make_number (5);
13481 else
b7826503 13482 CHECK_NATNUM (timeout);
ee78dc32 13483
71eab8d1
AI
13484 if (NILP (dx))
13485 dx = make_number (5);
13486 else
b7826503 13487 CHECK_NUMBER (dx);
71eab8d1
AI
13488
13489 if (NILP (dy))
dc220243 13490 dy = make_number (-10);
71eab8d1 13491 else
b7826503 13492 CHECK_NUMBER (dy);
71eab8d1 13493
dc220243
JR
13494 if (NILP (last_show_tip_args))
13495 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13496
13497 if (!NILP (tip_frame))
13498 {
13499 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13500 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13501 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13502
13503 if (EQ (frame, last_frame)
13504 && !NILP (Fequal (last_string, string))
13505 && !NILP (Fequal (last_parms, parms)))
13506 {
13507 struct frame *f = XFRAME (tip_frame);
13508
13509 /* Only DX and DY have changed. */
13510 if (!NILP (tip_timer))
13511 {
13512 Lisp_Object timer = tip_timer;
13513 tip_timer = Qnil;
13514 call1 (Qcancel_timer, timer);
13515 }
13516
13517 BLOCK_INPUT;
ca56d953
JR
13518 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13519 PIXEL_HEIGHT (f), &root_x, &root_y);
13520 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13521 root_x, root_y, 0, 0,
13522 SWP_NOSIZE | SWP_NOACTIVATE);
dc220243
JR
13523 UNBLOCK_INPUT;
13524 goto start_timer;
13525 }
13526 }
13527
6fc2811b
JR
13528 /* Hide a previous tip, if any. */
13529 Fx_hide_tip ();
ee78dc32 13530
dc220243
JR
13531 ASET (last_show_tip_args, 0, string);
13532 ASET (last_show_tip_args, 1, frame);
13533 ASET (last_show_tip_args, 2, parms);
13534
6fc2811b
JR
13535 /* Add default values to frame parameters. */
13536 if (NILP (Fassq (Qname, parms)))
13537 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13538 if (NILP (Fassq (Qinternal_border_width, parms)))
13539 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13540 if (NILP (Fassq (Qborder_width, parms)))
13541 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13542 if (NILP (Fassq (Qborder_color, parms)))
13543 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13544 if (NILP (Fassq (Qbackground_color, parms)))
13545 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13546 parms);
13547
0e3fcdef
JR
13548 /* Block input until the tip has been fully drawn, to avoid crashes
13549 when drawing tips in menus. */
13550 BLOCK_INPUT;
13551
6fc2811b
JR
13552 /* Create a frame for the tooltip, and record it in the global
13553 variable tip_frame. */
ca56d953 13554 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 13555 f = XFRAME (frame);
6fc2811b 13556
3cf3436e 13557 /* Set up the frame's root window. */
6fc2811b
JR
13558 w = XWINDOW (FRAME_ROOT_WINDOW (f));
13559 w->left = w->top = make_number (0);
3cf3436e
JR
13560
13561 if (CONSP (Vx_max_tooltip_size)
13562 && INTEGERP (XCAR (Vx_max_tooltip_size))
13563 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13564 && INTEGERP (XCDR (Vx_max_tooltip_size))
13565 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13566 {
13567 w->width = XCAR (Vx_max_tooltip_size);
13568 w->height = XCDR (Vx_max_tooltip_size);
13569 }
13570 else
13571 {
13572 w->width = make_number (80);
13573 w->height = make_number (40);
13574 }
13575
13576 f->window_width = XINT (w->width);
6fc2811b
JR
13577 adjust_glyphs (f);
13578 w->pseudo_window_p = 1;
13579
13580 /* Display the tooltip text in a temporary buffer. */
6fc2811b 13581 old_buffer = current_buffer;
3cf3436e
JR
13582 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13583 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
13584 clear_glyph_matrix (w->desired_matrix);
13585 clear_glyph_matrix (w->current_matrix);
13586 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13587 try_window (FRAME_ROOT_WINDOW (f), pos);
13588
13589 /* Compute width and height of the tooltip. */
13590 width = height = 0;
13591 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 13592 {
6fc2811b
JR
13593 struct glyph_row *row = &w->desired_matrix->rows[i];
13594 struct glyph *last;
13595 int row_width;
13596
13597 /* Stop at the first empty row at the end. */
13598 if (!row->enabled_p || !row->displays_text_p)
13599 break;
13600
13601 /* Let the row go over the full width of the frame. */
13602 row->full_width_p = 1;
13603
4e3a1c61
JR
13604#ifdef TODO /* Investigate why some fonts need more width than is
13605 calculated for some tooltips. */
6fc2811b
JR
13606 /* There's a glyph at the end of rows that is use to place
13607 the cursor there. Don't include the width of this glyph. */
13608 if (row->used[TEXT_AREA])
13609 {
13610 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13611 row_width = row->pixel_width - last->pixel_width;
13612 }
13613 else
4e3a1c61 13614#endif
6fc2811b
JR
13615 row_width = row->pixel_width;
13616
ca56d953 13617 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 13618 height += row->height;
6fc2811b 13619 width = max (width, row_width);
ee78dc32
GV
13620 }
13621
6fc2811b
JR
13622 /* Add the frame's internal border to the width and height the X
13623 window should have. */
13624 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13625 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 13626
6fc2811b
JR
13627 /* Move the tooltip window where the mouse pointer is. Resize and
13628 show it. */
3cf3436e 13629 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 13630
bfd6edcc
JR
13631 {
13632 /* Adjust Window size to take border into account. */
13633 RECT rect;
13634 rect.left = rect.top = 0;
13635 rect.right = width;
13636 rect.bottom = height;
13637 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
13638 FRAME_EXTERNAL_MENU_BAR (f));
13639
13640 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13641 root_x, root_y, rect.right - rect.left,
13642 rect.bottom - rect.top, SWP_NOACTIVATE);
13643
13644 /* Let redisplay know that we have made the frame visible already. */
13645 f->async_visible = 1;
13646
13647 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
13648 }
ee78dc32 13649
6fc2811b
JR
13650 /* Draw into the window. */
13651 w->must_be_updated_p = 1;
13652 update_single_window (w, 1);
ee78dc32 13653
0e3fcdef
JR
13654 UNBLOCK_INPUT;
13655
6fc2811b
JR
13656 /* Restore original current buffer. */
13657 set_buffer_internal_1 (old_buffer);
13658 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 13659
dc220243 13660 start_timer:
6fc2811b
JR
13661 /* Let the tip disappear after timeout seconds. */
13662 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13663 intern ("x-hide-tip"));
ee78dc32 13664
dfff8a69 13665 UNGCPRO;
6fc2811b 13666 return unbind_to (count, Qnil);
ee78dc32
GV
13667}
13668
ee78dc32 13669
6fc2811b 13670DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
13671 doc: /* Hide the current tooltip window, if there is any.
13672Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
13673 ()
13674{
937e601e
AI
13675 int count;
13676 Lisp_Object deleted, frame, timer;
13677 struct gcpro gcpro1, gcpro2;
13678
13679 /* Return quickly if nothing to do. */
13680 if (NILP (tip_timer) && NILP (tip_frame))
13681 return Qnil;
13682
13683 frame = tip_frame;
13684 timer = tip_timer;
13685 GCPRO2 (frame, timer);
13686 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 13687
937e601e 13688 count = BINDING_STACK_SIZE ();
6fc2811b 13689 specbind (Qinhibit_redisplay, Qt);
937e601e 13690 specbind (Qinhibit_quit, Qt);
6fc2811b 13691
937e601e 13692 if (!NILP (timer))
dc220243 13693 call1 (Qcancel_timer, timer);
ee78dc32 13694
937e601e 13695 if (FRAMEP (frame))
6fc2811b 13696 {
937e601e
AI
13697 Fdelete_frame (frame, Qnil);
13698 deleted = Qt;
6fc2811b 13699 }
1edf84e7 13700
937e601e
AI
13701 UNGCPRO;
13702 return unbind_to (count, deleted);
6fc2811b 13703}
5ac45f98 13704
5ac45f98 13705
6fc2811b
JR
13706\f
13707/***********************************************************************
13708 File selection dialog
13709 ***********************************************************************/
13710
13711extern Lisp_Object Qfile_name_history;
13712
13713DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
13714 doc: /* Read file name, prompting with PROMPT in directory DIR.
13715Use a file selection dialog.
13716Select DEFAULT-FILENAME in the dialog's file selection box, if
13717specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
13718 (prompt, dir, default_filename, mustmatch)
13719 Lisp_Object prompt, dir, default_filename, mustmatch;
13720{
13721 struct frame *f = SELECTED_FRAME ();
13722 Lisp_Object file = Qnil;
13723 int count = specpdl_ptr - specpdl;
13724 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
13725 char filename[MAX_PATH + 1];
13726 char init_dir[MAX_PATH + 1];
13727 int use_dialog_p = 1;
13728
13729 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
13730 CHECK_STRING (prompt);
13731 CHECK_STRING (dir);
6fc2811b
JR
13732
13733 /* Create the dialog with PROMPT as title, using DIR as initial
13734 directory and using "*" as pattern. */
13735 dir = Fexpand_file_name (dir, Qnil);
13736 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
13737 init_dir[MAX_PATH] = '\0';
13738 unixtodos_filename (init_dir);
13739
13740 if (STRINGP (default_filename))
13741 {
13742 char *file_name_only;
13743 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 13744
6fc2811b 13745 unixtodos_filename (full_path_name);
5ac45f98 13746
6fc2811b
JR
13747 file_name_only = strrchr (full_path_name, '\\');
13748 if (!file_name_only)
13749 file_name_only = full_path_name;
13750 else
13751 {
13752 file_name_only++;
5ac45f98 13753
6fc2811b
JR
13754 /* If default_file_name is a directory, don't use the open
13755 file dialog, as it does not support selecting
13756 directories. */
13757 if (!(*file_name_only))
13758 use_dialog_p = 0;
13759 }
ee78dc32 13760
6fc2811b
JR
13761 strncpy (filename, file_name_only, MAX_PATH);
13762 filename[MAX_PATH] = '\0';
13763 }
ee78dc32 13764 else
6fc2811b 13765 filename[0] = '\0';
ee78dc32 13766
6fc2811b
JR
13767 if (use_dialog_p)
13768 {
13769 OPENFILENAME file_details;
5ac45f98 13770
6fc2811b
JR
13771 /* Prevent redisplay. */
13772 specbind (Qinhibit_redisplay, Qt);
13773 BLOCK_INPUT;
ee78dc32 13774
6fc2811b
JR
13775 bzero (&file_details, sizeof (file_details));
13776 file_details.lStructSize = sizeof (file_details);
13777 file_details.hwndOwner = FRAME_W32_WINDOW (f);
3cf3436e
JR
13778 /* Undocumented Bug in Common File Dialog:
13779 If a filter is not specified, shell links are not resolved. */
13780 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
6fc2811b
JR
13781 file_details.lpstrFile = filename;
13782 file_details.nMaxFile = sizeof (filename);
13783 file_details.lpstrInitialDir = init_dir;
13784 file_details.lpstrTitle = XSTRING (prompt)->data;
13785 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 13786
6fc2811b
JR
13787 if (!NILP (mustmatch))
13788 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 13789
6fc2811b
JR
13790 if (GetOpenFileName (&file_details))
13791 {
13792 dostounix_filename (filename);
13793 file = build_string (filename);
13794 }
ee78dc32 13795 else
6fc2811b
JR
13796 file = Qnil;
13797
13798 UNBLOCK_INPUT;
13799 file = unbind_to (count, file);
ee78dc32 13800 }
6fc2811b
JR
13801 /* Open File dialog will not allow folders to be selected, so resort
13802 to minibuffer completing reads for directories. */
13803 else
13804 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
13805 dir, mustmatch, dir, Qfile_name_history,
13806 default_filename, Qnil);
ee78dc32 13807
6fc2811b 13808 UNGCPRO;
1edf84e7 13809
6fc2811b
JR
13810 /* Make "Cancel" equivalent to C-g. */
13811 if (NILP (file))
13812 Fsignal (Qquit, Qnil);
ee78dc32 13813
dfff8a69 13814 return unbind_to (count, file);
6fc2811b 13815}
ee78dc32 13816
ee78dc32 13817
6fc2811b 13818\f
6fc2811b
JR
13819/***********************************************************************
13820 w32 specialized functions
13821 ***********************************************************************/
ee78dc32 13822
fbd6baed 13823DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
74e1aeec
JR
13824 doc: /* Select a font using the W32 font dialog.
13825Returns an X font string corresponding to the selection. */)
ee78dc32
GV
13826 (frame)
13827 Lisp_Object frame;
13828{
13829 FRAME_PTR f = check_x_frame (frame);
13830 CHOOSEFONT cf;
13831 LOGFONT lf;
f46e6225
GV
13832 TEXTMETRIC tm;
13833 HDC hdc;
13834 HANDLE oldobj;
ee78dc32
GV
13835 char buf[100];
13836
13837 bzero (&cf, sizeof (cf));
f46e6225 13838 bzero (&lf, sizeof (lf));
ee78dc32
GV
13839
13840 cf.lStructSize = sizeof (cf);
fbd6baed 13841 cf.hwndOwner = FRAME_W32_WINDOW (f);
6fc2811b 13842 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
ee78dc32
GV
13843 cf.lpLogFont = &lf;
13844
f46e6225
GV
13845 /* Initialize as much of the font details as we can from the current
13846 default font. */
13847 hdc = GetDC (FRAME_W32_WINDOW (f));
13848 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
13849 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
13850 if (GetTextMetrics (hdc, &tm))
13851 {
13852 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
13853 lf.lfWeight = tm.tmWeight;
13854 lf.lfItalic = tm.tmItalic;
13855 lf.lfUnderline = tm.tmUnderlined;
13856 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
13857 lf.lfCharSet = tm.tmCharSet;
13858 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
13859 }
13860 SelectObject (hdc, oldobj);
6fc2811b 13861 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 13862
767b1ff0 13863 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 13864 return Qnil;
ee78dc32
GV
13865
13866 return build_string (buf);
13867}
13868
74e1aeec
JR
13869DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
13870 Sw32_send_sys_command, 1, 2, 0,
13871 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
13872Some useful values for command are 0xf030 to maximise frame (0xf020
13873to minimize), 0xf120 to restore frame to original size, and 0xf100
13874to activate the menubar for keyboard access. 0xf140 activates the
13875screen saver if defined.
13876
13877If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
13878 (command, frame)
13879 Lisp_Object command, frame;
13880{
1edf84e7
GV
13881 FRAME_PTR f = check_x_frame (frame);
13882
b7826503 13883 CHECK_NUMBER (command);
1edf84e7 13884
ce6059da 13885 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
13886
13887 return Qnil;
13888}
13889
55dcfc15 13890DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
13891 doc: /* Get Windows to perform OPERATION on DOCUMENT.
13892This is a wrapper around the ShellExecute system function, which
13893invokes the application registered to handle OPERATION for DOCUMENT.
13894OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
13895nil for the default action), and DOCUMENT is typically the name of a
13896document file or URL, but can also be a program executable to run or
13897a directory to open in the Windows Explorer.
13898
13899If DOCUMENT is a program executable, PARAMETERS can be a string
13900containing command line parameters, but otherwise should be nil.
13901
13902SHOW-FLAG can be used to control whether the invoked application is hidden
13903or minimized. If SHOW-FLAG is nil, the application is displayed normally,
13904otherwise it is an integer representing a ShowWindow flag:
13905
13906 0 - start hidden
13907 1 - start normally
13908 3 - start maximized
13909 6 - start minimized */)
55dcfc15
AI
13910 (operation, document, parameters, show_flag)
13911 Lisp_Object operation, document, parameters, show_flag;
13912{
13913 Lisp_Object current_dir;
13914
b7826503 13915 CHECK_STRING (document);
55dcfc15
AI
13916
13917 /* Encode filename and current directory. */
13918 current_dir = ENCODE_FILE (current_buffer->directory);
13919 document = ENCODE_FILE (document);
13920 if ((int) ShellExecute (NULL,
6fc2811b
JR
13921 (STRINGP (operation) ?
13922 XSTRING (operation)->data : NULL),
55dcfc15
AI
13923 XSTRING (document)->data,
13924 (STRINGP (parameters) ?
13925 XSTRING (parameters)->data : NULL),
13926 XSTRING (current_dir)->data,
13927 (INTEGERP (show_flag) ?
13928 XINT (show_flag) : SW_SHOWDEFAULT))
13929 > 32)
13930 return Qt;
90d97e64 13931 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
13932}
13933
ccc2d29c
GV
13934/* Lookup virtual keycode from string representing the name of a
13935 non-ascii keystroke into the corresponding virtual key, using
13936 lispy_function_keys. */
13937static int
13938lookup_vk_code (char *key)
13939{
13940 int i;
13941
13942 for (i = 0; i < 256; i++)
13943 if (lispy_function_keys[i] != 0
13944 && strcmp (lispy_function_keys[i], key) == 0)
13945 return i;
13946
13947 return -1;
13948}
13949
13950/* Convert a one-element vector style key sequence to a hot key
13951 definition. */
13952static int
13953w32_parse_hot_key (key)
13954 Lisp_Object key;
13955{
13956 /* Copied from Fdefine_key and store_in_keymap. */
13957 register Lisp_Object c;
13958 int vk_code;
13959 int lisp_modifiers;
13960 int w32_modifiers;
13961 struct gcpro gcpro1;
13962
b7826503 13963 CHECK_VECTOR (key);
ccc2d29c
GV
13964
13965 if (XFASTINT (Flength (key)) != 1)
13966 return Qnil;
13967
13968 GCPRO1 (key);
13969
13970 c = Faref (key, make_number (0));
13971
13972 if (CONSP (c) && lucid_event_type_list_p (c))
13973 c = Fevent_convert_list (c);
13974
13975 UNGCPRO;
13976
13977 if (! INTEGERP (c) && ! SYMBOLP (c))
13978 error ("Key definition is invalid");
13979
13980 /* Work out the base key and the modifiers. */
13981 if (SYMBOLP (c))
13982 {
13983 c = parse_modifiers (c);
13984 lisp_modifiers = Fcar (Fcdr (c));
13985 c = Fcar (c);
13986 if (!SYMBOLP (c))
13987 abort ();
13988 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
13989 }
13990 else if (INTEGERP (c))
13991 {
13992 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13993 /* Many ascii characters are their own virtual key code. */
13994 vk_code = XINT (c) & CHARACTERBITS;
13995 }
13996
13997 if (vk_code < 0 || vk_code > 255)
13998 return Qnil;
13999
14000 if ((lisp_modifiers & meta_modifier) != 0
14001 && !NILP (Vw32_alt_is_meta))
14002 lisp_modifiers |= alt_modifier;
14003
71eab8d1
AI
14004 /* Supply defs missing from mingw32. */
14005#ifndef MOD_ALT
14006#define MOD_ALT 0x0001
14007#define MOD_CONTROL 0x0002
14008#define MOD_SHIFT 0x0004
14009#define MOD_WIN 0x0008
14010#endif
14011
ccc2d29c
GV
14012 /* Convert lisp modifiers to Windows hot-key form. */
14013 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14014 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14015 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14016 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14017
14018 return HOTKEY (vk_code, w32_modifiers);
14019}
14020
74e1aeec
JR
14021DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14022 Sw32_register_hot_key, 1, 1, 0,
14023 doc: /* Register KEY as a hot-key combination.
14024Certain key combinations like Alt-Tab are reserved for system use on
14025Windows, and therefore are normally intercepted by the system. However,
14026most of these key combinations can be received by registering them as
14027hot-keys, overriding their special meaning.
14028
14029KEY must be a one element key definition in vector form that would be
14030acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14031modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14032is always interpreted as the Windows modifier keys.
14033
14034The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14035 (key)
14036 Lisp_Object key;
14037{
14038 key = w32_parse_hot_key (key);
14039
14040 if (NILP (Fmemq (key, w32_grabbed_keys)))
14041 {
14042 /* Reuse an empty slot if possible. */
14043 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14044
14045 /* Safe to add new key to list, even if we have focus. */
14046 if (NILP (item))
14047 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14048 else
f3fbd155 14049 XSETCAR (item, key);
ccc2d29c
GV
14050
14051 /* Notify input thread about new hot-key definition, so that it
14052 takes effect without needing to switch focus. */
14053 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14054 (WPARAM) key, 0);
14055 }
14056
14057 return key;
14058}
14059
74e1aeec
JR
14060DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14061 Sw32_unregister_hot_key, 1, 1, 0,
14062 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14063 (key)
14064 Lisp_Object key;
14065{
14066 Lisp_Object item;
14067
14068 if (!INTEGERP (key))
14069 key = w32_parse_hot_key (key);
14070
14071 item = Fmemq (key, w32_grabbed_keys);
14072
14073 if (!NILP (item))
14074 {
14075 /* Notify input thread about hot-key definition being removed, so
14076 that it takes effect without needing focus switch. */
14077 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14078 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14079 {
14080 MSG msg;
14081 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14082 }
14083 return Qt;
14084 }
14085 return Qnil;
14086}
14087
74e1aeec
JR
14088DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14089 Sw32_registered_hot_keys, 0, 0, 0,
14090 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14091 ()
14092{
14093 return Fcopy_sequence (w32_grabbed_keys);
14094}
14095
74e1aeec
JR
14096DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14097 Sw32_reconstruct_hot_key, 1, 1, 0,
14098 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14099 (hotkeyid)
14100 Lisp_Object hotkeyid;
14101{
14102 int vk_code, w32_modifiers;
14103 Lisp_Object key;
14104
b7826503 14105 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14106
14107 vk_code = HOTKEY_VK_CODE (hotkeyid);
14108 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14109
14110 if (lispy_function_keys[vk_code])
14111 key = intern (lispy_function_keys[vk_code]);
14112 else
14113 key = make_number (vk_code);
14114
14115 key = Fcons (key, Qnil);
14116 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14117 key = Fcons (Qshift, key);
ccc2d29c 14118 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14119 key = Fcons (Qctrl, key);
ccc2d29c 14120 if (w32_modifiers & MOD_ALT)
3ef68e6b 14121 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14122 if (w32_modifiers & MOD_WIN)
3ef68e6b 14123 key = Fcons (Qhyper, key);
ccc2d29c
GV
14124
14125 return key;
14126}
adcc3809 14127
74e1aeec
JR
14128DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14129 Sw32_toggle_lock_key, 1, 2, 0,
14130 doc: /* Toggle the state of the lock key KEY.
14131KEY can be `capslock', `kp-numlock', or `scroll'.
14132If the optional parameter NEW-STATE is a number, then the state of KEY
14133is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14134 (key, new_state)
14135 Lisp_Object key, new_state;
14136{
14137 int vk_code;
adcc3809
GV
14138
14139 if (EQ (key, intern ("capslock")))
14140 vk_code = VK_CAPITAL;
14141 else if (EQ (key, intern ("kp-numlock")))
14142 vk_code = VK_NUMLOCK;
14143 else if (EQ (key, intern ("scroll")))
14144 vk_code = VK_SCROLL;
14145 else
14146 return Qnil;
14147
14148 if (!dwWindowsThreadId)
14149 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14150
14151 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14152 (WPARAM) vk_code, (LPARAM) new_state))
14153 {
14154 MSG msg;
14155 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14156 return make_number (msg.wParam);
14157 }
14158 return Qnil;
14159}
ee78dc32 14160\f
2254bcde 14161DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14162 doc: /* Return storage information about the file system FILENAME is on.
14163Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14164storage of the file system, FREE is the free storage, and AVAIL is the
14165storage available to a non-superuser. All 3 numbers are in bytes.
14166If the underlying system call fails, value is nil. */)
2254bcde
AI
14167 (filename)
14168 Lisp_Object filename;
14169{
14170 Lisp_Object encoded, value;
14171
b7826503 14172 CHECK_STRING (filename);
2254bcde
AI
14173 filename = Fexpand_file_name (filename, Qnil);
14174 encoded = ENCODE_FILE (filename);
14175
14176 value = Qnil;
14177
14178 /* Determining the required information on Windows turns out, sadly,
14179 to be more involved than one would hope. The original Win32 api
14180 call for this will return bogus information on some systems, but we
14181 must dynamically probe for the replacement api, since that was
14182 added rather late on. */
14183 {
14184 HMODULE hKernel = GetModuleHandle ("kernel32");
14185 BOOL (*pfn_GetDiskFreeSpaceEx)
14186 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14187 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14188
14189 /* On Windows, we may need to specify the root directory of the
14190 volume holding FILENAME. */
14191 char rootname[MAX_PATH];
14192 char *name = XSTRING (encoded)->data;
14193
14194 /* find the root name of the volume if given */
14195 if (isalpha (name[0]) && name[1] == ':')
14196 {
14197 rootname[0] = name[0];
14198 rootname[1] = name[1];
14199 rootname[2] = '\\';
14200 rootname[3] = 0;
14201 }
14202 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14203 {
14204 char *str = rootname;
14205 int slashes = 4;
14206 do
14207 {
14208 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14209 break;
14210 *str++ = *name++;
14211 }
14212 while ( *name );
14213
14214 *str++ = '\\';
14215 *str = 0;
14216 }
14217
14218 if (pfn_GetDiskFreeSpaceEx)
14219 {
14220 LARGE_INTEGER availbytes;
14221 LARGE_INTEGER freebytes;
14222 LARGE_INTEGER totalbytes;
14223
14224 if (pfn_GetDiskFreeSpaceEx(rootname,
14225 &availbytes,
14226 &totalbytes,
14227 &freebytes))
14228 value = list3 (make_float ((double) totalbytes.QuadPart),
14229 make_float ((double) freebytes.QuadPart),
14230 make_float ((double) availbytes.QuadPart));
14231 }
14232 else
14233 {
14234 DWORD sectors_per_cluster;
14235 DWORD bytes_per_sector;
14236 DWORD free_clusters;
14237 DWORD total_clusters;
14238
14239 if (GetDiskFreeSpace(rootname,
14240 &sectors_per_cluster,
14241 &bytes_per_sector,
14242 &free_clusters,
14243 &total_clusters))
14244 value = list3 (make_float ((double) total_clusters
14245 * sectors_per_cluster * bytes_per_sector),
14246 make_float ((double) free_clusters
14247 * sectors_per_cluster * bytes_per_sector),
14248 make_float ((double) free_clusters
14249 * sectors_per_cluster * bytes_per_sector));
14250 }
14251 }
14252
14253 return value;
14254}
14255\f
0e3fcdef
JR
14256/***********************************************************************
14257 Initialization
14258 ***********************************************************************/
14259
14260void
fbd6baed 14261syms_of_w32fns ()
ee78dc32 14262{
9eb16b62
JR
14263 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14264
1edf84e7
GV
14265 /* This is zero if not using MS-Windows. */
14266 w32_in_use = 0;
14267
9eb16b62
JR
14268 /* TrackMouseEvent not available in all versions of Windows, so must load
14269 it dynamically. Do it once, here, instead of every time it is used. */
14270 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14271 track_mouse_window = NULL;
14272
ee78dc32
GV
14273 /* The section below is built by the lisp expression at the top of the file,
14274 just above where these variables are declared. */
14275 /*&&& init symbols here &&&*/
14276 Qauto_raise = intern ("auto-raise");
14277 staticpro (&Qauto_raise);
14278 Qauto_lower = intern ("auto-lower");
14279 staticpro (&Qauto_lower);
ee78dc32
GV
14280 Qbar = intern ("bar");
14281 staticpro (&Qbar);
14282 Qborder_color = intern ("border-color");
14283 staticpro (&Qborder_color);
14284 Qborder_width = intern ("border-width");
14285 staticpro (&Qborder_width);
14286 Qbox = intern ("box");
14287 staticpro (&Qbox);
14288 Qcursor_color = intern ("cursor-color");
14289 staticpro (&Qcursor_color);
14290 Qcursor_type = intern ("cursor-type");
14291 staticpro (&Qcursor_type);
ee78dc32
GV
14292 Qgeometry = intern ("geometry");
14293 staticpro (&Qgeometry);
14294 Qicon_left = intern ("icon-left");
14295 staticpro (&Qicon_left);
14296 Qicon_top = intern ("icon-top");
14297 staticpro (&Qicon_top);
14298 Qicon_type = intern ("icon-type");
14299 staticpro (&Qicon_type);
14300 Qicon_name = intern ("icon-name");
14301 staticpro (&Qicon_name);
14302 Qinternal_border_width = intern ("internal-border-width");
14303 staticpro (&Qinternal_border_width);
14304 Qleft = intern ("left");
14305 staticpro (&Qleft);
1026b400
RS
14306 Qright = intern ("right");
14307 staticpro (&Qright);
ee78dc32
GV
14308 Qmouse_color = intern ("mouse-color");
14309 staticpro (&Qmouse_color);
14310 Qnone = intern ("none");
14311 staticpro (&Qnone);
14312 Qparent_id = intern ("parent-id");
14313 staticpro (&Qparent_id);
14314 Qscroll_bar_width = intern ("scroll-bar-width");
14315 staticpro (&Qscroll_bar_width);
14316 Qsuppress_icon = intern ("suppress-icon");
14317 staticpro (&Qsuppress_icon);
ee78dc32
GV
14318 Qundefined_color = intern ("undefined-color");
14319 staticpro (&Qundefined_color);
14320 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14321 staticpro (&Qvertical_scroll_bars);
14322 Qvisibility = intern ("visibility");
14323 staticpro (&Qvisibility);
14324 Qwindow_id = intern ("window-id");
14325 staticpro (&Qwindow_id);
14326 Qx_frame_parameter = intern ("x-frame-parameter");
14327 staticpro (&Qx_frame_parameter);
14328 Qx_resource_name = intern ("x-resource-name");
14329 staticpro (&Qx_resource_name);
14330 Quser_position = intern ("user-position");
14331 staticpro (&Quser_position);
14332 Quser_size = intern ("user-size");
14333 staticpro (&Quser_size);
6fc2811b
JR
14334 Qscreen_gamma = intern ("screen-gamma");
14335 staticpro (&Qscreen_gamma);
dfff8a69
JR
14336 Qline_spacing = intern ("line-spacing");
14337 staticpro (&Qline_spacing);
14338 Qcenter = intern ("center");
14339 staticpro (&Qcenter);
dc220243
JR
14340 Qcancel_timer = intern ("cancel-timer");
14341 staticpro (&Qcancel_timer);
ee78dc32
GV
14342 /* This is the end of symbol initialization. */
14343
adcc3809
GV
14344 Qhyper = intern ("hyper");
14345 staticpro (&Qhyper);
14346 Qsuper = intern ("super");
14347 staticpro (&Qsuper);
14348 Qmeta = intern ("meta");
14349 staticpro (&Qmeta);
14350 Qalt = intern ("alt");
14351 staticpro (&Qalt);
14352 Qctrl = intern ("ctrl");
14353 staticpro (&Qctrl);
14354 Qcontrol = intern ("control");
14355 staticpro (&Qcontrol);
14356 Qshift = intern ("shift");
14357 staticpro (&Qshift);
14358
6fc2811b
JR
14359 /* Text property `display' should be nonsticky by default. */
14360 Vtext_property_default_nonsticky
14361 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14362
14363
14364 Qlaplace = intern ("laplace");
14365 staticpro (&Qlaplace);
3cf3436e
JR
14366 Qemboss = intern ("emboss");
14367 staticpro (&Qemboss);
14368 Qedge_detection = intern ("edge-detection");
14369 staticpro (&Qedge_detection);
14370 Qheuristic = intern ("heuristic");
14371 staticpro (&Qheuristic);
14372 QCmatrix = intern (":matrix");
14373 staticpro (&QCmatrix);
14374 QCcolor_adjustment = intern (":color-adjustment");
14375 staticpro (&QCcolor_adjustment);
14376 QCmask = intern (":mask");
14377 staticpro (&QCmask);
6fc2811b 14378
4b817373
RS
14379 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14380 staticpro (&Qface_set_after_frame_default);
14381
ee78dc32
GV
14382 Fput (Qundefined_color, Qerror_conditions,
14383 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14384 Fput (Qundefined_color, Qerror_message,
14385 build_string ("Undefined color"));
14386
ccc2d29c
GV
14387 staticpro (&w32_grabbed_keys);
14388 w32_grabbed_keys = Qnil;
14389
fbd6baed 14390 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14391 doc: /* An array of color name mappings for windows. */);
fbd6baed 14392 Vw32_color_map = Qnil;
ee78dc32 14393
fbd6baed 14394 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14395 doc: /* Non-nil if alt key presses are passed on to Windows.
14396When non-nil, for example, alt pressed and released and then space will
14397open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14398 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14399
fbd6baed 14400 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14401 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14402When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14403 Vw32_alt_is_meta = Qt;
8c205c63 14404
7d081355 14405 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14406 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14407 XSETINT (Vw32_quit_key, 0);
14408
ccc2d29c
GV
14409 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14410 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14411 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14412When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14413 Vw32_pass_lwindow_to_system = Qt;
14414
14415 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14416 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14417 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14418When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14419 Vw32_pass_rwindow_to_system = Qt;
14420
adcc3809
GV
14421 DEFVAR_INT ("w32-phantom-key-code",
14422 &Vw32_phantom_key_code,
74e1aeec
JR
14423 doc: /* Virtual key code used to generate \"phantom\" key presses.
14424Value is a number between 0 and 255.
14425
14426Phantom key presses are generated in order to stop the system from
14427acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14428`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14429 /* Although 255 is technically not a valid key code, it works and
14430 means that this hack won't interfere with any real key code. */
14431 Vw32_phantom_key_code = 255;
adcc3809 14432
ccc2d29c
GV
14433 DEFVAR_LISP ("w32-enable-num-lock",
14434 &Vw32_enable_num_lock,
74e1aeec
JR
14435 doc: /* Non-nil if Num Lock should act normally.
14436Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14437 Vw32_enable_num_lock = Qt;
14438
14439 DEFVAR_LISP ("w32-enable-caps-lock",
14440 &Vw32_enable_caps_lock,
74e1aeec
JR
14441 doc: /* Non-nil if Caps Lock should act normally.
14442Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14443 Vw32_enable_caps_lock = Qt;
14444
14445 DEFVAR_LISP ("w32-scroll-lock-modifier",
14446 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14447 doc: /* Modifier to use for the Scroll Lock on state.
14448The value can be hyper, super, meta, alt, control or shift for the
14449respective modifier, or nil to see Scroll Lock as the key `scroll'.
14450Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14451 Vw32_scroll_lock_modifier = Qt;
14452
14453 DEFVAR_LISP ("w32-lwindow-modifier",
14454 &Vw32_lwindow_modifier,
74e1aeec
JR
14455 doc: /* Modifier to use for the left \"Windows\" key.
14456The value can be hyper, super, meta, alt, control or shift for the
14457respective modifier, or nil to appear as the key `lwindow'.
14458Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14459 Vw32_lwindow_modifier = Qnil;
14460
14461 DEFVAR_LISP ("w32-rwindow-modifier",
14462 &Vw32_rwindow_modifier,
74e1aeec
JR
14463 doc: /* Modifier to use for the right \"Windows\" key.
14464The value can be hyper, super, meta, alt, control or shift for the
14465respective modifier, or nil to appear as the key `rwindow'.
14466Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14467 Vw32_rwindow_modifier = Qnil;
14468
14469 DEFVAR_LISP ("w32-apps-modifier",
14470 &Vw32_apps_modifier,
74e1aeec
JR
14471 doc: /* Modifier to use for the \"Apps\" key.
14472The value can be hyper, super, meta, alt, control or shift for the
14473respective modifier, or nil to appear as the key `apps'.
14474Any other value will cause the key to be ignored. */);
ccc2d29c 14475 Vw32_apps_modifier = Qnil;
da36a4d6 14476
212da13b 14477 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
74e1aeec 14478 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
6fc2811b 14479 Vw32_enable_synthesized_fonts = Qnil;
5ac45f98 14480
fbd6baed 14481 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 14482 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 14483 Vw32_enable_palette = Qt;
5ac45f98 14484
fbd6baed
GV
14485 DEFVAR_INT ("w32-mouse-button-tolerance",
14486 &Vw32_mouse_button_tolerance,
74e1aeec
JR
14487 doc: /* Analogue of double click interval for faking middle mouse events.
14488The value is the minimum time in milliseconds that must elapse between
14489left/right button down events before they are considered distinct events.
14490If both mouse buttons are depressed within this interval, a middle mouse
14491button down event is generated instead. */);
fbd6baed 14492 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 14493
fbd6baed
GV
14494 DEFVAR_INT ("w32-mouse-move-interval",
14495 &Vw32_mouse_move_interval,
74e1aeec
JR
14496 doc: /* Minimum interval between mouse move events.
14497The value is the minimum time in milliseconds that must elapse between
14498successive mouse move (or scroll bar drag) events before they are
14499reported as lisp events. */);
247be837 14500 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 14501
ee78dc32
GV
14502 init_x_parm_symbols ();
14503
14504 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 14505 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
14506 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14507
14508 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
14509 doc: /* The shape of the pointer when over text.
14510Changing the value does not affect existing frames
14511unless you set the mouse color. */);
ee78dc32
GV
14512 Vx_pointer_shape = Qnil;
14513
14514 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
14515 doc: /* The name Emacs uses to look up resources; for internal use only.
14516`x-get-resource' uses this as the first component of the instance name
14517when requesting resource values.
14518Emacs initially sets `x-resource-name' to the name under which Emacs
14519was invoked, or to the value specified with the `-name' or `-rn'
14520switches, if present. */);
ee78dc32
GV
14521 Vx_resource_name = Qnil;
14522
14523 Vx_nontext_pointer_shape = Qnil;
14524
14525 Vx_mode_pointer_shape = Qnil;
14526
0af913d7 14527 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
14528 doc: /* The shape of the pointer when Emacs is busy.
14529This variable takes effect when you create a new frame
14530or when you set the mouse color. */);
0af913d7 14531 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 14532
0af913d7 14533 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 14534 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 14535 display_hourglass_p = 1;
6fc2811b 14536
0af913d7 14537 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
14538 doc: /* *Seconds to wait before displaying an hourglass pointer.
14539Value must be an integer or float. */);
0af913d7 14540 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 14541
6fc2811b 14542 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 14543 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
14544 doc: /* The shape of the pointer when over mouse-sensitive text.
14545This variable takes effect when you create a new frame
14546or when you set the mouse color. */);
ee78dc32
GV
14547 Vx_sensitive_text_pointer_shape = Qnil;
14548
4694d762
JR
14549 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14550 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
14551 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14552This variable takes effect when you create a new frame
14553or when you set the mouse color. */);
4694d762
JR
14554 Vx_window_horizontal_drag_shape = Qnil;
14555
ee78dc32 14556 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 14557 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
14558 Vx_cursor_fore_pixel = Qnil;
14559
3cf3436e 14560 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
14561 doc: /* Maximum size for tooltips.
14562Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
14563 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
14564
ee78dc32 14565 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
14566 doc: /* Non-nil if no window manager is in use.
14567Emacs doesn't try to figure this out; this is always nil
14568unless you set it to something else. */);
ee78dc32
GV
14569 /* We don't have any way to find this out, so set it to nil
14570 and maybe the user would like to set it to t. */
14571 Vx_no_window_manager = Qnil;
14572
4587b026
GV
14573 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14574 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
14575 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14576
14577Since Emacs gets width of a font matching with this regexp from
14578PIXEL_SIZE field of the name, font finding mechanism gets faster for
14579such a font. This is especially effective for such large fonts as
14580Chinese, Japanese, and Korean. */);
4587b026
GV
14581 Vx_pixel_size_width_font_regexp = Qnil;
14582
6fc2811b 14583 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
14584 doc: /* Time after which cached images are removed from the cache.
14585When an image has not been displayed this many seconds, remove it
14586from the image cache. Value must be an integer or nil with nil
14587meaning don't clear the cache. */);
6fc2811b
JR
14588 Vimage_cache_eviction_delay = make_number (30 * 60);
14589
33d52f9c
GV
14590 DEFVAR_LISP ("w32-bdf-filename-alist",
14591 &Vw32_bdf_filename_alist,
74e1aeec 14592 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
14593 Vw32_bdf_filename_alist = Qnil;
14594
1075afa9
GV
14595 DEFVAR_BOOL ("w32-strict-fontnames",
14596 &w32_strict_fontnames,
74e1aeec
JR
14597 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14598Default is nil, which allows old fontnames that are not XLFD compliant,
14599and allows third-party CJK display to work by specifying false charset
14600fields to trick Emacs into translating to Big5, SJIS etc.
14601Setting this to t will prevent wrong fonts being selected when
14602fontsets are automatically created. */);
1075afa9
GV
14603 w32_strict_fontnames = 0;
14604
c0611964
AI
14605 DEFVAR_BOOL ("w32-strict-painting",
14606 &w32_strict_painting,
74e1aeec
JR
14607 doc: /* Non-nil means use strict rules for repainting frames.
14608Set this to nil to get the old behaviour for repainting; this should
14609only be necessary if the default setting causes problems. */);
c0611964
AI
14610 w32_strict_painting = 1;
14611
dfff8a69
JR
14612 DEFVAR_LISP ("w32-charset-info-alist",
14613 &Vw32_charset_info_alist,
b3700ae7
JR
14614 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14615Each entry should be of the form:
74e1aeec
JR
14616
14617 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14618
14619where CHARSET_NAME is a string used in font names to identify the charset,
14620WINDOWS_CHARSET is a symbol that can be one of:
14621w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14622w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14623w32-charset-chinesebig5,
dfff8a69 14624#ifdef JOHAB_CHARSET
74e1aeec
JR
14625w32-charset-johab, w32-charset-hebrew,
14626w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14627w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14628w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
14629#endif
14630#ifdef UNICODE_CHARSET
74e1aeec 14631w32-charset-unicode,
dfff8a69 14632#endif
74e1aeec
JR
14633or w32-charset-oem.
14634CODEPAGE should be an integer specifying the codepage that should be used
14635to display the character set, t to do no translation and output as Unicode,
14636or nil to do no translation and output as 8 bit (or multibyte on far-east
14637versions of Windows) characters. */);
dfff8a69
JR
14638 Vw32_charset_info_alist = Qnil;
14639
14640 staticpro (&Qw32_charset_ansi);
14641 Qw32_charset_ansi = intern ("w32-charset-ansi");
14642 staticpro (&Qw32_charset_symbol);
14643 Qw32_charset_symbol = intern ("w32-charset-symbol");
14644 staticpro (&Qw32_charset_shiftjis);
14645 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
14646 staticpro (&Qw32_charset_hangeul);
14647 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
14648 staticpro (&Qw32_charset_chinesebig5);
14649 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
14650 staticpro (&Qw32_charset_gb2312);
14651 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
14652 staticpro (&Qw32_charset_oem);
14653 Qw32_charset_oem = intern ("w32-charset-oem");
14654
14655#ifdef JOHAB_CHARSET
14656 {
14657 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
14658 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
14659 doc: /* Internal variable. */);
dfff8a69
JR
14660
14661 staticpro (&Qw32_charset_johab);
14662 Qw32_charset_johab = intern ("w32-charset-johab");
14663 staticpro (&Qw32_charset_easteurope);
14664 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
14665 staticpro (&Qw32_charset_turkish);
14666 Qw32_charset_turkish = intern ("w32-charset-turkish");
14667 staticpro (&Qw32_charset_baltic);
14668 Qw32_charset_baltic = intern ("w32-charset-baltic");
14669 staticpro (&Qw32_charset_russian);
14670 Qw32_charset_russian = intern ("w32-charset-russian");
14671 staticpro (&Qw32_charset_arabic);
14672 Qw32_charset_arabic = intern ("w32-charset-arabic");
14673 staticpro (&Qw32_charset_greek);
14674 Qw32_charset_greek = intern ("w32-charset-greek");
14675 staticpro (&Qw32_charset_hebrew);
14676 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
14677 staticpro (&Qw32_charset_vietnamese);
14678 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
14679 staticpro (&Qw32_charset_thai);
14680 Qw32_charset_thai = intern ("w32-charset-thai");
14681 staticpro (&Qw32_charset_mac);
14682 Qw32_charset_mac = intern ("w32-charset-mac");
14683 }
14684#endif
14685
14686#ifdef UNICODE_CHARSET
14687 {
14688 static int w32_unicode_charset_defined = 1;
14689 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
14690 &w32_unicode_charset_defined,
14691 doc: /* Internal variable. */);
dfff8a69
JR
14692
14693 staticpro (&Qw32_charset_unicode);
14694 Qw32_charset_unicode = intern ("w32-charset-unicode");
14695#endif
14696
ee78dc32 14697 defsubr (&Sx_get_resource);
767b1ff0 14698#if 0 /* TODO: Port to W32 */
6fc2811b
JR
14699 defsubr (&Sx_change_window_property);
14700 defsubr (&Sx_delete_window_property);
14701 defsubr (&Sx_window_property);
14702#endif
2d764c78 14703 defsubr (&Sxw_display_color_p);
ee78dc32 14704 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
14705 defsubr (&Sxw_color_defined_p);
14706 defsubr (&Sxw_color_values);
ee78dc32
GV
14707 defsubr (&Sx_server_max_request_size);
14708 defsubr (&Sx_server_vendor);
14709 defsubr (&Sx_server_version);
14710 defsubr (&Sx_display_pixel_width);
14711 defsubr (&Sx_display_pixel_height);
14712 defsubr (&Sx_display_mm_width);
14713 defsubr (&Sx_display_mm_height);
14714 defsubr (&Sx_display_screens);
14715 defsubr (&Sx_display_planes);
14716 defsubr (&Sx_display_color_cells);
14717 defsubr (&Sx_display_visual_class);
14718 defsubr (&Sx_display_backing_store);
14719 defsubr (&Sx_display_save_under);
14720 defsubr (&Sx_parse_geometry);
14721 defsubr (&Sx_create_frame);
ee78dc32
GV
14722 defsubr (&Sx_open_connection);
14723 defsubr (&Sx_close_connection);
14724 defsubr (&Sx_display_list);
14725 defsubr (&Sx_synchronize);
14726
fbd6baed 14727 /* W32 specific functions */
ee78dc32 14728
1edf84e7 14729 defsubr (&Sw32_focus_frame);
fbd6baed
GV
14730 defsubr (&Sw32_select_font);
14731 defsubr (&Sw32_define_rgb_color);
14732 defsubr (&Sw32_default_color_map);
14733 defsubr (&Sw32_load_color_file);
1edf84e7 14734 defsubr (&Sw32_send_sys_command);
55dcfc15 14735 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
14736 defsubr (&Sw32_register_hot_key);
14737 defsubr (&Sw32_unregister_hot_key);
14738 defsubr (&Sw32_registered_hot_keys);
14739 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 14740 defsubr (&Sw32_toggle_lock_key);
33d52f9c 14741 defsubr (&Sw32_find_bdf_fonts);
4587b026 14742
2254bcde
AI
14743 defsubr (&Sfile_system_info);
14744
4587b026
GV
14745 /* Setting callback functions for fontset handler. */
14746 get_font_info_func = w32_get_font_info;
6fc2811b
JR
14747
14748#if 0 /* This function pointer doesn't seem to be used anywhere.
14749 And the pointer assigned has the wrong type, anyway. */
4587b026 14750 list_fonts_func = w32_list_fonts;
6fc2811b
JR
14751#endif
14752
4587b026
GV
14753 load_font_func = w32_load_font;
14754 find_ccl_program_func = w32_find_ccl_program;
14755 query_font_func = w32_query_font;
14756 set_frame_fontset_func = x_set_font;
14757 check_window_system_func = check_w32;
6fc2811b 14758
767b1ff0 14759#if 0 /* TODO Image support for W32 */
6fc2811b
JR
14760 /* Images. */
14761 Qxbm = intern ("xbm");
14762 staticpro (&Qxbm);
14763 QCtype = intern (":type");
14764 staticpro (&QCtype);
a93f4566
GM
14765 QCconversion = intern (":conversion");
14766 staticpro (&QCconversion);
6fc2811b
JR
14767 QCheuristic_mask = intern (":heuristic-mask");
14768 staticpro (&QCheuristic_mask);
14769 QCcolor_symbols = intern (":color-symbols");
14770 staticpro (&QCcolor_symbols);
6fc2811b
JR
14771 QCascent = intern (":ascent");
14772 staticpro (&QCascent);
14773 QCmargin = intern (":margin");
14774 staticpro (&QCmargin);
14775 QCrelief = intern (":relief");
14776 staticpro (&QCrelief);
14777 Qpostscript = intern ("postscript");
14778 staticpro (&Qpostscript);
14779 QCloader = intern (":loader");
14780 staticpro (&QCloader);
14781 QCbounding_box = intern (":bounding-box");
14782 staticpro (&QCbounding_box);
14783 QCpt_width = intern (":pt-width");
14784 staticpro (&QCpt_width);
14785 QCpt_height = intern (":pt-height");
14786 staticpro (&QCpt_height);
14787 QCindex = intern (":index");
14788 staticpro (&QCindex);
14789 Qpbm = intern ("pbm");
14790 staticpro (&Qpbm);
14791
14792#if HAVE_XPM
14793 Qxpm = intern ("xpm");
14794 staticpro (&Qxpm);
14795#endif
14796
14797#if HAVE_JPEG
14798 Qjpeg = intern ("jpeg");
14799 staticpro (&Qjpeg);
14800#endif
14801
14802#if HAVE_TIFF
14803 Qtiff = intern ("tiff");
14804 staticpro (&Qtiff);
14805#endif
14806
14807#if HAVE_GIF
14808 Qgif = intern ("gif");
14809 staticpro (&Qgif);
14810#endif
14811
14812#if HAVE_PNG
14813 Qpng = intern ("png");
14814 staticpro (&Qpng);
14815#endif
14816
14817 defsubr (&Sclear_image_cache);
14818
14819#if GLYPH_DEBUG
14820 defsubr (&Simagep);
14821 defsubr (&Slookup_image);
14822#endif
767b1ff0 14823#endif /* TODO */
6fc2811b 14824
0af913d7
GM
14825 hourglass_atimer = NULL;
14826 hourglass_shown_p = 0;
6fc2811b
JR
14827 defsubr (&Sx_show_tip);
14828 defsubr (&Sx_hide_tip);
6fc2811b 14829 tip_timer = Qnil;
57fa2774
JR
14830 staticpro (&tip_timer);
14831 tip_frame = Qnil;
14832 staticpro (&tip_frame);
6fc2811b 14833
ca56d953
JR
14834 last_show_tip_args = Qnil;
14835 staticpro (&last_show_tip_args);
14836
6fc2811b
JR
14837 defsubr (&Sx_file_dialog);
14838}
14839
14840
14841void
14842init_xfns ()
14843{
14844 image_types = NULL;
14845 Vimage_types = Qnil;
14846
767b1ff0 14847#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
14848 define_image_type (&xbm_type);
14849 define_image_type (&gs_type);
14850 define_image_type (&pbm_type);
14851
14852#if HAVE_XPM
14853 define_image_type (&xpm_type);
14854#endif
14855
14856#if HAVE_JPEG
14857 define_image_type (&jpeg_type);
14858#endif
14859
14860#if HAVE_TIFF
14861 define_image_type (&tiff_type);
14862#endif
14863
14864#if HAVE_GIF
14865 define_image_type (&gif_type);
14866#endif
14867
14868#if HAVE_PNG
14869 define_image_type (&png_type);
14870#endif
767b1ff0 14871#endif /* TODO */
ee78dc32
GV
14872}
14873
14874#undef abort
14875
14876void
fbd6baed 14877w32_abort()
ee78dc32 14878{
5ac45f98
GV
14879 int button;
14880 button = MessageBox (NULL,
14881 "A fatal error has occurred!\n\n"
14882 "Select Abort to exit, Retry to debug, Ignore to continue",
14883 "Emacs Abort Dialog",
14884 MB_ICONEXCLAMATION | MB_TASKMODAL
14885 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
14886 switch (button)
14887 {
14888 case IDRETRY:
14889 DebugBreak ();
14890 break;
14891 case IDIGNORE:
14892 break;
14893 case IDABORT:
14894 default:
14895 abort ();
14896 break;
14897 }
ee78dc32 14898}
d573caac 14899
83c75055
GV
14900/* For convenience when debugging. */
14901int
14902w32_last_error()
14903{
14904 return GetLastError ();
14905}