(bdf-read-font-info): Modify the kludgy code for fonts
[bpt/emacs.git] / src / w32fns.c
CommitLineData
e9e23e23 1/* Graphical user interface functions for the Microsoft W32 API.
6fc2811b
JR
2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999
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
GV
34#include "w32term.h"
35#include "frame.h"
36#include "window.h"
37#include "buffer.h"
126f2e35 38#include "fontset.h"
6fc2811b 39#include "intervals.h"
ee78dc32
GV
40#include "keyboard.h"
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
71eab8d1
AI
55#define max(a, b) ((a) > (b) ? (a) : (b))
56
ee78dc32 57extern void free_frame_menubar ();
6fc2811b 58extern double atof ();
adcc3809 59extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
5ac45f98 60extern int quit_char;
ee78dc32 61
6fc2811b
JR
62/* A definition of XColor for non-X frames. */
63#ifndef HAVE_X_WINDOWS
64typedef struct {
65 unsigned long pixel;
66 unsigned short red, green, blue;
67 char flags;
68 char pad;
69} XColor;
70#endif
71
ccc2d29c
GV
72extern char *lispy_function_keys[];
73
6fc2811b
JR
74/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
75 it, and including `bitmaps/gray' more than once is a problem when
76 config.h defines `static' as an empty replacement string. */
77
78int gray_bitmap_width = gray_width;
79int gray_bitmap_height = gray_height;
80unsigned char *gray_bitmap_bits = gray_bits;
81
ee78dc32 82/* The colormap for converting color names to RGB values */
fbd6baed 83Lisp_Object Vw32_color_map;
ee78dc32 84
da36a4d6 85/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 86Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 87
8c205c63
RS
88/* Non nil if alt key is translated to meta_modifier, nil if it is translated
89 to alt_modifier. */
fbd6baed 90Lisp_Object Vw32_alt_is_meta;
8c205c63 91
7d081355
AI
92/* If non-zero, the windows virtual key code for an alternative quit key. */
93Lisp_Object Vw32_quit_key;
94
ccc2d29c
GV
95/* Non nil if left window key events are passed on to Windows (this only
96 affects whether "tapping" the key opens the Start menu). */
97Lisp_Object Vw32_pass_lwindow_to_system;
98
99/* Non nil if right window key events are passed on to Windows (this
100 only affects whether "tapping" the key opens the Start menu). */
101Lisp_Object Vw32_pass_rwindow_to_system;
102
adcc3809
GV
103/* Virtual key code used to generate "phantom" key presses in order
104 to stop system from acting on Windows key events. */
105Lisp_Object Vw32_phantom_key_code;
106
ccc2d29c
GV
107/* Modifier associated with the left "Windows" key, or nil to act as a
108 normal key. */
109Lisp_Object Vw32_lwindow_modifier;
110
111/* Modifier associated with the right "Windows" key, or nil to act as a
112 normal key. */
113Lisp_Object Vw32_rwindow_modifier;
114
115/* Modifier associated with the "Apps" key, or nil to act as a normal
116 key. */
117Lisp_Object Vw32_apps_modifier;
118
119/* Value is nil if Num Lock acts as a function key. */
120Lisp_Object Vw32_enable_num_lock;
121
122/* Value is nil if Caps Lock acts as a function key. */
123Lisp_Object Vw32_enable_caps_lock;
124
125/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
126Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 127
7ce9aaca 128/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b
JR
129 and italic versions of fonts. */
130Lisp_Object Vw32_enable_synthesized_fonts;
5ac45f98
GV
131
132/* Enable palette management. */
fbd6baed 133Lisp_Object Vw32_enable_palette;
5ac45f98
GV
134
135/* Control how close left/right button down events must be to
136 be converted to a middle button down event. */
fbd6baed 137Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 138
84fb1139
KH
139/* Minimum interval between mouse movement (and scroll bar drag)
140 events that are passed on to the event loop. */
fbd6baed 141Lisp_Object Vw32_mouse_move_interval;
84fb1139 142
ee78dc32
GV
143/* The name we're using in resource queries. */
144Lisp_Object Vx_resource_name;
145
146/* Non nil if no window manager is in use. */
147Lisp_Object Vx_no_window_manager;
148
6fc2811b 149/* Non-zero means we're allowed to display a busy cursor. */
dfff8a69 150
6fc2811b
JR
151int display_busy_cursor_p;
152
ee78dc32
GV
153/* The background and shape of the mouse pointer, and shape when not
154 over text or in the modeline. */
dfff8a69 155
ee78dc32 156Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
4694d762 157Lisp_Object Vx_busy_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 158
ee78dc32 159/* The shape when over mouse-sensitive text. */
dfff8a69 160
ee78dc32
GV
161Lisp_Object Vx_sensitive_text_pointer_shape;
162
163/* Color of chars displayed in cursor box. */
dfff8a69 164
ee78dc32
GV
165Lisp_Object Vx_cursor_fore_pixel;
166
1edf84e7 167/* Nonzero if using Windows. */
dfff8a69 168
1edf84e7
GV
169static int w32_in_use;
170
ee78dc32 171/* Search path for bitmap files. */
dfff8a69 172
ee78dc32
GV
173Lisp_Object Vx_bitmap_file_path;
174
4587b026 175/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 176
4587b026
GV
177Lisp_Object Vx_pixel_size_width_font_regexp;
178
33d52f9c
GV
179/* Alist of bdf fonts and the files that define them. */
180Lisp_Object Vw32_bdf_filename_alist;
181
f46e6225
GV
182Lisp_Object Vw32_system_coding_system;
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
199
ee78dc32
GV
200/* Evaluate this expression to rebuild the section of syms_of_w32fns
201 that initializes and staticpros the symbols declared below. Note
202 that Emacs 18 has a bug that keeps C-x C-e from being able to
203 evaluate this expression.
204
205(progn
206 ;; Accumulate a list of the symbols we want to initialize from the
207 ;; declarations at the top of the file.
208 (goto-char (point-min))
209 (search-forward "/\*&&& symbols declared here &&&*\/\n")
210 (let (symbol-list)
211 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
212 (setq symbol-list
213 (cons (buffer-substring (match-beginning 1) (match-end 1))
214 symbol-list))
215 (forward-line 1))
216 (setq symbol-list (nreverse symbol-list))
217 ;; Delete the section of syms_of_... where we initialize the symbols.
218 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
219 (let ((start (point)))
220 (while (looking-at "^ Q")
221 (forward-line 2))
222 (kill-region start (point)))
223 ;; Write a new symbol initialization section.
224 (while symbol-list
225 (insert (format " %s = intern (\"" (car symbol-list)))
226 (let ((start (point)))
227 (insert (substring (car symbol-list) 1))
228 (subst-char-in-region start (point) ?_ ?-))
229 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
230 (setq symbol-list (cdr symbol-list)))))
231
232 */
233
234/*&&& symbols declared here &&&*/
235Lisp_Object Qauto_raise;
236Lisp_Object Qauto_lower;
ee78dc32
GV
237Lisp_Object Qbar;
238Lisp_Object Qborder_color;
239Lisp_Object Qborder_width;
240Lisp_Object Qbox;
241Lisp_Object Qcursor_color;
242Lisp_Object Qcursor_type;
ee78dc32
GV
243Lisp_Object Qgeometry;
244Lisp_Object Qicon_left;
245Lisp_Object Qicon_top;
246Lisp_Object Qicon_type;
247Lisp_Object Qicon_name;
248Lisp_Object Qinternal_border_width;
249Lisp_Object Qleft;
1026b400 250Lisp_Object Qright;
ee78dc32
GV
251Lisp_Object Qmouse_color;
252Lisp_Object Qnone;
253Lisp_Object Qparent_id;
254Lisp_Object Qscroll_bar_width;
255Lisp_Object Qsuppress_icon;
ee78dc32
GV
256Lisp_Object Qundefined_color;
257Lisp_Object Qvertical_scroll_bars;
258Lisp_Object Qvisibility;
259Lisp_Object Qwindow_id;
260Lisp_Object Qx_frame_parameter;
261Lisp_Object Qx_resource_name;
262Lisp_Object Quser_position;
263Lisp_Object Quser_size;
6fc2811b 264Lisp_Object Qscreen_gamma;
dfff8a69
JR
265Lisp_Object Qline_spacing;
266Lisp_Object Qcenter;
adcc3809
GV
267Lisp_Object Qhyper;
268Lisp_Object Qsuper;
269Lisp_Object Qmeta;
270Lisp_Object Qalt;
271Lisp_Object Qctrl;
272Lisp_Object Qcontrol;
273Lisp_Object Qshift;
274
dfff8a69
JR
275Lisp_Object Qw32_charset_ansi;
276Lisp_Object Qw32_charset_default;
277Lisp_Object Qw32_charset_symbol;
278Lisp_Object Qw32_charset_shiftjis;
767b1ff0 279Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
280Lisp_Object Qw32_charset_gb2312;
281Lisp_Object Qw32_charset_chinesebig5;
282Lisp_Object Qw32_charset_oem;
283
71eab8d1
AI
284#ifndef JOHAB_CHARSET
285#define JOHAB_CHARSET 130
286#endif
dfff8a69
JR
287#ifdef JOHAB_CHARSET
288Lisp_Object Qw32_charset_easteurope;
289Lisp_Object Qw32_charset_turkish;
290Lisp_Object Qw32_charset_baltic;
291Lisp_Object Qw32_charset_russian;
292Lisp_Object Qw32_charset_arabic;
293Lisp_Object Qw32_charset_greek;
294Lisp_Object Qw32_charset_hebrew;
767b1ff0 295Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
296Lisp_Object Qw32_charset_thai;
297Lisp_Object Qw32_charset_johab;
298Lisp_Object Qw32_charset_mac;
299#endif
300
301#ifdef UNICODE_CHARSET
302Lisp_Object Qw32_charset_unicode;
303#endif
304
6fc2811b
JR
305extern Lisp_Object Qtop;
306extern Lisp_Object Qdisplay;
307extern Lisp_Object Qtool_bar_lines;
308
5ac45f98
GV
309/* State variables for emulating a three button mouse. */
310#define LMOUSE 1
311#define MMOUSE 2
312#define RMOUSE 4
313
314static int button_state = 0;
fbd6baed 315static W32Msg saved_mouse_button_msg;
84fb1139 316static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 317static W32Msg saved_mouse_move_msg;
84fb1139
KH
318static unsigned mouse_move_timer;
319
93fbe8b7
GV
320/* W95 mousewheel handler */
321unsigned int msh_mousewheel = 0;
322
84fb1139
KH
323#define MOUSE_BUTTON_ID 1
324#define MOUSE_MOVE_ID 2
5ac45f98 325
ee78dc32 326/* The below are defined in frame.c. */
dfff8a69 327
ee78dc32 328extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 329extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 330extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
331
332extern Lisp_Object Vwindow_system_version;
333
4b817373
RS
334Lisp_Object Qface_set_after_frame_default;
335
fbd6baed
GV
336/* From w32term.c. */
337extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 338extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 339
ee78dc32 340\f
1edf84e7
GV
341/* Error if we are not connected to MS-Windows. */
342void
343check_w32 ()
344{
345 if (! w32_in_use)
346 error ("MS-Windows not in use or not initialized");
347}
348
349/* Nonzero if we can use mouse menus.
350 You should not call this unless HAVE_MENUS is defined. */
351
352int
353have_menus_p ()
354{
355 return w32_in_use;
356}
357
ee78dc32 358/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 359 and checking validity for W32. */
ee78dc32
GV
360
361FRAME_PTR
362check_x_frame (frame)
363 Lisp_Object frame;
364{
365 FRAME_PTR f;
366
367 if (NILP (frame))
6fc2811b
JR
368 frame = selected_frame;
369 CHECK_LIVE_FRAME (frame, 0);
370 f = XFRAME (frame);
fbd6baed
GV
371 if (! FRAME_W32_P (f))
372 error ("non-w32 frame used");
ee78dc32
GV
373 return f;
374}
375
376/* Let the user specify an display with a frame.
fbd6baed 377 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
378 the first display on the list. */
379
fbd6baed 380static struct w32_display_info *
ee78dc32
GV
381check_x_display_info (frame)
382 Lisp_Object frame;
383{
384 if (NILP (frame))
385 {
6fc2811b
JR
386 struct frame *sf = XFRAME (selected_frame);
387
388 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
389 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 390 else
fbd6baed 391 return &one_w32_display_info;
ee78dc32
GV
392 }
393 else if (STRINGP (frame))
394 return x_display_info_for_name (frame);
395 else
396 {
397 FRAME_PTR f;
398
399 CHECK_LIVE_FRAME (frame, 0);
400 f = XFRAME (frame);
fbd6baed
GV
401 if (! FRAME_W32_P (f))
402 error ("non-w32 frame used");
403 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
404 }
405}
406\f
fbd6baed 407/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
408 It could be the frame's main window or an icon window. */
409
410/* This function can be called during GC, so use GC_xxx type test macros. */
411
412struct frame *
413x_window_to_frame (dpyinfo, wdesc)
fbd6baed 414 struct w32_display_info *dpyinfo;
ee78dc32
GV
415 HWND wdesc;
416{
417 Lisp_Object tail, frame;
418 struct frame *f;
419
8e713be6 420 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 421 {
8e713be6 422 frame = XCAR (tail);
ee78dc32
GV
423 if (!GC_FRAMEP (frame))
424 continue;
425 f = XFRAME (frame);
2d764c78 426 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 427 continue;
f79e6790
JR
428 if (f->output_data.w32->busy_window == wdesc)
429 return f;
430
767b1ff0 431 /* TODO: Check tooltips when supported. */
fbd6baed 432 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
433 return f;
434 }
435 return 0;
436}
437
438\f
439
440/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
441 id, which is just an int that this section returns. Bitmaps are
442 reference counted so they can be shared among frames.
443
444 Bitmap indices are guaranteed to be > 0, so a negative number can
445 be used to indicate no bitmap.
446
447 If you use x_create_bitmap_from_data, then you must keep track of
448 the bitmaps yourself. That is, creating a bitmap from the same
449 data more than once will not be caught. */
450
451
452/* Functions to access the contents of a bitmap, given an id. */
453
454int
455x_bitmap_height (f, id)
456 FRAME_PTR f;
457 int id;
458{
fbd6baed 459 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
460}
461
462int
463x_bitmap_width (f, id)
464 FRAME_PTR f;
465 int id;
466{
fbd6baed 467 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
468}
469
470int
471x_bitmap_pixmap (f, id)
472 FRAME_PTR f;
473 int id;
474{
fbd6baed 475 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
476}
477
478
479/* Allocate a new bitmap record. Returns index of new record. */
480
481static int
482x_allocate_bitmap_record (f)
483 FRAME_PTR f;
484{
fbd6baed 485 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
486 int i;
487
488 if (dpyinfo->bitmaps == NULL)
489 {
490 dpyinfo->bitmaps_size = 10;
491 dpyinfo->bitmaps
fbd6baed 492 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
493 dpyinfo->bitmaps_last = 1;
494 return 1;
495 }
496
497 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
498 return ++dpyinfo->bitmaps_last;
499
500 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
501 if (dpyinfo->bitmaps[i].refcount == 0)
502 return i + 1;
503
504 dpyinfo->bitmaps_size *= 2;
505 dpyinfo->bitmaps
fbd6baed
GV
506 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
507 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
508 return ++dpyinfo->bitmaps_last;
509}
510
511/* Add one reference to the reference count of the bitmap with id ID. */
512
513void
514x_reference_bitmap (f, id)
515 FRAME_PTR f;
516 int id;
517{
fbd6baed 518 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
519}
520
521/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
522
523int
524x_create_bitmap_from_data (f, bits, width, height)
525 struct frame *f;
526 char *bits;
527 unsigned int width, height;
528{
fbd6baed 529 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
530 Pixmap bitmap;
531 int id;
532
533 bitmap = CreateBitmap (width, height,
fbd6baed
GV
534 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
535 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
536 bits);
537
538 if (! bitmap)
539 return -1;
540
541 id = x_allocate_bitmap_record (f);
542 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
543 dpyinfo->bitmaps[id - 1].file = NULL;
544 dpyinfo->bitmaps[id - 1].hinst = NULL;
545 dpyinfo->bitmaps[id - 1].refcount = 1;
546 dpyinfo->bitmaps[id - 1].depth = 1;
547 dpyinfo->bitmaps[id - 1].height = height;
548 dpyinfo->bitmaps[id - 1].width = width;
549
550 return id;
551}
552
553/* Create bitmap from file FILE for frame F. */
554
555int
556x_create_bitmap_from_file (f, file)
557 struct frame *f;
558 Lisp_Object file;
559{
560 return -1;
767b1ff0 561#if 0 /* TODO : bitmap support */
fbd6baed 562 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 563 unsigned int width, height;
6fc2811b 564 HBITMAP bitmap;
ee78dc32
GV
565 int xhot, yhot, result, id;
566 Lisp_Object found;
567 int fd;
568 char *filename;
569 HINSTANCE hinst;
570
571 /* Look for an existing bitmap with the same name. */
572 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
573 {
574 if (dpyinfo->bitmaps[id].refcount
575 && dpyinfo->bitmaps[id].file
576 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
577 {
578 ++dpyinfo->bitmaps[id].refcount;
579 return id + 1;
580 }
581 }
582
583 /* Search bitmap-file-path for the file, if appropriate. */
584 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
585 if (fd < 0)
586 return -1;
6fc2811b 587 emacs_close (fd);
ee78dc32
GV
588
589 filename = (char *) XSTRING (found)->data;
590
591 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
592
593 if (hinst == NULL)
594 return -1;
595
596
fbd6baed 597 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
598 filename, &width, &height, &bitmap, &xhot, &yhot);
599 if (result != BitmapSuccess)
600 return -1;
601
602 id = x_allocate_bitmap_record (f);
603 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
604 dpyinfo->bitmaps[id - 1].refcount = 1;
605 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
606 dpyinfo->bitmaps[id - 1].depth = 1;
607 dpyinfo->bitmaps[id - 1].height = height;
608 dpyinfo->bitmaps[id - 1].width = width;
609 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
610
611 return id;
767b1ff0 612#endif /* TODO */
ee78dc32
GV
613}
614
615/* Remove reference to bitmap with id number ID. */
616
33d52f9c 617void
ee78dc32
GV
618x_destroy_bitmap (f, id)
619 FRAME_PTR f;
620 int id;
621{
fbd6baed 622 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
623
624 if (id > 0)
625 {
626 --dpyinfo->bitmaps[id - 1].refcount;
627 if (dpyinfo->bitmaps[id - 1].refcount == 0)
628 {
629 BLOCK_INPUT;
630 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
631 if (dpyinfo->bitmaps[id - 1].file)
632 {
6fc2811b 633 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
634 dpyinfo->bitmaps[id - 1].file = NULL;
635 }
636 UNBLOCK_INPUT;
637 }
638 }
639}
640
641/* Free all the bitmaps for the display specified by DPYINFO. */
642
643static void
644x_destroy_all_bitmaps (dpyinfo)
fbd6baed 645 struct w32_display_info *dpyinfo;
ee78dc32
GV
646{
647 int i;
648 for (i = 0; i < dpyinfo->bitmaps_last; i++)
649 if (dpyinfo->bitmaps[i].refcount > 0)
650 {
651 DeleteObject (dpyinfo->bitmaps[i].pixmap);
652 if (dpyinfo->bitmaps[i].file)
6fc2811b 653 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
654 }
655 dpyinfo->bitmaps_last = 0;
656}
657\f
fbd6baed 658/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
659 to the ways of passing the parameter values to the window system.
660
661 The name of a parameter, as a Lisp symbol,
662 has an `x-frame-parameter' property which is an integer in Lisp
663 but can be interpreted as an `enum x_frame_parm' in C. */
664
665enum x_frame_parm
666{
667 X_PARM_FOREGROUND_COLOR,
668 X_PARM_BACKGROUND_COLOR,
669 X_PARM_MOUSE_COLOR,
670 X_PARM_CURSOR_COLOR,
671 X_PARM_BORDER_COLOR,
672 X_PARM_ICON_TYPE,
673 X_PARM_FONT,
674 X_PARM_BORDER_WIDTH,
675 X_PARM_INTERNAL_BORDER_WIDTH,
676 X_PARM_NAME,
677 X_PARM_AUTORAISE,
678 X_PARM_AUTOLOWER,
679 X_PARM_VERT_SCROLL_BAR,
680 X_PARM_VISIBILITY,
681 X_PARM_MENU_BAR_LINES
682};
683
684
685struct x_frame_parm_table
686{
687 char *name;
6fc2811b 688 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
689};
690
767b1ff0 691/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 692void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 693static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
694void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
695void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
698void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
701void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
702void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
703void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
704 Lisp_Object));
705void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
706void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
707void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
708void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
709 Lisp_Object));
710void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
711void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
712void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
713void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
714void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
715void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
716static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
717
718static struct x_frame_parm_table x_frame_parms[] =
719{
1edf84e7
GV
720 "auto-raise", x_set_autoraise,
721 "auto-lower", x_set_autolower,
ee78dc32 722 "background-color", x_set_background_color,
ee78dc32 723 "border-color", x_set_border_color,
1edf84e7
GV
724 "border-width", x_set_border_width,
725 "cursor-color", x_set_cursor_color,
ee78dc32 726 "cursor-type", x_set_cursor_type,
ee78dc32 727 "font", x_set_font,
1edf84e7
GV
728 "foreground-color", x_set_foreground_color,
729 "icon-name", x_set_icon_name,
730 "icon-type", x_set_icon_type,
ee78dc32 731 "internal-border-width", x_set_internal_border_width,
ee78dc32 732 "menu-bar-lines", x_set_menu_bar_lines,
1edf84e7
GV
733 "mouse-color", x_set_mouse_color,
734 "name", x_explicitly_set_name,
ee78dc32 735 "scroll-bar-width", x_set_scroll_bar_width,
1edf84e7 736 "title", x_set_title,
ee78dc32 737 "unsplittable", x_set_unsplittable,
1edf84e7
GV
738 "vertical-scroll-bars", x_set_vertical_scroll_bars,
739 "visibility", x_set_visibility,
6fc2811b 740 "tool-bar-lines", x_set_tool_bar_lines,
dfff8a69
JR
741 "screen-gamma", x_set_screen_gamma,
742 "line-spacing", x_set_line_spacing
ee78dc32
GV
743};
744
745/* Attach the `x-frame-parameter' properties to
fbd6baed 746 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 747
dfff8a69 748void
ee78dc32
GV
749init_x_parm_symbols ()
750{
751 int i;
752
753 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
754 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
755 make_number (i));
756}
757\f
dfff8a69 758/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
759 If a parameter is not specially recognized, do nothing;
760 otherwise call the `x_set_...' function for that parameter. */
761
762void
763x_set_frame_parameters (f, alist)
764 FRAME_PTR f;
765 Lisp_Object alist;
766{
767 Lisp_Object tail;
768
769 /* If both of these parameters are present, it's more efficient to
770 set them both at once. So we wait until we've looked at the
771 entire list before we set them. */
b839712d 772 int width, height;
ee78dc32
GV
773
774 /* Same here. */
775 Lisp_Object left, top;
776
777 /* Same with these. */
778 Lisp_Object icon_left, icon_top;
779
780 /* Record in these vectors all the parms specified. */
781 Lisp_Object *parms;
782 Lisp_Object *values;
a797a73d 783 int i, p;
ee78dc32
GV
784 int left_no_change = 0, top_no_change = 0;
785 int icon_left_no_change = 0, icon_top_no_change = 0;
786
5878523b
RS
787 struct gcpro gcpro1, gcpro2;
788
ee78dc32
GV
789 i = 0;
790 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
791 i++;
792
793 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
794 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
795
796 /* Extract parm names and values into those vectors. */
797
798 i = 0;
799 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
800 {
6fc2811b 801 Lisp_Object elt;
ee78dc32
GV
802
803 elt = Fcar (tail);
804 parms[i] = Fcar (elt);
805 values[i] = Fcdr (elt);
806 i++;
807 }
5878523b
RS
808 /* TAIL and ALIST are not used again below here. */
809 alist = tail = Qnil;
810
811 GCPRO2 (*parms, *values);
812 gcpro1.nvars = i;
813 gcpro2.nvars = i;
814
815 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
816 because their values appear in VALUES and strings are not valid. */
b839712d 817 top = left = Qunbound;
ee78dc32
GV
818 icon_left = icon_top = Qunbound;
819
b839712d 820 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
821 if (FRAME_NEW_WIDTH (f))
822 width = FRAME_NEW_WIDTH (f);
823 else
824 width = FRAME_WIDTH (f);
825
826 if (FRAME_NEW_HEIGHT (f))
827 height = FRAME_NEW_HEIGHT (f);
828 else
829 height = FRAME_HEIGHT (f);
b839712d 830
a797a73d
GV
831 /* Process foreground_color and background_color before anything else.
832 They are independent of other properties, but other properties (e.g.,
833 cursor_color) are dependent upon them. */
834 for (p = 0; p < i; p++)
835 {
836 Lisp_Object prop, val;
837
838 prop = parms[p];
839 val = values[p];
840 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
841 {
842 register Lisp_Object param_index, old_value;
843
844 param_index = Fget (prop, Qx_frame_parameter);
845 old_value = get_frame_param (f, prop);
846 store_frame_param (f, prop, val);
847 if (NATNUMP (param_index)
848 && (XFASTINT (param_index)
849 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
850 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
851 }
852 }
853
ee78dc32
GV
854 /* Now process them in reverse of specified order. */
855 for (i--; i >= 0; i--)
856 {
857 Lisp_Object prop, val;
858
859 prop = parms[i];
860 val = values[i];
861
b839712d
RS
862 if (EQ (prop, Qwidth) && NUMBERP (val))
863 width = XFASTINT (val);
864 else if (EQ (prop, Qheight) && NUMBERP (val))
865 height = XFASTINT (val);
ee78dc32
GV
866 else if (EQ (prop, Qtop))
867 top = val;
868 else if (EQ (prop, Qleft))
869 left = val;
870 else if (EQ (prop, Qicon_top))
871 icon_top = val;
872 else if (EQ (prop, Qicon_left))
873 icon_left = val;
a797a73d
GV
874 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
875 /* Processed above. */
876 continue;
ee78dc32
GV
877 else
878 {
879 register Lisp_Object param_index, old_value;
880
881 param_index = Fget (prop, Qx_frame_parameter);
882 old_value = get_frame_param (f, prop);
883 store_frame_param (f, prop, val);
884 if (NATNUMP (param_index)
885 && (XFASTINT (param_index)
886 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 887 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
888 }
889 }
890
891 /* Don't die if just one of these was set. */
892 if (EQ (left, Qunbound))
893 {
894 left_no_change = 1;
fbd6baed
GV
895 if (f->output_data.w32->left_pos < 0)
896 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 897 else
fbd6baed 898 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
899 }
900 if (EQ (top, Qunbound))
901 {
902 top_no_change = 1;
fbd6baed
GV
903 if (f->output_data.w32->top_pos < 0)
904 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 905 else
fbd6baed 906 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
907 }
908
909 /* If one of the icon positions was not set, preserve or default it. */
910 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
911 {
912 icon_left_no_change = 1;
913 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
914 if (NILP (icon_left))
915 XSETINT (icon_left, 0);
916 }
917 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
918 {
919 icon_top_no_change = 1;
920 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
921 if (NILP (icon_top))
922 XSETINT (icon_top, 0);
923 }
924
ee78dc32
GV
925 /* Don't set these parameters unless they've been explicitly
926 specified. The window might be mapped or resized while we're in
927 this function, and we don't want to override that unless the lisp
928 code has asked for it.
929
930 Don't set these parameters unless they actually differ from the
931 window's current parameters; the window may not actually exist
932 yet. */
933 {
934 Lisp_Object frame;
935
936 check_frame_size (f, &height, &width);
937
938 XSETFRAME (frame, f);
939
dfff8a69
JR
940 if (width != FRAME_WIDTH (f)
941 || height != FRAME_HEIGHT (f)
942 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 943 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
944
945 if ((!NILP (left) || !NILP (top))
946 && ! (left_no_change && top_no_change)
fbd6baed
GV
947 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
948 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
949 {
950 int leftpos = 0;
951 int toppos = 0;
952
953 /* Record the signs. */
fbd6baed 954 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 955 if (EQ (left, Qminus))
fbd6baed 956 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
957 else if (INTEGERP (left))
958 {
959 leftpos = XINT (left);
960 if (leftpos < 0)
fbd6baed 961 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 962 }
8e713be6
KR
963 else if (CONSP (left) && EQ (XCAR (left), Qminus)
964 && CONSP (XCDR (left))
965 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 966 {
8e713be6 967 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 968 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 969 }
8e713be6
KR
970 else if (CONSP (left) && EQ (XCAR (left), Qplus)
971 && CONSP (XCDR (left))
972 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 973 {
8e713be6 974 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
975 }
976
977 if (EQ (top, Qminus))
fbd6baed 978 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
979 else if (INTEGERP (top))
980 {
981 toppos = XINT (top);
982 if (toppos < 0)
fbd6baed 983 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 984 }
8e713be6
KR
985 else if (CONSP (top) && EQ (XCAR (top), Qminus)
986 && CONSP (XCDR (top))
987 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 988 {
8e713be6 989 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 990 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 991 }
8e713be6
KR
992 else if (CONSP (top) && EQ (XCAR (top), Qplus)
993 && CONSP (XCDR (top))
994 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 995 {
8e713be6 996 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
997 }
998
999
1000 /* Store the numeric value of the position. */
fbd6baed
GV
1001 f->output_data.w32->top_pos = toppos;
1002 f->output_data.w32->left_pos = leftpos;
ee78dc32 1003
fbd6baed 1004 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1005
1006 /* Actually set that position, and convert to absolute. */
1007 x_set_offset (f, leftpos, toppos, -1);
1008 }
1009
1010 if ((!NILP (icon_left) || !NILP (icon_top))
1011 && ! (icon_left_no_change && icon_top_no_change))
1012 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1013 }
5878523b
RS
1014
1015 UNGCPRO;
ee78dc32
GV
1016}
1017
1018/* Store the screen positions of frame F into XPTR and YPTR.
1019 These are the positions of the containing window manager window,
1020 not Emacs's own window. */
1021
1022void
1023x_real_positions (f, xptr, yptr)
1024 FRAME_PTR f;
1025 int *xptr, *yptr;
1026{
1027 POINT pt;
3c190163
GV
1028
1029 {
1030 RECT rect;
ee78dc32 1031
fbd6baed
GV
1032 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1033 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 1034
3c190163
GV
1035 pt.x = rect.left;
1036 pt.y = rect.top;
1037 }
ee78dc32 1038
fbd6baed 1039 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
1040
1041 *xptr = pt.x;
1042 *yptr = pt.y;
1043}
1044
1045/* Insert a description of internally-recorded parameters of frame X
1046 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1047 Only parameters that are specific to W32
ee78dc32
GV
1048 and whose values are not correctly recorded in the frame's
1049 param_alist need to be considered here. */
1050
dfff8a69 1051void
ee78dc32
GV
1052x_report_frame_params (f, alistptr)
1053 struct frame *f;
1054 Lisp_Object *alistptr;
1055{
1056 char buf[16];
1057 Lisp_Object tem;
1058
1059 /* Represent negative positions (off the top or left screen edge)
1060 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1061 XSETINT (tem, f->output_data.w32->left_pos);
1062 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1063 store_in_alist (alistptr, Qleft, tem);
1064 else
1065 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1066
fbd6baed
GV
1067 XSETINT (tem, f->output_data.w32->top_pos);
1068 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1069 store_in_alist (alistptr, Qtop, tem);
1070 else
1071 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1072
1073 store_in_alist (alistptr, Qborder_width,
fbd6baed 1074 make_number (f->output_data.w32->border_width));
ee78dc32 1075 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed
GV
1076 make_number (f->output_data.w32->internal_border_width));
1077 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1078 store_in_alist (alistptr, Qwindow_id,
1079 build_string (buf));
1080 store_in_alist (alistptr, Qicon_name, f->icon_name);
1081 FRAME_SAMPLE_VISIBILITY (f);
1082 store_in_alist (alistptr, Qvisibility,
1083 (FRAME_VISIBLE_P (f) ? Qt
1084 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1085 store_in_alist (alistptr, Qdisplay,
8e713be6 1086 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1087}
1088\f
1089
fbd6baed 1090DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
5ac45f98 1091 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
fbd6baed 1092This adds or updates a named color to w32-color-map, making it available for use.\n\
5ac45f98
GV
1093The original entry's RGB ref is returned, or nil if the entry is new.")
1094 (red, green, blue, name)
1095 Lisp_Object red, green, blue, name;
ee78dc32 1096{
5ac45f98
GV
1097 Lisp_Object rgb;
1098 Lisp_Object oldrgb = Qnil;
1099 Lisp_Object entry;
1100
1101 CHECK_NUMBER (red, 0);
1102 CHECK_NUMBER (green, 0);
1103 CHECK_NUMBER (blue, 0);
1104 CHECK_STRING (name, 0);
ee78dc32 1105
5ac45f98 1106 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1107
5ac45f98 1108 BLOCK_INPUT;
ee78dc32 1109
fbd6baed
GV
1110 /* replace existing entry in w32-color-map or add new entry. */
1111 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1112 if (NILP (entry))
1113 {
1114 entry = Fcons (name, rgb);
fbd6baed 1115 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1116 }
1117 else
1118 {
1119 oldrgb = Fcdr (entry);
1120 Fsetcdr (entry, rgb);
1121 }
1122
1123 UNBLOCK_INPUT;
1124
1125 return (oldrgb);
ee78dc32
GV
1126}
1127
fbd6baed 1128DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
5ac45f98 1129 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
fbd6baed 1130Assign this value to w32-color-map to replace the existing color map.\n\
5ac45f98
GV
1131\
1132The file should define one named RGB color per line like so:\
1133 R G B name\n\
1134where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1135 (filename)
1136 Lisp_Object filename;
1137{
1138 FILE *fp;
1139 Lisp_Object cmap = Qnil;
1140 Lisp_Object abspath;
1141
1142 CHECK_STRING (filename, 0);
1143 abspath = Fexpand_file_name (filename, Qnil);
1144
1145 fp = fopen (XSTRING (filename)->data, "rt");
1146 if (fp)
1147 {
1148 char buf[512];
1149 int red, green, blue;
1150 int num;
1151
1152 BLOCK_INPUT;
1153
1154 while (fgets (buf, sizeof (buf), fp) != NULL) {
1155 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1156 {
1157 char *name = buf + num;
1158 num = strlen (name) - 1;
1159 if (name[num] == '\n')
1160 name[num] = 0;
1161 cmap = Fcons (Fcons (build_string (name),
1162 make_number (RGB (red, green, blue))),
1163 cmap);
1164 }
1165 }
1166 fclose (fp);
1167
1168 UNBLOCK_INPUT;
1169 }
1170
1171 return cmap;
1172}
ee78dc32 1173
fbd6baed 1174/* The default colors for the w32 color map */
ee78dc32
GV
1175typedef struct colormap_t
1176{
1177 char *name;
1178 COLORREF colorref;
1179} colormap_t;
1180
fbd6baed 1181colormap_t w32_color_map[] =
ee78dc32 1182{
1da8a614
GV
1183 {"snow" , PALETTERGB (255,250,250)},
1184 {"ghost white" , PALETTERGB (248,248,255)},
1185 {"GhostWhite" , PALETTERGB (248,248,255)},
1186 {"white smoke" , PALETTERGB (245,245,245)},
1187 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1188 {"gainsboro" , PALETTERGB (220,220,220)},
1189 {"floral white" , PALETTERGB (255,250,240)},
1190 {"FloralWhite" , PALETTERGB (255,250,240)},
1191 {"old lace" , PALETTERGB (253,245,230)},
1192 {"OldLace" , PALETTERGB (253,245,230)},
1193 {"linen" , PALETTERGB (250,240,230)},
1194 {"antique white" , PALETTERGB (250,235,215)},
1195 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1196 {"papaya whip" , PALETTERGB (255,239,213)},
1197 {"PapayaWhip" , PALETTERGB (255,239,213)},
1198 {"blanched almond" , PALETTERGB (255,235,205)},
1199 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1200 {"bisque" , PALETTERGB (255,228,196)},
1201 {"peach puff" , PALETTERGB (255,218,185)},
1202 {"PeachPuff" , PALETTERGB (255,218,185)},
1203 {"navajo white" , PALETTERGB (255,222,173)},
1204 {"NavajoWhite" , PALETTERGB (255,222,173)},
1205 {"moccasin" , PALETTERGB (255,228,181)},
1206 {"cornsilk" , PALETTERGB (255,248,220)},
1207 {"ivory" , PALETTERGB (255,255,240)},
1208 {"lemon chiffon" , PALETTERGB (255,250,205)},
1209 {"LemonChiffon" , PALETTERGB (255,250,205)},
1210 {"seashell" , PALETTERGB (255,245,238)},
1211 {"honeydew" , PALETTERGB (240,255,240)},
1212 {"mint cream" , PALETTERGB (245,255,250)},
1213 {"MintCream" , PALETTERGB (245,255,250)},
1214 {"azure" , PALETTERGB (240,255,255)},
1215 {"alice blue" , PALETTERGB (240,248,255)},
1216 {"AliceBlue" , PALETTERGB (240,248,255)},
1217 {"lavender" , PALETTERGB (230,230,250)},
1218 {"lavender blush" , PALETTERGB (255,240,245)},
1219 {"LavenderBlush" , PALETTERGB (255,240,245)},
1220 {"misty rose" , PALETTERGB (255,228,225)},
1221 {"MistyRose" , PALETTERGB (255,228,225)},
1222 {"white" , PALETTERGB (255,255,255)},
1223 {"black" , PALETTERGB ( 0, 0, 0)},
1224 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1225 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1226 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1227 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1228 {"dim gray" , PALETTERGB (105,105,105)},
1229 {"DimGray" , PALETTERGB (105,105,105)},
1230 {"dim grey" , PALETTERGB (105,105,105)},
1231 {"DimGrey" , PALETTERGB (105,105,105)},
1232 {"slate gray" , PALETTERGB (112,128,144)},
1233 {"SlateGray" , PALETTERGB (112,128,144)},
1234 {"slate grey" , PALETTERGB (112,128,144)},
1235 {"SlateGrey" , PALETTERGB (112,128,144)},
1236 {"light slate gray" , PALETTERGB (119,136,153)},
1237 {"LightSlateGray" , PALETTERGB (119,136,153)},
1238 {"light slate grey" , PALETTERGB (119,136,153)},
1239 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1240 {"gray" , PALETTERGB (190,190,190)},
1241 {"grey" , PALETTERGB (190,190,190)},
1242 {"light grey" , PALETTERGB (211,211,211)},
1243 {"LightGrey" , PALETTERGB (211,211,211)},
1244 {"light gray" , PALETTERGB (211,211,211)},
1245 {"LightGray" , PALETTERGB (211,211,211)},
1246 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1247 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1248 {"navy" , PALETTERGB ( 0, 0,128)},
1249 {"navy blue" , PALETTERGB ( 0, 0,128)},
1250 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1251 {"cornflower blue" , PALETTERGB (100,149,237)},
1252 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1253 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1254 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1255 {"slate blue" , PALETTERGB (106, 90,205)},
1256 {"SlateBlue" , PALETTERGB (106, 90,205)},
1257 {"medium slate blue" , PALETTERGB (123,104,238)},
1258 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1259 {"light slate blue" , PALETTERGB (132,112,255)},
1260 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1261 {"medium blue" , PALETTERGB ( 0, 0,205)},
1262 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1263 {"royal blue" , PALETTERGB ( 65,105,225)},
1264 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1265 {"blue" , PALETTERGB ( 0, 0,255)},
1266 {"dodger blue" , PALETTERGB ( 30,144,255)},
1267 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1268 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1269 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1270 {"sky blue" , PALETTERGB (135,206,235)},
1271 {"SkyBlue" , PALETTERGB (135,206,235)},
1272 {"light sky blue" , PALETTERGB (135,206,250)},
1273 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1274 {"steel blue" , PALETTERGB ( 70,130,180)},
1275 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1276 {"light steel blue" , PALETTERGB (176,196,222)},
1277 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1278 {"light blue" , PALETTERGB (173,216,230)},
1279 {"LightBlue" , PALETTERGB (173,216,230)},
1280 {"powder blue" , PALETTERGB (176,224,230)},
1281 {"PowderBlue" , PALETTERGB (176,224,230)},
1282 {"pale turquoise" , PALETTERGB (175,238,238)},
1283 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1284 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1285 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1286 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1287 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1288 {"turquoise" , PALETTERGB ( 64,224,208)},
1289 {"cyan" , PALETTERGB ( 0,255,255)},
1290 {"light cyan" , PALETTERGB (224,255,255)},
1291 {"LightCyan" , PALETTERGB (224,255,255)},
1292 {"cadet blue" , PALETTERGB ( 95,158,160)},
1293 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1294 {"medium aquamarine" , PALETTERGB (102,205,170)},
1295 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1296 {"aquamarine" , PALETTERGB (127,255,212)},
1297 {"dark green" , PALETTERGB ( 0,100, 0)},
1298 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1299 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1300 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1301 {"dark sea green" , PALETTERGB (143,188,143)},
1302 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1303 {"sea green" , PALETTERGB ( 46,139, 87)},
1304 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1305 {"medium sea green" , PALETTERGB ( 60,179,113)},
1306 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1307 {"light sea green" , PALETTERGB ( 32,178,170)},
1308 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1309 {"pale green" , PALETTERGB (152,251,152)},
1310 {"PaleGreen" , PALETTERGB (152,251,152)},
1311 {"spring green" , PALETTERGB ( 0,255,127)},
1312 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1313 {"lawn green" , PALETTERGB (124,252, 0)},
1314 {"LawnGreen" , PALETTERGB (124,252, 0)},
1315 {"green" , PALETTERGB ( 0,255, 0)},
1316 {"chartreuse" , PALETTERGB (127,255, 0)},
1317 {"medium spring green" , PALETTERGB ( 0,250,154)},
1318 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1319 {"green yellow" , PALETTERGB (173,255, 47)},
1320 {"GreenYellow" , PALETTERGB (173,255, 47)},
1321 {"lime green" , PALETTERGB ( 50,205, 50)},
1322 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1323 {"yellow green" , PALETTERGB (154,205, 50)},
1324 {"YellowGreen" , PALETTERGB (154,205, 50)},
1325 {"forest green" , PALETTERGB ( 34,139, 34)},
1326 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1327 {"olive drab" , PALETTERGB (107,142, 35)},
1328 {"OliveDrab" , PALETTERGB (107,142, 35)},
1329 {"dark khaki" , PALETTERGB (189,183,107)},
1330 {"DarkKhaki" , PALETTERGB (189,183,107)},
1331 {"khaki" , PALETTERGB (240,230,140)},
1332 {"pale goldenrod" , PALETTERGB (238,232,170)},
1333 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1334 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1335 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1336 {"light yellow" , PALETTERGB (255,255,224)},
1337 {"LightYellow" , PALETTERGB (255,255,224)},
1338 {"yellow" , PALETTERGB (255,255, 0)},
1339 {"gold" , PALETTERGB (255,215, 0)},
1340 {"light goldenrod" , PALETTERGB (238,221,130)},
1341 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1342 {"goldenrod" , PALETTERGB (218,165, 32)},
1343 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1344 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1345 {"rosy brown" , PALETTERGB (188,143,143)},
1346 {"RosyBrown" , PALETTERGB (188,143,143)},
1347 {"indian red" , PALETTERGB (205, 92, 92)},
1348 {"IndianRed" , PALETTERGB (205, 92, 92)},
1349 {"saddle brown" , PALETTERGB (139, 69, 19)},
1350 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1351 {"sienna" , PALETTERGB (160, 82, 45)},
1352 {"peru" , PALETTERGB (205,133, 63)},
1353 {"burlywood" , PALETTERGB (222,184,135)},
1354 {"beige" , PALETTERGB (245,245,220)},
1355 {"wheat" , PALETTERGB (245,222,179)},
1356 {"sandy brown" , PALETTERGB (244,164, 96)},
1357 {"SandyBrown" , PALETTERGB (244,164, 96)},
1358 {"tan" , PALETTERGB (210,180,140)},
1359 {"chocolate" , PALETTERGB (210,105, 30)},
1360 {"firebrick" , PALETTERGB (178,34, 34)},
1361 {"brown" , PALETTERGB (165,42, 42)},
1362 {"dark salmon" , PALETTERGB (233,150,122)},
1363 {"DarkSalmon" , PALETTERGB (233,150,122)},
1364 {"salmon" , PALETTERGB (250,128,114)},
1365 {"light salmon" , PALETTERGB (255,160,122)},
1366 {"LightSalmon" , PALETTERGB (255,160,122)},
1367 {"orange" , PALETTERGB (255,165, 0)},
1368 {"dark orange" , PALETTERGB (255,140, 0)},
1369 {"DarkOrange" , PALETTERGB (255,140, 0)},
1370 {"coral" , PALETTERGB (255,127, 80)},
1371 {"light coral" , PALETTERGB (240,128,128)},
1372 {"LightCoral" , PALETTERGB (240,128,128)},
1373 {"tomato" , PALETTERGB (255, 99, 71)},
1374 {"orange red" , PALETTERGB (255, 69, 0)},
1375 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1376 {"red" , PALETTERGB (255, 0, 0)},
1377 {"hot pink" , PALETTERGB (255,105,180)},
1378 {"HotPink" , PALETTERGB (255,105,180)},
1379 {"deep pink" , PALETTERGB (255, 20,147)},
1380 {"DeepPink" , PALETTERGB (255, 20,147)},
1381 {"pink" , PALETTERGB (255,192,203)},
1382 {"light pink" , PALETTERGB (255,182,193)},
1383 {"LightPink" , PALETTERGB (255,182,193)},
1384 {"pale violet red" , PALETTERGB (219,112,147)},
1385 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1386 {"maroon" , PALETTERGB (176, 48, 96)},
1387 {"medium violet red" , PALETTERGB (199, 21,133)},
1388 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1389 {"violet red" , PALETTERGB (208, 32,144)},
1390 {"VioletRed" , PALETTERGB (208, 32,144)},
1391 {"magenta" , PALETTERGB (255, 0,255)},
1392 {"violet" , PALETTERGB (238,130,238)},
1393 {"plum" , PALETTERGB (221,160,221)},
1394 {"orchid" , PALETTERGB (218,112,214)},
1395 {"medium orchid" , PALETTERGB (186, 85,211)},
1396 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1397 {"dark orchid" , PALETTERGB (153, 50,204)},
1398 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1399 {"dark violet" , PALETTERGB (148, 0,211)},
1400 {"DarkViolet" , PALETTERGB (148, 0,211)},
1401 {"blue violet" , PALETTERGB (138, 43,226)},
1402 {"BlueViolet" , PALETTERGB (138, 43,226)},
1403 {"purple" , PALETTERGB (160, 32,240)},
1404 {"medium purple" , PALETTERGB (147,112,219)},
1405 {"MediumPurple" , PALETTERGB (147,112,219)},
1406 {"thistle" , PALETTERGB (216,191,216)},
1407 {"gray0" , PALETTERGB ( 0, 0, 0)},
1408 {"grey0" , PALETTERGB ( 0, 0, 0)},
1409 {"dark grey" , PALETTERGB (169,169,169)},
1410 {"DarkGrey" , PALETTERGB (169,169,169)},
1411 {"dark gray" , PALETTERGB (169,169,169)},
1412 {"DarkGray" , PALETTERGB (169,169,169)},
1413 {"dark blue" , PALETTERGB ( 0, 0,139)},
1414 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1415 {"dark cyan" , PALETTERGB ( 0,139,139)},
1416 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1417 {"dark magenta" , PALETTERGB (139, 0,139)},
1418 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1419 {"dark red" , PALETTERGB (139, 0, 0)},
1420 {"DarkRed" , PALETTERGB (139, 0, 0)},
1421 {"light green" , PALETTERGB (144,238,144)},
1422 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1423};
1424
fbd6baed 1425DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
ee78dc32
GV
1426 0, 0, 0, "Return the default color map.")
1427 ()
1428{
1429 int i;
fbd6baed 1430 colormap_t *pc = w32_color_map;
ee78dc32
GV
1431 Lisp_Object cmap;
1432
1433 BLOCK_INPUT;
1434
1435 cmap = Qnil;
1436
fbd6baed 1437 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1438 pc++, i++)
1439 cmap = Fcons (Fcons (build_string (pc->name),
1440 make_number (pc->colorref)),
1441 cmap);
1442
1443 UNBLOCK_INPUT;
1444
1445 return (cmap);
1446}
ee78dc32
GV
1447
1448Lisp_Object
fbd6baed 1449w32_to_x_color (rgb)
ee78dc32
GV
1450 Lisp_Object rgb;
1451{
1452 Lisp_Object color;
1453
1454 CHECK_NUMBER (rgb, 0);
1455
1456 BLOCK_INPUT;
1457
fbd6baed 1458 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1459
1460 UNBLOCK_INPUT;
1461
1462 if (!NILP (color))
1463 return (Fcar (color));
1464 else
1465 return Qnil;
1466}
1467
5d7fed93
GV
1468COLORREF
1469w32_color_map_lookup (colorname)
1470 char *colorname;
1471{
1472 Lisp_Object tail, ret = Qnil;
1473
1474 BLOCK_INPUT;
1475
1476 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1477 {
1478 register Lisp_Object elt, tem;
1479
1480 elt = Fcar (tail);
1481 if (!CONSP (elt)) continue;
1482
1483 tem = Fcar (elt);
1484
1485 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1486 {
1487 ret = XUINT (Fcdr (elt));
1488 break;
1489 }
1490
1491 QUIT;
1492 }
1493
1494
1495 UNBLOCK_INPUT;
1496
1497 return ret;
1498}
1499
ee78dc32 1500COLORREF
fbd6baed 1501x_to_w32_color (colorname)
ee78dc32
GV
1502 char * colorname;
1503{
1504 register Lisp_Object tail, ret = Qnil;
1505
1506 BLOCK_INPUT;
1edf84e7
GV
1507
1508 if (colorname[0] == '#')
1509 {
1510 /* Could be an old-style RGB Device specification. */
1511 char *color;
1512 int size;
1513 color = colorname + 1;
1514
1515 size = strlen(color);
1516 if (size == 3 || size == 6 || size == 9 || size == 12)
1517 {
1518 UINT colorval;
1519 int i, pos;
1520 pos = 0;
1521 size /= 3;
1522 colorval = 0;
1523
1524 for (i = 0; i < 3; i++)
1525 {
1526 char *end;
1527 char t;
1528 unsigned long value;
1529
1530 /* The check for 'x' in the following conditional takes into
1531 account the fact that strtol allows a "0x" in front of
1532 our numbers, and we don't. */
1533 if (!isxdigit(color[0]) || color[1] == 'x')
1534 break;
1535 t = color[size];
1536 color[size] = '\0';
1537 value = strtoul(color, &end, 16);
1538 color[size] = t;
1539 if (errno == ERANGE || end - color != size)
1540 break;
1541 switch (size)
1542 {
1543 case 1:
1544 value = value * 0x10;
1545 break;
1546 case 2:
1547 break;
1548 case 3:
1549 value /= 0x10;
1550 break;
1551 case 4:
1552 value /= 0x100;
1553 break;
1554 }
1555 colorval |= (value << pos);
1556 pos += 0x8;
1557 if (i == 2)
1558 {
1559 UNBLOCK_INPUT;
1560 return (colorval);
1561 }
1562 color = end;
1563 }
1564 }
1565 }
1566 else if (strnicmp(colorname, "rgb:", 4) == 0)
1567 {
1568 char *color;
1569 UINT colorval;
1570 int i, pos;
1571 pos = 0;
1572
1573 colorval = 0;
1574 color = colorname + 4;
1575 for (i = 0; i < 3; i++)
1576 {
1577 char *end;
1578 unsigned long value;
1579
1580 /* The check for 'x' in the following conditional takes into
1581 account the fact that strtol allows a "0x" in front of
1582 our numbers, and we don't. */
1583 if (!isxdigit(color[0]) || color[1] == 'x')
1584 break;
1585 value = strtoul(color, &end, 16);
1586 if (errno == ERANGE)
1587 break;
1588 switch (end - color)
1589 {
1590 case 1:
1591 value = value * 0x10 + value;
1592 break;
1593 case 2:
1594 break;
1595 case 3:
1596 value /= 0x10;
1597 break;
1598 case 4:
1599 value /= 0x100;
1600 break;
1601 default:
1602 value = ULONG_MAX;
1603 }
1604 if (value == ULONG_MAX)
1605 break;
1606 colorval |= (value << pos);
1607 pos += 0x8;
1608 if (i == 2)
1609 {
1610 if (*end != '\0')
1611 break;
1612 UNBLOCK_INPUT;
1613 return (colorval);
1614 }
1615 if (*end != '/')
1616 break;
1617 color = end + 1;
1618 }
1619 }
1620 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1621 {
1622 /* This is an RGB Intensity specification. */
1623 char *color;
1624 UINT colorval;
1625 int i, pos;
1626 pos = 0;
1627
1628 colorval = 0;
1629 color = colorname + 5;
1630 for (i = 0; i < 3; i++)
1631 {
1632 char *end;
1633 double value;
1634 UINT val;
1635
1636 value = strtod(color, &end);
1637 if (errno == ERANGE)
1638 break;
1639 if (value < 0.0 || value > 1.0)
1640 break;
1641 val = (UINT)(0x100 * value);
1642 /* We used 0x100 instead of 0xFF to give an continuous
1643 range between 0.0 and 1.0 inclusive. The next statement
1644 fixes the 1.0 case. */
1645 if (val == 0x100)
1646 val = 0xFF;
1647 colorval |= (val << pos);
1648 pos += 0x8;
1649 if (i == 2)
1650 {
1651 if (*end != '\0')
1652 break;
1653 UNBLOCK_INPUT;
1654 return (colorval);
1655 }
1656 if (*end != '/')
1657 break;
1658 color = end + 1;
1659 }
1660 }
1661 /* I am not going to attempt to handle any of the CIE color schemes
1662 or TekHVC, since I don't know the algorithms for conversion to
1663 RGB. */
f695b4b1
GV
1664
1665 /* If we fail to lookup the color name in w32_color_map, then check the
1666 colorname to see if it can be crudely approximated: If the X color
1667 ends in a number (e.g., "darkseagreen2"), strip the number and
1668 return the result of looking up the base color name. */
1669 ret = w32_color_map_lookup (colorname);
1670 if (NILP (ret))
ee78dc32 1671 {
f695b4b1 1672 int len = strlen (colorname);
ee78dc32 1673
f695b4b1
GV
1674 if (isdigit (colorname[len - 1]))
1675 {
1676 char *ptr, *approx = alloca (len);
ee78dc32 1677
f695b4b1
GV
1678 strcpy (approx, colorname);
1679 ptr = &approx[len - 1];
1680 while (ptr > approx && isdigit (*ptr))
1681 *ptr-- = '\0';
ee78dc32 1682
f695b4b1 1683 ret = w32_color_map_lookup (approx);
ee78dc32 1684 }
ee78dc32
GV
1685 }
1686
1687 UNBLOCK_INPUT;
ee78dc32
GV
1688 return ret;
1689}
1690
5ac45f98
GV
1691
1692void
fbd6baed 1693w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1694{
fbd6baed 1695 struct w32_palette_entry * list;
5ac45f98
GV
1696 LOGPALETTE * log_palette;
1697 HPALETTE new_palette;
1698 int i;
1699
1700 /* don't bother trying to create palette if not supported */
fbd6baed 1701 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1702 return;
1703
1704 log_palette = (LOGPALETTE *)
1705 alloca (sizeof (LOGPALETTE) +
fbd6baed 1706 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1707 log_palette->palVersion = 0x300;
fbd6baed 1708 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1709
fbd6baed 1710 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1711 for (i = 0;
fbd6baed 1712 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1713 i++, list = list->next)
1714 log_palette->palPalEntry[i] = list->entry;
1715
1716 new_palette = CreatePalette (log_palette);
1717
1718 enter_crit ();
1719
fbd6baed
GV
1720 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1721 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1722 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1723
1724 /* Realize display palette and garbage all frames. */
1725 release_frame_dc (f, get_frame_dc (f));
1726
1727 leave_crit ();
1728}
1729
fbd6baed
GV
1730#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1731#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1732 do \
1733 { \
1734 pe.peRed = GetRValue (color); \
1735 pe.peGreen = GetGValue (color); \
1736 pe.peBlue = GetBValue (color); \
1737 pe.peFlags = 0; \
1738 } while (0)
1739
1740#if 0
1741/* Keep these around in case we ever want to track color usage. */
1742void
fbd6baed 1743w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1744{
fbd6baed 1745 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1746
fbd6baed 1747 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1748 return;
1749
1750 /* check if color is already mapped */
1751 while (list)
1752 {
fbd6baed 1753 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1754 {
1755 ++list->refcount;
1756 return;
1757 }
1758 list = list->next;
1759 }
1760
1761 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1762 list = (struct w32_palette_entry *)
1763 xmalloc (sizeof (struct w32_palette_entry));
1764 SET_W32_COLOR (list->entry, color);
5ac45f98 1765 list->refcount = 1;
fbd6baed
GV
1766 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1767 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1768 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1769
1770 /* set flag that palette must be regenerated */
fbd6baed 1771 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1772}
1773
1774void
fbd6baed 1775w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1776{
fbd6baed
GV
1777 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1778 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1779
fbd6baed 1780 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1781 return;
1782
1783 /* check if color is already mapped */
1784 while (list)
1785 {
fbd6baed 1786 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1787 {
1788 if (--list->refcount == 0)
1789 {
1790 *prev = list->next;
1791 xfree (list);
fbd6baed 1792 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1793 break;
1794 }
1795 else
1796 return;
1797 }
1798 prev = &list->next;
1799 list = list->next;
1800 }
1801
1802 /* set flag that palette must be regenerated */
fbd6baed 1803 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1804}
1805#endif
1806
6fc2811b
JR
1807
1808/* Gamma-correct COLOR on frame F. */
1809
1810void
1811gamma_correct (f, color)
1812 struct frame *f;
1813 COLORREF *color;
1814{
1815 if (f->gamma)
1816 {
1817 *color = PALETTERGB (
1818 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1819 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1820 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1821 }
1822}
1823
1824
ee78dc32
GV
1825/* Decide if color named COLOR is valid for the display associated with
1826 the selected frame; if so, return the rgb values in COLOR_DEF.
1827 If ALLOC is nonzero, allocate a new colormap cell. */
1828
1829int
6fc2811b 1830w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1831 FRAME_PTR f;
1832 char *color;
6fc2811b 1833 XColor *color_def;
ee78dc32
GV
1834 int alloc;
1835{
1836 register Lisp_Object tem;
6fc2811b 1837 COLORREF w32_color_ref;
3c190163 1838
fbd6baed 1839 tem = x_to_w32_color (color);
3c190163 1840
ee78dc32
GV
1841 if (!NILP (tem))
1842 {
d88c567c
JR
1843 if (f)
1844 {
1845 /* Apply gamma correction. */
1846 w32_color_ref = XUINT (tem);
1847 gamma_correct (f, &w32_color_ref);
1848 XSETINT (tem, w32_color_ref);
1849 }
9badad41
JR
1850
1851 /* Map this color to the palette if it is enabled. */
fbd6baed 1852 if (!NILP (Vw32_enable_palette))
5ac45f98 1853 {
fbd6baed 1854 struct w32_palette_entry * entry =
d88c567c 1855 one_w32_display_info.color_list;
fbd6baed 1856 struct w32_palette_entry ** prev =
d88c567c 1857 &one_w32_display_info.color_list;
5ac45f98
GV
1858
1859 /* check if color is already mapped */
1860 while (entry)
1861 {
fbd6baed 1862 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1863 break;
1864 prev = &entry->next;
1865 entry = entry->next;
1866 }
1867
1868 if (entry == NULL && alloc)
1869 {
1870 /* not already mapped, so add to list */
fbd6baed
GV
1871 entry = (struct w32_palette_entry *)
1872 xmalloc (sizeof (struct w32_palette_entry));
1873 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1874 entry->next = NULL;
1875 *prev = entry;
d88c567c 1876 one_w32_display_info.num_colors++;
5ac45f98
GV
1877
1878 /* set flag that palette must be regenerated */
d88c567c 1879 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1880 }
1881 }
1882 /* Ensure COLORREF value is snapped to nearest color in (default)
1883 palette by simulating the PALETTERGB macro. This works whether
1884 or not the display device has a palette. */
6fc2811b
JR
1885 w32_color_ref = XUINT (tem) | 0x2000000;
1886
6fc2811b
JR
1887 color_def->pixel = w32_color_ref;
1888 color_def->red = GetRValue (w32_color_ref);
1889 color_def->green = GetGValue (w32_color_ref);
1890 color_def->blue = GetBValue (w32_color_ref);
1891
ee78dc32 1892 return 1;
5ac45f98 1893 }
7fb46567 1894 else
3c190163
GV
1895 {
1896 return 0;
1897 }
ee78dc32
GV
1898}
1899
1900/* Given a string ARG naming a color, compute a pixel value from it
1901 suitable for screen F.
1902 If F is not a color screen, return DEF (default) regardless of what
1903 ARG says. */
1904
1905int
1906x_decode_color (f, arg, def)
1907 FRAME_PTR f;
1908 Lisp_Object arg;
1909 int def;
1910{
6fc2811b 1911 XColor cdef;
ee78dc32
GV
1912
1913 CHECK_STRING (arg, 0);
1914
1915 if (strcmp (XSTRING (arg)->data, "black") == 0)
1916 return BLACK_PIX_DEFAULT (f);
1917 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1918 return WHITE_PIX_DEFAULT (f);
1919
fbd6baed 1920 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1921 return def;
1922
6fc2811b 1923 /* w32_defined_color is responsible for coping with failures
ee78dc32 1924 by looking for a near-miss. */
6fc2811b
JR
1925 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1926 return cdef.pixel;
ee78dc32
GV
1927
1928 /* defined_color failed; return an ultimate default. */
1929 return def;
1930}
1931\f
dfff8a69
JR
1932/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1933 the previous value of that parameter, NEW_VALUE is the new value. */
1934
1935static void
1936x_set_line_spacing (f, new_value, old_value)
1937 struct frame *f;
1938 Lisp_Object new_value, old_value;
1939{
1940 if (NILP (new_value))
1941 f->extra_line_spacing = 0;
1942 else if (NATNUMP (new_value))
1943 f->extra_line_spacing = XFASTINT (new_value);
1944 else
1a948b17 1945 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
1946 Fcons (new_value, Qnil)));
1947 if (FRAME_VISIBLE_P (f))
1948 redraw_frame (f);
1949}
1950
1951
6fc2811b
JR
1952/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1953 the previous value of that parameter, NEW_VALUE is the new value. */
1954
1955static void
1956x_set_screen_gamma (f, new_value, old_value)
1957 struct frame *f;
1958 Lisp_Object new_value, old_value;
1959{
1960 if (NILP (new_value))
1961 f->gamma = 0;
1962 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1963 /* The value 0.4545 is the normal viewing gamma. */
1964 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1965 else
1a948b17 1966 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
1967 Fcons (new_value, Qnil)));
1968
1969 clear_face_cache (0);
1970}
1971
1972
ee78dc32
GV
1973/* Functions called only from `x_set_frame_param'
1974 to set individual parameters.
1975
fbd6baed 1976 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1977 the frame is being created and its window does not exist yet.
1978 In that case, just record the parameter's new value
1979 in the standard place; do not attempt to change the window. */
1980
1981void
1982x_set_foreground_color (f, arg, oldval)
1983 struct frame *f;
1984 Lisp_Object arg, oldval;
1985{
6fc2811b 1986 FRAME_FOREGROUND_PIXEL (f)
ee78dc32 1987 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
5ac45f98 1988
fbd6baed 1989 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1990 {
6fc2811b 1991 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
1992 if (FRAME_VISIBLE_P (f))
1993 redraw_frame (f);
1994 }
1995}
1996
1997void
1998x_set_background_color (f, arg, oldval)
1999 struct frame *f;
2000 Lisp_Object arg, oldval;
2001{
6fc2811b 2002 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2003 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2004
fbd6baed 2005 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2006 {
6fc2811b
JR
2007 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2008 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2009
6fc2811b 2010 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2011
2012 if (FRAME_VISIBLE_P (f))
2013 redraw_frame (f);
2014 }
2015}
2016
2017void
2018x_set_mouse_color (f, arg, oldval)
2019 struct frame *f;
2020 Lisp_Object arg, oldval;
2021{
ee78dc32 2022 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2023 int count;
ee78dc32
GV
2024 int mask_color;
2025
2026 if (!EQ (Qnil, arg))
fbd6baed 2027 f->output_data.w32->mouse_pixel
ee78dc32 2028 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2029 mask_color = FRAME_BACKGROUND_PIXEL (f);
2030
2031 /* Don't let pointers be invisible. */
fbd6baed 2032 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2033 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2034 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2035
767b1ff0 2036#if 0 /* TODO : cursor changes */
ee78dc32
GV
2037 BLOCK_INPUT;
2038
2039 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2040 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2041
2042 if (!EQ (Qnil, Vx_pointer_shape))
2043 {
2044 CHECK_NUMBER (Vx_pointer_shape, 0);
fbd6baed 2045 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2046 }
2047 else
fbd6baed
GV
2048 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2049 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2050
2051 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2052 {
2053 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
fbd6baed 2054 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2055 XINT (Vx_nontext_pointer_shape));
2056 }
2057 else
fbd6baed
GV
2058 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2059 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2060
6fc2811b
JR
2061 if (!EQ (Qnil, Vx_busy_pointer_shape))
2062 {
2063 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
2064 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2065 XINT (Vx_busy_pointer_shape));
2066 }
2067 else
2068 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2069 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2070
2071 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2072 if (!EQ (Qnil, Vx_mode_pointer_shape))
2073 {
2074 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
fbd6baed 2075 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2076 XINT (Vx_mode_pointer_shape));
2077 }
2078 else
fbd6baed
GV
2079 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2080 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2081
2082 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2083 {
2084 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2085 cross_cursor
fbd6baed 2086 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2087 XINT (Vx_sensitive_text_pointer_shape));
2088 }
2089 else
fbd6baed 2090 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2091
4694d762
JR
2092 if (!NILP (Vx_window_horizontal_drag_shape))
2093 {
2094 CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
2095 horizontal_drag_cursor
2096 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2097 XINT (Vx_window_horizontal_drag_shape));
2098 }
2099 else
2100 horizontal_drag_cursor
2101 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2102
ee78dc32 2103 /* Check and report errors with the above calls. */
fbd6baed 2104 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2105 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2106
2107 {
2108 XColor fore_color, back_color;
2109
fbd6baed 2110 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2111 back_color.pixel = mask_color;
fbd6baed
GV
2112 XQueryColor (FRAME_W32_DISPLAY (f),
2113 DefaultColormap (FRAME_W32_DISPLAY (f),
2114 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2115 &fore_color);
fbd6baed
GV
2116 XQueryColor (FRAME_W32_DISPLAY (f),
2117 DefaultColormap (FRAME_W32_DISPLAY (f),
2118 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2119 &back_color);
fbd6baed 2120 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2121 &fore_color, &back_color);
fbd6baed 2122 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2123 &fore_color, &back_color);
fbd6baed 2124 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2125 &fore_color, &back_color);
fbd6baed 2126 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2127 &fore_color, &back_color);
6fc2811b
JR
2128 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2129 &fore_color, &back_color);
ee78dc32
GV
2130 }
2131
fbd6baed 2132 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2133 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2134
fbd6baed
GV
2135 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2136 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2137 f->output_data.w32->text_cursor = cursor;
2138
2139 if (nontext_cursor != f->output_data.w32->nontext_cursor
2140 && f->output_data.w32->nontext_cursor != 0)
2141 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2142 f->output_data.w32->nontext_cursor = nontext_cursor;
2143
6fc2811b
JR
2144 if (busy_cursor != f->output_data.w32->busy_cursor
2145 && f->output_data.w32->busy_cursor != 0)
2146 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2147 f->output_data.w32->busy_cursor = busy_cursor;
2148
fbd6baed
GV
2149 if (mode_cursor != f->output_data.w32->modeline_cursor
2150 && f->output_data.w32->modeline_cursor != 0)
2151 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2152 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2153
fbd6baed
GV
2154 if (cross_cursor != f->output_data.w32->cross_cursor
2155 && f->output_data.w32->cross_cursor != 0)
2156 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2157 f->output_data.w32->cross_cursor = cross_cursor;
2158
2159 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2160 UNBLOCK_INPUT;
6fc2811b
JR
2161
2162 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2163#endif /* TODO */
ee78dc32
GV
2164}
2165
70a0239a
JR
2166/* Defined in w32term.c. */
2167void x_update_cursor (struct frame *f, int on_p);
2168
ee78dc32
GV
2169void
2170x_set_cursor_color (f, arg, oldval)
2171 struct frame *f;
2172 Lisp_Object arg, oldval;
2173{
70a0239a 2174 unsigned long fore_pixel, pixel;
ee78dc32 2175
dfff8a69 2176 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2177 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2178 WHITE_PIX_DEFAULT (f));
ee78dc32 2179 else
6fc2811b 2180 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2181
6759f872 2182 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2183
2184 /* Make sure that the cursor color differs from the background color. */
70a0239a 2185 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2186 {
70a0239a
JR
2187 pixel = f->output_data.w32->mouse_pixel;
2188 if (pixel == fore_pixel)
6fc2811b 2189 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2190 }
70a0239a 2191
6fc2811b 2192 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
70a0239a 2193 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2194
fbd6baed 2195 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2196 {
2197 if (FRAME_VISIBLE_P (f))
2198 {
70a0239a
JR
2199 x_update_cursor (f, 0);
2200 x_update_cursor (f, 1);
ee78dc32
GV
2201 }
2202 }
6fc2811b
JR
2203
2204 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2205}
2206
33d52f9c
GV
2207/* Set the border-color of frame F to pixel value PIX.
2208 Note that this does not fully take effect if done before
2209 F has an window. */
2210void
2211x_set_border_pixel (f, pix)
2212 struct frame *f;
2213 int pix;
2214{
2215 f->output_data.w32->border_pixel = pix;
2216
2217 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2218 {
2219 if (FRAME_VISIBLE_P (f))
2220 redraw_frame (f);
2221 }
2222}
2223
ee78dc32
GV
2224/* Set the border-color of frame F to value described by ARG.
2225 ARG can be a string naming a color.
2226 The border-color is used for the border that is drawn by the server.
2227 Note that this does not fully take effect if done before
2228 F has a window; it must be redone when the window is created. */
2229
2230void
2231x_set_border_color (f, arg, oldval)
2232 struct frame *f;
2233 Lisp_Object arg, oldval;
2234{
ee78dc32
GV
2235 int pix;
2236
2237 CHECK_STRING (arg, 0);
ee78dc32 2238 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2239 x_set_border_pixel (f, pix);
6fc2811b 2240 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2241}
2242
dfff8a69
JR
2243/* Value is the internal representation of the specified cursor type
2244 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2245 of the bar cursor. */
2246
2247enum text_cursor_kinds
2248x_specified_cursor_type (arg, width)
2249 Lisp_Object arg;
2250 int *width;
ee78dc32 2251{
dfff8a69
JR
2252 enum text_cursor_kinds type;
2253
ee78dc32
GV
2254 if (EQ (arg, Qbar))
2255 {
dfff8a69
JR
2256 type = BAR_CURSOR;
2257 *width = 2;
ee78dc32 2258 }
dfff8a69
JR
2259 else if (CONSP (arg)
2260 && EQ (XCAR (arg), Qbar)
2261 && INTEGERP (XCDR (arg))
2262 && XINT (XCDR (arg)) >= 0)
ee78dc32 2263 {
dfff8a69
JR
2264 type = BAR_CURSOR;
2265 *width = XINT (XCDR (arg));
ee78dc32 2266 }
dfff8a69
JR
2267 else if (NILP (arg))
2268 type = NO_CURSOR;
ee78dc32
GV
2269 else
2270 /* Treat anything unknown as "box cursor".
2271 It was bad to signal an error; people have trouble fixing
2272 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2273 type = FILLED_BOX_CURSOR;
2274
2275 return type;
2276}
2277
2278void
2279x_set_cursor_type (f, arg, oldval)
2280 FRAME_PTR f;
2281 Lisp_Object arg, oldval;
2282{
2283 int width;
2284
2285 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2286 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2287
2288 /* Make sure the cursor gets redrawn. This is overkill, but how
2289 often do people change cursor types? */
2290 update_mode_lines++;
2291}
dfff8a69 2292\f
ee78dc32
GV
2293void
2294x_set_icon_type (f, arg, oldval)
2295 struct frame *f;
2296 Lisp_Object arg, oldval;
2297{
ee78dc32
GV
2298 int result;
2299
eb7576ce
GV
2300 if (NILP (arg) && NILP (oldval))
2301 return;
2302
2303 if (STRINGP (arg) && STRINGP (oldval)
2304 && EQ (Fstring_equal (oldval, arg), Qt))
2305 return;
2306
2307 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2308 return;
2309
2310 BLOCK_INPUT;
ee78dc32 2311
eb7576ce 2312 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2313 if (result)
2314 {
2315 UNBLOCK_INPUT;
2316 error ("No icon window available");
2317 }
2318
ee78dc32 2319 UNBLOCK_INPUT;
ee78dc32
GV
2320}
2321
2322/* Return non-nil if frame F wants a bitmap icon. */
2323
2324Lisp_Object
2325x_icon_type (f)
2326 FRAME_PTR f;
2327{
2328 Lisp_Object tem;
2329
2330 tem = assq_no_quit (Qicon_type, f->param_alist);
2331 if (CONSP (tem))
8e713be6 2332 return XCDR (tem);
ee78dc32
GV
2333 else
2334 return Qnil;
2335}
2336
2337void
2338x_set_icon_name (f, arg, oldval)
2339 struct frame *f;
2340 Lisp_Object arg, oldval;
2341{
ee78dc32
GV
2342 int result;
2343
2344 if (STRINGP (arg))
2345 {
2346 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2347 return;
2348 }
2349 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2350 return;
2351
2352 f->icon_name = arg;
2353
2354#if 0
fbd6baed 2355 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2356 return;
2357
2358 BLOCK_INPUT;
2359
2360 result = x_text_icon (f,
1edf84e7 2361 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2362 ? f->icon_name
1edf84e7
GV
2363 : !NILP (f->title)
2364 ? f->title
ee78dc32
GV
2365 : f->name))->data);
2366
2367 if (result)
2368 {
2369 UNBLOCK_INPUT;
2370 error ("No icon window available");
2371 }
2372
2373 /* If the window was unmapped (and its icon was mapped),
2374 the new icon is not mapped, so map the window in its stead. */
2375 if (FRAME_VISIBLE_P (f))
2376 {
2377#ifdef USE_X_TOOLKIT
fbd6baed 2378 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2379#endif
fbd6baed 2380 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2381 }
2382
fbd6baed 2383 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2384 UNBLOCK_INPUT;
2385#endif
2386}
2387
2388extern Lisp_Object x_new_font ();
4587b026 2389extern Lisp_Object x_new_fontset();
ee78dc32
GV
2390
2391void
2392x_set_font (f, arg, oldval)
2393 struct frame *f;
2394 Lisp_Object arg, oldval;
2395{
2396 Lisp_Object result;
4587b026 2397 Lisp_Object fontset_name;
4b817373 2398 Lisp_Object frame;
ee78dc32
GV
2399
2400 CHECK_STRING (arg, 1);
2401
4587b026
GV
2402 fontset_name = Fquery_fontset (arg, Qnil);
2403
ee78dc32 2404 BLOCK_INPUT;
4587b026
GV
2405 result = (STRINGP (fontset_name)
2406 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2407 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2408 UNBLOCK_INPUT;
2409
2410 if (EQ (result, Qnil))
dfff8a69 2411 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2412 else if (EQ (result, Qt))
dfff8a69 2413 error ("The characters of the given font have varying widths");
ee78dc32
GV
2414 else if (STRINGP (result))
2415 {
ee78dc32 2416 store_frame_param (f, Qfont, result);
6fc2811b 2417 recompute_basic_faces (f);
ee78dc32
GV
2418 }
2419 else
2420 abort ();
4b817373 2421
6fc2811b
JR
2422 do_pending_window_change (0);
2423
2424 /* Don't call `face-set-after-frame-default' when faces haven't been
2425 initialized yet. This is the case when called from
2426 Fx_create_frame. In that case, the X widget or window doesn't
2427 exist either, and we can end up in x_report_frame_params with a
2428 null widget which gives a segfault. */
2429 if (FRAME_FACE_CACHE (f))
2430 {
2431 XSETFRAME (frame, f);
2432 call1 (Qface_set_after_frame_default, frame);
2433 }
ee78dc32
GV
2434}
2435
2436void
2437x_set_border_width (f, arg, oldval)
2438 struct frame *f;
2439 Lisp_Object arg, oldval;
2440{
2441 CHECK_NUMBER (arg, 0);
2442
fbd6baed 2443 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2444 return;
2445
fbd6baed 2446 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2447 error ("Cannot change the border width of a window");
2448
fbd6baed 2449 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2450}
2451
2452void
2453x_set_internal_border_width (f, arg, oldval)
2454 struct frame *f;
2455 Lisp_Object arg, oldval;
2456{
fbd6baed 2457 int old = f->output_data.w32->internal_border_width;
ee78dc32
GV
2458
2459 CHECK_NUMBER (arg, 0);
fbd6baed
GV
2460 f->output_data.w32->internal_border_width = XINT (arg);
2461 if (f->output_data.w32->internal_border_width < 0)
2462 f->output_data.w32->internal_border_width = 0;
ee78dc32 2463
fbd6baed 2464 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2465 return;
2466
fbd6baed 2467 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2468 {
ee78dc32 2469 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2470 SET_FRAME_GARBAGED (f);
6fc2811b 2471 do_pending_window_change (0);
ee78dc32
GV
2472 }
2473}
2474
2475void
2476x_set_visibility (f, value, oldval)
2477 struct frame *f;
2478 Lisp_Object value, oldval;
2479{
2480 Lisp_Object frame;
2481 XSETFRAME (frame, f);
2482
2483 if (NILP (value))
2484 Fmake_frame_invisible (frame, Qt);
2485 else if (EQ (value, Qicon))
2486 Ficonify_frame (frame);
2487 else
2488 Fmake_frame_visible (frame);
2489}
2490
a1258667
JR
2491\f
2492/* Change window heights in windows rooted in WINDOW by N lines. */
2493
2494static void
2495x_change_window_heights (window, n)
2496 Lisp_Object window;
2497 int n;
2498{
2499 struct window *w = XWINDOW (window);
2500
2501 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2502 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2503
2504 if (INTEGERP (w->orig_top))
2505 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2506 if (INTEGERP (w->orig_height))
2507 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2508
2509 /* Handle just the top child in a vertical split. */
2510 if (!NILP (w->vchild))
2511 x_change_window_heights (w->vchild, n);
2512
2513 /* Adjust all children in a horizontal split. */
2514 for (window = w->hchild; !NILP (window); window = w->next)
2515 {
2516 w = XWINDOW (window);
2517 x_change_window_heights (window, n);
2518 }
2519}
2520
ee78dc32
GV
2521void
2522x_set_menu_bar_lines (f, value, oldval)
2523 struct frame *f;
2524 Lisp_Object value, oldval;
2525{
2526 int nlines;
2527 int olines = FRAME_MENU_BAR_LINES (f);
2528
2529 /* Right now, menu bars don't work properly in minibuf-only frames;
2530 most of the commands try to apply themselves to the minibuffer
6fc2811b 2531 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2532 in or split the minibuffer window. */
2533 if (FRAME_MINIBUF_ONLY_P (f))
2534 return;
2535
2536 if (INTEGERP (value))
2537 nlines = XINT (value);
2538 else
2539 nlines = 0;
2540
2541 FRAME_MENU_BAR_LINES (f) = 0;
2542 if (nlines)
2543 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2544 else
2545 {
2546 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2547 free_frame_menubar (f);
2548 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2549
2550 /* Adjust the frame size so that the client (text) dimensions
2551 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2552 set correctly. */
2553 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2554 do_pending_window_change (0);
ee78dc32 2555 }
6fc2811b
JR
2556 adjust_glyphs (f);
2557}
2558
2559
2560/* Set the number of lines used for the tool bar of frame F to VALUE.
2561 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2562 is the old number of tool bar lines. This function changes the
2563 height of all windows on frame F to match the new tool bar height.
2564 The frame's height doesn't change. */
2565
2566void
2567x_set_tool_bar_lines (f, value, oldval)
2568 struct frame *f;
2569 Lisp_Object value, oldval;
2570{
36f8209a
JR
2571 int delta, nlines, root_height;
2572 Lisp_Object root_window;
6fc2811b
JR
2573
2574 /* Use VALUE only if an integer >= 0. */
2575 if (INTEGERP (value) && XINT (value) >= 0)
2576 nlines = XFASTINT (value);
2577 else
2578 nlines = 0;
2579
2580 /* Make sure we redisplay all windows in this frame. */
2581 ++windows_or_buffers_changed;
2582
2583 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2584
2585 /* Don't resize the tool-bar to more than we have room for. */
2586 root_window = FRAME_ROOT_WINDOW (f);
2587 root_height = XINT (XWINDOW (root_window)->height);
2588 if (root_height - delta < 1)
2589 {
2590 delta = root_height - 1;
2591 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2592 }
2593
6fc2811b 2594 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2595 x_change_window_heights (root_window, delta);
6fc2811b 2596 adjust_glyphs (f);
36f8209a
JR
2597
2598 /* We also have to make sure that the internal border at the top of
2599 the frame, below the menu bar or tool bar, is redrawn when the
2600 tool bar disappears. This is so because the internal border is
2601 below the tool bar if one is displayed, but is below the menu bar
2602 if there isn't a tool bar. The tool bar draws into the area
2603 below the menu bar. */
2604 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2605 {
2606 updating_frame = f;
2607 clear_frame ();
2608 clear_current_matrices (f);
2609 updating_frame = NULL;
2610 }
2611
2612 /* If the tool bar gets smaller, the internal border below it
2613 has to be cleared. It was formerly part of the display
2614 of the larger tool bar, and updating windows won't clear it. */
2615 if (delta < 0)
2616 {
2617 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2618 int width = PIXEL_WIDTH (f);
2619 int y = nlines * CANON_Y_UNIT (f);
2620
2621 BLOCK_INPUT;
2622 {
2623 HDC hdc = get_frame_dc (f);
2624 w32_clear_area (f, hdc, 0, y, width, height);
2625 release_frame_dc (f, hdc);
2626 }
2627 UNBLOCK_INPUT;
2628 }
ee78dc32
GV
2629}
2630
6fc2811b 2631
ee78dc32 2632/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2633 w32_id_name.
ee78dc32
GV
2634
2635 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2636 name; if NAME is a string, set F's name to NAME and set
2637 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2638
2639 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2640 suggesting a new name, which lisp code should override; if
2641 F->explicit_name is set, ignore the new name; otherwise, set it. */
2642
2643void
2644x_set_name (f, name, explicit)
2645 struct frame *f;
2646 Lisp_Object name;
2647 int explicit;
2648{
2649 /* Make sure that requests from lisp code override requests from
2650 Emacs redisplay code. */
2651 if (explicit)
2652 {
2653 /* If we're switching from explicit to implicit, we had better
2654 update the mode lines and thereby update the title. */
2655 if (f->explicit_name && NILP (name))
2656 update_mode_lines = 1;
2657
2658 f->explicit_name = ! NILP (name);
2659 }
2660 else if (f->explicit_name)
2661 return;
2662
fbd6baed 2663 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2664 if (NILP (name))
2665 {
2666 /* Check for no change needed in this very common case
2667 before we do any consing. */
fbd6baed 2668 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2669 XSTRING (f->name)->data))
2670 return;
fbd6baed 2671 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2672 }
2673 else
2674 CHECK_STRING (name, 0);
2675
2676 /* Don't change the name if it's already NAME. */
2677 if (! NILP (Fstring_equal (name, f->name)))
2678 return;
2679
1edf84e7
GV
2680 f->name = name;
2681
2682 /* For setting the frame title, the title parameter should override
2683 the name parameter. */
2684 if (! NILP (f->title))
2685 name = f->title;
2686
fbd6baed 2687 if (FRAME_W32_WINDOW (f))
ee78dc32 2688 {
6fc2811b 2689 if (STRING_MULTIBYTE (name))
dfff8a69 2690 name = ENCODE_SYSTEM (name);
6fc2811b 2691
ee78dc32 2692 BLOCK_INPUT;
fbd6baed 2693 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2694 UNBLOCK_INPUT;
2695 }
ee78dc32
GV
2696}
2697
2698/* This function should be called when the user's lisp code has
2699 specified a name for the frame; the name will override any set by the
2700 redisplay code. */
2701void
2702x_explicitly_set_name (f, arg, oldval)
2703 FRAME_PTR f;
2704 Lisp_Object arg, oldval;
2705{
2706 x_set_name (f, arg, 1);
2707}
2708
2709/* This function should be called by Emacs redisplay code to set the
2710 name; names set this way will never override names set by the user's
2711 lisp code. */
2712void
2713x_implicitly_set_name (f, arg, oldval)
2714 FRAME_PTR f;
2715 Lisp_Object arg, oldval;
2716{
2717 x_set_name (f, arg, 0);
2718}
1edf84e7
GV
2719\f
2720/* Change the title of frame F to NAME.
2721 If NAME is nil, use the frame name as the title.
2722
2723 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2724 name; if NAME is a string, set F's name to NAME and set
2725 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2726
2727 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2728 suggesting a new name, which lisp code should override; if
2729 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2730
1edf84e7 2731void
6fc2811b 2732x_set_title (f, name, old_name)
1edf84e7 2733 struct frame *f;
6fc2811b 2734 Lisp_Object name, old_name;
1edf84e7
GV
2735{
2736 /* Don't change the title if it's already NAME. */
2737 if (EQ (name, f->title))
2738 return;
2739
2740 update_mode_lines = 1;
2741
2742 f->title = name;
2743
2744 if (NILP (name))
2745 name = f->name;
2746
2747 if (FRAME_W32_WINDOW (f))
2748 {
6fc2811b 2749 if (STRING_MULTIBYTE (name))
dfff8a69 2750 name = ENCODE_SYSTEM (name);
6fc2811b 2751
1edf84e7
GV
2752 BLOCK_INPUT;
2753 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2754 UNBLOCK_INPUT;
2755 }
2756}
2757\f
ee78dc32
GV
2758void
2759x_set_autoraise (f, arg, oldval)
2760 struct frame *f;
2761 Lisp_Object arg, oldval;
2762{
2763 f->auto_raise = !EQ (Qnil, arg);
2764}
2765
2766void
2767x_set_autolower (f, arg, oldval)
2768 struct frame *f;
2769 Lisp_Object arg, oldval;
2770{
2771 f->auto_lower = !EQ (Qnil, arg);
2772}
2773
2774void
2775x_set_unsplittable (f, arg, oldval)
2776 struct frame *f;
2777 Lisp_Object arg, oldval;
2778{
2779 f->no_split = !NILP (arg);
2780}
2781
2782void
2783x_set_vertical_scroll_bars (f, arg, oldval)
2784 struct frame *f;
2785 Lisp_Object arg, oldval;
2786{
1026b400
RS
2787 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2788 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2789 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2790 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2791 {
1026b400
RS
2792 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2793 vertical_scroll_bar_none :
87996783
GV
2794 /* Put scroll bars on the right by default, as is conventional
2795 on MS-Windows. */
2796 EQ (Qleft, arg)
2797 ? vertical_scroll_bar_left
2798 : vertical_scroll_bar_right;
ee78dc32
GV
2799
2800 /* We set this parameter before creating the window for the
2801 frame, so we can get the geometry right from the start.
2802 However, if the window hasn't been created yet, we shouldn't
2803 call x_set_window_size. */
fbd6baed 2804 if (FRAME_W32_WINDOW (f))
ee78dc32 2805 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2806 do_pending_window_change (0);
ee78dc32
GV
2807 }
2808}
2809
2810void
2811x_set_scroll_bar_width (f, arg, oldval)
2812 struct frame *f;
2813 Lisp_Object arg, oldval;
2814{
6fc2811b
JR
2815 int wid = FONT_WIDTH (f->output_data.w32->font);
2816
ee78dc32
GV
2817 if (NILP (arg))
2818 {
6fc2811b
JR
2819 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2820 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2821 wid - 1) / wid;
2822 if (FRAME_W32_WINDOW (f))
2823 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2824 do_pending_window_change (0);
ee78dc32
GV
2825 }
2826 else if (INTEGERP (arg) && XINT (arg) > 0
2827 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2828 {
ee78dc32 2829 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2830 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2831 + wid-1) / wid;
fbd6baed 2832 if (FRAME_W32_WINDOW (f))
ee78dc32 2833 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2834 do_pending_window_change (0);
ee78dc32 2835 }
6fc2811b
JR
2836 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2837 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2838 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2839}
2840\f
2841/* Subroutines of creating an frame. */
2842
2843/* Make sure that Vx_resource_name is set to a reasonable value.
2844 Fix it up, or set it to `emacs' if it is too hopeless. */
2845
2846static void
2847validate_x_resource_name ()
2848{
6fc2811b 2849 int len = 0;
ee78dc32
GV
2850 /* Number of valid characters in the resource name. */
2851 int good_count = 0;
2852 /* Number of invalid characters in the resource name. */
2853 int bad_count = 0;
2854 Lisp_Object new;
2855 int i;
2856
2857 if (STRINGP (Vx_resource_name))
2858 {
2859 unsigned char *p = XSTRING (Vx_resource_name)->data;
2860 int i;
2861
dfff8a69 2862 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2863
2864 /* Only letters, digits, - and _ are valid in resource names.
2865 Count the valid characters and count the invalid ones. */
2866 for (i = 0; i < len; i++)
2867 {
2868 int c = p[i];
2869 if (! ((c >= 'a' && c <= 'z')
2870 || (c >= 'A' && c <= 'Z')
2871 || (c >= '0' && c <= '9')
2872 || c == '-' || c == '_'))
2873 bad_count++;
2874 else
2875 good_count++;
2876 }
2877 }
2878 else
2879 /* Not a string => completely invalid. */
2880 bad_count = 5, good_count = 0;
2881
2882 /* If name is valid already, return. */
2883 if (bad_count == 0)
2884 return;
2885
2886 /* If name is entirely invalid, or nearly so, use `emacs'. */
2887 if (good_count == 0
2888 || (good_count == 1 && bad_count > 0))
2889 {
2890 Vx_resource_name = build_string ("emacs");
2891 return;
2892 }
2893
2894 /* Name is partly valid. Copy it and replace the invalid characters
2895 with underscores. */
2896
2897 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2898
2899 for (i = 0; i < len; i++)
2900 {
2901 int c = XSTRING (new)->data[i];
2902 if (! ((c >= 'a' && c <= 'z')
2903 || (c >= 'A' && c <= 'Z')
2904 || (c >= '0' && c <= '9')
2905 || c == '-' || c == '_'))
2906 XSTRING (new)->data[i] = '_';
2907 }
2908}
2909
2910
2911extern char *x_get_string_resource ();
2912
2913DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2914 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2915This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2916class, where INSTANCE is the name under which Emacs was invoked, or\n\
2917the name specified by the `-name' or `-rn' command-line arguments.\n\
2918\n\
2919The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2920class, respectively. You must specify both of them or neither.\n\
2921If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2922and the class is `Emacs.CLASS.SUBCLASS'.")
2923 (attribute, class, component, subclass)
2924 Lisp_Object attribute, class, component, subclass;
2925{
2926 register char *value;
2927 char *name_key;
2928 char *class_key;
2929
2930 CHECK_STRING (attribute, 0);
2931 CHECK_STRING (class, 0);
2932
2933 if (!NILP (component))
2934 CHECK_STRING (component, 1);
2935 if (!NILP (subclass))
2936 CHECK_STRING (subclass, 2);
2937 if (NILP (component) != NILP (subclass))
2938 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2939
2940 validate_x_resource_name ();
2941
2942 /* Allocate space for the components, the dots which separate them,
2943 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 2944 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 2945 + (STRINGP (component)
dfff8a69
JR
2946 ? STRING_BYTES (XSTRING (component)) : 0)
2947 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
2948 + 3);
2949
2950 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 2951 + STRING_BYTES (XSTRING (class))
ee78dc32 2952 + (STRINGP (subclass)
dfff8a69 2953 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
2954 + 3);
2955
2956 /* Start with emacs.FRAMENAME for the name (the specific one)
2957 and with `Emacs' for the class key (the general one). */
2958 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2959 strcpy (class_key, EMACS_CLASS);
2960
2961 strcat (class_key, ".");
2962 strcat (class_key, XSTRING (class)->data);
2963
2964 if (!NILP (component))
2965 {
2966 strcat (class_key, ".");
2967 strcat (class_key, XSTRING (subclass)->data);
2968
2969 strcat (name_key, ".");
2970 strcat (name_key, XSTRING (component)->data);
2971 }
2972
2973 strcat (name_key, ".");
2974 strcat (name_key, XSTRING (attribute)->data);
2975
2976 value = x_get_string_resource (Qnil,
2977 name_key, class_key);
2978
2979 if (value != (char *) 0)
2980 return build_string (value);
2981 else
2982 return Qnil;
2983}
2984
2985/* Used when C code wants a resource value. */
2986
2987char *
2988x_get_resource_string (attribute, class)
2989 char *attribute, *class;
2990{
ee78dc32
GV
2991 char *name_key;
2992 char *class_key;
6fc2811b 2993 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
2994
2995 /* Allocate space for the components, the dots which separate them,
2996 and the final '\0'. */
dfff8a69 2997 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
2998 + strlen (attribute) + 2);
2999 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3000 + strlen (class) + 2);
3001
3002 sprintf (name_key, "%s.%s",
3003 XSTRING (Vinvocation_name)->data,
3004 attribute);
3005 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3006
6fc2811b 3007 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3008}
3009
3010/* Types we might convert a resource string into. */
3011enum resource_types
6fc2811b
JR
3012{
3013 RES_TYPE_NUMBER,
3014 RES_TYPE_FLOAT,
3015 RES_TYPE_BOOLEAN,
3016 RES_TYPE_STRING,
3017 RES_TYPE_SYMBOL
3018};
ee78dc32
GV
3019
3020/* Return the value of parameter PARAM.
3021
3022 First search ALIST, then Vdefault_frame_alist, then the X defaults
3023 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3024
3025 Convert the resource to the type specified by desired_type.
3026
3027 If no default is specified, return Qunbound. If you call
6fc2811b 3028 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3029 and don't let it get stored in any Lisp-visible variables! */
3030
3031static Lisp_Object
6fc2811b 3032w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3033 Lisp_Object alist, param;
3034 char *attribute;
3035 char *class;
3036 enum resource_types type;
3037{
3038 register Lisp_Object tem;
3039
3040 tem = Fassq (param, alist);
3041 if (EQ (tem, Qnil))
3042 tem = Fassq (param, Vdefault_frame_alist);
3043 if (EQ (tem, Qnil))
3044 {
3045
3046 if (attribute)
3047 {
3048 tem = Fx_get_resource (build_string (attribute),
3049 build_string (class),
3050 Qnil, Qnil);
3051
3052 if (NILP (tem))
3053 return Qunbound;
3054
3055 switch (type)
3056 {
6fc2811b 3057 case RES_TYPE_NUMBER:
ee78dc32
GV
3058 return make_number (atoi (XSTRING (tem)->data));
3059
6fc2811b
JR
3060 case RES_TYPE_FLOAT:
3061 return make_float (atof (XSTRING (tem)->data));
3062
3063 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3064 tem = Fdowncase (tem);
3065 if (!strcmp (XSTRING (tem)->data, "on")
3066 || !strcmp (XSTRING (tem)->data, "true"))
3067 return Qt;
3068 else
3069 return Qnil;
3070
6fc2811b 3071 case RES_TYPE_STRING:
ee78dc32
GV
3072 return tem;
3073
6fc2811b 3074 case RES_TYPE_SYMBOL:
ee78dc32
GV
3075 /* As a special case, we map the values `true' and `on'
3076 to Qt, and `false' and `off' to Qnil. */
3077 {
3078 Lisp_Object lower;
3079 lower = Fdowncase (tem);
3080 if (!strcmp (XSTRING (lower)->data, "on")
3081 || !strcmp (XSTRING (lower)->data, "true"))
3082 return Qt;
3083 else if (!strcmp (XSTRING (lower)->data, "off")
3084 || !strcmp (XSTRING (lower)->data, "false"))
3085 return Qnil;
3086 else
3087 return Fintern (tem, Qnil);
3088 }
3089
3090 default:
3091 abort ();
3092 }
3093 }
3094 else
3095 return Qunbound;
3096 }
3097 return Fcdr (tem);
3098}
3099
3100/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3101 of the parameter named PROP (a Lisp symbol).
3102 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3103 on the frame named NAME.
3104 If that is not found either, use the value DEFLT. */
3105
3106static Lisp_Object
3107x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3108 struct frame *f;
3109 Lisp_Object alist;
3110 Lisp_Object prop;
3111 Lisp_Object deflt;
3112 char *xprop;
3113 char *xclass;
3114 enum resource_types type;
3115{
3116 Lisp_Object tem;
3117
6fc2811b 3118 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3119 if (EQ (tem, Qunbound))
3120 tem = deflt;
3121 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3122 return tem;
3123}
3124\f
3125DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3126 "Parse an X-style geometry string STRING.\n\
3127Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3128The properties returned may include `top', `left', `height', and `width'.\n\
3129The value of `left' or `top' may be an integer,\n\
3130or a list (+ N) meaning N pixels relative to top/left corner,\n\
3131or a list (- N) meaning -N pixels relative to bottom/right corner.")
3132 (string)
3133 Lisp_Object string;
3134{
3135 int geometry, x, y;
3136 unsigned int width, height;
3137 Lisp_Object result;
3138
3139 CHECK_STRING (string, 0);
3140
3141 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3142 &x, &y, &width, &height);
3143
3144 result = Qnil;
3145 if (geometry & XValue)
3146 {
3147 Lisp_Object element;
3148
3149 if (x >= 0 && (geometry & XNegative))
3150 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3151 else if (x < 0 && ! (geometry & XNegative))
3152 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3153 else
3154 element = Fcons (Qleft, make_number (x));
3155 result = Fcons (element, result);
3156 }
3157
3158 if (geometry & YValue)
3159 {
3160 Lisp_Object element;
3161
3162 if (y >= 0 && (geometry & YNegative))
3163 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3164 else if (y < 0 && ! (geometry & YNegative))
3165 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3166 else
3167 element = Fcons (Qtop, make_number (y));
3168 result = Fcons (element, result);
3169 }
3170
3171 if (geometry & WidthValue)
3172 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3173 if (geometry & HeightValue)
3174 result = Fcons (Fcons (Qheight, make_number (height)), result);
3175
3176 return result;
3177}
3178
3179/* Calculate the desired size and position of this window,
3180 and return the flags saying which aspects were specified.
3181
3182 This function does not make the coordinates positive. */
3183
3184#define DEFAULT_ROWS 40
3185#define DEFAULT_COLS 80
3186
3187static int
3188x_figure_window_size (f, parms)
3189 struct frame *f;
3190 Lisp_Object parms;
3191{
3192 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3193 long window_prompting = 0;
3194
3195 /* Default values if we fall through.
3196 Actually, if that happens we should get
3197 window manager prompting. */
1026b400 3198 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3199 f->height = DEFAULT_ROWS;
3200 /* Window managers expect that if program-specified
3201 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3202 f->output_data.w32->top_pos = 0;
3203 f->output_data.w32->left_pos = 0;
ee78dc32 3204
6fc2811b
JR
3205 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3206 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3207 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3208 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3209 {
3210 if (!EQ (tem0, Qunbound))
3211 {
3212 CHECK_NUMBER (tem0, 0);
3213 f->height = XINT (tem0);
3214 }
3215 if (!EQ (tem1, Qunbound))
3216 {
3217 CHECK_NUMBER (tem1, 0);
1026b400 3218 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3219 }
3220 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3221 window_prompting |= USSize;
3222 else
3223 window_prompting |= PSize;
3224 }
3225
fbd6baed 3226 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3227 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3228 ? 0
3229 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3230 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3231 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
6fc2811b
JR
3232 f->output_data.w32->flags_areas_extra
3233 = FRAME_FLAGS_AREA_WIDTH (f);
fbd6baed
GV
3234 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3235 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3236
6fc2811b
JR
3237 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3238 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3239 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3240 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3241 {
3242 if (EQ (tem0, Qminus))
3243 {
fbd6baed 3244 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3245 window_prompting |= YNegative;
3246 }
8e713be6
KR
3247 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3248 && CONSP (XCDR (tem0))
3249 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3250 {
8e713be6 3251 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3252 window_prompting |= YNegative;
3253 }
8e713be6
KR
3254 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3255 && CONSP (XCDR (tem0))
3256 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3257 {
8e713be6 3258 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3259 }
3260 else if (EQ (tem0, Qunbound))
fbd6baed 3261 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3262 else
3263 {
3264 CHECK_NUMBER (tem0, 0);
fbd6baed
GV
3265 f->output_data.w32->top_pos = XINT (tem0);
3266 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3267 window_prompting |= YNegative;
3268 }
3269
3270 if (EQ (tem1, Qminus))
3271 {
fbd6baed 3272 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3273 window_prompting |= XNegative;
3274 }
8e713be6
KR
3275 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3276 && CONSP (XCDR (tem1))
3277 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3278 {
8e713be6 3279 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3280 window_prompting |= XNegative;
3281 }
8e713be6
KR
3282 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3283 && CONSP (XCDR (tem1))
3284 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3285 {
8e713be6 3286 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3287 }
3288 else if (EQ (tem1, Qunbound))
fbd6baed 3289 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3290 else
3291 {
3292 CHECK_NUMBER (tem1, 0);
fbd6baed
GV
3293 f->output_data.w32->left_pos = XINT (tem1);
3294 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3295 window_prompting |= XNegative;
3296 }
3297
3298 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3299 window_prompting |= USPosition;
3300 else
3301 window_prompting |= PPosition;
3302 }
3303
3304 return window_prompting;
3305}
3306
3307\f
3308
fbd6baed 3309extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3310
3311BOOL
fbd6baed 3312w32_init_class (hinst)
ee78dc32
GV
3313 HINSTANCE hinst;
3314{
3315 WNDCLASS wc;
3316
5ac45f98 3317 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3318 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3319 wc.cbClsExtra = 0;
3320 wc.cbWndExtra = WND_EXTRA_BYTES;
3321 wc.hInstance = hinst;
3322 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3323 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3324 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3325 wc.lpszMenuName = NULL;
3326 wc.lpszClassName = EMACS_CLASS;
3327
3328 return (RegisterClass (&wc));
3329}
3330
3331HWND
fbd6baed 3332w32_createscrollbar (f, bar)
ee78dc32
GV
3333 struct frame *f;
3334 struct scroll_bar * bar;
3335{
3336 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3337 /* Position and size of scroll bar. */
6fc2811b
JR
3338 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3339 XINT(bar->top),
3340 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3341 XINT(bar->height),
fbd6baed 3342 FRAME_W32_WINDOW (f),
ee78dc32
GV
3343 NULL,
3344 hinst,
3345 NULL));
3346}
3347
3348void
fbd6baed 3349w32_createwindow (f)
ee78dc32
GV
3350 struct frame *f;
3351{
3352 HWND hwnd;
1edf84e7
GV
3353 RECT rect;
3354
3355 rect.left = rect.top = 0;
3356 rect.right = PIXEL_WIDTH (f);
3357 rect.bottom = PIXEL_HEIGHT (f);
3358
3359 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3360 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3361
3362 /* Do first time app init */
3363
3364 if (!hprevinst)
3365 {
fbd6baed 3366 w32_init_class (hinst);
ee78dc32
GV
3367 }
3368
1edf84e7
GV
3369 FRAME_W32_WINDOW (f) = hwnd
3370 = CreateWindow (EMACS_CLASS,
3371 f->namebuf,
3372 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3373 f->output_data.w32->left_pos,
3374 f->output_data.w32->top_pos,
3375 rect.right - rect.left,
3376 rect.bottom - rect.top,
3377 NULL,
3378 NULL,
3379 hinst,
3380 NULL);
3381
ee78dc32
GV
3382 if (hwnd)
3383 {
1edf84e7
GV
3384 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3385 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3386 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3387 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3388 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3389
cb9e33d4
RS
3390 /* Enable drag-n-drop. */
3391 DragAcceptFiles (hwnd, TRUE);
3392
5ac45f98
GV
3393 /* Do this to discard the default setting specified by our parent. */
3394 ShowWindow (hwnd, SW_HIDE);
3c190163 3395 }
3c190163
GV
3396}
3397
ee78dc32
GV
3398void
3399my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3400 W32Msg * wmsg;
ee78dc32
GV
3401 HWND hwnd;
3402 UINT msg;
3403 WPARAM wParam;
3404 LPARAM lParam;
3405{
3406 wmsg->msg.hwnd = hwnd;
3407 wmsg->msg.message = msg;
3408 wmsg->msg.wParam = wParam;
3409 wmsg->msg.lParam = lParam;
3410 wmsg->msg.time = GetMessageTime ();
3411
3412 post_msg (wmsg);
3413}
3414
e9e23e23 3415/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3416 between left and right keys as advertised. We test for this
3417 support dynamically, and set a flag when the support is absent. If
3418 absent, we keep track of the left and right control and alt keys
3419 ourselves. This is particularly necessary on keyboards that rely
3420 upon the AltGr key, which is represented as having the left control
3421 and right alt keys pressed. For these keyboards, we need to know
3422 when the left alt key has been pressed in addition to the AltGr key
3423 so that we can properly support M-AltGr-key sequences (such as M-@
3424 on Swedish keyboards). */
3425
3426#define EMACS_LCONTROL 0
3427#define EMACS_RCONTROL 1
3428#define EMACS_LMENU 2
3429#define EMACS_RMENU 3
3430
3431static int modifiers[4];
3432static int modifiers_recorded;
3433static int modifier_key_support_tested;
3434
3435static void
3436test_modifier_support (unsigned int wparam)
3437{
3438 unsigned int l, r;
3439
3440 if (wparam != VK_CONTROL && wparam != VK_MENU)
3441 return;
3442 if (wparam == VK_CONTROL)
3443 {
3444 l = VK_LCONTROL;
3445 r = VK_RCONTROL;
3446 }
3447 else
3448 {
3449 l = VK_LMENU;
3450 r = VK_RMENU;
3451 }
3452 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3453 modifiers_recorded = 1;
3454 else
3455 modifiers_recorded = 0;
3456 modifier_key_support_tested = 1;
3457}
3458
3459static void
3460record_keydown (unsigned int wparam, unsigned int lparam)
3461{
3462 int i;
3463
3464 if (!modifier_key_support_tested)
3465 test_modifier_support (wparam);
3466
3467 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3468 return;
3469
3470 if (wparam == VK_CONTROL)
3471 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3472 else
3473 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3474
3475 modifiers[i] = 1;
3476}
3477
3478static void
3479record_keyup (unsigned int wparam, unsigned int lparam)
3480{
3481 int i;
3482
3483 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3484 return;
3485
3486 if (wparam == VK_CONTROL)
3487 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3488 else
3489 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3490
3491 modifiers[i] = 0;
3492}
3493
da36a4d6
GV
3494/* Emacs can lose focus while a modifier key has been pressed. When
3495 it regains focus, be conservative and clear all modifiers since
3496 we cannot reconstruct the left and right modifier state. */
3497static void
3498reset_modifiers ()
3499{
8681157a
RS
3500 SHORT ctrl, alt;
3501
adcc3809
GV
3502 if (GetFocus () == NULL)
3503 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3504 return;
8681157a
RS
3505
3506 ctrl = GetAsyncKeyState (VK_CONTROL);
3507 alt = GetAsyncKeyState (VK_MENU);
3508
8681157a
RS
3509 if (!(ctrl & 0x08000))
3510 /* Clear any recorded control modifier state. */
3511 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3512
3513 if (!(alt & 0x08000))
3514 /* Clear any recorded alt modifier state. */
3515 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3516
adcc3809
GV
3517 /* Update the state of all modifier keys, because modifiers used in
3518 hot-key combinations can get stuck on if Emacs loses focus as a
3519 result of a hot-key being pressed. */
3520 {
3521 BYTE keystate[256];
3522
3523#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3524
3525 GetKeyboardState (keystate);
3526 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3527 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3528 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3529 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3530 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3531 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3532 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3533 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3534 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3535 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3536 SetKeyboardState (keystate);
3537 }
da36a4d6
GV
3538}
3539
7830e24b
RS
3540/* Synchronize modifier state with what is reported with the current
3541 keystroke. Even if we cannot distinguish between left and right
3542 modifier keys, we know that, if no modifiers are set, then neither
3543 the left or right modifier should be set. */
3544static void
3545sync_modifiers ()
3546{
3547 if (!modifiers_recorded)
3548 return;
3549
3550 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3551 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3552
3553 if (!(GetKeyState (VK_MENU) & 0x8000))
3554 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3555}
3556
a1a80b40
GV
3557static int
3558modifier_set (int vkey)
3559{
ccc2d29c 3560 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3561 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3562 if (!modifiers_recorded)
3563 return (GetKeyState (vkey) & 0x8000);
3564
3565 switch (vkey)
3566 {
3567 case VK_LCONTROL:
3568 return modifiers[EMACS_LCONTROL];
3569 case VK_RCONTROL:
3570 return modifiers[EMACS_RCONTROL];
3571 case VK_LMENU:
3572 return modifiers[EMACS_LMENU];
3573 case VK_RMENU:
3574 return modifiers[EMACS_RMENU];
a1a80b40
GV
3575 }
3576 return (GetKeyState (vkey) & 0x8000);
3577}
3578
ccc2d29c
GV
3579/* Convert between the modifier bits W32 uses and the modifier bits
3580 Emacs uses. */
3581
3582unsigned int
3583w32_key_to_modifier (int key)
3584{
3585 Lisp_Object key_mapping;
3586
3587 switch (key)
3588 {
3589 case VK_LWIN:
3590 key_mapping = Vw32_lwindow_modifier;
3591 break;
3592 case VK_RWIN:
3593 key_mapping = Vw32_rwindow_modifier;
3594 break;
3595 case VK_APPS:
3596 key_mapping = Vw32_apps_modifier;
3597 break;
3598 case VK_SCROLL:
3599 key_mapping = Vw32_scroll_lock_modifier;
3600 break;
3601 default:
3602 key_mapping = Qnil;
3603 }
3604
adcc3809
GV
3605 /* NB. This code runs in the input thread, asychronously to the lisp
3606 thread, so we must be careful to ensure access to lisp data is
3607 thread-safe. The following code is safe because the modifier
3608 variable values are updated atomically from lisp and symbols are
3609 not relocated by GC. Also, we don't have to worry about seeing GC
3610 markbits here. */
3611 if (EQ (key_mapping, Qhyper))
ccc2d29c 3612 return hyper_modifier;
adcc3809 3613 if (EQ (key_mapping, Qsuper))
ccc2d29c 3614 return super_modifier;
adcc3809 3615 if (EQ (key_mapping, Qmeta))
ccc2d29c 3616 return meta_modifier;
adcc3809 3617 if (EQ (key_mapping, Qalt))
ccc2d29c 3618 return alt_modifier;
adcc3809 3619 if (EQ (key_mapping, Qctrl))
ccc2d29c 3620 return ctrl_modifier;
adcc3809 3621 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3622 return ctrl_modifier;
adcc3809 3623 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3624 return shift_modifier;
3625
3626 /* Don't generate any modifier if not explicitly requested. */
3627 return 0;
3628}
3629
3630unsigned int
3631w32_get_modifiers ()
3632{
3633 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3634 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3635 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3636 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3637 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3638 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3639 (modifier_set (VK_MENU) ?
3640 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3641}
3642
a1a80b40
GV
3643/* We map the VK_* modifiers into console modifier constants
3644 so that we can use the same routines to handle both console
3645 and window input. */
3646
3647static int
ccc2d29c 3648construct_console_modifiers ()
a1a80b40
GV
3649{
3650 int mods;
3651
a1a80b40
GV
3652 mods = 0;
3653 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3654 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3655 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3656 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3657 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3658 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3659 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3660 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3661 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3662 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3663 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3664
3665 return mods;
3666}
3667
ccc2d29c
GV
3668static int
3669w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3670{
ccc2d29c
GV
3671 int mods;
3672
3673 /* Convert to emacs modifiers. */
3674 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3675
3676 return mods;
3677}
da36a4d6 3678
ccc2d29c
GV
3679unsigned int
3680map_keypad_keys (unsigned int virt_key, unsigned int extended)
3681{
3682 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3683 return virt_key;
da36a4d6 3684
ccc2d29c 3685 if (virt_key == VK_RETURN)
da36a4d6
GV
3686 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3687
ccc2d29c
GV
3688 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3689 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3690
3691 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3692 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3693
3694 if (virt_key == VK_CLEAR)
3695 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3696
3697 return virt_key;
3698}
3699
3700/* List of special key combinations which w32 would normally capture,
3701 but emacs should grab instead. Not directly visible to lisp, to
3702 simplify synchronization. Each item is an integer encoding a virtual
3703 key code and modifier combination to capture. */
3704Lisp_Object w32_grabbed_keys;
3705
3706#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3707#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3708#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3709#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3710
3711/* Register hot-keys for reserved key combinations when Emacs has
3712 keyboard focus, since this is the only way Emacs can receive key
3713 combinations like Alt-Tab which are used by the system. */
3714
3715static void
3716register_hot_keys (hwnd)
3717 HWND hwnd;
3718{
3719 Lisp_Object keylist;
3720
3721 /* Use GC_CONSP, since we are called asynchronously. */
3722 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3723 {
3724 Lisp_Object key = XCAR (keylist);
3725
3726 /* Deleted entries get set to nil. */
3727 if (!INTEGERP (key))
3728 continue;
3729
3730 RegisterHotKey (hwnd, HOTKEY_ID (key),
3731 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3732 }
3733}
3734
3735static void
3736unregister_hot_keys (hwnd)
3737 HWND hwnd;
3738{
3739 Lisp_Object keylist;
3740
3741 /* Use GC_CONSP, since we are called asynchronously. */
3742 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3743 {
3744 Lisp_Object key = XCAR (keylist);
3745
3746 if (!INTEGERP (key))
3747 continue;
3748
3749 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3750 }
3751}
3752
5ac45f98
GV
3753/* Main message dispatch loop. */
3754
1edf84e7
GV
3755static void
3756w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3757{
3758 MSG msg;
ccc2d29c
GV
3759 int result;
3760 HWND focus_window;
93fbe8b7
GV
3761
3762 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3763
5ac45f98
GV
3764 while (GetMessage (&msg, NULL, 0, 0))
3765 {
3766 if (msg.hwnd == NULL)
3767 {
3768 switch (msg.message)
3769 {
3ef68e6b
AI
3770 case WM_NULL:
3771 /* Produced by complete_deferred_msg; just ignore. */
3772 break;
5ac45f98 3773 case WM_EMACS_CREATEWINDOW:
fbd6baed 3774 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3775 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3776 abort ();
5ac45f98 3777 break;
dfdb4047
GV
3778 case WM_EMACS_SETLOCALE:
3779 SetThreadLocale (msg.wParam);
3780 /* Reply is not expected. */
3781 break;
ccc2d29c
GV
3782 case WM_EMACS_SETKEYBOARDLAYOUT:
3783 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3784 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3785 result, 0))
3786 abort ();
3787 break;
3788 case WM_EMACS_REGISTER_HOT_KEY:
3789 focus_window = GetFocus ();
3790 if (focus_window != NULL)
3791 RegisterHotKey (focus_window,
3792 HOTKEY_ID (msg.wParam),
3793 HOTKEY_MODIFIERS (msg.wParam),
3794 HOTKEY_VK_CODE (msg.wParam));
3795 /* Reply is not expected. */
3796 break;
3797 case WM_EMACS_UNREGISTER_HOT_KEY:
3798 focus_window = GetFocus ();
3799 if (focus_window != NULL)
3800 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3801 /* Mark item as erased. NB: this code must be
3802 thread-safe. The next line is okay because the cons
3803 cell is never made into garbage and is not relocated by
3804 GC. */
ccc2d29c
GV
3805 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3806 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3807 abort ();
3808 break;
adcc3809
GV
3809 case WM_EMACS_TOGGLE_LOCK_KEY:
3810 {
3811 int vk_code = (int) msg.wParam;
3812 int cur_state = (GetKeyState (vk_code) & 1);
3813 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3814
3815 /* NB: This code must be thread-safe. It is safe to
3816 call NILP because symbols are not relocated by GC,
3817 and pointer here is not touched by GC (so the markbit
3818 can't be set). Numbers are safe because they are
3819 immediate values. */
3820 if (NILP (new_state)
3821 || (NUMBERP (new_state)
3822 && (XUINT (new_state)) & 1 != cur_state))
3823 {
3824 one_w32_display_info.faked_key = vk_code;
3825
3826 keybd_event ((BYTE) vk_code,
3827 (BYTE) MapVirtualKey (vk_code, 0),
3828 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3829 keybd_event ((BYTE) vk_code,
3830 (BYTE) MapVirtualKey (vk_code, 0),
3831 KEYEVENTF_EXTENDEDKEY | 0, 0);
3832 keybd_event ((BYTE) vk_code,
3833 (BYTE) MapVirtualKey (vk_code, 0),
3834 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3835 cur_state = !cur_state;
3836 }
3837 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3838 cur_state, 0))
3839 abort ();
3840 }
3841 break;
1edf84e7 3842 default:
1edf84e7 3843 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3844 }
3845 }
3846 else
3847 {
3848 DispatchMessage (&msg);
3849 }
1edf84e7
GV
3850
3851 /* Exit nested loop when our deferred message has completed. */
3852 if (msg_buf->completed)
3853 break;
5ac45f98 3854 }
1edf84e7
GV
3855}
3856
3857deferred_msg * deferred_msg_head;
3858
3859static deferred_msg *
3860find_deferred_msg (HWND hwnd, UINT msg)
3861{
3862 deferred_msg * item;
3863
3864 /* Don't actually need synchronization for read access, since
3865 modification of single pointer is always atomic. */
3866 /* enter_crit (); */
3867
3868 for (item = deferred_msg_head; item != NULL; item = item->next)
3869 if (item->w32msg.msg.hwnd == hwnd
3870 && item->w32msg.msg.message == msg)
3871 break;
3872
3873 /* leave_crit (); */
3874
3875 return item;
3876}
3877
3878static LRESULT
3879send_deferred_msg (deferred_msg * msg_buf,
3880 HWND hwnd,
3881 UINT msg,
3882 WPARAM wParam,
3883 LPARAM lParam)
3884{
3885 /* Only input thread can send deferred messages. */
3886 if (GetCurrentThreadId () != dwWindowsThreadId)
3887 abort ();
3888
3889 /* It is an error to send a message that is already deferred. */
3890 if (find_deferred_msg (hwnd, msg) != NULL)
3891 abort ();
3892
3893 /* Enforced synchronization is not needed because this is the only
3894 function that alters deferred_msg_head, and the following critical
3895 section is guaranteed to only be serially reentered (since only the
3896 input thread can call us). */
3897
3898 /* enter_crit (); */
3899
3900 msg_buf->completed = 0;
3901 msg_buf->next = deferred_msg_head;
3902 deferred_msg_head = msg_buf;
3903 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3904
3905 /* leave_crit (); */
3906
3907 /* Start a new nested message loop to process other messages until
3908 this one is completed. */
3909 w32_msg_pump (msg_buf);
3910
3911 deferred_msg_head = msg_buf->next;
3912
3913 return msg_buf->result;
3914}
3915
3916void
3917complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3918{
3919 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3920
3921 if (msg_buf == NULL)
3ef68e6b
AI
3922 /* Message may have been cancelled, so don't abort(). */
3923 return;
1edf84e7
GV
3924
3925 msg_buf->result = result;
3926 msg_buf->completed = 1;
3927
3928 /* Ensure input thread is woken so it notices the completion. */
3929 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3930}
3931
3ef68e6b
AI
3932void
3933cancel_all_deferred_msgs ()
3934{
3935 deferred_msg * item;
3936
3937 /* Don't actually need synchronization for read access, since
3938 modification of single pointer is always atomic. */
3939 /* enter_crit (); */
3940
3941 for (item = deferred_msg_head; item != NULL; item = item->next)
3942 {
3943 item->result = 0;
3944 item->completed = 1;
3945 }
3946
3947 /* leave_crit (); */
3948
3949 /* Ensure input thread is woken so it notices the completion. */
3950 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3951}
1edf84e7
GV
3952
3953DWORD
3954w32_msg_worker (dw)
3955 DWORD dw;
3956{
3957 MSG msg;
3958 deferred_msg dummy_buf;
3959
3960 /* Ensure our message queue is created */
3961
3962 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 3963
1edf84e7
GV
3964 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3965 abort ();
3966
3967 memset (&dummy_buf, 0, sizeof (dummy_buf));
3968 dummy_buf.w32msg.msg.hwnd = NULL;
3969 dummy_buf.w32msg.msg.message = WM_NULL;
3970
3971 /* This is the inital message loop which should only exit when the
3972 application quits. */
3973 w32_msg_pump (&dummy_buf);
3974
3975 return 0;
5ac45f98
GV
3976}
3977
3ef68e6b
AI
3978static void
3979post_character_message (hwnd, msg, wParam, lParam, modifiers)
3980 HWND hwnd;
3981 UINT msg;
3982 WPARAM wParam;
3983 LPARAM lParam;
3984 DWORD modifiers;
3985
3986{
3987 W32Msg wmsg;
3988
3989 wmsg.dwModifiers = modifiers;
3990
3991 /* Detect quit_char and set quit-flag directly. Note that we
3992 still need to post a message to ensure the main thread will be
3993 woken up if blocked in sys_select(), but we do NOT want to post
3994 the quit_char message itself (because it will usually be as if
3995 the user had typed quit_char twice). Instead, we post a dummy
3996 message that has no particular effect. */
3997 {
3998 int c = wParam;
3999 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4000 c = make_ctrl_char (c) & 0377;
7d081355
AI
4001 if (c == quit_char
4002 || (wmsg.dwModifiers == 0 &&
4003 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4004 {
4005 Vquit_flag = Qt;
4006
4007 /* The choice of message is somewhat arbitrary, as long as
4008 the main thread handler just ignores it. */
4009 msg = WM_NULL;
4010
4011 /* Interrupt any blocking system calls. */
4012 signal_quit ();
4013
4014 /* As a safety precaution, forcibly complete any deferred
4015 messages. This is a kludge, but I don't see any particularly
4016 clean way to handle the situation where a deferred message is
4017 "dropped" in the lisp thread, and will thus never be
4018 completed, eg. by the user trying to activate the menubar
4019 when the lisp thread is busy, and then typing C-g when the
4020 menubar doesn't open promptly (with the result that the
4021 menubar never responds at all because the deferred
4022 WM_INITMENU message is never completed). Another problem
4023 situation is when the lisp thread calls SendMessage (to send
4024 a window manager command) when a message has been deferred;
4025 the lisp thread gets blocked indefinitely waiting for the
4026 deferred message to be completed, which itself is waiting for
4027 the lisp thread to respond.
4028
4029 Note that we don't want to block the input thread waiting for
4030 a reponse from the lisp thread (although that would at least
4031 solve the deadlock problem above), because we want to be able
4032 to receive C-g to interrupt the lisp thread. */
4033 cancel_all_deferred_msgs ();
4034 }
4035 }
4036
4037 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4038}
4039
ee78dc32
GV
4040/* Main window procedure */
4041
ee78dc32 4042LRESULT CALLBACK
fbd6baed 4043w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4044 HWND hwnd;
4045 UINT msg;
4046 WPARAM wParam;
4047 LPARAM lParam;
4048{
4049 struct frame *f;
fbd6baed
GV
4050 struct w32_display_info *dpyinfo = &one_w32_display_info;
4051 W32Msg wmsg;
84fb1139 4052 int windows_translate;
576ba81c 4053 int key;
84fb1139 4054
a6085637
KH
4055 /* Note that it is okay to call x_window_to_frame, even though we are
4056 not running in the main lisp thread, because frame deletion
4057 requires the lisp thread to synchronize with this thread. Thus, if
4058 a frame struct is returned, it can be used without concern that the
4059 lisp thread might make it disappear while we are using it.
4060
4061 NB. Walking the frame list in this thread is safe (as long as
4062 writes of Lisp_Object slots are atomic, which they are on Windows).
4063 Although delete-frame can destructively modify the frame list while
4064 we are walking it, a garbage collection cannot occur until after
4065 delete-frame has synchronized with this thread.
4066
4067 It is also safe to use functions that make GDI calls, such as
fbd6baed 4068 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4069 from the frame struct using get_frame_dc which is thread-aware. */
4070
ee78dc32
GV
4071 switch (msg)
4072 {
4073 case WM_ERASEBKGND:
a6085637
KH
4074 f = x_window_to_frame (dpyinfo, hwnd);
4075 if (f)
4076 {
9badad41 4077 HDC hdc = get_frame_dc (f);
a6085637 4078 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4079 w32_clear_rect (f, hdc, &wmsg.rect);
4080 release_frame_dc (f, hdc);
ce6059da
AI
4081
4082#if defined (W32_DEBUG_DISPLAY)
4083 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
4084 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
4085 wmsg.rect.bottom));
4086#endif /* W32_DEBUG_DISPLAY */
a6085637 4087 }
5ac45f98
GV
4088 return 1;
4089 case WM_PALETTECHANGED:
4090 /* ignore our own changes */
4091 if ((HWND)wParam != hwnd)
4092 {
a6085637
KH
4093 f = x_window_to_frame (dpyinfo, hwnd);
4094 if (f)
4095 /* get_frame_dc will realize our palette and force all
4096 frames to be redrawn if needed. */
4097 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4098 }
4099 return 0;
ee78dc32 4100 case WM_PAINT:
ce6059da 4101 {
55dcfc15
AI
4102 PAINTSTRUCT paintStruct;
4103 RECT update_rect;
4104
4105 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4106 fails. Apparently this can happen under some
4107 circumstances. */
c0611964 4108 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
4109 {
4110 enter_crit ();
4111 BeginPaint (hwnd, &paintStruct);
4112
c0611964
AI
4113 if (w32_strict_painting)
4114 /* The rectangles returned by GetUpdateRect and BeginPaint
4115 do not always match. GetUpdateRect seems to be the
4116 more reliable of the two. */
4117 wmsg.rect = update_rect;
4118 else
4119 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
4120
4121#if defined (W32_DEBUG_DISPLAY)
4122 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
4123 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
4124 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
4125 update_rect.left, update_rect.top,
4126 update_rect.right, update_rect.bottom));
4127#endif
4128 EndPaint (hwnd, &paintStruct);
4129 leave_crit ();
4130
4131 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4132
4133 return 0;
4134 }
c0611964
AI
4135
4136 /* If GetUpdateRect returns 0 (meaning there is no update
4137 region), assume the whole window needs to be repainted. */
4138 GetClientRect(hwnd, &wmsg.rect);
4139 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4140 return 0;
ee78dc32 4141 }
a1a80b40 4142
ccc2d29c
GV
4143 case WM_INPUTLANGCHANGE:
4144 /* Inform lisp thread of keyboard layout changes. */
4145 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4146
4147 /* Clear dead keys in the keyboard state; for simplicity only
4148 preserve modifier key states. */
4149 {
4150 int i;
4151 BYTE keystate[256];
4152
4153 GetKeyboardState (keystate);
4154 for (i = 0; i < 256; i++)
4155 if (1
4156 && i != VK_SHIFT
4157 && i != VK_LSHIFT
4158 && i != VK_RSHIFT
4159 && i != VK_CAPITAL
4160 && i != VK_NUMLOCK
4161 && i != VK_SCROLL
4162 && i != VK_CONTROL
4163 && i != VK_LCONTROL
4164 && i != VK_RCONTROL
4165 && i != VK_MENU
4166 && i != VK_LMENU
4167 && i != VK_RMENU
4168 && i != VK_LWIN
4169 && i != VK_RWIN)
4170 keystate[i] = 0;
4171 SetKeyboardState (keystate);
4172 }
4173 goto dflt;
4174
4175 case WM_HOTKEY:
4176 /* Synchronize hot keys with normal input. */
4177 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4178 return (0);
4179
a1a80b40
GV
4180 case WM_KEYUP:
4181 case WM_SYSKEYUP:
4182 record_keyup (wParam, lParam);
4183 goto dflt;
4184
ee78dc32
GV
4185 case WM_KEYDOWN:
4186 case WM_SYSKEYDOWN:
ccc2d29c
GV
4187 /* Ignore keystrokes we fake ourself; see below. */
4188 if (dpyinfo->faked_key == wParam)
4189 {
4190 dpyinfo->faked_key = 0;
576ba81c
AI
4191 /* Make sure TranslateMessage sees them though (as long as
4192 they don't produce WM_CHAR messages). This ensures that
4193 indicator lights are toggled promptly on Windows 9x, for
4194 example. */
4195 if (lispy_function_keys[wParam] != 0)
4196 {
4197 windows_translate = 1;
4198 goto translate;
4199 }
4200 return 0;
ccc2d29c
GV
4201 }
4202
7830e24b
RS
4203 /* Synchronize modifiers with current keystroke. */
4204 sync_modifiers ();
a1a80b40 4205 record_keydown (wParam, lParam);
ccc2d29c 4206 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4207
4208 windows_translate = 0;
ccc2d29c
GV
4209
4210 switch (wParam)
4211 {
4212 case VK_LWIN:
4213 if (NILP (Vw32_pass_lwindow_to_system))
4214 {
4215 /* Prevent system from acting on keyup (which opens the
4216 Start menu if no other key was pressed) by simulating a
4217 press of Space which we will ignore. */
4218 if (GetAsyncKeyState (wParam) & 1)
4219 {
adcc3809 4220 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4221 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4222 else
576ba81c
AI
4223 key = VK_SPACE;
4224 dpyinfo->faked_key = key;
4225 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4226 }
4227 }
4228 if (!NILP (Vw32_lwindow_modifier))
4229 return 0;
4230 break;
4231 case VK_RWIN:
4232 if (NILP (Vw32_pass_rwindow_to_system))
4233 {
4234 if (GetAsyncKeyState (wParam) & 1)
4235 {
adcc3809 4236 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4237 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4238 else
576ba81c
AI
4239 key = VK_SPACE;
4240 dpyinfo->faked_key = key;
4241 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4242 }
4243 }
4244 if (!NILP (Vw32_rwindow_modifier))
4245 return 0;
4246 break;
576ba81c 4247 case VK_APPS:
ccc2d29c
GV
4248 if (!NILP (Vw32_apps_modifier))
4249 return 0;
4250 break;
4251 case VK_MENU:
4252 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4253 /* Prevent DefWindowProc from activating the menu bar if an
4254 Alt key is pressed and released by itself. */
ccc2d29c 4255 return 0;
84fb1139 4256 windows_translate = 1;
ccc2d29c
GV
4257 break;
4258 case VK_CAPITAL:
4259 /* Decide whether to treat as modifier or function key. */
4260 if (NILP (Vw32_enable_caps_lock))
4261 goto disable_lock_key;
adcc3809
GV
4262 windows_translate = 1;
4263 break;
ccc2d29c
GV
4264 case VK_NUMLOCK:
4265 /* Decide whether to treat as modifier or function key. */
4266 if (NILP (Vw32_enable_num_lock))
4267 goto disable_lock_key;
adcc3809
GV
4268 windows_translate = 1;
4269 break;
ccc2d29c
GV
4270 case VK_SCROLL:
4271 /* Decide whether to treat as modifier or function key. */
4272 if (NILP (Vw32_scroll_lock_modifier))
4273 goto disable_lock_key;
adcc3809
GV
4274 windows_translate = 1;
4275 break;
ccc2d29c 4276 disable_lock_key:
adcc3809
GV
4277 /* Ensure the appropriate lock key state (and indicator light)
4278 remains in the same state. We do this by faking another
4279 press of the relevant key. Apparently, this really is the
4280 only way to toggle the state of the indicator lights. */
4281 dpyinfo->faked_key = wParam;
4282 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4283 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4284 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4285 KEYEVENTF_EXTENDEDKEY | 0, 0);
4286 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4287 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4288 /* Ensure indicator lights are updated promptly on Windows 9x
4289 (TranslateMessage apparently does this), after forwarding
4290 input event. */
4291 post_character_message (hwnd, msg, wParam, lParam,
4292 w32_get_key_modifiers (wParam, lParam));
4293 windows_translate = 1;
ccc2d29c
GV
4294 break;
4295 case VK_CONTROL:
4296 case VK_SHIFT:
4297 case VK_PROCESSKEY: /* Generated by IME. */
4298 windows_translate = 1;
4299 break;
adcc3809
GV
4300 case VK_CANCEL:
4301 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4302 which is confusing for purposes of key binding; convert
4303 VK_CANCEL events into VK_PAUSE events. */
4304 wParam = VK_PAUSE;
4305 break;
4306 case VK_PAUSE:
4307 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4308 for purposes of key binding; convert these back into
4309 VK_NUMLOCK events, at least when we want to see NumLock key
4310 presses. (Note that there is never any possibility that
4311 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4312 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4313 wParam = VK_NUMLOCK;
4314 break;
ccc2d29c
GV
4315 default:
4316 /* If not defined as a function key, change it to a WM_CHAR message. */
4317 if (lispy_function_keys[wParam] == 0)
4318 {
adcc3809
GV
4319 DWORD modifiers = construct_console_modifiers ();
4320
ccc2d29c
GV
4321 if (!NILP (Vw32_recognize_altgr)
4322 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4323 {
4324 /* Always let TranslateMessage handle AltGr key chords;
4325 for some reason, ToAscii doesn't always process AltGr
4326 chords correctly. */
4327 windows_translate = 1;
4328 }
adcc3809 4329 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4330 {
adcc3809
GV
4331 /* Handle key chords including any modifiers other
4332 than shift directly, in order to preserve as much
4333 modifier information as possible. */
ccc2d29c
GV
4334 if ('A' <= wParam && wParam <= 'Z')
4335 {
4336 /* Don't translate modified alphabetic keystrokes,
4337 so the user doesn't need to constantly switch
4338 layout to type control or meta keystrokes when
4339 the normal layout translates alphabetic
4340 characters to non-ascii characters. */
4341 if (!modifier_set (VK_SHIFT))
4342 wParam += ('a' - 'A');
4343 msg = WM_CHAR;
4344 }
4345 else
4346 {
4347 /* Try to handle other keystrokes by determining the
4348 base character (ie. translating the base key plus
4349 shift modifier). */
4350 int add;
4351 int isdead = 0;
4352 KEY_EVENT_RECORD key;
4353
4354 key.bKeyDown = TRUE;
4355 key.wRepeatCount = 1;
4356 key.wVirtualKeyCode = wParam;
4357 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4358 key.uChar.AsciiChar = 0;
adcc3809 4359 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4360
4361 add = w32_kbd_patch_key (&key);
4362 /* 0 means an unrecognised keycode, negative means
4363 dead key. Ignore both. */
4364 while (--add >= 0)
4365 {
4366 /* Forward asciified character sequence. */
4367 post_character_message
4368 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4369 w32_get_key_modifiers (wParam, lParam));
4370 w32_kbd_patch_key (&key);
4371 }
4372 return 0;
4373 }
4374 }
4375 else
4376 {
4377 /* Let TranslateMessage handle everything else. */
4378 windows_translate = 1;
4379 }
4380 }
4381 }
a1a80b40 4382
adcc3809 4383 translate:
84fb1139
KH
4384 if (windows_translate)
4385 {
e9e23e23 4386 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4387
e9e23e23
GV
4388 windows_msg.time = GetMessageTime ();
4389 TranslateMessage (&windows_msg);
84fb1139
KH
4390 goto dflt;
4391 }
4392
ee78dc32
GV
4393 /* Fall through */
4394
4395 case WM_SYSCHAR:
4396 case WM_CHAR:
ccc2d29c
GV
4397 post_character_message (hwnd, msg, wParam, lParam,
4398 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4399 break;
da36a4d6 4400
5ac45f98
GV
4401 /* Simulate middle mouse button events when left and right buttons
4402 are used together, but only if user has two button mouse. */
ee78dc32 4403 case WM_LBUTTONDOWN:
5ac45f98 4404 case WM_RBUTTONDOWN:
7ce9aaca 4405 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4406 goto handle_plain_button;
4407
4408 {
4409 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4410 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4411
3cb20f4a
RS
4412 if (button_state & this)
4413 return 0;
5ac45f98
GV
4414
4415 if (button_state == 0)
4416 SetCapture (hwnd);
4417
4418 button_state |= this;
4419
4420 if (button_state & other)
4421 {
84fb1139 4422 if (mouse_button_timer)
5ac45f98 4423 {
84fb1139
KH
4424 KillTimer (hwnd, mouse_button_timer);
4425 mouse_button_timer = 0;
5ac45f98
GV
4426
4427 /* Generate middle mouse event instead. */
4428 msg = WM_MBUTTONDOWN;
4429 button_state |= MMOUSE;
4430 }
4431 else if (button_state & MMOUSE)
4432 {
4433 /* Ignore button event if we've already generated a
4434 middle mouse down event. This happens if the
4435 user releases and press one of the two buttons
4436 after we've faked a middle mouse event. */
4437 return 0;
4438 }
4439 else
4440 {
4441 /* Flush out saved message. */
84fb1139 4442 post_msg (&saved_mouse_button_msg);
5ac45f98 4443 }
fbd6baed 4444 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4445 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4446
4447 /* Clear message buffer. */
84fb1139 4448 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4449 }
4450 else
4451 {
4452 /* Hold onto message for now. */
84fb1139 4453 mouse_button_timer =
adcc3809
GV
4454 SetTimer (hwnd, MOUSE_BUTTON_ID,
4455 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4456 saved_mouse_button_msg.msg.hwnd = hwnd;
4457 saved_mouse_button_msg.msg.message = msg;
4458 saved_mouse_button_msg.msg.wParam = wParam;
4459 saved_mouse_button_msg.msg.lParam = lParam;
4460 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4461 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4462 }
4463 }
4464 return 0;
4465
ee78dc32 4466 case WM_LBUTTONUP:
5ac45f98 4467 case WM_RBUTTONUP:
7ce9aaca 4468 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4469 goto handle_plain_button;
4470
4471 {
4472 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4473 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4474
3cb20f4a
RS
4475 if ((button_state & this) == 0)
4476 return 0;
5ac45f98
GV
4477
4478 button_state &= ~this;
4479
4480 if (button_state & MMOUSE)
4481 {
4482 /* Only generate event when second button is released. */
4483 if ((button_state & other) == 0)
4484 {
4485 msg = WM_MBUTTONUP;
4486 button_state &= ~MMOUSE;
4487
4488 if (button_state) abort ();
4489 }
4490 else
4491 return 0;
4492 }
4493 else
4494 {
4495 /* Flush out saved message if necessary. */
84fb1139 4496 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4497 {
84fb1139 4498 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4499 }
4500 }
fbd6baed 4501 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4502 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4503
4504 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4505 saved_mouse_button_msg.msg.hwnd = 0;
4506 KillTimer (hwnd, mouse_button_timer);
4507 mouse_button_timer = 0;
5ac45f98
GV
4508
4509 if (button_state == 0)
4510 ReleaseCapture ();
4511 }
4512 return 0;
4513
ee78dc32
GV
4514 case WM_MBUTTONDOWN:
4515 case WM_MBUTTONUP:
5ac45f98 4516 handle_plain_button:
ee78dc32
GV
4517 {
4518 BOOL up;
1edf84e7 4519 int button;
ee78dc32 4520
1edf84e7 4521 if (parse_button (msg, &button, &up))
ee78dc32
GV
4522 {
4523 if (up) ReleaseCapture ();
4524 else SetCapture (hwnd);
1edf84e7
GV
4525 button = (button == 0) ? LMOUSE :
4526 ((button == 1) ? MMOUSE : RMOUSE);
4527 if (up)
4528 button_state &= ~button;
4529 else
4530 button_state |= button;
ee78dc32
GV
4531 }
4532 }
4533
fbd6baed 4534 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4535 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5ac45f98
GV
4536 return 0;
4537
84fb1139 4538 case WM_VSCROLL:
5ac45f98 4539 case WM_MOUSEMOVE:
fbd6baed 4540 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4541 || (msg == WM_MOUSEMOVE && button_state == 0))
4542 {
fbd6baed 4543 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4544 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4545 return 0;
4546 }
4547
4548 /* Hang onto mouse move and scroll messages for a bit, to avoid
4549 sending such events to Emacs faster than it can process them.
4550 If we get more events before the timer from the first message
4551 expires, we just replace the first message. */
4552
4553 if (saved_mouse_move_msg.msg.hwnd == 0)
4554 mouse_move_timer =
adcc3809
GV
4555 SetTimer (hwnd, MOUSE_MOVE_ID,
4556 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4557
4558 /* Hold onto message for now. */
4559 saved_mouse_move_msg.msg.hwnd = hwnd;
4560 saved_mouse_move_msg.msg.message = msg;
4561 saved_mouse_move_msg.msg.wParam = wParam;
4562 saved_mouse_move_msg.msg.lParam = lParam;
4563 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4564 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4565
4566 return 0;
4567
1edf84e7
GV
4568 case WM_MOUSEWHEEL:
4569 wmsg.dwModifiers = w32_get_modifiers ();
4570 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4571 return 0;
4572
cb9e33d4
RS
4573 case WM_DROPFILES:
4574 wmsg.dwModifiers = w32_get_modifiers ();
4575 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4576 return 0;
4577
84fb1139
KH
4578 case WM_TIMER:
4579 /* Flush out saved messages if necessary. */
4580 if (wParam == mouse_button_timer)
5ac45f98 4581 {
84fb1139
KH
4582 if (saved_mouse_button_msg.msg.hwnd)
4583 {
4584 post_msg (&saved_mouse_button_msg);
4585 saved_mouse_button_msg.msg.hwnd = 0;
4586 }
4587 KillTimer (hwnd, mouse_button_timer);
4588 mouse_button_timer = 0;
4589 }
4590 else if (wParam == mouse_move_timer)
4591 {
4592 if (saved_mouse_move_msg.msg.hwnd)
4593 {
4594 post_msg (&saved_mouse_move_msg);
4595 saved_mouse_move_msg.msg.hwnd = 0;
4596 }
4597 KillTimer (hwnd, mouse_move_timer);
4598 mouse_move_timer = 0;
5ac45f98 4599 }
5ac45f98 4600 return 0;
84fb1139
KH
4601
4602 case WM_NCACTIVATE:
4603 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4604 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4605 The only indication we get that something happened is receiving
4606 this message afterwards. So this is a good time to reset our
4607 keyboard modifiers' state. */
4608 reset_modifiers ();
4609 goto dflt;
da36a4d6 4610
1edf84e7 4611 case WM_INITMENU:
487163ac
AI
4612 button_state = 0;
4613 ReleaseCapture ();
1edf84e7
GV
4614 /* We must ensure menu bar is fully constructed and up to date
4615 before allowing user interaction with it. To achieve this
4616 we send this message to the lisp thread and wait for a
4617 reply (whose value is not actually needed) to indicate that
4618 the menu bar is now ready for use, so we can now return.
4619
4620 To remain responsive in the meantime, we enter a nested message
4621 loop that can process all other messages.
4622
4623 However, we skip all this if the message results from calling
4624 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4625 thread a message because it is blocked on us at this point. We
4626 set menubar_active before calling TrackPopupMenu to indicate
4627 this (there is no possibility of confusion with real menubar
4628 being active). */
4629
4630 f = x_window_to_frame (dpyinfo, hwnd);
4631 if (f
4632 && (f->output_data.w32->menubar_active
4633 /* We can receive this message even in the absence of a
4634 menubar (ie. when the system menu is activated) - in this
4635 case we do NOT want to forward the message, otherwise it
4636 will cause the menubar to suddenly appear when the user
4637 had requested it to be turned off! */
4638 || f->output_data.w32->menubar_widget == NULL))
4639 return 0;
4640
4641 {
4642 deferred_msg msg_buf;
4643
4644 /* Detect if message has already been deferred; in this case
4645 we cannot return any sensible value to ignore this. */
4646 if (find_deferred_msg (hwnd, msg) != NULL)
4647 abort ();
4648
4649 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4650 }
4651
4652 case WM_EXITMENULOOP:
4653 f = x_window_to_frame (dpyinfo, hwnd);
4654
4655 /* Indicate that menubar can be modified again. */
4656 if (f)
4657 f->output_data.w32->menubar_active = 0;
4658 goto dflt;
4659
126f2e35
JR
4660 case WM_MENUSELECT:
4661 wmsg.dwModifiers = w32_get_modifiers ();
4662 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4663 return 0;
4664
87996783
GV
4665 case WM_MEASUREITEM:
4666 f = x_window_to_frame (dpyinfo, hwnd);
4667 if (f)
4668 {
4669 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4670
4671 if (pMis->CtlType == ODT_MENU)
4672 {
4673 /* Work out dimensions for popup menu titles. */
4674 char * title = (char *) pMis->itemData;
4675 HDC hdc = GetDC (hwnd);
4676 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4677 LOGFONT menu_logfont;
4678 HFONT old_font;
4679 SIZE size;
4680
4681 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4682 menu_logfont.lfWeight = FW_BOLD;
4683 menu_font = CreateFontIndirect (&menu_logfont);
4684 old_font = SelectObject (hdc, menu_font);
4685
dfff8a69
JR
4686 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4687 if (title)
4688 {
4689 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4690 pMis->itemWidth = size.cx;
4691 if (pMis->itemHeight < size.cy)
4692 pMis->itemHeight = size.cy;
4693 }
4694 else
4695 pMis->itemWidth = 0;
87996783
GV
4696
4697 SelectObject (hdc, old_font);
4698 DeleteObject (menu_font);
4699 ReleaseDC (hwnd, hdc);
4700 return TRUE;
4701 }
4702 }
4703 return 0;
4704
4705 case WM_DRAWITEM:
4706 f = x_window_to_frame (dpyinfo, hwnd);
4707 if (f)
4708 {
4709 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4710
4711 if (pDis->CtlType == ODT_MENU)
4712 {
4713 /* Draw popup menu title. */
4714 char * title = (char *) pDis->itemData;
212da13b
JR
4715 if (title)
4716 {
4717 HDC hdc = pDis->hDC;
4718 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4719 LOGFONT menu_logfont;
4720 HFONT old_font;
4721
4722 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4723 menu_logfont.lfWeight = FW_BOLD;
4724 menu_font = CreateFontIndirect (&menu_logfont);
4725 old_font = SelectObject (hdc, menu_font);
4726
4727 /* Always draw title as if not selected. */
4728 ExtTextOut (hdc,
4729 pDis->rcItem.left
4730 + GetSystemMetrics (SM_CXMENUCHECK),
4731 pDis->rcItem.top,
4732 ETO_OPAQUE, &pDis->rcItem,
4733 title, strlen (title), NULL);
4734
4735 SelectObject (hdc, old_font);
4736 DeleteObject (menu_font);
4737 }
87996783
GV
4738 return TRUE;
4739 }
4740 }
4741 return 0;
4742
1edf84e7
GV
4743#if 0
4744 /* Still not right - can't distinguish between clicks in the
4745 client area of the frame from clicks forwarded from the scroll
4746 bars - may have to hook WM_NCHITTEST to remember the mouse
4747 position and then check if it is in the client area ourselves. */
4748 case WM_MOUSEACTIVATE:
4749 /* Discard the mouse click that activates a frame, allowing the
4750 user to click anywhere without changing point (or worse!).
4751 Don't eat mouse clicks on scrollbars though!! */
4752 if (LOWORD (lParam) == HTCLIENT )
4753 return MA_ACTIVATEANDEAT;
4754 goto dflt;
4755#endif
4756
1edf84e7 4757 case WM_ACTIVATEAPP:
ccc2d29c 4758 case WM_ACTIVATE:
1edf84e7
GV
4759 case WM_WINDOWPOSCHANGED:
4760 case WM_SHOWWINDOW:
4761 /* Inform lisp thread that a frame might have just been obscured
4762 or exposed, so should recheck visibility of all frames. */
4763 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4764 goto dflt;
4765
da36a4d6 4766 case WM_SETFOCUS:
adcc3809
GV
4767 dpyinfo->faked_key = 0;
4768 reset_modifiers ();
ccc2d29c
GV
4769 register_hot_keys (hwnd);
4770 goto command;
8681157a 4771 case WM_KILLFOCUS:
ccc2d29c 4772 unregister_hot_keys (hwnd);
487163ac
AI
4773 button_state = 0;
4774 ReleaseCapture ();
ee78dc32
GV
4775 case WM_MOVE:
4776 case WM_SIZE:
ee78dc32 4777 case WM_COMMAND:
ccc2d29c 4778 command:
fbd6baed 4779 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4780 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4781 goto dflt;
8847d890
RS
4782
4783 case WM_CLOSE:
fbd6baed 4784 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4785 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4786 return 0;
4787
ee78dc32
GV
4788 case WM_WINDOWPOSCHANGING:
4789 {
4790 WINDOWPLACEMENT wp;
4791 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4792
4793 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4794 GetWindowPlacement (hwnd, &wp);
4795
1edf84e7 4796 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4797 {
4798 RECT rect;
4799 int wdiff;
4800 int hdiff;
1edf84e7
GV
4801 DWORD font_width;
4802 DWORD line_height;
4803 DWORD internal_border;
4804 DWORD scrollbar_extra;
ee78dc32
GV
4805 RECT wr;
4806
5ac45f98 4807 wp.length = sizeof(wp);
ee78dc32
GV
4808 GetWindowRect (hwnd, &wr);
4809
3c190163 4810 enter_crit ();
ee78dc32 4811
1edf84e7
GV
4812 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4813 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4814 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4815 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4816
3c190163 4817 leave_crit ();
ee78dc32
GV
4818
4819 memset (&rect, 0, sizeof (rect));
4820 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4821 GetMenu (hwnd) != NULL);
4822
1edf84e7
GV
4823 /* Force width and height of client area to be exact
4824 multiples of the character cell dimensions. */
4825 wdiff = (lppos->cx - (rect.right - rect.left)
4826 - 2 * internal_border - scrollbar_extra)
4827 % font_width;
4828 hdiff = (lppos->cy - (rect.bottom - rect.top)
4829 - 2 * internal_border)
4830 % line_height;
ee78dc32
GV
4831
4832 if (wdiff || hdiff)
4833 {
4834 /* For right/bottom sizing we can just fix the sizes.
4835 However for top/left sizing we will need to fix the X
4836 and Y positions as well. */
4837
4838 lppos->cx -= wdiff;
4839 lppos->cy -= hdiff;
4840
4841 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4842 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4843 {
4844 if (lppos->x != wr.left || lppos->y != wr.top)
4845 {
4846 lppos->x += wdiff;
4847 lppos->y += hdiff;
4848 }
4849 else
4850 {
4851 lppos->flags |= SWP_NOMOVE;
4852 }
4853 }
4854
1edf84e7 4855 return 0;
ee78dc32
GV
4856 }
4857 }
4858 }
ee78dc32
GV
4859
4860 goto dflt;
1edf84e7 4861
b1f918f8
GV
4862 case WM_GETMINMAXINFO:
4863 /* Hack to correct bug that allows Emacs frames to be resized
4864 below the Minimum Tracking Size. */
4865 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4866 return 0;
4867
1edf84e7
GV
4868 case WM_EMACS_CREATESCROLLBAR:
4869 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4870 (struct scroll_bar *) lParam);
4871
5ac45f98 4872 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4873 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4874
dfdb4047 4875 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4876 {
4877 HWND foreground_window;
4878 DWORD foreground_thread, retval;
4879
4880 /* On NT 5.0, and apparently Windows 98, it is necessary to
4881 attach to the thread that currently has focus in order to
4882 pull the focus away from it. */
4883 foreground_window = GetForegroundWindow ();
4884 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4885 if (!foreground_window
4886 || foreground_thread == GetCurrentThreadId ()
4887 || !AttachThreadInput (GetCurrentThreadId (),
4888 foreground_thread, TRUE))
4889 foreground_thread = 0;
4890
4891 retval = SetForegroundWindow ((HWND) wParam);
4892
4893 /* Detach from the previous foreground thread. */
4894 if (foreground_thread)
4895 AttachThreadInput (GetCurrentThreadId (),
4896 foreground_thread, FALSE);
4897
4898 return retval;
4899 }
dfdb4047 4900
5ac45f98
GV
4901 case WM_EMACS_SETWINDOWPOS:
4902 {
1edf84e7
GV
4903 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4904 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
4905 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4906 }
1edf84e7 4907
ee78dc32 4908 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 4909 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
4910 return DestroyWindow ((HWND) wParam);
4911
4912 case WM_EMACS_TRACKPOPUPMENU:
4913 {
4914 UINT flags;
4915 POINT *pos;
4916 int retval;
4917 pos = (POINT *)lParam;
4918 flags = TPM_CENTERALIGN;
4919 if (button_state & LMOUSE)
4920 flags |= TPM_LEFTBUTTON;
4921 else if (button_state & RMOUSE)
4922 flags |= TPM_RIGHTBUTTON;
4923
87996783
GV
4924 /* Remember we did a SetCapture on the initial mouse down event,
4925 so for safety, we make sure the capture is cancelled now. */
4926 ReleaseCapture ();
490822ff 4927 button_state = 0;
87996783 4928
1edf84e7
GV
4929 /* Use menubar_active to indicate that WM_INITMENU is from
4930 TrackPopupMenu below, and should be ignored. */
4931 f = x_window_to_frame (dpyinfo, hwnd);
4932 if (f)
4933 f->output_data.w32->menubar_active = 1;
4934
4935 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4936 0, hwnd, NULL))
4937 {
4938 MSG amsg;
4939 /* Eat any mouse messages during popupmenu */
4940 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4941 PM_REMOVE));
4942 /* Get the menu selection, if any */
4943 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4944 {
4945 retval = LOWORD (amsg.wParam);
4946 }
4947 else
4948 {
4949 retval = 0;
4950 }
1edf84e7
GV
4951 }
4952 else
4953 {
4954 retval = -1;
4955 }
4956
4957 return retval;
4958 }
4959
ee78dc32 4960 default:
93fbe8b7
GV
4961 /* Check for messages registered at runtime. */
4962 if (msg == msh_mousewheel)
4963 {
4964 wmsg.dwModifiers = w32_get_modifiers ();
4965 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4966 return 0;
4967 }
4968
ee78dc32
GV
4969 dflt:
4970 return DefWindowProc (hwnd, msg, wParam, lParam);
4971 }
4972
1edf84e7
GV
4973
4974 /* The most common default return code for handled messages is 0. */
4975 return 0;
ee78dc32
GV
4976}
4977
4978void
4979my_create_window (f)
4980 struct frame * f;
4981{
4982 MSG msg;
4983
1edf84e7
GV
4984 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4985 abort ();
ee78dc32
GV
4986 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4987}
4988
fbd6baed 4989/* Create and set up the w32 window for frame F. */
ee78dc32
GV
4990
4991static void
fbd6baed 4992w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
4993 struct frame *f;
4994 long window_prompting;
4995 int minibuffer_only;
4996{
4997 BLOCK_INPUT;
4998
4999 /* Use the resource name as the top-level window name
5000 for looking up resources. Make a non-Lisp copy
5001 for the window manager, so GC relocation won't bother it.
5002
5003 Elsewhere we specify the window name for the window manager. */
5004
5005 {
5006 char *str = (char *) XSTRING (Vx_resource_name)->data;
5007 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5008 strcpy (f->namebuf, str);
5009 }
5010
5011 my_create_window (f);
5012
5013 validate_x_resource_name ();
5014
5015 /* x_set_name normally ignores requests to set the name if the
5016 requested name is the same as the current name. This is the one
5017 place where that assumption isn't correct; f->name is set, but
5018 the server hasn't been told. */
5019 {
5020 Lisp_Object name;
5021 int explicit = f->explicit_name;
5022
5023 f->explicit_name = 0;
5024 name = f->name;
5025 f->name = Qnil;
5026 x_set_name (f, name, explicit);
5027 }
5028
5029 UNBLOCK_INPUT;
5030
5031 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5032 initialize_frame_menubar (f);
5033
fbd6baed 5034 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5035 error ("Unable to create window");
5036}
5037
5038/* Handle the icon stuff for this window. Perhaps later we might
5039 want an x_set_icon_position which can be called interactively as
5040 well. */
5041
5042static void
5043x_icon (f, parms)
5044 struct frame *f;
5045 Lisp_Object parms;
5046{
5047 Lisp_Object icon_x, icon_y;
5048
e9e23e23 5049 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5050 icons in the tray. */
6fc2811b
JR
5051 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5052 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5053 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5054 {
5055 CHECK_NUMBER (icon_x, 0);
5056 CHECK_NUMBER (icon_y, 0);
5057 }
5058 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5059 error ("Both left and top icon corners of icon must be specified");
5060
5061 BLOCK_INPUT;
5062
5063 if (! EQ (icon_x, Qunbound))
5064 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5065
1edf84e7
GV
5066#if 0 /* TODO */
5067 /* Start up iconic or window? */
5068 x_wm_set_window_state
6fc2811b 5069 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5070 ? IconicState
5071 : NormalState));
5072
5073 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5074 ? f->icon_name
5075 : f->name))->data);
5076#endif
5077
ee78dc32
GV
5078 UNBLOCK_INPUT;
5079}
5080
6fc2811b
JR
5081
5082static void
5083x_make_gc (f)
5084 struct frame *f;
5085{
5086 XGCValues gc_values;
5087
5088 BLOCK_INPUT;
5089
5090 /* Create the GC's of this frame.
5091 Note that many default values are used. */
5092
5093 /* Normal video */
5094 gc_values.font = f->output_data.w32->font;
5095
5096 /* Cursor has cursor-color background, background-color foreground. */
5097 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5098 gc_values.background = f->output_data.w32->cursor_pixel;
5099 f->output_data.w32->cursor_gc
5100 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5101 (GCFont | GCForeground | GCBackground),
5102 &gc_values);
5103
5104 /* Reliefs. */
5105 f->output_data.w32->white_relief.gc = 0;
5106 f->output_data.w32->black_relief.gc = 0;
5107
5108 UNBLOCK_INPUT;
5109}
5110
5111
ee78dc32
GV
5112DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5113 1, 1, 0,
5114 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5115Returns an Emacs frame object.\n\
5116ALIST is an alist of frame parameters.\n\
5117If the parameters specify that the frame should not have a minibuffer,\n\
5118and do not specify a specific minibuffer window to use,\n\
5119then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5120be shared by the new frame.\n\
5121\n\
5122This function is an internal primitive--use `make-frame' instead.")
5123 (parms)
5124 Lisp_Object parms;
5125{
5126 struct frame *f;
5127 Lisp_Object frame, tem;
5128 Lisp_Object name;
5129 int minibuffer_only = 0;
5130 long window_prompting = 0;
5131 int width, height;
5132 int count = specpdl_ptr - specpdl;
1edf84e7 5133 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5134 Lisp_Object display;
6fc2811b 5135 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5136 Lisp_Object parent;
5137 struct kboard *kb;
5138
4587b026
GV
5139 check_w32 ();
5140
ee78dc32
GV
5141 /* Use this general default value to start with
5142 until we know if this frame has a specified name. */
5143 Vx_resource_name = Vinvocation_name;
5144
6fc2811b 5145 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5146 if (EQ (display, Qunbound))
5147 display = Qnil;
5148 dpyinfo = check_x_display_info (display);
5149#ifdef MULTI_KBOARD
5150 kb = dpyinfo->kboard;
5151#else
5152 kb = &the_only_kboard;
5153#endif
5154
6fc2811b 5155 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5156 if (!STRINGP (name)
5157 && ! EQ (name, Qunbound)
5158 && ! NILP (name))
5159 error ("Invalid frame name--not a string or nil");
5160
5161 if (STRINGP (name))
5162 Vx_resource_name = name;
5163
5164 /* See if parent window is specified. */
6fc2811b 5165 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5166 if (EQ (parent, Qunbound))
5167 parent = Qnil;
5168 if (! NILP (parent))
5169 CHECK_NUMBER (parent, 0);
5170
1edf84e7
GV
5171 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5172 /* No need to protect DISPLAY because that's not used after passing
5173 it to make_frame_without_minibuffer. */
5174 frame = Qnil;
5175 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5176 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5177 RES_TYPE_SYMBOL);
ee78dc32
GV
5178 if (EQ (tem, Qnone) || NILP (tem))
5179 f = make_frame_without_minibuffer (Qnil, kb, display);
5180 else if (EQ (tem, Qonly))
5181 {
5182 f = make_minibuffer_frame ();
5183 minibuffer_only = 1;
5184 }
5185 else if (WINDOWP (tem))
5186 f = make_frame_without_minibuffer (tem, kb, display);
5187 else
5188 f = make_frame (1);
5189
1edf84e7
GV
5190 XSETFRAME (frame, f);
5191
ee78dc32
GV
5192 /* Note that Windows does support scroll bars. */
5193 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5194 /* By default, make scrollbars the system standard width. */
5195 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5196
fbd6baed 5197 f->output_method = output_w32;
6fc2811b
JR
5198 f->output_data.w32 =
5199 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5200 bzero (f->output_data.w32, sizeof (struct w32_output));
ee78dc32 5201
4587b026
GV
5202 FRAME_FONTSET (f) = -1;
5203
1edf84e7 5204 f->icon_name
6fc2811b 5205 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5206 if (! STRINGP (f->icon_name))
5207 f->icon_name = Qnil;
5208
fbd6baed 5209/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5210#ifdef MULTI_KBOARD
5211 FRAME_KBOARD (f) = kb;
5212#endif
5213
5214 /* Specify the parent under which to make this window. */
5215
5216 if (!NILP (parent))
5217 {
1660f34a 5218 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5219 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5220 }
5221 else
5222 {
fbd6baed
GV
5223 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5224 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5225 }
5226
ee78dc32
GV
5227 /* Set the name; the functions to which we pass f expect the name to
5228 be set. */
5229 if (EQ (name, Qunbound) || NILP (name))
5230 {
fbd6baed 5231 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5232 f->explicit_name = 0;
5233 }
5234 else
5235 {
5236 f->name = name;
5237 f->explicit_name = 1;
5238 /* use the frame's title when getting resources for this frame. */
5239 specbind (Qx_resource_name, name);
5240 }
5241
5242 /* Extract the window parameters from the supplied values
5243 that are needed to determine window geometry. */
5244 {
5245 Lisp_Object font;
5246
6fc2811b
JR
5247 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5248
ee78dc32
GV
5249 BLOCK_INPUT;
5250 /* First, try whatever font the caller has specified. */
5251 if (STRINGP (font))
4587b026
GV
5252 {
5253 tem = Fquery_fontset (font, Qnil);
5254 if (STRINGP (tem))
5255 font = x_new_fontset (f, XSTRING (tem)->data);
5256 else
1075afa9 5257 font = x_new_font (f, XSTRING (font)->data);
4587b026 5258 }
ee78dc32
GV
5259 /* Try out a font which we hope has bold and italic variations. */
5260 if (!STRINGP (font))
e39649be 5261 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5262 if (! STRINGP (font))
6fc2811b 5263 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5264 /* If those didn't work, look for something which will at least work. */
5265 if (! STRINGP (font))
6fc2811b 5266 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5267 UNBLOCK_INPUT;
5268 if (! STRINGP (font))
1edf84e7 5269 font = build_string ("Fixedsys");
ee78dc32
GV
5270
5271 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5272 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5273 }
5274
5275 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5276 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5277 /* This defaults to 2 in order to match xterm. We recognize either
5278 internalBorderWidth or internalBorder (which is what xterm calls
5279 it). */
5280 if (NILP (Fassq (Qinternal_border_width, parms)))
5281 {
5282 Lisp_Object value;
5283
6fc2811b 5284 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5285 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5286 if (! EQ (value, Qunbound))
5287 parms = Fcons (Fcons (Qinternal_border_width, value),
5288 parms);
5289 }
1edf84e7 5290 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5291 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5292 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5293 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5294 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5295
5296 /* Also do the stuff which must be set before the window exists. */
5297 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5298 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5299 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5300 "background", "Background", RES_TYPE_STRING);
ee78dc32 5301 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5302 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5303 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5304 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5305 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5306 "borderColor", "BorderColor", RES_TYPE_STRING);
5307 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5308 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5309 x_default_parameter (f, parms, Qline_spacing, Qnil,
5310 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
6fc2811b 5311
ee78dc32 5312
6fc2811b
JR
5313 /* Init faces before x_default_parameter is called for scroll-bar
5314 parameters because that function calls x_set_scroll_bar_width,
5315 which calls change_frame_size, which calls Fset_window_buffer,
5316 which runs hooks, which call Fvertical_motion. At the end, we
5317 end up in init_iterator with a null face cache, which should not
5318 happen. */
5319 init_frame_faces (f);
5320
ee78dc32 5321 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5322 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5323 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5324 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5325 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5326 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5327 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5328 "title", "Title", RES_TYPE_STRING);
ee78dc32 5329
fbd6baed
GV
5330 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5331 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
ee78dc32
GV
5332 window_prompting = x_figure_window_size (f, parms);
5333
5334 if (window_prompting & XNegative)
5335 {
5336 if (window_prompting & YNegative)
fbd6baed 5337 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5338 else
fbd6baed 5339 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5340 }
5341 else
5342 {
5343 if (window_prompting & YNegative)
fbd6baed 5344 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5345 else
fbd6baed 5346 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5347 }
5348
fbd6baed 5349 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5350
6fc2811b
JR
5351 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5352 f->no_split = minibuffer_only || EQ (tem, Qt);
5353
5354 /* Create the window. Add the tool-bar height to the initial frame
5355 height so that the user gets a text display area of the size he
5356 specified with -g or via the registry. Later changes of the
5357 tool-bar height don't change the frame size. This is done so that
5358 users can create tall Emacs frames without having to guess how
5359 tall the tool-bar will get. */
5360 f->height += FRAME_TOOL_BAR_LINES (f);
fbd6baed 5361 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5362 x_icon (f, parms);
6fc2811b
JR
5363
5364 x_make_gc (f);
5365
5366 /* Now consider the frame official. */
5367 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5368 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5369
5370 /* We need to do this after creating the window, so that the
5371 icon-creation functions can say whose icon they're describing. */
5372 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5373 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5374
5375 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5376 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5377 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5378 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5379 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5380 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5381 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5382 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5383
5384 /* Dimensions, especially f->height, must be done via change_frame_size.
5385 Change will not be effected unless different from the current
5386 f->height. */
5387 width = f->width;
5388 height = f->height;
1026b400
RS
5389 f->height = 0;
5390 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5391 change_frame_size (f, height, width, 1, 0, 0);
5392
6fc2811b
JR
5393 /* Tell the server what size and position, etc, we want, and how
5394 badly we want them. This should be done after we have the menu
5395 bar so that its size can be taken into account. */
ee78dc32
GV
5396 BLOCK_INPUT;
5397 x_wm_set_size_hint (f, window_prompting, 0);
5398 UNBLOCK_INPUT;
5399
4694d762
JR
5400 /* Set up faces after all frame parameters are known. This call
5401 also merges in face attributes specified for new frames. If we
5402 don't do this, the `menu' face for instance won't have the right
5403 colors, and the menu bar won't appear in the specified colors for
5404 new frames. */
5405 call1 (Qface_set_after_frame_default, frame);
5406
6fc2811b
JR
5407 /* Make the window appear on the frame and enable display, unless
5408 the caller says not to. However, with explicit parent, Emacs
5409 cannot control visibility, so don't try. */
fbd6baed 5410 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5411 {
5412 Lisp_Object visibility;
5413
6fc2811b 5414 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5415 if (EQ (visibility, Qunbound))
5416 visibility = Qt;
5417
5418 if (EQ (visibility, Qicon))
5419 x_iconify_frame (f);
5420 else if (! NILP (visibility))
5421 x_make_frame_visible (f);
5422 else
5423 /* Must have been Qnil. */
5424 ;
5425 }
6fc2811b 5426 UNGCPRO;
ee78dc32
GV
5427 return unbind_to (count, frame);
5428}
5429
5430/* FRAME is used only to get a handle on the X display. We don't pass the
5431 display info directly because we're called from frame.c, which doesn't
5432 know about that structure. */
5433Lisp_Object
5434x_get_focus_frame (frame)
5435 struct frame *frame;
5436{
fbd6baed 5437 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5438 Lisp_Object xfocus;
fbd6baed 5439 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5440 return Qnil;
5441
fbd6baed 5442 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5443 return xfocus;
5444}
1edf84e7
GV
5445
5446DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5447 "Give FRAME input focus, raising to foreground if necessary.")
5448 (frame)
5449 Lisp_Object frame;
5450{
5451 x_focus_on_frame (check_x_frame (frame));
5452 return Qnil;
5453}
5454
ee78dc32 5455\f
767b1ff0
JR
5456/* Return the charset portion of a font name. */
5457char * xlfd_charset_of_font (char * fontname)
5458{
5459 char *charset, *encoding;
5460
5461 encoding = strrchr(fontname, '-');
ceb12877 5462 if (!encoding || encoding == fontname)
767b1ff0
JR
5463 return NULL;
5464
ceb12877 5465 charset = strrchr(encoding - 1, '-');
767b1ff0
JR
5466
5467 if (!charset || strcmp(charset, "-*-*") == 0)
5468 return NULL;
5469
5470 return charset + 1;
5471}
5472
33d52f9c
GV
5473struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5474 int size, char* filename);
767b1ff0 5475BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len, char * charset);
33d52f9c 5476
4587b026 5477struct font_info *
33d52f9c 5478w32_load_system_font (f,fontname,size)
55dcfc15
AI
5479 struct frame *f;
5480 char * fontname;
5481 int size;
ee78dc32 5482{
4587b026
GV
5483 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5484 Lisp_Object font_names;
5485
4587b026
GV
5486 /* Get a list of all the fonts that match this name. Once we
5487 have a list of matching fonts, we compare them against the fonts
5488 we already have loaded by comparing names. */
5489 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5490
5491 if (!NILP (font_names))
3c190163 5492 {
4587b026
GV
5493 Lisp_Object tail;
5494 int i;
4587b026
GV
5495
5496 /* First check if any are already loaded, as that is cheaper
5497 than loading another one. */
5498 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5499 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5500 if (dpyinfo->font_table[i].name
5501 && (!strcmp (dpyinfo->font_table[i].name,
5502 XSTRING (XCAR (tail))->data)
5503 || !strcmp (dpyinfo->font_table[i].full_name,
5504 XSTRING (XCAR (tail))->data)))
4587b026 5505 return (dpyinfo->font_table + i);
6fc2811b 5506
8e713be6 5507 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5508 }
1075afa9 5509 else if (w32_strict_fontnames)
5ca0cd71
GV
5510 {
5511 /* If EnumFontFamiliesEx was available, we got a full list of
5512 fonts back so stop now to avoid the possibility of loading a
5513 random font. If we had to fall back to EnumFontFamilies, the
5514 list is incomplete, so continue whether the font we want was
5515 listed or not. */
5516 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5517 FARPROC enum_font_families_ex
1075afa9 5518 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5519 if (enum_font_families_ex)
5520 return NULL;
5521 }
4587b026
GV
5522
5523 /* Load the font and add it to the table. */
5524 {
767b1ff0 5525 char *full_name, *encoding, *charset;
4587b026
GV
5526 XFontStruct *font;
5527 struct font_info *fontp;
3c190163 5528 LOGFONT lf;
4587b026 5529 BOOL ok;
6fc2811b 5530 int i;
5ac45f98 5531
4587b026 5532 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5533 return (NULL);
5ac45f98 5534
4587b026
GV
5535 if (!*lf.lfFaceName)
5536 /* If no name was specified for the font, we get a random font
5537 from CreateFontIndirect - this is not particularly
5538 desirable, especially since CreateFontIndirect does not
5539 fill out the missing name in lf, so we never know what we
5540 ended up with. */
5541 return NULL;
5542
3c190163 5543 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5544 bzero (font, sizeof (*font));
5ac45f98 5545
33d52f9c
GV
5546 /* Set bdf to NULL to indicate that this is a Windows font. */
5547 font->bdf = NULL;
5ac45f98 5548
3c190163 5549 BLOCK_INPUT;
5ac45f98
GV
5550
5551 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5552
1a292d24
AI
5553 if (font->hfont == NULL)
5554 {
5555 ok = FALSE;
5556 }
5557 else
5558 {
5559 HDC hdc;
5560 HANDLE oldobj;
5c6682be 5561 int codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5562
5563 hdc = GetDC (dpyinfo->root_window);
5564 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5565
1a292d24 5566 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5567 if (codepage == CP_UNICODE)
5568 font->double_byte_p = 1;
5569 else
5570 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
5571
1a292d24
AI
5572 SelectObject (hdc, oldobj);
5573 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5574 /* Fill out details in lf according to the font that was
5575 actually loaded. */
5576 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5577 lf.lfWidth = font->tm.tmAveCharWidth;
5578 lf.lfWeight = font->tm.tmWeight;
5579 lf.lfItalic = font->tm.tmItalic;
5580 lf.lfCharSet = font->tm.tmCharSet;
5581 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5582 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5583 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5584 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5585
5586 w32_cache_char_metrics (font);
1a292d24 5587 }
5ac45f98 5588
1a292d24 5589 UNBLOCK_INPUT;
5ac45f98 5590
4587b026
GV
5591 if (!ok)
5592 {
1a292d24
AI
5593 w32_unload_font (dpyinfo, font);
5594 return (NULL);
5595 }
ee78dc32 5596
6fc2811b
JR
5597 /* Find a free slot in the font table. */
5598 for (i = 0; i < dpyinfo->n_fonts; ++i)
5599 if (dpyinfo->font_table[i].name == NULL)
5600 break;
5601
5602 /* If no free slot found, maybe enlarge the font table. */
5603 if (i == dpyinfo->n_fonts
5604 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5605 {
6fc2811b
JR
5606 int sz;
5607 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5608 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5609 dpyinfo->font_table
6fc2811b 5610 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5611 }
5612
6fc2811b
JR
5613 fontp = dpyinfo->font_table + i;
5614 if (i == dpyinfo->n_fonts)
5615 ++dpyinfo->n_fonts;
4587b026
GV
5616
5617 /* Now fill in the slots of *FONTP. */
5618 BLOCK_INPUT;
5619 fontp->font = font;
6fc2811b 5620 fontp->font_idx = i;
4587b026
GV
5621 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5622 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5623
767b1ff0
JR
5624 charset = xlfd_charset_of_font (fontname);
5625
4587b026
GV
5626 /* Work out the font's full name. */
5627 full_name = (char *)xmalloc (100);
767b1ff0 5628 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
5629 fontp->full_name = full_name;
5630 else
5631 {
5632 /* If all else fails - just use the name we used to load it. */
5633 xfree (full_name);
5634 fontp->full_name = fontp->name;
5635 }
5636
5637 fontp->size = FONT_WIDTH (font);
5638 fontp->height = FONT_HEIGHT (font);
5639
5640 /* The slot `encoding' specifies how to map a character
5641 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
5642 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5643 (0:0x20..0x7F, 1:0xA0..0xFF,
5644 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 5645 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 5646 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
5647 which is never used by any charset. If mapping can't be
5648 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5649
5650 /* SJIS fonts need to be set to type 4, all others seem to work as
5651 type FONT_ENCODING_NOT_DECIDED. */
5652 encoding = strrchr (fontp->name, '-');
5653 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5654 fontp->encoding[1] = 4;
33d52f9c 5655 else
1c885fe1 5656 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5657
5658 /* The following three values are set to 0 under W32, which is
5659 what they get set to if XGetFontProperty fails under X. */
5660 fontp->baseline_offset = 0;
5661 fontp->relative_compose = 0;
33d52f9c 5662 fontp->default_ascent = 0;
4587b026 5663
6fc2811b
JR
5664 /* Set global flag fonts_changed_p to non-zero if the font loaded
5665 has a character with a smaller width than any other character
5666 before, or if the font loaded has a smalle>r height than any
5667 other font loaded before. If this happens, it will make a
5668 glyph matrix reallocation necessary. */
5669 fonts_changed_p = x_compute_min_glyph_bounds (f);
4587b026 5670 UNBLOCK_INPUT;
4587b026
GV
5671 return fontp;
5672 }
5673}
5674
33d52f9c
GV
5675/* Load font named FONTNAME of size SIZE for frame F, and return a
5676 pointer to the structure font_info while allocating it dynamically.
5677 If loading fails, return NULL. */
5678struct font_info *
5679w32_load_font (f,fontname,size)
5680struct frame *f;
5681char * fontname;
5682int size;
5683{
5684 Lisp_Object bdf_fonts;
5685 struct font_info *retval = NULL;
5686
5687 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5688
5689 while (!retval && CONSP (bdf_fonts))
5690 {
5691 char *bdf_name, *bdf_file;
5692 Lisp_Object bdf_pair;
5693
8e713be6
KR
5694 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5695 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5696 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
5697
5698 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5699
8e713be6 5700 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
5701 }
5702
5703 if (retval)
5704 return retval;
5705
5706 return w32_load_system_font(f, fontname, size);
5707}
5708
5709
ee78dc32 5710void
fbd6baed
GV
5711w32_unload_font (dpyinfo, font)
5712 struct w32_display_info *dpyinfo;
ee78dc32
GV
5713 XFontStruct * font;
5714{
5715 if (font)
5716 {
c6be3860 5717 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
5718 if (font->bdf) w32_free_bdf_font (font->bdf);
5719
3c190163 5720 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5721 xfree (font);
5722 }
5723}
5724
fbd6baed 5725/* The font conversion stuff between x and w32 */
ee78dc32
GV
5726
5727/* X font string is as follows (from faces.el)
5728 * (let ((- "[-?]")
5729 * (foundry "[^-]+")
5730 * (family "[^-]+")
5731 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5732 * (weight\? "\\([^-]*\\)") ; 1
5733 * (slant "\\([ior]\\)") ; 2
5734 * (slant\? "\\([^-]?\\)") ; 2
5735 * (swidth "\\([^-]*\\)") ; 3
5736 * (adstyle "[^-]*") ; 4
5737 * (pixelsize "[0-9]+")
5738 * (pointsize "[0-9][0-9]+")
5739 * (resx "[0-9][0-9]+")
5740 * (resy "[0-9][0-9]+")
5741 * (spacing "[cmp?*]")
5742 * (avgwidth "[0-9]+")
5743 * (registry "[^-]+")
5744 * (encoding "[^-]+")
5745 * )
ee78dc32 5746 */
ee78dc32
GV
5747
5748LONG
fbd6baed 5749x_to_w32_weight (lpw)
ee78dc32
GV
5750 char * lpw;
5751{
5752 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
5753
5754 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5755 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5756 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5757 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 5758 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
5759 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5760 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5761 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5762 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5763 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 5764 else
5ac45f98 5765 return FW_DONTCARE;
ee78dc32
GV
5766}
5767
5ac45f98 5768
ee78dc32 5769char *
fbd6baed 5770w32_to_x_weight (fnweight)
ee78dc32
GV
5771 int fnweight;
5772{
5ac45f98
GV
5773 if (fnweight >= FW_HEAVY) return "heavy";
5774 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5775 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 5776 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
5777 if (fnweight >= FW_MEDIUM) return "medium";
5778 if (fnweight >= FW_NORMAL) return "normal";
5779 if (fnweight >= FW_LIGHT) return "light";
5780 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5781 if (fnweight >= FW_THIN) return "thin";
5782 else
5783 return "*";
5784}
5785
5786LONG
fbd6baed 5787x_to_w32_charset (lpcs)
5ac45f98
GV
5788 char * lpcs;
5789{
767b1ff0 5790 Lisp_Object this_entry, w32_charset;
4587b026 5791
dfff8a69
JR
5792 /* Look through w32-charset-info-alist for the character set.
5793 Format of each entry is
5794 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5795 */
767b1ff0 5796 this_entry = Fassoc (build_string(lpcs), Vw32_charset_info_alist);
4587b026 5797
767b1ff0
JR
5798 if (NILP(this_entry))
5799 {
5800 /* At startup, we want iso8859-1 fonts to come up properly. */
5801 if (stricmp(lpcs, "iso8859-1") == 0)
5802 return ANSI_CHARSET;
5803 else
5804 return DEFAULT_CHARSET;
5805 }
5806
5807 w32_charset = Fcar (Fcdr (this_entry));
5808
5809 // Translate Lisp symbol to number.
5810 if (w32_charset == Qw32_charset_ansi)
5811 return ANSI_CHARSET;
5812 if (w32_charset == Qw32_charset_symbol)
5813 return SYMBOL_CHARSET;
5814 if (w32_charset == Qw32_charset_shiftjis)
5815 return SHIFTJIS_CHARSET;
5816 if (w32_charset == Qw32_charset_hangeul)
5817 return HANGEUL_CHARSET;
5818 if (w32_charset == Qw32_charset_chinesebig5)
5819 return CHINESEBIG5_CHARSET;
5820 if (w32_charset == Qw32_charset_gb2312)
5821 return GB2312_CHARSET;
5822 if (w32_charset == Qw32_charset_oem)
5823 return OEM_CHARSET;
dfff8a69 5824#ifdef JOHAB_CHARSET
767b1ff0
JR
5825 if (w32_charset == Qw32_charset_johab)
5826 return JOHAB_CHARSET;
5827 if (w32_charset == Qw32_charset_easteurope)
5828 return EASTEUROPE_CHARSET;
5829 if (w32_charset == Qw32_charset_turkish)
5830 return TURKISH_CHARSET;
5831 if (w32_charset == Qw32_charset_baltic)
5832 return BALTIC_CHARSET;
5833 if (w32_charset == Qw32_charset_russian)
5834 return RUSSIAN_CHARSET;
5835 if (w32_charset == Qw32_charset_arabic)
5836 return ARABIC_CHARSET;
5837 if (w32_charset == Qw32_charset_greek)
5838 return GREEK_CHARSET;
5839 if (w32_charset == Qw32_charset_hebrew)
5840 return HEBREW_CHARSET;
5841 if (w32_charset == Qw32_charset_vietnamese)
5842 return VIETNAMESE_CHARSET;
5843 if (w32_charset == Qw32_charset_thai)
5844 return THAI_CHARSET;
5845 if (w32_charset == Qw32_charset_mac)
5846 return MAC_CHARSET;
dfff8a69 5847#endif /* JOHAB_CHARSET */
5ac45f98 5848#ifdef UNICODE_CHARSET
767b1ff0
JR
5849 if (w32_charset == Qw32_charset_unicode)
5850 return UNICODE_CHARSET;
5ac45f98 5851#endif
dfff8a69
JR
5852
5853 return DEFAULT_CHARSET;
5ac45f98
GV
5854}
5855
dfff8a69 5856
5ac45f98 5857char *
fbd6baed 5858w32_to_x_charset (fncharset)
5ac45f98
GV
5859 int fncharset;
5860{
1edf84e7 5861 static char buf[16];
767b1ff0 5862 Lisp_Object charset_type;
1edf84e7 5863
5ac45f98
GV
5864 switch (fncharset)
5865 {
767b1ff0
JR
5866 case ANSI_CHARSET:
5867 /* Handle startup case of w32-charset-info-alist not
5868 being set up yet. */
5869 if (NILP(Vw32_charset_info_alist))
5870 return "iso8859-1";
5871 charset_type = Qw32_charset_ansi;
5872 break;
5873 case DEFAULT_CHARSET:
5874 charset_type = Qw32_charset_default;
5875 break;
5876 case SYMBOL_CHARSET:
5877 charset_type = Qw32_charset_symbol;
5878 break;
5879 case SHIFTJIS_CHARSET:
5880 charset_type = Qw32_charset_shiftjis;
5881 break;
5882 case HANGEUL_CHARSET:
5883 charset_type = Qw32_charset_hangeul;
5884 break;
5885 case GB2312_CHARSET:
5886 charset_type = Qw32_charset_gb2312;
5887 break;
5888 case CHINESEBIG5_CHARSET:
5889 charset_type = Qw32_charset_chinesebig5;
5890 break;
5891 case OEM_CHARSET:
5892 charset_type = Qw32_charset_oem;
5893 break;
4587b026
GV
5894
5895 /* More recent versions of Windows (95 and NT4.0) define more
5896 character sets. */
5897#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
5898 case EASTEUROPE_CHARSET:
5899 charset_type = Qw32_charset_easteurope;
5900 break;
5901 case TURKISH_CHARSET:
5902 charset_type = Qw32_charset_turkish;
5903 break;
5904 case BALTIC_CHARSET:
5905 charset_type = Qw32_charset_baltic;
5906 break;
33d52f9c 5907 case RUSSIAN_CHARSET:
767b1ff0
JR
5908 charset_type = Qw32_charset_russian;
5909 break;
5910 case ARABIC_CHARSET:
5911 charset_type = Qw32_charset_arabic;
5912 break;
5913 case GREEK_CHARSET:
5914 charset_type = Qw32_charset_greek;
5915 break;
5916 case HEBREW_CHARSET:
5917 charset_type = Qw32_charset_hebrew;
5918 break;
5919 case VIETNAMESE_CHARSET:
5920 charset_type = Qw32_charset_vietnamese;
5921 break;
5922 case THAI_CHARSET:
5923 charset_type = Qw32_charset_thai;
5924 break;
5925 case MAC_CHARSET:
5926 charset_type = Qw32_charset_mac;
5927 break;
5928 case JOHAB_CHARSET:
5929 charset_type = Qw32_charset_johab;
5930 break;
4587b026
GV
5931#endif
5932
5ac45f98 5933#ifdef UNICODE_CHARSET
767b1ff0
JR
5934 case UNICODE_CHARSET:
5935 charset_type = Qw32_charset_unicode;
5936 break;
5ac45f98 5937#endif
767b1ff0
JR
5938 default:
5939 /* Encode numerical value of unknown charset. */
5940 sprintf (buf, "*-#%u", fncharset);
5941 return buf;
5ac45f98 5942 }
767b1ff0
JR
5943
5944 {
5945 Lisp_Object rest;
5946 char * best_match = NULL;
5947
5948 /* Look through w32-charset-info-alist for the character set.
5949 Prefer ISO codepages, and prefer lower numbers in the ISO
5950 range. Only return charsets for codepages which are installed.
5951
5952 Format of each entry is
5953 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5954 */
5955 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5956 {
5957 char * x_charset;
5958 Lisp_Object w32_charset;
5959 Lisp_Object codepage;
5960
5961 Lisp_Object this_entry = XCAR (rest);
5962
5963 /* Skip invalid entries in alist. */
5964 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
5965 || !CONSP (XCDR (this_entry))
5966 || !SYMBOLP (XCAR (XCDR (this_entry))))
5967 continue;
5968
5969 x_charset = XSTRING (XCAR (this_entry))->data;
5970 w32_charset = XCAR (XCDR (this_entry));
5971 codepage = XCDR (XCDR (this_entry));
5972
5973 /* Look for Same charset and a valid codepage (or non-int
5974 which means ignore). */
5975 if (w32_charset == charset_type
5976 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
5977 || IsValidCodePage (XINT (codepage))))
5978 {
5979 /* If we don't have a match already, then this is the
5980 best. */
5981 if (!best_match)
5982 best_match = x_charset;
5983 /* If this is an ISO codepage, and the best so far isn't,
5984 then this is better. */
5985 else if (stricmp (best_match, "iso") != 0
5986 && stricmp (x_charset, "iso") == 0)
5987 best_match = x_charset;
5988 /* If both are ISO8859 codepages, choose the one with the
5989 lowest number in the encoding field. */
5990 else if (stricmp (best_match, "iso8859-") == 0
5991 && stricmp (x_charset, "iso8859-") == 0)
5992 {
5993 int best_enc = atoi (best_match + 8);
5994 int this_enc = atoi (x_charset + 8);
5995 if (this_enc > 0 && this_enc < best_enc)
5996 best_match = x_charset;
5997 }
5998 }
5999 }
6000
6001 /* If no match, encode the numeric value. */
6002 if (!best_match)
6003 {
6004 sprintf (buf, "*-#%u", fncharset);
6005 return buf;
6006 }
6007
6008 strncpy(buf, best_match, 15);
6009 buf[15] = '\0';
6010 return buf;
6011 }
ee78dc32
GV
6012}
6013
dfff8a69
JR
6014
6015/* Get the Windows codepage corresponding to the specified font. The
6016 charset info in the font name is used to look up
6017 w32-charset-to-codepage-alist. */
6018int
6019w32_codepage_for_font (char *fontname)
6020{
767b1ff0
JR
6021 Lisp_Object codepage, entry;
6022 char *charset_str, *charset, *end;
dfff8a69 6023
767b1ff0 6024 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6025 return CP_DEFAULT;
6026
767b1ff0
JR
6027 /* Extract charset part of font string. */
6028 charset = xlfd_charset_of_font (fontname);
6029
6030 if (!charset)
ceb12877 6031 return CP_UNKNOWN;
767b1ff0
JR
6032
6033 charset_str = (char *) alloca (strlen (charset));
6034 strcpy (charset_str, charset);
6035
dfff8a69
JR
6036 /* Remove leading "*-". */
6037 if (strncmp ("*-", charset_str, 2) == 0)
6038 charset = charset_str + 2;
6039 else
6040 charset = charset_str;
6041
6042 /* Stop match at wildcard (including preceding '-'). */
6043 if (end = strchr (charset, '*'))
6044 {
6045 if (end > charset && *(end-1) == '-')
6046 end--;
6047 *end = '\0';
6048 }
6049
767b1ff0
JR
6050 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6051 if (NILP (entry))
ceb12877 6052 return CP_UNKNOWN;
767b1ff0
JR
6053
6054 codepage = Fcdr (Fcdr (entry));
6055
6056 if (NILP (codepage))
6057 return CP_8BIT;
6058 else if (XFASTINT (codepage) == XFASTINT (Qt))
6059 return CP_UNICODE;
6060 else if (INTEGERP (codepage))
dfff8a69
JR
6061 return XINT (codepage);
6062 else
ceb12877 6063 return CP_UNKNOWN;
dfff8a69
JR
6064}
6065
6066
ee78dc32 6067BOOL
767b1ff0 6068w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6069 LOGFONT * lplogfont;
6070 char * lpxstr;
6071 int len;
767b1ff0 6072 char * specific_charset;
ee78dc32 6073{
6fc2811b 6074 char* fonttype;
f46e6225 6075 char *fontname;
3cb20f4a
RS
6076 char height_pixels[8];
6077 char height_dpi[8];
6078 char width_pixels[8];
4587b026 6079 char *fontname_dash;
d88c567c
JR
6080 int display_resy = one_w32_display_info.resy;
6081 int display_resx = one_w32_display_info.resx;
f46e6225
GV
6082 int bufsz;
6083 struct coding_system coding;
3cb20f4a
RS
6084
6085 if (!lpxstr) abort ();
ee78dc32 6086
3cb20f4a
RS
6087 if (!lplogfont)
6088 return FALSE;
6089
6fc2811b
JR
6090 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6091 fonttype = "raster";
6092 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6093 fonttype = "outline";
6094 else
6095 fonttype = "unknown";
6096
f46e6225
GV
6097 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
6098 &coding);
aab5ac44
KH
6099 coding.src_multibyte = 0;
6100 coding.dst_multibyte = 1;
f46e6225
GV
6101 coding.mode |= CODING_MODE_LAST_BLOCK;
6102 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6103
6104 fontname = alloca(sizeof(*fontname) * bufsz);
6105 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6106 strlen(lplogfont->lfFaceName), bufsz - 1);
6107 *(fontname + coding.produced) = '\0';
4587b026
GV
6108
6109 /* Replace dashes with underscores so the dashes are not
f46e6225 6110 misinterpreted. */
4587b026
GV
6111 fontname_dash = fontname;
6112 while (fontname_dash = strchr (fontname_dash, '-'))
6113 *fontname_dash = '_';
6114
3cb20f4a 6115 if (lplogfont->lfHeight)
ee78dc32 6116 {
3cb20f4a
RS
6117 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6118 sprintf (height_dpi, "%u",
33d52f9c 6119 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6120 }
6121 else
ee78dc32 6122 {
3cb20f4a
RS
6123 strcpy (height_pixels, "*");
6124 strcpy (height_dpi, "*");
ee78dc32 6125 }
3cb20f4a
RS
6126 if (lplogfont->lfWidth)
6127 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6128 else
6129 strcpy (width_pixels, "*");
6130
6131 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6132 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6133 fonttype, /* foundry */
4587b026
GV
6134 fontname, /* family */
6135 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6136 lplogfont->lfItalic?'i':'r', /* slant */
6137 /* setwidth name */
6138 /* add style name */
6139 height_pixels, /* pixel size */
6140 height_dpi, /* point size */
33d52f9c
GV
6141 display_resx, /* resx */
6142 display_resy, /* resy */
4587b026
GV
6143 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6144 ? 'p' : 'c', /* spacing */
6145 width_pixels, /* avg width */
767b1ff0
JR
6146 specific_charset ? specific_charset
6147 : w32_to_x_charset (lplogfont->lfCharSet)
6148 /* charset registry and encoding */
3cb20f4a
RS
6149 );
6150
ee78dc32
GV
6151 lpxstr[len - 1] = 0; /* just to be sure */
6152 return (TRUE);
6153}
6154
6155BOOL
fbd6baed 6156x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6157 char * lpxstr;
6158 LOGFONT * lplogfont;
6159{
f46e6225
GV
6160 struct coding_system coding;
6161
ee78dc32 6162 if (!lplogfont) return (FALSE);
f46e6225 6163
ee78dc32 6164 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6165
1a292d24 6166 /* Set default value for each field. */
771c47d5 6167#if 1
ee78dc32
GV
6168 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6169 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6170 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6171#else
6172 /* go for maximum quality */
6173 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6174 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6175 lplogfont->lfQuality = PROOF_QUALITY;
6176#endif
6177
1a292d24
AI
6178 lplogfont->lfCharSet = DEFAULT_CHARSET;
6179 lplogfont->lfWeight = FW_DONTCARE;
6180 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6181
5ac45f98
GV
6182 if (!lpxstr)
6183 return FALSE;
6184
6185 /* Provide a simple escape mechanism for specifying Windows font names
6186 * directly -- if font spec does not beginning with '-', assume this
6187 * format:
6188 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6189 */
ee78dc32 6190
5ac45f98
GV
6191 if (*lpxstr == '-')
6192 {
33d52f9c
GV
6193 int fields, tem;
6194 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6195 width[10], resy[10], remainder[20];
5ac45f98 6196 char * encoding;
d98c0337 6197 int dpi = one_w32_display_info.resy;
5ac45f98
GV
6198
6199 fields = sscanf (lpxstr,
33d52f9c
GV
6200 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
6201 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5ac45f98
GV
6202 if (fields == EOF) return (FALSE);
6203
6fc2811b
JR
6204 /* If wildcards cover more than one field, we don't know which
6205 field is which, so don't fill any in. */
6206
6207 if (fields < 9)
6208 fields = 0;
6209
5ac45f98
GV
6210 if (fields > 0 && name[0] != '*')
6211 {
8ea3e054
RS
6212 int bufsize;
6213 unsigned char *buf;
6214
f46e6225
GV
6215 setup_coding_system
6216 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
aab5ac44
KH
6217 coding.src_multibyte = 1;
6218 coding.dst_multibyte = 1;
8ea3e054
RS
6219 bufsize = encoding_buffer_size (&coding, strlen (name));
6220 buf = (unsigned char *) alloca (bufsize);
f46e6225 6221 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6222 encode_coding (&coding, name, buf, strlen (name), bufsize);
6223 if (coding.produced >= LF_FACESIZE)
6224 coding.produced = LF_FACESIZE - 1;
6225 buf[coding.produced] = 0;
6226 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6227 }
6228 else
6229 {
6fc2811b 6230 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6231 }
6232
6233 fields--;
6234
fbd6baed 6235 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6236
6237 fields--;
6238
c8874f14 6239 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6240
6241 fields--;
6242
6243 if (fields > 0 && pixels[0] != '*')
6244 lplogfont->lfHeight = atoi (pixels);
6245
6246 fields--;
5ac45f98 6247 fields--;
33d52f9c
GV
6248 if (fields > 0 && resy[0] != '*')
6249 {
6fc2811b 6250 tem = atoi (resy);
33d52f9c
GV
6251 if (tem > 0) dpi = tem;
6252 }
5ac45f98 6253
33d52f9c
GV
6254 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6255 lplogfont->lfHeight = atoi (height) * dpi / 720;
6256
6257 if (fields > 0)
5ac45f98
GV
6258 lplogfont->lfPitchAndFamily =
6259 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6260
6261 fields--;
6262
6263 if (fields > 0 && width[0] != '*')
6264 lplogfont->lfWidth = atoi (width) / 10;
6265
6266 fields--;
6267
4587b026 6268 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6269 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6270 {
5ac45f98
GV
6271 int len = strlen (remainder);
6272 if (len > 0 && remainder[len-1] == '-')
6273 remainder[len-1] = 0;
ee78dc32 6274 }
5ac45f98
GV
6275 encoding = remainder;
6276 if (strncmp (encoding, "*-", 2) == 0)
6277 encoding += 2;
fbd6baed 6278 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
5ac45f98
GV
6279 }
6280 else
6281 {
6282 int fields;
6283 char name[100], height[10], width[10], weight[20];
a1a80b40 6284
5ac45f98
GV
6285 fields = sscanf (lpxstr,
6286 "%99[^:]:%9[^:]:%9[^:]:%19s",
6287 name, height, width, weight);
6288
6289 if (fields == EOF) return (FALSE);
6290
6291 if (fields > 0)
6292 {
6293 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6294 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6295 }
6296 else
6297 {
6298 lplogfont->lfFaceName[0] = 0;
6299 }
6300
6301 fields--;
6302
6303 if (fields > 0)
6304 lplogfont->lfHeight = atoi (height);
6305
6306 fields--;
6307
6308 if (fields > 0)
6309 lplogfont->lfWidth = atoi (width);
6310
6311 fields--;
6312
fbd6baed 6313 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6314 }
6315
6316 /* This makes TrueType fonts work better. */
6317 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6318
ee78dc32
GV
6319 return (TRUE);
6320}
6321
d88c567c
JR
6322/* Strip the pixel height and point height from the given xlfd, and
6323 return the pixel height. If no pixel height is specified, calculate
6324 one from the point height, or if that isn't defined either, return
6325 0 (which usually signifies a scalable font).
6326*/
6327int xlfd_strip_height (char *fontname)
6328{
6329 int pixel_height, point_height, dpi, field_number;
6330 char *read_from, *write_to;
6331
6332 xassert (fontname);
6333
6334 pixel_height = field_number = 0;
6335 write_to = NULL;
6336
6337 /* Look for height fields. */
6338 for (read_from = fontname; *read_from; read_from++)
6339 {
6340 if (*read_from == '-')
6341 {
6342 field_number++;
6343 if (field_number == 7) /* Pixel height. */
6344 {
6345 read_from++;
6346 write_to = read_from;
6347
6348 /* Find end of field. */
6349 for (;*read_from && *read_from != '-'; read_from++)
6350 ;
6351
6352 /* Split the fontname at end of field. */
6353 if (*read_from)
6354 {
6355 *read_from = '\0';
6356 read_from++;
6357 }
6358 pixel_height = atoi (write_to);
6359 /* Blank out field. */
6360 if (read_from > write_to)
6361 {
6362 *write_to = '-';
6363 write_to++;
6364 }
767b1ff0 6365 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6366 return now. */
6367 else
6368 return pixel_height;
6369
6370 /* If we got a pixel height, the point height can be
6371 ignored. Just blank it out and break now. */
6372 if (pixel_height)
6373 {
6374 /* Find end of point size field. */
6375 for (; *read_from && *read_from != '-'; read_from++)
6376 ;
6377
6378 if (*read_from)
6379 read_from++;
6380
6381 /* Blank out the point size field. */
6382 if (read_from > write_to)
6383 {
6384 *write_to = '-';
6385 write_to++;
6386 }
6387 else
6388 return pixel_height;
6389
6390 break;
6391 }
6392 /* If the point height is already blank, break now. */
6393 if (*read_from == '-')
6394 {
6395 read_from++;
6396 break;
6397 }
6398 }
6399 else if (field_number == 8)
6400 {
6401 /* If we didn't get a pixel height, try to get the point
6402 height and convert that. */
6403 int point_size;
6404 char *point_size_start = read_from++;
6405
6406 /* Find end of field. */
6407 for (; *read_from && *read_from != '-'; read_from++)
6408 ;
6409
6410 if (*read_from)
6411 {
6412 *read_from = '\0';
6413 read_from++;
6414 }
6415
6416 point_size = atoi (point_size_start);
6417
6418 /* Convert to pixel height. */
6419 pixel_height = point_size
6420 * one_w32_display_info.height_in / 720;
6421
6422 /* Blank out this field and break. */
6423 *write_to = '-';
6424 write_to++;
6425 break;
6426 }
6427 }
6428 }
6429
6430 /* Shift the rest of the font spec into place. */
6431 if (write_to && read_from > write_to)
6432 {
6433 for (; *read_from; read_from++, write_to++)
6434 *write_to = *read_from;
6435 *write_to = '\0';
6436 }
6437
6438 return pixel_height;
6439}
6440
6fc2811b 6441/* Assume parameter 1 is fully qualified, no wildcards. */
ee78dc32 6442BOOL
6fc2811b
JR
6443w32_font_match (fontname, pattern)
6444 char * fontname;
6445 char * pattern;
ee78dc32 6446{
6fc2811b 6447 char *regex = alloca (strlen (pattern) * 2);
d88c567c 6448 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6449 char *ptr;
ee78dc32 6450
d88c567c
JR
6451 /* Copy fontname so we can modify it during comparison. */
6452 strcpy (font_name_copy, fontname);
6453
6fc2811b
JR
6454 ptr = regex;
6455 *ptr++ = '^';
ee78dc32 6456
6fc2811b
JR
6457 /* Turn pattern into a regexp and do a regexp match. */
6458 for (; *pattern; pattern++)
6459 {
6460 if (*pattern == '?')
6461 *ptr++ = '.';
6462 else if (*pattern == '*')
6463 {
6464 *ptr++ = '.';
6465 *ptr++ = '*';
6466 }
33d52f9c 6467 else
6fc2811b 6468 *ptr++ = *pattern;
ee78dc32 6469 }
6fc2811b
JR
6470 *ptr = '$';
6471 *(ptr + 1) = '\0';
6472
d88c567c
JR
6473 /* Strip out font heights and compare them seperately, since
6474 rounding error can cause mismatches. This also allows a
6475 comparison between a font that declares only a pixel height and a
6476 pattern that declares the point height.
6477 */
6478 {
6479 int font_height, pattern_height;
6480
6481 font_height = xlfd_strip_height (font_name_copy);
6482 pattern_height = xlfd_strip_height (regex);
6483
6484 /* Compare now, and don't bother doing expensive regexp matching
6485 if the heights differ. */
6486 if (font_height && pattern_height && (font_height != pattern_height))
6487 return FALSE;
6488 }
6489
6fc2811b 6490 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 6491 font_name_copy) >= 0);
ee78dc32
GV
6492}
6493
5ca0cd71
GV
6494/* Callback functions, and a structure holding info they need, for
6495 listing system fonts on W32. We need one set of functions to do the
6496 job properly, but these don't work on NT 3.51 and earlier, so we
6497 have a second set which don't handle character sets properly to
6498 fall back on.
6499
6500 In both cases, there are two passes made. The first pass gets one
6501 font from each family, the second pass lists all the fonts from
6502 each family. */
6503
ee78dc32
GV
6504typedef struct enumfont_t
6505{
6506 HDC hdc;
6507 int numFonts;
3cb20f4a 6508 LOGFONT logfont;
ee78dc32
GV
6509 XFontStruct *size_ref;
6510 Lisp_Object *pattern;
ee78dc32
GV
6511 Lisp_Object *tail;
6512} enumfont_t;
6513
6514int CALLBACK
6515enum_font_cb2 (lplf, lptm, FontType, lpef)
6516 ENUMLOGFONT * lplf;
6517 NEWTEXTMETRIC * lptm;
6518 int FontType;
6519 enumfont_t * lpef;
6520{
1edf84e7 6521 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
ee78dc32
GV
6522 return (1);
6523
4587b026
GV
6524 /* Check that the character set matches if it was specified */
6525 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6526 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6527 return (1);
6528
ee78dc32
GV
6529 {
6530 char buf[100];
4587b026 6531 Lisp_Object width = Qnil;
767b1ff0 6532 char *charset = NULL;
ee78dc32 6533
6fc2811b
JR
6534 /* Truetype fonts do not report their true metrics until loaded */
6535 if (FontType != RASTER_FONTTYPE)
3cb20f4a 6536 {
6fc2811b
JR
6537 if (!NILP (*(lpef->pattern)))
6538 {
6539 /* Scalable fonts are as big as you want them to be. */
6540 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6541 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6542 width = make_number (lpef->logfont.lfWidth);
6543 }
6544 else
6545 {
6546 lplf->elfLogFont.lfHeight = 0;
6547 lplf->elfLogFont.lfWidth = 0;
6548 }
3cb20f4a 6549 }
6fc2811b 6550
f46e6225
GV
6551 /* Make sure the height used here is the same as everywhere
6552 else (ie character height, not cell height). */
6fc2811b
JR
6553 if (lplf->elfLogFont.lfHeight > 0)
6554 {
6555 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6556 if (FontType == RASTER_FONTTYPE)
6557 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6558 else
6559 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6560 }
4587b026 6561
767b1ff0
JR
6562 if (!NILP (*(lpef->pattern)))
6563 {
6564 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6565
6566 /* Ensure that charset is valid for this font. */
6567 if (charset
6568 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6569 charset = NULL;
6570 }
6571
6572 /* TODO: List all relevant charsets if charset not specified. */
6573 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
33d52f9c 6574 return (0);
ee78dc32 6575
5ca0cd71
GV
6576 if (NILP (*(lpef->pattern))
6577 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 6578 {
4587b026 6579 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
8e713be6 6580 lpef->tail = &(XCDR (*lpef->tail));
ee78dc32
GV
6581 lpef->numFonts++;
6582 }
6583 }
6fc2811b 6584
ee78dc32
GV
6585 return (1);
6586}
6587
6588int CALLBACK
6589enum_font_cb1 (lplf, lptm, FontType, lpef)
6590 ENUMLOGFONT * lplf;
6591 NEWTEXTMETRIC * lptm;
6592 int FontType;
6593 enumfont_t * lpef;
6594{
6595 return EnumFontFamilies (lpef->hdc,
6596 lplf->elfLogFont.lfFaceName,
6597 (FONTENUMPROC) enum_font_cb2,
6598 (LPARAM) lpef);
6599}
6600
6601
5ca0cd71
GV
6602int CALLBACK
6603enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6604 ENUMLOGFONTEX * lplf;
6605 NEWTEXTMETRICEX * lptm;
6606 int font_type;
6607 enumfont_t * lpef;
6608{
6609 /* We are not interested in the extra info we get back from the 'Ex
6610 version - only the fact that we get character set variations
6611 enumerated seperately. */
6612 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6613 font_type, lpef);
6614}
6615
6616int CALLBACK
6617enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6618 ENUMLOGFONTEX * lplf;
6619 NEWTEXTMETRICEX * lptm;
6620 int font_type;
6621 enumfont_t * lpef;
6622{
6623 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6624 FARPROC enum_font_families_ex
6625 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6626 /* We don't really expect EnumFontFamiliesEx to disappear once we
6627 get here, so don't bother handling it gracefully. */
6628 if (enum_font_families_ex == NULL)
6629 error ("gdi32.dll has disappeared!");
6630 return enum_font_families_ex (lpef->hdc,
6631 &lplf->elfLogFont,
6632 (FONTENUMPROC) enum_fontex_cb2,
6633 (LPARAM) lpef, 0);
6634}
6635
4587b026
GV
6636/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6637 and xterm.c in Emacs 20.3) */
6638
5ca0cd71 6639Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6640{
6641 char *fontname, *ptnstr;
6642 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6643 int n_fonts = 0;
33d52f9c
GV
6644
6645 list = Vw32_bdf_filename_alist;
6646 ptnstr = XSTRING (pattern)->data;
6647
8e713be6 6648 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6649 {
8e713be6 6650 tem = XCAR (list);
33d52f9c 6651 if (CONSP (tem))
8e713be6 6652 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
6653 else if (STRINGP (tem))
6654 fontname = XSTRING (tem)->data;
6655 else
6656 continue;
6657
6658 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6659 {
8e713be6 6660 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6661 n_fonts++;
6662 if (n_fonts >= max_names)
6663 break;
6664 }
33d52f9c
GV
6665 }
6666
6667 return newlist;
6668}
6669
5ca0cd71
GV
6670Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
6671 int size, int max_names);
6672
4587b026
GV
6673/* Return a list of names of available fonts matching PATTERN on frame
6674 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6675 to be listed. Frame F NULL means we have not yet created any
6676 frame, which means we can't get proper size info, as we don't have
6677 a device context to use for GetTextMetrics.
6678 MAXNAMES sets a limit on how many fonts to match. */
6679
6680Lisp_Object
6681w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
6682{
6fc2811b 6683 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6684 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6685 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6686 int n_fonts = 0;
396594fe 6687
4587b026
GV
6688 patterns = Fassoc (pattern, Valternate_fontname_alist);
6689 if (NILP (patterns))
6690 patterns = Fcons (pattern, Qnil);
6691
8e713be6 6692 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6693 {
6694 enumfont_t ef;
767b1ff0 6695 int codepage;
4587b026 6696
8e713be6 6697 tpat = XCAR (patterns);
4587b026 6698
767b1ff0
JR
6699 if (!STRINGP (tpat))
6700 continue;
6701
6702 /* Avoid expensive EnumFontFamilies functions if we are not
6703 going to be able to output one of these anyway. */
6704 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6705 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
6706 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6707 && !IsValidCodePage(codepage))
767b1ff0
JR
6708 continue;
6709
4587b026
GV
6710 /* See if we cached the result for this particular query.
6711 The cache is an alist of the form:
6712 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6713 */
8e713be6 6714 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 6715 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
6716 {
6717 list = Fcdr_safe (list);
6718 /* We have a cached list. Don't have to get the list again. */
6719 goto label_cached;
6720 }
6721
6722 BLOCK_INPUT;
6723 /* At first, put PATTERN in the cache. */
6724 list = Qnil;
33d52f9c
GV
6725 ef.pattern = &tpat;
6726 ef.tail = &list;
4587b026 6727 ef.numFonts = 0;
33d52f9c 6728
5ca0cd71
GV
6729 /* Use EnumFontFamiliesEx where it is available, as it knows
6730 about character sets. Fall back to EnumFontFamilies for
6731 older versions of NT that don't support the 'Ex function. */
767b1ff0 6732 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 6733 {
5ca0cd71
GV
6734 LOGFONT font_match_pattern;
6735 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6736 FARPROC enum_font_families_ex
6737 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6738
6739 /* We do our own pattern matching so we can handle wildcards. */
6740 font_match_pattern.lfFaceName[0] = 0;
6741 font_match_pattern.lfPitchAndFamily = 0;
6742 /* We can use the charset, because if it is a wildcard it will
6743 be DEFAULT_CHARSET anyway. */
6744 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6745
33d52f9c 6746 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 6747
5ca0cd71
GV
6748 if (enum_font_families_ex)
6749 enum_font_families_ex (ef.hdc,
6750 &font_match_pattern,
6751 (FONTENUMPROC) enum_fontex_cb1,
6752 (LPARAM) &ef, 0);
6753 else
6754 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6755 (LPARAM)&ef);
4587b026 6756
33d52f9c 6757 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
6758 }
6759
6760 UNBLOCK_INPUT;
6761
6762 /* Make a list of the fonts we got back.
6763 Store that in the font cache for the display. */
8e713be6 6764 XCDR (dpyinfo->name_list_element)
33d52f9c 6765 = Fcons (Fcons (tpat, list),
8e713be6 6766 XCDR (dpyinfo->name_list_element));
4587b026
GV
6767
6768 label_cached:
6769 if (NILP (list)) continue; /* Try the remaining alternatives. */
6770
6771 newlist = second_best = Qnil;
6772
6773 /* Make a list of the fonts that have the right width. */
8e713be6 6774 for (; CONSP (list); list = XCDR (list))
4587b026
GV
6775 {
6776 int found_size;
8e713be6 6777 tem = XCAR (list);
4587b026
GV
6778
6779 if (!CONSP (tem))
6780 continue;
8e713be6 6781 if (NILP (XCAR (tem)))
4587b026
GV
6782 continue;
6783 if (!size)
6784 {
8e713be6 6785 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6786 n_fonts++;
6787 if (n_fonts >= maxnames)
6788 break;
6789 else
6790 continue;
4587b026 6791 }
8e713be6 6792 if (!INTEGERP (XCDR (tem)))
4587b026
GV
6793 {
6794 /* Since we don't yet know the size of the font, we must
6795 load it and try GetTextMetrics. */
4587b026
GV
6796 W32FontStruct thisinfo;
6797 LOGFONT lf;
6798 HDC hdc;
6799 HANDLE oldobj;
6800
8e713be6 6801 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
6802 continue;
6803
6804 BLOCK_INPUT;
33d52f9c 6805 thisinfo.bdf = NULL;
4587b026
GV
6806 thisinfo.hfont = CreateFontIndirect (&lf);
6807 if (thisinfo.hfont == NULL)
6808 continue;
6809
6810 hdc = GetDC (dpyinfo->root_window);
6811 oldobj = SelectObject (hdc, thisinfo.hfont);
6812 if (GetTextMetrics (hdc, &thisinfo.tm))
8e713be6 6813 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
4587b026 6814 else
8e713be6 6815 XCDR (tem) = make_number (0);
4587b026
GV
6816 SelectObject (hdc, oldobj);
6817 ReleaseDC (dpyinfo->root_window, hdc);
6818 DeleteObject(thisinfo.hfont);
6819 UNBLOCK_INPUT;
6820 }
8e713be6 6821 found_size = XINT (XCDR (tem));
4587b026 6822 if (found_size == size)
5ca0cd71 6823 {
8e713be6 6824 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6825 n_fonts++;
6826 if (n_fonts >= maxnames)
6827 break;
6828 }
4587b026
GV
6829 /* keep track of the closest matching size in case
6830 no exact match is found. */
6831 else if (found_size > 0)
6832 {
6833 if (NILP (second_best))
6834 second_best = tem;
5ca0cd71 6835
4587b026
GV
6836 else if (found_size < size)
6837 {
8e713be6
KR
6838 if (XINT (XCDR (second_best)) > size
6839 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
6840 second_best = tem;
6841 }
6842 else
6843 {
8e713be6
KR
6844 if (XINT (XCDR (second_best)) > size
6845 && XINT (XCDR (second_best)) >
4587b026
GV
6846 found_size)
6847 second_best = tem;
6848 }
6849 }
6850 }
6851
6852 if (!NILP (newlist))
6853 break;
6854 else if (!NILP (second_best))
6855 {
8e713be6 6856 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
6857 break;
6858 }
6859 }
6860
33d52f9c 6861 /* Include any bdf fonts. */
5ca0cd71 6862 if (n_fonts < maxnames)
33d52f9c
GV
6863 {
6864 Lisp_Object combined[2];
5ca0cd71 6865 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
6866 combined[1] = newlist;
6867 newlist = Fnconc(2, combined);
6868 }
6869
5ca0cd71
GV
6870 /* If we can't find a font that matches, check if Windows would be
6871 able to synthesize it from a different style. */
6fc2811b 6872 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
5ca0cd71
GV
6873 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6874
4587b026
GV
6875 return newlist;
6876}
6877
5ca0cd71
GV
6878Lisp_Object
6879w32_list_synthesized_fonts (f, pattern, size, max_names)
6880 FRAME_PTR f;
6881 Lisp_Object pattern;
6882 int size;
6883 int max_names;
6884{
6885 int fields;
6886 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6887 char style[20], slant;
6888 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6889
6890 full_pattn = XSTRING (pattern)->data;
6891
6892 pattn_part2 = alloca (XSTRING (pattern)->size);
6893 /* Allow some space for wildcard expansion. */
6894 new_pattn = alloca (XSTRING (pattern)->size + 100);
6895
6896 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6897 foundary, family, style, &slant, pattn_part2);
6898 if (fields == EOF || fields < 5)
6899 return Qnil;
6900
6901 /* If the style and slant are wildcards already there is no point
6902 checking again (and we don't want to keep recursing). */
6903 if (*style == '*' && slant == '*')
6904 return Qnil;
6905
6906 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6907
6908 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6909
8e713be6 6910 for ( ; CONSP (matches); matches = XCDR (matches))
5ca0cd71 6911 {
8e713be6 6912 tem = XCAR (matches);
5ca0cd71
GV
6913 if (!STRINGP (tem))
6914 continue;
6915
6916 full_pattn = XSTRING (tem)->data;
6917 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6918 foundary, family, pattn_part2);
6919 if (fields == EOF || fields < 3)
6920 continue;
6921
6922 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6923 slant, pattn_part2);
6924
6925 synthed_matches = Fcons (build_string (new_pattn),
6926 synthed_matches);
6927 }
6928
6929 return synthed_matches;
6930}
6931
6932
4587b026
GV
6933/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6934struct font_info *
6935w32_get_font_info (f, font_idx)
6936 FRAME_PTR f;
6937 int font_idx;
6938{
6939 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6940}
6941
6942
6943struct font_info*
6944w32_query_font (struct frame *f, char *fontname)
6945{
6946 int i;
6947 struct font_info *pfi;
6948
6949 pfi = FRAME_W32_FONT_TABLE (f);
6950
6951 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6952 {
6953 if (strcmp(pfi->name, fontname) == 0) return pfi;
6954 }
6955
6956 return NULL;
6957}
6958
6959/* Find a CCL program for a font specified by FONTP, and set the member
6960 `encoder' of the structure. */
6961
6962void
6963w32_find_ccl_program (fontp)
6964 struct font_info *fontp;
6965{
3545439c 6966 Lisp_Object list, elt;
4587b026 6967
8e713be6 6968 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 6969 {
8e713be6 6970 elt = XCAR (list);
4587b026 6971 if (CONSP (elt)
8e713be6
KR
6972 && STRINGP (XCAR (elt))
6973 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 6974 >= 0))
3545439c
KH
6975 break;
6976 }
6977 if (! NILP (list))
6978 {
17eedd00
KH
6979 struct ccl_program *ccl
6980 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 6981
8e713be6 6982 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
6983 xfree (ccl);
6984 else
6985 fontp->font_encoder = ccl;
4587b026
GV
6986 }
6987}
6988
6989\f
6fc2811b
JR
6990DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6991 1, 1, 0,
6992 "Return a list of BDF fonts in DIR, suitable for appending to\n\
767b1ff0 6993w32-bdf-filename-alist. Fonts which do not contain an xlfd description\n\
6fc2811b
JR
6994will not be included in the list. DIR may be a list of directories.")
6995 (directory)
6996 Lisp_Object directory;
6997{
6998 Lisp_Object list = Qnil;
6999 struct gcpro gcpro1, gcpro2;
ee78dc32 7000
6fc2811b
JR
7001 if (!CONSP (directory))
7002 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7003
6fc2811b 7004 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7005 {
6fc2811b
JR
7006 Lisp_Object pair[2];
7007 pair[0] = list;
7008 pair[1] = Qnil;
7009 GCPRO2 (directory, list);
7010 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7011 list = Fnconc( 2, pair );
7012 UNGCPRO;
7013 }
7014 return list;
7015}
ee78dc32 7016
6fc2811b
JR
7017/* Find BDF files in a specified directory. (use GCPRO when calling,
7018 as this calls lisp to get a directory listing). */
7019Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
7020{
7021 Lisp_Object filelist, list = Qnil;
7022 char fontname[100];
ee78dc32 7023
6fc2811b
JR
7024 if (!STRINGP(directory))
7025 return Qnil;
ee78dc32 7026
6fc2811b
JR
7027 filelist = Fdirectory_files (directory, Qt,
7028 build_string (".*\\.[bB][dD][fF]"), Qt);
ee78dc32 7029
6fc2811b 7030 for ( ; CONSP(filelist); filelist = XCDR (filelist))
ee78dc32 7031 {
6fc2811b
JR
7032 Lisp_Object filename = XCAR (filelist);
7033 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7034 store_in_alist (&list, build_string (fontname), filename);
7035 }
7036 return list;
7037}
ee78dc32 7038
6fc2811b
JR
7039\f
7040DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
dfff8a69 7041 "Internal function called by `color-defined-p', which see.")
6fc2811b
JR
7042 (color, frame)
7043 Lisp_Object color, frame;
7044{
7045 XColor foo;
7046 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7047
6fc2811b 7048 CHECK_STRING (color, 1);
ee78dc32 7049
6fc2811b
JR
7050 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7051 return Qt;
7052 else
7053 return Qnil;
7054}
ee78dc32 7055
2d764c78 7056DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
dfff8a69 7057 "Internal function called by `color-values', which see.")
ee78dc32
GV
7058 (color, frame)
7059 Lisp_Object color, frame;
7060{
6fc2811b 7061 XColor foo;
ee78dc32
GV
7062 FRAME_PTR f = check_x_frame (frame);
7063
7064 CHECK_STRING (color, 1);
7065
6fc2811b 7066 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7067 {
7068 Lisp_Object rgb[3];
7069
6fc2811b
JR
7070 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7071 | GetRValue (foo.pixel));
7072 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7073 | GetGValue (foo.pixel));
7074 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7075 | GetBValue (foo.pixel));
ee78dc32
GV
7076 return Flist (3, rgb);
7077 }
7078 else
7079 return Qnil;
7080}
7081
2d764c78 7082DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
dfff8a69 7083 "Internal function called by `display-color-p', which see.")
ee78dc32
GV
7084 (display)
7085 Lisp_Object display;
7086{
fbd6baed 7087 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7088
7089 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7090 return Qnil;
7091
7092 return Qt;
7093}
7094
7095DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
7096 0, 1, 0,
7097 "Return t if the X display supports shades of gray.\n\
7098Note that color displays do support shades of gray.\n\
7099The optional argument DISPLAY specifies which display to ask about.\n\
7100DISPLAY should be either a frame or a display name (a string).\n\
7101If omitted or nil, that stands for the selected frame's display.")
7102 (display)
7103 Lisp_Object display;
7104{
fbd6baed 7105 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7106
7107 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7108 return Qnil;
7109
7110 return Qt;
7111}
7112
7113DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
7114 0, 1, 0,
7115 "Returns the width in pixels of the X display DISPLAY.\n\
7116The optional argument DISPLAY specifies which display to ask about.\n\
7117DISPLAY should be either a frame or a display name (a string).\n\
7118If omitted or nil, that stands for the selected frame's display.")
7119 (display)
7120 Lisp_Object display;
7121{
fbd6baed 7122 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7123
7124 return make_number (dpyinfo->width);
7125}
7126
7127DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7128 Sx_display_pixel_height, 0, 1, 0,
7129 "Returns the height in pixels of the X display DISPLAY.\n\
7130The optional argument DISPLAY specifies which display to ask about.\n\
7131DISPLAY should be either a frame or a display name (a string).\n\
7132If omitted or nil, that stands for the selected frame's display.")
7133 (display)
7134 Lisp_Object display;
7135{
fbd6baed 7136 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7137
7138 return make_number (dpyinfo->height);
7139}
7140
7141DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7142 0, 1, 0,
7143 "Returns the number of bitplanes of the display DISPLAY.\n\
7144The optional argument DISPLAY specifies which display to ask about.\n\
7145DISPLAY should be either a frame or a display name (a string).\n\
7146If omitted or nil, that stands for the selected frame's display.")
7147 (display)
7148 Lisp_Object display;
7149{
fbd6baed 7150 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7151
7152 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7153}
7154
7155DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7156 0, 1, 0,
7157 "Returns the number of color cells of the display DISPLAY.\n\
7158The optional argument DISPLAY specifies which display to ask about.\n\
7159DISPLAY should be either a frame or a display name (a string).\n\
7160If omitted or nil, that stands for the selected frame's display.")
7161 (display)
7162 Lisp_Object display;
7163{
fbd6baed 7164 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7165 HDC hdc;
7166 int cap;
7167
5ac45f98
GV
7168 hdc = GetDC (dpyinfo->root_window);
7169 if (dpyinfo->has_palette)
7170 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7171 else
7172 cap = GetDeviceCaps (hdc,NUMCOLORS);
ee78dc32
GV
7173
7174 ReleaseDC (dpyinfo->root_window, hdc);
7175
7176 return make_number (cap);
7177}
7178
7179DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7180 Sx_server_max_request_size,
7181 0, 1, 0,
7182 "Returns the maximum request size of the server of display DISPLAY.\n\
7183The optional argument DISPLAY specifies which display to ask about.\n\
7184DISPLAY should be either a frame or a display name (a string).\n\
7185If omitted or nil, that stands for the selected frame's display.")
7186 (display)
7187 Lisp_Object display;
7188{
fbd6baed 7189 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7190
7191 return make_number (1);
7192}
7193
7194DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
fbd6baed 7195 "Returns the vendor ID string of the W32 system (Microsoft).\n\
ee78dc32
GV
7196The optional argument DISPLAY specifies which display to ask about.\n\
7197DISPLAY should be either a frame or a display name (a string).\n\
7198If omitted or nil, that stands for the selected frame's display.")
7199 (display)
7200 Lisp_Object display;
7201{
dfff8a69 7202 return build_string ("Microsoft Corp.");
ee78dc32
GV
7203}
7204
7205DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7206 "Returns the version numbers of the server of display DISPLAY.\n\
7207The value is a list of three integers: the major and minor\n\
7208version numbers, and the vendor-specific release\n\
7209number. See also the function `x-server-vendor'.\n\n\
7210The optional argument DISPLAY specifies which display to ask about.\n\
7211DISPLAY should be either a frame or a display name (a string).\n\
7212If omitted or nil, that stands for the selected frame's display.")
7213 (display)
7214 Lisp_Object display;
7215{
fbd6baed 7216 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7217 Fcons (make_number (w32_minor_version),
7218 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7219}
7220
7221DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7222 "Returns the number of screens on the server of display DISPLAY.\n\
7223The optional argument DISPLAY specifies which display to ask about.\n\
7224DISPLAY should be either a frame or a display name (a string).\n\
7225If omitted or nil, that stands for the selected frame's display.")
7226 (display)
7227 Lisp_Object display;
7228{
ee78dc32
GV
7229 return make_number (1);
7230}
7231
7232DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7233 "Returns the height in millimeters of the X display DISPLAY.\n\
7234The optional argument DISPLAY specifies which display to ask about.\n\
7235DISPLAY should be either a frame or a display name (a string).\n\
7236If omitted or nil, that stands for the selected frame's display.")
7237 (display)
7238 Lisp_Object display;
7239{
fbd6baed 7240 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7241 HDC hdc;
7242 int cap;
7243
5ac45f98 7244 hdc = GetDC (dpyinfo->root_window);
3c190163 7245
ee78dc32 7246 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7247
ee78dc32
GV
7248 ReleaseDC (dpyinfo->root_window, hdc);
7249
7250 return make_number (cap);
7251}
7252
7253DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7254 "Returns the width in millimeters of the X display DISPLAY.\n\
7255The optional argument DISPLAY specifies which display to ask about.\n\
7256DISPLAY should be either a frame or a display name (a string).\n\
7257If omitted or nil, that stands for the selected frame's display.")
7258 (display)
7259 Lisp_Object display;
7260{
fbd6baed 7261 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7262
7263 HDC hdc;
7264 int cap;
7265
5ac45f98 7266 hdc = GetDC (dpyinfo->root_window);
3c190163 7267
ee78dc32 7268 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7269
ee78dc32
GV
7270 ReleaseDC (dpyinfo->root_window, hdc);
7271
7272 return make_number (cap);
7273}
7274
7275DEFUN ("x-display-backing-store", Fx_display_backing_store,
7276 Sx_display_backing_store, 0, 1, 0,
7277 "Returns an indication of whether display DISPLAY does backing store.\n\
7278The value may be `always', `when-mapped', or `not-useful'.\n\
7279The optional argument DISPLAY specifies which display to ask about.\n\
7280DISPLAY should be either a frame or a display name (a string).\n\
7281If omitted or nil, that stands for the selected frame's display.")
7282 (display)
7283 Lisp_Object display;
7284{
7285 return intern ("not-useful");
7286}
7287
7288DEFUN ("x-display-visual-class", Fx_display_visual_class,
7289 Sx_display_visual_class, 0, 1, 0,
7290 "Returns the visual class of the display DISPLAY.\n\
7291The value is one of the symbols `static-gray', `gray-scale',\n\
7292`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7293The optional argument DISPLAY specifies which display to ask about.\n\
7294DISPLAY should be either a frame or a display name (a string).\n\
7295If omitted or nil, that stands for the selected frame's display.")
7296 (display)
7297 Lisp_Object display;
7298{
fbd6baed 7299 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7300
7301#if 0
7302 switch (dpyinfo->visual->class)
7303 {
7304 case StaticGray: return (intern ("static-gray"));
7305 case GrayScale: return (intern ("gray-scale"));
7306 case StaticColor: return (intern ("static-color"));
7307 case PseudoColor: return (intern ("pseudo-color"));
7308 case TrueColor: return (intern ("true-color"));
7309 case DirectColor: return (intern ("direct-color"));
7310 default:
7311 error ("Display has an unknown visual class");
7312 }
7313#endif
7314
7315 error ("Display has an unknown visual class");
7316}
7317
7318DEFUN ("x-display-save-under", Fx_display_save_under,
7319 Sx_display_save_under, 0, 1, 0,
7320 "Returns t if the display DISPLAY supports the save-under feature.\n\
7321The optional argument DISPLAY specifies which display to ask about.\n\
7322DISPLAY should be either a frame or a display name (a string).\n\
7323If omitted or nil, that stands for the selected frame's display.")
7324 (display)
7325 Lisp_Object display;
7326{
6fc2811b
JR
7327 return Qnil;
7328}
7329\f
7330int
7331x_pixel_width (f)
7332 register struct frame *f;
7333{
7334 return PIXEL_WIDTH (f);
7335}
7336
7337int
7338x_pixel_height (f)
7339 register struct frame *f;
7340{
7341 return PIXEL_HEIGHT (f);
7342}
7343
7344int
7345x_char_width (f)
7346 register struct frame *f;
7347{
7348 return FONT_WIDTH (f->output_data.w32->font);
7349}
7350
7351int
7352x_char_height (f)
7353 register struct frame *f;
7354{
7355 return f->output_data.w32->line_height;
7356}
7357
7358int
7359x_screen_planes (f)
7360 register struct frame *f;
7361{
7362 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7363}
7364\f
7365/* Return the display structure for the display named NAME.
7366 Open a new connection if necessary. */
7367
7368struct w32_display_info *
7369x_display_info_for_name (name)
7370 Lisp_Object name;
7371{
7372 Lisp_Object names;
7373 struct w32_display_info *dpyinfo;
7374
7375 CHECK_STRING (name, 0);
7376
7377 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7378 dpyinfo;
7379 dpyinfo = dpyinfo->next, names = XCDR (names))
7380 {
7381 Lisp_Object tem;
7382 tem = Fstring_equal (XCAR (XCAR (names)), name);
7383 if (!NILP (tem))
7384 return dpyinfo;
7385 }
7386
7387 /* Use this general default value to start with. */
7388 Vx_resource_name = Vinvocation_name;
7389
7390 validate_x_resource_name ();
7391
7392 dpyinfo = w32_term_init (name, (unsigned char *)0,
7393 (char *) XSTRING (Vx_resource_name)->data);
7394
7395 if (dpyinfo == 0)
7396 error ("Cannot connect to server %s", XSTRING (name)->data);
7397
7398 w32_in_use = 1;
7399 XSETFASTINT (Vwindow_system_version, 3);
7400
7401 return dpyinfo;
7402}
7403
7404DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7405 1, 3, 0, "Open a connection to a server.\n\
7406DISPLAY is the name of the display to connect to.\n\
7407Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7408If the optional third arg MUST-SUCCEED is non-nil,\n\
7409terminate Emacs if we can't open the connection.")
7410 (display, xrm_string, must_succeed)
7411 Lisp_Object display, xrm_string, must_succeed;
7412{
7413 unsigned char *xrm_option;
7414 struct w32_display_info *dpyinfo;
7415
7416 CHECK_STRING (display, 0);
7417 if (! NILP (xrm_string))
7418 CHECK_STRING (xrm_string, 1);
7419
7420 if (! EQ (Vwindow_system, intern ("w32")))
7421 error ("Not using Microsoft Windows");
7422
7423 /* Allow color mapping to be defined externally; first look in user's
7424 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7425 {
7426 Lisp_Object color_file;
7427 struct gcpro gcpro1;
7428
7429 color_file = build_string("~/rgb.txt");
7430
7431 GCPRO1 (color_file);
7432
7433 if (NILP (Ffile_readable_p (color_file)))
7434 color_file =
7435 Fexpand_file_name (build_string ("rgb.txt"),
7436 Fsymbol_value (intern ("data-directory")));
7437
7438 Vw32_color_map = Fw32_load_color_file (color_file);
7439
7440 UNGCPRO;
7441 }
7442 if (NILP (Vw32_color_map))
7443 Vw32_color_map = Fw32_default_color_map ();
7444
7445 if (! NILP (xrm_string))
7446 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7447 else
7448 xrm_option = (unsigned char *) 0;
7449
7450 /* Use this general default value to start with. */
7451 /* First remove .exe suffix from invocation-name - it looks ugly. */
7452 {
7453 char basename[ MAX_PATH ], *str;
7454
7455 strcpy (basename, XSTRING (Vinvocation_name)->data);
7456 str = strrchr (basename, '.');
7457 if (str) *str = 0;
7458 Vinvocation_name = build_string (basename);
7459 }
7460 Vx_resource_name = Vinvocation_name;
7461
7462 validate_x_resource_name ();
7463
7464 /* This is what opens the connection and sets x_current_display.
7465 This also initializes many symbols, such as those used for input. */
7466 dpyinfo = w32_term_init (display, xrm_option,
7467 (char *) XSTRING (Vx_resource_name)->data);
7468
7469 if (dpyinfo == 0)
7470 {
7471 if (!NILP (must_succeed))
7472 fatal ("Cannot connect to server %s.\n",
7473 XSTRING (display)->data);
7474 else
7475 error ("Cannot connect to server %s", XSTRING (display)->data);
7476 }
7477
7478 w32_in_use = 1;
7479
7480 XSETFASTINT (Vwindow_system_version, 3);
7481 return Qnil;
7482}
7483
7484DEFUN ("x-close-connection", Fx_close_connection,
7485 Sx_close_connection, 1, 1, 0,
7486 "Close the connection to DISPLAY's server.\n\
7487For DISPLAY, specify either a frame or a display name (a string).\n\
7488If DISPLAY is nil, that stands for the selected frame's display.")
7489 (display)
7490 Lisp_Object display;
7491{
7492 struct w32_display_info *dpyinfo = check_x_display_info (display);
7493 int i;
7494
7495 if (dpyinfo->reference_count > 0)
7496 error ("Display still has frames on it");
7497
7498 BLOCK_INPUT;
7499 /* Free the fonts in the font table. */
7500 for (i = 0; i < dpyinfo->n_fonts; i++)
7501 if (dpyinfo->font_table[i].name)
7502 {
126f2e35
JR
7503 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7504 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 7505 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
7506 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7507 }
7508 x_destroy_all_bitmaps (dpyinfo);
7509
7510 x_delete_display (dpyinfo);
7511 UNBLOCK_INPUT;
7512
7513 return Qnil;
7514}
7515
7516DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7517 "Return the list of display names that Emacs has connections to.")
7518 ()
7519{
7520 Lisp_Object tail, result;
7521
7522 result = Qnil;
7523 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7524 result = Fcons (XCAR (XCAR (tail)), result);
7525
7526 return result;
7527}
7528
7529DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7530 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7531If ON is nil, allow buffering of requests.\n\
7532This is a noop on W32 systems.\n\
7533The optional second argument DISPLAY specifies which display to act on.\n\
7534DISPLAY should be either a frame or a display name (a string).\n\
7535If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7536 (on, display)
7537 Lisp_Object display, on;
7538{
6fc2811b
JR
7539 return Qnil;
7540}
7541
7542\f
7543\f
7544/***********************************************************************
7545 Image types
7546 ***********************************************************************/
7547
7548/* Value is the number of elements of vector VECTOR. */
7549
7550#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7551
7552/* List of supported image types. Use define_image_type to add new
7553 types. Use lookup_image_type to find a type for a given symbol. */
7554
7555static struct image_type *image_types;
7556
6fc2811b
JR
7557/* The symbol `image' which is the car of the lists used to represent
7558 images in Lisp. */
7559
7560extern Lisp_Object Qimage;
7561
7562/* The symbol `xbm' which is used as the type symbol for XBM images. */
7563
7564Lisp_Object Qxbm;
7565
7566/* Keywords. */
7567
6fc2811b 7568extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
7569extern Lisp_Object QCdata;
7570Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
6fc2811b 7571Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
dfff8a69 7572Lisp_Object QCindex;
6fc2811b
JR
7573
7574/* Other symbols. */
7575
7576Lisp_Object Qlaplace;
7577
7578/* Time in seconds after which images should be removed from the cache
7579 if not displayed. */
7580
7581Lisp_Object Vimage_cache_eviction_delay;
7582
7583/* Function prototypes. */
7584
7585static void define_image_type P_ ((struct image_type *type));
7586static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7587static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7588static void x_laplace P_ ((struct frame *, struct image *));
7589static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7590 Lisp_Object));
7591
dfff8a69 7592
6fc2811b
JR
7593/* Define a new image type from TYPE. This adds a copy of TYPE to
7594 image_types and adds the symbol *TYPE->type to Vimage_types. */
7595
7596static void
7597define_image_type (type)
7598 struct image_type *type;
7599{
7600 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7601 The initialized data segment is read-only. */
7602 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7603 bcopy (type, p, sizeof *p);
7604 p->next = image_types;
7605 image_types = p;
7606 Vimage_types = Fcons (*p->type, Vimage_types);
7607}
7608
7609
7610/* Look up image type SYMBOL, and return a pointer to its image_type
7611 structure. Value is null if SYMBOL is not a known image type. */
7612
7613static INLINE struct image_type *
7614lookup_image_type (symbol)
7615 Lisp_Object symbol;
7616{
7617 struct image_type *type;
7618
7619 for (type = image_types; type; type = type->next)
7620 if (EQ (symbol, *type->type))
7621 break;
7622
7623 return type;
7624}
7625
7626
7627/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7628 valid image specification is a list whose car is the symbol
7629 `image', and whose rest is a property list. The property list must
7630 contain a value for key `:type'. That value must be the name of a
7631 supported image type. The rest of the property list depends on the
7632 image type. */
7633
7634int
7635valid_image_p (object)
7636 Lisp_Object object;
7637{
7638 int valid_p = 0;
7639
7640 if (CONSP (object) && EQ (XCAR (object), Qimage))
7641 {
7642 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7643 struct image_type *type = lookup_image_type (symbol);
7644
7645 if (type)
7646 valid_p = type->valid_p (object);
7647 }
7648
7649 return valid_p;
7650}
7651
7652
7653/* Log error message with format string FORMAT and argument ARG.
7654 Signaling an error, e.g. when an image cannot be loaded, is not a
7655 good idea because this would interrupt redisplay, and the error
7656 message display would lead to another redisplay. This function
7657 therefore simply displays a message. */
7658
7659static void
7660image_error (format, arg1, arg2)
7661 char *format;
7662 Lisp_Object arg1, arg2;
7663{
7664 add_to_log (format, arg1, arg2);
7665}
7666
7667
7668\f
7669/***********************************************************************
7670 Image specifications
7671 ***********************************************************************/
7672
7673enum image_value_type
7674{
7675 IMAGE_DONT_CHECK_VALUE_TYPE,
7676 IMAGE_STRING_VALUE,
7677 IMAGE_SYMBOL_VALUE,
7678 IMAGE_POSITIVE_INTEGER_VALUE,
7679 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 7680 IMAGE_ASCENT_VALUE,
6fc2811b
JR
7681 IMAGE_INTEGER_VALUE,
7682 IMAGE_FUNCTION_VALUE,
7683 IMAGE_NUMBER_VALUE,
7684 IMAGE_BOOL_VALUE
7685};
7686
7687/* Structure used when parsing image specifications. */
7688
7689struct image_keyword
7690{
7691 /* Name of keyword. */
7692 char *name;
7693
7694 /* The type of value allowed. */
7695 enum image_value_type type;
7696
7697 /* Non-zero means key must be present. */
7698 int mandatory_p;
7699
7700 /* Used to recognize duplicate keywords in a property list. */
7701 int count;
7702
7703 /* The value that was found. */
7704 Lisp_Object value;
7705};
7706
7707
7708static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7709 int, Lisp_Object));
7710static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7711
7712
7713/* Parse image spec SPEC according to KEYWORDS. A valid image spec
7714 has the format (image KEYWORD VALUE ...). One of the keyword/
7715 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7716 image_keywords structures of size NKEYWORDS describing other
7717 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7718
7719static int
7720parse_image_spec (spec, keywords, nkeywords, type)
7721 Lisp_Object spec;
7722 struct image_keyword *keywords;
7723 int nkeywords;
7724 Lisp_Object type;
7725{
7726 int i;
7727 Lisp_Object plist;
7728
7729 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7730 return 0;
7731
7732 plist = XCDR (spec);
7733 while (CONSP (plist))
7734 {
7735 Lisp_Object key, value;
7736
7737 /* First element of a pair must be a symbol. */
7738 key = XCAR (plist);
7739 plist = XCDR (plist);
7740 if (!SYMBOLP (key))
7741 return 0;
7742
7743 /* There must follow a value. */
7744 if (!CONSP (plist))
7745 return 0;
7746 value = XCAR (plist);
7747 plist = XCDR (plist);
7748
7749 /* Find key in KEYWORDS. Error if not found. */
7750 for (i = 0; i < nkeywords; ++i)
7751 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7752 break;
7753
7754 if (i == nkeywords)
7755 continue;
7756
7757 /* Record that we recognized the keyword. If a keywords
7758 was found more than once, it's an error. */
7759 keywords[i].value = value;
7760 ++keywords[i].count;
7761
7762 if (keywords[i].count > 1)
7763 return 0;
7764
7765 /* Check type of value against allowed type. */
7766 switch (keywords[i].type)
7767 {
7768 case IMAGE_STRING_VALUE:
7769 if (!STRINGP (value))
7770 return 0;
7771 break;
7772
7773 case IMAGE_SYMBOL_VALUE:
7774 if (!SYMBOLP (value))
7775 return 0;
7776 break;
7777
7778 case IMAGE_POSITIVE_INTEGER_VALUE:
7779 if (!INTEGERP (value) || XINT (value) <= 0)
7780 return 0;
7781 break;
7782
dfff8a69
JR
7783 case IMAGE_ASCENT_VALUE:
7784 if (SYMBOLP (value) && EQ (value, Qcenter))
7785 break;
7786 else if (INTEGERP (value)
7787 && XINT (value) >= 0
7788 && XINT (value) <= 100)
7789 break;
7790 return 0;
7791
6fc2811b
JR
7792 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7793 if (!INTEGERP (value) || XINT (value) < 0)
7794 return 0;
7795 break;
7796
7797 case IMAGE_DONT_CHECK_VALUE_TYPE:
7798 break;
7799
7800 case IMAGE_FUNCTION_VALUE:
7801 value = indirect_function (value);
7802 if (SUBRP (value)
7803 || COMPILEDP (value)
7804 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7805 break;
7806 return 0;
7807
7808 case IMAGE_NUMBER_VALUE:
7809 if (!INTEGERP (value) && !FLOATP (value))
7810 return 0;
7811 break;
7812
7813 case IMAGE_INTEGER_VALUE:
7814 if (!INTEGERP (value))
7815 return 0;
7816 break;
7817
7818 case IMAGE_BOOL_VALUE:
7819 if (!NILP (value) && !EQ (value, Qt))
7820 return 0;
7821 break;
7822
7823 default:
7824 abort ();
7825 break;
7826 }
7827
7828 if (EQ (key, QCtype) && !EQ (type, value))
7829 return 0;
7830 }
7831
7832 /* Check that all mandatory fields are present. */
7833 for (i = 0; i < nkeywords; ++i)
7834 if (keywords[i].mandatory_p && keywords[i].count == 0)
7835 return 0;
7836
7837 return NILP (plist);
7838}
7839
7840
7841/* Return the value of KEY in image specification SPEC. Value is nil
7842 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7843 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7844
7845static Lisp_Object
7846image_spec_value (spec, key, found)
7847 Lisp_Object spec, key;
7848 int *found;
7849{
7850 Lisp_Object tail;
7851
7852 xassert (valid_image_p (spec));
7853
7854 for (tail = XCDR (spec);
7855 CONSP (tail) && CONSP (XCDR (tail));
7856 tail = XCDR (XCDR (tail)))
7857 {
7858 if (EQ (XCAR (tail), key))
7859 {
7860 if (found)
7861 *found = 1;
7862 return XCAR (XCDR (tail));
7863 }
7864 }
7865
7866 if (found)
7867 *found = 0;
7868 return Qnil;
7869}
7870
7871
7872
7873\f
7874/***********************************************************************
7875 Image type independent image structures
7876 ***********************************************************************/
7877
7878static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7879static void free_image P_ ((struct frame *f, struct image *img));
7880
7881
7882/* Allocate and return a new image structure for image specification
7883 SPEC. SPEC has a hash value of HASH. */
7884
7885static struct image *
7886make_image (spec, hash)
7887 Lisp_Object spec;
7888 unsigned hash;
7889{
7890 struct image *img = (struct image *) xmalloc (sizeof *img);
7891
7892 xassert (valid_image_p (spec));
7893 bzero (img, sizeof *img);
7894 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7895 xassert (img->type != NULL);
7896 img->spec = spec;
7897 img->data.lisp_val = Qnil;
7898 img->ascent = DEFAULT_IMAGE_ASCENT;
7899 img->hash = hash;
7900 return img;
7901}
7902
7903
7904/* Free image IMG which was used on frame F, including its resources. */
7905
7906static void
7907free_image (f, img)
7908 struct frame *f;
7909 struct image *img;
7910{
7911 if (img)
7912 {
7913 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7914
7915 /* Remove IMG from the hash table of its cache. */
7916 if (img->prev)
7917 img->prev->next = img->next;
7918 else
7919 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7920
7921 if (img->next)
7922 img->next->prev = img->prev;
7923
7924 c->images[img->id] = NULL;
7925
7926 /* Free resources, then free IMG. */
7927 img->type->free (f, img);
7928 xfree (img);
7929 }
7930}
7931
7932
7933/* Prepare image IMG for display on frame F. Must be called before
7934 drawing an image. */
7935
7936void
7937prepare_image_for_display (f, img)
7938 struct frame *f;
7939 struct image *img;
7940{
7941 EMACS_TIME t;
7942
7943 /* We're about to display IMG, so set its timestamp to `now'. */
7944 EMACS_GET_TIME (t);
7945 img->timestamp = EMACS_SECS (t);
7946
7947 /* If IMG doesn't have a pixmap yet, load it now, using the image
7948 type dependent loader function. */
7949 if (img->pixmap == 0 && !img->load_failed_p)
7950 img->load_failed_p = img->type->load (f, img) == 0;
7951}
7952
7953
dfff8a69
JR
7954/* Value is the number of pixels for the ascent of image IMG when
7955 drawn in face FACE. */
7956
7957int
7958image_ascent (img, face)
7959 struct image *img;
7960 struct face *face;
7961{
7962 int height = img->height + img->margin;
7963 int ascent;
7964
7965 if (img->ascent == CENTERED_IMAGE_ASCENT)
7966 {
7967 if (face->font)
7968 ascent = height / 2 - (FONT_DESCENT(face->font)
7969 - FONT_BASE(face->font)) / 2;
7970 else
7971 ascent = height / 2;
7972 }
7973 else
7974 ascent = height * img->ascent / 100.0;
7975
7976 return ascent;
7977}
7978
7979
6fc2811b
JR
7980\f
7981/***********************************************************************
7982 Helper functions for X image types
7983 ***********************************************************************/
7984
7985static void x_clear_image P_ ((struct frame *f, struct image *img));
7986static unsigned long x_alloc_image_color P_ ((struct frame *f,
7987 struct image *img,
7988 Lisp_Object color_name,
7989 unsigned long dflt));
7990
7991/* Free X resources of image IMG which is used on frame F. */
7992
7993static void
7994x_clear_image (f, img)
7995 struct frame *f;
7996 struct image *img;
7997{
767b1ff0 7998#if 0 /* TODO: W32 image support */
6fc2811b
JR
7999
8000 if (img->pixmap)
8001 {
8002 BLOCK_INPUT;
8003 XFreePixmap (NULL, img->pixmap);
8004 img->pixmap = 0;
8005 UNBLOCK_INPUT;
8006 }
8007
8008 if (img->ncolors)
8009 {
8010 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8011
8012 /* If display has an immutable color map, freeing colors is not
8013 necessary and some servers don't allow it. So don't do it. */
8014 if (class != StaticColor
8015 && class != StaticGray
8016 && class != TrueColor)
8017 {
8018 Colormap cmap;
8019 BLOCK_INPUT;
8020 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8021 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8022 img->ncolors, 0);
8023 UNBLOCK_INPUT;
8024 }
8025
8026 xfree (img->colors);
8027 img->colors = NULL;
8028 img->ncolors = 0;
8029 }
8030#endif
8031}
8032
8033
8034/* Allocate color COLOR_NAME for image IMG on frame F. If color
8035 cannot be allocated, use DFLT. Add a newly allocated color to
8036 IMG->colors, so that it can be freed again. Value is the pixel
8037 color. */
8038
8039static unsigned long
8040x_alloc_image_color (f, img, color_name, dflt)
8041 struct frame *f;
8042 struct image *img;
8043 Lisp_Object color_name;
8044 unsigned long dflt;
8045{
767b1ff0 8046#if 0 /* TODO: allocing colors. */
6fc2811b
JR
8047 XColor color;
8048 unsigned long result;
8049
8050 xassert (STRINGP (color_name));
8051
8052 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8053 {
8054 /* This isn't called frequently so we get away with simply
8055 reallocating the color vector to the needed size, here. */
8056 ++img->ncolors;
8057 img->colors =
8058 (unsigned long *) xrealloc (img->colors,
8059 img->ncolors * sizeof *img->colors);
8060 img->colors[img->ncolors - 1] = color.pixel;
8061 result = color.pixel;
8062 }
8063 else
8064 result = dflt;
8065 return result;
8066#endif
8067 return 0;
8068}
8069
8070
8071\f
8072/***********************************************************************
8073 Image Cache
8074 ***********************************************************************/
8075
8076static void cache_image P_ ((struct frame *f, struct image *img));
8077
8078
8079/* Return a new, initialized image cache that is allocated from the
8080 heap. Call free_image_cache to free an image cache. */
8081
8082struct image_cache *
8083make_image_cache ()
8084{
8085 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8086 int size;
8087
8088 bzero (c, sizeof *c);
8089 c->size = 50;
8090 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8091 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8092 c->buckets = (struct image **) xmalloc (size);
8093 bzero (c->buckets, size);
8094 return c;
8095}
8096
8097
8098/* Free image cache of frame F. Be aware that X frames share images
8099 caches. */
8100
8101void
8102free_image_cache (f)
8103 struct frame *f;
8104{
8105 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8106 if (c)
8107 {
8108 int i;
8109
8110 /* Cache should not be referenced by any frame when freed. */
8111 xassert (c->refcount == 0);
8112
8113 for (i = 0; i < c->used; ++i)
8114 free_image (f, c->images[i]);
8115 xfree (c->images);
8116 xfree (c);
8117 xfree (c->buckets);
8118 FRAME_X_IMAGE_CACHE (f) = NULL;
8119 }
8120}
8121
8122
8123/* Clear image cache of frame F. FORCE_P non-zero means free all
8124 images. FORCE_P zero means clear only images that haven't been
8125 displayed for some time. Should be called from time to time to
dfff8a69
JR
8126 reduce the number of loaded images. If image-eviction-seconds is
8127 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8128 at least that many seconds. */
8129
8130void
8131clear_image_cache (f, force_p)
8132 struct frame *f;
8133 int force_p;
8134{
8135 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8136
8137 if (c && INTEGERP (Vimage_cache_eviction_delay))
8138 {
8139 EMACS_TIME t;
8140 unsigned long old;
8141 int i, any_freed_p = 0;
8142
8143 EMACS_GET_TIME (t);
8144 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8145
8146 for (i = 0; i < c->used; ++i)
8147 {
8148 struct image *img = c->images[i];
8149 if (img != NULL
8150 && (force_p
8151 || (img->timestamp > old)))
8152 {
8153 free_image (f, img);
8154 any_freed_p = 1;
8155 }
8156 }
8157
8158 /* We may be clearing the image cache because, for example,
8159 Emacs was iconified for a longer period of time. In that
8160 case, current matrices may still contain references to
8161 images freed above. So, clear these matrices. */
8162 if (any_freed_p)
8163 {
8164 clear_current_matrices (f);
8165 ++windows_or_buffers_changed;
8166 }
8167 }
8168}
8169
8170
8171DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8172 0, 1, 0,
8173 "Clear the image cache of FRAME.\n\
8174FRAME nil or omitted means use the selected frame.\n\
8175FRAME t means clear the image caches of all frames.")
8176 (frame)
8177 Lisp_Object frame;
8178{
8179 if (EQ (frame, Qt))
8180 {
8181 Lisp_Object tail;
8182
8183 FOR_EACH_FRAME (tail, frame)
8184 if (FRAME_W32_P (XFRAME (frame)))
8185 clear_image_cache (XFRAME (frame), 1);
8186 }
8187 else
8188 clear_image_cache (check_x_frame (frame), 1);
8189
8190 return Qnil;
8191}
8192
8193
8194/* Return the id of image with Lisp specification SPEC on frame F.
8195 SPEC must be a valid Lisp image specification (see valid_image_p). */
8196
8197int
8198lookup_image (f, spec)
8199 struct frame *f;
8200 Lisp_Object spec;
8201{
8202 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8203 struct image *img;
8204 int i;
8205 unsigned hash;
8206 struct gcpro gcpro1;
8207 EMACS_TIME now;
8208
8209 /* F must be a window-system frame, and SPEC must be a valid image
8210 specification. */
8211 xassert (FRAME_WINDOW_P (f));
8212 xassert (valid_image_p (spec));
8213
8214 GCPRO1 (spec);
8215
8216 /* Look up SPEC in the hash table of the image cache. */
8217 hash = sxhash (spec, 0);
8218 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8219
8220 for (img = c->buckets[i]; img; img = img->next)
8221 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8222 break;
8223
8224 /* If not found, create a new image and cache it. */
8225 if (img == NULL)
8226 {
8227 img = make_image (spec, hash);
8228 cache_image (f, img);
8229 img->load_failed_p = img->type->load (f, img) == 0;
8230 xassert (!interrupt_input_blocked);
8231
8232 /* If we can't load the image, and we don't have a width and
8233 height, use some arbitrary width and height so that we can
8234 draw a rectangle for it. */
8235 if (img->load_failed_p)
8236 {
8237 Lisp_Object value;
8238
8239 value = image_spec_value (spec, QCwidth, NULL);
8240 img->width = (INTEGERP (value)
8241 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8242 value = image_spec_value (spec, QCheight, NULL);
8243 img->height = (INTEGERP (value)
8244 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8245 }
8246 else
8247 {
8248 /* Handle image type independent image attributes
8249 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
8250 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
8251 Lisp_Object file;
8252
8253 ascent = image_spec_value (spec, QCascent, NULL);
8254 if (INTEGERP (ascent))
8255 img->ascent = XFASTINT (ascent);
dfff8a69
JR
8256 else if (EQ (ascent, Qcenter))
8257 img->ascent = CENTERED_IMAGE_ASCENT;
8258
6fc2811b
JR
8259 margin = image_spec_value (spec, QCmargin, NULL);
8260 if (INTEGERP (margin) && XINT (margin) >= 0)
8261 img->margin = XFASTINT (margin);
8262
8263 relief = image_spec_value (spec, QCrelief, NULL);
8264 if (INTEGERP (relief))
8265 {
8266 img->relief = XINT (relief);
8267 img->margin += abs (img->relief);
8268 }
8269
8270 /* Should we apply a Laplace edge-detection algorithm? */
8271 algorithm = image_spec_value (spec, QCalgorithm, NULL);
8272 if (img->pixmap && EQ (algorithm, Qlaplace))
8273 x_laplace (f, img);
8274
8275 /* Should we built a mask heuristically? */
8276 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
8277 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
8278 x_build_heuristic_mask (f, img, heuristic_mask);
8279 }
8280 }
8281
8282 /* We're using IMG, so set its timestamp to `now'. */
8283 EMACS_GET_TIME (now);
8284 img->timestamp = EMACS_SECS (now);
8285
8286 UNGCPRO;
8287
8288 /* Value is the image id. */
8289 return img->id;
8290}
8291
8292
8293/* Cache image IMG in the image cache of frame F. */
8294
8295static void
8296cache_image (f, img)
8297 struct frame *f;
8298 struct image *img;
8299{
8300 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8301 int i;
8302
8303 /* Find a free slot in c->images. */
8304 for (i = 0; i < c->used; ++i)
8305 if (c->images[i] == NULL)
8306 break;
8307
8308 /* If no free slot found, maybe enlarge c->images. */
8309 if (i == c->used && c->used == c->size)
8310 {
8311 c->size *= 2;
8312 c->images = (struct image **) xrealloc (c->images,
8313 c->size * sizeof *c->images);
8314 }
8315
8316 /* Add IMG to c->images, and assign IMG an id. */
8317 c->images[i] = img;
8318 img->id = i;
8319 if (i == c->used)
8320 ++c->used;
8321
8322 /* Add IMG to the cache's hash table. */
8323 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8324 img->next = c->buckets[i];
8325 if (img->next)
8326 img->next->prev = img;
8327 img->prev = NULL;
8328 c->buckets[i] = img;
8329}
8330
8331
8332/* Call FN on every image in the image cache of frame F. Used to mark
8333 Lisp Objects in the image cache. */
8334
8335void
8336forall_images_in_image_cache (f, fn)
8337 struct frame *f;
8338 void (*fn) P_ ((struct image *img));
8339{
8340 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8341 {
8342 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8343 if (c)
8344 {
8345 int i;
8346 for (i = 0; i < c->used; ++i)
8347 if (c->images[i])
8348 fn (c->images[i]);
8349 }
8350 }
8351}
8352
8353
8354\f
8355/***********************************************************************
8356 W32 support code
8357 ***********************************************************************/
8358
767b1ff0 8359#if 0 /* TODO: W32 specific image code. */
6fc2811b
JR
8360
8361static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8362 XImage **, Pixmap *));
8363static void x_destroy_x_image P_ ((XImage *));
8364static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8365
8366
8367/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8368 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8369 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8370 via xmalloc. Print error messages via image_error if an error
8371 occurs. Value is non-zero if successful. */
8372
8373static int
8374x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8375 struct frame *f;
8376 int width, height, depth;
8377 XImage **ximg;
8378 Pixmap *pixmap;
8379{
767b1ff0 8380#if 0 /* TODO: Image support for W32 */
6fc2811b
JR
8381 Display *display = FRAME_W32_DISPLAY (f);
8382 Screen *screen = FRAME_X_SCREEN (f);
8383 Window window = FRAME_W32_WINDOW (f);
8384
8385 xassert (interrupt_input_blocked);
8386
8387 if (depth <= 0)
8388 depth = DefaultDepthOfScreen (screen);
8389 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8390 depth, ZPixmap, 0, NULL, width, height,
8391 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8392 if (*ximg == NULL)
8393 {
8394 image_error ("Unable to allocate X image", Qnil, Qnil);
8395 return 0;
8396 }
8397
8398 /* Allocate image raster. */
8399 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8400
8401 /* Allocate a pixmap of the same size. */
8402 *pixmap = XCreatePixmap (display, window, width, height, depth);
8403 if (*pixmap == 0)
8404 {
8405 x_destroy_x_image (*ximg);
8406 *ximg = NULL;
8407 image_error ("Unable to create X pixmap", Qnil, Qnil);
8408 return 0;
8409 }
8410#endif
8411 return 1;
8412}
8413
8414
8415/* Destroy XImage XIMG. Free XIMG->data. */
8416
8417static void
8418x_destroy_x_image (ximg)
8419 XImage *ximg;
8420{
8421 xassert (interrupt_input_blocked);
8422 if (ximg)
8423 {
8424 xfree (ximg->data);
8425 ximg->data = NULL;
8426 XDestroyImage (ximg);
8427 }
8428}
8429
8430
8431/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8432 are width and height of both the image and pixmap. */
8433
8434static void
8435x_put_x_image (f, ximg, pixmap, width, height)
8436 struct frame *f;
8437 XImage *ximg;
8438 Pixmap pixmap;
8439{
8440 GC gc;
8441
8442 xassert (interrupt_input_blocked);
8443 gc = XCreateGC (NULL, pixmap, 0, NULL);
8444 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8445 XFreeGC (NULL, gc);
8446}
8447
8448#endif
8449
8450\f
8451/***********************************************************************
8452 Searching files
8453 ***********************************************************************/
8454
8455static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8456
8457/* Find image file FILE. Look in data-directory, then
8458 x-bitmap-file-path. Value is the full name of the file found, or
8459 nil if not found. */
8460
8461static Lisp_Object
8462x_find_image_file (file)
8463 Lisp_Object file;
8464{
8465 Lisp_Object file_found, search_path;
8466 struct gcpro gcpro1, gcpro2;
8467 int fd;
8468
8469 file_found = Qnil;
8470 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8471 GCPRO2 (file_found, search_path);
8472
8473 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8474 fd = openp (search_path, file, "", &file_found, 0);
8475
939d6465 8476 if (fd == -1)
6fc2811b
JR
8477 file_found = Qnil;
8478 else
8479 close (fd);
8480
8481 UNGCPRO;
8482 return file_found;
8483}
8484
8485
8486\f
8487/***********************************************************************
8488 XBM images
8489 ***********************************************************************/
8490
8491static int xbm_load P_ ((struct frame *f, struct image *img));
8492static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8493 Lisp_Object file));
8494static int xbm_image_p P_ ((Lisp_Object object));
8495static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8496 unsigned char **));
8497
8498
8499/* Indices of image specification fields in xbm_format, below. */
8500
8501enum xbm_keyword_index
8502{
8503 XBM_TYPE,
8504 XBM_FILE,
8505 XBM_WIDTH,
8506 XBM_HEIGHT,
8507 XBM_DATA,
8508 XBM_FOREGROUND,
8509 XBM_BACKGROUND,
8510 XBM_ASCENT,
8511 XBM_MARGIN,
8512 XBM_RELIEF,
8513 XBM_ALGORITHM,
8514 XBM_HEURISTIC_MASK,
8515 XBM_LAST
8516};
8517
8518/* Vector of image_keyword structures describing the format
8519 of valid XBM image specifications. */
8520
8521static struct image_keyword xbm_format[XBM_LAST] =
8522{
8523 {":type", IMAGE_SYMBOL_VALUE, 1},
8524 {":file", IMAGE_STRING_VALUE, 0},
8525 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8526 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8527 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8528 {":foreground", IMAGE_STRING_VALUE, 0},
8529 {":background", IMAGE_STRING_VALUE, 0},
8530 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8531 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8532 {":relief", IMAGE_INTEGER_VALUE, 0},
8533 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8534 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8535};
8536
8537/* Structure describing the image type XBM. */
8538
8539static struct image_type xbm_type =
8540{
8541 &Qxbm,
8542 xbm_image_p,
8543 xbm_load,
8544 x_clear_image,
8545 NULL
8546};
8547
8548/* Tokens returned from xbm_scan. */
8549
8550enum xbm_token
8551{
8552 XBM_TK_IDENT = 256,
8553 XBM_TK_NUMBER
8554};
8555
8556
8557/* Return non-zero if OBJECT is a valid XBM-type image specification.
8558 A valid specification is a list starting with the symbol `image'
8559 The rest of the list is a property list which must contain an
8560 entry `:type xbm..
8561
8562 If the specification specifies a file to load, it must contain
8563 an entry `:file FILENAME' where FILENAME is a string.
8564
8565 If the specification is for a bitmap loaded from memory it must
8566 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8567 WIDTH and HEIGHT are integers > 0. DATA may be:
8568
8569 1. a string large enough to hold the bitmap data, i.e. it must
8570 have a size >= (WIDTH + 7) / 8 * HEIGHT
8571
8572 2. a bool-vector of size >= WIDTH * HEIGHT
8573
8574 3. a vector of strings or bool-vectors, one for each line of the
8575 bitmap.
8576
8577 Both the file and data forms may contain the additional entries
8578 `:background COLOR' and `:foreground COLOR'. If not present,
8579 foreground and background of the frame on which the image is
8580 displayed, is used. */
8581
8582static int
8583xbm_image_p (object)
8584 Lisp_Object object;
8585{
8586 struct image_keyword kw[XBM_LAST];
8587
8588 bcopy (xbm_format, kw, sizeof kw);
8589 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8590 return 0;
8591
8592 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8593
8594 if (kw[XBM_FILE].count)
8595 {
8596 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8597 return 0;
8598 }
8599 else
8600 {
8601 Lisp_Object data;
8602 int width, height;
8603
8604 /* Entries for `:width', `:height' and `:data' must be present. */
8605 if (!kw[XBM_WIDTH].count
8606 || !kw[XBM_HEIGHT].count
8607 || !kw[XBM_DATA].count)
8608 return 0;
8609
8610 data = kw[XBM_DATA].value;
8611 width = XFASTINT (kw[XBM_WIDTH].value);
8612 height = XFASTINT (kw[XBM_HEIGHT].value);
8613
8614 /* Check type of data, and width and height against contents of
8615 data. */
8616 if (VECTORP (data))
8617 {
8618 int i;
8619
8620 /* Number of elements of the vector must be >= height. */
8621 if (XVECTOR (data)->size < height)
8622 return 0;
8623
8624 /* Each string or bool-vector in data must be large enough
8625 for one line of the image. */
8626 for (i = 0; i < height; ++i)
8627 {
8628 Lisp_Object elt = XVECTOR (data)->contents[i];
8629
8630 if (STRINGP (elt))
8631 {
8632 if (XSTRING (elt)->size
8633 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8634 return 0;
8635 }
8636 else if (BOOL_VECTOR_P (elt))
8637 {
8638 if (XBOOL_VECTOR (elt)->size < width)
8639 return 0;
8640 }
8641 else
8642 return 0;
8643 }
8644 }
8645 else if (STRINGP (data))
8646 {
8647 if (XSTRING (data)->size
8648 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8649 return 0;
8650 }
8651 else if (BOOL_VECTOR_P (data))
8652 {
8653 if (XBOOL_VECTOR (data)->size < width * height)
8654 return 0;
8655 }
8656 else
8657 return 0;
8658 }
8659
8660 /* Baseline must be a value between 0 and 100 (a percentage). */
8661 if (kw[XBM_ASCENT].count
8662 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8663 return 0;
8664
8665 return 1;
8666}
8667
8668
8669/* Scan a bitmap file. FP is the stream to read from. Value is
8670 either an enumerator from enum xbm_token, or a character for a
8671 single-character token, or 0 at end of file. If scanning an
8672 identifier, store the lexeme of the identifier in SVAL. If
8673 scanning a number, store its value in *IVAL. */
8674
8675static int
8676xbm_scan (fp, sval, ival)
8677 FILE *fp;
8678 char *sval;
8679 int *ival;
8680{
8681 int c;
8682
8683 /* Skip white space. */
8684 while ((c = fgetc (fp)) != EOF && isspace (c))
8685 ;
8686
8687 if (c == EOF)
8688 c = 0;
8689 else if (isdigit (c))
8690 {
8691 int value = 0, digit;
8692
8693 if (c == '0')
8694 {
8695 c = fgetc (fp);
8696 if (c == 'x' || c == 'X')
8697 {
8698 while ((c = fgetc (fp)) != EOF)
8699 {
8700 if (isdigit (c))
8701 digit = c - '0';
8702 else if (c >= 'a' && c <= 'f')
8703 digit = c - 'a' + 10;
8704 else if (c >= 'A' && c <= 'F')
8705 digit = c - 'A' + 10;
8706 else
8707 break;
8708 value = 16 * value + digit;
8709 }
8710 }
8711 else if (isdigit (c))
8712 {
8713 value = c - '0';
8714 while ((c = fgetc (fp)) != EOF
8715 && isdigit (c))
8716 value = 8 * value + c - '0';
8717 }
8718 }
8719 else
8720 {
8721 value = c - '0';
8722 while ((c = fgetc (fp)) != EOF
8723 && isdigit (c))
8724 value = 10 * value + c - '0';
8725 }
8726
8727 if (c != EOF)
8728 ungetc (c, fp);
8729 *ival = value;
8730 c = XBM_TK_NUMBER;
8731 }
8732 else if (isalpha (c) || c == '_')
8733 {
8734 *sval++ = c;
8735 while ((c = fgetc (fp)) != EOF
8736 && (isalnum (c) || c == '_'))
8737 *sval++ = c;
8738 *sval = 0;
8739 if (c != EOF)
8740 ungetc (c, fp);
8741 c = XBM_TK_IDENT;
8742 }
8743
8744 return c;
8745}
8746
8747
8748/* Replacement for XReadBitmapFileData which isn't available under old
8749 X versions. FILE is the name of the bitmap file to read. Set
8750 *WIDTH and *HEIGHT to the width and height of the image. Return in
8751 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8752 successful. */
8753
8754static int
8755xbm_read_bitmap_file_data (file, width, height, data)
8756 char *file;
8757 int *width, *height;
8758 unsigned char **data;
8759{
8760 FILE *fp;
8761 char buffer[BUFSIZ];
8762 int padding_p = 0;
8763 int v10 = 0;
8764 int bytes_per_line, i, nbytes;
8765 unsigned char *p;
8766 int value;
8767 int LA1;
8768
8769#define match() \
8770 LA1 = xbm_scan (fp, buffer, &value)
8771
8772#define expect(TOKEN) \
8773 if (LA1 != (TOKEN)) \
8774 goto failure; \
8775 else \
8776 match ()
8777
8778#define expect_ident(IDENT) \
8779 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8780 match (); \
8781 else \
8782 goto failure
8783
8784 fp = fopen (file, "r");
8785 if (fp == NULL)
8786 return 0;
8787
8788 *width = *height = -1;
8789 *data = NULL;
8790 LA1 = xbm_scan (fp, buffer, &value);
8791
8792 /* Parse defines for width, height and hot-spots. */
8793 while (LA1 == '#')
8794 {
8795 match ();
8796 expect_ident ("define");
8797 expect (XBM_TK_IDENT);
8798
8799 if (LA1 == XBM_TK_NUMBER);
8800 {
8801 char *p = strrchr (buffer, '_');
8802 p = p ? p + 1 : buffer;
8803 if (strcmp (p, "width") == 0)
8804 *width = value;
8805 else if (strcmp (p, "height") == 0)
8806 *height = value;
8807 }
8808 expect (XBM_TK_NUMBER);
8809 }
8810
8811 if (*width < 0 || *height < 0)
8812 goto failure;
8813
8814 /* Parse bits. Must start with `static'. */
8815 expect_ident ("static");
8816 if (LA1 == XBM_TK_IDENT)
8817 {
8818 if (strcmp (buffer, "unsigned") == 0)
8819 {
8820 match ();
8821 expect_ident ("char");
8822 }
8823 else if (strcmp (buffer, "short") == 0)
8824 {
8825 match ();
8826 v10 = 1;
8827 if (*width % 16 && *width % 16 < 9)
8828 padding_p = 1;
8829 }
8830 else if (strcmp (buffer, "char") == 0)
8831 match ();
8832 else
8833 goto failure;
8834 }
8835 else
8836 goto failure;
8837
8838 expect (XBM_TK_IDENT);
8839 expect ('[');
8840 expect (']');
8841 expect ('=');
8842 expect ('{');
8843
8844 bytes_per_line = (*width + 7) / 8 + padding_p;
8845 nbytes = bytes_per_line * *height;
8846 p = *data = (char *) xmalloc (nbytes);
8847
8848 if (v10)
8849 {
8850
8851 for (i = 0; i < nbytes; i += 2)
8852 {
8853 int val = value;
8854 expect (XBM_TK_NUMBER);
8855
8856 *p++ = val;
8857 if (!padding_p || ((i + 2) % bytes_per_line))
8858 *p++ = value >> 8;
8859
8860 if (LA1 == ',' || LA1 == '}')
8861 match ();
8862 else
8863 goto failure;
8864 }
8865 }
8866 else
8867 {
8868 for (i = 0; i < nbytes; ++i)
8869 {
8870 int val = value;
8871 expect (XBM_TK_NUMBER);
8872
8873 *p++ = val;
8874
8875 if (LA1 == ',' || LA1 == '}')
8876 match ();
8877 else
8878 goto failure;
8879 }
8880 }
8881
8882 fclose (fp);
8883 return 1;
8884
8885 failure:
8886
8887 fclose (fp);
8888 if (*data)
8889 {
8890 xfree (*data);
8891 *data = NULL;
8892 }
8893 return 0;
8894
8895#undef match
8896#undef expect
8897#undef expect_ident
8898}
8899
8900
8901/* Load XBM image IMG which will be displayed on frame F from file
8902 SPECIFIED_FILE. Value is non-zero if successful. */
8903
8904static int
8905xbm_load_image_from_file (f, img, specified_file)
8906 struct frame *f;
8907 struct image *img;
8908 Lisp_Object specified_file;
8909{
8910 int rc;
8911 unsigned char *data;
8912 int success_p = 0;
8913 Lisp_Object file;
8914 struct gcpro gcpro1;
8915
8916 xassert (STRINGP (specified_file));
8917 file = Qnil;
8918 GCPRO1 (file);
8919
8920 file = x_find_image_file (specified_file);
8921 if (!STRINGP (file))
8922 {
8923 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8924 UNGCPRO;
8925 return 0;
8926 }
8927
8928 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
8929 &img->height, &data);
8930 if (rc)
8931 {
8932 int depth = one_w32_display_info.n_cbits;
8933 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8934 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8935 Lisp_Object value;
8936
8937 xassert (img->width > 0 && img->height > 0);
8938
8939 /* Get foreground and background colors, maybe allocate colors. */
8940 value = image_spec_value (img->spec, QCforeground, NULL);
8941 if (!NILP (value))
8942 foreground = x_alloc_image_color (f, img, value, foreground);
8943
8944 value = image_spec_value (img->spec, QCbackground, NULL);
8945 if (!NILP (value))
8946 background = x_alloc_image_color (f, img, value, background);
8947
767b1ff0 8948#if 0 /* TODO : Port image display to W32 */
6fc2811b
JR
8949 BLOCK_INPUT;
8950 img->pixmap
8951 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8952 FRAME_W32_WINDOW (f),
8953 data,
8954 img->width, img->height,
8955 foreground, background,
8956 depth);
8957 xfree (data);
8958
8959 if (img->pixmap == 0)
8960 {
8961 x_clear_image (f, img);
8962 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
8963 }
8964 else
8965 success_p = 1;
8966
8967 UNBLOCK_INPUT;
8968#endif
8969 }
8970 else
8971 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8972
8973 UNGCPRO;
8974 return success_p;
8975}
8976
8977
8978/* Fill image IMG which is used on frame F with pixmap data. Value is
8979 non-zero if successful. */
8980
8981static int
8982xbm_load (f, img)
8983 struct frame *f;
8984 struct image *img;
8985{
8986 int success_p = 0;
8987 Lisp_Object file_name;
8988
8989 xassert (xbm_image_p (img->spec));
8990
8991 /* If IMG->spec specifies a file name, create a non-file spec from it. */
8992 file_name = image_spec_value (img->spec, QCfile, NULL);
8993 if (STRINGP (file_name))
8994 success_p = xbm_load_image_from_file (f, img, file_name);
8995 else
8996 {
8997 struct image_keyword fmt[XBM_LAST];
8998 Lisp_Object data;
8999 int depth;
9000 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9001 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9002 char *bits;
9003 int parsed_p;
9004
9005 /* Parse the list specification. */
9006 bcopy (xbm_format, fmt, sizeof fmt);
9007 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9008 xassert (parsed_p);
9009
9010 /* Get specified width, and height. */
9011 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9012 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9013 xassert (img->width > 0 && img->height > 0);
9014
9015 BLOCK_INPUT;
9016
9017 if (fmt[XBM_ASCENT].count)
9018 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
9019
9020 /* Get foreground and background colors, maybe allocate colors. */
9021 if (fmt[XBM_FOREGROUND].count)
9022 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9023 foreground);
9024 if (fmt[XBM_BACKGROUND].count)
9025 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9026 background);
9027
9028 /* Set bits to the bitmap image data. */
9029 data = fmt[XBM_DATA].value;
9030 if (VECTORP (data))
9031 {
9032 int i;
9033 char *p;
9034 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
9035
9036 p = bits = (char *) alloca (nbytes * img->height);
9037 for (i = 0; i < img->height; ++i, p += nbytes)
9038 {
9039 Lisp_Object line = XVECTOR (data)->contents[i];
9040 if (STRINGP (line))
9041 bcopy (XSTRING (line)->data, p, nbytes);
9042 else
9043 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9044 }
9045 }
9046 else if (STRINGP (data))
9047 bits = XSTRING (data)->data;
9048 else
9049 bits = XBOOL_VECTOR (data)->data;
9050
767b1ff0 9051#if 0 /* TODO : W32 XPM code */
6fc2811b
JR
9052 /* Create the pixmap. */
9053 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
9054 img->pixmap
9055 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9056 FRAME_W32_WINDOW (f),
9057 bits,
9058 img->width, img->height,
9059 foreground, background,
9060 depth);
767b1ff0 9061#endif /* TODO */
6fc2811b
JR
9062
9063 if (img->pixmap)
9064 success_p = 1;
9065 else
9066 {
9067 image_error ("Unable to create pixmap for XBM image `%s'",
9068 img->spec, Qnil);
9069 x_clear_image (f, img);
9070 }
9071
9072 UNBLOCK_INPUT;
9073 }
9074
9075 return success_p;
9076}
9077
9078
9079\f
9080/***********************************************************************
9081 XPM images
9082 ***********************************************************************/
9083
9084#if HAVE_XPM
9085
9086static int xpm_image_p P_ ((Lisp_Object object));
9087static int xpm_load P_ ((struct frame *f, struct image *img));
9088static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9089
9090#include "X11/xpm.h"
9091
9092/* The symbol `xpm' identifying XPM-format images. */
9093
9094Lisp_Object Qxpm;
9095
9096/* Indices of image specification fields in xpm_format, below. */
9097
9098enum xpm_keyword_index
9099{
9100 XPM_TYPE,
9101 XPM_FILE,
9102 XPM_DATA,
9103 XPM_ASCENT,
9104 XPM_MARGIN,
9105 XPM_RELIEF,
9106 XPM_ALGORITHM,
9107 XPM_HEURISTIC_MASK,
9108 XPM_COLOR_SYMBOLS,
9109 XPM_LAST
9110};
9111
9112/* Vector of image_keyword structures describing the format
9113 of valid XPM image specifications. */
9114
9115static struct image_keyword xpm_format[XPM_LAST] =
9116{
9117 {":type", IMAGE_SYMBOL_VALUE, 1},
9118 {":file", IMAGE_STRING_VALUE, 0},
9119 {":data", IMAGE_STRING_VALUE, 0},
9120 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9121 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9122 {":relief", IMAGE_INTEGER_VALUE, 0},
9123 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9124 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9125 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9126};
9127
9128/* Structure describing the image type XBM. */
9129
9130static struct image_type xpm_type =
9131{
9132 &Qxpm,
9133 xpm_image_p,
9134 xpm_load,
9135 x_clear_image,
9136 NULL
9137};
9138
9139
9140/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9141 for XPM images. Such a list must consist of conses whose car and
9142 cdr are strings. */
9143
9144static int
9145xpm_valid_color_symbols_p (color_symbols)
9146 Lisp_Object color_symbols;
9147{
9148 while (CONSP (color_symbols))
9149 {
9150 Lisp_Object sym = XCAR (color_symbols);
9151 if (!CONSP (sym)
9152 || !STRINGP (XCAR (sym))
9153 || !STRINGP (XCDR (sym)))
9154 break;
9155 color_symbols = XCDR (color_symbols);
9156 }
9157
9158 return NILP (color_symbols);
9159}
9160
9161
9162/* Value is non-zero if OBJECT is a valid XPM image specification. */
9163
9164static int
9165xpm_image_p (object)
9166 Lisp_Object object;
9167{
9168 struct image_keyword fmt[XPM_LAST];
9169 bcopy (xpm_format, fmt, sizeof fmt);
9170 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9171 /* Either `:file' or `:data' must be present. */
9172 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9173 /* Either no `:color-symbols' or it's a list of conses
9174 whose car and cdr are strings. */
9175 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9176 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9177 && (fmt[XPM_ASCENT].count == 0
9178 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9179}
9180
9181
9182/* Load image IMG which will be displayed on frame F. Value is
9183 non-zero if successful. */
9184
9185static int
9186xpm_load (f, img)
9187 struct frame *f;
9188 struct image *img;
9189{
9190 int rc, i;
9191 XpmAttributes attrs;
9192 Lisp_Object specified_file, color_symbols;
9193
9194 /* Configure the XPM lib. Use the visual of frame F. Allocate
9195 close colors. Return colors allocated. */
9196 bzero (&attrs, sizeof attrs);
dfff8a69
JR
9197 attrs.visual = FRAME_X_VISUAL (f);
9198 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 9199 attrs.valuemask |= XpmVisual;
dfff8a69 9200 attrs.valuemask |= XpmColormap;
6fc2811b 9201 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 9202#ifdef XpmAllocCloseColors
6fc2811b
JR
9203 attrs.alloc_close_colors = 1;
9204 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
9205#else
9206 attrs.closeness = 600;
9207 attrs.valuemask |= XpmCloseness;
9208#endif
6fc2811b
JR
9209
9210 /* If image specification contains symbolic color definitions, add
9211 these to `attrs'. */
9212 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9213 if (CONSP (color_symbols))
9214 {
9215 Lisp_Object tail;
9216 XpmColorSymbol *xpm_syms;
9217 int i, size;
9218
9219 attrs.valuemask |= XpmColorSymbols;
9220
9221 /* Count number of symbols. */
9222 attrs.numsymbols = 0;
9223 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9224 ++attrs.numsymbols;
9225
9226 /* Allocate an XpmColorSymbol array. */
9227 size = attrs.numsymbols * sizeof *xpm_syms;
9228 xpm_syms = (XpmColorSymbol *) alloca (size);
9229 bzero (xpm_syms, size);
9230 attrs.colorsymbols = xpm_syms;
9231
9232 /* Fill the color symbol array. */
9233 for (tail = color_symbols, i = 0;
9234 CONSP (tail);
9235 ++i, tail = XCDR (tail))
9236 {
9237 Lisp_Object name = XCAR (XCAR (tail));
9238 Lisp_Object color = XCDR (XCAR (tail));
9239 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9240 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9241 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9242 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9243 }
9244 }
9245
9246 /* Create a pixmap for the image, either from a file, or from a
9247 string buffer containing data in the same format as an XPM file. */
9248 BLOCK_INPUT;
9249 specified_file = image_spec_value (img->spec, QCfile, NULL);
9250 if (STRINGP (specified_file))
9251 {
9252 Lisp_Object file = x_find_image_file (specified_file);
9253 if (!STRINGP (file))
9254 {
9255 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9256 UNBLOCK_INPUT;
9257 return 0;
9258 }
9259
9260 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9261 XSTRING (file)->data, &img->pixmap, &img->mask,
9262 &attrs);
9263 }
9264 else
9265 {
9266 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9267 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9268 XSTRING (buffer)->data,
9269 &img->pixmap, &img->mask,
9270 &attrs);
9271 }
9272 UNBLOCK_INPUT;
9273
9274 if (rc == XpmSuccess)
9275 {
9276 /* Remember allocated colors. */
9277 img->ncolors = attrs.nalloc_pixels;
9278 img->colors = (unsigned long *) xmalloc (img->ncolors
9279 * sizeof *img->colors);
9280 for (i = 0; i < attrs.nalloc_pixels; ++i)
9281 img->colors[i] = attrs.alloc_pixels[i];
9282
9283 img->width = attrs.width;
9284 img->height = attrs.height;
9285 xassert (img->width > 0 && img->height > 0);
9286
9287 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9288 BLOCK_INPUT;
9289 XpmFreeAttributes (&attrs);
9290 UNBLOCK_INPUT;
9291 }
9292 else
9293 {
9294 switch (rc)
9295 {
9296 case XpmOpenFailed:
9297 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9298 break;
9299
9300 case XpmFileInvalid:
9301 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9302 break;
9303
9304 case XpmNoMemory:
9305 image_error ("Out of memory (%s)", img->spec, Qnil);
9306 break;
9307
9308 case XpmColorFailed:
9309 image_error ("Color allocation error (%s)", img->spec, Qnil);
9310 break;
9311
9312 default:
9313 image_error ("Unknown error (%s)", img->spec, Qnil);
9314 break;
9315 }
9316 }
9317
9318 return rc == XpmSuccess;
9319}
9320
9321#endif /* HAVE_XPM != 0 */
9322
9323\f
767b1ff0 9324#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
9325/***********************************************************************
9326 Color table
9327 ***********************************************************************/
9328
9329/* An entry in the color table mapping an RGB color to a pixel color. */
9330
9331struct ct_color
9332{
9333 int r, g, b;
9334 unsigned long pixel;
9335
9336 /* Next in color table collision list. */
9337 struct ct_color *next;
9338};
9339
9340/* The bucket vector size to use. Must be prime. */
9341
9342#define CT_SIZE 101
9343
9344/* Value is a hash of the RGB color given by R, G, and B. */
9345
9346#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9347
9348/* The color hash table. */
9349
9350struct ct_color **ct_table;
9351
9352/* Number of entries in the color table. */
9353
9354int ct_colors_allocated;
9355
9356/* Function prototypes. */
9357
9358static void init_color_table P_ ((void));
9359static void free_color_table P_ ((void));
9360static unsigned long *colors_in_color_table P_ ((int *n));
9361static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9362static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9363
9364
9365/* Initialize the color table. */
9366
9367static void
9368init_color_table ()
9369{
9370 int size = CT_SIZE * sizeof (*ct_table);
9371 ct_table = (struct ct_color **) xmalloc (size);
9372 bzero (ct_table, size);
9373 ct_colors_allocated = 0;
9374}
9375
9376
9377/* Free memory associated with the color table. */
9378
9379static void
9380free_color_table ()
9381{
9382 int i;
9383 struct ct_color *p, *next;
9384
9385 for (i = 0; i < CT_SIZE; ++i)
9386 for (p = ct_table[i]; p; p = next)
9387 {
9388 next = p->next;
9389 xfree (p);
9390 }
9391
9392 xfree (ct_table);
9393 ct_table = NULL;
9394}
9395
9396
9397/* Value is a pixel color for RGB color R, G, B on frame F. If an
9398 entry for that color already is in the color table, return the
9399 pixel color of that entry. Otherwise, allocate a new color for R,
9400 G, B, and make an entry in the color table. */
9401
9402static unsigned long
9403lookup_rgb_color (f, r, g, b)
9404 struct frame *f;
9405 int r, g, b;
9406{
9407 unsigned hash = CT_HASH_RGB (r, g, b);
9408 int i = hash % CT_SIZE;
9409 struct ct_color *p;
9410
9411 for (p = ct_table[i]; p; p = p->next)
9412 if (p->r == r && p->g == g && p->b == b)
9413 break;
9414
9415 if (p == NULL)
9416 {
9417 COLORREF color;
9418 Colormap cmap;
9419 int rc;
9420
9421 color = PALETTERGB (r, g, b);
9422
9423 ++ct_colors_allocated;
9424
9425 p = (struct ct_color *) xmalloc (sizeof *p);
9426 p->r = r;
9427 p->g = g;
9428 p->b = b;
9429 p->pixel = color;
9430 p->next = ct_table[i];
9431 ct_table[i] = p;
9432 }
9433
9434 return p->pixel;
9435}
9436
9437
9438/* Look up pixel color PIXEL which is used on frame F in the color
9439 table. If not already present, allocate it. Value is PIXEL. */
9440
9441static unsigned long
9442lookup_pixel_color (f, pixel)
9443 struct frame *f;
9444 unsigned long pixel;
9445{
9446 int i = pixel % CT_SIZE;
9447 struct ct_color *p;
9448
9449 for (p = ct_table[i]; p; p = p->next)
9450 if (p->pixel == pixel)
9451 break;
9452
9453 if (p == NULL)
9454 {
9455 XColor color;
9456 Colormap cmap;
9457 int rc;
9458
9459 BLOCK_INPUT;
9460
9461 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9462 color.pixel = pixel;
9463 XQueryColor (NULL, cmap, &color);
9464 rc = x_alloc_nearest_color (f, cmap, &color);
9465 UNBLOCK_INPUT;
9466
9467 if (rc)
9468 {
9469 ++ct_colors_allocated;
9470
9471 p = (struct ct_color *) xmalloc (sizeof *p);
9472 p->r = color.red;
9473 p->g = color.green;
9474 p->b = color.blue;
9475 p->pixel = pixel;
9476 p->next = ct_table[i];
9477 ct_table[i] = p;
9478 }
9479 else
9480 return FRAME_FOREGROUND_PIXEL (f);
9481 }
9482 return p->pixel;
9483}
9484
9485
9486/* Value is a vector of all pixel colors contained in the color table,
9487 allocated via xmalloc. Set *N to the number of colors. */
9488
9489static unsigned long *
9490colors_in_color_table (n)
9491 int *n;
9492{
9493 int i, j;
9494 struct ct_color *p;
9495 unsigned long *colors;
9496
9497 if (ct_colors_allocated == 0)
9498 {
9499 *n = 0;
9500 colors = NULL;
9501 }
9502 else
9503 {
9504 colors = (unsigned long *) xmalloc (ct_colors_allocated
9505 * sizeof *colors);
9506 *n = ct_colors_allocated;
9507
9508 for (i = j = 0; i < CT_SIZE; ++i)
9509 for (p = ct_table[i]; p; p = p->next)
9510 colors[j++] = p->pixel;
9511 }
9512
9513 return colors;
9514}
9515
767b1ff0 9516#endif /* TODO */
6fc2811b
JR
9517
9518\f
9519/***********************************************************************
9520 Algorithms
9521 ***********************************************************************/
9522
767b1ff0 9523#if 0 /* TODO : W32 versions of low level algorithms */
6fc2811b
JR
9524static void x_laplace_write_row P_ ((struct frame *, long *,
9525 int, XImage *, int));
9526static void x_laplace_read_row P_ ((struct frame *, Colormap,
9527 XColor *, int, XImage *, int));
9528
9529
9530/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9531 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9532 the width of one row in the image. */
9533
9534static void
9535x_laplace_read_row (f, cmap, colors, width, ximg, y)
9536 struct frame *f;
9537 Colormap cmap;
9538 XColor *colors;
9539 int width;
9540 XImage *ximg;
9541 int y;
9542{
9543 int x;
9544
9545 for (x = 0; x < width; ++x)
9546 colors[x].pixel = XGetPixel (ximg, x, y);
9547
9548 XQueryColors (NULL, cmap, colors, width);
9549}
9550
9551
9552/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9553 containing the pixel colors to write. F is the frame we are
9554 working on. */
9555
9556static void
9557x_laplace_write_row (f, pixels, width, ximg, y)
9558 struct frame *f;
9559 long *pixels;
9560 int width;
9561 XImage *ximg;
9562 int y;
9563{
9564 int x;
9565
9566 for (x = 0; x < width; ++x)
9567 XPutPixel (ximg, x, y, pixels[x]);
9568}
9569#endif
9570
9571/* Transform image IMG which is used on frame F with a Laplace
9572 edge-detection algorithm. The result is an image that can be used
9573 to draw disabled buttons, for example. */
9574
9575static void
9576x_laplace (f, img)
9577 struct frame *f;
9578 struct image *img;
9579{
767b1ff0 9580#if 0 /* TODO : W32 version */
6fc2811b
JR
9581 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9582 XImage *ximg, *oimg;
9583 XColor *in[3];
9584 long *out;
9585 Pixmap pixmap;
9586 int x, y, i;
9587 long pixel;
9588 int in_y, out_y, rc;
9589 int mv2 = 45000;
9590
9591 BLOCK_INPUT;
9592
9593 /* Get the X image IMG->pixmap. */
9594 ximg = XGetImage (NULL, img->pixmap,
9595 0, 0, img->width, img->height, ~0, ZPixmap);
9596
9597 /* Allocate 3 input rows, and one output row of colors. */
9598 for (i = 0; i < 3; ++i)
9599 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9600 out = (long *) alloca (img->width * sizeof (long));
9601
9602 /* Create an X image for output. */
9603 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9604 &oimg, &pixmap);
9605
9606 /* Fill first two rows. */
9607 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9608 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9609 in_y = 2;
9610
9611 /* Write first row, all zeros. */
9612 init_color_table ();
9613 pixel = lookup_rgb_color (f, 0, 0, 0);
9614 for (x = 0; x < img->width; ++x)
9615 out[x] = pixel;
9616 x_laplace_write_row (f, out, img->width, oimg, 0);
9617 out_y = 1;
9618
9619 for (y = 2; y < img->height; ++y)
9620 {
9621 int rowa = y % 3;
9622 int rowb = (y + 2) % 3;
9623
9624 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9625
9626 for (x = 0; x < img->width - 2; ++x)
9627 {
9628 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9629 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9630 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9631
9632 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9633 b & 0xffff);
9634 }
9635
9636 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9637 }
9638
9639 /* Write last line, all zeros. */
9640 for (x = 0; x < img->width; ++x)
9641 out[x] = pixel;
9642 x_laplace_write_row (f, out, img->width, oimg, out_y);
9643
9644 /* Free the input image, and free resources of IMG. */
9645 XDestroyImage (ximg);
9646 x_clear_image (f, img);
9647
9648 /* Put the output image into pixmap, and destroy it. */
9649 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9650 x_destroy_x_image (oimg);
9651
9652 /* Remember new pixmap and colors in IMG. */
9653 img->pixmap = pixmap;
9654 img->colors = colors_in_color_table (&img->ncolors);
9655 free_color_table ();
9656
9657 UNBLOCK_INPUT;
767b1ff0 9658#endif /* TODO */
6fc2811b
JR
9659}
9660
9661
9662/* Build a mask for image IMG which is used on frame F. FILE is the
9663 name of an image file, for error messages. HOW determines how to
9664 determine the background color of IMG. If it is a list '(R G B)',
9665 with R, G, and B being integers >= 0, take that as the color of the
9666 background. Otherwise, determine the background color of IMG
9667 heuristically. Value is non-zero if successful. */
9668
9669static int
9670x_build_heuristic_mask (f, img, how)
9671 struct frame *f;
9672 struct image *img;
9673 Lisp_Object how;
9674{
767b1ff0 9675#if 0 /* TODO : W32 version */
6fc2811b
JR
9676 Display *dpy = FRAME_W32_DISPLAY (f);
9677 XImage *ximg, *mask_img;
9678 int x, y, rc, look_at_corners_p;
9679 unsigned long bg;
9680
9681 BLOCK_INPUT;
9682
9683 /* Create an image and pixmap serving as mask. */
9684 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9685 &mask_img, &img->mask);
9686 if (!rc)
9687 {
9688 UNBLOCK_INPUT;
9689 return 0;
9690 }
9691
9692 /* Get the X image of IMG->pixmap. */
9693 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9694 ~0, ZPixmap);
9695
9696 /* Determine the background color of ximg. If HOW is `(R G B)'
9697 take that as color. Otherwise, try to determine the color
9698 heuristically. */
9699 look_at_corners_p = 1;
9700
9701 if (CONSP (how))
9702 {
9703 int rgb[3], i = 0;
9704
9705 while (i < 3
9706 && CONSP (how)
9707 && NATNUMP (XCAR (how)))
9708 {
9709 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9710 how = XCDR (how);
9711 }
9712
9713 if (i == 3 && NILP (how))
9714 {
9715 char color_name[30];
9716 XColor exact, color;
9717 Colormap cmap;
9718
9719 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9720
9721 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9722 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9723 {
9724 bg = color.pixel;
9725 look_at_corners_p = 0;
9726 }
9727 }
9728 }
9729
9730 if (look_at_corners_p)
9731 {
9732 unsigned long corners[4];
9733 int i, best_count;
9734
9735 /* Get the colors at the corners of ximg. */
9736 corners[0] = XGetPixel (ximg, 0, 0);
9737 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9738 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9739 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9740
9741 /* Choose the most frequently found color as background. */
9742 for (i = best_count = 0; i < 4; ++i)
9743 {
9744 int j, n;
9745
9746 for (j = n = 0; j < 4; ++j)
9747 if (corners[i] == corners[j])
9748 ++n;
9749
9750 if (n > best_count)
9751 bg = corners[i], best_count = n;
9752 }
9753 }
9754
9755 /* Set all bits in mask_img to 1 whose color in ximg is different
9756 from the background color bg. */
9757 for (y = 0; y < img->height; ++y)
9758 for (x = 0; x < img->width; ++x)
9759 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9760
9761 /* Put mask_img into img->mask. */
9762 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9763 x_destroy_x_image (mask_img);
9764 XDestroyImage (ximg);
9765
9766 UNBLOCK_INPUT;
767b1ff0 9767#endif /* TODO */
6fc2811b
JR
9768
9769 return 1;
9770}
9771
9772
9773\f
9774/***********************************************************************
9775 PBM (mono, gray, color)
9776 ***********************************************************************/
9777#ifdef HAVE_PBM
9778
9779static int pbm_image_p P_ ((Lisp_Object object));
9780static int pbm_load P_ ((struct frame *f, struct image *img));
9781static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9782
9783/* The symbol `pbm' identifying images of this type. */
9784
9785Lisp_Object Qpbm;
9786
9787/* Indices of image specification fields in gs_format, below. */
9788
9789enum pbm_keyword_index
9790{
9791 PBM_TYPE,
9792 PBM_FILE,
9793 PBM_DATA,
9794 PBM_ASCENT,
9795 PBM_MARGIN,
9796 PBM_RELIEF,
9797 PBM_ALGORITHM,
9798 PBM_HEURISTIC_MASK,
9799 PBM_LAST
9800};
9801
9802/* Vector of image_keyword structures describing the format
9803 of valid user-defined image specifications. */
9804
9805static struct image_keyword pbm_format[PBM_LAST] =
9806{
9807 {":type", IMAGE_SYMBOL_VALUE, 1},
9808 {":file", IMAGE_STRING_VALUE, 0},
9809 {":data", IMAGE_STRING_VALUE, 0},
9810 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9811 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9812 {":relief", IMAGE_INTEGER_VALUE, 0},
9813 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9814 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9815};
9816
9817/* Structure describing the image type `pbm'. */
9818
9819static struct image_type pbm_type =
9820{
9821 &Qpbm,
9822 pbm_image_p,
9823 pbm_load,
9824 x_clear_image,
9825 NULL
9826};
9827
9828
9829/* Return non-zero if OBJECT is a valid PBM image specification. */
9830
9831static int
9832pbm_image_p (object)
9833 Lisp_Object object;
9834{
9835 struct image_keyword fmt[PBM_LAST];
9836
9837 bcopy (pbm_format, fmt, sizeof fmt);
9838
9839 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9840 || (fmt[PBM_ASCENT].count
9841 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9842 return 0;
9843
9844 /* Must specify either :data or :file. */
9845 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9846}
9847
9848
9849/* Scan a decimal number from *S and return it. Advance *S while
9850 reading the number. END is the end of the string. Value is -1 at
9851 end of input. */
9852
9853static int
9854pbm_scan_number (s, end)
9855 unsigned char **s, *end;
9856{
9857 int c, val = -1;
9858
9859 while (*s < end)
9860 {
9861 /* Skip white-space. */
9862 while (*s < end && (c = *(*s)++, isspace (c)))
9863 ;
9864
9865 if (c == '#')
9866 {
9867 /* Skip comment to end of line. */
9868 while (*s < end && (c = *(*s)++, c != '\n'))
9869 ;
9870 }
9871 else if (isdigit (c))
9872 {
9873 /* Read decimal number. */
9874 val = c - '0';
9875 while (*s < end && (c = *(*s)++, isdigit (c)))
9876 val = 10 * val + c - '0';
9877 break;
9878 }
9879 else
9880 break;
9881 }
9882
9883 return val;
9884}
9885
9886
9887/* Read FILE into memory. Value is a pointer to a buffer allocated
9888 with xmalloc holding FILE's contents. Value is null if an error
9889 occured. *SIZE is set to the size of the file. */
9890
9891static char *
9892pbm_read_file (file, size)
9893 Lisp_Object file;
9894 int *size;
9895{
9896 FILE *fp = NULL;
9897 char *buf = NULL;
9898 struct stat st;
9899
9900 if (stat (XSTRING (file)->data, &st) == 0
9901 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
9902 && (buf = (char *) xmalloc (st.st_size),
9903 fread (buf, 1, st.st_size, fp) == st.st_size))
9904 {
9905 *size = st.st_size;
9906 fclose (fp);
9907 }
9908 else
9909 {
9910 if (fp)
9911 fclose (fp);
9912 if (buf)
9913 {
9914 xfree (buf);
9915 buf = NULL;
9916 }
9917 }
9918
9919 return buf;
9920}
9921
9922
9923/* Load PBM image IMG for use on frame F. */
9924
9925static int
9926pbm_load (f, img)
9927 struct frame *f;
9928 struct image *img;
9929{
9930 int raw_p, x, y;
9931 int width, height, max_color_idx = 0;
9932 XImage *ximg;
9933 Lisp_Object file, specified_file;
9934 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
9935 struct gcpro gcpro1;
9936 unsigned char *contents = NULL;
9937 unsigned char *end, *p;
9938 int size;
9939
9940 specified_file = image_spec_value (img->spec, QCfile, NULL);
9941 file = Qnil;
9942 GCPRO1 (file);
9943
9944 if (STRINGP (specified_file))
9945 {
9946 file = x_find_image_file (specified_file);
9947 if (!STRINGP (file))
9948 {
9949 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9950 UNGCPRO;
9951 return 0;
9952 }
9953
9954 contents = pbm_read_file (file, &size);
9955 if (contents == NULL)
9956 {
9957 image_error ("Error reading `%s'", file, Qnil);
9958 UNGCPRO;
9959 return 0;
9960 }
9961
9962 p = contents;
9963 end = contents + size;
9964 }
9965 else
9966 {
9967 Lisp_Object data;
9968 data = image_spec_value (img->spec, QCdata, NULL);
9969 p = XSTRING (data)->data;
9970 end = p + STRING_BYTES (XSTRING (data));
9971 }
9972
9973 /* Check magic number. */
9974 if (end - p < 2 || *p++ != 'P')
9975 {
9976 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9977 error:
9978 xfree (contents);
9979 UNGCPRO;
9980 return 0;
9981 }
9982
6fc2811b
JR
9983 switch (*p++)
9984 {
9985 case '1':
9986 raw_p = 0, type = PBM_MONO;
9987 break;
9988
9989 case '2':
9990 raw_p = 0, type = PBM_GRAY;
9991 break;
9992
9993 case '3':
9994 raw_p = 0, type = PBM_COLOR;
9995 break;
9996
9997 case '4':
9998 raw_p = 1, type = PBM_MONO;
9999 break;
10000
10001 case '5':
10002 raw_p = 1, type = PBM_GRAY;
10003 break;
10004
10005 case '6':
10006 raw_p = 1, type = PBM_COLOR;
10007 break;
10008
10009 default:
10010 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10011 goto error;
10012 }
10013
10014 /* Read width, height, maximum color-component. Characters
10015 starting with `#' up to the end of a line are ignored. */
10016 width = pbm_scan_number (&p, end);
10017 height = pbm_scan_number (&p, end);
10018
10019 if (type != PBM_MONO)
10020 {
10021 max_color_idx = pbm_scan_number (&p, end);
10022 if (raw_p && max_color_idx > 255)
10023 max_color_idx = 255;
10024 }
10025
10026 if (width < 0
10027 || height < 0
10028 || (type != PBM_MONO && max_color_idx < 0))
10029 goto error;
10030
10031 BLOCK_INPUT;
10032 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10033 &ximg, &img->pixmap))
10034 {
10035 UNBLOCK_INPUT;
10036 goto error;
10037 }
10038
10039 /* Initialize the color hash table. */
10040 init_color_table ();
10041
10042 if (type == PBM_MONO)
10043 {
10044 int c = 0, g;
10045
10046 for (y = 0; y < height; ++y)
10047 for (x = 0; x < width; ++x)
10048 {
10049 if (raw_p)
10050 {
10051 if ((x & 7) == 0)
10052 c = *p++;
10053 g = c & 0x80;
10054 c <<= 1;
10055 }
10056 else
10057 g = pbm_scan_number (&p, end);
10058
10059 XPutPixel (ximg, x, y, (g
10060 ? FRAME_FOREGROUND_PIXEL (f)
10061 : FRAME_BACKGROUND_PIXEL (f)));
10062 }
10063 }
10064 else
10065 {
10066 for (y = 0; y < height; ++y)
10067 for (x = 0; x < width; ++x)
10068 {
10069 int r, g, b;
10070
10071 if (type == PBM_GRAY)
10072 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10073 else if (raw_p)
10074 {
10075 r = *p++;
10076 g = *p++;
10077 b = *p++;
10078 }
10079 else
10080 {
10081 r = pbm_scan_number (&p, end);
10082 g = pbm_scan_number (&p, end);
10083 b = pbm_scan_number (&p, end);
10084 }
10085
10086 if (r < 0 || g < 0 || b < 0)
10087 {
dfff8a69 10088 xfree (ximg->data);
6fc2811b
JR
10089 ximg->data = NULL;
10090 XDestroyImage (ximg);
10091 UNBLOCK_INPUT;
10092 image_error ("Invalid pixel value in image `%s'",
10093 img->spec, Qnil);
10094 goto error;
10095 }
10096
10097 /* RGB values are now in the range 0..max_color_idx.
10098 Scale this to the range 0..0xffff supported by X. */
10099 r = (double) r * 65535 / max_color_idx;
10100 g = (double) g * 65535 / max_color_idx;
10101 b = (double) b * 65535 / max_color_idx;
10102 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10103 }
10104 }
10105
10106 /* Store in IMG->colors the colors allocated for the image, and
10107 free the color table. */
10108 img->colors = colors_in_color_table (&img->ncolors);
10109 free_color_table ();
10110
10111 /* Put the image into a pixmap. */
10112 x_put_x_image (f, ximg, img->pixmap, width, height);
10113 x_destroy_x_image (ximg);
10114 UNBLOCK_INPUT;
10115
10116 img->width = width;
10117 img->height = height;
10118
10119 UNGCPRO;
10120 xfree (contents);
10121 return 1;
10122}
10123#endif /* HAVE_PBM */
10124
10125\f
10126/***********************************************************************
10127 PNG
10128 ***********************************************************************/
10129
10130#if HAVE_PNG
10131
10132#include <png.h>
10133
10134/* Function prototypes. */
10135
10136static int png_image_p P_ ((Lisp_Object object));
10137static int png_load P_ ((struct frame *f, struct image *img));
10138
10139/* The symbol `png' identifying images of this type. */
10140
10141Lisp_Object Qpng;
10142
10143/* Indices of image specification fields in png_format, below. */
10144
10145enum png_keyword_index
10146{
10147 PNG_TYPE,
10148 PNG_DATA,
10149 PNG_FILE,
10150 PNG_ASCENT,
10151 PNG_MARGIN,
10152 PNG_RELIEF,
10153 PNG_ALGORITHM,
10154 PNG_HEURISTIC_MASK,
10155 PNG_LAST
10156};
10157
10158/* Vector of image_keyword structures describing the format
10159 of valid user-defined image specifications. */
10160
10161static struct image_keyword png_format[PNG_LAST] =
10162{
10163 {":type", IMAGE_SYMBOL_VALUE, 1},
10164 {":data", IMAGE_STRING_VALUE, 0},
10165 {":file", IMAGE_STRING_VALUE, 0},
10166 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10167 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10168 {":relief", IMAGE_INTEGER_VALUE, 0},
10169 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10170 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10171};
10172
10173/* Structure describing the image type `png'. */
10174
10175static struct image_type png_type =
10176{
10177 &Qpng,
10178 png_image_p,
10179 png_load,
10180 x_clear_image,
10181 NULL
10182};
10183
10184
10185/* Return non-zero if OBJECT is a valid PNG image specification. */
10186
10187static int
10188png_image_p (object)
10189 Lisp_Object object;
10190{
10191 struct image_keyword fmt[PNG_LAST];
10192 bcopy (png_format, fmt, sizeof fmt);
10193
10194 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
10195 || (fmt[PNG_ASCENT].count
10196 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
10197 return 0;
10198
10199 /* Must specify either the :data or :file keyword. */
10200 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
10201}
10202
10203
10204/* Error and warning handlers installed when the PNG library
10205 is initialized. */
10206
10207static void
10208my_png_error (png_ptr, msg)
10209 png_struct *png_ptr;
10210 char *msg;
10211{
10212 xassert (png_ptr != NULL);
10213 image_error ("PNG error: %s", build_string (msg), Qnil);
10214 longjmp (png_ptr->jmpbuf, 1);
10215}
10216
10217
10218static void
10219my_png_warning (png_ptr, msg)
10220 png_struct *png_ptr;
10221 char *msg;
10222{
10223 xassert (png_ptr != NULL);
10224 image_error ("PNG warning: %s", build_string (msg), Qnil);
10225}
10226
6fc2811b
JR
10227/* Memory source for PNG decoding. */
10228
10229struct png_memory_storage
10230{
10231 unsigned char *bytes; /* The data */
10232 size_t len; /* How big is it? */
10233 int index; /* Where are we? */
10234};
10235
10236
10237/* Function set as reader function when reading PNG image from memory.
10238 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10239 bytes from the input to DATA. */
10240
10241static void
10242png_read_from_memory (png_ptr, data, length)
10243 png_structp png_ptr;
10244 png_bytep data;
10245 png_size_t length;
10246{
10247 struct png_memory_storage *tbr
10248 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
10249
10250 if (length > tbr->len - tbr->index)
10251 png_error (png_ptr, "Read error");
10252
10253 bcopy (tbr->bytes + tbr->index, data, length);
10254 tbr->index = tbr->index + length;
10255}
10256
6fc2811b
JR
10257/* Load PNG image IMG for use on frame F. Value is non-zero if
10258 successful. */
10259
10260static int
10261png_load (f, img)
10262 struct frame *f;
10263 struct image *img;
10264{
10265 Lisp_Object file, specified_file;
10266 Lisp_Object specified_data;
10267 int x, y, i;
10268 XImage *ximg, *mask_img = NULL;
10269 struct gcpro gcpro1;
10270 png_struct *png_ptr = NULL;
10271 png_info *info_ptr = NULL, *end_info = NULL;
10272 FILE *fp = NULL;
10273 png_byte sig[8];
10274 png_byte *pixels = NULL;
10275 png_byte **rows = NULL;
10276 png_uint_32 width, height;
10277 int bit_depth, color_type, interlace_type;
10278 png_byte channels;
10279 png_uint_32 row_bytes;
10280 int transparent_p;
10281 char *gamma_str;
10282 double screen_gamma, image_gamma;
10283 int intent;
10284 struct png_memory_storage tbr; /* Data to be read */
10285
10286 /* Find out what file to load. */
10287 specified_file = image_spec_value (img->spec, QCfile, NULL);
10288 specified_data = image_spec_value (img->spec, QCdata, NULL);
10289 file = Qnil;
10290 GCPRO1 (file);
10291
10292 if (NILP (specified_data))
10293 {
10294 file = x_find_image_file (specified_file);
10295 if (!STRINGP (file))
10296 {
10297 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10298 UNGCPRO;
10299 return 0;
10300 }
10301
10302 /* Open the image file. */
10303 fp = fopen (XSTRING (file)->data, "rb");
10304 if (!fp)
10305 {
10306 image_error ("Cannot open image file `%s'", file, Qnil);
10307 UNGCPRO;
10308 fclose (fp);
10309 return 0;
10310 }
10311
10312 /* Check PNG signature. */
10313 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10314 || !png_check_sig (sig, sizeof sig))
10315 {
10316 image_error ("Not a PNG file:` %s'", file, Qnil);
10317 UNGCPRO;
10318 fclose (fp);
10319 return 0;
10320 }
10321 }
10322 else
10323 {
10324 /* Read from memory. */
10325 tbr.bytes = XSTRING (specified_data)->data;
10326 tbr.len = STRING_BYTES (XSTRING (specified_data));
10327 tbr.index = 0;
10328
10329 /* Check PNG signature. */
10330 if (tbr.len < sizeof sig
10331 || !png_check_sig (tbr.bytes, sizeof sig))
10332 {
10333 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10334 UNGCPRO;
10335 return 0;
10336 }
10337
10338 /* Need to skip past the signature. */
10339 tbr.bytes += sizeof (sig);
10340 }
10341
6fc2811b
JR
10342 /* Initialize read and info structs for PNG lib. */
10343 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10344 my_png_error, my_png_warning);
10345 if (!png_ptr)
10346 {
10347 if (fp) fclose (fp);
10348 UNGCPRO;
10349 return 0;
10350 }
10351
10352 info_ptr = png_create_info_struct (png_ptr);
10353 if (!info_ptr)
10354 {
10355 png_destroy_read_struct (&png_ptr, NULL, NULL);
10356 if (fp) fclose (fp);
10357 UNGCPRO;
10358 return 0;
10359 }
10360
10361 end_info = png_create_info_struct (png_ptr);
10362 if (!end_info)
10363 {
10364 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10365 if (fp) fclose (fp);
10366 UNGCPRO;
10367 return 0;
10368 }
10369
10370 /* Set error jump-back. We come back here when the PNG library
10371 detects an error. */
10372 if (setjmp (png_ptr->jmpbuf))
10373 {
10374 error:
10375 if (png_ptr)
10376 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10377 xfree (pixels);
10378 xfree (rows);
10379 if (fp) fclose (fp);
10380 UNGCPRO;
10381 return 0;
10382 }
10383
10384 /* Read image info. */
10385 if (!NILP (specified_data))
10386 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10387 else
10388 png_init_io (png_ptr, fp);
10389
10390 png_set_sig_bytes (png_ptr, sizeof sig);
10391 png_read_info (png_ptr, info_ptr);
10392 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10393 &interlace_type, NULL, NULL);
10394
10395 /* If image contains simply transparency data, we prefer to
10396 construct a clipping mask. */
10397 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10398 transparent_p = 1;
10399 else
10400 transparent_p = 0;
10401
10402 /* This function is easier to write if we only have to handle
10403 one data format: RGB or RGBA with 8 bits per channel. Let's
10404 transform other formats into that format. */
10405
10406 /* Strip more than 8 bits per channel. */
10407 if (bit_depth == 16)
10408 png_set_strip_16 (png_ptr);
10409
10410 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10411 if available. */
10412 png_set_expand (png_ptr);
10413
10414 /* Convert grayscale images to RGB. */
10415 if (color_type == PNG_COLOR_TYPE_GRAY
10416 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10417 png_set_gray_to_rgb (png_ptr);
10418
10419 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10420 gamma_str = getenv ("SCREEN_GAMMA");
10421 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10422
10423 /* Tell the PNG lib to handle gamma correction for us. */
10424
10425#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10426 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10427 /* There is a special chunk in the image specifying the gamma. */
10428 png_set_sRGB (png_ptr, info_ptr, intent);
10429 else
10430#endif
10431 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10432 /* Image contains gamma information. */
10433 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10434 else
10435 /* Use a default of 0.5 for the image gamma. */
10436 png_set_gamma (png_ptr, screen_gamma, 0.5);
10437
10438 /* Handle alpha channel by combining the image with a background
10439 color. Do this only if a real alpha channel is supplied. For
10440 simple transparency, we prefer a clipping mask. */
10441 if (!transparent_p)
10442 {
10443 png_color_16 *image_background;
10444
10445 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10446 /* Image contains a background color with which to
10447 combine the image. */
10448 png_set_background (png_ptr, image_background,
10449 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10450 else
10451 {
10452 /* Image does not contain a background color with which
10453 to combine the image data via an alpha channel. Use
10454 the frame's background instead. */
10455 XColor color;
10456 Colormap cmap;
10457 png_color_16 frame_background;
10458
10459 BLOCK_INPUT;
10460 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10461 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10462 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10463 UNBLOCK_INPUT;
10464
10465 bzero (&frame_background, sizeof frame_background);
10466 frame_background.red = color.red;
10467 frame_background.green = color.green;
10468 frame_background.blue = color.blue;
10469
10470 png_set_background (png_ptr, &frame_background,
10471 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10472 }
10473 }
10474
10475 /* Update info structure. */
10476 png_read_update_info (png_ptr, info_ptr);
10477
10478 /* Get number of channels. Valid values are 1 for grayscale images
10479 and images with a palette, 2 for grayscale images with transparency
10480 information (alpha channel), 3 for RGB images, and 4 for RGB
10481 images with alpha channel, i.e. RGBA. If conversions above were
10482 sufficient we should only have 3 or 4 channels here. */
10483 channels = png_get_channels (png_ptr, info_ptr);
10484 xassert (channels == 3 || channels == 4);
10485
10486 /* Number of bytes needed for one row of the image. */
10487 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10488
10489 /* Allocate memory for the image. */
10490 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10491 rows = (png_byte **) xmalloc (height * sizeof *rows);
10492 for (i = 0; i < height; ++i)
10493 rows[i] = pixels + i * row_bytes;
10494
10495 /* Read the entire image. */
10496 png_read_image (png_ptr, rows);
10497 png_read_end (png_ptr, info_ptr);
10498 if (fp)
10499 {
10500 fclose (fp);
10501 fp = NULL;
10502 }
10503
10504 BLOCK_INPUT;
10505
10506 /* Create the X image and pixmap. */
10507 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10508 &img->pixmap))
10509 {
10510 UNBLOCK_INPUT;
10511 goto error;
10512 }
10513
10514 /* Create an image and pixmap serving as mask if the PNG image
10515 contains an alpha channel. */
10516 if (channels == 4
10517 && !transparent_p
10518 && !x_create_x_image_and_pixmap (f, width, height, 1,
10519 &mask_img, &img->mask))
10520 {
10521 x_destroy_x_image (ximg);
10522 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10523 img->pixmap = 0;
10524 UNBLOCK_INPUT;
10525 goto error;
10526 }
10527
10528 /* Fill the X image and mask from PNG data. */
10529 init_color_table ();
10530
10531 for (y = 0; y < height; ++y)
10532 {
10533 png_byte *p = rows[y];
10534
10535 for (x = 0; x < width; ++x)
10536 {
10537 unsigned r, g, b;
10538
10539 r = *p++ << 8;
10540 g = *p++ << 8;
10541 b = *p++ << 8;
10542 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10543
10544 /* An alpha channel, aka mask channel, associates variable
10545 transparency with an image. Where other image formats
10546 support binary transparency---fully transparent or fully
10547 opaque---PNG allows up to 254 levels of partial transparency.
10548 The PNG library implements partial transparency by combining
10549 the image with a specified background color.
10550
10551 I'm not sure how to handle this here nicely: because the
10552 background on which the image is displayed may change, for
10553 real alpha channel support, it would be necessary to create
10554 a new image for each possible background.
10555
10556 What I'm doing now is that a mask is created if we have
10557 boolean transparency information. Otherwise I'm using
10558 the frame's background color to combine the image with. */
10559
10560 if (channels == 4)
10561 {
10562 if (mask_img)
10563 XPutPixel (mask_img, x, y, *p > 0);
10564 ++p;
10565 }
10566 }
10567 }
10568
10569 /* Remember colors allocated for this image. */
10570 img->colors = colors_in_color_table (&img->ncolors);
10571 free_color_table ();
10572
10573 /* Clean up. */
10574 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10575 xfree (rows);
10576 xfree (pixels);
10577
10578 img->width = width;
10579 img->height = height;
10580
10581 /* Put the image into the pixmap, then free the X image and its buffer. */
10582 x_put_x_image (f, ximg, img->pixmap, width, height);
10583 x_destroy_x_image (ximg);
10584
10585 /* Same for the mask. */
10586 if (mask_img)
10587 {
10588 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10589 x_destroy_x_image (mask_img);
10590 }
10591
10592 UNBLOCK_INPUT;
10593 UNGCPRO;
10594 return 1;
10595}
10596
10597#endif /* HAVE_PNG != 0 */
10598
10599
10600\f
10601/***********************************************************************
10602 JPEG
10603 ***********************************************************************/
10604
10605#if HAVE_JPEG
10606
10607/* Work around a warning about HAVE_STDLIB_H being redefined in
10608 jconfig.h. */
10609#ifdef HAVE_STDLIB_H
10610#define HAVE_STDLIB_H_1
10611#undef HAVE_STDLIB_H
10612#endif /* HAVE_STLIB_H */
10613
10614#include <jpeglib.h>
10615#include <jerror.h>
10616#include <setjmp.h>
10617
10618#ifdef HAVE_STLIB_H_1
10619#define HAVE_STDLIB_H 1
10620#endif
10621
10622static int jpeg_image_p P_ ((Lisp_Object object));
10623static int jpeg_load P_ ((struct frame *f, struct image *img));
10624
10625/* The symbol `jpeg' identifying images of this type. */
10626
10627Lisp_Object Qjpeg;
10628
10629/* Indices of image specification fields in gs_format, below. */
10630
10631enum jpeg_keyword_index
10632{
10633 JPEG_TYPE,
10634 JPEG_DATA,
10635 JPEG_FILE,
10636 JPEG_ASCENT,
10637 JPEG_MARGIN,
10638 JPEG_RELIEF,
10639 JPEG_ALGORITHM,
10640 JPEG_HEURISTIC_MASK,
10641 JPEG_LAST
10642};
10643
10644/* Vector of image_keyword structures describing the format
10645 of valid user-defined image specifications. */
10646
10647static struct image_keyword jpeg_format[JPEG_LAST] =
10648{
10649 {":type", IMAGE_SYMBOL_VALUE, 1},
10650 {":data", IMAGE_STRING_VALUE, 0},
10651 {":file", IMAGE_STRING_VALUE, 0},
10652 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10653 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10654 {":relief", IMAGE_INTEGER_VALUE, 0},
10655 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10656 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10657};
10658
10659/* Structure describing the image type `jpeg'. */
10660
10661static struct image_type jpeg_type =
10662{
10663 &Qjpeg,
10664 jpeg_image_p,
10665 jpeg_load,
10666 x_clear_image,
10667 NULL
10668};
10669
10670
10671/* Return non-zero if OBJECT is a valid JPEG image specification. */
10672
10673static int
10674jpeg_image_p (object)
10675 Lisp_Object object;
10676{
10677 struct image_keyword fmt[JPEG_LAST];
10678
10679 bcopy (jpeg_format, fmt, sizeof fmt);
10680
10681 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10682 || (fmt[JPEG_ASCENT].count
10683 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10684 return 0;
10685
10686 /* Must specify either the :data or :file keyword. */
10687 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10688}
10689
10690
10691struct my_jpeg_error_mgr
10692{
10693 struct jpeg_error_mgr pub;
10694 jmp_buf setjmp_buffer;
10695};
10696
10697static void
10698my_error_exit (cinfo)
10699 j_common_ptr cinfo;
10700{
10701 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10702 longjmp (mgr->setjmp_buffer, 1);
10703}
10704
6fc2811b
JR
10705/* Init source method for JPEG data source manager. Called by
10706 jpeg_read_header() before any data is actually read. See
10707 libjpeg.doc from the JPEG lib distribution. */
10708
10709static void
10710our_init_source (cinfo)
10711 j_decompress_ptr cinfo;
10712{
10713}
10714
10715
10716/* Fill input buffer method for JPEG data source manager. Called
10717 whenever more data is needed. We read the whole image in one step,
10718 so this only adds a fake end of input marker at the end. */
10719
10720static boolean
10721our_fill_input_buffer (cinfo)
10722 j_decompress_ptr cinfo;
10723{
10724 /* Insert a fake EOI marker. */
10725 struct jpeg_source_mgr *src = cinfo->src;
10726 static JOCTET buffer[2];
10727
10728 buffer[0] = (JOCTET) 0xFF;
10729 buffer[1] = (JOCTET) JPEG_EOI;
10730
10731 src->next_input_byte = buffer;
10732 src->bytes_in_buffer = 2;
10733 return TRUE;
10734}
10735
10736
10737/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10738 is the JPEG data source manager. */
10739
10740static void
10741our_skip_input_data (cinfo, num_bytes)
10742 j_decompress_ptr cinfo;
10743 long num_bytes;
10744{
10745 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10746
10747 if (src)
10748 {
10749 if (num_bytes > src->bytes_in_buffer)
10750 ERREXIT (cinfo, JERR_INPUT_EOF);
10751
10752 src->bytes_in_buffer -= num_bytes;
10753 src->next_input_byte += num_bytes;
10754 }
10755}
10756
10757
10758/* Method to terminate data source. Called by
10759 jpeg_finish_decompress() after all data has been processed. */
10760
10761static void
10762our_term_source (cinfo)
10763 j_decompress_ptr cinfo;
10764{
10765}
10766
10767
10768/* Set up the JPEG lib for reading an image from DATA which contains
10769 LEN bytes. CINFO is the decompression info structure created for
10770 reading the image. */
10771
10772static void
10773jpeg_memory_src (cinfo, data, len)
10774 j_decompress_ptr cinfo;
10775 JOCTET *data;
10776 unsigned int len;
10777{
10778 struct jpeg_source_mgr *src;
10779
10780 if (cinfo->src == NULL)
10781 {
10782 /* First time for this JPEG object? */
10783 cinfo->src = (struct jpeg_source_mgr *)
10784 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10785 sizeof (struct jpeg_source_mgr));
10786 src = (struct jpeg_source_mgr *) cinfo->src;
10787 src->next_input_byte = data;
10788 }
10789
10790 src = (struct jpeg_source_mgr *) cinfo->src;
10791 src->init_source = our_init_source;
10792 src->fill_input_buffer = our_fill_input_buffer;
10793 src->skip_input_data = our_skip_input_data;
10794 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10795 src->term_source = our_term_source;
10796 src->bytes_in_buffer = len;
10797 src->next_input_byte = data;
10798}
10799
10800
10801/* Load image IMG for use on frame F. Patterned after example.c
10802 from the JPEG lib. */
10803
10804static int
10805jpeg_load (f, img)
10806 struct frame *f;
10807 struct image *img;
10808{
10809 struct jpeg_decompress_struct cinfo;
10810 struct my_jpeg_error_mgr mgr;
10811 Lisp_Object file, specified_file;
10812 Lisp_Object specified_data;
10813 FILE *fp = NULL;
10814 JSAMPARRAY buffer;
10815 int row_stride, x, y;
10816 XImage *ximg = NULL;
10817 int rc;
10818 unsigned long *colors;
10819 int width, height;
10820 struct gcpro gcpro1;
10821
10822 /* Open the JPEG file. */
10823 specified_file = image_spec_value (img->spec, QCfile, NULL);
10824 specified_data = image_spec_value (img->spec, QCdata, NULL);
10825 file = Qnil;
10826 GCPRO1 (file);
10827
6fc2811b
JR
10828 if (NILP (specified_data))
10829 {
10830 file = x_find_image_file (specified_file);
10831 if (!STRINGP (file))
10832 {
10833 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10834 UNGCPRO;
10835 return 0;
10836 }
10837
10838 fp = fopen (XSTRING (file)->data, "r");
10839 if (fp == NULL)
10840 {
10841 image_error ("Cannot open `%s'", file, Qnil);
10842 UNGCPRO;
10843 return 0;
10844 }
10845 }
10846
10847 /* Customize libjpeg's error handling to call my_error_exit when an
10848 error is detected. This function will perform a longjmp. */
10849 mgr.pub.error_exit = my_error_exit;
10850 cinfo.err = jpeg_std_error (&mgr.pub);
10851
10852 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10853 {
10854 if (rc == 1)
10855 {
10856 /* Called from my_error_exit. Display a JPEG error. */
10857 char buffer[JMSG_LENGTH_MAX];
10858 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10859 image_error ("Error reading JPEG image `%s': %s", img->spec,
10860 build_string (buffer));
10861 }
10862
10863 /* Close the input file and destroy the JPEG object. */
10864 if (fp)
10865 fclose (fp);
10866 jpeg_destroy_decompress (&cinfo);
10867
10868 BLOCK_INPUT;
10869
10870 /* If we already have an XImage, free that. */
10871 x_destroy_x_image (ximg);
10872
10873 /* Free pixmap and colors. */
10874 x_clear_image (f, img);
10875
10876 UNBLOCK_INPUT;
10877 UNGCPRO;
10878 return 0;
10879 }
10880
10881 /* Create the JPEG decompression object. Let it read from fp.
10882 Read the JPEG image header. */
10883 jpeg_create_decompress (&cinfo);
10884
10885 if (NILP (specified_data))
10886 jpeg_stdio_src (&cinfo, fp);
10887 else
10888 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
10889 STRING_BYTES (XSTRING (specified_data)));
10890
10891 jpeg_read_header (&cinfo, TRUE);
10892
10893 /* Customize decompression so that color quantization will be used.
10894 Start decompression. */
10895 cinfo.quantize_colors = TRUE;
10896 jpeg_start_decompress (&cinfo);
10897 width = img->width = cinfo.output_width;
10898 height = img->height = cinfo.output_height;
10899
10900 BLOCK_INPUT;
10901
10902 /* Create X image and pixmap. */
10903 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10904 &img->pixmap))
10905 {
10906 UNBLOCK_INPUT;
10907 longjmp (mgr.setjmp_buffer, 2);
10908 }
10909
10910 /* Allocate colors. When color quantization is used,
10911 cinfo.actual_number_of_colors has been set with the number of
10912 colors generated, and cinfo.colormap is a two-dimensional array
10913 of color indices in the range 0..cinfo.actual_number_of_colors.
10914 No more than 255 colors will be generated. */
10915 {
10916 int i, ir, ig, ib;
10917
10918 if (cinfo.out_color_components > 2)
10919 ir = 0, ig = 1, ib = 2;
10920 else if (cinfo.out_color_components > 1)
10921 ir = 0, ig = 1, ib = 0;
10922 else
10923 ir = 0, ig = 0, ib = 0;
10924
10925 /* Use the color table mechanism because it handles colors that
10926 cannot be allocated nicely. Such colors will be replaced with
10927 a default color, and we don't have to care about which colors
10928 can be freed safely, and which can't. */
10929 init_color_table ();
10930 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
10931 * sizeof *colors);
10932
10933 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
10934 {
10935 /* Multiply RGB values with 255 because X expects RGB values
10936 in the range 0..0xffff. */
10937 int r = cinfo.colormap[ir][i] << 8;
10938 int g = cinfo.colormap[ig][i] << 8;
10939 int b = cinfo.colormap[ib][i] << 8;
10940 colors[i] = lookup_rgb_color (f, r, g, b);
10941 }
10942
10943 /* Remember those colors actually allocated. */
10944 img->colors = colors_in_color_table (&img->ncolors);
10945 free_color_table ();
10946 }
10947
10948 /* Read pixels. */
10949 row_stride = width * cinfo.output_components;
10950 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
10951 row_stride, 1);
10952 for (y = 0; y < height; ++y)
10953 {
10954 jpeg_read_scanlines (&cinfo, buffer, 1);
10955 for (x = 0; x < cinfo.output_width; ++x)
10956 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
10957 }
10958
10959 /* Clean up. */
10960 jpeg_finish_decompress (&cinfo);
10961 jpeg_destroy_decompress (&cinfo);
10962 if (fp)
10963 fclose (fp);
10964
10965 /* Put the image into the pixmap. */
10966 x_put_x_image (f, ximg, img->pixmap, width, height);
10967 x_destroy_x_image (ximg);
10968 UNBLOCK_INPUT;
10969 UNGCPRO;
10970 return 1;
10971}
10972
10973#endif /* HAVE_JPEG */
10974
10975
10976\f
10977/***********************************************************************
10978 TIFF
10979 ***********************************************************************/
10980
10981#if HAVE_TIFF
10982
10983#include <tiffio.h>
10984
10985static int tiff_image_p P_ ((Lisp_Object object));
10986static int tiff_load P_ ((struct frame *f, struct image *img));
10987
10988/* The symbol `tiff' identifying images of this type. */
10989
10990Lisp_Object Qtiff;
10991
10992/* Indices of image specification fields in tiff_format, below. */
10993
10994enum tiff_keyword_index
10995{
10996 TIFF_TYPE,
10997 TIFF_DATA,
10998 TIFF_FILE,
10999 TIFF_ASCENT,
11000 TIFF_MARGIN,
11001 TIFF_RELIEF,
11002 TIFF_ALGORITHM,
11003 TIFF_HEURISTIC_MASK,
11004 TIFF_LAST
11005};
11006
11007/* Vector of image_keyword structures describing the format
11008 of valid user-defined image specifications. */
11009
11010static struct image_keyword tiff_format[TIFF_LAST] =
11011{
11012 {":type", IMAGE_SYMBOL_VALUE, 1},
11013 {":data", IMAGE_STRING_VALUE, 0},
11014 {":file", IMAGE_STRING_VALUE, 0},
11015 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11016 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11017 {":relief", IMAGE_INTEGER_VALUE, 0},
11018 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11019 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11020};
11021
11022/* Structure describing the image type `tiff'. */
11023
11024static struct image_type tiff_type =
11025{
11026 &Qtiff,
11027 tiff_image_p,
11028 tiff_load,
11029 x_clear_image,
11030 NULL
11031};
11032
11033
11034/* Return non-zero if OBJECT is a valid TIFF image specification. */
11035
11036static int
11037tiff_image_p (object)
11038 Lisp_Object object;
11039{
11040 struct image_keyword fmt[TIFF_LAST];
11041 bcopy (tiff_format, fmt, sizeof fmt);
11042
11043 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11044 || (fmt[TIFF_ASCENT].count
11045 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11046 return 0;
11047
11048 /* Must specify either the :data or :file keyword. */
11049 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11050}
11051
11052
11053/* Reading from a memory buffer for TIFF images Based on the PNG
11054 memory source, but we have to provide a lot of extra functions.
11055 Blah.
11056
11057 We really only need to implement read and seek, but I am not
11058 convinced that the TIFF library is smart enough not to destroy
11059 itself if we only hand it the function pointers we need to
11060 override. */
11061
11062typedef struct
11063{
11064 unsigned char *bytes;
11065 size_t len;
11066 int index;
11067}
11068tiff_memory_source;
11069
11070static size_t
11071tiff_read_from_memory (data, buf, size)
11072 thandle_t data;
11073 tdata_t buf;
11074 tsize_t size;
11075{
11076 tiff_memory_source *src = (tiff_memory_source *) data;
11077
11078 if (size > src->len - src->index)
11079 return (size_t) -1;
11080 bcopy (src->bytes + src->index, buf, size);
11081 src->index += size;
11082 return size;
11083}
11084
11085static size_t
11086tiff_write_from_memory (data, buf, size)
11087 thandle_t data;
11088 tdata_t buf;
11089 tsize_t size;
11090{
11091 return (size_t) -1;
11092}
11093
11094static toff_t
11095tiff_seek_in_memory (data, off, whence)
11096 thandle_t data;
11097 toff_t off;
11098 int whence;
11099{
11100 tiff_memory_source *src = (tiff_memory_source *) data;
11101 int idx;
11102
11103 switch (whence)
11104 {
11105 case SEEK_SET: /* Go from beginning of source. */
11106 idx = off;
11107 break;
11108
11109 case SEEK_END: /* Go from end of source. */
11110 idx = src->len + off;
11111 break;
11112
11113 case SEEK_CUR: /* Go from current position. */
11114 idx = src->index + off;
11115 break;
11116
11117 default: /* Invalid `whence'. */
11118 return -1;
11119 }
11120
11121 if (idx > src->len || idx < 0)
11122 return -1;
11123
11124 src->index = idx;
11125 return src->index;
11126}
11127
11128static int
11129tiff_close_memory (data)
11130 thandle_t data;
11131{
11132 /* NOOP */
11133 return 0;
11134}
11135
11136static int
11137tiff_mmap_memory (data, pbase, psize)
11138 thandle_t data;
11139 tdata_t *pbase;
11140 toff_t *psize;
11141{
11142 /* It is already _IN_ memory. */
11143 return 0;
11144}
11145
11146static void
11147tiff_unmap_memory (data, base, size)
11148 thandle_t data;
11149 tdata_t base;
11150 toff_t size;
11151{
11152 /* We don't need to do this. */
11153}
11154
11155static toff_t
11156tiff_size_of_memory (data)
11157 thandle_t data;
11158{
11159 return ((tiff_memory_source *) data)->len;
11160}
11161
6fc2811b
JR
11162/* Load TIFF image IMG for use on frame F. Value is non-zero if
11163 successful. */
11164
11165static int
11166tiff_load (f, img)
11167 struct frame *f;
11168 struct image *img;
11169{
11170 Lisp_Object file, specified_file;
11171 Lisp_Object specified_data;
11172 TIFF *tiff;
11173 int width, height, x, y;
11174 uint32 *buf;
11175 int rc;
11176 XImage *ximg;
11177 struct gcpro gcpro1;
11178 tiff_memory_source memsrc;
11179
11180 specified_file = image_spec_value (img->spec, QCfile, NULL);
11181 specified_data = image_spec_value (img->spec, QCdata, NULL);
11182 file = Qnil;
11183 GCPRO1 (file);
11184
11185 if (NILP (specified_data))
11186 {
11187 /* Read from a file */
11188 file = x_find_image_file (specified_file);
11189 if (!STRINGP (file))
11190 {
11191 image_error ("Cannot find image file `%s'", file, Qnil);
11192 UNGCPRO;
11193 return 0;
11194 }
11195
11196 /* Try to open the image file. */
11197 tiff = TIFFOpen (XSTRING (file)->data, "r");
11198 if (tiff == NULL)
11199 {
11200 image_error ("Cannot open `%s'", file, Qnil);
11201 UNGCPRO;
11202 return 0;
11203 }
11204 }
11205 else
11206 {
11207 /* Memory source! */
11208 memsrc.bytes = XSTRING (specified_data)->data;
11209 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11210 memsrc.index = 0;
11211
11212 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
11213 (TIFFReadWriteProc) tiff_read_from_memory,
11214 (TIFFReadWriteProc) tiff_write_from_memory,
11215 tiff_seek_in_memory,
11216 tiff_close_memory,
11217 tiff_size_of_memory,
11218 tiff_mmap_memory,
11219 tiff_unmap_memory);
11220
11221 if (!tiff)
11222 {
11223 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
11224 UNGCPRO;
11225 return 0;
11226 }
11227 }
11228
11229 /* Get width and height of the image, and allocate a raster buffer
11230 of width x height 32-bit values. */
11231 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11232 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
11233 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
11234
11235 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
11236 TIFFClose (tiff);
11237 if (!rc)
11238 {
11239 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11240 xfree (buf);
11241 UNGCPRO;
11242 return 0;
11243 }
11244
11245 BLOCK_INPUT;
11246
11247 /* Create the X image and pixmap. */
11248 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11249 {
11250 UNBLOCK_INPUT;
11251 xfree (buf);
11252 UNGCPRO;
11253 return 0;
11254 }
11255
11256 /* Initialize the color table. */
11257 init_color_table ();
11258
11259 /* Process the pixel raster. Origin is in the lower-left corner. */
11260 for (y = 0; y < height; ++y)
11261 {
11262 uint32 *row = buf + y * width;
11263
11264 for (x = 0; x < width; ++x)
11265 {
11266 uint32 abgr = row[x];
11267 int r = TIFFGetR (abgr) << 8;
11268 int g = TIFFGetG (abgr) << 8;
11269 int b = TIFFGetB (abgr) << 8;
11270 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11271 }
11272 }
11273
11274 /* Remember the colors allocated for the image. Free the color table. */
11275 img->colors = colors_in_color_table (&img->ncolors);
11276 free_color_table ();
11277
11278 /* Put the image into the pixmap, then free the X image and its buffer. */
11279 x_put_x_image (f, ximg, img->pixmap, width, height);
11280 x_destroy_x_image (ximg);
11281 xfree (buf);
11282 UNBLOCK_INPUT;
11283
11284 img->width = width;
11285 img->height = height;
11286
11287 UNGCPRO;
11288 return 1;
11289}
11290
11291#endif /* HAVE_TIFF != 0 */
11292
11293
11294\f
11295/***********************************************************************
11296 GIF
11297 ***********************************************************************/
11298
11299#if HAVE_GIF
11300
11301#include <gif_lib.h>
11302
11303static int gif_image_p P_ ((Lisp_Object object));
11304static int gif_load P_ ((struct frame *f, struct image *img));
11305
11306/* The symbol `gif' identifying images of this type. */
11307
11308Lisp_Object Qgif;
11309
11310/* Indices of image specification fields in gif_format, below. */
11311
11312enum gif_keyword_index
11313{
11314 GIF_TYPE,
11315 GIF_DATA,
11316 GIF_FILE,
11317 GIF_ASCENT,
11318 GIF_MARGIN,
11319 GIF_RELIEF,
11320 GIF_ALGORITHM,
11321 GIF_HEURISTIC_MASK,
11322 GIF_IMAGE,
11323 GIF_LAST
11324};
11325
11326/* Vector of image_keyword structures describing the format
11327 of valid user-defined image specifications. */
11328
11329static struct image_keyword gif_format[GIF_LAST] =
11330{
11331 {":type", IMAGE_SYMBOL_VALUE, 1},
11332 {":data", IMAGE_STRING_VALUE, 0},
11333 {":file", IMAGE_STRING_VALUE, 0},
11334 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11335 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11336 {":relief", IMAGE_INTEGER_VALUE, 0},
11337 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11338 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11339 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11340};
11341
11342/* Structure describing the image type `gif'. */
11343
11344static struct image_type gif_type =
11345{
11346 &Qgif,
11347 gif_image_p,
11348 gif_load,
11349 x_clear_image,
11350 NULL
11351};
11352
11353/* Return non-zero if OBJECT is a valid GIF image specification. */
11354
11355static int
11356gif_image_p (object)
11357 Lisp_Object object;
11358{
11359 struct image_keyword fmt[GIF_LAST];
11360 bcopy (gif_format, fmt, sizeof fmt);
11361
11362 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11363 || (fmt[GIF_ASCENT].count
11364 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11365 return 0;
11366
11367 /* Must specify either the :data or :file keyword. */
11368 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11369}
11370
11371/* Reading a GIF image from memory
11372 Based on the PNG memory stuff to a certain extent. */
11373
11374typedef struct
11375{
11376 unsigned char *bytes;
11377 size_t len;
11378 int index;
11379}
11380gif_memory_source;
11381
11382/* Make the current memory source available to gif_read_from_memory.
11383 It's done this way because not all versions of libungif support
11384 a UserData field in the GifFileType structure. */
11385static gif_memory_source *current_gif_memory_src;
11386
11387static int
11388gif_read_from_memory (file, buf, len)
11389 GifFileType *file;
11390 GifByteType *buf;
11391 int len;
11392{
11393 gif_memory_source *src = current_gif_memory_src;
11394
11395 if (len > src->len - src->index)
11396 return -1;
11397
11398 bcopy (src->bytes + src->index, buf, len);
11399 src->index += len;
11400 return len;
11401}
11402
11403
11404/* Load GIF image IMG for use on frame F. Value is non-zero if
11405 successful. */
11406
11407static int
11408gif_load (f, img)
11409 struct frame *f;
11410 struct image *img;
11411{
11412 Lisp_Object file, specified_file;
11413 Lisp_Object specified_data;
11414 int rc, width, height, x, y, i;
11415 XImage *ximg;
11416 ColorMapObject *gif_color_map;
11417 unsigned long pixel_colors[256];
11418 GifFileType *gif;
11419 struct gcpro gcpro1;
11420 Lisp_Object image;
11421 int ino, image_left, image_top, image_width, image_height;
11422 gif_memory_source memsrc;
11423 unsigned char *raster;
11424
11425 specified_file = image_spec_value (img->spec, QCfile, NULL);
11426 specified_data = image_spec_value (img->spec, QCdata, NULL);
11427 file = Qnil;
dfff8a69 11428 GCPRO1 (file);
6fc2811b
JR
11429
11430 if (NILP (specified_data))
11431 {
11432 file = x_find_image_file (specified_file);
6fc2811b
JR
11433 if (!STRINGP (file))
11434 {
11435 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11436 UNGCPRO;
11437 return 0;
11438 }
11439
11440 /* Open the GIF file. */
11441 gif = DGifOpenFileName (XSTRING (file)->data);
11442 if (gif == NULL)
11443 {
11444 image_error ("Cannot open `%s'", file, Qnil);
11445 UNGCPRO;
11446 return 0;
11447 }
11448 }
11449 else
11450 {
11451 /* Read from memory! */
11452 current_gif_memory_src = &memsrc;
11453 memsrc.bytes = XSTRING (specified_data)->data;
11454 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11455 memsrc.index = 0;
11456
11457 gif = DGifOpen(&memsrc, gif_read_from_memory);
11458 if (!gif)
11459 {
11460 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11461 UNGCPRO;
11462 return 0;
11463 }
11464 }
11465
11466 /* Read entire contents. */
11467 rc = DGifSlurp (gif);
11468 if (rc == GIF_ERROR)
11469 {
11470 image_error ("Error reading `%s'", img->spec, Qnil);
11471 DGifCloseFile (gif);
11472 UNGCPRO;
11473 return 0;
11474 }
11475
11476 image = image_spec_value (img->spec, QCindex, NULL);
11477 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11478 if (ino >= gif->ImageCount)
11479 {
11480 image_error ("Invalid image number `%s' in image `%s'",
11481 image, img->spec);
11482 DGifCloseFile (gif);
11483 UNGCPRO;
11484 return 0;
11485 }
11486
11487 width = img->width = gif->SWidth;
11488 height = img->height = gif->SHeight;
11489
11490 BLOCK_INPUT;
11491
11492 /* Create the X image and pixmap. */
11493 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11494 {
11495 UNBLOCK_INPUT;
11496 DGifCloseFile (gif);
11497 UNGCPRO;
11498 return 0;
11499 }
11500
11501 /* Allocate colors. */
11502 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11503 if (!gif_color_map)
11504 gif_color_map = gif->SColorMap;
11505 init_color_table ();
11506 bzero (pixel_colors, sizeof pixel_colors);
11507
11508 for (i = 0; i < gif_color_map->ColorCount; ++i)
11509 {
11510 int r = gif_color_map->Colors[i].Red << 8;
11511 int g = gif_color_map->Colors[i].Green << 8;
11512 int b = gif_color_map->Colors[i].Blue << 8;
11513 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11514 }
11515
11516 img->colors = colors_in_color_table (&img->ncolors);
11517 free_color_table ();
11518
11519 /* Clear the part of the screen image that are not covered by
11520 the image from the GIF file. Full animated GIF support
11521 requires more than can be done here (see the gif89 spec,
11522 disposal methods). Let's simply assume that the part
11523 not covered by a sub-image is in the frame's background color. */
11524 image_top = gif->SavedImages[ino].ImageDesc.Top;
11525 image_left = gif->SavedImages[ino].ImageDesc.Left;
11526 image_width = gif->SavedImages[ino].ImageDesc.Width;
11527 image_height = gif->SavedImages[ino].ImageDesc.Height;
11528
11529 for (y = 0; y < image_top; ++y)
11530 for (x = 0; x < width; ++x)
11531 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11532
11533 for (y = image_top + image_height; y < height; ++y)
11534 for (x = 0; x < width; ++x)
11535 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11536
11537 for (y = image_top; y < image_top + image_height; ++y)
11538 {
11539 for (x = 0; x < image_left; ++x)
11540 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11541 for (x = image_left + image_width; x < width; ++x)
11542 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11543 }
11544
11545 /* Read the GIF image into the X image. We use a local variable
11546 `raster' here because RasterBits below is a char *, and invites
11547 problems with bytes >= 0x80. */
11548 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11549
11550 if (gif->SavedImages[ino].ImageDesc.Interlace)
11551 {
11552 static int interlace_start[] = {0, 4, 2, 1};
11553 static int interlace_increment[] = {8, 8, 4, 2};
11554 int pass, inc;
11555 int row = interlace_start[0];
11556
11557 pass = 0;
11558
11559 for (y = 0; y < image_height; y++)
11560 {
11561 if (row >= image_height)
11562 {
11563 row = interlace_start[++pass];
11564 while (row >= image_height)
11565 row = interlace_start[++pass];
11566 }
11567
11568 for (x = 0; x < image_width; x++)
11569 {
11570 int i = raster[(y * image_width) + x];
11571 XPutPixel (ximg, x + image_left, row + image_top,
11572 pixel_colors[i]);
11573 }
11574
11575 row += interlace_increment[pass];
11576 }
11577 }
11578 else
11579 {
11580 for (y = 0; y < image_height; ++y)
11581 for (x = 0; x < image_width; ++x)
11582 {
11583 int i = raster[y* image_width + x];
11584 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11585 }
11586 }
11587
11588 DGifCloseFile (gif);
11589
11590 /* Put the image into the pixmap, then free the X image and its buffer. */
11591 x_put_x_image (f, ximg, img->pixmap, width, height);
11592 x_destroy_x_image (ximg);
11593 UNBLOCK_INPUT;
11594
11595 UNGCPRO;
11596 return 1;
11597}
11598
11599#endif /* HAVE_GIF != 0 */
11600
11601
11602\f
11603/***********************************************************************
11604 Ghostscript
11605 ***********************************************************************/
11606
11607#ifdef HAVE_GHOSTSCRIPT
11608static int gs_image_p P_ ((Lisp_Object object));
11609static int gs_load P_ ((struct frame *f, struct image *img));
11610static void gs_clear_image P_ ((struct frame *f, struct image *img));
11611
11612/* The symbol `postscript' identifying images of this type. */
11613
11614Lisp_Object Qpostscript;
11615
11616/* Keyword symbols. */
11617
11618Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11619
11620/* Indices of image specification fields in gs_format, below. */
11621
11622enum gs_keyword_index
11623{
11624 GS_TYPE,
11625 GS_PT_WIDTH,
11626 GS_PT_HEIGHT,
11627 GS_FILE,
11628 GS_LOADER,
11629 GS_BOUNDING_BOX,
11630 GS_ASCENT,
11631 GS_MARGIN,
11632 GS_RELIEF,
11633 GS_ALGORITHM,
11634 GS_HEURISTIC_MASK,
11635 GS_LAST
11636};
11637
11638/* Vector of image_keyword structures describing the format
11639 of valid user-defined image specifications. */
11640
11641static struct image_keyword gs_format[GS_LAST] =
11642{
11643 {":type", IMAGE_SYMBOL_VALUE, 1},
11644 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11645 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11646 {":file", IMAGE_STRING_VALUE, 1},
11647 {":loader", IMAGE_FUNCTION_VALUE, 0},
11648 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11649 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11650 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11651 {":relief", IMAGE_INTEGER_VALUE, 0},
11652 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11653 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11654};
11655
11656/* Structure describing the image type `ghostscript'. */
11657
11658static struct image_type gs_type =
11659{
11660 &Qpostscript,
11661 gs_image_p,
11662 gs_load,
11663 gs_clear_image,
11664 NULL
11665};
11666
11667
11668/* Free X resources of Ghostscript image IMG which is used on frame F. */
11669
11670static void
11671gs_clear_image (f, img)
11672 struct frame *f;
11673 struct image *img;
11674{
11675 /* IMG->data.ptr_val may contain a recorded colormap. */
11676 xfree (img->data.ptr_val);
11677 x_clear_image (f, img);
11678}
11679
11680
11681/* Return non-zero if OBJECT is a valid Ghostscript image
11682 specification. */
11683
11684static int
11685gs_image_p (object)
11686 Lisp_Object object;
11687{
11688 struct image_keyword fmt[GS_LAST];
11689 Lisp_Object tem;
11690 int i;
11691
11692 bcopy (gs_format, fmt, sizeof fmt);
11693
11694 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11695 || (fmt[GS_ASCENT].count
11696 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11697 return 0;
11698
11699 /* Bounding box must be a list or vector containing 4 integers. */
11700 tem = fmt[GS_BOUNDING_BOX].value;
11701 if (CONSP (tem))
11702 {
11703 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11704 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11705 return 0;
11706 if (!NILP (tem))
11707 return 0;
11708 }
11709 else if (VECTORP (tem))
11710 {
11711 if (XVECTOR (tem)->size != 4)
11712 return 0;
11713 for (i = 0; i < 4; ++i)
11714 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11715 return 0;
11716 }
11717 else
11718 return 0;
11719
11720 return 1;
11721}
11722
11723
11724/* Load Ghostscript image IMG for use on frame F. Value is non-zero
11725 if successful. */
11726
11727static int
11728gs_load (f, img)
11729 struct frame *f;
11730 struct image *img;
11731{
11732 char buffer[100];
11733 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11734 struct gcpro gcpro1, gcpro2;
11735 Lisp_Object frame;
11736 double in_width, in_height;
11737 Lisp_Object pixel_colors = Qnil;
11738
11739 /* Compute pixel size of pixmap needed from the given size in the
11740 image specification. Sizes in the specification are in pt. 1 pt
11741 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11742 info. */
11743 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11744 in_width = XFASTINT (pt_width) / 72.0;
11745 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11746 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11747 in_height = XFASTINT (pt_height) / 72.0;
11748 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11749
11750 /* Create the pixmap. */
11751 BLOCK_INPUT;
11752 xassert (img->pixmap == 0);
11753 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11754 img->width, img->height,
11755 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11756 UNBLOCK_INPUT;
11757
11758 if (!img->pixmap)
11759 {
11760 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11761 return 0;
11762 }
11763
11764 /* Call the loader to fill the pixmap. It returns a process object
11765 if successful. We do not record_unwind_protect here because
11766 other places in redisplay like calling window scroll functions
11767 don't either. Let the Lisp loader use `unwind-protect' instead. */
11768 GCPRO2 (window_and_pixmap_id, pixel_colors);
11769
11770 sprintf (buffer, "%lu %lu",
11771 (unsigned long) FRAME_W32_WINDOW (f),
11772 (unsigned long) img->pixmap);
11773 window_and_pixmap_id = build_string (buffer);
11774
11775 sprintf (buffer, "%lu %lu",
11776 FRAME_FOREGROUND_PIXEL (f),
11777 FRAME_BACKGROUND_PIXEL (f));
11778 pixel_colors = build_string (buffer);
11779
11780 XSETFRAME (frame, f);
11781 loader = image_spec_value (img->spec, QCloader, NULL);
11782 if (NILP (loader))
11783 loader = intern ("gs-load-image");
11784
11785 img->data.lisp_val = call6 (loader, frame, img->spec,
11786 make_number (img->width),
11787 make_number (img->height),
11788 window_and_pixmap_id,
11789 pixel_colors);
11790 UNGCPRO;
11791 return PROCESSP (img->data.lisp_val);
11792}
11793
11794
11795/* Kill the Ghostscript process that was started to fill PIXMAP on
11796 frame F. Called from XTread_socket when receiving an event
11797 telling Emacs that Ghostscript has finished drawing. */
11798
11799void
11800x_kill_gs_process (pixmap, f)
11801 Pixmap pixmap;
11802 struct frame *f;
11803{
11804 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11805 int class, i;
11806 struct image *img;
11807
11808 /* Find the image containing PIXMAP. */
11809 for (i = 0; i < c->used; ++i)
11810 if (c->images[i]->pixmap == pixmap)
11811 break;
11812
11813 /* Kill the GS process. We should have found PIXMAP in the image
11814 cache and its image should contain a process object. */
11815 xassert (i < c->used);
11816 img = c->images[i];
11817 xassert (PROCESSP (img->data.lisp_val));
11818 Fkill_process (img->data.lisp_val, Qnil);
11819 img->data.lisp_val = Qnil;
11820
11821 /* On displays with a mutable colormap, figure out the colors
11822 allocated for the image by looking at the pixels of an XImage for
11823 img->pixmap. */
11824 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11825 if (class != StaticColor && class != StaticGray && class != TrueColor)
11826 {
11827 XImage *ximg;
11828
11829 BLOCK_INPUT;
11830
11831 /* Try to get an XImage for img->pixmep. */
11832 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11833 0, 0, img->width, img->height, ~0, ZPixmap);
11834 if (ximg)
11835 {
11836 int x, y;
11837
11838 /* Initialize the color table. */
11839 init_color_table ();
11840
11841 /* For each pixel of the image, look its color up in the
11842 color table. After having done so, the color table will
11843 contain an entry for each color used by the image. */
11844 for (y = 0; y < img->height; ++y)
11845 for (x = 0; x < img->width; ++x)
11846 {
11847 unsigned long pixel = XGetPixel (ximg, x, y);
11848 lookup_pixel_color (f, pixel);
11849 }
11850
11851 /* Record colors in the image. Free color table and XImage. */
11852 img->colors = colors_in_color_table (&img->ncolors);
11853 free_color_table ();
11854 XDestroyImage (ximg);
11855
11856#if 0 /* This doesn't seem to be the case. If we free the colors
11857 here, we get a BadAccess later in x_clear_image when
11858 freeing the colors. */
11859 /* We have allocated colors once, but Ghostscript has also
11860 allocated colors on behalf of us. So, to get the
11861 reference counts right, free them once. */
11862 if (img->ncolors)
11863 {
11864 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11865 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11866 img->colors, img->ncolors, 0);
11867 }
11868#endif
11869 }
11870 else
11871 image_error ("Cannot get X image of `%s'; colors will not be freed",
11872 img->spec, Qnil);
11873
11874 UNBLOCK_INPUT;
11875 }
11876}
11877
11878#endif /* HAVE_GHOSTSCRIPT */
11879
11880\f
11881/***********************************************************************
11882 Window properties
11883 ***********************************************************************/
11884
11885DEFUN ("x-change-window-property", Fx_change_window_property,
11886 Sx_change_window_property, 2, 3, 0,
11887 "Change window property PROP to VALUE on the X window of FRAME.\n\
11888PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
11889selected frame. Value is VALUE.")
11890 (prop, value, frame)
11891 Lisp_Object frame, prop, value;
11892{
767b1ff0 11893#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
11894 struct frame *f = check_x_frame (frame);
11895 Atom prop_atom;
11896
11897 CHECK_STRING (prop, 1);
11898 CHECK_STRING (value, 2);
11899
11900 BLOCK_INPUT;
11901 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11902 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11903 prop_atom, XA_STRING, 8, PropModeReplace,
11904 XSTRING (value)->data, XSTRING (value)->size);
11905
11906 /* Make sure the property is set when we return. */
11907 XFlush (FRAME_W32_DISPLAY (f));
11908 UNBLOCK_INPUT;
11909
767b1ff0 11910#endif /* TODO */
6fc2811b
JR
11911
11912 return value;
11913}
11914
11915
11916DEFUN ("x-delete-window-property", Fx_delete_window_property,
11917 Sx_delete_window_property, 1, 2, 0,
11918 "Remove window property PROP from X window of FRAME.\n\
11919FRAME nil or omitted means use the selected frame. Value is PROP.")
11920 (prop, frame)
11921 Lisp_Object prop, frame;
11922{
767b1ff0 11923#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
11924
11925 struct frame *f = check_x_frame (frame);
11926 Atom prop_atom;
11927
11928 CHECK_STRING (prop, 1);
11929 BLOCK_INPUT;
11930 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11931 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
11932
11933 /* Make sure the property is removed when we return. */
11934 XFlush (FRAME_W32_DISPLAY (f));
11935 UNBLOCK_INPUT;
767b1ff0 11936#endif /* TODO */
6fc2811b
JR
11937
11938 return prop;
11939}
11940
11941
11942DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
11943 1, 2, 0,
11944 "Value is the value of window property PROP on FRAME.\n\
11945If FRAME is nil or omitted, use the selected frame. Value is nil\n\
11946if FRAME hasn't a property with name PROP or if PROP has no string\n\
11947value.")
11948 (prop, frame)
11949 Lisp_Object prop, frame;
11950{
767b1ff0 11951#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
11952
11953 struct frame *f = check_x_frame (frame);
11954 Atom prop_atom;
11955 int rc;
11956 Lisp_Object prop_value = Qnil;
11957 char *tmp_data = NULL;
11958 Atom actual_type;
11959 int actual_format;
11960 unsigned long actual_size, bytes_remaining;
11961
11962 CHECK_STRING (prop, 1);
11963 BLOCK_INPUT;
11964 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11965 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11966 prop_atom, 0, 0, False, XA_STRING,
11967 &actual_type, &actual_format, &actual_size,
11968 &bytes_remaining, (unsigned char **) &tmp_data);
11969 if (rc == Success)
11970 {
11971 int size = bytes_remaining;
11972
11973 XFree (tmp_data);
11974 tmp_data = NULL;
11975
11976 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11977 prop_atom, 0, bytes_remaining,
11978 False, XA_STRING,
11979 &actual_type, &actual_format,
11980 &actual_size, &bytes_remaining,
11981 (unsigned char **) &tmp_data);
11982 if (rc == Success)
11983 prop_value = make_string (tmp_data, size);
11984
11985 XFree (tmp_data);
11986 }
11987
11988 UNBLOCK_INPUT;
11989
11990 return prop_value;
11991
767b1ff0 11992#endif /* TODO */
6fc2811b
JR
11993 return Qnil;
11994}
11995
11996
11997\f
11998/***********************************************************************
11999 Busy cursor
12000 ***********************************************************************/
12001
f79e6790
JR
12002/* If non-null, an asynchronous timer that, when it expires, displays
12003 a busy cursor on all frames. */
6fc2811b 12004
f79e6790 12005static struct atimer *busy_cursor_atimer;
6fc2811b 12006
f79e6790 12007/* Non-zero means a busy cursor is currently shown. */
6fc2811b 12008
f79e6790 12009static int busy_cursor_shown_p;
6fc2811b 12010
f79e6790 12011/* Number of seconds to wait before displaying a busy cursor. */
6fc2811b 12012
f79e6790 12013static Lisp_Object Vbusy_cursor_delay;
6fc2811b 12014
f79e6790
JR
12015/* Default number of seconds to wait before displaying a busy
12016 cursor. */
12017
12018#define DEFAULT_BUSY_CURSOR_DELAY 1
12019
12020/* Function prototypes. */
12021
12022static void show_busy_cursor P_ ((struct atimer *));
12023static void hide_busy_cursor P_ ((void));
12024
12025
12026/* Cancel a currently active busy-cursor timer, and start a new one. */
12027
12028void
12029start_busy_cursor ()
12030{
767b1ff0 12031#if 0 /* TODO: cursor shape changes. */
f79e6790 12032 EMACS_TIME delay;
dfff8a69 12033 int secs, usecs = 0;
f79e6790
JR
12034
12035 cancel_busy_cursor ();
12036
12037 if (INTEGERP (Vbusy_cursor_delay)
12038 && XINT (Vbusy_cursor_delay) > 0)
12039 secs = XFASTINT (Vbusy_cursor_delay);
dfff8a69
JR
12040 else if (FLOATP (Vbusy_cursor_delay)
12041 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
12042 {
12043 Lisp_Object tem;
12044 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
12045 secs = XFASTINT (tem);
12046 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
12047 }
f79e6790
JR
12048 else
12049 secs = DEFAULT_BUSY_CURSOR_DELAY;
12050
dfff8a69 12051 EMACS_SET_SECS_USECS (delay, secs, usecs);
f79e6790
JR
12052 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
12053 show_busy_cursor, NULL);
12054#endif
12055}
12056
12057
12058/* Cancel the busy cursor timer if active, hide a busy cursor if
12059 shown. */
12060
12061void
12062cancel_busy_cursor ()
12063{
12064 if (busy_cursor_atimer)
dfff8a69
JR
12065 {
12066 cancel_atimer (busy_cursor_atimer);
12067 busy_cursor_atimer = NULL;
12068 }
12069
f79e6790
JR
12070 if (busy_cursor_shown_p)
12071 hide_busy_cursor ();
12072}
12073
12074
12075/* Timer function of busy_cursor_atimer. TIMER is equal to
12076 busy_cursor_atimer.
12077
12078 Display a busy cursor on all frames by mapping the frames'
12079 busy_window. Set the busy_p flag in the frames' output_data.x
12080 structure to indicate that a busy cursor is shown on the
12081 frames. */
12082
12083static void
12084show_busy_cursor (timer)
12085 struct atimer *timer;
6fc2811b 12086{
767b1ff0 12087#if 0 /* TODO: cursor shape changes. */
f79e6790
JR
12088 /* The timer implementation will cancel this timer automatically
12089 after this function has run. Set busy_cursor_atimer to null
12090 so that we know the timer doesn't have to be canceled. */
12091 busy_cursor_atimer = NULL;
12092
12093 if (!busy_cursor_shown_p)
6fc2811b
JR
12094 {
12095 Lisp_Object rest, frame;
f79e6790
JR
12096
12097 BLOCK_INPUT;
12098
6fc2811b
JR
12099 FOR_EACH_FRAME (rest, frame)
12100 if (FRAME_X_P (XFRAME (frame)))
12101 {
12102 struct frame *f = XFRAME (frame);
f79e6790 12103
6fc2811b 12104 f->output_data.w32->busy_p = 1;
f79e6790 12105
6fc2811b
JR
12106 if (!f->output_data.w32->busy_window)
12107 {
12108 unsigned long mask = CWCursor;
12109 XSetWindowAttributes attrs;
f79e6790 12110
6fc2811b 12111 attrs.cursor = f->output_data.w32->busy_cursor;
f79e6790 12112
6fc2811b 12113 f->output_data.w32->busy_window
f79e6790 12114 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
12115 FRAME_OUTER_WINDOW (f),
12116 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
12117 InputOnly,
12118 CopyFromParent,
6fc2811b
JR
12119 mask, &attrs);
12120 }
f79e6790
JR
12121
12122 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
12123 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 12124 }
6fc2811b 12125
f79e6790
JR
12126 busy_cursor_shown_p = 1;
12127 UNBLOCK_INPUT;
12128 }
12129#endif
6fc2811b
JR
12130}
12131
12132
f79e6790 12133/* Hide the busy cursor on all frames, if it is currently shown. */
6fc2811b 12134
f79e6790
JR
12135static void
12136hide_busy_cursor ()
12137{
767b1ff0 12138#if 0 /* TODO: cursor shape changes. */
f79e6790 12139 if (busy_cursor_shown_p)
6fc2811b 12140 {
f79e6790
JR
12141 Lisp_Object rest, frame;
12142
12143 BLOCK_INPUT;
12144 FOR_EACH_FRAME (rest, frame)
6fc2811b 12145 {
f79e6790
JR
12146 struct frame *f = XFRAME (frame);
12147
12148 if (FRAME_X_P (f)
12149 /* Watch out for newly created frames. */
12150 && f->output_data.x->busy_window)
12151 {
12152 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
12153 /* Sync here because XTread_socket looks at the busy_p flag
12154 that is reset to zero below. */
12155 XSync (FRAME_X_DISPLAY (f), False);
12156 f->output_data.x->busy_p = 0;
12157 }
6fc2811b 12158 }
6fc2811b 12159
f79e6790
JR
12160 busy_cursor_shown_p = 0;
12161 UNBLOCK_INPUT;
12162 }
12163#endif
6fc2811b
JR
12164}
12165
12166
12167\f
12168/***********************************************************************
12169 Tool tips
12170 ***********************************************************************/
12171
12172static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
12173 Lisp_Object));
12174
12175/* The frame of a currently visible tooltip, or null. */
12176
12177struct frame *tip_frame;
12178
12179/* If non-nil, a timer started that hides the last tooltip when it
12180 fires. */
12181
12182Lisp_Object tip_timer;
12183Window tip_window;
12184
12185/* Create a frame for a tooltip on the display described by DPYINFO.
12186 PARMS is a list of frame parameters. Value is the frame. */
12187
12188static Lisp_Object
12189x_create_tip_frame (dpyinfo, parms)
12190 struct w32_display_info *dpyinfo;
12191 Lisp_Object parms;
12192{
767b1ff0 12193#if 0 /* TODO : w32 version */
6fc2811b
JR
12194 struct frame *f;
12195 Lisp_Object frame, tem;
12196 Lisp_Object name;
12197 long window_prompting = 0;
12198 int width, height;
12199 int count = specpdl_ptr - specpdl;
12200 struct gcpro gcpro1, gcpro2, gcpro3;
12201 struct kboard *kb;
12202
12203 check_x ();
12204
12205 /* Use this general default value to start with until we know if
12206 this frame has a specified name. */
12207 Vx_resource_name = Vinvocation_name;
12208
12209#ifdef MULTI_KBOARD
12210 kb = dpyinfo->kboard;
12211#else
12212 kb = &the_only_kboard;
12213#endif
12214
12215 /* Get the name of the frame to use for resource lookup. */
12216 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
12217 if (!STRINGP (name)
12218 && !EQ (name, Qunbound)
12219 && !NILP (name))
12220 error ("Invalid frame name--not a string or nil");
12221 Vx_resource_name = name;
12222
12223 frame = Qnil;
12224 GCPRO3 (parms, name, frame);
12225 tip_frame = f = make_frame (1);
12226 XSETFRAME (frame, f);
12227 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
12228
d88c567c 12229 f->output_method = output_w32;
6fc2811b
JR
12230 f->output_data.w32 =
12231 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12232 bzero (f->output_data.w32, sizeof (struct w32_output));
12233#if 0
12234 f->output_data.w32->icon_bitmap = -1;
12235#endif
12236 f->output_data.w32->fontset = -1;
12237 f->icon_name = Qnil;
12238
12239#ifdef MULTI_KBOARD
12240 FRAME_KBOARD (f) = kb;
12241#endif
12242 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12243 f->output_data.w32->explicit_parent = 0;
12244
12245 /* Set the name; the functions to which we pass f expect the name to
12246 be set. */
12247 if (EQ (name, Qunbound) || NILP (name))
12248 {
12249 f->name = build_string (dpyinfo->x_id_name);
12250 f->explicit_name = 0;
12251 }
12252 else
12253 {
12254 f->name = name;
12255 f->explicit_name = 1;
12256 /* use the frame's title when getting resources for this frame. */
12257 specbind (Qx_resource_name, name);
12258 }
12259
6fc2811b
JR
12260 /* Extract the window parameters from the supplied values
12261 that are needed to determine window geometry. */
12262 {
12263 Lisp_Object font;
12264
12265 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12266
12267 BLOCK_INPUT;
12268 /* First, try whatever font the caller has specified. */
12269 if (STRINGP (font))
12270 {
12271 tem = Fquery_fontset (font, Qnil);
12272 if (STRINGP (tem))
12273 font = x_new_fontset (f, XSTRING (tem)->data);
12274 else
12275 font = x_new_font (f, XSTRING (font)->data);
12276 }
12277
12278 /* Try out a font which we hope has bold and italic variations. */
12279 if (!STRINGP (font))
e39649be 12280 font = x_new_font (f, "-*-courier new-normal-r-*-*-*-100-*-*-*-*-iso8859-1");
6fc2811b
JR
12281 if (!STRINGP (font))
12282 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12283 if (! STRINGP (font))
12284 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12285 if (! STRINGP (font))
12286 /* This was formerly the first thing tried, but it finds too many fonts
12287 and takes too long. */
12288 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12289 /* If those didn't work, look for something which will at least work. */
12290 if (! STRINGP (font))
12291 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12292 UNBLOCK_INPUT;
12293 if (! STRINGP (font))
12294 font = build_string ("fixed");
12295
12296 x_default_parameter (f, parms, Qfont, font,
12297 "font", "Font", RES_TYPE_STRING);
12298 }
12299
12300 x_default_parameter (f, parms, Qborder_width, make_number (2),
12301 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12302
12303 /* This defaults to 2 in order to match xterm. We recognize either
12304 internalBorderWidth or internalBorder (which is what xterm calls
12305 it). */
12306 if (NILP (Fassq (Qinternal_border_width, parms)))
12307 {
12308 Lisp_Object value;
12309
12310 value = w32_get_arg (parms, Qinternal_border_width,
12311 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12312 if (! EQ (value, Qunbound))
12313 parms = Fcons (Fcons (Qinternal_border_width, value),
12314 parms);
12315 }
12316
12317 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12318 "internalBorderWidth", "internalBorderWidth",
12319 RES_TYPE_NUMBER);
12320
12321 /* Also do the stuff which must be set before the window exists. */
12322 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12323 "foreground", "Foreground", RES_TYPE_STRING);
12324 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12325 "background", "Background", RES_TYPE_STRING);
12326 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12327 "pointerColor", "Foreground", RES_TYPE_STRING);
12328 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12329 "cursorColor", "Foreground", RES_TYPE_STRING);
12330 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12331 "borderColor", "BorderColor", RES_TYPE_STRING);
12332
12333 /* Init faces before x_default_parameter is called for scroll-bar
12334 parameters because that function calls x_set_scroll_bar_width,
12335 which calls change_frame_size, which calls Fset_window_buffer,
12336 which runs hooks, which call Fvertical_motion. At the end, we
12337 end up in init_iterator with a null face cache, which should not
12338 happen. */
12339 init_frame_faces (f);
12340
12341 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12342 window_prompting = x_figure_window_size (f, parms);
12343
12344 if (window_prompting & XNegative)
12345 {
12346 if (window_prompting & YNegative)
12347 f->output_data.w32->win_gravity = SouthEastGravity;
12348 else
12349 f->output_data.w32->win_gravity = NorthEastGravity;
12350 }
12351 else
12352 {
12353 if (window_prompting & YNegative)
12354 f->output_data.w32->win_gravity = SouthWestGravity;
12355 else
12356 f->output_data.w32->win_gravity = NorthWestGravity;
12357 }
12358
12359 f->output_data.w32->size_hint_flags = window_prompting;
12360 {
12361 XSetWindowAttributes attrs;
12362 unsigned long mask;
12363
12364 BLOCK_INPUT;
12365 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12366 /* Window managers looks at the override-redirect flag to
12367 determine whether or net to give windows a decoration (Xlib
12368 3.2.8). */
12369 attrs.override_redirect = True;
12370 attrs.save_under = True;
12371 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12372 /* Arrange for getting MapNotify and UnmapNotify events. */
12373 attrs.event_mask = StructureNotifyMask;
12374 tip_window
12375 = FRAME_W32_WINDOW (f)
12376 = XCreateWindow (FRAME_W32_DISPLAY (f),
12377 FRAME_W32_DISPLAY_INFO (f)->root_window,
12378 /* x, y, width, height */
12379 0, 0, 1, 1,
12380 /* Border. */
12381 1,
12382 CopyFromParent, InputOutput, CopyFromParent,
12383 mask, &attrs);
12384 UNBLOCK_INPUT;
12385 }
12386
12387 x_make_gc (f);
12388
12389 x_default_parameter (f, parms, Qauto_raise, Qnil,
12390 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12391 x_default_parameter (f, parms, Qauto_lower, Qnil,
12392 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12393 x_default_parameter (f, parms, Qcursor_type, Qbox,
12394 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12395
12396 /* Dimensions, especially f->height, must be done via change_frame_size.
12397 Change will not be effected unless different from the current
12398 f->height. */
12399 width = f->width;
12400 height = f->height;
12401 f->height = 0;
12402 SET_FRAME_WIDTH (f, 0);
12403 change_frame_size (f, height, width, 1, 0, 0);
12404
12405 f->no_split = 1;
12406
12407 UNGCPRO;
12408
12409 /* It is now ok to make the frame official even if we get an error
12410 below. And the frame needs to be on Vframe_list or making it
12411 visible won't work. */
12412 Vframe_list = Fcons (frame, Vframe_list);
12413
12414 /* Now that the frame is official, it counts as a reference to
12415 its display. */
12416 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 12417
6fc2811b 12418 return unbind_to (count, frame);
767b1ff0 12419#endif /* TODO */
6fc2811b 12420 return Qnil;
ee78dc32
GV
12421}
12422
767b1ff0 12423#ifdef TODO /* Tooltip support not complete. */
71eab8d1 12424DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
6fc2811b 12425 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
71eab8d1
AI
12426A tooltip window is a small X window displaying a string.\n\
12427\n\
6fc2811b 12428FRAME nil or omitted means use the selected frame.\n\
71eab8d1 12429\n\
6fc2811b
JR
12430PARMS is an optional list of frame parameters which can be\n\
12431used to change the tooltip's appearance.\n\
71eab8d1 12432\n\
6fc2811b 12433Automatically hide the tooltip after TIMEOUT seconds.\n\
71eab8d1
AI
12434TIMEOUT nil means use the default timeout of 5 seconds.\n\
12435\n\
12436If the list of frame parameters PARAMS contains a `left' parameters,\n\
12437the tooltip is displayed at that x-position. Otherwise it is\n\
12438displayed at the mouse position, with offset DX added (default is 5 if\n\
12439DX isn't specified). Likewise for the y-position; if a `top' frame\n\
12440parameter is specified, it determines the y-position of the tooltip\n\
12441window, otherwise it is displayed at the mouse position, with offset\n\
12442DY added (default is -5).")
12443 (string, frame, parms, timeout, dx, dy)
12444 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 12445{
6fc2811b
JR
12446 struct frame *f;
12447 struct window *w;
12448 Window root, child;
71eab8d1 12449 Lisp_Object buffer, top, left;
6fc2811b
JR
12450 struct buffer *old_buffer;
12451 struct text_pos pos;
12452 int i, width, height;
12453 int root_x, root_y, win_x, win_y;
12454 unsigned pmask;
12455 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12456 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12457 int count = specpdl_ptr - specpdl;
12458
12459 specbind (Qinhibit_redisplay, Qt);
ee78dc32 12460
dfff8a69 12461 GCPRO4 (string, parms, frame, timeout);
ee78dc32 12462
6fc2811b
JR
12463 CHECK_STRING (string, 0);
12464 f = check_x_frame (frame);
12465 if (NILP (timeout))
12466 timeout = make_number (5);
12467 else
12468 CHECK_NATNUM (timeout, 2);
ee78dc32 12469
71eab8d1
AI
12470 if (NILP (dx))
12471 dx = make_number (5);
12472 else
12473 CHECK_NUMBER (dx, 5);
12474
12475 if (NILP (dy))
12476 dy = make_number (-5);
12477 else
12478 CHECK_NUMBER (dy, 6);
12479
6fc2811b
JR
12480 /* Hide a previous tip, if any. */
12481 Fx_hide_tip ();
ee78dc32 12482
6fc2811b
JR
12483 /* Add default values to frame parameters. */
12484 if (NILP (Fassq (Qname, parms)))
12485 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12486 if (NILP (Fassq (Qinternal_border_width, parms)))
12487 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12488 if (NILP (Fassq (Qborder_width, parms)))
12489 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12490 if (NILP (Fassq (Qborder_color, parms)))
12491 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12492 if (NILP (Fassq (Qbackground_color, parms)))
12493 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12494 parms);
12495
12496 /* Create a frame for the tooltip, and record it in the global
12497 variable tip_frame. */
12498 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
12499 tip_frame = f = XFRAME (frame);
12500
12501 /* Set up the frame's root window. Currently we use a size of 80
12502 columns x 40 lines. If someone wants to show a larger tip, he
12503 will loose. I don't think this is a realistic case. */
12504 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12505 w->left = w->top = make_number (0);
12506 w->width = 80;
12507 w->height = 40;
12508 adjust_glyphs (f);
12509 w->pseudo_window_p = 1;
12510
12511 /* Display the tooltip text in a temporary buffer. */
12512 buffer = Fget_buffer_create (build_string (" *tip*"));
12513 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12514 old_buffer = current_buffer;
12515 set_buffer_internal_1 (XBUFFER (buffer));
12516 Ferase_buffer ();
12517 Finsert (make_number (1), &string);
12518 clear_glyph_matrix (w->desired_matrix);
12519 clear_glyph_matrix (w->current_matrix);
12520 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12521 try_window (FRAME_ROOT_WINDOW (f), pos);
12522
12523 /* Compute width and height of the tooltip. */
12524 width = height = 0;
12525 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 12526 {
6fc2811b
JR
12527 struct glyph_row *row = &w->desired_matrix->rows[i];
12528 struct glyph *last;
12529 int row_width;
12530
12531 /* Stop at the first empty row at the end. */
12532 if (!row->enabled_p || !row->displays_text_p)
12533 break;
12534
12535 /* Let the row go over the full width of the frame. */
12536 row->full_width_p = 1;
12537
12538 /* There's a glyph at the end of rows that is use to place
12539 the cursor there. Don't include the width of this glyph. */
12540 if (row->used[TEXT_AREA])
12541 {
12542 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12543 row_width = row->pixel_width - last->pixel_width;
12544 }
12545 else
12546 row_width = row->pixel_width;
12547
12548 height += row->height;
12549 width = max (width, row_width);
ee78dc32
GV
12550 }
12551
6fc2811b
JR
12552 /* Add the frame's internal border to the width and height the X
12553 window should have. */
12554 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12555 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 12556
71eab8d1
AI
12557 /* User-specified position? */
12558 left = Fcdr (Fassq (Qleft, parms));
12559 top = Fcdr (Fassq (Qtop, parms));
12560
6fc2811b
JR
12561 /* Move the tooltip window where the mouse pointer is. Resize and
12562 show it. */
767b1ff0 12563#if 0 /* TODO : W32 specifics */
6fc2811b 12564 BLOCK_INPUT;
71eab8d1 12565 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
6fc2811b 12566 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
71eab8d1
AI
12567 UNBLOCK_INPUT;
12568
12569 root_x += XINT (dx);
12570 root_y += XINT (dy);
12571
12572 if (INTEGERP (left))
12573 root_x = XINT (left);
12574 if (INTEGERP (top))
12575 root_y = XINT (top);
12576
12577 BLOCK_INPUT;
12578 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12579 root_x, root_y - height, width, height);
12580 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
6fc2811b 12581 UNBLOCK_INPUT;
767b1ff0 12582#endif /* TODO */
ee78dc32 12583
6fc2811b
JR
12584 /* Draw into the window. */
12585 w->must_be_updated_p = 1;
12586 update_single_window (w, 1);
ee78dc32 12587
6fc2811b
JR
12588 /* Restore original current buffer. */
12589 set_buffer_internal_1 (old_buffer);
12590 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 12591
6fc2811b
JR
12592 /* Let the tip disappear after timeout seconds. */
12593 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12594 intern ("x-hide-tip"));
ee78dc32 12595
dfff8a69 12596 UNGCPRO;
6fc2811b 12597 return unbind_to (count, Qnil);
ee78dc32
GV
12598}
12599
ee78dc32 12600
6fc2811b
JR
12601DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12602 "Hide the current tooltip window, if there is any.\n\
12603Value is t is tooltip was open, nil otherwise.")
12604 ()
12605{
12606 int count = specpdl_ptr - specpdl;
12607 int deleted_p = 0;
12608
12609 specbind (Qinhibit_redisplay, Qt);
12610
12611 if (!NILP (tip_timer))
12612 {
12613 call1 (intern ("cancel-timer"), tip_timer);
12614 tip_timer = Qnil;
12615 }
ee78dc32 12616
6fc2811b
JR
12617 if (tip_frame)
12618 {
12619 Lisp_Object frame;
12620
12621 XSETFRAME (frame, tip_frame);
12622 Fdelete_frame (frame, Qt);
12623 tip_frame = NULL;
12624 deleted_p = 1;
12625 }
1edf84e7 12626
6fc2811b
JR
12627 return unbind_to (count, deleted_p ? Qt : Qnil);
12628}
767b1ff0 12629#endif
5ac45f98 12630
5ac45f98 12631
6fc2811b
JR
12632\f
12633/***********************************************************************
12634 File selection dialog
12635 ***********************************************************************/
12636
12637extern Lisp_Object Qfile_name_history;
12638
12639DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12640 "Read file name, prompting with PROMPT in directory DIR.\n\
12641Use a file selection dialog.\n\
12642Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12643specified. Don't let the user enter a file name in the file\n\
12644selection dialog's entry field, if MUSTMATCH is non-nil.")
12645 (prompt, dir, default_filename, mustmatch)
12646 Lisp_Object prompt, dir, default_filename, mustmatch;
12647{
12648 struct frame *f = SELECTED_FRAME ();
12649 Lisp_Object file = Qnil;
12650 int count = specpdl_ptr - specpdl;
12651 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12652 char filename[MAX_PATH + 1];
12653 char init_dir[MAX_PATH + 1];
12654 int use_dialog_p = 1;
12655
12656 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12657 CHECK_STRING (prompt, 0);
12658 CHECK_STRING (dir, 1);
12659
12660 /* Create the dialog with PROMPT as title, using DIR as initial
12661 directory and using "*" as pattern. */
12662 dir = Fexpand_file_name (dir, Qnil);
12663 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12664 init_dir[MAX_PATH] = '\0';
12665 unixtodos_filename (init_dir);
12666
12667 if (STRINGP (default_filename))
12668 {
12669 char *file_name_only;
12670 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 12671
6fc2811b 12672 unixtodos_filename (full_path_name);
5ac45f98 12673
6fc2811b
JR
12674 file_name_only = strrchr (full_path_name, '\\');
12675 if (!file_name_only)
12676 file_name_only = full_path_name;
12677 else
12678 {
12679 file_name_only++;
5ac45f98 12680
6fc2811b
JR
12681 /* If default_file_name is a directory, don't use the open
12682 file dialog, as it does not support selecting
12683 directories. */
12684 if (!(*file_name_only))
12685 use_dialog_p = 0;
12686 }
ee78dc32 12687
6fc2811b
JR
12688 strncpy (filename, file_name_only, MAX_PATH);
12689 filename[MAX_PATH] = '\0';
12690 }
ee78dc32 12691 else
6fc2811b 12692 filename[0] = '\0';
ee78dc32 12693
6fc2811b
JR
12694 if (use_dialog_p)
12695 {
12696 OPENFILENAME file_details;
12697 char *filename_file;
5ac45f98 12698
6fc2811b
JR
12699 /* Prevent redisplay. */
12700 specbind (Qinhibit_redisplay, Qt);
12701 BLOCK_INPUT;
ee78dc32 12702
6fc2811b
JR
12703 bzero (&file_details, sizeof (file_details));
12704 file_details.lStructSize = sizeof (file_details);
12705 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12706 file_details.lpstrFile = filename;
12707 file_details.nMaxFile = sizeof (filename);
12708 file_details.lpstrInitialDir = init_dir;
12709 file_details.lpstrTitle = XSTRING (prompt)->data;
12710 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 12711
6fc2811b
JR
12712 if (!NILP (mustmatch))
12713 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 12714
6fc2811b
JR
12715 if (GetOpenFileName (&file_details))
12716 {
12717 dostounix_filename (filename);
12718 file = build_string (filename);
12719 }
ee78dc32 12720 else
6fc2811b
JR
12721 file = Qnil;
12722
12723 UNBLOCK_INPUT;
12724 file = unbind_to (count, file);
ee78dc32 12725 }
6fc2811b
JR
12726 /* Open File dialog will not allow folders to be selected, so resort
12727 to minibuffer completing reads for directories. */
12728 else
12729 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12730 dir, mustmatch, dir, Qfile_name_history,
12731 default_filename, Qnil);
ee78dc32 12732
6fc2811b 12733 UNGCPRO;
1edf84e7 12734
6fc2811b
JR
12735 /* Make "Cancel" equivalent to C-g. */
12736 if (NILP (file))
12737 Fsignal (Qquit, Qnil);
ee78dc32 12738
dfff8a69 12739 return unbind_to (count, file);
6fc2811b 12740}
ee78dc32 12741
ee78dc32 12742
6fc2811b
JR
12743\f
12744/***********************************************************************
12745 Tests
12746 ***********************************************************************/
ee78dc32 12747
6fc2811b 12748#if GLYPH_DEBUG
ee78dc32 12749
6fc2811b
JR
12750DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12751 "Value is non-nil if SPEC is a valid image specification.")
12752 (spec)
12753 Lisp_Object spec;
12754{
12755 return valid_image_p (spec) ? Qt : Qnil;
ee78dc32
GV
12756}
12757
ee78dc32 12758
6fc2811b
JR
12759DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12760 (spec)
12761 Lisp_Object spec;
12762{
12763 int id = -1;
12764
12765 if (valid_image_p (spec))
12766 id = lookup_image (SELECTED_FRAME (), spec);
ee78dc32 12767
6fc2811b
JR
12768 debug_print (spec);
12769 return make_number (id);
ee78dc32
GV
12770}
12771
6fc2811b 12772#endif /* GLYPH_DEBUG != 0 */
ee78dc32 12773
ee78dc32
GV
12774
12775\f
6fc2811b
JR
12776/***********************************************************************
12777 w32 specialized functions
12778 ***********************************************************************/
ee78dc32 12779
fbd6baed
GV
12780DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12781 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
ee78dc32
GV
12782 (frame)
12783 Lisp_Object frame;
12784{
12785 FRAME_PTR f = check_x_frame (frame);
12786 CHOOSEFONT cf;
12787 LOGFONT lf;
f46e6225
GV
12788 TEXTMETRIC tm;
12789 HDC hdc;
12790 HANDLE oldobj;
ee78dc32
GV
12791 char buf[100];
12792
12793 bzero (&cf, sizeof (cf));
f46e6225 12794 bzero (&lf, sizeof (lf));
ee78dc32
GV
12795
12796 cf.lStructSize = sizeof (cf);
fbd6baed 12797 cf.hwndOwner = FRAME_W32_WINDOW (f);
6fc2811b 12798 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
ee78dc32
GV
12799 cf.lpLogFont = &lf;
12800
f46e6225
GV
12801 /* Initialize as much of the font details as we can from the current
12802 default font. */
12803 hdc = GetDC (FRAME_W32_WINDOW (f));
12804 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12805 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12806 if (GetTextMetrics (hdc, &tm))
12807 {
12808 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12809 lf.lfWeight = tm.tmWeight;
12810 lf.lfItalic = tm.tmItalic;
12811 lf.lfUnderline = tm.tmUnderlined;
12812 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
12813 lf.lfCharSet = tm.tmCharSet;
12814 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12815 }
12816 SelectObject (hdc, oldobj);
6fc2811b 12817 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 12818
767b1ff0 12819 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 12820 return Qnil;
ee78dc32
GV
12821
12822 return build_string (buf);
12823}
12824
1edf84e7
GV
12825DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
12826 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
12827Some useful values for command are 0xf030 to maximise frame (0xf020\n\
12828to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
12829to activate the menubar for keyboard access. 0xf140 activates the\n\
12830screen saver if defined.\n\
12831\n\
12832If optional parameter FRAME is not specified, use selected frame.")
12833 (command, frame)
12834 Lisp_Object command, frame;
12835{
12836 WPARAM code;
12837 FRAME_PTR f = check_x_frame (frame);
12838
12839 CHECK_NUMBER (command, 0);
12840
ce6059da 12841 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
12842
12843 return Qnil;
12844}
12845
55dcfc15
AI
12846DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
12847 "Get Windows to perform OPERATION on DOCUMENT.\n\
12848This is a wrapper around the ShellExecute system function, which\n\
12849invokes the application registered to handle OPERATION for DOCUMENT.\n\
6fc2811b
JR
12850OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
12851nil for the default action), and DOCUMENT is typically the name of a\n\
12852document file or URL, but can also be a program executable to run or\n\
12853a directory to open in the Windows Explorer.\n\
55dcfc15 12854\n\
6fc2811b
JR
12855If DOCUMENT is a program executable, PARAMETERS can be a string\n\
12856containing command line parameters, but otherwise should be nil.\n\
55dcfc15
AI
12857\n\
12858SHOW-FLAG can be used to control whether the invoked application is hidden\n\
6fc2811b 12859or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
55dcfc15
AI
12860otherwise it is an integer representing a ShowWindow flag:\n\
12861\n\
12862 0 - start hidden\n\
12863 1 - start normally\n\
12864 3 - start maximized\n\
12865 6 - start minimized")
12866 (operation, document, parameters, show_flag)
12867 Lisp_Object operation, document, parameters, show_flag;
12868{
12869 Lisp_Object current_dir;
12870
55dcfc15
AI
12871 CHECK_STRING (document, 0);
12872
12873 /* Encode filename and current directory. */
12874 current_dir = ENCODE_FILE (current_buffer->directory);
12875 document = ENCODE_FILE (document);
12876 if ((int) ShellExecute (NULL,
6fc2811b
JR
12877 (STRINGP (operation) ?
12878 XSTRING (operation)->data : NULL),
55dcfc15
AI
12879 XSTRING (document)->data,
12880 (STRINGP (parameters) ?
12881 XSTRING (parameters)->data : NULL),
12882 XSTRING (current_dir)->data,
12883 (INTEGERP (show_flag) ?
12884 XINT (show_flag) : SW_SHOWDEFAULT))
12885 > 32)
12886 return Qt;
12887 error ("ShellExecute failed");
12888}
12889
ccc2d29c
GV
12890/* Lookup virtual keycode from string representing the name of a
12891 non-ascii keystroke into the corresponding virtual key, using
12892 lispy_function_keys. */
12893static int
12894lookup_vk_code (char *key)
12895{
12896 int i;
12897
12898 for (i = 0; i < 256; i++)
12899 if (lispy_function_keys[i] != 0
12900 && strcmp (lispy_function_keys[i], key) == 0)
12901 return i;
12902
12903 return -1;
12904}
12905
12906/* Convert a one-element vector style key sequence to a hot key
12907 definition. */
12908static int
12909w32_parse_hot_key (key)
12910 Lisp_Object key;
12911{
12912 /* Copied from Fdefine_key and store_in_keymap. */
12913 register Lisp_Object c;
12914 int vk_code;
12915 int lisp_modifiers;
12916 int w32_modifiers;
12917 struct gcpro gcpro1;
12918
12919 CHECK_VECTOR (key, 0);
12920
12921 if (XFASTINT (Flength (key)) != 1)
12922 return Qnil;
12923
12924 GCPRO1 (key);
12925
12926 c = Faref (key, make_number (0));
12927
12928 if (CONSP (c) && lucid_event_type_list_p (c))
12929 c = Fevent_convert_list (c);
12930
12931 UNGCPRO;
12932
12933 if (! INTEGERP (c) && ! SYMBOLP (c))
12934 error ("Key definition is invalid");
12935
12936 /* Work out the base key and the modifiers. */
12937 if (SYMBOLP (c))
12938 {
12939 c = parse_modifiers (c);
12940 lisp_modifiers = Fcar (Fcdr (c));
12941 c = Fcar (c);
12942 if (!SYMBOLP (c))
12943 abort ();
12944 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
12945 }
12946 else if (INTEGERP (c))
12947 {
12948 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
12949 /* Many ascii characters are their own virtual key code. */
12950 vk_code = XINT (c) & CHARACTERBITS;
12951 }
12952
12953 if (vk_code < 0 || vk_code > 255)
12954 return Qnil;
12955
12956 if ((lisp_modifiers & meta_modifier) != 0
12957 && !NILP (Vw32_alt_is_meta))
12958 lisp_modifiers |= alt_modifier;
12959
71eab8d1
AI
12960 /* Supply defs missing from mingw32. */
12961#ifndef MOD_ALT
12962#define MOD_ALT 0x0001
12963#define MOD_CONTROL 0x0002
12964#define MOD_SHIFT 0x0004
12965#define MOD_WIN 0x0008
12966#endif
12967
ccc2d29c
GV
12968 /* Convert lisp modifiers to Windows hot-key form. */
12969 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
12970 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
12971 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
12972 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
12973
12974 return HOTKEY (vk_code, w32_modifiers);
12975}
12976
12977DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
12978 "Register KEY as a hot-key combination.\n\
12979Certain key combinations like Alt-Tab are reserved for system use on\n\
12980Windows, and therefore are normally intercepted by the system. However,\n\
12981most of these key combinations can be received by registering them as\n\
12982hot-keys, overriding their special meaning.\n\
12983\n\
12984KEY must be a one element key definition in vector form that would be\n\
12985acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
12986modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
12987is always interpreted as the Windows modifier keys.\n\
12988\n\
12989The return value is the hotkey-id if registered, otherwise nil.")
12990 (key)
12991 Lisp_Object key;
12992{
12993 key = w32_parse_hot_key (key);
12994
12995 if (NILP (Fmemq (key, w32_grabbed_keys)))
12996 {
12997 /* Reuse an empty slot if possible. */
12998 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
12999
13000 /* Safe to add new key to list, even if we have focus. */
13001 if (NILP (item))
13002 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
13003 else
13004 XCAR (item) = key;
13005
13006 /* Notify input thread about new hot-key definition, so that it
13007 takes effect without needing to switch focus. */
13008 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
13009 (WPARAM) key, 0);
13010 }
13011
13012 return key;
13013}
13014
13015DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
13016 "Unregister HOTKEY as a hot-key combination.")
13017 (key)
13018 Lisp_Object key;
13019{
13020 Lisp_Object item;
13021
13022 if (!INTEGERP (key))
13023 key = w32_parse_hot_key (key);
13024
13025 item = Fmemq (key, w32_grabbed_keys);
13026
13027 if (!NILP (item))
13028 {
13029 /* Notify input thread about hot-key definition being removed, so
13030 that it takes effect without needing focus switch. */
13031 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
13032 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
13033 {
13034 MSG msg;
13035 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13036 }
13037 return Qt;
13038 }
13039 return Qnil;
13040}
13041
13042DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
13043 "Return list of registered hot-key IDs.")
13044 ()
13045{
13046 return Fcopy_sequence (w32_grabbed_keys);
13047}
13048
13049DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
13050 "Convert hot-key ID to a lisp key combination.")
13051 (hotkeyid)
13052 Lisp_Object hotkeyid;
13053{
13054 int vk_code, w32_modifiers;
13055 Lisp_Object key;
13056
13057 CHECK_NUMBER (hotkeyid, 0);
13058
13059 vk_code = HOTKEY_VK_CODE (hotkeyid);
13060 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
13061
13062 if (lispy_function_keys[vk_code])
13063 key = intern (lispy_function_keys[vk_code]);
13064 else
13065 key = make_number (vk_code);
13066
13067 key = Fcons (key, Qnil);
13068 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 13069 key = Fcons (Qshift, key);
ccc2d29c 13070 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 13071 key = Fcons (Qctrl, key);
ccc2d29c 13072 if (w32_modifiers & MOD_ALT)
3ef68e6b 13073 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 13074 if (w32_modifiers & MOD_WIN)
3ef68e6b 13075 key = Fcons (Qhyper, key);
ccc2d29c
GV
13076
13077 return key;
13078}
adcc3809
GV
13079
13080DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
13081 "Toggle the state of the lock key KEY.\n\
13082KEY can be `capslock', `kp-numlock', or `scroll'.\n\
13083If the optional parameter NEW-STATE is a number, then the state of KEY\n\
13084is set to off if the low bit of NEW-STATE is zero, otherwise on.")
13085 (key, new_state)
13086 Lisp_Object key, new_state;
13087{
13088 int vk_code;
13089 int cur_state;
13090
13091 if (EQ (key, intern ("capslock")))
13092 vk_code = VK_CAPITAL;
13093 else if (EQ (key, intern ("kp-numlock")))
13094 vk_code = VK_NUMLOCK;
13095 else if (EQ (key, intern ("scroll")))
13096 vk_code = VK_SCROLL;
13097 else
13098 return Qnil;
13099
13100 if (!dwWindowsThreadId)
13101 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
13102
13103 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
13104 (WPARAM) vk_code, (LPARAM) new_state))
13105 {
13106 MSG msg;
13107 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13108 return make_number (msg.wParam);
13109 }
13110 return Qnil;
13111}
ee78dc32 13112\f
fbd6baed 13113syms_of_w32fns ()
ee78dc32 13114{
1edf84e7
GV
13115 /* This is zero if not using MS-Windows. */
13116 w32_in_use = 0;
13117
ee78dc32
GV
13118 /* The section below is built by the lisp expression at the top of the file,
13119 just above where these variables are declared. */
13120 /*&&& init symbols here &&&*/
13121 Qauto_raise = intern ("auto-raise");
13122 staticpro (&Qauto_raise);
13123 Qauto_lower = intern ("auto-lower");
13124 staticpro (&Qauto_lower);
ee78dc32
GV
13125 Qbar = intern ("bar");
13126 staticpro (&Qbar);
13127 Qborder_color = intern ("border-color");
13128 staticpro (&Qborder_color);
13129 Qborder_width = intern ("border-width");
13130 staticpro (&Qborder_width);
13131 Qbox = intern ("box");
13132 staticpro (&Qbox);
13133 Qcursor_color = intern ("cursor-color");
13134 staticpro (&Qcursor_color);
13135 Qcursor_type = intern ("cursor-type");
13136 staticpro (&Qcursor_type);
ee78dc32
GV
13137 Qgeometry = intern ("geometry");
13138 staticpro (&Qgeometry);
13139 Qicon_left = intern ("icon-left");
13140 staticpro (&Qicon_left);
13141 Qicon_top = intern ("icon-top");
13142 staticpro (&Qicon_top);
13143 Qicon_type = intern ("icon-type");
13144 staticpro (&Qicon_type);
13145 Qicon_name = intern ("icon-name");
13146 staticpro (&Qicon_name);
13147 Qinternal_border_width = intern ("internal-border-width");
13148 staticpro (&Qinternal_border_width);
13149 Qleft = intern ("left");
13150 staticpro (&Qleft);
1026b400
RS
13151 Qright = intern ("right");
13152 staticpro (&Qright);
ee78dc32
GV
13153 Qmouse_color = intern ("mouse-color");
13154 staticpro (&Qmouse_color);
13155 Qnone = intern ("none");
13156 staticpro (&Qnone);
13157 Qparent_id = intern ("parent-id");
13158 staticpro (&Qparent_id);
13159 Qscroll_bar_width = intern ("scroll-bar-width");
13160 staticpro (&Qscroll_bar_width);
13161 Qsuppress_icon = intern ("suppress-icon");
13162 staticpro (&Qsuppress_icon);
ee78dc32
GV
13163 Qundefined_color = intern ("undefined-color");
13164 staticpro (&Qundefined_color);
13165 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
13166 staticpro (&Qvertical_scroll_bars);
13167 Qvisibility = intern ("visibility");
13168 staticpro (&Qvisibility);
13169 Qwindow_id = intern ("window-id");
13170 staticpro (&Qwindow_id);
13171 Qx_frame_parameter = intern ("x-frame-parameter");
13172 staticpro (&Qx_frame_parameter);
13173 Qx_resource_name = intern ("x-resource-name");
13174 staticpro (&Qx_resource_name);
13175 Quser_position = intern ("user-position");
13176 staticpro (&Quser_position);
13177 Quser_size = intern ("user-size");
13178 staticpro (&Quser_size);
6fc2811b
JR
13179 Qscreen_gamma = intern ("screen-gamma");
13180 staticpro (&Qscreen_gamma);
dfff8a69
JR
13181 Qline_spacing = intern ("line-spacing");
13182 staticpro (&Qline_spacing);
13183 Qcenter = intern ("center");
13184 staticpro (&Qcenter);
ee78dc32
GV
13185 /* This is the end of symbol initialization. */
13186
adcc3809
GV
13187 Qhyper = intern ("hyper");
13188 staticpro (&Qhyper);
13189 Qsuper = intern ("super");
13190 staticpro (&Qsuper);
13191 Qmeta = intern ("meta");
13192 staticpro (&Qmeta);
13193 Qalt = intern ("alt");
13194 staticpro (&Qalt);
13195 Qctrl = intern ("ctrl");
13196 staticpro (&Qctrl);
13197 Qcontrol = intern ("control");
13198 staticpro (&Qcontrol);
13199 Qshift = intern ("shift");
13200 staticpro (&Qshift);
13201
6fc2811b
JR
13202 /* Text property `display' should be nonsticky by default. */
13203 Vtext_property_default_nonsticky
13204 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
13205
13206
13207 Qlaplace = intern ("laplace");
13208 staticpro (&Qlaplace);
13209
4b817373
RS
13210 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
13211 staticpro (&Qface_set_after_frame_default);
13212
ee78dc32
GV
13213 Fput (Qundefined_color, Qerror_conditions,
13214 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
13215 Fput (Qundefined_color, Qerror_message,
13216 build_string ("Undefined color"));
13217
ccc2d29c
GV
13218 staticpro (&w32_grabbed_keys);
13219 w32_grabbed_keys = Qnil;
13220
fbd6baed 13221 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
ccc2d29c 13222 "An array of color name mappings for windows.");
fbd6baed 13223 Vw32_color_map = Qnil;
ee78dc32 13224
fbd6baed 13225 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
da36a4d6
GV
13226 "Non-nil if alt key presses are passed on to Windows.\n\
13227When non-nil, for example, alt pressed and released and then space will\n\
13228open the System menu. When nil, Emacs silently swallows alt key events.");
fbd6baed 13229 Vw32_pass_alt_to_system = Qnil;
da36a4d6 13230
fbd6baed 13231 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
8c205c63
RS
13232 "Non-nil if the alt key is to be considered the same as the meta key.\n\
13233When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
fbd6baed 13234 Vw32_alt_is_meta = Qt;
8c205c63 13235
7d081355
AI
13236 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
13237 "If non-zero, the virtual key code for an alternative quit key.");
13238 XSETINT (Vw32_quit_key, 0);
13239
ccc2d29c
GV
13240 DEFVAR_LISP ("w32-pass-lwindow-to-system",
13241 &Vw32_pass_lwindow_to_system,
13242 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
13243When non-nil, the Start menu is opened by tapping the key.");
13244 Vw32_pass_lwindow_to_system = Qt;
13245
13246 DEFVAR_LISP ("w32-pass-rwindow-to-system",
13247 &Vw32_pass_rwindow_to_system,
13248 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
13249When non-nil, the Start menu is opened by tapping the key.");
13250 Vw32_pass_rwindow_to_system = Qt;
13251
adcc3809
GV
13252 DEFVAR_INT ("w32-phantom-key-code",
13253 &Vw32_phantom_key_code,
13254 "Virtual key code used to generate \"phantom\" key presses.\n\
13255Value is a number between 0 and 255.\n\
13256\n\
13257Phantom key presses are generated in order to stop the system from\n\
13258acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
13259`w32-pass-rwindow-to-system' is nil.");
ce6059da
AI
13260 /* Although 255 is technically not a valid key code, it works and
13261 means that this hack won't interfere with any real key code. */
13262 Vw32_phantom_key_code = 255;
adcc3809 13263
ccc2d29c
GV
13264 DEFVAR_LISP ("w32-enable-num-lock",
13265 &Vw32_enable_num_lock,
13266 "Non-nil if Num Lock should act normally.\n\
13267Set to nil to see Num Lock as the key `kp-numlock'.");
13268 Vw32_enable_num_lock = Qt;
13269
13270 DEFVAR_LISP ("w32-enable-caps-lock",
13271 &Vw32_enable_caps_lock,
13272 "Non-nil if Caps Lock should act normally.\n\
13273Set to nil to see Caps Lock as the key `capslock'.");
13274 Vw32_enable_caps_lock = Qt;
13275
13276 DEFVAR_LISP ("w32-scroll-lock-modifier",
13277 &Vw32_scroll_lock_modifier,
13278 "Modifier to use for the Scroll Lock on state.\n\
13279The value can be hyper, super, meta, alt, control or shift for the\n\
13280respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
13281Any other value will cause the key to be ignored.");
13282 Vw32_scroll_lock_modifier = Qt;
13283
13284 DEFVAR_LISP ("w32-lwindow-modifier",
13285 &Vw32_lwindow_modifier,
13286 "Modifier to use for the left \"Windows\" key.\n\
13287The value can be hyper, super, meta, alt, control or shift for the\n\
13288respective modifier, or nil to appear as the key `lwindow'.\n\
13289Any other value will cause the key to be ignored.");
13290 Vw32_lwindow_modifier = Qnil;
13291
13292 DEFVAR_LISP ("w32-rwindow-modifier",
13293 &Vw32_rwindow_modifier,
13294 "Modifier to use for the right \"Windows\" key.\n\
13295The value can be hyper, super, meta, alt, control or shift for the\n\
13296respective modifier, or nil to appear as the key `rwindow'.\n\
13297Any other value will cause the key to be ignored.");
13298 Vw32_rwindow_modifier = Qnil;
13299
13300 DEFVAR_LISP ("w32-apps-modifier",
13301 &Vw32_apps_modifier,
13302 "Modifier to use for the \"Apps\" key.\n\
13303The value can be hyper, super, meta, alt, control or shift for the\n\
13304respective modifier, or nil to appear as the key `apps'.\n\
13305Any other value will cause the key to be ignored.");
13306 Vw32_apps_modifier = Qnil;
da36a4d6 13307
212da13b 13308 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
6fc2811b
JR
13309 "Non-nil enables selection of artificially italicized and bold fonts.");
13310 Vw32_enable_synthesized_fonts = Qnil;
5ac45f98 13311
fbd6baed 13312 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
6fc2811b 13313 "Non-nil enables Windows palette management to map colors exactly.");
fbd6baed 13314 Vw32_enable_palette = Qt;
5ac45f98 13315
fbd6baed
GV
13316 DEFVAR_INT ("w32-mouse-button-tolerance",
13317 &Vw32_mouse_button_tolerance,
6fc2811b 13318 "Analogue of double click interval for faking middle mouse events.\n\
5ac45f98
GV
13319The value is the minimum time in milliseconds that must elapse between\n\
13320left/right button down events before they are considered distinct events.\n\
13321If both mouse buttons are depressed within this interval, a middle mouse\n\
13322button down event is generated instead.");
fbd6baed 13323 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 13324
fbd6baed
GV
13325 DEFVAR_INT ("w32-mouse-move-interval",
13326 &Vw32_mouse_move_interval,
84fb1139
KH
13327 "Minimum interval between mouse move events.\n\
13328The value is the minimum time in milliseconds that must elapse between\n\
13329successive mouse move (or scroll bar drag) events before they are\n\
13330reported as lisp events.");
247be837 13331 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 13332
ee78dc32
GV
13333 init_x_parm_symbols ();
13334
13335 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
fbd6baed 13336 "List of directories to search for bitmap files for w32.");
ee78dc32
GV
13337 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13338
13339 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13340 "The shape of the pointer when over text.\n\
13341Changing the value does not affect existing frames\n\
13342unless you set the mouse color.");
13343 Vx_pointer_shape = Qnil;
13344
13345 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13346 "The name Emacs uses to look up resources; for internal use only.\n\
13347`x-get-resource' uses this as the first component of the instance name\n\
13348when requesting resource values.\n\
13349Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13350was invoked, or to the value specified with the `-name' or `-rn'\n\
13351switches, if present.");
13352 Vx_resource_name = Qnil;
13353
13354 Vx_nontext_pointer_shape = Qnil;
13355
13356 Vx_mode_pointer_shape = Qnil;
13357
6fc2811b
JR
13358 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
13359 "The shape of the pointer when Emacs is busy.\n\
13360This variable takes effect when you create a new frame\n\
13361or when you set the mouse color.");
13362 Vx_busy_pointer_shape = Qnil;
13363
13364 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
13365 "Non-zero means Emacs displays a busy cursor on window systems.");
13366 display_busy_cursor_p = 1;
13367
f79e6790
JR
13368 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
13369 "*Seconds to wait before displaying a busy-cursor.\n\
dfff8a69 13370Value must be an integer or float.");
f79e6790
JR
13371 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
13372
6fc2811b 13373 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32
GV
13374 &Vx_sensitive_text_pointer_shape,
13375 "The shape of the pointer when over mouse-sensitive text.\n\
13376This variable takes effect when you create a new frame\n\
13377or when you set the mouse color.");
13378 Vx_sensitive_text_pointer_shape = Qnil;
13379
4694d762
JR
13380 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
13381 &Vx_window_horizontal_drag_shape,
13382 "Pointer shape to use for indicating a window can be dragged horizontally.\n\
13383This variable takes effect when you create a new frame\n\
13384or when you set the mouse color.");
13385 Vx_window_horizontal_drag_shape = Qnil;
13386
ee78dc32
GV
13387 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13388 "A string indicating the foreground color of the cursor box.");
13389 Vx_cursor_fore_pixel = Qnil;
13390
13391 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13392 "Non-nil if no window manager is in use.\n\
13393Emacs doesn't try to figure this out; this is always nil\n\
13394unless you set it to something else.");
13395 /* We don't have any way to find this out, so set it to nil
13396 and maybe the user would like to set it to t. */
13397 Vx_no_window_manager = Qnil;
13398
4587b026
GV
13399 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13400 &Vx_pixel_size_width_font_regexp,
13401 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13402\n\
13403Since Emacs gets width of a font matching with this regexp from\n\
13404PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13405such a font. This is especially effective for such large fonts as\n\
13406Chinese, Japanese, and Korean.");
13407 Vx_pixel_size_width_font_regexp = Qnil;
13408
6fc2811b
JR
13409 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13410 "Time after which cached images are removed from the cache.\n\
13411When an image has not been displayed this many seconds, remove it\n\
13412from the image cache. Value must be an integer or nil with nil\n\
13413meaning don't clear the cache.");
13414 Vimage_cache_eviction_delay = make_number (30 * 60);
13415
33d52f9c
GV
13416 DEFVAR_LISP ("w32-bdf-filename-alist",
13417 &Vw32_bdf_filename_alist,
13418 "List of bdf fonts and their corresponding filenames.");
13419 Vw32_bdf_filename_alist = Qnil;
13420
1075afa9
GV
13421 DEFVAR_BOOL ("w32-strict-fontnames",
13422 &w32_strict_fontnames,
13423 "Non-nil means only use fonts that are exact matches for those requested.\n\
13424Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13425and allows third-party CJK display to work by specifying false charset\n\
13426fields to trick Emacs into translating to Big5, SJIS etc.\n\
13427Setting this to t will prevent wrong fonts being selected when\n\
13428fontsets are automatically created.");
13429 w32_strict_fontnames = 0;
13430
c0611964
AI
13431 DEFVAR_BOOL ("w32-strict-painting",
13432 &w32_strict_painting,
13433 "Non-nil means use strict rules for repainting frames.\n\
13434Set this to nil to get the old behaviour for repainting; this should\n\
13435only be necessary if the default setting causes problems.");
13436 w32_strict_painting = 1;
13437
f46e6225
GV
13438 DEFVAR_LISP ("w32-system-coding-system",
13439 &Vw32_system_coding_system,
13440 "Coding system used by Windows system functions, such as for font names.");
13441 Vw32_system_coding_system = Qnil;
13442
dfff8a69
JR
13443 DEFVAR_LISP ("w32-charset-info-alist",
13444 &Vw32_charset_info_alist,
13445 "Alist linking Emacs character sets to Windows fonts\n\
13446and codepages. Each entry should be of the form:\n\
13447\n\
13448 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13449\n\
13450where CHARSET_NAME is a string used in font names to identify the charset,\n\
13451WINDOWS_CHARSET is a symbol that can be one of:\n\
13452w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
767b1ff0 13453w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,\n\
dfff8a69
JR
13454w32-charset-chinesebig5, "
13455#ifdef JOHAB_CHARSET
13456"w32-charset-johab, w32-charset-hebrew,\n\
13457w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13458w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13459w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13460#endif
13461#ifdef UNICODE_CHARSET
13462"w32-charset-unicode, "
13463#endif
13464"or w32-charset-oem.\n\
13465CODEPAGE should be an integer specifying the codepage that should be used\n\
13466to display the character set, t to do no translation and output as Unicode,\n\
13467or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13468versions of Windows) characters.");
13469 Vw32_charset_info_alist = Qnil;
13470
13471 staticpro (&Qw32_charset_ansi);
13472 Qw32_charset_ansi = intern ("w32-charset-ansi");
13473 staticpro (&Qw32_charset_symbol);
13474 Qw32_charset_symbol = intern ("w32-charset-symbol");
13475 staticpro (&Qw32_charset_shiftjis);
13476 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
13477 staticpro (&Qw32_charset_hangeul);
13478 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
13479 staticpro (&Qw32_charset_chinesebig5);
13480 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13481 staticpro (&Qw32_charset_gb2312);
13482 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13483 staticpro (&Qw32_charset_oem);
13484 Qw32_charset_oem = intern ("w32-charset-oem");
13485
13486#ifdef JOHAB_CHARSET
13487 {
13488 static int w32_extra_charsets_defined = 1;
767b1ff0 13489 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined, "");
dfff8a69
JR
13490
13491 staticpro (&Qw32_charset_johab);
13492 Qw32_charset_johab = intern ("w32-charset-johab");
13493 staticpro (&Qw32_charset_easteurope);
13494 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13495 staticpro (&Qw32_charset_turkish);
13496 Qw32_charset_turkish = intern ("w32-charset-turkish");
13497 staticpro (&Qw32_charset_baltic);
13498 Qw32_charset_baltic = intern ("w32-charset-baltic");
13499 staticpro (&Qw32_charset_russian);
13500 Qw32_charset_russian = intern ("w32-charset-russian");
13501 staticpro (&Qw32_charset_arabic);
13502 Qw32_charset_arabic = intern ("w32-charset-arabic");
13503 staticpro (&Qw32_charset_greek);
13504 Qw32_charset_greek = intern ("w32-charset-greek");
13505 staticpro (&Qw32_charset_hebrew);
13506 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
13507 staticpro (&Qw32_charset_vietnamese);
13508 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
13509 staticpro (&Qw32_charset_thai);
13510 Qw32_charset_thai = intern ("w32-charset-thai");
13511 staticpro (&Qw32_charset_mac);
13512 Qw32_charset_mac = intern ("w32-charset-mac");
13513 }
13514#endif
13515
13516#ifdef UNICODE_CHARSET
13517 {
13518 static int w32_unicode_charset_defined = 1;
13519 DEFVAR_BOOL ("w32-unicode-charset-defined",
767b1ff0 13520 &w32_unicode_charset_defined, "");
dfff8a69
JR
13521
13522 staticpro (&Qw32_charset_unicode);
13523 Qw32_charset_unicode = intern ("w32-charset-unicode");
13524#endif
13525
ee78dc32 13526 defsubr (&Sx_get_resource);
767b1ff0 13527#if 0 /* TODO: Port to W32 */
6fc2811b
JR
13528 defsubr (&Sx_change_window_property);
13529 defsubr (&Sx_delete_window_property);
13530 defsubr (&Sx_window_property);
13531#endif
2d764c78 13532 defsubr (&Sxw_display_color_p);
ee78dc32 13533 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
13534 defsubr (&Sxw_color_defined_p);
13535 defsubr (&Sxw_color_values);
ee78dc32
GV
13536 defsubr (&Sx_server_max_request_size);
13537 defsubr (&Sx_server_vendor);
13538 defsubr (&Sx_server_version);
13539 defsubr (&Sx_display_pixel_width);
13540 defsubr (&Sx_display_pixel_height);
13541 defsubr (&Sx_display_mm_width);
13542 defsubr (&Sx_display_mm_height);
13543 defsubr (&Sx_display_screens);
13544 defsubr (&Sx_display_planes);
13545 defsubr (&Sx_display_color_cells);
13546 defsubr (&Sx_display_visual_class);
13547 defsubr (&Sx_display_backing_store);
13548 defsubr (&Sx_display_save_under);
13549 defsubr (&Sx_parse_geometry);
13550 defsubr (&Sx_create_frame);
ee78dc32
GV
13551 defsubr (&Sx_open_connection);
13552 defsubr (&Sx_close_connection);
13553 defsubr (&Sx_display_list);
13554 defsubr (&Sx_synchronize);
13555
fbd6baed 13556 /* W32 specific functions */
ee78dc32 13557
1edf84e7 13558 defsubr (&Sw32_focus_frame);
fbd6baed
GV
13559 defsubr (&Sw32_select_font);
13560 defsubr (&Sw32_define_rgb_color);
13561 defsubr (&Sw32_default_color_map);
13562 defsubr (&Sw32_load_color_file);
1edf84e7 13563 defsubr (&Sw32_send_sys_command);
55dcfc15 13564 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
13565 defsubr (&Sw32_register_hot_key);
13566 defsubr (&Sw32_unregister_hot_key);
13567 defsubr (&Sw32_registered_hot_keys);
13568 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 13569 defsubr (&Sw32_toggle_lock_key);
33d52f9c 13570 defsubr (&Sw32_find_bdf_fonts);
4587b026
GV
13571
13572 /* Setting callback functions for fontset handler. */
13573 get_font_info_func = w32_get_font_info;
6fc2811b
JR
13574
13575#if 0 /* This function pointer doesn't seem to be used anywhere.
13576 And the pointer assigned has the wrong type, anyway. */
4587b026 13577 list_fonts_func = w32_list_fonts;
6fc2811b
JR
13578#endif
13579
4587b026
GV
13580 load_font_func = w32_load_font;
13581 find_ccl_program_func = w32_find_ccl_program;
13582 query_font_func = w32_query_font;
13583 set_frame_fontset_func = x_set_font;
13584 check_window_system_func = check_w32;
6fc2811b 13585
767b1ff0 13586#if 0 /* TODO Image support for W32 */
6fc2811b
JR
13587 /* Images. */
13588 Qxbm = intern ("xbm");
13589 staticpro (&Qxbm);
13590 QCtype = intern (":type");
13591 staticpro (&QCtype);
13592 QCalgorithm = intern (":algorithm");
13593 staticpro (&QCalgorithm);
13594 QCheuristic_mask = intern (":heuristic-mask");
13595 staticpro (&QCheuristic_mask);
13596 QCcolor_symbols = intern (":color-symbols");
13597 staticpro (&QCcolor_symbols);
6fc2811b
JR
13598 QCascent = intern (":ascent");
13599 staticpro (&QCascent);
13600 QCmargin = intern (":margin");
13601 staticpro (&QCmargin);
13602 QCrelief = intern (":relief");
13603 staticpro (&QCrelief);
13604 Qpostscript = intern ("postscript");
13605 staticpro (&Qpostscript);
13606 QCloader = intern (":loader");
13607 staticpro (&QCloader);
13608 QCbounding_box = intern (":bounding-box");
13609 staticpro (&QCbounding_box);
13610 QCpt_width = intern (":pt-width");
13611 staticpro (&QCpt_width);
13612 QCpt_height = intern (":pt-height");
13613 staticpro (&QCpt_height);
13614 QCindex = intern (":index");
13615 staticpro (&QCindex);
13616 Qpbm = intern ("pbm");
13617 staticpro (&Qpbm);
13618
13619#if HAVE_XPM
13620 Qxpm = intern ("xpm");
13621 staticpro (&Qxpm);
13622#endif
13623
13624#if HAVE_JPEG
13625 Qjpeg = intern ("jpeg");
13626 staticpro (&Qjpeg);
13627#endif
13628
13629#if HAVE_TIFF
13630 Qtiff = intern ("tiff");
13631 staticpro (&Qtiff);
13632#endif
13633
13634#if HAVE_GIF
13635 Qgif = intern ("gif");
13636 staticpro (&Qgif);
13637#endif
13638
13639#if HAVE_PNG
13640 Qpng = intern ("png");
13641 staticpro (&Qpng);
13642#endif
13643
13644 defsubr (&Sclear_image_cache);
13645
13646#if GLYPH_DEBUG
13647 defsubr (&Simagep);
13648 defsubr (&Slookup_image);
13649#endif
767b1ff0 13650#endif /* TODO */
6fc2811b 13651
dfff8a69
JR
13652 busy_cursor_atimer = NULL;
13653 busy_cursor_shown_p = 0;
767b1ff0 13654#ifdef TODO /* Tooltip support not complete. */
6fc2811b
JR
13655 defsubr (&Sx_show_tip);
13656 defsubr (&Sx_hide_tip);
767b1ff0 13657#endif
6fc2811b
JR
13658 staticpro (&tip_timer);
13659 tip_timer = Qnil;
13660
13661 defsubr (&Sx_file_dialog);
13662}
13663
13664
13665void
13666init_xfns ()
13667{
13668 image_types = NULL;
13669 Vimage_types = Qnil;
13670
767b1ff0 13671#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
13672 define_image_type (&xbm_type);
13673 define_image_type (&gs_type);
13674 define_image_type (&pbm_type);
13675
13676#if HAVE_XPM
13677 define_image_type (&xpm_type);
13678#endif
13679
13680#if HAVE_JPEG
13681 define_image_type (&jpeg_type);
13682#endif
13683
13684#if HAVE_TIFF
13685 define_image_type (&tiff_type);
13686#endif
13687
13688#if HAVE_GIF
13689 define_image_type (&gif_type);
13690#endif
13691
13692#if HAVE_PNG
13693 define_image_type (&png_type);
13694#endif
767b1ff0 13695#endif /* TODO */
ee78dc32
GV
13696}
13697
13698#undef abort
13699
13700void
fbd6baed 13701w32_abort()
ee78dc32 13702{
5ac45f98
GV
13703 int button;
13704 button = MessageBox (NULL,
13705 "A fatal error has occurred!\n\n"
13706 "Select Abort to exit, Retry to debug, Ignore to continue",
13707 "Emacs Abort Dialog",
13708 MB_ICONEXCLAMATION | MB_TASKMODAL
13709 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
13710 switch (button)
13711 {
13712 case IDRETRY:
13713 DebugBreak ();
13714 break;
13715 case IDIGNORE:
13716 break;
13717 case IDABORT:
13718 default:
13719 abort ();
13720 break;
13721 }
ee78dc32 13722}
d573caac 13723
83c75055
GV
13724/* For convenience when debugging. */
13725int
13726w32_last_error()
13727{
13728 return GetLastError ();
13729}