(Fx_hide_tip): Avoid unnecessary work when there's
[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
937e601e
AI
336#ifdef GLYPH_DEBUG
337int image_cache_refcount, dpyinfo_refcount;
338#endif
339
340
fbd6baed
GV
341/* From w32term.c. */
342extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 343extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 344
ee78dc32 345\f
1edf84e7
GV
346/* Error if we are not connected to MS-Windows. */
347void
348check_w32 ()
349{
350 if (! w32_in_use)
351 error ("MS-Windows not in use or not initialized");
352}
353
354/* Nonzero if we can use mouse menus.
355 You should not call this unless HAVE_MENUS is defined. */
356
357int
358have_menus_p ()
359{
360 return w32_in_use;
361}
362
ee78dc32 363/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 364 and checking validity for W32. */
ee78dc32
GV
365
366FRAME_PTR
367check_x_frame (frame)
368 Lisp_Object frame;
369{
370 FRAME_PTR f;
371
372 if (NILP (frame))
6fc2811b
JR
373 frame = selected_frame;
374 CHECK_LIVE_FRAME (frame, 0);
375 f = XFRAME (frame);
fbd6baed
GV
376 if (! FRAME_W32_P (f))
377 error ("non-w32 frame used");
ee78dc32
GV
378 return f;
379}
380
381/* Let the user specify an display with a frame.
fbd6baed 382 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
383 the first display on the list. */
384
fbd6baed 385static struct w32_display_info *
ee78dc32
GV
386check_x_display_info (frame)
387 Lisp_Object frame;
388{
389 if (NILP (frame))
390 {
6fc2811b
JR
391 struct frame *sf = XFRAME (selected_frame);
392
393 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
394 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 395 else
fbd6baed 396 return &one_w32_display_info;
ee78dc32
GV
397 }
398 else if (STRINGP (frame))
399 return x_display_info_for_name (frame);
400 else
401 {
402 FRAME_PTR f;
403
404 CHECK_LIVE_FRAME (frame, 0);
405 f = XFRAME (frame);
fbd6baed
GV
406 if (! FRAME_W32_P (f))
407 error ("non-w32 frame used");
408 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
409 }
410}
411\f
fbd6baed 412/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
413 It could be the frame's main window or an icon window. */
414
415/* This function can be called during GC, so use GC_xxx type test macros. */
416
417struct frame *
418x_window_to_frame (dpyinfo, wdesc)
fbd6baed 419 struct w32_display_info *dpyinfo;
ee78dc32
GV
420 HWND wdesc;
421{
422 Lisp_Object tail, frame;
423 struct frame *f;
424
8e713be6 425 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 426 {
8e713be6 427 frame = XCAR (tail);
ee78dc32
GV
428 if (!GC_FRAMEP (frame))
429 continue;
430 f = XFRAME (frame);
2d764c78 431 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 432 continue;
f79e6790
JR
433 if (f->output_data.w32->busy_window == wdesc)
434 return f;
435
767b1ff0 436 /* TODO: Check tooltips when supported. */
fbd6baed 437 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
438 return f;
439 }
440 return 0;
441}
442
443\f
444
445/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
446 id, which is just an int that this section returns. Bitmaps are
447 reference counted so they can be shared among frames.
448
449 Bitmap indices are guaranteed to be > 0, so a negative number can
450 be used to indicate no bitmap.
451
452 If you use x_create_bitmap_from_data, then you must keep track of
453 the bitmaps yourself. That is, creating a bitmap from the same
454 data more than once will not be caught. */
455
456
457/* Functions to access the contents of a bitmap, given an id. */
458
459int
460x_bitmap_height (f, id)
461 FRAME_PTR f;
462 int id;
463{
fbd6baed 464 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
465}
466
467int
468x_bitmap_width (f, id)
469 FRAME_PTR f;
470 int id;
471{
fbd6baed 472 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
473}
474
475int
476x_bitmap_pixmap (f, id)
477 FRAME_PTR f;
478 int id;
479{
fbd6baed 480 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
481}
482
483
484/* Allocate a new bitmap record. Returns index of new record. */
485
486static int
487x_allocate_bitmap_record (f)
488 FRAME_PTR f;
489{
fbd6baed 490 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
491 int i;
492
493 if (dpyinfo->bitmaps == NULL)
494 {
495 dpyinfo->bitmaps_size = 10;
496 dpyinfo->bitmaps
fbd6baed 497 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
498 dpyinfo->bitmaps_last = 1;
499 return 1;
500 }
501
502 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
503 return ++dpyinfo->bitmaps_last;
504
505 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
506 if (dpyinfo->bitmaps[i].refcount == 0)
507 return i + 1;
508
509 dpyinfo->bitmaps_size *= 2;
510 dpyinfo->bitmaps
fbd6baed
GV
511 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
512 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
513 return ++dpyinfo->bitmaps_last;
514}
515
516/* Add one reference to the reference count of the bitmap with id ID. */
517
518void
519x_reference_bitmap (f, id)
520 FRAME_PTR f;
521 int id;
522{
fbd6baed 523 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
524}
525
526/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
527
528int
529x_create_bitmap_from_data (f, bits, width, height)
530 struct frame *f;
531 char *bits;
532 unsigned int width, height;
533{
fbd6baed 534 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
535 Pixmap bitmap;
536 int id;
537
538 bitmap = CreateBitmap (width, height,
fbd6baed
GV
539 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
540 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
541 bits);
542
543 if (! bitmap)
544 return -1;
545
546 id = x_allocate_bitmap_record (f);
547 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
548 dpyinfo->bitmaps[id - 1].file = NULL;
549 dpyinfo->bitmaps[id - 1].hinst = NULL;
550 dpyinfo->bitmaps[id - 1].refcount = 1;
551 dpyinfo->bitmaps[id - 1].depth = 1;
552 dpyinfo->bitmaps[id - 1].height = height;
553 dpyinfo->bitmaps[id - 1].width = width;
554
555 return id;
556}
557
558/* Create bitmap from file FILE for frame F. */
559
560int
561x_create_bitmap_from_file (f, file)
562 struct frame *f;
563 Lisp_Object file;
564{
565 return -1;
767b1ff0 566#if 0 /* TODO : bitmap support */
fbd6baed 567 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 568 unsigned int width, height;
6fc2811b 569 HBITMAP bitmap;
ee78dc32
GV
570 int xhot, yhot, result, id;
571 Lisp_Object found;
572 int fd;
573 char *filename;
574 HINSTANCE hinst;
575
576 /* Look for an existing bitmap with the same name. */
577 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
578 {
579 if (dpyinfo->bitmaps[id].refcount
580 && dpyinfo->bitmaps[id].file
581 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
582 {
583 ++dpyinfo->bitmaps[id].refcount;
584 return id + 1;
585 }
586 }
587
588 /* Search bitmap-file-path for the file, if appropriate. */
589 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
590 if (fd < 0)
591 return -1;
6fc2811b 592 emacs_close (fd);
ee78dc32
GV
593
594 filename = (char *) XSTRING (found)->data;
595
596 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
597
598 if (hinst == NULL)
599 return -1;
600
601
fbd6baed 602 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
603 filename, &width, &height, &bitmap, &xhot, &yhot);
604 if (result != BitmapSuccess)
605 return -1;
606
607 id = x_allocate_bitmap_record (f);
608 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
609 dpyinfo->bitmaps[id - 1].refcount = 1;
610 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
611 dpyinfo->bitmaps[id - 1].depth = 1;
612 dpyinfo->bitmaps[id - 1].height = height;
613 dpyinfo->bitmaps[id - 1].width = width;
614 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
615
616 return id;
767b1ff0 617#endif /* TODO */
ee78dc32
GV
618}
619
620/* Remove reference to bitmap with id number ID. */
621
33d52f9c 622void
ee78dc32
GV
623x_destroy_bitmap (f, id)
624 FRAME_PTR f;
625 int id;
626{
fbd6baed 627 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
628
629 if (id > 0)
630 {
631 --dpyinfo->bitmaps[id - 1].refcount;
632 if (dpyinfo->bitmaps[id - 1].refcount == 0)
633 {
634 BLOCK_INPUT;
635 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
636 if (dpyinfo->bitmaps[id - 1].file)
637 {
6fc2811b 638 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
639 dpyinfo->bitmaps[id - 1].file = NULL;
640 }
641 UNBLOCK_INPUT;
642 }
643 }
644}
645
646/* Free all the bitmaps for the display specified by DPYINFO. */
647
648static void
649x_destroy_all_bitmaps (dpyinfo)
fbd6baed 650 struct w32_display_info *dpyinfo;
ee78dc32
GV
651{
652 int i;
653 for (i = 0; i < dpyinfo->bitmaps_last; i++)
654 if (dpyinfo->bitmaps[i].refcount > 0)
655 {
656 DeleteObject (dpyinfo->bitmaps[i].pixmap);
657 if (dpyinfo->bitmaps[i].file)
6fc2811b 658 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
659 }
660 dpyinfo->bitmaps_last = 0;
661}
662\f
fbd6baed 663/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
664 to the ways of passing the parameter values to the window system.
665
666 The name of a parameter, as a Lisp symbol,
667 has an `x-frame-parameter' property which is an integer in Lisp
668 but can be interpreted as an `enum x_frame_parm' in C. */
669
670enum x_frame_parm
671{
672 X_PARM_FOREGROUND_COLOR,
673 X_PARM_BACKGROUND_COLOR,
674 X_PARM_MOUSE_COLOR,
675 X_PARM_CURSOR_COLOR,
676 X_PARM_BORDER_COLOR,
677 X_PARM_ICON_TYPE,
678 X_PARM_FONT,
679 X_PARM_BORDER_WIDTH,
680 X_PARM_INTERNAL_BORDER_WIDTH,
681 X_PARM_NAME,
682 X_PARM_AUTORAISE,
683 X_PARM_AUTOLOWER,
684 X_PARM_VERT_SCROLL_BAR,
685 X_PARM_VISIBILITY,
686 X_PARM_MENU_BAR_LINES
687};
688
689
690struct x_frame_parm_table
691{
692 char *name;
6fc2811b 693 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
694};
695
937e601e
AI
696static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
697static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
698static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 699/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 700void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 701static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
702void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
703void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
704void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
706void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
707void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
708void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
709void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
710void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
711void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
712 Lisp_Object));
713void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
714void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
715void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
716void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
717 Lisp_Object));
718void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
719void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
720void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
721void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
722void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
723void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
724static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
725
726static struct x_frame_parm_table x_frame_parms[] =
727{
1edf84e7
GV
728 "auto-raise", x_set_autoraise,
729 "auto-lower", x_set_autolower,
ee78dc32 730 "background-color", x_set_background_color,
ee78dc32 731 "border-color", x_set_border_color,
1edf84e7
GV
732 "border-width", x_set_border_width,
733 "cursor-color", x_set_cursor_color,
ee78dc32 734 "cursor-type", x_set_cursor_type,
ee78dc32 735 "font", x_set_font,
1edf84e7
GV
736 "foreground-color", x_set_foreground_color,
737 "icon-name", x_set_icon_name,
738 "icon-type", x_set_icon_type,
ee78dc32 739 "internal-border-width", x_set_internal_border_width,
ee78dc32 740 "menu-bar-lines", x_set_menu_bar_lines,
1edf84e7
GV
741 "mouse-color", x_set_mouse_color,
742 "name", x_explicitly_set_name,
ee78dc32 743 "scroll-bar-width", x_set_scroll_bar_width,
1edf84e7 744 "title", x_set_title,
ee78dc32 745 "unsplittable", x_set_unsplittable,
1edf84e7
GV
746 "vertical-scroll-bars", x_set_vertical_scroll_bars,
747 "visibility", x_set_visibility,
6fc2811b 748 "tool-bar-lines", x_set_tool_bar_lines,
dfff8a69
JR
749 "screen-gamma", x_set_screen_gamma,
750 "line-spacing", x_set_line_spacing
ee78dc32
GV
751};
752
753/* Attach the `x-frame-parameter' properties to
fbd6baed 754 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 755
dfff8a69 756void
ee78dc32
GV
757init_x_parm_symbols ()
758{
759 int i;
760
761 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
762 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
763 make_number (i));
764}
765\f
dfff8a69 766/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
767 If a parameter is not specially recognized, do nothing;
768 otherwise call the `x_set_...' function for that parameter. */
769
770void
771x_set_frame_parameters (f, alist)
772 FRAME_PTR f;
773 Lisp_Object alist;
774{
775 Lisp_Object tail;
776
777 /* If both of these parameters are present, it's more efficient to
778 set them both at once. So we wait until we've looked at the
779 entire list before we set them. */
b839712d 780 int width, height;
ee78dc32
GV
781
782 /* Same here. */
783 Lisp_Object left, top;
784
785 /* Same with these. */
786 Lisp_Object icon_left, icon_top;
787
788 /* Record in these vectors all the parms specified. */
789 Lisp_Object *parms;
790 Lisp_Object *values;
a797a73d 791 int i, p;
ee78dc32
GV
792 int left_no_change = 0, top_no_change = 0;
793 int icon_left_no_change = 0, icon_top_no_change = 0;
794
5878523b
RS
795 struct gcpro gcpro1, gcpro2;
796
ee78dc32
GV
797 i = 0;
798 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
799 i++;
800
801 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
802 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
803
804 /* Extract parm names and values into those vectors. */
805
806 i = 0;
807 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
808 {
6fc2811b 809 Lisp_Object elt;
ee78dc32
GV
810
811 elt = Fcar (tail);
812 parms[i] = Fcar (elt);
813 values[i] = Fcdr (elt);
814 i++;
815 }
5878523b
RS
816 /* TAIL and ALIST are not used again below here. */
817 alist = tail = Qnil;
818
819 GCPRO2 (*parms, *values);
820 gcpro1.nvars = i;
821 gcpro2.nvars = i;
822
823 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
824 because their values appear in VALUES and strings are not valid. */
b839712d 825 top = left = Qunbound;
ee78dc32
GV
826 icon_left = icon_top = Qunbound;
827
b839712d 828 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
829 if (FRAME_NEW_WIDTH (f))
830 width = FRAME_NEW_WIDTH (f);
831 else
832 width = FRAME_WIDTH (f);
833
834 if (FRAME_NEW_HEIGHT (f))
835 height = FRAME_NEW_HEIGHT (f);
836 else
837 height = FRAME_HEIGHT (f);
b839712d 838
a797a73d
GV
839 /* Process foreground_color and background_color before anything else.
840 They are independent of other properties, but other properties (e.g.,
841 cursor_color) are dependent upon them. */
842 for (p = 0; p < i; p++)
843 {
844 Lisp_Object prop, val;
845
846 prop = parms[p];
847 val = values[p];
848 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
849 {
850 register Lisp_Object param_index, old_value;
851
852 param_index = Fget (prop, Qx_frame_parameter);
853 old_value = get_frame_param (f, prop);
854 store_frame_param (f, prop, val);
855 if (NATNUMP (param_index)
856 && (XFASTINT (param_index)
857 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
858 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
859 }
860 }
861
ee78dc32
GV
862 /* Now process them in reverse of specified order. */
863 for (i--; i >= 0; i--)
864 {
865 Lisp_Object prop, val;
866
867 prop = parms[i];
868 val = values[i];
869
b839712d
RS
870 if (EQ (prop, Qwidth) && NUMBERP (val))
871 width = XFASTINT (val);
872 else if (EQ (prop, Qheight) && NUMBERP (val))
873 height = XFASTINT (val);
ee78dc32
GV
874 else if (EQ (prop, Qtop))
875 top = val;
876 else if (EQ (prop, Qleft))
877 left = val;
878 else if (EQ (prop, Qicon_top))
879 icon_top = val;
880 else if (EQ (prop, Qicon_left))
881 icon_left = val;
a797a73d
GV
882 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
883 /* Processed above. */
884 continue;
ee78dc32
GV
885 else
886 {
887 register Lisp_Object param_index, old_value;
888
889 param_index = Fget (prop, Qx_frame_parameter);
890 old_value = get_frame_param (f, prop);
891 store_frame_param (f, prop, val);
892 if (NATNUMP (param_index)
893 && (XFASTINT (param_index)
894 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 895 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
896 }
897 }
898
899 /* Don't die if just one of these was set. */
900 if (EQ (left, Qunbound))
901 {
902 left_no_change = 1;
fbd6baed
GV
903 if (f->output_data.w32->left_pos < 0)
904 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 905 else
fbd6baed 906 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
907 }
908 if (EQ (top, Qunbound))
909 {
910 top_no_change = 1;
fbd6baed
GV
911 if (f->output_data.w32->top_pos < 0)
912 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 913 else
fbd6baed 914 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
915 }
916
917 /* If one of the icon positions was not set, preserve or default it. */
918 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
919 {
920 icon_left_no_change = 1;
921 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
922 if (NILP (icon_left))
923 XSETINT (icon_left, 0);
924 }
925 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
926 {
927 icon_top_no_change = 1;
928 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
929 if (NILP (icon_top))
930 XSETINT (icon_top, 0);
931 }
932
ee78dc32
GV
933 /* Don't set these parameters unless they've been explicitly
934 specified. The window might be mapped or resized while we're in
935 this function, and we don't want to override that unless the lisp
936 code has asked for it.
937
938 Don't set these parameters unless they actually differ from the
939 window's current parameters; the window may not actually exist
940 yet. */
941 {
942 Lisp_Object frame;
943
944 check_frame_size (f, &height, &width);
945
946 XSETFRAME (frame, f);
947
dfff8a69
JR
948 if (width != FRAME_WIDTH (f)
949 || height != FRAME_HEIGHT (f)
950 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 951 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
952
953 if ((!NILP (left) || !NILP (top))
954 && ! (left_no_change && top_no_change)
fbd6baed
GV
955 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
956 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
957 {
958 int leftpos = 0;
959 int toppos = 0;
960
961 /* Record the signs. */
fbd6baed 962 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 963 if (EQ (left, Qminus))
fbd6baed 964 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
965 else if (INTEGERP (left))
966 {
967 leftpos = XINT (left);
968 if (leftpos < 0)
fbd6baed 969 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 970 }
8e713be6
KR
971 else if (CONSP (left) && EQ (XCAR (left), Qminus)
972 && CONSP (XCDR (left))
973 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 974 {
8e713be6 975 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 976 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 977 }
8e713be6
KR
978 else if (CONSP (left) && EQ (XCAR (left), Qplus)
979 && CONSP (XCDR (left))
980 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 981 {
8e713be6 982 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
983 }
984
985 if (EQ (top, Qminus))
fbd6baed 986 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
987 else if (INTEGERP (top))
988 {
989 toppos = XINT (top);
990 if (toppos < 0)
fbd6baed 991 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 992 }
8e713be6
KR
993 else if (CONSP (top) && EQ (XCAR (top), Qminus)
994 && CONSP (XCDR (top))
995 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 996 {
8e713be6 997 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 998 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 999 }
8e713be6
KR
1000 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1001 && CONSP (XCDR (top))
1002 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1003 {
8e713be6 1004 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1005 }
1006
1007
1008 /* Store the numeric value of the position. */
fbd6baed
GV
1009 f->output_data.w32->top_pos = toppos;
1010 f->output_data.w32->left_pos = leftpos;
ee78dc32 1011
fbd6baed 1012 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1013
1014 /* Actually set that position, and convert to absolute. */
1015 x_set_offset (f, leftpos, toppos, -1);
1016 }
1017
1018 if ((!NILP (icon_left) || !NILP (icon_top))
1019 && ! (icon_left_no_change && icon_top_no_change))
1020 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1021 }
5878523b
RS
1022
1023 UNGCPRO;
ee78dc32
GV
1024}
1025
1026/* Store the screen positions of frame F into XPTR and YPTR.
1027 These are the positions of the containing window manager window,
1028 not Emacs's own window. */
1029
1030void
1031x_real_positions (f, xptr, yptr)
1032 FRAME_PTR f;
1033 int *xptr, *yptr;
1034{
1035 POINT pt;
3c190163
GV
1036
1037 {
1038 RECT rect;
ee78dc32 1039
fbd6baed
GV
1040 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1041 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 1042
3c190163
GV
1043 pt.x = rect.left;
1044 pt.y = rect.top;
1045 }
ee78dc32 1046
fbd6baed 1047 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
1048
1049 *xptr = pt.x;
1050 *yptr = pt.y;
1051}
1052
1053/* Insert a description of internally-recorded parameters of frame X
1054 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1055 Only parameters that are specific to W32
ee78dc32
GV
1056 and whose values are not correctly recorded in the frame's
1057 param_alist need to be considered here. */
1058
dfff8a69 1059void
ee78dc32
GV
1060x_report_frame_params (f, alistptr)
1061 struct frame *f;
1062 Lisp_Object *alistptr;
1063{
1064 char buf[16];
1065 Lisp_Object tem;
1066
1067 /* Represent negative positions (off the top or left screen edge)
1068 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1069 XSETINT (tem, f->output_data.w32->left_pos);
1070 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1071 store_in_alist (alistptr, Qleft, tem);
1072 else
1073 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1074
fbd6baed
GV
1075 XSETINT (tem, f->output_data.w32->top_pos);
1076 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1077 store_in_alist (alistptr, Qtop, tem);
1078 else
1079 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1080
1081 store_in_alist (alistptr, Qborder_width,
fbd6baed 1082 make_number (f->output_data.w32->border_width));
ee78dc32 1083 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed
GV
1084 make_number (f->output_data.w32->internal_border_width));
1085 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1086 store_in_alist (alistptr, Qwindow_id,
1087 build_string (buf));
1088 store_in_alist (alistptr, Qicon_name, f->icon_name);
1089 FRAME_SAMPLE_VISIBILITY (f);
1090 store_in_alist (alistptr, Qvisibility,
1091 (FRAME_VISIBLE_P (f) ? Qt
1092 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1093 store_in_alist (alistptr, Qdisplay,
8e713be6 1094 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1095}
1096\f
1097
fbd6baed 1098DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
5ac45f98 1099 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
fbd6baed 1100This adds or updates a named color to w32-color-map, making it available for use.\n\
5ac45f98
GV
1101The original entry's RGB ref is returned, or nil if the entry is new.")
1102 (red, green, blue, name)
1103 Lisp_Object red, green, blue, name;
ee78dc32 1104{
5ac45f98
GV
1105 Lisp_Object rgb;
1106 Lisp_Object oldrgb = Qnil;
1107 Lisp_Object entry;
1108
1109 CHECK_NUMBER (red, 0);
1110 CHECK_NUMBER (green, 0);
1111 CHECK_NUMBER (blue, 0);
1112 CHECK_STRING (name, 0);
ee78dc32 1113
5ac45f98 1114 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1115
5ac45f98 1116 BLOCK_INPUT;
ee78dc32 1117
fbd6baed
GV
1118 /* replace existing entry in w32-color-map or add new entry. */
1119 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1120 if (NILP (entry))
1121 {
1122 entry = Fcons (name, rgb);
fbd6baed 1123 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1124 }
1125 else
1126 {
1127 oldrgb = Fcdr (entry);
1128 Fsetcdr (entry, rgb);
1129 }
1130
1131 UNBLOCK_INPUT;
1132
1133 return (oldrgb);
ee78dc32
GV
1134}
1135
fbd6baed 1136DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
5ac45f98 1137 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
fbd6baed 1138Assign this value to w32-color-map to replace the existing color map.\n\
5ac45f98
GV
1139\
1140The file should define one named RGB color per line like so:\
1141 R G B name\n\
1142where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1143 (filename)
1144 Lisp_Object filename;
1145{
1146 FILE *fp;
1147 Lisp_Object cmap = Qnil;
1148 Lisp_Object abspath;
1149
1150 CHECK_STRING (filename, 0);
1151 abspath = Fexpand_file_name (filename, Qnil);
1152
1153 fp = fopen (XSTRING (filename)->data, "rt");
1154 if (fp)
1155 {
1156 char buf[512];
1157 int red, green, blue;
1158 int num;
1159
1160 BLOCK_INPUT;
1161
1162 while (fgets (buf, sizeof (buf), fp) != NULL) {
1163 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1164 {
1165 char *name = buf + num;
1166 num = strlen (name) - 1;
1167 if (name[num] == '\n')
1168 name[num] = 0;
1169 cmap = Fcons (Fcons (build_string (name),
1170 make_number (RGB (red, green, blue))),
1171 cmap);
1172 }
1173 }
1174 fclose (fp);
1175
1176 UNBLOCK_INPUT;
1177 }
1178
1179 return cmap;
1180}
ee78dc32 1181
fbd6baed 1182/* The default colors for the w32 color map */
ee78dc32
GV
1183typedef struct colormap_t
1184{
1185 char *name;
1186 COLORREF colorref;
1187} colormap_t;
1188
fbd6baed 1189colormap_t w32_color_map[] =
ee78dc32 1190{
1da8a614
GV
1191 {"snow" , PALETTERGB (255,250,250)},
1192 {"ghost white" , PALETTERGB (248,248,255)},
1193 {"GhostWhite" , PALETTERGB (248,248,255)},
1194 {"white smoke" , PALETTERGB (245,245,245)},
1195 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1196 {"gainsboro" , PALETTERGB (220,220,220)},
1197 {"floral white" , PALETTERGB (255,250,240)},
1198 {"FloralWhite" , PALETTERGB (255,250,240)},
1199 {"old lace" , PALETTERGB (253,245,230)},
1200 {"OldLace" , PALETTERGB (253,245,230)},
1201 {"linen" , PALETTERGB (250,240,230)},
1202 {"antique white" , PALETTERGB (250,235,215)},
1203 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1204 {"papaya whip" , PALETTERGB (255,239,213)},
1205 {"PapayaWhip" , PALETTERGB (255,239,213)},
1206 {"blanched almond" , PALETTERGB (255,235,205)},
1207 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1208 {"bisque" , PALETTERGB (255,228,196)},
1209 {"peach puff" , PALETTERGB (255,218,185)},
1210 {"PeachPuff" , PALETTERGB (255,218,185)},
1211 {"navajo white" , PALETTERGB (255,222,173)},
1212 {"NavajoWhite" , PALETTERGB (255,222,173)},
1213 {"moccasin" , PALETTERGB (255,228,181)},
1214 {"cornsilk" , PALETTERGB (255,248,220)},
1215 {"ivory" , PALETTERGB (255,255,240)},
1216 {"lemon chiffon" , PALETTERGB (255,250,205)},
1217 {"LemonChiffon" , PALETTERGB (255,250,205)},
1218 {"seashell" , PALETTERGB (255,245,238)},
1219 {"honeydew" , PALETTERGB (240,255,240)},
1220 {"mint cream" , PALETTERGB (245,255,250)},
1221 {"MintCream" , PALETTERGB (245,255,250)},
1222 {"azure" , PALETTERGB (240,255,255)},
1223 {"alice blue" , PALETTERGB (240,248,255)},
1224 {"AliceBlue" , PALETTERGB (240,248,255)},
1225 {"lavender" , PALETTERGB (230,230,250)},
1226 {"lavender blush" , PALETTERGB (255,240,245)},
1227 {"LavenderBlush" , PALETTERGB (255,240,245)},
1228 {"misty rose" , PALETTERGB (255,228,225)},
1229 {"MistyRose" , PALETTERGB (255,228,225)},
1230 {"white" , PALETTERGB (255,255,255)},
1231 {"black" , PALETTERGB ( 0, 0, 0)},
1232 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1233 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1234 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1235 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1236 {"dim gray" , PALETTERGB (105,105,105)},
1237 {"DimGray" , PALETTERGB (105,105,105)},
1238 {"dim grey" , PALETTERGB (105,105,105)},
1239 {"DimGrey" , PALETTERGB (105,105,105)},
1240 {"slate gray" , PALETTERGB (112,128,144)},
1241 {"SlateGray" , PALETTERGB (112,128,144)},
1242 {"slate grey" , PALETTERGB (112,128,144)},
1243 {"SlateGrey" , PALETTERGB (112,128,144)},
1244 {"light slate gray" , PALETTERGB (119,136,153)},
1245 {"LightSlateGray" , PALETTERGB (119,136,153)},
1246 {"light slate grey" , PALETTERGB (119,136,153)},
1247 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1248 {"gray" , PALETTERGB (190,190,190)},
1249 {"grey" , PALETTERGB (190,190,190)},
1250 {"light grey" , PALETTERGB (211,211,211)},
1251 {"LightGrey" , PALETTERGB (211,211,211)},
1252 {"light gray" , PALETTERGB (211,211,211)},
1253 {"LightGray" , PALETTERGB (211,211,211)},
1254 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1255 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1256 {"navy" , PALETTERGB ( 0, 0,128)},
1257 {"navy blue" , PALETTERGB ( 0, 0,128)},
1258 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1259 {"cornflower blue" , PALETTERGB (100,149,237)},
1260 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1261 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1262 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1263 {"slate blue" , PALETTERGB (106, 90,205)},
1264 {"SlateBlue" , PALETTERGB (106, 90,205)},
1265 {"medium slate blue" , PALETTERGB (123,104,238)},
1266 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1267 {"light slate blue" , PALETTERGB (132,112,255)},
1268 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1269 {"medium blue" , PALETTERGB ( 0, 0,205)},
1270 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1271 {"royal blue" , PALETTERGB ( 65,105,225)},
1272 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1273 {"blue" , PALETTERGB ( 0, 0,255)},
1274 {"dodger blue" , PALETTERGB ( 30,144,255)},
1275 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1276 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1277 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1278 {"sky blue" , PALETTERGB (135,206,235)},
1279 {"SkyBlue" , PALETTERGB (135,206,235)},
1280 {"light sky blue" , PALETTERGB (135,206,250)},
1281 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1282 {"steel blue" , PALETTERGB ( 70,130,180)},
1283 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1284 {"light steel blue" , PALETTERGB (176,196,222)},
1285 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1286 {"light blue" , PALETTERGB (173,216,230)},
1287 {"LightBlue" , PALETTERGB (173,216,230)},
1288 {"powder blue" , PALETTERGB (176,224,230)},
1289 {"PowderBlue" , PALETTERGB (176,224,230)},
1290 {"pale turquoise" , PALETTERGB (175,238,238)},
1291 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1292 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1293 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1294 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1295 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1296 {"turquoise" , PALETTERGB ( 64,224,208)},
1297 {"cyan" , PALETTERGB ( 0,255,255)},
1298 {"light cyan" , PALETTERGB (224,255,255)},
1299 {"LightCyan" , PALETTERGB (224,255,255)},
1300 {"cadet blue" , PALETTERGB ( 95,158,160)},
1301 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1302 {"medium aquamarine" , PALETTERGB (102,205,170)},
1303 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1304 {"aquamarine" , PALETTERGB (127,255,212)},
1305 {"dark green" , PALETTERGB ( 0,100, 0)},
1306 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1307 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1308 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1309 {"dark sea green" , PALETTERGB (143,188,143)},
1310 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1311 {"sea green" , PALETTERGB ( 46,139, 87)},
1312 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1313 {"medium sea green" , PALETTERGB ( 60,179,113)},
1314 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1315 {"light sea green" , PALETTERGB ( 32,178,170)},
1316 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1317 {"pale green" , PALETTERGB (152,251,152)},
1318 {"PaleGreen" , PALETTERGB (152,251,152)},
1319 {"spring green" , PALETTERGB ( 0,255,127)},
1320 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1321 {"lawn green" , PALETTERGB (124,252, 0)},
1322 {"LawnGreen" , PALETTERGB (124,252, 0)},
1323 {"green" , PALETTERGB ( 0,255, 0)},
1324 {"chartreuse" , PALETTERGB (127,255, 0)},
1325 {"medium spring green" , PALETTERGB ( 0,250,154)},
1326 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1327 {"green yellow" , PALETTERGB (173,255, 47)},
1328 {"GreenYellow" , PALETTERGB (173,255, 47)},
1329 {"lime green" , PALETTERGB ( 50,205, 50)},
1330 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1331 {"yellow green" , PALETTERGB (154,205, 50)},
1332 {"YellowGreen" , PALETTERGB (154,205, 50)},
1333 {"forest green" , PALETTERGB ( 34,139, 34)},
1334 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1335 {"olive drab" , PALETTERGB (107,142, 35)},
1336 {"OliveDrab" , PALETTERGB (107,142, 35)},
1337 {"dark khaki" , PALETTERGB (189,183,107)},
1338 {"DarkKhaki" , PALETTERGB (189,183,107)},
1339 {"khaki" , PALETTERGB (240,230,140)},
1340 {"pale goldenrod" , PALETTERGB (238,232,170)},
1341 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1342 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1343 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1344 {"light yellow" , PALETTERGB (255,255,224)},
1345 {"LightYellow" , PALETTERGB (255,255,224)},
1346 {"yellow" , PALETTERGB (255,255, 0)},
1347 {"gold" , PALETTERGB (255,215, 0)},
1348 {"light goldenrod" , PALETTERGB (238,221,130)},
1349 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1350 {"goldenrod" , PALETTERGB (218,165, 32)},
1351 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1352 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1353 {"rosy brown" , PALETTERGB (188,143,143)},
1354 {"RosyBrown" , PALETTERGB (188,143,143)},
1355 {"indian red" , PALETTERGB (205, 92, 92)},
1356 {"IndianRed" , PALETTERGB (205, 92, 92)},
1357 {"saddle brown" , PALETTERGB (139, 69, 19)},
1358 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1359 {"sienna" , PALETTERGB (160, 82, 45)},
1360 {"peru" , PALETTERGB (205,133, 63)},
1361 {"burlywood" , PALETTERGB (222,184,135)},
1362 {"beige" , PALETTERGB (245,245,220)},
1363 {"wheat" , PALETTERGB (245,222,179)},
1364 {"sandy brown" , PALETTERGB (244,164, 96)},
1365 {"SandyBrown" , PALETTERGB (244,164, 96)},
1366 {"tan" , PALETTERGB (210,180,140)},
1367 {"chocolate" , PALETTERGB (210,105, 30)},
1368 {"firebrick" , PALETTERGB (178,34, 34)},
1369 {"brown" , PALETTERGB (165,42, 42)},
1370 {"dark salmon" , PALETTERGB (233,150,122)},
1371 {"DarkSalmon" , PALETTERGB (233,150,122)},
1372 {"salmon" , PALETTERGB (250,128,114)},
1373 {"light salmon" , PALETTERGB (255,160,122)},
1374 {"LightSalmon" , PALETTERGB (255,160,122)},
1375 {"orange" , PALETTERGB (255,165, 0)},
1376 {"dark orange" , PALETTERGB (255,140, 0)},
1377 {"DarkOrange" , PALETTERGB (255,140, 0)},
1378 {"coral" , PALETTERGB (255,127, 80)},
1379 {"light coral" , PALETTERGB (240,128,128)},
1380 {"LightCoral" , PALETTERGB (240,128,128)},
1381 {"tomato" , PALETTERGB (255, 99, 71)},
1382 {"orange red" , PALETTERGB (255, 69, 0)},
1383 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1384 {"red" , PALETTERGB (255, 0, 0)},
1385 {"hot pink" , PALETTERGB (255,105,180)},
1386 {"HotPink" , PALETTERGB (255,105,180)},
1387 {"deep pink" , PALETTERGB (255, 20,147)},
1388 {"DeepPink" , PALETTERGB (255, 20,147)},
1389 {"pink" , PALETTERGB (255,192,203)},
1390 {"light pink" , PALETTERGB (255,182,193)},
1391 {"LightPink" , PALETTERGB (255,182,193)},
1392 {"pale violet red" , PALETTERGB (219,112,147)},
1393 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1394 {"maroon" , PALETTERGB (176, 48, 96)},
1395 {"medium violet red" , PALETTERGB (199, 21,133)},
1396 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1397 {"violet red" , PALETTERGB (208, 32,144)},
1398 {"VioletRed" , PALETTERGB (208, 32,144)},
1399 {"magenta" , PALETTERGB (255, 0,255)},
1400 {"violet" , PALETTERGB (238,130,238)},
1401 {"plum" , PALETTERGB (221,160,221)},
1402 {"orchid" , PALETTERGB (218,112,214)},
1403 {"medium orchid" , PALETTERGB (186, 85,211)},
1404 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1405 {"dark orchid" , PALETTERGB (153, 50,204)},
1406 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1407 {"dark violet" , PALETTERGB (148, 0,211)},
1408 {"DarkViolet" , PALETTERGB (148, 0,211)},
1409 {"blue violet" , PALETTERGB (138, 43,226)},
1410 {"BlueViolet" , PALETTERGB (138, 43,226)},
1411 {"purple" , PALETTERGB (160, 32,240)},
1412 {"medium purple" , PALETTERGB (147,112,219)},
1413 {"MediumPurple" , PALETTERGB (147,112,219)},
1414 {"thistle" , PALETTERGB (216,191,216)},
1415 {"gray0" , PALETTERGB ( 0, 0, 0)},
1416 {"grey0" , PALETTERGB ( 0, 0, 0)},
1417 {"dark grey" , PALETTERGB (169,169,169)},
1418 {"DarkGrey" , PALETTERGB (169,169,169)},
1419 {"dark gray" , PALETTERGB (169,169,169)},
1420 {"DarkGray" , PALETTERGB (169,169,169)},
1421 {"dark blue" , PALETTERGB ( 0, 0,139)},
1422 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1423 {"dark cyan" , PALETTERGB ( 0,139,139)},
1424 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1425 {"dark magenta" , PALETTERGB (139, 0,139)},
1426 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1427 {"dark red" , PALETTERGB (139, 0, 0)},
1428 {"DarkRed" , PALETTERGB (139, 0, 0)},
1429 {"light green" , PALETTERGB (144,238,144)},
1430 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1431};
1432
fbd6baed 1433DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
ee78dc32
GV
1434 0, 0, 0, "Return the default color map.")
1435 ()
1436{
1437 int i;
fbd6baed 1438 colormap_t *pc = w32_color_map;
ee78dc32
GV
1439 Lisp_Object cmap;
1440
1441 BLOCK_INPUT;
1442
1443 cmap = Qnil;
1444
fbd6baed 1445 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1446 pc++, i++)
1447 cmap = Fcons (Fcons (build_string (pc->name),
1448 make_number (pc->colorref)),
1449 cmap);
1450
1451 UNBLOCK_INPUT;
1452
1453 return (cmap);
1454}
ee78dc32
GV
1455
1456Lisp_Object
fbd6baed 1457w32_to_x_color (rgb)
ee78dc32
GV
1458 Lisp_Object rgb;
1459{
1460 Lisp_Object color;
1461
1462 CHECK_NUMBER (rgb, 0);
1463
1464 BLOCK_INPUT;
1465
fbd6baed 1466 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1467
1468 UNBLOCK_INPUT;
1469
1470 if (!NILP (color))
1471 return (Fcar (color));
1472 else
1473 return Qnil;
1474}
1475
5d7fed93
GV
1476COLORREF
1477w32_color_map_lookup (colorname)
1478 char *colorname;
1479{
1480 Lisp_Object tail, ret = Qnil;
1481
1482 BLOCK_INPUT;
1483
1484 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1485 {
1486 register Lisp_Object elt, tem;
1487
1488 elt = Fcar (tail);
1489 if (!CONSP (elt)) continue;
1490
1491 tem = Fcar (elt);
1492
1493 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1494 {
1495 ret = XUINT (Fcdr (elt));
1496 break;
1497 }
1498
1499 QUIT;
1500 }
1501
1502
1503 UNBLOCK_INPUT;
1504
1505 return ret;
1506}
1507
ee78dc32 1508COLORREF
fbd6baed 1509x_to_w32_color (colorname)
ee78dc32
GV
1510 char * colorname;
1511{
1512 register Lisp_Object tail, ret = Qnil;
1513
1514 BLOCK_INPUT;
1edf84e7
GV
1515
1516 if (colorname[0] == '#')
1517 {
1518 /* Could be an old-style RGB Device specification. */
1519 char *color;
1520 int size;
1521 color = colorname + 1;
1522
1523 size = strlen(color);
1524 if (size == 3 || size == 6 || size == 9 || size == 12)
1525 {
1526 UINT colorval;
1527 int i, pos;
1528 pos = 0;
1529 size /= 3;
1530 colorval = 0;
1531
1532 for (i = 0; i < 3; i++)
1533 {
1534 char *end;
1535 char t;
1536 unsigned long value;
1537
1538 /* The check for 'x' in the following conditional takes into
1539 account the fact that strtol allows a "0x" in front of
1540 our numbers, and we don't. */
1541 if (!isxdigit(color[0]) || color[1] == 'x')
1542 break;
1543 t = color[size];
1544 color[size] = '\0';
1545 value = strtoul(color, &end, 16);
1546 color[size] = t;
1547 if (errno == ERANGE || end - color != size)
1548 break;
1549 switch (size)
1550 {
1551 case 1:
1552 value = value * 0x10;
1553 break;
1554 case 2:
1555 break;
1556 case 3:
1557 value /= 0x10;
1558 break;
1559 case 4:
1560 value /= 0x100;
1561 break;
1562 }
1563 colorval |= (value << pos);
1564 pos += 0x8;
1565 if (i == 2)
1566 {
1567 UNBLOCK_INPUT;
1568 return (colorval);
1569 }
1570 color = end;
1571 }
1572 }
1573 }
1574 else if (strnicmp(colorname, "rgb:", 4) == 0)
1575 {
1576 char *color;
1577 UINT colorval;
1578 int i, pos;
1579 pos = 0;
1580
1581 colorval = 0;
1582 color = colorname + 4;
1583 for (i = 0; i < 3; i++)
1584 {
1585 char *end;
1586 unsigned long value;
1587
1588 /* The check for 'x' in the following conditional takes into
1589 account the fact that strtol allows a "0x" in front of
1590 our numbers, and we don't. */
1591 if (!isxdigit(color[0]) || color[1] == 'x')
1592 break;
1593 value = strtoul(color, &end, 16);
1594 if (errno == ERANGE)
1595 break;
1596 switch (end - color)
1597 {
1598 case 1:
1599 value = value * 0x10 + value;
1600 break;
1601 case 2:
1602 break;
1603 case 3:
1604 value /= 0x10;
1605 break;
1606 case 4:
1607 value /= 0x100;
1608 break;
1609 default:
1610 value = ULONG_MAX;
1611 }
1612 if (value == ULONG_MAX)
1613 break;
1614 colorval |= (value << pos);
1615 pos += 0x8;
1616 if (i == 2)
1617 {
1618 if (*end != '\0')
1619 break;
1620 UNBLOCK_INPUT;
1621 return (colorval);
1622 }
1623 if (*end != '/')
1624 break;
1625 color = end + 1;
1626 }
1627 }
1628 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1629 {
1630 /* This is an RGB Intensity specification. */
1631 char *color;
1632 UINT colorval;
1633 int i, pos;
1634 pos = 0;
1635
1636 colorval = 0;
1637 color = colorname + 5;
1638 for (i = 0; i < 3; i++)
1639 {
1640 char *end;
1641 double value;
1642 UINT val;
1643
1644 value = strtod(color, &end);
1645 if (errno == ERANGE)
1646 break;
1647 if (value < 0.0 || value > 1.0)
1648 break;
1649 val = (UINT)(0x100 * value);
1650 /* We used 0x100 instead of 0xFF to give an continuous
1651 range between 0.0 and 1.0 inclusive. The next statement
1652 fixes the 1.0 case. */
1653 if (val == 0x100)
1654 val = 0xFF;
1655 colorval |= (val << pos);
1656 pos += 0x8;
1657 if (i == 2)
1658 {
1659 if (*end != '\0')
1660 break;
1661 UNBLOCK_INPUT;
1662 return (colorval);
1663 }
1664 if (*end != '/')
1665 break;
1666 color = end + 1;
1667 }
1668 }
1669 /* I am not going to attempt to handle any of the CIE color schemes
1670 or TekHVC, since I don't know the algorithms for conversion to
1671 RGB. */
f695b4b1
GV
1672
1673 /* If we fail to lookup the color name in w32_color_map, then check the
1674 colorname to see if it can be crudely approximated: If the X color
1675 ends in a number (e.g., "darkseagreen2"), strip the number and
1676 return the result of looking up the base color name. */
1677 ret = w32_color_map_lookup (colorname);
1678 if (NILP (ret))
ee78dc32 1679 {
f695b4b1 1680 int len = strlen (colorname);
ee78dc32 1681
f695b4b1
GV
1682 if (isdigit (colorname[len - 1]))
1683 {
1684 char *ptr, *approx = alloca (len);
ee78dc32 1685
f695b4b1
GV
1686 strcpy (approx, colorname);
1687 ptr = &approx[len - 1];
1688 while (ptr > approx && isdigit (*ptr))
1689 *ptr-- = '\0';
ee78dc32 1690
f695b4b1 1691 ret = w32_color_map_lookup (approx);
ee78dc32 1692 }
ee78dc32
GV
1693 }
1694
1695 UNBLOCK_INPUT;
ee78dc32
GV
1696 return ret;
1697}
1698
5ac45f98
GV
1699
1700void
fbd6baed 1701w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1702{
fbd6baed 1703 struct w32_palette_entry * list;
5ac45f98
GV
1704 LOGPALETTE * log_palette;
1705 HPALETTE new_palette;
1706 int i;
1707
1708 /* don't bother trying to create palette if not supported */
fbd6baed 1709 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1710 return;
1711
1712 log_palette = (LOGPALETTE *)
1713 alloca (sizeof (LOGPALETTE) +
fbd6baed 1714 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1715 log_palette->palVersion = 0x300;
fbd6baed 1716 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1717
fbd6baed 1718 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1719 for (i = 0;
fbd6baed 1720 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1721 i++, list = list->next)
1722 log_palette->palPalEntry[i] = list->entry;
1723
1724 new_palette = CreatePalette (log_palette);
1725
1726 enter_crit ();
1727
fbd6baed
GV
1728 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1729 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1730 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1731
1732 /* Realize display palette and garbage all frames. */
1733 release_frame_dc (f, get_frame_dc (f));
1734
1735 leave_crit ();
1736}
1737
fbd6baed
GV
1738#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1739#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1740 do \
1741 { \
1742 pe.peRed = GetRValue (color); \
1743 pe.peGreen = GetGValue (color); \
1744 pe.peBlue = GetBValue (color); \
1745 pe.peFlags = 0; \
1746 } while (0)
1747
1748#if 0
1749/* Keep these around in case we ever want to track color usage. */
1750void
fbd6baed 1751w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1752{
fbd6baed 1753 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1754
fbd6baed 1755 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1756 return;
1757
1758 /* check if color is already mapped */
1759 while (list)
1760 {
fbd6baed 1761 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1762 {
1763 ++list->refcount;
1764 return;
1765 }
1766 list = list->next;
1767 }
1768
1769 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1770 list = (struct w32_palette_entry *)
1771 xmalloc (sizeof (struct w32_palette_entry));
1772 SET_W32_COLOR (list->entry, color);
5ac45f98 1773 list->refcount = 1;
fbd6baed
GV
1774 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1775 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1776 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1777
1778 /* set flag that palette must be regenerated */
fbd6baed 1779 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1780}
1781
1782void
fbd6baed 1783w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1784{
fbd6baed
GV
1785 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1786 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1787
fbd6baed 1788 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1789 return;
1790
1791 /* check if color is already mapped */
1792 while (list)
1793 {
fbd6baed 1794 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1795 {
1796 if (--list->refcount == 0)
1797 {
1798 *prev = list->next;
1799 xfree (list);
fbd6baed 1800 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1801 break;
1802 }
1803 else
1804 return;
1805 }
1806 prev = &list->next;
1807 list = list->next;
1808 }
1809
1810 /* set flag that palette must be regenerated */
fbd6baed 1811 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1812}
1813#endif
1814
6fc2811b
JR
1815
1816/* Gamma-correct COLOR on frame F. */
1817
1818void
1819gamma_correct (f, color)
1820 struct frame *f;
1821 COLORREF *color;
1822{
1823 if (f->gamma)
1824 {
1825 *color = PALETTERGB (
1826 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1827 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1828 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1829 }
1830}
1831
1832
ee78dc32
GV
1833/* Decide if color named COLOR is valid for the display associated with
1834 the selected frame; if so, return the rgb values in COLOR_DEF.
1835 If ALLOC is nonzero, allocate a new colormap cell. */
1836
1837int
6fc2811b 1838w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1839 FRAME_PTR f;
1840 char *color;
6fc2811b 1841 XColor *color_def;
ee78dc32
GV
1842 int alloc;
1843{
1844 register Lisp_Object tem;
6fc2811b 1845 COLORREF w32_color_ref;
3c190163 1846
fbd6baed 1847 tem = x_to_w32_color (color);
3c190163 1848
ee78dc32
GV
1849 if (!NILP (tem))
1850 {
d88c567c
JR
1851 if (f)
1852 {
1853 /* Apply gamma correction. */
1854 w32_color_ref = XUINT (tem);
1855 gamma_correct (f, &w32_color_ref);
1856 XSETINT (tem, w32_color_ref);
1857 }
9badad41
JR
1858
1859 /* Map this color to the palette if it is enabled. */
fbd6baed 1860 if (!NILP (Vw32_enable_palette))
5ac45f98 1861 {
fbd6baed 1862 struct w32_palette_entry * entry =
d88c567c 1863 one_w32_display_info.color_list;
fbd6baed 1864 struct w32_palette_entry ** prev =
d88c567c 1865 &one_w32_display_info.color_list;
5ac45f98
GV
1866
1867 /* check if color is already mapped */
1868 while (entry)
1869 {
fbd6baed 1870 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1871 break;
1872 prev = &entry->next;
1873 entry = entry->next;
1874 }
1875
1876 if (entry == NULL && alloc)
1877 {
1878 /* not already mapped, so add to list */
fbd6baed
GV
1879 entry = (struct w32_palette_entry *)
1880 xmalloc (sizeof (struct w32_palette_entry));
1881 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1882 entry->next = NULL;
1883 *prev = entry;
d88c567c 1884 one_w32_display_info.num_colors++;
5ac45f98
GV
1885
1886 /* set flag that palette must be regenerated */
d88c567c 1887 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1888 }
1889 }
1890 /* Ensure COLORREF value is snapped to nearest color in (default)
1891 palette by simulating the PALETTERGB macro. This works whether
1892 or not the display device has a palette. */
6fc2811b
JR
1893 w32_color_ref = XUINT (tem) | 0x2000000;
1894
6fc2811b
JR
1895 color_def->pixel = w32_color_ref;
1896 color_def->red = GetRValue (w32_color_ref);
1897 color_def->green = GetGValue (w32_color_ref);
1898 color_def->blue = GetBValue (w32_color_ref);
1899
ee78dc32 1900 return 1;
5ac45f98 1901 }
7fb46567 1902 else
3c190163
GV
1903 {
1904 return 0;
1905 }
ee78dc32
GV
1906}
1907
1908/* Given a string ARG naming a color, compute a pixel value from it
1909 suitable for screen F.
1910 If F is not a color screen, return DEF (default) regardless of what
1911 ARG says. */
1912
1913int
1914x_decode_color (f, arg, def)
1915 FRAME_PTR f;
1916 Lisp_Object arg;
1917 int def;
1918{
6fc2811b 1919 XColor cdef;
ee78dc32
GV
1920
1921 CHECK_STRING (arg, 0);
1922
1923 if (strcmp (XSTRING (arg)->data, "black") == 0)
1924 return BLACK_PIX_DEFAULT (f);
1925 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1926 return WHITE_PIX_DEFAULT (f);
1927
fbd6baed 1928 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1929 return def;
1930
6fc2811b 1931 /* w32_defined_color is responsible for coping with failures
ee78dc32 1932 by looking for a near-miss. */
6fc2811b
JR
1933 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1934 return cdef.pixel;
ee78dc32
GV
1935
1936 /* defined_color failed; return an ultimate default. */
1937 return def;
1938}
1939\f
dfff8a69
JR
1940/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1941 the previous value of that parameter, NEW_VALUE is the new value. */
1942
1943static void
1944x_set_line_spacing (f, new_value, old_value)
1945 struct frame *f;
1946 Lisp_Object new_value, old_value;
1947{
1948 if (NILP (new_value))
1949 f->extra_line_spacing = 0;
1950 else if (NATNUMP (new_value))
1951 f->extra_line_spacing = XFASTINT (new_value);
1952 else
1a948b17 1953 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
1954 Fcons (new_value, Qnil)));
1955 if (FRAME_VISIBLE_P (f))
1956 redraw_frame (f);
1957}
1958
1959
6fc2811b
JR
1960/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1961 the previous value of that parameter, NEW_VALUE is the new value. */
1962
1963static void
1964x_set_screen_gamma (f, new_value, old_value)
1965 struct frame *f;
1966 Lisp_Object new_value, old_value;
1967{
1968 if (NILP (new_value))
1969 f->gamma = 0;
1970 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1971 /* The value 0.4545 is the normal viewing gamma. */
1972 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1973 else
1a948b17 1974 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
1975 Fcons (new_value, Qnil)));
1976
1977 clear_face_cache (0);
1978}
1979
1980
ee78dc32
GV
1981/* Functions called only from `x_set_frame_param'
1982 to set individual parameters.
1983
fbd6baed 1984 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1985 the frame is being created and its window does not exist yet.
1986 In that case, just record the parameter's new value
1987 in the standard place; do not attempt to change the window. */
1988
1989void
1990x_set_foreground_color (f, arg, oldval)
1991 struct frame *f;
1992 Lisp_Object arg, oldval;
1993{
6fc2811b 1994 FRAME_FOREGROUND_PIXEL (f)
ee78dc32 1995 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
5ac45f98 1996
fbd6baed 1997 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1998 {
6fc2811b 1999 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2000 if (FRAME_VISIBLE_P (f))
2001 redraw_frame (f);
2002 }
2003}
2004
2005void
2006x_set_background_color (f, arg, oldval)
2007 struct frame *f;
2008 Lisp_Object arg, oldval;
2009{
6fc2811b 2010 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2011 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2012
fbd6baed 2013 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2014 {
6fc2811b
JR
2015 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2016 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2017
6fc2811b 2018 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2019
2020 if (FRAME_VISIBLE_P (f))
2021 redraw_frame (f);
2022 }
2023}
2024
2025void
2026x_set_mouse_color (f, arg, oldval)
2027 struct frame *f;
2028 Lisp_Object arg, oldval;
2029{
ee78dc32 2030 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2031 int count;
ee78dc32
GV
2032 int mask_color;
2033
2034 if (!EQ (Qnil, arg))
fbd6baed 2035 f->output_data.w32->mouse_pixel
ee78dc32 2036 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2037 mask_color = FRAME_BACKGROUND_PIXEL (f);
2038
2039 /* Don't let pointers be invisible. */
fbd6baed 2040 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2041 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2042 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2043
767b1ff0 2044#if 0 /* TODO : cursor changes */
ee78dc32
GV
2045 BLOCK_INPUT;
2046
2047 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2048 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2049
2050 if (!EQ (Qnil, Vx_pointer_shape))
2051 {
2052 CHECK_NUMBER (Vx_pointer_shape, 0);
fbd6baed 2053 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2054 }
2055 else
fbd6baed
GV
2056 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2057 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2058
2059 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2060 {
2061 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
fbd6baed 2062 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2063 XINT (Vx_nontext_pointer_shape));
2064 }
2065 else
fbd6baed
GV
2066 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2067 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2068
6fc2811b
JR
2069 if (!EQ (Qnil, Vx_busy_pointer_shape))
2070 {
2071 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
2072 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2073 XINT (Vx_busy_pointer_shape));
2074 }
2075 else
2076 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2077 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2078
2079 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2080 if (!EQ (Qnil, Vx_mode_pointer_shape))
2081 {
2082 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
fbd6baed 2083 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2084 XINT (Vx_mode_pointer_shape));
2085 }
2086 else
fbd6baed
GV
2087 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2088 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2089
2090 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2091 {
2092 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2093 cross_cursor
fbd6baed 2094 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2095 XINT (Vx_sensitive_text_pointer_shape));
2096 }
2097 else
fbd6baed 2098 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2099
4694d762
JR
2100 if (!NILP (Vx_window_horizontal_drag_shape))
2101 {
2102 CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
2103 horizontal_drag_cursor
2104 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2105 XINT (Vx_window_horizontal_drag_shape));
2106 }
2107 else
2108 horizontal_drag_cursor
2109 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2110
ee78dc32 2111 /* Check and report errors with the above calls. */
fbd6baed 2112 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2113 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2114
2115 {
2116 XColor fore_color, back_color;
2117
fbd6baed 2118 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2119 back_color.pixel = mask_color;
fbd6baed
GV
2120 XQueryColor (FRAME_W32_DISPLAY (f),
2121 DefaultColormap (FRAME_W32_DISPLAY (f),
2122 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2123 &fore_color);
fbd6baed
GV
2124 XQueryColor (FRAME_W32_DISPLAY (f),
2125 DefaultColormap (FRAME_W32_DISPLAY (f),
2126 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2127 &back_color);
fbd6baed 2128 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2129 &fore_color, &back_color);
fbd6baed 2130 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2131 &fore_color, &back_color);
fbd6baed 2132 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2133 &fore_color, &back_color);
fbd6baed 2134 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2135 &fore_color, &back_color);
6fc2811b
JR
2136 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2137 &fore_color, &back_color);
ee78dc32
GV
2138 }
2139
fbd6baed 2140 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2141 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2142
fbd6baed
GV
2143 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2144 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2145 f->output_data.w32->text_cursor = cursor;
2146
2147 if (nontext_cursor != f->output_data.w32->nontext_cursor
2148 && f->output_data.w32->nontext_cursor != 0)
2149 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2150 f->output_data.w32->nontext_cursor = nontext_cursor;
2151
6fc2811b
JR
2152 if (busy_cursor != f->output_data.w32->busy_cursor
2153 && f->output_data.w32->busy_cursor != 0)
2154 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2155 f->output_data.w32->busy_cursor = busy_cursor;
2156
fbd6baed
GV
2157 if (mode_cursor != f->output_data.w32->modeline_cursor
2158 && f->output_data.w32->modeline_cursor != 0)
2159 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2160 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2161
fbd6baed
GV
2162 if (cross_cursor != f->output_data.w32->cross_cursor
2163 && f->output_data.w32->cross_cursor != 0)
2164 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2165 f->output_data.w32->cross_cursor = cross_cursor;
2166
2167 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2168 UNBLOCK_INPUT;
6fc2811b
JR
2169
2170 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2171#endif /* TODO */
ee78dc32
GV
2172}
2173
70a0239a
JR
2174/* Defined in w32term.c. */
2175void x_update_cursor (struct frame *f, int on_p);
2176
ee78dc32
GV
2177void
2178x_set_cursor_color (f, arg, oldval)
2179 struct frame *f;
2180 Lisp_Object arg, oldval;
2181{
70a0239a 2182 unsigned long fore_pixel, pixel;
ee78dc32 2183
dfff8a69 2184 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2185 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2186 WHITE_PIX_DEFAULT (f));
ee78dc32 2187 else
6fc2811b 2188 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2189
6759f872 2190 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2191
2192 /* Make sure that the cursor color differs from the background color. */
70a0239a 2193 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2194 {
70a0239a
JR
2195 pixel = f->output_data.w32->mouse_pixel;
2196 if (pixel == fore_pixel)
6fc2811b 2197 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2198 }
70a0239a 2199
6fc2811b 2200 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
70a0239a 2201 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2202
fbd6baed 2203 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2204 {
2205 if (FRAME_VISIBLE_P (f))
2206 {
70a0239a
JR
2207 x_update_cursor (f, 0);
2208 x_update_cursor (f, 1);
ee78dc32
GV
2209 }
2210 }
6fc2811b
JR
2211
2212 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2213}
2214
33d52f9c
GV
2215/* Set the border-color of frame F to pixel value PIX.
2216 Note that this does not fully take effect if done before
2217 F has an window. */
2218void
2219x_set_border_pixel (f, pix)
2220 struct frame *f;
2221 int pix;
2222{
2223 f->output_data.w32->border_pixel = pix;
2224
2225 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2226 {
2227 if (FRAME_VISIBLE_P (f))
2228 redraw_frame (f);
2229 }
2230}
2231
ee78dc32
GV
2232/* Set the border-color of frame F to value described by ARG.
2233 ARG can be a string naming a color.
2234 The border-color is used for the border that is drawn by the server.
2235 Note that this does not fully take effect if done before
2236 F has a window; it must be redone when the window is created. */
2237
2238void
2239x_set_border_color (f, arg, oldval)
2240 struct frame *f;
2241 Lisp_Object arg, oldval;
2242{
ee78dc32
GV
2243 int pix;
2244
2245 CHECK_STRING (arg, 0);
ee78dc32 2246 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2247 x_set_border_pixel (f, pix);
6fc2811b 2248 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2249}
2250
dfff8a69
JR
2251/* Value is the internal representation of the specified cursor type
2252 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2253 of the bar cursor. */
2254
2255enum text_cursor_kinds
2256x_specified_cursor_type (arg, width)
2257 Lisp_Object arg;
2258 int *width;
ee78dc32 2259{
dfff8a69
JR
2260 enum text_cursor_kinds type;
2261
ee78dc32
GV
2262 if (EQ (arg, Qbar))
2263 {
dfff8a69
JR
2264 type = BAR_CURSOR;
2265 *width = 2;
ee78dc32 2266 }
dfff8a69
JR
2267 else if (CONSP (arg)
2268 && EQ (XCAR (arg), Qbar)
2269 && INTEGERP (XCDR (arg))
2270 && XINT (XCDR (arg)) >= 0)
ee78dc32 2271 {
dfff8a69
JR
2272 type = BAR_CURSOR;
2273 *width = XINT (XCDR (arg));
ee78dc32 2274 }
dfff8a69
JR
2275 else if (NILP (arg))
2276 type = NO_CURSOR;
ee78dc32
GV
2277 else
2278 /* Treat anything unknown as "box cursor".
2279 It was bad to signal an error; people have trouble fixing
2280 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2281 type = FILLED_BOX_CURSOR;
2282
2283 return type;
2284}
2285
2286void
2287x_set_cursor_type (f, arg, oldval)
2288 FRAME_PTR f;
2289 Lisp_Object arg, oldval;
2290{
2291 int width;
2292
2293 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2294 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2295
2296 /* Make sure the cursor gets redrawn. This is overkill, but how
2297 often do people change cursor types? */
2298 update_mode_lines++;
2299}
dfff8a69 2300\f
ee78dc32
GV
2301void
2302x_set_icon_type (f, arg, oldval)
2303 struct frame *f;
2304 Lisp_Object arg, oldval;
2305{
ee78dc32
GV
2306 int result;
2307
eb7576ce
GV
2308 if (NILP (arg) && NILP (oldval))
2309 return;
2310
2311 if (STRINGP (arg) && STRINGP (oldval)
2312 && EQ (Fstring_equal (oldval, arg), Qt))
2313 return;
2314
2315 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2316 return;
2317
2318 BLOCK_INPUT;
ee78dc32 2319
eb7576ce 2320 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2321 if (result)
2322 {
2323 UNBLOCK_INPUT;
2324 error ("No icon window available");
2325 }
2326
ee78dc32 2327 UNBLOCK_INPUT;
ee78dc32
GV
2328}
2329
2330/* Return non-nil if frame F wants a bitmap icon. */
2331
2332Lisp_Object
2333x_icon_type (f)
2334 FRAME_PTR f;
2335{
2336 Lisp_Object tem;
2337
2338 tem = assq_no_quit (Qicon_type, f->param_alist);
2339 if (CONSP (tem))
8e713be6 2340 return XCDR (tem);
ee78dc32
GV
2341 else
2342 return Qnil;
2343}
2344
2345void
2346x_set_icon_name (f, arg, oldval)
2347 struct frame *f;
2348 Lisp_Object arg, oldval;
2349{
ee78dc32
GV
2350 int result;
2351
2352 if (STRINGP (arg))
2353 {
2354 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2355 return;
2356 }
2357 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2358 return;
2359
2360 f->icon_name = arg;
2361
2362#if 0
fbd6baed 2363 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2364 return;
2365
2366 BLOCK_INPUT;
2367
2368 result = x_text_icon (f,
1edf84e7 2369 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2370 ? f->icon_name
1edf84e7
GV
2371 : !NILP (f->title)
2372 ? f->title
ee78dc32
GV
2373 : f->name))->data);
2374
2375 if (result)
2376 {
2377 UNBLOCK_INPUT;
2378 error ("No icon window available");
2379 }
2380
2381 /* If the window was unmapped (and its icon was mapped),
2382 the new icon is not mapped, so map the window in its stead. */
2383 if (FRAME_VISIBLE_P (f))
2384 {
2385#ifdef USE_X_TOOLKIT
fbd6baed 2386 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2387#endif
fbd6baed 2388 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2389 }
2390
fbd6baed 2391 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2392 UNBLOCK_INPUT;
2393#endif
2394}
2395
2396extern Lisp_Object x_new_font ();
4587b026 2397extern Lisp_Object x_new_fontset();
ee78dc32
GV
2398
2399void
2400x_set_font (f, arg, oldval)
2401 struct frame *f;
2402 Lisp_Object arg, oldval;
2403{
2404 Lisp_Object result;
4587b026 2405 Lisp_Object fontset_name;
4b817373 2406 Lisp_Object frame;
ee78dc32
GV
2407
2408 CHECK_STRING (arg, 1);
2409
4587b026
GV
2410 fontset_name = Fquery_fontset (arg, Qnil);
2411
ee78dc32 2412 BLOCK_INPUT;
4587b026
GV
2413 result = (STRINGP (fontset_name)
2414 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2415 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2416 UNBLOCK_INPUT;
2417
2418 if (EQ (result, Qnil))
dfff8a69 2419 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2420 else if (EQ (result, Qt))
dfff8a69 2421 error ("The characters of the given font have varying widths");
ee78dc32
GV
2422 else if (STRINGP (result))
2423 {
ee78dc32 2424 store_frame_param (f, Qfont, result);
6fc2811b 2425 recompute_basic_faces (f);
ee78dc32
GV
2426 }
2427 else
2428 abort ();
4b817373 2429
6fc2811b
JR
2430 do_pending_window_change (0);
2431
2432 /* Don't call `face-set-after-frame-default' when faces haven't been
2433 initialized yet. This is the case when called from
2434 Fx_create_frame. In that case, the X widget or window doesn't
2435 exist either, and we can end up in x_report_frame_params with a
2436 null widget which gives a segfault. */
2437 if (FRAME_FACE_CACHE (f))
2438 {
2439 XSETFRAME (frame, f);
2440 call1 (Qface_set_after_frame_default, frame);
2441 }
ee78dc32
GV
2442}
2443
2444void
2445x_set_border_width (f, arg, oldval)
2446 struct frame *f;
2447 Lisp_Object arg, oldval;
2448{
2449 CHECK_NUMBER (arg, 0);
2450
fbd6baed 2451 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2452 return;
2453
fbd6baed 2454 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2455 error ("Cannot change the border width of a window");
2456
fbd6baed 2457 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2458}
2459
2460void
2461x_set_internal_border_width (f, arg, oldval)
2462 struct frame *f;
2463 Lisp_Object arg, oldval;
2464{
fbd6baed 2465 int old = f->output_data.w32->internal_border_width;
ee78dc32
GV
2466
2467 CHECK_NUMBER (arg, 0);
fbd6baed
GV
2468 f->output_data.w32->internal_border_width = XINT (arg);
2469 if (f->output_data.w32->internal_border_width < 0)
2470 f->output_data.w32->internal_border_width = 0;
ee78dc32 2471
fbd6baed 2472 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2473 return;
2474
fbd6baed 2475 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2476 {
ee78dc32 2477 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2478 SET_FRAME_GARBAGED (f);
6fc2811b 2479 do_pending_window_change (0);
ee78dc32
GV
2480 }
2481}
2482
2483void
2484x_set_visibility (f, value, oldval)
2485 struct frame *f;
2486 Lisp_Object value, oldval;
2487{
2488 Lisp_Object frame;
2489 XSETFRAME (frame, f);
2490
2491 if (NILP (value))
2492 Fmake_frame_invisible (frame, Qt);
2493 else if (EQ (value, Qicon))
2494 Ficonify_frame (frame);
2495 else
2496 Fmake_frame_visible (frame);
2497}
2498
a1258667
JR
2499\f
2500/* Change window heights in windows rooted in WINDOW by N lines. */
2501
2502static void
2503x_change_window_heights (window, n)
2504 Lisp_Object window;
2505 int n;
2506{
2507 struct window *w = XWINDOW (window);
2508
2509 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2510 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2511
2512 if (INTEGERP (w->orig_top))
2513 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2514 if (INTEGERP (w->orig_height))
2515 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2516
2517 /* Handle just the top child in a vertical split. */
2518 if (!NILP (w->vchild))
2519 x_change_window_heights (w->vchild, n);
2520
2521 /* Adjust all children in a horizontal split. */
2522 for (window = w->hchild; !NILP (window); window = w->next)
2523 {
2524 w = XWINDOW (window);
2525 x_change_window_heights (window, n);
2526 }
2527}
2528
ee78dc32
GV
2529void
2530x_set_menu_bar_lines (f, value, oldval)
2531 struct frame *f;
2532 Lisp_Object value, oldval;
2533{
2534 int nlines;
2535 int olines = FRAME_MENU_BAR_LINES (f);
2536
2537 /* Right now, menu bars don't work properly in minibuf-only frames;
2538 most of the commands try to apply themselves to the minibuffer
6fc2811b 2539 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2540 in or split the minibuffer window. */
2541 if (FRAME_MINIBUF_ONLY_P (f))
2542 return;
2543
2544 if (INTEGERP (value))
2545 nlines = XINT (value);
2546 else
2547 nlines = 0;
2548
2549 FRAME_MENU_BAR_LINES (f) = 0;
2550 if (nlines)
2551 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2552 else
2553 {
2554 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2555 free_frame_menubar (f);
2556 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2557
2558 /* Adjust the frame size so that the client (text) dimensions
2559 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2560 set correctly. */
2561 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2562 do_pending_window_change (0);
ee78dc32 2563 }
6fc2811b
JR
2564 adjust_glyphs (f);
2565}
2566
2567
2568/* Set the number of lines used for the tool bar of frame F to VALUE.
2569 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2570 is the old number of tool bar lines. This function changes the
2571 height of all windows on frame F to match the new tool bar height.
2572 The frame's height doesn't change. */
2573
2574void
2575x_set_tool_bar_lines (f, value, oldval)
2576 struct frame *f;
2577 Lisp_Object value, oldval;
2578{
36f8209a
JR
2579 int delta, nlines, root_height;
2580 Lisp_Object root_window;
6fc2811b
JR
2581
2582 /* Use VALUE only if an integer >= 0. */
2583 if (INTEGERP (value) && XINT (value) >= 0)
2584 nlines = XFASTINT (value);
2585 else
2586 nlines = 0;
2587
2588 /* Make sure we redisplay all windows in this frame. */
2589 ++windows_or_buffers_changed;
2590
2591 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2592
2593 /* Don't resize the tool-bar to more than we have room for. */
2594 root_window = FRAME_ROOT_WINDOW (f);
2595 root_height = XINT (XWINDOW (root_window)->height);
2596 if (root_height - delta < 1)
2597 {
2598 delta = root_height - 1;
2599 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2600 }
2601
6fc2811b 2602 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2603 x_change_window_heights (root_window, delta);
6fc2811b 2604 adjust_glyphs (f);
36f8209a
JR
2605
2606 /* We also have to make sure that the internal border at the top of
2607 the frame, below the menu bar or tool bar, is redrawn when the
2608 tool bar disappears. This is so because the internal border is
2609 below the tool bar if one is displayed, but is below the menu bar
2610 if there isn't a tool bar. The tool bar draws into the area
2611 below the menu bar. */
2612 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2613 {
2614 updating_frame = f;
2615 clear_frame ();
2616 clear_current_matrices (f);
2617 updating_frame = NULL;
2618 }
2619
2620 /* If the tool bar gets smaller, the internal border below it
2621 has to be cleared. It was formerly part of the display
2622 of the larger tool bar, and updating windows won't clear it. */
2623 if (delta < 0)
2624 {
2625 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2626 int width = PIXEL_WIDTH (f);
2627 int y = nlines * CANON_Y_UNIT (f);
2628
2629 BLOCK_INPUT;
2630 {
2631 HDC hdc = get_frame_dc (f);
2632 w32_clear_area (f, hdc, 0, y, width, height);
2633 release_frame_dc (f, hdc);
2634 }
2635 UNBLOCK_INPUT;
2636 }
ee78dc32
GV
2637}
2638
6fc2811b 2639
ee78dc32 2640/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2641 w32_id_name.
ee78dc32
GV
2642
2643 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2644 name; if NAME is a string, set F's name to NAME and set
2645 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2646
2647 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2648 suggesting a new name, which lisp code should override; if
2649 F->explicit_name is set, ignore the new name; otherwise, set it. */
2650
2651void
2652x_set_name (f, name, explicit)
2653 struct frame *f;
2654 Lisp_Object name;
2655 int explicit;
2656{
2657 /* Make sure that requests from lisp code override requests from
2658 Emacs redisplay code. */
2659 if (explicit)
2660 {
2661 /* If we're switching from explicit to implicit, we had better
2662 update the mode lines and thereby update the title. */
2663 if (f->explicit_name && NILP (name))
2664 update_mode_lines = 1;
2665
2666 f->explicit_name = ! NILP (name);
2667 }
2668 else if (f->explicit_name)
2669 return;
2670
fbd6baed 2671 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2672 if (NILP (name))
2673 {
2674 /* Check for no change needed in this very common case
2675 before we do any consing. */
fbd6baed 2676 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2677 XSTRING (f->name)->data))
2678 return;
fbd6baed 2679 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2680 }
2681 else
2682 CHECK_STRING (name, 0);
2683
2684 /* Don't change the name if it's already NAME. */
2685 if (! NILP (Fstring_equal (name, f->name)))
2686 return;
2687
1edf84e7
GV
2688 f->name = name;
2689
2690 /* For setting the frame title, the title parameter should override
2691 the name parameter. */
2692 if (! NILP (f->title))
2693 name = f->title;
2694
fbd6baed 2695 if (FRAME_W32_WINDOW (f))
ee78dc32 2696 {
6fc2811b 2697 if (STRING_MULTIBYTE (name))
dfff8a69 2698 name = ENCODE_SYSTEM (name);
6fc2811b 2699
ee78dc32 2700 BLOCK_INPUT;
fbd6baed 2701 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2702 UNBLOCK_INPUT;
2703 }
ee78dc32
GV
2704}
2705
2706/* This function should be called when the user's lisp code has
2707 specified a name for the frame; the name will override any set by the
2708 redisplay code. */
2709void
2710x_explicitly_set_name (f, arg, oldval)
2711 FRAME_PTR f;
2712 Lisp_Object arg, oldval;
2713{
2714 x_set_name (f, arg, 1);
2715}
2716
2717/* This function should be called by Emacs redisplay code to set the
2718 name; names set this way will never override names set by the user's
2719 lisp code. */
2720void
2721x_implicitly_set_name (f, arg, oldval)
2722 FRAME_PTR f;
2723 Lisp_Object arg, oldval;
2724{
2725 x_set_name (f, arg, 0);
2726}
1edf84e7
GV
2727\f
2728/* Change the title of frame F to NAME.
2729 If NAME is nil, use the frame name as the title.
2730
2731 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2732 name; if NAME is a string, set F's name to NAME and set
2733 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2734
2735 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2736 suggesting a new name, which lisp code should override; if
2737 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2738
1edf84e7 2739void
6fc2811b 2740x_set_title (f, name, old_name)
1edf84e7 2741 struct frame *f;
6fc2811b 2742 Lisp_Object name, old_name;
1edf84e7
GV
2743{
2744 /* Don't change the title if it's already NAME. */
2745 if (EQ (name, f->title))
2746 return;
2747
2748 update_mode_lines = 1;
2749
2750 f->title = name;
2751
2752 if (NILP (name))
2753 name = f->name;
2754
2755 if (FRAME_W32_WINDOW (f))
2756 {
6fc2811b 2757 if (STRING_MULTIBYTE (name))
dfff8a69 2758 name = ENCODE_SYSTEM (name);
6fc2811b 2759
1edf84e7
GV
2760 BLOCK_INPUT;
2761 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2762 UNBLOCK_INPUT;
2763 }
2764}
2765\f
ee78dc32
GV
2766void
2767x_set_autoraise (f, arg, oldval)
2768 struct frame *f;
2769 Lisp_Object arg, oldval;
2770{
2771 f->auto_raise = !EQ (Qnil, arg);
2772}
2773
2774void
2775x_set_autolower (f, arg, oldval)
2776 struct frame *f;
2777 Lisp_Object arg, oldval;
2778{
2779 f->auto_lower = !EQ (Qnil, arg);
2780}
2781
2782void
2783x_set_unsplittable (f, arg, oldval)
2784 struct frame *f;
2785 Lisp_Object arg, oldval;
2786{
2787 f->no_split = !NILP (arg);
2788}
2789
2790void
2791x_set_vertical_scroll_bars (f, arg, oldval)
2792 struct frame *f;
2793 Lisp_Object arg, oldval;
2794{
1026b400
RS
2795 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2796 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2797 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2798 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2799 {
1026b400
RS
2800 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2801 vertical_scroll_bar_none :
87996783
GV
2802 /* Put scroll bars on the right by default, as is conventional
2803 on MS-Windows. */
2804 EQ (Qleft, arg)
2805 ? vertical_scroll_bar_left
2806 : vertical_scroll_bar_right;
ee78dc32
GV
2807
2808 /* We set this parameter before creating the window for the
2809 frame, so we can get the geometry right from the start.
2810 However, if the window hasn't been created yet, we shouldn't
2811 call x_set_window_size. */
fbd6baed 2812 if (FRAME_W32_WINDOW (f))
ee78dc32 2813 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2814 do_pending_window_change (0);
ee78dc32
GV
2815 }
2816}
2817
2818void
2819x_set_scroll_bar_width (f, arg, oldval)
2820 struct frame *f;
2821 Lisp_Object arg, oldval;
2822{
6fc2811b
JR
2823 int wid = FONT_WIDTH (f->output_data.w32->font);
2824
ee78dc32
GV
2825 if (NILP (arg))
2826 {
6fc2811b
JR
2827 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2828 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2829 wid - 1) / wid;
2830 if (FRAME_W32_WINDOW (f))
2831 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2832 do_pending_window_change (0);
ee78dc32
GV
2833 }
2834 else if (INTEGERP (arg) && XINT (arg) > 0
2835 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2836 {
ee78dc32 2837 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2838 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2839 + wid-1) / wid;
fbd6baed 2840 if (FRAME_W32_WINDOW (f))
ee78dc32 2841 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2842 do_pending_window_change (0);
ee78dc32 2843 }
6fc2811b
JR
2844 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2845 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2846 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2847}
2848\f
2849/* Subroutines of creating an frame. */
2850
2851/* Make sure that Vx_resource_name is set to a reasonable value.
2852 Fix it up, or set it to `emacs' if it is too hopeless. */
2853
2854static void
2855validate_x_resource_name ()
2856{
6fc2811b 2857 int len = 0;
ee78dc32
GV
2858 /* Number of valid characters in the resource name. */
2859 int good_count = 0;
2860 /* Number of invalid characters in the resource name. */
2861 int bad_count = 0;
2862 Lisp_Object new;
2863 int i;
2864
2865 if (STRINGP (Vx_resource_name))
2866 {
2867 unsigned char *p = XSTRING (Vx_resource_name)->data;
2868 int i;
2869
dfff8a69 2870 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2871
2872 /* Only letters, digits, - and _ are valid in resource names.
2873 Count the valid characters and count the invalid ones. */
2874 for (i = 0; i < len; i++)
2875 {
2876 int c = p[i];
2877 if (! ((c >= 'a' && c <= 'z')
2878 || (c >= 'A' && c <= 'Z')
2879 || (c >= '0' && c <= '9')
2880 || c == '-' || c == '_'))
2881 bad_count++;
2882 else
2883 good_count++;
2884 }
2885 }
2886 else
2887 /* Not a string => completely invalid. */
2888 bad_count = 5, good_count = 0;
2889
2890 /* If name is valid already, return. */
2891 if (bad_count == 0)
2892 return;
2893
2894 /* If name is entirely invalid, or nearly so, use `emacs'. */
2895 if (good_count == 0
2896 || (good_count == 1 && bad_count > 0))
2897 {
2898 Vx_resource_name = build_string ("emacs");
2899 return;
2900 }
2901
2902 /* Name is partly valid. Copy it and replace the invalid characters
2903 with underscores. */
2904
2905 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2906
2907 for (i = 0; i < len; i++)
2908 {
2909 int c = XSTRING (new)->data[i];
2910 if (! ((c >= 'a' && c <= 'z')
2911 || (c >= 'A' && c <= 'Z')
2912 || (c >= '0' && c <= '9')
2913 || c == '-' || c == '_'))
2914 XSTRING (new)->data[i] = '_';
2915 }
2916}
2917
2918
2919extern char *x_get_string_resource ();
2920
2921DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2922 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2923This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2924class, where INSTANCE is the name under which Emacs was invoked, or\n\
2925the name specified by the `-name' or `-rn' command-line arguments.\n\
2926\n\
2927The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2928class, respectively. You must specify both of them or neither.\n\
2929If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2930and the class is `Emacs.CLASS.SUBCLASS'.")
2931 (attribute, class, component, subclass)
2932 Lisp_Object attribute, class, component, subclass;
2933{
2934 register char *value;
2935 char *name_key;
2936 char *class_key;
2937
2938 CHECK_STRING (attribute, 0);
2939 CHECK_STRING (class, 0);
2940
2941 if (!NILP (component))
2942 CHECK_STRING (component, 1);
2943 if (!NILP (subclass))
2944 CHECK_STRING (subclass, 2);
2945 if (NILP (component) != NILP (subclass))
2946 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2947
2948 validate_x_resource_name ();
2949
2950 /* Allocate space for the components, the dots which separate them,
2951 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 2952 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 2953 + (STRINGP (component)
dfff8a69
JR
2954 ? STRING_BYTES (XSTRING (component)) : 0)
2955 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
2956 + 3);
2957
2958 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 2959 + STRING_BYTES (XSTRING (class))
ee78dc32 2960 + (STRINGP (subclass)
dfff8a69 2961 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
2962 + 3);
2963
2964 /* Start with emacs.FRAMENAME for the name (the specific one)
2965 and with `Emacs' for the class key (the general one). */
2966 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2967 strcpy (class_key, EMACS_CLASS);
2968
2969 strcat (class_key, ".");
2970 strcat (class_key, XSTRING (class)->data);
2971
2972 if (!NILP (component))
2973 {
2974 strcat (class_key, ".");
2975 strcat (class_key, XSTRING (subclass)->data);
2976
2977 strcat (name_key, ".");
2978 strcat (name_key, XSTRING (component)->data);
2979 }
2980
2981 strcat (name_key, ".");
2982 strcat (name_key, XSTRING (attribute)->data);
2983
2984 value = x_get_string_resource (Qnil,
2985 name_key, class_key);
2986
2987 if (value != (char *) 0)
2988 return build_string (value);
2989 else
2990 return Qnil;
2991}
2992
2993/* Used when C code wants a resource value. */
2994
2995char *
2996x_get_resource_string (attribute, class)
2997 char *attribute, *class;
2998{
ee78dc32
GV
2999 char *name_key;
3000 char *class_key;
6fc2811b 3001 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3002
3003 /* Allocate space for the components, the dots which separate them,
3004 and the final '\0'. */
dfff8a69 3005 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3006 + strlen (attribute) + 2);
3007 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3008 + strlen (class) + 2);
3009
3010 sprintf (name_key, "%s.%s",
3011 XSTRING (Vinvocation_name)->data,
3012 attribute);
3013 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3014
6fc2811b 3015 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3016}
3017
3018/* Types we might convert a resource string into. */
3019enum resource_types
6fc2811b
JR
3020{
3021 RES_TYPE_NUMBER,
3022 RES_TYPE_FLOAT,
3023 RES_TYPE_BOOLEAN,
3024 RES_TYPE_STRING,
3025 RES_TYPE_SYMBOL
3026};
ee78dc32
GV
3027
3028/* Return the value of parameter PARAM.
3029
3030 First search ALIST, then Vdefault_frame_alist, then the X defaults
3031 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3032
3033 Convert the resource to the type specified by desired_type.
3034
3035 If no default is specified, return Qunbound. If you call
6fc2811b 3036 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3037 and don't let it get stored in any Lisp-visible variables! */
3038
3039static Lisp_Object
6fc2811b 3040w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3041 Lisp_Object alist, param;
3042 char *attribute;
3043 char *class;
3044 enum resource_types type;
3045{
3046 register Lisp_Object tem;
3047
3048 tem = Fassq (param, alist);
3049 if (EQ (tem, Qnil))
3050 tem = Fassq (param, Vdefault_frame_alist);
3051 if (EQ (tem, Qnil))
3052 {
3053
3054 if (attribute)
3055 {
3056 tem = Fx_get_resource (build_string (attribute),
3057 build_string (class),
3058 Qnil, Qnil);
3059
3060 if (NILP (tem))
3061 return Qunbound;
3062
3063 switch (type)
3064 {
6fc2811b 3065 case RES_TYPE_NUMBER:
ee78dc32
GV
3066 return make_number (atoi (XSTRING (tem)->data));
3067
6fc2811b
JR
3068 case RES_TYPE_FLOAT:
3069 return make_float (atof (XSTRING (tem)->data));
3070
3071 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3072 tem = Fdowncase (tem);
3073 if (!strcmp (XSTRING (tem)->data, "on")
3074 || !strcmp (XSTRING (tem)->data, "true"))
3075 return Qt;
3076 else
3077 return Qnil;
3078
6fc2811b 3079 case RES_TYPE_STRING:
ee78dc32
GV
3080 return tem;
3081
6fc2811b 3082 case RES_TYPE_SYMBOL:
ee78dc32
GV
3083 /* As a special case, we map the values `true' and `on'
3084 to Qt, and `false' and `off' to Qnil. */
3085 {
3086 Lisp_Object lower;
3087 lower = Fdowncase (tem);
3088 if (!strcmp (XSTRING (lower)->data, "on")
3089 || !strcmp (XSTRING (lower)->data, "true"))
3090 return Qt;
3091 else if (!strcmp (XSTRING (lower)->data, "off")
3092 || !strcmp (XSTRING (lower)->data, "false"))
3093 return Qnil;
3094 else
3095 return Fintern (tem, Qnil);
3096 }
3097
3098 default:
3099 abort ();
3100 }
3101 }
3102 else
3103 return Qunbound;
3104 }
3105 return Fcdr (tem);
3106}
3107
3108/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3109 of the parameter named PROP (a Lisp symbol).
3110 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3111 on the frame named NAME.
3112 If that is not found either, use the value DEFLT. */
3113
3114static Lisp_Object
3115x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3116 struct frame *f;
3117 Lisp_Object alist;
3118 Lisp_Object prop;
3119 Lisp_Object deflt;
3120 char *xprop;
3121 char *xclass;
3122 enum resource_types type;
3123{
3124 Lisp_Object tem;
3125
6fc2811b 3126 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3127 if (EQ (tem, Qunbound))
3128 tem = deflt;
3129 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3130 return tem;
3131}
3132\f
3133DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3134 "Parse an X-style geometry string STRING.\n\
3135Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3136The properties returned may include `top', `left', `height', and `width'.\n\
3137The value of `left' or `top' may be an integer,\n\
3138or a list (+ N) meaning N pixels relative to top/left corner,\n\
3139or a list (- N) meaning -N pixels relative to bottom/right corner.")
3140 (string)
3141 Lisp_Object string;
3142{
3143 int geometry, x, y;
3144 unsigned int width, height;
3145 Lisp_Object result;
3146
3147 CHECK_STRING (string, 0);
3148
3149 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3150 &x, &y, &width, &height);
3151
3152 result = Qnil;
3153 if (geometry & XValue)
3154 {
3155 Lisp_Object element;
3156
3157 if (x >= 0 && (geometry & XNegative))
3158 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3159 else if (x < 0 && ! (geometry & XNegative))
3160 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3161 else
3162 element = Fcons (Qleft, make_number (x));
3163 result = Fcons (element, result);
3164 }
3165
3166 if (geometry & YValue)
3167 {
3168 Lisp_Object element;
3169
3170 if (y >= 0 && (geometry & YNegative))
3171 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3172 else if (y < 0 && ! (geometry & YNegative))
3173 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3174 else
3175 element = Fcons (Qtop, make_number (y));
3176 result = Fcons (element, result);
3177 }
3178
3179 if (geometry & WidthValue)
3180 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3181 if (geometry & HeightValue)
3182 result = Fcons (Fcons (Qheight, make_number (height)), result);
3183
3184 return result;
3185}
3186
3187/* Calculate the desired size and position of this window,
3188 and return the flags saying which aspects were specified.
3189
3190 This function does not make the coordinates positive. */
3191
3192#define DEFAULT_ROWS 40
3193#define DEFAULT_COLS 80
3194
3195static int
3196x_figure_window_size (f, parms)
3197 struct frame *f;
3198 Lisp_Object parms;
3199{
3200 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3201 long window_prompting = 0;
3202
3203 /* Default values if we fall through.
3204 Actually, if that happens we should get
3205 window manager prompting. */
1026b400 3206 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3207 f->height = DEFAULT_ROWS;
3208 /* Window managers expect that if program-specified
3209 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3210 f->output_data.w32->top_pos = 0;
3211 f->output_data.w32->left_pos = 0;
ee78dc32 3212
6fc2811b
JR
3213 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3214 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3215 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3216 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3217 {
3218 if (!EQ (tem0, Qunbound))
3219 {
3220 CHECK_NUMBER (tem0, 0);
3221 f->height = XINT (tem0);
3222 }
3223 if (!EQ (tem1, Qunbound))
3224 {
3225 CHECK_NUMBER (tem1, 0);
1026b400 3226 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3227 }
3228 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3229 window_prompting |= USSize;
3230 else
3231 window_prompting |= PSize;
3232 }
3233
fbd6baed 3234 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3235 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3236 ? 0
3237 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3238 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3239 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
6fc2811b
JR
3240 f->output_data.w32->flags_areas_extra
3241 = FRAME_FLAGS_AREA_WIDTH (f);
fbd6baed
GV
3242 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3243 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3244
6fc2811b
JR
3245 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3246 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3247 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3248 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3249 {
3250 if (EQ (tem0, Qminus))
3251 {
fbd6baed 3252 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3253 window_prompting |= YNegative;
3254 }
8e713be6
KR
3255 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3256 && CONSP (XCDR (tem0))
3257 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3258 {
8e713be6 3259 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3260 window_prompting |= YNegative;
3261 }
8e713be6
KR
3262 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3263 && CONSP (XCDR (tem0))
3264 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3265 {
8e713be6 3266 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3267 }
3268 else if (EQ (tem0, Qunbound))
fbd6baed 3269 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3270 else
3271 {
3272 CHECK_NUMBER (tem0, 0);
fbd6baed
GV
3273 f->output_data.w32->top_pos = XINT (tem0);
3274 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3275 window_prompting |= YNegative;
3276 }
3277
3278 if (EQ (tem1, Qminus))
3279 {
fbd6baed 3280 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3281 window_prompting |= XNegative;
3282 }
8e713be6
KR
3283 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3284 && CONSP (XCDR (tem1))
3285 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3286 {
8e713be6 3287 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3288 window_prompting |= XNegative;
3289 }
8e713be6
KR
3290 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3291 && CONSP (XCDR (tem1))
3292 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3293 {
8e713be6 3294 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3295 }
3296 else if (EQ (tem1, Qunbound))
fbd6baed 3297 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3298 else
3299 {
3300 CHECK_NUMBER (tem1, 0);
fbd6baed
GV
3301 f->output_data.w32->left_pos = XINT (tem1);
3302 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3303 window_prompting |= XNegative;
3304 }
3305
3306 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3307 window_prompting |= USPosition;
3308 else
3309 window_prompting |= PPosition;
3310 }
3311
3312 return window_prompting;
3313}
3314
3315\f
3316
fbd6baed 3317extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3318
3319BOOL
fbd6baed 3320w32_init_class (hinst)
ee78dc32
GV
3321 HINSTANCE hinst;
3322{
3323 WNDCLASS wc;
3324
5ac45f98 3325 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3326 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3327 wc.cbClsExtra = 0;
3328 wc.cbWndExtra = WND_EXTRA_BYTES;
3329 wc.hInstance = hinst;
3330 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3331 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3332 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3333 wc.lpszMenuName = NULL;
3334 wc.lpszClassName = EMACS_CLASS;
3335
3336 return (RegisterClass (&wc));
3337}
3338
3339HWND
fbd6baed 3340w32_createscrollbar (f, bar)
ee78dc32
GV
3341 struct frame *f;
3342 struct scroll_bar * bar;
3343{
3344 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3345 /* Position and size of scroll bar. */
6fc2811b
JR
3346 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3347 XINT(bar->top),
3348 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3349 XINT(bar->height),
fbd6baed 3350 FRAME_W32_WINDOW (f),
ee78dc32
GV
3351 NULL,
3352 hinst,
3353 NULL));
3354}
3355
3356void
fbd6baed 3357w32_createwindow (f)
ee78dc32
GV
3358 struct frame *f;
3359{
3360 HWND hwnd;
1edf84e7
GV
3361 RECT rect;
3362
3363 rect.left = rect.top = 0;
3364 rect.right = PIXEL_WIDTH (f);
3365 rect.bottom = PIXEL_HEIGHT (f);
3366
3367 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3368 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3369
3370 /* Do first time app init */
3371
3372 if (!hprevinst)
3373 {
fbd6baed 3374 w32_init_class (hinst);
ee78dc32
GV
3375 }
3376
1edf84e7
GV
3377 FRAME_W32_WINDOW (f) = hwnd
3378 = CreateWindow (EMACS_CLASS,
3379 f->namebuf,
3380 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3381 f->output_data.w32->left_pos,
3382 f->output_data.w32->top_pos,
3383 rect.right - rect.left,
3384 rect.bottom - rect.top,
3385 NULL,
3386 NULL,
3387 hinst,
3388 NULL);
3389
ee78dc32
GV
3390 if (hwnd)
3391 {
1edf84e7
GV
3392 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3393 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3394 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3395 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3396 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3397
cb9e33d4
RS
3398 /* Enable drag-n-drop. */
3399 DragAcceptFiles (hwnd, TRUE);
3400
5ac45f98
GV
3401 /* Do this to discard the default setting specified by our parent. */
3402 ShowWindow (hwnd, SW_HIDE);
3c190163 3403 }
3c190163
GV
3404}
3405
ee78dc32
GV
3406void
3407my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3408 W32Msg * wmsg;
ee78dc32
GV
3409 HWND hwnd;
3410 UINT msg;
3411 WPARAM wParam;
3412 LPARAM lParam;
3413{
3414 wmsg->msg.hwnd = hwnd;
3415 wmsg->msg.message = msg;
3416 wmsg->msg.wParam = wParam;
3417 wmsg->msg.lParam = lParam;
3418 wmsg->msg.time = GetMessageTime ();
3419
3420 post_msg (wmsg);
3421}
3422
e9e23e23 3423/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3424 between left and right keys as advertised. We test for this
3425 support dynamically, and set a flag when the support is absent. If
3426 absent, we keep track of the left and right control and alt keys
3427 ourselves. This is particularly necessary on keyboards that rely
3428 upon the AltGr key, which is represented as having the left control
3429 and right alt keys pressed. For these keyboards, we need to know
3430 when the left alt key has been pressed in addition to the AltGr key
3431 so that we can properly support M-AltGr-key sequences (such as M-@
3432 on Swedish keyboards). */
3433
3434#define EMACS_LCONTROL 0
3435#define EMACS_RCONTROL 1
3436#define EMACS_LMENU 2
3437#define EMACS_RMENU 3
3438
3439static int modifiers[4];
3440static int modifiers_recorded;
3441static int modifier_key_support_tested;
3442
3443static void
3444test_modifier_support (unsigned int wparam)
3445{
3446 unsigned int l, r;
3447
3448 if (wparam != VK_CONTROL && wparam != VK_MENU)
3449 return;
3450 if (wparam == VK_CONTROL)
3451 {
3452 l = VK_LCONTROL;
3453 r = VK_RCONTROL;
3454 }
3455 else
3456 {
3457 l = VK_LMENU;
3458 r = VK_RMENU;
3459 }
3460 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3461 modifiers_recorded = 1;
3462 else
3463 modifiers_recorded = 0;
3464 modifier_key_support_tested = 1;
3465}
3466
3467static void
3468record_keydown (unsigned int wparam, unsigned int lparam)
3469{
3470 int i;
3471
3472 if (!modifier_key_support_tested)
3473 test_modifier_support (wparam);
3474
3475 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3476 return;
3477
3478 if (wparam == VK_CONTROL)
3479 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3480 else
3481 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3482
3483 modifiers[i] = 1;
3484}
3485
3486static void
3487record_keyup (unsigned int wparam, unsigned int lparam)
3488{
3489 int i;
3490
3491 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3492 return;
3493
3494 if (wparam == VK_CONTROL)
3495 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3496 else
3497 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3498
3499 modifiers[i] = 0;
3500}
3501
da36a4d6
GV
3502/* Emacs can lose focus while a modifier key has been pressed. When
3503 it regains focus, be conservative and clear all modifiers since
3504 we cannot reconstruct the left and right modifier state. */
3505static void
3506reset_modifiers ()
3507{
8681157a
RS
3508 SHORT ctrl, alt;
3509
adcc3809
GV
3510 if (GetFocus () == NULL)
3511 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3512 return;
8681157a
RS
3513
3514 ctrl = GetAsyncKeyState (VK_CONTROL);
3515 alt = GetAsyncKeyState (VK_MENU);
3516
8681157a
RS
3517 if (!(ctrl & 0x08000))
3518 /* Clear any recorded control modifier state. */
3519 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3520
3521 if (!(alt & 0x08000))
3522 /* Clear any recorded alt modifier state. */
3523 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3524
adcc3809
GV
3525 /* Update the state of all modifier keys, because modifiers used in
3526 hot-key combinations can get stuck on if Emacs loses focus as a
3527 result of a hot-key being pressed. */
3528 {
3529 BYTE keystate[256];
3530
3531#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3532
3533 GetKeyboardState (keystate);
3534 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3535 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3536 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3537 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3538 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3539 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3540 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3541 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3542 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3543 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3544 SetKeyboardState (keystate);
3545 }
da36a4d6
GV
3546}
3547
7830e24b
RS
3548/* Synchronize modifier state with what is reported with the current
3549 keystroke. Even if we cannot distinguish between left and right
3550 modifier keys, we know that, if no modifiers are set, then neither
3551 the left or right modifier should be set. */
3552static void
3553sync_modifiers ()
3554{
3555 if (!modifiers_recorded)
3556 return;
3557
3558 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3559 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3560
3561 if (!(GetKeyState (VK_MENU) & 0x8000))
3562 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3563}
3564
a1a80b40
GV
3565static int
3566modifier_set (int vkey)
3567{
ccc2d29c 3568 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3569 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3570 if (!modifiers_recorded)
3571 return (GetKeyState (vkey) & 0x8000);
3572
3573 switch (vkey)
3574 {
3575 case VK_LCONTROL:
3576 return modifiers[EMACS_LCONTROL];
3577 case VK_RCONTROL:
3578 return modifiers[EMACS_RCONTROL];
3579 case VK_LMENU:
3580 return modifiers[EMACS_LMENU];
3581 case VK_RMENU:
3582 return modifiers[EMACS_RMENU];
a1a80b40
GV
3583 }
3584 return (GetKeyState (vkey) & 0x8000);
3585}
3586
ccc2d29c
GV
3587/* Convert between the modifier bits W32 uses and the modifier bits
3588 Emacs uses. */
3589
3590unsigned int
3591w32_key_to_modifier (int key)
3592{
3593 Lisp_Object key_mapping;
3594
3595 switch (key)
3596 {
3597 case VK_LWIN:
3598 key_mapping = Vw32_lwindow_modifier;
3599 break;
3600 case VK_RWIN:
3601 key_mapping = Vw32_rwindow_modifier;
3602 break;
3603 case VK_APPS:
3604 key_mapping = Vw32_apps_modifier;
3605 break;
3606 case VK_SCROLL:
3607 key_mapping = Vw32_scroll_lock_modifier;
3608 break;
3609 default:
3610 key_mapping = Qnil;
3611 }
3612
adcc3809
GV
3613 /* NB. This code runs in the input thread, asychronously to the lisp
3614 thread, so we must be careful to ensure access to lisp data is
3615 thread-safe. The following code is safe because the modifier
3616 variable values are updated atomically from lisp and symbols are
3617 not relocated by GC. Also, we don't have to worry about seeing GC
3618 markbits here. */
3619 if (EQ (key_mapping, Qhyper))
ccc2d29c 3620 return hyper_modifier;
adcc3809 3621 if (EQ (key_mapping, Qsuper))
ccc2d29c 3622 return super_modifier;
adcc3809 3623 if (EQ (key_mapping, Qmeta))
ccc2d29c 3624 return meta_modifier;
adcc3809 3625 if (EQ (key_mapping, Qalt))
ccc2d29c 3626 return alt_modifier;
adcc3809 3627 if (EQ (key_mapping, Qctrl))
ccc2d29c 3628 return ctrl_modifier;
adcc3809 3629 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3630 return ctrl_modifier;
adcc3809 3631 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3632 return shift_modifier;
3633
3634 /* Don't generate any modifier if not explicitly requested. */
3635 return 0;
3636}
3637
3638unsigned int
3639w32_get_modifiers ()
3640{
3641 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3642 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3643 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3644 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3645 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3646 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3647 (modifier_set (VK_MENU) ?
3648 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3649}
3650
a1a80b40
GV
3651/* We map the VK_* modifiers into console modifier constants
3652 so that we can use the same routines to handle both console
3653 and window input. */
3654
3655static int
ccc2d29c 3656construct_console_modifiers ()
a1a80b40
GV
3657{
3658 int mods;
3659
a1a80b40
GV
3660 mods = 0;
3661 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3662 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3663 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3664 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3665 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3666 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3667 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3668 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3669 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3670 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3671 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3672
3673 return mods;
3674}
3675
ccc2d29c
GV
3676static int
3677w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3678{
ccc2d29c
GV
3679 int mods;
3680
3681 /* Convert to emacs modifiers. */
3682 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3683
3684 return mods;
3685}
da36a4d6 3686
ccc2d29c
GV
3687unsigned int
3688map_keypad_keys (unsigned int virt_key, unsigned int extended)
3689{
3690 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3691 return virt_key;
da36a4d6 3692
ccc2d29c 3693 if (virt_key == VK_RETURN)
da36a4d6
GV
3694 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3695
ccc2d29c
GV
3696 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3697 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3698
3699 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3700 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3701
3702 if (virt_key == VK_CLEAR)
3703 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3704
3705 return virt_key;
3706}
3707
3708/* List of special key combinations which w32 would normally capture,
3709 but emacs should grab instead. Not directly visible to lisp, to
3710 simplify synchronization. Each item is an integer encoding a virtual
3711 key code and modifier combination to capture. */
3712Lisp_Object w32_grabbed_keys;
3713
3714#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3715#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3716#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3717#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3718
3719/* Register hot-keys for reserved key combinations when Emacs has
3720 keyboard focus, since this is the only way Emacs can receive key
3721 combinations like Alt-Tab which are used by the system. */
3722
3723static void
3724register_hot_keys (hwnd)
3725 HWND hwnd;
3726{
3727 Lisp_Object keylist;
3728
3729 /* Use GC_CONSP, since we are called asynchronously. */
3730 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3731 {
3732 Lisp_Object key = XCAR (keylist);
3733
3734 /* Deleted entries get set to nil. */
3735 if (!INTEGERP (key))
3736 continue;
3737
3738 RegisterHotKey (hwnd, HOTKEY_ID (key),
3739 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3740 }
3741}
3742
3743static void
3744unregister_hot_keys (hwnd)
3745 HWND hwnd;
3746{
3747 Lisp_Object keylist;
3748
3749 /* Use GC_CONSP, since we are called asynchronously. */
3750 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3751 {
3752 Lisp_Object key = XCAR (keylist);
3753
3754 if (!INTEGERP (key))
3755 continue;
3756
3757 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3758 }
3759}
3760
5ac45f98
GV
3761/* Main message dispatch loop. */
3762
1edf84e7
GV
3763static void
3764w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3765{
3766 MSG msg;
ccc2d29c
GV
3767 int result;
3768 HWND focus_window;
93fbe8b7
GV
3769
3770 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3771
5ac45f98
GV
3772 while (GetMessage (&msg, NULL, 0, 0))
3773 {
3774 if (msg.hwnd == NULL)
3775 {
3776 switch (msg.message)
3777 {
3ef68e6b
AI
3778 case WM_NULL:
3779 /* Produced by complete_deferred_msg; just ignore. */
3780 break;
5ac45f98 3781 case WM_EMACS_CREATEWINDOW:
fbd6baed 3782 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3783 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3784 abort ();
5ac45f98 3785 break;
dfdb4047
GV
3786 case WM_EMACS_SETLOCALE:
3787 SetThreadLocale (msg.wParam);
3788 /* Reply is not expected. */
3789 break;
ccc2d29c
GV
3790 case WM_EMACS_SETKEYBOARDLAYOUT:
3791 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3792 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3793 result, 0))
3794 abort ();
3795 break;
3796 case WM_EMACS_REGISTER_HOT_KEY:
3797 focus_window = GetFocus ();
3798 if (focus_window != NULL)
3799 RegisterHotKey (focus_window,
3800 HOTKEY_ID (msg.wParam),
3801 HOTKEY_MODIFIERS (msg.wParam),
3802 HOTKEY_VK_CODE (msg.wParam));
3803 /* Reply is not expected. */
3804 break;
3805 case WM_EMACS_UNREGISTER_HOT_KEY:
3806 focus_window = GetFocus ();
3807 if (focus_window != NULL)
3808 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3809 /* Mark item as erased. NB: this code must be
3810 thread-safe. The next line is okay because the cons
3811 cell is never made into garbage and is not relocated by
3812 GC. */
ccc2d29c
GV
3813 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3814 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3815 abort ();
3816 break;
adcc3809
GV
3817 case WM_EMACS_TOGGLE_LOCK_KEY:
3818 {
3819 int vk_code = (int) msg.wParam;
3820 int cur_state = (GetKeyState (vk_code) & 1);
3821 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3822
3823 /* NB: This code must be thread-safe. It is safe to
3824 call NILP because symbols are not relocated by GC,
3825 and pointer here is not touched by GC (so the markbit
3826 can't be set). Numbers are safe because they are
3827 immediate values. */
3828 if (NILP (new_state)
3829 || (NUMBERP (new_state)
3830 && (XUINT (new_state)) & 1 != cur_state))
3831 {
3832 one_w32_display_info.faked_key = vk_code;
3833
3834 keybd_event ((BYTE) vk_code,
3835 (BYTE) MapVirtualKey (vk_code, 0),
3836 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3837 keybd_event ((BYTE) vk_code,
3838 (BYTE) MapVirtualKey (vk_code, 0),
3839 KEYEVENTF_EXTENDEDKEY | 0, 0);
3840 keybd_event ((BYTE) vk_code,
3841 (BYTE) MapVirtualKey (vk_code, 0),
3842 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3843 cur_state = !cur_state;
3844 }
3845 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3846 cur_state, 0))
3847 abort ();
3848 }
3849 break;
1edf84e7 3850 default:
1edf84e7 3851 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3852 }
3853 }
3854 else
3855 {
3856 DispatchMessage (&msg);
3857 }
1edf84e7
GV
3858
3859 /* Exit nested loop when our deferred message has completed. */
3860 if (msg_buf->completed)
3861 break;
5ac45f98 3862 }
1edf84e7
GV
3863}
3864
3865deferred_msg * deferred_msg_head;
3866
3867static deferred_msg *
3868find_deferred_msg (HWND hwnd, UINT msg)
3869{
3870 deferred_msg * item;
3871
3872 /* Don't actually need synchronization for read access, since
3873 modification of single pointer is always atomic. */
3874 /* enter_crit (); */
3875
3876 for (item = deferred_msg_head; item != NULL; item = item->next)
3877 if (item->w32msg.msg.hwnd == hwnd
3878 && item->w32msg.msg.message == msg)
3879 break;
3880
3881 /* leave_crit (); */
3882
3883 return item;
3884}
3885
3886static LRESULT
3887send_deferred_msg (deferred_msg * msg_buf,
3888 HWND hwnd,
3889 UINT msg,
3890 WPARAM wParam,
3891 LPARAM lParam)
3892{
3893 /* Only input thread can send deferred messages. */
3894 if (GetCurrentThreadId () != dwWindowsThreadId)
3895 abort ();
3896
3897 /* It is an error to send a message that is already deferred. */
3898 if (find_deferred_msg (hwnd, msg) != NULL)
3899 abort ();
3900
3901 /* Enforced synchronization is not needed because this is the only
3902 function that alters deferred_msg_head, and the following critical
3903 section is guaranteed to only be serially reentered (since only the
3904 input thread can call us). */
3905
3906 /* enter_crit (); */
3907
3908 msg_buf->completed = 0;
3909 msg_buf->next = deferred_msg_head;
3910 deferred_msg_head = msg_buf;
3911 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3912
3913 /* leave_crit (); */
3914
3915 /* Start a new nested message loop to process other messages until
3916 this one is completed. */
3917 w32_msg_pump (msg_buf);
3918
3919 deferred_msg_head = msg_buf->next;
3920
3921 return msg_buf->result;
3922}
3923
3924void
3925complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3926{
3927 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3928
3929 if (msg_buf == NULL)
3ef68e6b
AI
3930 /* Message may have been cancelled, so don't abort(). */
3931 return;
1edf84e7
GV
3932
3933 msg_buf->result = result;
3934 msg_buf->completed = 1;
3935
3936 /* Ensure input thread is woken so it notices the completion. */
3937 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3938}
3939
3ef68e6b
AI
3940void
3941cancel_all_deferred_msgs ()
3942{
3943 deferred_msg * item;
3944
3945 /* Don't actually need synchronization for read access, since
3946 modification of single pointer is always atomic. */
3947 /* enter_crit (); */
3948
3949 for (item = deferred_msg_head; item != NULL; item = item->next)
3950 {
3951 item->result = 0;
3952 item->completed = 1;
3953 }
3954
3955 /* leave_crit (); */
3956
3957 /* Ensure input thread is woken so it notices the completion. */
3958 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3959}
1edf84e7
GV
3960
3961DWORD
3962w32_msg_worker (dw)
3963 DWORD dw;
3964{
3965 MSG msg;
3966 deferred_msg dummy_buf;
3967
3968 /* Ensure our message queue is created */
3969
3970 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 3971
1edf84e7
GV
3972 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3973 abort ();
3974
3975 memset (&dummy_buf, 0, sizeof (dummy_buf));
3976 dummy_buf.w32msg.msg.hwnd = NULL;
3977 dummy_buf.w32msg.msg.message = WM_NULL;
3978
3979 /* This is the inital message loop which should only exit when the
3980 application quits. */
3981 w32_msg_pump (&dummy_buf);
3982
3983 return 0;
5ac45f98
GV
3984}
3985
3ef68e6b
AI
3986static void
3987post_character_message (hwnd, msg, wParam, lParam, modifiers)
3988 HWND hwnd;
3989 UINT msg;
3990 WPARAM wParam;
3991 LPARAM lParam;
3992 DWORD modifiers;
3993
3994{
3995 W32Msg wmsg;
3996
3997 wmsg.dwModifiers = modifiers;
3998
3999 /* Detect quit_char and set quit-flag directly. Note that we
4000 still need to post a message to ensure the main thread will be
4001 woken up if blocked in sys_select(), but we do NOT want to post
4002 the quit_char message itself (because it will usually be as if
4003 the user had typed quit_char twice). Instead, we post a dummy
4004 message that has no particular effect. */
4005 {
4006 int c = wParam;
4007 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4008 c = make_ctrl_char (c) & 0377;
7d081355
AI
4009 if (c == quit_char
4010 || (wmsg.dwModifiers == 0 &&
4011 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4012 {
4013 Vquit_flag = Qt;
4014
4015 /* The choice of message is somewhat arbitrary, as long as
4016 the main thread handler just ignores it. */
4017 msg = WM_NULL;
4018
4019 /* Interrupt any blocking system calls. */
4020 signal_quit ();
4021
4022 /* As a safety precaution, forcibly complete any deferred
4023 messages. This is a kludge, but I don't see any particularly
4024 clean way to handle the situation where a deferred message is
4025 "dropped" in the lisp thread, and will thus never be
4026 completed, eg. by the user trying to activate the menubar
4027 when the lisp thread is busy, and then typing C-g when the
4028 menubar doesn't open promptly (with the result that the
4029 menubar never responds at all because the deferred
4030 WM_INITMENU message is never completed). Another problem
4031 situation is when the lisp thread calls SendMessage (to send
4032 a window manager command) when a message has been deferred;
4033 the lisp thread gets blocked indefinitely waiting for the
4034 deferred message to be completed, which itself is waiting for
4035 the lisp thread to respond.
4036
4037 Note that we don't want to block the input thread waiting for
4038 a reponse from the lisp thread (although that would at least
4039 solve the deadlock problem above), because we want to be able
4040 to receive C-g to interrupt the lisp thread. */
4041 cancel_all_deferred_msgs ();
4042 }
4043 }
4044
4045 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4046}
4047
ee78dc32
GV
4048/* Main window procedure */
4049
ee78dc32 4050LRESULT CALLBACK
fbd6baed 4051w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4052 HWND hwnd;
4053 UINT msg;
4054 WPARAM wParam;
4055 LPARAM lParam;
4056{
4057 struct frame *f;
fbd6baed
GV
4058 struct w32_display_info *dpyinfo = &one_w32_display_info;
4059 W32Msg wmsg;
84fb1139 4060 int windows_translate;
576ba81c 4061 int key;
84fb1139 4062
a6085637
KH
4063 /* Note that it is okay to call x_window_to_frame, even though we are
4064 not running in the main lisp thread, because frame deletion
4065 requires the lisp thread to synchronize with this thread. Thus, if
4066 a frame struct is returned, it can be used without concern that the
4067 lisp thread might make it disappear while we are using it.
4068
4069 NB. Walking the frame list in this thread is safe (as long as
4070 writes of Lisp_Object slots are atomic, which they are on Windows).
4071 Although delete-frame can destructively modify the frame list while
4072 we are walking it, a garbage collection cannot occur until after
4073 delete-frame has synchronized with this thread.
4074
4075 It is also safe to use functions that make GDI calls, such as
fbd6baed 4076 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4077 from the frame struct using get_frame_dc which is thread-aware. */
4078
ee78dc32
GV
4079 switch (msg)
4080 {
4081 case WM_ERASEBKGND:
a6085637
KH
4082 f = x_window_to_frame (dpyinfo, hwnd);
4083 if (f)
4084 {
9badad41 4085 HDC hdc = get_frame_dc (f);
a6085637 4086 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4087 w32_clear_rect (f, hdc, &wmsg.rect);
4088 release_frame_dc (f, hdc);
ce6059da
AI
4089
4090#if defined (W32_DEBUG_DISPLAY)
4091 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
4092 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
4093 wmsg.rect.bottom));
4094#endif /* W32_DEBUG_DISPLAY */
a6085637 4095 }
5ac45f98
GV
4096 return 1;
4097 case WM_PALETTECHANGED:
4098 /* ignore our own changes */
4099 if ((HWND)wParam != hwnd)
4100 {
a6085637
KH
4101 f = x_window_to_frame (dpyinfo, hwnd);
4102 if (f)
4103 /* get_frame_dc will realize our palette and force all
4104 frames to be redrawn if needed. */
4105 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4106 }
4107 return 0;
ee78dc32 4108 case WM_PAINT:
ce6059da 4109 {
55dcfc15
AI
4110 PAINTSTRUCT paintStruct;
4111 RECT update_rect;
4112
4113 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4114 fails. Apparently this can happen under some
4115 circumstances. */
c0611964 4116 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
4117 {
4118 enter_crit ();
4119 BeginPaint (hwnd, &paintStruct);
4120
c0611964
AI
4121 if (w32_strict_painting)
4122 /* The rectangles returned by GetUpdateRect and BeginPaint
4123 do not always match. GetUpdateRect seems to be the
4124 more reliable of the two. */
4125 wmsg.rect = update_rect;
4126 else
4127 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
4128
4129#if defined (W32_DEBUG_DISPLAY)
4130 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
4131 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
4132 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
4133 update_rect.left, update_rect.top,
4134 update_rect.right, update_rect.bottom));
4135#endif
4136 EndPaint (hwnd, &paintStruct);
4137 leave_crit ();
4138
4139 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4140
4141 return 0;
4142 }
c0611964
AI
4143
4144 /* If GetUpdateRect returns 0 (meaning there is no update
4145 region), assume the whole window needs to be repainted. */
4146 GetClientRect(hwnd, &wmsg.rect);
4147 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4148 return 0;
ee78dc32 4149 }
a1a80b40 4150
ccc2d29c
GV
4151 case WM_INPUTLANGCHANGE:
4152 /* Inform lisp thread of keyboard layout changes. */
4153 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4154
4155 /* Clear dead keys in the keyboard state; for simplicity only
4156 preserve modifier key states. */
4157 {
4158 int i;
4159 BYTE keystate[256];
4160
4161 GetKeyboardState (keystate);
4162 for (i = 0; i < 256; i++)
4163 if (1
4164 && i != VK_SHIFT
4165 && i != VK_LSHIFT
4166 && i != VK_RSHIFT
4167 && i != VK_CAPITAL
4168 && i != VK_NUMLOCK
4169 && i != VK_SCROLL
4170 && i != VK_CONTROL
4171 && i != VK_LCONTROL
4172 && i != VK_RCONTROL
4173 && i != VK_MENU
4174 && i != VK_LMENU
4175 && i != VK_RMENU
4176 && i != VK_LWIN
4177 && i != VK_RWIN)
4178 keystate[i] = 0;
4179 SetKeyboardState (keystate);
4180 }
4181 goto dflt;
4182
4183 case WM_HOTKEY:
4184 /* Synchronize hot keys with normal input. */
4185 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4186 return (0);
4187
a1a80b40
GV
4188 case WM_KEYUP:
4189 case WM_SYSKEYUP:
4190 record_keyup (wParam, lParam);
4191 goto dflt;
4192
ee78dc32
GV
4193 case WM_KEYDOWN:
4194 case WM_SYSKEYDOWN:
ccc2d29c
GV
4195 /* Ignore keystrokes we fake ourself; see below. */
4196 if (dpyinfo->faked_key == wParam)
4197 {
4198 dpyinfo->faked_key = 0;
576ba81c
AI
4199 /* Make sure TranslateMessage sees them though (as long as
4200 they don't produce WM_CHAR messages). This ensures that
4201 indicator lights are toggled promptly on Windows 9x, for
4202 example. */
4203 if (lispy_function_keys[wParam] != 0)
4204 {
4205 windows_translate = 1;
4206 goto translate;
4207 }
4208 return 0;
ccc2d29c
GV
4209 }
4210
7830e24b
RS
4211 /* Synchronize modifiers with current keystroke. */
4212 sync_modifiers ();
a1a80b40 4213 record_keydown (wParam, lParam);
ccc2d29c 4214 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4215
4216 windows_translate = 0;
ccc2d29c
GV
4217
4218 switch (wParam)
4219 {
4220 case VK_LWIN:
4221 if (NILP (Vw32_pass_lwindow_to_system))
4222 {
4223 /* Prevent system from acting on keyup (which opens the
4224 Start menu if no other key was pressed) by simulating a
4225 press of Space which we will ignore. */
4226 if (GetAsyncKeyState (wParam) & 1)
4227 {
adcc3809 4228 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4229 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4230 else
576ba81c
AI
4231 key = VK_SPACE;
4232 dpyinfo->faked_key = key;
4233 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4234 }
4235 }
4236 if (!NILP (Vw32_lwindow_modifier))
4237 return 0;
4238 break;
4239 case VK_RWIN:
4240 if (NILP (Vw32_pass_rwindow_to_system))
4241 {
4242 if (GetAsyncKeyState (wParam) & 1)
4243 {
adcc3809 4244 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4245 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4246 else
576ba81c
AI
4247 key = VK_SPACE;
4248 dpyinfo->faked_key = key;
4249 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4250 }
4251 }
4252 if (!NILP (Vw32_rwindow_modifier))
4253 return 0;
4254 break;
576ba81c 4255 case VK_APPS:
ccc2d29c
GV
4256 if (!NILP (Vw32_apps_modifier))
4257 return 0;
4258 break;
4259 case VK_MENU:
4260 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4261 /* Prevent DefWindowProc from activating the menu bar if an
4262 Alt key is pressed and released by itself. */
ccc2d29c 4263 return 0;
84fb1139 4264 windows_translate = 1;
ccc2d29c
GV
4265 break;
4266 case VK_CAPITAL:
4267 /* Decide whether to treat as modifier or function key. */
4268 if (NILP (Vw32_enable_caps_lock))
4269 goto disable_lock_key;
adcc3809
GV
4270 windows_translate = 1;
4271 break;
ccc2d29c
GV
4272 case VK_NUMLOCK:
4273 /* Decide whether to treat as modifier or function key. */
4274 if (NILP (Vw32_enable_num_lock))
4275 goto disable_lock_key;
adcc3809
GV
4276 windows_translate = 1;
4277 break;
ccc2d29c
GV
4278 case VK_SCROLL:
4279 /* Decide whether to treat as modifier or function key. */
4280 if (NILP (Vw32_scroll_lock_modifier))
4281 goto disable_lock_key;
adcc3809
GV
4282 windows_translate = 1;
4283 break;
ccc2d29c 4284 disable_lock_key:
adcc3809
GV
4285 /* Ensure the appropriate lock key state (and indicator light)
4286 remains in the same state. We do this by faking another
4287 press of the relevant key. Apparently, this really is the
4288 only way to toggle the state of the indicator lights. */
4289 dpyinfo->faked_key = wParam;
4290 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4291 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4292 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4293 KEYEVENTF_EXTENDEDKEY | 0, 0);
4294 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4295 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4296 /* Ensure indicator lights are updated promptly on Windows 9x
4297 (TranslateMessage apparently does this), after forwarding
4298 input event. */
4299 post_character_message (hwnd, msg, wParam, lParam,
4300 w32_get_key_modifiers (wParam, lParam));
4301 windows_translate = 1;
ccc2d29c
GV
4302 break;
4303 case VK_CONTROL:
4304 case VK_SHIFT:
4305 case VK_PROCESSKEY: /* Generated by IME. */
4306 windows_translate = 1;
4307 break;
adcc3809
GV
4308 case VK_CANCEL:
4309 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4310 which is confusing for purposes of key binding; convert
4311 VK_CANCEL events into VK_PAUSE events. */
4312 wParam = VK_PAUSE;
4313 break;
4314 case VK_PAUSE:
4315 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4316 for purposes of key binding; convert these back into
4317 VK_NUMLOCK events, at least when we want to see NumLock key
4318 presses. (Note that there is never any possibility that
4319 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4320 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4321 wParam = VK_NUMLOCK;
4322 break;
ccc2d29c
GV
4323 default:
4324 /* If not defined as a function key, change it to a WM_CHAR message. */
4325 if (lispy_function_keys[wParam] == 0)
4326 {
adcc3809
GV
4327 DWORD modifiers = construct_console_modifiers ();
4328
ccc2d29c
GV
4329 if (!NILP (Vw32_recognize_altgr)
4330 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4331 {
4332 /* Always let TranslateMessage handle AltGr key chords;
4333 for some reason, ToAscii doesn't always process AltGr
4334 chords correctly. */
4335 windows_translate = 1;
4336 }
adcc3809 4337 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4338 {
adcc3809
GV
4339 /* Handle key chords including any modifiers other
4340 than shift directly, in order to preserve as much
4341 modifier information as possible. */
ccc2d29c
GV
4342 if ('A' <= wParam && wParam <= 'Z')
4343 {
4344 /* Don't translate modified alphabetic keystrokes,
4345 so the user doesn't need to constantly switch
4346 layout to type control or meta keystrokes when
4347 the normal layout translates alphabetic
4348 characters to non-ascii characters. */
4349 if (!modifier_set (VK_SHIFT))
4350 wParam += ('a' - 'A');
4351 msg = WM_CHAR;
4352 }
4353 else
4354 {
4355 /* Try to handle other keystrokes by determining the
4356 base character (ie. translating the base key plus
4357 shift modifier). */
4358 int add;
4359 int isdead = 0;
4360 KEY_EVENT_RECORD key;
4361
4362 key.bKeyDown = TRUE;
4363 key.wRepeatCount = 1;
4364 key.wVirtualKeyCode = wParam;
4365 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4366 key.uChar.AsciiChar = 0;
adcc3809 4367 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4368
4369 add = w32_kbd_patch_key (&key);
4370 /* 0 means an unrecognised keycode, negative means
4371 dead key. Ignore both. */
4372 while (--add >= 0)
4373 {
4374 /* Forward asciified character sequence. */
4375 post_character_message
4376 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4377 w32_get_key_modifiers (wParam, lParam));
4378 w32_kbd_patch_key (&key);
4379 }
4380 return 0;
4381 }
4382 }
4383 else
4384 {
4385 /* Let TranslateMessage handle everything else. */
4386 windows_translate = 1;
4387 }
4388 }
4389 }
a1a80b40 4390
adcc3809 4391 translate:
84fb1139
KH
4392 if (windows_translate)
4393 {
e9e23e23 4394 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4395
e9e23e23
GV
4396 windows_msg.time = GetMessageTime ();
4397 TranslateMessage (&windows_msg);
84fb1139
KH
4398 goto dflt;
4399 }
4400
ee78dc32
GV
4401 /* Fall through */
4402
4403 case WM_SYSCHAR:
4404 case WM_CHAR:
ccc2d29c
GV
4405 post_character_message (hwnd, msg, wParam, lParam,
4406 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4407 break;
da36a4d6 4408
5ac45f98
GV
4409 /* Simulate middle mouse button events when left and right buttons
4410 are used together, but only if user has two button mouse. */
ee78dc32 4411 case WM_LBUTTONDOWN:
5ac45f98 4412 case WM_RBUTTONDOWN:
7ce9aaca 4413 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4414 goto handle_plain_button;
4415
4416 {
4417 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4418 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4419
3cb20f4a
RS
4420 if (button_state & this)
4421 return 0;
5ac45f98
GV
4422
4423 if (button_state == 0)
4424 SetCapture (hwnd);
4425
4426 button_state |= this;
4427
4428 if (button_state & other)
4429 {
84fb1139 4430 if (mouse_button_timer)
5ac45f98 4431 {
84fb1139
KH
4432 KillTimer (hwnd, mouse_button_timer);
4433 mouse_button_timer = 0;
5ac45f98
GV
4434
4435 /* Generate middle mouse event instead. */
4436 msg = WM_MBUTTONDOWN;
4437 button_state |= MMOUSE;
4438 }
4439 else if (button_state & MMOUSE)
4440 {
4441 /* Ignore button event if we've already generated a
4442 middle mouse down event. This happens if the
4443 user releases and press one of the two buttons
4444 after we've faked a middle mouse event. */
4445 return 0;
4446 }
4447 else
4448 {
4449 /* Flush out saved message. */
84fb1139 4450 post_msg (&saved_mouse_button_msg);
5ac45f98 4451 }
fbd6baed 4452 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4453 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4454
4455 /* Clear message buffer. */
84fb1139 4456 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4457 }
4458 else
4459 {
4460 /* Hold onto message for now. */
84fb1139 4461 mouse_button_timer =
adcc3809
GV
4462 SetTimer (hwnd, MOUSE_BUTTON_ID,
4463 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4464 saved_mouse_button_msg.msg.hwnd = hwnd;
4465 saved_mouse_button_msg.msg.message = msg;
4466 saved_mouse_button_msg.msg.wParam = wParam;
4467 saved_mouse_button_msg.msg.lParam = lParam;
4468 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4469 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4470 }
4471 }
4472 return 0;
4473
ee78dc32 4474 case WM_LBUTTONUP:
5ac45f98 4475 case WM_RBUTTONUP:
7ce9aaca 4476 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4477 goto handle_plain_button;
4478
4479 {
4480 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4481 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4482
3cb20f4a
RS
4483 if ((button_state & this) == 0)
4484 return 0;
5ac45f98
GV
4485
4486 button_state &= ~this;
4487
4488 if (button_state & MMOUSE)
4489 {
4490 /* Only generate event when second button is released. */
4491 if ((button_state & other) == 0)
4492 {
4493 msg = WM_MBUTTONUP;
4494 button_state &= ~MMOUSE;
4495
4496 if (button_state) abort ();
4497 }
4498 else
4499 return 0;
4500 }
4501 else
4502 {
4503 /* Flush out saved message if necessary. */
84fb1139 4504 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4505 {
84fb1139 4506 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4507 }
4508 }
fbd6baed 4509 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4510 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4511
4512 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4513 saved_mouse_button_msg.msg.hwnd = 0;
4514 KillTimer (hwnd, mouse_button_timer);
4515 mouse_button_timer = 0;
5ac45f98
GV
4516
4517 if (button_state == 0)
4518 ReleaseCapture ();
4519 }
4520 return 0;
4521
ee78dc32
GV
4522 case WM_MBUTTONDOWN:
4523 case WM_MBUTTONUP:
5ac45f98 4524 handle_plain_button:
ee78dc32
GV
4525 {
4526 BOOL up;
1edf84e7 4527 int button;
ee78dc32 4528
1edf84e7 4529 if (parse_button (msg, &button, &up))
ee78dc32
GV
4530 {
4531 if (up) ReleaseCapture ();
4532 else SetCapture (hwnd);
1edf84e7
GV
4533 button = (button == 0) ? LMOUSE :
4534 ((button == 1) ? MMOUSE : RMOUSE);
4535 if (up)
4536 button_state &= ~button;
4537 else
4538 button_state |= button;
ee78dc32
GV
4539 }
4540 }
4541
fbd6baed 4542 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4543 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5ac45f98
GV
4544 return 0;
4545
84fb1139 4546 case WM_VSCROLL:
5ac45f98 4547 case WM_MOUSEMOVE:
fbd6baed 4548 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4549 || (msg == WM_MOUSEMOVE && button_state == 0))
4550 {
fbd6baed 4551 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4552 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4553 return 0;
4554 }
4555
4556 /* Hang onto mouse move and scroll messages for a bit, to avoid
4557 sending such events to Emacs faster than it can process them.
4558 If we get more events before the timer from the first message
4559 expires, we just replace the first message. */
4560
4561 if (saved_mouse_move_msg.msg.hwnd == 0)
4562 mouse_move_timer =
adcc3809
GV
4563 SetTimer (hwnd, MOUSE_MOVE_ID,
4564 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4565
4566 /* Hold onto message for now. */
4567 saved_mouse_move_msg.msg.hwnd = hwnd;
4568 saved_mouse_move_msg.msg.message = msg;
4569 saved_mouse_move_msg.msg.wParam = wParam;
4570 saved_mouse_move_msg.msg.lParam = lParam;
4571 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4572 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4573
4574 return 0;
4575
1edf84e7
GV
4576 case WM_MOUSEWHEEL:
4577 wmsg.dwModifiers = w32_get_modifiers ();
4578 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4579 return 0;
4580
cb9e33d4
RS
4581 case WM_DROPFILES:
4582 wmsg.dwModifiers = w32_get_modifiers ();
4583 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4584 return 0;
4585
84fb1139
KH
4586 case WM_TIMER:
4587 /* Flush out saved messages if necessary. */
4588 if (wParam == mouse_button_timer)
5ac45f98 4589 {
84fb1139
KH
4590 if (saved_mouse_button_msg.msg.hwnd)
4591 {
4592 post_msg (&saved_mouse_button_msg);
4593 saved_mouse_button_msg.msg.hwnd = 0;
4594 }
4595 KillTimer (hwnd, mouse_button_timer);
4596 mouse_button_timer = 0;
4597 }
4598 else if (wParam == mouse_move_timer)
4599 {
4600 if (saved_mouse_move_msg.msg.hwnd)
4601 {
4602 post_msg (&saved_mouse_move_msg);
4603 saved_mouse_move_msg.msg.hwnd = 0;
4604 }
4605 KillTimer (hwnd, mouse_move_timer);
4606 mouse_move_timer = 0;
5ac45f98 4607 }
5ac45f98 4608 return 0;
84fb1139
KH
4609
4610 case WM_NCACTIVATE:
4611 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4612 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4613 The only indication we get that something happened is receiving
4614 this message afterwards. So this is a good time to reset our
4615 keyboard modifiers' state. */
4616 reset_modifiers ();
4617 goto dflt;
da36a4d6 4618
1edf84e7 4619 case WM_INITMENU:
487163ac
AI
4620 button_state = 0;
4621 ReleaseCapture ();
1edf84e7
GV
4622 /* We must ensure menu bar is fully constructed and up to date
4623 before allowing user interaction with it. To achieve this
4624 we send this message to the lisp thread and wait for a
4625 reply (whose value is not actually needed) to indicate that
4626 the menu bar is now ready for use, so we can now return.
4627
4628 To remain responsive in the meantime, we enter a nested message
4629 loop that can process all other messages.
4630
4631 However, we skip all this if the message results from calling
4632 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4633 thread a message because it is blocked on us at this point. We
4634 set menubar_active before calling TrackPopupMenu to indicate
4635 this (there is no possibility of confusion with real menubar
4636 being active). */
4637
4638 f = x_window_to_frame (dpyinfo, hwnd);
4639 if (f
4640 && (f->output_data.w32->menubar_active
4641 /* We can receive this message even in the absence of a
4642 menubar (ie. when the system menu is activated) - in this
4643 case we do NOT want to forward the message, otherwise it
4644 will cause the menubar to suddenly appear when the user
4645 had requested it to be turned off! */
4646 || f->output_data.w32->menubar_widget == NULL))
4647 return 0;
4648
4649 {
4650 deferred_msg msg_buf;
4651
4652 /* Detect if message has already been deferred; in this case
4653 we cannot return any sensible value to ignore this. */
4654 if (find_deferred_msg (hwnd, msg) != NULL)
4655 abort ();
4656
4657 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4658 }
4659
4660 case WM_EXITMENULOOP:
4661 f = x_window_to_frame (dpyinfo, hwnd);
4662
4663 /* Indicate that menubar can be modified again. */
4664 if (f)
4665 f->output_data.w32->menubar_active = 0;
4666 goto dflt;
4667
126f2e35
JR
4668 case WM_MENUSELECT:
4669 wmsg.dwModifiers = w32_get_modifiers ();
4670 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4671 return 0;
4672
87996783
GV
4673 case WM_MEASUREITEM:
4674 f = x_window_to_frame (dpyinfo, hwnd);
4675 if (f)
4676 {
4677 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4678
4679 if (pMis->CtlType == ODT_MENU)
4680 {
4681 /* Work out dimensions for popup menu titles. */
4682 char * title = (char *) pMis->itemData;
4683 HDC hdc = GetDC (hwnd);
4684 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4685 LOGFONT menu_logfont;
4686 HFONT old_font;
4687 SIZE size;
4688
4689 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4690 menu_logfont.lfWeight = FW_BOLD;
4691 menu_font = CreateFontIndirect (&menu_logfont);
4692 old_font = SelectObject (hdc, menu_font);
4693
dfff8a69
JR
4694 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4695 if (title)
4696 {
4697 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4698 pMis->itemWidth = size.cx;
4699 if (pMis->itemHeight < size.cy)
4700 pMis->itemHeight = size.cy;
4701 }
4702 else
4703 pMis->itemWidth = 0;
87996783
GV
4704
4705 SelectObject (hdc, old_font);
4706 DeleteObject (menu_font);
4707 ReleaseDC (hwnd, hdc);
4708 return TRUE;
4709 }
4710 }
4711 return 0;
4712
4713 case WM_DRAWITEM:
4714 f = x_window_to_frame (dpyinfo, hwnd);
4715 if (f)
4716 {
4717 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4718
4719 if (pDis->CtlType == ODT_MENU)
4720 {
4721 /* Draw popup menu title. */
4722 char * title = (char *) pDis->itemData;
212da13b
JR
4723 if (title)
4724 {
4725 HDC hdc = pDis->hDC;
4726 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4727 LOGFONT menu_logfont;
4728 HFONT old_font;
4729
4730 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4731 menu_logfont.lfWeight = FW_BOLD;
4732 menu_font = CreateFontIndirect (&menu_logfont);
4733 old_font = SelectObject (hdc, menu_font);
4734
4735 /* Always draw title as if not selected. */
4736 ExtTextOut (hdc,
4737 pDis->rcItem.left
4738 + GetSystemMetrics (SM_CXMENUCHECK),
4739 pDis->rcItem.top,
4740 ETO_OPAQUE, &pDis->rcItem,
4741 title, strlen (title), NULL);
4742
4743 SelectObject (hdc, old_font);
4744 DeleteObject (menu_font);
4745 }
87996783
GV
4746 return TRUE;
4747 }
4748 }
4749 return 0;
4750
1edf84e7
GV
4751#if 0
4752 /* Still not right - can't distinguish between clicks in the
4753 client area of the frame from clicks forwarded from the scroll
4754 bars - may have to hook WM_NCHITTEST to remember the mouse
4755 position and then check if it is in the client area ourselves. */
4756 case WM_MOUSEACTIVATE:
4757 /* Discard the mouse click that activates a frame, allowing the
4758 user to click anywhere without changing point (or worse!).
4759 Don't eat mouse clicks on scrollbars though!! */
4760 if (LOWORD (lParam) == HTCLIENT )
4761 return MA_ACTIVATEANDEAT;
4762 goto dflt;
4763#endif
4764
1edf84e7 4765 case WM_ACTIVATEAPP:
ccc2d29c 4766 case WM_ACTIVATE:
1edf84e7
GV
4767 case WM_WINDOWPOSCHANGED:
4768 case WM_SHOWWINDOW:
4769 /* Inform lisp thread that a frame might have just been obscured
4770 or exposed, so should recheck visibility of all frames. */
4771 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4772 goto dflt;
4773
da36a4d6 4774 case WM_SETFOCUS:
adcc3809
GV
4775 dpyinfo->faked_key = 0;
4776 reset_modifiers ();
ccc2d29c
GV
4777 register_hot_keys (hwnd);
4778 goto command;
8681157a 4779 case WM_KILLFOCUS:
ccc2d29c 4780 unregister_hot_keys (hwnd);
487163ac
AI
4781 button_state = 0;
4782 ReleaseCapture ();
ee78dc32
GV
4783 case WM_MOVE:
4784 case WM_SIZE:
ee78dc32 4785 case WM_COMMAND:
ccc2d29c 4786 command:
fbd6baed 4787 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4788 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4789 goto dflt;
8847d890
RS
4790
4791 case WM_CLOSE:
fbd6baed 4792 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4793 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4794 return 0;
4795
ee78dc32
GV
4796 case WM_WINDOWPOSCHANGING:
4797 {
4798 WINDOWPLACEMENT wp;
4799 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4800
4801 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4802 GetWindowPlacement (hwnd, &wp);
4803
1edf84e7 4804 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4805 {
4806 RECT rect;
4807 int wdiff;
4808 int hdiff;
1edf84e7
GV
4809 DWORD font_width;
4810 DWORD line_height;
4811 DWORD internal_border;
4812 DWORD scrollbar_extra;
ee78dc32
GV
4813 RECT wr;
4814
5ac45f98 4815 wp.length = sizeof(wp);
ee78dc32
GV
4816 GetWindowRect (hwnd, &wr);
4817
3c190163 4818 enter_crit ();
ee78dc32 4819
1edf84e7
GV
4820 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4821 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4822 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4823 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4824
3c190163 4825 leave_crit ();
ee78dc32
GV
4826
4827 memset (&rect, 0, sizeof (rect));
4828 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4829 GetMenu (hwnd) != NULL);
4830
1edf84e7
GV
4831 /* Force width and height of client area to be exact
4832 multiples of the character cell dimensions. */
4833 wdiff = (lppos->cx - (rect.right - rect.left)
4834 - 2 * internal_border - scrollbar_extra)
4835 % font_width;
4836 hdiff = (lppos->cy - (rect.bottom - rect.top)
4837 - 2 * internal_border)
4838 % line_height;
ee78dc32
GV
4839
4840 if (wdiff || hdiff)
4841 {
4842 /* For right/bottom sizing we can just fix the sizes.
4843 However for top/left sizing we will need to fix the X
4844 and Y positions as well. */
4845
4846 lppos->cx -= wdiff;
4847 lppos->cy -= hdiff;
4848
4849 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4850 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4851 {
4852 if (lppos->x != wr.left || lppos->y != wr.top)
4853 {
4854 lppos->x += wdiff;
4855 lppos->y += hdiff;
4856 }
4857 else
4858 {
4859 lppos->flags |= SWP_NOMOVE;
4860 }
4861 }
4862
1edf84e7 4863 return 0;
ee78dc32
GV
4864 }
4865 }
4866 }
ee78dc32
GV
4867
4868 goto dflt;
1edf84e7 4869
b1f918f8
GV
4870 case WM_GETMINMAXINFO:
4871 /* Hack to correct bug that allows Emacs frames to be resized
4872 below the Minimum Tracking Size. */
4873 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4874 return 0;
4875
1edf84e7
GV
4876 case WM_EMACS_CREATESCROLLBAR:
4877 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4878 (struct scroll_bar *) lParam);
4879
5ac45f98 4880 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4881 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4882
dfdb4047 4883 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4884 {
4885 HWND foreground_window;
4886 DWORD foreground_thread, retval;
4887
4888 /* On NT 5.0, and apparently Windows 98, it is necessary to
4889 attach to the thread that currently has focus in order to
4890 pull the focus away from it. */
4891 foreground_window = GetForegroundWindow ();
4892 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4893 if (!foreground_window
4894 || foreground_thread == GetCurrentThreadId ()
4895 || !AttachThreadInput (GetCurrentThreadId (),
4896 foreground_thread, TRUE))
4897 foreground_thread = 0;
4898
4899 retval = SetForegroundWindow ((HWND) wParam);
4900
4901 /* Detach from the previous foreground thread. */
4902 if (foreground_thread)
4903 AttachThreadInput (GetCurrentThreadId (),
4904 foreground_thread, FALSE);
4905
4906 return retval;
4907 }
dfdb4047 4908
5ac45f98
GV
4909 case WM_EMACS_SETWINDOWPOS:
4910 {
1edf84e7
GV
4911 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4912 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
4913 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4914 }
1edf84e7 4915
ee78dc32 4916 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 4917 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
4918 return DestroyWindow ((HWND) wParam);
4919
4920 case WM_EMACS_TRACKPOPUPMENU:
4921 {
4922 UINT flags;
4923 POINT *pos;
4924 int retval;
4925 pos = (POINT *)lParam;
4926 flags = TPM_CENTERALIGN;
4927 if (button_state & LMOUSE)
4928 flags |= TPM_LEFTBUTTON;
4929 else if (button_state & RMOUSE)
4930 flags |= TPM_RIGHTBUTTON;
4931
87996783
GV
4932 /* Remember we did a SetCapture on the initial mouse down event,
4933 so for safety, we make sure the capture is cancelled now. */
4934 ReleaseCapture ();
490822ff 4935 button_state = 0;
87996783 4936
1edf84e7
GV
4937 /* Use menubar_active to indicate that WM_INITMENU is from
4938 TrackPopupMenu below, and should be ignored. */
4939 f = x_window_to_frame (dpyinfo, hwnd);
4940 if (f)
4941 f->output_data.w32->menubar_active = 1;
4942
4943 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4944 0, hwnd, NULL))
4945 {
4946 MSG amsg;
4947 /* Eat any mouse messages during popupmenu */
4948 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4949 PM_REMOVE));
4950 /* Get the menu selection, if any */
4951 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4952 {
4953 retval = LOWORD (amsg.wParam);
4954 }
4955 else
4956 {
4957 retval = 0;
4958 }
1edf84e7
GV
4959 }
4960 else
4961 {
4962 retval = -1;
4963 }
4964
4965 return retval;
4966 }
4967
ee78dc32 4968 default:
93fbe8b7
GV
4969 /* Check for messages registered at runtime. */
4970 if (msg == msh_mousewheel)
4971 {
4972 wmsg.dwModifiers = w32_get_modifiers ();
4973 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4974 return 0;
4975 }
4976
ee78dc32
GV
4977 dflt:
4978 return DefWindowProc (hwnd, msg, wParam, lParam);
4979 }
4980
1edf84e7
GV
4981
4982 /* The most common default return code for handled messages is 0. */
4983 return 0;
ee78dc32
GV
4984}
4985
4986void
4987my_create_window (f)
4988 struct frame * f;
4989{
4990 MSG msg;
4991
1edf84e7
GV
4992 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4993 abort ();
ee78dc32
GV
4994 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4995}
4996
fbd6baed 4997/* Create and set up the w32 window for frame F. */
ee78dc32
GV
4998
4999static void
fbd6baed 5000w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5001 struct frame *f;
5002 long window_prompting;
5003 int minibuffer_only;
5004{
5005 BLOCK_INPUT;
5006
5007 /* Use the resource name as the top-level window name
5008 for looking up resources. Make a non-Lisp copy
5009 for the window manager, so GC relocation won't bother it.
5010
5011 Elsewhere we specify the window name for the window manager. */
5012
5013 {
5014 char *str = (char *) XSTRING (Vx_resource_name)->data;
5015 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5016 strcpy (f->namebuf, str);
5017 }
5018
5019 my_create_window (f);
5020
5021 validate_x_resource_name ();
5022
5023 /* x_set_name normally ignores requests to set the name if the
5024 requested name is the same as the current name. This is the one
5025 place where that assumption isn't correct; f->name is set, but
5026 the server hasn't been told. */
5027 {
5028 Lisp_Object name;
5029 int explicit = f->explicit_name;
5030
5031 f->explicit_name = 0;
5032 name = f->name;
5033 f->name = Qnil;
5034 x_set_name (f, name, explicit);
5035 }
5036
5037 UNBLOCK_INPUT;
5038
5039 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5040 initialize_frame_menubar (f);
5041
fbd6baed 5042 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5043 error ("Unable to create window");
5044}
5045
5046/* Handle the icon stuff for this window. Perhaps later we might
5047 want an x_set_icon_position which can be called interactively as
5048 well. */
5049
5050static void
5051x_icon (f, parms)
5052 struct frame *f;
5053 Lisp_Object parms;
5054{
5055 Lisp_Object icon_x, icon_y;
5056
e9e23e23 5057 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5058 icons in the tray. */
6fc2811b
JR
5059 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5060 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5061 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5062 {
5063 CHECK_NUMBER (icon_x, 0);
5064 CHECK_NUMBER (icon_y, 0);
5065 }
5066 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5067 error ("Both left and top icon corners of icon must be specified");
5068
5069 BLOCK_INPUT;
5070
5071 if (! EQ (icon_x, Qunbound))
5072 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5073
1edf84e7
GV
5074#if 0 /* TODO */
5075 /* Start up iconic or window? */
5076 x_wm_set_window_state
6fc2811b 5077 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5078 ? IconicState
5079 : NormalState));
5080
5081 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5082 ? f->icon_name
5083 : f->name))->data);
5084#endif
5085
ee78dc32
GV
5086 UNBLOCK_INPUT;
5087}
5088
6fc2811b
JR
5089
5090static void
5091x_make_gc (f)
5092 struct frame *f;
5093{
5094 XGCValues gc_values;
5095
5096 BLOCK_INPUT;
5097
5098 /* Create the GC's of this frame.
5099 Note that many default values are used. */
5100
5101 /* Normal video */
5102 gc_values.font = f->output_data.w32->font;
5103
5104 /* Cursor has cursor-color background, background-color foreground. */
5105 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5106 gc_values.background = f->output_data.w32->cursor_pixel;
5107 f->output_data.w32->cursor_gc
5108 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5109 (GCFont | GCForeground | GCBackground),
5110 &gc_values);
5111
5112 /* Reliefs. */
5113 f->output_data.w32->white_relief.gc = 0;
5114 f->output_data.w32->black_relief.gc = 0;
5115
5116 UNBLOCK_INPUT;
5117}
5118
5119
937e601e
AI
5120/* Handler for signals raised during x_create_frame and
5121 x_create_top_frame. FRAME is the frame which is partially
5122 constructed. */
5123
5124static Lisp_Object
5125unwind_create_frame (frame)
5126 Lisp_Object frame;
5127{
5128 struct frame *f = XFRAME (frame);
5129
5130 /* If frame is ``official'', nothing to do. */
5131 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5132 {
5133#ifdef GLYPH_DEBUG
5134 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5135#endif
5136
5137 x_free_frame_resources (f);
5138
5139 /* Check that reference counts are indeed correct. */
5140 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5141 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
5142
5143 tip_window = NULL;
5144 tip_frame = Qnil;
5145 }
5146
5147 return Qnil;
5148}
5149
5150
ee78dc32
GV
5151DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5152 1, 1, 0,
5153 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5154Returns an Emacs frame object.\n\
5155ALIST is an alist of frame parameters.\n\
5156If the parameters specify that the frame should not have a minibuffer,\n\
5157and do not specify a specific minibuffer window to use,\n\
5158then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5159be shared by the new frame.\n\
5160\n\
5161This function is an internal primitive--use `make-frame' instead.")
5162 (parms)
5163 Lisp_Object parms;
5164{
5165 struct frame *f;
5166 Lisp_Object frame, tem;
5167 Lisp_Object name;
5168 int minibuffer_only = 0;
5169 long window_prompting = 0;
5170 int width, height;
5171 int count = specpdl_ptr - specpdl;
1edf84e7 5172 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5173 Lisp_Object display;
6fc2811b 5174 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5175 Lisp_Object parent;
5176 struct kboard *kb;
5177
4587b026
GV
5178 check_w32 ();
5179
ee78dc32
GV
5180 /* Use this general default value to start with
5181 until we know if this frame has a specified name. */
5182 Vx_resource_name = Vinvocation_name;
5183
6fc2811b 5184 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5185 if (EQ (display, Qunbound))
5186 display = Qnil;
5187 dpyinfo = check_x_display_info (display);
5188#ifdef MULTI_KBOARD
5189 kb = dpyinfo->kboard;
5190#else
5191 kb = &the_only_kboard;
5192#endif
5193
6fc2811b 5194 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5195 if (!STRINGP (name)
5196 && ! EQ (name, Qunbound)
5197 && ! NILP (name))
5198 error ("Invalid frame name--not a string or nil");
5199
5200 if (STRINGP (name))
5201 Vx_resource_name = name;
5202
5203 /* See if parent window is specified. */
6fc2811b 5204 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5205 if (EQ (parent, Qunbound))
5206 parent = Qnil;
5207 if (! NILP (parent))
5208 CHECK_NUMBER (parent, 0);
5209
1edf84e7
GV
5210 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5211 /* No need to protect DISPLAY because that's not used after passing
5212 it to make_frame_without_minibuffer. */
5213 frame = Qnil;
5214 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5215 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5216 RES_TYPE_SYMBOL);
ee78dc32
GV
5217 if (EQ (tem, Qnone) || NILP (tem))
5218 f = make_frame_without_minibuffer (Qnil, kb, display);
5219 else if (EQ (tem, Qonly))
5220 {
5221 f = make_minibuffer_frame ();
5222 minibuffer_only = 1;
5223 }
5224 else if (WINDOWP (tem))
5225 f = make_frame_without_minibuffer (tem, kb, display);
5226 else
5227 f = make_frame (1);
5228
1edf84e7
GV
5229 XSETFRAME (frame, f);
5230
ee78dc32
GV
5231 /* Note that Windows does support scroll bars. */
5232 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5233 /* By default, make scrollbars the system standard width. */
5234 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5235
fbd6baed 5236 f->output_method = output_w32;
6fc2811b
JR
5237 f->output_data.w32 =
5238 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5239 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5240 FRAME_FONTSET (f) = -1;
937e601e 5241 record_unwind_protect (unwind_create_frame, frame);
4587b026 5242
1edf84e7 5243 f->icon_name
6fc2811b 5244 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5245 if (! STRINGP (f->icon_name))
5246 f->icon_name = Qnil;
5247
fbd6baed 5248/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5249#ifdef MULTI_KBOARD
5250 FRAME_KBOARD (f) = kb;
5251#endif
5252
5253 /* Specify the parent under which to make this window. */
5254
5255 if (!NILP (parent))
5256 {
1660f34a 5257 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5258 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5259 }
5260 else
5261 {
fbd6baed
GV
5262 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5263 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5264 }
5265
ee78dc32
GV
5266 /* Set the name; the functions to which we pass f expect the name to
5267 be set. */
5268 if (EQ (name, Qunbound) || NILP (name))
5269 {
fbd6baed 5270 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5271 f->explicit_name = 0;
5272 }
5273 else
5274 {
5275 f->name = name;
5276 f->explicit_name = 1;
5277 /* use the frame's title when getting resources for this frame. */
5278 specbind (Qx_resource_name, name);
5279 }
5280
5281 /* Extract the window parameters from the supplied values
5282 that are needed to determine window geometry. */
5283 {
5284 Lisp_Object font;
5285
6fc2811b
JR
5286 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5287
ee78dc32
GV
5288 BLOCK_INPUT;
5289 /* First, try whatever font the caller has specified. */
5290 if (STRINGP (font))
4587b026
GV
5291 {
5292 tem = Fquery_fontset (font, Qnil);
5293 if (STRINGP (tem))
5294 font = x_new_fontset (f, XSTRING (tem)->data);
5295 else
1075afa9 5296 font = x_new_font (f, XSTRING (font)->data);
4587b026 5297 }
ee78dc32
GV
5298 /* Try out a font which we hope has bold and italic variations. */
5299 if (!STRINGP (font))
e39649be 5300 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5301 if (! STRINGP (font))
6fc2811b 5302 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5303 /* If those didn't work, look for something which will at least work. */
5304 if (! STRINGP (font))
6fc2811b 5305 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5306 UNBLOCK_INPUT;
5307 if (! STRINGP (font))
1edf84e7 5308 font = build_string ("Fixedsys");
ee78dc32
GV
5309
5310 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5311 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5312 }
5313
5314 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5315 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5316 /* This defaults to 2 in order to match xterm. We recognize either
5317 internalBorderWidth or internalBorder (which is what xterm calls
5318 it). */
5319 if (NILP (Fassq (Qinternal_border_width, parms)))
5320 {
5321 Lisp_Object value;
5322
6fc2811b 5323 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5324 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5325 if (! EQ (value, Qunbound))
5326 parms = Fcons (Fcons (Qinternal_border_width, value),
5327 parms);
5328 }
1edf84e7 5329 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5330 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5331 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5332 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5333 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5334
5335 /* Also do the stuff which must be set before the window exists. */
5336 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5337 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5338 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5339 "background", "Background", RES_TYPE_STRING);
ee78dc32 5340 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5341 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5342 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5343 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5344 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5345 "borderColor", "BorderColor", RES_TYPE_STRING);
5346 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5347 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5348 x_default_parameter (f, parms, Qline_spacing, Qnil,
5349 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
6fc2811b 5350
ee78dc32 5351
6fc2811b
JR
5352 /* Init faces before x_default_parameter is called for scroll-bar
5353 parameters because that function calls x_set_scroll_bar_width,
5354 which calls change_frame_size, which calls Fset_window_buffer,
5355 which runs hooks, which call Fvertical_motion. At the end, we
5356 end up in init_iterator with a null face cache, which should not
5357 happen. */
5358 init_frame_faces (f);
5359
ee78dc32 5360 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5361 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5362 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5363 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5364 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5365 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5366 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5367 "title", "Title", RES_TYPE_STRING);
ee78dc32 5368
fbd6baed
GV
5369 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5370 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
ee78dc32
GV
5371 window_prompting = x_figure_window_size (f, parms);
5372
5373 if (window_prompting & XNegative)
5374 {
5375 if (window_prompting & YNegative)
fbd6baed 5376 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5377 else
fbd6baed 5378 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5379 }
5380 else
5381 {
5382 if (window_prompting & YNegative)
fbd6baed 5383 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5384 else
fbd6baed 5385 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5386 }
5387
fbd6baed 5388 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5389
6fc2811b
JR
5390 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5391 f->no_split = minibuffer_only || EQ (tem, Qt);
5392
5393 /* Create the window. Add the tool-bar height to the initial frame
5394 height so that the user gets a text display area of the size he
5395 specified with -g or via the registry. Later changes of the
5396 tool-bar height don't change the frame size. This is done so that
5397 users can create tall Emacs frames without having to guess how
5398 tall the tool-bar will get. */
5399 f->height += FRAME_TOOL_BAR_LINES (f);
fbd6baed 5400 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5401 x_icon (f, parms);
6fc2811b
JR
5402
5403 x_make_gc (f);
5404
5405 /* Now consider the frame official. */
5406 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5407 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5408
5409 /* We need to do this after creating the window, so that the
5410 icon-creation functions can say whose icon they're describing. */
5411 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5412 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5413
5414 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5415 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5416 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5417 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5418 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5419 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5420 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5421 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5422
5423 /* Dimensions, especially f->height, must be done via change_frame_size.
5424 Change will not be effected unless different from the current
5425 f->height. */
5426 width = f->width;
5427 height = f->height;
1026b400
RS
5428 f->height = 0;
5429 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5430 change_frame_size (f, height, width, 1, 0, 0);
5431
6fc2811b
JR
5432 /* Tell the server what size and position, etc, we want, and how
5433 badly we want them. This should be done after we have the menu
5434 bar so that its size can be taken into account. */
ee78dc32
GV
5435 BLOCK_INPUT;
5436 x_wm_set_size_hint (f, window_prompting, 0);
5437 UNBLOCK_INPUT;
5438
4694d762
JR
5439 /* Set up faces after all frame parameters are known. This call
5440 also merges in face attributes specified for new frames. If we
5441 don't do this, the `menu' face for instance won't have the right
5442 colors, and the menu bar won't appear in the specified colors for
5443 new frames. */
5444 call1 (Qface_set_after_frame_default, frame);
5445
6fc2811b
JR
5446 /* Make the window appear on the frame and enable display, unless
5447 the caller says not to. However, with explicit parent, Emacs
5448 cannot control visibility, so don't try. */
fbd6baed 5449 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5450 {
5451 Lisp_Object visibility;
5452
6fc2811b 5453 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5454 if (EQ (visibility, Qunbound))
5455 visibility = Qt;
5456
5457 if (EQ (visibility, Qicon))
5458 x_iconify_frame (f);
5459 else if (! NILP (visibility))
5460 x_make_frame_visible (f);
5461 else
5462 /* Must have been Qnil. */
5463 ;
5464 }
6fc2811b 5465 UNGCPRO;
ee78dc32
GV
5466 return unbind_to (count, frame);
5467}
5468
5469/* FRAME is used only to get a handle on the X display. We don't pass the
5470 display info directly because we're called from frame.c, which doesn't
5471 know about that structure. */
5472Lisp_Object
5473x_get_focus_frame (frame)
5474 struct frame *frame;
5475{
fbd6baed 5476 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5477 Lisp_Object xfocus;
fbd6baed 5478 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5479 return Qnil;
5480
fbd6baed 5481 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5482 return xfocus;
5483}
1edf84e7
GV
5484
5485DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5486 "Give FRAME input focus, raising to foreground if necessary.")
5487 (frame)
5488 Lisp_Object frame;
5489{
5490 x_focus_on_frame (check_x_frame (frame));
5491 return Qnil;
5492}
5493
ee78dc32 5494\f
767b1ff0
JR
5495/* Return the charset portion of a font name. */
5496char * xlfd_charset_of_font (char * fontname)
5497{
5498 char *charset, *encoding;
5499
5500 encoding = strrchr(fontname, '-');
ceb12877 5501 if (!encoding || encoding == fontname)
767b1ff0
JR
5502 return NULL;
5503
478ea067
AI
5504 for (charset = encoding - 1; charset >= fontname; charset--)
5505 if (*charset == '-')
5506 break;
767b1ff0 5507
478ea067 5508 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5509 return NULL;
5510
5511 return charset + 1;
5512}
5513
33d52f9c
GV
5514struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5515 int size, char* filename);
767b1ff0 5516BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len, char * charset);
33d52f9c 5517
4587b026 5518struct font_info *
33d52f9c 5519w32_load_system_font (f,fontname,size)
55dcfc15
AI
5520 struct frame *f;
5521 char * fontname;
5522 int size;
ee78dc32 5523{
4587b026
GV
5524 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5525 Lisp_Object font_names;
5526
4587b026
GV
5527 /* Get a list of all the fonts that match this name. Once we
5528 have a list of matching fonts, we compare them against the fonts
5529 we already have loaded by comparing names. */
5530 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5531
5532 if (!NILP (font_names))
3c190163 5533 {
4587b026
GV
5534 Lisp_Object tail;
5535 int i;
4587b026
GV
5536
5537 /* First check if any are already loaded, as that is cheaper
5538 than loading another one. */
5539 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5540 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5541 if (dpyinfo->font_table[i].name
5542 && (!strcmp (dpyinfo->font_table[i].name,
5543 XSTRING (XCAR (tail))->data)
5544 || !strcmp (dpyinfo->font_table[i].full_name,
5545 XSTRING (XCAR (tail))->data)))
4587b026 5546 return (dpyinfo->font_table + i);
6fc2811b 5547
8e713be6 5548 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5549 }
1075afa9 5550 else if (w32_strict_fontnames)
5ca0cd71
GV
5551 {
5552 /* If EnumFontFamiliesEx was available, we got a full list of
5553 fonts back so stop now to avoid the possibility of loading a
5554 random font. If we had to fall back to EnumFontFamilies, the
5555 list is incomplete, so continue whether the font we want was
5556 listed or not. */
5557 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5558 FARPROC enum_font_families_ex
1075afa9 5559 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5560 if (enum_font_families_ex)
5561 return NULL;
5562 }
4587b026
GV
5563
5564 /* Load the font and add it to the table. */
5565 {
767b1ff0 5566 char *full_name, *encoding, *charset;
4587b026
GV
5567 XFontStruct *font;
5568 struct font_info *fontp;
3c190163 5569 LOGFONT lf;
4587b026 5570 BOOL ok;
6fc2811b 5571 int i;
5ac45f98 5572
4587b026 5573 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5574 return (NULL);
5ac45f98 5575
4587b026
GV
5576 if (!*lf.lfFaceName)
5577 /* If no name was specified for the font, we get a random font
5578 from CreateFontIndirect - this is not particularly
5579 desirable, especially since CreateFontIndirect does not
5580 fill out the missing name in lf, so we never know what we
5581 ended up with. */
5582 return NULL;
5583
3c190163 5584 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5585 bzero (font, sizeof (*font));
5ac45f98 5586
33d52f9c
GV
5587 /* Set bdf to NULL to indicate that this is a Windows font. */
5588 font->bdf = NULL;
5ac45f98 5589
3c190163 5590 BLOCK_INPUT;
5ac45f98
GV
5591
5592 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5593
1a292d24
AI
5594 if (font->hfont == NULL)
5595 {
5596 ok = FALSE;
5597 }
5598 else
5599 {
5600 HDC hdc;
5601 HANDLE oldobj;
5c6682be 5602 int codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5603
5604 hdc = GetDC (dpyinfo->root_window);
5605 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5606
1a292d24 5607 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5608 if (codepage == CP_UNICODE)
5609 font->double_byte_p = 1;
5610 else
5611 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
5612
1a292d24
AI
5613 SelectObject (hdc, oldobj);
5614 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5615 /* Fill out details in lf according to the font that was
5616 actually loaded. */
5617 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5618 lf.lfWidth = font->tm.tmAveCharWidth;
5619 lf.lfWeight = font->tm.tmWeight;
5620 lf.lfItalic = font->tm.tmItalic;
5621 lf.lfCharSet = font->tm.tmCharSet;
5622 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5623 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5624 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5625 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5626
5627 w32_cache_char_metrics (font);
1a292d24 5628 }
5ac45f98 5629
1a292d24 5630 UNBLOCK_INPUT;
5ac45f98 5631
4587b026
GV
5632 if (!ok)
5633 {
1a292d24
AI
5634 w32_unload_font (dpyinfo, font);
5635 return (NULL);
5636 }
ee78dc32 5637
6fc2811b
JR
5638 /* Find a free slot in the font table. */
5639 for (i = 0; i < dpyinfo->n_fonts; ++i)
5640 if (dpyinfo->font_table[i].name == NULL)
5641 break;
5642
5643 /* If no free slot found, maybe enlarge the font table. */
5644 if (i == dpyinfo->n_fonts
5645 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5646 {
6fc2811b
JR
5647 int sz;
5648 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5649 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5650 dpyinfo->font_table
6fc2811b 5651 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5652 }
5653
6fc2811b
JR
5654 fontp = dpyinfo->font_table + i;
5655 if (i == dpyinfo->n_fonts)
5656 ++dpyinfo->n_fonts;
4587b026
GV
5657
5658 /* Now fill in the slots of *FONTP. */
5659 BLOCK_INPUT;
5660 fontp->font = font;
6fc2811b 5661 fontp->font_idx = i;
4587b026
GV
5662 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5663 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5664
767b1ff0
JR
5665 charset = xlfd_charset_of_font (fontname);
5666
4587b026
GV
5667 /* Work out the font's full name. */
5668 full_name = (char *)xmalloc (100);
767b1ff0 5669 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
5670 fontp->full_name = full_name;
5671 else
5672 {
5673 /* If all else fails - just use the name we used to load it. */
5674 xfree (full_name);
5675 fontp->full_name = fontp->name;
5676 }
5677
5678 fontp->size = FONT_WIDTH (font);
5679 fontp->height = FONT_HEIGHT (font);
5680
5681 /* The slot `encoding' specifies how to map a character
5682 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
5683 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5684 (0:0x20..0x7F, 1:0xA0..0xFF,
5685 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 5686 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 5687 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
5688 which is never used by any charset. If mapping can't be
5689 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5690
5691 /* SJIS fonts need to be set to type 4, all others seem to work as
5692 type FONT_ENCODING_NOT_DECIDED. */
5693 encoding = strrchr (fontp->name, '-');
5694 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5695 fontp->encoding[1] = 4;
33d52f9c 5696 else
1c885fe1 5697 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5698
5699 /* The following three values are set to 0 under W32, which is
5700 what they get set to if XGetFontProperty fails under X. */
5701 fontp->baseline_offset = 0;
5702 fontp->relative_compose = 0;
33d52f9c 5703 fontp->default_ascent = 0;
4587b026 5704
6fc2811b
JR
5705 /* Set global flag fonts_changed_p to non-zero if the font loaded
5706 has a character with a smaller width than any other character
5707 before, or if the font loaded has a smalle>r height than any
5708 other font loaded before. If this happens, it will make a
5709 glyph matrix reallocation necessary. */
5710 fonts_changed_p = x_compute_min_glyph_bounds (f);
4587b026 5711 UNBLOCK_INPUT;
4587b026
GV
5712 return fontp;
5713 }
5714}
5715
33d52f9c
GV
5716/* Load font named FONTNAME of size SIZE for frame F, and return a
5717 pointer to the structure font_info while allocating it dynamically.
5718 If loading fails, return NULL. */
5719struct font_info *
5720w32_load_font (f,fontname,size)
5721struct frame *f;
5722char * fontname;
5723int size;
5724{
5725 Lisp_Object bdf_fonts;
5726 struct font_info *retval = NULL;
5727
5728 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5729
5730 while (!retval && CONSP (bdf_fonts))
5731 {
5732 char *bdf_name, *bdf_file;
5733 Lisp_Object bdf_pair;
5734
8e713be6
KR
5735 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5736 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5737 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
5738
5739 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5740
8e713be6 5741 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
5742 }
5743
5744 if (retval)
5745 return retval;
5746
5747 return w32_load_system_font(f, fontname, size);
5748}
5749
5750
ee78dc32 5751void
fbd6baed
GV
5752w32_unload_font (dpyinfo, font)
5753 struct w32_display_info *dpyinfo;
ee78dc32
GV
5754 XFontStruct * font;
5755{
5756 if (font)
5757 {
c6be3860 5758 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
5759 if (font->bdf) w32_free_bdf_font (font->bdf);
5760
3c190163 5761 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5762 xfree (font);
5763 }
5764}
5765
fbd6baed 5766/* The font conversion stuff between x and w32 */
ee78dc32
GV
5767
5768/* X font string is as follows (from faces.el)
5769 * (let ((- "[-?]")
5770 * (foundry "[^-]+")
5771 * (family "[^-]+")
5772 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5773 * (weight\? "\\([^-]*\\)") ; 1
5774 * (slant "\\([ior]\\)") ; 2
5775 * (slant\? "\\([^-]?\\)") ; 2
5776 * (swidth "\\([^-]*\\)") ; 3
5777 * (adstyle "[^-]*") ; 4
5778 * (pixelsize "[0-9]+")
5779 * (pointsize "[0-9][0-9]+")
5780 * (resx "[0-9][0-9]+")
5781 * (resy "[0-9][0-9]+")
5782 * (spacing "[cmp?*]")
5783 * (avgwidth "[0-9]+")
5784 * (registry "[^-]+")
5785 * (encoding "[^-]+")
5786 * )
ee78dc32 5787 */
ee78dc32
GV
5788
5789LONG
fbd6baed 5790x_to_w32_weight (lpw)
ee78dc32
GV
5791 char * lpw;
5792{
5793 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
5794
5795 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5796 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5797 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5798 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 5799 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
5800 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5801 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5802 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5803 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5804 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 5805 else
5ac45f98 5806 return FW_DONTCARE;
ee78dc32
GV
5807}
5808
5ac45f98 5809
ee78dc32 5810char *
fbd6baed 5811w32_to_x_weight (fnweight)
ee78dc32
GV
5812 int fnweight;
5813{
5ac45f98
GV
5814 if (fnweight >= FW_HEAVY) return "heavy";
5815 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5816 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 5817 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
5818 if (fnweight >= FW_MEDIUM) return "medium";
5819 if (fnweight >= FW_NORMAL) return "normal";
5820 if (fnweight >= FW_LIGHT) return "light";
5821 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5822 if (fnweight >= FW_THIN) return "thin";
5823 else
5824 return "*";
5825}
5826
5827LONG
fbd6baed 5828x_to_w32_charset (lpcs)
5ac45f98
GV
5829 char * lpcs;
5830{
767b1ff0 5831 Lisp_Object this_entry, w32_charset;
4587b026 5832
dfff8a69
JR
5833 /* Look through w32-charset-info-alist for the character set.
5834 Format of each entry is
5835 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5836 */
767b1ff0 5837 this_entry = Fassoc (build_string(lpcs), Vw32_charset_info_alist);
4587b026 5838
767b1ff0
JR
5839 if (NILP(this_entry))
5840 {
5841 /* At startup, we want iso8859-1 fonts to come up properly. */
5842 if (stricmp(lpcs, "iso8859-1") == 0)
5843 return ANSI_CHARSET;
5844 else
5845 return DEFAULT_CHARSET;
5846 }
5847
5848 w32_charset = Fcar (Fcdr (this_entry));
5849
5850 // Translate Lisp symbol to number.
5851 if (w32_charset == Qw32_charset_ansi)
5852 return ANSI_CHARSET;
5853 if (w32_charset == Qw32_charset_symbol)
5854 return SYMBOL_CHARSET;
5855 if (w32_charset == Qw32_charset_shiftjis)
5856 return SHIFTJIS_CHARSET;
5857 if (w32_charset == Qw32_charset_hangeul)
5858 return HANGEUL_CHARSET;
5859 if (w32_charset == Qw32_charset_chinesebig5)
5860 return CHINESEBIG5_CHARSET;
5861 if (w32_charset == Qw32_charset_gb2312)
5862 return GB2312_CHARSET;
5863 if (w32_charset == Qw32_charset_oem)
5864 return OEM_CHARSET;
dfff8a69 5865#ifdef JOHAB_CHARSET
767b1ff0
JR
5866 if (w32_charset == Qw32_charset_johab)
5867 return JOHAB_CHARSET;
5868 if (w32_charset == Qw32_charset_easteurope)
5869 return EASTEUROPE_CHARSET;
5870 if (w32_charset == Qw32_charset_turkish)
5871 return TURKISH_CHARSET;
5872 if (w32_charset == Qw32_charset_baltic)
5873 return BALTIC_CHARSET;
5874 if (w32_charset == Qw32_charset_russian)
5875 return RUSSIAN_CHARSET;
5876 if (w32_charset == Qw32_charset_arabic)
5877 return ARABIC_CHARSET;
5878 if (w32_charset == Qw32_charset_greek)
5879 return GREEK_CHARSET;
5880 if (w32_charset == Qw32_charset_hebrew)
5881 return HEBREW_CHARSET;
5882 if (w32_charset == Qw32_charset_vietnamese)
5883 return VIETNAMESE_CHARSET;
5884 if (w32_charset == Qw32_charset_thai)
5885 return THAI_CHARSET;
5886 if (w32_charset == Qw32_charset_mac)
5887 return MAC_CHARSET;
dfff8a69 5888#endif /* JOHAB_CHARSET */
5ac45f98 5889#ifdef UNICODE_CHARSET
767b1ff0
JR
5890 if (w32_charset == Qw32_charset_unicode)
5891 return UNICODE_CHARSET;
5ac45f98 5892#endif
dfff8a69
JR
5893
5894 return DEFAULT_CHARSET;
5ac45f98
GV
5895}
5896
dfff8a69 5897
5ac45f98 5898char *
fbd6baed 5899w32_to_x_charset (fncharset)
5ac45f98
GV
5900 int fncharset;
5901{
1edf84e7 5902 static char buf[16];
767b1ff0 5903 Lisp_Object charset_type;
1edf84e7 5904
5ac45f98
GV
5905 switch (fncharset)
5906 {
767b1ff0
JR
5907 case ANSI_CHARSET:
5908 /* Handle startup case of w32-charset-info-alist not
5909 being set up yet. */
5910 if (NILP(Vw32_charset_info_alist))
5911 return "iso8859-1";
5912 charset_type = Qw32_charset_ansi;
5913 break;
5914 case DEFAULT_CHARSET:
5915 charset_type = Qw32_charset_default;
5916 break;
5917 case SYMBOL_CHARSET:
5918 charset_type = Qw32_charset_symbol;
5919 break;
5920 case SHIFTJIS_CHARSET:
5921 charset_type = Qw32_charset_shiftjis;
5922 break;
5923 case HANGEUL_CHARSET:
5924 charset_type = Qw32_charset_hangeul;
5925 break;
5926 case GB2312_CHARSET:
5927 charset_type = Qw32_charset_gb2312;
5928 break;
5929 case CHINESEBIG5_CHARSET:
5930 charset_type = Qw32_charset_chinesebig5;
5931 break;
5932 case OEM_CHARSET:
5933 charset_type = Qw32_charset_oem;
5934 break;
4587b026
GV
5935
5936 /* More recent versions of Windows (95 and NT4.0) define more
5937 character sets. */
5938#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
5939 case EASTEUROPE_CHARSET:
5940 charset_type = Qw32_charset_easteurope;
5941 break;
5942 case TURKISH_CHARSET:
5943 charset_type = Qw32_charset_turkish;
5944 break;
5945 case BALTIC_CHARSET:
5946 charset_type = Qw32_charset_baltic;
5947 break;
33d52f9c 5948 case RUSSIAN_CHARSET:
767b1ff0
JR
5949 charset_type = Qw32_charset_russian;
5950 break;
5951 case ARABIC_CHARSET:
5952 charset_type = Qw32_charset_arabic;
5953 break;
5954 case GREEK_CHARSET:
5955 charset_type = Qw32_charset_greek;
5956 break;
5957 case HEBREW_CHARSET:
5958 charset_type = Qw32_charset_hebrew;
5959 break;
5960 case VIETNAMESE_CHARSET:
5961 charset_type = Qw32_charset_vietnamese;
5962 break;
5963 case THAI_CHARSET:
5964 charset_type = Qw32_charset_thai;
5965 break;
5966 case MAC_CHARSET:
5967 charset_type = Qw32_charset_mac;
5968 break;
5969 case JOHAB_CHARSET:
5970 charset_type = Qw32_charset_johab;
5971 break;
4587b026
GV
5972#endif
5973
5ac45f98 5974#ifdef UNICODE_CHARSET
767b1ff0
JR
5975 case UNICODE_CHARSET:
5976 charset_type = Qw32_charset_unicode;
5977 break;
5ac45f98 5978#endif
767b1ff0
JR
5979 default:
5980 /* Encode numerical value of unknown charset. */
5981 sprintf (buf, "*-#%u", fncharset);
5982 return buf;
5ac45f98 5983 }
767b1ff0
JR
5984
5985 {
5986 Lisp_Object rest;
5987 char * best_match = NULL;
5988
5989 /* Look through w32-charset-info-alist for the character set.
5990 Prefer ISO codepages, and prefer lower numbers in the ISO
5991 range. Only return charsets for codepages which are installed.
5992
5993 Format of each entry is
5994 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5995 */
5996 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5997 {
5998 char * x_charset;
5999 Lisp_Object w32_charset;
6000 Lisp_Object codepage;
6001
6002 Lisp_Object this_entry = XCAR (rest);
6003
6004 /* Skip invalid entries in alist. */
6005 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6006 || !CONSP (XCDR (this_entry))
6007 || !SYMBOLP (XCAR (XCDR (this_entry))))
6008 continue;
6009
6010 x_charset = XSTRING (XCAR (this_entry))->data;
6011 w32_charset = XCAR (XCDR (this_entry));
6012 codepage = XCDR (XCDR (this_entry));
6013
6014 /* Look for Same charset and a valid codepage (or non-int
6015 which means ignore). */
6016 if (w32_charset == charset_type
6017 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6018 || IsValidCodePage (XINT (codepage))))
6019 {
6020 /* If we don't have a match already, then this is the
6021 best. */
6022 if (!best_match)
6023 best_match = x_charset;
6024 /* If this is an ISO codepage, and the best so far isn't,
6025 then this is better. */
6026 else if (stricmp (best_match, "iso") != 0
6027 && stricmp (x_charset, "iso") == 0)
6028 best_match = x_charset;
6029 /* If both are ISO8859 codepages, choose the one with the
6030 lowest number in the encoding field. */
6031 else if (stricmp (best_match, "iso8859-") == 0
6032 && stricmp (x_charset, "iso8859-") == 0)
6033 {
6034 int best_enc = atoi (best_match + 8);
6035 int this_enc = atoi (x_charset + 8);
6036 if (this_enc > 0 && this_enc < best_enc)
6037 best_match = x_charset;
6038 }
6039 }
6040 }
6041
6042 /* If no match, encode the numeric value. */
6043 if (!best_match)
6044 {
6045 sprintf (buf, "*-#%u", fncharset);
6046 return buf;
6047 }
6048
6049 strncpy(buf, best_match, 15);
6050 buf[15] = '\0';
6051 return buf;
6052 }
ee78dc32
GV
6053}
6054
dfff8a69
JR
6055
6056/* Get the Windows codepage corresponding to the specified font. The
6057 charset info in the font name is used to look up
6058 w32-charset-to-codepage-alist. */
6059int
6060w32_codepage_for_font (char *fontname)
6061{
767b1ff0
JR
6062 Lisp_Object codepage, entry;
6063 char *charset_str, *charset, *end;
dfff8a69 6064
767b1ff0 6065 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6066 return CP_DEFAULT;
6067
767b1ff0
JR
6068 /* Extract charset part of font string. */
6069 charset = xlfd_charset_of_font (fontname);
6070
6071 if (!charset)
ceb12877 6072 return CP_UNKNOWN;
767b1ff0
JR
6073
6074 charset_str = (char *) alloca (strlen (charset));
6075 strcpy (charset_str, charset);
6076
dfff8a69
JR
6077 /* Remove leading "*-". */
6078 if (strncmp ("*-", charset_str, 2) == 0)
6079 charset = charset_str + 2;
6080 else
6081 charset = charset_str;
6082
6083 /* Stop match at wildcard (including preceding '-'). */
6084 if (end = strchr (charset, '*'))
6085 {
6086 if (end > charset && *(end-1) == '-')
6087 end--;
6088 *end = '\0';
6089 }
6090
767b1ff0
JR
6091 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6092 if (NILP (entry))
ceb12877 6093 return CP_UNKNOWN;
767b1ff0
JR
6094
6095 codepage = Fcdr (Fcdr (entry));
6096
6097 if (NILP (codepage))
6098 return CP_8BIT;
6099 else if (XFASTINT (codepage) == XFASTINT (Qt))
6100 return CP_UNICODE;
6101 else if (INTEGERP (codepage))
dfff8a69
JR
6102 return XINT (codepage);
6103 else
ceb12877 6104 return CP_UNKNOWN;
dfff8a69
JR
6105}
6106
6107
ee78dc32 6108BOOL
767b1ff0 6109w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6110 LOGFONT * lplogfont;
6111 char * lpxstr;
6112 int len;
767b1ff0 6113 char * specific_charset;
ee78dc32 6114{
6fc2811b 6115 char* fonttype;
f46e6225 6116 char *fontname;
3cb20f4a
RS
6117 char height_pixels[8];
6118 char height_dpi[8];
6119 char width_pixels[8];
4587b026 6120 char *fontname_dash;
d88c567c
JR
6121 int display_resy = one_w32_display_info.resy;
6122 int display_resx = one_w32_display_info.resx;
f46e6225
GV
6123 int bufsz;
6124 struct coding_system coding;
3cb20f4a
RS
6125
6126 if (!lpxstr) abort ();
ee78dc32 6127
3cb20f4a
RS
6128 if (!lplogfont)
6129 return FALSE;
6130
6fc2811b
JR
6131 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6132 fonttype = "raster";
6133 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6134 fonttype = "outline";
6135 else
6136 fonttype = "unknown";
6137
f46e6225
GV
6138 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
6139 &coding);
aab5ac44
KH
6140 coding.src_multibyte = 0;
6141 coding.dst_multibyte = 1;
f46e6225
GV
6142 coding.mode |= CODING_MODE_LAST_BLOCK;
6143 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6144
6145 fontname = alloca(sizeof(*fontname) * bufsz);
6146 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6147 strlen(lplogfont->lfFaceName), bufsz - 1);
6148 *(fontname + coding.produced) = '\0';
4587b026
GV
6149
6150 /* Replace dashes with underscores so the dashes are not
f46e6225 6151 misinterpreted. */
4587b026
GV
6152 fontname_dash = fontname;
6153 while (fontname_dash = strchr (fontname_dash, '-'))
6154 *fontname_dash = '_';
6155
3cb20f4a 6156 if (lplogfont->lfHeight)
ee78dc32 6157 {
3cb20f4a
RS
6158 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6159 sprintf (height_dpi, "%u",
33d52f9c 6160 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6161 }
6162 else
ee78dc32 6163 {
3cb20f4a
RS
6164 strcpy (height_pixels, "*");
6165 strcpy (height_dpi, "*");
ee78dc32 6166 }
3cb20f4a
RS
6167 if (lplogfont->lfWidth)
6168 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6169 else
6170 strcpy (width_pixels, "*");
6171
6172 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6173 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6174 fonttype, /* foundry */
4587b026
GV
6175 fontname, /* family */
6176 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6177 lplogfont->lfItalic?'i':'r', /* slant */
6178 /* setwidth name */
6179 /* add style name */
6180 height_pixels, /* pixel size */
6181 height_dpi, /* point size */
33d52f9c
GV
6182 display_resx, /* resx */
6183 display_resy, /* resy */
4587b026
GV
6184 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6185 ? 'p' : 'c', /* spacing */
6186 width_pixels, /* avg width */
767b1ff0
JR
6187 specific_charset ? specific_charset
6188 : w32_to_x_charset (lplogfont->lfCharSet)
6189 /* charset registry and encoding */
3cb20f4a
RS
6190 );
6191
ee78dc32
GV
6192 lpxstr[len - 1] = 0; /* just to be sure */
6193 return (TRUE);
6194}
6195
6196BOOL
fbd6baed 6197x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6198 char * lpxstr;
6199 LOGFONT * lplogfont;
6200{
f46e6225
GV
6201 struct coding_system coding;
6202
ee78dc32 6203 if (!lplogfont) return (FALSE);
f46e6225 6204
ee78dc32 6205 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6206
1a292d24 6207 /* Set default value for each field. */
771c47d5 6208#if 1
ee78dc32
GV
6209 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6210 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6211 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6212#else
6213 /* go for maximum quality */
6214 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6215 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6216 lplogfont->lfQuality = PROOF_QUALITY;
6217#endif
6218
1a292d24
AI
6219 lplogfont->lfCharSet = DEFAULT_CHARSET;
6220 lplogfont->lfWeight = FW_DONTCARE;
6221 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6222
5ac45f98
GV
6223 if (!lpxstr)
6224 return FALSE;
6225
6226 /* Provide a simple escape mechanism for specifying Windows font names
6227 * directly -- if font spec does not beginning with '-', assume this
6228 * format:
6229 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6230 */
ee78dc32 6231
5ac45f98
GV
6232 if (*lpxstr == '-')
6233 {
33d52f9c
GV
6234 int fields, tem;
6235 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6236 width[10], resy[10], remainder[20];
5ac45f98 6237 char * encoding;
d98c0337 6238 int dpi = one_w32_display_info.resy;
5ac45f98
GV
6239
6240 fields = sscanf (lpxstr,
33d52f9c
GV
6241 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
6242 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5ac45f98
GV
6243 if (fields == EOF) return (FALSE);
6244
6fc2811b
JR
6245 /* If wildcards cover more than one field, we don't know which
6246 field is which, so don't fill any in. */
6247
6248 if (fields < 9)
6249 fields = 0;
6250
5ac45f98
GV
6251 if (fields > 0 && name[0] != '*')
6252 {
8ea3e054
RS
6253 int bufsize;
6254 unsigned char *buf;
6255
f46e6225
GV
6256 setup_coding_system
6257 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
aab5ac44
KH
6258 coding.src_multibyte = 1;
6259 coding.dst_multibyte = 1;
8ea3e054
RS
6260 bufsize = encoding_buffer_size (&coding, strlen (name));
6261 buf = (unsigned char *) alloca (bufsize);
f46e6225 6262 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6263 encode_coding (&coding, name, buf, strlen (name), bufsize);
6264 if (coding.produced >= LF_FACESIZE)
6265 coding.produced = LF_FACESIZE - 1;
6266 buf[coding.produced] = 0;
6267 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6268 }
6269 else
6270 {
6fc2811b 6271 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6272 }
6273
6274 fields--;
6275
fbd6baed 6276 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6277
6278 fields--;
6279
c8874f14 6280 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6281
6282 fields--;
6283
6284 if (fields > 0 && pixels[0] != '*')
6285 lplogfont->lfHeight = atoi (pixels);
6286
6287 fields--;
5ac45f98 6288 fields--;
33d52f9c
GV
6289 if (fields > 0 && resy[0] != '*')
6290 {
6fc2811b 6291 tem = atoi (resy);
33d52f9c
GV
6292 if (tem > 0) dpi = tem;
6293 }
5ac45f98 6294
33d52f9c
GV
6295 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6296 lplogfont->lfHeight = atoi (height) * dpi / 720;
6297
6298 if (fields > 0)
5ac45f98
GV
6299 lplogfont->lfPitchAndFamily =
6300 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6301
6302 fields--;
6303
6304 if (fields > 0 && width[0] != '*')
6305 lplogfont->lfWidth = atoi (width) / 10;
6306
6307 fields--;
6308
4587b026 6309 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6310 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6311 {
5ac45f98
GV
6312 int len = strlen (remainder);
6313 if (len > 0 && remainder[len-1] == '-')
6314 remainder[len-1] = 0;
ee78dc32 6315 }
5ac45f98
GV
6316 encoding = remainder;
6317 if (strncmp (encoding, "*-", 2) == 0)
6318 encoding += 2;
fbd6baed 6319 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
5ac45f98
GV
6320 }
6321 else
6322 {
6323 int fields;
6324 char name[100], height[10], width[10], weight[20];
a1a80b40 6325
5ac45f98
GV
6326 fields = sscanf (lpxstr,
6327 "%99[^:]:%9[^:]:%9[^:]:%19s",
6328 name, height, width, weight);
6329
6330 if (fields == EOF) return (FALSE);
6331
6332 if (fields > 0)
6333 {
6334 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6335 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6336 }
6337 else
6338 {
6339 lplogfont->lfFaceName[0] = 0;
6340 }
6341
6342 fields--;
6343
6344 if (fields > 0)
6345 lplogfont->lfHeight = atoi (height);
6346
6347 fields--;
6348
6349 if (fields > 0)
6350 lplogfont->lfWidth = atoi (width);
6351
6352 fields--;
6353
fbd6baed 6354 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6355 }
6356
6357 /* This makes TrueType fonts work better. */
6358 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6359
ee78dc32
GV
6360 return (TRUE);
6361}
6362
d88c567c
JR
6363/* Strip the pixel height and point height from the given xlfd, and
6364 return the pixel height. If no pixel height is specified, calculate
6365 one from the point height, or if that isn't defined either, return
6366 0 (which usually signifies a scalable font).
6367*/
6368int xlfd_strip_height (char *fontname)
6369{
6370 int pixel_height, point_height, dpi, field_number;
6371 char *read_from, *write_to;
6372
6373 xassert (fontname);
6374
6375 pixel_height = field_number = 0;
6376 write_to = NULL;
6377
6378 /* Look for height fields. */
6379 for (read_from = fontname; *read_from; read_from++)
6380 {
6381 if (*read_from == '-')
6382 {
6383 field_number++;
6384 if (field_number == 7) /* Pixel height. */
6385 {
6386 read_from++;
6387 write_to = read_from;
6388
6389 /* Find end of field. */
6390 for (;*read_from && *read_from != '-'; read_from++)
6391 ;
6392
6393 /* Split the fontname at end of field. */
6394 if (*read_from)
6395 {
6396 *read_from = '\0';
6397 read_from++;
6398 }
6399 pixel_height = atoi (write_to);
6400 /* Blank out field. */
6401 if (read_from > write_to)
6402 {
6403 *write_to = '-';
6404 write_to++;
6405 }
767b1ff0 6406 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6407 return now. */
6408 else
6409 return pixel_height;
6410
6411 /* If we got a pixel height, the point height can be
6412 ignored. Just blank it out and break now. */
6413 if (pixel_height)
6414 {
6415 /* Find end of point size field. */
6416 for (; *read_from && *read_from != '-'; read_from++)
6417 ;
6418
6419 if (*read_from)
6420 read_from++;
6421
6422 /* Blank out the point size field. */
6423 if (read_from > write_to)
6424 {
6425 *write_to = '-';
6426 write_to++;
6427 }
6428 else
6429 return pixel_height;
6430
6431 break;
6432 }
6433 /* If the point height is already blank, break now. */
6434 if (*read_from == '-')
6435 {
6436 read_from++;
6437 break;
6438 }
6439 }
6440 else if (field_number == 8)
6441 {
6442 /* If we didn't get a pixel height, try to get the point
6443 height and convert that. */
6444 int point_size;
6445 char *point_size_start = read_from++;
6446
6447 /* Find end of field. */
6448 for (; *read_from && *read_from != '-'; read_from++)
6449 ;
6450
6451 if (*read_from)
6452 {
6453 *read_from = '\0';
6454 read_from++;
6455 }
6456
6457 point_size = atoi (point_size_start);
6458
6459 /* Convert to pixel height. */
6460 pixel_height = point_size
6461 * one_w32_display_info.height_in / 720;
6462
6463 /* Blank out this field and break. */
6464 *write_to = '-';
6465 write_to++;
6466 break;
6467 }
6468 }
6469 }
6470
6471 /* Shift the rest of the font spec into place. */
6472 if (write_to && read_from > write_to)
6473 {
6474 for (; *read_from; read_from++, write_to++)
6475 *write_to = *read_from;
6476 *write_to = '\0';
6477 }
6478
6479 return pixel_height;
6480}
6481
6fc2811b 6482/* Assume parameter 1 is fully qualified, no wildcards. */
ee78dc32 6483BOOL
6fc2811b
JR
6484w32_font_match (fontname, pattern)
6485 char * fontname;
6486 char * pattern;
ee78dc32 6487{
6fc2811b 6488 char *regex = alloca (strlen (pattern) * 2);
d88c567c 6489 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6490 char *ptr;
ee78dc32 6491
d88c567c
JR
6492 /* Copy fontname so we can modify it during comparison. */
6493 strcpy (font_name_copy, fontname);
6494
6fc2811b
JR
6495 ptr = regex;
6496 *ptr++ = '^';
ee78dc32 6497
6fc2811b
JR
6498 /* Turn pattern into a regexp and do a regexp match. */
6499 for (; *pattern; pattern++)
6500 {
6501 if (*pattern == '?')
6502 *ptr++ = '.';
6503 else if (*pattern == '*')
6504 {
6505 *ptr++ = '.';
6506 *ptr++ = '*';
6507 }
33d52f9c 6508 else
6fc2811b 6509 *ptr++ = *pattern;
ee78dc32 6510 }
6fc2811b
JR
6511 *ptr = '$';
6512 *(ptr + 1) = '\0';
6513
d88c567c
JR
6514 /* Strip out font heights and compare them seperately, since
6515 rounding error can cause mismatches. This also allows a
6516 comparison between a font that declares only a pixel height and a
6517 pattern that declares the point height.
6518 */
6519 {
6520 int font_height, pattern_height;
6521
6522 font_height = xlfd_strip_height (font_name_copy);
6523 pattern_height = xlfd_strip_height (regex);
6524
6525 /* Compare now, and don't bother doing expensive regexp matching
6526 if the heights differ. */
6527 if (font_height && pattern_height && (font_height != pattern_height))
6528 return FALSE;
6529 }
6530
6fc2811b 6531 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 6532 font_name_copy) >= 0);
ee78dc32
GV
6533}
6534
5ca0cd71
GV
6535/* Callback functions, and a structure holding info they need, for
6536 listing system fonts on W32. We need one set of functions to do the
6537 job properly, but these don't work on NT 3.51 and earlier, so we
6538 have a second set which don't handle character sets properly to
6539 fall back on.
6540
6541 In both cases, there are two passes made. The first pass gets one
6542 font from each family, the second pass lists all the fonts from
6543 each family. */
6544
ee78dc32
GV
6545typedef struct enumfont_t
6546{
6547 HDC hdc;
6548 int numFonts;
3cb20f4a 6549 LOGFONT logfont;
ee78dc32
GV
6550 XFontStruct *size_ref;
6551 Lisp_Object *pattern;
ee78dc32
GV
6552 Lisp_Object *tail;
6553} enumfont_t;
6554
6555int CALLBACK
6556enum_font_cb2 (lplf, lptm, FontType, lpef)
6557 ENUMLOGFONT * lplf;
6558 NEWTEXTMETRIC * lptm;
6559 int FontType;
6560 enumfont_t * lpef;
6561{
1edf84e7 6562 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
ee78dc32
GV
6563 return (1);
6564
4587b026
GV
6565 /* Check that the character set matches if it was specified */
6566 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6567 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6568 return (1);
6569
ee78dc32
GV
6570 {
6571 char buf[100];
4587b026 6572 Lisp_Object width = Qnil;
767b1ff0 6573 char *charset = NULL;
ee78dc32 6574
6fc2811b
JR
6575 /* Truetype fonts do not report their true metrics until loaded */
6576 if (FontType != RASTER_FONTTYPE)
3cb20f4a 6577 {
6fc2811b
JR
6578 if (!NILP (*(lpef->pattern)))
6579 {
6580 /* Scalable fonts are as big as you want them to be. */
6581 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6582 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6583 width = make_number (lpef->logfont.lfWidth);
6584 }
6585 else
6586 {
6587 lplf->elfLogFont.lfHeight = 0;
6588 lplf->elfLogFont.lfWidth = 0;
6589 }
3cb20f4a 6590 }
6fc2811b 6591
f46e6225
GV
6592 /* Make sure the height used here is the same as everywhere
6593 else (ie character height, not cell height). */
6fc2811b
JR
6594 if (lplf->elfLogFont.lfHeight > 0)
6595 {
6596 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6597 if (FontType == RASTER_FONTTYPE)
6598 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6599 else
6600 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6601 }
4587b026 6602
767b1ff0
JR
6603 if (!NILP (*(lpef->pattern)))
6604 {
6605 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6606
6607 /* Ensure that charset is valid for this font. */
6608 if (charset
6609 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6610 charset = NULL;
6611 }
6612
6613 /* TODO: List all relevant charsets if charset not specified. */
6614 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
33d52f9c 6615 return (0);
ee78dc32 6616
5ca0cd71
GV
6617 if (NILP (*(lpef->pattern))
6618 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 6619 {
4587b026 6620 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
8e713be6 6621 lpef->tail = &(XCDR (*lpef->tail));
ee78dc32
GV
6622 lpef->numFonts++;
6623 }
6624 }
6fc2811b 6625
ee78dc32
GV
6626 return (1);
6627}
6628
6629int CALLBACK
6630enum_font_cb1 (lplf, lptm, FontType, lpef)
6631 ENUMLOGFONT * lplf;
6632 NEWTEXTMETRIC * lptm;
6633 int FontType;
6634 enumfont_t * lpef;
6635{
6636 return EnumFontFamilies (lpef->hdc,
6637 lplf->elfLogFont.lfFaceName,
6638 (FONTENUMPROC) enum_font_cb2,
6639 (LPARAM) lpef);
6640}
6641
6642
5ca0cd71
GV
6643int CALLBACK
6644enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6645 ENUMLOGFONTEX * lplf;
6646 NEWTEXTMETRICEX * lptm;
6647 int font_type;
6648 enumfont_t * lpef;
6649{
6650 /* We are not interested in the extra info we get back from the 'Ex
6651 version - only the fact that we get character set variations
6652 enumerated seperately. */
6653 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6654 font_type, lpef);
6655}
6656
6657int CALLBACK
6658enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6659 ENUMLOGFONTEX * lplf;
6660 NEWTEXTMETRICEX * lptm;
6661 int font_type;
6662 enumfont_t * lpef;
6663{
6664 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6665 FARPROC enum_font_families_ex
6666 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6667 /* We don't really expect EnumFontFamiliesEx to disappear once we
6668 get here, so don't bother handling it gracefully. */
6669 if (enum_font_families_ex == NULL)
6670 error ("gdi32.dll has disappeared!");
6671 return enum_font_families_ex (lpef->hdc,
6672 &lplf->elfLogFont,
6673 (FONTENUMPROC) enum_fontex_cb2,
6674 (LPARAM) lpef, 0);
6675}
6676
4587b026
GV
6677/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6678 and xterm.c in Emacs 20.3) */
6679
5ca0cd71 6680Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6681{
6682 char *fontname, *ptnstr;
6683 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6684 int n_fonts = 0;
33d52f9c
GV
6685
6686 list = Vw32_bdf_filename_alist;
6687 ptnstr = XSTRING (pattern)->data;
6688
8e713be6 6689 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6690 {
8e713be6 6691 tem = XCAR (list);
33d52f9c 6692 if (CONSP (tem))
8e713be6 6693 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
6694 else if (STRINGP (tem))
6695 fontname = XSTRING (tem)->data;
6696 else
6697 continue;
6698
6699 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6700 {
8e713be6 6701 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6702 n_fonts++;
6703 if (n_fonts >= max_names)
6704 break;
6705 }
33d52f9c
GV
6706 }
6707
6708 return newlist;
6709}
6710
5ca0cd71
GV
6711Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
6712 int size, int max_names);
6713
4587b026
GV
6714/* Return a list of names of available fonts matching PATTERN on frame
6715 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6716 to be listed. Frame F NULL means we have not yet created any
6717 frame, which means we can't get proper size info, as we don't have
6718 a device context to use for GetTextMetrics.
6719 MAXNAMES sets a limit on how many fonts to match. */
6720
6721Lisp_Object
6722w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
6723{
6fc2811b 6724 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6725 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6726 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6727 int n_fonts = 0;
396594fe 6728
4587b026
GV
6729 patterns = Fassoc (pattern, Valternate_fontname_alist);
6730 if (NILP (patterns))
6731 patterns = Fcons (pattern, Qnil);
6732
8e713be6 6733 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6734 {
6735 enumfont_t ef;
767b1ff0 6736 int codepage;
4587b026 6737
8e713be6 6738 tpat = XCAR (patterns);
4587b026 6739
767b1ff0
JR
6740 if (!STRINGP (tpat))
6741 continue;
6742
6743 /* Avoid expensive EnumFontFamilies functions if we are not
6744 going to be able to output one of these anyway. */
6745 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6746 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
6747 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6748 && !IsValidCodePage(codepage))
767b1ff0
JR
6749 continue;
6750
4587b026
GV
6751 /* See if we cached the result for this particular query.
6752 The cache is an alist of the form:
6753 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6754 */
8e713be6 6755 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 6756 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
6757 {
6758 list = Fcdr_safe (list);
6759 /* We have a cached list. Don't have to get the list again. */
6760 goto label_cached;
6761 }
6762
6763 BLOCK_INPUT;
6764 /* At first, put PATTERN in the cache. */
6765 list = Qnil;
33d52f9c
GV
6766 ef.pattern = &tpat;
6767 ef.tail = &list;
4587b026 6768 ef.numFonts = 0;
33d52f9c 6769
5ca0cd71
GV
6770 /* Use EnumFontFamiliesEx where it is available, as it knows
6771 about character sets. Fall back to EnumFontFamilies for
6772 older versions of NT that don't support the 'Ex function. */
767b1ff0 6773 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 6774 {
5ca0cd71
GV
6775 LOGFONT font_match_pattern;
6776 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6777 FARPROC enum_font_families_ex
6778 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6779
6780 /* We do our own pattern matching so we can handle wildcards. */
6781 font_match_pattern.lfFaceName[0] = 0;
6782 font_match_pattern.lfPitchAndFamily = 0;
6783 /* We can use the charset, because if it is a wildcard it will
6784 be DEFAULT_CHARSET anyway. */
6785 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6786
33d52f9c 6787 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 6788
5ca0cd71
GV
6789 if (enum_font_families_ex)
6790 enum_font_families_ex (ef.hdc,
6791 &font_match_pattern,
6792 (FONTENUMPROC) enum_fontex_cb1,
6793 (LPARAM) &ef, 0);
6794 else
6795 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6796 (LPARAM)&ef);
4587b026 6797
33d52f9c 6798 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
6799 }
6800
6801 UNBLOCK_INPUT;
6802
6803 /* Make a list of the fonts we got back.
6804 Store that in the font cache for the display. */
8e713be6 6805 XCDR (dpyinfo->name_list_element)
33d52f9c 6806 = Fcons (Fcons (tpat, list),
8e713be6 6807 XCDR (dpyinfo->name_list_element));
4587b026
GV
6808
6809 label_cached:
6810 if (NILP (list)) continue; /* Try the remaining alternatives. */
6811
6812 newlist = second_best = Qnil;
6813
6814 /* Make a list of the fonts that have the right width. */
8e713be6 6815 for (; CONSP (list); list = XCDR (list))
4587b026
GV
6816 {
6817 int found_size;
8e713be6 6818 tem = XCAR (list);
4587b026
GV
6819
6820 if (!CONSP (tem))
6821 continue;
8e713be6 6822 if (NILP (XCAR (tem)))
4587b026
GV
6823 continue;
6824 if (!size)
6825 {
8e713be6 6826 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6827 n_fonts++;
6828 if (n_fonts >= maxnames)
6829 break;
6830 else
6831 continue;
4587b026 6832 }
8e713be6 6833 if (!INTEGERP (XCDR (tem)))
4587b026
GV
6834 {
6835 /* Since we don't yet know the size of the font, we must
6836 load it and try GetTextMetrics. */
4587b026
GV
6837 W32FontStruct thisinfo;
6838 LOGFONT lf;
6839 HDC hdc;
6840 HANDLE oldobj;
6841
8e713be6 6842 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
6843 continue;
6844
6845 BLOCK_INPUT;
33d52f9c 6846 thisinfo.bdf = NULL;
4587b026
GV
6847 thisinfo.hfont = CreateFontIndirect (&lf);
6848 if (thisinfo.hfont == NULL)
6849 continue;
6850
6851 hdc = GetDC (dpyinfo->root_window);
6852 oldobj = SelectObject (hdc, thisinfo.hfont);
6853 if (GetTextMetrics (hdc, &thisinfo.tm))
8e713be6 6854 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
4587b026 6855 else
8e713be6 6856 XCDR (tem) = make_number (0);
4587b026
GV
6857 SelectObject (hdc, oldobj);
6858 ReleaseDC (dpyinfo->root_window, hdc);
6859 DeleteObject(thisinfo.hfont);
6860 UNBLOCK_INPUT;
6861 }
8e713be6 6862 found_size = XINT (XCDR (tem));
4587b026 6863 if (found_size == size)
5ca0cd71 6864 {
8e713be6 6865 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6866 n_fonts++;
6867 if (n_fonts >= maxnames)
6868 break;
6869 }
4587b026
GV
6870 /* keep track of the closest matching size in case
6871 no exact match is found. */
6872 else if (found_size > 0)
6873 {
6874 if (NILP (second_best))
6875 second_best = tem;
5ca0cd71 6876
4587b026
GV
6877 else if (found_size < size)
6878 {
8e713be6
KR
6879 if (XINT (XCDR (second_best)) > size
6880 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
6881 second_best = tem;
6882 }
6883 else
6884 {
8e713be6
KR
6885 if (XINT (XCDR (second_best)) > size
6886 && XINT (XCDR (second_best)) >
4587b026
GV
6887 found_size)
6888 second_best = tem;
6889 }
6890 }
6891 }
6892
6893 if (!NILP (newlist))
6894 break;
6895 else if (!NILP (second_best))
6896 {
8e713be6 6897 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
6898 break;
6899 }
6900 }
6901
33d52f9c 6902 /* Include any bdf fonts. */
5ca0cd71 6903 if (n_fonts < maxnames)
33d52f9c
GV
6904 {
6905 Lisp_Object combined[2];
5ca0cd71 6906 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
6907 combined[1] = newlist;
6908 newlist = Fnconc(2, combined);
6909 }
6910
5ca0cd71
GV
6911 /* If we can't find a font that matches, check if Windows would be
6912 able to synthesize it from a different style. */
6fc2811b 6913 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
5ca0cd71
GV
6914 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6915
4587b026
GV
6916 return newlist;
6917}
6918
5ca0cd71
GV
6919Lisp_Object
6920w32_list_synthesized_fonts (f, pattern, size, max_names)
6921 FRAME_PTR f;
6922 Lisp_Object pattern;
6923 int size;
6924 int max_names;
6925{
6926 int fields;
6927 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6928 char style[20], slant;
6929 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6930
6931 full_pattn = XSTRING (pattern)->data;
6932
6933 pattn_part2 = alloca (XSTRING (pattern)->size);
6934 /* Allow some space for wildcard expansion. */
6935 new_pattn = alloca (XSTRING (pattern)->size + 100);
6936
6937 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6938 foundary, family, style, &slant, pattn_part2);
6939 if (fields == EOF || fields < 5)
6940 return Qnil;
6941
6942 /* If the style and slant are wildcards already there is no point
6943 checking again (and we don't want to keep recursing). */
6944 if (*style == '*' && slant == '*')
6945 return Qnil;
6946
6947 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6948
6949 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6950
8e713be6 6951 for ( ; CONSP (matches); matches = XCDR (matches))
5ca0cd71 6952 {
8e713be6 6953 tem = XCAR (matches);
5ca0cd71
GV
6954 if (!STRINGP (tem))
6955 continue;
6956
6957 full_pattn = XSTRING (tem)->data;
6958 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6959 foundary, family, pattn_part2);
6960 if (fields == EOF || fields < 3)
6961 continue;
6962
6963 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6964 slant, pattn_part2);
6965
6966 synthed_matches = Fcons (build_string (new_pattn),
6967 synthed_matches);
6968 }
6969
6970 return synthed_matches;
6971}
6972
6973
4587b026
GV
6974/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6975struct font_info *
6976w32_get_font_info (f, font_idx)
6977 FRAME_PTR f;
6978 int font_idx;
6979{
6980 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6981}
6982
6983
6984struct font_info*
6985w32_query_font (struct frame *f, char *fontname)
6986{
6987 int i;
6988 struct font_info *pfi;
6989
6990 pfi = FRAME_W32_FONT_TABLE (f);
6991
6992 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6993 {
6994 if (strcmp(pfi->name, fontname) == 0) return pfi;
6995 }
6996
6997 return NULL;
6998}
6999
7000/* Find a CCL program for a font specified by FONTP, and set the member
7001 `encoder' of the structure. */
7002
7003void
7004w32_find_ccl_program (fontp)
7005 struct font_info *fontp;
7006{
3545439c 7007 Lisp_Object list, elt;
4587b026 7008
8e713be6 7009 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7010 {
8e713be6 7011 elt = XCAR (list);
4587b026 7012 if (CONSP (elt)
8e713be6
KR
7013 && STRINGP (XCAR (elt))
7014 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7015 >= 0))
3545439c
KH
7016 break;
7017 }
7018 if (! NILP (list))
7019 {
17eedd00
KH
7020 struct ccl_program *ccl
7021 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7022
8e713be6 7023 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7024 xfree (ccl);
7025 else
7026 fontp->font_encoder = ccl;
4587b026
GV
7027 }
7028}
7029
7030\f
6fc2811b
JR
7031DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7032 1, 1, 0,
7033 "Return a list of BDF fonts in DIR, suitable for appending to\n\
767b1ff0 7034w32-bdf-filename-alist. Fonts which do not contain an xlfd description\n\
6fc2811b
JR
7035will not be included in the list. DIR may be a list of directories.")
7036 (directory)
7037 Lisp_Object directory;
7038{
7039 Lisp_Object list = Qnil;
7040 struct gcpro gcpro1, gcpro2;
ee78dc32 7041
6fc2811b
JR
7042 if (!CONSP (directory))
7043 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7044
6fc2811b 7045 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7046 {
6fc2811b
JR
7047 Lisp_Object pair[2];
7048 pair[0] = list;
7049 pair[1] = Qnil;
7050 GCPRO2 (directory, list);
7051 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7052 list = Fnconc( 2, pair );
7053 UNGCPRO;
7054 }
7055 return list;
7056}
ee78dc32 7057
6fc2811b
JR
7058/* Find BDF files in a specified directory. (use GCPRO when calling,
7059 as this calls lisp to get a directory listing). */
7060Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
7061{
7062 Lisp_Object filelist, list = Qnil;
7063 char fontname[100];
ee78dc32 7064
6fc2811b
JR
7065 if (!STRINGP(directory))
7066 return Qnil;
ee78dc32 7067
6fc2811b
JR
7068 filelist = Fdirectory_files (directory, Qt,
7069 build_string (".*\\.[bB][dD][fF]"), Qt);
ee78dc32 7070
6fc2811b 7071 for ( ; CONSP(filelist); filelist = XCDR (filelist))
ee78dc32 7072 {
6fc2811b
JR
7073 Lisp_Object filename = XCAR (filelist);
7074 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7075 store_in_alist (&list, build_string (fontname), filename);
7076 }
7077 return list;
7078}
ee78dc32 7079
6fc2811b
JR
7080\f
7081DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
dfff8a69 7082 "Internal function called by `color-defined-p', which see.")
6fc2811b
JR
7083 (color, frame)
7084 Lisp_Object color, frame;
7085{
7086 XColor foo;
7087 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7088
6fc2811b 7089 CHECK_STRING (color, 1);
ee78dc32 7090
6fc2811b
JR
7091 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7092 return Qt;
7093 else
7094 return Qnil;
7095}
ee78dc32 7096
2d764c78 7097DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
dfff8a69 7098 "Internal function called by `color-values', which see.")
ee78dc32
GV
7099 (color, frame)
7100 Lisp_Object color, frame;
7101{
6fc2811b 7102 XColor foo;
ee78dc32
GV
7103 FRAME_PTR f = check_x_frame (frame);
7104
7105 CHECK_STRING (color, 1);
7106
6fc2811b 7107 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7108 {
7109 Lisp_Object rgb[3];
7110
6fc2811b
JR
7111 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7112 | GetRValue (foo.pixel));
7113 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7114 | GetGValue (foo.pixel));
7115 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7116 | GetBValue (foo.pixel));
ee78dc32
GV
7117 return Flist (3, rgb);
7118 }
7119 else
7120 return Qnil;
7121}
7122
2d764c78 7123DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
dfff8a69 7124 "Internal function called by `display-color-p', which see.")
ee78dc32
GV
7125 (display)
7126 Lisp_Object display;
7127{
fbd6baed 7128 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7129
7130 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7131 return Qnil;
7132
7133 return Qt;
7134}
7135
7136DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
7137 0, 1, 0,
7138 "Return t if the X display supports shades of gray.\n\
7139Note that color displays do support shades of gray.\n\
7140The optional argument DISPLAY specifies which display to ask about.\n\
7141DISPLAY should be either a frame or a display name (a string).\n\
7142If omitted or nil, that stands for the selected frame's display.")
7143 (display)
7144 Lisp_Object display;
7145{
fbd6baed 7146 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7147
7148 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7149 return Qnil;
7150
7151 return Qt;
7152}
7153
7154DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
7155 0, 1, 0,
7156 "Returns the width in pixels of the X display DISPLAY.\n\
7157The optional argument DISPLAY specifies which display to ask about.\n\
7158DISPLAY should be either a frame or a display name (a string).\n\
7159If omitted or nil, that stands for the selected frame's display.")
7160 (display)
7161 Lisp_Object display;
7162{
fbd6baed 7163 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7164
7165 return make_number (dpyinfo->width);
7166}
7167
7168DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7169 Sx_display_pixel_height, 0, 1, 0,
7170 "Returns the height in pixels of the X display DISPLAY.\n\
7171The optional argument DISPLAY specifies which display to ask about.\n\
7172DISPLAY should be either a frame or a display name (a string).\n\
7173If omitted or nil, that stands for the selected frame's display.")
7174 (display)
7175 Lisp_Object display;
7176{
fbd6baed 7177 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7178
7179 return make_number (dpyinfo->height);
7180}
7181
7182DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7183 0, 1, 0,
7184 "Returns the number of bitplanes of the display DISPLAY.\n\
7185The optional argument DISPLAY specifies which display to ask about.\n\
7186DISPLAY should be either a frame or a display name (a string).\n\
7187If omitted or nil, that stands for the selected frame's display.")
7188 (display)
7189 Lisp_Object display;
7190{
fbd6baed 7191 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7192
7193 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7194}
7195
7196DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7197 0, 1, 0,
7198 "Returns the number of color cells of the display DISPLAY.\n\
7199The optional argument DISPLAY specifies which display to ask about.\n\
7200DISPLAY should be either a frame or a display name (a string).\n\
7201If omitted or nil, that stands for the selected frame's display.")
7202 (display)
7203 Lisp_Object display;
7204{
fbd6baed 7205 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7206 HDC hdc;
7207 int cap;
7208
5ac45f98
GV
7209 hdc = GetDC (dpyinfo->root_window);
7210 if (dpyinfo->has_palette)
7211 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7212 else
7213 cap = GetDeviceCaps (hdc,NUMCOLORS);
ee78dc32
GV
7214
7215 ReleaseDC (dpyinfo->root_window, hdc);
7216
7217 return make_number (cap);
7218}
7219
7220DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7221 Sx_server_max_request_size,
7222 0, 1, 0,
7223 "Returns the maximum request size of the server of display DISPLAY.\n\
7224The optional argument DISPLAY specifies which display to ask about.\n\
7225DISPLAY should be either a frame or a display name (a string).\n\
7226If omitted or nil, that stands for the selected frame's display.")
7227 (display)
7228 Lisp_Object display;
7229{
fbd6baed 7230 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7231
7232 return make_number (1);
7233}
7234
7235DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
fbd6baed 7236 "Returns the vendor ID string of the W32 system (Microsoft).\n\
ee78dc32
GV
7237The optional argument DISPLAY specifies which display to ask about.\n\
7238DISPLAY should be either a frame or a display name (a string).\n\
7239If omitted or nil, that stands for the selected frame's display.")
7240 (display)
7241 Lisp_Object display;
7242{
dfff8a69 7243 return build_string ("Microsoft Corp.");
ee78dc32
GV
7244}
7245
7246DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7247 "Returns the version numbers of the server of display DISPLAY.\n\
7248The value is a list of three integers: the major and minor\n\
7249version numbers, and the vendor-specific release\n\
7250number. See also the function `x-server-vendor'.\n\n\
7251The optional argument DISPLAY specifies which display to ask about.\n\
7252DISPLAY should be either a frame or a display name (a string).\n\
7253If omitted or nil, that stands for the selected frame's display.")
7254 (display)
7255 Lisp_Object display;
7256{
fbd6baed 7257 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7258 Fcons (make_number (w32_minor_version),
7259 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7260}
7261
7262DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7263 "Returns the number of screens on the server of display DISPLAY.\n\
7264The optional argument DISPLAY specifies which display to ask about.\n\
7265DISPLAY should be either a frame or a display name (a string).\n\
7266If omitted or nil, that stands for the selected frame's display.")
7267 (display)
7268 Lisp_Object display;
7269{
ee78dc32
GV
7270 return make_number (1);
7271}
7272
7273DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7274 "Returns the height in millimeters of the X display DISPLAY.\n\
7275The optional argument DISPLAY specifies which display to ask about.\n\
7276DISPLAY should be either a frame or a display name (a string).\n\
7277If omitted or nil, that stands for the selected frame's display.")
7278 (display)
7279 Lisp_Object display;
7280{
fbd6baed 7281 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7282 HDC hdc;
7283 int cap;
7284
5ac45f98 7285 hdc = GetDC (dpyinfo->root_window);
3c190163 7286
ee78dc32 7287 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7288
ee78dc32
GV
7289 ReleaseDC (dpyinfo->root_window, hdc);
7290
7291 return make_number (cap);
7292}
7293
7294DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7295 "Returns the width in millimeters of the X display DISPLAY.\n\
7296The optional argument DISPLAY specifies which display to ask about.\n\
7297DISPLAY should be either a frame or a display name (a string).\n\
7298If omitted or nil, that stands for the selected frame's display.")
7299 (display)
7300 Lisp_Object display;
7301{
fbd6baed 7302 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7303
7304 HDC hdc;
7305 int cap;
7306
5ac45f98 7307 hdc = GetDC (dpyinfo->root_window);
3c190163 7308
ee78dc32 7309 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7310
ee78dc32
GV
7311 ReleaseDC (dpyinfo->root_window, hdc);
7312
7313 return make_number (cap);
7314}
7315
7316DEFUN ("x-display-backing-store", Fx_display_backing_store,
7317 Sx_display_backing_store, 0, 1, 0,
7318 "Returns an indication of whether display DISPLAY does backing store.\n\
7319The value may be `always', `when-mapped', or `not-useful'.\n\
7320The optional argument DISPLAY specifies which display to ask about.\n\
7321DISPLAY should be either a frame or a display name (a string).\n\
7322If omitted or nil, that stands for the selected frame's display.")
7323 (display)
7324 Lisp_Object display;
7325{
7326 return intern ("not-useful");
7327}
7328
7329DEFUN ("x-display-visual-class", Fx_display_visual_class,
7330 Sx_display_visual_class, 0, 1, 0,
7331 "Returns the visual class of the display DISPLAY.\n\
7332The value is one of the symbols `static-gray', `gray-scale',\n\
7333`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7334The optional argument DISPLAY specifies which display to ask about.\n\
7335DISPLAY should be either a frame or a display name (a string).\n\
7336If omitted or nil, that stands for the selected frame's display.")
7337 (display)
7338 Lisp_Object display;
7339{
fbd6baed 7340 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7341
7342#if 0
7343 switch (dpyinfo->visual->class)
7344 {
7345 case StaticGray: return (intern ("static-gray"));
7346 case GrayScale: return (intern ("gray-scale"));
7347 case StaticColor: return (intern ("static-color"));
7348 case PseudoColor: return (intern ("pseudo-color"));
7349 case TrueColor: return (intern ("true-color"));
7350 case DirectColor: return (intern ("direct-color"));
7351 default:
7352 error ("Display has an unknown visual class");
7353 }
7354#endif
7355
7356 error ("Display has an unknown visual class");
7357}
7358
7359DEFUN ("x-display-save-under", Fx_display_save_under,
7360 Sx_display_save_under, 0, 1, 0,
7361 "Returns t if the display DISPLAY supports the save-under feature.\n\
7362The optional argument DISPLAY specifies which display to ask about.\n\
7363DISPLAY should be either a frame or a display name (a string).\n\
7364If omitted or nil, that stands for the selected frame's display.")
7365 (display)
7366 Lisp_Object display;
7367{
6fc2811b
JR
7368 return Qnil;
7369}
7370\f
7371int
7372x_pixel_width (f)
7373 register struct frame *f;
7374{
7375 return PIXEL_WIDTH (f);
7376}
7377
7378int
7379x_pixel_height (f)
7380 register struct frame *f;
7381{
7382 return PIXEL_HEIGHT (f);
7383}
7384
7385int
7386x_char_width (f)
7387 register struct frame *f;
7388{
7389 return FONT_WIDTH (f->output_data.w32->font);
7390}
7391
7392int
7393x_char_height (f)
7394 register struct frame *f;
7395{
7396 return f->output_data.w32->line_height;
7397}
7398
7399int
7400x_screen_planes (f)
7401 register struct frame *f;
7402{
7403 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7404}
7405\f
7406/* Return the display structure for the display named NAME.
7407 Open a new connection if necessary. */
7408
7409struct w32_display_info *
7410x_display_info_for_name (name)
7411 Lisp_Object name;
7412{
7413 Lisp_Object names;
7414 struct w32_display_info *dpyinfo;
7415
7416 CHECK_STRING (name, 0);
7417
7418 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7419 dpyinfo;
7420 dpyinfo = dpyinfo->next, names = XCDR (names))
7421 {
7422 Lisp_Object tem;
7423 tem = Fstring_equal (XCAR (XCAR (names)), name);
7424 if (!NILP (tem))
7425 return dpyinfo;
7426 }
7427
7428 /* Use this general default value to start with. */
7429 Vx_resource_name = Vinvocation_name;
7430
7431 validate_x_resource_name ();
7432
7433 dpyinfo = w32_term_init (name, (unsigned char *)0,
7434 (char *) XSTRING (Vx_resource_name)->data);
7435
7436 if (dpyinfo == 0)
7437 error ("Cannot connect to server %s", XSTRING (name)->data);
7438
7439 w32_in_use = 1;
7440 XSETFASTINT (Vwindow_system_version, 3);
7441
7442 return dpyinfo;
7443}
7444
7445DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7446 1, 3, 0, "Open a connection to a server.\n\
7447DISPLAY is the name of the display to connect to.\n\
7448Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7449If the optional third arg MUST-SUCCEED is non-nil,\n\
7450terminate Emacs if we can't open the connection.")
7451 (display, xrm_string, must_succeed)
7452 Lisp_Object display, xrm_string, must_succeed;
7453{
7454 unsigned char *xrm_option;
7455 struct w32_display_info *dpyinfo;
7456
7457 CHECK_STRING (display, 0);
7458 if (! NILP (xrm_string))
7459 CHECK_STRING (xrm_string, 1);
7460
7461 if (! EQ (Vwindow_system, intern ("w32")))
7462 error ("Not using Microsoft Windows");
7463
7464 /* Allow color mapping to be defined externally; first look in user's
7465 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7466 {
7467 Lisp_Object color_file;
7468 struct gcpro gcpro1;
7469
7470 color_file = build_string("~/rgb.txt");
7471
7472 GCPRO1 (color_file);
7473
7474 if (NILP (Ffile_readable_p (color_file)))
7475 color_file =
7476 Fexpand_file_name (build_string ("rgb.txt"),
7477 Fsymbol_value (intern ("data-directory")));
7478
7479 Vw32_color_map = Fw32_load_color_file (color_file);
7480
7481 UNGCPRO;
7482 }
7483 if (NILP (Vw32_color_map))
7484 Vw32_color_map = Fw32_default_color_map ();
7485
7486 if (! NILP (xrm_string))
7487 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7488 else
7489 xrm_option = (unsigned char *) 0;
7490
7491 /* Use this general default value to start with. */
7492 /* First remove .exe suffix from invocation-name - it looks ugly. */
7493 {
7494 char basename[ MAX_PATH ], *str;
7495
7496 strcpy (basename, XSTRING (Vinvocation_name)->data);
7497 str = strrchr (basename, '.');
7498 if (str) *str = 0;
7499 Vinvocation_name = build_string (basename);
7500 }
7501 Vx_resource_name = Vinvocation_name;
7502
7503 validate_x_resource_name ();
7504
7505 /* This is what opens the connection and sets x_current_display.
7506 This also initializes many symbols, such as those used for input. */
7507 dpyinfo = w32_term_init (display, xrm_option,
7508 (char *) XSTRING (Vx_resource_name)->data);
7509
7510 if (dpyinfo == 0)
7511 {
7512 if (!NILP (must_succeed))
7513 fatal ("Cannot connect to server %s.\n",
7514 XSTRING (display)->data);
7515 else
7516 error ("Cannot connect to server %s", XSTRING (display)->data);
7517 }
7518
7519 w32_in_use = 1;
7520
7521 XSETFASTINT (Vwindow_system_version, 3);
7522 return Qnil;
7523}
7524
7525DEFUN ("x-close-connection", Fx_close_connection,
7526 Sx_close_connection, 1, 1, 0,
7527 "Close the connection to DISPLAY's server.\n\
7528For DISPLAY, specify either a frame or a display name (a string).\n\
7529If DISPLAY is nil, that stands for the selected frame's display.")
7530 (display)
7531 Lisp_Object display;
7532{
7533 struct w32_display_info *dpyinfo = check_x_display_info (display);
7534 int i;
7535
7536 if (dpyinfo->reference_count > 0)
7537 error ("Display still has frames on it");
7538
7539 BLOCK_INPUT;
7540 /* Free the fonts in the font table. */
7541 for (i = 0; i < dpyinfo->n_fonts; i++)
7542 if (dpyinfo->font_table[i].name)
7543 {
126f2e35
JR
7544 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7545 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 7546 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
7547 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7548 }
7549 x_destroy_all_bitmaps (dpyinfo);
7550
7551 x_delete_display (dpyinfo);
7552 UNBLOCK_INPUT;
7553
7554 return Qnil;
7555}
7556
7557DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7558 "Return the list of display names that Emacs has connections to.")
7559 ()
7560{
7561 Lisp_Object tail, result;
7562
7563 result = Qnil;
7564 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7565 result = Fcons (XCAR (XCAR (tail)), result);
7566
7567 return result;
7568}
7569
7570DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7571 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7572If ON is nil, allow buffering of requests.\n\
7573This is a noop on W32 systems.\n\
7574The optional second argument DISPLAY specifies which display to act on.\n\
7575DISPLAY should be either a frame or a display name (a string).\n\
7576If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7577 (on, display)
7578 Lisp_Object display, on;
7579{
6fc2811b
JR
7580 return Qnil;
7581}
7582
7583\f
7584\f
7585/***********************************************************************
7586 Image types
7587 ***********************************************************************/
7588
7589/* Value is the number of elements of vector VECTOR. */
7590
7591#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7592
7593/* List of supported image types. Use define_image_type to add new
7594 types. Use lookup_image_type to find a type for a given symbol. */
7595
7596static struct image_type *image_types;
7597
6fc2811b
JR
7598/* The symbol `image' which is the car of the lists used to represent
7599 images in Lisp. */
7600
7601extern Lisp_Object Qimage;
7602
7603/* The symbol `xbm' which is used as the type symbol for XBM images. */
7604
7605Lisp_Object Qxbm;
7606
7607/* Keywords. */
7608
6fc2811b 7609extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
7610extern Lisp_Object QCdata;
7611Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
6fc2811b 7612Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
dfff8a69 7613Lisp_Object QCindex;
6fc2811b
JR
7614
7615/* Other symbols. */
7616
7617Lisp_Object Qlaplace;
7618
7619/* Time in seconds after which images should be removed from the cache
7620 if not displayed. */
7621
7622Lisp_Object Vimage_cache_eviction_delay;
7623
7624/* Function prototypes. */
7625
7626static void define_image_type P_ ((struct image_type *type));
7627static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7628static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7629static void x_laplace P_ ((struct frame *, struct image *));
7630static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7631 Lisp_Object));
7632
dfff8a69 7633
6fc2811b
JR
7634/* Define a new image type from TYPE. This adds a copy of TYPE to
7635 image_types and adds the symbol *TYPE->type to Vimage_types. */
7636
7637static void
7638define_image_type (type)
7639 struct image_type *type;
7640{
7641 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7642 The initialized data segment is read-only. */
7643 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7644 bcopy (type, p, sizeof *p);
7645 p->next = image_types;
7646 image_types = p;
7647 Vimage_types = Fcons (*p->type, Vimage_types);
7648}
7649
7650
7651/* Look up image type SYMBOL, and return a pointer to its image_type
7652 structure. Value is null if SYMBOL is not a known image type. */
7653
7654static INLINE struct image_type *
7655lookup_image_type (symbol)
7656 Lisp_Object symbol;
7657{
7658 struct image_type *type;
7659
7660 for (type = image_types; type; type = type->next)
7661 if (EQ (symbol, *type->type))
7662 break;
7663
7664 return type;
7665}
7666
7667
7668/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7669 valid image specification is a list whose car is the symbol
7670 `image', and whose rest is a property list. The property list must
7671 contain a value for key `:type'. That value must be the name of a
7672 supported image type. The rest of the property list depends on the
7673 image type. */
7674
7675int
7676valid_image_p (object)
7677 Lisp_Object object;
7678{
7679 int valid_p = 0;
7680
7681 if (CONSP (object) && EQ (XCAR (object), Qimage))
7682 {
7683 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7684 struct image_type *type = lookup_image_type (symbol);
7685
7686 if (type)
7687 valid_p = type->valid_p (object);
7688 }
7689
7690 return valid_p;
7691}
7692
7693
7694/* Log error message with format string FORMAT and argument ARG.
7695 Signaling an error, e.g. when an image cannot be loaded, is not a
7696 good idea because this would interrupt redisplay, and the error
7697 message display would lead to another redisplay. This function
7698 therefore simply displays a message. */
7699
7700static void
7701image_error (format, arg1, arg2)
7702 char *format;
7703 Lisp_Object arg1, arg2;
7704{
7705 add_to_log (format, arg1, arg2);
7706}
7707
7708
7709\f
7710/***********************************************************************
7711 Image specifications
7712 ***********************************************************************/
7713
7714enum image_value_type
7715{
7716 IMAGE_DONT_CHECK_VALUE_TYPE,
7717 IMAGE_STRING_VALUE,
7718 IMAGE_SYMBOL_VALUE,
7719 IMAGE_POSITIVE_INTEGER_VALUE,
7720 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 7721 IMAGE_ASCENT_VALUE,
6fc2811b
JR
7722 IMAGE_INTEGER_VALUE,
7723 IMAGE_FUNCTION_VALUE,
7724 IMAGE_NUMBER_VALUE,
7725 IMAGE_BOOL_VALUE
7726};
7727
7728/* Structure used when parsing image specifications. */
7729
7730struct image_keyword
7731{
7732 /* Name of keyword. */
7733 char *name;
7734
7735 /* The type of value allowed. */
7736 enum image_value_type type;
7737
7738 /* Non-zero means key must be present. */
7739 int mandatory_p;
7740
7741 /* Used to recognize duplicate keywords in a property list. */
7742 int count;
7743
7744 /* The value that was found. */
7745 Lisp_Object value;
7746};
7747
7748
7749static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7750 int, Lisp_Object));
7751static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7752
7753
7754/* Parse image spec SPEC according to KEYWORDS. A valid image spec
7755 has the format (image KEYWORD VALUE ...). One of the keyword/
7756 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7757 image_keywords structures of size NKEYWORDS describing other
7758 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7759
7760static int
7761parse_image_spec (spec, keywords, nkeywords, type)
7762 Lisp_Object spec;
7763 struct image_keyword *keywords;
7764 int nkeywords;
7765 Lisp_Object type;
7766{
7767 int i;
7768 Lisp_Object plist;
7769
7770 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7771 return 0;
7772
7773 plist = XCDR (spec);
7774 while (CONSP (plist))
7775 {
7776 Lisp_Object key, value;
7777
7778 /* First element of a pair must be a symbol. */
7779 key = XCAR (plist);
7780 plist = XCDR (plist);
7781 if (!SYMBOLP (key))
7782 return 0;
7783
7784 /* There must follow a value. */
7785 if (!CONSP (plist))
7786 return 0;
7787 value = XCAR (plist);
7788 plist = XCDR (plist);
7789
7790 /* Find key in KEYWORDS. Error if not found. */
7791 for (i = 0; i < nkeywords; ++i)
7792 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7793 break;
7794
7795 if (i == nkeywords)
7796 continue;
7797
7798 /* Record that we recognized the keyword. If a keywords
7799 was found more than once, it's an error. */
7800 keywords[i].value = value;
7801 ++keywords[i].count;
7802
7803 if (keywords[i].count > 1)
7804 return 0;
7805
7806 /* Check type of value against allowed type. */
7807 switch (keywords[i].type)
7808 {
7809 case IMAGE_STRING_VALUE:
7810 if (!STRINGP (value))
7811 return 0;
7812 break;
7813
7814 case IMAGE_SYMBOL_VALUE:
7815 if (!SYMBOLP (value))
7816 return 0;
7817 break;
7818
7819 case IMAGE_POSITIVE_INTEGER_VALUE:
7820 if (!INTEGERP (value) || XINT (value) <= 0)
7821 return 0;
7822 break;
7823
dfff8a69
JR
7824 case IMAGE_ASCENT_VALUE:
7825 if (SYMBOLP (value) && EQ (value, Qcenter))
7826 break;
7827 else if (INTEGERP (value)
7828 && XINT (value) >= 0
7829 && XINT (value) <= 100)
7830 break;
7831 return 0;
7832
6fc2811b
JR
7833 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7834 if (!INTEGERP (value) || XINT (value) < 0)
7835 return 0;
7836 break;
7837
7838 case IMAGE_DONT_CHECK_VALUE_TYPE:
7839 break;
7840
7841 case IMAGE_FUNCTION_VALUE:
7842 value = indirect_function (value);
7843 if (SUBRP (value)
7844 || COMPILEDP (value)
7845 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7846 break;
7847 return 0;
7848
7849 case IMAGE_NUMBER_VALUE:
7850 if (!INTEGERP (value) && !FLOATP (value))
7851 return 0;
7852 break;
7853
7854 case IMAGE_INTEGER_VALUE:
7855 if (!INTEGERP (value))
7856 return 0;
7857 break;
7858
7859 case IMAGE_BOOL_VALUE:
7860 if (!NILP (value) && !EQ (value, Qt))
7861 return 0;
7862 break;
7863
7864 default:
7865 abort ();
7866 break;
7867 }
7868
7869 if (EQ (key, QCtype) && !EQ (type, value))
7870 return 0;
7871 }
7872
7873 /* Check that all mandatory fields are present. */
7874 for (i = 0; i < nkeywords; ++i)
7875 if (keywords[i].mandatory_p && keywords[i].count == 0)
7876 return 0;
7877
7878 return NILP (plist);
7879}
7880
7881
7882/* Return the value of KEY in image specification SPEC. Value is nil
7883 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7884 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7885
7886static Lisp_Object
7887image_spec_value (spec, key, found)
7888 Lisp_Object spec, key;
7889 int *found;
7890{
7891 Lisp_Object tail;
7892
7893 xassert (valid_image_p (spec));
7894
7895 for (tail = XCDR (spec);
7896 CONSP (tail) && CONSP (XCDR (tail));
7897 tail = XCDR (XCDR (tail)))
7898 {
7899 if (EQ (XCAR (tail), key))
7900 {
7901 if (found)
7902 *found = 1;
7903 return XCAR (XCDR (tail));
7904 }
7905 }
7906
7907 if (found)
7908 *found = 0;
7909 return Qnil;
7910}
7911
7912
7913
7914\f
7915/***********************************************************************
7916 Image type independent image structures
7917 ***********************************************************************/
7918
7919static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7920static void free_image P_ ((struct frame *f, struct image *img));
7921
7922
7923/* Allocate and return a new image structure for image specification
7924 SPEC. SPEC has a hash value of HASH. */
7925
7926static struct image *
7927make_image (spec, hash)
7928 Lisp_Object spec;
7929 unsigned hash;
7930{
7931 struct image *img = (struct image *) xmalloc (sizeof *img);
7932
7933 xassert (valid_image_p (spec));
7934 bzero (img, sizeof *img);
7935 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7936 xassert (img->type != NULL);
7937 img->spec = spec;
7938 img->data.lisp_val = Qnil;
7939 img->ascent = DEFAULT_IMAGE_ASCENT;
7940 img->hash = hash;
7941 return img;
7942}
7943
7944
7945/* Free image IMG which was used on frame F, including its resources. */
7946
7947static void
7948free_image (f, img)
7949 struct frame *f;
7950 struct image *img;
7951{
7952 if (img)
7953 {
7954 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7955
7956 /* Remove IMG from the hash table of its cache. */
7957 if (img->prev)
7958 img->prev->next = img->next;
7959 else
7960 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7961
7962 if (img->next)
7963 img->next->prev = img->prev;
7964
7965 c->images[img->id] = NULL;
7966
7967 /* Free resources, then free IMG. */
7968 img->type->free (f, img);
7969 xfree (img);
7970 }
7971}
7972
7973
7974/* Prepare image IMG for display on frame F. Must be called before
7975 drawing an image. */
7976
7977void
7978prepare_image_for_display (f, img)
7979 struct frame *f;
7980 struct image *img;
7981{
7982 EMACS_TIME t;
7983
7984 /* We're about to display IMG, so set its timestamp to `now'. */
7985 EMACS_GET_TIME (t);
7986 img->timestamp = EMACS_SECS (t);
7987
7988 /* If IMG doesn't have a pixmap yet, load it now, using the image
7989 type dependent loader function. */
7990 if (img->pixmap == 0 && !img->load_failed_p)
7991 img->load_failed_p = img->type->load (f, img) == 0;
7992}
7993
7994
dfff8a69
JR
7995/* Value is the number of pixels for the ascent of image IMG when
7996 drawn in face FACE. */
7997
7998int
7999image_ascent (img, face)
8000 struct image *img;
8001 struct face *face;
8002{
8003 int height = img->height + img->margin;
8004 int ascent;
8005
8006 if (img->ascent == CENTERED_IMAGE_ASCENT)
8007 {
8008 if (face->font)
8009 ascent = height / 2 - (FONT_DESCENT(face->font)
8010 - FONT_BASE(face->font)) / 2;
8011 else
8012 ascent = height / 2;
8013 }
8014 else
8015 ascent = height * img->ascent / 100.0;
8016
8017 return ascent;
8018}
8019
8020
6fc2811b
JR
8021\f
8022/***********************************************************************
8023 Helper functions for X image types
8024 ***********************************************************************/
8025
8026static void x_clear_image P_ ((struct frame *f, struct image *img));
8027static unsigned long x_alloc_image_color P_ ((struct frame *f,
8028 struct image *img,
8029 Lisp_Object color_name,
8030 unsigned long dflt));
8031
8032/* Free X resources of image IMG which is used on frame F. */
8033
8034static void
8035x_clear_image (f, img)
8036 struct frame *f;
8037 struct image *img;
8038{
767b1ff0 8039#if 0 /* TODO: W32 image support */
6fc2811b
JR
8040
8041 if (img->pixmap)
8042 {
8043 BLOCK_INPUT;
8044 XFreePixmap (NULL, img->pixmap);
8045 img->pixmap = 0;
8046 UNBLOCK_INPUT;
8047 }
8048
8049 if (img->ncolors)
8050 {
8051 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8052
8053 /* If display has an immutable color map, freeing colors is not
8054 necessary and some servers don't allow it. So don't do it. */
8055 if (class != StaticColor
8056 && class != StaticGray
8057 && class != TrueColor)
8058 {
8059 Colormap cmap;
8060 BLOCK_INPUT;
8061 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8062 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8063 img->ncolors, 0);
8064 UNBLOCK_INPUT;
8065 }
8066
8067 xfree (img->colors);
8068 img->colors = NULL;
8069 img->ncolors = 0;
8070 }
8071#endif
8072}
8073
8074
8075/* Allocate color COLOR_NAME for image IMG on frame F. If color
8076 cannot be allocated, use DFLT. Add a newly allocated color to
8077 IMG->colors, so that it can be freed again. Value is the pixel
8078 color. */
8079
8080static unsigned long
8081x_alloc_image_color (f, img, color_name, dflt)
8082 struct frame *f;
8083 struct image *img;
8084 Lisp_Object color_name;
8085 unsigned long dflt;
8086{
767b1ff0 8087#if 0 /* TODO: allocing colors. */
6fc2811b
JR
8088 XColor color;
8089 unsigned long result;
8090
8091 xassert (STRINGP (color_name));
8092
8093 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8094 {
8095 /* This isn't called frequently so we get away with simply
8096 reallocating the color vector to the needed size, here. */
8097 ++img->ncolors;
8098 img->colors =
8099 (unsigned long *) xrealloc (img->colors,
8100 img->ncolors * sizeof *img->colors);
8101 img->colors[img->ncolors - 1] = color.pixel;
8102 result = color.pixel;
8103 }
8104 else
8105 result = dflt;
8106 return result;
8107#endif
8108 return 0;
8109}
8110
8111
8112\f
8113/***********************************************************************
8114 Image Cache
8115 ***********************************************************************/
8116
8117static void cache_image P_ ((struct frame *f, struct image *img));
8118
8119
8120/* Return a new, initialized image cache that is allocated from the
8121 heap. Call free_image_cache to free an image cache. */
8122
8123struct image_cache *
8124make_image_cache ()
8125{
8126 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8127 int size;
8128
8129 bzero (c, sizeof *c);
8130 c->size = 50;
8131 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8132 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8133 c->buckets = (struct image **) xmalloc (size);
8134 bzero (c->buckets, size);
8135 return c;
8136}
8137
8138
8139/* Free image cache of frame F. Be aware that X frames share images
8140 caches. */
8141
8142void
8143free_image_cache (f)
8144 struct frame *f;
8145{
8146 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8147 if (c)
8148 {
8149 int i;
8150
8151 /* Cache should not be referenced by any frame when freed. */
8152 xassert (c->refcount == 0);
8153
8154 for (i = 0; i < c->used; ++i)
8155 free_image (f, c->images[i]);
8156 xfree (c->images);
8157 xfree (c);
8158 xfree (c->buckets);
8159 FRAME_X_IMAGE_CACHE (f) = NULL;
8160 }
8161}
8162
8163
8164/* Clear image cache of frame F. FORCE_P non-zero means free all
8165 images. FORCE_P zero means clear only images that haven't been
8166 displayed for some time. Should be called from time to time to
dfff8a69
JR
8167 reduce the number of loaded images. If image-eviction-seconds is
8168 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8169 at least that many seconds. */
8170
8171void
8172clear_image_cache (f, force_p)
8173 struct frame *f;
8174 int force_p;
8175{
8176 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8177
8178 if (c && INTEGERP (Vimage_cache_eviction_delay))
8179 {
8180 EMACS_TIME t;
8181 unsigned long old;
8182 int i, any_freed_p = 0;
8183
8184 EMACS_GET_TIME (t);
8185 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8186
8187 for (i = 0; i < c->used; ++i)
8188 {
8189 struct image *img = c->images[i];
8190 if (img != NULL
8191 && (force_p
8192 || (img->timestamp > old)))
8193 {
8194 free_image (f, img);
8195 any_freed_p = 1;
8196 }
8197 }
8198
8199 /* We may be clearing the image cache because, for example,
8200 Emacs was iconified for a longer period of time. In that
8201 case, current matrices may still contain references to
8202 images freed above. So, clear these matrices. */
8203 if (any_freed_p)
8204 {
8205 clear_current_matrices (f);
8206 ++windows_or_buffers_changed;
8207 }
8208 }
8209}
8210
8211
8212DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8213 0, 1, 0,
8214 "Clear the image cache of FRAME.\n\
8215FRAME nil or omitted means use the selected frame.\n\
8216FRAME t means clear the image caches of all frames.")
8217 (frame)
8218 Lisp_Object frame;
8219{
8220 if (EQ (frame, Qt))
8221 {
8222 Lisp_Object tail;
8223
8224 FOR_EACH_FRAME (tail, frame)
8225 if (FRAME_W32_P (XFRAME (frame)))
8226 clear_image_cache (XFRAME (frame), 1);
8227 }
8228 else
8229 clear_image_cache (check_x_frame (frame), 1);
8230
8231 return Qnil;
8232}
8233
8234
8235/* Return the id of image with Lisp specification SPEC on frame F.
8236 SPEC must be a valid Lisp image specification (see valid_image_p). */
8237
8238int
8239lookup_image (f, spec)
8240 struct frame *f;
8241 Lisp_Object spec;
8242{
8243 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8244 struct image *img;
8245 int i;
8246 unsigned hash;
8247 struct gcpro gcpro1;
8248 EMACS_TIME now;
8249
8250 /* F must be a window-system frame, and SPEC must be a valid image
8251 specification. */
8252 xassert (FRAME_WINDOW_P (f));
8253 xassert (valid_image_p (spec));
8254
8255 GCPRO1 (spec);
8256
8257 /* Look up SPEC in the hash table of the image cache. */
8258 hash = sxhash (spec, 0);
8259 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8260
8261 for (img = c->buckets[i]; img; img = img->next)
8262 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8263 break;
8264
8265 /* If not found, create a new image and cache it. */
8266 if (img == NULL)
8267 {
8268 img = make_image (spec, hash);
8269 cache_image (f, img);
8270 img->load_failed_p = img->type->load (f, img) == 0;
8271 xassert (!interrupt_input_blocked);
8272
8273 /* If we can't load the image, and we don't have a width and
8274 height, use some arbitrary width and height so that we can
8275 draw a rectangle for it. */
8276 if (img->load_failed_p)
8277 {
8278 Lisp_Object value;
8279
8280 value = image_spec_value (spec, QCwidth, NULL);
8281 img->width = (INTEGERP (value)
8282 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8283 value = image_spec_value (spec, QCheight, NULL);
8284 img->height = (INTEGERP (value)
8285 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8286 }
8287 else
8288 {
8289 /* Handle image type independent image attributes
8290 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
8291 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
8292 Lisp_Object file;
8293
8294 ascent = image_spec_value (spec, QCascent, NULL);
8295 if (INTEGERP (ascent))
8296 img->ascent = XFASTINT (ascent);
dfff8a69
JR
8297 else if (EQ (ascent, Qcenter))
8298 img->ascent = CENTERED_IMAGE_ASCENT;
8299
6fc2811b
JR
8300 margin = image_spec_value (spec, QCmargin, NULL);
8301 if (INTEGERP (margin) && XINT (margin) >= 0)
8302 img->margin = XFASTINT (margin);
8303
8304 relief = image_spec_value (spec, QCrelief, NULL);
8305 if (INTEGERP (relief))
8306 {
8307 img->relief = XINT (relief);
8308 img->margin += abs (img->relief);
8309 }
8310
8311 /* Should we apply a Laplace edge-detection algorithm? */
8312 algorithm = image_spec_value (spec, QCalgorithm, NULL);
8313 if (img->pixmap && EQ (algorithm, Qlaplace))
8314 x_laplace (f, img);
8315
8316 /* Should we built a mask heuristically? */
8317 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
8318 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
8319 x_build_heuristic_mask (f, img, heuristic_mask);
8320 }
8321 }
8322
8323 /* We're using IMG, so set its timestamp to `now'. */
8324 EMACS_GET_TIME (now);
8325 img->timestamp = EMACS_SECS (now);
8326
8327 UNGCPRO;
8328
8329 /* Value is the image id. */
8330 return img->id;
8331}
8332
8333
8334/* Cache image IMG in the image cache of frame F. */
8335
8336static void
8337cache_image (f, img)
8338 struct frame *f;
8339 struct image *img;
8340{
8341 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8342 int i;
8343
8344 /* Find a free slot in c->images. */
8345 for (i = 0; i < c->used; ++i)
8346 if (c->images[i] == NULL)
8347 break;
8348
8349 /* If no free slot found, maybe enlarge c->images. */
8350 if (i == c->used && c->used == c->size)
8351 {
8352 c->size *= 2;
8353 c->images = (struct image **) xrealloc (c->images,
8354 c->size * sizeof *c->images);
8355 }
8356
8357 /* Add IMG to c->images, and assign IMG an id. */
8358 c->images[i] = img;
8359 img->id = i;
8360 if (i == c->used)
8361 ++c->used;
8362
8363 /* Add IMG to the cache's hash table. */
8364 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8365 img->next = c->buckets[i];
8366 if (img->next)
8367 img->next->prev = img;
8368 img->prev = NULL;
8369 c->buckets[i] = img;
8370}
8371
8372
8373/* Call FN on every image in the image cache of frame F. Used to mark
8374 Lisp Objects in the image cache. */
8375
8376void
8377forall_images_in_image_cache (f, fn)
8378 struct frame *f;
8379 void (*fn) P_ ((struct image *img));
8380{
8381 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8382 {
8383 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8384 if (c)
8385 {
8386 int i;
8387 for (i = 0; i < c->used; ++i)
8388 if (c->images[i])
8389 fn (c->images[i]);
8390 }
8391 }
8392}
8393
8394
8395\f
8396/***********************************************************************
8397 W32 support code
8398 ***********************************************************************/
8399
767b1ff0 8400#if 0 /* TODO: W32 specific image code. */
6fc2811b
JR
8401
8402static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8403 XImage **, Pixmap *));
8404static void x_destroy_x_image P_ ((XImage *));
8405static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8406
8407
8408/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8409 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8410 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8411 via xmalloc. Print error messages via image_error if an error
8412 occurs. Value is non-zero if successful. */
8413
8414static int
8415x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8416 struct frame *f;
8417 int width, height, depth;
8418 XImage **ximg;
8419 Pixmap *pixmap;
8420{
767b1ff0 8421#if 0 /* TODO: Image support for W32 */
6fc2811b
JR
8422 Display *display = FRAME_W32_DISPLAY (f);
8423 Screen *screen = FRAME_X_SCREEN (f);
8424 Window window = FRAME_W32_WINDOW (f);
8425
8426 xassert (interrupt_input_blocked);
8427
8428 if (depth <= 0)
8429 depth = DefaultDepthOfScreen (screen);
8430 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8431 depth, ZPixmap, 0, NULL, width, height,
8432 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8433 if (*ximg == NULL)
8434 {
8435 image_error ("Unable to allocate X image", Qnil, Qnil);
8436 return 0;
8437 }
8438
8439 /* Allocate image raster. */
8440 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8441
8442 /* Allocate a pixmap of the same size. */
8443 *pixmap = XCreatePixmap (display, window, width, height, depth);
8444 if (*pixmap == 0)
8445 {
8446 x_destroy_x_image (*ximg);
8447 *ximg = NULL;
8448 image_error ("Unable to create X pixmap", Qnil, Qnil);
8449 return 0;
8450 }
8451#endif
8452 return 1;
8453}
8454
8455
8456/* Destroy XImage XIMG. Free XIMG->data. */
8457
8458static void
8459x_destroy_x_image (ximg)
8460 XImage *ximg;
8461{
8462 xassert (interrupt_input_blocked);
8463 if (ximg)
8464 {
8465 xfree (ximg->data);
8466 ximg->data = NULL;
8467 XDestroyImage (ximg);
8468 }
8469}
8470
8471
8472/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8473 are width and height of both the image and pixmap. */
8474
8475static void
8476x_put_x_image (f, ximg, pixmap, width, height)
8477 struct frame *f;
8478 XImage *ximg;
8479 Pixmap pixmap;
8480{
8481 GC gc;
8482
8483 xassert (interrupt_input_blocked);
8484 gc = XCreateGC (NULL, pixmap, 0, NULL);
8485 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8486 XFreeGC (NULL, gc);
8487}
8488
8489#endif
8490
8491\f
8492/***********************************************************************
8493 Searching files
8494 ***********************************************************************/
8495
8496static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8497
8498/* Find image file FILE. Look in data-directory, then
8499 x-bitmap-file-path. Value is the full name of the file found, or
8500 nil if not found. */
8501
8502static Lisp_Object
8503x_find_image_file (file)
8504 Lisp_Object file;
8505{
8506 Lisp_Object file_found, search_path;
8507 struct gcpro gcpro1, gcpro2;
8508 int fd;
8509
8510 file_found = Qnil;
8511 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8512 GCPRO2 (file_found, search_path);
8513
8514 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8515 fd = openp (search_path, file, "", &file_found, 0);
8516
939d6465 8517 if (fd == -1)
6fc2811b
JR
8518 file_found = Qnil;
8519 else
8520 close (fd);
8521
8522 UNGCPRO;
8523 return file_found;
8524}
8525
8526
8527\f
8528/***********************************************************************
8529 XBM images
8530 ***********************************************************************/
8531
8532static int xbm_load P_ ((struct frame *f, struct image *img));
8533static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8534 Lisp_Object file));
8535static int xbm_image_p P_ ((Lisp_Object object));
8536static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8537 unsigned char **));
8538
8539
8540/* Indices of image specification fields in xbm_format, below. */
8541
8542enum xbm_keyword_index
8543{
8544 XBM_TYPE,
8545 XBM_FILE,
8546 XBM_WIDTH,
8547 XBM_HEIGHT,
8548 XBM_DATA,
8549 XBM_FOREGROUND,
8550 XBM_BACKGROUND,
8551 XBM_ASCENT,
8552 XBM_MARGIN,
8553 XBM_RELIEF,
8554 XBM_ALGORITHM,
8555 XBM_HEURISTIC_MASK,
8556 XBM_LAST
8557};
8558
8559/* Vector of image_keyword structures describing the format
8560 of valid XBM image specifications. */
8561
8562static struct image_keyword xbm_format[XBM_LAST] =
8563{
8564 {":type", IMAGE_SYMBOL_VALUE, 1},
8565 {":file", IMAGE_STRING_VALUE, 0},
8566 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8567 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8568 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8569 {":foreground", IMAGE_STRING_VALUE, 0},
8570 {":background", IMAGE_STRING_VALUE, 0},
8571 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8572 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8573 {":relief", IMAGE_INTEGER_VALUE, 0},
8574 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8575 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8576};
8577
8578/* Structure describing the image type XBM. */
8579
8580static struct image_type xbm_type =
8581{
8582 &Qxbm,
8583 xbm_image_p,
8584 xbm_load,
8585 x_clear_image,
8586 NULL
8587};
8588
8589/* Tokens returned from xbm_scan. */
8590
8591enum xbm_token
8592{
8593 XBM_TK_IDENT = 256,
8594 XBM_TK_NUMBER
8595};
8596
8597
8598/* Return non-zero if OBJECT is a valid XBM-type image specification.
8599 A valid specification is a list starting with the symbol `image'
8600 The rest of the list is a property list which must contain an
8601 entry `:type xbm..
8602
8603 If the specification specifies a file to load, it must contain
8604 an entry `:file FILENAME' where FILENAME is a string.
8605
8606 If the specification is for a bitmap loaded from memory it must
8607 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8608 WIDTH and HEIGHT are integers > 0. DATA may be:
8609
8610 1. a string large enough to hold the bitmap data, i.e. it must
8611 have a size >= (WIDTH + 7) / 8 * HEIGHT
8612
8613 2. a bool-vector of size >= WIDTH * HEIGHT
8614
8615 3. a vector of strings or bool-vectors, one for each line of the
8616 bitmap.
8617
8618 Both the file and data forms may contain the additional entries
8619 `:background COLOR' and `:foreground COLOR'. If not present,
8620 foreground and background of the frame on which the image is
8621 displayed, is used. */
8622
8623static int
8624xbm_image_p (object)
8625 Lisp_Object object;
8626{
8627 struct image_keyword kw[XBM_LAST];
8628
8629 bcopy (xbm_format, kw, sizeof kw);
8630 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8631 return 0;
8632
8633 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8634
8635 if (kw[XBM_FILE].count)
8636 {
8637 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8638 return 0;
8639 }
8640 else
8641 {
8642 Lisp_Object data;
8643 int width, height;
8644
8645 /* Entries for `:width', `:height' and `:data' must be present. */
8646 if (!kw[XBM_WIDTH].count
8647 || !kw[XBM_HEIGHT].count
8648 || !kw[XBM_DATA].count)
8649 return 0;
8650
8651 data = kw[XBM_DATA].value;
8652 width = XFASTINT (kw[XBM_WIDTH].value);
8653 height = XFASTINT (kw[XBM_HEIGHT].value);
8654
8655 /* Check type of data, and width and height against contents of
8656 data. */
8657 if (VECTORP (data))
8658 {
8659 int i;
8660
8661 /* Number of elements of the vector must be >= height. */
8662 if (XVECTOR (data)->size < height)
8663 return 0;
8664
8665 /* Each string or bool-vector in data must be large enough
8666 for one line of the image. */
8667 for (i = 0; i < height; ++i)
8668 {
8669 Lisp_Object elt = XVECTOR (data)->contents[i];
8670
8671 if (STRINGP (elt))
8672 {
8673 if (XSTRING (elt)->size
8674 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8675 return 0;
8676 }
8677 else if (BOOL_VECTOR_P (elt))
8678 {
8679 if (XBOOL_VECTOR (elt)->size < width)
8680 return 0;
8681 }
8682 else
8683 return 0;
8684 }
8685 }
8686 else if (STRINGP (data))
8687 {
8688 if (XSTRING (data)->size
8689 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8690 return 0;
8691 }
8692 else if (BOOL_VECTOR_P (data))
8693 {
8694 if (XBOOL_VECTOR (data)->size < width * height)
8695 return 0;
8696 }
8697 else
8698 return 0;
8699 }
8700
8701 /* Baseline must be a value between 0 and 100 (a percentage). */
8702 if (kw[XBM_ASCENT].count
8703 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8704 return 0;
8705
8706 return 1;
8707}
8708
8709
8710/* Scan a bitmap file. FP is the stream to read from. Value is
8711 either an enumerator from enum xbm_token, or a character for a
8712 single-character token, or 0 at end of file. If scanning an
8713 identifier, store the lexeme of the identifier in SVAL. If
8714 scanning a number, store its value in *IVAL. */
8715
8716static int
8717xbm_scan (fp, sval, ival)
8718 FILE *fp;
8719 char *sval;
8720 int *ival;
8721{
8722 int c;
8723
8724 /* Skip white space. */
8725 while ((c = fgetc (fp)) != EOF && isspace (c))
8726 ;
8727
8728 if (c == EOF)
8729 c = 0;
8730 else if (isdigit (c))
8731 {
8732 int value = 0, digit;
8733
8734 if (c == '0')
8735 {
8736 c = fgetc (fp);
8737 if (c == 'x' || c == 'X')
8738 {
8739 while ((c = fgetc (fp)) != EOF)
8740 {
8741 if (isdigit (c))
8742 digit = c - '0';
8743 else if (c >= 'a' && c <= 'f')
8744 digit = c - 'a' + 10;
8745 else if (c >= 'A' && c <= 'F')
8746 digit = c - 'A' + 10;
8747 else
8748 break;
8749 value = 16 * value + digit;
8750 }
8751 }
8752 else if (isdigit (c))
8753 {
8754 value = c - '0';
8755 while ((c = fgetc (fp)) != EOF
8756 && isdigit (c))
8757 value = 8 * value + c - '0';
8758 }
8759 }
8760 else
8761 {
8762 value = c - '0';
8763 while ((c = fgetc (fp)) != EOF
8764 && isdigit (c))
8765 value = 10 * value + c - '0';
8766 }
8767
8768 if (c != EOF)
8769 ungetc (c, fp);
8770 *ival = value;
8771 c = XBM_TK_NUMBER;
8772 }
8773 else if (isalpha (c) || c == '_')
8774 {
8775 *sval++ = c;
8776 while ((c = fgetc (fp)) != EOF
8777 && (isalnum (c) || c == '_'))
8778 *sval++ = c;
8779 *sval = 0;
8780 if (c != EOF)
8781 ungetc (c, fp);
8782 c = XBM_TK_IDENT;
8783 }
8784
8785 return c;
8786}
8787
8788
8789/* Replacement for XReadBitmapFileData which isn't available under old
8790 X versions. FILE is the name of the bitmap file to read. Set
8791 *WIDTH and *HEIGHT to the width and height of the image. Return in
8792 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8793 successful. */
8794
8795static int
8796xbm_read_bitmap_file_data (file, width, height, data)
8797 char *file;
8798 int *width, *height;
8799 unsigned char **data;
8800{
8801 FILE *fp;
8802 char buffer[BUFSIZ];
8803 int padding_p = 0;
8804 int v10 = 0;
8805 int bytes_per_line, i, nbytes;
8806 unsigned char *p;
8807 int value;
8808 int LA1;
8809
8810#define match() \
8811 LA1 = xbm_scan (fp, buffer, &value)
8812
8813#define expect(TOKEN) \
8814 if (LA1 != (TOKEN)) \
8815 goto failure; \
8816 else \
8817 match ()
8818
8819#define expect_ident(IDENT) \
8820 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8821 match (); \
8822 else \
8823 goto failure
8824
8825 fp = fopen (file, "r");
8826 if (fp == NULL)
8827 return 0;
8828
8829 *width = *height = -1;
8830 *data = NULL;
8831 LA1 = xbm_scan (fp, buffer, &value);
8832
8833 /* Parse defines for width, height and hot-spots. */
8834 while (LA1 == '#')
8835 {
8836 match ();
8837 expect_ident ("define");
8838 expect (XBM_TK_IDENT);
8839
8840 if (LA1 == XBM_TK_NUMBER);
8841 {
8842 char *p = strrchr (buffer, '_');
8843 p = p ? p + 1 : buffer;
8844 if (strcmp (p, "width") == 0)
8845 *width = value;
8846 else if (strcmp (p, "height") == 0)
8847 *height = value;
8848 }
8849 expect (XBM_TK_NUMBER);
8850 }
8851
8852 if (*width < 0 || *height < 0)
8853 goto failure;
8854
8855 /* Parse bits. Must start with `static'. */
8856 expect_ident ("static");
8857 if (LA1 == XBM_TK_IDENT)
8858 {
8859 if (strcmp (buffer, "unsigned") == 0)
8860 {
8861 match ();
8862 expect_ident ("char");
8863 }
8864 else if (strcmp (buffer, "short") == 0)
8865 {
8866 match ();
8867 v10 = 1;
8868 if (*width % 16 && *width % 16 < 9)
8869 padding_p = 1;
8870 }
8871 else if (strcmp (buffer, "char") == 0)
8872 match ();
8873 else
8874 goto failure;
8875 }
8876 else
8877 goto failure;
8878
8879 expect (XBM_TK_IDENT);
8880 expect ('[');
8881 expect (']');
8882 expect ('=');
8883 expect ('{');
8884
8885 bytes_per_line = (*width + 7) / 8 + padding_p;
8886 nbytes = bytes_per_line * *height;
8887 p = *data = (char *) xmalloc (nbytes);
8888
8889 if (v10)
8890 {
8891
8892 for (i = 0; i < nbytes; i += 2)
8893 {
8894 int val = value;
8895 expect (XBM_TK_NUMBER);
8896
8897 *p++ = val;
8898 if (!padding_p || ((i + 2) % bytes_per_line))
8899 *p++ = value >> 8;
8900
8901 if (LA1 == ',' || LA1 == '}')
8902 match ();
8903 else
8904 goto failure;
8905 }
8906 }
8907 else
8908 {
8909 for (i = 0; i < nbytes; ++i)
8910 {
8911 int val = value;
8912 expect (XBM_TK_NUMBER);
8913
8914 *p++ = val;
8915
8916 if (LA1 == ',' || LA1 == '}')
8917 match ();
8918 else
8919 goto failure;
8920 }
8921 }
8922
8923 fclose (fp);
8924 return 1;
8925
8926 failure:
8927
8928 fclose (fp);
8929 if (*data)
8930 {
8931 xfree (*data);
8932 *data = NULL;
8933 }
8934 return 0;
8935
8936#undef match
8937#undef expect
8938#undef expect_ident
8939}
8940
8941
8942/* Load XBM image IMG which will be displayed on frame F from file
8943 SPECIFIED_FILE. Value is non-zero if successful. */
8944
8945static int
8946xbm_load_image_from_file (f, img, specified_file)
8947 struct frame *f;
8948 struct image *img;
8949 Lisp_Object specified_file;
8950{
8951 int rc;
8952 unsigned char *data;
8953 int success_p = 0;
8954 Lisp_Object file;
8955 struct gcpro gcpro1;
8956
8957 xassert (STRINGP (specified_file));
8958 file = Qnil;
8959 GCPRO1 (file);
8960
8961 file = x_find_image_file (specified_file);
8962 if (!STRINGP (file))
8963 {
8964 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8965 UNGCPRO;
8966 return 0;
8967 }
8968
8969 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
8970 &img->height, &data);
8971 if (rc)
8972 {
8973 int depth = one_w32_display_info.n_cbits;
8974 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8975 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8976 Lisp_Object value;
8977
8978 xassert (img->width > 0 && img->height > 0);
8979
8980 /* Get foreground and background colors, maybe allocate colors. */
8981 value = image_spec_value (img->spec, QCforeground, NULL);
8982 if (!NILP (value))
8983 foreground = x_alloc_image_color (f, img, value, foreground);
8984
8985 value = image_spec_value (img->spec, QCbackground, NULL);
8986 if (!NILP (value))
8987 background = x_alloc_image_color (f, img, value, background);
8988
767b1ff0 8989#if 0 /* TODO : Port image display to W32 */
6fc2811b
JR
8990 BLOCK_INPUT;
8991 img->pixmap
8992 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8993 FRAME_W32_WINDOW (f),
8994 data,
8995 img->width, img->height,
8996 foreground, background,
8997 depth);
8998 xfree (data);
8999
9000 if (img->pixmap == 0)
9001 {
9002 x_clear_image (f, img);
9003 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
9004 }
9005 else
9006 success_p = 1;
9007
9008 UNBLOCK_INPUT;
9009#endif
9010 }
9011 else
9012 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9013
9014 UNGCPRO;
9015 return success_p;
9016}
9017
9018
9019/* Fill image IMG which is used on frame F with pixmap data. Value is
9020 non-zero if successful. */
9021
9022static int
9023xbm_load (f, img)
9024 struct frame *f;
9025 struct image *img;
9026{
9027 int success_p = 0;
9028 Lisp_Object file_name;
9029
9030 xassert (xbm_image_p (img->spec));
9031
9032 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9033 file_name = image_spec_value (img->spec, QCfile, NULL);
9034 if (STRINGP (file_name))
9035 success_p = xbm_load_image_from_file (f, img, file_name);
9036 else
9037 {
9038 struct image_keyword fmt[XBM_LAST];
9039 Lisp_Object data;
9040 int depth;
9041 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9042 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9043 char *bits;
9044 int parsed_p;
9045
9046 /* Parse the list specification. */
9047 bcopy (xbm_format, fmt, sizeof fmt);
9048 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9049 xassert (parsed_p);
9050
9051 /* Get specified width, and height. */
9052 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9053 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9054 xassert (img->width > 0 && img->height > 0);
9055
9056 BLOCK_INPUT;
9057
9058 if (fmt[XBM_ASCENT].count)
9059 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
9060
9061 /* Get foreground and background colors, maybe allocate colors. */
9062 if (fmt[XBM_FOREGROUND].count)
9063 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9064 foreground);
9065 if (fmt[XBM_BACKGROUND].count)
9066 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9067 background);
9068
9069 /* Set bits to the bitmap image data. */
9070 data = fmt[XBM_DATA].value;
9071 if (VECTORP (data))
9072 {
9073 int i;
9074 char *p;
9075 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
9076
9077 p = bits = (char *) alloca (nbytes * img->height);
9078 for (i = 0; i < img->height; ++i, p += nbytes)
9079 {
9080 Lisp_Object line = XVECTOR (data)->contents[i];
9081 if (STRINGP (line))
9082 bcopy (XSTRING (line)->data, p, nbytes);
9083 else
9084 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9085 }
9086 }
9087 else if (STRINGP (data))
9088 bits = XSTRING (data)->data;
9089 else
9090 bits = XBOOL_VECTOR (data)->data;
9091
767b1ff0 9092#if 0 /* TODO : W32 XPM code */
6fc2811b
JR
9093 /* Create the pixmap. */
9094 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
9095 img->pixmap
9096 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9097 FRAME_W32_WINDOW (f),
9098 bits,
9099 img->width, img->height,
9100 foreground, background,
9101 depth);
767b1ff0 9102#endif /* TODO */
6fc2811b
JR
9103
9104 if (img->pixmap)
9105 success_p = 1;
9106 else
9107 {
9108 image_error ("Unable to create pixmap for XBM image `%s'",
9109 img->spec, Qnil);
9110 x_clear_image (f, img);
9111 }
9112
9113 UNBLOCK_INPUT;
9114 }
9115
9116 return success_p;
9117}
9118
9119
9120\f
9121/***********************************************************************
9122 XPM images
9123 ***********************************************************************/
9124
9125#if HAVE_XPM
9126
9127static int xpm_image_p P_ ((Lisp_Object object));
9128static int xpm_load P_ ((struct frame *f, struct image *img));
9129static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9130
9131#include "X11/xpm.h"
9132
9133/* The symbol `xpm' identifying XPM-format images. */
9134
9135Lisp_Object Qxpm;
9136
9137/* Indices of image specification fields in xpm_format, below. */
9138
9139enum xpm_keyword_index
9140{
9141 XPM_TYPE,
9142 XPM_FILE,
9143 XPM_DATA,
9144 XPM_ASCENT,
9145 XPM_MARGIN,
9146 XPM_RELIEF,
9147 XPM_ALGORITHM,
9148 XPM_HEURISTIC_MASK,
9149 XPM_COLOR_SYMBOLS,
9150 XPM_LAST
9151};
9152
9153/* Vector of image_keyword structures describing the format
9154 of valid XPM image specifications. */
9155
9156static struct image_keyword xpm_format[XPM_LAST] =
9157{
9158 {":type", IMAGE_SYMBOL_VALUE, 1},
9159 {":file", IMAGE_STRING_VALUE, 0},
9160 {":data", IMAGE_STRING_VALUE, 0},
9161 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9162 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9163 {":relief", IMAGE_INTEGER_VALUE, 0},
9164 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9165 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9166 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9167};
9168
9169/* Structure describing the image type XBM. */
9170
9171static struct image_type xpm_type =
9172{
9173 &Qxpm,
9174 xpm_image_p,
9175 xpm_load,
9176 x_clear_image,
9177 NULL
9178};
9179
9180
9181/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9182 for XPM images. Such a list must consist of conses whose car and
9183 cdr are strings. */
9184
9185static int
9186xpm_valid_color_symbols_p (color_symbols)
9187 Lisp_Object color_symbols;
9188{
9189 while (CONSP (color_symbols))
9190 {
9191 Lisp_Object sym = XCAR (color_symbols);
9192 if (!CONSP (sym)
9193 || !STRINGP (XCAR (sym))
9194 || !STRINGP (XCDR (sym)))
9195 break;
9196 color_symbols = XCDR (color_symbols);
9197 }
9198
9199 return NILP (color_symbols);
9200}
9201
9202
9203/* Value is non-zero if OBJECT is a valid XPM image specification. */
9204
9205static int
9206xpm_image_p (object)
9207 Lisp_Object object;
9208{
9209 struct image_keyword fmt[XPM_LAST];
9210 bcopy (xpm_format, fmt, sizeof fmt);
9211 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9212 /* Either `:file' or `:data' must be present. */
9213 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9214 /* Either no `:color-symbols' or it's a list of conses
9215 whose car and cdr are strings. */
9216 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9217 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9218 && (fmt[XPM_ASCENT].count == 0
9219 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9220}
9221
9222
9223/* Load image IMG which will be displayed on frame F. Value is
9224 non-zero if successful. */
9225
9226static int
9227xpm_load (f, img)
9228 struct frame *f;
9229 struct image *img;
9230{
9231 int rc, i;
9232 XpmAttributes attrs;
9233 Lisp_Object specified_file, color_symbols;
9234
9235 /* Configure the XPM lib. Use the visual of frame F. Allocate
9236 close colors. Return colors allocated. */
9237 bzero (&attrs, sizeof attrs);
dfff8a69
JR
9238 attrs.visual = FRAME_X_VISUAL (f);
9239 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 9240 attrs.valuemask |= XpmVisual;
dfff8a69 9241 attrs.valuemask |= XpmColormap;
6fc2811b 9242 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 9243#ifdef XpmAllocCloseColors
6fc2811b
JR
9244 attrs.alloc_close_colors = 1;
9245 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
9246#else
9247 attrs.closeness = 600;
9248 attrs.valuemask |= XpmCloseness;
9249#endif
6fc2811b
JR
9250
9251 /* If image specification contains symbolic color definitions, add
9252 these to `attrs'. */
9253 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9254 if (CONSP (color_symbols))
9255 {
9256 Lisp_Object tail;
9257 XpmColorSymbol *xpm_syms;
9258 int i, size;
9259
9260 attrs.valuemask |= XpmColorSymbols;
9261
9262 /* Count number of symbols. */
9263 attrs.numsymbols = 0;
9264 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9265 ++attrs.numsymbols;
9266
9267 /* Allocate an XpmColorSymbol array. */
9268 size = attrs.numsymbols * sizeof *xpm_syms;
9269 xpm_syms = (XpmColorSymbol *) alloca (size);
9270 bzero (xpm_syms, size);
9271 attrs.colorsymbols = xpm_syms;
9272
9273 /* Fill the color symbol array. */
9274 for (tail = color_symbols, i = 0;
9275 CONSP (tail);
9276 ++i, tail = XCDR (tail))
9277 {
9278 Lisp_Object name = XCAR (XCAR (tail));
9279 Lisp_Object color = XCDR (XCAR (tail));
9280 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9281 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9282 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9283 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9284 }
9285 }
9286
9287 /* Create a pixmap for the image, either from a file, or from a
9288 string buffer containing data in the same format as an XPM file. */
9289 BLOCK_INPUT;
9290 specified_file = image_spec_value (img->spec, QCfile, NULL);
9291 if (STRINGP (specified_file))
9292 {
9293 Lisp_Object file = x_find_image_file (specified_file);
9294 if (!STRINGP (file))
9295 {
9296 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9297 UNBLOCK_INPUT;
9298 return 0;
9299 }
9300
9301 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9302 XSTRING (file)->data, &img->pixmap, &img->mask,
9303 &attrs);
9304 }
9305 else
9306 {
9307 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9308 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9309 XSTRING (buffer)->data,
9310 &img->pixmap, &img->mask,
9311 &attrs);
9312 }
9313 UNBLOCK_INPUT;
9314
9315 if (rc == XpmSuccess)
9316 {
9317 /* Remember allocated colors. */
9318 img->ncolors = attrs.nalloc_pixels;
9319 img->colors = (unsigned long *) xmalloc (img->ncolors
9320 * sizeof *img->colors);
9321 for (i = 0; i < attrs.nalloc_pixels; ++i)
9322 img->colors[i] = attrs.alloc_pixels[i];
9323
9324 img->width = attrs.width;
9325 img->height = attrs.height;
9326 xassert (img->width > 0 && img->height > 0);
9327
9328 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9329 BLOCK_INPUT;
9330 XpmFreeAttributes (&attrs);
9331 UNBLOCK_INPUT;
9332 }
9333 else
9334 {
9335 switch (rc)
9336 {
9337 case XpmOpenFailed:
9338 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9339 break;
9340
9341 case XpmFileInvalid:
9342 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9343 break;
9344
9345 case XpmNoMemory:
9346 image_error ("Out of memory (%s)", img->spec, Qnil);
9347 break;
9348
9349 case XpmColorFailed:
9350 image_error ("Color allocation error (%s)", img->spec, Qnil);
9351 break;
9352
9353 default:
9354 image_error ("Unknown error (%s)", img->spec, Qnil);
9355 break;
9356 }
9357 }
9358
9359 return rc == XpmSuccess;
9360}
9361
9362#endif /* HAVE_XPM != 0 */
9363
9364\f
767b1ff0 9365#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
9366/***********************************************************************
9367 Color table
9368 ***********************************************************************/
9369
9370/* An entry in the color table mapping an RGB color to a pixel color. */
9371
9372struct ct_color
9373{
9374 int r, g, b;
9375 unsigned long pixel;
9376
9377 /* Next in color table collision list. */
9378 struct ct_color *next;
9379};
9380
9381/* The bucket vector size to use. Must be prime. */
9382
9383#define CT_SIZE 101
9384
9385/* Value is a hash of the RGB color given by R, G, and B. */
9386
9387#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9388
9389/* The color hash table. */
9390
9391struct ct_color **ct_table;
9392
9393/* Number of entries in the color table. */
9394
9395int ct_colors_allocated;
9396
9397/* Function prototypes. */
9398
9399static void init_color_table P_ ((void));
9400static void free_color_table P_ ((void));
9401static unsigned long *colors_in_color_table P_ ((int *n));
9402static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9403static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9404
9405
9406/* Initialize the color table. */
9407
9408static void
9409init_color_table ()
9410{
9411 int size = CT_SIZE * sizeof (*ct_table);
9412 ct_table = (struct ct_color **) xmalloc (size);
9413 bzero (ct_table, size);
9414 ct_colors_allocated = 0;
9415}
9416
9417
9418/* Free memory associated with the color table. */
9419
9420static void
9421free_color_table ()
9422{
9423 int i;
9424 struct ct_color *p, *next;
9425
9426 for (i = 0; i < CT_SIZE; ++i)
9427 for (p = ct_table[i]; p; p = next)
9428 {
9429 next = p->next;
9430 xfree (p);
9431 }
9432
9433 xfree (ct_table);
9434 ct_table = NULL;
9435}
9436
9437
9438/* Value is a pixel color for RGB color R, G, B on frame F. If an
9439 entry for that color already is in the color table, return the
9440 pixel color of that entry. Otherwise, allocate a new color for R,
9441 G, B, and make an entry in the color table. */
9442
9443static unsigned long
9444lookup_rgb_color (f, r, g, b)
9445 struct frame *f;
9446 int r, g, b;
9447{
9448 unsigned hash = CT_HASH_RGB (r, g, b);
9449 int i = hash % CT_SIZE;
9450 struct ct_color *p;
9451
9452 for (p = ct_table[i]; p; p = p->next)
9453 if (p->r == r && p->g == g && p->b == b)
9454 break;
9455
9456 if (p == NULL)
9457 {
9458 COLORREF color;
9459 Colormap cmap;
9460 int rc;
9461
9462 color = PALETTERGB (r, g, b);
9463
9464 ++ct_colors_allocated;
9465
9466 p = (struct ct_color *) xmalloc (sizeof *p);
9467 p->r = r;
9468 p->g = g;
9469 p->b = b;
9470 p->pixel = color;
9471 p->next = ct_table[i];
9472 ct_table[i] = p;
9473 }
9474
9475 return p->pixel;
9476}
9477
9478
9479/* Look up pixel color PIXEL which is used on frame F in the color
9480 table. If not already present, allocate it. Value is PIXEL. */
9481
9482static unsigned long
9483lookup_pixel_color (f, pixel)
9484 struct frame *f;
9485 unsigned long pixel;
9486{
9487 int i = pixel % CT_SIZE;
9488 struct ct_color *p;
9489
9490 for (p = ct_table[i]; p; p = p->next)
9491 if (p->pixel == pixel)
9492 break;
9493
9494 if (p == NULL)
9495 {
9496 XColor color;
9497 Colormap cmap;
9498 int rc;
9499
9500 BLOCK_INPUT;
9501
9502 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9503 color.pixel = pixel;
9504 XQueryColor (NULL, cmap, &color);
9505 rc = x_alloc_nearest_color (f, cmap, &color);
9506 UNBLOCK_INPUT;
9507
9508 if (rc)
9509 {
9510 ++ct_colors_allocated;
9511
9512 p = (struct ct_color *) xmalloc (sizeof *p);
9513 p->r = color.red;
9514 p->g = color.green;
9515 p->b = color.blue;
9516 p->pixel = pixel;
9517 p->next = ct_table[i];
9518 ct_table[i] = p;
9519 }
9520 else
9521 return FRAME_FOREGROUND_PIXEL (f);
9522 }
9523 return p->pixel;
9524}
9525
9526
9527/* Value is a vector of all pixel colors contained in the color table,
9528 allocated via xmalloc. Set *N to the number of colors. */
9529
9530static unsigned long *
9531colors_in_color_table (n)
9532 int *n;
9533{
9534 int i, j;
9535 struct ct_color *p;
9536 unsigned long *colors;
9537
9538 if (ct_colors_allocated == 0)
9539 {
9540 *n = 0;
9541 colors = NULL;
9542 }
9543 else
9544 {
9545 colors = (unsigned long *) xmalloc (ct_colors_allocated
9546 * sizeof *colors);
9547 *n = ct_colors_allocated;
9548
9549 for (i = j = 0; i < CT_SIZE; ++i)
9550 for (p = ct_table[i]; p; p = p->next)
9551 colors[j++] = p->pixel;
9552 }
9553
9554 return colors;
9555}
9556
767b1ff0 9557#endif /* TODO */
6fc2811b
JR
9558
9559\f
9560/***********************************************************************
9561 Algorithms
9562 ***********************************************************************/
9563
767b1ff0 9564#if 0 /* TODO : W32 versions of low level algorithms */
6fc2811b
JR
9565static void x_laplace_write_row P_ ((struct frame *, long *,
9566 int, XImage *, int));
9567static void x_laplace_read_row P_ ((struct frame *, Colormap,
9568 XColor *, int, XImage *, int));
9569
9570
9571/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9572 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9573 the width of one row in the image. */
9574
9575static void
9576x_laplace_read_row (f, cmap, colors, width, ximg, y)
9577 struct frame *f;
9578 Colormap cmap;
9579 XColor *colors;
9580 int width;
9581 XImage *ximg;
9582 int y;
9583{
9584 int x;
9585
9586 for (x = 0; x < width; ++x)
9587 colors[x].pixel = XGetPixel (ximg, x, y);
9588
9589 XQueryColors (NULL, cmap, colors, width);
9590}
9591
9592
9593/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9594 containing the pixel colors to write. F is the frame we are
9595 working on. */
9596
9597static void
9598x_laplace_write_row (f, pixels, width, ximg, y)
9599 struct frame *f;
9600 long *pixels;
9601 int width;
9602 XImage *ximg;
9603 int y;
9604{
9605 int x;
9606
9607 for (x = 0; x < width; ++x)
9608 XPutPixel (ximg, x, y, pixels[x]);
9609}
9610#endif
9611
9612/* Transform image IMG which is used on frame F with a Laplace
9613 edge-detection algorithm. The result is an image that can be used
9614 to draw disabled buttons, for example. */
9615
9616static void
9617x_laplace (f, img)
9618 struct frame *f;
9619 struct image *img;
9620{
767b1ff0 9621#if 0 /* TODO : W32 version */
6fc2811b
JR
9622 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9623 XImage *ximg, *oimg;
9624 XColor *in[3];
9625 long *out;
9626 Pixmap pixmap;
9627 int x, y, i;
9628 long pixel;
9629 int in_y, out_y, rc;
9630 int mv2 = 45000;
9631
9632 BLOCK_INPUT;
9633
9634 /* Get the X image IMG->pixmap. */
9635 ximg = XGetImage (NULL, img->pixmap,
9636 0, 0, img->width, img->height, ~0, ZPixmap);
9637
9638 /* Allocate 3 input rows, and one output row of colors. */
9639 for (i = 0; i < 3; ++i)
9640 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9641 out = (long *) alloca (img->width * sizeof (long));
9642
9643 /* Create an X image for output. */
9644 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9645 &oimg, &pixmap);
9646
9647 /* Fill first two rows. */
9648 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9649 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9650 in_y = 2;
9651
9652 /* Write first row, all zeros. */
9653 init_color_table ();
9654 pixel = lookup_rgb_color (f, 0, 0, 0);
9655 for (x = 0; x < img->width; ++x)
9656 out[x] = pixel;
9657 x_laplace_write_row (f, out, img->width, oimg, 0);
9658 out_y = 1;
9659
9660 for (y = 2; y < img->height; ++y)
9661 {
9662 int rowa = y % 3;
9663 int rowb = (y + 2) % 3;
9664
9665 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9666
9667 for (x = 0; x < img->width - 2; ++x)
9668 {
9669 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9670 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9671 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9672
9673 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9674 b & 0xffff);
9675 }
9676
9677 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9678 }
9679
9680 /* Write last line, all zeros. */
9681 for (x = 0; x < img->width; ++x)
9682 out[x] = pixel;
9683 x_laplace_write_row (f, out, img->width, oimg, out_y);
9684
9685 /* Free the input image, and free resources of IMG. */
9686 XDestroyImage (ximg);
9687 x_clear_image (f, img);
9688
9689 /* Put the output image into pixmap, and destroy it. */
9690 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9691 x_destroy_x_image (oimg);
9692
9693 /* Remember new pixmap and colors in IMG. */
9694 img->pixmap = pixmap;
9695 img->colors = colors_in_color_table (&img->ncolors);
9696 free_color_table ();
9697
9698 UNBLOCK_INPUT;
767b1ff0 9699#endif /* TODO */
6fc2811b
JR
9700}
9701
9702
9703/* Build a mask for image IMG which is used on frame F. FILE is the
9704 name of an image file, for error messages. HOW determines how to
9705 determine the background color of IMG. If it is a list '(R G B)',
9706 with R, G, and B being integers >= 0, take that as the color of the
9707 background. Otherwise, determine the background color of IMG
9708 heuristically. Value is non-zero if successful. */
9709
9710static int
9711x_build_heuristic_mask (f, img, how)
9712 struct frame *f;
9713 struct image *img;
9714 Lisp_Object how;
9715{
767b1ff0 9716#if 0 /* TODO : W32 version */
6fc2811b
JR
9717 Display *dpy = FRAME_W32_DISPLAY (f);
9718 XImage *ximg, *mask_img;
9719 int x, y, rc, look_at_corners_p;
9720 unsigned long bg;
9721
9722 BLOCK_INPUT;
9723
9724 /* Create an image and pixmap serving as mask. */
9725 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9726 &mask_img, &img->mask);
9727 if (!rc)
9728 {
9729 UNBLOCK_INPUT;
9730 return 0;
9731 }
9732
9733 /* Get the X image of IMG->pixmap. */
9734 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9735 ~0, ZPixmap);
9736
9737 /* Determine the background color of ximg. If HOW is `(R G B)'
9738 take that as color. Otherwise, try to determine the color
9739 heuristically. */
9740 look_at_corners_p = 1;
9741
9742 if (CONSP (how))
9743 {
9744 int rgb[3], i = 0;
9745
9746 while (i < 3
9747 && CONSP (how)
9748 && NATNUMP (XCAR (how)))
9749 {
9750 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9751 how = XCDR (how);
9752 }
9753
9754 if (i == 3 && NILP (how))
9755 {
9756 char color_name[30];
9757 XColor exact, color;
9758 Colormap cmap;
9759
9760 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9761
9762 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9763 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9764 {
9765 bg = color.pixel;
9766 look_at_corners_p = 0;
9767 }
9768 }
9769 }
9770
9771 if (look_at_corners_p)
9772 {
9773 unsigned long corners[4];
9774 int i, best_count;
9775
9776 /* Get the colors at the corners of ximg. */
9777 corners[0] = XGetPixel (ximg, 0, 0);
9778 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9779 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9780 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9781
9782 /* Choose the most frequently found color as background. */
9783 for (i = best_count = 0; i < 4; ++i)
9784 {
9785 int j, n;
9786
9787 for (j = n = 0; j < 4; ++j)
9788 if (corners[i] == corners[j])
9789 ++n;
9790
9791 if (n > best_count)
9792 bg = corners[i], best_count = n;
9793 }
9794 }
9795
9796 /* Set all bits in mask_img to 1 whose color in ximg is different
9797 from the background color bg. */
9798 for (y = 0; y < img->height; ++y)
9799 for (x = 0; x < img->width; ++x)
9800 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9801
9802 /* Put mask_img into img->mask. */
9803 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9804 x_destroy_x_image (mask_img);
9805 XDestroyImage (ximg);
9806
9807 UNBLOCK_INPUT;
767b1ff0 9808#endif /* TODO */
6fc2811b
JR
9809
9810 return 1;
9811}
9812
9813
9814\f
9815/***********************************************************************
9816 PBM (mono, gray, color)
9817 ***********************************************************************/
9818#ifdef HAVE_PBM
9819
9820static int pbm_image_p P_ ((Lisp_Object object));
9821static int pbm_load P_ ((struct frame *f, struct image *img));
9822static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9823
9824/* The symbol `pbm' identifying images of this type. */
9825
9826Lisp_Object Qpbm;
9827
9828/* Indices of image specification fields in gs_format, below. */
9829
9830enum pbm_keyword_index
9831{
9832 PBM_TYPE,
9833 PBM_FILE,
9834 PBM_DATA,
9835 PBM_ASCENT,
9836 PBM_MARGIN,
9837 PBM_RELIEF,
9838 PBM_ALGORITHM,
9839 PBM_HEURISTIC_MASK,
9840 PBM_LAST
9841};
9842
9843/* Vector of image_keyword structures describing the format
9844 of valid user-defined image specifications. */
9845
9846static struct image_keyword pbm_format[PBM_LAST] =
9847{
9848 {":type", IMAGE_SYMBOL_VALUE, 1},
9849 {":file", IMAGE_STRING_VALUE, 0},
9850 {":data", IMAGE_STRING_VALUE, 0},
9851 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9852 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9853 {":relief", IMAGE_INTEGER_VALUE, 0},
9854 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9855 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9856};
9857
9858/* Structure describing the image type `pbm'. */
9859
9860static struct image_type pbm_type =
9861{
9862 &Qpbm,
9863 pbm_image_p,
9864 pbm_load,
9865 x_clear_image,
9866 NULL
9867};
9868
9869
9870/* Return non-zero if OBJECT is a valid PBM image specification. */
9871
9872static int
9873pbm_image_p (object)
9874 Lisp_Object object;
9875{
9876 struct image_keyword fmt[PBM_LAST];
9877
9878 bcopy (pbm_format, fmt, sizeof fmt);
9879
9880 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9881 || (fmt[PBM_ASCENT].count
9882 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9883 return 0;
9884
9885 /* Must specify either :data or :file. */
9886 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9887}
9888
9889
9890/* Scan a decimal number from *S and return it. Advance *S while
9891 reading the number. END is the end of the string. Value is -1 at
9892 end of input. */
9893
9894static int
9895pbm_scan_number (s, end)
9896 unsigned char **s, *end;
9897{
9898 int c, val = -1;
9899
9900 while (*s < end)
9901 {
9902 /* Skip white-space. */
9903 while (*s < end && (c = *(*s)++, isspace (c)))
9904 ;
9905
9906 if (c == '#')
9907 {
9908 /* Skip comment to end of line. */
9909 while (*s < end && (c = *(*s)++, c != '\n'))
9910 ;
9911 }
9912 else if (isdigit (c))
9913 {
9914 /* Read decimal number. */
9915 val = c - '0';
9916 while (*s < end && (c = *(*s)++, isdigit (c)))
9917 val = 10 * val + c - '0';
9918 break;
9919 }
9920 else
9921 break;
9922 }
9923
9924 return val;
9925}
9926
9927
9928/* Read FILE into memory. Value is a pointer to a buffer allocated
9929 with xmalloc holding FILE's contents. Value is null if an error
9930 occured. *SIZE is set to the size of the file. */
9931
9932static char *
9933pbm_read_file (file, size)
9934 Lisp_Object file;
9935 int *size;
9936{
9937 FILE *fp = NULL;
9938 char *buf = NULL;
9939 struct stat st;
9940
9941 if (stat (XSTRING (file)->data, &st) == 0
9942 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
9943 && (buf = (char *) xmalloc (st.st_size),
9944 fread (buf, 1, st.st_size, fp) == st.st_size))
9945 {
9946 *size = st.st_size;
9947 fclose (fp);
9948 }
9949 else
9950 {
9951 if (fp)
9952 fclose (fp);
9953 if (buf)
9954 {
9955 xfree (buf);
9956 buf = NULL;
9957 }
9958 }
9959
9960 return buf;
9961}
9962
9963
9964/* Load PBM image IMG for use on frame F. */
9965
9966static int
9967pbm_load (f, img)
9968 struct frame *f;
9969 struct image *img;
9970{
9971 int raw_p, x, y;
9972 int width, height, max_color_idx = 0;
9973 XImage *ximg;
9974 Lisp_Object file, specified_file;
9975 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
9976 struct gcpro gcpro1;
9977 unsigned char *contents = NULL;
9978 unsigned char *end, *p;
9979 int size;
9980
9981 specified_file = image_spec_value (img->spec, QCfile, NULL);
9982 file = Qnil;
9983 GCPRO1 (file);
9984
9985 if (STRINGP (specified_file))
9986 {
9987 file = x_find_image_file (specified_file);
9988 if (!STRINGP (file))
9989 {
9990 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9991 UNGCPRO;
9992 return 0;
9993 }
9994
9995 contents = pbm_read_file (file, &size);
9996 if (contents == NULL)
9997 {
9998 image_error ("Error reading `%s'", file, Qnil);
9999 UNGCPRO;
10000 return 0;
10001 }
10002
10003 p = contents;
10004 end = contents + size;
10005 }
10006 else
10007 {
10008 Lisp_Object data;
10009 data = image_spec_value (img->spec, QCdata, NULL);
10010 p = XSTRING (data)->data;
10011 end = p + STRING_BYTES (XSTRING (data));
10012 }
10013
10014 /* Check magic number. */
10015 if (end - p < 2 || *p++ != 'P')
10016 {
10017 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10018 error:
10019 xfree (contents);
10020 UNGCPRO;
10021 return 0;
10022 }
10023
6fc2811b
JR
10024 switch (*p++)
10025 {
10026 case '1':
10027 raw_p = 0, type = PBM_MONO;
10028 break;
10029
10030 case '2':
10031 raw_p = 0, type = PBM_GRAY;
10032 break;
10033
10034 case '3':
10035 raw_p = 0, type = PBM_COLOR;
10036 break;
10037
10038 case '4':
10039 raw_p = 1, type = PBM_MONO;
10040 break;
10041
10042 case '5':
10043 raw_p = 1, type = PBM_GRAY;
10044 break;
10045
10046 case '6':
10047 raw_p = 1, type = PBM_COLOR;
10048 break;
10049
10050 default:
10051 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10052 goto error;
10053 }
10054
10055 /* Read width, height, maximum color-component. Characters
10056 starting with `#' up to the end of a line are ignored. */
10057 width = pbm_scan_number (&p, end);
10058 height = pbm_scan_number (&p, end);
10059
10060 if (type != PBM_MONO)
10061 {
10062 max_color_idx = pbm_scan_number (&p, end);
10063 if (raw_p && max_color_idx > 255)
10064 max_color_idx = 255;
10065 }
10066
10067 if (width < 0
10068 || height < 0
10069 || (type != PBM_MONO && max_color_idx < 0))
10070 goto error;
10071
10072 BLOCK_INPUT;
10073 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10074 &ximg, &img->pixmap))
10075 {
10076 UNBLOCK_INPUT;
10077 goto error;
10078 }
10079
10080 /* Initialize the color hash table. */
10081 init_color_table ();
10082
10083 if (type == PBM_MONO)
10084 {
10085 int c = 0, g;
10086
10087 for (y = 0; y < height; ++y)
10088 for (x = 0; x < width; ++x)
10089 {
10090 if (raw_p)
10091 {
10092 if ((x & 7) == 0)
10093 c = *p++;
10094 g = c & 0x80;
10095 c <<= 1;
10096 }
10097 else
10098 g = pbm_scan_number (&p, end);
10099
10100 XPutPixel (ximg, x, y, (g
10101 ? FRAME_FOREGROUND_PIXEL (f)
10102 : FRAME_BACKGROUND_PIXEL (f)));
10103 }
10104 }
10105 else
10106 {
10107 for (y = 0; y < height; ++y)
10108 for (x = 0; x < width; ++x)
10109 {
10110 int r, g, b;
10111
10112 if (type == PBM_GRAY)
10113 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10114 else if (raw_p)
10115 {
10116 r = *p++;
10117 g = *p++;
10118 b = *p++;
10119 }
10120 else
10121 {
10122 r = pbm_scan_number (&p, end);
10123 g = pbm_scan_number (&p, end);
10124 b = pbm_scan_number (&p, end);
10125 }
10126
10127 if (r < 0 || g < 0 || b < 0)
10128 {
dfff8a69 10129 xfree (ximg->data);
6fc2811b
JR
10130 ximg->data = NULL;
10131 XDestroyImage (ximg);
10132 UNBLOCK_INPUT;
10133 image_error ("Invalid pixel value in image `%s'",
10134 img->spec, Qnil);
10135 goto error;
10136 }
10137
10138 /* RGB values are now in the range 0..max_color_idx.
10139 Scale this to the range 0..0xffff supported by X. */
10140 r = (double) r * 65535 / max_color_idx;
10141 g = (double) g * 65535 / max_color_idx;
10142 b = (double) b * 65535 / max_color_idx;
10143 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10144 }
10145 }
10146
10147 /* Store in IMG->colors the colors allocated for the image, and
10148 free the color table. */
10149 img->colors = colors_in_color_table (&img->ncolors);
10150 free_color_table ();
10151
10152 /* Put the image into a pixmap. */
10153 x_put_x_image (f, ximg, img->pixmap, width, height);
10154 x_destroy_x_image (ximg);
10155 UNBLOCK_INPUT;
10156
10157 img->width = width;
10158 img->height = height;
10159
10160 UNGCPRO;
10161 xfree (contents);
10162 return 1;
10163}
10164#endif /* HAVE_PBM */
10165
10166\f
10167/***********************************************************************
10168 PNG
10169 ***********************************************************************/
10170
10171#if HAVE_PNG
10172
10173#include <png.h>
10174
10175/* Function prototypes. */
10176
10177static int png_image_p P_ ((Lisp_Object object));
10178static int png_load P_ ((struct frame *f, struct image *img));
10179
10180/* The symbol `png' identifying images of this type. */
10181
10182Lisp_Object Qpng;
10183
10184/* Indices of image specification fields in png_format, below. */
10185
10186enum png_keyword_index
10187{
10188 PNG_TYPE,
10189 PNG_DATA,
10190 PNG_FILE,
10191 PNG_ASCENT,
10192 PNG_MARGIN,
10193 PNG_RELIEF,
10194 PNG_ALGORITHM,
10195 PNG_HEURISTIC_MASK,
10196 PNG_LAST
10197};
10198
10199/* Vector of image_keyword structures describing the format
10200 of valid user-defined image specifications. */
10201
10202static struct image_keyword png_format[PNG_LAST] =
10203{
10204 {":type", IMAGE_SYMBOL_VALUE, 1},
10205 {":data", IMAGE_STRING_VALUE, 0},
10206 {":file", IMAGE_STRING_VALUE, 0},
10207 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10208 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10209 {":relief", IMAGE_INTEGER_VALUE, 0},
10210 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10211 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10212};
10213
10214/* Structure describing the image type `png'. */
10215
10216static struct image_type png_type =
10217{
10218 &Qpng,
10219 png_image_p,
10220 png_load,
10221 x_clear_image,
10222 NULL
10223};
10224
10225
10226/* Return non-zero if OBJECT is a valid PNG image specification. */
10227
10228static int
10229png_image_p (object)
10230 Lisp_Object object;
10231{
10232 struct image_keyword fmt[PNG_LAST];
10233 bcopy (png_format, fmt, sizeof fmt);
10234
10235 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
10236 || (fmt[PNG_ASCENT].count
10237 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
10238 return 0;
10239
10240 /* Must specify either the :data or :file keyword. */
10241 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
10242}
10243
10244
10245/* Error and warning handlers installed when the PNG library
10246 is initialized. */
10247
10248static void
10249my_png_error (png_ptr, msg)
10250 png_struct *png_ptr;
10251 char *msg;
10252{
10253 xassert (png_ptr != NULL);
10254 image_error ("PNG error: %s", build_string (msg), Qnil);
10255 longjmp (png_ptr->jmpbuf, 1);
10256}
10257
10258
10259static void
10260my_png_warning (png_ptr, msg)
10261 png_struct *png_ptr;
10262 char *msg;
10263{
10264 xassert (png_ptr != NULL);
10265 image_error ("PNG warning: %s", build_string (msg), Qnil);
10266}
10267
6fc2811b
JR
10268/* Memory source for PNG decoding. */
10269
10270struct png_memory_storage
10271{
10272 unsigned char *bytes; /* The data */
10273 size_t len; /* How big is it? */
10274 int index; /* Where are we? */
10275};
10276
10277
10278/* Function set as reader function when reading PNG image from memory.
10279 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10280 bytes from the input to DATA. */
10281
10282static void
10283png_read_from_memory (png_ptr, data, length)
10284 png_structp png_ptr;
10285 png_bytep data;
10286 png_size_t length;
10287{
10288 struct png_memory_storage *tbr
10289 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
10290
10291 if (length > tbr->len - tbr->index)
10292 png_error (png_ptr, "Read error");
10293
10294 bcopy (tbr->bytes + tbr->index, data, length);
10295 tbr->index = tbr->index + length;
10296}
10297
6fc2811b
JR
10298/* Load PNG image IMG for use on frame F. Value is non-zero if
10299 successful. */
10300
10301static int
10302png_load (f, img)
10303 struct frame *f;
10304 struct image *img;
10305{
10306 Lisp_Object file, specified_file;
10307 Lisp_Object specified_data;
10308 int x, y, i;
10309 XImage *ximg, *mask_img = NULL;
10310 struct gcpro gcpro1;
10311 png_struct *png_ptr = NULL;
10312 png_info *info_ptr = NULL, *end_info = NULL;
10313 FILE *fp = NULL;
10314 png_byte sig[8];
10315 png_byte *pixels = NULL;
10316 png_byte **rows = NULL;
10317 png_uint_32 width, height;
10318 int bit_depth, color_type, interlace_type;
10319 png_byte channels;
10320 png_uint_32 row_bytes;
10321 int transparent_p;
10322 char *gamma_str;
10323 double screen_gamma, image_gamma;
10324 int intent;
10325 struct png_memory_storage tbr; /* Data to be read */
10326
10327 /* Find out what file to load. */
10328 specified_file = image_spec_value (img->spec, QCfile, NULL);
10329 specified_data = image_spec_value (img->spec, QCdata, NULL);
10330 file = Qnil;
10331 GCPRO1 (file);
10332
10333 if (NILP (specified_data))
10334 {
10335 file = x_find_image_file (specified_file);
10336 if (!STRINGP (file))
10337 {
10338 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10339 UNGCPRO;
10340 return 0;
10341 }
10342
10343 /* Open the image file. */
10344 fp = fopen (XSTRING (file)->data, "rb");
10345 if (!fp)
10346 {
10347 image_error ("Cannot open image file `%s'", file, Qnil);
10348 UNGCPRO;
10349 fclose (fp);
10350 return 0;
10351 }
10352
10353 /* Check PNG signature. */
10354 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10355 || !png_check_sig (sig, sizeof sig))
10356 {
10357 image_error ("Not a PNG file:` %s'", file, Qnil);
10358 UNGCPRO;
10359 fclose (fp);
10360 return 0;
10361 }
10362 }
10363 else
10364 {
10365 /* Read from memory. */
10366 tbr.bytes = XSTRING (specified_data)->data;
10367 tbr.len = STRING_BYTES (XSTRING (specified_data));
10368 tbr.index = 0;
10369
10370 /* Check PNG signature. */
10371 if (tbr.len < sizeof sig
10372 || !png_check_sig (tbr.bytes, sizeof sig))
10373 {
10374 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10375 UNGCPRO;
10376 return 0;
10377 }
10378
10379 /* Need to skip past the signature. */
10380 tbr.bytes += sizeof (sig);
10381 }
10382
6fc2811b
JR
10383 /* Initialize read and info structs for PNG lib. */
10384 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10385 my_png_error, my_png_warning);
10386 if (!png_ptr)
10387 {
10388 if (fp) fclose (fp);
10389 UNGCPRO;
10390 return 0;
10391 }
10392
10393 info_ptr = png_create_info_struct (png_ptr);
10394 if (!info_ptr)
10395 {
10396 png_destroy_read_struct (&png_ptr, NULL, NULL);
10397 if (fp) fclose (fp);
10398 UNGCPRO;
10399 return 0;
10400 }
10401
10402 end_info = png_create_info_struct (png_ptr);
10403 if (!end_info)
10404 {
10405 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10406 if (fp) fclose (fp);
10407 UNGCPRO;
10408 return 0;
10409 }
10410
10411 /* Set error jump-back. We come back here when the PNG library
10412 detects an error. */
10413 if (setjmp (png_ptr->jmpbuf))
10414 {
10415 error:
10416 if (png_ptr)
10417 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10418 xfree (pixels);
10419 xfree (rows);
10420 if (fp) fclose (fp);
10421 UNGCPRO;
10422 return 0;
10423 }
10424
10425 /* Read image info. */
10426 if (!NILP (specified_data))
10427 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10428 else
10429 png_init_io (png_ptr, fp);
10430
10431 png_set_sig_bytes (png_ptr, sizeof sig);
10432 png_read_info (png_ptr, info_ptr);
10433 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10434 &interlace_type, NULL, NULL);
10435
10436 /* If image contains simply transparency data, we prefer to
10437 construct a clipping mask. */
10438 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10439 transparent_p = 1;
10440 else
10441 transparent_p = 0;
10442
10443 /* This function is easier to write if we only have to handle
10444 one data format: RGB or RGBA with 8 bits per channel. Let's
10445 transform other formats into that format. */
10446
10447 /* Strip more than 8 bits per channel. */
10448 if (bit_depth == 16)
10449 png_set_strip_16 (png_ptr);
10450
10451 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10452 if available. */
10453 png_set_expand (png_ptr);
10454
10455 /* Convert grayscale images to RGB. */
10456 if (color_type == PNG_COLOR_TYPE_GRAY
10457 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10458 png_set_gray_to_rgb (png_ptr);
10459
10460 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10461 gamma_str = getenv ("SCREEN_GAMMA");
10462 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10463
10464 /* Tell the PNG lib to handle gamma correction for us. */
10465
10466#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10467 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10468 /* There is a special chunk in the image specifying the gamma. */
10469 png_set_sRGB (png_ptr, info_ptr, intent);
10470 else
10471#endif
10472 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10473 /* Image contains gamma information. */
10474 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10475 else
10476 /* Use a default of 0.5 for the image gamma. */
10477 png_set_gamma (png_ptr, screen_gamma, 0.5);
10478
10479 /* Handle alpha channel by combining the image with a background
10480 color. Do this only if a real alpha channel is supplied. For
10481 simple transparency, we prefer a clipping mask. */
10482 if (!transparent_p)
10483 {
10484 png_color_16 *image_background;
10485
10486 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10487 /* Image contains a background color with which to
10488 combine the image. */
10489 png_set_background (png_ptr, image_background,
10490 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10491 else
10492 {
10493 /* Image does not contain a background color with which
10494 to combine the image data via an alpha channel. Use
10495 the frame's background instead. */
10496 XColor color;
10497 Colormap cmap;
10498 png_color_16 frame_background;
10499
10500 BLOCK_INPUT;
10501 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10502 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10503 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10504 UNBLOCK_INPUT;
10505
10506 bzero (&frame_background, sizeof frame_background);
10507 frame_background.red = color.red;
10508 frame_background.green = color.green;
10509 frame_background.blue = color.blue;
10510
10511 png_set_background (png_ptr, &frame_background,
10512 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10513 }
10514 }
10515
10516 /* Update info structure. */
10517 png_read_update_info (png_ptr, info_ptr);
10518
10519 /* Get number of channels. Valid values are 1 for grayscale images
10520 and images with a palette, 2 for grayscale images with transparency
10521 information (alpha channel), 3 for RGB images, and 4 for RGB
10522 images with alpha channel, i.e. RGBA. If conversions above were
10523 sufficient we should only have 3 or 4 channels here. */
10524 channels = png_get_channels (png_ptr, info_ptr);
10525 xassert (channels == 3 || channels == 4);
10526
10527 /* Number of bytes needed for one row of the image. */
10528 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10529
10530 /* Allocate memory for the image. */
10531 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10532 rows = (png_byte **) xmalloc (height * sizeof *rows);
10533 for (i = 0; i < height; ++i)
10534 rows[i] = pixels + i * row_bytes;
10535
10536 /* Read the entire image. */
10537 png_read_image (png_ptr, rows);
10538 png_read_end (png_ptr, info_ptr);
10539 if (fp)
10540 {
10541 fclose (fp);
10542 fp = NULL;
10543 }
10544
10545 BLOCK_INPUT;
10546
10547 /* Create the X image and pixmap. */
10548 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10549 &img->pixmap))
10550 {
10551 UNBLOCK_INPUT;
10552 goto error;
10553 }
10554
10555 /* Create an image and pixmap serving as mask if the PNG image
10556 contains an alpha channel. */
10557 if (channels == 4
10558 && !transparent_p
10559 && !x_create_x_image_and_pixmap (f, width, height, 1,
10560 &mask_img, &img->mask))
10561 {
10562 x_destroy_x_image (ximg);
10563 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10564 img->pixmap = 0;
10565 UNBLOCK_INPUT;
10566 goto error;
10567 }
10568
10569 /* Fill the X image and mask from PNG data. */
10570 init_color_table ();
10571
10572 for (y = 0; y < height; ++y)
10573 {
10574 png_byte *p = rows[y];
10575
10576 for (x = 0; x < width; ++x)
10577 {
10578 unsigned r, g, b;
10579
10580 r = *p++ << 8;
10581 g = *p++ << 8;
10582 b = *p++ << 8;
10583 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10584
10585 /* An alpha channel, aka mask channel, associates variable
10586 transparency with an image. Where other image formats
10587 support binary transparency---fully transparent or fully
10588 opaque---PNG allows up to 254 levels of partial transparency.
10589 The PNG library implements partial transparency by combining
10590 the image with a specified background color.
10591
10592 I'm not sure how to handle this here nicely: because the
10593 background on which the image is displayed may change, for
10594 real alpha channel support, it would be necessary to create
10595 a new image for each possible background.
10596
10597 What I'm doing now is that a mask is created if we have
10598 boolean transparency information. Otherwise I'm using
10599 the frame's background color to combine the image with. */
10600
10601 if (channels == 4)
10602 {
10603 if (mask_img)
10604 XPutPixel (mask_img, x, y, *p > 0);
10605 ++p;
10606 }
10607 }
10608 }
10609
10610 /* Remember colors allocated for this image. */
10611 img->colors = colors_in_color_table (&img->ncolors);
10612 free_color_table ();
10613
10614 /* Clean up. */
10615 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10616 xfree (rows);
10617 xfree (pixels);
10618
10619 img->width = width;
10620 img->height = height;
10621
10622 /* Put the image into the pixmap, then free the X image and its buffer. */
10623 x_put_x_image (f, ximg, img->pixmap, width, height);
10624 x_destroy_x_image (ximg);
10625
10626 /* Same for the mask. */
10627 if (mask_img)
10628 {
10629 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10630 x_destroy_x_image (mask_img);
10631 }
10632
10633 UNBLOCK_INPUT;
10634 UNGCPRO;
10635 return 1;
10636}
10637
10638#endif /* HAVE_PNG != 0 */
10639
10640
10641\f
10642/***********************************************************************
10643 JPEG
10644 ***********************************************************************/
10645
10646#if HAVE_JPEG
10647
10648/* Work around a warning about HAVE_STDLIB_H being redefined in
10649 jconfig.h. */
10650#ifdef HAVE_STDLIB_H
10651#define HAVE_STDLIB_H_1
10652#undef HAVE_STDLIB_H
10653#endif /* HAVE_STLIB_H */
10654
10655#include <jpeglib.h>
10656#include <jerror.h>
10657#include <setjmp.h>
10658
10659#ifdef HAVE_STLIB_H_1
10660#define HAVE_STDLIB_H 1
10661#endif
10662
10663static int jpeg_image_p P_ ((Lisp_Object object));
10664static int jpeg_load P_ ((struct frame *f, struct image *img));
10665
10666/* The symbol `jpeg' identifying images of this type. */
10667
10668Lisp_Object Qjpeg;
10669
10670/* Indices of image specification fields in gs_format, below. */
10671
10672enum jpeg_keyword_index
10673{
10674 JPEG_TYPE,
10675 JPEG_DATA,
10676 JPEG_FILE,
10677 JPEG_ASCENT,
10678 JPEG_MARGIN,
10679 JPEG_RELIEF,
10680 JPEG_ALGORITHM,
10681 JPEG_HEURISTIC_MASK,
10682 JPEG_LAST
10683};
10684
10685/* Vector of image_keyword structures describing the format
10686 of valid user-defined image specifications. */
10687
10688static struct image_keyword jpeg_format[JPEG_LAST] =
10689{
10690 {":type", IMAGE_SYMBOL_VALUE, 1},
10691 {":data", IMAGE_STRING_VALUE, 0},
10692 {":file", IMAGE_STRING_VALUE, 0},
10693 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10694 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10695 {":relief", IMAGE_INTEGER_VALUE, 0},
10696 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10697 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10698};
10699
10700/* Structure describing the image type `jpeg'. */
10701
10702static struct image_type jpeg_type =
10703{
10704 &Qjpeg,
10705 jpeg_image_p,
10706 jpeg_load,
10707 x_clear_image,
10708 NULL
10709};
10710
10711
10712/* Return non-zero if OBJECT is a valid JPEG image specification. */
10713
10714static int
10715jpeg_image_p (object)
10716 Lisp_Object object;
10717{
10718 struct image_keyword fmt[JPEG_LAST];
10719
10720 bcopy (jpeg_format, fmt, sizeof fmt);
10721
10722 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10723 || (fmt[JPEG_ASCENT].count
10724 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10725 return 0;
10726
10727 /* Must specify either the :data or :file keyword. */
10728 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10729}
10730
10731
10732struct my_jpeg_error_mgr
10733{
10734 struct jpeg_error_mgr pub;
10735 jmp_buf setjmp_buffer;
10736};
10737
10738static void
10739my_error_exit (cinfo)
10740 j_common_ptr cinfo;
10741{
10742 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10743 longjmp (mgr->setjmp_buffer, 1);
10744}
10745
6fc2811b
JR
10746/* Init source method for JPEG data source manager. Called by
10747 jpeg_read_header() before any data is actually read. See
10748 libjpeg.doc from the JPEG lib distribution. */
10749
10750static void
10751our_init_source (cinfo)
10752 j_decompress_ptr cinfo;
10753{
10754}
10755
10756
10757/* Fill input buffer method for JPEG data source manager. Called
10758 whenever more data is needed. We read the whole image in one step,
10759 so this only adds a fake end of input marker at the end. */
10760
10761static boolean
10762our_fill_input_buffer (cinfo)
10763 j_decompress_ptr cinfo;
10764{
10765 /* Insert a fake EOI marker. */
10766 struct jpeg_source_mgr *src = cinfo->src;
10767 static JOCTET buffer[2];
10768
10769 buffer[0] = (JOCTET) 0xFF;
10770 buffer[1] = (JOCTET) JPEG_EOI;
10771
10772 src->next_input_byte = buffer;
10773 src->bytes_in_buffer = 2;
10774 return TRUE;
10775}
10776
10777
10778/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10779 is the JPEG data source manager. */
10780
10781static void
10782our_skip_input_data (cinfo, num_bytes)
10783 j_decompress_ptr cinfo;
10784 long num_bytes;
10785{
10786 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10787
10788 if (src)
10789 {
10790 if (num_bytes > src->bytes_in_buffer)
10791 ERREXIT (cinfo, JERR_INPUT_EOF);
10792
10793 src->bytes_in_buffer -= num_bytes;
10794 src->next_input_byte += num_bytes;
10795 }
10796}
10797
10798
10799/* Method to terminate data source. Called by
10800 jpeg_finish_decompress() after all data has been processed. */
10801
10802static void
10803our_term_source (cinfo)
10804 j_decompress_ptr cinfo;
10805{
10806}
10807
10808
10809/* Set up the JPEG lib for reading an image from DATA which contains
10810 LEN bytes. CINFO is the decompression info structure created for
10811 reading the image. */
10812
10813static void
10814jpeg_memory_src (cinfo, data, len)
10815 j_decompress_ptr cinfo;
10816 JOCTET *data;
10817 unsigned int len;
10818{
10819 struct jpeg_source_mgr *src;
10820
10821 if (cinfo->src == NULL)
10822 {
10823 /* First time for this JPEG object? */
10824 cinfo->src = (struct jpeg_source_mgr *)
10825 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10826 sizeof (struct jpeg_source_mgr));
10827 src = (struct jpeg_source_mgr *) cinfo->src;
10828 src->next_input_byte = data;
10829 }
10830
10831 src = (struct jpeg_source_mgr *) cinfo->src;
10832 src->init_source = our_init_source;
10833 src->fill_input_buffer = our_fill_input_buffer;
10834 src->skip_input_data = our_skip_input_data;
10835 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10836 src->term_source = our_term_source;
10837 src->bytes_in_buffer = len;
10838 src->next_input_byte = data;
10839}
10840
10841
10842/* Load image IMG for use on frame F. Patterned after example.c
10843 from the JPEG lib. */
10844
10845static int
10846jpeg_load (f, img)
10847 struct frame *f;
10848 struct image *img;
10849{
10850 struct jpeg_decompress_struct cinfo;
10851 struct my_jpeg_error_mgr mgr;
10852 Lisp_Object file, specified_file;
10853 Lisp_Object specified_data;
10854 FILE *fp = NULL;
10855 JSAMPARRAY buffer;
10856 int row_stride, x, y;
10857 XImage *ximg = NULL;
10858 int rc;
10859 unsigned long *colors;
10860 int width, height;
10861 struct gcpro gcpro1;
10862
10863 /* Open the JPEG file. */
10864 specified_file = image_spec_value (img->spec, QCfile, NULL);
10865 specified_data = image_spec_value (img->spec, QCdata, NULL);
10866 file = Qnil;
10867 GCPRO1 (file);
10868
6fc2811b
JR
10869 if (NILP (specified_data))
10870 {
10871 file = x_find_image_file (specified_file);
10872 if (!STRINGP (file))
10873 {
10874 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10875 UNGCPRO;
10876 return 0;
10877 }
10878
10879 fp = fopen (XSTRING (file)->data, "r");
10880 if (fp == NULL)
10881 {
10882 image_error ("Cannot open `%s'", file, Qnil);
10883 UNGCPRO;
10884 return 0;
10885 }
10886 }
10887
10888 /* Customize libjpeg's error handling to call my_error_exit when an
10889 error is detected. This function will perform a longjmp. */
10890 mgr.pub.error_exit = my_error_exit;
10891 cinfo.err = jpeg_std_error (&mgr.pub);
10892
10893 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10894 {
10895 if (rc == 1)
10896 {
10897 /* Called from my_error_exit. Display a JPEG error. */
10898 char buffer[JMSG_LENGTH_MAX];
10899 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10900 image_error ("Error reading JPEG image `%s': %s", img->spec,
10901 build_string (buffer));
10902 }
10903
10904 /* Close the input file and destroy the JPEG object. */
10905 if (fp)
10906 fclose (fp);
10907 jpeg_destroy_decompress (&cinfo);
10908
10909 BLOCK_INPUT;
10910
10911 /* If we already have an XImage, free that. */
10912 x_destroy_x_image (ximg);
10913
10914 /* Free pixmap and colors. */
10915 x_clear_image (f, img);
10916
10917 UNBLOCK_INPUT;
10918 UNGCPRO;
10919 return 0;
10920 }
10921
10922 /* Create the JPEG decompression object. Let it read from fp.
10923 Read the JPEG image header. */
10924 jpeg_create_decompress (&cinfo);
10925
10926 if (NILP (specified_data))
10927 jpeg_stdio_src (&cinfo, fp);
10928 else
10929 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
10930 STRING_BYTES (XSTRING (specified_data)));
10931
10932 jpeg_read_header (&cinfo, TRUE);
10933
10934 /* Customize decompression so that color quantization will be used.
10935 Start decompression. */
10936 cinfo.quantize_colors = TRUE;
10937 jpeg_start_decompress (&cinfo);
10938 width = img->width = cinfo.output_width;
10939 height = img->height = cinfo.output_height;
10940
10941 BLOCK_INPUT;
10942
10943 /* Create X image and pixmap. */
10944 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10945 &img->pixmap))
10946 {
10947 UNBLOCK_INPUT;
10948 longjmp (mgr.setjmp_buffer, 2);
10949 }
10950
10951 /* Allocate colors. When color quantization is used,
10952 cinfo.actual_number_of_colors has been set with the number of
10953 colors generated, and cinfo.colormap is a two-dimensional array
10954 of color indices in the range 0..cinfo.actual_number_of_colors.
10955 No more than 255 colors will be generated. */
10956 {
10957 int i, ir, ig, ib;
10958
10959 if (cinfo.out_color_components > 2)
10960 ir = 0, ig = 1, ib = 2;
10961 else if (cinfo.out_color_components > 1)
10962 ir = 0, ig = 1, ib = 0;
10963 else
10964 ir = 0, ig = 0, ib = 0;
10965
10966 /* Use the color table mechanism because it handles colors that
10967 cannot be allocated nicely. Such colors will be replaced with
10968 a default color, and we don't have to care about which colors
10969 can be freed safely, and which can't. */
10970 init_color_table ();
10971 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
10972 * sizeof *colors);
10973
10974 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
10975 {
10976 /* Multiply RGB values with 255 because X expects RGB values
10977 in the range 0..0xffff. */
10978 int r = cinfo.colormap[ir][i] << 8;
10979 int g = cinfo.colormap[ig][i] << 8;
10980 int b = cinfo.colormap[ib][i] << 8;
10981 colors[i] = lookup_rgb_color (f, r, g, b);
10982 }
10983
10984 /* Remember those colors actually allocated. */
10985 img->colors = colors_in_color_table (&img->ncolors);
10986 free_color_table ();
10987 }
10988
10989 /* Read pixels. */
10990 row_stride = width * cinfo.output_components;
10991 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
10992 row_stride, 1);
10993 for (y = 0; y < height; ++y)
10994 {
10995 jpeg_read_scanlines (&cinfo, buffer, 1);
10996 for (x = 0; x < cinfo.output_width; ++x)
10997 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
10998 }
10999
11000 /* Clean up. */
11001 jpeg_finish_decompress (&cinfo);
11002 jpeg_destroy_decompress (&cinfo);
11003 if (fp)
11004 fclose (fp);
11005
11006 /* Put the image into the pixmap. */
11007 x_put_x_image (f, ximg, img->pixmap, width, height);
11008 x_destroy_x_image (ximg);
11009 UNBLOCK_INPUT;
11010 UNGCPRO;
11011 return 1;
11012}
11013
11014#endif /* HAVE_JPEG */
11015
11016
11017\f
11018/***********************************************************************
11019 TIFF
11020 ***********************************************************************/
11021
11022#if HAVE_TIFF
11023
11024#include <tiffio.h>
11025
11026static int tiff_image_p P_ ((Lisp_Object object));
11027static int tiff_load P_ ((struct frame *f, struct image *img));
11028
11029/* The symbol `tiff' identifying images of this type. */
11030
11031Lisp_Object Qtiff;
11032
11033/* Indices of image specification fields in tiff_format, below. */
11034
11035enum tiff_keyword_index
11036{
11037 TIFF_TYPE,
11038 TIFF_DATA,
11039 TIFF_FILE,
11040 TIFF_ASCENT,
11041 TIFF_MARGIN,
11042 TIFF_RELIEF,
11043 TIFF_ALGORITHM,
11044 TIFF_HEURISTIC_MASK,
11045 TIFF_LAST
11046};
11047
11048/* Vector of image_keyword structures describing the format
11049 of valid user-defined image specifications. */
11050
11051static struct image_keyword tiff_format[TIFF_LAST] =
11052{
11053 {":type", IMAGE_SYMBOL_VALUE, 1},
11054 {":data", IMAGE_STRING_VALUE, 0},
11055 {":file", IMAGE_STRING_VALUE, 0},
11056 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11057 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11058 {":relief", IMAGE_INTEGER_VALUE, 0},
11059 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11060 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11061};
11062
11063/* Structure describing the image type `tiff'. */
11064
11065static struct image_type tiff_type =
11066{
11067 &Qtiff,
11068 tiff_image_p,
11069 tiff_load,
11070 x_clear_image,
11071 NULL
11072};
11073
11074
11075/* Return non-zero if OBJECT is a valid TIFF image specification. */
11076
11077static int
11078tiff_image_p (object)
11079 Lisp_Object object;
11080{
11081 struct image_keyword fmt[TIFF_LAST];
11082 bcopy (tiff_format, fmt, sizeof fmt);
11083
11084 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11085 || (fmt[TIFF_ASCENT].count
11086 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11087 return 0;
11088
11089 /* Must specify either the :data or :file keyword. */
11090 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11091}
11092
11093
11094/* Reading from a memory buffer for TIFF images Based on the PNG
11095 memory source, but we have to provide a lot of extra functions.
11096 Blah.
11097
11098 We really only need to implement read and seek, but I am not
11099 convinced that the TIFF library is smart enough not to destroy
11100 itself if we only hand it the function pointers we need to
11101 override. */
11102
11103typedef struct
11104{
11105 unsigned char *bytes;
11106 size_t len;
11107 int index;
11108}
11109tiff_memory_source;
11110
11111static size_t
11112tiff_read_from_memory (data, buf, size)
11113 thandle_t data;
11114 tdata_t buf;
11115 tsize_t size;
11116{
11117 tiff_memory_source *src = (tiff_memory_source *) data;
11118
11119 if (size > src->len - src->index)
11120 return (size_t) -1;
11121 bcopy (src->bytes + src->index, buf, size);
11122 src->index += size;
11123 return size;
11124}
11125
11126static size_t
11127tiff_write_from_memory (data, buf, size)
11128 thandle_t data;
11129 tdata_t buf;
11130 tsize_t size;
11131{
11132 return (size_t) -1;
11133}
11134
11135static toff_t
11136tiff_seek_in_memory (data, off, whence)
11137 thandle_t data;
11138 toff_t off;
11139 int whence;
11140{
11141 tiff_memory_source *src = (tiff_memory_source *) data;
11142 int idx;
11143
11144 switch (whence)
11145 {
11146 case SEEK_SET: /* Go from beginning of source. */
11147 idx = off;
11148 break;
11149
11150 case SEEK_END: /* Go from end of source. */
11151 idx = src->len + off;
11152 break;
11153
11154 case SEEK_CUR: /* Go from current position. */
11155 idx = src->index + off;
11156 break;
11157
11158 default: /* Invalid `whence'. */
11159 return -1;
11160 }
11161
11162 if (idx > src->len || idx < 0)
11163 return -1;
11164
11165 src->index = idx;
11166 return src->index;
11167}
11168
11169static int
11170tiff_close_memory (data)
11171 thandle_t data;
11172{
11173 /* NOOP */
11174 return 0;
11175}
11176
11177static int
11178tiff_mmap_memory (data, pbase, psize)
11179 thandle_t data;
11180 tdata_t *pbase;
11181 toff_t *psize;
11182{
11183 /* It is already _IN_ memory. */
11184 return 0;
11185}
11186
11187static void
11188tiff_unmap_memory (data, base, size)
11189 thandle_t data;
11190 tdata_t base;
11191 toff_t size;
11192{
11193 /* We don't need to do this. */
11194}
11195
11196static toff_t
11197tiff_size_of_memory (data)
11198 thandle_t data;
11199{
11200 return ((tiff_memory_source *) data)->len;
11201}
11202
6fc2811b
JR
11203/* Load TIFF image IMG for use on frame F. Value is non-zero if
11204 successful. */
11205
11206static int
11207tiff_load (f, img)
11208 struct frame *f;
11209 struct image *img;
11210{
11211 Lisp_Object file, specified_file;
11212 Lisp_Object specified_data;
11213 TIFF *tiff;
11214 int width, height, x, y;
11215 uint32 *buf;
11216 int rc;
11217 XImage *ximg;
11218 struct gcpro gcpro1;
11219 tiff_memory_source memsrc;
11220
11221 specified_file = image_spec_value (img->spec, QCfile, NULL);
11222 specified_data = image_spec_value (img->spec, QCdata, NULL);
11223 file = Qnil;
11224 GCPRO1 (file);
11225
11226 if (NILP (specified_data))
11227 {
11228 /* Read from a file */
11229 file = x_find_image_file (specified_file);
11230 if (!STRINGP (file))
11231 {
11232 image_error ("Cannot find image file `%s'", file, Qnil);
11233 UNGCPRO;
11234 return 0;
11235 }
11236
11237 /* Try to open the image file. */
11238 tiff = TIFFOpen (XSTRING (file)->data, "r");
11239 if (tiff == NULL)
11240 {
11241 image_error ("Cannot open `%s'", file, Qnil);
11242 UNGCPRO;
11243 return 0;
11244 }
11245 }
11246 else
11247 {
11248 /* Memory source! */
11249 memsrc.bytes = XSTRING (specified_data)->data;
11250 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11251 memsrc.index = 0;
11252
11253 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
11254 (TIFFReadWriteProc) tiff_read_from_memory,
11255 (TIFFReadWriteProc) tiff_write_from_memory,
11256 tiff_seek_in_memory,
11257 tiff_close_memory,
11258 tiff_size_of_memory,
11259 tiff_mmap_memory,
11260 tiff_unmap_memory);
11261
11262 if (!tiff)
11263 {
11264 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
11265 UNGCPRO;
11266 return 0;
11267 }
11268 }
11269
11270 /* Get width and height of the image, and allocate a raster buffer
11271 of width x height 32-bit values. */
11272 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11273 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
11274 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
11275
11276 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
11277 TIFFClose (tiff);
11278 if (!rc)
11279 {
11280 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11281 xfree (buf);
11282 UNGCPRO;
11283 return 0;
11284 }
11285
11286 BLOCK_INPUT;
11287
11288 /* Create the X image and pixmap. */
11289 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11290 {
11291 UNBLOCK_INPUT;
11292 xfree (buf);
11293 UNGCPRO;
11294 return 0;
11295 }
11296
11297 /* Initialize the color table. */
11298 init_color_table ();
11299
11300 /* Process the pixel raster. Origin is in the lower-left corner. */
11301 for (y = 0; y < height; ++y)
11302 {
11303 uint32 *row = buf + y * width;
11304
11305 for (x = 0; x < width; ++x)
11306 {
11307 uint32 abgr = row[x];
11308 int r = TIFFGetR (abgr) << 8;
11309 int g = TIFFGetG (abgr) << 8;
11310 int b = TIFFGetB (abgr) << 8;
11311 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11312 }
11313 }
11314
11315 /* Remember the colors allocated for the image. Free the color table. */
11316 img->colors = colors_in_color_table (&img->ncolors);
11317 free_color_table ();
11318
11319 /* Put the image into the pixmap, then free the X image and its buffer. */
11320 x_put_x_image (f, ximg, img->pixmap, width, height);
11321 x_destroy_x_image (ximg);
11322 xfree (buf);
11323 UNBLOCK_INPUT;
11324
11325 img->width = width;
11326 img->height = height;
11327
11328 UNGCPRO;
11329 return 1;
11330}
11331
11332#endif /* HAVE_TIFF != 0 */
11333
11334
11335\f
11336/***********************************************************************
11337 GIF
11338 ***********************************************************************/
11339
11340#if HAVE_GIF
11341
11342#include <gif_lib.h>
11343
11344static int gif_image_p P_ ((Lisp_Object object));
11345static int gif_load P_ ((struct frame *f, struct image *img));
11346
11347/* The symbol `gif' identifying images of this type. */
11348
11349Lisp_Object Qgif;
11350
11351/* Indices of image specification fields in gif_format, below. */
11352
11353enum gif_keyword_index
11354{
11355 GIF_TYPE,
11356 GIF_DATA,
11357 GIF_FILE,
11358 GIF_ASCENT,
11359 GIF_MARGIN,
11360 GIF_RELIEF,
11361 GIF_ALGORITHM,
11362 GIF_HEURISTIC_MASK,
11363 GIF_IMAGE,
11364 GIF_LAST
11365};
11366
11367/* Vector of image_keyword structures describing the format
11368 of valid user-defined image specifications. */
11369
11370static struct image_keyword gif_format[GIF_LAST] =
11371{
11372 {":type", IMAGE_SYMBOL_VALUE, 1},
11373 {":data", IMAGE_STRING_VALUE, 0},
11374 {":file", IMAGE_STRING_VALUE, 0},
11375 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11376 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11377 {":relief", IMAGE_INTEGER_VALUE, 0},
11378 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11379 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11380 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11381};
11382
11383/* Structure describing the image type `gif'. */
11384
11385static struct image_type gif_type =
11386{
11387 &Qgif,
11388 gif_image_p,
11389 gif_load,
11390 x_clear_image,
11391 NULL
11392};
11393
11394/* Return non-zero if OBJECT is a valid GIF image specification. */
11395
11396static int
11397gif_image_p (object)
11398 Lisp_Object object;
11399{
11400 struct image_keyword fmt[GIF_LAST];
11401 bcopy (gif_format, fmt, sizeof fmt);
11402
11403 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11404 || (fmt[GIF_ASCENT].count
11405 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11406 return 0;
11407
11408 /* Must specify either the :data or :file keyword. */
11409 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11410}
11411
11412/* Reading a GIF image from memory
11413 Based on the PNG memory stuff to a certain extent. */
11414
11415typedef struct
11416{
11417 unsigned char *bytes;
11418 size_t len;
11419 int index;
11420}
11421gif_memory_source;
11422
11423/* Make the current memory source available to gif_read_from_memory.
11424 It's done this way because not all versions of libungif support
11425 a UserData field in the GifFileType structure. */
11426static gif_memory_source *current_gif_memory_src;
11427
11428static int
11429gif_read_from_memory (file, buf, len)
11430 GifFileType *file;
11431 GifByteType *buf;
11432 int len;
11433{
11434 gif_memory_source *src = current_gif_memory_src;
11435
11436 if (len > src->len - src->index)
11437 return -1;
11438
11439 bcopy (src->bytes + src->index, buf, len);
11440 src->index += len;
11441 return len;
11442}
11443
11444
11445/* Load GIF image IMG for use on frame F. Value is non-zero if
11446 successful. */
11447
11448static int
11449gif_load (f, img)
11450 struct frame *f;
11451 struct image *img;
11452{
11453 Lisp_Object file, specified_file;
11454 Lisp_Object specified_data;
11455 int rc, width, height, x, y, i;
11456 XImage *ximg;
11457 ColorMapObject *gif_color_map;
11458 unsigned long pixel_colors[256];
11459 GifFileType *gif;
11460 struct gcpro gcpro1;
11461 Lisp_Object image;
11462 int ino, image_left, image_top, image_width, image_height;
11463 gif_memory_source memsrc;
11464 unsigned char *raster;
11465
11466 specified_file = image_spec_value (img->spec, QCfile, NULL);
11467 specified_data = image_spec_value (img->spec, QCdata, NULL);
11468 file = Qnil;
dfff8a69 11469 GCPRO1 (file);
6fc2811b
JR
11470
11471 if (NILP (specified_data))
11472 {
11473 file = x_find_image_file (specified_file);
6fc2811b
JR
11474 if (!STRINGP (file))
11475 {
11476 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11477 UNGCPRO;
11478 return 0;
11479 }
11480
11481 /* Open the GIF file. */
11482 gif = DGifOpenFileName (XSTRING (file)->data);
11483 if (gif == NULL)
11484 {
11485 image_error ("Cannot open `%s'", file, Qnil);
11486 UNGCPRO;
11487 return 0;
11488 }
11489 }
11490 else
11491 {
11492 /* Read from memory! */
11493 current_gif_memory_src = &memsrc;
11494 memsrc.bytes = XSTRING (specified_data)->data;
11495 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11496 memsrc.index = 0;
11497
11498 gif = DGifOpen(&memsrc, gif_read_from_memory);
11499 if (!gif)
11500 {
11501 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11502 UNGCPRO;
11503 return 0;
11504 }
11505 }
11506
11507 /* Read entire contents. */
11508 rc = DGifSlurp (gif);
11509 if (rc == GIF_ERROR)
11510 {
11511 image_error ("Error reading `%s'", img->spec, Qnil);
11512 DGifCloseFile (gif);
11513 UNGCPRO;
11514 return 0;
11515 }
11516
11517 image = image_spec_value (img->spec, QCindex, NULL);
11518 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11519 if (ino >= gif->ImageCount)
11520 {
11521 image_error ("Invalid image number `%s' in image `%s'",
11522 image, img->spec);
11523 DGifCloseFile (gif);
11524 UNGCPRO;
11525 return 0;
11526 }
11527
11528 width = img->width = gif->SWidth;
11529 height = img->height = gif->SHeight;
11530
11531 BLOCK_INPUT;
11532
11533 /* Create the X image and pixmap. */
11534 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11535 {
11536 UNBLOCK_INPUT;
11537 DGifCloseFile (gif);
11538 UNGCPRO;
11539 return 0;
11540 }
11541
11542 /* Allocate colors. */
11543 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11544 if (!gif_color_map)
11545 gif_color_map = gif->SColorMap;
11546 init_color_table ();
11547 bzero (pixel_colors, sizeof pixel_colors);
11548
11549 for (i = 0; i < gif_color_map->ColorCount; ++i)
11550 {
11551 int r = gif_color_map->Colors[i].Red << 8;
11552 int g = gif_color_map->Colors[i].Green << 8;
11553 int b = gif_color_map->Colors[i].Blue << 8;
11554 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11555 }
11556
11557 img->colors = colors_in_color_table (&img->ncolors);
11558 free_color_table ();
11559
11560 /* Clear the part of the screen image that are not covered by
11561 the image from the GIF file. Full animated GIF support
11562 requires more than can be done here (see the gif89 spec,
11563 disposal methods). Let's simply assume that the part
11564 not covered by a sub-image is in the frame's background color. */
11565 image_top = gif->SavedImages[ino].ImageDesc.Top;
11566 image_left = gif->SavedImages[ino].ImageDesc.Left;
11567 image_width = gif->SavedImages[ino].ImageDesc.Width;
11568 image_height = gif->SavedImages[ino].ImageDesc.Height;
11569
11570 for (y = 0; y < image_top; ++y)
11571 for (x = 0; x < width; ++x)
11572 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11573
11574 for (y = image_top + image_height; y < height; ++y)
11575 for (x = 0; x < width; ++x)
11576 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11577
11578 for (y = image_top; y < image_top + image_height; ++y)
11579 {
11580 for (x = 0; x < image_left; ++x)
11581 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11582 for (x = image_left + image_width; x < width; ++x)
11583 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11584 }
11585
11586 /* Read the GIF image into the X image. We use a local variable
11587 `raster' here because RasterBits below is a char *, and invites
11588 problems with bytes >= 0x80. */
11589 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11590
11591 if (gif->SavedImages[ino].ImageDesc.Interlace)
11592 {
11593 static int interlace_start[] = {0, 4, 2, 1};
11594 static int interlace_increment[] = {8, 8, 4, 2};
11595 int pass, inc;
11596 int row = interlace_start[0];
11597
11598 pass = 0;
11599
11600 for (y = 0; y < image_height; y++)
11601 {
11602 if (row >= image_height)
11603 {
11604 row = interlace_start[++pass];
11605 while (row >= image_height)
11606 row = interlace_start[++pass];
11607 }
11608
11609 for (x = 0; x < image_width; x++)
11610 {
11611 int i = raster[(y * image_width) + x];
11612 XPutPixel (ximg, x + image_left, row + image_top,
11613 pixel_colors[i]);
11614 }
11615
11616 row += interlace_increment[pass];
11617 }
11618 }
11619 else
11620 {
11621 for (y = 0; y < image_height; ++y)
11622 for (x = 0; x < image_width; ++x)
11623 {
11624 int i = raster[y* image_width + x];
11625 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11626 }
11627 }
11628
11629 DGifCloseFile (gif);
11630
11631 /* Put the image into the pixmap, then free the X image and its buffer. */
11632 x_put_x_image (f, ximg, img->pixmap, width, height);
11633 x_destroy_x_image (ximg);
11634 UNBLOCK_INPUT;
11635
11636 UNGCPRO;
11637 return 1;
11638}
11639
11640#endif /* HAVE_GIF != 0 */
11641
11642
11643\f
11644/***********************************************************************
11645 Ghostscript
11646 ***********************************************************************/
11647
11648#ifdef HAVE_GHOSTSCRIPT
11649static int gs_image_p P_ ((Lisp_Object object));
11650static int gs_load P_ ((struct frame *f, struct image *img));
11651static void gs_clear_image P_ ((struct frame *f, struct image *img));
11652
11653/* The symbol `postscript' identifying images of this type. */
11654
11655Lisp_Object Qpostscript;
11656
11657/* Keyword symbols. */
11658
11659Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11660
11661/* Indices of image specification fields in gs_format, below. */
11662
11663enum gs_keyword_index
11664{
11665 GS_TYPE,
11666 GS_PT_WIDTH,
11667 GS_PT_HEIGHT,
11668 GS_FILE,
11669 GS_LOADER,
11670 GS_BOUNDING_BOX,
11671 GS_ASCENT,
11672 GS_MARGIN,
11673 GS_RELIEF,
11674 GS_ALGORITHM,
11675 GS_HEURISTIC_MASK,
11676 GS_LAST
11677};
11678
11679/* Vector of image_keyword structures describing the format
11680 of valid user-defined image specifications. */
11681
11682static struct image_keyword gs_format[GS_LAST] =
11683{
11684 {":type", IMAGE_SYMBOL_VALUE, 1},
11685 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11686 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11687 {":file", IMAGE_STRING_VALUE, 1},
11688 {":loader", IMAGE_FUNCTION_VALUE, 0},
11689 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11690 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11691 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11692 {":relief", IMAGE_INTEGER_VALUE, 0},
11693 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11694 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11695};
11696
11697/* Structure describing the image type `ghostscript'. */
11698
11699static struct image_type gs_type =
11700{
11701 &Qpostscript,
11702 gs_image_p,
11703 gs_load,
11704 gs_clear_image,
11705 NULL
11706};
11707
11708
11709/* Free X resources of Ghostscript image IMG which is used on frame F. */
11710
11711static void
11712gs_clear_image (f, img)
11713 struct frame *f;
11714 struct image *img;
11715{
11716 /* IMG->data.ptr_val may contain a recorded colormap. */
11717 xfree (img->data.ptr_val);
11718 x_clear_image (f, img);
11719}
11720
11721
11722/* Return non-zero if OBJECT is a valid Ghostscript image
11723 specification. */
11724
11725static int
11726gs_image_p (object)
11727 Lisp_Object object;
11728{
11729 struct image_keyword fmt[GS_LAST];
11730 Lisp_Object tem;
11731 int i;
11732
11733 bcopy (gs_format, fmt, sizeof fmt);
11734
11735 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11736 || (fmt[GS_ASCENT].count
11737 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11738 return 0;
11739
11740 /* Bounding box must be a list or vector containing 4 integers. */
11741 tem = fmt[GS_BOUNDING_BOX].value;
11742 if (CONSP (tem))
11743 {
11744 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11745 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11746 return 0;
11747 if (!NILP (tem))
11748 return 0;
11749 }
11750 else if (VECTORP (tem))
11751 {
11752 if (XVECTOR (tem)->size != 4)
11753 return 0;
11754 for (i = 0; i < 4; ++i)
11755 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11756 return 0;
11757 }
11758 else
11759 return 0;
11760
11761 return 1;
11762}
11763
11764
11765/* Load Ghostscript image IMG for use on frame F. Value is non-zero
11766 if successful. */
11767
11768static int
11769gs_load (f, img)
11770 struct frame *f;
11771 struct image *img;
11772{
11773 char buffer[100];
11774 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11775 struct gcpro gcpro1, gcpro2;
11776 Lisp_Object frame;
11777 double in_width, in_height;
11778 Lisp_Object pixel_colors = Qnil;
11779
11780 /* Compute pixel size of pixmap needed from the given size in the
11781 image specification. Sizes in the specification are in pt. 1 pt
11782 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11783 info. */
11784 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11785 in_width = XFASTINT (pt_width) / 72.0;
11786 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11787 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11788 in_height = XFASTINT (pt_height) / 72.0;
11789 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11790
11791 /* Create the pixmap. */
11792 BLOCK_INPUT;
11793 xassert (img->pixmap == 0);
11794 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11795 img->width, img->height,
11796 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11797 UNBLOCK_INPUT;
11798
11799 if (!img->pixmap)
11800 {
11801 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11802 return 0;
11803 }
11804
11805 /* Call the loader to fill the pixmap. It returns a process object
11806 if successful. We do not record_unwind_protect here because
11807 other places in redisplay like calling window scroll functions
11808 don't either. Let the Lisp loader use `unwind-protect' instead. */
11809 GCPRO2 (window_and_pixmap_id, pixel_colors);
11810
11811 sprintf (buffer, "%lu %lu",
11812 (unsigned long) FRAME_W32_WINDOW (f),
11813 (unsigned long) img->pixmap);
11814 window_and_pixmap_id = build_string (buffer);
11815
11816 sprintf (buffer, "%lu %lu",
11817 FRAME_FOREGROUND_PIXEL (f),
11818 FRAME_BACKGROUND_PIXEL (f));
11819 pixel_colors = build_string (buffer);
11820
11821 XSETFRAME (frame, f);
11822 loader = image_spec_value (img->spec, QCloader, NULL);
11823 if (NILP (loader))
11824 loader = intern ("gs-load-image");
11825
11826 img->data.lisp_val = call6 (loader, frame, img->spec,
11827 make_number (img->width),
11828 make_number (img->height),
11829 window_and_pixmap_id,
11830 pixel_colors);
11831 UNGCPRO;
11832 return PROCESSP (img->data.lisp_val);
11833}
11834
11835
11836/* Kill the Ghostscript process that was started to fill PIXMAP on
11837 frame F. Called from XTread_socket when receiving an event
11838 telling Emacs that Ghostscript has finished drawing. */
11839
11840void
11841x_kill_gs_process (pixmap, f)
11842 Pixmap pixmap;
11843 struct frame *f;
11844{
11845 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11846 int class, i;
11847 struct image *img;
11848
11849 /* Find the image containing PIXMAP. */
11850 for (i = 0; i < c->used; ++i)
11851 if (c->images[i]->pixmap == pixmap)
11852 break;
11853
11854 /* Kill the GS process. We should have found PIXMAP in the image
11855 cache and its image should contain a process object. */
11856 xassert (i < c->used);
11857 img = c->images[i];
11858 xassert (PROCESSP (img->data.lisp_val));
11859 Fkill_process (img->data.lisp_val, Qnil);
11860 img->data.lisp_val = Qnil;
11861
11862 /* On displays with a mutable colormap, figure out the colors
11863 allocated for the image by looking at the pixels of an XImage for
11864 img->pixmap. */
11865 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11866 if (class != StaticColor && class != StaticGray && class != TrueColor)
11867 {
11868 XImage *ximg;
11869
11870 BLOCK_INPUT;
11871
11872 /* Try to get an XImage for img->pixmep. */
11873 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11874 0, 0, img->width, img->height, ~0, ZPixmap);
11875 if (ximg)
11876 {
11877 int x, y;
11878
11879 /* Initialize the color table. */
11880 init_color_table ();
11881
11882 /* For each pixel of the image, look its color up in the
11883 color table. After having done so, the color table will
11884 contain an entry for each color used by the image. */
11885 for (y = 0; y < img->height; ++y)
11886 for (x = 0; x < img->width; ++x)
11887 {
11888 unsigned long pixel = XGetPixel (ximg, x, y);
11889 lookup_pixel_color (f, pixel);
11890 }
11891
11892 /* Record colors in the image. Free color table and XImage. */
11893 img->colors = colors_in_color_table (&img->ncolors);
11894 free_color_table ();
11895 XDestroyImage (ximg);
11896
11897#if 0 /* This doesn't seem to be the case. If we free the colors
11898 here, we get a BadAccess later in x_clear_image when
11899 freeing the colors. */
11900 /* We have allocated colors once, but Ghostscript has also
11901 allocated colors on behalf of us. So, to get the
11902 reference counts right, free them once. */
11903 if (img->ncolors)
11904 {
11905 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11906 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11907 img->colors, img->ncolors, 0);
11908 }
11909#endif
11910 }
11911 else
11912 image_error ("Cannot get X image of `%s'; colors will not be freed",
11913 img->spec, Qnil);
11914
11915 UNBLOCK_INPUT;
11916 }
11917}
11918
11919#endif /* HAVE_GHOSTSCRIPT */
11920
11921\f
11922/***********************************************************************
11923 Window properties
11924 ***********************************************************************/
11925
11926DEFUN ("x-change-window-property", Fx_change_window_property,
11927 Sx_change_window_property, 2, 3, 0,
11928 "Change window property PROP to VALUE on the X window of FRAME.\n\
11929PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
11930selected frame. Value is VALUE.")
11931 (prop, value, frame)
11932 Lisp_Object frame, prop, value;
11933{
767b1ff0 11934#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
11935 struct frame *f = check_x_frame (frame);
11936 Atom prop_atom;
11937
11938 CHECK_STRING (prop, 1);
11939 CHECK_STRING (value, 2);
11940
11941 BLOCK_INPUT;
11942 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11943 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11944 prop_atom, XA_STRING, 8, PropModeReplace,
11945 XSTRING (value)->data, XSTRING (value)->size);
11946
11947 /* Make sure the property is set when we return. */
11948 XFlush (FRAME_W32_DISPLAY (f));
11949 UNBLOCK_INPUT;
11950
767b1ff0 11951#endif /* TODO */
6fc2811b
JR
11952
11953 return value;
11954}
11955
11956
11957DEFUN ("x-delete-window-property", Fx_delete_window_property,
11958 Sx_delete_window_property, 1, 2, 0,
11959 "Remove window property PROP from X window of FRAME.\n\
11960FRAME nil or omitted means use the selected frame. Value is PROP.")
11961 (prop, frame)
11962 Lisp_Object prop, frame;
11963{
767b1ff0 11964#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
11965
11966 struct frame *f = check_x_frame (frame);
11967 Atom prop_atom;
11968
11969 CHECK_STRING (prop, 1);
11970 BLOCK_INPUT;
11971 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11972 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
11973
11974 /* Make sure the property is removed when we return. */
11975 XFlush (FRAME_W32_DISPLAY (f));
11976 UNBLOCK_INPUT;
767b1ff0 11977#endif /* TODO */
6fc2811b
JR
11978
11979 return prop;
11980}
11981
11982
11983DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
11984 1, 2, 0,
11985 "Value is the value of window property PROP on FRAME.\n\
11986If FRAME is nil or omitted, use the selected frame. Value is nil\n\
11987if FRAME hasn't a property with name PROP or if PROP has no string\n\
11988value.")
11989 (prop, frame)
11990 Lisp_Object prop, frame;
11991{
767b1ff0 11992#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
11993
11994 struct frame *f = check_x_frame (frame);
11995 Atom prop_atom;
11996 int rc;
11997 Lisp_Object prop_value = Qnil;
11998 char *tmp_data = NULL;
11999 Atom actual_type;
12000 int actual_format;
12001 unsigned long actual_size, bytes_remaining;
12002
12003 CHECK_STRING (prop, 1);
12004 BLOCK_INPUT;
12005 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12006 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12007 prop_atom, 0, 0, False, XA_STRING,
12008 &actual_type, &actual_format, &actual_size,
12009 &bytes_remaining, (unsigned char **) &tmp_data);
12010 if (rc == Success)
12011 {
12012 int size = bytes_remaining;
12013
12014 XFree (tmp_data);
12015 tmp_data = NULL;
12016
12017 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12018 prop_atom, 0, bytes_remaining,
12019 False, XA_STRING,
12020 &actual_type, &actual_format,
12021 &actual_size, &bytes_remaining,
12022 (unsigned char **) &tmp_data);
12023 if (rc == Success)
12024 prop_value = make_string (tmp_data, size);
12025
12026 XFree (tmp_data);
12027 }
12028
12029 UNBLOCK_INPUT;
12030
12031 return prop_value;
12032
767b1ff0 12033#endif /* TODO */
6fc2811b
JR
12034 return Qnil;
12035}
12036
12037
12038\f
12039/***********************************************************************
12040 Busy cursor
12041 ***********************************************************************/
12042
f79e6790
JR
12043/* If non-null, an asynchronous timer that, when it expires, displays
12044 a busy cursor on all frames. */
6fc2811b 12045
f79e6790 12046static struct atimer *busy_cursor_atimer;
6fc2811b 12047
f79e6790 12048/* Non-zero means a busy cursor is currently shown. */
6fc2811b 12049
f79e6790 12050static int busy_cursor_shown_p;
6fc2811b 12051
f79e6790 12052/* Number of seconds to wait before displaying a busy cursor. */
6fc2811b 12053
f79e6790 12054static Lisp_Object Vbusy_cursor_delay;
6fc2811b 12055
f79e6790
JR
12056/* Default number of seconds to wait before displaying a busy
12057 cursor. */
12058
12059#define DEFAULT_BUSY_CURSOR_DELAY 1
12060
12061/* Function prototypes. */
12062
12063static void show_busy_cursor P_ ((struct atimer *));
12064static void hide_busy_cursor P_ ((void));
12065
12066
12067/* Cancel a currently active busy-cursor timer, and start a new one. */
12068
12069void
12070start_busy_cursor ()
12071{
767b1ff0 12072#if 0 /* TODO: cursor shape changes. */
f79e6790 12073 EMACS_TIME delay;
dfff8a69 12074 int secs, usecs = 0;
f79e6790
JR
12075
12076 cancel_busy_cursor ();
12077
12078 if (INTEGERP (Vbusy_cursor_delay)
12079 && XINT (Vbusy_cursor_delay) > 0)
12080 secs = XFASTINT (Vbusy_cursor_delay);
dfff8a69
JR
12081 else if (FLOATP (Vbusy_cursor_delay)
12082 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
12083 {
12084 Lisp_Object tem;
12085 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
12086 secs = XFASTINT (tem);
12087 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
12088 }
f79e6790
JR
12089 else
12090 secs = DEFAULT_BUSY_CURSOR_DELAY;
12091
dfff8a69 12092 EMACS_SET_SECS_USECS (delay, secs, usecs);
f79e6790
JR
12093 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
12094 show_busy_cursor, NULL);
12095#endif
12096}
12097
12098
12099/* Cancel the busy cursor timer if active, hide a busy cursor if
12100 shown. */
12101
12102void
12103cancel_busy_cursor ()
12104{
12105 if (busy_cursor_atimer)
dfff8a69
JR
12106 {
12107 cancel_atimer (busy_cursor_atimer);
12108 busy_cursor_atimer = NULL;
12109 }
12110
f79e6790
JR
12111 if (busy_cursor_shown_p)
12112 hide_busy_cursor ();
12113}
12114
12115
12116/* Timer function of busy_cursor_atimer. TIMER is equal to
12117 busy_cursor_atimer.
12118
12119 Display a busy cursor on all frames by mapping the frames'
12120 busy_window. Set the busy_p flag in the frames' output_data.x
12121 structure to indicate that a busy cursor is shown on the
12122 frames. */
12123
12124static void
12125show_busy_cursor (timer)
12126 struct atimer *timer;
6fc2811b 12127{
767b1ff0 12128#if 0 /* TODO: cursor shape changes. */
f79e6790
JR
12129 /* The timer implementation will cancel this timer automatically
12130 after this function has run. Set busy_cursor_atimer to null
12131 so that we know the timer doesn't have to be canceled. */
12132 busy_cursor_atimer = NULL;
12133
12134 if (!busy_cursor_shown_p)
6fc2811b
JR
12135 {
12136 Lisp_Object rest, frame;
f79e6790
JR
12137
12138 BLOCK_INPUT;
12139
6fc2811b
JR
12140 FOR_EACH_FRAME (rest, frame)
12141 if (FRAME_X_P (XFRAME (frame)))
12142 {
12143 struct frame *f = XFRAME (frame);
f79e6790 12144
6fc2811b 12145 f->output_data.w32->busy_p = 1;
f79e6790 12146
6fc2811b
JR
12147 if (!f->output_data.w32->busy_window)
12148 {
12149 unsigned long mask = CWCursor;
12150 XSetWindowAttributes attrs;
f79e6790 12151
6fc2811b 12152 attrs.cursor = f->output_data.w32->busy_cursor;
f79e6790 12153
6fc2811b 12154 f->output_data.w32->busy_window
f79e6790 12155 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
12156 FRAME_OUTER_WINDOW (f),
12157 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
12158 InputOnly,
12159 CopyFromParent,
6fc2811b
JR
12160 mask, &attrs);
12161 }
f79e6790
JR
12162
12163 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
12164 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 12165 }
6fc2811b 12166
f79e6790
JR
12167 busy_cursor_shown_p = 1;
12168 UNBLOCK_INPUT;
12169 }
12170#endif
6fc2811b
JR
12171}
12172
12173
f79e6790 12174/* Hide the busy cursor on all frames, if it is currently shown. */
6fc2811b 12175
f79e6790
JR
12176static void
12177hide_busy_cursor ()
12178{
767b1ff0 12179#if 0 /* TODO: cursor shape changes. */
f79e6790 12180 if (busy_cursor_shown_p)
6fc2811b 12181 {
f79e6790
JR
12182 Lisp_Object rest, frame;
12183
12184 BLOCK_INPUT;
12185 FOR_EACH_FRAME (rest, frame)
6fc2811b 12186 {
f79e6790
JR
12187 struct frame *f = XFRAME (frame);
12188
12189 if (FRAME_X_P (f)
12190 /* Watch out for newly created frames. */
12191 && f->output_data.x->busy_window)
12192 {
12193 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
12194 /* Sync here because XTread_socket looks at the busy_p flag
12195 that is reset to zero below. */
12196 XSync (FRAME_X_DISPLAY (f), False);
12197 f->output_data.x->busy_p = 0;
12198 }
6fc2811b 12199 }
6fc2811b 12200
f79e6790
JR
12201 busy_cursor_shown_p = 0;
12202 UNBLOCK_INPUT;
12203 }
12204#endif
6fc2811b
JR
12205}
12206
12207
12208\f
12209/***********************************************************************
12210 Tool tips
12211 ***********************************************************************/
12212
12213static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
12214 Lisp_Object));
12215
12216/* The frame of a currently visible tooltip, or null. */
12217
937e601e 12218Lisp_Object tip_frame;
6fc2811b
JR
12219
12220/* If non-nil, a timer started that hides the last tooltip when it
12221 fires. */
12222
12223Lisp_Object tip_timer;
12224Window tip_window;
12225
937e601e
AI
12226static Lisp_Object
12227unwind_create_tip_frame (frame)
12228 Lisp_Object frame;
12229{
12230 tip_window = NULL;
12231 tip_frame = Qnil;
12232 return unwind_create_frame (frame);
12233}
12234
12235
6fc2811b 12236/* Create a frame for a tooltip on the display described by DPYINFO.
937e601e
AI
12237 PARMS is a list of frame parameters. Value is the frame.
12238
12239 Note that functions called here, esp. x_default_parameter can
12240 signal errors, for instance when a specified color name is
12241 undefined. We have to make sure that we're in a consistent state
12242 when this happens. */
6fc2811b
JR
12243
12244static Lisp_Object
12245x_create_tip_frame (dpyinfo, parms)
12246 struct w32_display_info *dpyinfo;
12247 Lisp_Object parms;
12248{
767b1ff0 12249#if 0 /* TODO : w32 version */
6fc2811b
JR
12250 struct frame *f;
12251 Lisp_Object frame, tem;
12252 Lisp_Object name;
12253 long window_prompting = 0;
12254 int width, height;
12255 int count = specpdl_ptr - specpdl;
12256 struct gcpro gcpro1, gcpro2, gcpro3;
12257 struct kboard *kb;
12258
12259 check_x ();
12260
12261 /* Use this general default value to start with until we know if
12262 this frame has a specified name. */
12263 Vx_resource_name = Vinvocation_name;
12264
12265#ifdef MULTI_KBOARD
12266 kb = dpyinfo->kboard;
12267#else
12268 kb = &the_only_kboard;
12269#endif
12270
12271 /* Get the name of the frame to use for resource lookup. */
12272 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
12273 if (!STRINGP (name)
12274 && !EQ (name, Qunbound)
12275 && !NILP (name))
12276 error ("Invalid frame name--not a string or nil");
12277 Vx_resource_name = name;
12278
12279 frame = Qnil;
12280 GCPRO3 (parms, name, frame);
937e601e 12281 f = make_frame (1);
6fc2811b
JR
12282 XSETFRAME (frame, f);
12283 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 12284 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 12285
d88c567c 12286 f->output_method = output_w32;
6fc2811b
JR
12287 f->output_data.w32 =
12288 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12289 bzero (f->output_data.w32, sizeof (struct w32_output));
12290#if 0
12291 f->output_data.w32->icon_bitmap = -1;
12292#endif
12293 f->output_data.w32->fontset = -1;
12294 f->icon_name = Qnil;
12295
937e601e
AI
12296#ifdef GLYPH_DEBUG
12297 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
12298 dpyinfo_refcount = dpyinfo->reference_count;
12299#endif /* GLYPH_DEBUG */
6fc2811b
JR
12300#ifdef MULTI_KBOARD
12301 FRAME_KBOARD (f) = kb;
12302#endif
12303 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12304 f->output_data.w32->explicit_parent = 0;
12305
12306 /* Set the name; the functions to which we pass f expect the name to
12307 be set. */
12308 if (EQ (name, Qunbound) || NILP (name))
12309 {
12310 f->name = build_string (dpyinfo->x_id_name);
12311 f->explicit_name = 0;
12312 }
12313 else
12314 {
12315 f->name = name;
12316 f->explicit_name = 1;
12317 /* use the frame's title when getting resources for this frame. */
12318 specbind (Qx_resource_name, name);
12319 }
12320
6fc2811b
JR
12321 /* Extract the window parameters from the supplied values
12322 that are needed to determine window geometry. */
12323 {
12324 Lisp_Object font;
12325
12326 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12327
12328 BLOCK_INPUT;
12329 /* First, try whatever font the caller has specified. */
12330 if (STRINGP (font))
12331 {
12332 tem = Fquery_fontset (font, Qnil);
12333 if (STRINGP (tem))
12334 font = x_new_fontset (f, XSTRING (tem)->data);
12335 else
12336 font = x_new_font (f, XSTRING (font)->data);
12337 }
12338
12339 /* Try out a font which we hope has bold and italic variations. */
12340 if (!STRINGP (font))
e39649be 12341 font = x_new_font (f, "-*-courier new-normal-r-*-*-*-100-*-*-*-*-iso8859-1");
6fc2811b
JR
12342 if (!STRINGP (font))
12343 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12344 if (! STRINGP (font))
12345 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12346 if (! STRINGP (font))
12347 /* This was formerly the first thing tried, but it finds too many fonts
12348 and takes too long. */
12349 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12350 /* If those didn't work, look for something which will at least work. */
12351 if (! STRINGP (font))
12352 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12353 UNBLOCK_INPUT;
12354 if (! STRINGP (font))
12355 font = build_string ("fixed");
12356
12357 x_default_parameter (f, parms, Qfont, font,
12358 "font", "Font", RES_TYPE_STRING);
12359 }
12360
12361 x_default_parameter (f, parms, Qborder_width, make_number (2),
12362 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12363
12364 /* This defaults to 2 in order to match xterm. We recognize either
12365 internalBorderWidth or internalBorder (which is what xterm calls
12366 it). */
12367 if (NILP (Fassq (Qinternal_border_width, parms)))
12368 {
12369 Lisp_Object value;
12370
12371 value = w32_get_arg (parms, Qinternal_border_width,
12372 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12373 if (! EQ (value, Qunbound))
12374 parms = Fcons (Fcons (Qinternal_border_width, value),
12375 parms);
12376 }
12377
12378 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12379 "internalBorderWidth", "internalBorderWidth",
12380 RES_TYPE_NUMBER);
12381
12382 /* Also do the stuff which must be set before the window exists. */
12383 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12384 "foreground", "Foreground", RES_TYPE_STRING);
12385 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12386 "background", "Background", RES_TYPE_STRING);
12387 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12388 "pointerColor", "Foreground", RES_TYPE_STRING);
12389 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12390 "cursorColor", "Foreground", RES_TYPE_STRING);
12391 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12392 "borderColor", "BorderColor", RES_TYPE_STRING);
12393
12394 /* Init faces before x_default_parameter is called for scroll-bar
12395 parameters because that function calls x_set_scroll_bar_width,
12396 which calls change_frame_size, which calls Fset_window_buffer,
12397 which runs hooks, which call Fvertical_motion. At the end, we
12398 end up in init_iterator with a null face cache, which should not
12399 happen. */
12400 init_frame_faces (f);
12401
12402 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12403 window_prompting = x_figure_window_size (f, parms);
12404
12405 if (window_prompting & XNegative)
12406 {
12407 if (window_prompting & YNegative)
12408 f->output_data.w32->win_gravity = SouthEastGravity;
12409 else
12410 f->output_data.w32->win_gravity = NorthEastGravity;
12411 }
12412 else
12413 {
12414 if (window_prompting & YNegative)
12415 f->output_data.w32->win_gravity = SouthWestGravity;
12416 else
12417 f->output_data.w32->win_gravity = NorthWestGravity;
12418 }
12419
12420 f->output_data.w32->size_hint_flags = window_prompting;
12421 {
12422 XSetWindowAttributes attrs;
12423 unsigned long mask;
12424
12425 BLOCK_INPUT;
12426 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12427 /* Window managers looks at the override-redirect flag to
12428 determine whether or net to give windows a decoration (Xlib
12429 3.2.8). */
12430 attrs.override_redirect = True;
12431 attrs.save_under = True;
12432 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12433 /* Arrange for getting MapNotify and UnmapNotify events. */
12434 attrs.event_mask = StructureNotifyMask;
12435 tip_window
12436 = FRAME_W32_WINDOW (f)
12437 = XCreateWindow (FRAME_W32_DISPLAY (f),
12438 FRAME_W32_DISPLAY_INFO (f)->root_window,
12439 /* x, y, width, height */
12440 0, 0, 1, 1,
12441 /* Border. */
12442 1,
12443 CopyFromParent, InputOutput, CopyFromParent,
12444 mask, &attrs);
12445 UNBLOCK_INPUT;
12446 }
12447
12448 x_make_gc (f);
12449
12450 x_default_parameter (f, parms, Qauto_raise, Qnil,
12451 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12452 x_default_parameter (f, parms, Qauto_lower, Qnil,
12453 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12454 x_default_parameter (f, parms, Qcursor_type, Qbox,
12455 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12456
12457 /* Dimensions, especially f->height, must be done via change_frame_size.
12458 Change will not be effected unless different from the current
12459 f->height. */
12460 width = f->width;
12461 height = f->height;
12462 f->height = 0;
12463 SET_FRAME_WIDTH (f, 0);
12464 change_frame_size (f, height, width, 1, 0, 0);
12465
12466 f->no_split = 1;
12467
12468 UNGCPRO;
12469
12470 /* It is now ok to make the frame official even if we get an error
12471 below. And the frame needs to be on Vframe_list or making it
12472 visible won't work. */
12473 Vframe_list = Fcons (frame, Vframe_list);
937e601e 12474 tip_frame = frame;
6fc2811b
JR
12475
12476 /* Now that the frame is official, it counts as a reference to
12477 its display. */
12478 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 12479
6fc2811b 12480 return unbind_to (count, frame);
767b1ff0 12481#endif /* TODO */
6fc2811b 12482 return Qnil;
ee78dc32
GV
12483}
12484
767b1ff0 12485#ifdef TODO /* Tooltip support not complete. */
71eab8d1 12486DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
6fc2811b 12487 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
71eab8d1
AI
12488A tooltip window is a small X window displaying a string.\n\
12489\n\
6fc2811b 12490FRAME nil or omitted means use the selected frame.\n\
71eab8d1 12491\n\
6fc2811b
JR
12492PARMS is an optional list of frame parameters which can be\n\
12493used to change the tooltip's appearance.\n\
71eab8d1 12494\n\
6fc2811b 12495Automatically hide the tooltip after TIMEOUT seconds.\n\
71eab8d1
AI
12496TIMEOUT nil means use the default timeout of 5 seconds.\n\
12497\n\
12498If the list of frame parameters PARAMS contains a `left' parameters,\n\
12499the tooltip is displayed at that x-position. Otherwise it is\n\
12500displayed at the mouse position, with offset DX added (default is 5 if\n\
12501DX isn't specified). Likewise for the y-position; if a `top' frame\n\
12502parameter is specified, it determines the y-position of the tooltip\n\
12503window, otherwise it is displayed at the mouse position, with offset\n\
12504DY added (default is -5).")
12505 (string, frame, parms, timeout, dx, dy)
12506 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 12507{
6fc2811b
JR
12508 struct frame *f;
12509 struct window *w;
12510 Window root, child;
71eab8d1 12511 Lisp_Object buffer, top, left;
6fc2811b
JR
12512 struct buffer *old_buffer;
12513 struct text_pos pos;
12514 int i, width, height;
12515 int root_x, root_y, win_x, win_y;
12516 unsigned pmask;
12517 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12518 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12519 int count = specpdl_ptr - specpdl;
12520
12521 specbind (Qinhibit_redisplay, Qt);
ee78dc32 12522
dfff8a69 12523 GCPRO4 (string, parms, frame, timeout);
ee78dc32 12524
6fc2811b
JR
12525 CHECK_STRING (string, 0);
12526 f = check_x_frame (frame);
12527 if (NILP (timeout))
12528 timeout = make_number (5);
12529 else
12530 CHECK_NATNUM (timeout, 2);
ee78dc32 12531
71eab8d1
AI
12532 if (NILP (dx))
12533 dx = make_number (5);
12534 else
12535 CHECK_NUMBER (dx, 5);
12536
12537 if (NILP (dy))
12538 dy = make_number (-5);
12539 else
12540 CHECK_NUMBER (dy, 6);
12541
6fc2811b
JR
12542 /* Hide a previous tip, if any. */
12543 Fx_hide_tip ();
ee78dc32 12544
6fc2811b
JR
12545 /* Add default values to frame parameters. */
12546 if (NILP (Fassq (Qname, parms)))
12547 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12548 if (NILP (Fassq (Qinternal_border_width, parms)))
12549 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12550 if (NILP (Fassq (Qborder_width, parms)))
12551 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12552 if (NILP (Fassq (Qborder_color, parms)))
12553 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12554 if (NILP (Fassq (Qbackground_color, parms)))
12555 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12556 parms);
12557
12558 /* Create a frame for the tooltip, and record it in the global
12559 variable tip_frame. */
12560 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
937e601e 12561 f = XFRAME (frame);
6fc2811b
JR
12562
12563 /* Set up the frame's root window. Currently we use a size of 80
12564 columns x 40 lines. If someone wants to show a larger tip, he
12565 will loose. I don't think this is a realistic case. */
12566 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12567 w->left = w->top = make_number (0);
12568 w->width = 80;
12569 w->height = 40;
12570 adjust_glyphs (f);
12571 w->pseudo_window_p = 1;
12572
12573 /* Display the tooltip text in a temporary buffer. */
12574 buffer = Fget_buffer_create (build_string (" *tip*"));
12575 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12576 old_buffer = current_buffer;
12577 set_buffer_internal_1 (XBUFFER (buffer));
12578 Ferase_buffer ();
12579 Finsert (make_number (1), &string);
12580 clear_glyph_matrix (w->desired_matrix);
12581 clear_glyph_matrix (w->current_matrix);
12582 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12583 try_window (FRAME_ROOT_WINDOW (f), pos);
12584
12585 /* Compute width and height of the tooltip. */
12586 width = height = 0;
12587 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 12588 {
6fc2811b
JR
12589 struct glyph_row *row = &w->desired_matrix->rows[i];
12590 struct glyph *last;
12591 int row_width;
12592
12593 /* Stop at the first empty row at the end. */
12594 if (!row->enabled_p || !row->displays_text_p)
12595 break;
12596
12597 /* Let the row go over the full width of the frame. */
12598 row->full_width_p = 1;
12599
12600 /* There's a glyph at the end of rows that is use to place
12601 the cursor there. Don't include the width of this glyph. */
12602 if (row->used[TEXT_AREA])
12603 {
12604 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12605 row_width = row->pixel_width - last->pixel_width;
12606 }
12607 else
12608 row_width = row->pixel_width;
12609
12610 height += row->height;
12611 width = max (width, row_width);
ee78dc32
GV
12612 }
12613
6fc2811b
JR
12614 /* Add the frame's internal border to the width and height the X
12615 window should have. */
12616 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12617 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 12618
71eab8d1
AI
12619 /* User-specified position? */
12620 left = Fcdr (Fassq (Qleft, parms));
12621 top = Fcdr (Fassq (Qtop, parms));
12622
6fc2811b
JR
12623 /* Move the tooltip window where the mouse pointer is. Resize and
12624 show it. */
767b1ff0 12625#if 0 /* TODO : W32 specifics */
6fc2811b 12626 BLOCK_INPUT;
71eab8d1 12627 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
6fc2811b 12628 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
71eab8d1
AI
12629 UNBLOCK_INPUT;
12630
12631 root_x += XINT (dx);
12632 root_y += XINT (dy);
12633
12634 if (INTEGERP (left))
12635 root_x = XINT (left);
12636 if (INTEGERP (top))
12637 root_y = XINT (top);
12638
12639 BLOCK_INPUT;
12640 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12641 root_x, root_y - height, width, height);
12642 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
6fc2811b 12643 UNBLOCK_INPUT;
767b1ff0 12644#endif /* TODO */
ee78dc32 12645
6fc2811b
JR
12646 /* Draw into the window. */
12647 w->must_be_updated_p = 1;
12648 update_single_window (w, 1);
ee78dc32 12649
6fc2811b
JR
12650 /* Restore original current buffer. */
12651 set_buffer_internal_1 (old_buffer);
12652 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 12653
6fc2811b
JR
12654 /* Let the tip disappear after timeout seconds. */
12655 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12656 intern ("x-hide-tip"));
ee78dc32 12657
dfff8a69 12658 UNGCPRO;
6fc2811b 12659 return unbind_to (count, Qnil);
ee78dc32
GV
12660}
12661
ee78dc32 12662
6fc2811b
JR
12663DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12664 "Hide the current tooltip window, if there is any.\n\
12665Value is t is tooltip was open, nil otherwise.")
12666 ()
12667{
937e601e
AI
12668 int count;
12669 Lisp_Object deleted, frame, timer;
12670 struct gcpro gcpro1, gcpro2;
12671
12672 /* Return quickly if nothing to do. */
12673 if (NILP (tip_timer) && NILP (tip_frame))
12674 return Qnil;
12675
12676 frame = tip_frame;
12677 timer = tip_timer;
12678 GCPRO2 (frame, timer);
12679 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 12680
937e601e 12681 count = BINDING_STACK_SIZE ();
6fc2811b 12682 specbind (Qinhibit_redisplay, Qt);
937e601e 12683 specbind (Qinhibit_quit, Qt);
6fc2811b 12684
937e601e
AI
12685 if (!NILP (timer))
12686 call1 (intern ("cancel-timer"), timer);
ee78dc32 12687
937e601e 12688 if (FRAMEP (frame))
6fc2811b 12689 {
937e601e
AI
12690 Fdelete_frame (frame, Qnil);
12691 deleted = Qt;
6fc2811b 12692 }
1edf84e7 12693
937e601e
AI
12694 UNGCPRO;
12695 return unbind_to (count, deleted);
6fc2811b 12696}
767b1ff0 12697#endif
5ac45f98 12698
5ac45f98 12699
6fc2811b
JR
12700\f
12701/***********************************************************************
12702 File selection dialog
12703 ***********************************************************************/
12704
12705extern Lisp_Object Qfile_name_history;
12706
12707DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12708 "Read file name, prompting with PROMPT in directory DIR.\n\
12709Use a file selection dialog.\n\
12710Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12711specified. Don't let the user enter a file name in the file\n\
12712selection dialog's entry field, if MUSTMATCH is non-nil.")
12713 (prompt, dir, default_filename, mustmatch)
12714 Lisp_Object prompt, dir, default_filename, mustmatch;
12715{
12716 struct frame *f = SELECTED_FRAME ();
12717 Lisp_Object file = Qnil;
12718 int count = specpdl_ptr - specpdl;
12719 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12720 char filename[MAX_PATH + 1];
12721 char init_dir[MAX_PATH + 1];
12722 int use_dialog_p = 1;
12723
12724 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12725 CHECK_STRING (prompt, 0);
12726 CHECK_STRING (dir, 1);
12727
12728 /* Create the dialog with PROMPT as title, using DIR as initial
12729 directory and using "*" as pattern. */
12730 dir = Fexpand_file_name (dir, Qnil);
12731 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12732 init_dir[MAX_PATH] = '\0';
12733 unixtodos_filename (init_dir);
12734
12735 if (STRINGP (default_filename))
12736 {
12737 char *file_name_only;
12738 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 12739
6fc2811b 12740 unixtodos_filename (full_path_name);
5ac45f98 12741
6fc2811b
JR
12742 file_name_only = strrchr (full_path_name, '\\');
12743 if (!file_name_only)
12744 file_name_only = full_path_name;
12745 else
12746 {
12747 file_name_only++;
5ac45f98 12748
6fc2811b
JR
12749 /* If default_file_name is a directory, don't use the open
12750 file dialog, as it does not support selecting
12751 directories. */
12752 if (!(*file_name_only))
12753 use_dialog_p = 0;
12754 }
ee78dc32 12755
6fc2811b
JR
12756 strncpy (filename, file_name_only, MAX_PATH);
12757 filename[MAX_PATH] = '\0';
12758 }
ee78dc32 12759 else
6fc2811b 12760 filename[0] = '\0';
ee78dc32 12761
6fc2811b
JR
12762 if (use_dialog_p)
12763 {
12764 OPENFILENAME file_details;
12765 char *filename_file;
5ac45f98 12766
6fc2811b
JR
12767 /* Prevent redisplay. */
12768 specbind (Qinhibit_redisplay, Qt);
12769 BLOCK_INPUT;
ee78dc32 12770
6fc2811b
JR
12771 bzero (&file_details, sizeof (file_details));
12772 file_details.lStructSize = sizeof (file_details);
12773 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12774 file_details.lpstrFile = filename;
12775 file_details.nMaxFile = sizeof (filename);
12776 file_details.lpstrInitialDir = init_dir;
12777 file_details.lpstrTitle = XSTRING (prompt)->data;
12778 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 12779
6fc2811b
JR
12780 if (!NILP (mustmatch))
12781 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 12782
6fc2811b
JR
12783 if (GetOpenFileName (&file_details))
12784 {
12785 dostounix_filename (filename);
12786 file = build_string (filename);
12787 }
ee78dc32 12788 else
6fc2811b
JR
12789 file = Qnil;
12790
12791 UNBLOCK_INPUT;
12792 file = unbind_to (count, file);
ee78dc32 12793 }
6fc2811b
JR
12794 /* Open File dialog will not allow folders to be selected, so resort
12795 to minibuffer completing reads for directories. */
12796 else
12797 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12798 dir, mustmatch, dir, Qfile_name_history,
12799 default_filename, Qnil);
ee78dc32 12800
6fc2811b 12801 UNGCPRO;
1edf84e7 12802
6fc2811b
JR
12803 /* Make "Cancel" equivalent to C-g. */
12804 if (NILP (file))
12805 Fsignal (Qquit, Qnil);
ee78dc32 12806
dfff8a69 12807 return unbind_to (count, file);
6fc2811b 12808}
ee78dc32 12809
ee78dc32 12810
6fc2811b
JR
12811\f
12812/***********************************************************************
12813 Tests
12814 ***********************************************************************/
ee78dc32 12815
6fc2811b 12816#if GLYPH_DEBUG
ee78dc32 12817
6fc2811b
JR
12818DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12819 "Value is non-nil if SPEC is a valid image specification.")
12820 (spec)
12821 Lisp_Object spec;
12822{
12823 return valid_image_p (spec) ? Qt : Qnil;
ee78dc32
GV
12824}
12825
ee78dc32 12826
6fc2811b
JR
12827DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12828 (spec)
12829 Lisp_Object spec;
12830{
12831 int id = -1;
12832
12833 if (valid_image_p (spec))
12834 id = lookup_image (SELECTED_FRAME (), spec);
ee78dc32 12835
6fc2811b
JR
12836 debug_print (spec);
12837 return make_number (id);
ee78dc32
GV
12838}
12839
6fc2811b 12840#endif /* GLYPH_DEBUG != 0 */
ee78dc32 12841
ee78dc32
GV
12842
12843\f
6fc2811b
JR
12844/***********************************************************************
12845 w32 specialized functions
12846 ***********************************************************************/
ee78dc32 12847
fbd6baed
GV
12848DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12849 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
ee78dc32
GV
12850 (frame)
12851 Lisp_Object frame;
12852{
12853 FRAME_PTR f = check_x_frame (frame);
12854 CHOOSEFONT cf;
12855 LOGFONT lf;
f46e6225
GV
12856 TEXTMETRIC tm;
12857 HDC hdc;
12858 HANDLE oldobj;
ee78dc32
GV
12859 char buf[100];
12860
12861 bzero (&cf, sizeof (cf));
f46e6225 12862 bzero (&lf, sizeof (lf));
ee78dc32
GV
12863
12864 cf.lStructSize = sizeof (cf);
fbd6baed 12865 cf.hwndOwner = FRAME_W32_WINDOW (f);
6fc2811b 12866 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
ee78dc32
GV
12867 cf.lpLogFont = &lf;
12868
f46e6225
GV
12869 /* Initialize as much of the font details as we can from the current
12870 default font. */
12871 hdc = GetDC (FRAME_W32_WINDOW (f));
12872 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12873 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12874 if (GetTextMetrics (hdc, &tm))
12875 {
12876 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12877 lf.lfWeight = tm.tmWeight;
12878 lf.lfItalic = tm.tmItalic;
12879 lf.lfUnderline = tm.tmUnderlined;
12880 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
12881 lf.lfCharSet = tm.tmCharSet;
12882 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12883 }
12884 SelectObject (hdc, oldobj);
6fc2811b 12885 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 12886
767b1ff0 12887 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 12888 return Qnil;
ee78dc32
GV
12889
12890 return build_string (buf);
12891}
12892
1edf84e7
GV
12893DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
12894 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
12895Some useful values for command are 0xf030 to maximise frame (0xf020\n\
12896to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
12897to activate the menubar for keyboard access. 0xf140 activates the\n\
12898screen saver if defined.\n\
12899\n\
12900If optional parameter FRAME is not specified, use selected frame.")
12901 (command, frame)
12902 Lisp_Object command, frame;
12903{
12904 WPARAM code;
12905 FRAME_PTR f = check_x_frame (frame);
12906
12907 CHECK_NUMBER (command, 0);
12908
ce6059da 12909 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
12910
12911 return Qnil;
12912}
12913
55dcfc15
AI
12914DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
12915 "Get Windows to perform OPERATION on DOCUMENT.\n\
12916This is a wrapper around the ShellExecute system function, which\n\
12917invokes the application registered to handle OPERATION for DOCUMENT.\n\
6fc2811b
JR
12918OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
12919nil for the default action), and DOCUMENT is typically the name of a\n\
12920document file or URL, but can also be a program executable to run or\n\
12921a directory to open in the Windows Explorer.\n\
55dcfc15 12922\n\
6fc2811b
JR
12923If DOCUMENT is a program executable, PARAMETERS can be a string\n\
12924containing command line parameters, but otherwise should be nil.\n\
55dcfc15
AI
12925\n\
12926SHOW-FLAG can be used to control whether the invoked application is hidden\n\
6fc2811b 12927or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
55dcfc15
AI
12928otherwise it is an integer representing a ShowWindow flag:\n\
12929\n\
12930 0 - start hidden\n\
12931 1 - start normally\n\
12932 3 - start maximized\n\
12933 6 - start minimized")
12934 (operation, document, parameters, show_flag)
12935 Lisp_Object operation, document, parameters, show_flag;
12936{
12937 Lisp_Object current_dir;
12938
55dcfc15
AI
12939 CHECK_STRING (document, 0);
12940
12941 /* Encode filename and current directory. */
12942 current_dir = ENCODE_FILE (current_buffer->directory);
12943 document = ENCODE_FILE (document);
12944 if ((int) ShellExecute (NULL,
6fc2811b
JR
12945 (STRINGP (operation) ?
12946 XSTRING (operation)->data : NULL),
55dcfc15
AI
12947 XSTRING (document)->data,
12948 (STRINGP (parameters) ?
12949 XSTRING (parameters)->data : NULL),
12950 XSTRING (current_dir)->data,
12951 (INTEGERP (show_flag) ?
12952 XINT (show_flag) : SW_SHOWDEFAULT))
12953 > 32)
12954 return Qt;
12955 error ("ShellExecute failed");
12956}
12957
ccc2d29c
GV
12958/* Lookup virtual keycode from string representing the name of a
12959 non-ascii keystroke into the corresponding virtual key, using
12960 lispy_function_keys. */
12961static int
12962lookup_vk_code (char *key)
12963{
12964 int i;
12965
12966 for (i = 0; i < 256; i++)
12967 if (lispy_function_keys[i] != 0
12968 && strcmp (lispy_function_keys[i], key) == 0)
12969 return i;
12970
12971 return -1;
12972}
12973
12974/* Convert a one-element vector style key sequence to a hot key
12975 definition. */
12976static int
12977w32_parse_hot_key (key)
12978 Lisp_Object key;
12979{
12980 /* Copied from Fdefine_key and store_in_keymap. */
12981 register Lisp_Object c;
12982 int vk_code;
12983 int lisp_modifiers;
12984 int w32_modifiers;
12985 struct gcpro gcpro1;
12986
12987 CHECK_VECTOR (key, 0);
12988
12989 if (XFASTINT (Flength (key)) != 1)
12990 return Qnil;
12991
12992 GCPRO1 (key);
12993
12994 c = Faref (key, make_number (0));
12995
12996 if (CONSP (c) && lucid_event_type_list_p (c))
12997 c = Fevent_convert_list (c);
12998
12999 UNGCPRO;
13000
13001 if (! INTEGERP (c) && ! SYMBOLP (c))
13002 error ("Key definition is invalid");
13003
13004 /* Work out the base key and the modifiers. */
13005 if (SYMBOLP (c))
13006 {
13007 c = parse_modifiers (c);
13008 lisp_modifiers = Fcar (Fcdr (c));
13009 c = Fcar (c);
13010 if (!SYMBOLP (c))
13011 abort ();
13012 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
13013 }
13014 else if (INTEGERP (c))
13015 {
13016 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13017 /* Many ascii characters are their own virtual key code. */
13018 vk_code = XINT (c) & CHARACTERBITS;
13019 }
13020
13021 if (vk_code < 0 || vk_code > 255)
13022 return Qnil;
13023
13024 if ((lisp_modifiers & meta_modifier) != 0
13025 && !NILP (Vw32_alt_is_meta))
13026 lisp_modifiers |= alt_modifier;
13027
71eab8d1
AI
13028 /* Supply defs missing from mingw32. */
13029#ifndef MOD_ALT
13030#define MOD_ALT 0x0001
13031#define MOD_CONTROL 0x0002
13032#define MOD_SHIFT 0x0004
13033#define MOD_WIN 0x0008
13034#endif
13035
ccc2d29c
GV
13036 /* Convert lisp modifiers to Windows hot-key form. */
13037 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
13038 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
13039 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
13040 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
13041
13042 return HOTKEY (vk_code, w32_modifiers);
13043}
13044
13045DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
13046 "Register KEY as a hot-key combination.\n\
13047Certain key combinations like Alt-Tab are reserved for system use on\n\
13048Windows, and therefore are normally intercepted by the system. However,\n\
13049most of these key combinations can be received by registering them as\n\
13050hot-keys, overriding their special meaning.\n\
13051\n\
13052KEY must be a one element key definition in vector form that would be\n\
13053acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
13054modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
13055is always interpreted as the Windows modifier keys.\n\
13056\n\
13057The return value is the hotkey-id if registered, otherwise nil.")
13058 (key)
13059 Lisp_Object key;
13060{
13061 key = w32_parse_hot_key (key);
13062
13063 if (NILP (Fmemq (key, w32_grabbed_keys)))
13064 {
13065 /* Reuse an empty slot if possible. */
13066 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
13067
13068 /* Safe to add new key to list, even if we have focus. */
13069 if (NILP (item))
13070 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
13071 else
13072 XCAR (item) = key;
13073
13074 /* Notify input thread about new hot-key definition, so that it
13075 takes effect without needing to switch focus. */
13076 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
13077 (WPARAM) key, 0);
13078 }
13079
13080 return key;
13081}
13082
13083DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
13084 "Unregister HOTKEY as a hot-key combination.")
13085 (key)
13086 Lisp_Object key;
13087{
13088 Lisp_Object item;
13089
13090 if (!INTEGERP (key))
13091 key = w32_parse_hot_key (key);
13092
13093 item = Fmemq (key, w32_grabbed_keys);
13094
13095 if (!NILP (item))
13096 {
13097 /* Notify input thread about hot-key definition being removed, so
13098 that it takes effect without needing focus switch. */
13099 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
13100 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
13101 {
13102 MSG msg;
13103 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13104 }
13105 return Qt;
13106 }
13107 return Qnil;
13108}
13109
13110DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
13111 "Return list of registered hot-key IDs.")
13112 ()
13113{
13114 return Fcopy_sequence (w32_grabbed_keys);
13115}
13116
13117DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
13118 "Convert hot-key ID to a lisp key combination.")
13119 (hotkeyid)
13120 Lisp_Object hotkeyid;
13121{
13122 int vk_code, w32_modifiers;
13123 Lisp_Object key;
13124
13125 CHECK_NUMBER (hotkeyid, 0);
13126
13127 vk_code = HOTKEY_VK_CODE (hotkeyid);
13128 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
13129
13130 if (lispy_function_keys[vk_code])
13131 key = intern (lispy_function_keys[vk_code]);
13132 else
13133 key = make_number (vk_code);
13134
13135 key = Fcons (key, Qnil);
13136 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 13137 key = Fcons (Qshift, key);
ccc2d29c 13138 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 13139 key = Fcons (Qctrl, key);
ccc2d29c 13140 if (w32_modifiers & MOD_ALT)
3ef68e6b 13141 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 13142 if (w32_modifiers & MOD_WIN)
3ef68e6b 13143 key = Fcons (Qhyper, key);
ccc2d29c
GV
13144
13145 return key;
13146}
adcc3809
GV
13147
13148DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
13149 "Toggle the state of the lock key KEY.\n\
13150KEY can be `capslock', `kp-numlock', or `scroll'.\n\
13151If the optional parameter NEW-STATE is a number, then the state of KEY\n\
13152is set to off if the low bit of NEW-STATE is zero, otherwise on.")
13153 (key, new_state)
13154 Lisp_Object key, new_state;
13155{
13156 int vk_code;
13157 int cur_state;
13158
13159 if (EQ (key, intern ("capslock")))
13160 vk_code = VK_CAPITAL;
13161 else if (EQ (key, intern ("kp-numlock")))
13162 vk_code = VK_NUMLOCK;
13163 else if (EQ (key, intern ("scroll")))
13164 vk_code = VK_SCROLL;
13165 else
13166 return Qnil;
13167
13168 if (!dwWindowsThreadId)
13169 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
13170
13171 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
13172 (WPARAM) vk_code, (LPARAM) new_state))
13173 {
13174 MSG msg;
13175 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13176 return make_number (msg.wParam);
13177 }
13178 return Qnil;
13179}
ee78dc32 13180\f
fbd6baed 13181syms_of_w32fns ()
ee78dc32 13182{
1edf84e7
GV
13183 /* This is zero if not using MS-Windows. */
13184 w32_in_use = 0;
13185
ee78dc32
GV
13186 /* The section below is built by the lisp expression at the top of the file,
13187 just above where these variables are declared. */
13188 /*&&& init symbols here &&&*/
13189 Qauto_raise = intern ("auto-raise");
13190 staticpro (&Qauto_raise);
13191 Qauto_lower = intern ("auto-lower");
13192 staticpro (&Qauto_lower);
ee78dc32
GV
13193 Qbar = intern ("bar");
13194 staticpro (&Qbar);
13195 Qborder_color = intern ("border-color");
13196 staticpro (&Qborder_color);
13197 Qborder_width = intern ("border-width");
13198 staticpro (&Qborder_width);
13199 Qbox = intern ("box");
13200 staticpro (&Qbox);
13201 Qcursor_color = intern ("cursor-color");
13202 staticpro (&Qcursor_color);
13203 Qcursor_type = intern ("cursor-type");
13204 staticpro (&Qcursor_type);
ee78dc32
GV
13205 Qgeometry = intern ("geometry");
13206 staticpro (&Qgeometry);
13207 Qicon_left = intern ("icon-left");
13208 staticpro (&Qicon_left);
13209 Qicon_top = intern ("icon-top");
13210 staticpro (&Qicon_top);
13211 Qicon_type = intern ("icon-type");
13212 staticpro (&Qicon_type);
13213 Qicon_name = intern ("icon-name");
13214 staticpro (&Qicon_name);
13215 Qinternal_border_width = intern ("internal-border-width");
13216 staticpro (&Qinternal_border_width);
13217 Qleft = intern ("left");
13218 staticpro (&Qleft);
1026b400
RS
13219 Qright = intern ("right");
13220 staticpro (&Qright);
ee78dc32
GV
13221 Qmouse_color = intern ("mouse-color");
13222 staticpro (&Qmouse_color);
13223 Qnone = intern ("none");
13224 staticpro (&Qnone);
13225 Qparent_id = intern ("parent-id");
13226 staticpro (&Qparent_id);
13227 Qscroll_bar_width = intern ("scroll-bar-width");
13228 staticpro (&Qscroll_bar_width);
13229 Qsuppress_icon = intern ("suppress-icon");
13230 staticpro (&Qsuppress_icon);
ee78dc32
GV
13231 Qundefined_color = intern ("undefined-color");
13232 staticpro (&Qundefined_color);
13233 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
13234 staticpro (&Qvertical_scroll_bars);
13235 Qvisibility = intern ("visibility");
13236 staticpro (&Qvisibility);
13237 Qwindow_id = intern ("window-id");
13238 staticpro (&Qwindow_id);
13239 Qx_frame_parameter = intern ("x-frame-parameter");
13240 staticpro (&Qx_frame_parameter);
13241 Qx_resource_name = intern ("x-resource-name");
13242 staticpro (&Qx_resource_name);
13243 Quser_position = intern ("user-position");
13244 staticpro (&Quser_position);
13245 Quser_size = intern ("user-size");
13246 staticpro (&Quser_size);
6fc2811b
JR
13247 Qscreen_gamma = intern ("screen-gamma");
13248 staticpro (&Qscreen_gamma);
dfff8a69
JR
13249 Qline_spacing = intern ("line-spacing");
13250 staticpro (&Qline_spacing);
13251 Qcenter = intern ("center");
13252 staticpro (&Qcenter);
ee78dc32
GV
13253 /* This is the end of symbol initialization. */
13254
adcc3809
GV
13255 Qhyper = intern ("hyper");
13256 staticpro (&Qhyper);
13257 Qsuper = intern ("super");
13258 staticpro (&Qsuper);
13259 Qmeta = intern ("meta");
13260 staticpro (&Qmeta);
13261 Qalt = intern ("alt");
13262 staticpro (&Qalt);
13263 Qctrl = intern ("ctrl");
13264 staticpro (&Qctrl);
13265 Qcontrol = intern ("control");
13266 staticpro (&Qcontrol);
13267 Qshift = intern ("shift");
13268 staticpro (&Qshift);
13269
6fc2811b
JR
13270 /* Text property `display' should be nonsticky by default. */
13271 Vtext_property_default_nonsticky
13272 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
13273
13274
13275 Qlaplace = intern ("laplace");
13276 staticpro (&Qlaplace);
13277
4b817373
RS
13278 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
13279 staticpro (&Qface_set_after_frame_default);
13280
ee78dc32
GV
13281 Fput (Qundefined_color, Qerror_conditions,
13282 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
13283 Fput (Qundefined_color, Qerror_message,
13284 build_string ("Undefined color"));
13285
ccc2d29c
GV
13286 staticpro (&w32_grabbed_keys);
13287 w32_grabbed_keys = Qnil;
13288
fbd6baed 13289 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
ccc2d29c 13290 "An array of color name mappings for windows.");
fbd6baed 13291 Vw32_color_map = Qnil;
ee78dc32 13292
fbd6baed 13293 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
da36a4d6
GV
13294 "Non-nil if alt key presses are passed on to Windows.\n\
13295When non-nil, for example, alt pressed and released and then space will\n\
13296open the System menu. When nil, Emacs silently swallows alt key events.");
fbd6baed 13297 Vw32_pass_alt_to_system = Qnil;
da36a4d6 13298
fbd6baed 13299 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
8c205c63
RS
13300 "Non-nil if the alt key is to be considered the same as the meta key.\n\
13301When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
fbd6baed 13302 Vw32_alt_is_meta = Qt;
8c205c63 13303
7d081355
AI
13304 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
13305 "If non-zero, the virtual key code for an alternative quit key.");
13306 XSETINT (Vw32_quit_key, 0);
13307
ccc2d29c
GV
13308 DEFVAR_LISP ("w32-pass-lwindow-to-system",
13309 &Vw32_pass_lwindow_to_system,
13310 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
13311When non-nil, the Start menu is opened by tapping the key.");
13312 Vw32_pass_lwindow_to_system = Qt;
13313
13314 DEFVAR_LISP ("w32-pass-rwindow-to-system",
13315 &Vw32_pass_rwindow_to_system,
13316 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
13317When non-nil, the Start menu is opened by tapping the key.");
13318 Vw32_pass_rwindow_to_system = Qt;
13319
adcc3809
GV
13320 DEFVAR_INT ("w32-phantom-key-code",
13321 &Vw32_phantom_key_code,
13322 "Virtual key code used to generate \"phantom\" key presses.\n\
13323Value is a number between 0 and 255.\n\
13324\n\
13325Phantom key presses are generated in order to stop the system from\n\
13326acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
13327`w32-pass-rwindow-to-system' is nil.");
ce6059da
AI
13328 /* Although 255 is technically not a valid key code, it works and
13329 means that this hack won't interfere with any real key code. */
13330 Vw32_phantom_key_code = 255;
adcc3809 13331
ccc2d29c
GV
13332 DEFVAR_LISP ("w32-enable-num-lock",
13333 &Vw32_enable_num_lock,
13334 "Non-nil if Num Lock should act normally.\n\
13335Set to nil to see Num Lock as the key `kp-numlock'.");
13336 Vw32_enable_num_lock = Qt;
13337
13338 DEFVAR_LISP ("w32-enable-caps-lock",
13339 &Vw32_enable_caps_lock,
13340 "Non-nil if Caps Lock should act normally.\n\
13341Set to nil to see Caps Lock as the key `capslock'.");
13342 Vw32_enable_caps_lock = Qt;
13343
13344 DEFVAR_LISP ("w32-scroll-lock-modifier",
13345 &Vw32_scroll_lock_modifier,
13346 "Modifier to use for the Scroll Lock on state.\n\
13347The value can be hyper, super, meta, alt, control or shift for the\n\
13348respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
13349Any other value will cause the key to be ignored.");
13350 Vw32_scroll_lock_modifier = Qt;
13351
13352 DEFVAR_LISP ("w32-lwindow-modifier",
13353 &Vw32_lwindow_modifier,
13354 "Modifier to use for the left \"Windows\" key.\n\
13355The value can be hyper, super, meta, alt, control or shift for the\n\
13356respective modifier, or nil to appear as the key `lwindow'.\n\
13357Any other value will cause the key to be ignored.");
13358 Vw32_lwindow_modifier = Qnil;
13359
13360 DEFVAR_LISP ("w32-rwindow-modifier",
13361 &Vw32_rwindow_modifier,
13362 "Modifier to use for the right \"Windows\" key.\n\
13363The value can be hyper, super, meta, alt, control or shift for the\n\
13364respective modifier, or nil to appear as the key `rwindow'.\n\
13365Any other value will cause the key to be ignored.");
13366 Vw32_rwindow_modifier = Qnil;
13367
13368 DEFVAR_LISP ("w32-apps-modifier",
13369 &Vw32_apps_modifier,
13370 "Modifier to use for the \"Apps\" key.\n\
13371The value can be hyper, super, meta, alt, control or shift for the\n\
13372respective modifier, or nil to appear as the key `apps'.\n\
13373Any other value will cause the key to be ignored.");
13374 Vw32_apps_modifier = Qnil;
da36a4d6 13375
212da13b 13376 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
6fc2811b
JR
13377 "Non-nil enables selection of artificially italicized and bold fonts.");
13378 Vw32_enable_synthesized_fonts = Qnil;
5ac45f98 13379
fbd6baed 13380 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
6fc2811b 13381 "Non-nil enables Windows palette management to map colors exactly.");
fbd6baed 13382 Vw32_enable_palette = Qt;
5ac45f98 13383
fbd6baed
GV
13384 DEFVAR_INT ("w32-mouse-button-tolerance",
13385 &Vw32_mouse_button_tolerance,
6fc2811b 13386 "Analogue of double click interval for faking middle mouse events.\n\
5ac45f98
GV
13387The value is the minimum time in milliseconds that must elapse between\n\
13388left/right button down events before they are considered distinct events.\n\
13389If both mouse buttons are depressed within this interval, a middle mouse\n\
13390button down event is generated instead.");
fbd6baed 13391 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 13392
fbd6baed
GV
13393 DEFVAR_INT ("w32-mouse-move-interval",
13394 &Vw32_mouse_move_interval,
84fb1139
KH
13395 "Minimum interval between mouse move events.\n\
13396The value is the minimum time in milliseconds that must elapse between\n\
13397successive mouse move (or scroll bar drag) events before they are\n\
13398reported as lisp events.");
247be837 13399 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 13400
ee78dc32
GV
13401 init_x_parm_symbols ();
13402
13403 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
fbd6baed 13404 "List of directories to search for bitmap files for w32.");
ee78dc32
GV
13405 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13406
13407 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13408 "The shape of the pointer when over text.\n\
13409Changing the value does not affect existing frames\n\
13410unless you set the mouse color.");
13411 Vx_pointer_shape = Qnil;
13412
13413 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13414 "The name Emacs uses to look up resources; for internal use only.\n\
13415`x-get-resource' uses this as the first component of the instance name\n\
13416when requesting resource values.\n\
13417Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13418was invoked, or to the value specified with the `-name' or `-rn'\n\
13419switches, if present.");
13420 Vx_resource_name = Qnil;
13421
13422 Vx_nontext_pointer_shape = Qnil;
13423
13424 Vx_mode_pointer_shape = Qnil;
13425
6fc2811b
JR
13426 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
13427 "The shape of the pointer when Emacs is busy.\n\
13428This variable takes effect when you create a new frame\n\
13429or when you set the mouse color.");
13430 Vx_busy_pointer_shape = Qnil;
13431
13432 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
13433 "Non-zero means Emacs displays a busy cursor on window systems.");
13434 display_busy_cursor_p = 1;
13435
f79e6790
JR
13436 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
13437 "*Seconds to wait before displaying a busy-cursor.\n\
dfff8a69 13438Value must be an integer or float.");
f79e6790
JR
13439 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
13440
6fc2811b 13441 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32
GV
13442 &Vx_sensitive_text_pointer_shape,
13443 "The shape of the pointer when over mouse-sensitive text.\n\
13444This variable takes effect when you create a new frame\n\
13445or when you set the mouse color.");
13446 Vx_sensitive_text_pointer_shape = Qnil;
13447
4694d762
JR
13448 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
13449 &Vx_window_horizontal_drag_shape,
13450 "Pointer shape to use for indicating a window can be dragged horizontally.\n\
13451This variable takes effect when you create a new frame\n\
13452or when you set the mouse color.");
13453 Vx_window_horizontal_drag_shape = Qnil;
13454
ee78dc32
GV
13455 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13456 "A string indicating the foreground color of the cursor box.");
13457 Vx_cursor_fore_pixel = Qnil;
13458
13459 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13460 "Non-nil if no window manager is in use.\n\
13461Emacs doesn't try to figure this out; this is always nil\n\
13462unless you set it to something else.");
13463 /* We don't have any way to find this out, so set it to nil
13464 and maybe the user would like to set it to t. */
13465 Vx_no_window_manager = Qnil;
13466
4587b026
GV
13467 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13468 &Vx_pixel_size_width_font_regexp,
13469 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13470\n\
13471Since Emacs gets width of a font matching with this regexp from\n\
13472PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13473such a font. This is especially effective for such large fonts as\n\
13474Chinese, Japanese, and Korean.");
13475 Vx_pixel_size_width_font_regexp = Qnil;
13476
6fc2811b
JR
13477 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13478 "Time after which cached images are removed from the cache.\n\
13479When an image has not been displayed this many seconds, remove it\n\
13480from the image cache. Value must be an integer or nil with nil\n\
13481meaning don't clear the cache.");
13482 Vimage_cache_eviction_delay = make_number (30 * 60);
13483
33d52f9c
GV
13484 DEFVAR_LISP ("w32-bdf-filename-alist",
13485 &Vw32_bdf_filename_alist,
13486 "List of bdf fonts and their corresponding filenames.");
13487 Vw32_bdf_filename_alist = Qnil;
13488
1075afa9
GV
13489 DEFVAR_BOOL ("w32-strict-fontnames",
13490 &w32_strict_fontnames,
13491 "Non-nil means only use fonts that are exact matches for those requested.\n\
13492Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13493and allows third-party CJK display to work by specifying false charset\n\
13494fields to trick Emacs into translating to Big5, SJIS etc.\n\
13495Setting this to t will prevent wrong fonts being selected when\n\
13496fontsets are automatically created.");
13497 w32_strict_fontnames = 0;
13498
c0611964
AI
13499 DEFVAR_BOOL ("w32-strict-painting",
13500 &w32_strict_painting,
13501 "Non-nil means use strict rules for repainting frames.\n\
13502Set this to nil to get the old behaviour for repainting; this should\n\
13503only be necessary if the default setting causes problems.");
13504 w32_strict_painting = 1;
13505
f46e6225
GV
13506 DEFVAR_LISP ("w32-system-coding-system",
13507 &Vw32_system_coding_system,
13508 "Coding system used by Windows system functions, such as for font names.");
13509 Vw32_system_coding_system = Qnil;
13510
dfff8a69
JR
13511 DEFVAR_LISP ("w32-charset-info-alist",
13512 &Vw32_charset_info_alist,
13513 "Alist linking Emacs character sets to Windows fonts\n\
13514and codepages. Each entry should be of the form:\n\
13515\n\
13516 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13517\n\
13518where CHARSET_NAME is a string used in font names to identify the charset,\n\
13519WINDOWS_CHARSET is a symbol that can be one of:\n\
13520w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
767b1ff0 13521w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,\n\
dfff8a69
JR
13522w32-charset-chinesebig5, "
13523#ifdef JOHAB_CHARSET
13524"w32-charset-johab, w32-charset-hebrew,\n\
13525w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13526w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13527w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13528#endif
13529#ifdef UNICODE_CHARSET
13530"w32-charset-unicode, "
13531#endif
13532"or w32-charset-oem.\n\
13533CODEPAGE should be an integer specifying the codepage that should be used\n\
13534to display the character set, t to do no translation and output as Unicode,\n\
13535or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13536versions of Windows) characters.");
13537 Vw32_charset_info_alist = Qnil;
13538
13539 staticpro (&Qw32_charset_ansi);
13540 Qw32_charset_ansi = intern ("w32-charset-ansi");
13541 staticpro (&Qw32_charset_symbol);
13542 Qw32_charset_symbol = intern ("w32-charset-symbol");
13543 staticpro (&Qw32_charset_shiftjis);
13544 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
13545 staticpro (&Qw32_charset_hangeul);
13546 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
13547 staticpro (&Qw32_charset_chinesebig5);
13548 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13549 staticpro (&Qw32_charset_gb2312);
13550 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13551 staticpro (&Qw32_charset_oem);
13552 Qw32_charset_oem = intern ("w32-charset-oem");
13553
13554#ifdef JOHAB_CHARSET
13555 {
13556 static int w32_extra_charsets_defined = 1;
767b1ff0 13557 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined, "");
dfff8a69
JR
13558
13559 staticpro (&Qw32_charset_johab);
13560 Qw32_charset_johab = intern ("w32-charset-johab");
13561 staticpro (&Qw32_charset_easteurope);
13562 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13563 staticpro (&Qw32_charset_turkish);
13564 Qw32_charset_turkish = intern ("w32-charset-turkish");
13565 staticpro (&Qw32_charset_baltic);
13566 Qw32_charset_baltic = intern ("w32-charset-baltic");
13567 staticpro (&Qw32_charset_russian);
13568 Qw32_charset_russian = intern ("w32-charset-russian");
13569 staticpro (&Qw32_charset_arabic);
13570 Qw32_charset_arabic = intern ("w32-charset-arabic");
13571 staticpro (&Qw32_charset_greek);
13572 Qw32_charset_greek = intern ("w32-charset-greek");
13573 staticpro (&Qw32_charset_hebrew);
13574 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
13575 staticpro (&Qw32_charset_vietnamese);
13576 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
13577 staticpro (&Qw32_charset_thai);
13578 Qw32_charset_thai = intern ("w32-charset-thai");
13579 staticpro (&Qw32_charset_mac);
13580 Qw32_charset_mac = intern ("w32-charset-mac");
13581 }
13582#endif
13583
13584#ifdef UNICODE_CHARSET
13585 {
13586 static int w32_unicode_charset_defined = 1;
13587 DEFVAR_BOOL ("w32-unicode-charset-defined",
767b1ff0 13588 &w32_unicode_charset_defined, "");
dfff8a69
JR
13589
13590 staticpro (&Qw32_charset_unicode);
13591 Qw32_charset_unicode = intern ("w32-charset-unicode");
13592#endif
13593
ee78dc32 13594 defsubr (&Sx_get_resource);
767b1ff0 13595#if 0 /* TODO: Port to W32 */
6fc2811b
JR
13596 defsubr (&Sx_change_window_property);
13597 defsubr (&Sx_delete_window_property);
13598 defsubr (&Sx_window_property);
13599#endif
2d764c78 13600 defsubr (&Sxw_display_color_p);
ee78dc32 13601 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
13602 defsubr (&Sxw_color_defined_p);
13603 defsubr (&Sxw_color_values);
ee78dc32
GV
13604 defsubr (&Sx_server_max_request_size);
13605 defsubr (&Sx_server_vendor);
13606 defsubr (&Sx_server_version);
13607 defsubr (&Sx_display_pixel_width);
13608 defsubr (&Sx_display_pixel_height);
13609 defsubr (&Sx_display_mm_width);
13610 defsubr (&Sx_display_mm_height);
13611 defsubr (&Sx_display_screens);
13612 defsubr (&Sx_display_planes);
13613 defsubr (&Sx_display_color_cells);
13614 defsubr (&Sx_display_visual_class);
13615 defsubr (&Sx_display_backing_store);
13616 defsubr (&Sx_display_save_under);
13617 defsubr (&Sx_parse_geometry);
13618 defsubr (&Sx_create_frame);
ee78dc32
GV
13619 defsubr (&Sx_open_connection);
13620 defsubr (&Sx_close_connection);
13621 defsubr (&Sx_display_list);
13622 defsubr (&Sx_synchronize);
13623
fbd6baed 13624 /* W32 specific functions */
ee78dc32 13625
1edf84e7 13626 defsubr (&Sw32_focus_frame);
fbd6baed
GV
13627 defsubr (&Sw32_select_font);
13628 defsubr (&Sw32_define_rgb_color);
13629 defsubr (&Sw32_default_color_map);
13630 defsubr (&Sw32_load_color_file);
1edf84e7 13631 defsubr (&Sw32_send_sys_command);
55dcfc15 13632 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
13633 defsubr (&Sw32_register_hot_key);
13634 defsubr (&Sw32_unregister_hot_key);
13635 defsubr (&Sw32_registered_hot_keys);
13636 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 13637 defsubr (&Sw32_toggle_lock_key);
33d52f9c 13638 defsubr (&Sw32_find_bdf_fonts);
4587b026
GV
13639
13640 /* Setting callback functions for fontset handler. */
13641 get_font_info_func = w32_get_font_info;
6fc2811b
JR
13642
13643#if 0 /* This function pointer doesn't seem to be used anywhere.
13644 And the pointer assigned has the wrong type, anyway. */
4587b026 13645 list_fonts_func = w32_list_fonts;
6fc2811b
JR
13646#endif
13647
4587b026
GV
13648 load_font_func = w32_load_font;
13649 find_ccl_program_func = w32_find_ccl_program;
13650 query_font_func = w32_query_font;
13651 set_frame_fontset_func = x_set_font;
13652 check_window_system_func = check_w32;
6fc2811b 13653
767b1ff0 13654#if 0 /* TODO Image support for W32 */
6fc2811b
JR
13655 /* Images. */
13656 Qxbm = intern ("xbm");
13657 staticpro (&Qxbm);
13658 QCtype = intern (":type");
13659 staticpro (&QCtype);
13660 QCalgorithm = intern (":algorithm");
13661 staticpro (&QCalgorithm);
13662 QCheuristic_mask = intern (":heuristic-mask");
13663 staticpro (&QCheuristic_mask);
13664 QCcolor_symbols = intern (":color-symbols");
13665 staticpro (&QCcolor_symbols);
6fc2811b
JR
13666 QCascent = intern (":ascent");
13667 staticpro (&QCascent);
13668 QCmargin = intern (":margin");
13669 staticpro (&QCmargin);
13670 QCrelief = intern (":relief");
13671 staticpro (&QCrelief);
13672 Qpostscript = intern ("postscript");
13673 staticpro (&Qpostscript);
13674 QCloader = intern (":loader");
13675 staticpro (&QCloader);
13676 QCbounding_box = intern (":bounding-box");
13677 staticpro (&QCbounding_box);
13678 QCpt_width = intern (":pt-width");
13679 staticpro (&QCpt_width);
13680 QCpt_height = intern (":pt-height");
13681 staticpro (&QCpt_height);
13682 QCindex = intern (":index");
13683 staticpro (&QCindex);
13684 Qpbm = intern ("pbm");
13685 staticpro (&Qpbm);
13686
13687#if HAVE_XPM
13688 Qxpm = intern ("xpm");
13689 staticpro (&Qxpm);
13690#endif
13691
13692#if HAVE_JPEG
13693 Qjpeg = intern ("jpeg");
13694 staticpro (&Qjpeg);
13695#endif
13696
13697#if HAVE_TIFF
13698 Qtiff = intern ("tiff");
13699 staticpro (&Qtiff);
13700#endif
13701
13702#if HAVE_GIF
13703 Qgif = intern ("gif");
13704 staticpro (&Qgif);
13705#endif
13706
13707#if HAVE_PNG
13708 Qpng = intern ("png");
13709 staticpro (&Qpng);
13710#endif
13711
13712 defsubr (&Sclear_image_cache);
13713
13714#if GLYPH_DEBUG
13715 defsubr (&Simagep);
13716 defsubr (&Slookup_image);
13717#endif
767b1ff0 13718#endif /* TODO */
6fc2811b 13719
dfff8a69
JR
13720 busy_cursor_atimer = NULL;
13721 busy_cursor_shown_p = 0;
767b1ff0 13722#ifdef TODO /* Tooltip support not complete. */
6fc2811b
JR
13723 defsubr (&Sx_show_tip);
13724 defsubr (&Sx_hide_tip);
767b1ff0 13725#endif
6fc2811b
JR
13726 staticpro (&tip_timer);
13727 tip_timer = Qnil;
13728
13729 defsubr (&Sx_file_dialog);
13730}
13731
13732
13733void
13734init_xfns ()
13735{
13736 image_types = NULL;
13737 Vimage_types = Qnil;
13738
767b1ff0 13739#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
13740 define_image_type (&xbm_type);
13741 define_image_type (&gs_type);
13742 define_image_type (&pbm_type);
13743
13744#if HAVE_XPM
13745 define_image_type (&xpm_type);
13746#endif
13747
13748#if HAVE_JPEG
13749 define_image_type (&jpeg_type);
13750#endif
13751
13752#if HAVE_TIFF
13753 define_image_type (&tiff_type);
13754#endif
13755
13756#if HAVE_GIF
13757 define_image_type (&gif_type);
13758#endif
13759
13760#if HAVE_PNG
13761 define_image_type (&png_type);
13762#endif
767b1ff0 13763#endif /* TODO */
ee78dc32
GV
13764}
13765
13766#undef abort
13767
13768void
fbd6baed 13769w32_abort()
ee78dc32 13770{
5ac45f98
GV
13771 int button;
13772 button = MessageBox (NULL,
13773 "A fatal error has occurred!\n\n"
13774 "Select Abort to exit, Retry to debug, Ignore to continue",
13775 "Emacs Abort Dialog",
13776 MB_ICONEXCLAMATION | MB_TASKMODAL
13777 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
13778 switch (button)
13779 {
13780 case IDRETRY:
13781 DebugBreak ();
13782 break;
13783 case IDIGNORE:
13784 break;
13785 case IDABORT:
13786 default:
13787 abort ();
13788 break;
13789 }
ee78dc32 13790}
d573caac 13791
83c75055
GV
13792/* For convenience when debugging. */
13793int
13794w32_last_error()
13795{
13796 return GetLastError ();
13797}