(src): Put gdb.tmp after -a, since -a requires an argument.
[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"
ee78dc32
GV
33#include "w32term.h"
34#include "frame.h"
35#include "window.h"
36#include "buffer.h"
37#include "dispextern.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
ee78dc32 55extern void free_frame_menubar ();
6fc2811b 56extern double atof ();
adcc3809 57extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
5ac45f98 58extern int quit_char;
ee78dc32 59
6fc2811b
JR
60/* A definition of XColor for non-X frames. */
61#ifndef HAVE_X_WINDOWS
62typedef struct {
63 unsigned long pixel;
64 unsigned short red, green, blue;
65 char flags;
66 char pad;
67} XColor;
68#endif
69
ccc2d29c
GV
70extern char *lispy_function_keys[];
71
6fc2811b
JR
72/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
73 it, and including `bitmaps/gray' more than once is a problem when
74 config.h defines `static' as an empty replacement string. */
75
76int gray_bitmap_width = gray_width;
77int gray_bitmap_height = gray_height;
78unsigned char *gray_bitmap_bits = gray_bits;
79
ee78dc32 80/* The colormap for converting color names to RGB values */
fbd6baed 81Lisp_Object Vw32_color_map;
ee78dc32 82
da36a4d6 83/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 84Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 85
8c205c63
RS
86/* Non nil if alt key is translated to meta_modifier, nil if it is translated
87 to alt_modifier. */
fbd6baed 88Lisp_Object Vw32_alt_is_meta;
8c205c63 89
7d081355
AI
90/* If non-zero, the windows virtual key code for an alternative quit key. */
91Lisp_Object Vw32_quit_key;
92
ccc2d29c
GV
93/* Non nil if left window key events are passed on to Windows (this only
94 affects whether "tapping" the key opens the Start menu). */
95Lisp_Object Vw32_pass_lwindow_to_system;
96
97/* Non nil if right window key events are passed on to Windows (this
98 only affects whether "tapping" the key opens the Start menu). */
99Lisp_Object Vw32_pass_rwindow_to_system;
100
adcc3809
GV
101/* Virtual key code used to generate "phantom" key presses in order
102 to stop system from acting on Windows key events. */
103Lisp_Object Vw32_phantom_key_code;
104
ccc2d29c
GV
105/* Modifier associated with the left "Windows" key, or nil to act as a
106 normal key. */
107Lisp_Object Vw32_lwindow_modifier;
108
109/* Modifier associated with the right "Windows" key, or nil to act as a
110 normal key. */
111Lisp_Object Vw32_rwindow_modifier;
112
113/* Modifier associated with the "Apps" key, or nil to act as a normal
114 key. */
115Lisp_Object Vw32_apps_modifier;
116
117/* Value is nil if Num Lock acts as a function key. */
118Lisp_Object Vw32_enable_num_lock;
119
120/* Value is nil if Caps Lock acts as a function key. */
121Lisp_Object Vw32_enable_caps_lock;
122
123/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
124Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 125
7ce9aaca 126/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b
JR
127 and italic versions of fonts. */
128Lisp_Object Vw32_enable_synthesized_fonts;
5ac45f98
GV
129
130/* Enable palette management. */
fbd6baed 131Lisp_Object Vw32_enable_palette;
5ac45f98
GV
132
133/* Control how close left/right button down events must be to
134 be converted to a middle button down event. */
fbd6baed 135Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 136
84fb1139
KH
137/* Minimum interval between mouse movement (and scroll bar drag)
138 events that are passed on to the event loop. */
fbd6baed 139Lisp_Object Vw32_mouse_move_interval;
84fb1139 140
ee78dc32
GV
141/* The name we're using in resource queries. */
142Lisp_Object Vx_resource_name;
143
144/* Non nil if no window manager is in use. */
145Lisp_Object Vx_no_window_manager;
146
6fc2811b 147/* Non-zero means we're allowed to display a busy cursor. */
dfff8a69 148
6fc2811b
JR
149int display_busy_cursor_p;
150
ee78dc32
GV
151/* The background and shape of the mouse pointer, and shape when not
152 over text or in the modeline. */
dfff8a69 153
ee78dc32 154Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
6fc2811b
JR
155Lisp_Object Vx_busy_pointer_shape;
156
ee78dc32 157/* The shape when over mouse-sensitive text. */
dfff8a69 158
ee78dc32
GV
159Lisp_Object Vx_sensitive_text_pointer_shape;
160
161/* Color of chars displayed in cursor box. */
dfff8a69 162
ee78dc32
GV
163Lisp_Object Vx_cursor_fore_pixel;
164
1edf84e7 165/* Nonzero if using Windows. */
dfff8a69 166
1edf84e7
GV
167static int w32_in_use;
168
ee78dc32 169/* Search path for bitmap files. */
dfff8a69 170
ee78dc32
GV
171Lisp_Object Vx_bitmap_file_path;
172
4587b026 173/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 174
4587b026
GV
175Lisp_Object Vx_pixel_size_width_font_regexp;
176
33d52f9c
GV
177/* Alist of bdf fonts and the files that define them. */
178Lisp_Object Vw32_bdf_filename_alist;
179
f46e6225
GV
180Lisp_Object Vw32_system_coding_system;
181
f46e6225 182/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
183int w32_strict_fontnames;
184
c0611964
AI
185/* A flag to control whether we should only repaint if GetUpdateRect
186 indicates there is an update region. */
187int w32_strict_painting;
188
dfff8a69
JR
189/* Associative list linking character set strings to Windows codepages. */
190Lisp_Object Vw32_charset_info_alist;
191
192/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
193#ifndef VIETNAMESE_CHARSET
194#define VIETNAMESE_CHARSET 163
195#endif
196
197
ee78dc32
GV
198/* Evaluate this expression to rebuild the section of syms_of_w32fns
199 that initializes and staticpros the symbols declared below. Note
200 that Emacs 18 has a bug that keeps C-x C-e from being able to
201 evaluate this expression.
202
203(progn
204 ;; Accumulate a list of the symbols we want to initialize from the
205 ;; declarations at the top of the file.
206 (goto-char (point-min))
207 (search-forward "/\*&&& symbols declared here &&&*\/\n")
208 (let (symbol-list)
209 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
210 (setq symbol-list
211 (cons (buffer-substring (match-beginning 1) (match-end 1))
212 symbol-list))
213 (forward-line 1))
214 (setq symbol-list (nreverse symbol-list))
215 ;; Delete the section of syms_of_... where we initialize the symbols.
216 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
217 (let ((start (point)))
218 (while (looking-at "^ Q")
219 (forward-line 2))
220 (kill-region start (point)))
221 ;; Write a new symbol initialization section.
222 (while symbol-list
223 (insert (format " %s = intern (\"" (car symbol-list)))
224 (let ((start (point)))
225 (insert (substring (car symbol-list) 1))
226 (subst-char-in-region start (point) ?_ ?-))
227 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
228 (setq symbol-list (cdr symbol-list)))))
229
230 */
231
232/*&&& symbols declared here &&&*/
233Lisp_Object Qauto_raise;
234Lisp_Object Qauto_lower;
ee78dc32
GV
235Lisp_Object Qbar;
236Lisp_Object Qborder_color;
237Lisp_Object Qborder_width;
238Lisp_Object Qbox;
239Lisp_Object Qcursor_color;
240Lisp_Object Qcursor_type;
ee78dc32
GV
241Lisp_Object Qgeometry;
242Lisp_Object Qicon_left;
243Lisp_Object Qicon_top;
244Lisp_Object Qicon_type;
245Lisp_Object Qicon_name;
246Lisp_Object Qinternal_border_width;
247Lisp_Object Qleft;
1026b400 248Lisp_Object Qright;
ee78dc32
GV
249Lisp_Object Qmouse_color;
250Lisp_Object Qnone;
251Lisp_Object Qparent_id;
252Lisp_Object Qscroll_bar_width;
253Lisp_Object Qsuppress_icon;
ee78dc32
GV
254Lisp_Object Qundefined_color;
255Lisp_Object Qvertical_scroll_bars;
256Lisp_Object Qvisibility;
257Lisp_Object Qwindow_id;
258Lisp_Object Qx_frame_parameter;
259Lisp_Object Qx_resource_name;
260Lisp_Object Quser_position;
261Lisp_Object Quser_size;
6fc2811b 262Lisp_Object Qscreen_gamma;
dfff8a69
JR
263Lisp_Object Qline_spacing;
264Lisp_Object Qcenter;
adcc3809
GV
265Lisp_Object Qhyper;
266Lisp_Object Qsuper;
267Lisp_Object Qmeta;
268Lisp_Object Qalt;
269Lisp_Object Qctrl;
270Lisp_Object Qcontrol;
271Lisp_Object Qshift;
272
dfff8a69
JR
273Lisp_Object Qw32_charset_ansi;
274Lisp_Object Qw32_charset_default;
275Lisp_Object Qw32_charset_symbol;
276Lisp_Object Qw32_charset_shiftjis;
277Lisp_Object Qw32_charset_hangul;
278Lisp_Object Qw32_charset_gb2312;
279Lisp_Object Qw32_charset_chinesebig5;
280Lisp_Object Qw32_charset_oem;
281
282#ifdef JOHAB_CHARSET
283Lisp_Object Qw32_charset_easteurope;
284Lisp_Object Qw32_charset_turkish;
285Lisp_Object Qw32_charset_baltic;
286Lisp_Object Qw32_charset_russian;
287Lisp_Object Qw32_charset_arabic;
288Lisp_Object Qw32_charset_greek;
289Lisp_Object Qw32_charset_hebrew;
290Lisp_Object Qw32_charset_thai;
291Lisp_Object Qw32_charset_johab;
292Lisp_Object Qw32_charset_mac;
293#endif
294
295#ifdef UNICODE_CHARSET
296Lisp_Object Qw32_charset_unicode;
297#endif
298
6fc2811b
JR
299extern Lisp_Object Qtop;
300extern Lisp_Object Qdisplay;
301extern Lisp_Object Qtool_bar_lines;
302
5ac45f98
GV
303/* State variables for emulating a three button mouse. */
304#define LMOUSE 1
305#define MMOUSE 2
306#define RMOUSE 4
307
308static int button_state = 0;
fbd6baed 309static W32Msg saved_mouse_button_msg;
84fb1139 310static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 311static W32Msg saved_mouse_move_msg;
84fb1139
KH
312static unsigned mouse_move_timer;
313
93fbe8b7
GV
314/* W95 mousewheel handler */
315unsigned int msh_mousewheel = 0;
316
84fb1139
KH
317#define MOUSE_BUTTON_ID 1
318#define MOUSE_MOVE_ID 2
5ac45f98 319
ee78dc32 320/* The below are defined in frame.c. */
dfff8a69 321
ee78dc32 322extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 323extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 324extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
325
326extern Lisp_Object Vwindow_system_version;
327
4b817373
RS
328Lisp_Object Qface_set_after_frame_default;
329
fbd6baed
GV
330/* From w32term.c. */
331extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 332extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 333
ee78dc32 334\f
1edf84e7
GV
335/* Error if we are not connected to MS-Windows. */
336void
337check_w32 ()
338{
339 if (! w32_in_use)
340 error ("MS-Windows not in use or not initialized");
341}
342
343/* Nonzero if we can use mouse menus.
344 You should not call this unless HAVE_MENUS is defined. */
345
346int
347have_menus_p ()
348{
349 return w32_in_use;
350}
351
ee78dc32 352/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 353 and checking validity for W32. */
ee78dc32
GV
354
355FRAME_PTR
356check_x_frame (frame)
357 Lisp_Object frame;
358{
359 FRAME_PTR f;
360
361 if (NILP (frame))
6fc2811b
JR
362 frame = selected_frame;
363 CHECK_LIVE_FRAME (frame, 0);
364 f = XFRAME (frame);
fbd6baed
GV
365 if (! FRAME_W32_P (f))
366 error ("non-w32 frame used");
ee78dc32
GV
367 return f;
368}
369
370/* Let the user specify an display with a frame.
fbd6baed 371 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
372 the first display on the list. */
373
fbd6baed 374static struct w32_display_info *
ee78dc32
GV
375check_x_display_info (frame)
376 Lisp_Object frame;
377{
378 if (NILP (frame))
379 {
6fc2811b
JR
380 struct frame *sf = XFRAME (selected_frame);
381
382 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
383 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 384 else
fbd6baed 385 return &one_w32_display_info;
ee78dc32
GV
386 }
387 else if (STRINGP (frame))
388 return x_display_info_for_name (frame);
389 else
390 {
391 FRAME_PTR f;
392
393 CHECK_LIVE_FRAME (frame, 0);
394 f = XFRAME (frame);
fbd6baed
GV
395 if (! FRAME_W32_P (f))
396 error ("non-w32 frame used");
397 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
398 }
399}
400\f
fbd6baed 401/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
402 It could be the frame's main window or an icon window. */
403
404/* This function can be called during GC, so use GC_xxx type test macros. */
405
406struct frame *
407x_window_to_frame (dpyinfo, wdesc)
fbd6baed 408 struct w32_display_info *dpyinfo;
ee78dc32
GV
409 HWND wdesc;
410{
411 Lisp_Object tail, frame;
412 struct frame *f;
413
8e713be6 414 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 415 {
8e713be6 416 frame = XCAR (tail);
ee78dc32
GV
417 if (!GC_FRAMEP (frame))
418 continue;
419 f = XFRAME (frame);
2d764c78 420 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 421 continue;
f79e6790
JR
422 if (f->output_data.w32->busy_window == wdesc)
423 return f;
424
425 /* NTEMACS_TODO: Check tooltips when supported. */
fbd6baed 426 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
427 return f;
428 }
429 return 0;
430}
431
432\f
433
434/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
435 id, which is just an int that this section returns. Bitmaps are
436 reference counted so they can be shared among frames.
437
438 Bitmap indices are guaranteed to be > 0, so a negative number can
439 be used to indicate no bitmap.
440
441 If you use x_create_bitmap_from_data, then you must keep track of
442 the bitmaps yourself. That is, creating a bitmap from the same
443 data more than once will not be caught. */
444
445
446/* Functions to access the contents of a bitmap, given an id. */
447
448int
449x_bitmap_height (f, id)
450 FRAME_PTR f;
451 int id;
452{
fbd6baed 453 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
454}
455
456int
457x_bitmap_width (f, id)
458 FRAME_PTR f;
459 int id;
460{
fbd6baed 461 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
462}
463
464int
465x_bitmap_pixmap (f, id)
466 FRAME_PTR f;
467 int id;
468{
fbd6baed 469 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
470}
471
472
473/* Allocate a new bitmap record. Returns index of new record. */
474
475static int
476x_allocate_bitmap_record (f)
477 FRAME_PTR f;
478{
fbd6baed 479 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
480 int i;
481
482 if (dpyinfo->bitmaps == NULL)
483 {
484 dpyinfo->bitmaps_size = 10;
485 dpyinfo->bitmaps
fbd6baed 486 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
487 dpyinfo->bitmaps_last = 1;
488 return 1;
489 }
490
491 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
492 return ++dpyinfo->bitmaps_last;
493
494 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
495 if (dpyinfo->bitmaps[i].refcount == 0)
496 return i + 1;
497
498 dpyinfo->bitmaps_size *= 2;
499 dpyinfo->bitmaps
fbd6baed
GV
500 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
501 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
502 return ++dpyinfo->bitmaps_last;
503}
504
505/* Add one reference to the reference count of the bitmap with id ID. */
506
507void
508x_reference_bitmap (f, id)
509 FRAME_PTR f;
510 int id;
511{
fbd6baed 512 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
513}
514
515/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
516
517int
518x_create_bitmap_from_data (f, bits, width, height)
519 struct frame *f;
520 char *bits;
521 unsigned int width, height;
522{
fbd6baed 523 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
524 Pixmap bitmap;
525 int id;
526
527 bitmap = CreateBitmap (width, height,
fbd6baed
GV
528 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
529 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
530 bits);
531
532 if (! bitmap)
533 return -1;
534
535 id = x_allocate_bitmap_record (f);
536 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
537 dpyinfo->bitmaps[id - 1].file = NULL;
538 dpyinfo->bitmaps[id - 1].hinst = NULL;
539 dpyinfo->bitmaps[id - 1].refcount = 1;
540 dpyinfo->bitmaps[id - 1].depth = 1;
541 dpyinfo->bitmaps[id - 1].height = height;
542 dpyinfo->bitmaps[id - 1].width = width;
543
544 return id;
545}
546
547/* Create bitmap from file FILE for frame F. */
548
549int
550x_create_bitmap_from_file (f, file)
551 struct frame *f;
552 Lisp_Object file;
553{
554 return -1;
6fc2811b 555#if 0 /* NTEMACS_TODO : bitmap support */
fbd6baed 556 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 557 unsigned int width, height;
6fc2811b 558 HBITMAP bitmap;
ee78dc32
GV
559 int xhot, yhot, result, id;
560 Lisp_Object found;
561 int fd;
562 char *filename;
563 HINSTANCE hinst;
564
565 /* Look for an existing bitmap with the same name. */
566 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
567 {
568 if (dpyinfo->bitmaps[id].refcount
569 && dpyinfo->bitmaps[id].file
570 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
571 {
572 ++dpyinfo->bitmaps[id].refcount;
573 return id + 1;
574 }
575 }
576
577 /* Search bitmap-file-path for the file, if appropriate. */
578 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
579 if (fd < 0)
580 return -1;
5d7fed93
GV
581 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
582 if (fd == 0)
583 return -1;
6fc2811b 584 emacs_close (fd);
ee78dc32
GV
585
586 filename = (char *) XSTRING (found)->data;
587
588 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
589
590 if (hinst == NULL)
591 return -1;
592
593
fbd6baed 594 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
595 filename, &width, &height, &bitmap, &xhot, &yhot);
596 if (result != BitmapSuccess)
597 return -1;
598
599 id = x_allocate_bitmap_record (f);
600 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
601 dpyinfo->bitmaps[id - 1].refcount = 1;
602 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
603 dpyinfo->bitmaps[id - 1].depth = 1;
604 dpyinfo->bitmaps[id - 1].height = height;
605 dpyinfo->bitmaps[id - 1].width = width;
606 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
607
608 return id;
6fc2811b 609#endif /* NTEMACS_TODO */
ee78dc32
GV
610}
611
612/* Remove reference to bitmap with id number ID. */
613
33d52f9c 614void
ee78dc32
GV
615x_destroy_bitmap (f, id)
616 FRAME_PTR f;
617 int id;
618{
fbd6baed 619 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
620
621 if (id > 0)
622 {
623 --dpyinfo->bitmaps[id - 1].refcount;
624 if (dpyinfo->bitmaps[id - 1].refcount == 0)
625 {
626 BLOCK_INPUT;
627 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
628 if (dpyinfo->bitmaps[id - 1].file)
629 {
6fc2811b 630 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
631 dpyinfo->bitmaps[id - 1].file = NULL;
632 }
633 UNBLOCK_INPUT;
634 }
635 }
636}
637
638/* Free all the bitmaps for the display specified by DPYINFO. */
639
640static void
641x_destroy_all_bitmaps (dpyinfo)
fbd6baed 642 struct w32_display_info *dpyinfo;
ee78dc32
GV
643{
644 int i;
645 for (i = 0; i < dpyinfo->bitmaps_last; i++)
646 if (dpyinfo->bitmaps[i].refcount > 0)
647 {
648 DeleteObject (dpyinfo->bitmaps[i].pixmap);
649 if (dpyinfo->bitmaps[i].file)
6fc2811b 650 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
651 }
652 dpyinfo->bitmaps_last = 0;
653}
654\f
fbd6baed 655/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
656 to the ways of passing the parameter values to the window system.
657
658 The name of a parameter, as a Lisp symbol,
659 has an `x-frame-parameter' property which is an integer in Lisp
660 but can be interpreted as an `enum x_frame_parm' in C. */
661
662enum x_frame_parm
663{
664 X_PARM_FOREGROUND_COLOR,
665 X_PARM_BACKGROUND_COLOR,
666 X_PARM_MOUSE_COLOR,
667 X_PARM_CURSOR_COLOR,
668 X_PARM_BORDER_COLOR,
669 X_PARM_ICON_TYPE,
670 X_PARM_FONT,
671 X_PARM_BORDER_WIDTH,
672 X_PARM_INTERNAL_BORDER_WIDTH,
673 X_PARM_NAME,
674 X_PARM_AUTORAISE,
675 X_PARM_AUTOLOWER,
676 X_PARM_VERT_SCROLL_BAR,
677 X_PARM_VISIBILITY,
678 X_PARM_MENU_BAR_LINES
679};
680
681
682struct x_frame_parm_table
683{
684 char *name;
6fc2811b 685 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
686};
687
6fc2811b
JR
688/* NTEMACS_TODO: Native Input Method support; see x_create_im. */
689void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 690static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
691void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
692void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
693void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
694void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
695void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
698void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
701 Lisp_Object));
702void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
703void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
704void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
706 Lisp_Object));
707void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
708void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
709void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
710void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
711void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
712void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
713static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
714
715static struct x_frame_parm_table x_frame_parms[] =
716{
1edf84e7
GV
717 "auto-raise", x_set_autoraise,
718 "auto-lower", x_set_autolower,
ee78dc32 719 "background-color", x_set_background_color,
ee78dc32 720 "border-color", x_set_border_color,
1edf84e7
GV
721 "border-width", x_set_border_width,
722 "cursor-color", x_set_cursor_color,
ee78dc32 723 "cursor-type", x_set_cursor_type,
ee78dc32 724 "font", x_set_font,
1edf84e7
GV
725 "foreground-color", x_set_foreground_color,
726 "icon-name", x_set_icon_name,
727 "icon-type", x_set_icon_type,
ee78dc32 728 "internal-border-width", x_set_internal_border_width,
ee78dc32 729 "menu-bar-lines", x_set_menu_bar_lines,
1edf84e7
GV
730 "mouse-color", x_set_mouse_color,
731 "name", x_explicitly_set_name,
ee78dc32 732 "scroll-bar-width", x_set_scroll_bar_width,
1edf84e7 733 "title", x_set_title,
ee78dc32 734 "unsplittable", x_set_unsplittable,
1edf84e7
GV
735 "vertical-scroll-bars", x_set_vertical_scroll_bars,
736 "visibility", x_set_visibility,
6fc2811b 737 "tool-bar-lines", x_set_tool_bar_lines,
dfff8a69
JR
738 "screen-gamma", x_set_screen_gamma,
739 "line-spacing", x_set_line_spacing
ee78dc32
GV
740};
741
742/* Attach the `x-frame-parameter' properties to
fbd6baed 743 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 744
dfff8a69 745void
ee78dc32
GV
746init_x_parm_symbols ()
747{
748 int i;
749
750 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
751 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
752 make_number (i));
753}
754\f
dfff8a69 755/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
756 If a parameter is not specially recognized, do nothing;
757 otherwise call the `x_set_...' function for that parameter. */
758
759void
760x_set_frame_parameters (f, alist)
761 FRAME_PTR f;
762 Lisp_Object alist;
763{
764 Lisp_Object tail;
765
766 /* If both of these parameters are present, it's more efficient to
767 set them both at once. So we wait until we've looked at the
768 entire list before we set them. */
b839712d 769 int width, height;
ee78dc32
GV
770
771 /* Same here. */
772 Lisp_Object left, top;
773
774 /* Same with these. */
775 Lisp_Object icon_left, icon_top;
776
777 /* Record in these vectors all the parms specified. */
778 Lisp_Object *parms;
779 Lisp_Object *values;
a797a73d 780 int i, p;
ee78dc32
GV
781 int left_no_change = 0, top_no_change = 0;
782 int icon_left_no_change = 0, icon_top_no_change = 0;
783
5878523b
RS
784 struct gcpro gcpro1, gcpro2;
785
ee78dc32
GV
786 i = 0;
787 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
788 i++;
789
790 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
791 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
792
793 /* Extract parm names and values into those vectors. */
794
795 i = 0;
796 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
797 {
6fc2811b 798 Lisp_Object elt;
ee78dc32
GV
799
800 elt = Fcar (tail);
801 parms[i] = Fcar (elt);
802 values[i] = Fcdr (elt);
803 i++;
804 }
5878523b
RS
805 /* TAIL and ALIST are not used again below here. */
806 alist = tail = Qnil;
807
808 GCPRO2 (*parms, *values);
809 gcpro1.nvars = i;
810 gcpro2.nvars = i;
811
812 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
813 because their values appear in VALUES and strings are not valid. */
b839712d 814 top = left = Qunbound;
ee78dc32
GV
815 icon_left = icon_top = Qunbound;
816
b839712d 817 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
818 if (FRAME_NEW_WIDTH (f))
819 width = FRAME_NEW_WIDTH (f);
820 else
821 width = FRAME_WIDTH (f);
822
823 if (FRAME_NEW_HEIGHT (f))
824 height = FRAME_NEW_HEIGHT (f);
825 else
826 height = FRAME_HEIGHT (f);
b839712d 827
a797a73d
GV
828 /* Process foreground_color and background_color before anything else.
829 They are independent of other properties, but other properties (e.g.,
830 cursor_color) are dependent upon them. */
831 for (p = 0; p < i; p++)
832 {
833 Lisp_Object prop, val;
834
835 prop = parms[p];
836 val = values[p];
837 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
838 {
839 register Lisp_Object param_index, old_value;
840
841 param_index = Fget (prop, Qx_frame_parameter);
842 old_value = get_frame_param (f, prop);
843 store_frame_param (f, prop, val);
844 if (NATNUMP (param_index)
845 && (XFASTINT (param_index)
846 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
847 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
848 }
849 }
850
ee78dc32
GV
851 /* Now process them in reverse of specified order. */
852 for (i--; i >= 0; i--)
853 {
854 Lisp_Object prop, val;
855
856 prop = parms[i];
857 val = values[i];
858
b839712d
RS
859 if (EQ (prop, Qwidth) && NUMBERP (val))
860 width = XFASTINT (val);
861 else if (EQ (prop, Qheight) && NUMBERP (val))
862 height = XFASTINT (val);
ee78dc32
GV
863 else if (EQ (prop, Qtop))
864 top = val;
865 else if (EQ (prop, Qleft))
866 left = val;
867 else if (EQ (prop, Qicon_top))
868 icon_top = val;
869 else if (EQ (prop, Qicon_left))
870 icon_left = val;
a797a73d
GV
871 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
872 /* Processed above. */
873 continue;
ee78dc32
GV
874 else
875 {
876 register Lisp_Object param_index, old_value;
877
878 param_index = Fget (prop, Qx_frame_parameter);
879 old_value = get_frame_param (f, prop);
880 store_frame_param (f, prop, val);
881 if (NATNUMP (param_index)
882 && (XFASTINT (param_index)
883 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 884 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
885 }
886 }
887
888 /* Don't die if just one of these was set. */
889 if (EQ (left, Qunbound))
890 {
891 left_no_change = 1;
fbd6baed
GV
892 if (f->output_data.w32->left_pos < 0)
893 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 894 else
fbd6baed 895 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
896 }
897 if (EQ (top, Qunbound))
898 {
899 top_no_change = 1;
fbd6baed
GV
900 if (f->output_data.w32->top_pos < 0)
901 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 902 else
fbd6baed 903 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
904 }
905
906 /* If one of the icon positions was not set, preserve or default it. */
907 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
908 {
909 icon_left_no_change = 1;
910 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
911 if (NILP (icon_left))
912 XSETINT (icon_left, 0);
913 }
914 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
915 {
916 icon_top_no_change = 1;
917 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
918 if (NILP (icon_top))
919 XSETINT (icon_top, 0);
920 }
921
ee78dc32
GV
922 /* Don't set these parameters unless they've been explicitly
923 specified. The window might be mapped or resized while we're in
924 this function, and we don't want to override that unless the lisp
925 code has asked for it.
926
927 Don't set these parameters unless they actually differ from the
928 window's current parameters; the window may not actually exist
929 yet. */
930 {
931 Lisp_Object frame;
932
933 check_frame_size (f, &height, &width);
934
935 XSETFRAME (frame, f);
936
dfff8a69
JR
937 if (width != FRAME_WIDTH (f)
938 || height != FRAME_HEIGHT (f)
939 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 940 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
941
942 if ((!NILP (left) || !NILP (top))
943 && ! (left_no_change && top_no_change)
fbd6baed
GV
944 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
945 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
946 {
947 int leftpos = 0;
948 int toppos = 0;
949
950 /* Record the signs. */
fbd6baed 951 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 952 if (EQ (left, Qminus))
fbd6baed 953 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
954 else if (INTEGERP (left))
955 {
956 leftpos = XINT (left);
957 if (leftpos < 0)
fbd6baed 958 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 959 }
8e713be6
KR
960 else if (CONSP (left) && EQ (XCAR (left), Qminus)
961 && CONSP (XCDR (left))
962 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 963 {
8e713be6 964 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 965 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 966 }
8e713be6
KR
967 else if (CONSP (left) && EQ (XCAR (left), Qplus)
968 && CONSP (XCDR (left))
969 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 970 {
8e713be6 971 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
972 }
973
974 if (EQ (top, Qminus))
fbd6baed 975 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
976 else if (INTEGERP (top))
977 {
978 toppos = XINT (top);
979 if (toppos < 0)
fbd6baed 980 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 981 }
8e713be6
KR
982 else if (CONSP (top) && EQ (XCAR (top), Qminus)
983 && CONSP (XCDR (top))
984 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 985 {
8e713be6 986 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 987 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 988 }
8e713be6
KR
989 else if (CONSP (top) && EQ (XCAR (top), Qplus)
990 && CONSP (XCDR (top))
991 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 992 {
8e713be6 993 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
994 }
995
996
997 /* Store the numeric value of the position. */
fbd6baed
GV
998 f->output_data.w32->top_pos = toppos;
999 f->output_data.w32->left_pos = leftpos;
ee78dc32 1000
fbd6baed 1001 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1002
1003 /* Actually set that position, and convert to absolute. */
1004 x_set_offset (f, leftpos, toppos, -1);
1005 }
1006
1007 if ((!NILP (icon_left) || !NILP (icon_top))
1008 && ! (icon_left_no_change && icon_top_no_change))
1009 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1010 }
5878523b
RS
1011
1012 UNGCPRO;
ee78dc32
GV
1013}
1014
1015/* Store the screen positions of frame F into XPTR and YPTR.
1016 These are the positions of the containing window manager window,
1017 not Emacs's own window. */
1018
1019void
1020x_real_positions (f, xptr, yptr)
1021 FRAME_PTR f;
1022 int *xptr, *yptr;
1023{
1024 POINT pt;
3c190163
GV
1025
1026 {
1027 RECT rect;
ee78dc32 1028
fbd6baed
GV
1029 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1030 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 1031
3c190163
GV
1032 pt.x = rect.left;
1033 pt.y = rect.top;
1034 }
ee78dc32 1035
fbd6baed 1036 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
1037
1038 *xptr = pt.x;
1039 *yptr = pt.y;
1040}
1041
1042/* Insert a description of internally-recorded parameters of frame X
1043 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1044 Only parameters that are specific to W32
ee78dc32
GV
1045 and whose values are not correctly recorded in the frame's
1046 param_alist need to be considered here. */
1047
dfff8a69 1048void
ee78dc32
GV
1049x_report_frame_params (f, alistptr)
1050 struct frame *f;
1051 Lisp_Object *alistptr;
1052{
1053 char buf[16];
1054 Lisp_Object tem;
1055
1056 /* Represent negative positions (off the top or left screen edge)
1057 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1058 XSETINT (tem, f->output_data.w32->left_pos);
1059 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1060 store_in_alist (alistptr, Qleft, tem);
1061 else
1062 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1063
fbd6baed
GV
1064 XSETINT (tem, f->output_data.w32->top_pos);
1065 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1066 store_in_alist (alistptr, Qtop, tem);
1067 else
1068 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1069
1070 store_in_alist (alistptr, Qborder_width,
fbd6baed 1071 make_number (f->output_data.w32->border_width));
ee78dc32 1072 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed
GV
1073 make_number (f->output_data.w32->internal_border_width));
1074 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1075 store_in_alist (alistptr, Qwindow_id,
1076 build_string (buf));
1077 store_in_alist (alistptr, Qicon_name, f->icon_name);
1078 FRAME_SAMPLE_VISIBILITY (f);
1079 store_in_alist (alistptr, Qvisibility,
1080 (FRAME_VISIBLE_P (f) ? Qt
1081 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1082 store_in_alist (alistptr, Qdisplay,
8e713be6 1083 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1084}
1085\f
1086
fbd6baed 1087DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
5ac45f98 1088 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
fbd6baed 1089This adds or updates a named color to w32-color-map, making it available for use.\n\
5ac45f98
GV
1090The original entry's RGB ref is returned, or nil if the entry is new.")
1091 (red, green, blue, name)
1092 Lisp_Object red, green, blue, name;
ee78dc32 1093{
5ac45f98
GV
1094 Lisp_Object rgb;
1095 Lisp_Object oldrgb = Qnil;
1096 Lisp_Object entry;
1097
1098 CHECK_NUMBER (red, 0);
1099 CHECK_NUMBER (green, 0);
1100 CHECK_NUMBER (blue, 0);
1101 CHECK_STRING (name, 0);
ee78dc32 1102
5ac45f98 1103 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1104
5ac45f98 1105 BLOCK_INPUT;
ee78dc32 1106
fbd6baed
GV
1107 /* replace existing entry in w32-color-map or add new entry. */
1108 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1109 if (NILP (entry))
1110 {
1111 entry = Fcons (name, rgb);
fbd6baed 1112 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1113 }
1114 else
1115 {
1116 oldrgb = Fcdr (entry);
1117 Fsetcdr (entry, rgb);
1118 }
1119
1120 UNBLOCK_INPUT;
1121
1122 return (oldrgb);
ee78dc32
GV
1123}
1124
fbd6baed 1125DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
5ac45f98 1126 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
fbd6baed 1127Assign this value to w32-color-map to replace the existing color map.\n\
5ac45f98
GV
1128\
1129The file should define one named RGB color per line like so:\
1130 R G B name\n\
1131where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1132 (filename)
1133 Lisp_Object filename;
1134{
1135 FILE *fp;
1136 Lisp_Object cmap = Qnil;
1137 Lisp_Object abspath;
1138
1139 CHECK_STRING (filename, 0);
1140 abspath = Fexpand_file_name (filename, Qnil);
1141
1142 fp = fopen (XSTRING (filename)->data, "rt");
1143 if (fp)
1144 {
1145 char buf[512];
1146 int red, green, blue;
1147 int num;
1148
1149 BLOCK_INPUT;
1150
1151 while (fgets (buf, sizeof (buf), fp) != NULL) {
1152 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1153 {
1154 char *name = buf + num;
1155 num = strlen (name) - 1;
1156 if (name[num] == '\n')
1157 name[num] = 0;
1158 cmap = Fcons (Fcons (build_string (name),
1159 make_number (RGB (red, green, blue))),
1160 cmap);
1161 }
1162 }
1163 fclose (fp);
1164
1165 UNBLOCK_INPUT;
1166 }
1167
1168 return cmap;
1169}
ee78dc32 1170
fbd6baed 1171/* The default colors for the w32 color map */
ee78dc32
GV
1172typedef struct colormap_t
1173{
1174 char *name;
1175 COLORREF colorref;
1176} colormap_t;
1177
fbd6baed 1178colormap_t w32_color_map[] =
ee78dc32 1179{
1da8a614
GV
1180 {"snow" , PALETTERGB (255,250,250)},
1181 {"ghost white" , PALETTERGB (248,248,255)},
1182 {"GhostWhite" , PALETTERGB (248,248,255)},
1183 {"white smoke" , PALETTERGB (245,245,245)},
1184 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1185 {"gainsboro" , PALETTERGB (220,220,220)},
1186 {"floral white" , PALETTERGB (255,250,240)},
1187 {"FloralWhite" , PALETTERGB (255,250,240)},
1188 {"old lace" , PALETTERGB (253,245,230)},
1189 {"OldLace" , PALETTERGB (253,245,230)},
1190 {"linen" , PALETTERGB (250,240,230)},
1191 {"antique white" , PALETTERGB (250,235,215)},
1192 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1193 {"papaya whip" , PALETTERGB (255,239,213)},
1194 {"PapayaWhip" , PALETTERGB (255,239,213)},
1195 {"blanched almond" , PALETTERGB (255,235,205)},
1196 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1197 {"bisque" , PALETTERGB (255,228,196)},
1198 {"peach puff" , PALETTERGB (255,218,185)},
1199 {"PeachPuff" , PALETTERGB (255,218,185)},
1200 {"navajo white" , PALETTERGB (255,222,173)},
1201 {"NavajoWhite" , PALETTERGB (255,222,173)},
1202 {"moccasin" , PALETTERGB (255,228,181)},
1203 {"cornsilk" , PALETTERGB (255,248,220)},
1204 {"ivory" , PALETTERGB (255,255,240)},
1205 {"lemon chiffon" , PALETTERGB (255,250,205)},
1206 {"LemonChiffon" , PALETTERGB (255,250,205)},
1207 {"seashell" , PALETTERGB (255,245,238)},
1208 {"honeydew" , PALETTERGB (240,255,240)},
1209 {"mint cream" , PALETTERGB (245,255,250)},
1210 {"MintCream" , PALETTERGB (245,255,250)},
1211 {"azure" , PALETTERGB (240,255,255)},
1212 {"alice blue" , PALETTERGB (240,248,255)},
1213 {"AliceBlue" , PALETTERGB (240,248,255)},
1214 {"lavender" , PALETTERGB (230,230,250)},
1215 {"lavender blush" , PALETTERGB (255,240,245)},
1216 {"LavenderBlush" , PALETTERGB (255,240,245)},
1217 {"misty rose" , PALETTERGB (255,228,225)},
1218 {"MistyRose" , PALETTERGB (255,228,225)},
1219 {"white" , PALETTERGB (255,255,255)},
1220 {"black" , PALETTERGB ( 0, 0, 0)},
1221 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1222 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1223 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1224 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1225 {"dim gray" , PALETTERGB (105,105,105)},
1226 {"DimGray" , PALETTERGB (105,105,105)},
1227 {"dim grey" , PALETTERGB (105,105,105)},
1228 {"DimGrey" , PALETTERGB (105,105,105)},
1229 {"slate gray" , PALETTERGB (112,128,144)},
1230 {"SlateGray" , PALETTERGB (112,128,144)},
1231 {"slate grey" , PALETTERGB (112,128,144)},
1232 {"SlateGrey" , PALETTERGB (112,128,144)},
1233 {"light slate gray" , PALETTERGB (119,136,153)},
1234 {"LightSlateGray" , PALETTERGB (119,136,153)},
1235 {"light slate grey" , PALETTERGB (119,136,153)},
1236 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1237 {"gray" , PALETTERGB (190,190,190)},
1238 {"grey" , PALETTERGB (190,190,190)},
1239 {"light grey" , PALETTERGB (211,211,211)},
1240 {"LightGrey" , PALETTERGB (211,211,211)},
1241 {"light gray" , PALETTERGB (211,211,211)},
1242 {"LightGray" , PALETTERGB (211,211,211)},
1243 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1244 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1245 {"navy" , PALETTERGB ( 0, 0,128)},
1246 {"navy blue" , PALETTERGB ( 0, 0,128)},
1247 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1248 {"cornflower blue" , PALETTERGB (100,149,237)},
1249 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1250 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1251 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1252 {"slate blue" , PALETTERGB (106, 90,205)},
1253 {"SlateBlue" , PALETTERGB (106, 90,205)},
1254 {"medium slate blue" , PALETTERGB (123,104,238)},
1255 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1256 {"light slate blue" , PALETTERGB (132,112,255)},
1257 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1258 {"medium blue" , PALETTERGB ( 0, 0,205)},
1259 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1260 {"royal blue" , PALETTERGB ( 65,105,225)},
1261 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1262 {"blue" , PALETTERGB ( 0, 0,255)},
1263 {"dodger blue" , PALETTERGB ( 30,144,255)},
1264 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1265 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1266 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1267 {"sky blue" , PALETTERGB (135,206,235)},
1268 {"SkyBlue" , PALETTERGB (135,206,235)},
1269 {"light sky blue" , PALETTERGB (135,206,250)},
1270 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1271 {"steel blue" , PALETTERGB ( 70,130,180)},
1272 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1273 {"light steel blue" , PALETTERGB (176,196,222)},
1274 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1275 {"light blue" , PALETTERGB (173,216,230)},
1276 {"LightBlue" , PALETTERGB (173,216,230)},
1277 {"powder blue" , PALETTERGB (176,224,230)},
1278 {"PowderBlue" , PALETTERGB (176,224,230)},
1279 {"pale turquoise" , PALETTERGB (175,238,238)},
1280 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1281 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1282 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1283 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1284 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1285 {"turquoise" , PALETTERGB ( 64,224,208)},
1286 {"cyan" , PALETTERGB ( 0,255,255)},
1287 {"light cyan" , PALETTERGB (224,255,255)},
1288 {"LightCyan" , PALETTERGB (224,255,255)},
1289 {"cadet blue" , PALETTERGB ( 95,158,160)},
1290 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1291 {"medium aquamarine" , PALETTERGB (102,205,170)},
1292 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1293 {"aquamarine" , PALETTERGB (127,255,212)},
1294 {"dark green" , PALETTERGB ( 0,100, 0)},
1295 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1296 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1297 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1298 {"dark sea green" , PALETTERGB (143,188,143)},
1299 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1300 {"sea green" , PALETTERGB ( 46,139, 87)},
1301 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1302 {"medium sea green" , PALETTERGB ( 60,179,113)},
1303 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1304 {"light sea green" , PALETTERGB ( 32,178,170)},
1305 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1306 {"pale green" , PALETTERGB (152,251,152)},
1307 {"PaleGreen" , PALETTERGB (152,251,152)},
1308 {"spring green" , PALETTERGB ( 0,255,127)},
1309 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1310 {"lawn green" , PALETTERGB (124,252, 0)},
1311 {"LawnGreen" , PALETTERGB (124,252, 0)},
1312 {"green" , PALETTERGB ( 0,255, 0)},
1313 {"chartreuse" , PALETTERGB (127,255, 0)},
1314 {"medium spring green" , PALETTERGB ( 0,250,154)},
1315 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1316 {"green yellow" , PALETTERGB (173,255, 47)},
1317 {"GreenYellow" , PALETTERGB (173,255, 47)},
1318 {"lime green" , PALETTERGB ( 50,205, 50)},
1319 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1320 {"yellow green" , PALETTERGB (154,205, 50)},
1321 {"YellowGreen" , PALETTERGB (154,205, 50)},
1322 {"forest green" , PALETTERGB ( 34,139, 34)},
1323 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1324 {"olive drab" , PALETTERGB (107,142, 35)},
1325 {"OliveDrab" , PALETTERGB (107,142, 35)},
1326 {"dark khaki" , PALETTERGB (189,183,107)},
1327 {"DarkKhaki" , PALETTERGB (189,183,107)},
1328 {"khaki" , PALETTERGB (240,230,140)},
1329 {"pale goldenrod" , PALETTERGB (238,232,170)},
1330 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1331 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1332 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1333 {"light yellow" , PALETTERGB (255,255,224)},
1334 {"LightYellow" , PALETTERGB (255,255,224)},
1335 {"yellow" , PALETTERGB (255,255, 0)},
1336 {"gold" , PALETTERGB (255,215, 0)},
1337 {"light goldenrod" , PALETTERGB (238,221,130)},
1338 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1339 {"goldenrod" , PALETTERGB (218,165, 32)},
1340 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1341 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1342 {"rosy brown" , PALETTERGB (188,143,143)},
1343 {"RosyBrown" , PALETTERGB (188,143,143)},
1344 {"indian red" , PALETTERGB (205, 92, 92)},
1345 {"IndianRed" , PALETTERGB (205, 92, 92)},
1346 {"saddle brown" , PALETTERGB (139, 69, 19)},
1347 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1348 {"sienna" , PALETTERGB (160, 82, 45)},
1349 {"peru" , PALETTERGB (205,133, 63)},
1350 {"burlywood" , PALETTERGB (222,184,135)},
1351 {"beige" , PALETTERGB (245,245,220)},
1352 {"wheat" , PALETTERGB (245,222,179)},
1353 {"sandy brown" , PALETTERGB (244,164, 96)},
1354 {"SandyBrown" , PALETTERGB (244,164, 96)},
1355 {"tan" , PALETTERGB (210,180,140)},
1356 {"chocolate" , PALETTERGB (210,105, 30)},
1357 {"firebrick" , PALETTERGB (178,34, 34)},
1358 {"brown" , PALETTERGB (165,42, 42)},
1359 {"dark salmon" , PALETTERGB (233,150,122)},
1360 {"DarkSalmon" , PALETTERGB (233,150,122)},
1361 {"salmon" , PALETTERGB (250,128,114)},
1362 {"light salmon" , PALETTERGB (255,160,122)},
1363 {"LightSalmon" , PALETTERGB (255,160,122)},
1364 {"orange" , PALETTERGB (255,165, 0)},
1365 {"dark orange" , PALETTERGB (255,140, 0)},
1366 {"DarkOrange" , PALETTERGB (255,140, 0)},
1367 {"coral" , PALETTERGB (255,127, 80)},
1368 {"light coral" , PALETTERGB (240,128,128)},
1369 {"LightCoral" , PALETTERGB (240,128,128)},
1370 {"tomato" , PALETTERGB (255, 99, 71)},
1371 {"orange red" , PALETTERGB (255, 69, 0)},
1372 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1373 {"red" , PALETTERGB (255, 0, 0)},
1374 {"hot pink" , PALETTERGB (255,105,180)},
1375 {"HotPink" , PALETTERGB (255,105,180)},
1376 {"deep pink" , PALETTERGB (255, 20,147)},
1377 {"DeepPink" , PALETTERGB (255, 20,147)},
1378 {"pink" , PALETTERGB (255,192,203)},
1379 {"light pink" , PALETTERGB (255,182,193)},
1380 {"LightPink" , PALETTERGB (255,182,193)},
1381 {"pale violet red" , PALETTERGB (219,112,147)},
1382 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1383 {"maroon" , PALETTERGB (176, 48, 96)},
1384 {"medium violet red" , PALETTERGB (199, 21,133)},
1385 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1386 {"violet red" , PALETTERGB (208, 32,144)},
1387 {"VioletRed" , PALETTERGB (208, 32,144)},
1388 {"magenta" , PALETTERGB (255, 0,255)},
1389 {"violet" , PALETTERGB (238,130,238)},
1390 {"plum" , PALETTERGB (221,160,221)},
1391 {"orchid" , PALETTERGB (218,112,214)},
1392 {"medium orchid" , PALETTERGB (186, 85,211)},
1393 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1394 {"dark orchid" , PALETTERGB (153, 50,204)},
1395 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1396 {"dark violet" , PALETTERGB (148, 0,211)},
1397 {"DarkViolet" , PALETTERGB (148, 0,211)},
1398 {"blue violet" , PALETTERGB (138, 43,226)},
1399 {"BlueViolet" , PALETTERGB (138, 43,226)},
1400 {"purple" , PALETTERGB (160, 32,240)},
1401 {"medium purple" , PALETTERGB (147,112,219)},
1402 {"MediumPurple" , PALETTERGB (147,112,219)},
1403 {"thistle" , PALETTERGB (216,191,216)},
1404 {"gray0" , PALETTERGB ( 0, 0, 0)},
1405 {"grey0" , PALETTERGB ( 0, 0, 0)},
1406 {"dark grey" , PALETTERGB (169,169,169)},
1407 {"DarkGrey" , PALETTERGB (169,169,169)},
1408 {"dark gray" , PALETTERGB (169,169,169)},
1409 {"DarkGray" , PALETTERGB (169,169,169)},
1410 {"dark blue" , PALETTERGB ( 0, 0,139)},
1411 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1412 {"dark cyan" , PALETTERGB ( 0,139,139)},
1413 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1414 {"dark magenta" , PALETTERGB (139, 0,139)},
1415 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1416 {"dark red" , PALETTERGB (139, 0, 0)},
1417 {"DarkRed" , PALETTERGB (139, 0, 0)},
1418 {"light green" , PALETTERGB (144,238,144)},
1419 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1420};
1421
fbd6baed 1422DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
ee78dc32
GV
1423 0, 0, 0, "Return the default color map.")
1424 ()
1425{
1426 int i;
fbd6baed 1427 colormap_t *pc = w32_color_map;
ee78dc32
GV
1428 Lisp_Object cmap;
1429
1430 BLOCK_INPUT;
1431
1432 cmap = Qnil;
1433
fbd6baed 1434 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1435 pc++, i++)
1436 cmap = Fcons (Fcons (build_string (pc->name),
1437 make_number (pc->colorref)),
1438 cmap);
1439
1440 UNBLOCK_INPUT;
1441
1442 return (cmap);
1443}
ee78dc32
GV
1444
1445Lisp_Object
fbd6baed 1446w32_to_x_color (rgb)
ee78dc32
GV
1447 Lisp_Object rgb;
1448{
1449 Lisp_Object color;
1450
1451 CHECK_NUMBER (rgb, 0);
1452
1453 BLOCK_INPUT;
1454
fbd6baed 1455 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1456
1457 UNBLOCK_INPUT;
1458
1459 if (!NILP (color))
1460 return (Fcar (color));
1461 else
1462 return Qnil;
1463}
1464
5d7fed93
GV
1465COLORREF
1466w32_color_map_lookup (colorname)
1467 char *colorname;
1468{
1469 Lisp_Object tail, ret = Qnil;
1470
1471 BLOCK_INPUT;
1472
1473 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1474 {
1475 register Lisp_Object elt, tem;
1476
1477 elt = Fcar (tail);
1478 if (!CONSP (elt)) continue;
1479
1480 tem = Fcar (elt);
1481
1482 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1483 {
1484 ret = XUINT (Fcdr (elt));
1485 break;
1486 }
1487
1488 QUIT;
1489 }
1490
1491
1492 UNBLOCK_INPUT;
1493
1494 return ret;
1495}
1496
ee78dc32 1497COLORREF
fbd6baed 1498x_to_w32_color (colorname)
ee78dc32
GV
1499 char * colorname;
1500{
1501 register Lisp_Object tail, ret = Qnil;
1502
1503 BLOCK_INPUT;
1edf84e7
GV
1504
1505 if (colorname[0] == '#')
1506 {
1507 /* Could be an old-style RGB Device specification. */
1508 char *color;
1509 int size;
1510 color = colorname + 1;
1511
1512 size = strlen(color);
1513 if (size == 3 || size == 6 || size == 9 || size == 12)
1514 {
1515 UINT colorval;
1516 int i, pos;
1517 pos = 0;
1518 size /= 3;
1519 colorval = 0;
1520
1521 for (i = 0; i < 3; i++)
1522 {
1523 char *end;
1524 char t;
1525 unsigned long value;
1526
1527 /* The check for 'x' in the following conditional takes into
1528 account the fact that strtol allows a "0x" in front of
1529 our numbers, and we don't. */
1530 if (!isxdigit(color[0]) || color[1] == 'x')
1531 break;
1532 t = color[size];
1533 color[size] = '\0';
1534 value = strtoul(color, &end, 16);
1535 color[size] = t;
1536 if (errno == ERANGE || end - color != size)
1537 break;
1538 switch (size)
1539 {
1540 case 1:
1541 value = value * 0x10;
1542 break;
1543 case 2:
1544 break;
1545 case 3:
1546 value /= 0x10;
1547 break;
1548 case 4:
1549 value /= 0x100;
1550 break;
1551 }
1552 colorval |= (value << pos);
1553 pos += 0x8;
1554 if (i == 2)
1555 {
1556 UNBLOCK_INPUT;
1557 return (colorval);
1558 }
1559 color = end;
1560 }
1561 }
1562 }
1563 else if (strnicmp(colorname, "rgb:", 4) == 0)
1564 {
1565 char *color;
1566 UINT colorval;
1567 int i, pos;
1568 pos = 0;
1569
1570 colorval = 0;
1571 color = colorname + 4;
1572 for (i = 0; i < 3; i++)
1573 {
1574 char *end;
1575 unsigned long value;
1576
1577 /* The check for 'x' in the following conditional takes into
1578 account the fact that strtol allows a "0x" in front of
1579 our numbers, and we don't. */
1580 if (!isxdigit(color[0]) || color[1] == 'x')
1581 break;
1582 value = strtoul(color, &end, 16);
1583 if (errno == ERANGE)
1584 break;
1585 switch (end - color)
1586 {
1587 case 1:
1588 value = value * 0x10 + value;
1589 break;
1590 case 2:
1591 break;
1592 case 3:
1593 value /= 0x10;
1594 break;
1595 case 4:
1596 value /= 0x100;
1597 break;
1598 default:
1599 value = ULONG_MAX;
1600 }
1601 if (value == ULONG_MAX)
1602 break;
1603 colorval |= (value << pos);
1604 pos += 0x8;
1605 if (i == 2)
1606 {
1607 if (*end != '\0')
1608 break;
1609 UNBLOCK_INPUT;
1610 return (colorval);
1611 }
1612 if (*end != '/')
1613 break;
1614 color = end + 1;
1615 }
1616 }
1617 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1618 {
1619 /* This is an RGB Intensity specification. */
1620 char *color;
1621 UINT colorval;
1622 int i, pos;
1623 pos = 0;
1624
1625 colorval = 0;
1626 color = colorname + 5;
1627 for (i = 0; i < 3; i++)
1628 {
1629 char *end;
1630 double value;
1631 UINT val;
1632
1633 value = strtod(color, &end);
1634 if (errno == ERANGE)
1635 break;
1636 if (value < 0.0 || value > 1.0)
1637 break;
1638 val = (UINT)(0x100 * value);
1639 /* We used 0x100 instead of 0xFF to give an continuous
1640 range between 0.0 and 1.0 inclusive. The next statement
1641 fixes the 1.0 case. */
1642 if (val == 0x100)
1643 val = 0xFF;
1644 colorval |= (val << pos);
1645 pos += 0x8;
1646 if (i == 2)
1647 {
1648 if (*end != '\0')
1649 break;
1650 UNBLOCK_INPUT;
1651 return (colorval);
1652 }
1653 if (*end != '/')
1654 break;
1655 color = end + 1;
1656 }
1657 }
1658 /* I am not going to attempt to handle any of the CIE color schemes
1659 or TekHVC, since I don't know the algorithms for conversion to
1660 RGB. */
f695b4b1
GV
1661
1662 /* If we fail to lookup the color name in w32_color_map, then check the
1663 colorname to see if it can be crudely approximated: If the X color
1664 ends in a number (e.g., "darkseagreen2"), strip the number and
1665 return the result of looking up the base color name. */
1666 ret = w32_color_map_lookup (colorname);
1667 if (NILP (ret))
ee78dc32 1668 {
f695b4b1 1669 int len = strlen (colorname);
ee78dc32 1670
f695b4b1
GV
1671 if (isdigit (colorname[len - 1]))
1672 {
1673 char *ptr, *approx = alloca (len);
ee78dc32 1674
f695b4b1
GV
1675 strcpy (approx, colorname);
1676 ptr = &approx[len - 1];
1677 while (ptr > approx && isdigit (*ptr))
1678 *ptr-- = '\0';
ee78dc32 1679
f695b4b1 1680 ret = w32_color_map_lookup (approx);
ee78dc32 1681 }
ee78dc32
GV
1682 }
1683
1684 UNBLOCK_INPUT;
ee78dc32
GV
1685 return ret;
1686}
1687
5ac45f98
GV
1688
1689void
fbd6baed 1690w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1691{
fbd6baed 1692 struct w32_palette_entry * list;
5ac45f98
GV
1693 LOGPALETTE * log_palette;
1694 HPALETTE new_palette;
1695 int i;
1696
1697 /* don't bother trying to create palette if not supported */
fbd6baed 1698 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1699 return;
1700
1701 log_palette = (LOGPALETTE *)
1702 alloca (sizeof (LOGPALETTE) +
fbd6baed 1703 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1704 log_palette->palVersion = 0x300;
fbd6baed 1705 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1706
fbd6baed 1707 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1708 for (i = 0;
fbd6baed 1709 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1710 i++, list = list->next)
1711 log_palette->palPalEntry[i] = list->entry;
1712
1713 new_palette = CreatePalette (log_palette);
1714
1715 enter_crit ();
1716
fbd6baed
GV
1717 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1718 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1719 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1720
1721 /* Realize display palette and garbage all frames. */
1722 release_frame_dc (f, get_frame_dc (f));
1723
1724 leave_crit ();
1725}
1726
fbd6baed
GV
1727#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1728#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1729 do \
1730 { \
1731 pe.peRed = GetRValue (color); \
1732 pe.peGreen = GetGValue (color); \
1733 pe.peBlue = GetBValue (color); \
1734 pe.peFlags = 0; \
1735 } while (0)
1736
1737#if 0
1738/* Keep these around in case we ever want to track color usage. */
1739void
fbd6baed 1740w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1741{
fbd6baed 1742 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1743
fbd6baed 1744 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1745 return;
1746
1747 /* check if color is already mapped */
1748 while (list)
1749 {
fbd6baed 1750 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1751 {
1752 ++list->refcount;
1753 return;
1754 }
1755 list = list->next;
1756 }
1757
1758 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1759 list = (struct w32_palette_entry *)
1760 xmalloc (sizeof (struct w32_palette_entry));
1761 SET_W32_COLOR (list->entry, color);
5ac45f98 1762 list->refcount = 1;
fbd6baed
GV
1763 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1764 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1765 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1766
1767 /* set flag that palette must be regenerated */
fbd6baed 1768 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1769}
1770
1771void
fbd6baed 1772w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1773{
fbd6baed
GV
1774 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1775 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1776
fbd6baed 1777 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1778 return;
1779
1780 /* check if color is already mapped */
1781 while (list)
1782 {
fbd6baed 1783 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1784 {
1785 if (--list->refcount == 0)
1786 {
1787 *prev = list->next;
1788 xfree (list);
fbd6baed 1789 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1790 break;
1791 }
1792 else
1793 return;
1794 }
1795 prev = &list->next;
1796 list = list->next;
1797 }
1798
1799 /* set flag that palette must be regenerated */
fbd6baed 1800 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1801}
1802#endif
1803
6fc2811b
JR
1804
1805/* Gamma-correct COLOR on frame F. */
1806
1807void
1808gamma_correct (f, color)
1809 struct frame *f;
1810 COLORREF *color;
1811{
1812 if (f->gamma)
1813 {
1814 *color = PALETTERGB (
1815 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1816 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1817 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1818 }
1819}
1820
1821
ee78dc32
GV
1822/* Decide if color named COLOR is valid for the display associated with
1823 the selected frame; if so, return the rgb values in COLOR_DEF.
1824 If ALLOC is nonzero, allocate a new colormap cell. */
1825
1826int
6fc2811b 1827w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1828 FRAME_PTR f;
1829 char *color;
6fc2811b 1830 XColor *color_def;
ee78dc32
GV
1831 int alloc;
1832{
1833 register Lisp_Object tem;
6fc2811b 1834 COLORREF w32_color_ref;
3c190163 1835
fbd6baed 1836 tem = x_to_w32_color (color);
3c190163 1837
ee78dc32
GV
1838 if (!NILP (tem))
1839 {
d88c567c
JR
1840 if (f)
1841 {
1842 /* Apply gamma correction. */
1843 w32_color_ref = XUINT (tem);
1844 gamma_correct (f, &w32_color_ref);
1845 XSETINT (tem, w32_color_ref);
1846 }
9badad41
JR
1847
1848 /* Map this color to the palette if it is enabled. */
fbd6baed 1849 if (!NILP (Vw32_enable_palette))
5ac45f98 1850 {
fbd6baed 1851 struct w32_palette_entry * entry =
d88c567c 1852 one_w32_display_info.color_list;
fbd6baed 1853 struct w32_palette_entry ** prev =
d88c567c 1854 &one_w32_display_info.color_list;
5ac45f98
GV
1855
1856 /* check if color is already mapped */
1857 while (entry)
1858 {
fbd6baed 1859 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1860 break;
1861 prev = &entry->next;
1862 entry = entry->next;
1863 }
1864
1865 if (entry == NULL && alloc)
1866 {
1867 /* not already mapped, so add to list */
fbd6baed
GV
1868 entry = (struct w32_palette_entry *)
1869 xmalloc (sizeof (struct w32_palette_entry));
1870 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1871 entry->next = NULL;
1872 *prev = entry;
d88c567c 1873 one_w32_display_info.num_colors++;
5ac45f98
GV
1874
1875 /* set flag that palette must be regenerated */
d88c567c 1876 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1877 }
1878 }
1879 /* Ensure COLORREF value is snapped to nearest color in (default)
1880 palette by simulating the PALETTERGB macro. This works whether
1881 or not the display device has a palette. */
6fc2811b
JR
1882 w32_color_ref = XUINT (tem) | 0x2000000;
1883
6fc2811b
JR
1884 color_def->pixel = w32_color_ref;
1885 color_def->red = GetRValue (w32_color_ref);
1886 color_def->green = GetGValue (w32_color_ref);
1887 color_def->blue = GetBValue (w32_color_ref);
1888
ee78dc32 1889 return 1;
5ac45f98 1890 }
7fb46567 1891 else
3c190163
GV
1892 {
1893 return 0;
1894 }
ee78dc32
GV
1895}
1896
1897/* Given a string ARG naming a color, compute a pixel value from it
1898 suitable for screen F.
1899 If F is not a color screen, return DEF (default) regardless of what
1900 ARG says. */
1901
1902int
1903x_decode_color (f, arg, def)
1904 FRAME_PTR f;
1905 Lisp_Object arg;
1906 int def;
1907{
6fc2811b 1908 XColor cdef;
ee78dc32
GV
1909
1910 CHECK_STRING (arg, 0);
1911
1912 if (strcmp (XSTRING (arg)->data, "black") == 0)
1913 return BLACK_PIX_DEFAULT (f);
1914 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1915 return WHITE_PIX_DEFAULT (f);
1916
fbd6baed 1917 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1918 return def;
1919
6fc2811b 1920 /* w32_defined_color is responsible for coping with failures
ee78dc32 1921 by looking for a near-miss. */
6fc2811b
JR
1922 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1923 return cdef.pixel;
ee78dc32
GV
1924
1925 /* defined_color failed; return an ultimate default. */
1926 return def;
1927}
1928\f
dfff8a69
JR
1929/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1930 the previous value of that parameter, NEW_VALUE is the new value. */
1931
1932static void
1933x_set_line_spacing (f, new_value, old_value)
1934 struct frame *f;
1935 Lisp_Object new_value, old_value;
1936{
1937 if (NILP (new_value))
1938 f->extra_line_spacing = 0;
1939 else if (NATNUMP (new_value))
1940 f->extra_line_spacing = XFASTINT (new_value);
1941 else
1942 Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
1943 Fcons (new_value, Qnil)));
1944 if (FRAME_VISIBLE_P (f))
1945 redraw_frame (f);
1946}
1947
1948
6fc2811b
JR
1949/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1950 the previous value of that parameter, NEW_VALUE is the new value. */
1951
1952static void
1953x_set_screen_gamma (f, new_value, old_value)
1954 struct frame *f;
1955 Lisp_Object new_value, old_value;
1956{
1957 if (NILP (new_value))
1958 f->gamma = 0;
1959 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1960 /* The value 0.4545 is the normal viewing gamma. */
1961 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1962 else
1963 Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
1964 Fcons (new_value, Qnil)));
1965
1966 clear_face_cache (0);
1967}
1968
1969
ee78dc32
GV
1970/* Functions called only from `x_set_frame_param'
1971 to set individual parameters.
1972
fbd6baed 1973 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1974 the frame is being created and its window does not exist yet.
1975 In that case, just record the parameter's new value
1976 in the standard place; do not attempt to change the window. */
1977
1978void
1979x_set_foreground_color (f, arg, oldval)
1980 struct frame *f;
1981 Lisp_Object arg, oldval;
1982{
6fc2811b 1983 FRAME_FOREGROUND_PIXEL (f)
ee78dc32 1984 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
5ac45f98 1985
fbd6baed 1986 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1987 {
6fc2811b 1988 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
1989 if (FRAME_VISIBLE_P (f))
1990 redraw_frame (f);
1991 }
1992}
1993
1994void
1995x_set_background_color (f, arg, oldval)
1996 struct frame *f;
1997 Lisp_Object arg, oldval;
1998{
6fc2811b 1999 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2000 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2001
fbd6baed 2002 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2003 {
6fc2811b
JR
2004 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2005 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2006
6fc2811b 2007 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2008
2009 if (FRAME_VISIBLE_P (f))
2010 redraw_frame (f);
2011 }
2012}
2013
2014void
2015x_set_mouse_color (f, arg, oldval)
2016 struct frame *f;
2017 Lisp_Object arg, oldval;
2018{
6fc2811b 2019
ee78dc32 2020 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2021 int count;
ee78dc32
GV
2022 int mask_color;
2023
2024 if (!EQ (Qnil, arg))
fbd6baed 2025 f->output_data.w32->mouse_pixel
ee78dc32 2026 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2027 mask_color = FRAME_BACKGROUND_PIXEL (f);
2028
2029 /* Don't let pointers be invisible. */
fbd6baed 2030 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2031 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2032 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2033
6fc2811b 2034#if 0 /* NTEMACS_TODO : cursor changes */
ee78dc32
GV
2035 BLOCK_INPUT;
2036
2037 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2038 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2039
2040 if (!EQ (Qnil, Vx_pointer_shape))
2041 {
2042 CHECK_NUMBER (Vx_pointer_shape, 0);
fbd6baed 2043 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2044 }
2045 else
fbd6baed
GV
2046 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2047 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2048
2049 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2050 {
2051 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
fbd6baed 2052 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2053 XINT (Vx_nontext_pointer_shape));
2054 }
2055 else
fbd6baed
GV
2056 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2057 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2058
6fc2811b
JR
2059 if (!EQ (Qnil, Vx_busy_pointer_shape))
2060 {
2061 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
2062 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2063 XINT (Vx_busy_pointer_shape));
2064 }
2065 else
2066 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2067 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2068
2069 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2070 if (!EQ (Qnil, Vx_mode_pointer_shape))
2071 {
2072 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
fbd6baed 2073 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2074 XINT (Vx_mode_pointer_shape));
2075 }
2076 else
fbd6baed
GV
2077 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2078 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2079
2080 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2081 {
2082 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2083 cross_cursor
fbd6baed 2084 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2085 XINT (Vx_sensitive_text_pointer_shape));
2086 }
2087 else
fbd6baed 2088 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32
GV
2089
2090 /* Check and report errors with the above calls. */
fbd6baed 2091 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2092 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2093
2094 {
2095 XColor fore_color, back_color;
2096
fbd6baed 2097 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2098 back_color.pixel = mask_color;
fbd6baed
GV
2099 XQueryColor (FRAME_W32_DISPLAY (f),
2100 DefaultColormap (FRAME_W32_DISPLAY (f),
2101 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2102 &fore_color);
fbd6baed
GV
2103 XQueryColor (FRAME_W32_DISPLAY (f),
2104 DefaultColormap (FRAME_W32_DISPLAY (f),
2105 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2106 &back_color);
fbd6baed 2107 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2108 &fore_color, &back_color);
fbd6baed 2109 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2110 &fore_color, &back_color);
fbd6baed 2111 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2112 &fore_color, &back_color);
fbd6baed 2113 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2114 &fore_color, &back_color);
6fc2811b
JR
2115 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2116 &fore_color, &back_color);
ee78dc32
GV
2117 }
2118
fbd6baed 2119 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2120 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2121
fbd6baed
GV
2122 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2123 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2124 f->output_data.w32->text_cursor = cursor;
2125
2126 if (nontext_cursor != f->output_data.w32->nontext_cursor
2127 && f->output_data.w32->nontext_cursor != 0)
2128 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2129 f->output_data.w32->nontext_cursor = nontext_cursor;
2130
6fc2811b
JR
2131 if (busy_cursor != f->output_data.w32->busy_cursor
2132 && f->output_data.w32->busy_cursor != 0)
2133 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2134 f->output_data.w32->busy_cursor = busy_cursor;
2135
fbd6baed
GV
2136 if (mode_cursor != f->output_data.w32->modeline_cursor
2137 && f->output_data.w32->modeline_cursor != 0)
2138 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2139 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2140
fbd6baed
GV
2141 if (cross_cursor != f->output_data.w32->cross_cursor
2142 && f->output_data.w32->cross_cursor != 0)
2143 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2144 f->output_data.w32->cross_cursor = cross_cursor;
2145
2146 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2147 UNBLOCK_INPUT;
6fc2811b
JR
2148
2149 update_face_from_frame_parameter (f, Qmouse_color, arg);
2150#endif /* NTEMACS_TODO */
ee78dc32
GV
2151}
2152
2153void
2154x_set_cursor_color (f, arg, oldval)
2155 struct frame *f;
2156 Lisp_Object arg, oldval;
2157{
2158 unsigned long fore_pixel;
2159
dfff8a69 2160 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32
GV
2161 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2162 WHITE_PIX_DEFAULT (f));
2163 else
6fc2811b 2164 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
fbd6baed 2165 f->output_data.w32->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2166
2167 /* Make sure that the cursor color differs from the background color. */
6fc2811b 2168 if (f->output_data.w32->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2169 {
fbd6baed
GV
2170 f->output_data.w32->cursor_pixel = f->output_data.w32->mouse_pixel;
2171 if (f->output_data.w32->cursor_pixel == fore_pixel)
6fc2811b 2172 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2173 }
6fc2811b 2174 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
ee78dc32 2175
fbd6baed 2176 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2177 {
2178 if (FRAME_VISIBLE_P (f))
2179 {
2180 x_display_cursor (f, 0);
2181 x_display_cursor (f, 1);
2182 }
2183 }
6fc2811b
JR
2184
2185 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2186}
2187
33d52f9c
GV
2188/* Set the border-color of frame F to pixel value PIX.
2189 Note that this does not fully take effect if done before
2190 F has an window. */
2191void
2192x_set_border_pixel (f, pix)
2193 struct frame *f;
2194 int pix;
2195{
2196 f->output_data.w32->border_pixel = pix;
2197
2198 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2199 {
2200 if (FRAME_VISIBLE_P (f))
2201 redraw_frame (f);
2202 }
2203}
2204
ee78dc32
GV
2205/* Set the border-color of frame F to value described by ARG.
2206 ARG can be a string naming a color.
2207 The border-color is used for the border that is drawn by the server.
2208 Note that this does not fully take effect if done before
2209 F has a window; it must be redone when the window is created. */
2210
2211void
2212x_set_border_color (f, arg, oldval)
2213 struct frame *f;
2214 Lisp_Object arg, oldval;
2215{
ee78dc32
GV
2216 int pix;
2217
2218 CHECK_STRING (arg, 0);
ee78dc32 2219 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2220 x_set_border_pixel (f, pix);
6fc2811b 2221 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2222}
2223
dfff8a69
JR
2224/* Value is the internal representation of the specified cursor type
2225 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2226 of the bar cursor. */
2227
2228enum text_cursor_kinds
2229x_specified_cursor_type (arg, width)
2230 Lisp_Object arg;
2231 int *width;
ee78dc32 2232{
dfff8a69
JR
2233 enum text_cursor_kinds type;
2234
ee78dc32
GV
2235 if (EQ (arg, Qbar))
2236 {
dfff8a69
JR
2237 type = BAR_CURSOR;
2238 *width = 2;
ee78dc32 2239 }
dfff8a69
JR
2240 else if (CONSP (arg)
2241 && EQ (XCAR (arg), Qbar)
2242 && INTEGERP (XCDR (arg))
2243 && XINT (XCDR (arg)) >= 0)
ee78dc32 2244 {
dfff8a69
JR
2245 type = BAR_CURSOR;
2246 *width = XINT (XCDR (arg));
ee78dc32 2247 }
dfff8a69
JR
2248 else if (NILP (arg))
2249 type = NO_CURSOR;
ee78dc32
GV
2250 else
2251 /* Treat anything unknown as "box cursor".
2252 It was bad to signal an error; people have trouble fixing
2253 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2254 type = FILLED_BOX_CURSOR;
2255
2256 return type;
2257}
2258
2259void
2260x_set_cursor_type (f, arg, oldval)
2261 FRAME_PTR f;
2262 Lisp_Object arg, oldval;
2263{
2264 int width;
2265
2266 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2267 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2268
2269 /* Make sure the cursor gets redrawn. This is overkill, but how
2270 often do people change cursor types? */
2271 update_mode_lines++;
2272}
dfff8a69 2273\f
ee78dc32
GV
2274void
2275x_set_icon_type (f, arg, oldval)
2276 struct frame *f;
2277 Lisp_Object arg, oldval;
2278{
ee78dc32
GV
2279 int result;
2280
eb7576ce
GV
2281 if (NILP (arg) && NILP (oldval))
2282 return;
2283
2284 if (STRINGP (arg) && STRINGP (oldval)
2285 && EQ (Fstring_equal (oldval, arg), Qt))
2286 return;
2287
2288 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2289 return;
2290
2291 BLOCK_INPUT;
ee78dc32 2292
eb7576ce 2293 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2294 if (result)
2295 {
2296 UNBLOCK_INPUT;
2297 error ("No icon window available");
2298 }
2299
ee78dc32 2300 UNBLOCK_INPUT;
ee78dc32
GV
2301}
2302
2303/* Return non-nil if frame F wants a bitmap icon. */
2304
2305Lisp_Object
2306x_icon_type (f)
2307 FRAME_PTR f;
2308{
2309 Lisp_Object tem;
2310
2311 tem = assq_no_quit (Qicon_type, f->param_alist);
2312 if (CONSP (tem))
8e713be6 2313 return XCDR (tem);
ee78dc32
GV
2314 else
2315 return Qnil;
2316}
2317
2318void
2319x_set_icon_name (f, arg, oldval)
2320 struct frame *f;
2321 Lisp_Object arg, oldval;
2322{
ee78dc32
GV
2323 int result;
2324
2325 if (STRINGP (arg))
2326 {
2327 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2328 return;
2329 }
2330 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2331 return;
2332
2333 f->icon_name = arg;
2334
2335#if 0
fbd6baed 2336 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2337 return;
2338
2339 BLOCK_INPUT;
2340
2341 result = x_text_icon (f,
1edf84e7 2342 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2343 ? f->icon_name
1edf84e7
GV
2344 : !NILP (f->title)
2345 ? f->title
ee78dc32
GV
2346 : f->name))->data);
2347
2348 if (result)
2349 {
2350 UNBLOCK_INPUT;
2351 error ("No icon window available");
2352 }
2353
2354 /* If the window was unmapped (and its icon was mapped),
2355 the new icon is not mapped, so map the window in its stead. */
2356 if (FRAME_VISIBLE_P (f))
2357 {
2358#ifdef USE_X_TOOLKIT
fbd6baed 2359 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2360#endif
fbd6baed 2361 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2362 }
2363
fbd6baed 2364 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2365 UNBLOCK_INPUT;
2366#endif
2367}
2368
2369extern Lisp_Object x_new_font ();
4587b026 2370extern Lisp_Object x_new_fontset();
ee78dc32
GV
2371
2372void
2373x_set_font (f, arg, oldval)
2374 struct frame *f;
2375 Lisp_Object arg, oldval;
2376{
2377 Lisp_Object result;
4587b026 2378 Lisp_Object fontset_name;
4b817373 2379 Lisp_Object frame;
ee78dc32
GV
2380
2381 CHECK_STRING (arg, 1);
2382
4587b026
GV
2383 fontset_name = Fquery_fontset (arg, Qnil);
2384
ee78dc32 2385 BLOCK_INPUT;
4587b026
GV
2386 result = (STRINGP (fontset_name)
2387 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2388 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2389 UNBLOCK_INPUT;
2390
2391 if (EQ (result, Qnil))
dfff8a69 2392 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2393 else if (EQ (result, Qt))
dfff8a69 2394 error ("The characters of the given font have varying widths");
ee78dc32
GV
2395 else if (STRINGP (result))
2396 {
ee78dc32 2397 store_frame_param (f, Qfont, result);
6fc2811b 2398 recompute_basic_faces (f);
ee78dc32
GV
2399 }
2400 else
2401 abort ();
4b817373 2402
6fc2811b
JR
2403 do_pending_window_change (0);
2404
2405 /* Don't call `face-set-after-frame-default' when faces haven't been
2406 initialized yet. This is the case when called from
2407 Fx_create_frame. In that case, the X widget or window doesn't
2408 exist either, and we can end up in x_report_frame_params with a
2409 null widget which gives a segfault. */
2410 if (FRAME_FACE_CACHE (f))
2411 {
2412 XSETFRAME (frame, f);
2413 call1 (Qface_set_after_frame_default, frame);
2414 }
ee78dc32
GV
2415}
2416
2417void
2418x_set_border_width (f, arg, oldval)
2419 struct frame *f;
2420 Lisp_Object arg, oldval;
2421{
2422 CHECK_NUMBER (arg, 0);
2423
fbd6baed 2424 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2425 return;
2426
fbd6baed 2427 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2428 error ("Cannot change the border width of a window");
2429
fbd6baed 2430 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2431}
2432
2433void
2434x_set_internal_border_width (f, arg, oldval)
2435 struct frame *f;
2436 Lisp_Object arg, oldval;
2437{
fbd6baed 2438 int old = f->output_data.w32->internal_border_width;
ee78dc32
GV
2439
2440 CHECK_NUMBER (arg, 0);
fbd6baed
GV
2441 f->output_data.w32->internal_border_width = XINT (arg);
2442 if (f->output_data.w32->internal_border_width < 0)
2443 f->output_data.w32->internal_border_width = 0;
ee78dc32 2444
fbd6baed 2445 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2446 return;
2447
fbd6baed 2448 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2449 {
ee78dc32 2450 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2451 SET_FRAME_GARBAGED (f);
6fc2811b 2452 do_pending_window_change (0);
ee78dc32
GV
2453 }
2454}
2455
2456void
2457x_set_visibility (f, value, oldval)
2458 struct frame *f;
2459 Lisp_Object value, oldval;
2460{
2461 Lisp_Object frame;
2462 XSETFRAME (frame, f);
2463
2464 if (NILP (value))
2465 Fmake_frame_invisible (frame, Qt);
2466 else if (EQ (value, Qicon))
2467 Ficonify_frame (frame);
2468 else
2469 Fmake_frame_visible (frame);
2470}
2471
2472void
2473x_set_menu_bar_lines (f, value, oldval)
2474 struct frame *f;
2475 Lisp_Object value, oldval;
2476{
2477 int nlines;
2478 int olines = FRAME_MENU_BAR_LINES (f);
2479
2480 /* Right now, menu bars don't work properly in minibuf-only frames;
2481 most of the commands try to apply themselves to the minibuffer
6fc2811b 2482 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2483 in or split the minibuffer window. */
2484 if (FRAME_MINIBUF_ONLY_P (f))
2485 return;
2486
2487 if (INTEGERP (value))
2488 nlines = XINT (value);
2489 else
2490 nlines = 0;
2491
2492 FRAME_MENU_BAR_LINES (f) = 0;
2493 if (nlines)
2494 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2495 else
2496 {
2497 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2498 free_frame_menubar (f);
2499 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2500
2501 /* Adjust the frame size so that the client (text) dimensions
2502 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2503 set correctly. */
2504 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2505 do_pending_window_change (0);
ee78dc32 2506 }
6fc2811b
JR
2507 adjust_glyphs (f);
2508}
2509
2510
2511/* Set the number of lines used for the tool bar of frame F to VALUE.
2512 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2513 is the old number of tool bar lines. This function changes the
2514 height of all windows on frame F to match the new tool bar height.
2515 The frame's height doesn't change. */
2516
2517void
2518x_set_tool_bar_lines (f, value, oldval)
2519 struct frame *f;
2520 Lisp_Object value, oldval;
2521{
2522 int delta, nlines;
2523
2524 /* Use VALUE only if an integer >= 0. */
2525 if (INTEGERP (value) && XINT (value) >= 0)
2526 nlines = XFASTINT (value);
2527 else
2528 nlines = 0;
2529
2530 /* Make sure we redisplay all windows in this frame. */
2531 ++windows_or_buffers_changed;
2532
2533 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2534 FRAME_TOOL_BAR_LINES (f) = nlines;
2535 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2536 do_pending_window_change (0);
2537 adjust_glyphs (f);
ee78dc32
GV
2538}
2539
6fc2811b 2540
ee78dc32 2541/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2542 w32_id_name.
ee78dc32
GV
2543
2544 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2545 name; if NAME is a string, set F's name to NAME and set
2546 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2547
2548 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2549 suggesting a new name, which lisp code should override; if
2550 F->explicit_name is set, ignore the new name; otherwise, set it. */
2551
2552void
2553x_set_name (f, name, explicit)
2554 struct frame *f;
2555 Lisp_Object name;
2556 int explicit;
2557{
2558 /* Make sure that requests from lisp code override requests from
2559 Emacs redisplay code. */
2560 if (explicit)
2561 {
2562 /* If we're switching from explicit to implicit, we had better
2563 update the mode lines and thereby update the title. */
2564 if (f->explicit_name && NILP (name))
2565 update_mode_lines = 1;
2566
2567 f->explicit_name = ! NILP (name);
2568 }
2569 else if (f->explicit_name)
2570 return;
2571
fbd6baed 2572 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2573 if (NILP (name))
2574 {
2575 /* Check for no change needed in this very common case
2576 before we do any consing. */
fbd6baed 2577 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2578 XSTRING (f->name)->data))
2579 return;
fbd6baed 2580 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2581 }
2582 else
2583 CHECK_STRING (name, 0);
2584
2585 /* Don't change the name if it's already NAME. */
2586 if (! NILP (Fstring_equal (name, f->name)))
2587 return;
2588
1edf84e7
GV
2589 f->name = name;
2590
2591 /* For setting the frame title, the title parameter should override
2592 the name parameter. */
2593 if (! NILP (f->title))
2594 name = f->title;
2595
fbd6baed 2596 if (FRAME_W32_WINDOW (f))
ee78dc32 2597 {
6fc2811b 2598 if (STRING_MULTIBYTE (name))
dfff8a69 2599 name = ENCODE_SYSTEM (name);
6fc2811b 2600
ee78dc32 2601 BLOCK_INPUT;
fbd6baed 2602 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2603 UNBLOCK_INPUT;
2604 }
ee78dc32
GV
2605}
2606
2607/* This function should be called when the user's lisp code has
2608 specified a name for the frame; the name will override any set by the
2609 redisplay code. */
2610void
2611x_explicitly_set_name (f, arg, oldval)
2612 FRAME_PTR f;
2613 Lisp_Object arg, oldval;
2614{
2615 x_set_name (f, arg, 1);
2616}
2617
2618/* This function should be called by Emacs redisplay code to set the
2619 name; names set this way will never override names set by the user's
2620 lisp code. */
2621void
2622x_implicitly_set_name (f, arg, oldval)
2623 FRAME_PTR f;
2624 Lisp_Object arg, oldval;
2625{
2626 x_set_name (f, arg, 0);
2627}
1edf84e7
GV
2628\f
2629/* Change the title of frame F to NAME.
2630 If NAME is nil, use the frame name as the title.
2631
2632 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2633 name; if NAME is a string, set F's name to NAME and set
2634 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2635
2636 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2637 suggesting a new name, which lisp code should override; if
2638 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2639
1edf84e7 2640void
6fc2811b 2641x_set_title (f, name, old_name)
1edf84e7 2642 struct frame *f;
6fc2811b 2643 Lisp_Object name, old_name;
1edf84e7
GV
2644{
2645 /* Don't change the title if it's already NAME. */
2646 if (EQ (name, f->title))
2647 return;
2648
2649 update_mode_lines = 1;
2650
2651 f->title = name;
2652
2653 if (NILP (name))
2654 name = f->name;
2655
2656 if (FRAME_W32_WINDOW (f))
2657 {
6fc2811b 2658 if (STRING_MULTIBYTE (name))
dfff8a69 2659 name = ENCODE_SYSTEM (name);
6fc2811b 2660
1edf84e7
GV
2661 BLOCK_INPUT;
2662 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2663 UNBLOCK_INPUT;
2664 }
2665}
2666\f
ee78dc32
GV
2667void
2668x_set_autoraise (f, arg, oldval)
2669 struct frame *f;
2670 Lisp_Object arg, oldval;
2671{
2672 f->auto_raise = !EQ (Qnil, arg);
2673}
2674
2675void
2676x_set_autolower (f, arg, oldval)
2677 struct frame *f;
2678 Lisp_Object arg, oldval;
2679{
2680 f->auto_lower = !EQ (Qnil, arg);
2681}
2682
2683void
2684x_set_unsplittable (f, arg, oldval)
2685 struct frame *f;
2686 Lisp_Object arg, oldval;
2687{
2688 f->no_split = !NILP (arg);
2689}
2690
2691void
2692x_set_vertical_scroll_bars (f, arg, oldval)
2693 struct frame *f;
2694 Lisp_Object arg, oldval;
2695{
1026b400
RS
2696 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2697 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2698 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2699 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2700 {
1026b400
RS
2701 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2702 vertical_scroll_bar_none :
87996783
GV
2703 /* Put scroll bars on the right by default, as is conventional
2704 on MS-Windows. */
2705 EQ (Qleft, arg)
2706 ? vertical_scroll_bar_left
2707 : vertical_scroll_bar_right;
ee78dc32
GV
2708
2709 /* We set this parameter before creating the window for the
2710 frame, so we can get the geometry right from the start.
2711 However, if the window hasn't been created yet, we shouldn't
2712 call x_set_window_size. */
fbd6baed 2713 if (FRAME_W32_WINDOW (f))
ee78dc32 2714 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2715 do_pending_window_change (0);
ee78dc32
GV
2716 }
2717}
2718
2719void
2720x_set_scroll_bar_width (f, arg, oldval)
2721 struct frame *f;
2722 Lisp_Object arg, oldval;
2723{
6fc2811b
JR
2724 int wid = FONT_WIDTH (f->output_data.w32->font);
2725
ee78dc32
GV
2726 if (NILP (arg))
2727 {
6fc2811b
JR
2728 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2729 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2730 wid - 1) / wid;
2731 if (FRAME_W32_WINDOW (f))
2732 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2733 do_pending_window_change (0);
ee78dc32
GV
2734 }
2735 else if (INTEGERP (arg) && XINT (arg) > 0
2736 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2737 {
ee78dc32 2738 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2739 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2740 + wid-1) / wid;
fbd6baed 2741 if (FRAME_W32_WINDOW (f))
ee78dc32 2742 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2743 do_pending_window_change (0);
ee78dc32 2744 }
6fc2811b
JR
2745 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2746 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2747 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2748}
2749\f
2750/* Subroutines of creating an frame. */
2751
2752/* Make sure that Vx_resource_name is set to a reasonable value.
2753 Fix it up, or set it to `emacs' if it is too hopeless. */
2754
2755static void
2756validate_x_resource_name ()
2757{
6fc2811b 2758 int len = 0;
ee78dc32
GV
2759 /* Number of valid characters in the resource name. */
2760 int good_count = 0;
2761 /* Number of invalid characters in the resource name. */
2762 int bad_count = 0;
2763 Lisp_Object new;
2764 int i;
2765
2766 if (STRINGP (Vx_resource_name))
2767 {
2768 unsigned char *p = XSTRING (Vx_resource_name)->data;
2769 int i;
2770
dfff8a69 2771 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2772
2773 /* Only letters, digits, - and _ are valid in resource names.
2774 Count the valid characters and count the invalid ones. */
2775 for (i = 0; i < len; i++)
2776 {
2777 int c = p[i];
2778 if (! ((c >= 'a' && c <= 'z')
2779 || (c >= 'A' && c <= 'Z')
2780 || (c >= '0' && c <= '9')
2781 || c == '-' || c == '_'))
2782 bad_count++;
2783 else
2784 good_count++;
2785 }
2786 }
2787 else
2788 /* Not a string => completely invalid. */
2789 bad_count = 5, good_count = 0;
2790
2791 /* If name is valid already, return. */
2792 if (bad_count == 0)
2793 return;
2794
2795 /* If name is entirely invalid, or nearly so, use `emacs'. */
2796 if (good_count == 0
2797 || (good_count == 1 && bad_count > 0))
2798 {
2799 Vx_resource_name = build_string ("emacs");
2800 return;
2801 }
2802
2803 /* Name is partly valid. Copy it and replace the invalid characters
2804 with underscores. */
2805
2806 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2807
2808 for (i = 0; i < len; i++)
2809 {
2810 int c = XSTRING (new)->data[i];
2811 if (! ((c >= 'a' && c <= 'z')
2812 || (c >= 'A' && c <= 'Z')
2813 || (c >= '0' && c <= '9')
2814 || c == '-' || c == '_'))
2815 XSTRING (new)->data[i] = '_';
2816 }
2817}
2818
2819
2820extern char *x_get_string_resource ();
2821
2822DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2823 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2824This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2825class, where INSTANCE is the name under which Emacs was invoked, or\n\
2826the name specified by the `-name' or `-rn' command-line arguments.\n\
2827\n\
2828The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2829class, respectively. You must specify both of them or neither.\n\
2830If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2831and the class is `Emacs.CLASS.SUBCLASS'.")
2832 (attribute, class, component, subclass)
2833 Lisp_Object attribute, class, component, subclass;
2834{
2835 register char *value;
2836 char *name_key;
2837 char *class_key;
2838
2839 CHECK_STRING (attribute, 0);
2840 CHECK_STRING (class, 0);
2841
2842 if (!NILP (component))
2843 CHECK_STRING (component, 1);
2844 if (!NILP (subclass))
2845 CHECK_STRING (subclass, 2);
2846 if (NILP (component) != NILP (subclass))
2847 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2848
2849 validate_x_resource_name ();
2850
2851 /* Allocate space for the components, the dots which separate them,
2852 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 2853 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 2854 + (STRINGP (component)
dfff8a69
JR
2855 ? STRING_BYTES (XSTRING (component)) : 0)
2856 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
2857 + 3);
2858
2859 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 2860 + STRING_BYTES (XSTRING (class))
ee78dc32 2861 + (STRINGP (subclass)
dfff8a69 2862 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
2863 + 3);
2864
2865 /* Start with emacs.FRAMENAME for the name (the specific one)
2866 and with `Emacs' for the class key (the general one). */
2867 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2868 strcpy (class_key, EMACS_CLASS);
2869
2870 strcat (class_key, ".");
2871 strcat (class_key, XSTRING (class)->data);
2872
2873 if (!NILP (component))
2874 {
2875 strcat (class_key, ".");
2876 strcat (class_key, XSTRING (subclass)->data);
2877
2878 strcat (name_key, ".");
2879 strcat (name_key, XSTRING (component)->data);
2880 }
2881
2882 strcat (name_key, ".");
2883 strcat (name_key, XSTRING (attribute)->data);
2884
2885 value = x_get_string_resource (Qnil,
2886 name_key, class_key);
2887
2888 if (value != (char *) 0)
2889 return build_string (value);
2890 else
2891 return Qnil;
2892}
2893
2894/* Used when C code wants a resource value. */
2895
2896char *
2897x_get_resource_string (attribute, class)
2898 char *attribute, *class;
2899{
ee78dc32
GV
2900 char *name_key;
2901 char *class_key;
6fc2811b 2902 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
2903
2904 /* Allocate space for the components, the dots which separate them,
2905 and the final '\0'. */
dfff8a69 2906 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
2907 + strlen (attribute) + 2);
2908 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2909 + strlen (class) + 2);
2910
2911 sprintf (name_key, "%s.%s",
2912 XSTRING (Vinvocation_name)->data,
2913 attribute);
2914 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2915
6fc2811b 2916 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
2917}
2918
2919/* Types we might convert a resource string into. */
2920enum resource_types
6fc2811b
JR
2921{
2922 RES_TYPE_NUMBER,
2923 RES_TYPE_FLOAT,
2924 RES_TYPE_BOOLEAN,
2925 RES_TYPE_STRING,
2926 RES_TYPE_SYMBOL
2927};
ee78dc32
GV
2928
2929/* Return the value of parameter PARAM.
2930
2931 First search ALIST, then Vdefault_frame_alist, then the X defaults
2932 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2933
2934 Convert the resource to the type specified by desired_type.
2935
2936 If no default is specified, return Qunbound. If you call
6fc2811b 2937 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
2938 and don't let it get stored in any Lisp-visible variables! */
2939
2940static Lisp_Object
6fc2811b 2941w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
2942 Lisp_Object alist, param;
2943 char *attribute;
2944 char *class;
2945 enum resource_types type;
2946{
2947 register Lisp_Object tem;
2948
2949 tem = Fassq (param, alist);
2950 if (EQ (tem, Qnil))
2951 tem = Fassq (param, Vdefault_frame_alist);
2952 if (EQ (tem, Qnil))
2953 {
2954
2955 if (attribute)
2956 {
2957 tem = Fx_get_resource (build_string (attribute),
2958 build_string (class),
2959 Qnil, Qnil);
2960
2961 if (NILP (tem))
2962 return Qunbound;
2963
2964 switch (type)
2965 {
6fc2811b 2966 case RES_TYPE_NUMBER:
ee78dc32
GV
2967 return make_number (atoi (XSTRING (tem)->data));
2968
6fc2811b
JR
2969 case RES_TYPE_FLOAT:
2970 return make_float (atof (XSTRING (tem)->data));
2971
2972 case RES_TYPE_BOOLEAN:
ee78dc32
GV
2973 tem = Fdowncase (tem);
2974 if (!strcmp (XSTRING (tem)->data, "on")
2975 || !strcmp (XSTRING (tem)->data, "true"))
2976 return Qt;
2977 else
2978 return Qnil;
2979
6fc2811b 2980 case RES_TYPE_STRING:
ee78dc32
GV
2981 return tem;
2982
6fc2811b 2983 case RES_TYPE_SYMBOL:
ee78dc32
GV
2984 /* As a special case, we map the values `true' and `on'
2985 to Qt, and `false' and `off' to Qnil. */
2986 {
2987 Lisp_Object lower;
2988 lower = Fdowncase (tem);
2989 if (!strcmp (XSTRING (lower)->data, "on")
2990 || !strcmp (XSTRING (lower)->data, "true"))
2991 return Qt;
2992 else if (!strcmp (XSTRING (lower)->data, "off")
2993 || !strcmp (XSTRING (lower)->data, "false"))
2994 return Qnil;
2995 else
2996 return Fintern (tem, Qnil);
2997 }
2998
2999 default:
3000 abort ();
3001 }
3002 }
3003 else
3004 return Qunbound;
3005 }
3006 return Fcdr (tem);
3007}
3008
3009/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3010 of the parameter named PROP (a Lisp symbol).
3011 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3012 on the frame named NAME.
3013 If that is not found either, use the value DEFLT. */
3014
3015static Lisp_Object
3016x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3017 struct frame *f;
3018 Lisp_Object alist;
3019 Lisp_Object prop;
3020 Lisp_Object deflt;
3021 char *xprop;
3022 char *xclass;
3023 enum resource_types type;
3024{
3025 Lisp_Object tem;
3026
6fc2811b 3027 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3028 if (EQ (tem, Qunbound))
3029 tem = deflt;
3030 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3031 return tem;
3032}
3033\f
3034DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3035 "Parse an X-style geometry string STRING.\n\
3036Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3037The properties returned may include `top', `left', `height', and `width'.\n\
3038The value of `left' or `top' may be an integer,\n\
3039or a list (+ N) meaning N pixels relative to top/left corner,\n\
3040or a list (- N) meaning -N pixels relative to bottom/right corner.")
3041 (string)
3042 Lisp_Object string;
3043{
3044 int geometry, x, y;
3045 unsigned int width, height;
3046 Lisp_Object result;
3047
3048 CHECK_STRING (string, 0);
3049
3050 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3051 &x, &y, &width, &height);
3052
3053 result = Qnil;
3054 if (geometry & XValue)
3055 {
3056 Lisp_Object element;
3057
3058 if (x >= 0 && (geometry & XNegative))
3059 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3060 else if (x < 0 && ! (geometry & XNegative))
3061 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3062 else
3063 element = Fcons (Qleft, make_number (x));
3064 result = Fcons (element, result);
3065 }
3066
3067 if (geometry & YValue)
3068 {
3069 Lisp_Object element;
3070
3071 if (y >= 0 && (geometry & YNegative))
3072 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3073 else if (y < 0 && ! (geometry & YNegative))
3074 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3075 else
3076 element = Fcons (Qtop, make_number (y));
3077 result = Fcons (element, result);
3078 }
3079
3080 if (geometry & WidthValue)
3081 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3082 if (geometry & HeightValue)
3083 result = Fcons (Fcons (Qheight, make_number (height)), result);
3084
3085 return result;
3086}
3087
3088/* Calculate the desired size and position of this window,
3089 and return the flags saying which aspects were specified.
3090
3091 This function does not make the coordinates positive. */
3092
3093#define DEFAULT_ROWS 40
3094#define DEFAULT_COLS 80
3095
3096static int
3097x_figure_window_size (f, parms)
3098 struct frame *f;
3099 Lisp_Object parms;
3100{
3101 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3102 long window_prompting = 0;
3103
3104 /* Default values if we fall through.
3105 Actually, if that happens we should get
3106 window manager prompting. */
1026b400 3107 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3108 f->height = DEFAULT_ROWS;
3109 /* Window managers expect that if program-specified
3110 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3111 f->output_data.w32->top_pos = 0;
3112 f->output_data.w32->left_pos = 0;
ee78dc32 3113
6fc2811b
JR
3114 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3115 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3116 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3117 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3118 {
3119 if (!EQ (tem0, Qunbound))
3120 {
3121 CHECK_NUMBER (tem0, 0);
3122 f->height = XINT (tem0);
3123 }
3124 if (!EQ (tem1, Qunbound))
3125 {
3126 CHECK_NUMBER (tem1, 0);
1026b400 3127 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3128 }
3129 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3130 window_prompting |= USSize;
3131 else
3132 window_prompting |= PSize;
3133 }
3134
fbd6baed 3135 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3136 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3137 ? 0
3138 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3139 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3140 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
6fc2811b
JR
3141 f->output_data.w32->flags_areas_extra
3142 = FRAME_FLAGS_AREA_WIDTH (f);
fbd6baed
GV
3143 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3144 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3145
6fc2811b
JR
3146 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3147 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3148 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3149 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3150 {
3151 if (EQ (tem0, Qminus))
3152 {
fbd6baed 3153 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3154 window_prompting |= YNegative;
3155 }
8e713be6
KR
3156 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3157 && CONSP (XCDR (tem0))
3158 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3159 {
8e713be6 3160 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3161 window_prompting |= YNegative;
3162 }
8e713be6
KR
3163 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3164 && CONSP (XCDR (tem0))
3165 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3166 {
8e713be6 3167 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3168 }
3169 else if (EQ (tem0, Qunbound))
fbd6baed 3170 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3171 else
3172 {
3173 CHECK_NUMBER (tem0, 0);
fbd6baed
GV
3174 f->output_data.w32->top_pos = XINT (tem0);
3175 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3176 window_prompting |= YNegative;
3177 }
3178
3179 if (EQ (tem1, Qminus))
3180 {
fbd6baed 3181 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3182 window_prompting |= XNegative;
3183 }
8e713be6
KR
3184 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3185 && CONSP (XCDR (tem1))
3186 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3187 {
8e713be6 3188 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3189 window_prompting |= XNegative;
3190 }
8e713be6
KR
3191 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3192 && CONSP (XCDR (tem1))
3193 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3194 {
8e713be6 3195 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3196 }
3197 else if (EQ (tem1, Qunbound))
fbd6baed 3198 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3199 else
3200 {
3201 CHECK_NUMBER (tem1, 0);
fbd6baed
GV
3202 f->output_data.w32->left_pos = XINT (tem1);
3203 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3204 window_prompting |= XNegative;
3205 }
3206
3207 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3208 window_prompting |= USPosition;
3209 else
3210 window_prompting |= PPosition;
3211 }
3212
3213 return window_prompting;
3214}
3215
3216\f
3217
fbd6baed 3218extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3219
3220BOOL
fbd6baed 3221w32_init_class (hinst)
ee78dc32
GV
3222 HINSTANCE hinst;
3223{
3224 WNDCLASS wc;
3225
5ac45f98 3226 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3227 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3228 wc.cbClsExtra = 0;
3229 wc.cbWndExtra = WND_EXTRA_BYTES;
3230 wc.hInstance = hinst;
3231 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3232 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3233 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3234 wc.lpszMenuName = NULL;
3235 wc.lpszClassName = EMACS_CLASS;
3236
3237 return (RegisterClass (&wc));
3238}
3239
3240HWND
fbd6baed 3241w32_createscrollbar (f, bar)
ee78dc32
GV
3242 struct frame *f;
3243 struct scroll_bar * bar;
3244{
3245 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3246 /* Position and size of scroll bar. */
6fc2811b
JR
3247 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3248 XINT(bar->top),
3249 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3250 XINT(bar->height),
fbd6baed 3251 FRAME_W32_WINDOW (f),
ee78dc32
GV
3252 NULL,
3253 hinst,
3254 NULL));
3255}
3256
3257void
fbd6baed 3258w32_createwindow (f)
ee78dc32
GV
3259 struct frame *f;
3260{
3261 HWND hwnd;
1edf84e7
GV
3262 RECT rect;
3263
3264 rect.left = rect.top = 0;
3265 rect.right = PIXEL_WIDTH (f);
3266 rect.bottom = PIXEL_HEIGHT (f);
3267
3268 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3269 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3270
3271 /* Do first time app init */
3272
3273 if (!hprevinst)
3274 {
fbd6baed 3275 w32_init_class (hinst);
ee78dc32
GV
3276 }
3277
1edf84e7
GV
3278 FRAME_W32_WINDOW (f) = hwnd
3279 = CreateWindow (EMACS_CLASS,
3280 f->namebuf,
3281 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3282 f->output_data.w32->left_pos,
3283 f->output_data.w32->top_pos,
3284 rect.right - rect.left,
3285 rect.bottom - rect.top,
3286 NULL,
3287 NULL,
3288 hinst,
3289 NULL);
3290
ee78dc32
GV
3291 if (hwnd)
3292 {
1edf84e7
GV
3293 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3294 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3295 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3296 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3297 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3298
cb9e33d4
RS
3299 /* Enable drag-n-drop. */
3300 DragAcceptFiles (hwnd, TRUE);
3301
5ac45f98
GV
3302 /* Do this to discard the default setting specified by our parent. */
3303 ShowWindow (hwnd, SW_HIDE);
3c190163 3304 }
3c190163
GV
3305}
3306
ee78dc32
GV
3307void
3308my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3309 W32Msg * wmsg;
ee78dc32
GV
3310 HWND hwnd;
3311 UINT msg;
3312 WPARAM wParam;
3313 LPARAM lParam;
3314{
3315 wmsg->msg.hwnd = hwnd;
3316 wmsg->msg.message = msg;
3317 wmsg->msg.wParam = wParam;
3318 wmsg->msg.lParam = lParam;
3319 wmsg->msg.time = GetMessageTime ();
3320
3321 post_msg (wmsg);
3322}
3323
e9e23e23 3324/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3325 between left and right keys as advertised. We test for this
3326 support dynamically, and set a flag when the support is absent. If
3327 absent, we keep track of the left and right control and alt keys
3328 ourselves. This is particularly necessary on keyboards that rely
3329 upon the AltGr key, which is represented as having the left control
3330 and right alt keys pressed. For these keyboards, we need to know
3331 when the left alt key has been pressed in addition to the AltGr key
3332 so that we can properly support M-AltGr-key sequences (such as M-@
3333 on Swedish keyboards). */
3334
3335#define EMACS_LCONTROL 0
3336#define EMACS_RCONTROL 1
3337#define EMACS_LMENU 2
3338#define EMACS_RMENU 3
3339
3340static int modifiers[4];
3341static int modifiers_recorded;
3342static int modifier_key_support_tested;
3343
3344static void
3345test_modifier_support (unsigned int wparam)
3346{
3347 unsigned int l, r;
3348
3349 if (wparam != VK_CONTROL && wparam != VK_MENU)
3350 return;
3351 if (wparam == VK_CONTROL)
3352 {
3353 l = VK_LCONTROL;
3354 r = VK_RCONTROL;
3355 }
3356 else
3357 {
3358 l = VK_LMENU;
3359 r = VK_RMENU;
3360 }
3361 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3362 modifiers_recorded = 1;
3363 else
3364 modifiers_recorded = 0;
3365 modifier_key_support_tested = 1;
3366}
3367
3368static void
3369record_keydown (unsigned int wparam, unsigned int lparam)
3370{
3371 int i;
3372
3373 if (!modifier_key_support_tested)
3374 test_modifier_support (wparam);
3375
3376 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3377 return;
3378
3379 if (wparam == VK_CONTROL)
3380 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3381 else
3382 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3383
3384 modifiers[i] = 1;
3385}
3386
3387static void
3388record_keyup (unsigned int wparam, unsigned int lparam)
3389{
3390 int i;
3391
3392 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3393 return;
3394
3395 if (wparam == VK_CONTROL)
3396 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3397 else
3398 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3399
3400 modifiers[i] = 0;
3401}
3402
da36a4d6
GV
3403/* Emacs can lose focus while a modifier key has been pressed. When
3404 it regains focus, be conservative and clear all modifiers since
3405 we cannot reconstruct the left and right modifier state. */
3406static void
3407reset_modifiers ()
3408{
8681157a
RS
3409 SHORT ctrl, alt;
3410
adcc3809
GV
3411 if (GetFocus () == NULL)
3412 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3413 return;
8681157a
RS
3414
3415 ctrl = GetAsyncKeyState (VK_CONTROL);
3416 alt = GetAsyncKeyState (VK_MENU);
3417
8681157a
RS
3418 if (!(ctrl & 0x08000))
3419 /* Clear any recorded control modifier state. */
3420 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3421
3422 if (!(alt & 0x08000))
3423 /* Clear any recorded alt modifier state. */
3424 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3425
adcc3809
GV
3426 /* Update the state of all modifier keys, because modifiers used in
3427 hot-key combinations can get stuck on if Emacs loses focus as a
3428 result of a hot-key being pressed. */
3429 {
3430 BYTE keystate[256];
3431
3432#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3433
3434 GetKeyboardState (keystate);
3435 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3436 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3437 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3438 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3439 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3440 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3441 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3442 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3443 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3444 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3445 SetKeyboardState (keystate);
3446 }
da36a4d6
GV
3447}
3448
7830e24b
RS
3449/* Synchronize modifier state with what is reported with the current
3450 keystroke. Even if we cannot distinguish between left and right
3451 modifier keys, we know that, if no modifiers are set, then neither
3452 the left or right modifier should be set. */
3453static void
3454sync_modifiers ()
3455{
3456 if (!modifiers_recorded)
3457 return;
3458
3459 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3460 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3461
3462 if (!(GetKeyState (VK_MENU) & 0x8000))
3463 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3464}
3465
a1a80b40
GV
3466static int
3467modifier_set (int vkey)
3468{
ccc2d29c 3469 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3470 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3471 if (!modifiers_recorded)
3472 return (GetKeyState (vkey) & 0x8000);
3473
3474 switch (vkey)
3475 {
3476 case VK_LCONTROL:
3477 return modifiers[EMACS_LCONTROL];
3478 case VK_RCONTROL:
3479 return modifiers[EMACS_RCONTROL];
3480 case VK_LMENU:
3481 return modifiers[EMACS_LMENU];
3482 case VK_RMENU:
3483 return modifiers[EMACS_RMENU];
a1a80b40
GV
3484 }
3485 return (GetKeyState (vkey) & 0x8000);
3486}
3487
ccc2d29c
GV
3488/* Convert between the modifier bits W32 uses and the modifier bits
3489 Emacs uses. */
3490
3491unsigned int
3492w32_key_to_modifier (int key)
3493{
3494 Lisp_Object key_mapping;
3495
3496 switch (key)
3497 {
3498 case VK_LWIN:
3499 key_mapping = Vw32_lwindow_modifier;
3500 break;
3501 case VK_RWIN:
3502 key_mapping = Vw32_rwindow_modifier;
3503 break;
3504 case VK_APPS:
3505 key_mapping = Vw32_apps_modifier;
3506 break;
3507 case VK_SCROLL:
3508 key_mapping = Vw32_scroll_lock_modifier;
3509 break;
3510 default:
3511 key_mapping = Qnil;
3512 }
3513
adcc3809
GV
3514 /* NB. This code runs in the input thread, asychronously to the lisp
3515 thread, so we must be careful to ensure access to lisp data is
3516 thread-safe. The following code is safe because the modifier
3517 variable values are updated atomically from lisp and symbols are
3518 not relocated by GC. Also, we don't have to worry about seeing GC
3519 markbits here. */
3520 if (EQ (key_mapping, Qhyper))
ccc2d29c 3521 return hyper_modifier;
adcc3809 3522 if (EQ (key_mapping, Qsuper))
ccc2d29c 3523 return super_modifier;
adcc3809 3524 if (EQ (key_mapping, Qmeta))
ccc2d29c 3525 return meta_modifier;
adcc3809 3526 if (EQ (key_mapping, Qalt))
ccc2d29c 3527 return alt_modifier;
adcc3809 3528 if (EQ (key_mapping, Qctrl))
ccc2d29c 3529 return ctrl_modifier;
adcc3809 3530 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3531 return ctrl_modifier;
adcc3809 3532 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3533 return shift_modifier;
3534
3535 /* Don't generate any modifier if not explicitly requested. */
3536 return 0;
3537}
3538
3539unsigned int
3540w32_get_modifiers ()
3541{
3542 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3543 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3544 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3545 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3546 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3547 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3548 (modifier_set (VK_MENU) ?
3549 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3550}
3551
a1a80b40
GV
3552/* We map the VK_* modifiers into console modifier constants
3553 so that we can use the same routines to handle both console
3554 and window input. */
3555
3556static int
ccc2d29c 3557construct_console_modifiers ()
a1a80b40
GV
3558{
3559 int mods;
3560
a1a80b40
GV
3561 mods = 0;
3562 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3563 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3564 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3565 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3566 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3567 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3568 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3569 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3570 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3571 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3572 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3573
3574 return mods;
3575}
3576
ccc2d29c
GV
3577static int
3578w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3579{
ccc2d29c
GV
3580 int mods;
3581
3582 /* Convert to emacs modifiers. */
3583 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3584
3585 return mods;
3586}
da36a4d6 3587
ccc2d29c
GV
3588unsigned int
3589map_keypad_keys (unsigned int virt_key, unsigned int extended)
3590{
3591 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3592 return virt_key;
da36a4d6 3593
ccc2d29c 3594 if (virt_key == VK_RETURN)
da36a4d6
GV
3595 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3596
ccc2d29c
GV
3597 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3598 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3599
3600 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3601 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3602
3603 if (virt_key == VK_CLEAR)
3604 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3605
3606 return virt_key;
3607}
3608
3609/* List of special key combinations which w32 would normally capture,
3610 but emacs should grab instead. Not directly visible to lisp, to
3611 simplify synchronization. Each item is an integer encoding a virtual
3612 key code and modifier combination to capture. */
3613Lisp_Object w32_grabbed_keys;
3614
3615#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3616#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3617#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3618#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3619
3620/* Register hot-keys for reserved key combinations when Emacs has
3621 keyboard focus, since this is the only way Emacs can receive key
3622 combinations like Alt-Tab which are used by the system. */
3623
3624static void
3625register_hot_keys (hwnd)
3626 HWND hwnd;
3627{
3628 Lisp_Object keylist;
3629
3630 /* Use GC_CONSP, since we are called asynchronously. */
3631 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3632 {
3633 Lisp_Object key = XCAR (keylist);
3634
3635 /* Deleted entries get set to nil. */
3636 if (!INTEGERP (key))
3637 continue;
3638
3639 RegisterHotKey (hwnd, HOTKEY_ID (key),
3640 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3641 }
3642}
3643
3644static void
3645unregister_hot_keys (hwnd)
3646 HWND hwnd;
3647{
3648 Lisp_Object keylist;
3649
3650 /* Use GC_CONSP, since we are called asynchronously. */
3651 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3652 {
3653 Lisp_Object key = XCAR (keylist);
3654
3655 if (!INTEGERP (key))
3656 continue;
3657
3658 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3659 }
3660}
3661
5ac45f98
GV
3662/* Main message dispatch loop. */
3663
1edf84e7
GV
3664static void
3665w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3666{
3667 MSG msg;
ccc2d29c
GV
3668 int result;
3669 HWND focus_window;
93fbe8b7
GV
3670
3671 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3672
5ac45f98
GV
3673 while (GetMessage (&msg, NULL, 0, 0))
3674 {
3675 if (msg.hwnd == NULL)
3676 {
3677 switch (msg.message)
3678 {
3ef68e6b
AI
3679 case WM_NULL:
3680 /* Produced by complete_deferred_msg; just ignore. */
3681 break;
5ac45f98 3682 case WM_EMACS_CREATEWINDOW:
fbd6baed 3683 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3684 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3685 abort ();
5ac45f98 3686 break;
dfdb4047
GV
3687 case WM_EMACS_SETLOCALE:
3688 SetThreadLocale (msg.wParam);
3689 /* Reply is not expected. */
3690 break;
ccc2d29c
GV
3691 case WM_EMACS_SETKEYBOARDLAYOUT:
3692 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3693 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3694 result, 0))
3695 abort ();
3696 break;
3697 case WM_EMACS_REGISTER_HOT_KEY:
3698 focus_window = GetFocus ();
3699 if (focus_window != NULL)
3700 RegisterHotKey (focus_window,
3701 HOTKEY_ID (msg.wParam),
3702 HOTKEY_MODIFIERS (msg.wParam),
3703 HOTKEY_VK_CODE (msg.wParam));
3704 /* Reply is not expected. */
3705 break;
3706 case WM_EMACS_UNREGISTER_HOT_KEY:
3707 focus_window = GetFocus ();
3708 if (focus_window != NULL)
3709 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3710 /* Mark item as erased. NB: this code must be
3711 thread-safe. The next line is okay because the cons
3712 cell is never made into garbage and is not relocated by
3713 GC. */
ccc2d29c
GV
3714 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3715 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3716 abort ();
3717 break;
adcc3809
GV
3718 case WM_EMACS_TOGGLE_LOCK_KEY:
3719 {
3720 int vk_code = (int) msg.wParam;
3721 int cur_state = (GetKeyState (vk_code) & 1);
3722 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3723
3724 /* NB: This code must be thread-safe. It is safe to
3725 call NILP because symbols are not relocated by GC,
3726 and pointer here is not touched by GC (so the markbit
3727 can't be set). Numbers are safe because they are
3728 immediate values. */
3729 if (NILP (new_state)
3730 || (NUMBERP (new_state)
3731 && (XUINT (new_state)) & 1 != cur_state))
3732 {
3733 one_w32_display_info.faked_key = vk_code;
3734
3735 keybd_event ((BYTE) vk_code,
3736 (BYTE) MapVirtualKey (vk_code, 0),
3737 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3738 keybd_event ((BYTE) vk_code,
3739 (BYTE) MapVirtualKey (vk_code, 0),
3740 KEYEVENTF_EXTENDEDKEY | 0, 0);
3741 keybd_event ((BYTE) vk_code,
3742 (BYTE) MapVirtualKey (vk_code, 0),
3743 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3744 cur_state = !cur_state;
3745 }
3746 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3747 cur_state, 0))
3748 abort ();
3749 }
3750 break;
1edf84e7 3751 default:
1edf84e7 3752 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3753 }
3754 }
3755 else
3756 {
3757 DispatchMessage (&msg);
3758 }
1edf84e7
GV
3759
3760 /* Exit nested loop when our deferred message has completed. */
3761 if (msg_buf->completed)
3762 break;
5ac45f98 3763 }
1edf84e7
GV
3764}
3765
3766deferred_msg * deferred_msg_head;
3767
3768static deferred_msg *
3769find_deferred_msg (HWND hwnd, UINT msg)
3770{
3771 deferred_msg * item;
3772
3773 /* Don't actually need synchronization for read access, since
3774 modification of single pointer is always atomic. */
3775 /* enter_crit (); */
3776
3777 for (item = deferred_msg_head; item != NULL; item = item->next)
3778 if (item->w32msg.msg.hwnd == hwnd
3779 && item->w32msg.msg.message == msg)
3780 break;
3781
3782 /* leave_crit (); */
3783
3784 return item;
3785}
3786
3787static LRESULT
3788send_deferred_msg (deferred_msg * msg_buf,
3789 HWND hwnd,
3790 UINT msg,
3791 WPARAM wParam,
3792 LPARAM lParam)
3793{
3794 /* Only input thread can send deferred messages. */
3795 if (GetCurrentThreadId () != dwWindowsThreadId)
3796 abort ();
3797
3798 /* It is an error to send a message that is already deferred. */
3799 if (find_deferred_msg (hwnd, msg) != NULL)
3800 abort ();
3801
3802 /* Enforced synchronization is not needed because this is the only
3803 function that alters deferred_msg_head, and the following critical
3804 section is guaranteed to only be serially reentered (since only the
3805 input thread can call us). */
3806
3807 /* enter_crit (); */
3808
3809 msg_buf->completed = 0;
3810 msg_buf->next = deferred_msg_head;
3811 deferred_msg_head = msg_buf;
3812 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3813
3814 /* leave_crit (); */
3815
3816 /* Start a new nested message loop to process other messages until
3817 this one is completed. */
3818 w32_msg_pump (msg_buf);
3819
3820 deferred_msg_head = msg_buf->next;
3821
3822 return msg_buf->result;
3823}
3824
3825void
3826complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3827{
3828 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3829
3830 if (msg_buf == NULL)
3ef68e6b
AI
3831 /* Message may have been cancelled, so don't abort(). */
3832 return;
1edf84e7
GV
3833
3834 msg_buf->result = result;
3835 msg_buf->completed = 1;
3836
3837 /* Ensure input thread is woken so it notices the completion. */
3838 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3839}
3840
3ef68e6b
AI
3841void
3842cancel_all_deferred_msgs ()
3843{
3844 deferred_msg * item;
3845
3846 /* Don't actually need synchronization for read access, since
3847 modification of single pointer is always atomic. */
3848 /* enter_crit (); */
3849
3850 for (item = deferred_msg_head; item != NULL; item = item->next)
3851 {
3852 item->result = 0;
3853 item->completed = 1;
3854 }
3855
3856 /* leave_crit (); */
3857
3858 /* Ensure input thread is woken so it notices the completion. */
3859 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3860}
1edf84e7
GV
3861
3862DWORD
3863w32_msg_worker (dw)
3864 DWORD dw;
3865{
3866 MSG msg;
3867 deferred_msg dummy_buf;
3868
3869 /* Ensure our message queue is created */
3870
3871 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 3872
1edf84e7
GV
3873 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3874 abort ();
3875
3876 memset (&dummy_buf, 0, sizeof (dummy_buf));
3877 dummy_buf.w32msg.msg.hwnd = NULL;
3878 dummy_buf.w32msg.msg.message = WM_NULL;
3879
3880 /* This is the inital message loop which should only exit when the
3881 application quits. */
3882 w32_msg_pump (&dummy_buf);
3883
3884 return 0;
5ac45f98
GV
3885}
3886
3ef68e6b
AI
3887static void
3888post_character_message (hwnd, msg, wParam, lParam, modifiers)
3889 HWND hwnd;
3890 UINT msg;
3891 WPARAM wParam;
3892 LPARAM lParam;
3893 DWORD modifiers;
3894
3895{
3896 W32Msg wmsg;
3897
3898 wmsg.dwModifiers = modifiers;
3899
3900 /* Detect quit_char and set quit-flag directly. Note that we
3901 still need to post a message to ensure the main thread will be
3902 woken up if blocked in sys_select(), but we do NOT want to post
3903 the quit_char message itself (because it will usually be as if
3904 the user had typed quit_char twice). Instead, we post a dummy
3905 message that has no particular effect. */
3906 {
3907 int c = wParam;
3908 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3909 c = make_ctrl_char (c) & 0377;
7d081355
AI
3910 if (c == quit_char
3911 || (wmsg.dwModifiers == 0 &&
3912 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
3913 {
3914 Vquit_flag = Qt;
3915
3916 /* The choice of message is somewhat arbitrary, as long as
3917 the main thread handler just ignores it. */
3918 msg = WM_NULL;
3919
3920 /* Interrupt any blocking system calls. */
3921 signal_quit ();
3922
3923 /* As a safety precaution, forcibly complete any deferred
3924 messages. This is a kludge, but I don't see any particularly
3925 clean way to handle the situation where a deferred message is
3926 "dropped" in the lisp thread, and will thus never be
3927 completed, eg. by the user trying to activate the menubar
3928 when the lisp thread is busy, and then typing C-g when the
3929 menubar doesn't open promptly (with the result that the
3930 menubar never responds at all because the deferred
3931 WM_INITMENU message is never completed). Another problem
3932 situation is when the lisp thread calls SendMessage (to send
3933 a window manager command) when a message has been deferred;
3934 the lisp thread gets blocked indefinitely waiting for the
3935 deferred message to be completed, which itself is waiting for
3936 the lisp thread to respond.
3937
3938 Note that we don't want to block the input thread waiting for
3939 a reponse from the lisp thread (although that would at least
3940 solve the deadlock problem above), because we want to be able
3941 to receive C-g to interrupt the lisp thread. */
3942 cancel_all_deferred_msgs ();
3943 }
3944 }
3945
3946 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3947}
3948
ee78dc32
GV
3949/* Main window procedure */
3950
ee78dc32 3951LRESULT CALLBACK
fbd6baed 3952w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
3953 HWND hwnd;
3954 UINT msg;
3955 WPARAM wParam;
3956 LPARAM lParam;
3957{
3958 struct frame *f;
fbd6baed
GV
3959 struct w32_display_info *dpyinfo = &one_w32_display_info;
3960 W32Msg wmsg;
84fb1139 3961 int windows_translate;
576ba81c 3962 int key;
84fb1139 3963
a6085637
KH
3964 /* Note that it is okay to call x_window_to_frame, even though we are
3965 not running in the main lisp thread, because frame deletion
3966 requires the lisp thread to synchronize with this thread. Thus, if
3967 a frame struct is returned, it can be used without concern that the
3968 lisp thread might make it disappear while we are using it.
3969
3970 NB. Walking the frame list in this thread is safe (as long as
3971 writes of Lisp_Object slots are atomic, which they are on Windows).
3972 Although delete-frame can destructively modify the frame list while
3973 we are walking it, a garbage collection cannot occur until after
3974 delete-frame has synchronized with this thread.
3975
3976 It is also safe to use functions that make GDI calls, such as
fbd6baed 3977 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
3978 from the frame struct using get_frame_dc which is thread-aware. */
3979
ee78dc32
GV
3980 switch (msg)
3981 {
3982 case WM_ERASEBKGND:
a6085637
KH
3983 f = x_window_to_frame (dpyinfo, hwnd);
3984 if (f)
3985 {
9badad41 3986 HDC hdc = get_frame_dc (f);
a6085637 3987 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
3988 w32_clear_rect (f, hdc, &wmsg.rect);
3989 release_frame_dc (f, hdc);
ce6059da
AI
3990
3991#if defined (W32_DEBUG_DISPLAY)
3992 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
3993 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
3994 wmsg.rect.bottom));
3995#endif /* W32_DEBUG_DISPLAY */
a6085637 3996 }
5ac45f98
GV
3997 return 1;
3998 case WM_PALETTECHANGED:
3999 /* ignore our own changes */
4000 if ((HWND)wParam != hwnd)
4001 {
a6085637
KH
4002 f = x_window_to_frame (dpyinfo, hwnd);
4003 if (f)
4004 /* get_frame_dc will realize our palette and force all
4005 frames to be redrawn if needed. */
4006 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4007 }
4008 return 0;
ee78dc32 4009 case WM_PAINT:
ce6059da 4010 {
55dcfc15
AI
4011 PAINTSTRUCT paintStruct;
4012 RECT update_rect;
4013
4014 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4015 fails. Apparently this can happen under some
4016 circumstances. */
c0611964 4017 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
4018 {
4019 enter_crit ();
4020 BeginPaint (hwnd, &paintStruct);
4021
c0611964
AI
4022 if (w32_strict_painting)
4023 /* The rectangles returned by GetUpdateRect and BeginPaint
4024 do not always match. GetUpdateRect seems to be the
4025 more reliable of the two. */
4026 wmsg.rect = update_rect;
4027 else
4028 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
4029
4030#if defined (W32_DEBUG_DISPLAY)
4031 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
4032 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
4033 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
4034 update_rect.left, update_rect.top,
4035 update_rect.right, update_rect.bottom));
4036#endif
4037 EndPaint (hwnd, &paintStruct);
4038 leave_crit ();
4039
4040 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4041
4042 return 0;
4043 }
c0611964
AI
4044
4045 /* If GetUpdateRect returns 0 (meaning there is no update
4046 region), assume the whole window needs to be repainted. */
4047 GetClientRect(hwnd, &wmsg.rect);
4048 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4049 return 0;
ee78dc32 4050 }
a1a80b40 4051
ccc2d29c
GV
4052 case WM_INPUTLANGCHANGE:
4053 /* Inform lisp thread of keyboard layout changes. */
4054 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4055
4056 /* Clear dead keys in the keyboard state; for simplicity only
4057 preserve modifier key states. */
4058 {
4059 int i;
4060 BYTE keystate[256];
4061
4062 GetKeyboardState (keystate);
4063 for (i = 0; i < 256; i++)
4064 if (1
4065 && i != VK_SHIFT
4066 && i != VK_LSHIFT
4067 && i != VK_RSHIFT
4068 && i != VK_CAPITAL
4069 && i != VK_NUMLOCK
4070 && i != VK_SCROLL
4071 && i != VK_CONTROL
4072 && i != VK_LCONTROL
4073 && i != VK_RCONTROL
4074 && i != VK_MENU
4075 && i != VK_LMENU
4076 && i != VK_RMENU
4077 && i != VK_LWIN
4078 && i != VK_RWIN)
4079 keystate[i] = 0;
4080 SetKeyboardState (keystate);
4081 }
4082 goto dflt;
4083
4084 case WM_HOTKEY:
4085 /* Synchronize hot keys with normal input. */
4086 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4087 return (0);
4088
a1a80b40
GV
4089 case WM_KEYUP:
4090 case WM_SYSKEYUP:
4091 record_keyup (wParam, lParam);
4092 goto dflt;
4093
ee78dc32
GV
4094 case WM_KEYDOWN:
4095 case WM_SYSKEYDOWN:
ccc2d29c
GV
4096 /* Ignore keystrokes we fake ourself; see below. */
4097 if (dpyinfo->faked_key == wParam)
4098 {
4099 dpyinfo->faked_key = 0;
576ba81c
AI
4100 /* Make sure TranslateMessage sees them though (as long as
4101 they don't produce WM_CHAR messages). This ensures that
4102 indicator lights are toggled promptly on Windows 9x, for
4103 example. */
4104 if (lispy_function_keys[wParam] != 0)
4105 {
4106 windows_translate = 1;
4107 goto translate;
4108 }
4109 return 0;
ccc2d29c
GV
4110 }
4111
7830e24b
RS
4112 /* Synchronize modifiers with current keystroke. */
4113 sync_modifiers ();
a1a80b40 4114 record_keydown (wParam, lParam);
ccc2d29c 4115 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4116
4117 windows_translate = 0;
ccc2d29c
GV
4118
4119 switch (wParam)
4120 {
4121 case VK_LWIN:
4122 if (NILP (Vw32_pass_lwindow_to_system))
4123 {
4124 /* Prevent system from acting on keyup (which opens the
4125 Start menu if no other key was pressed) by simulating a
4126 press of Space which we will ignore. */
4127 if (GetAsyncKeyState (wParam) & 1)
4128 {
adcc3809 4129 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4130 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4131 else
576ba81c
AI
4132 key = VK_SPACE;
4133 dpyinfo->faked_key = key;
4134 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4135 }
4136 }
4137 if (!NILP (Vw32_lwindow_modifier))
4138 return 0;
4139 break;
4140 case VK_RWIN:
4141 if (NILP (Vw32_pass_rwindow_to_system))
4142 {
4143 if (GetAsyncKeyState (wParam) & 1)
4144 {
adcc3809 4145 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4146 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4147 else
576ba81c
AI
4148 key = VK_SPACE;
4149 dpyinfo->faked_key = key;
4150 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4151 }
4152 }
4153 if (!NILP (Vw32_rwindow_modifier))
4154 return 0;
4155 break;
576ba81c 4156 case VK_APPS:
ccc2d29c
GV
4157 if (!NILP (Vw32_apps_modifier))
4158 return 0;
4159 break;
4160 case VK_MENU:
4161 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4162 /* Prevent DefWindowProc from activating the menu bar if an
4163 Alt key is pressed and released by itself. */
ccc2d29c 4164 return 0;
84fb1139 4165 windows_translate = 1;
ccc2d29c
GV
4166 break;
4167 case VK_CAPITAL:
4168 /* Decide whether to treat as modifier or function key. */
4169 if (NILP (Vw32_enable_caps_lock))
4170 goto disable_lock_key;
adcc3809
GV
4171 windows_translate = 1;
4172 break;
ccc2d29c
GV
4173 case VK_NUMLOCK:
4174 /* Decide whether to treat as modifier or function key. */
4175 if (NILP (Vw32_enable_num_lock))
4176 goto disable_lock_key;
adcc3809
GV
4177 windows_translate = 1;
4178 break;
ccc2d29c
GV
4179 case VK_SCROLL:
4180 /* Decide whether to treat as modifier or function key. */
4181 if (NILP (Vw32_scroll_lock_modifier))
4182 goto disable_lock_key;
adcc3809
GV
4183 windows_translate = 1;
4184 break;
ccc2d29c 4185 disable_lock_key:
adcc3809
GV
4186 /* Ensure the appropriate lock key state (and indicator light)
4187 remains in the same state. We do this by faking another
4188 press of the relevant key. Apparently, this really is the
4189 only way to toggle the state of the indicator lights. */
4190 dpyinfo->faked_key = wParam;
4191 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4192 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4193 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4194 KEYEVENTF_EXTENDEDKEY | 0, 0);
4195 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4196 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4197 /* Ensure indicator lights are updated promptly on Windows 9x
4198 (TranslateMessage apparently does this), after forwarding
4199 input event. */
4200 post_character_message (hwnd, msg, wParam, lParam,
4201 w32_get_key_modifiers (wParam, lParam));
4202 windows_translate = 1;
ccc2d29c
GV
4203 break;
4204 case VK_CONTROL:
4205 case VK_SHIFT:
4206 case VK_PROCESSKEY: /* Generated by IME. */
4207 windows_translate = 1;
4208 break;
adcc3809
GV
4209 case VK_CANCEL:
4210 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4211 which is confusing for purposes of key binding; convert
4212 VK_CANCEL events into VK_PAUSE events. */
4213 wParam = VK_PAUSE;
4214 break;
4215 case VK_PAUSE:
4216 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4217 for purposes of key binding; convert these back into
4218 VK_NUMLOCK events, at least when we want to see NumLock key
4219 presses. (Note that there is never any possibility that
4220 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4221 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4222 wParam = VK_NUMLOCK;
4223 break;
ccc2d29c
GV
4224 default:
4225 /* If not defined as a function key, change it to a WM_CHAR message. */
4226 if (lispy_function_keys[wParam] == 0)
4227 {
adcc3809
GV
4228 DWORD modifiers = construct_console_modifiers ();
4229
ccc2d29c
GV
4230 if (!NILP (Vw32_recognize_altgr)
4231 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4232 {
4233 /* Always let TranslateMessage handle AltGr key chords;
4234 for some reason, ToAscii doesn't always process AltGr
4235 chords correctly. */
4236 windows_translate = 1;
4237 }
adcc3809 4238 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4239 {
adcc3809
GV
4240 /* Handle key chords including any modifiers other
4241 than shift directly, in order to preserve as much
4242 modifier information as possible. */
ccc2d29c
GV
4243 if ('A' <= wParam && wParam <= 'Z')
4244 {
4245 /* Don't translate modified alphabetic keystrokes,
4246 so the user doesn't need to constantly switch
4247 layout to type control or meta keystrokes when
4248 the normal layout translates alphabetic
4249 characters to non-ascii characters. */
4250 if (!modifier_set (VK_SHIFT))
4251 wParam += ('a' - 'A');
4252 msg = WM_CHAR;
4253 }
4254 else
4255 {
4256 /* Try to handle other keystrokes by determining the
4257 base character (ie. translating the base key plus
4258 shift modifier). */
4259 int add;
4260 int isdead = 0;
4261 KEY_EVENT_RECORD key;
4262
4263 key.bKeyDown = TRUE;
4264 key.wRepeatCount = 1;
4265 key.wVirtualKeyCode = wParam;
4266 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4267 key.uChar.AsciiChar = 0;
adcc3809 4268 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4269
4270 add = w32_kbd_patch_key (&key);
4271 /* 0 means an unrecognised keycode, negative means
4272 dead key. Ignore both. */
4273 while (--add >= 0)
4274 {
4275 /* Forward asciified character sequence. */
4276 post_character_message
4277 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4278 w32_get_key_modifiers (wParam, lParam));
4279 w32_kbd_patch_key (&key);
4280 }
4281 return 0;
4282 }
4283 }
4284 else
4285 {
4286 /* Let TranslateMessage handle everything else. */
4287 windows_translate = 1;
4288 }
4289 }
4290 }
a1a80b40 4291
adcc3809 4292 translate:
84fb1139
KH
4293 if (windows_translate)
4294 {
e9e23e23 4295 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4296
e9e23e23
GV
4297 windows_msg.time = GetMessageTime ();
4298 TranslateMessage (&windows_msg);
84fb1139
KH
4299 goto dflt;
4300 }
4301
ee78dc32
GV
4302 /* Fall through */
4303
4304 case WM_SYSCHAR:
4305 case WM_CHAR:
ccc2d29c
GV
4306 post_character_message (hwnd, msg, wParam, lParam,
4307 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4308 break;
da36a4d6 4309
5ac45f98
GV
4310 /* Simulate middle mouse button events when left and right buttons
4311 are used together, but only if user has two button mouse. */
ee78dc32 4312 case WM_LBUTTONDOWN:
5ac45f98 4313 case WM_RBUTTONDOWN:
7ce9aaca 4314 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4315 goto handle_plain_button;
4316
4317 {
4318 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4319 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4320
3cb20f4a
RS
4321 if (button_state & this)
4322 return 0;
5ac45f98
GV
4323
4324 if (button_state == 0)
4325 SetCapture (hwnd);
4326
4327 button_state |= this;
4328
4329 if (button_state & other)
4330 {
84fb1139 4331 if (mouse_button_timer)
5ac45f98 4332 {
84fb1139
KH
4333 KillTimer (hwnd, mouse_button_timer);
4334 mouse_button_timer = 0;
5ac45f98
GV
4335
4336 /* Generate middle mouse event instead. */
4337 msg = WM_MBUTTONDOWN;
4338 button_state |= MMOUSE;
4339 }
4340 else if (button_state & MMOUSE)
4341 {
4342 /* Ignore button event if we've already generated a
4343 middle mouse down event. This happens if the
4344 user releases and press one of the two buttons
4345 after we've faked a middle mouse event. */
4346 return 0;
4347 }
4348 else
4349 {
4350 /* Flush out saved message. */
84fb1139 4351 post_msg (&saved_mouse_button_msg);
5ac45f98 4352 }
fbd6baed 4353 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4354 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4355
4356 /* Clear message buffer. */
84fb1139 4357 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4358 }
4359 else
4360 {
4361 /* Hold onto message for now. */
84fb1139 4362 mouse_button_timer =
adcc3809
GV
4363 SetTimer (hwnd, MOUSE_BUTTON_ID,
4364 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4365 saved_mouse_button_msg.msg.hwnd = hwnd;
4366 saved_mouse_button_msg.msg.message = msg;
4367 saved_mouse_button_msg.msg.wParam = wParam;
4368 saved_mouse_button_msg.msg.lParam = lParam;
4369 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4370 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4371 }
4372 }
4373 return 0;
4374
ee78dc32 4375 case WM_LBUTTONUP:
5ac45f98 4376 case WM_RBUTTONUP:
7ce9aaca 4377 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4378 goto handle_plain_button;
4379
4380 {
4381 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4382 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4383
3cb20f4a
RS
4384 if ((button_state & this) == 0)
4385 return 0;
5ac45f98
GV
4386
4387 button_state &= ~this;
4388
4389 if (button_state & MMOUSE)
4390 {
4391 /* Only generate event when second button is released. */
4392 if ((button_state & other) == 0)
4393 {
4394 msg = WM_MBUTTONUP;
4395 button_state &= ~MMOUSE;
4396
4397 if (button_state) abort ();
4398 }
4399 else
4400 return 0;
4401 }
4402 else
4403 {
4404 /* Flush out saved message if necessary. */
84fb1139 4405 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4406 {
84fb1139 4407 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4408 }
4409 }
fbd6baed 4410 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4411 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4412
4413 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4414 saved_mouse_button_msg.msg.hwnd = 0;
4415 KillTimer (hwnd, mouse_button_timer);
4416 mouse_button_timer = 0;
5ac45f98
GV
4417
4418 if (button_state == 0)
4419 ReleaseCapture ();
4420 }
4421 return 0;
4422
ee78dc32
GV
4423 case WM_MBUTTONDOWN:
4424 case WM_MBUTTONUP:
5ac45f98 4425 handle_plain_button:
ee78dc32
GV
4426 {
4427 BOOL up;
1edf84e7 4428 int button;
ee78dc32 4429
1edf84e7 4430 if (parse_button (msg, &button, &up))
ee78dc32
GV
4431 {
4432 if (up) ReleaseCapture ();
4433 else SetCapture (hwnd);
1edf84e7
GV
4434 button = (button == 0) ? LMOUSE :
4435 ((button == 1) ? MMOUSE : RMOUSE);
4436 if (up)
4437 button_state &= ~button;
4438 else
4439 button_state |= button;
ee78dc32
GV
4440 }
4441 }
4442
fbd6baed 4443 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4444 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5ac45f98
GV
4445 return 0;
4446
84fb1139 4447 case WM_VSCROLL:
5ac45f98 4448 case WM_MOUSEMOVE:
fbd6baed 4449 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4450 || (msg == WM_MOUSEMOVE && button_state == 0))
4451 {
fbd6baed 4452 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4453 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4454 return 0;
4455 }
4456
4457 /* Hang onto mouse move and scroll messages for a bit, to avoid
4458 sending such events to Emacs faster than it can process them.
4459 If we get more events before the timer from the first message
4460 expires, we just replace the first message. */
4461
4462 if (saved_mouse_move_msg.msg.hwnd == 0)
4463 mouse_move_timer =
adcc3809
GV
4464 SetTimer (hwnd, MOUSE_MOVE_ID,
4465 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4466
4467 /* Hold onto message for now. */
4468 saved_mouse_move_msg.msg.hwnd = hwnd;
4469 saved_mouse_move_msg.msg.message = msg;
4470 saved_mouse_move_msg.msg.wParam = wParam;
4471 saved_mouse_move_msg.msg.lParam = lParam;
4472 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4473 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4474
4475 return 0;
4476
1edf84e7
GV
4477 case WM_MOUSEWHEEL:
4478 wmsg.dwModifiers = w32_get_modifiers ();
4479 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4480 return 0;
4481
cb9e33d4
RS
4482 case WM_DROPFILES:
4483 wmsg.dwModifiers = w32_get_modifiers ();
4484 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4485 return 0;
4486
84fb1139
KH
4487 case WM_TIMER:
4488 /* Flush out saved messages if necessary. */
4489 if (wParam == mouse_button_timer)
5ac45f98 4490 {
84fb1139
KH
4491 if (saved_mouse_button_msg.msg.hwnd)
4492 {
4493 post_msg (&saved_mouse_button_msg);
4494 saved_mouse_button_msg.msg.hwnd = 0;
4495 }
4496 KillTimer (hwnd, mouse_button_timer);
4497 mouse_button_timer = 0;
4498 }
4499 else if (wParam == mouse_move_timer)
4500 {
4501 if (saved_mouse_move_msg.msg.hwnd)
4502 {
4503 post_msg (&saved_mouse_move_msg);
4504 saved_mouse_move_msg.msg.hwnd = 0;
4505 }
4506 KillTimer (hwnd, mouse_move_timer);
4507 mouse_move_timer = 0;
5ac45f98 4508 }
5ac45f98 4509 return 0;
84fb1139
KH
4510
4511 case WM_NCACTIVATE:
4512 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4513 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4514 The only indication we get that something happened is receiving
4515 this message afterwards. So this is a good time to reset our
4516 keyboard modifiers' state. */
4517 reset_modifiers ();
4518 goto dflt;
da36a4d6 4519
1edf84e7 4520 case WM_INITMENU:
487163ac
AI
4521 button_state = 0;
4522 ReleaseCapture ();
1edf84e7
GV
4523 /* We must ensure menu bar is fully constructed and up to date
4524 before allowing user interaction with it. To achieve this
4525 we send this message to the lisp thread and wait for a
4526 reply (whose value is not actually needed) to indicate that
4527 the menu bar is now ready for use, so we can now return.
4528
4529 To remain responsive in the meantime, we enter a nested message
4530 loop that can process all other messages.
4531
4532 However, we skip all this if the message results from calling
4533 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4534 thread a message because it is blocked on us at this point. We
4535 set menubar_active before calling TrackPopupMenu to indicate
4536 this (there is no possibility of confusion with real menubar
4537 being active). */
4538
4539 f = x_window_to_frame (dpyinfo, hwnd);
4540 if (f
4541 && (f->output_data.w32->menubar_active
4542 /* We can receive this message even in the absence of a
4543 menubar (ie. when the system menu is activated) - in this
4544 case we do NOT want to forward the message, otherwise it
4545 will cause the menubar to suddenly appear when the user
4546 had requested it to be turned off! */
4547 || f->output_data.w32->menubar_widget == NULL))
4548 return 0;
4549
4550 {
4551 deferred_msg msg_buf;
4552
4553 /* Detect if message has already been deferred; in this case
4554 we cannot return any sensible value to ignore this. */
4555 if (find_deferred_msg (hwnd, msg) != NULL)
4556 abort ();
4557
4558 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4559 }
4560
4561 case WM_EXITMENULOOP:
4562 f = x_window_to_frame (dpyinfo, hwnd);
4563
4564 /* Indicate that menubar can be modified again. */
4565 if (f)
4566 f->output_data.w32->menubar_active = 0;
4567 goto dflt;
4568
126f2e35
JR
4569 case WM_MENUSELECT:
4570 wmsg.dwModifiers = w32_get_modifiers ();
4571 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4572 return 0;
4573
87996783
GV
4574 case WM_MEASUREITEM:
4575 f = x_window_to_frame (dpyinfo, hwnd);
4576 if (f)
4577 {
4578 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4579
4580 if (pMis->CtlType == ODT_MENU)
4581 {
4582 /* Work out dimensions for popup menu titles. */
4583 char * title = (char *) pMis->itemData;
4584 HDC hdc = GetDC (hwnd);
4585 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4586 LOGFONT menu_logfont;
4587 HFONT old_font;
4588 SIZE size;
4589
4590 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4591 menu_logfont.lfWeight = FW_BOLD;
4592 menu_font = CreateFontIndirect (&menu_logfont);
4593 old_font = SelectObject (hdc, menu_font);
4594
dfff8a69
JR
4595 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4596 if (title)
4597 {
4598 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4599 pMis->itemWidth = size.cx;
4600 if (pMis->itemHeight < size.cy)
4601 pMis->itemHeight = size.cy;
4602 }
4603 else
4604 pMis->itemWidth = 0;
87996783
GV
4605
4606 SelectObject (hdc, old_font);
4607 DeleteObject (menu_font);
4608 ReleaseDC (hwnd, hdc);
4609 return TRUE;
4610 }
4611 }
4612 return 0;
4613
4614 case WM_DRAWITEM:
4615 f = x_window_to_frame (dpyinfo, hwnd);
4616 if (f)
4617 {
4618 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4619
4620 if (pDis->CtlType == ODT_MENU)
4621 {
4622 /* Draw popup menu title. */
4623 char * title = (char *) pDis->itemData;
212da13b
JR
4624 if (title)
4625 {
4626 HDC hdc = pDis->hDC;
4627 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4628 LOGFONT menu_logfont;
4629 HFONT old_font;
4630
4631 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4632 menu_logfont.lfWeight = FW_BOLD;
4633 menu_font = CreateFontIndirect (&menu_logfont);
4634 old_font = SelectObject (hdc, menu_font);
4635
4636 /* Always draw title as if not selected. */
4637 ExtTextOut (hdc,
4638 pDis->rcItem.left
4639 + GetSystemMetrics (SM_CXMENUCHECK),
4640 pDis->rcItem.top,
4641 ETO_OPAQUE, &pDis->rcItem,
4642 title, strlen (title), NULL);
4643
4644 SelectObject (hdc, old_font);
4645 DeleteObject (menu_font);
4646 }
87996783
GV
4647 return TRUE;
4648 }
4649 }
4650 return 0;
4651
1edf84e7
GV
4652#if 0
4653 /* Still not right - can't distinguish between clicks in the
4654 client area of the frame from clicks forwarded from the scroll
4655 bars - may have to hook WM_NCHITTEST to remember the mouse
4656 position and then check if it is in the client area ourselves. */
4657 case WM_MOUSEACTIVATE:
4658 /* Discard the mouse click that activates a frame, allowing the
4659 user to click anywhere without changing point (or worse!).
4660 Don't eat mouse clicks on scrollbars though!! */
4661 if (LOWORD (lParam) == HTCLIENT )
4662 return MA_ACTIVATEANDEAT;
4663 goto dflt;
4664#endif
4665
1edf84e7 4666 case WM_ACTIVATEAPP:
ccc2d29c 4667 case WM_ACTIVATE:
1edf84e7
GV
4668 case WM_WINDOWPOSCHANGED:
4669 case WM_SHOWWINDOW:
4670 /* Inform lisp thread that a frame might have just been obscured
4671 or exposed, so should recheck visibility of all frames. */
4672 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4673 goto dflt;
4674
da36a4d6 4675 case WM_SETFOCUS:
adcc3809
GV
4676 dpyinfo->faked_key = 0;
4677 reset_modifiers ();
ccc2d29c
GV
4678 register_hot_keys (hwnd);
4679 goto command;
8681157a 4680 case WM_KILLFOCUS:
ccc2d29c 4681 unregister_hot_keys (hwnd);
487163ac
AI
4682 button_state = 0;
4683 ReleaseCapture ();
ee78dc32
GV
4684 case WM_MOVE:
4685 case WM_SIZE:
ee78dc32 4686 case WM_COMMAND:
ccc2d29c 4687 command:
fbd6baed 4688 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4689 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4690 goto dflt;
8847d890
RS
4691
4692 case WM_CLOSE:
fbd6baed 4693 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4694 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4695 return 0;
4696
ee78dc32
GV
4697 case WM_WINDOWPOSCHANGING:
4698 {
4699 WINDOWPLACEMENT wp;
4700 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4701
4702 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4703 GetWindowPlacement (hwnd, &wp);
4704
1edf84e7 4705 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4706 {
4707 RECT rect;
4708 int wdiff;
4709 int hdiff;
1edf84e7
GV
4710 DWORD font_width;
4711 DWORD line_height;
4712 DWORD internal_border;
4713 DWORD scrollbar_extra;
ee78dc32
GV
4714 RECT wr;
4715
5ac45f98 4716 wp.length = sizeof(wp);
ee78dc32
GV
4717 GetWindowRect (hwnd, &wr);
4718
3c190163 4719 enter_crit ();
ee78dc32 4720
1edf84e7
GV
4721 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4722 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4723 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4724 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4725
3c190163 4726 leave_crit ();
ee78dc32
GV
4727
4728 memset (&rect, 0, sizeof (rect));
4729 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4730 GetMenu (hwnd) != NULL);
4731
1edf84e7
GV
4732 /* Force width and height of client area to be exact
4733 multiples of the character cell dimensions. */
4734 wdiff = (lppos->cx - (rect.right - rect.left)
4735 - 2 * internal_border - scrollbar_extra)
4736 % font_width;
4737 hdiff = (lppos->cy - (rect.bottom - rect.top)
4738 - 2 * internal_border)
4739 % line_height;
ee78dc32
GV
4740
4741 if (wdiff || hdiff)
4742 {
4743 /* For right/bottom sizing we can just fix the sizes.
4744 However for top/left sizing we will need to fix the X
4745 and Y positions as well. */
4746
4747 lppos->cx -= wdiff;
4748 lppos->cy -= hdiff;
4749
4750 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4751 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4752 {
4753 if (lppos->x != wr.left || lppos->y != wr.top)
4754 {
4755 lppos->x += wdiff;
4756 lppos->y += hdiff;
4757 }
4758 else
4759 {
4760 lppos->flags |= SWP_NOMOVE;
4761 }
4762 }
4763
1edf84e7 4764 return 0;
ee78dc32
GV
4765 }
4766 }
4767 }
ee78dc32
GV
4768
4769 goto dflt;
1edf84e7 4770
b1f918f8
GV
4771 case WM_GETMINMAXINFO:
4772 /* Hack to correct bug that allows Emacs frames to be resized
4773 below the Minimum Tracking Size. */
4774 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4775 return 0;
4776
1edf84e7
GV
4777 case WM_EMACS_CREATESCROLLBAR:
4778 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4779 (struct scroll_bar *) lParam);
4780
5ac45f98 4781 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4782 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4783
dfdb4047 4784 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4785 {
4786 HWND foreground_window;
4787 DWORD foreground_thread, retval;
4788
4789 /* On NT 5.0, and apparently Windows 98, it is necessary to
4790 attach to the thread that currently has focus in order to
4791 pull the focus away from it. */
4792 foreground_window = GetForegroundWindow ();
4793 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4794 if (!foreground_window
4795 || foreground_thread == GetCurrentThreadId ()
4796 || !AttachThreadInput (GetCurrentThreadId (),
4797 foreground_thread, TRUE))
4798 foreground_thread = 0;
4799
4800 retval = SetForegroundWindow ((HWND) wParam);
4801
4802 /* Detach from the previous foreground thread. */
4803 if (foreground_thread)
4804 AttachThreadInput (GetCurrentThreadId (),
4805 foreground_thread, FALSE);
4806
4807 return retval;
4808 }
dfdb4047 4809
5ac45f98
GV
4810 case WM_EMACS_SETWINDOWPOS:
4811 {
1edf84e7
GV
4812 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4813 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
4814 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4815 }
1edf84e7 4816
ee78dc32 4817 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 4818 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
4819 return DestroyWindow ((HWND) wParam);
4820
4821 case WM_EMACS_TRACKPOPUPMENU:
4822 {
4823 UINT flags;
4824 POINT *pos;
4825 int retval;
4826 pos = (POINT *)lParam;
4827 flags = TPM_CENTERALIGN;
4828 if (button_state & LMOUSE)
4829 flags |= TPM_LEFTBUTTON;
4830 else if (button_state & RMOUSE)
4831 flags |= TPM_RIGHTBUTTON;
4832
87996783
GV
4833 /* Remember we did a SetCapture on the initial mouse down event,
4834 so for safety, we make sure the capture is cancelled now. */
4835 ReleaseCapture ();
490822ff 4836 button_state = 0;
87996783 4837
1edf84e7
GV
4838 /* Use menubar_active to indicate that WM_INITMENU is from
4839 TrackPopupMenu below, and should be ignored. */
4840 f = x_window_to_frame (dpyinfo, hwnd);
4841 if (f)
4842 f->output_data.w32->menubar_active = 1;
4843
4844 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4845 0, hwnd, NULL))
4846 {
4847 MSG amsg;
4848 /* Eat any mouse messages during popupmenu */
4849 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4850 PM_REMOVE));
4851 /* Get the menu selection, if any */
4852 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4853 {
4854 retval = LOWORD (amsg.wParam);
4855 }
4856 else
4857 {
4858 retval = 0;
4859 }
1edf84e7
GV
4860 }
4861 else
4862 {
4863 retval = -1;
4864 }
4865
4866 return retval;
4867 }
4868
ee78dc32 4869 default:
93fbe8b7
GV
4870 /* Check for messages registered at runtime. */
4871 if (msg == msh_mousewheel)
4872 {
4873 wmsg.dwModifiers = w32_get_modifiers ();
4874 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4875 return 0;
4876 }
4877
ee78dc32
GV
4878 dflt:
4879 return DefWindowProc (hwnd, msg, wParam, lParam);
4880 }
4881
1edf84e7
GV
4882
4883 /* The most common default return code for handled messages is 0. */
4884 return 0;
ee78dc32
GV
4885}
4886
4887void
4888my_create_window (f)
4889 struct frame * f;
4890{
4891 MSG msg;
4892
1edf84e7
GV
4893 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4894 abort ();
ee78dc32
GV
4895 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4896}
4897
fbd6baed 4898/* Create and set up the w32 window for frame F. */
ee78dc32
GV
4899
4900static void
fbd6baed 4901w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
4902 struct frame *f;
4903 long window_prompting;
4904 int minibuffer_only;
4905{
4906 BLOCK_INPUT;
4907
4908 /* Use the resource name as the top-level window name
4909 for looking up resources. Make a non-Lisp copy
4910 for the window manager, so GC relocation won't bother it.
4911
4912 Elsewhere we specify the window name for the window manager. */
4913
4914 {
4915 char *str = (char *) XSTRING (Vx_resource_name)->data;
4916 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4917 strcpy (f->namebuf, str);
4918 }
4919
4920 my_create_window (f);
4921
4922 validate_x_resource_name ();
4923
4924 /* x_set_name normally ignores requests to set the name if the
4925 requested name is the same as the current name. This is the one
4926 place where that assumption isn't correct; f->name is set, but
4927 the server hasn't been told. */
4928 {
4929 Lisp_Object name;
4930 int explicit = f->explicit_name;
4931
4932 f->explicit_name = 0;
4933 name = f->name;
4934 f->name = Qnil;
4935 x_set_name (f, name, explicit);
4936 }
4937
4938 UNBLOCK_INPUT;
4939
4940 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4941 initialize_frame_menubar (f);
4942
fbd6baed 4943 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
4944 error ("Unable to create window");
4945}
4946
4947/* Handle the icon stuff for this window. Perhaps later we might
4948 want an x_set_icon_position which can be called interactively as
4949 well. */
4950
4951static void
4952x_icon (f, parms)
4953 struct frame *f;
4954 Lisp_Object parms;
4955{
4956 Lisp_Object icon_x, icon_y;
4957
e9e23e23 4958 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 4959 icons in the tray. */
6fc2811b
JR
4960 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4961 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
4962 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4963 {
4964 CHECK_NUMBER (icon_x, 0);
4965 CHECK_NUMBER (icon_y, 0);
4966 }
4967 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4968 error ("Both left and top icon corners of icon must be specified");
4969
4970 BLOCK_INPUT;
4971
4972 if (! EQ (icon_x, Qunbound))
4973 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4974
1edf84e7
GV
4975#if 0 /* TODO */
4976 /* Start up iconic or window? */
4977 x_wm_set_window_state
6fc2811b 4978 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
4979 ? IconicState
4980 : NormalState));
4981
4982 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4983 ? f->icon_name
4984 : f->name))->data);
4985#endif
4986
ee78dc32
GV
4987 UNBLOCK_INPUT;
4988}
4989
6fc2811b
JR
4990
4991static void
4992x_make_gc (f)
4993 struct frame *f;
4994{
4995 XGCValues gc_values;
4996
4997 BLOCK_INPUT;
4998
4999 /* Create the GC's of this frame.
5000 Note that many default values are used. */
5001
5002 /* Normal video */
5003 gc_values.font = f->output_data.w32->font;
5004
5005 /* Cursor has cursor-color background, background-color foreground. */
5006 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5007 gc_values.background = f->output_data.w32->cursor_pixel;
5008 f->output_data.w32->cursor_gc
5009 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5010 (GCFont | GCForeground | GCBackground),
5011 &gc_values);
5012
5013 /* Reliefs. */
5014 f->output_data.w32->white_relief.gc = 0;
5015 f->output_data.w32->black_relief.gc = 0;
5016
5017 UNBLOCK_INPUT;
5018}
5019
5020
ee78dc32
GV
5021DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5022 1, 1, 0,
5023 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5024Returns an Emacs frame object.\n\
5025ALIST is an alist of frame parameters.\n\
5026If the parameters specify that the frame should not have a minibuffer,\n\
5027and do not specify a specific minibuffer window to use,\n\
5028then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5029be shared by the new frame.\n\
5030\n\
5031This function is an internal primitive--use `make-frame' instead.")
5032 (parms)
5033 Lisp_Object parms;
5034{
5035 struct frame *f;
5036 Lisp_Object frame, tem;
5037 Lisp_Object name;
5038 int minibuffer_only = 0;
5039 long window_prompting = 0;
5040 int width, height;
5041 int count = specpdl_ptr - specpdl;
1edf84e7 5042 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5043 Lisp_Object display;
6fc2811b 5044 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5045 Lisp_Object parent;
5046 struct kboard *kb;
5047
4587b026
GV
5048 check_w32 ();
5049
ee78dc32
GV
5050 /* Use this general default value to start with
5051 until we know if this frame has a specified name. */
5052 Vx_resource_name = Vinvocation_name;
5053
6fc2811b 5054 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5055 if (EQ (display, Qunbound))
5056 display = Qnil;
5057 dpyinfo = check_x_display_info (display);
5058#ifdef MULTI_KBOARD
5059 kb = dpyinfo->kboard;
5060#else
5061 kb = &the_only_kboard;
5062#endif
5063
6fc2811b 5064 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5065 if (!STRINGP (name)
5066 && ! EQ (name, Qunbound)
5067 && ! NILP (name))
5068 error ("Invalid frame name--not a string or nil");
5069
5070 if (STRINGP (name))
5071 Vx_resource_name = name;
5072
5073 /* See if parent window is specified. */
6fc2811b 5074 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5075 if (EQ (parent, Qunbound))
5076 parent = Qnil;
5077 if (! NILP (parent))
5078 CHECK_NUMBER (parent, 0);
5079
1edf84e7
GV
5080 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5081 /* No need to protect DISPLAY because that's not used after passing
5082 it to make_frame_without_minibuffer. */
5083 frame = Qnil;
5084 GCPRO4 (parms, parent, name, frame);
6fc2811b 5085 tem = w32_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5086 if (EQ (tem, Qnone) || NILP (tem))
5087 f = make_frame_without_minibuffer (Qnil, kb, display);
5088 else if (EQ (tem, Qonly))
5089 {
5090 f = make_minibuffer_frame ();
5091 minibuffer_only = 1;
5092 }
5093 else if (WINDOWP (tem))
5094 f = make_frame_without_minibuffer (tem, kb, display);
5095 else
5096 f = make_frame (1);
5097
1edf84e7
GV
5098 XSETFRAME (frame, f);
5099
ee78dc32
GV
5100 /* Note that Windows does support scroll bars. */
5101 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5102 /* By default, make scrollbars the system standard width. */
5103 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5104
fbd6baed 5105 f->output_method = output_w32;
6fc2811b
JR
5106 f->output_data.w32 =
5107 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5108 bzero (f->output_data.w32, sizeof (struct w32_output));
ee78dc32 5109
4587b026
GV
5110 FRAME_FONTSET (f) = -1;
5111
1edf84e7 5112 f->icon_name
6fc2811b 5113 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5114 if (! STRINGP (f->icon_name))
5115 f->icon_name = Qnil;
5116
fbd6baed 5117/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5118#ifdef MULTI_KBOARD
5119 FRAME_KBOARD (f) = kb;
5120#endif
5121
5122 /* Specify the parent under which to make this window. */
5123
5124 if (!NILP (parent))
5125 {
fbd6baed
GV
5126 f->output_data.w32->parent_desc = (Window) parent;
5127 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5128 }
5129 else
5130 {
fbd6baed
GV
5131 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5132 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5133 }
5134
ee78dc32
GV
5135 /* Set the name; the functions to which we pass f expect the name to
5136 be set. */
5137 if (EQ (name, Qunbound) || NILP (name))
5138 {
fbd6baed 5139 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5140 f->explicit_name = 0;
5141 }
5142 else
5143 {
5144 f->name = name;
5145 f->explicit_name = 1;
5146 /* use the frame's title when getting resources for this frame. */
5147 specbind (Qx_resource_name, name);
5148 }
5149
5150 /* Extract the window parameters from the supplied values
5151 that are needed to determine window geometry. */
5152 {
5153 Lisp_Object font;
5154
6fc2811b
JR
5155 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5156
ee78dc32
GV
5157 BLOCK_INPUT;
5158 /* First, try whatever font the caller has specified. */
5159 if (STRINGP (font))
4587b026
GV
5160 {
5161 tem = Fquery_fontset (font, Qnil);
5162 if (STRINGP (tem))
5163 font = x_new_fontset (f, XSTRING (tem)->data);
5164 else
1075afa9 5165 font = x_new_font (f, XSTRING (font)->data);
4587b026 5166 }
ee78dc32
GV
5167 /* Try out a font which we hope has bold and italic variations. */
5168 if (!STRINGP (font))
4587b026 5169 font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32 5170 if (! STRINGP (font))
6fc2811b 5171 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5172 /* If those didn't work, look for something which will at least work. */
5173 if (! STRINGP (font))
6fc2811b 5174 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5175 UNBLOCK_INPUT;
5176 if (! STRINGP (font))
1edf84e7 5177 font = build_string ("Fixedsys");
ee78dc32
GV
5178
5179 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5180 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5181 }
5182
5183 x_default_parameter (f, parms, Qborder_width, make_number (2),
6fc2811b 5184 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5185 /* This defaults to 2 in order to match xterm. We recognize either
5186 internalBorderWidth or internalBorder (which is what xterm calls
5187 it). */
5188 if (NILP (Fassq (Qinternal_border_width, parms)))
5189 {
5190 Lisp_Object value;
5191
6fc2811b
JR
5192 value = w32_get_arg (parms, Qinternal_border_width,
5193 "internalBorder", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5194 if (! EQ (value, Qunbound))
5195 parms = Fcons (Fcons (Qinternal_border_width, value),
5196 parms);
5197 }
1edf84e7 5198 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5199 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
6fc2811b 5200 "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32 5201 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
6fc2811b 5202 "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN);
ee78dc32
GV
5203
5204 /* Also do the stuff which must be set before the window exists. */
5205 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5206 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5207 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5208 "background", "Background", RES_TYPE_STRING);
ee78dc32 5209 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5210 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5211 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5212 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5213 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5214 "borderColor", "BorderColor", RES_TYPE_STRING);
5215 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5216 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5217 x_default_parameter (f, parms, Qline_spacing, Qnil,
5218 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
6fc2811b 5219
ee78dc32 5220
6fc2811b
JR
5221 /* Init faces before x_default_parameter is called for scroll-bar
5222 parameters because that function calls x_set_scroll_bar_width,
5223 which calls change_frame_size, which calls Fset_window_buffer,
5224 which runs hooks, which call Fvertical_motion. At the end, we
5225 end up in init_iterator with a null face cache, which should not
5226 happen. */
5227 init_frame_faces (f);
5228
ee78dc32 5229 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5230 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5231 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5232 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5233 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5234 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5235 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5236 "title", "Title", RES_TYPE_STRING);
ee78dc32 5237
fbd6baed
GV
5238 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5239 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
ee78dc32
GV
5240 window_prompting = x_figure_window_size (f, parms);
5241
5242 if (window_prompting & XNegative)
5243 {
5244 if (window_prompting & YNegative)
fbd6baed 5245 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5246 else
fbd6baed 5247 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5248 }
5249 else
5250 {
5251 if (window_prompting & YNegative)
fbd6baed 5252 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5253 else
fbd6baed 5254 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5255 }
5256
fbd6baed 5257 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5258
6fc2811b
JR
5259 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5260 f->no_split = minibuffer_only || EQ (tem, Qt);
5261
5262 /* Create the window. Add the tool-bar height to the initial frame
5263 height so that the user gets a text display area of the size he
5264 specified with -g or via the registry. Later changes of the
5265 tool-bar height don't change the frame size. This is done so that
5266 users can create tall Emacs frames without having to guess how
5267 tall the tool-bar will get. */
5268 f->height += FRAME_TOOL_BAR_LINES (f);
fbd6baed 5269 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5270 x_icon (f, parms);
6fc2811b
JR
5271
5272 x_make_gc (f);
5273
5274 /* Now consider the frame official. */
5275 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5276 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5277
5278 /* We need to do this after creating the window, so that the
5279 icon-creation functions can say whose icon they're describing. */
5280 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5281 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5282
5283 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5284 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5285 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5286 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5287 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5288 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5289 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5290 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5291
5292 /* Dimensions, especially f->height, must be done via change_frame_size.
5293 Change will not be effected unless different from the current
5294 f->height. */
5295 width = f->width;
5296 height = f->height;
1026b400
RS
5297 f->height = 0;
5298 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5299 change_frame_size (f, height, width, 1, 0, 0);
5300
5301 /* Set up faces after all frame parameters are known. */
5302 call1 (Qface_set_after_frame_default, frame);
ee78dc32 5303
6fc2811b
JR
5304 /* Tell the server what size and position, etc, we want, and how
5305 badly we want them. This should be done after we have the menu
5306 bar so that its size can be taken into account. */
ee78dc32
GV
5307 BLOCK_INPUT;
5308 x_wm_set_size_hint (f, window_prompting, 0);
5309 UNBLOCK_INPUT;
5310
6fc2811b
JR
5311 /* Make the window appear on the frame and enable display, unless
5312 the caller says not to. However, with explicit parent, Emacs
5313 cannot control visibility, so don't try. */
fbd6baed 5314 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5315 {
5316 Lisp_Object visibility;
5317
6fc2811b 5318 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5319 if (EQ (visibility, Qunbound))
5320 visibility = Qt;
5321
5322 if (EQ (visibility, Qicon))
5323 x_iconify_frame (f);
5324 else if (! NILP (visibility))
5325 x_make_frame_visible (f);
5326 else
5327 /* Must have been Qnil. */
5328 ;
5329 }
6fc2811b 5330 UNGCPRO;
ee78dc32
GV
5331 return unbind_to (count, frame);
5332}
5333
5334/* FRAME is used only to get a handle on the X display. We don't pass the
5335 display info directly because we're called from frame.c, which doesn't
5336 know about that structure. */
5337Lisp_Object
5338x_get_focus_frame (frame)
5339 struct frame *frame;
5340{
fbd6baed 5341 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5342 Lisp_Object xfocus;
fbd6baed 5343 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5344 return Qnil;
5345
fbd6baed 5346 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5347 return xfocus;
5348}
1edf84e7
GV
5349
5350DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5351 "Give FRAME input focus, raising to foreground if necessary.")
5352 (frame)
5353 Lisp_Object frame;
5354{
5355 x_focus_on_frame (check_x_frame (frame));
5356 return Qnil;
5357}
5358
ee78dc32 5359\f
33d52f9c
GV
5360struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5361 int size, char* filename);
5362
4587b026 5363struct font_info *
33d52f9c 5364w32_load_system_font (f,fontname,size)
55dcfc15
AI
5365 struct frame *f;
5366 char * fontname;
5367 int size;
ee78dc32 5368{
4587b026
GV
5369 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5370 Lisp_Object font_names;
5371
4587b026
GV
5372 /* Get a list of all the fonts that match this name. Once we
5373 have a list of matching fonts, we compare them against the fonts
5374 we already have loaded by comparing names. */
5375 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5376
5377 if (!NILP (font_names))
3c190163 5378 {
4587b026
GV
5379 Lisp_Object tail;
5380 int i;
4587b026
GV
5381
5382 /* First check if any are already loaded, as that is cheaper
5383 than loading another one. */
5384 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5385 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5386 if (dpyinfo->font_table[i].name
5387 && (!strcmp (dpyinfo->font_table[i].name,
5388 XSTRING (XCAR (tail))->data)
5389 || !strcmp (dpyinfo->font_table[i].full_name,
5390 XSTRING (XCAR (tail))->data)))
4587b026 5391 return (dpyinfo->font_table + i);
6fc2811b 5392
8e713be6 5393 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5394 }
1075afa9 5395 else if (w32_strict_fontnames)
5ca0cd71
GV
5396 {
5397 /* If EnumFontFamiliesEx was available, we got a full list of
5398 fonts back so stop now to avoid the possibility of loading a
5399 random font. If we had to fall back to EnumFontFamilies, the
5400 list is incomplete, so continue whether the font we want was
5401 listed or not. */
5402 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5403 FARPROC enum_font_families_ex
1075afa9 5404 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5405 if (enum_font_families_ex)
5406 return NULL;
5407 }
4587b026
GV
5408
5409 /* Load the font and add it to the table. */
5410 {
33d52f9c 5411 char *full_name, *encoding;
4587b026
GV
5412 XFontStruct *font;
5413 struct font_info *fontp;
3c190163 5414 LOGFONT lf;
4587b026 5415 BOOL ok;
6fc2811b 5416 int i;
5ac45f98 5417
4587b026 5418 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5419 return (NULL);
5ac45f98 5420
4587b026
GV
5421 if (!*lf.lfFaceName)
5422 /* If no name was specified for the font, we get a random font
5423 from CreateFontIndirect - this is not particularly
5424 desirable, especially since CreateFontIndirect does not
5425 fill out the missing name in lf, so we never know what we
5426 ended up with. */
5427 return NULL;
5428
3c190163 5429 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5ac45f98 5430
33d52f9c
GV
5431 /* Set bdf to NULL to indicate that this is a Windows font. */
5432 font->bdf = NULL;
5ac45f98 5433
3c190163 5434 BLOCK_INPUT;
5ac45f98
GV
5435
5436 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5437
1a292d24
AI
5438 if (font->hfont == NULL)
5439 {
5440 ok = FALSE;
5441 }
5442 else
5443 {
5444 HDC hdc;
5445 HANDLE oldobj;
5446
5447 hdc = GetDC (dpyinfo->root_window);
5448 oldobj = SelectObject (hdc, font->hfont);
5449 ok = GetTextMetrics (hdc, &font->tm);
dfff8a69 5450 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
1a292d24
AI
5451 SelectObject (hdc, oldobj);
5452 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5453 /* Fill out details in lf according to the font that was
5454 actually loaded. */
5455 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5456 lf.lfWidth = font->tm.tmAveCharWidth;
5457 lf.lfWeight = font->tm.tmWeight;
5458 lf.lfItalic = font->tm.tmItalic;
5459 lf.lfCharSet = font->tm.tmCharSet;
5460 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5461 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5462 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5463 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
1a292d24 5464 }
5ac45f98 5465
1a292d24 5466 UNBLOCK_INPUT;
5ac45f98 5467
4587b026
GV
5468 if (!ok)
5469 {
1a292d24
AI
5470 w32_unload_font (dpyinfo, font);
5471 return (NULL);
5472 }
ee78dc32 5473
6fc2811b
JR
5474 /* Find a free slot in the font table. */
5475 for (i = 0; i < dpyinfo->n_fonts; ++i)
5476 if (dpyinfo->font_table[i].name == NULL)
5477 break;
5478
5479 /* If no free slot found, maybe enlarge the font table. */
5480 if (i == dpyinfo->n_fonts
5481 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5482 {
6fc2811b
JR
5483 int sz;
5484 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5485 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5486 dpyinfo->font_table
6fc2811b 5487 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5488 }
5489
6fc2811b
JR
5490 fontp = dpyinfo->font_table + i;
5491 if (i == dpyinfo->n_fonts)
5492 ++dpyinfo->n_fonts;
4587b026
GV
5493
5494 /* Now fill in the slots of *FONTP. */
5495 BLOCK_INPUT;
5496 fontp->font = font;
6fc2811b 5497 fontp->font_idx = i;
4587b026
GV
5498 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5499 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5500
5501 /* Work out the font's full name. */
5502 full_name = (char *)xmalloc (100);
5503 if (full_name && w32_to_x_font (&lf, full_name, 100))
5504 fontp->full_name = full_name;
5505 else
5506 {
5507 /* If all else fails - just use the name we used to load it. */
5508 xfree (full_name);
5509 fontp->full_name = fontp->name;
5510 }
5511
5512 fontp->size = FONT_WIDTH (font);
5513 fontp->height = FONT_HEIGHT (font);
5514
5515 /* The slot `encoding' specifies how to map a character
5516 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
5517 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5518 (0:0x20..0x7F, 1:0xA0..0xFF,
5519 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 5520 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 5521 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
5522 which is never used by any charset. If mapping can't be
5523 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5524
5525 /* SJIS fonts need to be set to type 4, all others seem to work as
5526 type FONT_ENCODING_NOT_DECIDED. */
5527 encoding = strrchr (fontp->name, '-');
5528 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5529 fontp->encoding[1] = 4;
33d52f9c 5530 else
1c885fe1 5531 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5532
5533 /* The following three values are set to 0 under W32, which is
5534 what they get set to if XGetFontProperty fails under X. */
5535 fontp->baseline_offset = 0;
5536 fontp->relative_compose = 0;
33d52f9c 5537 fontp->default_ascent = 0;
4587b026 5538
6fc2811b
JR
5539 /* Set global flag fonts_changed_p to non-zero if the font loaded
5540 has a character with a smaller width than any other character
5541 before, or if the font loaded has a smalle>r height than any
5542 other font loaded before. If this happens, it will make a
5543 glyph matrix reallocation necessary. */
5544 fonts_changed_p = x_compute_min_glyph_bounds (f);
4587b026 5545 UNBLOCK_INPUT;
4587b026
GV
5546 return fontp;
5547 }
5548}
5549
33d52f9c
GV
5550/* Load font named FONTNAME of size SIZE for frame F, and return a
5551 pointer to the structure font_info while allocating it dynamically.
5552 If loading fails, return NULL. */
5553struct font_info *
5554w32_load_font (f,fontname,size)
5555struct frame *f;
5556char * fontname;
5557int size;
5558{
5559 Lisp_Object bdf_fonts;
5560 struct font_info *retval = NULL;
5561
5562 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5563
5564 while (!retval && CONSP (bdf_fonts))
5565 {
5566 char *bdf_name, *bdf_file;
5567 Lisp_Object bdf_pair;
5568
8e713be6
KR
5569 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5570 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5571 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
5572
5573 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5574
8e713be6 5575 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
5576 }
5577
5578 if (retval)
5579 return retval;
5580
5581 return w32_load_system_font(f, fontname, size);
5582}
5583
5584
ee78dc32 5585void
fbd6baed
GV
5586w32_unload_font (dpyinfo, font)
5587 struct w32_display_info *dpyinfo;
ee78dc32
GV
5588 XFontStruct * font;
5589{
5590 if (font)
5591 {
33d52f9c
GV
5592 if (font->bdf) w32_free_bdf_font (font->bdf);
5593
3c190163 5594 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5595 xfree (font);
5596 }
5597}
5598
fbd6baed 5599/* The font conversion stuff between x and w32 */
ee78dc32
GV
5600
5601/* X font string is as follows (from faces.el)
5602 * (let ((- "[-?]")
5603 * (foundry "[^-]+")
5604 * (family "[^-]+")
5605 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5606 * (weight\? "\\([^-]*\\)") ; 1
5607 * (slant "\\([ior]\\)") ; 2
5608 * (slant\? "\\([^-]?\\)") ; 2
5609 * (swidth "\\([^-]*\\)") ; 3
5610 * (adstyle "[^-]*") ; 4
5611 * (pixelsize "[0-9]+")
5612 * (pointsize "[0-9][0-9]+")
5613 * (resx "[0-9][0-9]+")
5614 * (resy "[0-9][0-9]+")
5615 * (spacing "[cmp?*]")
5616 * (avgwidth "[0-9]+")
5617 * (registry "[^-]+")
5618 * (encoding "[^-]+")
5619 * )
ee78dc32 5620 */
ee78dc32
GV
5621
5622LONG
fbd6baed 5623x_to_w32_weight (lpw)
ee78dc32
GV
5624 char * lpw;
5625{
5626 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
5627
5628 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5629 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5630 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5631 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 5632 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
5633 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5634 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5635 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5636 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5637 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 5638 else
5ac45f98 5639 return FW_DONTCARE;
ee78dc32
GV
5640}
5641
5ac45f98 5642
ee78dc32 5643char *
fbd6baed 5644w32_to_x_weight (fnweight)
ee78dc32
GV
5645 int fnweight;
5646{
5ac45f98
GV
5647 if (fnweight >= FW_HEAVY) return "heavy";
5648 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5649 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 5650 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
5651 if (fnweight >= FW_MEDIUM) return "medium";
5652 if (fnweight >= FW_NORMAL) return "normal";
5653 if (fnweight >= FW_LIGHT) return "light";
5654 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5655 if (fnweight >= FW_THIN) return "thin";
5656 else
5657 return "*";
5658}
5659
5660LONG
fbd6baed 5661x_to_w32_charset (lpcs)
5ac45f98
GV
5662 char * lpcs;
5663{
dfff8a69 5664 Lisp_Object rest;
4587b026 5665
dfff8a69
JR
5666 /* Look through w32-charset-info-alist for the character set.
5667 Format of each entry is
5668 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5669 */
5670 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5671 {
5672 Lisp_Object this_entry = XCAR (rest);
5673 char * x_charset = XSTRING (XCAR (this_entry))->data;
4587b026 5674
dfff8a69
JR
5675 if (strnicmp (lpcs, x_charset, strlen(x_charset)) == 0)
5676 {
5677 Lisp_Object w32_charset = XCAR (XCDR (this_entry));
5678 // Translate Lisp symbol to number.
5679 if (w32_charset == Qw32_charset_ansi)
5680 return ANSI_CHARSET;
5681 if (w32_charset == Qw32_charset_symbol)
5682 return SYMBOL_CHARSET;
5683 if (w32_charset == Qw32_charset_shiftjis)
5684 return SHIFTJIS_CHARSET;
5685 if (w32_charset == Qw32_charset_hangul)
5686 return HANGEUL_CHARSET;
5687 if (w32_charset == Qw32_charset_chinesebig5)
5688 return CHINESEBIG5_CHARSET;
5689 if (w32_charset == Qw32_charset_gb2312)
5690 return GB2312_CHARSET;
5691 if (w32_charset == Qw32_charset_oem)
5692 return OEM_CHARSET;
5693#ifdef JOHAB_CHARSET
5694 if (w32_charset == Qw32_charset_johab)
5695 return JOHAB_CHARSET;
5696 if (w32_charset == Qw32_charset_easteurope)
5697 return EASTEUROPE_CHARSET;
5698 if (w32_charset == Qw32_charset_turkish)
5699 return TURKISH_CHARSET;
5700 if (w32_charset == Qw32_charset_baltic)
5701 return BALTIC_CHARSET;
5702 if (w32_charset == Qw32_charset_russian)
5703 return RUSSIAN_CHARSET;
5704 if (w32_charset == Qw32_charset_arabic)
5705 return ARABIC_CHARSET;
5706 if (w32_charset == Qw32_charset_greek)
5707 return GREEK_CHARSET;
5708 if (w32_charset == Qw32_charset_hebrew)
5709 return HEBREW_CHARSET;
5710 if (w32_charset == Qw32_charset_thai)
5711 return THAI_CHARSET;
5712 if (w32_charset == Qw32_charset_mac)
5713 return MAC_CHARSET;
5714#endif /* JOHAB_CHARSET */
5ac45f98 5715#ifdef UNICODE_CHARSET
dfff8a69
JR
5716 if (w32_charset == Qw32_charset_unicode)
5717 return UNICODE_CHARSET;
5ac45f98 5718#endif
dfff8a69
JR
5719 }
5720 }
5721
5722 return DEFAULT_CHARSET;
5ac45f98
GV
5723}
5724
dfff8a69 5725
5ac45f98 5726char *
fbd6baed 5727w32_to_x_charset (fncharset)
5ac45f98
GV
5728 int fncharset;
5729{
1edf84e7
GV
5730 static char buf[16];
5731
dfff8a69
JR
5732 /* NTEMACS_TODO: use w32-charset-info-alist. Multiple matches
5733 are possible, so this will require more than just a rewrite of
5734 this function. w32_to_x_font is the only user of this function,
5735 and that will require rewriting too, and its users. */
5ac45f98
GV
5736 switch (fncharset)
5737 {
4587b026
GV
5738 /* ansi is considered iso8859-1, as most modern ansi fonts are. */
5739 case ANSI_CHARSET: return "iso8859-1";
5740 case DEFAULT_CHARSET: return "ascii-*";
33d52f9c 5741 case SYMBOL_CHARSET: return "ms-symbol";
a4e691ee 5742 case SHIFTJIS_CHARSET: return "jisx0208-sjis";
33d52f9c 5743 case HANGEUL_CHARSET: return "ksc5601.1987-*";
4587b026
GV
5744 case GB2312_CHARSET: return "gb2312-*";
5745 case CHINESEBIG5_CHARSET: return "big5-*";
33d52f9c 5746 case OEM_CHARSET: return "ms-oem";
4587b026
GV
5747
5748 /* More recent versions of Windows (95 and NT4.0) define more
5749 character sets. */
5750#ifdef EASTEUROPE_CHARSET
5751 case EASTEUROPE_CHARSET: return "iso8859-2";
a4e691ee 5752 case TURKISH_CHARSET: return "iso8859-9";
4587b026 5753 case BALTIC_CHARSET: return "iso8859-4";
33d52f9c
GV
5754
5755 /* W95 with international support but not IE4 often has the
5756 KOI8-R codepage but not ISO8859-5. */
5757 case RUSSIAN_CHARSET:
5758 if (!IsValidCodePage(28595) && IsValidCodePage(20886))
5759 return "koi8-r";
5760 else
5761 return "iso8859-5";
4587b026
GV
5762 case ARABIC_CHARSET: return "iso8859-6";
5763 case GREEK_CHARSET: return "iso8859-7";
5764 case HEBREW_CHARSET: return "iso8859-8";
5765 case VIETNAMESE_CHARSET: return "viscii1.1-*";
5766 case THAI_CHARSET: return "tis620-*";
33d52f9c
GV
5767 case MAC_CHARSET: return "mac-*";
5768 case JOHAB_CHARSET: return "ksc5601.1992-*";
a4e691ee 5769
4587b026
GV
5770#endif
5771
5ac45f98 5772#ifdef UNICODE_CHARSET
4587b026 5773 case UNICODE_CHARSET: return "iso10646-unicode";
5ac45f98
GV
5774#endif
5775 }
1edf84e7 5776 /* Encode numerical value of unknown charset. */
4587b026 5777 sprintf (buf, "*-#%u", fncharset);
1edf84e7 5778 return buf;
ee78dc32
GV
5779}
5780
dfff8a69
JR
5781
5782/* Get the Windows codepage corresponding to the specified font. The
5783 charset info in the font name is used to look up
5784 w32-charset-to-codepage-alist. */
5785int
5786w32_codepage_for_font (char *fontname)
5787{
5788 Lisp_Object codepage;
5789 char charset_str[20], *charset, *end;
5790
5791 /* Extract charset part of font string. */
5792 if (sscanf (fontname,
5793 "-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%19s",
5794 charset_str) == EOF)
5795 return CP_DEFAULT;
5796
5797 /* Remove leading "*-". */
5798 if (strncmp ("*-", charset_str, 2) == 0)
5799 charset = charset_str + 2;
5800 else
5801 charset = charset_str;
5802
5803 /* Stop match at wildcard (including preceding '-'). */
5804 if (end = strchr (charset, '*'))
5805 {
5806 if (end > charset && *(end-1) == '-')
5807 end--;
5808 *end = '\0';
5809 }
5810
5811 codepage = Fcdr (Fcdr (Fassoc (build_string(charset),
5812 Vw32_charset_info_alist)));
5813 if (INTEGERP (codepage))
5814 return XINT (codepage);
5815 else
5816 return CP_DEFAULT;
5817}
5818
5819
ee78dc32 5820BOOL
fbd6baed 5821w32_to_x_font (lplogfont, lpxstr, len)
ee78dc32
GV
5822 LOGFONT * lplogfont;
5823 char * lpxstr;
5824 int len;
5825{
6fc2811b 5826 char* fonttype;
f46e6225 5827 char *fontname;
3cb20f4a
RS
5828 char height_pixels[8];
5829 char height_dpi[8];
5830 char width_pixels[8];
4587b026 5831 char *fontname_dash;
d88c567c
JR
5832 int display_resy = one_w32_display_info.resy;
5833 int display_resx = one_w32_display_info.resx;
f46e6225
GV
5834 int bufsz;
5835 struct coding_system coding;
3cb20f4a
RS
5836
5837 if (!lpxstr) abort ();
ee78dc32 5838
3cb20f4a
RS
5839 if (!lplogfont)
5840 return FALSE;
5841
6fc2811b
JR
5842 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
5843 fonttype = "raster";
5844 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
5845 fonttype = "outline";
5846 else
5847 fonttype = "unknown";
5848
f46e6225
GV
5849 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
5850 &coding);
aab5ac44
KH
5851 coding.src_multibyte = 0;
5852 coding.dst_multibyte = 1;
f46e6225
GV
5853 coding.mode |= CODING_MODE_LAST_BLOCK;
5854 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
5855
5856 fontname = alloca(sizeof(*fontname) * bufsz);
5857 decode_coding (&coding, lplogfont->lfFaceName, fontname,
5858 strlen(lplogfont->lfFaceName), bufsz - 1);
5859 *(fontname + coding.produced) = '\0';
4587b026
GV
5860
5861 /* Replace dashes with underscores so the dashes are not
f46e6225 5862 misinterpreted. */
4587b026
GV
5863 fontname_dash = fontname;
5864 while (fontname_dash = strchr (fontname_dash, '-'))
5865 *fontname_dash = '_';
5866
3cb20f4a 5867 if (lplogfont->lfHeight)
ee78dc32 5868 {
3cb20f4a
RS
5869 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
5870 sprintf (height_dpi, "%u",
33d52f9c 5871 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
5872 }
5873 else
ee78dc32 5874 {
3cb20f4a
RS
5875 strcpy (height_pixels, "*");
5876 strcpy (height_dpi, "*");
ee78dc32 5877 }
3cb20f4a
RS
5878 if (lplogfont->lfWidth)
5879 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5880 else
5881 strcpy (width_pixels, "*");
5882
5883 _snprintf (lpxstr, len - 1,
6fc2811b
JR
5884 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
5885 fonttype, /* foundry */
4587b026
GV
5886 fontname, /* family */
5887 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5888 lplogfont->lfItalic?'i':'r', /* slant */
5889 /* setwidth name */
5890 /* add style name */
5891 height_pixels, /* pixel size */
5892 height_dpi, /* point size */
33d52f9c
GV
5893 display_resx, /* resx */
5894 display_resy, /* resy */
4587b026
GV
5895 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5896 ? 'p' : 'c', /* spacing */
5897 width_pixels, /* avg width */
5898 w32_to_x_charset (lplogfont->lfCharSet) /* charset registry
5899 and encoding*/
3cb20f4a
RS
5900 );
5901
ee78dc32
GV
5902 lpxstr[len - 1] = 0; /* just to be sure */
5903 return (TRUE);
5904}
5905
5906BOOL
fbd6baed 5907x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
5908 char * lpxstr;
5909 LOGFONT * lplogfont;
5910{
f46e6225
GV
5911 struct coding_system coding;
5912
ee78dc32 5913 if (!lplogfont) return (FALSE);
f46e6225 5914
ee78dc32 5915 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 5916
1a292d24 5917 /* Set default value for each field. */
771c47d5 5918#if 1
ee78dc32
GV
5919 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5920 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5921 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
5922#else
5923 /* go for maximum quality */
5924 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5925 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5926 lplogfont->lfQuality = PROOF_QUALITY;
5927#endif
5928
1a292d24
AI
5929 lplogfont->lfCharSet = DEFAULT_CHARSET;
5930 lplogfont->lfWeight = FW_DONTCARE;
5931 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5932
5ac45f98
GV
5933 if (!lpxstr)
5934 return FALSE;
5935
5936 /* Provide a simple escape mechanism for specifying Windows font names
5937 * directly -- if font spec does not beginning with '-', assume this
5938 * format:
5939 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5940 */
ee78dc32 5941
5ac45f98
GV
5942 if (*lpxstr == '-')
5943 {
33d52f9c
GV
5944 int fields, tem;
5945 char name[50], weight[20], slant, pitch, pixels[10], height[10],
5946 width[10], resy[10], remainder[20];
5ac45f98 5947 char * encoding;
33d52f9c 5948 int dpi = one_w32_display_info.height_in;
5ac45f98
GV
5949
5950 fields = sscanf (lpxstr,
33d52f9c
GV
5951 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
5952 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5ac45f98
GV
5953 if (fields == EOF) return (FALSE);
5954
6fc2811b
JR
5955 /* If wildcards cover more than one field, we don't know which
5956 field is which, so don't fill any in. */
5957
5958 if (fields < 9)
5959 fields = 0;
5960
5ac45f98
GV
5961 if (fields > 0 && name[0] != '*')
5962 {
8ea3e054
RS
5963 int bufsize;
5964 unsigned char *buf;
5965
f46e6225
GV
5966 setup_coding_system
5967 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
aab5ac44
KH
5968 coding.src_multibyte = 1;
5969 coding.dst_multibyte = 1;
8ea3e054
RS
5970 bufsize = encoding_buffer_size (&coding, strlen (name));
5971 buf = (unsigned char *) alloca (bufsize);
f46e6225 5972 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
5973 encode_coding (&coding, name, buf, strlen (name), bufsize);
5974 if (coding.produced >= LF_FACESIZE)
5975 coding.produced = LF_FACESIZE - 1;
5976 buf[coding.produced] = 0;
5977 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
5978 }
5979 else
5980 {
6fc2811b 5981 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
5982 }
5983
5984 fields--;
5985
fbd6baed 5986 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
5987
5988 fields--;
5989
6fc2811b 5990 if (!NILP (Vw32_enable_synthesized_fonts))
5ac45f98
GV
5991 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5992
5993 fields--;
5994
5995 if (fields > 0 && pixels[0] != '*')
5996 lplogfont->lfHeight = atoi (pixels);
5997
5998 fields--;
5ac45f98 5999 fields--;
33d52f9c
GV
6000 if (fields > 0 && resy[0] != '*')
6001 {
6fc2811b 6002 tem = atoi (resy);
33d52f9c
GV
6003 if (tem > 0) dpi = tem;
6004 }
5ac45f98 6005
33d52f9c
GV
6006 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6007 lplogfont->lfHeight = atoi (height) * dpi / 720;
6008
6009 if (fields > 0)
5ac45f98
GV
6010 lplogfont->lfPitchAndFamily =
6011 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6012
6013 fields--;
6014
6015 if (fields > 0 && width[0] != '*')
6016 lplogfont->lfWidth = atoi (width) / 10;
6017
6018 fields--;
6019
4587b026 6020 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6021 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6022 {
5ac45f98
GV
6023 int len = strlen (remainder);
6024 if (len > 0 && remainder[len-1] == '-')
6025 remainder[len-1] = 0;
ee78dc32 6026 }
5ac45f98
GV
6027 encoding = remainder;
6028 if (strncmp (encoding, "*-", 2) == 0)
6029 encoding += 2;
fbd6baed 6030 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
5ac45f98
GV
6031 }
6032 else
6033 {
6034 int fields;
6035 char name[100], height[10], width[10], weight[20];
a1a80b40 6036
5ac45f98
GV
6037 fields = sscanf (lpxstr,
6038 "%99[^:]:%9[^:]:%9[^:]:%19s",
6039 name, height, width, weight);
6040
6041 if (fields == EOF) return (FALSE);
6042
6043 if (fields > 0)
6044 {
6045 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6046 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6047 }
6048 else
6049 {
6050 lplogfont->lfFaceName[0] = 0;
6051 }
6052
6053 fields--;
6054
6055 if (fields > 0)
6056 lplogfont->lfHeight = atoi (height);
6057
6058 fields--;
6059
6060 if (fields > 0)
6061 lplogfont->lfWidth = atoi (width);
6062
6063 fields--;
6064
fbd6baed 6065 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6066 }
6067
6068 /* This makes TrueType fonts work better. */
6069 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6070
ee78dc32
GV
6071 return (TRUE);
6072}
6073
d88c567c
JR
6074/* Strip the pixel height and point height from the given xlfd, and
6075 return the pixel height. If no pixel height is specified, calculate
6076 one from the point height, or if that isn't defined either, return
6077 0 (which usually signifies a scalable font).
6078*/
6079int xlfd_strip_height (char *fontname)
6080{
6081 int pixel_height, point_height, dpi, field_number;
6082 char *read_from, *write_to;
6083
6084 xassert (fontname);
6085
6086 pixel_height = field_number = 0;
6087 write_to = NULL;
6088
6089 /* Look for height fields. */
6090 for (read_from = fontname; *read_from; read_from++)
6091 {
6092 if (*read_from == '-')
6093 {
6094 field_number++;
6095 if (field_number == 7) /* Pixel height. */
6096 {
6097 read_from++;
6098 write_to = read_from;
6099
6100 /* Find end of field. */
6101 for (;*read_from && *read_from != '-'; read_from++)
6102 ;
6103
6104 /* Split the fontname at end of field. */
6105 if (*read_from)
6106 {
6107 *read_from = '\0';
6108 read_from++;
6109 }
6110 pixel_height = atoi (write_to);
6111 /* Blank out field. */
6112 if (read_from > write_to)
6113 {
6114 *write_to = '-';
6115 write_to++;
6116 }
6117 /* If the pixel height field is at the end (partial xfld),
6118 return now. */
6119 else
6120 return pixel_height;
6121
6122 /* If we got a pixel height, the point height can be
6123 ignored. Just blank it out and break now. */
6124 if (pixel_height)
6125 {
6126 /* Find end of point size field. */
6127 for (; *read_from && *read_from != '-'; read_from++)
6128 ;
6129
6130 if (*read_from)
6131 read_from++;
6132
6133 /* Blank out the point size field. */
6134 if (read_from > write_to)
6135 {
6136 *write_to = '-';
6137 write_to++;
6138 }
6139 else
6140 return pixel_height;
6141
6142 break;
6143 }
6144 /* If the point height is already blank, break now. */
6145 if (*read_from == '-')
6146 {
6147 read_from++;
6148 break;
6149 }
6150 }
6151 else if (field_number == 8)
6152 {
6153 /* If we didn't get a pixel height, try to get the point
6154 height and convert that. */
6155 int point_size;
6156 char *point_size_start = read_from++;
6157
6158 /* Find end of field. */
6159 for (; *read_from && *read_from != '-'; read_from++)
6160 ;
6161
6162 if (*read_from)
6163 {
6164 *read_from = '\0';
6165 read_from++;
6166 }
6167
6168 point_size = atoi (point_size_start);
6169
6170 /* Convert to pixel height. */
6171 pixel_height = point_size
6172 * one_w32_display_info.height_in / 720;
6173
6174 /* Blank out this field and break. */
6175 *write_to = '-';
6176 write_to++;
6177 break;
6178 }
6179 }
6180 }
6181
6182 /* Shift the rest of the font spec into place. */
6183 if (write_to && read_from > write_to)
6184 {
6185 for (; *read_from; read_from++, write_to++)
6186 *write_to = *read_from;
6187 *write_to = '\0';
6188 }
6189
6190 return pixel_height;
6191}
6192
6fc2811b 6193/* Assume parameter 1 is fully qualified, no wildcards. */
ee78dc32 6194BOOL
6fc2811b
JR
6195w32_font_match (fontname, pattern)
6196 char * fontname;
6197 char * pattern;
ee78dc32 6198{
6fc2811b 6199 char *regex = alloca (strlen (pattern) * 2);
d88c567c 6200 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6201 char *ptr;
ee78dc32 6202
d88c567c
JR
6203 /* Copy fontname so we can modify it during comparison. */
6204 strcpy (font_name_copy, fontname);
6205
6fc2811b
JR
6206 ptr = regex;
6207 *ptr++ = '^';
ee78dc32 6208
6fc2811b
JR
6209 /* Turn pattern into a regexp and do a regexp match. */
6210 for (; *pattern; pattern++)
6211 {
6212 if (*pattern == '?')
6213 *ptr++ = '.';
6214 else if (*pattern == '*')
6215 {
6216 *ptr++ = '.';
6217 *ptr++ = '*';
6218 }
33d52f9c 6219 else
6fc2811b 6220 *ptr++ = *pattern;
ee78dc32 6221 }
6fc2811b
JR
6222 *ptr = '$';
6223 *(ptr + 1) = '\0';
6224
d88c567c
JR
6225 /* Strip out font heights and compare them seperately, since
6226 rounding error can cause mismatches. This also allows a
6227 comparison between a font that declares only a pixel height and a
6228 pattern that declares the point height.
6229 */
6230 {
6231 int font_height, pattern_height;
6232
6233 font_height = xlfd_strip_height (font_name_copy);
6234 pattern_height = xlfd_strip_height (regex);
6235
6236 /* Compare now, and don't bother doing expensive regexp matching
6237 if the heights differ. */
6238 if (font_height && pattern_height && (font_height != pattern_height))
6239 return FALSE;
6240 }
6241
6fc2811b 6242 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 6243 font_name_copy) >= 0);
ee78dc32
GV
6244}
6245
5ca0cd71
GV
6246/* Callback functions, and a structure holding info they need, for
6247 listing system fonts on W32. We need one set of functions to do the
6248 job properly, but these don't work on NT 3.51 and earlier, so we
6249 have a second set which don't handle character sets properly to
6250 fall back on.
6251
6252 In both cases, there are two passes made. The first pass gets one
6253 font from each family, the second pass lists all the fonts from
6254 each family. */
6255
ee78dc32
GV
6256typedef struct enumfont_t
6257{
6258 HDC hdc;
6259 int numFonts;
3cb20f4a 6260 LOGFONT logfont;
ee78dc32
GV
6261 XFontStruct *size_ref;
6262 Lisp_Object *pattern;
ee78dc32
GV
6263 Lisp_Object *tail;
6264} enumfont_t;
6265
6266int CALLBACK
6267enum_font_cb2 (lplf, lptm, FontType, lpef)
6268 ENUMLOGFONT * lplf;
6269 NEWTEXTMETRIC * lptm;
6270 int FontType;
6271 enumfont_t * lpef;
6272{
1edf84e7 6273 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
ee78dc32
GV
6274 return (1);
6275
4587b026
GV
6276 /* Check that the character set matches if it was specified */
6277 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6278 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6279 return (1);
6280
ee78dc32
GV
6281 {
6282 char buf[100];
4587b026 6283 Lisp_Object width = Qnil;
ee78dc32 6284
6fc2811b
JR
6285 /* Truetype fonts do not report their true metrics until loaded */
6286 if (FontType != RASTER_FONTTYPE)
3cb20f4a 6287 {
6fc2811b
JR
6288 if (!NILP (*(lpef->pattern)))
6289 {
6290 /* Scalable fonts are as big as you want them to be. */
6291 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6292 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6293 width = make_number (lpef->logfont.lfWidth);
6294 }
6295 else
6296 {
6297 lplf->elfLogFont.lfHeight = 0;
6298 lplf->elfLogFont.lfWidth = 0;
6299 }
3cb20f4a 6300 }
6fc2811b 6301
f46e6225
GV
6302 /* Make sure the height used here is the same as everywhere
6303 else (ie character height, not cell height). */
6fc2811b
JR
6304 if (lplf->elfLogFont.lfHeight > 0)
6305 {
6306 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6307 if (FontType == RASTER_FONTTYPE)
6308 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6309 else
6310 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6311 }
4587b026 6312
33d52f9c
GV
6313 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100))
6314 return (0);
ee78dc32 6315
5ca0cd71
GV
6316 if (NILP (*(lpef->pattern))
6317 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 6318 {
4587b026 6319 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
8e713be6 6320 lpef->tail = &(XCDR (*lpef->tail));
ee78dc32
GV
6321 lpef->numFonts++;
6322 }
6323 }
6fc2811b 6324
ee78dc32
GV
6325 return (1);
6326}
6327
6328int CALLBACK
6329enum_font_cb1 (lplf, lptm, FontType, lpef)
6330 ENUMLOGFONT * lplf;
6331 NEWTEXTMETRIC * lptm;
6332 int FontType;
6333 enumfont_t * lpef;
6334{
6335 return EnumFontFamilies (lpef->hdc,
6336 lplf->elfLogFont.lfFaceName,
6337 (FONTENUMPROC) enum_font_cb2,
6338 (LPARAM) lpef);
6339}
6340
6341
5ca0cd71
GV
6342int CALLBACK
6343enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6344 ENUMLOGFONTEX * lplf;
6345 NEWTEXTMETRICEX * lptm;
6346 int font_type;
6347 enumfont_t * lpef;
6348{
6349 /* We are not interested in the extra info we get back from the 'Ex
6350 version - only the fact that we get character set variations
6351 enumerated seperately. */
6352 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6353 font_type, lpef);
6354}
6355
6356int CALLBACK
6357enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6358 ENUMLOGFONTEX * lplf;
6359 NEWTEXTMETRICEX * lptm;
6360 int font_type;
6361 enumfont_t * lpef;
6362{
6363 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6364 FARPROC enum_font_families_ex
6365 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6366 /* We don't really expect EnumFontFamiliesEx to disappear once we
6367 get here, so don't bother handling it gracefully. */
6368 if (enum_font_families_ex == NULL)
6369 error ("gdi32.dll has disappeared!");
6370 return enum_font_families_ex (lpef->hdc,
6371 &lplf->elfLogFont,
6372 (FONTENUMPROC) enum_fontex_cb2,
6373 (LPARAM) lpef, 0);
6374}
6375
4587b026
GV
6376/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6377 and xterm.c in Emacs 20.3) */
6378
5ca0cd71 6379Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6380{
6381 char *fontname, *ptnstr;
6382 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6383 int n_fonts = 0;
33d52f9c
GV
6384
6385 list = Vw32_bdf_filename_alist;
6386 ptnstr = XSTRING (pattern)->data;
6387
8e713be6 6388 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6389 {
8e713be6 6390 tem = XCAR (list);
33d52f9c 6391 if (CONSP (tem))
8e713be6 6392 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
6393 else if (STRINGP (tem))
6394 fontname = XSTRING (tem)->data;
6395 else
6396 continue;
6397
6398 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6399 {
8e713be6 6400 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6401 n_fonts++;
6402 if (n_fonts >= max_names)
6403 break;
6404 }
33d52f9c
GV
6405 }
6406
6407 return newlist;
6408}
6409
5ca0cd71
GV
6410Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
6411 int size, int max_names);
6412
4587b026
GV
6413/* Return a list of names of available fonts matching PATTERN on frame
6414 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6415 to be listed. Frame F NULL means we have not yet created any
6416 frame, which means we can't get proper size info, as we don't have
6417 a device context to use for GetTextMetrics.
6418 MAXNAMES sets a limit on how many fonts to match. */
6419
6420Lisp_Object
6421w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
6422{
6fc2811b 6423 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6424 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6425 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6426 int n_fonts = 0;
396594fe 6427
4587b026
GV
6428 patterns = Fassoc (pattern, Valternate_fontname_alist);
6429 if (NILP (patterns))
6430 patterns = Fcons (pattern, Qnil);
6431
8e713be6 6432 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6433 {
6434 enumfont_t ef;
6435
8e713be6 6436 tpat = XCAR (patterns);
4587b026
GV
6437
6438 /* See if we cached the result for this particular query.
6439 The cache is an alist of the form:
6440 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6441 */
8e713be6 6442 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 6443 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
6444 {
6445 list = Fcdr_safe (list);
6446 /* We have a cached list. Don't have to get the list again. */
6447 goto label_cached;
6448 }
6449
6450 BLOCK_INPUT;
6451 /* At first, put PATTERN in the cache. */
6452 list = Qnil;
33d52f9c
GV
6453 ef.pattern = &tpat;
6454 ef.tail = &list;
4587b026 6455 ef.numFonts = 0;
33d52f9c 6456
5ca0cd71
GV
6457 /* Use EnumFontFamiliesEx where it is available, as it knows
6458 about character sets. Fall back to EnumFontFamilies for
6459 older versions of NT that don't support the 'Ex function. */
33d52f9c 6460 x_to_w32_font (STRINGP (tpat) ? XSTRING (tpat)->data :
4587b026
GV
6461 NULL, &ef.logfont);
6462 {
5ca0cd71
GV
6463 LOGFONT font_match_pattern;
6464 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6465 FARPROC enum_font_families_ex
6466 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6467
6468 /* We do our own pattern matching so we can handle wildcards. */
6469 font_match_pattern.lfFaceName[0] = 0;
6470 font_match_pattern.lfPitchAndFamily = 0;
6471 /* We can use the charset, because if it is a wildcard it will
6472 be DEFAULT_CHARSET anyway. */
6473 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6474
33d52f9c 6475 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 6476
5ca0cd71
GV
6477 if (enum_font_families_ex)
6478 enum_font_families_ex (ef.hdc,
6479 &font_match_pattern,
6480 (FONTENUMPROC) enum_fontex_cb1,
6481 (LPARAM) &ef, 0);
6482 else
6483 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6484 (LPARAM)&ef);
4587b026 6485
33d52f9c 6486 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
6487 }
6488
6489 UNBLOCK_INPUT;
6490
6491 /* Make a list of the fonts we got back.
6492 Store that in the font cache for the display. */
8e713be6 6493 XCDR (dpyinfo->name_list_element)
33d52f9c 6494 = Fcons (Fcons (tpat, list),
8e713be6 6495 XCDR (dpyinfo->name_list_element));
4587b026
GV
6496
6497 label_cached:
6498 if (NILP (list)) continue; /* Try the remaining alternatives. */
6499
6500 newlist = second_best = Qnil;
6501
6502 /* Make a list of the fonts that have the right width. */
8e713be6 6503 for (; CONSP (list); list = XCDR (list))
4587b026
GV
6504 {
6505 int found_size;
8e713be6 6506 tem = XCAR (list);
4587b026
GV
6507
6508 if (!CONSP (tem))
6509 continue;
8e713be6 6510 if (NILP (XCAR (tem)))
4587b026
GV
6511 continue;
6512 if (!size)
6513 {
8e713be6 6514 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6515 n_fonts++;
6516 if (n_fonts >= maxnames)
6517 break;
6518 else
6519 continue;
4587b026 6520 }
8e713be6 6521 if (!INTEGERP (XCDR (tem)))
4587b026
GV
6522 {
6523 /* Since we don't yet know the size of the font, we must
6524 load it and try GetTextMetrics. */
4587b026
GV
6525 W32FontStruct thisinfo;
6526 LOGFONT lf;
6527 HDC hdc;
6528 HANDLE oldobj;
6529
8e713be6 6530 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
6531 continue;
6532
6533 BLOCK_INPUT;
33d52f9c 6534 thisinfo.bdf = NULL;
4587b026
GV
6535 thisinfo.hfont = CreateFontIndirect (&lf);
6536 if (thisinfo.hfont == NULL)
6537 continue;
6538
6539 hdc = GetDC (dpyinfo->root_window);
6540 oldobj = SelectObject (hdc, thisinfo.hfont);
6541 if (GetTextMetrics (hdc, &thisinfo.tm))
8e713be6 6542 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
4587b026 6543 else
8e713be6 6544 XCDR (tem) = make_number (0);
4587b026
GV
6545 SelectObject (hdc, oldobj);
6546 ReleaseDC (dpyinfo->root_window, hdc);
6547 DeleteObject(thisinfo.hfont);
6548 UNBLOCK_INPUT;
6549 }
8e713be6 6550 found_size = XINT (XCDR (tem));
4587b026 6551 if (found_size == size)
5ca0cd71 6552 {
8e713be6 6553 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6554 n_fonts++;
6555 if (n_fonts >= maxnames)
6556 break;
6557 }
4587b026
GV
6558 /* keep track of the closest matching size in case
6559 no exact match is found. */
6560 else if (found_size > 0)
6561 {
6562 if (NILP (second_best))
6563 second_best = tem;
5ca0cd71 6564
4587b026
GV
6565 else if (found_size < size)
6566 {
8e713be6
KR
6567 if (XINT (XCDR (second_best)) > size
6568 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
6569 second_best = tem;
6570 }
6571 else
6572 {
8e713be6
KR
6573 if (XINT (XCDR (second_best)) > size
6574 && XINT (XCDR (second_best)) >
4587b026
GV
6575 found_size)
6576 second_best = tem;
6577 }
6578 }
6579 }
6580
6581 if (!NILP (newlist))
6582 break;
6583 else if (!NILP (second_best))
6584 {
8e713be6 6585 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
6586 break;
6587 }
6588 }
6589
33d52f9c 6590 /* Include any bdf fonts. */
5ca0cd71 6591 if (n_fonts < maxnames)
33d52f9c
GV
6592 {
6593 Lisp_Object combined[2];
5ca0cd71 6594 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
6595 combined[1] = newlist;
6596 newlist = Fnconc(2, combined);
6597 }
6598
5ca0cd71
GV
6599 /* If we can't find a font that matches, check if Windows would be
6600 able to synthesize it from a different style. */
6fc2811b 6601 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
5ca0cd71
GV
6602 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6603
4587b026
GV
6604 return newlist;
6605}
6606
5ca0cd71
GV
6607Lisp_Object
6608w32_list_synthesized_fonts (f, pattern, size, max_names)
6609 FRAME_PTR f;
6610 Lisp_Object pattern;
6611 int size;
6612 int max_names;
6613{
6614 int fields;
6615 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6616 char style[20], slant;
6617 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6618
6619 full_pattn = XSTRING (pattern)->data;
6620
6621 pattn_part2 = alloca (XSTRING (pattern)->size);
6622 /* Allow some space for wildcard expansion. */
6623 new_pattn = alloca (XSTRING (pattern)->size + 100);
6624
6625 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6626 foundary, family, style, &slant, pattn_part2);
6627 if (fields == EOF || fields < 5)
6628 return Qnil;
6629
6630 /* If the style and slant are wildcards already there is no point
6631 checking again (and we don't want to keep recursing). */
6632 if (*style == '*' && slant == '*')
6633 return Qnil;
6634
6635 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6636
6637 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6638
8e713be6 6639 for ( ; CONSP (matches); matches = XCDR (matches))
5ca0cd71 6640 {
8e713be6 6641 tem = XCAR (matches);
5ca0cd71
GV
6642 if (!STRINGP (tem))
6643 continue;
6644
6645 full_pattn = XSTRING (tem)->data;
6646 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6647 foundary, family, pattn_part2);
6648 if (fields == EOF || fields < 3)
6649 continue;
6650
6651 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6652 slant, pattn_part2);
6653
6654 synthed_matches = Fcons (build_string (new_pattn),
6655 synthed_matches);
6656 }
6657
6658 return synthed_matches;
6659}
6660
6661
4587b026
GV
6662/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6663struct font_info *
6664w32_get_font_info (f, font_idx)
6665 FRAME_PTR f;
6666 int font_idx;
6667{
6668 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6669}
6670
6671
6672struct font_info*
6673w32_query_font (struct frame *f, char *fontname)
6674{
6675 int i;
6676 struct font_info *pfi;
6677
6678 pfi = FRAME_W32_FONT_TABLE (f);
6679
6680 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6681 {
6682 if (strcmp(pfi->name, fontname) == 0) return pfi;
6683 }
6684
6685 return NULL;
6686}
6687
6688/* Find a CCL program for a font specified by FONTP, and set the member
6689 `encoder' of the structure. */
6690
6691void
6692w32_find_ccl_program (fontp)
6693 struct font_info *fontp;
6694{
3545439c 6695 Lisp_Object list, elt;
4587b026 6696
8e713be6 6697 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 6698 {
8e713be6 6699 elt = XCAR (list);
4587b026 6700 if (CONSP (elt)
8e713be6
KR
6701 && STRINGP (XCAR (elt))
6702 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 6703 >= 0))
3545439c
KH
6704 break;
6705 }
6706 if (! NILP (list))
6707 {
17eedd00
KH
6708 struct ccl_program *ccl
6709 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 6710
8e713be6 6711 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
6712 xfree (ccl);
6713 else
6714 fontp->font_encoder = ccl;
4587b026
GV
6715 }
6716}
6717
6718\f
6fc2811b
JR
6719DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6720 1, 1, 0,
6721 "Return a list of BDF fonts in DIR, suitable for appending to\n\
6722w32-bdf-filename-alist. Fonts which do not contain an xfld description\n\
6723will not be included in the list. DIR may be a list of directories.")
6724 (directory)
6725 Lisp_Object directory;
6726{
6727 Lisp_Object list = Qnil;
6728 struct gcpro gcpro1, gcpro2;
ee78dc32 6729
6fc2811b
JR
6730 if (!CONSP (directory))
6731 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 6732
6fc2811b 6733 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 6734 {
6fc2811b
JR
6735 Lisp_Object pair[2];
6736 pair[0] = list;
6737 pair[1] = Qnil;
6738 GCPRO2 (directory, list);
6739 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
6740 list = Fnconc( 2, pair );
6741 UNGCPRO;
6742 }
6743 return list;
6744}
ee78dc32 6745
6fc2811b
JR
6746/* Find BDF files in a specified directory. (use GCPRO when calling,
6747 as this calls lisp to get a directory listing). */
6748Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
6749{
6750 Lisp_Object filelist, list = Qnil;
6751 char fontname[100];
ee78dc32 6752
6fc2811b
JR
6753 if (!STRINGP(directory))
6754 return Qnil;
ee78dc32 6755
6fc2811b
JR
6756 filelist = Fdirectory_files (directory, Qt,
6757 build_string (".*\\.[bB][dD][fF]"), Qt);
ee78dc32 6758
6fc2811b 6759 for ( ; CONSP(filelist); filelist = XCDR (filelist))
ee78dc32 6760 {
6fc2811b
JR
6761 Lisp_Object filename = XCAR (filelist);
6762 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
6763 store_in_alist (&list, build_string (fontname), filename);
6764 }
6765 return list;
6766}
ee78dc32 6767
6fc2811b
JR
6768\f
6769DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
dfff8a69 6770 "Internal function called by `color-defined-p', which see.")
6fc2811b
JR
6771 (color, frame)
6772 Lisp_Object color, frame;
6773{
6774 XColor foo;
6775 FRAME_PTR f = check_x_frame (frame);
ee78dc32 6776
6fc2811b 6777 CHECK_STRING (color, 1);
ee78dc32 6778
6fc2811b
JR
6779 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6780 return Qt;
6781 else
6782 return Qnil;
6783}
ee78dc32 6784
2d764c78 6785DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
dfff8a69 6786 "Internal function called by `color-values', which see.")
ee78dc32
GV
6787 (color, frame)
6788 Lisp_Object color, frame;
6789{
6fc2811b 6790 XColor foo;
ee78dc32
GV
6791 FRAME_PTR f = check_x_frame (frame);
6792
6793 CHECK_STRING (color, 1);
6794
6fc2811b 6795 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
6796 {
6797 Lisp_Object rgb[3];
6798
6fc2811b
JR
6799 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
6800 | GetRValue (foo.pixel));
6801 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
6802 | GetGValue (foo.pixel));
6803 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
6804 | GetBValue (foo.pixel));
ee78dc32
GV
6805 return Flist (3, rgb);
6806 }
6807 else
6808 return Qnil;
6809}
6810
2d764c78 6811DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
dfff8a69 6812 "Internal function called by `display-color-p', which see.")
ee78dc32
GV
6813 (display)
6814 Lisp_Object display;
6815{
fbd6baed 6816 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6817
6818 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6819 return Qnil;
6820
6821 return Qt;
6822}
6823
6824DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
6825 0, 1, 0,
6826 "Return t if the X display supports shades of gray.\n\
6827Note that color displays do support shades of gray.\n\
6828The optional argument DISPLAY specifies which display to ask about.\n\
6829DISPLAY should be either a frame or a display name (a string).\n\
6830If omitted or nil, that stands for the selected frame's display.")
6831 (display)
6832 Lisp_Object display;
6833{
fbd6baed 6834 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6835
6836 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6837 return Qnil;
6838
6839 return Qt;
6840}
6841
6842DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
6843 0, 1, 0,
6844 "Returns the width in pixels of the X display DISPLAY.\n\
6845The optional argument DISPLAY specifies which display to ask about.\n\
6846DISPLAY should be either a frame or a display name (a string).\n\
6847If omitted or nil, that stands for the selected frame's display.")
6848 (display)
6849 Lisp_Object display;
6850{
fbd6baed 6851 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6852
6853 return make_number (dpyinfo->width);
6854}
6855
6856DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
6857 Sx_display_pixel_height, 0, 1, 0,
6858 "Returns the height in pixels of the X display DISPLAY.\n\
6859The optional argument DISPLAY specifies which display to ask about.\n\
6860DISPLAY should be either a frame or a display name (a string).\n\
6861If omitted or nil, that stands for the selected frame's display.")
6862 (display)
6863 Lisp_Object display;
6864{
fbd6baed 6865 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6866
6867 return make_number (dpyinfo->height);
6868}
6869
6870DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
6871 0, 1, 0,
6872 "Returns the number of bitplanes of the display DISPLAY.\n\
6873The optional argument DISPLAY specifies which display to ask about.\n\
6874DISPLAY should be either a frame or a display name (a string).\n\
6875If omitted or nil, that stands for the selected frame's display.")
6876 (display)
6877 Lisp_Object display;
6878{
fbd6baed 6879 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6880
6881 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6882}
6883
6884DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
6885 0, 1, 0,
6886 "Returns the number of color cells of the display DISPLAY.\n\
6887The optional argument DISPLAY specifies which display to ask about.\n\
6888DISPLAY should be either a frame or a display name (a string).\n\
6889If omitted or nil, that stands for the selected frame's display.")
6890 (display)
6891 Lisp_Object display;
6892{
fbd6baed 6893 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6894 HDC hdc;
6895 int cap;
6896
5ac45f98
GV
6897 hdc = GetDC (dpyinfo->root_window);
6898 if (dpyinfo->has_palette)
6899 cap = GetDeviceCaps (hdc,SIZEPALETTE);
6900 else
6901 cap = GetDeviceCaps (hdc,NUMCOLORS);
ee78dc32
GV
6902
6903 ReleaseDC (dpyinfo->root_window, hdc);
6904
6905 return make_number (cap);
6906}
6907
6908DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6909 Sx_server_max_request_size,
6910 0, 1, 0,
6911 "Returns the maximum request size of the server of display DISPLAY.\n\
6912The optional argument DISPLAY specifies which display to ask about.\n\
6913DISPLAY should be either a frame or a display name (a string).\n\
6914If omitted or nil, that stands for the selected frame's display.")
6915 (display)
6916 Lisp_Object display;
6917{
fbd6baed 6918 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6919
6920 return make_number (1);
6921}
6922
6923DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
fbd6baed 6924 "Returns the vendor ID string of the W32 system (Microsoft).\n\
ee78dc32
GV
6925The optional argument DISPLAY specifies which display to ask about.\n\
6926DISPLAY should be either a frame or a display name (a string).\n\
6927If omitted or nil, that stands for the selected frame's display.")
6928 (display)
6929 Lisp_Object display;
6930{
dfff8a69 6931 return build_string ("Microsoft Corp.");
ee78dc32
GV
6932}
6933
6934DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
6935 "Returns the version numbers of the server of display DISPLAY.\n\
6936The value is a list of three integers: the major and minor\n\
6937version numbers, and the vendor-specific release\n\
6938number. See also the function `x-server-vendor'.\n\n\
6939The optional argument DISPLAY specifies which display to ask about.\n\
6940DISPLAY should be either a frame or a display name (a string).\n\
6941If omitted or nil, that stands for the selected frame's display.")
6942 (display)
6943 Lisp_Object display;
6944{
fbd6baed
GV
6945 return Fcons (make_number (w32_major_version),
6946 Fcons (make_number (w32_minor_version), Qnil));
ee78dc32
GV
6947}
6948
6949DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
6950 "Returns the number of screens on the server of display DISPLAY.\n\
6951The optional argument DISPLAY specifies which display to ask about.\n\
6952DISPLAY should be either a frame or a display name (a string).\n\
6953If omitted or nil, that stands for the selected frame's display.")
6954 (display)
6955 Lisp_Object display;
6956{
ee78dc32
GV
6957 return make_number (1);
6958}
6959
6960DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
6961 "Returns the height in millimeters of the X display DISPLAY.\n\
6962The optional argument DISPLAY specifies which display to ask about.\n\
6963DISPLAY should be either a frame or a display name (a string).\n\
6964If omitted or nil, that stands for the selected frame's display.")
6965 (display)
6966 Lisp_Object display;
6967{
fbd6baed 6968 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6969 HDC hdc;
6970 int cap;
6971
5ac45f98 6972 hdc = GetDC (dpyinfo->root_window);
3c190163 6973
ee78dc32 6974 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 6975
ee78dc32
GV
6976 ReleaseDC (dpyinfo->root_window, hdc);
6977
6978 return make_number (cap);
6979}
6980
6981DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
6982 "Returns the width in millimeters of the X display DISPLAY.\n\
6983The optional argument DISPLAY specifies which display to ask about.\n\
6984DISPLAY should be either a frame or a display name (a string).\n\
6985If omitted or nil, that stands for the selected frame's display.")
6986 (display)
6987 Lisp_Object display;
6988{
fbd6baed 6989 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6990
6991 HDC hdc;
6992 int cap;
6993
5ac45f98 6994 hdc = GetDC (dpyinfo->root_window);
3c190163 6995
ee78dc32 6996 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 6997
ee78dc32
GV
6998 ReleaseDC (dpyinfo->root_window, hdc);
6999
7000 return make_number (cap);
7001}
7002
7003DEFUN ("x-display-backing-store", Fx_display_backing_store,
7004 Sx_display_backing_store, 0, 1, 0,
7005 "Returns an indication of whether display DISPLAY does backing store.\n\
7006The value may be `always', `when-mapped', or `not-useful'.\n\
7007The optional argument DISPLAY specifies which display to ask about.\n\
7008DISPLAY should be either a frame or a display name (a string).\n\
7009If omitted or nil, that stands for the selected frame's display.")
7010 (display)
7011 Lisp_Object display;
7012{
7013 return intern ("not-useful");
7014}
7015
7016DEFUN ("x-display-visual-class", Fx_display_visual_class,
7017 Sx_display_visual_class, 0, 1, 0,
7018 "Returns the visual class of the display DISPLAY.\n\
7019The value is one of the symbols `static-gray', `gray-scale',\n\
7020`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7021The optional argument DISPLAY specifies which display to ask about.\n\
7022DISPLAY should be either a frame or a display name (a string).\n\
7023If omitted or nil, that stands for the selected frame's display.")
7024 (display)
7025 Lisp_Object display;
7026{
fbd6baed 7027 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7028
7029#if 0
7030 switch (dpyinfo->visual->class)
7031 {
7032 case StaticGray: return (intern ("static-gray"));
7033 case GrayScale: return (intern ("gray-scale"));
7034 case StaticColor: return (intern ("static-color"));
7035 case PseudoColor: return (intern ("pseudo-color"));
7036 case TrueColor: return (intern ("true-color"));
7037 case DirectColor: return (intern ("direct-color"));
7038 default:
7039 error ("Display has an unknown visual class");
7040 }
7041#endif
7042
7043 error ("Display has an unknown visual class");
7044}
7045
7046DEFUN ("x-display-save-under", Fx_display_save_under,
7047 Sx_display_save_under, 0, 1, 0,
7048 "Returns t if the display DISPLAY supports the save-under feature.\n\
7049The optional argument DISPLAY specifies which display to ask about.\n\
7050DISPLAY should be either a frame or a display name (a string).\n\
7051If omitted or nil, that stands for the selected frame's display.")
7052 (display)
7053 Lisp_Object display;
7054{
6fc2811b
JR
7055 return Qnil;
7056}
7057\f
7058int
7059x_pixel_width (f)
7060 register struct frame *f;
7061{
7062 return PIXEL_WIDTH (f);
7063}
7064
7065int
7066x_pixel_height (f)
7067 register struct frame *f;
7068{
7069 return PIXEL_HEIGHT (f);
7070}
7071
7072int
7073x_char_width (f)
7074 register struct frame *f;
7075{
7076 return FONT_WIDTH (f->output_data.w32->font);
7077}
7078
7079int
7080x_char_height (f)
7081 register struct frame *f;
7082{
7083 return f->output_data.w32->line_height;
7084}
7085
7086int
7087x_screen_planes (f)
7088 register struct frame *f;
7089{
7090 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7091}
7092\f
7093/* Return the display structure for the display named NAME.
7094 Open a new connection if necessary. */
7095
7096struct w32_display_info *
7097x_display_info_for_name (name)
7098 Lisp_Object name;
7099{
7100 Lisp_Object names;
7101 struct w32_display_info *dpyinfo;
7102
7103 CHECK_STRING (name, 0);
7104
7105 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7106 dpyinfo;
7107 dpyinfo = dpyinfo->next, names = XCDR (names))
7108 {
7109 Lisp_Object tem;
7110 tem = Fstring_equal (XCAR (XCAR (names)), name);
7111 if (!NILP (tem))
7112 return dpyinfo;
7113 }
7114
7115 /* Use this general default value to start with. */
7116 Vx_resource_name = Vinvocation_name;
7117
7118 validate_x_resource_name ();
7119
7120 dpyinfo = w32_term_init (name, (unsigned char *)0,
7121 (char *) XSTRING (Vx_resource_name)->data);
7122
7123 if (dpyinfo == 0)
7124 error ("Cannot connect to server %s", XSTRING (name)->data);
7125
7126 w32_in_use = 1;
7127 XSETFASTINT (Vwindow_system_version, 3);
7128
7129 return dpyinfo;
7130}
7131
7132DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7133 1, 3, 0, "Open a connection to a server.\n\
7134DISPLAY is the name of the display to connect to.\n\
7135Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7136If the optional third arg MUST-SUCCEED is non-nil,\n\
7137terminate Emacs if we can't open the connection.")
7138 (display, xrm_string, must_succeed)
7139 Lisp_Object display, xrm_string, must_succeed;
7140{
7141 unsigned char *xrm_option;
7142 struct w32_display_info *dpyinfo;
7143
7144 CHECK_STRING (display, 0);
7145 if (! NILP (xrm_string))
7146 CHECK_STRING (xrm_string, 1);
7147
7148 if (! EQ (Vwindow_system, intern ("w32")))
7149 error ("Not using Microsoft Windows");
7150
7151 /* Allow color mapping to be defined externally; first look in user's
7152 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7153 {
7154 Lisp_Object color_file;
7155 struct gcpro gcpro1;
7156
7157 color_file = build_string("~/rgb.txt");
7158
7159 GCPRO1 (color_file);
7160
7161 if (NILP (Ffile_readable_p (color_file)))
7162 color_file =
7163 Fexpand_file_name (build_string ("rgb.txt"),
7164 Fsymbol_value (intern ("data-directory")));
7165
7166 Vw32_color_map = Fw32_load_color_file (color_file);
7167
7168 UNGCPRO;
7169 }
7170 if (NILP (Vw32_color_map))
7171 Vw32_color_map = Fw32_default_color_map ();
7172
7173 if (! NILP (xrm_string))
7174 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7175 else
7176 xrm_option = (unsigned char *) 0;
7177
7178 /* Use this general default value to start with. */
7179 /* First remove .exe suffix from invocation-name - it looks ugly. */
7180 {
7181 char basename[ MAX_PATH ], *str;
7182
7183 strcpy (basename, XSTRING (Vinvocation_name)->data);
7184 str = strrchr (basename, '.');
7185 if (str) *str = 0;
7186 Vinvocation_name = build_string (basename);
7187 }
7188 Vx_resource_name = Vinvocation_name;
7189
7190 validate_x_resource_name ();
7191
7192 /* This is what opens the connection and sets x_current_display.
7193 This also initializes many symbols, such as those used for input. */
7194 dpyinfo = w32_term_init (display, xrm_option,
7195 (char *) XSTRING (Vx_resource_name)->data);
7196
7197 if (dpyinfo == 0)
7198 {
7199 if (!NILP (must_succeed))
7200 fatal ("Cannot connect to server %s.\n",
7201 XSTRING (display)->data);
7202 else
7203 error ("Cannot connect to server %s", XSTRING (display)->data);
7204 }
7205
7206 w32_in_use = 1;
7207
7208 XSETFASTINT (Vwindow_system_version, 3);
7209 return Qnil;
7210}
7211
7212DEFUN ("x-close-connection", Fx_close_connection,
7213 Sx_close_connection, 1, 1, 0,
7214 "Close the connection to DISPLAY's server.\n\
7215For DISPLAY, specify either a frame or a display name (a string).\n\
7216If DISPLAY is nil, that stands for the selected frame's display.")
7217 (display)
7218 Lisp_Object display;
7219{
7220 struct w32_display_info *dpyinfo = check_x_display_info (display);
7221 int i;
7222
7223 if (dpyinfo->reference_count > 0)
7224 error ("Display still has frames on it");
7225
7226 BLOCK_INPUT;
7227 /* Free the fonts in the font table. */
7228 for (i = 0; i < dpyinfo->n_fonts; i++)
7229 if (dpyinfo->font_table[i].name)
7230 {
126f2e35
JR
7231 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7232 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 7233 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
7234 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7235 }
7236 x_destroy_all_bitmaps (dpyinfo);
7237
7238 x_delete_display (dpyinfo);
7239 UNBLOCK_INPUT;
7240
7241 return Qnil;
7242}
7243
7244DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7245 "Return the list of display names that Emacs has connections to.")
7246 ()
7247{
7248 Lisp_Object tail, result;
7249
7250 result = Qnil;
7251 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7252 result = Fcons (XCAR (XCAR (tail)), result);
7253
7254 return result;
7255}
7256
7257DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7258 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7259If ON is nil, allow buffering of requests.\n\
7260This is a noop on W32 systems.\n\
7261The optional second argument DISPLAY specifies which display to act on.\n\
7262DISPLAY should be either a frame or a display name (a string).\n\
7263If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7264 (on, display)
7265 Lisp_Object display, on;
7266{
6fc2811b
JR
7267 return Qnil;
7268}
7269
7270\f
7271\f
7272/***********************************************************************
7273 Image types
7274 ***********************************************************************/
7275
7276/* Value is the number of elements of vector VECTOR. */
7277
7278#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7279
7280/* List of supported image types. Use define_image_type to add new
7281 types. Use lookup_image_type to find a type for a given symbol. */
7282
7283static struct image_type *image_types;
7284
6fc2811b
JR
7285/* The symbol `image' which is the car of the lists used to represent
7286 images in Lisp. */
7287
7288extern Lisp_Object Qimage;
7289
7290/* The symbol `xbm' which is used as the type symbol for XBM images. */
7291
7292Lisp_Object Qxbm;
7293
7294/* Keywords. */
7295
6fc2811b 7296extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
7297extern Lisp_Object QCdata;
7298Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
6fc2811b 7299Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
dfff8a69 7300Lisp_Object QCindex;
6fc2811b
JR
7301
7302/* Other symbols. */
7303
7304Lisp_Object Qlaplace;
7305
7306/* Time in seconds after which images should be removed from the cache
7307 if not displayed. */
7308
7309Lisp_Object Vimage_cache_eviction_delay;
7310
7311/* Function prototypes. */
7312
7313static void define_image_type P_ ((struct image_type *type));
7314static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7315static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7316static void x_laplace P_ ((struct frame *, struct image *));
7317static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7318 Lisp_Object));
7319
dfff8a69 7320
6fc2811b
JR
7321/* Define a new image type from TYPE. This adds a copy of TYPE to
7322 image_types and adds the symbol *TYPE->type to Vimage_types. */
7323
7324static void
7325define_image_type (type)
7326 struct image_type *type;
7327{
7328 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7329 The initialized data segment is read-only. */
7330 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7331 bcopy (type, p, sizeof *p);
7332 p->next = image_types;
7333 image_types = p;
7334 Vimage_types = Fcons (*p->type, Vimage_types);
7335}
7336
7337
7338/* Look up image type SYMBOL, and return a pointer to its image_type
7339 structure. Value is null if SYMBOL is not a known image type. */
7340
7341static INLINE struct image_type *
7342lookup_image_type (symbol)
7343 Lisp_Object symbol;
7344{
7345 struct image_type *type;
7346
7347 for (type = image_types; type; type = type->next)
7348 if (EQ (symbol, *type->type))
7349 break;
7350
7351 return type;
7352}
7353
7354
7355/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7356 valid image specification is a list whose car is the symbol
7357 `image', and whose rest is a property list. The property list must
7358 contain a value for key `:type'. That value must be the name of a
7359 supported image type. The rest of the property list depends on the
7360 image type. */
7361
7362int
7363valid_image_p (object)
7364 Lisp_Object object;
7365{
7366 int valid_p = 0;
7367
7368 if (CONSP (object) && EQ (XCAR (object), Qimage))
7369 {
7370 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7371 struct image_type *type = lookup_image_type (symbol);
7372
7373 if (type)
7374 valid_p = type->valid_p (object);
7375 }
7376
7377 return valid_p;
7378}
7379
7380
7381/* Log error message with format string FORMAT and argument ARG.
7382 Signaling an error, e.g. when an image cannot be loaded, is not a
7383 good idea because this would interrupt redisplay, and the error
7384 message display would lead to another redisplay. This function
7385 therefore simply displays a message. */
7386
7387static void
7388image_error (format, arg1, arg2)
7389 char *format;
7390 Lisp_Object arg1, arg2;
7391{
7392 add_to_log (format, arg1, arg2);
7393}
7394
7395
7396\f
7397/***********************************************************************
7398 Image specifications
7399 ***********************************************************************/
7400
7401enum image_value_type
7402{
7403 IMAGE_DONT_CHECK_VALUE_TYPE,
7404 IMAGE_STRING_VALUE,
7405 IMAGE_SYMBOL_VALUE,
7406 IMAGE_POSITIVE_INTEGER_VALUE,
7407 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 7408 IMAGE_ASCENT_VALUE,
6fc2811b
JR
7409 IMAGE_INTEGER_VALUE,
7410 IMAGE_FUNCTION_VALUE,
7411 IMAGE_NUMBER_VALUE,
7412 IMAGE_BOOL_VALUE
7413};
7414
7415/* Structure used when parsing image specifications. */
7416
7417struct image_keyword
7418{
7419 /* Name of keyword. */
7420 char *name;
7421
7422 /* The type of value allowed. */
7423 enum image_value_type type;
7424
7425 /* Non-zero means key must be present. */
7426 int mandatory_p;
7427
7428 /* Used to recognize duplicate keywords in a property list. */
7429 int count;
7430
7431 /* The value that was found. */
7432 Lisp_Object value;
7433};
7434
7435
7436static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7437 int, Lisp_Object));
7438static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7439
7440
7441/* Parse image spec SPEC according to KEYWORDS. A valid image spec
7442 has the format (image KEYWORD VALUE ...). One of the keyword/
7443 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7444 image_keywords structures of size NKEYWORDS describing other
7445 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7446
7447static int
7448parse_image_spec (spec, keywords, nkeywords, type)
7449 Lisp_Object spec;
7450 struct image_keyword *keywords;
7451 int nkeywords;
7452 Lisp_Object type;
7453{
7454 int i;
7455 Lisp_Object plist;
7456
7457 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7458 return 0;
7459
7460 plist = XCDR (spec);
7461 while (CONSP (plist))
7462 {
7463 Lisp_Object key, value;
7464
7465 /* First element of a pair must be a symbol. */
7466 key = XCAR (plist);
7467 plist = XCDR (plist);
7468 if (!SYMBOLP (key))
7469 return 0;
7470
7471 /* There must follow a value. */
7472 if (!CONSP (plist))
7473 return 0;
7474 value = XCAR (plist);
7475 plist = XCDR (plist);
7476
7477 /* Find key in KEYWORDS. Error if not found. */
7478 for (i = 0; i < nkeywords; ++i)
7479 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7480 break;
7481
7482 if (i == nkeywords)
7483 continue;
7484
7485 /* Record that we recognized the keyword. If a keywords
7486 was found more than once, it's an error. */
7487 keywords[i].value = value;
7488 ++keywords[i].count;
7489
7490 if (keywords[i].count > 1)
7491 return 0;
7492
7493 /* Check type of value against allowed type. */
7494 switch (keywords[i].type)
7495 {
7496 case IMAGE_STRING_VALUE:
7497 if (!STRINGP (value))
7498 return 0;
7499 break;
7500
7501 case IMAGE_SYMBOL_VALUE:
7502 if (!SYMBOLP (value))
7503 return 0;
7504 break;
7505
7506 case IMAGE_POSITIVE_INTEGER_VALUE:
7507 if (!INTEGERP (value) || XINT (value) <= 0)
7508 return 0;
7509 break;
7510
dfff8a69
JR
7511 case IMAGE_ASCENT_VALUE:
7512 if (SYMBOLP (value) && EQ (value, Qcenter))
7513 break;
7514 else if (INTEGERP (value)
7515 && XINT (value) >= 0
7516 && XINT (value) <= 100)
7517 break;
7518 return 0;
7519
6fc2811b
JR
7520 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7521 if (!INTEGERP (value) || XINT (value) < 0)
7522 return 0;
7523 break;
7524
7525 case IMAGE_DONT_CHECK_VALUE_TYPE:
7526 break;
7527
7528 case IMAGE_FUNCTION_VALUE:
7529 value = indirect_function (value);
7530 if (SUBRP (value)
7531 || COMPILEDP (value)
7532 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7533 break;
7534 return 0;
7535
7536 case IMAGE_NUMBER_VALUE:
7537 if (!INTEGERP (value) && !FLOATP (value))
7538 return 0;
7539 break;
7540
7541 case IMAGE_INTEGER_VALUE:
7542 if (!INTEGERP (value))
7543 return 0;
7544 break;
7545
7546 case IMAGE_BOOL_VALUE:
7547 if (!NILP (value) && !EQ (value, Qt))
7548 return 0;
7549 break;
7550
7551 default:
7552 abort ();
7553 break;
7554 }
7555
7556 if (EQ (key, QCtype) && !EQ (type, value))
7557 return 0;
7558 }
7559
7560 /* Check that all mandatory fields are present. */
7561 for (i = 0; i < nkeywords; ++i)
7562 if (keywords[i].mandatory_p && keywords[i].count == 0)
7563 return 0;
7564
7565 return NILP (plist);
7566}
7567
7568
7569/* Return the value of KEY in image specification SPEC. Value is nil
7570 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7571 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7572
7573static Lisp_Object
7574image_spec_value (spec, key, found)
7575 Lisp_Object spec, key;
7576 int *found;
7577{
7578 Lisp_Object tail;
7579
7580 xassert (valid_image_p (spec));
7581
7582 for (tail = XCDR (spec);
7583 CONSP (tail) && CONSP (XCDR (tail));
7584 tail = XCDR (XCDR (tail)))
7585 {
7586 if (EQ (XCAR (tail), key))
7587 {
7588 if (found)
7589 *found = 1;
7590 return XCAR (XCDR (tail));
7591 }
7592 }
7593
7594 if (found)
7595 *found = 0;
7596 return Qnil;
7597}
7598
7599
7600
7601\f
7602/***********************************************************************
7603 Image type independent image structures
7604 ***********************************************************************/
7605
7606static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7607static void free_image P_ ((struct frame *f, struct image *img));
7608
7609
7610/* Allocate and return a new image structure for image specification
7611 SPEC. SPEC has a hash value of HASH. */
7612
7613static struct image *
7614make_image (spec, hash)
7615 Lisp_Object spec;
7616 unsigned hash;
7617{
7618 struct image *img = (struct image *) xmalloc (sizeof *img);
7619
7620 xassert (valid_image_p (spec));
7621 bzero (img, sizeof *img);
7622 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7623 xassert (img->type != NULL);
7624 img->spec = spec;
7625 img->data.lisp_val = Qnil;
7626 img->ascent = DEFAULT_IMAGE_ASCENT;
7627 img->hash = hash;
7628 return img;
7629}
7630
7631
7632/* Free image IMG which was used on frame F, including its resources. */
7633
7634static void
7635free_image (f, img)
7636 struct frame *f;
7637 struct image *img;
7638{
7639 if (img)
7640 {
7641 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7642
7643 /* Remove IMG from the hash table of its cache. */
7644 if (img->prev)
7645 img->prev->next = img->next;
7646 else
7647 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7648
7649 if (img->next)
7650 img->next->prev = img->prev;
7651
7652 c->images[img->id] = NULL;
7653
7654 /* Free resources, then free IMG. */
7655 img->type->free (f, img);
7656 xfree (img);
7657 }
7658}
7659
7660
7661/* Prepare image IMG for display on frame F. Must be called before
7662 drawing an image. */
7663
7664void
7665prepare_image_for_display (f, img)
7666 struct frame *f;
7667 struct image *img;
7668{
7669 EMACS_TIME t;
7670
7671 /* We're about to display IMG, so set its timestamp to `now'. */
7672 EMACS_GET_TIME (t);
7673 img->timestamp = EMACS_SECS (t);
7674
7675 /* If IMG doesn't have a pixmap yet, load it now, using the image
7676 type dependent loader function. */
7677 if (img->pixmap == 0 && !img->load_failed_p)
7678 img->load_failed_p = img->type->load (f, img) == 0;
7679}
7680
7681
dfff8a69
JR
7682/* Value is the number of pixels for the ascent of image IMG when
7683 drawn in face FACE. */
7684
7685int
7686image_ascent (img, face)
7687 struct image *img;
7688 struct face *face;
7689{
7690 int height = img->height + img->margin;
7691 int ascent;
7692
7693 if (img->ascent == CENTERED_IMAGE_ASCENT)
7694 {
7695 if (face->font)
7696 ascent = height / 2 - (FONT_DESCENT(face->font)
7697 - FONT_BASE(face->font)) / 2;
7698 else
7699 ascent = height / 2;
7700 }
7701 else
7702 ascent = height * img->ascent / 100.0;
7703
7704 return ascent;
7705}
7706
7707
6fc2811b
JR
7708\f
7709/***********************************************************************
7710 Helper functions for X image types
7711 ***********************************************************************/
7712
7713static void x_clear_image P_ ((struct frame *f, struct image *img));
7714static unsigned long x_alloc_image_color P_ ((struct frame *f,
7715 struct image *img,
7716 Lisp_Object color_name,
7717 unsigned long dflt));
7718
7719/* Free X resources of image IMG which is used on frame F. */
7720
7721static void
7722x_clear_image (f, img)
7723 struct frame *f;
7724 struct image *img;
7725{
7726#if 0 /* NTEMACS_TODO: W32 image support */
7727
7728 if (img->pixmap)
7729 {
7730 BLOCK_INPUT;
7731 XFreePixmap (NULL, img->pixmap);
7732 img->pixmap = 0;
7733 UNBLOCK_INPUT;
7734 }
7735
7736 if (img->ncolors)
7737 {
7738 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7739
7740 /* If display has an immutable color map, freeing colors is not
7741 necessary and some servers don't allow it. So don't do it. */
7742 if (class != StaticColor
7743 && class != StaticGray
7744 && class != TrueColor)
7745 {
7746 Colormap cmap;
7747 BLOCK_INPUT;
7748 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
7749 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
7750 img->ncolors, 0);
7751 UNBLOCK_INPUT;
7752 }
7753
7754 xfree (img->colors);
7755 img->colors = NULL;
7756 img->ncolors = 0;
7757 }
7758#endif
7759}
7760
7761
7762/* Allocate color COLOR_NAME for image IMG on frame F. If color
7763 cannot be allocated, use DFLT. Add a newly allocated color to
7764 IMG->colors, so that it can be freed again. Value is the pixel
7765 color. */
7766
7767static unsigned long
7768x_alloc_image_color (f, img, color_name, dflt)
7769 struct frame *f;
7770 struct image *img;
7771 Lisp_Object color_name;
7772 unsigned long dflt;
7773{
7774#if 0 /* NTEMACS_TODO: allocing colors. */
7775 XColor color;
7776 unsigned long result;
7777
7778 xassert (STRINGP (color_name));
7779
7780 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
7781 {
7782 /* This isn't called frequently so we get away with simply
7783 reallocating the color vector to the needed size, here. */
7784 ++img->ncolors;
7785 img->colors =
7786 (unsigned long *) xrealloc (img->colors,
7787 img->ncolors * sizeof *img->colors);
7788 img->colors[img->ncolors - 1] = color.pixel;
7789 result = color.pixel;
7790 }
7791 else
7792 result = dflt;
7793 return result;
7794#endif
7795 return 0;
7796}
7797
7798
7799\f
7800/***********************************************************************
7801 Image Cache
7802 ***********************************************************************/
7803
7804static void cache_image P_ ((struct frame *f, struct image *img));
7805
7806
7807/* Return a new, initialized image cache that is allocated from the
7808 heap. Call free_image_cache to free an image cache. */
7809
7810struct image_cache *
7811make_image_cache ()
7812{
7813 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
7814 int size;
7815
7816 bzero (c, sizeof *c);
7817 c->size = 50;
7818 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
7819 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
7820 c->buckets = (struct image **) xmalloc (size);
7821 bzero (c->buckets, size);
7822 return c;
7823}
7824
7825
7826/* Free image cache of frame F. Be aware that X frames share images
7827 caches. */
7828
7829void
7830free_image_cache (f)
7831 struct frame *f;
7832{
7833 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7834 if (c)
7835 {
7836 int i;
7837
7838 /* Cache should not be referenced by any frame when freed. */
7839 xassert (c->refcount == 0);
7840
7841 for (i = 0; i < c->used; ++i)
7842 free_image (f, c->images[i]);
7843 xfree (c->images);
7844 xfree (c);
7845 xfree (c->buckets);
7846 FRAME_X_IMAGE_CACHE (f) = NULL;
7847 }
7848}
7849
7850
7851/* Clear image cache of frame F. FORCE_P non-zero means free all
7852 images. FORCE_P zero means clear only images that haven't been
7853 displayed for some time. Should be called from time to time to
dfff8a69
JR
7854 reduce the number of loaded images. If image-eviction-seconds is
7855 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
7856 at least that many seconds. */
7857
7858void
7859clear_image_cache (f, force_p)
7860 struct frame *f;
7861 int force_p;
7862{
7863 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7864
7865 if (c && INTEGERP (Vimage_cache_eviction_delay))
7866 {
7867 EMACS_TIME t;
7868 unsigned long old;
7869 int i, any_freed_p = 0;
7870
7871 EMACS_GET_TIME (t);
7872 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7873
7874 for (i = 0; i < c->used; ++i)
7875 {
7876 struct image *img = c->images[i];
7877 if (img != NULL
7878 && (force_p
7879 || (img->timestamp > old)))
7880 {
7881 free_image (f, img);
7882 any_freed_p = 1;
7883 }
7884 }
7885
7886 /* We may be clearing the image cache because, for example,
7887 Emacs was iconified for a longer period of time. In that
7888 case, current matrices may still contain references to
7889 images freed above. So, clear these matrices. */
7890 if (any_freed_p)
7891 {
7892 clear_current_matrices (f);
7893 ++windows_or_buffers_changed;
7894 }
7895 }
7896}
7897
7898
7899DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
7900 0, 1, 0,
7901 "Clear the image cache of FRAME.\n\
7902FRAME nil or omitted means use the selected frame.\n\
7903FRAME t means clear the image caches of all frames.")
7904 (frame)
7905 Lisp_Object frame;
7906{
7907 if (EQ (frame, Qt))
7908 {
7909 Lisp_Object tail;
7910
7911 FOR_EACH_FRAME (tail, frame)
7912 if (FRAME_W32_P (XFRAME (frame)))
7913 clear_image_cache (XFRAME (frame), 1);
7914 }
7915 else
7916 clear_image_cache (check_x_frame (frame), 1);
7917
7918 return Qnil;
7919}
7920
7921
7922/* Return the id of image with Lisp specification SPEC on frame F.
7923 SPEC must be a valid Lisp image specification (see valid_image_p). */
7924
7925int
7926lookup_image (f, spec)
7927 struct frame *f;
7928 Lisp_Object spec;
7929{
7930 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7931 struct image *img;
7932 int i;
7933 unsigned hash;
7934 struct gcpro gcpro1;
7935 EMACS_TIME now;
7936
7937 /* F must be a window-system frame, and SPEC must be a valid image
7938 specification. */
7939 xassert (FRAME_WINDOW_P (f));
7940 xassert (valid_image_p (spec));
7941
7942 GCPRO1 (spec);
7943
7944 /* Look up SPEC in the hash table of the image cache. */
7945 hash = sxhash (spec, 0);
7946 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
7947
7948 for (img = c->buckets[i]; img; img = img->next)
7949 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
7950 break;
7951
7952 /* If not found, create a new image and cache it. */
7953 if (img == NULL)
7954 {
7955 img = make_image (spec, hash);
7956 cache_image (f, img);
7957 img->load_failed_p = img->type->load (f, img) == 0;
7958 xassert (!interrupt_input_blocked);
7959
7960 /* If we can't load the image, and we don't have a width and
7961 height, use some arbitrary width and height so that we can
7962 draw a rectangle for it. */
7963 if (img->load_failed_p)
7964 {
7965 Lisp_Object value;
7966
7967 value = image_spec_value (spec, QCwidth, NULL);
7968 img->width = (INTEGERP (value)
7969 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
7970 value = image_spec_value (spec, QCheight, NULL);
7971 img->height = (INTEGERP (value)
7972 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
7973 }
7974 else
7975 {
7976 /* Handle image type independent image attributes
7977 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
7978 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
7979 Lisp_Object file;
7980
7981 ascent = image_spec_value (spec, QCascent, NULL);
7982 if (INTEGERP (ascent))
7983 img->ascent = XFASTINT (ascent);
dfff8a69
JR
7984 else if (EQ (ascent, Qcenter))
7985 img->ascent = CENTERED_IMAGE_ASCENT;
7986
6fc2811b
JR
7987 margin = image_spec_value (spec, QCmargin, NULL);
7988 if (INTEGERP (margin) && XINT (margin) >= 0)
7989 img->margin = XFASTINT (margin);
7990
7991 relief = image_spec_value (spec, QCrelief, NULL);
7992 if (INTEGERP (relief))
7993 {
7994 img->relief = XINT (relief);
7995 img->margin += abs (img->relief);
7996 }
7997
7998 /* Should we apply a Laplace edge-detection algorithm? */
7999 algorithm = image_spec_value (spec, QCalgorithm, NULL);
8000 if (img->pixmap && EQ (algorithm, Qlaplace))
8001 x_laplace (f, img);
8002
8003 /* Should we built a mask heuristically? */
8004 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
8005 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
8006 x_build_heuristic_mask (f, img, heuristic_mask);
8007 }
8008 }
8009
8010 /* We're using IMG, so set its timestamp to `now'. */
8011 EMACS_GET_TIME (now);
8012 img->timestamp = EMACS_SECS (now);
8013
8014 UNGCPRO;
8015
8016 /* Value is the image id. */
8017 return img->id;
8018}
8019
8020
8021/* Cache image IMG in the image cache of frame F. */
8022
8023static void
8024cache_image (f, img)
8025 struct frame *f;
8026 struct image *img;
8027{
8028 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8029 int i;
8030
8031 /* Find a free slot in c->images. */
8032 for (i = 0; i < c->used; ++i)
8033 if (c->images[i] == NULL)
8034 break;
8035
8036 /* If no free slot found, maybe enlarge c->images. */
8037 if (i == c->used && c->used == c->size)
8038 {
8039 c->size *= 2;
8040 c->images = (struct image **) xrealloc (c->images,
8041 c->size * sizeof *c->images);
8042 }
8043
8044 /* Add IMG to c->images, and assign IMG an id. */
8045 c->images[i] = img;
8046 img->id = i;
8047 if (i == c->used)
8048 ++c->used;
8049
8050 /* Add IMG to the cache's hash table. */
8051 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8052 img->next = c->buckets[i];
8053 if (img->next)
8054 img->next->prev = img;
8055 img->prev = NULL;
8056 c->buckets[i] = img;
8057}
8058
8059
8060/* Call FN on every image in the image cache of frame F. Used to mark
8061 Lisp Objects in the image cache. */
8062
8063void
8064forall_images_in_image_cache (f, fn)
8065 struct frame *f;
8066 void (*fn) P_ ((struct image *img));
8067{
8068 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8069 {
8070 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8071 if (c)
8072 {
8073 int i;
8074 for (i = 0; i < c->used; ++i)
8075 if (c->images[i])
8076 fn (c->images[i]);
8077 }
8078 }
8079}
8080
8081
8082\f
8083/***********************************************************************
8084 W32 support code
8085 ***********************************************************************/
8086
8087#if 0 /* NTEMACS_TODO: W32 specific image code. */
8088
8089static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8090 XImage **, Pixmap *));
8091static void x_destroy_x_image P_ ((XImage *));
8092static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8093
8094
8095/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8096 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8097 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8098 via xmalloc. Print error messages via image_error if an error
8099 occurs. Value is non-zero if successful. */
8100
8101static int
8102x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8103 struct frame *f;
8104 int width, height, depth;
8105 XImage **ximg;
8106 Pixmap *pixmap;
8107{
8108#if 0 /* NTEMACS_TODO: Image support for W32 */
8109 Display *display = FRAME_W32_DISPLAY (f);
8110 Screen *screen = FRAME_X_SCREEN (f);
8111 Window window = FRAME_W32_WINDOW (f);
8112
8113 xassert (interrupt_input_blocked);
8114
8115 if (depth <= 0)
8116 depth = DefaultDepthOfScreen (screen);
8117 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8118 depth, ZPixmap, 0, NULL, width, height,
8119 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8120 if (*ximg == NULL)
8121 {
8122 image_error ("Unable to allocate X image", Qnil, Qnil);
8123 return 0;
8124 }
8125
8126 /* Allocate image raster. */
8127 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8128
8129 /* Allocate a pixmap of the same size. */
8130 *pixmap = XCreatePixmap (display, window, width, height, depth);
8131 if (*pixmap == 0)
8132 {
8133 x_destroy_x_image (*ximg);
8134 *ximg = NULL;
8135 image_error ("Unable to create X pixmap", Qnil, Qnil);
8136 return 0;
8137 }
8138#endif
8139 return 1;
8140}
8141
8142
8143/* Destroy XImage XIMG. Free XIMG->data. */
8144
8145static void
8146x_destroy_x_image (ximg)
8147 XImage *ximg;
8148{
8149 xassert (interrupt_input_blocked);
8150 if (ximg)
8151 {
8152 xfree (ximg->data);
8153 ximg->data = NULL;
8154 XDestroyImage (ximg);
8155 }
8156}
8157
8158
8159/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8160 are width and height of both the image and pixmap. */
8161
8162static void
8163x_put_x_image (f, ximg, pixmap, width, height)
8164 struct frame *f;
8165 XImage *ximg;
8166 Pixmap pixmap;
8167{
8168 GC gc;
8169
8170 xassert (interrupt_input_blocked);
8171 gc = XCreateGC (NULL, pixmap, 0, NULL);
8172 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8173 XFreeGC (NULL, gc);
8174}
8175
8176#endif
8177
8178\f
8179/***********************************************************************
8180 Searching files
8181 ***********************************************************************/
8182
8183static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8184
8185/* Find image file FILE. Look in data-directory, then
8186 x-bitmap-file-path. Value is the full name of the file found, or
8187 nil if not found. */
8188
8189static Lisp_Object
8190x_find_image_file (file)
8191 Lisp_Object file;
8192{
8193 Lisp_Object file_found, search_path;
8194 struct gcpro gcpro1, gcpro2;
8195 int fd;
8196
8197 file_found = Qnil;
8198 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8199 GCPRO2 (file_found, search_path);
8200
8201 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8202 fd = openp (search_path, file, "", &file_found, 0);
8203
8204 if (fd < 0)
8205 file_found = Qnil;
8206 else
8207 close (fd);
8208
8209 UNGCPRO;
8210 return file_found;
8211}
8212
8213
8214\f
8215/***********************************************************************
8216 XBM images
8217 ***********************************************************************/
8218
8219static int xbm_load P_ ((struct frame *f, struct image *img));
8220static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8221 Lisp_Object file));
8222static int xbm_image_p P_ ((Lisp_Object object));
8223static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8224 unsigned char **));
8225
8226
8227/* Indices of image specification fields in xbm_format, below. */
8228
8229enum xbm_keyword_index
8230{
8231 XBM_TYPE,
8232 XBM_FILE,
8233 XBM_WIDTH,
8234 XBM_HEIGHT,
8235 XBM_DATA,
8236 XBM_FOREGROUND,
8237 XBM_BACKGROUND,
8238 XBM_ASCENT,
8239 XBM_MARGIN,
8240 XBM_RELIEF,
8241 XBM_ALGORITHM,
8242 XBM_HEURISTIC_MASK,
8243 XBM_LAST
8244};
8245
8246/* Vector of image_keyword structures describing the format
8247 of valid XBM image specifications. */
8248
8249static struct image_keyword xbm_format[XBM_LAST] =
8250{
8251 {":type", IMAGE_SYMBOL_VALUE, 1},
8252 {":file", IMAGE_STRING_VALUE, 0},
8253 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8254 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8255 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8256 {":foreground", IMAGE_STRING_VALUE, 0},
8257 {":background", IMAGE_STRING_VALUE, 0},
8258 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8259 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8260 {":relief", IMAGE_INTEGER_VALUE, 0},
8261 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8262 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8263};
8264
8265/* Structure describing the image type XBM. */
8266
8267static struct image_type xbm_type =
8268{
8269 &Qxbm,
8270 xbm_image_p,
8271 xbm_load,
8272 x_clear_image,
8273 NULL
8274};
8275
8276/* Tokens returned from xbm_scan. */
8277
8278enum xbm_token
8279{
8280 XBM_TK_IDENT = 256,
8281 XBM_TK_NUMBER
8282};
8283
8284
8285/* Return non-zero if OBJECT is a valid XBM-type image specification.
8286 A valid specification is a list starting with the symbol `image'
8287 The rest of the list is a property list which must contain an
8288 entry `:type xbm..
8289
8290 If the specification specifies a file to load, it must contain
8291 an entry `:file FILENAME' where FILENAME is a string.
8292
8293 If the specification is for a bitmap loaded from memory it must
8294 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8295 WIDTH and HEIGHT are integers > 0. DATA may be:
8296
8297 1. a string large enough to hold the bitmap data, i.e. it must
8298 have a size >= (WIDTH + 7) / 8 * HEIGHT
8299
8300 2. a bool-vector of size >= WIDTH * HEIGHT
8301
8302 3. a vector of strings or bool-vectors, one for each line of the
8303 bitmap.
8304
8305 Both the file and data forms may contain the additional entries
8306 `:background COLOR' and `:foreground COLOR'. If not present,
8307 foreground and background of the frame on which the image is
8308 displayed, is used. */
8309
8310static int
8311xbm_image_p (object)
8312 Lisp_Object object;
8313{
8314 struct image_keyword kw[XBM_LAST];
8315
8316 bcopy (xbm_format, kw, sizeof kw);
8317 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8318 return 0;
8319
8320 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8321
8322 if (kw[XBM_FILE].count)
8323 {
8324 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8325 return 0;
8326 }
8327 else
8328 {
8329 Lisp_Object data;
8330 int width, height;
8331
8332 /* Entries for `:width', `:height' and `:data' must be present. */
8333 if (!kw[XBM_WIDTH].count
8334 || !kw[XBM_HEIGHT].count
8335 || !kw[XBM_DATA].count)
8336 return 0;
8337
8338 data = kw[XBM_DATA].value;
8339 width = XFASTINT (kw[XBM_WIDTH].value);
8340 height = XFASTINT (kw[XBM_HEIGHT].value);
8341
8342 /* Check type of data, and width and height against contents of
8343 data. */
8344 if (VECTORP (data))
8345 {
8346 int i;
8347
8348 /* Number of elements of the vector must be >= height. */
8349 if (XVECTOR (data)->size < height)
8350 return 0;
8351
8352 /* Each string or bool-vector in data must be large enough
8353 for one line of the image. */
8354 for (i = 0; i < height; ++i)
8355 {
8356 Lisp_Object elt = XVECTOR (data)->contents[i];
8357
8358 if (STRINGP (elt))
8359 {
8360 if (XSTRING (elt)->size
8361 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8362 return 0;
8363 }
8364 else if (BOOL_VECTOR_P (elt))
8365 {
8366 if (XBOOL_VECTOR (elt)->size < width)
8367 return 0;
8368 }
8369 else
8370 return 0;
8371 }
8372 }
8373 else if (STRINGP (data))
8374 {
8375 if (XSTRING (data)->size
8376 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8377 return 0;
8378 }
8379 else if (BOOL_VECTOR_P (data))
8380 {
8381 if (XBOOL_VECTOR (data)->size < width * height)
8382 return 0;
8383 }
8384 else
8385 return 0;
8386 }
8387
8388 /* Baseline must be a value between 0 and 100 (a percentage). */
8389 if (kw[XBM_ASCENT].count
8390 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8391 return 0;
8392
8393 return 1;
8394}
8395
8396
8397/* Scan a bitmap file. FP is the stream to read from. Value is
8398 either an enumerator from enum xbm_token, or a character for a
8399 single-character token, or 0 at end of file. If scanning an
8400 identifier, store the lexeme of the identifier in SVAL. If
8401 scanning a number, store its value in *IVAL. */
8402
8403static int
8404xbm_scan (fp, sval, ival)
8405 FILE *fp;
8406 char *sval;
8407 int *ival;
8408{
8409 int c;
8410
8411 /* Skip white space. */
8412 while ((c = fgetc (fp)) != EOF && isspace (c))
8413 ;
8414
8415 if (c == EOF)
8416 c = 0;
8417 else if (isdigit (c))
8418 {
8419 int value = 0, digit;
8420
8421 if (c == '0')
8422 {
8423 c = fgetc (fp);
8424 if (c == 'x' || c == 'X')
8425 {
8426 while ((c = fgetc (fp)) != EOF)
8427 {
8428 if (isdigit (c))
8429 digit = c - '0';
8430 else if (c >= 'a' && c <= 'f')
8431 digit = c - 'a' + 10;
8432 else if (c >= 'A' && c <= 'F')
8433 digit = c - 'A' + 10;
8434 else
8435 break;
8436 value = 16 * value + digit;
8437 }
8438 }
8439 else if (isdigit (c))
8440 {
8441 value = c - '0';
8442 while ((c = fgetc (fp)) != EOF
8443 && isdigit (c))
8444 value = 8 * value + c - '0';
8445 }
8446 }
8447 else
8448 {
8449 value = c - '0';
8450 while ((c = fgetc (fp)) != EOF
8451 && isdigit (c))
8452 value = 10 * value + c - '0';
8453 }
8454
8455 if (c != EOF)
8456 ungetc (c, fp);
8457 *ival = value;
8458 c = XBM_TK_NUMBER;
8459 }
8460 else if (isalpha (c) || c == '_')
8461 {
8462 *sval++ = c;
8463 while ((c = fgetc (fp)) != EOF
8464 && (isalnum (c) || c == '_'))
8465 *sval++ = c;
8466 *sval = 0;
8467 if (c != EOF)
8468 ungetc (c, fp);
8469 c = XBM_TK_IDENT;
8470 }
8471
8472 return c;
8473}
8474
8475
8476/* Replacement for XReadBitmapFileData which isn't available under old
8477 X versions. FILE is the name of the bitmap file to read. Set
8478 *WIDTH and *HEIGHT to the width and height of the image. Return in
8479 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8480 successful. */
8481
8482static int
8483xbm_read_bitmap_file_data (file, width, height, data)
8484 char *file;
8485 int *width, *height;
8486 unsigned char **data;
8487{
8488 FILE *fp;
8489 char buffer[BUFSIZ];
8490 int padding_p = 0;
8491 int v10 = 0;
8492 int bytes_per_line, i, nbytes;
8493 unsigned char *p;
8494 int value;
8495 int LA1;
8496
8497#define match() \
8498 LA1 = xbm_scan (fp, buffer, &value)
8499
8500#define expect(TOKEN) \
8501 if (LA1 != (TOKEN)) \
8502 goto failure; \
8503 else \
8504 match ()
8505
8506#define expect_ident(IDENT) \
8507 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8508 match (); \
8509 else \
8510 goto failure
8511
8512 fp = fopen (file, "r");
8513 if (fp == NULL)
8514 return 0;
8515
8516 *width = *height = -1;
8517 *data = NULL;
8518 LA1 = xbm_scan (fp, buffer, &value);
8519
8520 /* Parse defines for width, height and hot-spots. */
8521 while (LA1 == '#')
8522 {
8523 match ();
8524 expect_ident ("define");
8525 expect (XBM_TK_IDENT);
8526
8527 if (LA1 == XBM_TK_NUMBER);
8528 {
8529 char *p = strrchr (buffer, '_');
8530 p = p ? p + 1 : buffer;
8531 if (strcmp (p, "width") == 0)
8532 *width = value;
8533 else if (strcmp (p, "height") == 0)
8534 *height = value;
8535 }
8536 expect (XBM_TK_NUMBER);
8537 }
8538
8539 if (*width < 0 || *height < 0)
8540 goto failure;
8541
8542 /* Parse bits. Must start with `static'. */
8543 expect_ident ("static");
8544 if (LA1 == XBM_TK_IDENT)
8545 {
8546 if (strcmp (buffer, "unsigned") == 0)
8547 {
8548 match ();
8549 expect_ident ("char");
8550 }
8551 else if (strcmp (buffer, "short") == 0)
8552 {
8553 match ();
8554 v10 = 1;
8555 if (*width % 16 && *width % 16 < 9)
8556 padding_p = 1;
8557 }
8558 else if (strcmp (buffer, "char") == 0)
8559 match ();
8560 else
8561 goto failure;
8562 }
8563 else
8564 goto failure;
8565
8566 expect (XBM_TK_IDENT);
8567 expect ('[');
8568 expect (']');
8569 expect ('=');
8570 expect ('{');
8571
8572 bytes_per_line = (*width + 7) / 8 + padding_p;
8573 nbytes = bytes_per_line * *height;
8574 p = *data = (char *) xmalloc (nbytes);
8575
8576 if (v10)
8577 {
8578
8579 for (i = 0; i < nbytes; i += 2)
8580 {
8581 int val = value;
8582 expect (XBM_TK_NUMBER);
8583
8584 *p++ = val;
8585 if (!padding_p || ((i + 2) % bytes_per_line))
8586 *p++ = value >> 8;
8587
8588 if (LA1 == ',' || LA1 == '}')
8589 match ();
8590 else
8591 goto failure;
8592 }
8593 }
8594 else
8595 {
8596 for (i = 0; i < nbytes; ++i)
8597 {
8598 int val = value;
8599 expect (XBM_TK_NUMBER);
8600
8601 *p++ = val;
8602
8603 if (LA1 == ',' || LA1 == '}')
8604 match ();
8605 else
8606 goto failure;
8607 }
8608 }
8609
8610 fclose (fp);
8611 return 1;
8612
8613 failure:
8614
8615 fclose (fp);
8616 if (*data)
8617 {
8618 xfree (*data);
8619 *data = NULL;
8620 }
8621 return 0;
8622
8623#undef match
8624#undef expect
8625#undef expect_ident
8626}
8627
8628
8629/* Load XBM image IMG which will be displayed on frame F from file
8630 SPECIFIED_FILE. Value is non-zero if successful. */
8631
8632static int
8633xbm_load_image_from_file (f, img, specified_file)
8634 struct frame *f;
8635 struct image *img;
8636 Lisp_Object specified_file;
8637{
8638 int rc;
8639 unsigned char *data;
8640 int success_p = 0;
8641 Lisp_Object file;
8642 struct gcpro gcpro1;
8643
8644 xassert (STRINGP (specified_file));
8645 file = Qnil;
8646 GCPRO1 (file);
8647
8648 file = x_find_image_file (specified_file);
8649 if (!STRINGP (file))
8650 {
8651 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8652 UNGCPRO;
8653 return 0;
8654 }
8655
8656 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
8657 &img->height, &data);
8658 if (rc)
8659 {
8660 int depth = one_w32_display_info.n_cbits;
8661 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8662 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8663 Lisp_Object value;
8664
8665 xassert (img->width > 0 && img->height > 0);
8666
8667 /* Get foreground and background colors, maybe allocate colors. */
8668 value = image_spec_value (img->spec, QCforeground, NULL);
8669 if (!NILP (value))
8670 foreground = x_alloc_image_color (f, img, value, foreground);
8671
8672 value = image_spec_value (img->spec, QCbackground, NULL);
8673 if (!NILP (value))
8674 background = x_alloc_image_color (f, img, value, background);
8675
8676#if 0 /* NTEMACS_TODO : Port image display to W32 */
8677 BLOCK_INPUT;
8678 img->pixmap
8679 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8680 FRAME_W32_WINDOW (f),
8681 data,
8682 img->width, img->height,
8683 foreground, background,
8684 depth);
8685 xfree (data);
8686
8687 if (img->pixmap == 0)
8688 {
8689 x_clear_image (f, img);
8690 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
8691 }
8692 else
8693 success_p = 1;
8694
8695 UNBLOCK_INPUT;
8696#endif
8697 }
8698 else
8699 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8700
8701 UNGCPRO;
8702 return success_p;
8703}
8704
8705
8706/* Fill image IMG which is used on frame F with pixmap data. Value is
8707 non-zero if successful. */
8708
8709static int
8710xbm_load (f, img)
8711 struct frame *f;
8712 struct image *img;
8713{
8714 int success_p = 0;
8715 Lisp_Object file_name;
8716
8717 xassert (xbm_image_p (img->spec));
8718
8719 /* If IMG->spec specifies a file name, create a non-file spec from it. */
8720 file_name = image_spec_value (img->spec, QCfile, NULL);
8721 if (STRINGP (file_name))
8722 success_p = xbm_load_image_from_file (f, img, file_name);
8723 else
8724 {
8725 struct image_keyword fmt[XBM_LAST];
8726 Lisp_Object data;
8727 int depth;
8728 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8729 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8730 char *bits;
8731 int parsed_p;
8732
8733 /* Parse the list specification. */
8734 bcopy (xbm_format, fmt, sizeof fmt);
8735 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
8736 xassert (parsed_p);
8737
8738 /* Get specified width, and height. */
8739 img->width = XFASTINT (fmt[XBM_WIDTH].value);
8740 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
8741 xassert (img->width > 0 && img->height > 0);
8742
8743 BLOCK_INPUT;
8744
8745 if (fmt[XBM_ASCENT].count)
8746 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
8747
8748 /* Get foreground and background colors, maybe allocate colors. */
8749 if (fmt[XBM_FOREGROUND].count)
8750 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
8751 foreground);
8752 if (fmt[XBM_BACKGROUND].count)
8753 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
8754 background);
8755
8756 /* Set bits to the bitmap image data. */
8757 data = fmt[XBM_DATA].value;
8758 if (VECTORP (data))
8759 {
8760 int i;
8761 char *p;
8762 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
8763
8764 p = bits = (char *) alloca (nbytes * img->height);
8765 for (i = 0; i < img->height; ++i, p += nbytes)
8766 {
8767 Lisp_Object line = XVECTOR (data)->contents[i];
8768 if (STRINGP (line))
8769 bcopy (XSTRING (line)->data, p, nbytes);
8770 else
8771 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
8772 }
8773 }
8774 else if (STRINGP (data))
8775 bits = XSTRING (data)->data;
8776 else
8777 bits = XBOOL_VECTOR (data)->data;
8778
8779#if 0 /* NTEMACS_TODO : W32 XPM code */
8780 /* Create the pixmap. */
8781 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
8782 img->pixmap
8783 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8784 FRAME_W32_WINDOW (f),
8785 bits,
8786 img->width, img->height,
8787 foreground, background,
8788 depth);
8789#endif /* NTEMACS_TODO */
8790
8791 if (img->pixmap)
8792 success_p = 1;
8793 else
8794 {
8795 image_error ("Unable to create pixmap for XBM image `%s'",
8796 img->spec, Qnil);
8797 x_clear_image (f, img);
8798 }
8799
8800 UNBLOCK_INPUT;
8801 }
8802
8803 return success_p;
8804}
8805
8806
8807\f
8808/***********************************************************************
8809 XPM images
8810 ***********************************************************************/
8811
8812#if HAVE_XPM
8813
8814static int xpm_image_p P_ ((Lisp_Object object));
8815static int xpm_load P_ ((struct frame *f, struct image *img));
8816static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
8817
8818#include "X11/xpm.h"
8819
8820/* The symbol `xpm' identifying XPM-format images. */
8821
8822Lisp_Object Qxpm;
8823
8824/* Indices of image specification fields in xpm_format, below. */
8825
8826enum xpm_keyword_index
8827{
8828 XPM_TYPE,
8829 XPM_FILE,
8830 XPM_DATA,
8831 XPM_ASCENT,
8832 XPM_MARGIN,
8833 XPM_RELIEF,
8834 XPM_ALGORITHM,
8835 XPM_HEURISTIC_MASK,
8836 XPM_COLOR_SYMBOLS,
8837 XPM_LAST
8838};
8839
8840/* Vector of image_keyword structures describing the format
8841 of valid XPM image specifications. */
8842
8843static struct image_keyword xpm_format[XPM_LAST] =
8844{
8845 {":type", IMAGE_SYMBOL_VALUE, 1},
8846 {":file", IMAGE_STRING_VALUE, 0},
8847 {":data", IMAGE_STRING_VALUE, 0},
8848 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8849 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8850 {":relief", IMAGE_INTEGER_VALUE, 0},
8851 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8852 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8853 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8854};
8855
8856/* Structure describing the image type XBM. */
8857
8858static struct image_type xpm_type =
8859{
8860 &Qxpm,
8861 xpm_image_p,
8862 xpm_load,
8863 x_clear_image,
8864 NULL
8865};
8866
8867
8868/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
8869 for XPM images. Such a list must consist of conses whose car and
8870 cdr are strings. */
8871
8872static int
8873xpm_valid_color_symbols_p (color_symbols)
8874 Lisp_Object color_symbols;
8875{
8876 while (CONSP (color_symbols))
8877 {
8878 Lisp_Object sym = XCAR (color_symbols);
8879 if (!CONSP (sym)
8880 || !STRINGP (XCAR (sym))
8881 || !STRINGP (XCDR (sym)))
8882 break;
8883 color_symbols = XCDR (color_symbols);
8884 }
8885
8886 return NILP (color_symbols);
8887}
8888
8889
8890/* Value is non-zero if OBJECT is a valid XPM image specification. */
8891
8892static int
8893xpm_image_p (object)
8894 Lisp_Object object;
8895{
8896 struct image_keyword fmt[XPM_LAST];
8897 bcopy (xpm_format, fmt, sizeof fmt);
8898 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
8899 /* Either `:file' or `:data' must be present. */
8900 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
8901 /* Either no `:color-symbols' or it's a list of conses
8902 whose car and cdr are strings. */
8903 && (fmt[XPM_COLOR_SYMBOLS].count == 0
8904 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
8905 && (fmt[XPM_ASCENT].count == 0
8906 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
8907}
8908
8909
8910/* Load image IMG which will be displayed on frame F. Value is
8911 non-zero if successful. */
8912
8913static int
8914xpm_load (f, img)
8915 struct frame *f;
8916 struct image *img;
8917{
8918 int rc, i;
8919 XpmAttributes attrs;
8920 Lisp_Object specified_file, color_symbols;
8921
8922 /* Configure the XPM lib. Use the visual of frame F. Allocate
8923 close colors. Return colors allocated. */
8924 bzero (&attrs, sizeof attrs);
dfff8a69
JR
8925 attrs.visual = FRAME_X_VISUAL (f);
8926 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 8927 attrs.valuemask |= XpmVisual;
dfff8a69 8928 attrs.valuemask |= XpmColormap;
6fc2811b 8929 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 8930#ifdef XpmAllocCloseColors
6fc2811b
JR
8931 attrs.alloc_close_colors = 1;
8932 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
8933#else
8934 attrs.closeness = 600;
8935 attrs.valuemask |= XpmCloseness;
8936#endif
6fc2811b
JR
8937
8938 /* If image specification contains symbolic color definitions, add
8939 these to `attrs'. */
8940 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
8941 if (CONSP (color_symbols))
8942 {
8943 Lisp_Object tail;
8944 XpmColorSymbol *xpm_syms;
8945 int i, size;
8946
8947 attrs.valuemask |= XpmColorSymbols;
8948
8949 /* Count number of symbols. */
8950 attrs.numsymbols = 0;
8951 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
8952 ++attrs.numsymbols;
8953
8954 /* Allocate an XpmColorSymbol array. */
8955 size = attrs.numsymbols * sizeof *xpm_syms;
8956 xpm_syms = (XpmColorSymbol *) alloca (size);
8957 bzero (xpm_syms, size);
8958 attrs.colorsymbols = xpm_syms;
8959
8960 /* Fill the color symbol array. */
8961 for (tail = color_symbols, i = 0;
8962 CONSP (tail);
8963 ++i, tail = XCDR (tail))
8964 {
8965 Lisp_Object name = XCAR (XCAR (tail));
8966 Lisp_Object color = XCDR (XCAR (tail));
8967 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
8968 strcpy (xpm_syms[i].name, XSTRING (name)->data);
8969 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
8970 strcpy (xpm_syms[i].value, XSTRING (color)->data);
8971 }
8972 }
8973
8974 /* Create a pixmap for the image, either from a file, or from a
8975 string buffer containing data in the same format as an XPM file. */
8976 BLOCK_INPUT;
8977 specified_file = image_spec_value (img->spec, QCfile, NULL);
8978 if (STRINGP (specified_file))
8979 {
8980 Lisp_Object file = x_find_image_file (specified_file);
8981 if (!STRINGP (file))
8982 {
8983 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8984 UNBLOCK_INPUT;
8985 return 0;
8986 }
8987
8988 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
8989 XSTRING (file)->data, &img->pixmap, &img->mask,
8990 &attrs);
8991 }
8992 else
8993 {
8994 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
8995 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
8996 XSTRING (buffer)->data,
8997 &img->pixmap, &img->mask,
8998 &attrs);
8999 }
9000 UNBLOCK_INPUT;
9001
9002 if (rc == XpmSuccess)
9003 {
9004 /* Remember allocated colors. */
9005 img->ncolors = attrs.nalloc_pixels;
9006 img->colors = (unsigned long *) xmalloc (img->ncolors
9007 * sizeof *img->colors);
9008 for (i = 0; i < attrs.nalloc_pixels; ++i)
9009 img->colors[i] = attrs.alloc_pixels[i];
9010
9011 img->width = attrs.width;
9012 img->height = attrs.height;
9013 xassert (img->width > 0 && img->height > 0);
9014
9015 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9016 BLOCK_INPUT;
9017 XpmFreeAttributes (&attrs);
9018 UNBLOCK_INPUT;
9019 }
9020 else
9021 {
9022 switch (rc)
9023 {
9024 case XpmOpenFailed:
9025 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9026 break;
9027
9028 case XpmFileInvalid:
9029 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9030 break;
9031
9032 case XpmNoMemory:
9033 image_error ("Out of memory (%s)", img->spec, Qnil);
9034 break;
9035
9036 case XpmColorFailed:
9037 image_error ("Color allocation error (%s)", img->spec, Qnil);
9038 break;
9039
9040 default:
9041 image_error ("Unknown error (%s)", img->spec, Qnil);
9042 break;
9043 }
9044 }
9045
9046 return rc == XpmSuccess;
9047}
9048
9049#endif /* HAVE_XPM != 0 */
9050
9051\f
9052#if 0 /* NTEMACS_TODO : Color tables on W32. */
9053/***********************************************************************
9054 Color table
9055 ***********************************************************************/
9056
9057/* An entry in the color table mapping an RGB color to a pixel color. */
9058
9059struct ct_color
9060{
9061 int r, g, b;
9062 unsigned long pixel;
9063
9064 /* Next in color table collision list. */
9065 struct ct_color *next;
9066};
9067
9068/* The bucket vector size to use. Must be prime. */
9069
9070#define CT_SIZE 101
9071
9072/* Value is a hash of the RGB color given by R, G, and B. */
9073
9074#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9075
9076/* The color hash table. */
9077
9078struct ct_color **ct_table;
9079
9080/* Number of entries in the color table. */
9081
9082int ct_colors_allocated;
9083
9084/* Function prototypes. */
9085
9086static void init_color_table P_ ((void));
9087static void free_color_table P_ ((void));
9088static unsigned long *colors_in_color_table P_ ((int *n));
9089static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9090static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9091
9092
9093/* Initialize the color table. */
9094
9095static void
9096init_color_table ()
9097{
9098 int size = CT_SIZE * sizeof (*ct_table);
9099 ct_table = (struct ct_color **) xmalloc (size);
9100 bzero (ct_table, size);
9101 ct_colors_allocated = 0;
9102}
9103
9104
9105/* Free memory associated with the color table. */
9106
9107static void
9108free_color_table ()
9109{
9110 int i;
9111 struct ct_color *p, *next;
9112
9113 for (i = 0; i < CT_SIZE; ++i)
9114 for (p = ct_table[i]; p; p = next)
9115 {
9116 next = p->next;
9117 xfree (p);
9118 }
9119
9120 xfree (ct_table);
9121 ct_table = NULL;
9122}
9123
9124
9125/* Value is a pixel color for RGB color R, G, B on frame F. If an
9126 entry for that color already is in the color table, return the
9127 pixel color of that entry. Otherwise, allocate a new color for R,
9128 G, B, and make an entry in the color table. */
9129
9130static unsigned long
9131lookup_rgb_color (f, r, g, b)
9132 struct frame *f;
9133 int r, g, b;
9134{
9135 unsigned hash = CT_HASH_RGB (r, g, b);
9136 int i = hash % CT_SIZE;
9137 struct ct_color *p;
9138
9139 for (p = ct_table[i]; p; p = p->next)
9140 if (p->r == r && p->g == g && p->b == b)
9141 break;
9142
9143 if (p == NULL)
9144 {
9145 COLORREF color;
9146 Colormap cmap;
9147 int rc;
9148
9149 color = PALETTERGB (r, g, b);
9150
9151 ++ct_colors_allocated;
9152
9153 p = (struct ct_color *) xmalloc (sizeof *p);
9154 p->r = r;
9155 p->g = g;
9156 p->b = b;
9157 p->pixel = color;
9158 p->next = ct_table[i];
9159 ct_table[i] = p;
9160 }
9161
9162 return p->pixel;
9163}
9164
9165
9166/* Look up pixel color PIXEL which is used on frame F in the color
9167 table. If not already present, allocate it. Value is PIXEL. */
9168
9169static unsigned long
9170lookup_pixel_color (f, pixel)
9171 struct frame *f;
9172 unsigned long pixel;
9173{
9174 int i = pixel % CT_SIZE;
9175 struct ct_color *p;
9176
9177 for (p = ct_table[i]; p; p = p->next)
9178 if (p->pixel == pixel)
9179 break;
9180
9181 if (p == NULL)
9182 {
9183 XColor color;
9184 Colormap cmap;
9185 int rc;
9186
9187 BLOCK_INPUT;
9188
9189 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9190 color.pixel = pixel;
9191 XQueryColor (NULL, cmap, &color);
9192 rc = x_alloc_nearest_color (f, cmap, &color);
9193 UNBLOCK_INPUT;
9194
9195 if (rc)
9196 {
9197 ++ct_colors_allocated;
9198
9199 p = (struct ct_color *) xmalloc (sizeof *p);
9200 p->r = color.red;
9201 p->g = color.green;
9202 p->b = color.blue;
9203 p->pixel = pixel;
9204 p->next = ct_table[i];
9205 ct_table[i] = p;
9206 }
9207 else
9208 return FRAME_FOREGROUND_PIXEL (f);
9209 }
9210 return p->pixel;
9211}
9212
9213
9214/* Value is a vector of all pixel colors contained in the color table,
9215 allocated via xmalloc. Set *N to the number of colors. */
9216
9217static unsigned long *
9218colors_in_color_table (n)
9219 int *n;
9220{
9221 int i, j;
9222 struct ct_color *p;
9223 unsigned long *colors;
9224
9225 if (ct_colors_allocated == 0)
9226 {
9227 *n = 0;
9228 colors = NULL;
9229 }
9230 else
9231 {
9232 colors = (unsigned long *) xmalloc (ct_colors_allocated
9233 * sizeof *colors);
9234 *n = ct_colors_allocated;
9235
9236 for (i = j = 0; i < CT_SIZE; ++i)
9237 for (p = ct_table[i]; p; p = p->next)
9238 colors[j++] = p->pixel;
9239 }
9240
9241 return colors;
9242}
9243
9244#endif /* NTEMACS_TODO */
9245
9246\f
9247/***********************************************************************
9248 Algorithms
9249 ***********************************************************************/
9250
9251#if 0 /* NTEMACS_TODO : W32 versions of low level algorithms */
9252static void x_laplace_write_row P_ ((struct frame *, long *,
9253 int, XImage *, int));
9254static void x_laplace_read_row P_ ((struct frame *, Colormap,
9255 XColor *, int, XImage *, int));
9256
9257
9258/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9259 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9260 the width of one row in the image. */
9261
9262static void
9263x_laplace_read_row (f, cmap, colors, width, ximg, y)
9264 struct frame *f;
9265 Colormap cmap;
9266 XColor *colors;
9267 int width;
9268 XImage *ximg;
9269 int y;
9270{
9271 int x;
9272
9273 for (x = 0; x < width; ++x)
9274 colors[x].pixel = XGetPixel (ximg, x, y);
9275
9276 XQueryColors (NULL, cmap, colors, width);
9277}
9278
9279
9280/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9281 containing the pixel colors to write. F is the frame we are
9282 working on. */
9283
9284static void
9285x_laplace_write_row (f, pixels, width, ximg, y)
9286 struct frame *f;
9287 long *pixels;
9288 int width;
9289 XImage *ximg;
9290 int y;
9291{
9292 int x;
9293
9294 for (x = 0; x < width; ++x)
9295 XPutPixel (ximg, x, y, pixels[x]);
9296}
9297#endif
9298
9299/* Transform image IMG which is used on frame F with a Laplace
9300 edge-detection algorithm. The result is an image that can be used
9301 to draw disabled buttons, for example. */
9302
9303static void
9304x_laplace (f, img)
9305 struct frame *f;
9306 struct image *img;
9307{
9308#if 0 /* NTEMACS_TODO : W32 version */
9309 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9310 XImage *ximg, *oimg;
9311 XColor *in[3];
9312 long *out;
9313 Pixmap pixmap;
9314 int x, y, i;
9315 long pixel;
9316 int in_y, out_y, rc;
9317 int mv2 = 45000;
9318
9319 BLOCK_INPUT;
9320
9321 /* Get the X image IMG->pixmap. */
9322 ximg = XGetImage (NULL, img->pixmap,
9323 0, 0, img->width, img->height, ~0, ZPixmap);
9324
9325 /* Allocate 3 input rows, and one output row of colors. */
9326 for (i = 0; i < 3; ++i)
9327 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9328 out = (long *) alloca (img->width * sizeof (long));
9329
9330 /* Create an X image for output. */
9331 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9332 &oimg, &pixmap);
9333
9334 /* Fill first two rows. */
9335 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9336 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9337 in_y = 2;
9338
9339 /* Write first row, all zeros. */
9340 init_color_table ();
9341 pixel = lookup_rgb_color (f, 0, 0, 0);
9342 for (x = 0; x < img->width; ++x)
9343 out[x] = pixel;
9344 x_laplace_write_row (f, out, img->width, oimg, 0);
9345 out_y = 1;
9346
9347 for (y = 2; y < img->height; ++y)
9348 {
9349 int rowa = y % 3;
9350 int rowb = (y + 2) % 3;
9351
9352 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9353
9354 for (x = 0; x < img->width - 2; ++x)
9355 {
9356 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9357 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9358 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9359
9360 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9361 b & 0xffff);
9362 }
9363
9364 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9365 }
9366
9367 /* Write last line, all zeros. */
9368 for (x = 0; x < img->width; ++x)
9369 out[x] = pixel;
9370 x_laplace_write_row (f, out, img->width, oimg, out_y);
9371
9372 /* Free the input image, and free resources of IMG. */
9373 XDestroyImage (ximg);
9374 x_clear_image (f, img);
9375
9376 /* Put the output image into pixmap, and destroy it. */
9377 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9378 x_destroy_x_image (oimg);
9379
9380 /* Remember new pixmap and colors in IMG. */
9381 img->pixmap = pixmap;
9382 img->colors = colors_in_color_table (&img->ncolors);
9383 free_color_table ();
9384
9385 UNBLOCK_INPUT;
9386#endif /* NTEMACS_TODO */
9387}
9388
9389
9390/* Build a mask for image IMG which is used on frame F. FILE is the
9391 name of an image file, for error messages. HOW determines how to
9392 determine the background color of IMG. If it is a list '(R G B)',
9393 with R, G, and B being integers >= 0, take that as the color of the
9394 background. Otherwise, determine the background color of IMG
9395 heuristically. Value is non-zero if successful. */
9396
9397static int
9398x_build_heuristic_mask (f, img, how)
9399 struct frame *f;
9400 struct image *img;
9401 Lisp_Object how;
9402{
9403#if 0 /* NTEMACS_TODO : W32 version */
9404 Display *dpy = FRAME_W32_DISPLAY (f);
9405 XImage *ximg, *mask_img;
9406 int x, y, rc, look_at_corners_p;
9407 unsigned long bg;
9408
9409 BLOCK_INPUT;
9410
9411 /* Create an image and pixmap serving as mask. */
9412 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9413 &mask_img, &img->mask);
9414 if (!rc)
9415 {
9416 UNBLOCK_INPUT;
9417 return 0;
9418 }
9419
9420 /* Get the X image of IMG->pixmap. */
9421 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9422 ~0, ZPixmap);
9423
9424 /* Determine the background color of ximg. If HOW is `(R G B)'
9425 take that as color. Otherwise, try to determine the color
9426 heuristically. */
9427 look_at_corners_p = 1;
9428
9429 if (CONSP (how))
9430 {
9431 int rgb[3], i = 0;
9432
9433 while (i < 3
9434 && CONSP (how)
9435 && NATNUMP (XCAR (how)))
9436 {
9437 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9438 how = XCDR (how);
9439 }
9440
9441 if (i == 3 && NILP (how))
9442 {
9443 char color_name[30];
9444 XColor exact, color;
9445 Colormap cmap;
9446
9447 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9448
9449 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9450 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9451 {
9452 bg = color.pixel;
9453 look_at_corners_p = 0;
9454 }
9455 }
9456 }
9457
9458 if (look_at_corners_p)
9459 {
9460 unsigned long corners[4];
9461 int i, best_count;
9462
9463 /* Get the colors at the corners of ximg. */
9464 corners[0] = XGetPixel (ximg, 0, 0);
9465 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9466 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9467 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9468
9469 /* Choose the most frequently found color as background. */
9470 for (i = best_count = 0; i < 4; ++i)
9471 {
9472 int j, n;
9473
9474 for (j = n = 0; j < 4; ++j)
9475 if (corners[i] == corners[j])
9476 ++n;
9477
9478 if (n > best_count)
9479 bg = corners[i], best_count = n;
9480 }
9481 }
9482
9483 /* Set all bits in mask_img to 1 whose color in ximg is different
9484 from the background color bg. */
9485 for (y = 0; y < img->height; ++y)
9486 for (x = 0; x < img->width; ++x)
9487 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9488
9489 /* Put mask_img into img->mask. */
9490 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9491 x_destroy_x_image (mask_img);
9492 XDestroyImage (ximg);
9493
9494 UNBLOCK_INPUT;
9495#endif /* NTEMACS_TODO */
9496
9497 return 1;
9498}
9499
9500
9501\f
9502/***********************************************************************
9503 PBM (mono, gray, color)
9504 ***********************************************************************/
9505#ifdef HAVE_PBM
9506
9507static int pbm_image_p P_ ((Lisp_Object object));
9508static int pbm_load P_ ((struct frame *f, struct image *img));
9509static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9510
9511/* The symbol `pbm' identifying images of this type. */
9512
9513Lisp_Object Qpbm;
9514
9515/* Indices of image specification fields in gs_format, below. */
9516
9517enum pbm_keyword_index
9518{
9519 PBM_TYPE,
9520 PBM_FILE,
9521 PBM_DATA,
9522 PBM_ASCENT,
9523 PBM_MARGIN,
9524 PBM_RELIEF,
9525 PBM_ALGORITHM,
9526 PBM_HEURISTIC_MASK,
9527 PBM_LAST
9528};
9529
9530/* Vector of image_keyword structures describing the format
9531 of valid user-defined image specifications. */
9532
9533static struct image_keyword pbm_format[PBM_LAST] =
9534{
9535 {":type", IMAGE_SYMBOL_VALUE, 1},
9536 {":file", IMAGE_STRING_VALUE, 0},
9537 {":data", IMAGE_STRING_VALUE, 0},
9538 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9539 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9540 {":relief", IMAGE_INTEGER_VALUE, 0},
9541 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9542 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9543};
9544
9545/* Structure describing the image type `pbm'. */
9546
9547static struct image_type pbm_type =
9548{
9549 &Qpbm,
9550 pbm_image_p,
9551 pbm_load,
9552 x_clear_image,
9553 NULL
9554};
9555
9556
9557/* Return non-zero if OBJECT is a valid PBM image specification. */
9558
9559static int
9560pbm_image_p (object)
9561 Lisp_Object object;
9562{
9563 struct image_keyword fmt[PBM_LAST];
9564
9565 bcopy (pbm_format, fmt, sizeof fmt);
9566
9567 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9568 || (fmt[PBM_ASCENT].count
9569 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9570 return 0;
9571
9572 /* Must specify either :data or :file. */
9573 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9574}
9575
9576
9577/* Scan a decimal number from *S and return it. Advance *S while
9578 reading the number. END is the end of the string. Value is -1 at
9579 end of input. */
9580
9581static int
9582pbm_scan_number (s, end)
9583 unsigned char **s, *end;
9584{
9585 int c, val = -1;
9586
9587 while (*s < end)
9588 {
9589 /* Skip white-space. */
9590 while (*s < end && (c = *(*s)++, isspace (c)))
9591 ;
9592
9593 if (c == '#')
9594 {
9595 /* Skip comment to end of line. */
9596 while (*s < end && (c = *(*s)++, c != '\n'))
9597 ;
9598 }
9599 else if (isdigit (c))
9600 {
9601 /* Read decimal number. */
9602 val = c - '0';
9603 while (*s < end && (c = *(*s)++, isdigit (c)))
9604 val = 10 * val + c - '0';
9605 break;
9606 }
9607 else
9608 break;
9609 }
9610
9611 return val;
9612}
9613
9614
9615/* Read FILE into memory. Value is a pointer to a buffer allocated
9616 with xmalloc holding FILE's contents. Value is null if an error
9617 occured. *SIZE is set to the size of the file. */
9618
9619static char *
9620pbm_read_file (file, size)
9621 Lisp_Object file;
9622 int *size;
9623{
9624 FILE *fp = NULL;
9625 char *buf = NULL;
9626 struct stat st;
9627
9628 if (stat (XSTRING (file)->data, &st) == 0
9629 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
9630 && (buf = (char *) xmalloc (st.st_size),
9631 fread (buf, 1, st.st_size, fp) == st.st_size))
9632 {
9633 *size = st.st_size;
9634 fclose (fp);
9635 }
9636 else
9637 {
9638 if (fp)
9639 fclose (fp);
9640 if (buf)
9641 {
9642 xfree (buf);
9643 buf = NULL;
9644 }
9645 }
9646
9647 return buf;
9648}
9649
9650
9651/* Load PBM image IMG for use on frame F. */
9652
9653static int
9654pbm_load (f, img)
9655 struct frame *f;
9656 struct image *img;
9657{
9658 int raw_p, x, y;
9659 int width, height, max_color_idx = 0;
9660 XImage *ximg;
9661 Lisp_Object file, specified_file;
9662 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
9663 struct gcpro gcpro1;
9664 unsigned char *contents = NULL;
9665 unsigned char *end, *p;
9666 int size;
9667
9668 specified_file = image_spec_value (img->spec, QCfile, NULL);
9669 file = Qnil;
9670 GCPRO1 (file);
9671
9672 if (STRINGP (specified_file))
9673 {
9674 file = x_find_image_file (specified_file);
9675 if (!STRINGP (file))
9676 {
9677 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9678 UNGCPRO;
9679 return 0;
9680 }
9681
9682 contents = pbm_read_file (file, &size);
9683 if (contents == NULL)
9684 {
9685 image_error ("Error reading `%s'", file, Qnil);
9686 UNGCPRO;
9687 return 0;
9688 }
9689
9690 p = contents;
9691 end = contents + size;
9692 }
9693 else
9694 {
9695 Lisp_Object data;
9696 data = image_spec_value (img->spec, QCdata, NULL);
9697 p = XSTRING (data)->data;
9698 end = p + STRING_BYTES (XSTRING (data));
9699 }
9700
9701 /* Check magic number. */
9702 if (end - p < 2 || *p++ != 'P')
9703 {
9704 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9705 error:
9706 xfree (contents);
9707 UNGCPRO;
9708 return 0;
9709 }
9710
6fc2811b
JR
9711 switch (*p++)
9712 {
9713 case '1':
9714 raw_p = 0, type = PBM_MONO;
9715 break;
9716
9717 case '2':
9718 raw_p = 0, type = PBM_GRAY;
9719 break;
9720
9721 case '3':
9722 raw_p = 0, type = PBM_COLOR;
9723 break;
9724
9725 case '4':
9726 raw_p = 1, type = PBM_MONO;
9727 break;
9728
9729 case '5':
9730 raw_p = 1, type = PBM_GRAY;
9731 break;
9732
9733 case '6':
9734 raw_p = 1, type = PBM_COLOR;
9735 break;
9736
9737 default:
9738 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9739 goto error;
9740 }
9741
9742 /* Read width, height, maximum color-component. Characters
9743 starting with `#' up to the end of a line are ignored. */
9744 width = pbm_scan_number (&p, end);
9745 height = pbm_scan_number (&p, end);
9746
9747 if (type != PBM_MONO)
9748 {
9749 max_color_idx = pbm_scan_number (&p, end);
9750 if (raw_p && max_color_idx > 255)
9751 max_color_idx = 255;
9752 }
9753
9754 if (width < 0
9755 || height < 0
9756 || (type != PBM_MONO && max_color_idx < 0))
9757 goto error;
9758
9759 BLOCK_INPUT;
9760 if (!x_create_x_image_and_pixmap (f, width, height, 0,
9761 &ximg, &img->pixmap))
9762 {
9763 UNBLOCK_INPUT;
9764 goto error;
9765 }
9766
9767 /* Initialize the color hash table. */
9768 init_color_table ();
9769
9770 if (type == PBM_MONO)
9771 {
9772 int c = 0, g;
9773
9774 for (y = 0; y < height; ++y)
9775 for (x = 0; x < width; ++x)
9776 {
9777 if (raw_p)
9778 {
9779 if ((x & 7) == 0)
9780 c = *p++;
9781 g = c & 0x80;
9782 c <<= 1;
9783 }
9784 else
9785 g = pbm_scan_number (&p, end);
9786
9787 XPutPixel (ximg, x, y, (g
9788 ? FRAME_FOREGROUND_PIXEL (f)
9789 : FRAME_BACKGROUND_PIXEL (f)));
9790 }
9791 }
9792 else
9793 {
9794 for (y = 0; y < height; ++y)
9795 for (x = 0; x < width; ++x)
9796 {
9797 int r, g, b;
9798
9799 if (type == PBM_GRAY)
9800 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
9801 else if (raw_p)
9802 {
9803 r = *p++;
9804 g = *p++;
9805 b = *p++;
9806 }
9807 else
9808 {
9809 r = pbm_scan_number (&p, end);
9810 g = pbm_scan_number (&p, end);
9811 b = pbm_scan_number (&p, end);
9812 }
9813
9814 if (r < 0 || g < 0 || b < 0)
9815 {
dfff8a69 9816 xfree (ximg->data);
6fc2811b
JR
9817 ximg->data = NULL;
9818 XDestroyImage (ximg);
9819 UNBLOCK_INPUT;
9820 image_error ("Invalid pixel value in image `%s'",
9821 img->spec, Qnil);
9822 goto error;
9823 }
9824
9825 /* RGB values are now in the range 0..max_color_idx.
9826 Scale this to the range 0..0xffff supported by X. */
9827 r = (double) r * 65535 / max_color_idx;
9828 g = (double) g * 65535 / max_color_idx;
9829 b = (double) b * 65535 / max_color_idx;
9830 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9831 }
9832 }
9833
9834 /* Store in IMG->colors the colors allocated for the image, and
9835 free the color table. */
9836 img->colors = colors_in_color_table (&img->ncolors);
9837 free_color_table ();
9838
9839 /* Put the image into a pixmap. */
9840 x_put_x_image (f, ximg, img->pixmap, width, height);
9841 x_destroy_x_image (ximg);
9842 UNBLOCK_INPUT;
9843
9844 img->width = width;
9845 img->height = height;
9846
9847 UNGCPRO;
9848 xfree (contents);
9849 return 1;
9850}
9851#endif /* HAVE_PBM */
9852
9853\f
9854/***********************************************************************
9855 PNG
9856 ***********************************************************************/
9857
9858#if HAVE_PNG
9859
9860#include <png.h>
9861
9862/* Function prototypes. */
9863
9864static int png_image_p P_ ((Lisp_Object object));
9865static int png_load P_ ((struct frame *f, struct image *img));
9866
9867/* The symbol `png' identifying images of this type. */
9868
9869Lisp_Object Qpng;
9870
9871/* Indices of image specification fields in png_format, below. */
9872
9873enum png_keyword_index
9874{
9875 PNG_TYPE,
9876 PNG_DATA,
9877 PNG_FILE,
9878 PNG_ASCENT,
9879 PNG_MARGIN,
9880 PNG_RELIEF,
9881 PNG_ALGORITHM,
9882 PNG_HEURISTIC_MASK,
9883 PNG_LAST
9884};
9885
9886/* Vector of image_keyword structures describing the format
9887 of valid user-defined image specifications. */
9888
9889static struct image_keyword png_format[PNG_LAST] =
9890{
9891 {":type", IMAGE_SYMBOL_VALUE, 1},
9892 {":data", IMAGE_STRING_VALUE, 0},
9893 {":file", IMAGE_STRING_VALUE, 0},
9894 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9895 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9896 {":relief", IMAGE_INTEGER_VALUE, 0},
9897 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9898 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9899};
9900
9901/* Structure describing the image type `png'. */
9902
9903static struct image_type png_type =
9904{
9905 &Qpng,
9906 png_image_p,
9907 png_load,
9908 x_clear_image,
9909 NULL
9910};
9911
9912
9913/* Return non-zero if OBJECT is a valid PNG image specification. */
9914
9915static int
9916png_image_p (object)
9917 Lisp_Object object;
9918{
9919 struct image_keyword fmt[PNG_LAST];
9920 bcopy (png_format, fmt, sizeof fmt);
9921
9922 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
9923 || (fmt[PNG_ASCENT].count
9924 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
9925 return 0;
9926
9927 /* Must specify either the :data or :file keyword. */
9928 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
9929}
9930
9931
9932/* Error and warning handlers installed when the PNG library
9933 is initialized. */
9934
9935static void
9936my_png_error (png_ptr, msg)
9937 png_struct *png_ptr;
9938 char *msg;
9939{
9940 xassert (png_ptr != NULL);
9941 image_error ("PNG error: %s", build_string (msg), Qnil);
9942 longjmp (png_ptr->jmpbuf, 1);
9943}
9944
9945
9946static void
9947my_png_warning (png_ptr, msg)
9948 png_struct *png_ptr;
9949 char *msg;
9950{
9951 xassert (png_ptr != NULL);
9952 image_error ("PNG warning: %s", build_string (msg), Qnil);
9953}
9954
6fc2811b
JR
9955/* Memory source for PNG decoding. */
9956
9957struct png_memory_storage
9958{
9959 unsigned char *bytes; /* The data */
9960 size_t len; /* How big is it? */
9961 int index; /* Where are we? */
9962};
9963
9964
9965/* Function set as reader function when reading PNG image from memory.
9966 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
9967 bytes from the input to DATA. */
9968
9969static void
9970png_read_from_memory (png_ptr, data, length)
9971 png_structp png_ptr;
9972 png_bytep data;
9973 png_size_t length;
9974{
9975 struct png_memory_storage *tbr
9976 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
9977
9978 if (length > tbr->len - tbr->index)
9979 png_error (png_ptr, "Read error");
9980
9981 bcopy (tbr->bytes + tbr->index, data, length);
9982 tbr->index = tbr->index + length;
9983}
9984
6fc2811b
JR
9985/* Load PNG image IMG for use on frame F. Value is non-zero if
9986 successful. */
9987
9988static int
9989png_load (f, img)
9990 struct frame *f;
9991 struct image *img;
9992{
9993 Lisp_Object file, specified_file;
9994 Lisp_Object specified_data;
9995 int x, y, i;
9996 XImage *ximg, *mask_img = NULL;
9997 struct gcpro gcpro1;
9998 png_struct *png_ptr = NULL;
9999 png_info *info_ptr = NULL, *end_info = NULL;
10000 FILE *fp = NULL;
10001 png_byte sig[8];
10002 png_byte *pixels = NULL;
10003 png_byte **rows = NULL;
10004 png_uint_32 width, height;
10005 int bit_depth, color_type, interlace_type;
10006 png_byte channels;
10007 png_uint_32 row_bytes;
10008 int transparent_p;
10009 char *gamma_str;
10010 double screen_gamma, image_gamma;
10011 int intent;
10012 struct png_memory_storage tbr; /* Data to be read */
10013
10014 /* Find out what file to load. */
10015 specified_file = image_spec_value (img->spec, QCfile, NULL);
10016 specified_data = image_spec_value (img->spec, QCdata, NULL);
10017 file = Qnil;
10018 GCPRO1 (file);
10019
10020 if (NILP (specified_data))
10021 {
10022 file = x_find_image_file (specified_file);
10023 if (!STRINGP (file))
10024 {
10025 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10026 UNGCPRO;
10027 return 0;
10028 }
10029
10030 /* Open the image file. */
10031 fp = fopen (XSTRING (file)->data, "rb");
10032 if (!fp)
10033 {
10034 image_error ("Cannot open image file `%s'", file, Qnil);
10035 UNGCPRO;
10036 fclose (fp);
10037 return 0;
10038 }
10039
10040 /* Check PNG signature. */
10041 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10042 || !png_check_sig (sig, sizeof sig))
10043 {
10044 image_error ("Not a PNG file:` %s'", file, Qnil);
10045 UNGCPRO;
10046 fclose (fp);
10047 return 0;
10048 }
10049 }
10050 else
10051 {
10052 /* Read from memory. */
10053 tbr.bytes = XSTRING (specified_data)->data;
10054 tbr.len = STRING_BYTES (XSTRING (specified_data));
10055 tbr.index = 0;
10056
10057 /* Check PNG signature. */
10058 if (tbr.len < sizeof sig
10059 || !png_check_sig (tbr.bytes, sizeof sig))
10060 {
10061 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10062 UNGCPRO;
10063 return 0;
10064 }
10065
10066 /* Need to skip past the signature. */
10067 tbr.bytes += sizeof (sig);
10068 }
10069
6fc2811b
JR
10070 /* Initialize read and info structs for PNG lib. */
10071 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10072 my_png_error, my_png_warning);
10073 if (!png_ptr)
10074 {
10075 if (fp) fclose (fp);
10076 UNGCPRO;
10077 return 0;
10078 }
10079
10080 info_ptr = png_create_info_struct (png_ptr);
10081 if (!info_ptr)
10082 {
10083 png_destroy_read_struct (&png_ptr, NULL, NULL);
10084 if (fp) fclose (fp);
10085 UNGCPRO;
10086 return 0;
10087 }
10088
10089 end_info = png_create_info_struct (png_ptr);
10090 if (!end_info)
10091 {
10092 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10093 if (fp) fclose (fp);
10094 UNGCPRO;
10095 return 0;
10096 }
10097
10098 /* Set error jump-back. We come back here when the PNG library
10099 detects an error. */
10100 if (setjmp (png_ptr->jmpbuf))
10101 {
10102 error:
10103 if (png_ptr)
10104 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10105 xfree (pixels);
10106 xfree (rows);
10107 if (fp) fclose (fp);
10108 UNGCPRO;
10109 return 0;
10110 }
10111
10112 /* Read image info. */
10113 if (!NILP (specified_data))
10114 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10115 else
10116 png_init_io (png_ptr, fp);
10117
10118 png_set_sig_bytes (png_ptr, sizeof sig);
10119 png_read_info (png_ptr, info_ptr);
10120 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10121 &interlace_type, NULL, NULL);
10122
10123 /* If image contains simply transparency data, we prefer to
10124 construct a clipping mask. */
10125 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10126 transparent_p = 1;
10127 else
10128 transparent_p = 0;
10129
10130 /* This function is easier to write if we only have to handle
10131 one data format: RGB or RGBA with 8 bits per channel. Let's
10132 transform other formats into that format. */
10133
10134 /* Strip more than 8 bits per channel. */
10135 if (bit_depth == 16)
10136 png_set_strip_16 (png_ptr);
10137
10138 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10139 if available. */
10140 png_set_expand (png_ptr);
10141
10142 /* Convert grayscale images to RGB. */
10143 if (color_type == PNG_COLOR_TYPE_GRAY
10144 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10145 png_set_gray_to_rgb (png_ptr);
10146
10147 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10148 gamma_str = getenv ("SCREEN_GAMMA");
10149 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10150
10151 /* Tell the PNG lib to handle gamma correction for us. */
10152
10153#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10154 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10155 /* There is a special chunk in the image specifying the gamma. */
10156 png_set_sRGB (png_ptr, info_ptr, intent);
10157 else
10158#endif
10159 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10160 /* Image contains gamma information. */
10161 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10162 else
10163 /* Use a default of 0.5 for the image gamma. */
10164 png_set_gamma (png_ptr, screen_gamma, 0.5);
10165
10166 /* Handle alpha channel by combining the image with a background
10167 color. Do this only if a real alpha channel is supplied. For
10168 simple transparency, we prefer a clipping mask. */
10169 if (!transparent_p)
10170 {
10171 png_color_16 *image_background;
10172
10173 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10174 /* Image contains a background color with which to
10175 combine the image. */
10176 png_set_background (png_ptr, image_background,
10177 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10178 else
10179 {
10180 /* Image does not contain a background color with which
10181 to combine the image data via an alpha channel. Use
10182 the frame's background instead. */
10183 XColor color;
10184 Colormap cmap;
10185 png_color_16 frame_background;
10186
10187 BLOCK_INPUT;
10188 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10189 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10190 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10191 UNBLOCK_INPUT;
10192
10193 bzero (&frame_background, sizeof frame_background);
10194 frame_background.red = color.red;
10195 frame_background.green = color.green;
10196 frame_background.blue = color.blue;
10197
10198 png_set_background (png_ptr, &frame_background,
10199 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10200 }
10201 }
10202
10203 /* Update info structure. */
10204 png_read_update_info (png_ptr, info_ptr);
10205
10206 /* Get number of channels. Valid values are 1 for grayscale images
10207 and images with a palette, 2 for grayscale images with transparency
10208 information (alpha channel), 3 for RGB images, and 4 for RGB
10209 images with alpha channel, i.e. RGBA. If conversions above were
10210 sufficient we should only have 3 or 4 channels here. */
10211 channels = png_get_channels (png_ptr, info_ptr);
10212 xassert (channels == 3 || channels == 4);
10213
10214 /* Number of bytes needed for one row of the image. */
10215 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10216
10217 /* Allocate memory for the image. */
10218 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10219 rows = (png_byte **) xmalloc (height * sizeof *rows);
10220 for (i = 0; i < height; ++i)
10221 rows[i] = pixels + i * row_bytes;
10222
10223 /* Read the entire image. */
10224 png_read_image (png_ptr, rows);
10225 png_read_end (png_ptr, info_ptr);
10226 if (fp)
10227 {
10228 fclose (fp);
10229 fp = NULL;
10230 }
10231
10232 BLOCK_INPUT;
10233
10234 /* Create the X image and pixmap. */
10235 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10236 &img->pixmap))
10237 {
10238 UNBLOCK_INPUT;
10239 goto error;
10240 }
10241
10242 /* Create an image and pixmap serving as mask if the PNG image
10243 contains an alpha channel. */
10244 if (channels == 4
10245 && !transparent_p
10246 && !x_create_x_image_and_pixmap (f, width, height, 1,
10247 &mask_img, &img->mask))
10248 {
10249 x_destroy_x_image (ximg);
10250 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10251 img->pixmap = 0;
10252 UNBLOCK_INPUT;
10253 goto error;
10254 }
10255
10256 /* Fill the X image and mask from PNG data. */
10257 init_color_table ();
10258
10259 for (y = 0; y < height; ++y)
10260 {
10261 png_byte *p = rows[y];
10262
10263 for (x = 0; x < width; ++x)
10264 {
10265 unsigned r, g, b;
10266
10267 r = *p++ << 8;
10268 g = *p++ << 8;
10269 b = *p++ << 8;
10270 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10271
10272 /* An alpha channel, aka mask channel, associates variable
10273 transparency with an image. Where other image formats
10274 support binary transparency---fully transparent or fully
10275 opaque---PNG allows up to 254 levels of partial transparency.
10276 The PNG library implements partial transparency by combining
10277 the image with a specified background color.
10278
10279 I'm not sure how to handle this here nicely: because the
10280 background on which the image is displayed may change, for
10281 real alpha channel support, it would be necessary to create
10282 a new image for each possible background.
10283
10284 What I'm doing now is that a mask is created if we have
10285 boolean transparency information. Otherwise I'm using
10286 the frame's background color to combine the image with. */
10287
10288 if (channels == 4)
10289 {
10290 if (mask_img)
10291 XPutPixel (mask_img, x, y, *p > 0);
10292 ++p;
10293 }
10294 }
10295 }
10296
10297 /* Remember colors allocated for this image. */
10298 img->colors = colors_in_color_table (&img->ncolors);
10299 free_color_table ();
10300
10301 /* Clean up. */
10302 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10303 xfree (rows);
10304 xfree (pixels);
10305
10306 img->width = width;
10307 img->height = height;
10308
10309 /* Put the image into the pixmap, then free the X image and its buffer. */
10310 x_put_x_image (f, ximg, img->pixmap, width, height);
10311 x_destroy_x_image (ximg);
10312
10313 /* Same for the mask. */
10314 if (mask_img)
10315 {
10316 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10317 x_destroy_x_image (mask_img);
10318 }
10319
10320 UNBLOCK_INPUT;
10321 UNGCPRO;
10322 return 1;
10323}
10324
10325#endif /* HAVE_PNG != 0 */
10326
10327
10328\f
10329/***********************************************************************
10330 JPEG
10331 ***********************************************************************/
10332
10333#if HAVE_JPEG
10334
10335/* Work around a warning about HAVE_STDLIB_H being redefined in
10336 jconfig.h. */
10337#ifdef HAVE_STDLIB_H
10338#define HAVE_STDLIB_H_1
10339#undef HAVE_STDLIB_H
10340#endif /* HAVE_STLIB_H */
10341
10342#include <jpeglib.h>
10343#include <jerror.h>
10344#include <setjmp.h>
10345
10346#ifdef HAVE_STLIB_H_1
10347#define HAVE_STDLIB_H 1
10348#endif
10349
10350static int jpeg_image_p P_ ((Lisp_Object object));
10351static int jpeg_load P_ ((struct frame *f, struct image *img));
10352
10353/* The symbol `jpeg' identifying images of this type. */
10354
10355Lisp_Object Qjpeg;
10356
10357/* Indices of image specification fields in gs_format, below. */
10358
10359enum jpeg_keyword_index
10360{
10361 JPEG_TYPE,
10362 JPEG_DATA,
10363 JPEG_FILE,
10364 JPEG_ASCENT,
10365 JPEG_MARGIN,
10366 JPEG_RELIEF,
10367 JPEG_ALGORITHM,
10368 JPEG_HEURISTIC_MASK,
10369 JPEG_LAST
10370};
10371
10372/* Vector of image_keyword structures describing the format
10373 of valid user-defined image specifications. */
10374
10375static struct image_keyword jpeg_format[JPEG_LAST] =
10376{
10377 {":type", IMAGE_SYMBOL_VALUE, 1},
10378 {":data", IMAGE_STRING_VALUE, 0},
10379 {":file", IMAGE_STRING_VALUE, 0},
10380 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10381 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10382 {":relief", IMAGE_INTEGER_VALUE, 0},
10383 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10384 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10385};
10386
10387/* Structure describing the image type `jpeg'. */
10388
10389static struct image_type jpeg_type =
10390{
10391 &Qjpeg,
10392 jpeg_image_p,
10393 jpeg_load,
10394 x_clear_image,
10395 NULL
10396};
10397
10398
10399/* Return non-zero if OBJECT is a valid JPEG image specification. */
10400
10401static int
10402jpeg_image_p (object)
10403 Lisp_Object object;
10404{
10405 struct image_keyword fmt[JPEG_LAST];
10406
10407 bcopy (jpeg_format, fmt, sizeof fmt);
10408
10409 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10410 || (fmt[JPEG_ASCENT].count
10411 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10412 return 0;
10413
10414 /* Must specify either the :data or :file keyword. */
10415 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10416}
10417
10418
10419struct my_jpeg_error_mgr
10420{
10421 struct jpeg_error_mgr pub;
10422 jmp_buf setjmp_buffer;
10423};
10424
10425static void
10426my_error_exit (cinfo)
10427 j_common_ptr cinfo;
10428{
10429 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10430 longjmp (mgr->setjmp_buffer, 1);
10431}
10432
6fc2811b
JR
10433/* Init source method for JPEG data source manager. Called by
10434 jpeg_read_header() before any data is actually read. See
10435 libjpeg.doc from the JPEG lib distribution. */
10436
10437static void
10438our_init_source (cinfo)
10439 j_decompress_ptr cinfo;
10440{
10441}
10442
10443
10444/* Fill input buffer method for JPEG data source manager. Called
10445 whenever more data is needed. We read the whole image in one step,
10446 so this only adds a fake end of input marker at the end. */
10447
10448static boolean
10449our_fill_input_buffer (cinfo)
10450 j_decompress_ptr cinfo;
10451{
10452 /* Insert a fake EOI marker. */
10453 struct jpeg_source_mgr *src = cinfo->src;
10454 static JOCTET buffer[2];
10455
10456 buffer[0] = (JOCTET) 0xFF;
10457 buffer[1] = (JOCTET) JPEG_EOI;
10458
10459 src->next_input_byte = buffer;
10460 src->bytes_in_buffer = 2;
10461 return TRUE;
10462}
10463
10464
10465/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10466 is the JPEG data source manager. */
10467
10468static void
10469our_skip_input_data (cinfo, num_bytes)
10470 j_decompress_ptr cinfo;
10471 long num_bytes;
10472{
10473 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10474
10475 if (src)
10476 {
10477 if (num_bytes > src->bytes_in_buffer)
10478 ERREXIT (cinfo, JERR_INPUT_EOF);
10479
10480 src->bytes_in_buffer -= num_bytes;
10481 src->next_input_byte += num_bytes;
10482 }
10483}
10484
10485
10486/* Method to terminate data source. Called by
10487 jpeg_finish_decompress() after all data has been processed. */
10488
10489static void
10490our_term_source (cinfo)
10491 j_decompress_ptr cinfo;
10492{
10493}
10494
10495
10496/* Set up the JPEG lib for reading an image from DATA which contains
10497 LEN bytes. CINFO is the decompression info structure created for
10498 reading the image. */
10499
10500static void
10501jpeg_memory_src (cinfo, data, len)
10502 j_decompress_ptr cinfo;
10503 JOCTET *data;
10504 unsigned int len;
10505{
10506 struct jpeg_source_mgr *src;
10507
10508 if (cinfo->src == NULL)
10509 {
10510 /* First time for this JPEG object? */
10511 cinfo->src = (struct jpeg_source_mgr *)
10512 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10513 sizeof (struct jpeg_source_mgr));
10514 src = (struct jpeg_source_mgr *) cinfo->src;
10515 src->next_input_byte = data;
10516 }
10517
10518 src = (struct jpeg_source_mgr *) cinfo->src;
10519 src->init_source = our_init_source;
10520 src->fill_input_buffer = our_fill_input_buffer;
10521 src->skip_input_data = our_skip_input_data;
10522 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10523 src->term_source = our_term_source;
10524 src->bytes_in_buffer = len;
10525 src->next_input_byte = data;
10526}
10527
10528
10529/* Load image IMG for use on frame F. Patterned after example.c
10530 from the JPEG lib. */
10531
10532static int
10533jpeg_load (f, img)
10534 struct frame *f;
10535 struct image *img;
10536{
10537 struct jpeg_decompress_struct cinfo;
10538 struct my_jpeg_error_mgr mgr;
10539 Lisp_Object file, specified_file;
10540 Lisp_Object specified_data;
10541 FILE *fp = NULL;
10542 JSAMPARRAY buffer;
10543 int row_stride, x, y;
10544 XImage *ximg = NULL;
10545 int rc;
10546 unsigned long *colors;
10547 int width, height;
10548 struct gcpro gcpro1;
10549
10550 /* Open the JPEG file. */
10551 specified_file = image_spec_value (img->spec, QCfile, NULL);
10552 specified_data = image_spec_value (img->spec, QCdata, NULL);
10553 file = Qnil;
10554 GCPRO1 (file);
10555
6fc2811b
JR
10556 if (NILP (specified_data))
10557 {
10558 file = x_find_image_file (specified_file);
10559 if (!STRINGP (file))
10560 {
10561 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10562 UNGCPRO;
10563 return 0;
10564 }
10565
10566 fp = fopen (XSTRING (file)->data, "r");
10567 if (fp == NULL)
10568 {
10569 image_error ("Cannot open `%s'", file, Qnil);
10570 UNGCPRO;
10571 return 0;
10572 }
10573 }
10574
10575 /* Customize libjpeg's error handling to call my_error_exit when an
10576 error is detected. This function will perform a longjmp. */
10577 mgr.pub.error_exit = my_error_exit;
10578 cinfo.err = jpeg_std_error (&mgr.pub);
10579
10580 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10581 {
10582 if (rc == 1)
10583 {
10584 /* Called from my_error_exit. Display a JPEG error. */
10585 char buffer[JMSG_LENGTH_MAX];
10586 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10587 image_error ("Error reading JPEG image `%s': %s", img->spec,
10588 build_string (buffer));
10589 }
10590
10591 /* Close the input file and destroy the JPEG object. */
10592 if (fp)
10593 fclose (fp);
10594 jpeg_destroy_decompress (&cinfo);
10595
10596 BLOCK_INPUT;
10597
10598 /* If we already have an XImage, free that. */
10599 x_destroy_x_image (ximg);
10600
10601 /* Free pixmap and colors. */
10602 x_clear_image (f, img);
10603
10604 UNBLOCK_INPUT;
10605 UNGCPRO;
10606 return 0;
10607 }
10608
10609 /* Create the JPEG decompression object. Let it read from fp.
10610 Read the JPEG image header. */
10611 jpeg_create_decompress (&cinfo);
10612
10613 if (NILP (specified_data))
10614 jpeg_stdio_src (&cinfo, fp);
10615 else
10616 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
10617 STRING_BYTES (XSTRING (specified_data)));
10618
10619 jpeg_read_header (&cinfo, TRUE);
10620
10621 /* Customize decompression so that color quantization will be used.
10622 Start decompression. */
10623 cinfo.quantize_colors = TRUE;
10624 jpeg_start_decompress (&cinfo);
10625 width = img->width = cinfo.output_width;
10626 height = img->height = cinfo.output_height;
10627
10628 BLOCK_INPUT;
10629
10630 /* Create X image and pixmap. */
10631 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10632 &img->pixmap))
10633 {
10634 UNBLOCK_INPUT;
10635 longjmp (mgr.setjmp_buffer, 2);
10636 }
10637
10638 /* Allocate colors. When color quantization is used,
10639 cinfo.actual_number_of_colors has been set with the number of
10640 colors generated, and cinfo.colormap is a two-dimensional array
10641 of color indices in the range 0..cinfo.actual_number_of_colors.
10642 No more than 255 colors will be generated. */
10643 {
10644 int i, ir, ig, ib;
10645
10646 if (cinfo.out_color_components > 2)
10647 ir = 0, ig = 1, ib = 2;
10648 else if (cinfo.out_color_components > 1)
10649 ir = 0, ig = 1, ib = 0;
10650 else
10651 ir = 0, ig = 0, ib = 0;
10652
10653 /* Use the color table mechanism because it handles colors that
10654 cannot be allocated nicely. Such colors will be replaced with
10655 a default color, and we don't have to care about which colors
10656 can be freed safely, and which can't. */
10657 init_color_table ();
10658 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
10659 * sizeof *colors);
10660
10661 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
10662 {
10663 /* Multiply RGB values with 255 because X expects RGB values
10664 in the range 0..0xffff. */
10665 int r = cinfo.colormap[ir][i] << 8;
10666 int g = cinfo.colormap[ig][i] << 8;
10667 int b = cinfo.colormap[ib][i] << 8;
10668 colors[i] = lookup_rgb_color (f, r, g, b);
10669 }
10670
10671 /* Remember those colors actually allocated. */
10672 img->colors = colors_in_color_table (&img->ncolors);
10673 free_color_table ();
10674 }
10675
10676 /* Read pixels. */
10677 row_stride = width * cinfo.output_components;
10678 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
10679 row_stride, 1);
10680 for (y = 0; y < height; ++y)
10681 {
10682 jpeg_read_scanlines (&cinfo, buffer, 1);
10683 for (x = 0; x < cinfo.output_width; ++x)
10684 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
10685 }
10686
10687 /* Clean up. */
10688 jpeg_finish_decompress (&cinfo);
10689 jpeg_destroy_decompress (&cinfo);
10690 if (fp)
10691 fclose (fp);
10692
10693 /* Put the image into the pixmap. */
10694 x_put_x_image (f, ximg, img->pixmap, width, height);
10695 x_destroy_x_image (ximg);
10696 UNBLOCK_INPUT;
10697 UNGCPRO;
10698 return 1;
10699}
10700
10701#endif /* HAVE_JPEG */
10702
10703
10704\f
10705/***********************************************************************
10706 TIFF
10707 ***********************************************************************/
10708
10709#if HAVE_TIFF
10710
10711#include <tiffio.h>
10712
10713static int tiff_image_p P_ ((Lisp_Object object));
10714static int tiff_load P_ ((struct frame *f, struct image *img));
10715
10716/* The symbol `tiff' identifying images of this type. */
10717
10718Lisp_Object Qtiff;
10719
10720/* Indices of image specification fields in tiff_format, below. */
10721
10722enum tiff_keyword_index
10723{
10724 TIFF_TYPE,
10725 TIFF_DATA,
10726 TIFF_FILE,
10727 TIFF_ASCENT,
10728 TIFF_MARGIN,
10729 TIFF_RELIEF,
10730 TIFF_ALGORITHM,
10731 TIFF_HEURISTIC_MASK,
10732 TIFF_LAST
10733};
10734
10735/* Vector of image_keyword structures describing the format
10736 of valid user-defined image specifications. */
10737
10738static struct image_keyword tiff_format[TIFF_LAST] =
10739{
10740 {":type", IMAGE_SYMBOL_VALUE, 1},
10741 {":data", IMAGE_STRING_VALUE, 0},
10742 {":file", IMAGE_STRING_VALUE, 0},
10743 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10744 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10745 {":relief", IMAGE_INTEGER_VALUE, 0},
10746 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10747 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10748};
10749
10750/* Structure describing the image type `tiff'. */
10751
10752static struct image_type tiff_type =
10753{
10754 &Qtiff,
10755 tiff_image_p,
10756 tiff_load,
10757 x_clear_image,
10758 NULL
10759};
10760
10761
10762/* Return non-zero if OBJECT is a valid TIFF image specification. */
10763
10764static int
10765tiff_image_p (object)
10766 Lisp_Object object;
10767{
10768 struct image_keyword fmt[TIFF_LAST];
10769 bcopy (tiff_format, fmt, sizeof fmt);
10770
10771 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
10772 || (fmt[TIFF_ASCENT].count
10773 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
10774 return 0;
10775
10776 /* Must specify either the :data or :file keyword. */
10777 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
10778}
10779
10780
10781/* Reading from a memory buffer for TIFF images Based on the PNG
10782 memory source, but we have to provide a lot of extra functions.
10783 Blah.
10784
10785 We really only need to implement read and seek, but I am not
10786 convinced that the TIFF library is smart enough not to destroy
10787 itself if we only hand it the function pointers we need to
10788 override. */
10789
10790typedef struct
10791{
10792 unsigned char *bytes;
10793 size_t len;
10794 int index;
10795}
10796tiff_memory_source;
10797
10798static size_t
10799tiff_read_from_memory (data, buf, size)
10800 thandle_t data;
10801 tdata_t buf;
10802 tsize_t size;
10803{
10804 tiff_memory_source *src = (tiff_memory_source *) data;
10805
10806 if (size > src->len - src->index)
10807 return (size_t) -1;
10808 bcopy (src->bytes + src->index, buf, size);
10809 src->index += size;
10810 return size;
10811}
10812
10813static size_t
10814tiff_write_from_memory (data, buf, size)
10815 thandle_t data;
10816 tdata_t buf;
10817 tsize_t size;
10818{
10819 return (size_t) -1;
10820}
10821
10822static toff_t
10823tiff_seek_in_memory (data, off, whence)
10824 thandle_t data;
10825 toff_t off;
10826 int whence;
10827{
10828 tiff_memory_source *src = (tiff_memory_source *) data;
10829 int idx;
10830
10831 switch (whence)
10832 {
10833 case SEEK_SET: /* Go from beginning of source. */
10834 idx = off;
10835 break;
10836
10837 case SEEK_END: /* Go from end of source. */
10838 idx = src->len + off;
10839 break;
10840
10841 case SEEK_CUR: /* Go from current position. */
10842 idx = src->index + off;
10843 break;
10844
10845 default: /* Invalid `whence'. */
10846 return -1;
10847 }
10848
10849 if (idx > src->len || idx < 0)
10850 return -1;
10851
10852 src->index = idx;
10853 return src->index;
10854}
10855
10856static int
10857tiff_close_memory (data)
10858 thandle_t data;
10859{
10860 /* NOOP */
10861 return 0;
10862}
10863
10864static int
10865tiff_mmap_memory (data, pbase, psize)
10866 thandle_t data;
10867 tdata_t *pbase;
10868 toff_t *psize;
10869{
10870 /* It is already _IN_ memory. */
10871 return 0;
10872}
10873
10874static void
10875tiff_unmap_memory (data, base, size)
10876 thandle_t data;
10877 tdata_t base;
10878 toff_t size;
10879{
10880 /* We don't need to do this. */
10881}
10882
10883static toff_t
10884tiff_size_of_memory (data)
10885 thandle_t data;
10886{
10887 return ((tiff_memory_source *) data)->len;
10888}
10889
6fc2811b
JR
10890/* Load TIFF image IMG for use on frame F. Value is non-zero if
10891 successful. */
10892
10893static int
10894tiff_load (f, img)
10895 struct frame *f;
10896 struct image *img;
10897{
10898 Lisp_Object file, specified_file;
10899 Lisp_Object specified_data;
10900 TIFF *tiff;
10901 int width, height, x, y;
10902 uint32 *buf;
10903 int rc;
10904 XImage *ximg;
10905 struct gcpro gcpro1;
10906 tiff_memory_source memsrc;
10907
10908 specified_file = image_spec_value (img->spec, QCfile, NULL);
10909 specified_data = image_spec_value (img->spec, QCdata, NULL);
10910 file = Qnil;
10911 GCPRO1 (file);
10912
10913 if (NILP (specified_data))
10914 {
10915 /* Read from a file */
10916 file = x_find_image_file (specified_file);
10917 if (!STRINGP (file))
10918 {
10919 image_error ("Cannot find image file `%s'", file, Qnil);
10920 UNGCPRO;
10921 return 0;
10922 }
10923
10924 /* Try to open the image file. */
10925 tiff = TIFFOpen (XSTRING (file)->data, "r");
10926 if (tiff == NULL)
10927 {
10928 image_error ("Cannot open `%s'", file, Qnil);
10929 UNGCPRO;
10930 return 0;
10931 }
10932 }
10933 else
10934 {
10935 /* Memory source! */
10936 memsrc.bytes = XSTRING (specified_data)->data;
10937 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10938 memsrc.index = 0;
10939
10940 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
10941 (TIFFReadWriteProc) tiff_read_from_memory,
10942 (TIFFReadWriteProc) tiff_write_from_memory,
10943 tiff_seek_in_memory,
10944 tiff_close_memory,
10945 tiff_size_of_memory,
10946 tiff_mmap_memory,
10947 tiff_unmap_memory);
10948
10949 if (!tiff)
10950 {
10951 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
10952 UNGCPRO;
10953 return 0;
10954 }
10955 }
10956
10957 /* Get width and height of the image, and allocate a raster buffer
10958 of width x height 32-bit values. */
10959 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
10960 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
10961 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
10962
10963 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
10964 TIFFClose (tiff);
10965 if (!rc)
10966 {
10967 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
10968 xfree (buf);
10969 UNGCPRO;
10970 return 0;
10971 }
10972
10973 BLOCK_INPUT;
10974
10975 /* Create the X image and pixmap. */
10976 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
10977 {
10978 UNBLOCK_INPUT;
10979 xfree (buf);
10980 UNGCPRO;
10981 return 0;
10982 }
10983
10984 /* Initialize the color table. */
10985 init_color_table ();
10986
10987 /* Process the pixel raster. Origin is in the lower-left corner. */
10988 for (y = 0; y < height; ++y)
10989 {
10990 uint32 *row = buf + y * width;
10991
10992 for (x = 0; x < width; ++x)
10993 {
10994 uint32 abgr = row[x];
10995 int r = TIFFGetR (abgr) << 8;
10996 int g = TIFFGetG (abgr) << 8;
10997 int b = TIFFGetB (abgr) << 8;
10998 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
10999 }
11000 }
11001
11002 /* Remember the colors allocated for the image. Free the color table. */
11003 img->colors = colors_in_color_table (&img->ncolors);
11004 free_color_table ();
11005
11006 /* Put the image into the pixmap, then free the X image and its buffer. */
11007 x_put_x_image (f, ximg, img->pixmap, width, height);
11008 x_destroy_x_image (ximg);
11009 xfree (buf);
11010 UNBLOCK_INPUT;
11011
11012 img->width = width;
11013 img->height = height;
11014
11015 UNGCPRO;
11016 return 1;
11017}
11018
11019#endif /* HAVE_TIFF != 0 */
11020
11021
11022\f
11023/***********************************************************************
11024 GIF
11025 ***********************************************************************/
11026
11027#if HAVE_GIF
11028
11029#include <gif_lib.h>
11030
11031static int gif_image_p P_ ((Lisp_Object object));
11032static int gif_load P_ ((struct frame *f, struct image *img));
11033
11034/* The symbol `gif' identifying images of this type. */
11035
11036Lisp_Object Qgif;
11037
11038/* Indices of image specification fields in gif_format, below. */
11039
11040enum gif_keyword_index
11041{
11042 GIF_TYPE,
11043 GIF_DATA,
11044 GIF_FILE,
11045 GIF_ASCENT,
11046 GIF_MARGIN,
11047 GIF_RELIEF,
11048 GIF_ALGORITHM,
11049 GIF_HEURISTIC_MASK,
11050 GIF_IMAGE,
11051 GIF_LAST
11052};
11053
11054/* Vector of image_keyword structures describing the format
11055 of valid user-defined image specifications. */
11056
11057static struct image_keyword gif_format[GIF_LAST] =
11058{
11059 {":type", IMAGE_SYMBOL_VALUE, 1},
11060 {":data", IMAGE_STRING_VALUE, 0},
11061 {":file", IMAGE_STRING_VALUE, 0},
11062 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11063 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11064 {":relief", IMAGE_INTEGER_VALUE, 0},
11065 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11066 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11067 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11068};
11069
11070/* Structure describing the image type `gif'. */
11071
11072static struct image_type gif_type =
11073{
11074 &Qgif,
11075 gif_image_p,
11076 gif_load,
11077 x_clear_image,
11078 NULL
11079};
11080
11081/* Return non-zero if OBJECT is a valid GIF image specification. */
11082
11083static int
11084gif_image_p (object)
11085 Lisp_Object object;
11086{
11087 struct image_keyword fmt[GIF_LAST];
11088 bcopy (gif_format, fmt, sizeof fmt);
11089
11090 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11091 || (fmt[GIF_ASCENT].count
11092 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11093 return 0;
11094
11095 /* Must specify either the :data or :file keyword. */
11096 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11097}
11098
11099/* Reading a GIF image from memory
11100 Based on the PNG memory stuff to a certain extent. */
11101
11102typedef struct
11103{
11104 unsigned char *bytes;
11105 size_t len;
11106 int index;
11107}
11108gif_memory_source;
11109
11110/* Make the current memory source available to gif_read_from_memory.
11111 It's done this way because not all versions of libungif support
11112 a UserData field in the GifFileType structure. */
11113static gif_memory_source *current_gif_memory_src;
11114
11115static int
11116gif_read_from_memory (file, buf, len)
11117 GifFileType *file;
11118 GifByteType *buf;
11119 int len;
11120{
11121 gif_memory_source *src = current_gif_memory_src;
11122
11123 if (len > src->len - src->index)
11124 return -1;
11125
11126 bcopy (src->bytes + src->index, buf, len);
11127 src->index += len;
11128 return len;
11129}
11130
11131
11132/* Load GIF image IMG for use on frame F. Value is non-zero if
11133 successful. */
11134
11135static int
11136gif_load (f, img)
11137 struct frame *f;
11138 struct image *img;
11139{
11140 Lisp_Object file, specified_file;
11141 Lisp_Object specified_data;
11142 int rc, width, height, x, y, i;
11143 XImage *ximg;
11144 ColorMapObject *gif_color_map;
11145 unsigned long pixel_colors[256];
11146 GifFileType *gif;
11147 struct gcpro gcpro1;
11148 Lisp_Object image;
11149 int ino, image_left, image_top, image_width, image_height;
11150 gif_memory_source memsrc;
11151 unsigned char *raster;
11152
11153 specified_file = image_spec_value (img->spec, QCfile, NULL);
11154 specified_data = image_spec_value (img->spec, QCdata, NULL);
11155 file = Qnil;
dfff8a69 11156 GCPRO1 (file);
6fc2811b
JR
11157
11158 if (NILP (specified_data))
11159 {
11160 file = x_find_image_file (specified_file);
6fc2811b
JR
11161 if (!STRINGP (file))
11162 {
11163 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11164 UNGCPRO;
11165 return 0;
11166 }
11167
11168 /* Open the GIF file. */
11169 gif = DGifOpenFileName (XSTRING (file)->data);
11170 if (gif == NULL)
11171 {
11172 image_error ("Cannot open `%s'", file, Qnil);
11173 UNGCPRO;
11174 return 0;
11175 }
11176 }
11177 else
11178 {
11179 /* Read from memory! */
11180 current_gif_memory_src = &memsrc;
11181 memsrc.bytes = XSTRING (specified_data)->data;
11182 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11183 memsrc.index = 0;
11184
11185 gif = DGifOpen(&memsrc, gif_read_from_memory);
11186 if (!gif)
11187 {
11188 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11189 UNGCPRO;
11190 return 0;
11191 }
11192 }
11193
11194 /* Read entire contents. */
11195 rc = DGifSlurp (gif);
11196 if (rc == GIF_ERROR)
11197 {
11198 image_error ("Error reading `%s'", img->spec, Qnil);
11199 DGifCloseFile (gif);
11200 UNGCPRO;
11201 return 0;
11202 }
11203
11204 image = image_spec_value (img->spec, QCindex, NULL);
11205 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11206 if (ino >= gif->ImageCount)
11207 {
11208 image_error ("Invalid image number `%s' in image `%s'",
11209 image, img->spec);
11210 DGifCloseFile (gif);
11211 UNGCPRO;
11212 return 0;
11213 }
11214
11215 width = img->width = gif->SWidth;
11216 height = img->height = gif->SHeight;
11217
11218 BLOCK_INPUT;
11219
11220 /* Create the X image and pixmap. */
11221 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11222 {
11223 UNBLOCK_INPUT;
11224 DGifCloseFile (gif);
11225 UNGCPRO;
11226 return 0;
11227 }
11228
11229 /* Allocate colors. */
11230 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11231 if (!gif_color_map)
11232 gif_color_map = gif->SColorMap;
11233 init_color_table ();
11234 bzero (pixel_colors, sizeof pixel_colors);
11235
11236 for (i = 0; i < gif_color_map->ColorCount; ++i)
11237 {
11238 int r = gif_color_map->Colors[i].Red << 8;
11239 int g = gif_color_map->Colors[i].Green << 8;
11240 int b = gif_color_map->Colors[i].Blue << 8;
11241 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11242 }
11243
11244 img->colors = colors_in_color_table (&img->ncolors);
11245 free_color_table ();
11246
11247 /* Clear the part of the screen image that are not covered by
11248 the image from the GIF file. Full animated GIF support
11249 requires more than can be done here (see the gif89 spec,
11250 disposal methods). Let's simply assume that the part
11251 not covered by a sub-image is in the frame's background color. */
11252 image_top = gif->SavedImages[ino].ImageDesc.Top;
11253 image_left = gif->SavedImages[ino].ImageDesc.Left;
11254 image_width = gif->SavedImages[ino].ImageDesc.Width;
11255 image_height = gif->SavedImages[ino].ImageDesc.Height;
11256
11257 for (y = 0; y < image_top; ++y)
11258 for (x = 0; x < width; ++x)
11259 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11260
11261 for (y = image_top + image_height; y < height; ++y)
11262 for (x = 0; x < width; ++x)
11263 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11264
11265 for (y = image_top; y < image_top + image_height; ++y)
11266 {
11267 for (x = 0; x < image_left; ++x)
11268 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11269 for (x = image_left + image_width; x < width; ++x)
11270 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11271 }
11272
11273 /* Read the GIF image into the X image. We use a local variable
11274 `raster' here because RasterBits below is a char *, and invites
11275 problems with bytes >= 0x80. */
11276 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11277
11278 if (gif->SavedImages[ino].ImageDesc.Interlace)
11279 {
11280 static int interlace_start[] = {0, 4, 2, 1};
11281 static int interlace_increment[] = {8, 8, 4, 2};
11282 int pass, inc;
11283 int row = interlace_start[0];
11284
11285 pass = 0;
11286
11287 for (y = 0; y < image_height; y++)
11288 {
11289 if (row >= image_height)
11290 {
11291 row = interlace_start[++pass];
11292 while (row >= image_height)
11293 row = interlace_start[++pass];
11294 }
11295
11296 for (x = 0; x < image_width; x++)
11297 {
11298 int i = raster[(y * image_width) + x];
11299 XPutPixel (ximg, x + image_left, row + image_top,
11300 pixel_colors[i]);
11301 }
11302
11303 row += interlace_increment[pass];
11304 }
11305 }
11306 else
11307 {
11308 for (y = 0; y < image_height; ++y)
11309 for (x = 0; x < image_width; ++x)
11310 {
11311 int i = raster[y* image_width + x];
11312 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11313 }
11314 }
11315
11316 DGifCloseFile (gif);
11317
11318 /* Put the image into the pixmap, then free the X image and its buffer. */
11319 x_put_x_image (f, ximg, img->pixmap, width, height);
11320 x_destroy_x_image (ximg);
11321 UNBLOCK_INPUT;
11322
11323 UNGCPRO;
11324 return 1;
11325}
11326
11327#endif /* HAVE_GIF != 0 */
11328
11329
11330\f
11331/***********************************************************************
11332 Ghostscript
11333 ***********************************************************************/
11334
11335#ifdef HAVE_GHOSTSCRIPT
11336static int gs_image_p P_ ((Lisp_Object object));
11337static int gs_load P_ ((struct frame *f, struct image *img));
11338static void gs_clear_image P_ ((struct frame *f, struct image *img));
11339
11340/* The symbol `postscript' identifying images of this type. */
11341
11342Lisp_Object Qpostscript;
11343
11344/* Keyword symbols. */
11345
11346Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11347
11348/* Indices of image specification fields in gs_format, below. */
11349
11350enum gs_keyword_index
11351{
11352 GS_TYPE,
11353 GS_PT_WIDTH,
11354 GS_PT_HEIGHT,
11355 GS_FILE,
11356 GS_LOADER,
11357 GS_BOUNDING_BOX,
11358 GS_ASCENT,
11359 GS_MARGIN,
11360 GS_RELIEF,
11361 GS_ALGORITHM,
11362 GS_HEURISTIC_MASK,
11363 GS_LAST
11364};
11365
11366/* Vector of image_keyword structures describing the format
11367 of valid user-defined image specifications. */
11368
11369static struct image_keyword gs_format[GS_LAST] =
11370{
11371 {":type", IMAGE_SYMBOL_VALUE, 1},
11372 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11373 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11374 {":file", IMAGE_STRING_VALUE, 1},
11375 {":loader", IMAGE_FUNCTION_VALUE, 0},
11376 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11377 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11378 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11379 {":relief", IMAGE_INTEGER_VALUE, 0},
11380 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11381 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11382};
11383
11384/* Structure describing the image type `ghostscript'. */
11385
11386static struct image_type gs_type =
11387{
11388 &Qpostscript,
11389 gs_image_p,
11390 gs_load,
11391 gs_clear_image,
11392 NULL
11393};
11394
11395
11396/* Free X resources of Ghostscript image IMG which is used on frame F. */
11397
11398static void
11399gs_clear_image (f, img)
11400 struct frame *f;
11401 struct image *img;
11402{
11403 /* IMG->data.ptr_val may contain a recorded colormap. */
11404 xfree (img->data.ptr_val);
11405 x_clear_image (f, img);
11406}
11407
11408
11409/* Return non-zero if OBJECT is a valid Ghostscript image
11410 specification. */
11411
11412static int
11413gs_image_p (object)
11414 Lisp_Object object;
11415{
11416 struct image_keyword fmt[GS_LAST];
11417 Lisp_Object tem;
11418 int i;
11419
11420 bcopy (gs_format, fmt, sizeof fmt);
11421
11422 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11423 || (fmt[GS_ASCENT].count
11424 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11425 return 0;
11426
11427 /* Bounding box must be a list or vector containing 4 integers. */
11428 tem = fmt[GS_BOUNDING_BOX].value;
11429 if (CONSP (tem))
11430 {
11431 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11432 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11433 return 0;
11434 if (!NILP (tem))
11435 return 0;
11436 }
11437 else if (VECTORP (tem))
11438 {
11439 if (XVECTOR (tem)->size != 4)
11440 return 0;
11441 for (i = 0; i < 4; ++i)
11442 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11443 return 0;
11444 }
11445 else
11446 return 0;
11447
11448 return 1;
11449}
11450
11451
11452/* Load Ghostscript image IMG for use on frame F. Value is non-zero
11453 if successful. */
11454
11455static int
11456gs_load (f, img)
11457 struct frame *f;
11458 struct image *img;
11459{
11460 char buffer[100];
11461 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11462 struct gcpro gcpro1, gcpro2;
11463 Lisp_Object frame;
11464 double in_width, in_height;
11465 Lisp_Object pixel_colors = Qnil;
11466
11467 /* Compute pixel size of pixmap needed from the given size in the
11468 image specification. Sizes in the specification are in pt. 1 pt
11469 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11470 info. */
11471 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11472 in_width = XFASTINT (pt_width) / 72.0;
11473 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11474 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11475 in_height = XFASTINT (pt_height) / 72.0;
11476 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11477
11478 /* Create the pixmap. */
11479 BLOCK_INPUT;
11480 xassert (img->pixmap == 0);
11481 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11482 img->width, img->height,
11483 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11484 UNBLOCK_INPUT;
11485
11486 if (!img->pixmap)
11487 {
11488 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11489 return 0;
11490 }
11491
11492 /* Call the loader to fill the pixmap. It returns a process object
11493 if successful. We do not record_unwind_protect here because
11494 other places in redisplay like calling window scroll functions
11495 don't either. Let the Lisp loader use `unwind-protect' instead. */
11496 GCPRO2 (window_and_pixmap_id, pixel_colors);
11497
11498 sprintf (buffer, "%lu %lu",
11499 (unsigned long) FRAME_W32_WINDOW (f),
11500 (unsigned long) img->pixmap);
11501 window_and_pixmap_id = build_string (buffer);
11502
11503 sprintf (buffer, "%lu %lu",
11504 FRAME_FOREGROUND_PIXEL (f),
11505 FRAME_BACKGROUND_PIXEL (f));
11506 pixel_colors = build_string (buffer);
11507
11508 XSETFRAME (frame, f);
11509 loader = image_spec_value (img->spec, QCloader, NULL);
11510 if (NILP (loader))
11511 loader = intern ("gs-load-image");
11512
11513 img->data.lisp_val = call6 (loader, frame, img->spec,
11514 make_number (img->width),
11515 make_number (img->height),
11516 window_and_pixmap_id,
11517 pixel_colors);
11518 UNGCPRO;
11519 return PROCESSP (img->data.lisp_val);
11520}
11521
11522
11523/* Kill the Ghostscript process that was started to fill PIXMAP on
11524 frame F. Called from XTread_socket when receiving an event
11525 telling Emacs that Ghostscript has finished drawing. */
11526
11527void
11528x_kill_gs_process (pixmap, f)
11529 Pixmap pixmap;
11530 struct frame *f;
11531{
11532 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11533 int class, i;
11534 struct image *img;
11535
11536 /* Find the image containing PIXMAP. */
11537 for (i = 0; i < c->used; ++i)
11538 if (c->images[i]->pixmap == pixmap)
11539 break;
11540
11541 /* Kill the GS process. We should have found PIXMAP in the image
11542 cache and its image should contain a process object. */
11543 xassert (i < c->used);
11544 img = c->images[i];
11545 xassert (PROCESSP (img->data.lisp_val));
11546 Fkill_process (img->data.lisp_val, Qnil);
11547 img->data.lisp_val = Qnil;
11548
11549 /* On displays with a mutable colormap, figure out the colors
11550 allocated for the image by looking at the pixels of an XImage for
11551 img->pixmap. */
11552 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11553 if (class != StaticColor && class != StaticGray && class != TrueColor)
11554 {
11555 XImage *ximg;
11556
11557 BLOCK_INPUT;
11558
11559 /* Try to get an XImage for img->pixmep. */
11560 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11561 0, 0, img->width, img->height, ~0, ZPixmap);
11562 if (ximg)
11563 {
11564 int x, y;
11565
11566 /* Initialize the color table. */
11567 init_color_table ();
11568
11569 /* For each pixel of the image, look its color up in the
11570 color table. After having done so, the color table will
11571 contain an entry for each color used by the image. */
11572 for (y = 0; y < img->height; ++y)
11573 for (x = 0; x < img->width; ++x)
11574 {
11575 unsigned long pixel = XGetPixel (ximg, x, y);
11576 lookup_pixel_color (f, pixel);
11577 }
11578
11579 /* Record colors in the image. Free color table and XImage. */
11580 img->colors = colors_in_color_table (&img->ncolors);
11581 free_color_table ();
11582 XDestroyImage (ximg);
11583
11584#if 0 /* This doesn't seem to be the case. If we free the colors
11585 here, we get a BadAccess later in x_clear_image when
11586 freeing the colors. */
11587 /* We have allocated colors once, but Ghostscript has also
11588 allocated colors on behalf of us. So, to get the
11589 reference counts right, free them once. */
11590 if (img->ncolors)
11591 {
11592 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11593 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11594 img->colors, img->ncolors, 0);
11595 }
11596#endif
11597 }
11598 else
11599 image_error ("Cannot get X image of `%s'; colors will not be freed",
11600 img->spec, Qnil);
11601
11602 UNBLOCK_INPUT;
11603 }
11604}
11605
11606#endif /* HAVE_GHOSTSCRIPT */
11607
11608\f
11609/***********************************************************************
11610 Window properties
11611 ***********************************************************************/
11612
11613DEFUN ("x-change-window-property", Fx_change_window_property,
11614 Sx_change_window_property, 2, 3, 0,
11615 "Change window property PROP to VALUE on the X window of FRAME.\n\
11616PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
11617selected frame. Value is VALUE.")
11618 (prop, value, frame)
11619 Lisp_Object frame, prop, value;
11620{
11621#if 0 /* NTEMACS_TODO : port window properties to W32 */
11622 struct frame *f = check_x_frame (frame);
11623 Atom prop_atom;
11624
11625 CHECK_STRING (prop, 1);
11626 CHECK_STRING (value, 2);
11627
11628 BLOCK_INPUT;
11629 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11630 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11631 prop_atom, XA_STRING, 8, PropModeReplace,
11632 XSTRING (value)->data, XSTRING (value)->size);
11633
11634 /* Make sure the property is set when we return. */
11635 XFlush (FRAME_W32_DISPLAY (f));
11636 UNBLOCK_INPUT;
11637
11638#endif /* NTEMACS_TODO */
11639
11640 return value;
11641}
11642
11643
11644DEFUN ("x-delete-window-property", Fx_delete_window_property,
11645 Sx_delete_window_property, 1, 2, 0,
11646 "Remove window property PROP from X window of FRAME.\n\
11647FRAME nil or omitted means use the selected frame. Value is PROP.")
11648 (prop, frame)
11649 Lisp_Object prop, frame;
11650{
11651#if 0 /* NTEMACS_TODO : port window properties to W32 */
11652
11653 struct frame *f = check_x_frame (frame);
11654 Atom prop_atom;
11655
11656 CHECK_STRING (prop, 1);
11657 BLOCK_INPUT;
11658 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11659 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
11660
11661 /* Make sure the property is removed when we return. */
11662 XFlush (FRAME_W32_DISPLAY (f));
11663 UNBLOCK_INPUT;
11664#endif /* NTEMACS_TODO */
11665
11666 return prop;
11667}
11668
11669
11670DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
11671 1, 2, 0,
11672 "Value is the value of window property PROP on FRAME.\n\
11673If FRAME is nil or omitted, use the selected frame. Value is nil\n\
11674if FRAME hasn't a property with name PROP or if PROP has no string\n\
11675value.")
11676 (prop, frame)
11677 Lisp_Object prop, frame;
11678{
11679#if 0 /* NTEMACS_TODO : port window properties to W32 */
11680
11681 struct frame *f = check_x_frame (frame);
11682 Atom prop_atom;
11683 int rc;
11684 Lisp_Object prop_value = Qnil;
11685 char *tmp_data = NULL;
11686 Atom actual_type;
11687 int actual_format;
11688 unsigned long actual_size, bytes_remaining;
11689
11690 CHECK_STRING (prop, 1);
11691 BLOCK_INPUT;
11692 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11693 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11694 prop_atom, 0, 0, False, XA_STRING,
11695 &actual_type, &actual_format, &actual_size,
11696 &bytes_remaining, (unsigned char **) &tmp_data);
11697 if (rc == Success)
11698 {
11699 int size = bytes_remaining;
11700
11701 XFree (tmp_data);
11702 tmp_data = NULL;
11703
11704 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11705 prop_atom, 0, bytes_remaining,
11706 False, XA_STRING,
11707 &actual_type, &actual_format,
11708 &actual_size, &bytes_remaining,
11709 (unsigned char **) &tmp_data);
11710 if (rc == Success)
11711 prop_value = make_string (tmp_data, size);
11712
11713 XFree (tmp_data);
11714 }
11715
11716 UNBLOCK_INPUT;
11717
11718 return prop_value;
11719
11720#endif /* NTEMACS_TODO */
11721 return Qnil;
11722}
11723
11724
11725\f
11726/***********************************************************************
11727 Busy cursor
11728 ***********************************************************************/
11729
f79e6790
JR
11730/* If non-null, an asynchronous timer that, when it expires, displays
11731 a busy cursor on all frames. */
6fc2811b 11732
f79e6790 11733static struct atimer *busy_cursor_atimer;
6fc2811b 11734
f79e6790 11735/* Non-zero means a busy cursor is currently shown. */
6fc2811b 11736
f79e6790 11737static int busy_cursor_shown_p;
6fc2811b 11738
f79e6790 11739/* Number of seconds to wait before displaying a busy cursor. */
6fc2811b 11740
f79e6790 11741static Lisp_Object Vbusy_cursor_delay;
6fc2811b 11742
f79e6790
JR
11743/* Default number of seconds to wait before displaying a busy
11744 cursor. */
11745
11746#define DEFAULT_BUSY_CURSOR_DELAY 1
11747
11748/* Function prototypes. */
11749
11750static void show_busy_cursor P_ ((struct atimer *));
11751static void hide_busy_cursor P_ ((void));
11752
11753
11754/* Cancel a currently active busy-cursor timer, and start a new one. */
11755
11756void
11757start_busy_cursor ()
11758{
11759#if 0 /* NTEMACS_TODO: cursor shape changes. */
11760 EMACS_TIME delay;
dfff8a69 11761 int secs, usecs = 0;
f79e6790
JR
11762
11763 cancel_busy_cursor ();
11764
11765 if (INTEGERP (Vbusy_cursor_delay)
11766 && XINT (Vbusy_cursor_delay) > 0)
11767 secs = XFASTINT (Vbusy_cursor_delay);
dfff8a69
JR
11768 else if (FLOATP (Vbusy_cursor_delay)
11769 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
11770 {
11771 Lisp_Object tem;
11772 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
11773 secs = XFASTINT (tem);
11774 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
11775 }
f79e6790
JR
11776 else
11777 secs = DEFAULT_BUSY_CURSOR_DELAY;
11778
dfff8a69 11779 EMACS_SET_SECS_USECS (delay, secs, usecs);
f79e6790
JR
11780 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
11781 show_busy_cursor, NULL);
11782#endif
11783}
11784
11785
11786/* Cancel the busy cursor timer if active, hide a busy cursor if
11787 shown. */
11788
11789void
11790cancel_busy_cursor ()
11791{
11792 if (busy_cursor_atimer)
dfff8a69
JR
11793 {
11794 cancel_atimer (busy_cursor_atimer);
11795 busy_cursor_atimer = NULL;
11796 }
11797
f79e6790
JR
11798 if (busy_cursor_shown_p)
11799 hide_busy_cursor ();
11800}
11801
11802
11803/* Timer function of busy_cursor_atimer. TIMER is equal to
11804 busy_cursor_atimer.
11805
11806 Display a busy cursor on all frames by mapping the frames'
11807 busy_window. Set the busy_p flag in the frames' output_data.x
11808 structure to indicate that a busy cursor is shown on the
11809 frames. */
11810
11811static void
11812show_busy_cursor (timer)
11813 struct atimer *timer;
6fc2811b 11814{
f79e6790
JR
11815#if 0 /* NTEMACS_TODO: cursor shape changes. */
11816 /* The timer implementation will cancel this timer automatically
11817 after this function has run. Set busy_cursor_atimer to null
11818 so that we know the timer doesn't have to be canceled. */
11819 busy_cursor_atimer = NULL;
11820
11821 if (!busy_cursor_shown_p)
6fc2811b
JR
11822 {
11823 Lisp_Object rest, frame;
f79e6790
JR
11824
11825 BLOCK_INPUT;
11826
6fc2811b
JR
11827 FOR_EACH_FRAME (rest, frame)
11828 if (FRAME_X_P (XFRAME (frame)))
11829 {
11830 struct frame *f = XFRAME (frame);
f79e6790 11831
6fc2811b 11832 f->output_data.w32->busy_p = 1;
f79e6790 11833
6fc2811b
JR
11834 if (!f->output_data.w32->busy_window)
11835 {
11836 unsigned long mask = CWCursor;
11837 XSetWindowAttributes attrs;
f79e6790 11838
6fc2811b 11839 attrs.cursor = f->output_data.w32->busy_cursor;
f79e6790 11840
6fc2811b 11841 f->output_data.w32->busy_window
f79e6790 11842 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
11843 FRAME_OUTER_WINDOW (f),
11844 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
11845 InputOnly,
11846 CopyFromParent,
6fc2811b
JR
11847 mask, &attrs);
11848 }
f79e6790
JR
11849
11850 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
11851 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 11852 }
6fc2811b 11853
f79e6790
JR
11854 busy_cursor_shown_p = 1;
11855 UNBLOCK_INPUT;
11856 }
11857#endif
6fc2811b
JR
11858}
11859
11860
f79e6790 11861/* Hide the busy cursor on all frames, if it is currently shown. */
6fc2811b 11862
f79e6790
JR
11863static void
11864hide_busy_cursor ()
11865{
11866#if 0 /* NTEMACS_TODO: cursor shape changes. */
11867 if (busy_cursor_shown_p)
6fc2811b 11868 {
f79e6790
JR
11869 Lisp_Object rest, frame;
11870
11871 BLOCK_INPUT;
11872 FOR_EACH_FRAME (rest, frame)
6fc2811b 11873 {
f79e6790
JR
11874 struct frame *f = XFRAME (frame);
11875
11876 if (FRAME_X_P (f)
11877 /* Watch out for newly created frames. */
11878 && f->output_data.x->busy_window)
11879 {
11880 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
11881 /* Sync here because XTread_socket looks at the busy_p flag
11882 that is reset to zero below. */
11883 XSync (FRAME_X_DISPLAY (f), False);
11884 f->output_data.x->busy_p = 0;
11885 }
6fc2811b 11886 }
6fc2811b 11887
f79e6790
JR
11888 busy_cursor_shown_p = 0;
11889 UNBLOCK_INPUT;
11890 }
11891#endif
6fc2811b
JR
11892}
11893
11894
11895\f
11896/***********************************************************************
11897 Tool tips
11898 ***********************************************************************/
11899
11900static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
11901 Lisp_Object));
11902
11903/* The frame of a currently visible tooltip, or null. */
11904
11905struct frame *tip_frame;
11906
11907/* If non-nil, a timer started that hides the last tooltip when it
11908 fires. */
11909
11910Lisp_Object tip_timer;
11911Window tip_window;
11912
11913/* Create a frame for a tooltip on the display described by DPYINFO.
11914 PARMS is a list of frame parameters. Value is the frame. */
11915
11916static Lisp_Object
11917x_create_tip_frame (dpyinfo, parms)
11918 struct w32_display_info *dpyinfo;
11919 Lisp_Object parms;
11920{
11921#if 0 /* NTEMACS_TODO : w32 version */
11922 struct frame *f;
11923 Lisp_Object frame, tem;
11924 Lisp_Object name;
11925 long window_prompting = 0;
11926 int width, height;
11927 int count = specpdl_ptr - specpdl;
11928 struct gcpro gcpro1, gcpro2, gcpro3;
11929 struct kboard *kb;
11930
11931 check_x ();
11932
11933 /* Use this general default value to start with until we know if
11934 this frame has a specified name. */
11935 Vx_resource_name = Vinvocation_name;
11936
11937#ifdef MULTI_KBOARD
11938 kb = dpyinfo->kboard;
11939#else
11940 kb = &the_only_kboard;
11941#endif
11942
11943 /* Get the name of the frame to use for resource lookup. */
11944 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
11945 if (!STRINGP (name)
11946 && !EQ (name, Qunbound)
11947 && !NILP (name))
11948 error ("Invalid frame name--not a string or nil");
11949 Vx_resource_name = name;
11950
11951 frame = Qnil;
11952 GCPRO3 (parms, name, frame);
11953 tip_frame = f = make_frame (1);
11954 XSETFRAME (frame, f);
11955 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
11956
d88c567c 11957 f->output_method = output_w32;
6fc2811b
JR
11958 f->output_data.w32 =
11959 (struct w32_output *) xmalloc (sizeof (struct w32_output));
11960 bzero (f->output_data.w32, sizeof (struct w32_output));
11961#if 0
11962 f->output_data.w32->icon_bitmap = -1;
11963#endif
11964 f->output_data.w32->fontset = -1;
11965 f->icon_name = Qnil;
11966
11967#ifdef MULTI_KBOARD
11968 FRAME_KBOARD (f) = kb;
11969#endif
11970 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
11971 f->output_data.w32->explicit_parent = 0;
11972
11973 /* Set the name; the functions to which we pass f expect the name to
11974 be set. */
11975 if (EQ (name, Qunbound) || NILP (name))
11976 {
11977 f->name = build_string (dpyinfo->x_id_name);
11978 f->explicit_name = 0;
11979 }
11980 else
11981 {
11982 f->name = name;
11983 f->explicit_name = 1;
11984 /* use the frame's title when getting resources for this frame. */
11985 specbind (Qx_resource_name, name);
11986 }
11987
6fc2811b
JR
11988 /* Extract the window parameters from the supplied values
11989 that are needed to determine window geometry. */
11990 {
11991 Lisp_Object font;
11992
11993 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
11994
11995 BLOCK_INPUT;
11996 /* First, try whatever font the caller has specified. */
11997 if (STRINGP (font))
11998 {
11999 tem = Fquery_fontset (font, Qnil);
12000 if (STRINGP (tem))
12001 font = x_new_fontset (f, XSTRING (tem)->data);
12002 else
12003 font = x_new_font (f, XSTRING (font)->data);
12004 }
12005
12006 /* Try out a font which we hope has bold and italic variations. */
12007 if (!STRINGP (font))
12008 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
12009 if (!STRINGP (font))
12010 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12011 if (! STRINGP (font))
12012 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12013 if (! STRINGP (font))
12014 /* This was formerly the first thing tried, but it finds too many fonts
12015 and takes too long. */
12016 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12017 /* If those didn't work, look for something which will at least work. */
12018 if (! STRINGP (font))
12019 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12020 UNBLOCK_INPUT;
12021 if (! STRINGP (font))
12022 font = build_string ("fixed");
12023
12024 x_default_parameter (f, parms, Qfont, font,
12025 "font", "Font", RES_TYPE_STRING);
12026 }
12027
12028 x_default_parameter (f, parms, Qborder_width, make_number (2),
12029 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12030
12031 /* This defaults to 2 in order to match xterm. We recognize either
12032 internalBorderWidth or internalBorder (which is what xterm calls
12033 it). */
12034 if (NILP (Fassq (Qinternal_border_width, parms)))
12035 {
12036 Lisp_Object value;
12037
12038 value = w32_get_arg (parms, Qinternal_border_width,
12039 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12040 if (! EQ (value, Qunbound))
12041 parms = Fcons (Fcons (Qinternal_border_width, value),
12042 parms);
12043 }
12044
12045 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12046 "internalBorderWidth", "internalBorderWidth",
12047 RES_TYPE_NUMBER);
12048
12049 /* Also do the stuff which must be set before the window exists. */
12050 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12051 "foreground", "Foreground", RES_TYPE_STRING);
12052 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12053 "background", "Background", RES_TYPE_STRING);
12054 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12055 "pointerColor", "Foreground", RES_TYPE_STRING);
12056 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12057 "cursorColor", "Foreground", RES_TYPE_STRING);
12058 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12059 "borderColor", "BorderColor", RES_TYPE_STRING);
12060
12061 /* Init faces before x_default_parameter is called for scroll-bar
12062 parameters because that function calls x_set_scroll_bar_width,
12063 which calls change_frame_size, which calls Fset_window_buffer,
12064 which runs hooks, which call Fvertical_motion. At the end, we
12065 end up in init_iterator with a null face cache, which should not
12066 happen. */
12067 init_frame_faces (f);
12068
12069 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12070 window_prompting = x_figure_window_size (f, parms);
12071
12072 if (window_prompting & XNegative)
12073 {
12074 if (window_prompting & YNegative)
12075 f->output_data.w32->win_gravity = SouthEastGravity;
12076 else
12077 f->output_data.w32->win_gravity = NorthEastGravity;
12078 }
12079 else
12080 {
12081 if (window_prompting & YNegative)
12082 f->output_data.w32->win_gravity = SouthWestGravity;
12083 else
12084 f->output_data.w32->win_gravity = NorthWestGravity;
12085 }
12086
12087 f->output_data.w32->size_hint_flags = window_prompting;
12088 {
12089 XSetWindowAttributes attrs;
12090 unsigned long mask;
12091
12092 BLOCK_INPUT;
12093 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12094 /* Window managers looks at the override-redirect flag to
12095 determine whether or net to give windows a decoration (Xlib
12096 3.2.8). */
12097 attrs.override_redirect = True;
12098 attrs.save_under = True;
12099 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12100 /* Arrange for getting MapNotify and UnmapNotify events. */
12101 attrs.event_mask = StructureNotifyMask;
12102 tip_window
12103 = FRAME_W32_WINDOW (f)
12104 = XCreateWindow (FRAME_W32_DISPLAY (f),
12105 FRAME_W32_DISPLAY_INFO (f)->root_window,
12106 /* x, y, width, height */
12107 0, 0, 1, 1,
12108 /* Border. */
12109 1,
12110 CopyFromParent, InputOutput, CopyFromParent,
12111 mask, &attrs);
12112 UNBLOCK_INPUT;
12113 }
12114
12115 x_make_gc (f);
12116
12117 x_default_parameter (f, parms, Qauto_raise, Qnil,
12118 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12119 x_default_parameter (f, parms, Qauto_lower, Qnil,
12120 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12121 x_default_parameter (f, parms, Qcursor_type, Qbox,
12122 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12123
12124 /* Dimensions, especially f->height, must be done via change_frame_size.
12125 Change will not be effected unless different from the current
12126 f->height. */
12127 width = f->width;
12128 height = f->height;
12129 f->height = 0;
12130 SET_FRAME_WIDTH (f, 0);
12131 change_frame_size (f, height, width, 1, 0, 0);
12132
12133 f->no_split = 1;
12134
12135 UNGCPRO;
12136
12137 /* It is now ok to make the frame official even if we get an error
12138 below. And the frame needs to be on Vframe_list or making it
12139 visible won't work. */
12140 Vframe_list = Fcons (frame, Vframe_list);
12141
12142 /* Now that the frame is official, it counts as a reference to
12143 its display. */
12144 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 12145
6fc2811b
JR
12146 return unbind_to (count, frame);
12147#endif /* NTEMACS_TODO */
12148 return Qnil;
ee78dc32
GV
12149}
12150
ee78dc32 12151
6fc2811b
JR
12152DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
12153 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
12154A tooltip window is a small X window displaying STRING at\n\
12155the current mouse position.\n\
12156FRAME nil or omitted means use the selected frame.\n\
12157PARMS is an optional list of frame parameters which can be\n\
12158used to change the tooltip's appearance.\n\
12159Automatically hide the tooltip after TIMEOUT seconds.\n\
12160TIMEOUT nil means use the default timeout of 5 seconds.")
12161 (string, frame, parms, timeout)
12162 Lisp_Object string, frame, parms, timeout;
ee78dc32 12163{
6fc2811b
JR
12164 struct frame *f;
12165 struct window *w;
12166 Window root, child;
12167 Lisp_Object buffer;
12168 struct buffer *old_buffer;
12169 struct text_pos pos;
12170 int i, width, height;
12171 int root_x, root_y, win_x, win_y;
12172 unsigned pmask;
12173 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12174 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12175 int count = specpdl_ptr - specpdl;
12176
12177 specbind (Qinhibit_redisplay, Qt);
ee78dc32 12178
dfff8a69 12179 GCPRO4 (string, parms, frame, timeout);
ee78dc32 12180
6fc2811b
JR
12181 CHECK_STRING (string, 0);
12182 f = check_x_frame (frame);
12183 if (NILP (timeout))
12184 timeout = make_number (5);
12185 else
12186 CHECK_NATNUM (timeout, 2);
ee78dc32 12187
6fc2811b
JR
12188 /* Hide a previous tip, if any. */
12189 Fx_hide_tip ();
ee78dc32 12190
6fc2811b
JR
12191 /* Add default values to frame parameters. */
12192 if (NILP (Fassq (Qname, parms)))
12193 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12194 if (NILP (Fassq (Qinternal_border_width, parms)))
12195 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12196 if (NILP (Fassq (Qborder_width, parms)))
12197 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12198 if (NILP (Fassq (Qborder_color, parms)))
12199 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12200 if (NILP (Fassq (Qbackground_color, parms)))
12201 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12202 parms);
12203
12204 /* Create a frame for the tooltip, and record it in the global
12205 variable tip_frame. */
12206 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
12207 tip_frame = f = XFRAME (frame);
12208
12209 /* Set up the frame's root window. Currently we use a size of 80
12210 columns x 40 lines. If someone wants to show a larger tip, he
12211 will loose. I don't think this is a realistic case. */
12212 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12213 w->left = w->top = make_number (0);
12214 w->width = 80;
12215 w->height = 40;
12216 adjust_glyphs (f);
12217 w->pseudo_window_p = 1;
12218
12219 /* Display the tooltip text in a temporary buffer. */
12220 buffer = Fget_buffer_create (build_string (" *tip*"));
12221 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12222 old_buffer = current_buffer;
12223 set_buffer_internal_1 (XBUFFER (buffer));
12224 Ferase_buffer ();
12225 Finsert (make_number (1), &string);
12226 clear_glyph_matrix (w->desired_matrix);
12227 clear_glyph_matrix (w->current_matrix);
12228 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12229 try_window (FRAME_ROOT_WINDOW (f), pos);
12230
12231 /* Compute width and height of the tooltip. */
12232 width = height = 0;
12233 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 12234 {
6fc2811b
JR
12235 struct glyph_row *row = &w->desired_matrix->rows[i];
12236 struct glyph *last;
12237 int row_width;
12238
12239 /* Stop at the first empty row at the end. */
12240 if (!row->enabled_p || !row->displays_text_p)
12241 break;
12242
12243 /* Let the row go over the full width of the frame. */
12244 row->full_width_p = 1;
12245
12246 /* There's a glyph at the end of rows that is use to place
12247 the cursor there. Don't include the width of this glyph. */
12248 if (row->used[TEXT_AREA])
12249 {
12250 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12251 row_width = row->pixel_width - last->pixel_width;
12252 }
12253 else
12254 row_width = row->pixel_width;
12255
12256 height += row->height;
12257 width = max (width, row_width);
ee78dc32
GV
12258 }
12259
6fc2811b
JR
12260 /* Add the frame's internal border to the width and height the X
12261 window should have. */
12262 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12263 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 12264
6fc2811b
JR
12265 /* Move the tooltip window where the mouse pointer is. Resize and
12266 show it. */
12267#if 0 /* NTEMACS_TODO : W32 specifics */
12268 BLOCK_INPUT;
12269 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
12270 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
12271 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12272 root_x + 5, root_y - height - 5, width, height);
12273 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
12274 UNBLOCK_INPUT;
12275#endif /* NTEMACS_TODO */
ee78dc32 12276
6fc2811b
JR
12277 /* Draw into the window. */
12278 w->must_be_updated_p = 1;
12279 update_single_window (w, 1);
ee78dc32 12280
6fc2811b
JR
12281 /* Restore original current buffer. */
12282 set_buffer_internal_1 (old_buffer);
12283 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 12284
6fc2811b
JR
12285 /* Let the tip disappear after timeout seconds. */
12286 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12287 intern ("x-hide-tip"));
ee78dc32 12288
dfff8a69 12289 UNGCPRO;
6fc2811b 12290 return unbind_to (count, Qnil);
ee78dc32
GV
12291}
12292
ee78dc32 12293
6fc2811b
JR
12294DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12295 "Hide the current tooltip window, if there is any.\n\
12296Value is t is tooltip was open, nil otherwise.")
12297 ()
12298{
12299 int count = specpdl_ptr - specpdl;
12300 int deleted_p = 0;
12301
12302 specbind (Qinhibit_redisplay, Qt);
12303
12304 if (!NILP (tip_timer))
12305 {
12306 call1 (intern ("cancel-timer"), tip_timer);
12307 tip_timer = Qnil;
12308 }
ee78dc32 12309
6fc2811b
JR
12310 if (tip_frame)
12311 {
12312 Lisp_Object frame;
12313
12314 XSETFRAME (frame, tip_frame);
12315 Fdelete_frame (frame, Qt);
12316 tip_frame = NULL;
12317 deleted_p = 1;
12318 }
1edf84e7 12319
6fc2811b
JR
12320 return unbind_to (count, deleted_p ? Qt : Qnil);
12321}
5ac45f98 12322
5ac45f98 12323
6fc2811b
JR
12324\f
12325/***********************************************************************
12326 File selection dialog
12327 ***********************************************************************/
12328
12329extern Lisp_Object Qfile_name_history;
12330
12331DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12332 "Read file name, prompting with PROMPT in directory DIR.\n\
12333Use a file selection dialog.\n\
12334Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12335specified. Don't let the user enter a file name in the file\n\
12336selection dialog's entry field, if MUSTMATCH is non-nil.")
12337 (prompt, dir, default_filename, mustmatch)
12338 Lisp_Object prompt, dir, default_filename, mustmatch;
12339{
12340 struct frame *f = SELECTED_FRAME ();
12341 Lisp_Object file = Qnil;
12342 int count = specpdl_ptr - specpdl;
12343 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12344 char filename[MAX_PATH + 1];
12345 char init_dir[MAX_PATH + 1];
12346 int use_dialog_p = 1;
12347
12348 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12349 CHECK_STRING (prompt, 0);
12350 CHECK_STRING (dir, 1);
12351
12352 /* Create the dialog with PROMPT as title, using DIR as initial
12353 directory and using "*" as pattern. */
12354 dir = Fexpand_file_name (dir, Qnil);
12355 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12356 init_dir[MAX_PATH] = '\0';
12357 unixtodos_filename (init_dir);
12358
12359 if (STRINGP (default_filename))
12360 {
12361 char *file_name_only;
12362 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 12363
6fc2811b 12364 unixtodos_filename (full_path_name);
5ac45f98 12365
6fc2811b
JR
12366 file_name_only = strrchr (full_path_name, '\\');
12367 if (!file_name_only)
12368 file_name_only = full_path_name;
12369 else
12370 {
12371 file_name_only++;
5ac45f98 12372
6fc2811b
JR
12373 /* If default_file_name is a directory, don't use the open
12374 file dialog, as it does not support selecting
12375 directories. */
12376 if (!(*file_name_only))
12377 use_dialog_p = 0;
12378 }
ee78dc32 12379
6fc2811b
JR
12380 strncpy (filename, file_name_only, MAX_PATH);
12381 filename[MAX_PATH] = '\0';
12382 }
ee78dc32 12383 else
6fc2811b 12384 filename[0] = '\0';
ee78dc32 12385
6fc2811b
JR
12386 if (use_dialog_p)
12387 {
12388 OPENFILENAME file_details;
12389 char *filename_file;
5ac45f98 12390
6fc2811b
JR
12391 /* Prevent redisplay. */
12392 specbind (Qinhibit_redisplay, Qt);
12393 BLOCK_INPUT;
ee78dc32 12394
6fc2811b
JR
12395 bzero (&file_details, sizeof (file_details));
12396 file_details.lStructSize = sizeof (file_details);
12397 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12398 file_details.lpstrFile = filename;
12399 file_details.nMaxFile = sizeof (filename);
12400 file_details.lpstrInitialDir = init_dir;
12401 file_details.lpstrTitle = XSTRING (prompt)->data;
12402 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 12403
6fc2811b
JR
12404 if (!NILP (mustmatch))
12405 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 12406
6fc2811b
JR
12407 if (GetOpenFileName (&file_details))
12408 {
12409 dostounix_filename (filename);
12410 file = build_string (filename);
12411 }
ee78dc32 12412 else
6fc2811b
JR
12413 file = Qnil;
12414
12415 UNBLOCK_INPUT;
12416 file = unbind_to (count, file);
ee78dc32 12417 }
6fc2811b
JR
12418 /* Open File dialog will not allow folders to be selected, so resort
12419 to minibuffer completing reads for directories. */
12420 else
12421 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12422 dir, mustmatch, dir, Qfile_name_history,
12423 default_filename, Qnil);
ee78dc32 12424
6fc2811b 12425 UNGCPRO;
1edf84e7 12426
6fc2811b
JR
12427 /* Make "Cancel" equivalent to C-g. */
12428 if (NILP (file))
12429 Fsignal (Qquit, Qnil);
ee78dc32 12430
dfff8a69 12431 return unbind_to (count, file);
6fc2811b 12432}
ee78dc32 12433
ee78dc32 12434
6fc2811b
JR
12435\f
12436/***********************************************************************
12437 Tests
12438 ***********************************************************************/
ee78dc32 12439
6fc2811b 12440#if GLYPH_DEBUG
ee78dc32 12441
6fc2811b
JR
12442DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12443 "Value is non-nil if SPEC is a valid image specification.")
12444 (spec)
12445 Lisp_Object spec;
12446{
12447 return valid_image_p (spec) ? Qt : Qnil;
ee78dc32
GV
12448}
12449
ee78dc32 12450
6fc2811b
JR
12451DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12452 (spec)
12453 Lisp_Object spec;
12454{
12455 int id = -1;
12456
12457 if (valid_image_p (spec))
12458 id = lookup_image (SELECTED_FRAME (), spec);
ee78dc32 12459
6fc2811b
JR
12460 debug_print (spec);
12461 return make_number (id);
ee78dc32
GV
12462}
12463
6fc2811b 12464#endif /* GLYPH_DEBUG != 0 */
ee78dc32 12465
ee78dc32
GV
12466
12467\f
6fc2811b
JR
12468/***********************************************************************
12469 w32 specialized functions
12470 ***********************************************************************/
ee78dc32 12471
fbd6baed
GV
12472DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12473 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
ee78dc32
GV
12474 (frame)
12475 Lisp_Object frame;
12476{
12477 FRAME_PTR f = check_x_frame (frame);
12478 CHOOSEFONT cf;
12479 LOGFONT lf;
f46e6225
GV
12480 TEXTMETRIC tm;
12481 HDC hdc;
12482 HANDLE oldobj;
ee78dc32
GV
12483 char buf[100];
12484
12485 bzero (&cf, sizeof (cf));
f46e6225 12486 bzero (&lf, sizeof (lf));
ee78dc32
GV
12487
12488 cf.lStructSize = sizeof (cf);
fbd6baed 12489 cf.hwndOwner = FRAME_W32_WINDOW (f);
6fc2811b 12490 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
ee78dc32
GV
12491 cf.lpLogFont = &lf;
12492
f46e6225
GV
12493 /* Initialize as much of the font details as we can from the current
12494 default font. */
12495 hdc = GetDC (FRAME_W32_WINDOW (f));
12496 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12497 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12498 if (GetTextMetrics (hdc, &tm))
12499 {
12500 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12501 lf.lfWeight = tm.tmWeight;
12502 lf.lfItalic = tm.tmItalic;
12503 lf.lfUnderline = tm.tmUnderlined;
12504 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
12505 lf.lfCharSet = tm.tmCharSet;
12506 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12507 }
12508 SelectObject (hdc, oldobj);
6fc2811b 12509 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 12510
fbd6baed 12511 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100))
3c190163 12512 return Qnil;
ee78dc32
GV
12513
12514 return build_string (buf);
12515}
12516
1edf84e7
GV
12517DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
12518 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
12519Some useful values for command are 0xf030 to maximise frame (0xf020\n\
12520to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
12521to activate the menubar for keyboard access. 0xf140 activates the\n\
12522screen saver if defined.\n\
12523\n\
12524If optional parameter FRAME is not specified, use selected frame.")
12525 (command, frame)
12526 Lisp_Object command, frame;
12527{
12528 WPARAM code;
12529 FRAME_PTR f = check_x_frame (frame);
12530
12531 CHECK_NUMBER (command, 0);
12532
ce6059da 12533 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
12534
12535 return Qnil;
12536}
12537
55dcfc15
AI
12538DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
12539 "Get Windows to perform OPERATION on DOCUMENT.\n\
12540This is a wrapper around the ShellExecute system function, which\n\
12541invokes the application registered to handle OPERATION for DOCUMENT.\n\
6fc2811b
JR
12542OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
12543nil for the default action), and DOCUMENT is typically the name of a\n\
12544document file or URL, but can also be a program executable to run or\n\
12545a directory to open in the Windows Explorer.\n\
55dcfc15 12546\n\
6fc2811b
JR
12547If DOCUMENT is a program executable, PARAMETERS can be a string\n\
12548containing command line parameters, but otherwise should be nil.\n\
55dcfc15
AI
12549\n\
12550SHOW-FLAG can be used to control whether the invoked application is hidden\n\
6fc2811b 12551or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
55dcfc15
AI
12552otherwise it is an integer representing a ShowWindow flag:\n\
12553\n\
12554 0 - start hidden\n\
12555 1 - start normally\n\
12556 3 - start maximized\n\
12557 6 - start minimized")
12558 (operation, document, parameters, show_flag)
12559 Lisp_Object operation, document, parameters, show_flag;
12560{
12561 Lisp_Object current_dir;
12562
55dcfc15
AI
12563 CHECK_STRING (document, 0);
12564
12565 /* Encode filename and current directory. */
12566 current_dir = ENCODE_FILE (current_buffer->directory);
12567 document = ENCODE_FILE (document);
12568 if ((int) ShellExecute (NULL,
6fc2811b
JR
12569 (STRINGP (operation) ?
12570 XSTRING (operation)->data : NULL),
55dcfc15
AI
12571 XSTRING (document)->data,
12572 (STRINGP (parameters) ?
12573 XSTRING (parameters)->data : NULL),
12574 XSTRING (current_dir)->data,
12575 (INTEGERP (show_flag) ?
12576 XINT (show_flag) : SW_SHOWDEFAULT))
12577 > 32)
12578 return Qt;
12579 error ("ShellExecute failed");
12580}
12581
ccc2d29c
GV
12582/* Lookup virtual keycode from string representing the name of a
12583 non-ascii keystroke into the corresponding virtual key, using
12584 lispy_function_keys. */
12585static int
12586lookup_vk_code (char *key)
12587{
12588 int i;
12589
12590 for (i = 0; i < 256; i++)
12591 if (lispy_function_keys[i] != 0
12592 && strcmp (lispy_function_keys[i], key) == 0)
12593 return i;
12594
12595 return -1;
12596}
12597
12598/* Convert a one-element vector style key sequence to a hot key
12599 definition. */
12600static int
12601w32_parse_hot_key (key)
12602 Lisp_Object key;
12603{
12604 /* Copied from Fdefine_key and store_in_keymap. */
12605 register Lisp_Object c;
12606 int vk_code;
12607 int lisp_modifiers;
12608 int w32_modifiers;
12609 struct gcpro gcpro1;
12610
12611 CHECK_VECTOR (key, 0);
12612
12613 if (XFASTINT (Flength (key)) != 1)
12614 return Qnil;
12615
12616 GCPRO1 (key);
12617
12618 c = Faref (key, make_number (0));
12619
12620 if (CONSP (c) && lucid_event_type_list_p (c))
12621 c = Fevent_convert_list (c);
12622
12623 UNGCPRO;
12624
12625 if (! INTEGERP (c) && ! SYMBOLP (c))
12626 error ("Key definition is invalid");
12627
12628 /* Work out the base key and the modifiers. */
12629 if (SYMBOLP (c))
12630 {
12631 c = parse_modifiers (c);
12632 lisp_modifiers = Fcar (Fcdr (c));
12633 c = Fcar (c);
12634 if (!SYMBOLP (c))
12635 abort ();
12636 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
12637 }
12638 else if (INTEGERP (c))
12639 {
12640 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
12641 /* Many ascii characters are their own virtual key code. */
12642 vk_code = XINT (c) & CHARACTERBITS;
12643 }
12644
12645 if (vk_code < 0 || vk_code > 255)
12646 return Qnil;
12647
12648 if ((lisp_modifiers & meta_modifier) != 0
12649 && !NILP (Vw32_alt_is_meta))
12650 lisp_modifiers |= alt_modifier;
12651
12652 /* Convert lisp modifiers to Windows hot-key form. */
12653 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
12654 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
12655 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
12656 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
12657
12658 return HOTKEY (vk_code, w32_modifiers);
12659}
12660
12661DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
12662 "Register KEY as a hot-key combination.\n\
12663Certain key combinations like Alt-Tab are reserved for system use on\n\
12664Windows, and therefore are normally intercepted by the system. However,\n\
12665most of these key combinations can be received by registering them as\n\
12666hot-keys, overriding their special meaning.\n\
12667\n\
12668KEY must be a one element key definition in vector form that would be\n\
12669acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
12670modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
12671is always interpreted as the Windows modifier keys.\n\
12672\n\
12673The return value is the hotkey-id if registered, otherwise nil.")
12674 (key)
12675 Lisp_Object key;
12676{
12677 key = w32_parse_hot_key (key);
12678
12679 if (NILP (Fmemq (key, w32_grabbed_keys)))
12680 {
12681 /* Reuse an empty slot if possible. */
12682 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
12683
12684 /* Safe to add new key to list, even if we have focus. */
12685 if (NILP (item))
12686 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
12687 else
12688 XCAR (item) = key;
12689
12690 /* Notify input thread about new hot-key definition, so that it
12691 takes effect without needing to switch focus. */
12692 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
12693 (WPARAM) key, 0);
12694 }
12695
12696 return key;
12697}
12698
12699DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
12700 "Unregister HOTKEY as a hot-key combination.")
12701 (key)
12702 Lisp_Object key;
12703{
12704 Lisp_Object item;
12705
12706 if (!INTEGERP (key))
12707 key = w32_parse_hot_key (key);
12708
12709 item = Fmemq (key, w32_grabbed_keys);
12710
12711 if (!NILP (item))
12712 {
12713 /* Notify input thread about hot-key definition being removed, so
12714 that it takes effect without needing focus switch. */
12715 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
12716 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
12717 {
12718 MSG msg;
12719 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12720 }
12721 return Qt;
12722 }
12723 return Qnil;
12724}
12725
12726DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
12727 "Return list of registered hot-key IDs.")
12728 ()
12729{
12730 return Fcopy_sequence (w32_grabbed_keys);
12731}
12732
12733DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
12734 "Convert hot-key ID to a lisp key combination.")
12735 (hotkeyid)
12736 Lisp_Object hotkeyid;
12737{
12738 int vk_code, w32_modifiers;
12739 Lisp_Object key;
12740
12741 CHECK_NUMBER (hotkeyid, 0);
12742
12743 vk_code = HOTKEY_VK_CODE (hotkeyid);
12744 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
12745
12746 if (lispy_function_keys[vk_code])
12747 key = intern (lispy_function_keys[vk_code]);
12748 else
12749 key = make_number (vk_code);
12750
12751 key = Fcons (key, Qnil);
12752 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 12753 key = Fcons (Qshift, key);
ccc2d29c 12754 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 12755 key = Fcons (Qctrl, key);
ccc2d29c 12756 if (w32_modifiers & MOD_ALT)
3ef68e6b 12757 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 12758 if (w32_modifiers & MOD_WIN)
3ef68e6b 12759 key = Fcons (Qhyper, key);
ccc2d29c
GV
12760
12761 return key;
12762}
adcc3809
GV
12763
12764DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
12765 "Toggle the state of the lock key KEY.\n\
12766KEY can be `capslock', `kp-numlock', or `scroll'.\n\
12767If the optional parameter NEW-STATE is a number, then the state of KEY\n\
12768is set to off if the low bit of NEW-STATE is zero, otherwise on.")
12769 (key, new_state)
12770 Lisp_Object key, new_state;
12771{
12772 int vk_code;
12773 int cur_state;
12774
12775 if (EQ (key, intern ("capslock")))
12776 vk_code = VK_CAPITAL;
12777 else if (EQ (key, intern ("kp-numlock")))
12778 vk_code = VK_NUMLOCK;
12779 else if (EQ (key, intern ("scroll")))
12780 vk_code = VK_SCROLL;
12781 else
12782 return Qnil;
12783
12784 if (!dwWindowsThreadId)
12785 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
12786
12787 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
12788 (WPARAM) vk_code, (LPARAM) new_state))
12789 {
12790 MSG msg;
12791 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12792 return make_number (msg.wParam);
12793 }
12794 return Qnil;
12795}
ee78dc32 12796\f
fbd6baed 12797syms_of_w32fns ()
ee78dc32 12798{
1edf84e7
GV
12799 /* This is zero if not using MS-Windows. */
12800 w32_in_use = 0;
12801
ee78dc32
GV
12802 /* The section below is built by the lisp expression at the top of the file,
12803 just above where these variables are declared. */
12804 /*&&& init symbols here &&&*/
12805 Qauto_raise = intern ("auto-raise");
12806 staticpro (&Qauto_raise);
12807 Qauto_lower = intern ("auto-lower");
12808 staticpro (&Qauto_lower);
ee78dc32
GV
12809 Qbar = intern ("bar");
12810 staticpro (&Qbar);
12811 Qborder_color = intern ("border-color");
12812 staticpro (&Qborder_color);
12813 Qborder_width = intern ("border-width");
12814 staticpro (&Qborder_width);
12815 Qbox = intern ("box");
12816 staticpro (&Qbox);
12817 Qcursor_color = intern ("cursor-color");
12818 staticpro (&Qcursor_color);
12819 Qcursor_type = intern ("cursor-type");
12820 staticpro (&Qcursor_type);
ee78dc32
GV
12821 Qgeometry = intern ("geometry");
12822 staticpro (&Qgeometry);
12823 Qicon_left = intern ("icon-left");
12824 staticpro (&Qicon_left);
12825 Qicon_top = intern ("icon-top");
12826 staticpro (&Qicon_top);
12827 Qicon_type = intern ("icon-type");
12828 staticpro (&Qicon_type);
12829 Qicon_name = intern ("icon-name");
12830 staticpro (&Qicon_name);
12831 Qinternal_border_width = intern ("internal-border-width");
12832 staticpro (&Qinternal_border_width);
12833 Qleft = intern ("left");
12834 staticpro (&Qleft);
1026b400
RS
12835 Qright = intern ("right");
12836 staticpro (&Qright);
ee78dc32
GV
12837 Qmouse_color = intern ("mouse-color");
12838 staticpro (&Qmouse_color);
12839 Qnone = intern ("none");
12840 staticpro (&Qnone);
12841 Qparent_id = intern ("parent-id");
12842 staticpro (&Qparent_id);
12843 Qscroll_bar_width = intern ("scroll-bar-width");
12844 staticpro (&Qscroll_bar_width);
12845 Qsuppress_icon = intern ("suppress-icon");
12846 staticpro (&Qsuppress_icon);
ee78dc32
GV
12847 Qundefined_color = intern ("undefined-color");
12848 staticpro (&Qundefined_color);
12849 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
12850 staticpro (&Qvertical_scroll_bars);
12851 Qvisibility = intern ("visibility");
12852 staticpro (&Qvisibility);
12853 Qwindow_id = intern ("window-id");
12854 staticpro (&Qwindow_id);
12855 Qx_frame_parameter = intern ("x-frame-parameter");
12856 staticpro (&Qx_frame_parameter);
12857 Qx_resource_name = intern ("x-resource-name");
12858 staticpro (&Qx_resource_name);
12859 Quser_position = intern ("user-position");
12860 staticpro (&Quser_position);
12861 Quser_size = intern ("user-size");
12862 staticpro (&Quser_size);
6fc2811b
JR
12863 Qscreen_gamma = intern ("screen-gamma");
12864 staticpro (&Qscreen_gamma);
dfff8a69
JR
12865 Qline_spacing = intern ("line-spacing");
12866 staticpro (&Qline_spacing);
12867 Qcenter = intern ("center");
12868 staticpro (&Qcenter);
ee78dc32
GV
12869 /* This is the end of symbol initialization. */
12870
adcc3809
GV
12871 Qhyper = intern ("hyper");
12872 staticpro (&Qhyper);
12873 Qsuper = intern ("super");
12874 staticpro (&Qsuper);
12875 Qmeta = intern ("meta");
12876 staticpro (&Qmeta);
12877 Qalt = intern ("alt");
12878 staticpro (&Qalt);
12879 Qctrl = intern ("ctrl");
12880 staticpro (&Qctrl);
12881 Qcontrol = intern ("control");
12882 staticpro (&Qcontrol);
12883 Qshift = intern ("shift");
12884 staticpro (&Qshift);
12885
6fc2811b
JR
12886 /* Text property `display' should be nonsticky by default. */
12887 Vtext_property_default_nonsticky
12888 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
12889
12890
12891 Qlaplace = intern ("laplace");
12892 staticpro (&Qlaplace);
12893
4b817373
RS
12894 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
12895 staticpro (&Qface_set_after_frame_default);
12896
ee78dc32
GV
12897 Fput (Qundefined_color, Qerror_conditions,
12898 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
12899 Fput (Qundefined_color, Qerror_message,
12900 build_string ("Undefined color"));
12901
ccc2d29c
GV
12902 staticpro (&w32_grabbed_keys);
12903 w32_grabbed_keys = Qnil;
12904
fbd6baed 12905 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
ccc2d29c 12906 "An array of color name mappings for windows.");
fbd6baed 12907 Vw32_color_map = Qnil;
ee78dc32 12908
fbd6baed 12909 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
da36a4d6
GV
12910 "Non-nil if alt key presses are passed on to Windows.\n\
12911When non-nil, for example, alt pressed and released and then space will\n\
12912open the System menu. When nil, Emacs silently swallows alt key events.");
fbd6baed 12913 Vw32_pass_alt_to_system = Qnil;
da36a4d6 12914
fbd6baed 12915 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
8c205c63
RS
12916 "Non-nil if the alt key is to be considered the same as the meta key.\n\
12917When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
fbd6baed 12918 Vw32_alt_is_meta = Qt;
8c205c63 12919
7d081355
AI
12920 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
12921 "If non-zero, the virtual key code for an alternative quit key.");
12922 XSETINT (Vw32_quit_key, 0);
12923
ccc2d29c
GV
12924 DEFVAR_LISP ("w32-pass-lwindow-to-system",
12925 &Vw32_pass_lwindow_to_system,
12926 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
12927When non-nil, the Start menu is opened by tapping the key.");
12928 Vw32_pass_lwindow_to_system = Qt;
12929
12930 DEFVAR_LISP ("w32-pass-rwindow-to-system",
12931 &Vw32_pass_rwindow_to_system,
12932 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
12933When non-nil, the Start menu is opened by tapping the key.");
12934 Vw32_pass_rwindow_to_system = Qt;
12935
adcc3809
GV
12936 DEFVAR_INT ("w32-phantom-key-code",
12937 &Vw32_phantom_key_code,
12938 "Virtual key code used to generate \"phantom\" key presses.\n\
12939Value is a number between 0 and 255.\n\
12940\n\
12941Phantom key presses are generated in order to stop the system from\n\
12942acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
12943`w32-pass-rwindow-to-system' is nil.");
ce6059da
AI
12944 /* Although 255 is technically not a valid key code, it works and
12945 means that this hack won't interfere with any real key code. */
12946 Vw32_phantom_key_code = 255;
adcc3809 12947
ccc2d29c
GV
12948 DEFVAR_LISP ("w32-enable-num-lock",
12949 &Vw32_enable_num_lock,
12950 "Non-nil if Num Lock should act normally.\n\
12951Set to nil to see Num Lock as the key `kp-numlock'.");
12952 Vw32_enable_num_lock = Qt;
12953
12954 DEFVAR_LISP ("w32-enable-caps-lock",
12955 &Vw32_enable_caps_lock,
12956 "Non-nil if Caps Lock should act normally.\n\
12957Set to nil to see Caps Lock as the key `capslock'.");
12958 Vw32_enable_caps_lock = Qt;
12959
12960 DEFVAR_LISP ("w32-scroll-lock-modifier",
12961 &Vw32_scroll_lock_modifier,
12962 "Modifier to use for the Scroll Lock on state.\n\
12963The value can be hyper, super, meta, alt, control or shift for the\n\
12964respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
12965Any other value will cause the key to be ignored.");
12966 Vw32_scroll_lock_modifier = Qt;
12967
12968 DEFVAR_LISP ("w32-lwindow-modifier",
12969 &Vw32_lwindow_modifier,
12970 "Modifier to use for the left \"Windows\" key.\n\
12971The value can be hyper, super, meta, alt, control or shift for the\n\
12972respective modifier, or nil to appear as the key `lwindow'.\n\
12973Any other value will cause the key to be ignored.");
12974 Vw32_lwindow_modifier = Qnil;
12975
12976 DEFVAR_LISP ("w32-rwindow-modifier",
12977 &Vw32_rwindow_modifier,
12978 "Modifier to use for the right \"Windows\" key.\n\
12979The value can be hyper, super, meta, alt, control or shift for the\n\
12980respective modifier, or nil to appear as the key `rwindow'.\n\
12981Any other value will cause the key to be ignored.");
12982 Vw32_rwindow_modifier = Qnil;
12983
12984 DEFVAR_LISP ("w32-apps-modifier",
12985 &Vw32_apps_modifier,
12986 "Modifier to use for the \"Apps\" key.\n\
12987The value can be hyper, super, meta, alt, control or shift for the\n\
12988respective modifier, or nil to appear as the key `apps'.\n\
12989Any other value will cause the key to be ignored.");
12990 Vw32_apps_modifier = Qnil;
da36a4d6 12991
212da13b 12992 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
6fc2811b
JR
12993 "Non-nil enables selection of artificially italicized and bold fonts.");
12994 Vw32_enable_synthesized_fonts = Qnil;
5ac45f98 12995
fbd6baed 12996 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
6fc2811b 12997 "Non-nil enables Windows palette management to map colors exactly.");
fbd6baed 12998 Vw32_enable_palette = Qt;
5ac45f98 12999
fbd6baed
GV
13000 DEFVAR_INT ("w32-mouse-button-tolerance",
13001 &Vw32_mouse_button_tolerance,
6fc2811b 13002 "Analogue of double click interval for faking middle mouse events.\n\
5ac45f98
GV
13003The value is the minimum time in milliseconds that must elapse between\n\
13004left/right button down events before they are considered distinct events.\n\
13005If both mouse buttons are depressed within this interval, a middle mouse\n\
13006button down event is generated instead.");
fbd6baed 13007 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 13008
fbd6baed
GV
13009 DEFVAR_INT ("w32-mouse-move-interval",
13010 &Vw32_mouse_move_interval,
84fb1139
KH
13011 "Minimum interval between mouse move events.\n\
13012The value is the minimum time in milliseconds that must elapse between\n\
13013successive mouse move (or scroll bar drag) events before they are\n\
13014reported as lisp events.");
247be837 13015 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 13016
ee78dc32
GV
13017 init_x_parm_symbols ();
13018
13019 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
fbd6baed 13020 "List of directories to search for bitmap files for w32.");
ee78dc32
GV
13021 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13022
13023 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13024 "The shape of the pointer when over text.\n\
13025Changing the value does not affect existing frames\n\
13026unless you set the mouse color.");
13027 Vx_pointer_shape = Qnil;
13028
13029 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13030 "The name Emacs uses to look up resources; for internal use only.\n\
13031`x-get-resource' uses this as the first component of the instance name\n\
13032when requesting resource values.\n\
13033Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13034was invoked, or to the value specified with the `-name' or `-rn'\n\
13035switches, if present.");
13036 Vx_resource_name = Qnil;
13037
13038 Vx_nontext_pointer_shape = Qnil;
13039
13040 Vx_mode_pointer_shape = Qnil;
13041
6fc2811b
JR
13042 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
13043 "The shape of the pointer when Emacs is busy.\n\
13044This variable takes effect when you create a new frame\n\
13045or when you set the mouse color.");
13046 Vx_busy_pointer_shape = Qnil;
13047
13048 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
13049 "Non-zero means Emacs displays a busy cursor on window systems.");
13050 display_busy_cursor_p = 1;
13051
f79e6790
JR
13052 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
13053 "*Seconds to wait before displaying a busy-cursor.\n\
dfff8a69 13054Value must be an integer or float.");
f79e6790
JR
13055 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
13056
6fc2811b 13057 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32
GV
13058 &Vx_sensitive_text_pointer_shape,
13059 "The shape of the pointer when over mouse-sensitive text.\n\
13060This variable takes effect when you create a new frame\n\
13061or when you set the mouse color.");
13062 Vx_sensitive_text_pointer_shape = Qnil;
13063
13064 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13065 "A string indicating the foreground color of the cursor box.");
13066 Vx_cursor_fore_pixel = Qnil;
13067
13068 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13069 "Non-nil if no window manager is in use.\n\
13070Emacs doesn't try to figure this out; this is always nil\n\
13071unless you set it to something else.");
13072 /* We don't have any way to find this out, so set it to nil
13073 and maybe the user would like to set it to t. */
13074 Vx_no_window_manager = Qnil;
13075
4587b026
GV
13076 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13077 &Vx_pixel_size_width_font_regexp,
13078 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13079\n\
13080Since Emacs gets width of a font matching with this regexp from\n\
13081PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13082such a font. This is especially effective for such large fonts as\n\
13083Chinese, Japanese, and Korean.");
13084 Vx_pixel_size_width_font_regexp = Qnil;
13085
6fc2811b
JR
13086 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13087 "Time after which cached images are removed from the cache.\n\
13088When an image has not been displayed this many seconds, remove it\n\
13089from the image cache. Value must be an integer or nil with nil\n\
13090meaning don't clear the cache.");
13091 Vimage_cache_eviction_delay = make_number (30 * 60);
13092
33d52f9c
GV
13093 DEFVAR_LISP ("w32-bdf-filename-alist",
13094 &Vw32_bdf_filename_alist,
13095 "List of bdf fonts and their corresponding filenames.");
13096 Vw32_bdf_filename_alist = Qnil;
13097
1075afa9
GV
13098 DEFVAR_BOOL ("w32-strict-fontnames",
13099 &w32_strict_fontnames,
13100 "Non-nil means only use fonts that are exact matches for those requested.\n\
13101Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13102and allows third-party CJK display to work by specifying false charset\n\
13103fields to trick Emacs into translating to Big5, SJIS etc.\n\
13104Setting this to t will prevent wrong fonts being selected when\n\
13105fontsets are automatically created.");
13106 w32_strict_fontnames = 0;
13107
c0611964
AI
13108 DEFVAR_BOOL ("w32-strict-painting",
13109 &w32_strict_painting,
13110 "Non-nil means use strict rules for repainting frames.\n\
13111Set this to nil to get the old behaviour for repainting; this should\n\
13112only be necessary if the default setting causes problems.");
13113 w32_strict_painting = 1;
13114
f46e6225
GV
13115 DEFVAR_LISP ("w32-system-coding-system",
13116 &Vw32_system_coding_system,
13117 "Coding system used by Windows system functions, such as for font names.");
13118 Vw32_system_coding_system = Qnil;
13119
dfff8a69
JR
13120 DEFVAR_LISP ("w32-charset-info-alist",
13121 &Vw32_charset_info_alist,
13122 "Alist linking Emacs character sets to Windows fonts\n\
13123and codepages. Each entry should be of the form:\n\
13124\n\
13125 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13126\n\
13127where CHARSET_NAME is a string used in font names to identify the charset,\n\
13128WINDOWS_CHARSET is a symbol that can be one of:\n\
13129w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
13130w32-charset-shiftjis, w32-charset-hangul, w32-charset-gb2312,\n\
13131w32-charset-chinesebig5, "
13132#ifdef JOHAB_CHARSET
13133"w32-charset-johab, w32-charset-hebrew,\n\
13134w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13135w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13136w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13137#endif
13138#ifdef UNICODE_CHARSET
13139"w32-charset-unicode, "
13140#endif
13141"or w32-charset-oem.\n\
13142CODEPAGE should be an integer specifying the codepage that should be used\n\
13143to display the character set, t to do no translation and output as Unicode,\n\
13144or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13145versions of Windows) characters.");
13146 Vw32_charset_info_alist = Qnil;
13147
13148 staticpro (&Qw32_charset_ansi);
13149 Qw32_charset_ansi = intern ("w32-charset-ansi");
13150 staticpro (&Qw32_charset_symbol);
13151 Qw32_charset_symbol = intern ("w32-charset-symbol");
13152 staticpro (&Qw32_charset_shiftjis);
13153 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
13154 staticpro (&Qw32_charset_hangul);
13155 Qw32_charset_hangul = intern ("w32-charset-hangul");
13156 staticpro (&Qw32_charset_chinesebig5);
13157 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13158 staticpro (&Qw32_charset_gb2312);
13159 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13160 staticpro (&Qw32_charset_oem);
13161 Qw32_charset_oem = intern ("w32-charset-oem");
13162
13163#ifdef JOHAB_CHARSET
13164 {
13165 static int w32_extra_charsets_defined = 1;
13166 DEFVAR_BOOL ("w32-extra-charsets-defined", w32_extra_charsets_defined, "");
13167
13168 staticpro (&Qw32_charset_johab);
13169 Qw32_charset_johab = intern ("w32-charset-johab");
13170 staticpro (&Qw32_charset_easteurope);
13171 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13172 staticpro (&Qw32_charset_turkish);
13173 Qw32_charset_turkish = intern ("w32-charset-turkish");
13174 staticpro (&Qw32_charset_baltic);
13175 Qw32_charset_baltic = intern ("w32-charset-baltic");
13176 staticpro (&Qw32_charset_russian);
13177 Qw32_charset_russian = intern ("w32-charset-russian");
13178 staticpro (&Qw32_charset_arabic);
13179 Qw32_charset_arabic = intern ("w32-charset-arabic");
13180 staticpro (&Qw32_charset_greek);
13181 Qw32_charset_greek = intern ("w32-charset-greek");
13182 staticpro (&Qw32_charset_hebrew);
13183 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
13184 staticpro (&Qw32_charset_thai);
13185 Qw32_charset_thai = intern ("w32-charset-thai");
13186 staticpro (&Qw32_charset_mac);
13187 Qw32_charset_mac = intern ("w32-charset-mac");
13188 }
13189#endif
13190
13191#ifdef UNICODE_CHARSET
13192 {
13193 static int w32_unicode_charset_defined = 1;
13194 DEFVAR_BOOL ("w32-unicode-charset-defined",
13195 w32_unicode_charset_defined, "");
13196
13197 staticpro (&Qw32_charset_unicode);
13198 Qw32_charset_unicode = intern ("w32-charset-unicode");
13199#endif
13200
ee78dc32 13201 defsubr (&Sx_get_resource);
6fc2811b
JR
13202#if 0 /* NTEMACS_TODO: Port to W32 */
13203 defsubr (&Sx_change_window_property);
13204 defsubr (&Sx_delete_window_property);
13205 defsubr (&Sx_window_property);
13206#endif
2d764c78 13207 defsubr (&Sxw_display_color_p);
ee78dc32 13208 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
13209 defsubr (&Sxw_color_defined_p);
13210 defsubr (&Sxw_color_values);
ee78dc32
GV
13211 defsubr (&Sx_server_max_request_size);
13212 defsubr (&Sx_server_vendor);
13213 defsubr (&Sx_server_version);
13214 defsubr (&Sx_display_pixel_width);
13215 defsubr (&Sx_display_pixel_height);
13216 defsubr (&Sx_display_mm_width);
13217 defsubr (&Sx_display_mm_height);
13218 defsubr (&Sx_display_screens);
13219 defsubr (&Sx_display_planes);
13220 defsubr (&Sx_display_color_cells);
13221 defsubr (&Sx_display_visual_class);
13222 defsubr (&Sx_display_backing_store);
13223 defsubr (&Sx_display_save_under);
13224 defsubr (&Sx_parse_geometry);
13225 defsubr (&Sx_create_frame);
ee78dc32
GV
13226 defsubr (&Sx_open_connection);
13227 defsubr (&Sx_close_connection);
13228 defsubr (&Sx_display_list);
13229 defsubr (&Sx_synchronize);
13230
fbd6baed 13231 /* W32 specific functions */
ee78dc32 13232
1edf84e7 13233 defsubr (&Sw32_focus_frame);
fbd6baed
GV
13234 defsubr (&Sw32_select_font);
13235 defsubr (&Sw32_define_rgb_color);
13236 defsubr (&Sw32_default_color_map);
13237 defsubr (&Sw32_load_color_file);
1edf84e7 13238 defsubr (&Sw32_send_sys_command);
55dcfc15 13239 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
13240 defsubr (&Sw32_register_hot_key);
13241 defsubr (&Sw32_unregister_hot_key);
13242 defsubr (&Sw32_registered_hot_keys);
13243 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 13244 defsubr (&Sw32_toggle_lock_key);
33d52f9c 13245 defsubr (&Sw32_find_bdf_fonts);
4587b026
GV
13246
13247 /* Setting callback functions for fontset handler. */
13248 get_font_info_func = w32_get_font_info;
6fc2811b
JR
13249
13250#if 0 /* This function pointer doesn't seem to be used anywhere.
13251 And the pointer assigned has the wrong type, anyway. */
4587b026 13252 list_fonts_func = w32_list_fonts;
6fc2811b
JR
13253#endif
13254
4587b026
GV
13255 load_font_func = w32_load_font;
13256 find_ccl_program_func = w32_find_ccl_program;
13257 query_font_func = w32_query_font;
13258 set_frame_fontset_func = x_set_font;
13259 check_window_system_func = check_w32;
6fc2811b
JR
13260
13261#if 0 /* NTEMACS_TODO Image support for W32 */
13262 /* Images. */
13263 Qxbm = intern ("xbm");
13264 staticpro (&Qxbm);
13265 QCtype = intern (":type");
13266 staticpro (&QCtype);
13267 QCalgorithm = intern (":algorithm");
13268 staticpro (&QCalgorithm);
13269 QCheuristic_mask = intern (":heuristic-mask");
13270 staticpro (&QCheuristic_mask);
13271 QCcolor_symbols = intern (":color-symbols");
13272 staticpro (&QCcolor_symbols);
6fc2811b
JR
13273 QCascent = intern (":ascent");
13274 staticpro (&QCascent);
13275 QCmargin = intern (":margin");
13276 staticpro (&QCmargin);
13277 QCrelief = intern (":relief");
13278 staticpro (&QCrelief);
13279 Qpostscript = intern ("postscript");
13280 staticpro (&Qpostscript);
13281 QCloader = intern (":loader");
13282 staticpro (&QCloader);
13283 QCbounding_box = intern (":bounding-box");
13284 staticpro (&QCbounding_box);
13285 QCpt_width = intern (":pt-width");
13286 staticpro (&QCpt_width);
13287 QCpt_height = intern (":pt-height");
13288 staticpro (&QCpt_height);
13289 QCindex = intern (":index");
13290 staticpro (&QCindex);
13291 Qpbm = intern ("pbm");
13292 staticpro (&Qpbm);
13293
13294#if HAVE_XPM
13295 Qxpm = intern ("xpm");
13296 staticpro (&Qxpm);
13297#endif
13298
13299#if HAVE_JPEG
13300 Qjpeg = intern ("jpeg");
13301 staticpro (&Qjpeg);
13302#endif
13303
13304#if HAVE_TIFF
13305 Qtiff = intern ("tiff");
13306 staticpro (&Qtiff);
13307#endif
13308
13309#if HAVE_GIF
13310 Qgif = intern ("gif");
13311 staticpro (&Qgif);
13312#endif
13313
13314#if HAVE_PNG
13315 Qpng = intern ("png");
13316 staticpro (&Qpng);
13317#endif
13318
13319 defsubr (&Sclear_image_cache);
13320
13321#if GLYPH_DEBUG
13322 defsubr (&Simagep);
13323 defsubr (&Slookup_image);
13324#endif
13325#endif /* NTEMACS_TODO */
13326
dfff8a69
JR
13327 busy_cursor_atimer = NULL;
13328 busy_cursor_shown_p = 0;
13329
6fc2811b
JR
13330 defsubr (&Sx_show_tip);
13331 defsubr (&Sx_hide_tip);
13332 staticpro (&tip_timer);
13333 tip_timer = Qnil;
13334
13335 defsubr (&Sx_file_dialog);
13336}
13337
13338
13339void
13340init_xfns ()
13341{
13342 image_types = NULL;
13343 Vimage_types = Qnil;
13344
13345#if 0 /* NTEMACS_TODO : Image support for W32 */
13346 define_image_type (&xbm_type);
13347 define_image_type (&gs_type);
13348 define_image_type (&pbm_type);
13349
13350#if HAVE_XPM
13351 define_image_type (&xpm_type);
13352#endif
13353
13354#if HAVE_JPEG
13355 define_image_type (&jpeg_type);
13356#endif
13357
13358#if HAVE_TIFF
13359 define_image_type (&tiff_type);
13360#endif
13361
13362#if HAVE_GIF
13363 define_image_type (&gif_type);
13364#endif
13365
13366#if HAVE_PNG
13367 define_image_type (&png_type);
13368#endif
13369#endif /* NTEMACS_TODO */
ee78dc32
GV
13370}
13371
13372#undef abort
13373
13374void
fbd6baed 13375w32_abort()
ee78dc32 13376{
5ac45f98
GV
13377 int button;
13378 button = MessageBox (NULL,
13379 "A fatal error has occurred!\n\n"
13380 "Select Abort to exit, Retry to debug, Ignore to continue",
13381 "Emacs Abort Dialog",
13382 MB_ICONEXCLAMATION | MB_TASKMODAL
13383 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
13384 switch (button)
13385 {
13386 case IDRETRY:
13387 DebugBreak ();
13388 break;
13389 case IDIGNORE:
13390 break;
13391 case IDABORT:
13392 default:
13393 abort ();
13394 break;
13395 }
ee78dc32 13396}
d573caac 13397
83c75055
GV
13398/* For convenience when debugging. */
13399int
13400w32_last_error()
13401{
13402 return GetLastError ();
13403}