Resolve CVS conflicts
[bpt/emacs.git] / src / w32fns.c
CommitLineData
e9e23e23 1/* Graphical user interface functions for the Microsoft W32 API.
a93f4566 2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
6fc2811b 3 Free Software Foundation, Inc.
ee78dc32
GV
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
ee78dc32
GV
21
22/* Added by Kevin Gallo */
23
ee78dc32 24#include <config.h>
1edf84e7
GV
25
26#include <signal.h>
ee78dc32 27#include <stdio.h>
1edf84e7
GV
28#include <limits.h>
29#include <errno.h>
ee78dc32
GV
30
31#include "lisp.h"
4587b026 32#include "charset.h"
71eab8d1 33#include "dispextern.h"
ee78dc32 34#include "w32term.h"
c7501041 35#include "keyboard.h"
ee78dc32
GV
36#include "frame.h"
37#include "window.h"
38#include "buffer.h"
126f2e35 39#include "fontset.h"
6fc2811b 40#include "intervals.h"
ee78dc32 41#include "blockinput.h"
57bda87a 42#include "epaths.h"
489f9371 43#include "w32heap.h"
ee78dc32 44#include "termhooks.h"
4587b026 45#include "coding.h"
3545439c 46#include "ccl.h"
6fc2811b
JR
47#include "systime.h"
48
49#include "bitmaps/gray.xbm"
ee78dc32
GV
50
51#include <commdlg.h>
cb9e33d4 52#include <shellapi.h>
6fc2811b 53#include <ctype.h>
39a0e135 54#include <winspool.h>
ee78dc32 55
1030b26b
JR
56#include <dlgs.h>
57#define FILE_NAME_TEXT_FIELD edt1
58
9785d95b
BK
59void syms_of_w32fns ();
60void globals_of_w32fns ();
839b1909 61static void init_external_image_libraries ();
9785d95b 62
ee78dc32 63extern void free_frame_menubar ();
6fc2811b 64extern double atof ();
9eb16b62
JR
65extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
66extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
67extern void w32_free_menu_strings P_ ((HWND));
68
5ac45f98 69extern int quit_char;
ee78dc32 70
ccc2d29c
GV
71extern char *lispy_function_keys[];
72
6fc2811b
JR
73/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
74 it, and including `bitmaps/gray' more than once is a problem when
75 config.h defines `static' as an empty replacement string. */
76
77int gray_bitmap_width = gray_width;
78int gray_bitmap_height = gray_height;
79unsigned char *gray_bitmap_bits = gray_bits;
80
ee78dc32 81/* The colormap for converting color names to RGB values */
fbd6baed 82Lisp_Object Vw32_color_map;
ee78dc32 83
da36a4d6 84/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 85Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 86
8c205c63
RS
87/* Non nil if alt key is translated to meta_modifier, nil if it is translated
88 to alt_modifier. */
fbd6baed 89Lisp_Object Vw32_alt_is_meta;
8c205c63 90
7d081355
AI
91/* If non-zero, the windows virtual key code for an alternative quit key. */
92Lisp_Object Vw32_quit_key;
93
ccc2d29c
GV
94/* Non nil if left window key events are passed on to Windows (this only
95 affects whether "tapping" the key opens the Start menu). */
96Lisp_Object Vw32_pass_lwindow_to_system;
97
98/* Non nil if right window key events are passed on to Windows (this
99 only affects whether "tapping" the key opens the Start menu). */
100Lisp_Object Vw32_pass_rwindow_to_system;
101
adcc3809
GV
102/* Virtual key code used to generate "phantom" key presses in order
103 to stop system from acting on Windows key events. */
104Lisp_Object Vw32_phantom_key_code;
105
ccc2d29c
GV
106/* Modifier associated with the left "Windows" key, or nil to act as a
107 normal key. */
108Lisp_Object Vw32_lwindow_modifier;
109
110/* Modifier associated with the right "Windows" key, or nil to act as a
111 normal key. */
112Lisp_Object Vw32_rwindow_modifier;
113
114/* Modifier associated with the "Apps" key, or nil to act as a normal
115 key. */
116Lisp_Object Vw32_apps_modifier;
117
118/* Value is nil if Num Lock acts as a function key. */
119Lisp_Object Vw32_enable_num_lock;
120
121/* Value is nil if Caps Lock acts as a function key. */
122Lisp_Object Vw32_enable_caps_lock;
123
124/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
125Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 126
7ce9aaca 127/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b 128 and italic versions of fonts. */
d84b082d 129int w32_enable_synthesized_fonts;
5ac45f98
GV
130
131/* Enable palette management. */
fbd6baed 132Lisp_Object Vw32_enable_palette;
5ac45f98
GV
133
134/* Control how close left/right button down events must be to
135 be converted to a middle button down event. */
fbd6baed 136Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 137
84fb1139
KH
138/* Minimum interval between mouse movement (and scroll bar drag)
139 events that are passed on to the event loop. */
fbd6baed 140Lisp_Object Vw32_mouse_move_interval;
84fb1139 141
74214547
JR
142/* Flag to indicate if XBUTTON events should be passed on to Windows. */
143int w32_pass_extra_mouse_buttons_to_system;
144
ee78dc32
GV
145/* Non nil if no window manager is in use. */
146Lisp_Object Vx_no_window_manager;
147
0af913d7 148/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 149
0af913d7 150int display_hourglass_p;
6fc2811b 151
ee78dc32
GV
152/* The background and shape of the mouse pointer, and shape when not
153 over text or in the modeline. */
dfff8a69 154
ee78dc32 155Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
c9b2104d 156Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape, Vx_hand_shape;
6fc2811b 157
ee78dc32 158/* The shape when over mouse-sensitive text. */
dfff8a69 159
ee78dc32
GV
160Lisp_Object Vx_sensitive_text_pointer_shape;
161
c9b2104d
JR
162#ifndef IDC_HAND
163#define IDC_HAND MAKEINTRESOURCE(32649)
164#endif
165
ee78dc32 166/* Color of chars displayed in cursor box. */
dfff8a69 167
ee78dc32
GV
168Lisp_Object Vx_cursor_fore_pixel;
169
1edf84e7 170/* Nonzero if using Windows. */
dfff8a69 171
1edf84e7
GV
172static int w32_in_use;
173
ee78dc32 174/* Search path for bitmap files. */
dfff8a69 175
ee78dc32
GV
176Lisp_Object Vx_bitmap_file_path;
177
4587b026 178/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 179
4587b026
GV
180Lisp_Object Vx_pixel_size_width_font_regexp;
181
33d52f9c
GV
182/* Alist of bdf fonts and the files that define them. */
183Lisp_Object Vw32_bdf_filename_alist;
184
f46e6225 185/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
186int w32_strict_fontnames;
187
c0611964
AI
188/* A flag to control whether we should only repaint if GetUpdateRect
189 indicates there is an update region. */
190int w32_strict_painting;
191
dfff8a69
JR
192/* Associative list linking character set strings to Windows codepages. */
193Lisp_Object Vw32_charset_info_alist;
194
195/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
196#ifndef VIETNAMESE_CHARSET
197#define VIETNAMESE_CHARSET 163
198#endif
199
ee78dc32 200Lisp_Object Qnone;
ee78dc32 201Lisp_Object Qsuppress_icon;
ee78dc32 202Lisp_Object Qundefined_color;
dfff8a69 203Lisp_Object Qcenter;
dc220243 204Lisp_Object Qcancel_timer;
adcc3809
GV
205Lisp_Object Qhyper;
206Lisp_Object Qsuper;
207Lisp_Object Qmeta;
208Lisp_Object Qalt;
209Lisp_Object Qctrl;
210Lisp_Object Qcontrol;
211Lisp_Object Qshift;
212
dfff8a69
JR
213Lisp_Object Qw32_charset_ansi;
214Lisp_Object Qw32_charset_default;
215Lisp_Object Qw32_charset_symbol;
216Lisp_Object Qw32_charset_shiftjis;
767b1ff0 217Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
218Lisp_Object Qw32_charset_gb2312;
219Lisp_Object Qw32_charset_chinesebig5;
220Lisp_Object Qw32_charset_oem;
221
71eab8d1
AI
222#ifndef JOHAB_CHARSET
223#define JOHAB_CHARSET 130
224#endif
dfff8a69
JR
225#ifdef JOHAB_CHARSET
226Lisp_Object Qw32_charset_easteurope;
227Lisp_Object Qw32_charset_turkish;
228Lisp_Object Qw32_charset_baltic;
229Lisp_Object Qw32_charset_russian;
230Lisp_Object Qw32_charset_arabic;
231Lisp_Object Qw32_charset_greek;
232Lisp_Object Qw32_charset_hebrew;
767b1ff0 233Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
234Lisp_Object Qw32_charset_thai;
235Lisp_Object Qw32_charset_johab;
236Lisp_Object Qw32_charset_mac;
237#endif
238
239#ifdef UNICODE_CHARSET
240Lisp_Object Qw32_charset_unicode;
241#endif
242
5a8a15ec
JR
243/* Prefix for system colors. */
244#define SYSTEM_COLOR_PREFIX "System"
245#define SYSTEM_COLOR_PREFIX_LEN (sizeof (SYSTEM_COLOR_PREFIX) - 1)
246
5ac45f98
GV
247/* State variables for emulating a three button mouse. */
248#define LMOUSE 1
249#define MMOUSE 2
250#define RMOUSE 4
251
252static int button_state = 0;
fbd6baed 253static W32Msg saved_mouse_button_msg;
48094ace 254static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
fbd6baed 255static W32Msg saved_mouse_move_msg;
48094ace 256static unsigned mouse_move_timer = 0;
84fb1139 257
9eb16b62
JR
258/* Window that is tracking the mouse. */
259static HWND track_mouse_window;
f60ae425 260
ccc0fdaa
JR
261typedef BOOL (WINAPI * TrackMouseEvent_Proc)
262 (IN OUT LPTRACKMOUSEEVENT lpEventTrack);
f60ae425 263
ccc0fdaa
JR
264TrackMouseEvent_Proc track_mouse_event_fn = NULL;
265ClipboardSequence_Proc clipboard_sequence_fn = NULL;
9eb16b62 266
93fbe8b7 267/* W95 mousewheel handler */
7d0393cf 268unsigned int msh_mousewheel = 0;
93fbe8b7 269
48094ace 270/* Timers */
84fb1139
KH
271#define MOUSE_BUTTON_ID 1
272#define MOUSE_MOVE_ID 2
48094ace
JR
273#define MENU_FREE_ID 3
274/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
275 is received. */
276#define MENU_FREE_DELAY 1000
277static unsigned menu_free_timer = 0;
5ac45f98 278
ee78dc32 279/* The below are defined in frame.c. */
dfff8a69 280
ee78dc32
GV
281extern Lisp_Object Vwindow_system_version;
282
937e601e
AI
283#ifdef GLYPH_DEBUG
284int image_cache_refcount, dpyinfo_refcount;
285#endif
286
287
fbd6baed
GV
288/* From w32term.c. */
289extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 290extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 291
65906840 292extern HWND w32_system_caret_hwnd;
93f2ca61 293
65906840
JR
294extern int w32_system_caret_height;
295extern int w32_system_caret_x;
296extern int w32_system_caret_y;
93f2ca61
JR
297extern int w32_use_visible_system_caret;
298
d285988b 299static HWND w32_visible_system_caret_hwnd;
65906840 300
ee78dc32 301\f
1edf84e7
GV
302/* Error if we are not connected to MS-Windows. */
303void
304check_w32 ()
305{
306 if (! w32_in_use)
307 error ("MS-Windows not in use or not initialized");
308}
309
310/* Nonzero if we can use mouse menus.
311 You should not call this unless HAVE_MENUS is defined. */
7d0393cf 312
1edf84e7
GV
313int
314have_menus_p ()
315{
316 return w32_in_use;
317}
318
ee78dc32 319/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 320 and checking validity for W32. */
ee78dc32
GV
321
322FRAME_PTR
323check_x_frame (frame)
324 Lisp_Object frame;
325{
326 FRAME_PTR f;
327
328 if (NILP (frame))
6fc2811b 329 frame = selected_frame;
b7826503 330 CHECK_LIVE_FRAME (frame);
6fc2811b 331 f = XFRAME (frame);
fbd6baed
GV
332 if (! FRAME_W32_P (f))
333 error ("non-w32 frame used");
ee78dc32
GV
334 return f;
335}
336
7d0393cf 337/* Let the user specify a display with a frame.
fbd6baed 338 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
339 the first display on the list. */
340
6d906347 341struct w32_display_info *
ee78dc32
GV
342check_x_display_info (frame)
343 Lisp_Object frame;
344{
345 if (NILP (frame))
346 {
6fc2811b 347 struct frame *sf = XFRAME (selected_frame);
7d0393cf 348
6fc2811b
JR
349 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
350 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 351 else
fbd6baed 352 return &one_w32_display_info;
ee78dc32
GV
353 }
354 else if (STRINGP (frame))
355 return x_display_info_for_name (frame);
356 else
357 {
358 FRAME_PTR f;
359
b7826503 360 CHECK_LIVE_FRAME (frame);
ee78dc32 361 f = XFRAME (frame);
fbd6baed
GV
362 if (! FRAME_W32_P (f))
363 error ("non-w32 frame used");
364 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
365 }
366}
367\f
fbd6baed 368/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
369 It could be the frame's main window or an icon window. */
370
371/* This function can be called during GC, so use GC_xxx type test macros. */
372
373struct frame *
374x_window_to_frame (dpyinfo, wdesc)
fbd6baed 375 struct w32_display_info *dpyinfo;
ee78dc32
GV
376 HWND wdesc;
377{
378 Lisp_Object tail, frame;
379 struct frame *f;
380
8e713be6 381 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 382 {
8e713be6 383 frame = XCAR (tail);
ee78dc32
GV
384 if (!GC_FRAMEP (frame))
385 continue;
386 f = XFRAME (frame);
2d764c78 387 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 388 continue;
0af913d7 389 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
390 return f;
391
fbd6baed 392 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
393 return f;
394 }
395 return 0;
396}
397
398\f
399
400/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
401 id, which is just an int that this section returns. Bitmaps are
402 reference counted so they can be shared among frames.
403
404 Bitmap indices are guaranteed to be > 0, so a negative number can
405 be used to indicate no bitmap.
406
407 If you use x_create_bitmap_from_data, then you must keep track of
408 the bitmaps yourself. That is, creating a bitmap from the same
409 data more than once will not be caught. */
410
411
412/* Functions to access the contents of a bitmap, given an id. */
413
414int
415x_bitmap_height (f, id)
416 FRAME_PTR f;
417 int id;
418{
fbd6baed 419 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
420}
421
422int
423x_bitmap_width (f, id)
424 FRAME_PTR f;
425 int id;
426{
fbd6baed 427 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
428}
429
430int
431x_bitmap_pixmap (f, id)
432 FRAME_PTR f;
433 int id;
434{
fbd6baed 435 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
436}
437
438
439/* Allocate a new bitmap record. Returns index of new record. */
440
441static int
442x_allocate_bitmap_record (f)
443 FRAME_PTR f;
444{
fbd6baed 445 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
446 int i;
447
448 if (dpyinfo->bitmaps == NULL)
449 {
450 dpyinfo->bitmaps_size = 10;
451 dpyinfo->bitmaps
fbd6baed 452 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
453 dpyinfo->bitmaps_last = 1;
454 return 1;
455 }
456
457 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
458 return ++dpyinfo->bitmaps_last;
459
460 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
461 if (dpyinfo->bitmaps[i].refcount == 0)
462 return i + 1;
463
464 dpyinfo->bitmaps_size *= 2;
465 dpyinfo->bitmaps
fbd6baed
GV
466 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
467 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
468 return ++dpyinfo->bitmaps_last;
469}
470
471/* Add one reference to the reference count of the bitmap with id ID. */
472
473void
474x_reference_bitmap (f, id)
475 FRAME_PTR f;
476 int id;
477{
fbd6baed 478 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
479}
480
481/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
482
483int
484x_create_bitmap_from_data (f, bits, width, height)
485 struct frame *f;
486 char *bits;
487 unsigned int width, height;
488{
fbd6baed 489 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
490 Pixmap bitmap;
491 int id;
492
493 bitmap = CreateBitmap (width, height,
fbd6baed
GV
494 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
495 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
496 bits);
497
498 if (! bitmap)
499 return -1;
500
501 id = x_allocate_bitmap_record (f);
502 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
503 dpyinfo->bitmaps[id - 1].file = NULL;
504 dpyinfo->bitmaps[id - 1].hinst = NULL;
505 dpyinfo->bitmaps[id - 1].refcount = 1;
506 dpyinfo->bitmaps[id - 1].depth = 1;
507 dpyinfo->bitmaps[id - 1].height = height;
508 dpyinfo->bitmaps[id - 1].width = width;
509
510 return id;
511}
512
513/* Create bitmap from file FILE for frame F. */
514
515int
516x_create_bitmap_from_file (f, file)
517 struct frame *f;
518 Lisp_Object file;
519{
520 return -1;
767b1ff0 521#if 0 /* TODO : bitmap support */
fbd6baed 522 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 523 unsigned int width, height;
6fc2811b 524 HBITMAP bitmap;
ee78dc32
GV
525 int xhot, yhot, result, id;
526 Lisp_Object found;
527 int fd;
528 char *filename;
529 HINSTANCE hinst;
530
531 /* Look for an existing bitmap with the same name. */
532 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
533 {
534 if (dpyinfo->bitmaps[id].refcount
535 && dpyinfo->bitmaps[id].file
d5db4077 536 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
ee78dc32
GV
537 {
538 ++dpyinfo->bitmaps[id].refcount;
539 return id + 1;
540 }
541 }
542
543 /* Search bitmap-file-path for the file, if appropriate. */
de2413e9 544 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
ee78dc32
GV
545 if (fd < 0)
546 return -1;
6fc2811b 547 emacs_close (fd);
ee78dc32 548
d5db4077 549 filename = (char *) SDATA (found);
ee78dc32
GV
550
551 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
552
553 if (hinst == NULL)
554 return -1;
555
7d0393cf 556
fbd6baed 557 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
558 filename, &width, &height, &bitmap, &xhot, &yhot);
559 if (result != BitmapSuccess)
560 return -1;
561
562 id = x_allocate_bitmap_record (f);
563 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
564 dpyinfo->bitmaps[id - 1].refcount = 1;
d5db4077 565 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1);
ee78dc32
GV
566 dpyinfo->bitmaps[id - 1].depth = 1;
567 dpyinfo->bitmaps[id - 1].height = height;
568 dpyinfo->bitmaps[id - 1].width = width;
d5db4077 569 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
ee78dc32
GV
570
571 return id;
767b1ff0 572#endif /* TODO */
ee78dc32
GV
573}
574
575/* Remove reference to bitmap with id number ID. */
576
33d52f9c 577void
ee78dc32
GV
578x_destroy_bitmap (f, id)
579 FRAME_PTR f;
580 int id;
581{
fbd6baed 582 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
583
584 if (id > 0)
585 {
586 --dpyinfo->bitmaps[id - 1].refcount;
587 if (dpyinfo->bitmaps[id - 1].refcount == 0)
588 {
589 BLOCK_INPUT;
590 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
591 if (dpyinfo->bitmaps[id - 1].file)
592 {
6fc2811b 593 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
594 dpyinfo->bitmaps[id - 1].file = NULL;
595 }
596 UNBLOCK_INPUT;
597 }
598 }
599}
600
601/* Free all the bitmaps for the display specified by DPYINFO. */
602
603static void
604x_destroy_all_bitmaps (dpyinfo)
fbd6baed 605 struct w32_display_info *dpyinfo;
ee78dc32
GV
606{
607 int i;
608 for (i = 0; i < dpyinfo->bitmaps_last; i++)
609 if (dpyinfo->bitmaps[i].refcount > 0)
610 {
611 DeleteObject (dpyinfo->bitmaps[i].pixmap);
612 if (dpyinfo->bitmaps[i].file)
6fc2811b 613 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
614 }
615 dpyinfo->bitmaps_last = 0;
616}
617\f
ca56d953
JR
618BOOL my_show_window P_ ((struct frame *, HWND, int));
619void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
620static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
621static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
6d906347 622
767b1ff0 623/* TODO: Native Input Method support; see x_create_im. */
6fc2811b
JR
624void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
625void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
626void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
627void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
628void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
629void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
630void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
631void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b 632void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b 633void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b 634void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b 635void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
636static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
637 Lisp_Object));
ee78dc32 638
ee78dc32 639
ee78dc32 640\f
ee78dc32
GV
641
642/* Store the screen positions of frame F into XPTR and YPTR.
643 These are the positions of the containing window manager window,
644 not Emacs's own window. */
645
646void
647x_real_positions (f, xptr, yptr)
648 FRAME_PTR f;
649 int *xptr, *yptr;
650{
651 POINT pt;
f7b9d4d1 652 RECT rect;
3c190163 653
f7b9d4d1
JR
654 GetClientRect(FRAME_W32_WINDOW(f), &rect);
655 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
656
657 pt.x = rect.left;
658 pt.y = rect.top;
ee78dc32 659
fbd6baed 660 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32 661
f7b9d4d1 662 /* Remember x_pixels_diff and y_pixels_diff. */
be786000
KS
663 f->x_pixels_diff = pt.x - rect.left;
664 f->y_pixels_diff = pt.y - rect.top;
f7b9d4d1 665
ee78dc32
GV
666 *xptr = pt.x;
667 *yptr = pt.y;
668}
669
ee78dc32
GV
670\f
671
74e1aeec
JR
672DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
673 Sw32_define_rgb_color, 4, 4, 0,
674 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
675This adds or updates a named color to w32-color-map, making it
676available for use. The original entry's RGB ref is returned, or nil
677if the entry is new. */)
5ac45f98
GV
678 (red, green, blue, name)
679 Lisp_Object red, green, blue, name;
ee78dc32 680{
5ac45f98
GV
681 Lisp_Object rgb;
682 Lisp_Object oldrgb = Qnil;
683 Lisp_Object entry;
684
b7826503
PJ
685 CHECK_NUMBER (red);
686 CHECK_NUMBER (green);
687 CHECK_NUMBER (blue);
688 CHECK_STRING (name);
ee78dc32 689
5ac45f98 690 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 691
5ac45f98 692 BLOCK_INPUT;
ee78dc32 693
fbd6baed
GV
694 /* replace existing entry in w32-color-map or add new entry. */
695 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
696 if (NILP (entry))
697 {
698 entry = Fcons (name, rgb);
fbd6baed 699 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
700 }
701 else
702 {
703 oldrgb = Fcdr (entry);
704 Fsetcdr (entry, rgb);
705 }
706
707 UNBLOCK_INPUT;
708
709 return (oldrgb);
ee78dc32
GV
710}
711
74e1aeec
JR
712DEFUN ("w32-load-color-file", Fw32_load_color_file,
713 Sw32_load_color_file, 1, 1, 0,
714 doc: /* Create an alist of color entries from an external file.
715Assign this value to w32-color-map to replace the existing color map.
716
717The file should define one named RGB color per line like so:
718 R G B name
719where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
720 (filename)
721 Lisp_Object filename;
722{
723 FILE *fp;
724 Lisp_Object cmap = Qnil;
725 Lisp_Object abspath;
726
b7826503 727 CHECK_STRING (filename);
5ac45f98
GV
728 abspath = Fexpand_file_name (filename, Qnil);
729
d5db4077 730 fp = fopen (SDATA (filename), "rt");
5ac45f98
GV
731 if (fp)
732 {
733 char buf[512];
734 int red, green, blue;
735 int num;
736
737 BLOCK_INPUT;
738
739 while (fgets (buf, sizeof (buf), fp) != NULL) {
740 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
741 {
742 char *name = buf + num;
743 num = strlen (name) - 1;
744 if (name[num] == '\n')
745 name[num] = 0;
746 cmap = Fcons (Fcons (build_string (name),
747 make_number (RGB (red, green, blue))),
748 cmap);
749 }
750 }
751 fclose (fp);
752
753 UNBLOCK_INPUT;
754 }
755
756 return cmap;
757}
ee78dc32 758
fbd6baed 759/* The default colors for the w32 color map */
7d0393cf 760typedef struct colormap_t
ee78dc32
GV
761{
762 char *name;
763 COLORREF colorref;
764} colormap_t;
765
7d0393cf 766colormap_t w32_color_map[] =
ee78dc32 767{
1da8a614
GV
768 {"snow" , PALETTERGB (255,250,250)},
769 {"ghost white" , PALETTERGB (248,248,255)},
770 {"GhostWhite" , PALETTERGB (248,248,255)},
771 {"white smoke" , PALETTERGB (245,245,245)},
772 {"WhiteSmoke" , PALETTERGB (245,245,245)},
773 {"gainsboro" , PALETTERGB (220,220,220)},
774 {"floral white" , PALETTERGB (255,250,240)},
775 {"FloralWhite" , PALETTERGB (255,250,240)},
776 {"old lace" , PALETTERGB (253,245,230)},
777 {"OldLace" , PALETTERGB (253,245,230)},
778 {"linen" , PALETTERGB (250,240,230)},
779 {"antique white" , PALETTERGB (250,235,215)},
780 {"AntiqueWhite" , PALETTERGB (250,235,215)},
781 {"papaya whip" , PALETTERGB (255,239,213)},
782 {"PapayaWhip" , PALETTERGB (255,239,213)},
783 {"blanched almond" , PALETTERGB (255,235,205)},
784 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
785 {"bisque" , PALETTERGB (255,228,196)},
786 {"peach puff" , PALETTERGB (255,218,185)},
787 {"PeachPuff" , PALETTERGB (255,218,185)},
788 {"navajo white" , PALETTERGB (255,222,173)},
789 {"NavajoWhite" , PALETTERGB (255,222,173)},
790 {"moccasin" , PALETTERGB (255,228,181)},
791 {"cornsilk" , PALETTERGB (255,248,220)},
792 {"ivory" , PALETTERGB (255,255,240)},
793 {"lemon chiffon" , PALETTERGB (255,250,205)},
794 {"LemonChiffon" , PALETTERGB (255,250,205)},
795 {"seashell" , PALETTERGB (255,245,238)},
796 {"honeydew" , PALETTERGB (240,255,240)},
797 {"mint cream" , PALETTERGB (245,255,250)},
798 {"MintCream" , PALETTERGB (245,255,250)},
799 {"azure" , PALETTERGB (240,255,255)},
800 {"alice blue" , PALETTERGB (240,248,255)},
801 {"AliceBlue" , PALETTERGB (240,248,255)},
802 {"lavender" , PALETTERGB (230,230,250)},
803 {"lavender blush" , PALETTERGB (255,240,245)},
804 {"LavenderBlush" , PALETTERGB (255,240,245)},
805 {"misty rose" , PALETTERGB (255,228,225)},
806 {"MistyRose" , PALETTERGB (255,228,225)},
807 {"white" , PALETTERGB (255,255,255)},
808 {"black" , PALETTERGB ( 0, 0, 0)},
809 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
810 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
811 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
812 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
813 {"dim gray" , PALETTERGB (105,105,105)},
814 {"DimGray" , PALETTERGB (105,105,105)},
815 {"dim grey" , PALETTERGB (105,105,105)},
816 {"DimGrey" , PALETTERGB (105,105,105)},
817 {"slate gray" , PALETTERGB (112,128,144)},
818 {"SlateGray" , PALETTERGB (112,128,144)},
819 {"slate grey" , PALETTERGB (112,128,144)},
820 {"SlateGrey" , PALETTERGB (112,128,144)},
821 {"light slate gray" , PALETTERGB (119,136,153)},
822 {"LightSlateGray" , PALETTERGB (119,136,153)},
823 {"light slate grey" , PALETTERGB (119,136,153)},
824 {"LightSlateGrey" , PALETTERGB (119,136,153)},
825 {"gray" , PALETTERGB (190,190,190)},
826 {"grey" , PALETTERGB (190,190,190)},
827 {"light grey" , PALETTERGB (211,211,211)},
828 {"LightGrey" , PALETTERGB (211,211,211)},
829 {"light gray" , PALETTERGB (211,211,211)},
830 {"LightGray" , PALETTERGB (211,211,211)},
831 {"midnight blue" , PALETTERGB ( 25, 25,112)},
832 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
833 {"navy" , PALETTERGB ( 0, 0,128)},
834 {"navy blue" , PALETTERGB ( 0, 0,128)},
835 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
836 {"cornflower blue" , PALETTERGB (100,149,237)},
837 {"CornflowerBlue" , PALETTERGB (100,149,237)},
838 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
839 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
840 {"slate blue" , PALETTERGB (106, 90,205)},
841 {"SlateBlue" , PALETTERGB (106, 90,205)},
842 {"medium slate blue" , PALETTERGB (123,104,238)},
843 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
844 {"light slate blue" , PALETTERGB (132,112,255)},
845 {"LightSlateBlue" , PALETTERGB (132,112,255)},
846 {"medium blue" , PALETTERGB ( 0, 0,205)},
847 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
848 {"royal blue" , PALETTERGB ( 65,105,225)},
849 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
850 {"blue" , PALETTERGB ( 0, 0,255)},
851 {"dodger blue" , PALETTERGB ( 30,144,255)},
852 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
853 {"deep sky blue" , PALETTERGB ( 0,191,255)},
854 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
855 {"sky blue" , PALETTERGB (135,206,235)},
856 {"SkyBlue" , PALETTERGB (135,206,235)},
857 {"light sky blue" , PALETTERGB (135,206,250)},
858 {"LightSkyBlue" , PALETTERGB (135,206,250)},
859 {"steel blue" , PALETTERGB ( 70,130,180)},
860 {"SteelBlue" , PALETTERGB ( 70,130,180)},
861 {"light steel blue" , PALETTERGB (176,196,222)},
862 {"LightSteelBlue" , PALETTERGB (176,196,222)},
863 {"light blue" , PALETTERGB (173,216,230)},
864 {"LightBlue" , PALETTERGB (173,216,230)},
865 {"powder blue" , PALETTERGB (176,224,230)},
866 {"PowderBlue" , PALETTERGB (176,224,230)},
867 {"pale turquoise" , PALETTERGB (175,238,238)},
868 {"PaleTurquoise" , PALETTERGB (175,238,238)},
869 {"dark turquoise" , PALETTERGB ( 0,206,209)},
870 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
871 {"medium turquoise" , PALETTERGB ( 72,209,204)},
872 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
873 {"turquoise" , PALETTERGB ( 64,224,208)},
874 {"cyan" , PALETTERGB ( 0,255,255)},
875 {"light cyan" , PALETTERGB (224,255,255)},
876 {"LightCyan" , PALETTERGB (224,255,255)},
877 {"cadet blue" , PALETTERGB ( 95,158,160)},
878 {"CadetBlue" , PALETTERGB ( 95,158,160)},
879 {"medium aquamarine" , PALETTERGB (102,205,170)},
880 {"MediumAquamarine" , PALETTERGB (102,205,170)},
881 {"aquamarine" , PALETTERGB (127,255,212)},
882 {"dark green" , PALETTERGB ( 0,100, 0)},
883 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
884 {"dark olive green" , PALETTERGB ( 85,107, 47)},
885 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
886 {"dark sea green" , PALETTERGB (143,188,143)},
887 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
888 {"sea green" , PALETTERGB ( 46,139, 87)},
889 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
890 {"medium sea green" , PALETTERGB ( 60,179,113)},
891 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
892 {"light sea green" , PALETTERGB ( 32,178,170)},
893 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
894 {"pale green" , PALETTERGB (152,251,152)},
895 {"PaleGreen" , PALETTERGB (152,251,152)},
896 {"spring green" , PALETTERGB ( 0,255,127)},
897 {"SpringGreen" , PALETTERGB ( 0,255,127)},
898 {"lawn green" , PALETTERGB (124,252, 0)},
899 {"LawnGreen" , PALETTERGB (124,252, 0)},
900 {"green" , PALETTERGB ( 0,255, 0)},
901 {"chartreuse" , PALETTERGB (127,255, 0)},
902 {"medium spring green" , PALETTERGB ( 0,250,154)},
903 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
904 {"green yellow" , PALETTERGB (173,255, 47)},
905 {"GreenYellow" , PALETTERGB (173,255, 47)},
906 {"lime green" , PALETTERGB ( 50,205, 50)},
907 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
908 {"yellow green" , PALETTERGB (154,205, 50)},
909 {"YellowGreen" , PALETTERGB (154,205, 50)},
910 {"forest green" , PALETTERGB ( 34,139, 34)},
911 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
912 {"olive drab" , PALETTERGB (107,142, 35)},
913 {"OliveDrab" , PALETTERGB (107,142, 35)},
914 {"dark khaki" , PALETTERGB (189,183,107)},
915 {"DarkKhaki" , PALETTERGB (189,183,107)},
916 {"khaki" , PALETTERGB (240,230,140)},
917 {"pale goldenrod" , PALETTERGB (238,232,170)},
918 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
919 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
920 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
921 {"light yellow" , PALETTERGB (255,255,224)},
922 {"LightYellow" , PALETTERGB (255,255,224)},
923 {"yellow" , PALETTERGB (255,255, 0)},
924 {"gold" , PALETTERGB (255,215, 0)},
925 {"light goldenrod" , PALETTERGB (238,221,130)},
926 {"LightGoldenrod" , PALETTERGB (238,221,130)},
927 {"goldenrod" , PALETTERGB (218,165, 32)},
928 {"dark goldenrod" , PALETTERGB (184,134, 11)},
929 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
930 {"rosy brown" , PALETTERGB (188,143,143)},
931 {"RosyBrown" , PALETTERGB (188,143,143)},
932 {"indian red" , PALETTERGB (205, 92, 92)},
933 {"IndianRed" , PALETTERGB (205, 92, 92)},
934 {"saddle brown" , PALETTERGB (139, 69, 19)},
935 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
936 {"sienna" , PALETTERGB (160, 82, 45)},
937 {"peru" , PALETTERGB (205,133, 63)},
938 {"burlywood" , PALETTERGB (222,184,135)},
939 {"beige" , PALETTERGB (245,245,220)},
940 {"wheat" , PALETTERGB (245,222,179)},
941 {"sandy brown" , PALETTERGB (244,164, 96)},
942 {"SandyBrown" , PALETTERGB (244,164, 96)},
943 {"tan" , PALETTERGB (210,180,140)},
944 {"chocolate" , PALETTERGB (210,105, 30)},
945 {"firebrick" , PALETTERGB (178,34, 34)},
946 {"brown" , PALETTERGB (165,42, 42)},
947 {"dark salmon" , PALETTERGB (233,150,122)},
948 {"DarkSalmon" , PALETTERGB (233,150,122)},
949 {"salmon" , PALETTERGB (250,128,114)},
950 {"light salmon" , PALETTERGB (255,160,122)},
951 {"LightSalmon" , PALETTERGB (255,160,122)},
952 {"orange" , PALETTERGB (255,165, 0)},
953 {"dark orange" , PALETTERGB (255,140, 0)},
954 {"DarkOrange" , PALETTERGB (255,140, 0)},
955 {"coral" , PALETTERGB (255,127, 80)},
956 {"light coral" , PALETTERGB (240,128,128)},
957 {"LightCoral" , PALETTERGB (240,128,128)},
958 {"tomato" , PALETTERGB (255, 99, 71)},
959 {"orange red" , PALETTERGB (255, 69, 0)},
960 {"OrangeRed" , PALETTERGB (255, 69, 0)},
961 {"red" , PALETTERGB (255, 0, 0)},
962 {"hot pink" , PALETTERGB (255,105,180)},
963 {"HotPink" , PALETTERGB (255,105,180)},
964 {"deep pink" , PALETTERGB (255, 20,147)},
965 {"DeepPink" , PALETTERGB (255, 20,147)},
966 {"pink" , PALETTERGB (255,192,203)},
967 {"light pink" , PALETTERGB (255,182,193)},
968 {"LightPink" , PALETTERGB (255,182,193)},
969 {"pale violet red" , PALETTERGB (219,112,147)},
970 {"PaleVioletRed" , PALETTERGB (219,112,147)},
971 {"maroon" , PALETTERGB (176, 48, 96)},
972 {"medium violet red" , PALETTERGB (199, 21,133)},
973 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
974 {"violet red" , PALETTERGB (208, 32,144)},
975 {"VioletRed" , PALETTERGB (208, 32,144)},
976 {"magenta" , PALETTERGB (255, 0,255)},
977 {"violet" , PALETTERGB (238,130,238)},
978 {"plum" , PALETTERGB (221,160,221)},
979 {"orchid" , PALETTERGB (218,112,214)},
980 {"medium orchid" , PALETTERGB (186, 85,211)},
981 {"MediumOrchid" , PALETTERGB (186, 85,211)},
982 {"dark orchid" , PALETTERGB (153, 50,204)},
983 {"DarkOrchid" , PALETTERGB (153, 50,204)},
984 {"dark violet" , PALETTERGB (148, 0,211)},
985 {"DarkViolet" , PALETTERGB (148, 0,211)},
986 {"blue violet" , PALETTERGB (138, 43,226)},
987 {"BlueViolet" , PALETTERGB (138, 43,226)},
988 {"purple" , PALETTERGB (160, 32,240)},
989 {"medium purple" , PALETTERGB (147,112,219)},
990 {"MediumPurple" , PALETTERGB (147,112,219)},
991 {"thistle" , PALETTERGB (216,191,216)},
992 {"gray0" , PALETTERGB ( 0, 0, 0)},
993 {"grey0" , PALETTERGB ( 0, 0, 0)},
994 {"dark grey" , PALETTERGB (169,169,169)},
995 {"DarkGrey" , PALETTERGB (169,169,169)},
996 {"dark gray" , PALETTERGB (169,169,169)},
997 {"DarkGray" , PALETTERGB (169,169,169)},
998 {"dark blue" , PALETTERGB ( 0, 0,139)},
999 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1000 {"dark cyan" , PALETTERGB ( 0,139,139)},
1001 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1002 {"dark magenta" , PALETTERGB (139, 0,139)},
1003 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1004 {"dark red" , PALETTERGB (139, 0, 0)},
1005 {"DarkRed" , PALETTERGB (139, 0, 0)},
1006 {"light green" , PALETTERGB (144,238,144)},
1007 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1008};
1009
fbd6baed 1010DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1011 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1012 ()
1013{
1014 int i;
fbd6baed 1015 colormap_t *pc = w32_color_map;
ee78dc32 1016 Lisp_Object cmap;
7d0393cf 1017
ee78dc32 1018 BLOCK_INPUT;
7d0393cf 1019
ee78dc32 1020 cmap = Qnil;
7d0393cf
JB
1021
1022 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1023 pc++, i++)
1024 cmap = Fcons (Fcons (build_string (pc->name),
1025 make_number (pc->colorref)),
1026 cmap);
7d0393cf 1027
ee78dc32 1028 UNBLOCK_INPUT;
7d0393cf 1029
ee78dc32
GV
1030 return (cmap);
1031}
ee78dc32 1032
7d0393cf 1033Lisp_Object
fbd6baed 1034w32_to_x_color (rgb)
ee78dc32
GV
1035 Lisp_Object rgb;
1036{
1037 Lisp_Object color;
7d0393cf 1038
b7826503 1039 CHECK_NUMBER (rgb);
7d0393cf 1040
ee78dc32 1041 BLOCK_INPUT;
7d0393cf 1042
fbd6baed 1043 color = Frassq (rgb, Vw32_color_map);
7d0393cf 1044
ee78dc32 1045 UNBLOCK_INPUT;
7d0393cf 1046
ee78dc32
GV
1047 if (!NILP (color))
1048 return (Fcar (color));
1049 else
1050 return Qnil;
1051}
1052
5d7fed93
GV
1053COLORREF
1054w32_color_map_lookup (colorname)
1055 char *colorname;
1056{
1057 Lisp_Object tail, ret = Qnil;
1058
1059 BLOCK_INPUT;
1060
1061 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1062 {
1063 register Lisp_Object elt, tem;
1064
1065 elt = Fcar (tail);
1066 if (!CONSP (elt)) continue;
1067
1068 tem = Fcar (elt);
1069
d5db4077 1070 if (lstrcmpi (SDATA (tem), colorname) == 0)
5d7fed93
GV
1071 {
1072 ret = XUINT (Fcdr (elt));
1073 break;
1074 }
1075
1076 QUIT;
1077 }
1078
1079
1080 UNBLOCK_INPUT;
1081
1082 return ret;
1083}
1084
5a8a15ec
JR
1085
1086static void
1087add_system_logical_colors_to_map (system_colors)
1088 Lisp_Object *system_colors;
1089{
1090 HKEY colors_key;
1091
1092 /* Other registry operations are done with input blocked. */
1093 BLOCK_INPUT;
1094
1095 /* Look for "Control Panel/Colors" under User and Machine registry
1096 settings. */
1097 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Control Panel\\Colors", 0,
1098 KEY_READ, &colors_key) == ERROR_SUCCESS
1099 || RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Control Panel\\Colors", 0,
1100 KEY_READ, &colors_key) == ERROR_SUCCESS)
1101 {
1102 /* List all keys. */
1103 char color_buffer[64];
1104 char full_name_buffer[MAX_PATH + SYSTEM_COLOR_PREFIX_LEN];
1105 int index = 0;
1106 DWORD name_size, color_size;
1107 char *name_buffer = full_name_buffer + SYSTEM_COLOR_PREFIX_LEN;
1108
1109 name_size = sizeof (full_name_buffer) - SYSTEM_COLOR_PREFIX_LEN;
1110 color_size = sizeof (color_buffer);
1111
1112 strcpy (full_name_buffer, SYSTEM_COLOR_PREFIX);
1113
1114 while (RegEnumValueA (colors_key, index, name_buffer, &name_size,
1115 NULL, NULL, color_buffer, &color_size)
1116 == ERROR_SUCCESS)
1117 {
1118 int r, g, b;
1119 if (sscanf (color_buffer, " %u %u %u", &r, &g, &b) == 3)
1120 *system_colors = Fcons (Fcons (build_string (full_name_buffer),
1121 make_number (RGB (r, g, b))),
1122 *system_colors);
1123
1124 name_size = sizeof (full_name_buffer) - SYSTEM_COLOR_PREFIX_LEN;
1125 color_size = sizeof (color_buffer);
1126 index++;
1127 }
1128 RegCloseKey (colors_key);
1129 }
1130
1131 UNBLOCK_INPUT;
1132}
1133
1134
7d0393cf 1135COLORREF
fbd6baed 1136x_to_w32_color (colorname)
ee78dc32
GV
1137 char * colorname;
1138{
8edb0a6f
JR
1139 register Lisp_Object ret = Qnil;
1140
ee78dc32 1141 BLOCK_INPUT;
1edf84e7
GV
1142
1143 if (colorname[0] == '#')
1144 {
1145 /* Could be an old-style RGB Device specification. */
1146 char *color;
1147 int size;
1148 color = colorname + 1;
7d0393cf 1149
1edf84e7
GV
1150 size = strlen(color);
1151 if (size == 3 || size == 6 || size == 9 || size == 12)
1152 {
1153 UINT colorval;
1154 int i, pos;
1155 pos = 0;
1156 size /= 3;
1157 colorval = 0;
7d0393cf 1158
1edf84e7
GV
1159 for (i = 0; i < 3; i++)
1160 {
1161 char *end;
1162 char t;
1163 unsigned long value;
1164
1165 /* The check for 'x' in the following conditional takes into
1166 account the fact that strtol allows a "0x" in front of
1167 our numbers, and we don't. */
1168 if (!isxdigit(color[0]) || color[1] == 'x')
1169 break;
1170 t = color[size];
1171 color[size] = '\0';
1172 value = strtoul(color, &end, 16);
1173 color[size] = t;
1174 if (errno == ERANGE || end - color != size)
1175 break;
1176 switch (size)
1177 {
1178 case 1:
1179 value = value * 0x10;
1180 break;
1181 case 2:
1182 break;
1183 case 3:
1184 value /= 0x10;
1185 break;
1186 case 4:
1187 value /= 0x100;
1188 break;
1189 }
1190 colorval |= (value << pos);
1191 pos += 0x8;
1192 if (i == 2)
1193 {
1194 UNBLOCK_INPUT;
1195 return (colorval);
1196 }
1197 color = end;
1198 }
1199 }
1200 }
1201 else if (strnicmp(colorname, "rgb:", 4) == 0)
1202 {
1203 char *color;
1204 UINT colorval;
1205 int i, pos;
1206 pos = 0;
1207
1208 colorval = 0;
1209 color = colorname + 4;
1210 for (i = 0; i < 3; i++)
1211 {
1212 char *end;
1213 unsigned long value;
7d0393cf 1214
1edf84e7
GV
1215 /* The check for 'x' in the following conditional takes into
1216 account the fact that strtol allows a "0x" in front of
1217 our numbers, and we don't. */
1218 if (!isxdigit(color[0]) || color[1] == 'x')
1219 break;
1220 value = strtoul(color, &end, 16);
1221 if (errno == ERANGE)
1222 break;
1223 switch (end - color)
1224 {
1225 case 1:
1226 value = value * 0x10 + value;
1227 break;
1228 case 2:
1229 break;
1230 case 3:
1231 value /= 0x10;
1232 break;
1233 case 4:
1234 value /= 0x100;
1235 break;
1236 default:
1237 value = ULONG_MAX;
1238 }
1239 if (value == ULONG_MAX)
1240 break;
1241 colorval |= (value << pos);
1242 pos += 0x8;
1243 if (i == 2)
1244 {
1245 if (*end != '\0')
1246 break;
1247 UNBLOCK_INPUT;
1248 return (colorval);
1249 }
1250 if (*end != '/')
1251 break;
1252 color = end + 1;
1253 }
1254 }
1255 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1256 {
1257 /* This is an RGB Intensity specification. */
1258 char *color;
1259 UINT colorval;
1260 int i, pos;
1261 pos = 0;
1262
1263 colorval = 0;
1264 color = colorname + 5;
1265 for (i = 0; i < 3; i++)
1266 {
1267 char *end;
1268 double value;
1269 UINT val;
1270
1271 value = strtod(color, &end);
1272 if (errno == ERANGE)
1273 break;
1274 if (value < 0.0 || value > 1.0)
1275 break;
1276 val = (UINT)(0x100 * value);
7d0393cf 1277 /* We used 0x100 instead of 0xFF to give a continuous
1edf84e7
GV
1278 range between 0.0 and 1.0 inclusive. The next statement
1279 fixes the 1.0 case. */
1280 if (val == 0x100)
1281 val = 0xFF;
1282 colorval |= (val << pos);
1283 pos += 0x8;
1284 if (i == 2)
1285 {
1286 if (*end != '\0')
1287 break;
1288 UNBLOCK_INPUT;
1289 return (colorval);
1290 }
1291 if (*end != '/')
1292 break;
1293 color = end + 1;
1294 }
1295 }
1296 /* I am not going to attempt to handle any of the CIE color schemes
1297 or TekHVC, since I don't know the algorithms for conversion to
1298 RGB. */
f695b4b1
GV
1299
1300 /* If we fail to lookup the color name in w32_color_map, then check the
7d0393cf 1301 colorname to see if it can be crudely approximated: If the X color
f695b4b1
GV
1302 ends in a number (e.g., "darkseagreen2"), strip the number and
1303 return the result of looking up the base color name. */
1304 ret = w32_color_map_lookup (colorname);
7d0393cf 1305 if (NILP (ret))
ee78dc32 1306 {
f695b4b1 1307 int len = strlen (colorname);
ee78dc32 1308
7d0393cf 1309 if (isdigit (colorname[len - 1]))
f695b4b1 1310 {
8b77111c 1311 char *ptr, *approx = alloca (len + 1);
ee78dc32 1312
f695b4b1
GV
1313 strcpy (approx, colorname);
1314 ptr = &approx[len - 1];
7d0393cf 1315 while (ptr > approx && isdigit (*ptr))
f695b4b1 1316 *ptr-- = '\0';
ee78dc32 1317
f695b4b1 1318 ret = w32_color_map_lookup (approx);
ee78dc32 1319 }
ee78dc32 1320 }
7d0393cf 1321
ee78dc32 1322 UNBLOCK_INPUT;
ee78dc32
GV
1323 return ret;
1324}
1325
5ac45f98 1326void
fbd6baed 1327w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1328{
fbd6baed 1329 struct w32_palette_entry * list;
5ac45f98
GV
1330 LOGPALETTE * log_palette;
1331 HPALETTE new_palette;
1332 int i;
1333
1334 /* don't bother trying to create palette if not supported */
fbd6baed 1335 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1336 return;
1337
1338 log_palette = (LOGPALETTE *)
1339 alloca (sizeof (LOGPALETTE) +
fbd6baed 1340 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1341 log_palette->palVersion = 0x300;
fbd6baed 1342 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1343
fbd6baed 1344 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1345 for (i = 0;
fbd6baed 1346 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1347 i++, list = list->next)
1348 log_palette->palPalEntry[i] = list->entry;
1349
1350 new_palette = CreatePalette (log_palette);
1351
1352 enter_crit ();
1353
fbd6baed
GV
1354 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1355 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1356 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1357
1358 /* Realize display palette and garbage all frames. */
1359 release_frame_dc (f, get_frame_dc (f));
1360
1361 leave_crit ();
1362}
1363
fbd6baed
GV
1364#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1365#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1366 do \
1367 { \
1368 pe.peRed = GetRValue (color); \
1369 pe.peGreen = GetGValue (color); \
1370 pe.peBlue = GetBValue (color); \
1371 pe.peFlags = 0; \
1372 } while (0)
1373
1374#if 0
1375/* Keep these around in case we ever want to track color usage. */
1376void
fbd6baed 1377w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1378{
fbd6baed 1379 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1380
fbd6baed 1381 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1382 return;
1383
1384 /* check if color is already mapped */
1385 while (list)
1386 {
fbd6baed 1387 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1388 {
1389 ++list->refcount;
1390 return;
1391 }
1392 list = list->next;
1393 }
1394
1395 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1396 list = (struct w32_palette_entry *)
1397 xmalloc (sizeof (struct w32_palette_entry));
1398 SET_W32_COLOR (list->entry, color);
5ac45f98 1399 list->refcount = 1;
fbd6baed
GV
1400 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1401 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1402 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1403
1404 /* set flag that palette must be regenerated */
fbd6baed 1405 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1406}
1407
1408void
fbd6baed 1409w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1410{
fbd6baed
GV
1411 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1412 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1413
fbd6baed 1414 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1415 return;
1416
1417 /* check if color is already mapped */
1418 while (list)
1419 {
fbd6baed 1420 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1421 {
1422 if (--list->refcount == 0)
1423 {
1424 *prev = list->next;
1425 xfree (list);
fbd6baed 1426 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1427 break;
1428 }
1429 else
1430 return;
1431 }
1432 prev = &list->next;
1433 list = list->next;
1434 }
1435
1436 /* set flag that palette must be regenerated */
fbd6baed 1437 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1438}
1439#endif
1440
6fc2811b
JR
1441
1442/* Gamma-correct COLOR on frame F. */
1443
1444void
1445gamma_correct (f, color)
1446 struct frame *f;
1447 COLORREF *color;
1448{
1449 if (f->gamma)
1450 {
1451 *color = PALETTERGB (
1452 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1453 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1454 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1455 }
1456}
1457
1458
ee78dc32
GV
1459/* Decide if color named COLOR is valid for the display associated with
1460 the selected frame; if so, return the rgb values in COLOR_DEF.
1461 If ALLOC is nonzero, allocate a new colormap cell. */
1462
1463int
6fc2811b 1464w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1465 FRAME_PTR f;
1466 char *color;
6fc2811b 1467 XColor *color_def;
ee78dc32
GV
1468 int alloc;
1469{
1470 register Lisp_Object tem;
6fc2811b 1471 COLORREF w32_color_ref;
3c190163 1472
fbd6baed 1473 tem = x_to_w32_color (color);
3c190163 1474
7d0393cf 1475 if (!NILP (tem))
ee78dc32 1476 {
d88c567c
JR
1477 if (f)
1478 {
1479 /* Apply gamma correction. */
1480 w32_color_ref = XUINT (tem);
1481 gamma_correct (f, &w32_color_ref);
1482 XSETINT (tem, w32_color_ref);
1483 }
9badad41
JR
1484
1485 /* Map this color to the palette if it is enabled. */
fbd6baed 1486 if (!NILP (Vw32_enable_palette))
5ac45f98 1487 {
fbd6baed 1488 struct w32_palette_entry * entry =
d88c567c 1489 one_w32_display_info.color_list;
fbd6baed 1490 struct w32_palette_entry ** prev =
d88c567c 1491 &one_w32_display_info.color_list;
7d0393cf 1492
5ac45f98
GV
1493 /* check if color is already mapped */
1494 while (entry)
1495 {
fbd6baed 1496 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1497 break;
1498 prev = &entry->next;
1499 entry = entry->next;
1500 }
1501
1502 if (entry == NULL && alloc)
1503 {
1504 /* not already mapped, so add to list */
fbd6baed
GV
1505 entry = (struct w32_palette_entry *)
1506 xmalloc (sizeof (struct w32_palette_entry));
1507 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1508 entry->next = NULL;
1509 *prev = entry;
d88c567c 1510 one_w32_display_info.num_colors++;
5ac45f98
GV
1511
1512 /* set flag that palette must be regenerated */
d88c567c 1513 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1514 }
1515 }
1516 /* Ensure COLORREF value is snapped to nearest color in (default)
1517 palette by simulating the PALETTERGB macro. This works whether
1518 or not the display device has a palette. */
6fc2811b
JR
1519 w32_color_ref = XUINT (tem) | 0x2000000;
1520
6fc2811b 1521 color_def->pixel = w32_color_ref;
197edd35
JR
1522 color_def->red = GetRValue (w32_color_ref) * 256;
1523 color_def->green = GetGValue (w32_color_ref) * 256;
1524 color_def->blue = GetBValue (w32_color_ref) * 256;
6fc2811b 1525
ee78dc32 1526 return 1;
5ac45f98 1527 }
7d0393cf 1528 else
3c190163
GV
1529 {
1530 return 0;
1531 }
ee78dc32
GV
1532}
1533
1534/* Given a string ARG naming a color, compute a pixel value from it
1535 suitable for screen F.
1536 If F is not a color screen, return DEF (default) regardless of what
1537 ARG says. */
1538
1539int
1540x_decode_color (f, arg, def)
1541 FRAME_PTR f;
1542 Lisp_Object arg;
1543 int def;
1544{
6fc2811b 1545 XColor cdef;
ee78dc32 1546
b7826503 1547 CHECK_STRING (arg);
ee78dc32 1548
d5db4077 1549 if (strcmp (SDATA (arg), "black") == 0)
ee78dc32 1550 return BLACK_PIX_DEFAULT (f);
d5db4077 1551 else if (strcmp (SDATA (arg), "white") == 0)
ee78dc32
GV
1552 return WHITE_PIX_DEFAULT (f);
1553
fbd6baed 1554 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1555 return def;
1556
6fc2811b 1557 /* w32_defined_color is responsible for coping with failures
ee78dc32 1558 by looking for a near-miss. */
d5db4077 1559 if (w32_defined_color (f, SDATA (arg), &cdef, 1))
6fc2811b 1560 return cdef.pixel;
ee78dc32
GV
1561
1562 /* defined_color failed; return an ultimate default. */
1563 return def;
1564}
1565\f
6fc2811b
JR
1566
1567
ee78dc32
GV
1568/* Functions called only from `x_set_frame_param'
1569 to set individual parameters.
1570
fbd6baed 1571 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1572 the frame is being created and its window does not exist yet.
1573 In that case, just record the parameter's new value
1574 in the standard place; do not attempt to change the window. */
1575
1576void
1577x_set_foreground_color (f, arg, oldval)
1578 struct frame *f;
1579 Lisp_Object arg, oldval;
1580{
3cf3436e
JR
1581 struct w32_output *x = f->output_data.w32;
1582 PIX_TYPE fg, old_fg;
1583
1584 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1585 old_fg = FRAME_FOREGROUND_PIXEL (f);
1586 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 1587
fbd6baed 1588 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1589 {
3cf3436e
JR
1590 if (x->cursor_pixel == old_fg)
1591 x->cursor_pixel = fg;
1592
6fc2811b 1593 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
1594 if (FRAME_VISIBLE_P (f))
1595 redraw_frame (f);
1596 }
1597}
1598
1599void
1600x_set_background_color (f, arg, oldval)
1601 struct frame *f;
1602 Lisp_Object arg, oldval;
1603{
6fc2811b 1604 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
1605 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1606
fbd6baed 1607 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1608 {
6fc2811b
JR
1609 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
1610 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 1611
6fc2811b 1612 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
1613
1614 if (FRAME_VISIBLE_P (f))
1615 redraw_frame (f);
1616 }
1617}
1618
1619void
1620x_set_mouse_color (f, arg, oldval)
1621 struct frame *f;
1622 Lisp_Object arg, oldval;
1623{
7d63e5e3 1624 Cursor cursor, nontext_cursor, mode_cursor, hand_cursor;
dfc465d3 1625 int count;
ee78dc32
GV
1626 int mask_color;
1627
1628 if (!EQ (Qnil, arg))
fbd6baed 1629 f->output_data.w32->mouse_pixel
ee78dc32 1630 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
1631 mask_color = FRAME_BACKGROUND_PIXEL (f);
1632
1633 /* Don't let pointers be invisible. */
fbd6baed 1634 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
1635 && mask_color == FRAME_BACKGROUND_PIXEL (f))
1636 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 1637
767b1ff0 1638#if 0 /* TODO : cursor changes */
ee78dc32
GV
1639 BLOCK_INPUT;
1640
1641 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 1642 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
1643
1644 if (!EQ (Qnil, Vx_pointer_shape))
1645 {
b7826503 1646 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 1647 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
1648 }
1649 else
fbd6baed
GV
1650 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1651 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
1652
1653 if (!EQ (Qnil, Vx_nontext_pointer_shape))
1654 {
b7826503 1655 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 1656 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
1657 XINT (Vx_nontext_pointer_shape));
1658 }
1659 else
fbd6baed
GV
1660 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
1661 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 1662
0af913d7 1663 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 1664 {
b7826503 1665 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
1666 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1667 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
1668 }
1669 else
0af913d7 1670 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b 1671 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
7d0393cf 1672
6fc2811b 1673 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
1674 if (!EQ (Qnil, Vx_mode_pointer_shape))
1675 {
b7826503 1676 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 1677 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
1678 XINT (Vx_mode_pointer_shape));
1679 }
1680 else
fbd6baed
GV
1681 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1682 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
1683
1684 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
1685 {
b7826503 1686 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
7d63e5e3 1687 hand_cursor
fbd6baed 1688 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
1689 XINT (Vx_sensitive_text_pointer_shape));
1690 }
1691 else
7d63e5e3 1692 hand_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 1693
4694d762
JR
1694 if (!NILP (Vx_window_horizontal_drag_shape))
1695 {
b7826503 1696 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
1697 horizontal_drag_cursor
1698 = XCreateFontCursor (FRAME_X_DISPLAY (f),
1699 XINT (Vx_window_horizontal_drag_shape));
1700 }
1701 else
1702 horizontal_drag_cursor
1703 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
1704
ee78dc32 1705 /* Check and report errors with the above calls. */
fbd6baed 1706 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 1707 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
1708
1709 {
1710 XColor fore_color, back_color;
1711
fbd6baed 1712 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 1713 back_color.pixel = mask_color;
fbd6baed
GV
1714 XQueryColor (FRAME_W32_DISPLAY (f),
1715 DefaultColormap (FRAME_W32_DISPLAY (f),
1716 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 1717 &fore_color);
fbd6baed
GV
1718 XQueryColor (FRAME_W32_DISPLAY (f),
1719 DefaultColormap (FRAME_W32_DISPLAY (f),
1720 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 1721 &back_color);
fbd6baed 1722 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 1723 &fore_color, &back_color);
fbd6baed 1724 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 1725 &fore_color, &back_color);
fbd6baed 1726 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 1727 &fore_color, &back_color);
7d63e5e3 1728 XRecolorCursor (FRAME_W32_DISPLAY (f), hand_cursor,
ee78dc32 1729 &fore_color, &back_color);
0af913d7 1730 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 1731 &fore_color, &back_color);
ee78dc32
GV
1732 }
1733
fbd6baed 1734 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 1735 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 1736
fbd6baed
GV
1737 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
1738 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
1739 f->output_data.w32->text_cursor = cursor;
1740
1741 if (nontext_cursor != f->output_data.w32->nontext_cursor
1742 && f->output_data.w32->nontext_cursor != 0)
1743 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
1744 f->output_data.w32->nontext_cursor = nontext_cursor;
1745
0af913d7
GM
1746 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
1747 && f->output_data.w32->hourglass_cursor != 0)
1748 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
1749 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 1750
fbd6baed
GV
1751 if (mode_cursor != f->output_data.w32->modeline_cursor
1752 && f->output_data.w32->modeline_cursor != 0)
1753 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
1754 f->output_data.w32->modeline_cursor = mode_cursor;
7d0393cf 1755
7d63e5e3
KS
1756 if (hand_cursor != f->output_data.w32->hand_cursor
1757 && f->output_data.w32->hand_cursor != 0)
1758 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hand_cursor);
1759 f->output_data.w32->hand_cursor = hand_cursor;
fbd6baed
GV
1760
1761 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 1762 UNBLOCK_INPUT;
6fc2811b
JR
1763
1764 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 1765#endif /* TODO */
ee78dc32
GV
1766}
1767
70a0239a 1768/* Defined in w32term.c. */
ee78dc32
GV
1769void
1770x_set_cursor_color (f, arg, oldval)
1771 struct frame *f;
1772 Lisp_Object arg, oldval;
1773{
70a0239a 1774 unsigned long fore_pixel, pixel;
ee78dc32 1775
dfff8a69 1776 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 1777 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 1778 WHITE_PIX_DEFAULT (f));
ee78dc32 1779 else
6fc2811b 1780 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 1781
6759f872 1782 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
7d0393cf 1783
ee78dc32 1784 /* Make sure that the cursor color differs from the background color. */
70a0239a 1785 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 1786 {
70a0239a
JR
1787 pixel = f->output_data.w32->mouse_pixel;
1788 if (pixel == fore_pixel)
6fc2811b 1789 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 1790 }
70a0239a 1791
ac849ba4 1792 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
70a0239a 1793 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 1794
fbd6baed 1795 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1796 {
0327b4cc
JR
1797 BLOCK_INPUT;
1798 /* Update frame's cursor_gc. */
1799 f->output_data.w32->cursor_gc->foreground = fore_pixel;
1800 f->output_data.w32->cursor_gc->background = pixel;
1801
1802 UNBLOCK_INPUT;
1803
ee78dc32
GV
1804 if (FRAME_VISIBLE_P (f))
1805 {
70a0239a
JR
1806 x_update_cursor (f, 0);
1807 x_update_cursor (f, 1);
ee78dc32
GV
1808 }
1809 }
6fc2811b
JR
1810
1811 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
1812}
1813
33d52f9c
GV
1814/* Set the border-color of frame F to pixel value PIX.
1815 Note that this does not fully take effect if done before
7d0393cf 1816 F has a window. */
6d906347 1817
33d52f9c
GV
1818void
1819x_set_border_pixel (f, pix)
1820 struct frame *f;
1821 int pix;
1822{
6d906347 1823
33d52f9c
GV
1824 f->output_data.w32->border_pixel = pix;
1825
be786000 1826 if (FRAME_W32_WINDOW (f) != 0 && f->border_width > 0)
33d52f9c
GV
1827 {
1828 if (FRAME_VISIBLE_P (f))
1829 redraw_frame (f);
1830 }
1831}
1832
ee78dc32
GV
1833/* Set the border-color of frame F to value described by ARG.
1834 ARG can be a string naming a color.
1835 The border-color is used for the border that is drawn by the server.
1836 Note that this does not fully take effect if done before
1837 F has a window; it must be redone when the window is created. */
1838
1839void
1840x_set_border_color (f, arg, oldval)
1841 struct frame *f;
1842 Lisp_Object arg, oldval;
1843{
ee78dc32
GV
1844 int pix;
1845
b7826503 1846 CHECK_STRING (arg);
ee78dc32 1847 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 1848 x_set_border_pixel (f, pix);
6fc2811b 1849 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
1850}
1851
dfff8a69
JR
1852
1853void
1854x_set_cursor_type (f, arg, oldval)
1855 FRAME_PTR f;
1856 Lisp_Object arg, oldval;
1857{
50e363e6 1858 set_frame_cursor_types (f, arg);
ee78dc32 1859
623cdbf2 1860 /* Make sure the cursor gets redrawn. */
c922a224 1861 cursor_type_changed = 1;
ee78dc32 1862}
dfff8a69 1863\f
ee78dc32
GV
1864void
1865x_set_icon_type (f, arg, oldval)
1866 struct frame *f;
1867 Lisp_Object arg, oldval;
1868{
ee78dc32
GV
1869 int result;
1870
eb7576ce
GV
1871 if (NILP (arg) && NILP (oldval))
1872 return;
1873
7d0393cf 1874 if (STRINGP (arg) && STRINGP (oldval)
eb7576ce
GV
1875 && EQ (Fstring_equal (oldval, arg), Qt))
1876 return;
1877
1878 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
1879 return;
1880
1881 BLOCK_INPUT;
ee78dc32 1882
eb7576ce 1883 result = x_bitmap_icon (f, arg);
ee78dc32
GV
1884 if (result)
1885 {
1886 UNBLOCK_INPUT;
1887 error ("No icon window available");
1888 }
1889
ee78dc32 1890 UNBLOCK_INPUT;
ee78dc32
GV
1891}
1892
ee78dc32
GV
1893void
1894x_set_icon_name (f, arg, oldval)
1895 struct frame *f;
1896 Lisp_Object arg, oldval;
1897{
ee78dc32
GV
1898 if (STRINGP (arg))
1899 {
1900 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1901 return;
1902 }
1903 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
1904 return;
1905
1906 f->icon_name = arg;
1907
1908#if 0
fbd6baed 1909 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
1910 return;
1911
1912 BLOCK_INPUT;
1913
1914 result = x_text_icon (f,
d5db4077
KR
1915 (char *) SDATA ((!NILP (f->icon_name)
1916 ? f->icon_name
1917 : !NILP (f->title)
1918 ? f->title
1919 : f->name)));
ee78dc32
GV
1920
1921 if (result)
1922 {
1923 UNBLOCK_INPUT;
1924 error ("No icon window available");
1925 }
1926
1927 /* If the window was unmapped (and its icon was mapped),
1928 the new icon is not mapped, so map the window in its stead. */
1929 if (FRAME_VISIBLE_P (f))
1930 {
1931#ifdef USE_X_TOOLKIT
fbd6baed 1932 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 1933#endif
fbd6baed 1934 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
1935 }
1936
fbd6baed 1937 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
1938 UNBLOCK_INPUT;
1939#endif
1940}
1941
a1258667 1942\f
ee78dc32
GV
1943void
1944x_set_menu_bar_lines (f, value, oldval)
1945 struct frame *f;
1946 Lisp_Object value, oldval;
1947{
1948 int nlines;
1949 int olines = FRAME_MENU_BAR_LINES (f);
1950
1951 /* Right now, menu bars don't work properly in minibuf-only frames;
1952 most of the commands try to apply themselves to the minibuffer
6fc2811b 1953 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
1954 in or split the minibuffer window. */
1955 if (FRAME_MINIBUF_ONLY_P (f))
1956 return;
1957
1958 if (INTEGERP (value))
1959 nlines = XINT (value);
1960 else
1961 nlines = 0;
1962
1963 FRAME_MENU_BAR_LINES (f) = 0;
1964 if (nlines)
1965 FRAME_EXTERNAL_MENU_BAR (f) = 1;
1966 else
1967 {
1968 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
1969 free_frame_menubar (f);
1970 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
1971
1972 /* Adjust the frame size so that the client (text) dimensions
1973 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
1974 set correctly. */
be786000 1975 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6fc2811b 1976 do_pending_window_change (0);
ee78dc32 1977 }
6fc2811b
JR
1978 adjust_glyphs (f);
1979}
1980
1981
1982/* Set the number of lines used for the tool bar of frame F to VALUE.
1983 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
1984 is the old number of tool bar lines. This function changes the
1985 height of all windows on frame F to match the new tool bar height.
1986 The frame's height doesn't change. */
1987
1988void
1989x_set_tool_bar_lines (f, value, oldval)
1990 struct frame *f;
1991 Lisp_Object value, oldval;
1992{
36f8209a
JR
1993 int delta, nlines, root_height;
1994 Lisp_Object root_window;
6fc2811b 1995
dc220243
JR
1996 /* Treat tool bars like menu bars. */
1997 if (FRAME_MINIBUF_ONLY_P (f))
1998 return;
1999
6fc2811b
JR
2000 /* Use VALUE only if an integer >= 0. */
2001 if (INTEGERP (value) && XINT (value) >= 0)
2002 nlines = XFASTINT (value);
2003 else
2004 nlines = 0;
2005
2006 /* Make sure we redisplay all windows in this frame. */
2007 ++windows_or_buffers_changed;
2008
2009 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2010
2011 /* Don't resize the tool-bar to more than we have room for. */
2012 root_window = FRAME_ROOT_WINDOW (f);
be786000 2013 root_height = WINDOW_TOTAL_LINES (XWINDOW (root_window));
36f8209a
JR
2014 if (root_height - delta < 1)
2015 {
2016 delta = root_height - 1;
2017 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2018 }
2019
6fc2811b 2020 FRAME_TOOL_BAR_LINES (f) = nlines;
6d906347 2021 change_window_heights (root_window, delta);
6fc2811b 2022 adjust_glyphs (f);
36f8209a
JR
2023
2024 /* We also have to make sure that the internal border at the top of
2025 the frame, below the menu bar or tool bar, is redrawn when the
2026 tool bar disappears. This is so because the internal border is
2027 below the tool bar if one is displayed, but is below the menu bar
2028 if there isn't a tool bar. The tool bar draws into the area
2029 below the menu bar. */
2030 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2031 {
2032 updating_frame = f;
2033 clear_frame ();
2034 clear_current_matrices (f);
2035 updating_frame = NULL;
2036 }
2037
2038 /* If the tool bar gets smaller, the internal border below it
2039 has to be cleared. It was formerly part of the display
2040 of the larger tool bar, and updating windows won't clear it. */
2041 if (delta < 0)
2042 {
2043 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
be786000
KS
2044 int width = FRAME_PIXEL_WIDTH (f);
2045 int y = nlines * FRAME_LINE_HEIGHT (f);
36f8209a
JR
2046
2047 BLOCK_INPUT;
2048 {
2049 HDC hdc = get_frame_dc (f);
2050 w32_clear_area (f, hdc, 0, y, width, height);
2051 release_frame_dc (f, hdc);
2052 }
2053 UNBLOCK_INPUT;
3cf3436e
JR
2054
2055 if (WINDOWP (f->tool_bar_window))
2056 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2057 }
ee78dc32
GV
2058}
2059
6fc2811b 2060
ee78dc32 2061/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2062 w32_id_name.
ee78dc32
GV
2063
2064 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2065 name; if NAME is a string, set F's name to NAME and set
2066 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2067
2068 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2069 suggesting a new name, which lisp code should override; if
2070 F->explicit_name is set, ignore the new name; otherwise, set it. */
2071
2072void
2073x_set_name (f, name, explicit)
2074 struct frame *f;
2075 Lisp_Object name;
2076 int explicit;
2077{
7d0393cf 2078 /* Make sure that requests from lisp code override requests from
ee78dc32
GV
2079 Emacs redisplay code. */
2080 if (explicit)
2081 {
2082 /* If we're switching from explicit to implicit, we had better
2083 update the mode lines and thereby update the title. */
2084 if (f->explicit_name && NILP (name))
2085 update_mode_lines = 1;
2086
2087 f->explicit_name = ! NILP (name);
2088 }
2089 else if (f->explicit_name)
2090 return;
2091
fbd6baed 2092 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2093 if (NILP (name))
2094 {
2095 /* Check for no change needed in this very common case
2096 before we do any consing. */
fbd6baed 2097 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
d5db4077 2098 SDATA (f->name)))
ee78dc32 2099 return;
fbd6baed 2100 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2101 }
2102 else
b7826503 2103 CHECK_STRING (name);
ee78dc32
GV
2104
2105 /* Don't change the name if it's already NAME. */
2106 if (! NILP (Fstring_equal (name, f->name)))
2107 return;
2108
1edf84e7
GV
2109 f->name = name;
2110
2111 /* For setting the frame title, the title parameter should override
2112 the name parameter. */
2113 if (! NILP (f->title))
2114 name = f->title;
2115
fbd6baed 2116 if (FRAME_W32_WINDOW (f))
ee78dc32 2117 {
6fc2811b 2118 if (STRING_MULTIBYTE (name))
dfff8a69 2119 name = ENCODE_SYSTEM (name);
6fc2811b 2120
ee78dc32 2121 BLOCK_INPUT;
d5db4077 2122 SetWindowText(FRAME_W32_WINDOW (f), SDATA (name));
ee78dc32
GV
2123 UNBLOCK_INPUT;
2124 }
ee78dc32
GV
2125}
2126
2127/* This function should be called when the user's lisp code has
2128 specified a name for the frame; the name will override any set by the
2129 redisplay code. */
2130void
2131x_explicitly_set_name (f, arg, oldval)
2132 FRAME_PTR f;
2133 Lisp_Object arg, oldval;
2134{
2135 x_set_name (f, arg, 1);
2136}
2137
2138/* This function should be called by Emacs redisplay code to set the
2139 name; names set this way will never override names set by the user's
2140 lisp code. */
2141void
2142x_implicitly_set_name (f, arg, oldval)
2143 FRAME_PTR f;
2144 Lisp_Object arg, oldval;
2145{
2146 x_set_name (f, arg, 0);
2147}
1edf84e7
GV
2148\f
2149/* Change the title of frame F to NAME.
2150 If NAME is nil, use the frame name as the title.
2151
2152 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2153 name; if NAME is a string, set F's name to NAME and set
2154 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2155
2156 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2157 suggesting a new name, which lisp code should override; if
2158 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2159
1edf84e7 2160void
6fc2811b 2161x_set_title (f, name, old_name)
1edf84e7 2162 struct frame *f;
6fc2811b 2163 Lisp_Object name, old_name;
1edf84e7
GV
2164{
2165 /* Don't change the title if it's already NAME. */
2166 if (EQ (name, f->title))
2167 return;
2168
2169 update_mode_lines = 1;
2170
2171 f->title = name;
2172
2173 if (NILP (name))
2174 name = f->name;
2175
2176 if (FRAME_W32_WINDOW (f))
2177 {
6fc2811b 2178 if (STRING_MULTIBYTE (name))
dfff8a69 2179 name = ENCODE_SYSTEM (name);
6fc2811b 2180
1edf84e7 2181 BLOCK_INPUT;
d5db4077 2182 SetWindowText(FRAME_W32_WINDOW (f), SDATA (name));
1edf84e7
GV
2183 UNBLOCK_INPUT;
2184 }
2185}
ee78dc32 2186
ee78dc32 2187
19f093e5 2188void x_set_scroll_bar_default_width (f)
ee78dc32 2189 struct frame *f;
ee78dc32 2190{
be786000 2191 int wid = FRAME_COLUMN_WIDTH (f);
6fc2811b 2192
be786000
KS
2193 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2194 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) +
2195 wid - 1) / wid;
ee78dc32 2196}
6d906347 2197
ee78dc32 2198\f
7d0393cf 2199/* Subroutines of creating a frame. */
ee78dc32 2200
ee78dc32
GV
2201
2202/* Return the value of parameter PARAM.
2203
2204 First search ALIST, then Vdefault_frame_alist, then the X defaults
2205 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2206
2207 Convert the resource to the type specified by desired_type.
2208
2209 If no default is specified, return Qunbound. If you call
6fc2811b 2210 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
2211 and don't let it get stored in any Lisp-visible variables! */
2212
2213static Lisp_Object
6fc2811b 2214w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
2215 Lisp_Object alist, param;
2216 char *attribute;
2217 char *class;
2218 enum resource_types type;
2219{
6d906347
KS
2220 return x_get_arg (check_x_display_info (Qnil),
2221 alist, param, attribute, class, type);
ee78dc32
GV
2222}
2223
2224\f
c9b2104d
JR
2225Cursor
2226w32_load_cursor (LPCTSTR name)
2227{
2228 /* Try first to load cursor from application resource. */
2229 Cursor cursor = LoadImage ((HINSTANCE) GetModuleHandle(NULL),
2230 name, IMAGE_CURSOR, 0, 0,
2231 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
2232 if (!cursor)
2233 {
2234 /* Then try to load a shared predefined cursor. */
2235 cursor = LoadImage (NULL, name, IMAGE_CURSOR, 0, 0,
2236 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
2237 }
2238 return cursor;
2239}
ee78dc32 2240
fbd6baed 2241extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32 2242
7d0393cf 2243BOOL
fbd6baed 2244w32_init_class (hinst)
ee78dc32
GV
2245 HINSTANCE hinst;
2246{
2247 WNDCLASS wc;
2248
5ac45f98 2249 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 2250 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
2251 wc.cbClsExtra = 0;
2252 wc.cbWndExtra = WND_EXTRA_BYTES;
2253 wc.hInstance = hinst;
2254 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
c9b2104d 2255 wc.hCursor = w32_load_cursor (IDC_ARROW);
4587b026 2256 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
2257 wc.lpszMenuName = NULL;
2258 wc.lpszClassName = EMACS_CLASS;
2259
2260 return (RegisterClass (&wc));
2261}
2262
7d0393cf 2263HWND
fbd6baed 2264w32_createscrollbar (f, bar)
ee78dc32
GV
2265 struct frame *f;
2266 struct scroll_bar * bar;
2267{
2268 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
2269 /* Position and size of scroll bar. */
6fc2811b 2270 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7d0393cf 2271 XINT(bar->top),
6fc2811b
JR
2272 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
2273 XINT(bar->height),
fbd6baed 2274 FRAME_W32_WINDOW (f),
ee78dc32
GV
2275 NULL,
2276 hinst,
2277 NULL));
2278}
2279
7d0393cf 2280void
fbd6baed 2281w32_createwindow (f)
ee78dc32
GV
2282 struct frame *f;
2283{
2284 HWND hwnd;
1edf84e7
GV
2285 RECT rect;
2286
2287 rect.left = rect.top = 0;
be786000
KS
2288 rect.right = FRAME_PIXEL_WIDTH (f);
2289 rect.bottom = FRAME_PIXEL_HEIGHT (f);
7d0393cf 2290
1edf84e7
GV
2291 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
2292 FRAME_EXTERNAL_MENU_BAR (f));
7d0393cf 2293
ee78dc32 2294 /* Do first time app init */
7d0393cf 2295
ee78dc32
GV
2296 if (!hprevinst)
2297 {
fbd6baed 2298 w32_init_class (hinst);
ee78dc32 2299 }
7d0393cf 2300
1edf84e7
GV
2301 FRAME_W32_WINDOW (f) = hwnd
2302 = CreateWindow (EMACS_CLASS,
2303 f->namebuf,
9ead1b60 2304 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
be786000
KS
2305 f->left_pos,
2306 f->top_pos,
1edf84e7
GV
2307 rect.right - rect.left,
2308 rect.bottom - rect.top,
2309 NULL,
2310 NULL,
2311 hinst,
2312 NULL);
2313
ee78dc32
GV
2314 if (hwnd)
2315 {
be786000
KS
2316 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
2317 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
2318 SetWindowLong (hwnd, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
2319 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->scroll_bar_actual_width);
6fc2811b 2320 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2321
cb9e33d4
RS
2322 /* Enable drag-n-drop. */
2323 DragAcceptFiles (hwnd, TRUE);
7d0393cf 2324
5ac45f98
GV
2325 /* Do this to discard the default setting specified by our parent. */
2326 ShowWindow (hwnd, SW_HIDE);
3c190163 2327 }
3c190163
GV
2328}
2329
7d0393cf 2330void
ee78dc32 2331my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 2332 W32Msg * wmsg;
ee78dc32
GV
2333 HWND hwnd;
2334 UINT msg;
2335 WPARAM wParam;
2336 LPARAM lParam;
2337{
2338 wmsg->msg.hwnd = hwnd;
2339 wmsg->msg.message = msg;
2340 wmsg->msg.wParam = wParam;
2341 wmsg->msg.lParam = lParam;
2342 wmsg->msg.time = GetMessageTime ();
2343
2344 post_msg (wmsg);
2345}
2346
e9e23e23 2347/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
2348 between left and right keys as advertised. We test for this
2349 support dynamically, and set a flag when the support is absent. If
2350 absent, we keep track of the left and right control and alt keys
2351 ourselves. This is particularly necessary on keyboards that rely
2352 upon the AltGr key, which is represented as having the left control
2353 and right alt keys pressed. For these keyboards, we need to know
2354 when the left alt key has been pressed in addition to the AltGr key
2355 so that we can properly support M-AltGr-key sequences (such as M-@
2356 on Swedish keyboards). */
2357
2358#define EMACS_LCONTROL 0
2359#define EMACS_RCONTROL 1
2360#define EMACS_LMENU 2
2361#define EMACS_RMENU 3
2362
2363static int modifiers[4];
2364static int modifiers_recorded;
2365static int modifier_key_support_tested;
2366
2367static void
2368test_modifier_support (unsigned int wparam)
2369{
2370 unsigned int l, r;
2371
2372 if (wparam != VK_CONTROL && wparam != VK_MENU)
2373 return;
2374 if (wparam == VK_CONTROL)
2375 {
2376 l = VK_LCONTROL;
2377 r = VK_RCONTROL;
2378 }
2379 else
2380 {
2381 l = VK_LMENU;
2382 r = VK_RMENU;
2383 }
2384 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
2385 modifiers_recorded = 1;
2386 else
2387 modifiers_recorded = 0;
2388 modifier_key_support_tested = 1;
2389}
2390
2391static void
2392record_keydown (unsigned int wparam, unsigned int lparam)
2393{
2394 int i;
2395
2396 if (!modifier_key_support_tested)
2397 test_modifier_support (wparam);
2398
2399 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
2400 return;
2401
2402 if (wparam == VK_CONTROL)
2403 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
2404 else
2405 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
2406
2407 modifiers[i] = 1;
2408}
2409
2410static void
2411record_keyup (unsigned int wparam, unsigned int lparam)
2412{
2413 int i;
2414
2415 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
2416 return;
2417
2418 if (wparam == VK_CONTROL)
2419 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
2420 else
2421 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
2422
2423 modifiers[i] = 0;
2424}
2425
da36a4d6 2426/* Emacs can lose focus while a modifier key has been pressed. When
7d0393cf 2427 it regains focus, be conservative and clear all modifiers since
da36a4d6
GV
2428 we cannot reconstruct the left and right modifier state. */
2429static void
2430reset_modifiers ()
2431{
8681157a
RS
2432 SHORT ctrl, alt;
2433
adcc3809
GV
2434 if (GetFocus () == NULL)
2435 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 2436 return;
8681157a
RS
2437
2438 ctrl = GetAsyncKeyState (VK_CONTROL);
2439 alt = GetAsyncKeyState (VK_MENU);
2440
8681157a
RS
2441 if (!(ctrl & 0x08000))
2442 /* Clear any recorded control modifier state. */
2443 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
2444
2445 if (!(alt & 0x08000))
2446 /* Clear any recorded alt modifier state. */
2447 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
2448
adcc3809
GV
2449 /* Update the state of all modifier keys, because modifiers used in
2450 hot-key combinations can get stuck on if Emacs loses focus as a
2451 result of a hot-key being pressed. */
2452 {
2453 BYTE keystate[256];
2454
2455#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
2456
2457 GetKeyboardState (keystate);
2458 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
2459 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
2460 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
2461 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
2462 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
2463 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
2464 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
2465 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
2466 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
2467 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
2468 SetKeyboardState (keystate);
2469 }
da36a4d6
GV
2470}
2471
7830e24b
RS
2472/* Synchronize modifier state with what is reported with the current
2473 keystroke. Even if we cannot distinguish between left and right
2474 modifier keys, we know that, if no modifiers are set, then neither
2475 the left or right modifier should be set. */
2476static void
2477sync_modifiers ()
2478{
2479 if (!modifiers_recorded)
2480 return;
2481
7d0393cf 2482 if (!(GetKeyState (VK_CONTROL) & 0x8000))
7830e24b
RS
2483 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
2484
7d0393cf 2485 if (!(GetKeyState (VK_MENU) & 0x8000))
7830e24b
RS
2486 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
2487}
2488
a1a80b40
GV
2489static int
2490modifier_set (int vkey)
2491{
ccc2d29c 2492 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 2493 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
2494 if (!modifiers_recorded)
2495 return (GetKeyState (vkey) & 0x8000);
2496
2497 switch (vkey)
2498 {
2499 case VK_LCONTROL:
2500 return modifiers[EMACS_LCONTROL];
2501 case VK_RCONTROL:
2502 return modifiers[EMACS_RCONTROL];
2503 case VK_LMENU:
2504 return modifiers[EMACS_LMENU];
2505 case VK_RMENU:
2506 return modifiers[EMACS_RMENU];
a1a80b40
GV
2507 }
2508 return (GetKeyState (vkey) & 0x8000);
2509}
2510
ccc2d29c
GV
2511/* Convert between the modifier bits W32 uses and the modifier bits
2512 Emacs uses. */
2513
2514unsigned int
2515w32_key_to_modifier (int key)
2516{
2517 Lisp_Object key_mapping;
2518
2519 switch (key)
2520 {
2521 case VK_LWIN:
2522 key_mapping = Vw32_lwindow_modifier;
2523 break;
2524 case VK_RWIN:
2525 key_mapping = Vw32_rwindow_modifier;
2526 break;
2527 case VK_APPS:
2528 key_mapping = Vw32_apps_modifier;
2529 break;
2530 case VK_SCROLL:
2531 key_mapping = Vw32_scroll_lock_modifier;
2532 break;
2533 default:
2534 key_mapping = Qnil;
2535 }
2536
adcc3809
GV
2537 /* NB. This code runs in the input thread, asychronously to the lisp
2538 thread, so we must be careful to ensure access to lisp data is
2539 thread-safe. The following code is safe because the modifier
2540 variable values are updated atomically from lisp and symbols are
2541 not relocated by GC. Also, we don't have to worry about seeing GC
2542 markbits here. */
2543 if (EQ (key_mapping, Qhyper))
ccc2d29c 2544 return hyper_modifier;
adcc3809 2545 if (EQ (key_mapping, Qsuper))
ccc2d29c 2546 return super_modifier;
adcc3809 2547 if (EQ (key_mapping, Qmeta))
ccc2d29c 2548 return meta_modifier;
adcc3809 2549 if (EQ (key_mapping, Qalt))
ccc2d29c 2550 return alt_modifier;
adcc3809 2551 if (EQ (key_mapping, Qctrl))
ccc2d29c 2552 return ctrl_modifier;
adcc3809 2553 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 2554 return ctrl_modifier;
adcc3809 2555 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
2556 return shift_modifier;
2557
2558 /* Don't generate any modifier if not explicitly requested. */
2559 return 0;
2560}
2561
2562unsigned int
2563w32_get_modifiers ()
2564{
2565 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
2566 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
2567 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
2568 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
2569 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
2570 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
2571 (modifier_set (VK_MENU) ?
2572 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
2573}
2574
a1a80b40
GV
2575/* We map the VK_* modifiers into console modifier constants
2576 so that we can use the same routines to handle both console
2577 and window input. */
2578
2579static int
ccc2d29c 2580construct_console_modifiers ()
a1a80b40
GV
2581{
2582 int mods;
2583
a1a80b40
GV
2584 mods = 0;
2585 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
2586 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
2587 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
2588 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
2589 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
2590 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
2591 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
2592 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
2593 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
2594 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
2595 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
2596
2597 return mods;
2598}
2599
ccc2d29c
GV
2600static int
2601w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 2602{
ccc2d29c
GV
2603 int mods;
2604
2605 /* Convert to emacs modifiers. */
2606 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
2607
2608 return mods;
2609}
da36a4d6 2610
ccc2d29c
GV
2611unsigned int
2612map_keypad_keys (unsigned int virt_key, unsigned int extended)
2613{
2614 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
2615 return virt_key;
da36a4d6 2616
ccc2d29c 2617 if (virt_key == VK_RETURN)
da36a4d6
GV
2618 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
2619
ccc2d29c
GV
2620 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
2621 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
2622
2623 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
2624 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
2625
2626 if (virt_key == VK_CLEAR)
2627 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
2628
2629 return virt_key;
2630}
2631
2632/* List of special key combinations which w32 would normally capture,
2633 but emacs should grab instead. Not directly visible to lisp, to
2634 simplify synchronization. Each item is an integer encoding a virtual
2635 key code and modifier combination to capture. */
2636Lisp_Object w32_grabbed_keys;
2637
2638#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
2639#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
2640#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
2641#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
2642
2643/* Register hot-keys for reserved key combinations when Emacs has
2644 keyboard focus, since this is the only way Emacs can receive key
2645 combinations like Alt-Tab which are used by the system. */
2646
2647static void
2648register_hot_keys (hwnd)
2649 HWND hwnd;
2650{
2651 Lisp_Object keylist;
2652
2653 /* Use GC_CONSP, since we are called asynchronously. */
2654 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
2655 {
2656 Lisp_Object key = XCAR (keylist);
2657
2658 /* Deleted entries get set to nil. */
2659 if (!INTEGERP (key))
2660 continue;
2661
2662 RegisterHotKey (hwnd, HOTKEY_ID (key),
2663 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
2664 }
2665}
2666
2667static void
2668unregister_hot_keys (hwnd)
2669 HWND hwnd;
2670{
2671 Lisp_Object keylist;
2672
2673 /* Use GC_CONSP, since we are called asynchronously. */
2674 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
2675 {
2676 Lisp_Object key = XCAR (keylist);
2677
2678 if (!INTEGERP (key))
2679 continue;
2680
2681 UnregisterHotKey (hwnd, HOTKEY_ID (key));
2682 }
2683}
2684
5ac45f98
GV
2685/* Main message dispatch loop. */
2686
1edf84e7
GV
2687static void
2688w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
2689{
2690 MSG msg;
ccc2d29c
GV
2691 int result;
2692 HWND focus_window;
93fbe8b7
GV
2693
2694 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
7d0393cf 2695
5ac45f98
GV
2696 while (GetMessage (&msg, NULL, 0, 0))
2697 {
2698 if (msg.hwnd == NULL)
2699 {
2700 switch (msg.message)
2701 {
3ef68e6b
AI
2702 case WM_NULL:
2703 /* Produced by complete_deferred_msg; just ignore. */
2704 break;
5ac45f98 2705 case WM_EMACS_CREATEWINDOW:
fbd6baed 2706 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
2707 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2708 abort ();
5ac45f98 2709 break;
dfdb4047
GV
2710 case WM_EMACS_SETLOCALE:
2711 SetThreadLocale (msg.wParam);
2712 /* Reply is not expected. */
2713 break;
ccc2d29c
GV
2714 case WM_EMACS_SETKEYBOARDLAYOUT:
2715 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
2716 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
2717 result, 0))
2718 abort ();
2719 break;
2720 case WM_EMACS_REGISTER_HOT_KEY:
2721 focus_window = GetFocus ();
2722 if (focus_window != NULL)
2723 RegisterHotKey (focus_window,
2724 HOTKEY_ID (msg.wParam),
2725 HOTKEY_MODIFIERS (msg.wParam),
2726 HOTKEY_VK_CODE (msg.wParam));
2727 /* Reply is not expected. */
2728 break;
2729 case WM_EMACS_UNREGISTER_HOT_KEY:
2730 focus_window = GetFocus ();
2731 if (focus_window != NULL)
2732 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
2733 /* Mark item as erased. NB: this code must be
2734 thread-safe. The next line is okay because the cons
2735 cell is never made into garbage and is not relocated by
2736 GC. */
f3fbd155 2737 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
2738 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2739 abort ();
2740 break;
adcc3809
GV
2741 case WM_EMACS_TOGGLE_LOCK_KEY:
2742 {
2743 int vk_code = (int) msg.wParam;
2744 int cur_state = (GetKeyState (vk_code) & 1);
2745 Lisp_Object new_state = (Lisp_Object) msg.lParam;
2746
2747 /* NB: This code must be thread-safe. It is safe to
2748 call NILP because symbols are not relocated by GC,
2749 and pointer here is not touched by GC (so the markbit
2750 can't be set). Numbers are safe because they are
2751 immediate values. */
2752 if (NILP (new_state)
2753 || (NUMBERP (new_state)
8edb0a6f 2754 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
2755 {
2756 one_w32_display_info.faked_key = vk_code;
2757
2758 keybd_event ((BYTE) vk_code,
2759 (BYTE) MapVirtualKey (vk_code, 0),
2760 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2761 keybd_event ((BYTE) vk_code,
2762 (BYTE) MapVirtualKey (vk_code, 0),
2763 KEYEVENTF_EXTENDEDKEY | 0, 0);
2764 keybd_event ((BYTE) vk_code,
2765 (BYTE) MapVirtualKey (vk_code, 0),
2766 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2767 cur_state = !cur_state;
2768 }
2769 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
2770 cur_state, 0))
2771 abort ();
2772 }
2773 break;
1edf84e7 2774 default:
1edf84e7 2775 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
2776 }
2777 }
2778 else
2779 {
2780 DispatchMessage (&msg);
2781 }
1edf84e7
GV
2782
2783 /* Exit nested loop when our deferred message has completed. */
2784 if (msg_buf->completed)
2785 break;
5ac45f98 2786 }
1edf84e7
GV
2787}
2788
2789deferred_msg * deferred_msg_head;
2790
2791static deferred_msg *
2792find_deferred_msg (HWND hwnd, UINT msg)
2793{
2794 deferred_msg * item;
2795
2796 /* Don't actually need synchronization for read access, since
2797 modification of single pointer is always atomic. */
2798 /* enter_crit (); */
2799
2800 for (item = deferred_msg_head; item != NULL; item = item->next)
2801 if (item->w32msg.msg.hwnd == hwnd
2802 && item->w32msg.msg.message == msg)
2803 break;
2804
2805 /* leave_crit (); */
2806
2807 return item;
2808}
2809
2810static LRESULT
2811send_deferred_msg (deferred_msg * msg_buf,
2812 HWND hwnd,
2813 UINT msg,
2814 WPARAM wParam,
2815 LPARAM lParam)
2816{
2817 /* Only input thread can send deferred messages. */
2818 if (GetCurrentThreadId () != dwWindowsThreadId)
2819 abort ();
2820
2821 /* It is an error to send a message that is already deferred. */
2822 if (find_deferred_msg (hwnd, msg) != NULL)
2823 abort ();
2824
2825 /* Enforced synchronization is not needed because this is the only
2826 function that alters deferred_msg_head, and the following critical
2827 section is guaranteed to only be serially reentered (since only the
2828 input thread can call us). */
2829
2830 /* enter_crit (); */
2831
2832 msg_buf->completed = 0;
2833 msg_buf->next = deferred_msg_head;
2834 deferred_msg_head = msg_buf;
2835 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
2836
2837 /* leave_crit (); */
2838
2839 /* Start a new nested message loop to process other messages until
2840 this one is completed. */
2841 w32_msg_pump (msg_buf);
2842
2843 deferred_msg_head = msg_buf->next;
2844
2845 return msg_buf->result;
2846}
2847
2848void
2849complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
2850{
2851 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
2852
2853 if (msg_buf == NULL)
3ef68e6b
AI
2854 /* Message may have been cancelled, so don't abort(). */
2855 return;
1edf84e7
GV
2856
2857 msg_buf->result = result;
2858 msg_buf->completed = 1;
2859
2860 /* Ensure input thread is woken so it notices the completion. */
2861 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
2862}
2863
3ef68e6b
AI
2864void
2865cancel_all_deferred_msgs ()
2866{
2867 deferred_msg * item;
2868
2869 /* Don't actually need synchronization for read access, since
2870 modification of single pointer is always atomic. */
2871 /* enter_crit (); */
2872
2873 for (item = deferred_msg_head; item != NULL; item = item->next)
2874 {
2875 item->result = 0;
2876 item->completed = 1;
2877 }
2878
2879 /* leave_crit (); */
2880
2881 /* Ensure input thread is woken so it notices the completion. */
2882 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
2883}
1edf84e7 2884
7d0393cf 2885DWORD
1edf84e7
GV
2886w32_msg_worker (dw)
2887 DWORD dw;
2888{
2889 MSG msg;
2890 deferred_msg dummy_buf;
2891
2892 /* Ensure our message queue is created */
7d0393cf 2893
1edf84e7 2894 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
7d0393cf 2895
1edf84e7
GV
2896 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2897 abort ();
2898
2899 memset (&dummy_buf, 0, sizeof (dummy_buf));
2900 dummy_buf.w32msg.msg.hwnd = NULL;
2901 dummy_buf.w32msg.msg.message = WM_NULL;
2902
2903 /* This is the inital message loop which should only exit when the
2904 application quits. */
2905 w32_msg_pump (&dummy_buf);
2906
2907 return 0;
5ac45f98
GV
2908}
2909
3ef68e6b
AI
2910static void
2911post_character_message (hwnd, msg, wParam, lParam, modifiers)
2912 HWND hwnd;
2913 UINT msg;
2914 WPARAM wParam;
2915 LPARAM lParam;
2916 DWORD modifiers;
2917
2918{
2919 W32Msg wmsg;
2920
2921 wmsg.dwModifiers = modifiers;
2922
2923 /* Detect quit_char and set quit-flag directly. Note that we
2924 still need to post a message to ensure the main thread will be
2925 woken up if blocked in sys_select(), but we do NOT want to post
2926 the quit_char message itself (because it will usually be as if
2927 the user had typed quit_char twice). Instead, we post a dummy
2928 message that has no particular effect. */
2929 {
2930 int c = wParam;
2931 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
2932 c = make_ctrl_char (c) & 0377;
7d081355
AI
2933 if (c == quit_char
2934 || (wmsg.dwModifiers == 0 &&
2935 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
2936 {
2937 Vquit_flag = Qt;
2938
2939 /* The choice of message is somewhat arbitrary, as long as
2940 the main thread handler just ignores it. */
2941 msg = WM_NULL;
2942
2943 /* Interrupt any blocking system calls. */
2944 signal_quit ();
2945
2946 /* As a safety precaution, forcibly complete any deferred
2947 messages. This is a kludge, but I don't see any particularly
2948 clean way to handle the situation where a deferred message is
2949 "dropped" in the lisp thread, and will thus never be
2950 completed, eg. by the user trying to activate the menubar
2951 when the lisp thread is busy, and then typing C-g when the
2952 menubar doesn't open promptly (with the result that the
2953 menubar never responds at all because the deferred
2954 WM_INITMENU message is never completed). Another problem
2955 situation is when the lisp thread calls SendMessage (to send
2956 a window manager command) when a message has been deferred;
2957 the lisp thread gets blocked indefinitely waiting for the
2958 deferred message to be completed, which itself is waiting for
2959 the lisp thread to respond.
2960
2961 Note that we don't want to block the input thread waiting for
2962 a reponse from the lisp thread (although that would at least
2963 solve the deadlock problem above), because we want to be able
2964 to receive C-g to interrupt the lisp thread. */
2965 cancel_all_deferred_msgs ();
2966 }
2967 }
2968
2969 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2970}
2971
ee78dc32
GV
2972/* Main window procedure */
2973
7d0393cf 2974LRESULT CALLBACK
fbd6baed 2975w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
2976 HWND hwnd;
2977 UINT msg;
2978 WPARAM wParam;
2979 LPARAM lParam;
2980{
2981 struct frame *f;
fbd6baed
GV
2982 struct w32_display_info *dpyinfo = &one_w32_display_info;
2983 W32Msg wmsg;
84fb1139 2984 int windows_translate;
576ba81c 2985 int key;
84fb1139 2986
a6085637
KH
2987 /* Note that it is okay to call x_window_to_frame, even though we are
2988 not running in the main lisp thread, because frame deletion
2989 requires the lisp thread to synchronize with this thread. Thus, if
2990 a frame struct is returned, it can be used without concern that the
2991 lisp thread might make it disappear while we are using it.
2992
2993 NB. Walking the frame list in this thread is safe (as long as
2994 writes of Lisp_Object slots are atomic, which they are on Windows).
2995 Although delete-frame can destructively modify the frame list while
2996 we are walking it, a garbage collection cannot occur until after
2997 delete-frame has synchronized with this thread.
2998
2999 It is also safe to use functions that make GDI calls, such as
fbd6baed 3000 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
3001 from the frame struct using get_frame_dc which is thread-aware. */
3002
7d0393cf 3003 switch (msg)
ee78dc32
GV
3004 {
3005 case WM_ERASEBKGND:
a6085637
KH
3006 f = x_window_to_frame (dpyinfo, hwnd);
3007 if (f)
3008 {
9badad41 3009 HDC hdc = get_frame_dc (f);
a6085637 3010 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
3011 w32_clear_rect (f, hdc, &wmsg.rect);
3012 release_frame_dc (f, hdc);
ce6059da
AI
3013
3014#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
3015 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
3016 f,
3017 wmsg.rect.left, wmsg.rect.top,
3018 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 3019#endif /* W32_DEBUG_DISPLAY */
a6085637 3020 }
5ac45f98
GV
3021 return 1;
3022 case WM_PALETTECHANGED:
3023 /* ignore our own changes */
3024 if ((HWND)wParam != hwnd)
3025 {
a6085637
KH
3026 f = x_window_to_frame (dpyinfo, hwnd);
3027 if (f)
3028 /* get_frame_dc will realize our palette and force all
3029 frames to be redrawn if needed. */
3030 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
3031 }
3032 return 0;
ee78dc32 3033 case WM_PAINT:
ce6059da 3034 {
55dcfc15
AI
3035 PAINTSTRUCT paintStruct;
3036 RECT update_rect;
aa35b6ad 3037 bzero (&update_rect, sizeof (update_rect));
55dcfc15 3038
18f0b342
AI
3039 f = x_window_to_frame (dpyinfo, hwnd);
3040 if (f == 0)
3041 {
3042 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
3043 return 0;
3044 }
3045
55dcfc15
AI
3046 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
3047 fails. Apparently this can happen under some
3048 circumstances. */
aa35b6ad 3049 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
55dcfc15
AI
3050 {
3051 enter_crit ();
3052 BeginPaint (hwnd, &paintStruct);
3053
aa35b6ad
JR
3054 /* The rectangles returned by GetUpdateRect and BeginPaint
3055 do not always match. Play it safe by assuming both areas
3056 are invalid. */
3057 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
55dcfc15
AI
3058
3059#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
3060 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
3061 f,
3062 wmsg.rect.left, wmsg.rect.top,
3063 wmsg.rect.right, wmsg.rect.bottom));
3064 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
3065 update_rect.left, update_rect.top,
3066 update_rect.right, update_rect.bottom));
3067#endif
3068 EndPaint (hwnd, &paintStruct);
3069 leave_crit ();
3070
3071 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
7d0393cf 3072
55dcfc15
AI
3073 return 0;
3074 }
c0611964
AI
3075
3076 /* If GetUpdateRect returns 0 (meaning there is no update
3077 region), assume the whole window needs to be repainted. */
3078 GetClientRect(hwnd, &wmsg.rect);
3079 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3080 return 0;
ee78dc32 3081 }
a1a80b40 3082
ccc2d29c
GV
3083 case WM_INPUTLANGCHANGE:
3084 /* Inform lisp thread of keyboard layout changes. */
3085 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3086
3087 /* Clear dead keys in the keyboard state; for simplicity only
3088 preserve modifier key states. */
3089 {
3090 int i;
3091 BYTE keystate[256];
3092
3093 GetKeyboardState (keystate);
3094 for (i = 0; i < 256; i++)
3095 if (1
3096 && i != VK_SHIFT
3097 && i != VK_LSHIFT
3098 && i != VK_RSHIFT
3099 && i != VK_CAPITAL
3100 && i != VK_NUMLOCK
3101 && i != VK_SCROLL
3102 && i != VK_CONTROL
3103 && i != VK_LCONTROL
3104 && i != VK_RCONTROL
3105 && i != VK_MENU
3106 && i != VK_LMENU
3107 && i != VK_RMENU
3108 && i != VK_LWIN
3109 && i != VK_RWIN)
3110 keystate[i] = 0;
3111 SetKeyboardState (keystate);
3112 }
3113 goto dflt;
3114
3115 case WM_HOTKEY:
3116 /* Synchronize hot keys with normal input. */
3117 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
3118 return (0);
3119
a1a80b40
GV
3120 case WM_KEYUP:
3121 case WM_SYSKEYUP:
3122 record_keyup (wParam, lParam);
3123 goto dflt;
3124
ee78dc32
GV
3125 case WM_KEYDOWN:
3126 case WM_SYSKEYDOWN:
ccc2d29c
GV
3127 /* Ignore keystrokes we fake ourself; see below. */
3128 if (dpyinfo->faked_key == wParam)
3129 {
3130 dpyinfo->faked_key = 0;
576ba81c
AI
3131 /* Make sure TranslateMessage sees them though (as long as
3132 they don't produce WM_CHAR messages). This ensures that
3133 indicator lights are toggled promptly on Windows 9x, for
3134 example. */
3135 if (lispy_function_keys[wParam] != 0)
3136 {
3137 windows_translate = 1;
3138 goto translate;
3139 }
3140 return 0;
ccc2d29c
GV
3141 }
3142
7830e24b
RS
3143 /* Synchronize modifiers with current keystroke. */
3144 sync_modifiers ();
a1a80b40 3145 record_keydown (wParam, lParam);
ccc2d29c 3146 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
3147
3148 windows_translate = 0;
ccc2d29c
GV
3149
3150 switch (wParam)
3151 {
3152 case VK_LWIN:
3153 if (NILP (Vw32_pass_lwindow_to_system))
3154 {
3155 /* Prevent system from acting on keyup (which opens the
3156 Start menu if no other key was pressed) by simulating a
3157 press of Space which we will ignore. */
3158 if (GetAsyncKeyState (wParam) & 1)
3159 {
adcc3809 3160 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 3161 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 3162 else
576ba81c
AI
3163 key = VK_SPACE;
3164 dpyinfo->faked_key = key;
3165 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
3166 }
3167 }
3168 if (!NILP (Vw32_lwindow_modifier))
3169 return 0;
3170 break;
3171 case VK_RWIN:
3172 if (NILP (Vw32_pass_rwindow_to_system))
3173 {
3174 if (GetAsyncKeyState (wParam) & 1)
3175 {
adcc3809 3176 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 3177 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 3178 else
576ba81c
AI
3179 key = VK_SPACE;
3180 dpyinfo->faked_key = key;
3181 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
3182 }
3183 }
3184 if (!NILP (Vw32_rwindow_modifier))
3185 return 0;
3186 break;
576ba81c 3187 case VK_APPS:
ccc2d29c
GV
3188 if (!NILP (Vw32_apps_modifier))
3189 return 0;
3190 break;
3191 case VK_MENU:
7d0393cf 3192 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
3193 /* Prevent DefWindowProc from activating the menu bar if an
3194 Alt key is pressed and released by itself. */
ccc2d29c 3195 return 0;
84fb1139 3196 windows_translate = 1;
ccc2d29c 3197 break;
7d0393cf 3198 case VK_CAPITAL:
ccc2d29c
GV
3199 /* Decide whether to treat as modifier or function key. */
3200 if (NILP (Vw32_enable_caps_lock))
3201 goto disable_lock_key;
adcc3809
GV
3202 windows_translate = 1;
3203 break;
ccc2d29c
GV
3204 case VK_NUMLOCK:
3205 /* Decide whether to treat as modifier or function key. */
3206 if (NILP (Vw32_enable_num_lock))
3207 goto disable_lock_key;
adcc3809
GV
3208 windows_translate = 1;
3209 break;
ccc2d29c
GV
3210 case VK_SCROLL:
3211 /* Decide whether to treat as modifier or function key. */
3212 if (NILP (Vw32_scroll_lock_modifier))
3213 goto disable_lock_key;
adcc3809
GV
3214 windows_translate = 1;
3215 break;
ccc2d29c 3216 disable_lock_key:
adcc3809
GV
3217 /* Ensure the appropriate lock key state (and indicator light)
3218 remains in the same state. We do this by faking another
3219 press of the relevant key. Apparently, this really is the
3220 only way to toggle the state of the indicator lights. */
3221 dpyinfo->faked_key = wParam;
3222 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3223 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3224 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3225 KEYEVENTF_EXTENDEDKEY | 0, 0);
3226 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3227 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3228 /* Ensure indicator lights are updated promptly on Windows 9x
3229 (TranslateMessage apparently does this), after forwarding
3230 input event. */
3231 post_character_message (hwnd, msg, wParam, lParam,
3232 w32_get_key_modifiers (wParam, lParam));
3233 windows_translate = 1;
ccc2d29c 3234 break;
7d0393cf 3235 case VK_CONTROL:
ccc2d29c
GV
3236 case VK_SHIFT:
3237 case VK_PROCESSKEY: /* Generated by IME. */
3238 windows_translate = 1;
3239 break;
adcc3809
GV
3240 case VK_CANCEL:
3241 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
3242 which is confusing for purposes of key binding; convert
3243 VK_CANCEL events into VK_PAUSE events. */
3244 wParam = VK_PAUSE;
3245 break;
3246 case VK_PAUSE:
3247 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
3248 for purposes of key binding; convert these back into
3249 VK_NUMLOCK events, at least when we want to see NumLock key
3250 presses. (Note that there is never any possibility that
3251 VK_PAUSE with Ctrl really is C-Pause as per above.) */
3252 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
3253 wParam = VK_NUMLOCK;
3254 break;
ccc2d29c
GV
3255 default:
3256 /* If not defined as a function key, change it to a WM_CHAR message. */
3257 if (lispy_function_keys[wParam] == 0)
3258 {
adcc3809
GV
3259 DWORD modifiers = construct_console_modifiers ();
3260
ccc2d29c
GV
3261 if (!NILP (Vw32_recognize_altgr)
3262 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
3263 {
3264 /* Always let TranslateMessage handle AltGr key chords;
3265 for some reason, ToAscii doesn't always process AltGr
3266 chords correctly. */
3267 windows_translate = 1;
3268 }
adcc3809 3269 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 3270 {
adcc3809
GV
3271 /* Handle key chords including any modifiers other
3272 than shift directly, in order to preserve as much
3273 modifier information as possible. */
ccc2d29c
GV
3274 if ('A' <= wParam && wParam <= 'Z')
3275 {
3276 /* Don't translate modified alphabetic keystrokes,
3277 so the user doesn't need to constantly switch
3278 layout to type control or meta keystrokes when
3279 the normal layout translates alphabetic
3280 characters to non-ascii characters. */
3281 if (!modifier_set (VK_SHIFT))
3282 wParam += ('a' - 'A');
3283 msg = WM_CHAR;
3284 }
3285 else
3286 {
3287 /* Try to handle other keystrokes by determining the
3288 base character (ie. translating the base key plus
3289 shift modifier). */
3290 int add;
3291 int isdead = 0;
3292 KEY_EVENT_RECORD key;
7d0393cf 3293
ccc2d29c
GV
3294 key.bKeyDown = TRUE;
3295 key.wRepeatCount = 1;
3296 key.wVirtualKeyCode = wParam;
3297 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
3298 key.uChar.AsciiChar = 0;
adcc3809 3299 key.dwControlKeyState = modifiers;
ccc2d29c
GV
3300
3301 add = w32_kbd_patch_key (&key);
3302 /* 0 means an unrecognised keycode, negative means
3303 dead key. Ignore both. */
3304 while (--add >= 0)
3305 {
3306 /* Forward asciified character sequence. */
3307 post_character_message
3308 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
3309 w32_get_key_modifiers (wParam, lParam));
3310 w32_kbd_patch_key (&key);
3311 }
3312 return 0;
3313 }
3314 }
3315 else
3316 {
3317 /* Let TranslateMessage handle everything else. */
3318 windows_translate = 1;
3319 }
3320 }
3321 }
a1a80b40 3322
adcc3809 3323 translate:
84fb1139
KH
3324 if (windows_translate)
3325 {
e9e23e23 3326 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 3327
e9e23e23
GV
3328 windows_msg.time = GetMessageTime ();
3329 TranslateMessage (&windows_msg);
84fb1139
KH
3330 goto dflt;
3331 }
3332
ee78dc32 3333 /* Fall through */
7d0393cf 3334
ee78dc32
GV
3335 case WM_SYSCHAR:
3336 case WM_CHAR:
ccc2d29c
GV
3337 post_character_message (hwnd, msg, wParam, lParam,
3338 w32_get_key_modifiers (wParam, lParam));
ee78dc32 3339 break;
da36a4d6 3340
5ac45f98
GV
3341 /* Simulate middle mouse button events when left and right buttons
3342 are used together, but only if user has two button mouse. */
ee78dc32 3343 case WM_LBUTTONDOWN:
5ac45f98 3344 case WM_RBUTTONDOWN:
7ce9aaca 3345 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
3346 goto handle_plain_button;
3347
3348 {
3349 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
3350 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
3351
3cb20f4a
RS
3352 if (button_state & this)
3353 return 0;
5ac45f98
GV
3354
3355 if (button_state == 0)
3356 SetCapture (hwnd);
3357
3358 button_state |= this;
3359
3360 if (button_state & other)
3361 {
84fb1139 3362 if (mouse_button_timer)
5ac45f98 3363 {
84fb1139
KH
3364 KillTimer (hwnd, mouse_button_timer);
3365 mouse_button_timer = 0;
5ac45f98
GV
3366
3367 /* Generate middle mouse event instead. */
3368 msg = WM_MBUTTONDOWN;
3369 button_state |= MMOUSE;
3370 }
3371 else if (button_state & MMOUSE)
3372 {
3373 /* Ignore button event if we've already generated a
3374 middle mouse down event. This happens if the
3375 user releases and press one of the two buttons
3376 after we've faked a middle mouse event. */
3377 return 0;
3378 }
3379 else
3380 {
3381 /* Flush out saved message. */
84fb1139 3382 post_msg (&saved_mouse_button_msg);
5ac45f98 3383 }
fbd6baed 3384 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
3385 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3386
3387 /* Clear message buffer. */
84fb1139 3388 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
3389 }
3390 else
3391 {
3392 /* Hold onto message for now. */
84fb1139 3393 mouse_button_timer =
adcc3809
GV
3394 SetTimer (hwnd, MOUSE_BUTTON_ID,
3395 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
3396 saved_mouse_button_msg.msg.hwnd = hwnd;
3397 saved_mouse_button_msg.msg.message = msg;
3398 saved_mouse_button_msg.msg.wParam = wParam;
3399 saved_mouse_button_msg.msg.lParam = lParam;
3400 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 3401 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
3402 }
3403 }
3404 return 0;
3405
ee78dc32 3406 case WM_LBUTTONUP:
5ac45f98 3407 case WM_RBUTTONUP:
7ce9aaca 3408 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
3409 goto handle_plain_button;
3410
3411 {
3412 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
3413 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
3414
3cb20f4a
RS
3415 if ((button_state & this) == 0)
3416 return 0;
5ac45f98
GV
3417
3418 button_state &= ~this;
3419
3420 if (button_state & MMOUSE)
3421 {
3422 /* Only generate event when second button is released. */
3423 if ((button_state & other) == 0)
3424 {
3425 msg = WM_MBUTTONUP;
3426 button_state &= ~MMOUSE;
3427
3428 if (button_state) abort ();
3429 }
3430 else
3431 return 0;
3432 }
3433 else
3434 {
3435 /* Flush out saved message if necessary. */
84fb1139 3436 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 3437 {
84fb1139 3438 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
3439 }
3440 }
fbd6baed 3441 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
3442 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3443
3444 /* Always clear message buffer and cancel timer. */
84fb1139
KH
3445 saved_mouse_button_msg.msg.hwnd = 0;
3446 KillTimer (hwnd, mouse_button_timer);
3447 mouse_button_timer = 0;
5ac45f98
GV
3448
3449 if (button_state == 0)
3450 ReleaseCapture ();
3451 }
3452 return 0;
3453
74214547
JR
3454 case WM_XBUTTONDOWN:
3455 case WM_XBUTTONUP:
3456 if (w32_pass_extra_mouse_buttons_to_system)
3457 goto dflt;
3458 /* else fall through and process them. */
ee78dc32
GV
3459 case WM_MBUTTONDOWN:
3460 case WM_MBUTTONUP:
5ac45f98 3461 handle_plain_button:
ee78dc32
GV
3462 {
3463 BOOL up;
1edf84e7 3464 int button;
ee78dc32 3465
74214547 3466 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
3467 {
3468 if (up) ReleaseCapture ();
3469 else SetCapture (hwnd);
7d0393cf 3470 button = (button == 0) ? LMOUSE :
1edf84e7
GV
3471 ((button == 1) ? MMOUSE : RMOUSE);
3472 if (up)
3473 button_state &= ~button;
3474 else
3475 button_state |= button;
ee78dc32
GV
3476 }
3477 }
7d0393cf 3478
fbd6baed 3479 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 3480 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
3481
3482 /* Need to return true for XBUTTON messages, false for others,
3483 to indicate that we processed the message. */
3484 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 3485
5ac45f98 3486 case WM_MOUSEMOVE:
9eb16b62
JR
3487 /* If the mouse has just moved into the frame, start tracking
3488 it, so we will be notified when it leaves the frame. Mouse
3489 tracking only works under W98 and NT4 and later. On earlier
3490 versions, there is no way of telling when the mouse leaves the
3491 frame, so we just have to put up with help-echo and mouse
3492 highlighting remaining while the frame is not active. */
3493 if (track_mouse_event_fn && !track_mouse_window)
3494 {
3495 TRACKMOUSEEVENT tme;
3496 tme.cbSize = sizeof (tme);
3497 tme.dwFlags = TME_LEAVE;
3498 tme.hwndTrack = hwnd;
3499
3500 track_mouse_event_fn (&tme);
3501 track_mouse_window = hwnd;
3502 }
3503 case WM_VSCROLL:
fbd6baed 3504 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
3505 || (msg == WM_MOUSEMOVE && button_state == 0))
3506 {
fbd6baed 3507 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
3508 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3509 return 0;
3510 }
7d0393cf 3511
84fb1139
KH
3512 /* Hang onto mouse move and scroll messages for a bit, to avoid
3513 sending such events to Emacs faster than it can process them.
3514 If we get more events before the timer from the first message
3515 expires, we just replace the first message. */
3516
3517 if (saved_mouse_move_msg.msg.hwnd == 0)
3518 mouse_move_timer =
adcc3809
GV
3519 SetTimer (hwnd, MOUSE_MOVE_ID,
3520 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
3521
3522 /* Hold onto message for now. */
3523 saved_mouse_move_msg.msg.hwnd = hwnd;
3524 saved_mouse_move_msg.msg.message = msg;
3525 saved_mouse_move_msg.msg.wParam = wParam;
3526 saved_mouse_move_msg.msg.lParam = lParam;
3527 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 3528 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
7d0393cf 3529
84fb1139
KH
3530 return 0;
3531
1edf84e7
GV
3532 case WM_MOUSEWHEEL:
3533 wmsg.dwModifiers = w32_get_modifiers ();
3534 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3535 return 0;
3536
cb9e33d4
RS
3537 case WM_DROPFILES:
3538 wmsg.dwModifiers = w32_get_modifiers ();
3539 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3540 return 0;
3541
84fb1139
KH
3542 case WM_TIMER:
3543 /* Flush out saved messages if necessary. */
3544 if (wParam == mouse_button_timer)
5ac45f98 3545 {
84fb1139
KH
3546 if (saved_mouse_button_msg.msg.hwnd)
3547 {
3548 post_msg (&saved_mouse_button_msg);
3549 saved_mouse_button_msg.msg.hwnd = 0;
3550 }
3551 KillTimer (hwnd, mouse_button_timer);
3552 mouse_button_timer = 0;
3553 }
3554 else if (wParam == mouse_move_timer)
3555 {
3556 if (saved_mouse_move_msg.msg.hwnd)
3557 {
3558 post_msg (&saved_mouse_move_msg);
3559 saved_mouse_move_msg.msg.hwnd = 0;
3560 }
3561 KillTimer (hwnd, mouse_move_timer);
3562 mouse_move_timer = 0;
5ac45f98 3563 }
48094ace
JR
3564 else if (wParam == menu_free_timer)
3565 {
3566 KillTimer (hwnd, menu_free_timer);
3567 menu_free_timer = 0;
27605fa7 3568 f = x_window_to_frame (dpyinfo, hwnd);
48094ace
JR
3569 if (!f->output_data.w32->menu_command_in_progress)
3570 {
3571 /* Free memory used by owner-drawn and help-echo strings. */
3572 w32_free_menu_strings (hwnd);
3573 f->output_data.w32->menubar_active = 0;
3574 }
3575 }
5ac45f98 3576 return 0;
7d0393cf 3577
84fb1139
KH
3578 case WM_NCACTIVATE:
3579 /* Windows doesn't send us focus messages when putting up and
e9e23e23 3580 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
3581 The only indication we get that something happened is receiving
3582 this message afterwards. So this is a good time to reset our
3583 keyboard modifiers' state. */
3584 reset_modifiers ();
3585 goto dflt;
da36a4d6 3586
1edf84e7 3587 case WM_INITMENU:
487163ac
AI
3588 button_state = 0;
3589 ReleaseCapture ();
1edf84e7
GV
3590 /* We must ensure menu bar is fully constructed and up to date
3591 before allowing user interaction with it. To achieve this
3592 we send this message to the lisp thread and wait for a
3593 reply (whose value is not actually needed) to indicate that
3594 the menu bar is now ready for use, so we can now return.
3595
3596 To remain responsive in the meantime, we enter a nested message
3597 loop that can process all other messages.
3598
3599 However, we skip all this if the message results from calling
3600 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
3601 thread a message because it is blocked on us at this point. We
3602 set menubar_active before calling TrackPopupMenu to indicate
3603 this (there is no possibility of confusion with real menubar
3604 being active). */
3605
3606 f = x_window_to_frame (dpyinfo, hwnd);
3607 if (f
3608 && (f->output_data.w32->menubar_active
3609 /* We can receive this message even in the absence of a
3610 menubar (ie. when the system menu is activated) - in this
3611 case we do NOT want to forward the message, otherwise it
3612 will cause the menubar to suddenly appear when the user
3613 had requested it to be turned off! */
3614 || f->output_data.w32->menubar_widget == NULL))
3615 return 0;
3616
3617 {
3618 deferred_msg msg_buf;
3619
3620 /* Detect if message has already been deferred; in this case
3621 we cannot return any sensible value to ignore this. */
3622 if (find_deferred_msg (hwnd, msg) != NULL)
3623 abort ();
3624
3625 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
3626 }
3627
3628 case WM_EXITMENULOOP:
3629 f = x_window_to_frame (dpyinfo, hwnd);
3630
48094ace
JR
3631 /* If a menu command is not already in progress, check again
3632 after a short delay, since Windows often (always?) sends the
3633 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
3634 if (f && !f->output_data.w32->menu_command_in_progress)
3635 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
1edf84e7
GV
3636 goto dflt;
3637
126f2e35 3638 case WM_MENUSELECT:
4e3a1c61
JR
3639 /* Direct handling of help_echo in menus. Should be safe now
3640 that we generate the help_echo by placing a help event in the
3641 keyboard buffer. */
ca56d953 3642 {
ca56d953
JR
3643 HMENU menu = (HMENU) lParam;
3644 UINT menu_item = (UINT) LOWORD (wParam);
3645 UINT flags = (UINT) HIWORD (wParam);
3646
4e3a1c61 3647 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 3648 }
126f2e35
JR
3649 return 0;
3650
87996783
GV
3651 case WM_MEASUREITEM:
3652 f = x_window_to_frame (dpyinfo, hwnd);
3653 if (f)
3654 {
3655 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
3656
3657 if (pMis->CtlType == ODT_MENU)
3658 {
3659 /* Work out dimensions for popup menu titles. */
3660 char * title = (char *) pMis->itemData;
3661 HDC hdc = GetDC (hwnd);
3662 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
3663 LOGFONT menu_logfont;
3664 HFONT old_font;
3665 SIZE size;
3666
3667 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
3668 menu_logfont.lfWeight = FW_BOLD;
3669 menu_font = CreateFontIndirect (&menu_logfont);
3670 old_font = SelectObject (hdc, menu_font);
3671
dfff8a69
JR
3672 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
3673 if (title)
3674 {
3675 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
3676 pMis->itemWidth = size.cx;
3677 if (pMis->itemHeight < size.cy)
3678 pMis->itemHeight = size.cy;
3679 }
3680 else
3681 pMis->itemWidth = 0;
87996783
GV
3682
3683 SelectObject (hdc, old_font);
3684 DeleteObject (menu_font);
3685 ReleaseDC (hwnd, hdc);
3686 return TRUE;
3687 }
3688 }
3689 return 0;
3690
3691 case WM_DRAWITEM:
3692 f = x_window_to_frame (dpyinfo, hwnd);
3693 if (f)
3694 {
3695 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
3696
3697 if (pDis->CtlType == ODT_MENU)
3698 {
3699 /* Draw popup menu title. */
3700 char * title = (char *) pDis->itemData;
212da13b
JR
3701 if (title)
3702 {
3703 HDC hdc = pDis->hDC;
3704 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
3705 LOGFONT menu_logfont;
3706 HFONT old_font;
3707
3708 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
3709 menu_logfont.lfWeight = FW_BOLD;
3710 menu_font = CreateFontIndirect (&menu_logfont);
3711 old_font = SelectObject (hdc, menu_font);
3712
3713 /* Always draw title as if not selected. */
3714 ExtTextOut (hdc,
3715 pDis->rcItem.left
3716 + GetSystemMetrics (SM_CXMENUCHECK),
3717 pDis->rcItem.top,
3718 ETO_OPAQUE, &pDis->rcItem,
3719 title, strlen (title), NULL);
3720
3721 SelectObject (hdc, old_font);
3722 DeleteObject (menu_font);
3723 }
87996783
GV
3724 return TRUE;
3725 }
3726 }
3727 return 0;
3728
1edf84e7
GV
3729#if 0
3730 /* Still not right - can't distinguish between clicks in the
3731 client area of the frame from clicks forwarded from the scroll
3732 bars - may have to hook WM_NCHITTEST to remember the mouse
3733 position and then check if it is in the client area ourselves. */
3734 case WM_MOUSEACTIVATE:
3735 /* Discard the mouse click that activates a frame, allowing the
3736 user to click anywhere without changing point (or worse!).
3737 Don't eat mouse clicks on scrollbars though!! */
3738 if (LOWORD (lParam) == HTCLIENT )
3739 return MA_ACTIVATEANDEAT;
3740 goto dflt;
3741#endif
3742
9eb16b62
JR
3743 case WM_MOUSELEAVE:
3744 /* No longer tracking mouse. */
3745 track_mouse_window = NULL;
3746
1edf84e7 3747 case WM_ACTIVATEAPP:
ccc2d29c 3748 case WM_ACTIVATE:
1edf84e7
GV
3749 case WM_WINDOWPOSCHANGED:
3750 case WM_SHOWWINDOW:
3751 /* Inform lisp thread that a frame might have just been obscured
3752 or exposed, so should recheck visibility of all frames. */
3753 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3754 goto dflt;
3755
da36a4d6 3756 case WM_SETFOCUS:
adcc3809
GV
3757 dpyinfo->faked_key = 0;
3758 reset_modifiers ();
ccc2d29c
GV
3759 register_hot_keys (hwnd);
3760 goto command;
8681157a 3761 case WM_KILLFOCUS:
ccc2d29c 3762 unregister_hot_keys (hwnd);
487163ac
AI
3763 button_state = 0;
3764 ReleaseCapture ();
65906840
JR
3765 /* Relinquish the system caret. */
3766 if (w32_system_caret_hwnd)
3767 {
93f2ca61 3768 w32_visible_system_caret_hwnd = NULL;
d285988b
JR
3769 w32_system_caret_hwnd = NULL;
3770 DestroyCaret ();
65906840 3771 }
48094ace
JR
3772 goto command;
3773 case WM_COMMAND:
3774 f = x_window_to_frame (dpyinfo, hwnd);
3775 if (f && HIWORD (wParam) == 0)
3776 {
3777 f->output_data.w32->menu_command_in_progress = 1;
3778 if (menu_free_timer)
3779 {
3780 KillTimer (hwnd, menu_free_timer);
7d0393cf 3781 menu_free_timer = 0;
48094ace
JR
3782 }
3783 }
ee78dc32
GV
3784 case WM_MOVE:
3785 case WM_SIZE:
ccc2d29c 3786 command:
fbd6baed 3787 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
3788 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3789 goto dflt;
8847d890
RS
3790
3791 case WM_CLOSE:
fbd6baed 3792 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
3793 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3794 return 0;
3795
ee78dc32 3796 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
3797 /* Don't restrict the sizing of tip frames. */
3798 if (hwnd == tip_window)
3799 return 0;
ee78dc32
GV
3800 {
3801 WINDOWPLACEMENT wp;
3802 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
3803
3804 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32 3805 GetWindowPlacement (hwnd, &wp);
7d0393cf 3806
1edf84e7 3807 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
3808 {
3809 RECT rect;
3810 int wdiff;
3811 int hdiff;
1edf84e7
GV
3812 DWORD font_width;
3813 DWORD line_height;
3814 DWORD internal_border;
3815 DWORD scrollbar_extra;
ee78dc32 3816 RECT wr;
7d0393cf 3817
5ac45f98 3818 wp.length = sizeof(wp);
ee78dc32 3819 GetWindowRect (hwnd, &wr);
7d0393cf 3820
3c190163 3821 enter_crit ();
7d0393cf 3822
1edf84e7
GV
3823 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
3824 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
3825 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
3826 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
7d0393cf 3827
3c190163 3828 leave_crit ();
7d0393cf 3829
ee78dc32 3830 memset (&rect, 0, sizeof (rect));
7d0393cf 3831 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
ee78dc32
GV
3832 GetMenu (hwnd) != NULL);
3833
1edf84e7
GV
3834 /* Force width and height of client area to be exact
3835 multiples of the character cell dimensions. */
3836 wdiff = (lppos->cx - (rect.right - rect.left)
3837 - 2 * internal_border - scrollbar_extra)
3838 % font_width;
3839 hdiff = (lppos->cy - (rect.bottom - rect.top)
3840 - 2 * internal_border)
3841 % line_height;
7d0393cf 3842
ee78dc32
GV
3843 if (wdiff || hdiff)
3844 {
7d0393cf
JB
3845 /* For right/bottom sizing we can just fix the sizes.
3846 However for top/left sizing we will need to fix the X
ee78dc32 3847 and Y positions as well. */
7d0393cf 3848
ee78dc32
GV
3849 lppos->cx -= wdiff;
3850 lppos->cy -= hdiff;
7d0393cf
JB
3851
3852 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 3853 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
3854 {
3855 if (lppos->x != wr.left || lppos->y != wr.top)
3856 {
3857 lppos->x += wdiff;
3858 lppos->y += hdiff;
3859 }
3860 else
3861 {
3862 lppos->flags |= SWP_NOMOVE;
3863 }
3864 }
7d0393cf 3865
1edf84e7 3866 return 0;
ee78dc32
GV
3867 }
3868 }
3869 }
7d0393cf 3870
ee78dc32 3871 goto dflt;
1edf84e7 3872
b1f918f8
GV
3873 case WM_GETMINMAXINFO:
3874 /* Hack to correct bug that allows Emacs frames to be resized
3875 below the Minimum Tracking Size. */
3876 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
3877 /* Hack to allow resizing the Emacs frame above the screen size.
3878 Note that Windows 9x limits coordinates to 16-bits. */
3879 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
3880 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
3881 return 0;
3882
c9b2104d
JR
3883 case WM_SETCURSOR:
3884 if (LOWORD (lParam) == HTCLIENT)
3885 return 0;
3886
3887 goto dflt;
c922a224 3888
c9b2104d
JR
3889 case WM_EMACS_SETCURSOR:
3890 {
3891 Cursor cursor = (Cursor) wParam;
3892 if (cursor)
3893 SetCursor (cursor);
3894 return 0;
3895 }
c922a224 3896
1edf84e7
GV
3897 case WM_EMACS_CREATESCROLLBAR:
3898 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
3899 (struct scroll_bar *) lParam);
3900
5ac45f98 3901 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
3902 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
3903
dfdb4047 3904 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
3905 {
3906 HWND foreground_window;
3907 DWORD foreground_thread, retval;
3908
3909 /* On NT 5.0, and apparently Windows 98, it is necessary to
3910 attach to the thread that currently has focus in order to
3911 pull the focus away from it. */
3912 foreground_window = GetForegroundWindow ();
3913 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
3914 if (!foreground_window
3915 || foreground_thread == GetCurrentThreadId ()
3916 || !AttachThreadInput (GetCurrentThreadId (),
3917 foreground_thread, TRUE))
3918 foreground_thread = 0;
3919
3920 retval = SetForegroundWindow ((HWND) wParam);
3921
3922 /* Detach from the previous foreground thread. */
3923 if (foreground_thread)
3924 AttachThreadInput (GetCurrentThreadId (),
3925 foreground_thread, FALSE);
3926
3927 return retval;
3928 }
dfdb4047 3929
5ac45f98
GV
3930 case WM_EMACS_SETWINDOWPOS:
3931 {
1edf84e7
GV
3932 WINDOWPOS * pos = (WINDOWPOS *) wParam;
3933 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
3934 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
3935 }
1edf84e7 3936
ee78dc32 3937 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 3938 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
3939 return DestroyWindow ((HWND) wParam);
3940
93f2ca61
JR
3941 case WM_EMACS_HIDE_CARET:
3942 return HideCaret (hwnd);
3943
3944 case WM_EMACS_SHOW_CARET:
3945 return ShowCaret (hwnd);
3946
65906840
JR
3947 case WM_EMACS_DESTROY_CARET:
3948 w32_system_caret_hwnd = NULL;
93f2ca61 3949 w32_visible_system_caret_hwnd = NULL;
65906840
JR
3950 return DestroyCaret ();
3951
3952 case WM_EMACS_TRACK_CARET:
3953 /* If there is currently no system caret, create one. */
3954 if (w32_system_caret_hwnd == NULL)
3955 {
93f2ca61
JR
3956 /* Use the default caret width, and avoid changing it
3957 unneccesarily, as it confuses screen reader software. */
65906840 3958 w32_system_caret_hwnd = hwnd;
93f2ca61 3959 CreateCaret (hwnd, NULL, 0,
65906840
JR
3960 w32_system_caret_height);
3961 }
7d0393cf 3962
93f2ca61
JR
3963 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
3964 return 0;
3965 /* Ensure visible caret gets turned on when requested. */
3966 else if (w32_use_visible_system_caret
3967 && w32_visible_system_caret_hwnd != hwnd)
3968 {
3969 w32_visible_system_caret_hwnd = hwnd;
3970 return ShowCaret (hwnd);
3971 }
3972 /* Ensure visible caret gets turned off when requested. */
3973 else if (!w32_use_visible_system_caret
3974 && w32_visible_system_caret_hwnd)
3975 {
3976 w32_visible_system_caret_hwnd = NULL;
3977 return HideCaret (hwnd);
3978 }
3979 else
3980 return 1;
65906840 3981
1edf84e7
GV
3982 case WM_EMACS_TRACKPOPUPMENU:
3983 {
3984 UINT flags;
3985 POINT *pos;
3986 int retval;
3987 pos = (POINT *)lParam;
3988 flags = TPM_CENTERALIGN;
3989 if (button_state & LMOUSE)
3990 flags |= TPM_LEFTBUTTON;
3991 else if (button_state & RMOUSE)
3992 flags |= TPM_RIGHTBUTTON;
7d0393cf 3993
87996783
GV
3994 /* Remember we did a SetCapture on the initial mouse down event,
3995 so for safety, we make sure the capture is cancelled now. */
3996 ReleaseCapture ();
490822ff 3997 button_state = 0;
87996783 3998
1edf84e7
GV
3999 /* Use menubar_active to indicate that WM_INITMENU is from
4000 TrackPopupMenu below, and should be ignored. */
4001 f = x_window_to_frame (dpyinfo, hwnd);
4002 if (f)
4003 f->output_data.w32->menubar_active = 1;
7d0393cf
JB
4004
4005 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
1edf84e7
GV
4006 0, hwnd, NULL))
4007 {
4008 MSG amsg;
4009 /* Eat any mouse messages during popupmenu */
4010 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4011 PM_REMOVE));
4012 /* Get the menu selection, if any */
4013 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4014 {
4015 retval = LOWORD (amsg.wParam);
4016 }
4017 else
4018 {
4019 retval = 0;
4020 }
1edf84e7
GV
4021 }
4022 else
4023 {
4024 retval = -1;
4025 }
4026
4027 return retval;
4028 }
4029
ee78dc32 4030 default:
93fbe8b7
GV
4031 /* Check for messages registered at runtime. */
4032 if (msg == msh_mousewheel)
4033 {
4034 wmsg.dwModifiers = w32_get_modifiers ();
4035 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4036 return 0;
4037 }
7d0393cf 4038
ee78dc32
GV
4039 dflt:
4040 return DefWindowProc (hwnd, msg, wParam, lParam);
4041 }
7d0393cf 4042
1edf84e7
GV
4043
4044 /* The most common default return code for handled messages is 0. */
4045 return 0;
ee78dc32
GV
4046}
4047
7d0393cf 4048void
ee78dc32
GV
4049my_create_window (f)
4050 struct frame * f;
4051{
4052 MSG msg;
4053
1edf84e7
GV
4054 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4055 abort ();
ee78dc32
GV
4056 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4057}
4058
ca56d953
JR
4059
4060/* Create a tooltip window. Unlike my_create_window, we do not do this
4061 indirectly via the Window thread, as we do not need to process Window
4062 messages for the tooltip. Creating tooltips indirectly also creates
4063 deadlocks when tooltips are created for menu items. */
7d0393cf 4064void
ca56d953
JR
4065my_create_tip_window (f)
4066 struct frame *f;
4067{
bfd6edcc 4068 RECT rect;
ca56d953 4069
bfd6edcc 4070 rect.left = rect.top = 0;
be786000
KS
4071 rect.right = FRAME_PIXEL_WIDTH (f);
4072 rect.bottom = FRAME_PIXEL_HEIGHT (f);
bfd6edcc
JR
4073
4074 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
4075 FRAME_EXTERNAL_MENU_BAR (f));
4076
4077 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
4078 = CreateWindow (EMACS_CLASS,
4079 f->namebuf,
4080 f->output_data.w32->dwStyle,
be786000
KS
4081 f->left_pos,
4082 f->top_pos,
bfd6edcc
JR
4083 rect.right - rect.left,
4084 rect.bottom - rect.top,
ca56d953
JR
4085 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
4086 NULL,
4087 hinst,
4088 NULL);
4089
bfd6edcc 4090 if (tip_window)
ca56d953 4091 {
be786000
KS
4092 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
4093 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
4094 SetWindowLong (tip_window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
bfd6edcc
JR
4095 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
4096
4097 /* Tip frames have no scrollbars. */
4098 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
4099
4100 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 4101 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
4102 }
4103}
4104
4105
fbd6baed 4106/* Create and set up the w32 window for frame F. */
ee78dc32
GV
4107
4108static void
fbd6baed 4109w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
4110 struct frame *f;
4111 long window_prompting;
4112 int minibuffer_only;
4113{
4114 BLOCK_INPUT;
4115
4116 /* Use the resource name as the top-level window name
4117 for looking up resources. Make a non-Lisp copy
4118 for the window manager, so GC relocation won't bother it.
4119
4120 Elsewhere we specify the window name for the window manager. */
7d0393cf 4121
ee78dc32 4122 {
d5db4077 4123 char *str = (char *) SDATA (Vx_resource_name);
ee78dc32
GV
4124 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4125 strcpy (f->namebuf, str);
4126 }
4127
4128 my_create_window (f);
4129
4130 validate_x_resource_name ();
4131
4132 /* x_set_name normally ignores requests to set the name if the
4133 requested name is the same as the current name. This is the one
4134 place where that assumption isn't correct; f->name is set, but
4135 the server hasn't been told. */
4136 {
4137 Lisp_Object name;
4138 int explicit = f->explicit_name;
4139
4140 f->explicit_name = 0;
4141 name = f->name;
4142 f->name = Qnil;
4143 x_set_name (f, name, explicit);
4144 }
4145
4146 UNBLOCK_INPUT;
4147
4148 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4149 initialize_frame_menubar (f);
4150
fbd6baed 4151 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
4152 error ("Unable to create window");
4153}
4154
4155/* Handle the icon stuff for this window. Perhaps later we might
4156 want an x_set_icon_position which can be called interactively as
4157 well. */
4158
4159static void
4160x_icon (f, parms)
4161 struct frame *f;
4162 Lisp_Object parms;
4163{
4164 Lisp_Object icon_x, icon_y;
4165
e9e23e23 4166 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 4167 icons in the tray. */
6fc2811b
JR
4168 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4169 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
4170 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4171 {
b7826503
PJ
4172 CHECK_NUMBER (icon_x);
4173 CHECK_NUMBER (icon_y);
ee78dc32
GV
4174 }
4175 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4176 error ("Both left and top icon corners of icon must be specified");
4177
4178 BLOCK_INPUT;
4179
4180 if (! EQ (icon_x, Qunbound))
4181 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4182
1edf84e7
GV
4183#if 0 /* TODO */
4184 /* Start up iconic or window? */
4185 x_wm_set_window_state
6fc2811b 4186 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
4187 ? IconicState
4188 : NormalState));
4189
d5db4077 4190 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
1edf84e7 4191 ? f->icon_name
d5db4077 4192 : f->name)));
1edf84e7
GV
4193#endif
4194
ee78dc32
GV
4195 UNBLOCK_INPUT;
4196}
4197
6fc2811b
JR
4198
4199static void
4200x_make_gc (f)
4201 struct frame *f;
4202{
4203 XGCValues gc_values;
4204
4205 BLOCK_INPUT;
4206
4207 /* Create the GC's of this frame.
4208 Note that many default values are used. */
4209
4210 /* Normal video */
be786000 4211 gc_values.font = FRAME_FONT (f);
6fc2811b
JR
4212
4213 /* Cursor has cursor-color background, background-color foreground. */
4214 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
4215 gc_values.background = f->output_data.w32->cursor_pixel;
4216 f->output_data.w32->cursor_gc
4217 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
4218 (GCFont | GCForeground | GCBackground),
4219 &gc_values);
4220
4221 /* Reliefs. */
4222 f->output_data.w32->white_relief.gc = 0;
4223 f->output_data.w32->black_relief.gc = 0;
4224
4225 UNBLOCK_INPUT;
4226}
4227
4228
937e601e
AI
4229/* Handler for signals raised during x_create_frame and
4230 x_create_top_frame. FRAME is the frame which is partially
4231 constructed. */
4232
4233static Lisp_Object
4234unwind_create_frame (frame)
4235 Lisp_Object frame;
4236{
4237 struct frame *f = XFRAME (frame);
4238
4239 /* If frame is ``official'', nothing to do. */
4240 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4241 {
4242#ifdef GLYPH_DEBUG
4243 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4244#endif
7d0393cf 4245
937e601e
AI
4246 x_free_frame_resources (f);
4247
4248 /* Check that reference counts are indeed correct. */
4249 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4250 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
4251
4252 return Qt;
937e601e 4253 }
7d0393cf 4254
937e601e
AI
4255 return Qnil;
4256}
4257
4258
ee78dc32
GV
4259DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
4260 1, 1, 0,
74e1aeec
JR
4261 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
4262Returns an Emacs frame object.
4263ALIST is an alist of frame parameters.
4264If the parameters specify that the frame should not have a minibuffer,
4265and do not specify a specific minibuffer window to use,
4266then `default-minibuffer-frame' must be a frame whose minibuffer can
4267be shared by the new frame.
4268
4269This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
4270 (parms)
4271 Lisp_Object parms;
4272{
4273 struct frame *f;
4274 Lisp_Object frame, tem;
4275 Lisp_Object name;
4276 int minibuffer_only = 0;
4277 long window_prompting = 0;
4278 int width, height;
331379bf 4279 int count = SPECPDL_INDEX ();
1edf84e7 4280 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 4281 Lisp_Object display;
6fc2811b 4282 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
4283 Lisp_Object parent;
4284 struct kboard *kb;
4285
4587b026
GV
4286 check_w32 ();
4287
ee78dc32
GV
4288 /* Use this general default value to start with
4289 until we know if this frame has a specified name. */
4290 Vx_resource_name = Vinvocation_name;
4291
6fc2811b 4292 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
4293 if (EQ (display, Qunbound))
4294 display = Qnil;
4295 dpyinfo = check_x_display_info (display);
4296#ifdef MULTI_KBOARD
4297 kb = dpyinfo->kboard;
4298#else
4299 kb = &the_only_kboard;
4300#endif
4301
6fc2811b 4302 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
4303 if (!STRINGP (name)
4304 && ! EQ (name, Qunbound)
4305 && ! NILP (name))
4306 error ("Invalid frame name--not a string or nil");
4307
4308 if (STRINGP (name))
4309 Vx_resource_name = name;
4310
4311 /* See if parent window is specified. */
6fc2811b 4312 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
4313 if (EQ (parent, Qunbound))
4314 parent = Qnil;
4315 if (! NILP (parent))
b7826503 4316 CHECK_NUMBER (parent);
ee78dc32 4317
1edf84e7
GV
4318 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4319 /* No need to protect DISPLAY because that's not used after passing
4320 it to make_frame_without_minibuffer. */
4321 frame = Qnil;
4322 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
4323 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
4324 RES_TYPE_SYMBOL);
ee78dc32
GV
4325 if (EQ (tem, Qnone) || NILP (tem))
4326 f = make_frame_without_minibuffer (Qnil, kb, display);
4327 else if (EQ (tem, Qonly))
4328 {
4329 f = make_minibuffer_frame ();
4330 minibuffer_only = 1;
4331 }
4332 else if (WINDOWP (tem))
4333 f = make_frame_without_minibuffer (tem, kb, display);
4334 else
4335 f = make_frame (1);
4336
1edf84e7
GV
4337 XSETFRAME (frame, f);
4338
ee78dc32
GV
4339 /* Note that Windows does support scroll bars. */
4340 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
6d906347 4341
5ac45f98 4342 /* By default, make scrollbars the system standard width. */
be786000 4343 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 4344
fbd6baed 4345 f->output_method = output_w32;
6fc2811b
JR
4346 f->output_data.w32 =
4347 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 4348 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 4349 FRAME_FONTSET (f) = -1;
937e601e 4350 record_unwind_protect (unwind_create_frame, frame);
4587b026 4351
1edf84e7 4352 f->icon_name
6fc2811b 4353 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
4354 if (! STRINGP (f->icon_name))
4355 f->icon_name = Qnil;
4356
fbd6baed 4357/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
4358#ifdef MULTI_KBOARD
4359 FRAME_KBOARD (f) = kb;
4360#endif
4361
4362 /* Specify the parent under which to make this window. */
4363
4364 if (!NILP (parent))
4365 {
1660f34a 4366 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 4367 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
4368 }
4369 else
4370 {
fbd6baed
GV
4371 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
4372 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
4373 }
4374
ee78dc32
GV
4375 /* Set the name; the functions to which we pass f expect the name to
4376 be set. */
4377 if (EQ (name, Qunbound) || NILP (name))
4378 {
fbd6baed 4379 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
4380 f->explicit_name = 0;
4381 }
4382 else
4383 {
4384 f->name = name;
4385 f->explicit_name = 1;
4386 /* use the frame's title when getting resources for this frame. */
4387 specbind (Qx_resource_name, name);
4388 }
4389
4390 /* Extract the window parameters from the supplied values
4391 that are needed to determine window geometry. */
4392 {
4393 Lisp_Object font;
4394
6fc2811b
JR
4395 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
4396
ee78dc32
GV
4397 BLOCK_INPUT;
4398 /* First, try whatever font the caller has specified. */
4399 if (STRINGP (font))
4587b026
GV
4400 {
4401 tem = Fquery_fontset (font, Qnil);
4402 if (STRINGP (tem))
d5db4077 4403 font = x_new_fontset (f, SDATA (tem));
4587b026 4404 else
d5db4077 4405 font = x_new_font (f, SDATA (font));
4587b026 4406 }
ee78dc32
GV
4407 /* Try out a font which we hope has bold and italic variations. */
4408 if (!STRINGP (font))
e39649be 4409 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 4410 if (! STRINGP (font))
6fc2811b 4411 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
4412 /* If those didn't work, look for something which will at least work. */
4413 if (! STRINGP (font))
6fc2811b 4414 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
4415 UNBLOCK_INPUT;
4416 if (! STRINGP (font))
1edf84e7 4417 font = build_string ("Fixedsys");
ee78dc32 4418
7d0393cf 4419 x_default_parameter (f, parms, Qfont, font,
6fc2811b 4420 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
4421 }
4422
4423 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 4424 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
4425 /* This defaults to 2 in order to match xterm. We recognize either
4426 internalBorderWidth or internalBorder (which is what xterm calls
4427 it). */
4428 if (NILP (Fassq (Qinternal_border_width, parms)))
4429 {
4430 Lisp_Object value;
4431
6fc2811b 4432 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 4433 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
4434 if (! EQ (value, Qunbound))
4435 parms = Fcons (Fcons (Qinternal_border_width, value),
4436 parms);
4437 }
1edf84e7 4438 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 4439 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
4440 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
4441 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
4442 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
4443
4444 /* Also do the stuff which must be set before the window exists. */
4445 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 4446 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 4447 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 4448 "background", "Background", RES_TYPE_STRING);
ee78dc32 4449 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 4450 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 4451 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 4452 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 4453 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
4454 "borderColor", "BorderColor", RES_TYPE_STRING);
4455 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
4456 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
4457 x_default_parameter (f, parms, Qline_spacing, Qnil,
4458 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
4459 x_default_parameter (f, parms, Qleft_fringe, Qnil,
4460 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4461 x_default_parameter (f, parms, Qright_fringe, Qnil,
4462 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 4463
ee78dc32 4464
6fc2811b
JR
4465 /* Init faces before x_default_parameter is called for scroll-bar
4466 parameters because that function calls x_set_scroll_bar_width,
4467 which calls change_frame_size, which calls Fset_window_buffer,
4468 which runs hooks, which call Fvertical_motion. At the end, we
4469 end up in init_iterator with a null face cache, which should not
4470 happen. */
4471 init_frame_faces (f);
7d0393cf 4472
ee78dc32 4473 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b 4474 "menuBar", "MenuBar", RES_TYPE_NUMBER);
d3109773 4475 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
6fc2811b 4476 "toolBar", "ToolBar", RES_TYPE_NUMBER);
919f1e88 4477
1edf84e7 4478 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 4479 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 4480 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 4481 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
4482 x_default_parameter (f, parms, Qfullscreen, Qnil,
4483 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 4484
fbd6baed
GV
4485 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
4486 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e 4487
c9b2104d
JR
4488 f->output_data.w32->text_cursor = w32_load_cursor (IDC_IBEAM);
4489 f->output_data.w32->nontext_cursor = w32_load_cursor (IDC_ARROW);
4490 f->output_data.w32->modeline_cursor = w32_load_cursor (IDC_ARROW);
7d63e5e3 4491 f->output_data.w32->hand_cursor = w32_load_cursor (IDC_HAND);
c9b2104d
JR
4492 f->output_data.w32->hourglass_cursor = w32_load_cursor (IDC_WAIT);
4493 f->output_data.w32->horizontal_drag_cursor = w32_load_cursor (IDC_SIZEWE);
c9b2104d 4494
6d906347 4495 window_prompting = x_figure_window_size (f, parms, 1);
ee78dc32 4496
6fc2811b
JR
4497 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4498 f->no_split = minibuffer_only || EQ (tem, Qt);
4499
fbd6baed 4500 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 4501 x_icon (f, parms);
6fc2811b
JR
4502
4503 x_make_gc (f);
4504
4505 /* Now consider the frame official. */
4506 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
4507 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
4508
4509 /* We need to do this after creating the window, so that the
4510 icon-creation functions can say whose icon they're describing. */
4511 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 4512 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
4513
4514 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 4515 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 4516 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 4517 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 4518 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
4519 "cursorType", "CursorType", RES_TYPE_SYMBOL);
4520 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4521 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32 4522
be786000 4523 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
ee78dc32 4524 Change will not be effected unless different from the current
be786000
KS
4525 FRAME_LINES (f). */
4526 width = FRAME_COLS (f);
4527 height = FRAME_LINES (f);
dc220243 4528
be786000
KS
4529 FRAME_LINES (f) = 0;
4530 SET_FRAME_COLS (f, 0);
6fc2811b
JR
4531 change_frame_size (f, height, width, 1, 0, 0);
4532
6fc2811b
JR
4533 /* Tell the server what size and position, etc, we want, and how
4534 badly we want them. This should be done after we have the menu
4535 bar so that its size can be taken into account. */
ee78dc32
GV
4536 BLOCK_INPUT;
4537 x_wm_set_size_hint (f, window_prompting, 0);
4538 UNBLOCK_INPUT;
4539
815d969e
JR
4540 /* Avoid a bug that causes the new frame to never become visible if
4541 an echo area message is displayed during the following call1. */
4542 specbind(Qredisplay_dont_pause, Qt);
4543
4694d762
JR
4544 /* Set up faces after all frame parameters are known. This call
4545 also merges in face attributes specified for new frames. If we
4546 don't do this, the `menu' face for instance won't have the right
4547 colors, and the menu bar won't appear in the specified colors for
4548 new frames. */
4549 call1 (Qface_set_after_frame_default, frame);
4550
6fc2811b
JR
4551 /* Make the window appear on the frame and enable display, unless
4552 the caller says not to. However, with explicit parent, Emacs
4553 cannot control visibility, so don't try. */
fbd6baed 4554 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
4555 {
4556 Lisp_Object visibility;
4557
6fc2811b 4558 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
4559 if (EQ (visibility, Qunbound))
4560 visibility = Qt;
4561
4562 if (EQ (visibility, Qicon))
4563 x_iconify_frame (f);
4564 else if (! NILP (visibility))
4565 x_make_frame_visible (f);
4566 else
4567 /* Must have been Qnil. */
4568 ;
4569 }
6fc2811b 4570 UNGCPRO;
7d0393cf 4571
9e57df62
GM
4572 /* Make sure windows on this frame appear in calls to next-window
4573 and similar functions. */
4574 Vwindow_list = Qnil;
7d0393cf 4575
ee78dc32
GV
4576 return unbind_to (count, frame);
4577}
4578
4579/* FRAME is used only to get a handle on the X display. We don't pass the
4580 display info directly because we're called from frame.c, which doesn't
4581 know about that structure. */
4582Lisp_Object
4583x_get_focus_frame (frame)
4584 struct frame *frame;
4585{
fbd6baed 4586 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 4587 Lisp_Object xfocus;
fbd6baed 4588 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
4589 return Qnil;
4590
fbd6baed 4591 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
4592 return xfocus;
4593}
1edf84e7
GV
4594
4595DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 4596 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
4597 (frame)
4598 Lisp_Object frame;
4599{
4600 x_focus_on_frame (check_x_frame (frame));
4601 return Qnil;
4602}
4603
ee78dc32 4604\f
767b1ff0
JR
4605/* Return the charset portion of a font name. */
4606char * xlfd_charset_of_font (char * fontname)
4607{
4608 char *charset, *encoding;
4609
4610 encoding = strrchr(fontname, '-');
ceb12877 4611 if (!encoding || encoding == fontname)
767b1ff0
JR
4612 return NULL;
4613
478ea067
AI
4614 for (charset = encoding - 1; charset >= fontname; charset--)
4615 if (*charset == '-')
4616 break;
767b1ff0 4617
478ea067 4618 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
4619 return NULL;
4620
4621 return charset + 1;
4622}
4623
33d52f9c
GV
4624struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
4625 int size, char* filename);
8edb0a6f 4626static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
4627static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
4628 char * charset);
4629static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 4630
8edb0a6f 4631static struct font_info *
33d52f9c 4632w32_load_system_font (f,fontname,size)
55dcfc15
AI
4633 struct frame *f;
4634 char * fontname;
4635 int size;
ee78dc32 4636{
4587b026
GV
4637 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4638 Lisp_Object font_names;
4639
4587b026
GV
4640 /* Get a list of all the fonts that match this name. Once we
4641 have a list of matching fonts, we compare them against the fonts
4642 we already have loaded by comparing names. */
4643 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
4644
4645 if (!NILP (font_names))
3c190163 4646 {
4587b026
GV
4647 Lisp_Object tail;
4648 int i;
4587b026
GV
4649
4650 /* First check if any are already loaded, as that is cheaper
4651 than loading another one. */
4652 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 4653 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
4654 if (dpyinfo->font_table[i].name
4655 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 4656 SDATA (XCAR (tail)))
6fc2811b 4657 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 4658 SDATA (XCAR (tail)))))
4587b026 4659 return (dpyinfo->font_table + i);
6fc2811b 4660
d5db4077 4661 fontname = (char *) SDATA (XCAR (font_names));
4587b026 4662 }
1075afa9 4663 else if (w32_strict_fontnames)
5ca0cd71
GV
4664 {
4665 /* If EnumFontFamiliesEx was available, we got a full list of
4666 fonts back so stop now to avoid the possibility of loading a
4667 random font. If we had to fall back to EnumFontFamilies, the
4668 list is incomplete, so continue whether the font we want was
4669 listed or not. */
4670 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
4671 FARPROC enum_font_families_ex
1075afa9 4672 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
4673 if (enum_font_families_ex)
4674 return NULL;
4675 }
4587b026
GV
4676
4677 /* Load the font and add it to the table. */
4678 {
767b1ff0 4679 char *full_name, *encoding, *charset;
4587b026
GV
4680 XFontStruct *font;
4681 struct font_info *fontp;
3c190163 4682 LOGFONT lf;
4587b026 4683 BOOL ok;
19c291d3 4684 int codepage;
6fc2811b 4685 int i;
5ac45f98 4686
4587b026 4687 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 4688 return (NULL);
5ac45f98 4689
4587b026
GV
4690 if (!*lf.lfFaceName)
4691 /* If no name was specified for the font, we get a random font
4692 from CreateFontIndirect - this is not particularly
4693 desirable, especially since CreateFontIndirect does not
4694 fill out the missing name in lf, so we never know what we
4695 ended up with. */
4696 return NULL;
4697
c8d88d08 4698 lf.lfQuality = DEFAULT_QUALITY;
d65a9cdc 4699
3c190163 4700 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 4701 bzero (font, sizeof (*font));
5ac45f98 4702
33d52f9c
GV
4703 /* Set bdf to NULL to indicate that this is a Windows font. */
4704 font->bdf = NULL;
5ac45f98 4705
3c190163 4706 BLOCK_INPUT;
5ac45f98
GV
4707
4708 font->hfont = CreateFontIndirect (&lf);
ee78dc32 4709
7d0393cf 4710 if (font->hfont == NULL)
1a292d24
AI
4711 {
4712 ok = FALSE;
7d0393cf
JB
4713 }
4714 else
1a292d24
AI
4715 {
4716 HDC hdc;
4717 HANDLE oldobj;
19c291d3
AI
4718
4719 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
4720
4721 hdc = GetDC (dpyinfo->root_window);
4722 oldobj = SelectObject (hdc, font->hfont);
5c6682be 4723
1a292d24 4724 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
4725 if (codepage == CP_UNICODE)
4726 font->double_byte_p = 1;
4727 else
8b77111c
AI
4728 {
4729 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
4730 don't report themselves as double byte fonts, when
4731 patently they are. So instead of trusting
4732 GetFontLanguageInfo, we check the properties of the
4733 codepage directly, since that is ultimately what we are
4734 working from anyway. */
4735 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
4736 CPINFO cpi = {0};
4737 GetCPInfo (codepage, &cpi);
4738 font->double_byte_p = cpi.MaxCharSize > 1;
4739 }
5c6682be 4740
1a292d24
AI
4741 SelectObject (hdc, oldobj);
4742 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
4743 /* Fill out details in lf according to the font that was
4744 actually loaded. */
4745 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
4746 lf.lfWidth = font->tm.tmAveCharWidth;
4747 lf.lfWeight = font->tm.tmWeight;
4748 lf.lfItalic = font->tm.tmItalic;
4749 lf.lfCharSet = font->tm.tmCharSet;
4750 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 4751 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
4752 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
4753 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
4754
4755 w32_cache_char_metrics (font);
1a292d24 4756 }
5ac45f98 4757
1a292d24 4758 UNBLOCK_INPUT;
5ac45f98 4759
4587b026
GV
4760 if (!ok)
4761 {
1a292d24
AI
4762 w32_unload_font (dpyinfo, font);
4763 return (NULL);
4764 }
ee78dc32 4765
6fc2811b
JR
4766 /* Find a free slot in the font table. */
4767 for (i = 0; i < dpyinfo->n_fonts; ++i)
4768 if (dpyinfo->font_table[i].name == NULL)
4769 break;
4770
4771 /* If no free slot found, maybe enlarge the font table. */
4772 if (i == dpyinfo->n_fonts
4773 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 4774 {
6fc2811b
JR
4775 int sz;
4776 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
4777 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 4778 dpyinfo->font_table
6fc2811b 4779 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
4780 }
4781
6fc2811b
JR
4782 fontp = dpyinfo->font_table + i;
4783 if (i == dpyinfo->n_fonts)
4784 ++dpyinfo->n_fonts;
4587b026
GV
4785
4786 /* Now fill in the slots of *FONTP. */
4787 BLOCK_INPUT;
0d4c2dc2 4788 bzero (fontp, sizeof (*fontp));
4587b026 4789 fontp->font = font;
6fc2811b 4790 fontp->font_idx = i;
4587b026
GV
4791 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
4792 bcopy (fontname, fontp->name, strlen (fontname) + 1);
4793
767b1ff0
JR
4794 charset = xlfd_charset_of_font (fontname);
4795
19c291d3
AI
4796 /* Cache the W32 codepage for a font. This makes w32_encode_char
4797 (called for every glyph during redisplay) much faster. */
4798 fontp->codepage = codepage;
4799
4587b026
GV
4800 /* Work out the font's full name. */
4801 full_name = (char *)xmalloc (100);
767b1ff0 4802 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
4803 fontp->full_name = full_name;
4804 else
4805 {
4806 /* If all else fails - just use the name we used to load it. */
4807 xfree (full_name);
4808 fontp->full_name = fontp->name;
4809 }
4810
4811 fontp->size = FONT_WIDTH (font);
4812 fontp->height = FONT_HEIGHT (font);
4813
4814 /* The slot `encoding' specifies how to map a character
4815 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
4816 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
4817 (0:0x20..0x7F, 1:0xA0..0xFF,
4818 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 4819 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 4820 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
4821 which is never used by any charset. If mapping can't be
4822 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
4823
4824 /* SJIS fonts need to be set to type 4, all others seem to work as
4825 type FONT_ENCODING_NOT_DECIDED. */
4826 encoding = strrchr (fontp->name, '-');
d84b082d 4827 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 4828 fontp->encoding[1] = 4;
33d52f9c 4829 else
1c885fe1 4830 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
4831
4832 /* The following three values are set to 0 under W32, which is
4833 what they get set to if XGetFontProperty fails under X. */
4834 fontp->baseline_offset = 0;
4835 fontp->relative_compose = 0;
33d52f9c 4836 fontp->default_ascent = 0;
4587b026 4837
6fc2811b
JR
4838 /* Set global flag fonts_changed_p to non-zero if the font loaded
4839 has a character with a smaller width than any other character
f7b9d4d1 4840 before, or if the font loaded has a smaller height than any
6fc2811b
JR
4841 other font loaded before. If this happens, it will make a
4842 glyph matrix reallocation necessary. */
f7b9d4d1 4843 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 4844 UNBLOCK_INPUT;
4587b026
GV
4845 return fontp;
4846 }
4847}
4848
33d52f9c
GV
4849/* Load font named FONTNAME of size SIZE for frame F, and return a
4850 pointer to the structure font_info while allocating it dynamically.
4851 If loading fails, return NULL. */
4852struct font_info *
4853w32_load_font (f,fontname,size)
4854struct frame *f;
4855char * fontname;
4856int size;
4857{
4858 Lisp_Object bdf_fonts;
4859 struct font_info *retval = NULL;
4860
8edb0a6f 4861 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
4862
4863 while (!retval && CONSP (bdf_fonts))
4864 {
4865 char *bdf_name, *bdf_file;
4866 Lisp_Object bdf_pair;
4867
d5db4077 4868 bdf_name = SDATA (XCAR (bdf_fonts));
8e713be6 4869 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
d5db4077 4870 bdf_file = SDATA (XCDR (bdf_pair));
33d52f9c
GV
4871
4872 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
4873
8e713be6 4874 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
4875 }
4876
4877 if (retval)
4878 return retval;
4879
4880 return w32_load_system_font(f, fontname, size);
4881}
4882
4883
7d0393cf 4884void
fbd6baed
GV
4885w32_unload_font (dpyinfo, font)
4886 struct w32_display_info *dpyinfo;
ee78dc32
GV
4887 XFontStruct * font;
4888{
7d0393cf 4889 if (font)
ee78dc32 4890 {
c6be3860 4891 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
4892 if (font->bdf) w32_free_bdf_font (font->bdf);
4893
3c190163 4894 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
4895 xfree (font);
4896 }
4897}
4898
fbd6baed 4899/* The font conversion stuff between x and w32 */
ee78dc32
GV
4900
4901/* X font string is as follows (from faces.el)
4902 * (let ((- "[-?]")
4903 * (foundry "[^-]+")
4904 * (family "[^-]+")
4905 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
4906 * (weight\? "\\([^-]*\\)") ; 1
4907 * (slant "\\([ior]\\)") ; 2
4908 * (slant\? "\\([^-]?\\)") ; 2
4909 * (swidth "\\([^-]*\\)") ; 3
4910 * (adstyle "[^-]*") ; 4
4911 * (pixelsize "[0-9]+")
4912 * (pointsize "[0-9][0-9]+")
4913 * (resx "[0-9][0-9]+")
4914 * (resy "[0-9][0-9]+")
4915 * (spacing "[cmp?*]")
4916 * (avgwidth "[0-9]+")
4917 * (registry "[^-]+")
4918 * (encoding "[^-]+")
4919 * )
ee78dc32 4920 */
ee78dc32 4921
7d0393cf 4922static LONG
fbd6baed 4923x_to_w32_weight (lpw)
ee78dc32
GV
4924 char * lpw;
4925{
4926 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
4927
4928 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
4929 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
4930 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
4931 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 4932 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
4933 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
4934 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
4935 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
4936 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
4937 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 4938 else
5ac45f98 4939 return FW_DONTCARE;
ee78dc32
GV
4940}
4941
5ac45f98 4942
7d0393cf 4943static char *
fbd6baed 4944w32_to_x_weight (fnweight)
ee78dc32
GV
4945 int fnweight;
4946{
5ac45f98
GV
4947 if (fnweight >= FW_HEAVY) return "heavy";
4948 if (fnweight >= FW_EXTRABOLD) return "extrabold";
4949 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 4950 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
4951 if (fnweight >= FW_MEDIUM) return "medium";
4952 if (fnweight >= FW_NORMAL) return "normal";
4953 if (fnweight >= FW_LIGHT) return "light";
4954 if (fnweight >= FW_EXTRALIGHT) return "extralight";
4955 if (fnweight >= FW_THIN) return "thin";
4956 else
4957 return "*";
4958}
4959
8edb0a6f 4960static LONG
fbd6baed 4961x_to_w32_charset (lpcs)
5ac45f98
GV
4962 char * lpcs;
4963{
767b1ff0 4964 Lisp_Object this_entry, w32_charset;
8b77111c
AI
4965 char *charset;
4966 int len = strlen (lpcs);
4967
4968 /* Support "*-#nnn" format for unknown charsets. */
4969 if (strncmp (lpcs, "*-#", 3) == 0)
4970 return atoi (lpcs + 3);
4971
4972 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
4973 charset = alloca (len + 1);
4974 strcpy (charset, lpcs);
4975 lpcs = strchr (charset, '*');
4976 if (lpcs)
4977 *lpcs = 0;
4587b026 4978
dfff8a69
JR
4979 /* Look through w32-charset-info-alist for the character set.
4980 Format of each entry is
4981 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
4982 */
8b77111c 4983 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 4984
767b1ff0
JR
4985 if (NILP(this_entry))
4986 {
4987 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 4988 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
4989 return ANSI_CHARSET;
4990 else
4991 return DEFAULT_CHARSET;
4992 }
4993
4994 w32_charset = Fcar (Fcdr (this_entry));
4995
d84b082d 4996 /* Translate Lisp symbol to number. */
767b1ff0
JR
4997 if (w32_charset == Qw32_charset_ansi)
4998 return ANSI_CHARSET;
4999 if (w32_charset == Qw32_charset_symbol)
5000 return SYMBOL_CHARSET;
5001 if (w32_charset == Qw32_charset_shiftjis)
5002 return SHIFTJIS_CHARSET;
5003 if (w32_charset == Qw32_charset_hangeul)
5004 return HANGEUL_CHARSET;
5005 if (w32_charset == Qw32_charset_chinesebig5)
5006 return CHINESEBIG5_CHARSET;
5007 if (w32_charset == Qw32_charset_gb2312)
5008 return GB2312_CHARSET;
5009 if (w32_charset == Qw32_charset_oem)
5010 return OEM_CHARSET;
dfff8a69 5011#ifdef JOHAB_CHARSET
767b1ff0
JR
5012 if (w32_charset == Qw32_charset_johab)
5013 return JOHAB_CHARSET;
5014 if (w32_charset == Qw32_charset_easteurope)
5015 return EASTEUROPE_CHARSET;
5016 if (w32_charset == Qw32_charset_turkish)
5017 return TURKISH_CHARSET;
5018 if (w32_charset == Qw32_charset_baltic)
5019 return BALTIC_CHARSET;
5020 if (w32_charset == Qw32_charset_russian)
5021 return RUSSIAN_CHARSET;
5022 if (w32_charset == Qw32_charset_arabic)
5023 return ARABIC_CHARSET;
5024 if (w32_charset == Qw32_charset_greek)
5025 return GREEK_CHARSET;
5026 if (w32_charset == Qw32_charset_hebrew)
5027 return HEBREW_CHARSET;
5028 if (w32_charset == Qw32_charset_vietnamese)
5029 return VIETNAMESE_CHARSET;
5030 if (w32_charset == Qw32_charset_thai)
5031 return THAI_CHARSET;
5032 if (w32_charset == Qw32_charset_mac)
5033 return MAC_CHARSET;
dfff8a69 5034#endif /* JOHAB_CHARSET */
5ac45f98 5035#ifdef UNICODE_CHARSET
767b1ff0
JR
5036 if (w32_charset == Qw32_charset_unicode)
5037 return UNICODE_CHARSET;
5ac45f98 5038#endif
dfff8a69
JR
5039
5040 return DEFAULT_CHARSET;
5ac45f98
GV
5041}
5042
dfff8a69 5043
8edb0a6f 5044static char *
fbd6baed 5045w32_to_x_charset (fncharset)
5ac45f98
GV
5046 int fncharset;
5047{
5e905a57 5048 static char buf[32];
767b1ff0 5049 Lisp_Object charset_type;
1edf84e7 5050
5ac45f98
GV
5051 switch (fncharset)
5052 {
767b1ff0
JR
5053 case ANSI_CHARSET:
5054 /* Handle startup case of w32-charset-info-alist not
5055 being set up yet. */
5056 if (NILP(Vw32_charset_info_alist))
5057 return "iso8859-1";
5058 charset_type = Qw32_charset_ansi;
5059 break;
5060 case DEFAULT_CHARSET:
5061 charset_type = Qw32_charset_default;
5062 break;
5063 case SYMBOL_CHARSET:
5064 charset_type = Qw32_charset_symbol;
5065 break;
5066 case SHIFTJIS_CHARSET:
5067 charset_type = Qw32_charset_shiftjis;
5068 break;
5069 case HANGEUL_CHARSET:
5070 charset_type = Qw32_charset_hangeul;
5071 break;
5072 case GB2312_CHARSET:
5073 charset_type = Qw32_charset_gb2312;
5074 break;
5075 case CHINESEBIG5_CHARSET:
5076 charset_type = Qw32_charset_chinesebig5;
5077 break;
5078 case OEM_CHARSET:
5079 charset_type = Qw32_charset_oem;
5080 break;
4587b026
GV
5081
5082 /* More recent versions of Windows (95 and NT4.0) define more
5083 character sets. */
5084#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
5085 case EASTEUROPE_CHARSET:
5086 charset_type = Qw32_charset_easteurope;
5087 break;
5088 case TURKISH_CHARSET:
5089 charset_type = Qw32_charset_turkish;
5090 break;
5091 case BALTIC_CHARSET:
5092 charset_type = Qw32_charset_baltic;
5093 break;
33d52f9c 5094 case RUSSIAN_CHARSET:
767b1ff0
JR
5095 charset_type = Qw32_charset_russian;
5096 break;
5097 case ARABIC_CHARSET:
5098 charset_type = Qw32_charset_arabic;
5099 break;
5100 case GREEK_CHARSET:
5101 charset_type = Qw32_charset_greek;
5102 break;
5103 case HEBREW_CHARSET:
5104 charset_type = Qw32_charset_hebrew;
5105 break;
5106 case VIETNAMESE_CHARSET:
5107 charset_type = Qw32_charset_vietnamese;
5108 break;
5109 case THAI_CHARSET:
5110 charset_type = Qw32_charset_thai;
5111 break;
5112 case MAC_CHARSET:
5113 charset_type = Qw32_charset_mac;
5114 break;
5115 case JOHAB_CHARSET:
5116 charset_type = Qw32_charset_johab;
5117 break;
4587b026
GV
5118#endif
5119
5ac45f98 5120#ifdef UNICODE_CHARSET
767b1ff0
JR
5121 case UNICODE_CHARSET:
5122 charset_type = Qw32_charset_unicode;
5123 break;
5ac45f98 5124#endif
767b1ff0
JR
5125 default:
5126 /* Encode numerical value of unknown charset. */
5127 sprintf (buf, "*-#%u", fncharset);
5128 return buf;
5ac45f98 5129 }
7d0393cf 5130
767b1ff0
JR
5131 {
5132 Lisp_Object rest;
5133 char * best_match = NULL;
5134
5135 /* Look through w32-charset-info-alist for the character set.
5136 Prefer ISO codepages, and prefer lower numbers in the ISO
5137 range. Only return charsets for codepages which are installed.
5138
5139 Format of each entry is
5140 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5141 */
5142 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5143 {
5144 char * x_charset;
5145 Lisp_Object w32_charset;
5146 Lisp_Object codepage;
5147
5148 Lisp_Object this_entry = XCAR (rest);
5149
5150 /* Skip invalid entries in alist. */
5151 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
5152 || !CONSP (XCDR (this_entry))
5153 || !SYMBOLP (XCAR (XCDR (this_entry))))
5154 continue;
5155
d5db4077 5156 x_charset = SDATA (XCAR (this_entry));
767b1ff0
JR
5157 w32_charset = XCAR (XCDR (this_entry));
5158 codepage = XCDR (XCDR (this_entry));
5159
5160 /* Look for Same charset and a valid codepage (or non-int
5161 which means ignore). */
5162 if (w32_charset == charset_type
5163 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
5164 || IsValidCodePage (XINT (codepage))))
5165 {
5166 /* If we don't have a match already, then this is the
5167 best. */
5168 if (!best_match)
5169 best_match = x_charset;
5170 /* If this is an ISO codepage, and the best so far isn't,
5171 then this is better. */
d84b082d
JR
5172 else if (strnicmp (best_match, "iso", 3) != 0
5173 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
5174 best_match = x_charset;
5175 /* If both are ISO8859 codepages, choose the one with the
5176 lowest number in the encoding field. */
d84b082d
JR
5177 else if (strnicmp (best_match, "iso8859-", 8) == 0
5178 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
5179 {
5180 int best_enc = atoi (best_match + 8);
5181 int this_enc = atoi (x_charset + 8);
5182 if (this_enc > 0 && this_enc < best_enc)
5183 best_match = x_charset;
7d0393cf 5184 }
767b1ff0
JR
5185 }
5186 }
5187
5188 /* If no match, encode the numeric value. */
5189 if (!best_match)
5190 {
5191 sprintf (buf, "*-#%u", fncharset);
5192 return buf;
5193 }
5194
5e905a57
JR
5195 strncpy(buf, best_match, 31);
5196 buf[31] = '\0';
767b1ff0
JR
5197 return buf;
5198 }
ee78dc32
GV
5199}
5200
dfff8a69 5201
d84b082d
JR
5202/* Return all the X charsets that map to a font. */
5203static Lisp_Object
5204w32_to_all_x_charsets (fncharset)
5205 int fncharset;
5206{
5207 static char buf[32];
5208 Lisp_Object charset_type;
5209 Lisp_Object retval = Qnil;
5210
5211 switch (fncharset)
5212 {
5213 case ANSI_CHARSET:
5214 /* Handle startup case of w32-charset-info-alist not
5215 being set up yet. */
5216 if (NILP(Vw32_charset_info_alist))
d86c35ee
JR
5217 return Fcons (build_string ("iso8859-1"), Qnil);
5218
d84b082d
JR
5219 charset_type = Qw32_charset_ansi;
5220 break;
5221 case DEFAULT_CHARSET:
5222 charset_type = Qw32_charset_default;
5223 break;
5224 case SYMBOL_CHARSET:
5225 charset_type = Qw32_charset_symbol;
5226 break;
5227 case SHIFTJIS_CHARSET:
5228 charset_type = Qw32_charset_shiftjis;
5229 break;
5230 case HANGEUL_CHARSET:
5231 charset_type = Qw32_charset_hangeul;
5232 break;
5233 case GB2312_CHARSET:
5234 charset_type = Qw32_charset_gb2312;
5235 break;
5236 case CHINESEBIG5_CHARSET:
5237 charset_type = Qw32_charset_chinesebig5;
5238 break;
5239 case OEM_CHARSET:
5240 charset_type = Qw32_charset_oem;
5241 break;
5242
5243 /* More recent versions of Windows (95 and NT4.0) define more
5244 character sets. */
5245#ifdef EASTEUROPE_CHARSET
5246 case EASTEUROPE_CHARSET:
5247 charset_type = Qw32_charset_easteurope;
5248 break;
5249 case TURKISH_CHARSET:
5250 charset_type = Qw32_charset_turkish;
5251 break;
5252 case BALTIC_CHARSET:
5253 charset_type = Qw32_charset_baltic;
5254 break;
5255 case RUSSIAN_CHARSET:
5256 charset_type = Qw32_charset_russian;
5257 break;
5258 case ARABIC_CHARSET:
5259 charset_type = Qw32_charset_arabic;
5260 break;
5261 case GREEK_CHARSET:
5262 charset_type = Qw32_charset_greek;
5263 break;
5264 case HEBREW_CHARSET:
5265 charset_type = Qw32_charset_hebrew;
5266 break;
5267 case VIETNAMESE_CHARSET:
5268 charset_type = Qw32_charset_vietnamese;
5269 break;
5270 case THAI_CHARSET:
5271 charset_type = Qw32_charset_thai;
5272 break;
5273 case MAC_CHARSET:
5274 charset_type = Qw32_charset_mac;
5275 break;
5276 case JOHAB_CHARSET:
5277 charset_type = Qw32_charset_johab;
5278 break;
5279#endif
5280
5281#ifdef UNICODE_CHARSET
5282 case UNICODE_CHARSET:
5283 charset_type = Qw32_charset_unicode;
5284 break;
5285#endif
5286 default:
5287 /* Encode numerical value of unknown charset. */
5288 sprintf (buf, "*-#%u", fncharset);
5289 return Fcons (build_string (buf), Qnil);
5290 }
7d0393cf 5291
d84b082d
JR
5292 {
5293 Lisp_Object rest;
5294 /* Look through w32-charset-info-alist for the character set.
5295 Only return charsets for codepages which are installed.
5296
5297 Format of each entry in Vw32_charset_info_alist is
5298 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5299 */
5300 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5301 {
5302 Lisp_Object x_charset;
5303 Lisp_Object w32_charset;
5304 Lisp_Object codepage;
5305
5306 Lisp_Object this_entry = XCAR (rest);
5307
5308 /* Skip invalid entries in alist. */
5309 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
5310 || !CONSP (XCDR (this_entry))
5311 || !SYMBOLP (XCAR (XCDR (this_entry))))
5312 continue;
5313
5314 x_charset = XCAR (this_entry);
5315 w32_charset = XCAR (XCDR (this_entry));
5316 codepage = XCDR (XCDR (this_entry));
5317
5318 /* Look for Same charset and a valid codepage (or non-int
5319 which means ignore). */
5320 if (w32_charset == charset_type
5321 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
5322 || IsValidCodePage (XINT (codepage))))
5323 {
5324 retval = Fcons (x_charset, retval);
5325 }
5326 }
5327
5328 /* If no match, encode the numeric value. */
5329 if (NILP (retval))
5330 {
5331 sprintf (buf, "*-#%u", fncharset);
5332 return Fcons (build_string (buf), Qnil);
5333 }
5334
5335 return retval;
5336 }
5337}
5338
dfff8a69
JR
5339/* Get the Windows codepage corresponding to the specified font. The
5340 charset info in the font name is used to look up
5341 w32-charset-to-codepage-alist. */
7d0393cf 5342int
dfff8a69
JR
5343w32_codepage_for_font (char *fontname)
5344{
767b1ff0
JR
5345 Lisp_Object codepage, entry;
5346 char *charset_str, *charset, *end;
dfff8a69 5347
767b1ff0 5348 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
5349 return CP_DEFAULT;
5350
767b1ff0
JR
5351 /* Extract charset part of font string. */
5352 charset = xlfd_charset_of_font (fontname);
5353
5354 if (!charset)
ceb12877 5355 return CP_UNKNOWN;
767b1ff0 5356
8b77111c 5357 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
5358 strcpy (charset_str, charset);
5359
8b77111c 5360#if 0
dfff8a69
JR
5361 /* Remove leading "*-". */
5362 if (strncmp ("*-", charset_str, 2) == 0)
5363 charset = charset_str + 2;
5364 else
8b77111c 5365#endif
dfff8a69
JR
5366 charset = charset_str;
5367
5368 /* Stop match at wildcard (including preceding '-'). */
5369 if (end = strchr (charset, '*'))
5370 {
5371 if (end > charset && *(end-1) == '-')
5372 end--;
5373 *end = '\0';
5374 }
5375
767b1ff0
JR
5376 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
5377 if (NILP (entry))
ceb12877 5378 return CP_UNKNOWN;
767b1ff0
JR
5379
5380 codepage = Fcdr (Fcdr (entry));
5381
5382 if (NILP (codepage))
5383 return CP_8BIT;
5384 else if (XFASTINT (codepage) == XFASTINT (Qt))
5385 return CP_UNICODE;
5386 else if (INTEGERP (codepage))
dfff8a69
JR
5387 return XINT (codepage);
5388 else
ceb12877 5389 return CP_UNKNOWN;
dfff8a69
JR
5390}
5391
5392
7d0393cf 5393static BOOL
767b1ff0 5394w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
5395 LOGFONT * lplogfont;
5396 char * lpxstr;
5397 int len;
767b1ff0 5398 char * specific_charset;
ee78dc32 5399{
6fc2811b 5400 char* fonttype;
f46e6225 5401 char *fontname;
3cb20f4a
RS
5402 char height_pixels[8];
5403 char height_dpi[8];
5404 char width_pixels[8];
4587b026 5405 char *fontname_dash;
ac849ba4
JR
5406 int display_resy = (int) one_w32_display_info.resy;
5407 int display_resx = (int) one_w32_display_info.resx;
f46e6225
GV
5408 int bufsz;
5409 struct coding_system coding;
3cb20f4a
RS
5410
5411 if (!lpxstr) abort ();
ee78dc32 5412
3cb20f4a
RS
5413 if (!lplogfont)
5414 return FALSE;
5415
6fc2811b
JR
5416 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
5417 fonttype = "raster";
5418 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
5419 fonttype = "outline";
5420 else
5421 fonttype = "unknown";
5422
1fa3a200 5423 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 5424 &coding);
aab5ac44
KH
5425 coding.src_multibyte = 0;
5426 coding.dst_multibyte = 1;
f46e6225 5427 coding.mode |= CODING_MODE_LAST_BLOCK;
65413122
KH
5428 /* We explicitely disable composition handling because selection
5429 data should not contain any composition sequence. */
5430 coding.composing = COMPOSITION_DISABLED;
f46e6225
GV
5431 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
5432
5433 fontname = alloca(sizeof(*fontname) * bufsz);
5434 decode_coding (&coding, lplogfont->lfFaceName, fontname,
5435 strlen(lplogfont->lfFaceName), bufsz - 1);
5436 *(fontname + coding.produced) = '\0';
4587b026
GV
5437
5438 /* Replace dashes with underscores so the dashes are not
f46e6225 5439 misinterpreted. */
4587b026
GV
5440 fontname_dash = fontname;
5441 while (fontname_dash = strchr (fontname_dash, '-'))
5442 *fontname_dash = '_';
5443
3cb20f4a 5444 if (lplogfont->lfHeight)
ee78dc32 5445 {
3cb20f4a
RS
5446 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
5447 sprintf (height_dpi, "%u",
33d52f9c 5448 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
5449 }
5450 else
ee78dc32 5451 {
3cb20f4a
RS
5452 strcpy (height_pixels, "*");
5453 strcpy (height_dpi, "*");
ee78dc32 5454 }
3cb20f4a
RS
5455 if (lplogfont->lfWidth)
5456 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5457 else
5458 strcpy (width_pixels, "*");
5459
5460 _snprintf (lpxstr, len - 1,
6fc2811b
JR
5461 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
5462 fonttype, /* foundry */
4587b026
GV
5463 fontname, /* family */
5464 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5465 lplogfont->lfItalic?'i':'r', /* slant */
5466 /* setwidth name */
5467 /* add style name */
5468 height_pixels, /* pixel size */
5469 height_dpi, /* point size */
33d52f9c
GV
5470 display_resx, /* resx */
5471 display_resy, /* resy */
4587b026
GV
5472 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5473 ? 'p' : 'c', /* spacing */
5474 width_pixels, /* avg width */
767b1ff0 5475 specific_charset ? specific_charset
7d0393cf 5476 : w32_to_x_charset (lplogfont->lfCharSet)
767b1ff0 5477 /* charset registry and encoding */
3cb20f4a
RS
5478 );
5479
ee78dc32
GV
5480 lpxstr[len - 1] = 0; /* just to be sure */
5481 return (TRUE);
5482}
5483
7d0393cf 5484static BOOL
fbd6baed 5485x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
5486 char * lpxstr;
5487 LOGFONT * lplogfont;
5488{
f46e6225
GV
5489 struct coding_system coding;
5490
ee78dc32 5491 if (!lplogfont) return (FALSE);
f46e6225 5492
ee78dc32 5493 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 5494
1a292d24 5495 /* Set default value for each field. */
771c47d5 5496#if 1
ee78dc32
GV
5497 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5498 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5499 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
5500#else
5501 /* go for maximum quality */
5502 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5503 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5504 lplogfont->lfQuality = PROOF_QUALITY;
5505#endif
5506
1a292d24
AI
5507 lplogfont->lfCharSet = DEFAULT_CHARSET;
5508 lplogfont->lfWeight = FW_DONTCARE;
5509 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5510
5ac45f98
GV
5511 if (!lpxstr)
5512 return FALSE;
5513
5514 /* Provide a simple escape mechanism for specifying Windows font names
5515 * directly -- if font spec does not beginning with '-', assume this
5516 * format:
5517 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5518 */
7d0393cf 5519
5ac45f98
GV
5520 if (*lpxstr == '-')
5521 {
33d52f9c
GV
5522 int fields, tem;
5523 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 5524 width[10], resy[10], remainder[50];
5ac45f98 5525 char * encoding;
ac849ba4 5526 int dpi = (int) one_w32_display_info.resy;
5ac45f98
GV
5527
5528 fields = sscanf (lpxstr,
8b77111c 5529 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 5530 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
5531 if (fields == EOF)
5532 return (FALSE);
5533
5534 /* In the general case when wildcards cover more than one field,
5535 we don't know which field is which, so don't fill any in.
5536 However, we need to cope with this particular form, which is
5537 generated by font_list_1 (invoked by try_font_list):
5538 "-raster-6x10-*-gb2312*-*"
5539 and make sure to correctly parse the charset field. */
5540 if (fields == 3)
5541 {
5542 fields = sscanf (lpxstr,
5543 "-%*[^-]-%49[^-]-*-%49s",
5544 name, remainder);
5545 }
5546 else if (fields < 9)
5547 {
5548 fields = 0;
5549 remainder[0] = 0;
5550 }
6fc2811b 5551
5ac45f98
GV
5552 if (fields > 0 && name[0] != '*')
5553 {
8ea3e054
RS
5554 int bufsize;
5555 unsigned char *buf;
5556
f46e6225 5557 setup_coding_system
1fa3a200 5558 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
5559 coding.src_multibyte = 1;
5560 coding.dst_multibyte = 1;
8ea3e054
RS
5561 bufsize = encoding_buffer_size (&coding, strlen (name));
5562 buf = (unsigned char *) alloca (bufsize);
f46e6225 5563 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
5564 encode_coding (&coding, name, buf, strlen (name), bufsize);
5565 if (coding.produced >= LF_FACESIZE)
5566 coding.produced = LF_FACESIZE - 1;
5567 buf[coding.produced] = 0;
5568 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
5569 }
5570 else
5571 {
6fc2811b 5572 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
5573 }
5574
5575 fields--;
5576
fbd6baed 5577 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
5578
5579 fields--;
5580
c8874f14 5581 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
5582
5583 fields--;
5584
5585 if (fields > 0 && pixels[0] != '*')
5586 lplogfont->lfHeight = atoi (pixels);
5587
5588 fields--;
5ac45f98 5589 fields--;
33d52f9c
GV
5590 if (fields > 0 && resy[0] != '*')
5591 {
6fc2811b 5592 tem = atoi (resy);
33d52f9c
GV
5593 if (tem > 0) dpi = tem;
5594 }
5ac45f98 5595
33d52f9c
GV
5596 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
5597 lplogfont->lfHeight = atoi (height) * dpi / 720;
5598
5599 if (fields > 0)
5ac45f98
GV
5600 lplogfont->lfPitchAndFamily =
5601 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
5602
5603 fields--;
5604
5605 if (fields > 0 && width[0] != '*')
5606 lplogfont->lfWidth = atoi (width) / 10;
5607
5608 fields--;
5609
4587b026 5610 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 5611 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 5612 {
5ac45f98
GV
5613 int len = strlen (remainder);
5614 if (len > 0 && remainder[len-1] == '-')
5615 remainder[len-1] = 0;
ee78dc32 5616 }
5ac45f98 5617 encoding = remainder;
8b77111c 5618#if 0
5ac45f98
GV
5619 if (strncmp (encoding, "*-", 2) == 0)
5620 encoding += 2;
8b77111c
AI
5621#endif
5622 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
5623 }
5624 else
5625 {
5626 int fields;
5627 char name[100], height[10], width[10], weight[20];
a1a80b40 5628
5ac45f98
GV
5629 fields = sscanf (lpxstr,
5630 "%99[^:]:%9[^:]:%9[^:]:%19s",
5631 name, height, width, weight);
5632
5633 if (fields == EOF) return (FALSE);
5634
5635 if (fields > 0)
5636 {
5637 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
5638 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
5639 }
5640 else
5641 {
5642 lplogfont->lfFaceName[0] = 0;
5643 }
5644
5645 fields--;
5646
5647 if (fields > 0)
5648 lplogfont->lfHeight = atoi (height);
5649
5650 fields--;
5651
5652 if (fields > 0)
5653 lplogfont->lfWidth = atoi (width);
5654
5655 fields--;
5656
fbd6baed 5657 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
5658 }
5659
5660 /* This makes TrueType fonts work better. */
5661 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 5662
ee78dc32
GV
5663 return (TRUE);
5664}
5665
d88c567c
JR
5666/* Strip the pixel height and point height from the given xlfd, and
5667 return the pixel height. If no pixel height is specified, calculate
5668 one from the point height, or if that isn't defined either, return
5669 0 (which usually signifies a scalable font).
5670*/
8edb0a6f
JR
5671static int
5672xlfd_strip_height (char *fontname)
d88c567c 5673{
8edb0a6f 5674 int pixel_height, field_number;
d88c567c
JR
5675 char *read_from, *write_to;
5676
5677 xassert (fontname);
5678
5679 pixel_height = field_number = 0;
5680 write_to = NULL;
5681
5682 /* Look for height fields. */
5683 for (read_from = fontname; *read_from; read_from++)
5684 {
5685 if (*read_from == '-')
5686 {
5687 field_number++;
5688 if (field_number == 7) /* Pixel height. */
5689 {
5690 read_from++;
5691 write_to = read_from;
5692
5693 /* Find end of field. */
5694 for (;*read_from && *read_from != '-'; read_from++)
5695 ;
5696
5697 /* Split the fontname at end of field. */
5698 if (*read_from)
5699 {
5700 *read_from = '\0';
5701 read_from++;
5702 }
5703 pixel_height = atoi (write_to);
5704 /* Blank out field. */
5705 if (read_from > write_to)
5706 {
5707 *write_to = '-';
5708 write_to++;
5709 }
767b1ff0 5710 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
5711 return now. */
5712 else
5713 return pixel_height;
5714
5715 /* If we got a pixel height, the point height can be
5716 ignored. Just blank it out and break now. */
5717 if (pixel_height)
5718 {
5719 /* Find end of point size field. */
5720 for (; *read_from && *read_from != '-'; read_from++)
5721 ;
5722
5723 if (*read_from)
5724 read_from++;
5725
5726 /* Blank out the point size field. */
5727 if (read_from > write_to)
5728 {
5729 *write_to = '-';
5730 write_to++;
5731 }
5732 else
5733 return pixel_height;
5734
5735 break;
5736 }
5737 /* If the point height is already blank, break now. */
5738 if (*read_from == '-')
5739 {
5740 read_from++;
5741 break;
5742 }
5743 }
5744 else if (field_number == 8)
5745 {
5746 /* If we didn't get a pixel height, try to get the point
5747 height and convert that. */
5748 int point_size;
5749 char *point_size_start = read_from++;
5750
5751 /* Find end of field. */
5752 for (; *read_from && *read_from != '-'; read_from++)
5753 ;
5754
5755 if (*read_from)
5756 {
5757 *read_from = '\0';
5758 read_from++;
5759 }
5760
5761 point_size = atoi (point_size_start);
5762
5763 /* Convert to pixel height. */
5764 pixel_height = point_size
5765 * one_w32_display_info.height_in / 720;
5766
5767 /* Blank out this field and break. */
5768 *write_to = '-';
5769 write_to++;
5770 break;
5771 }
5772 }
5773 }
5774
5775 /* Shift the rest of the font spec into place. */
5776 if (write_to && read_from > write_to)
5777 {
5778 for (; *read_from; read_from++, write_to++)
5779 *write_to = *read_from;
5780 *write_to = '\0';
5781 }
5782
5783 return pixel_height;
5784}
5785
6fc2811b 5786/* Assume parameter 1 is fully qualified, no wildcards. */
7d0393cf 5787static BOOL
6fc2811b
JR
5788w32_font_match (fontname, pattern)
5789 char * fontname;
5790 char * pattern;
ee78dc32 5791{
e7c72122 5792 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 5793 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 5794 char *ptr;
ee78dc32 5795
d88c567c
JR
5796 /* Copy fontname so we can modify it during comparison. */
5797 strcpy (font_name_copy, fontname);
5798
6fc2811b
JR
5799 ptr = regex;
5800 *ptr++ = '^';
ee78dc32 5801
6fc2811b
JR
5802 /* Turn pattern into a regexp and do a regexp match. */
5803 for (; *pattern; pattern++)
5804 {
5805 if (*pattern == '?')
5806 *ptr++ = '.';
5807 else if (*pattern == '*')
5808 {
5809 *ptr++ = '.';
5810 *ptr++ = '*';
5811 }
33d52f9c 5812 else
6fc2811b 5813 *ptr++ = *pattern;
ee78dc32 5814 }
6fc2811b
JR
5815 *ptr = '$';
5816 *(ptr + 1) = '\0';
5817
d88c567c
JR
5818 /* Strip out font heights and compare them seperately, since
5819 rounding error can cause mismatches. This also allows a
5820 comparison between a font that declares only a pixel height and a
5821 pattern that declares the point height.
5822 */
5823 {
5824 int font_height, pattern_height;
5825
5826 font_height = xlfd_strip_height (font_name_copy);
5827 pattern_height = xlfd_strip_height (regex);
5828
5829 /* Compare now, and don't bother doing expensive regexp matching
5830 if the heights differ. */
5831 if (font_height && pattern_height && (font_height != pattern_height))
5832 return FALSE;
5833 }
5834
6fc2811b 5835 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 5836 font_name_copy) >= 0);
ee78dc32
GV
5837}
5838
5ca0cd71
GV
5839/* Callback functions, and a structure holding info they need, for
5840 listing system fonts on W32. We need one set of functions to do the
5841 job properly, but these don't work on NT 3.51 and earlier, so we
5842 have a second set which don't handle character sets properly to
5843 fall back on.
5844
5845 In both cases, there are two passes made. The first pass gets one
5846 font from each family, the second pass lists all the fonts from
5847 each family. */
5848
7d0393cf 5849typedef struct enumfont_t
ee78dc32
GV
5850{
5851 HDC hdc;
5852 int numFonts;
3cb20f4a 5853 LOGFONT logfont;
ee78dc32 5854 XFontStruct *size_ref;
23afac8f 5855 Lisp_Object pattern;
d84b082d 5856 Lisp_Object list;
ee78dc32
GV
5857} enumfont_t;
5858
d84b082d
JR
5859
5860static void
5861enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
5862
5863
7d0393cf 5864static int CALLBACK
ee78dc32
GV
5865enum_font_cb2 (lplf, lptm, FontType, lpef)
5866 ENUMLOGFONT * lplf;
5867 NEWTEXTMETRIC * lptm;
5868 int FontType;
5869 enumfont_t * lpef;
5870{
66895301
JR
5871 /* Ignore struck out and underlined versions of fonts. */
5872 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
5873 return 1;
5874
5875 /* Only return fonts with names starting with @ if they were
5876 explicitly specified, since Microsoft uses an initial @ to
5877 denote fonts for vertical writing, without providing a more
5878 convenient way of identifying them. */
5879 if (lplf->elfLogFont.lfFaceName[0] == '@'
5880 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
5881 return 1;
5882
4587b026
GV
5883 /* Check that the character set matches if it was specified */
5884 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
5885 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 5886 return 1;
4587b026 5887
6358474d
JR
5888 if (FontType == RASTER_FONTTYPE)
5889 {
5890 /* DBCS raster fonts have problems displaying, so skip them. */
5891 int charset = lplf->elfLogFont.lfCharSet;
5892 if (charset == SHIFTJIS_CHARSET
5893 || charset == HANGEUL_CHARSET
5894 || charset == CHINESEBIG5_CHARSET
5895 || charset == GB2312_CHARSET
5896#ifdef JOHAB_CHARSET
5897 || charset == JOHAB_CHARSET
5898#endif
5899 )
5900 return 1;
5901 }
5902
ee78dc32
GV
5903 {
5904 char buf[100];
4587b026 5905 Lisp_Object width = Qnil;
d84b082d 5906 Lisp_Object charset_list = Qnil;
767b1ff0 5907 char *charset = NULL;
ee78dc32 5908
6fc2811b
JR
5909 /* Truetype fonts do not report their true metrics until loaded */
5910 if (FontType != RASTER_FONTTYPE)
3cb20f4a 5911 {
23afac8f 5912 if (!NILP (lpef->pattern))
6fc2811b
JR
5913 {
5914 /* Scalable fonts are as big as you want them to be. */
5915 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
5916 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
5917 width = make_number (lpef->logfont.lfWidth);
5918 }
5919 else
5920 {
5921 lplf->elfLogFont.lfHeight = 0;
5922 lplf->elfLogFont.lfWidth = 0;
5923 }
3cb20f4a 5924 }
6fc2811b 5925
f46e6225
GV
5926 /* Make sure the height used here is the same as everywhere
5927 else (ie character height, not cell height). */
6fc2811b
JR
5928 if (lplf->elfLogFont.lfHeight > 0)
5929 {
5930 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
5931 if (FontType == RASTER_FONTTYPE)
5932 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
5933 else
5934 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
5935 }
4587b026 5936
23afac8f 5937 if (!NILP (lpef->pattern))
767b1ff0 5938 {
d5db4077 5939 charset = xlfd_charset_of_font (SDATA (lpef->pattern));
767b1ff0 5940
644cefdf
JR
5941 /* We already checked charsets above, but DEFAULT_CHARSET
5942 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
5943 if (charset
5944 && strncmp (charset, "*-*", 3) != 0
5945 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
5946 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
5947 return 1;
767b1ff0
JR
5948 }
5949
d84b082d
JR
5950 if (charset)
5951 charset_list = Fcons (build_string (charset), Qnil);
5952 else
5953 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 5954
d84b082d
JR
5955 /* Loop through the charsets. */
5956 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 5957 {
d84b082d 5958 Lisp_Object this_charset = Fcar (charset_list);
d5db4077 5959 charset = SDATA (this_charset);
d84b082d
JR
5960
5961 /* List bold and italic variations if w32-enable-synthesized-fonts
5962 is non-nil and this is a plain font. */
5963 if (w32_enable_synthesized_fonts
5964 && lplf->elfLogFont.lfWeight == FW_NORMAL
5965 && lplf->elfLogFont.lfItalic == FALSE)
5966 {
5967 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
5968 charset, width);
5969 /* bold. */
5970 lplf->elfLogFont.lfWeight = FW_BOLD;
5971 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
5972 charset, width);
5973 /* bold italic. */
5974 lplf->elfLogFont.lfItalic = TRUE;
5975 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
5976 charset, width);
5977 /* italic. */
5978 lplf->elfLogFont.lfWeight = FW_NORMAL;
5979 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
5980 charset, width);
5981 }
5982 else
5983 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
5984 charset, width);
ee78dc32
GV
5985 }
5986 }
6fc2811b 5987
5e905a57 5988 return 1;
ee78dc32
GV
5989}
5990
d84b082d
JR
5991static void
5992enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
5993 enumfont_t * lpef;
5994 LOGFONT * logfont;
5995 char * match_charset;
5996 Lisp_Object width;
5997{
5998 char buf[100];
5999
6000 if (!w32_to_x_font (logfont, buf, 100, match_charset))
6001 return;
6002
23afac8f 6003 if (NILP (lpef->pattern)
d5db4077 6004 || w32_font_match (buf, SDATA (lpef->pattern)))
d84b082d
JR
6005 {
6006 /* Check if we already listed this font. This may happen if
6007 w32_enable_synthesized_fonts is non-nil, and there are real
6008 bold and italic versions of the font. */
6009 Lisp_Object font_name = build_string (buf);
6010 if (NILP (Fmember (font_name, lpef->list)))
6011 {
23afac8f
JR
6012 Lisp_Object entry = Fcons (font_name, width);
6013 lpef->list = Fcons (entry, lpef->list);
d84b082d
JR
6014 lpef->numFonts++;
6015 }
6016 }
6017}
6018
6019
7d0393cf 6020static int CALLBACK
ee78dc32
GV
6021enum_font_cb1 (lplf, lptm, FontType, lpef)
6022 ENUMLOGFONT * lplf;
6023 NEWTEXTMETRIC * lptm;
6024 int FontType;
6025 enumfont_t * lpef;
6026{
6027 return EnumFontFamilies (lpef->hdc,
6028 lplf->elfLogFont.lfFaceName,
6029 (FONTENUMPROC) enum_font_cb2,
6030 (LPARAM) lpef);
6031}
6032
6033
8edb0a6f 6034static int CALLBACK
5ca0cd71
GV
6035enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6036 ENUMLOGFONTEX * lplf;
6037 NEWTEXTMETRICEX * lptm;
6038 int font_type;
6039 enumfont_t * lpef;
6040{
6041 /* We are not interested in the extra info we get back from the 'Ex
6042 version - only the fact that we get character set variations
6043 enumerated seperately. */
6044 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6045 font_type, lpef);
6046}
6047
8edb0a6f 6048static int CALLBACK
5ca0cd71
GV
6049enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6050 ENUMLOGFONTEX * lplf;
6051 NEWTEXTMETRICEX * lptm;
6052 int font_type;
6053 enumfont_t * lpef;
6054{
6055 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6056 FARPROC enum_font_families_ex
6057 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6058 /* We don't really expect EnumFontFamiliesEx to disappear once we
6059 get here, so don't bother handling it gracefully. */
6060 if (enum_font_families_ex == NULL)
6061 error ("gdi32.dll has disappeared!");
6062 return enum_font_families_ex (lpef->hdc,
6063 &lplf->elfLogFont,
6064 (FONTENUMPROC) enum_fontex_cb2,
6065 (LPARAM) lpef, 0);
6066}
6067
4587b026
GV
6068/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6069 and xterm.c in Emacs 20.3) */
6070
8edb0a6f 6071static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6072{
6073 char *fontname, *ptnstr;
6074 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6075 int n_fonts = 0;
33d52f9c
GV
6076
6077 list = Vw32_bdf_filename_alist;
d5db4077 6078 ptnstr = SDATA (pattern);
33d52f9c 6079
8e713be6 6080 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6081 {
8e713be6 6082 tem = XCAR (list);
33d52f9c 6083 if (CONSP (tem))
d5db4077 6084 fontname = SDATA (XCAR (tem));
33d52f9c 6085 else if (STRINGP (tem))
d5db4077 6086 fontname = SDATA (tem);
33d52f9c
GV
6087 else
6088 continue;
6089
6090 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6091 {
8e713be6 6092 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71 6093 n_fonts++;
bd11cc09 6094 if (max_names >= 0 && n_fonts >= max_names)
5ca0cd71
GV
6095 break;
6096 }
33d52f9c
GV
6097 }
6098
6099 return newlist;
6100}
6101
5ca0cd71 6102
4587b026
GV
6103/* Return a list of names of available fonts matching PATTERN on frame
6104 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6105 to be listed. Frame F NULL means we have not yet created any
6106 frame, which means we can't get proper size info, as we don't have
6107 a device context to use for GetTextMetrics.
bd11cc09
JR
6108 MAXNAMES sets a limit on how many fonts to match. If MAXNAMES is
6109 negative, then all matching fonts are returned. */
4587b026
GV
6110
6111Lisp_Object
dc220243
JR
6112w32_list_fonts (f, pattern, size, maxnames)
6113 struct frame *f;
6114 Lisp_Object pattern;
6115 int size;
6116 int maxnames;
4587b026 6117{
6fc2811b 6118 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6119 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6120 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6121 int n_fonts = 0;
396594fe 6122
4587b026
GV
6123 patterns = Fassoc (pattern, Valternate_fontname_alist);
6124 if (NILP (patterns))
6125 patterns = Fcons (pattern, Qnil);
6126
8e713be6 6127 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6128 {
6129 enumfont_t ef;
767b1ff0 6130 int codepage;
4587b026 6131
8e713be6 6132 tpat = XCAR (patterns);
4587b026 6133
767b1ff0
JR
6134 if (!STRINGP (tpat))
6135 continue;
6136
6137 /* Avoid expensive EnumFontFamilies functions if we are not
6138 going to be able to output one of these anyway. */
d5db4077 6139 codepage = w32_codepage_for_font (SDATA (tpat));
767b1ff0 6140 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
6141 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6142 && !IsValidCodePage(codepage))
767b1ff0
JR
6143 continue;
6144
4587b026
GV
6145 /* See if we cached the result for this particular query.
6146 The cache is an alist of the form:
6147 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6148 */
8e713be6 6149 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 6150 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
6151 {
6152 list = Fcdr_safe (list);
6153 /* We have a cached list. Don't have to get the list again. */
6154 goto label_cached;
6155 }
6156
6157 BLOCK_INPUT;
6158 /* At first, put PATTERN in the cache. */
23afac8f
JR
6159 ef.pattern = tpat;
6160 ef.list = Qnil;
4587b026 6161 ef.numFonts = 0;
33d52f9c 6162
5ca0cd71
GV
6163 /* Use EnumFontFamiliesEx where it is available, as it knows
6164 about character sets. Fall back to EnumFontFamilies for
6165 older versions of NT that don't support the 'Ex function. */
d5db4077 6166 x_to_w32_font (SDATA (tpat), &ef.logfont);
4587b026 6167 {
5ca0cd71
GV
6168 LOGFONT font_match_pattern;
6169 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6170 FARPROC enum_font_families_ex
6171 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6172
6173 /* We do our own pattern matching so we can handle wildcards. */
6174 font_match_pattern.lfFaceName[0] = 0;
6175 font_match_pattern.lfPitchAndFamily = 0;
6176 /* We can use the charset, because if it is a wildcard it will
6177 be DEFAULT_CHARSET anyway. */
6178 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6179
33d52f9c 6180 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 6181
5ca0cd71
GV
6182 if (enum_font_families_ex)
6183 enum_font_families_ex (ef.hdc,
6184 &font_match_pattern,
6185 (FONTENUMPROC) enum_fontex_cb1,
6186 (LPARAM) &ef, 0);
6187 else
6188 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6189 (LPARAM)&ef);
4587b026 6190
33d52f9c 6191 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
6192 }
6193
6194 UNBLOCK_INPUT;
23afac8f 6195 list = ef.list;
4587b026
GV
6196
6197 /* Make a list of the fonts we got back.
6198 Store that in the font cache for the display. */
f3fbd155
KR
6199 XSETCDR (dpyinfo->name_list_element,
6200 Fcons (Fcons (tpat, list),
6201 XCDR (dpyinfo->name_list_element)));
4587b026
GV
6202
6203 label_cached:
6204 if (NILP (list)) continue; /* Try the remaining alternatives. */
6205
6206 newlist = second_best = Qnil;
6207
7d0393cf 6208 /* Make a list of the fonts that have the right width. */
8e713be6 6209 for (; CONSP (list); list = XCDR (list))
4587b026
GV
6210 {
6211 int found_size;
8e713be6 6212 tem = XCAR (list);
4587b026
GV
6213
6214 if (!CONSP (tem))
6215 continue;
8e713be6 6216 if (NILP (XCAR (tem)))
4587b026
GV
6217 continue;
6218 if (!size)
6219 {
8e713be6 6220 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71 6221 n_fonts++;
bd11cc09 6222 if (maxnames >= 0 && n_fonts >= maxnames)
5ca0cd71
GV
6223 break;
6224 else
6225 continue;
4587b026 6226 }
8e713be6 6227 if (!INTEGERP (XCDR (tem)))
4587b026
GV
6228 {
6229 /* Since we don't yet know the size of the font, we must
6230 load it and try GetTextMetrics. */
4587b026
GV
6231 W32FontStruct thisinfo;
6232 LOGFONT lf;
6233 HDC hdc;
6234 HANDLE oldobj;
6235
d5db4077 6236 if (!x_to_w32_font (SDATA (XCAR (tem)), &lf))
4587b026
GV
6237 continue;
6238
6239 BLOCK_INPUT;
33d52f9c 6240 thisinfo.bdf = NULL;
4587b026
GV
6241 thisinfo.hfont = CreateFontIndirect (&lf);
6242 if (thisinfo.hfont == NULL)
6243 continue;
6244
6245 hdc = GetDC (dpyinfo->root_window);
6246 oldobj = SelectObject (hdc, thisinfo.hfont);
6247 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 6248 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 6249 else
f3fbd155 6250 XSETCDR (tem, make_number (0));
4587b026
GV
6251 SelectObject (hdc, oldobj);
6252 ReleaseDC (dpyinfo->root_window, hdc);
6253 DeleteObject(thisinfo.hfont);
6254 UNBLOCK_INPUT;
6255 }
8e713be6 6256 found_size = XINT (XCDR (tem));
4587b026 6257 if (found_size == size)
5ca0cd71 6258 {
8e713be6 6259 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71 6260 n_fonts++;
bd11cc09 6261 if (maxnames >= 0 && n_fonts >= maxnames)
5ca0cd71
GV
6262 break;
6263 }
4587b026
GV
6264 /* keep track of the closest matching size in case
6265 no exact match is found. */
6266 else if (found_size > 0)
6267 {
6268 if (NILP (second_best))
6269 second_best = tem;
7d0393cf 6270
4587b026
GV
6271 else if (found_size < size)
6272 {
8e713be6
KR
6273 if (XINT (XCDR (second_best)) > size
6274 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
6275 second_best = tem;
6276 }
6277 else
6278 {
8e713be6
KR
6279 if (XINT (XCDR (second_best)) > size
6280 && XINT (XCDR (second_best)) >
4587b026
GV
6281 found_size)
6282 second_best = tem;
6283 }
6284 }
6285 }
6286
6287 if (!NILP (newlist))
6288 break;
6289 else if (!NILP (second_best))
6290 {
8e713be6 6291 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
6292 break;
6293 }
6294 }
6295
33d52f9c 6296 /* Include any bdf fonts. */
bd11cc09 6297 if (n_fonts < maxnames || maxnames < 0)
33d52f9c
GV
6298 {
6299 Lisp_Object combined[2];
5ca0cd71 6300 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
6301 combined[1] = newlist;
6302 newlist = Fnconc(2, combined);
6303 }
6304
4587b026
GV
6305 return newlist;
6306}
6307
5ca0cd71 6308
4587b026
GV
6309/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6310struct font_info *
6311w32_get_font_info (f, font_idx)
6312 FRAME_PTR f;
6313 int font_idx;
6314{
6315 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6316}
6317
6318
6319struct font_info*
6320w32_query_font (struct frame *f, char *fontname)
6321{
6322 int i;
6323 struct font_info *pfi;
6324
6325 pfi = FRAME_W32_FONT_TABLE (f);
6326
6327 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6328 {
6329 if (strcmp(pfi->name, fontname) == 0) return pfi;
6330 }
6331
6332 return NULL;
6333}
6334
6335/* Find a CCL program for a font specified by FONTP, and set the member
6336 `encoder' of the structure. */
6337
6338void
6339w32_find_ccl_program (fontp)
6340 struct font_info *fontp;
6341{
3545439c 6342 Lisp_Object list, elt;
4587b026 6343
8e713be6 6344 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 6345 {
8e713be6 6346 elt = XCAR (list);
4587b026 6347 if (CONSP (elt)
8e713be6
KR
6348 && STRINGP (XCAR (elt))
6349 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 6350 >= 0))
3545439c
KH
6351 break;
6352 }
6353 if (! NILP (list))
6354 {
17eedd00
KH
6355 struct ccl_program *ccl
6356 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 6357
8e713be6 6358 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
6359 xfree (ccl);
6360 else
6361 fontp->font_encoder = ccl;
4587b026
GV
6362 }
6363}
6364
6365\f
8edb0a6f
JR
6366/* Find BDF files in a specified directory. (use GCPRO when calling,
6367 as this calls lisp to get a directory listing). */
6368static Lisp_Object
6369w32_find_bdf_fonts_in_dir (Lisp_Object directory)
6370{
6371 Lisp_Object filelist, list = Qnil;
6372 char fontname[100];
6373
6374 if (!STRINGP(directory))
6375 return Qnil;
6376
6377 filelist = Fdirectory_files (directory, Qt,
6378 build_string (".*\\.[bB][dD][fF]"), Qt);
6379
6380 for ( ; CONSP(filelist); filelist = XCDR (filelist))
6381 {
6382 Lisp_Object filename = XCAR (filelist);
d5db4077 6383 if (w32_BDF_to_x_font (SDATA (filename), fontname, 100))
8edb0a6f
JR
6384 store_in_alist (&list, build_string (fontname), filename);
6385 }
6386 return list;
6387}
6388
6fc2811b
JR
6389DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6390 1, 1, 0,
b3700ae7
JR
6391 doc: /* Return a list of BDF fonts in DIR.
6392The list is suitable for appending to w32-bdf-filename-alist. Fonts
6393which do not contain an xlfd description will not be included in the
6394list. DIR may be a list of directories. */)
6fc2811b
JR
6395 (directory)
6396 Lisp_Object directory;
6397{
6398 Lisp_Object list = Qnil;
6399 struct gcpro gcpro1, gcpro2;
ee78dc32 6400
6fc2811b
JR
6401 if (!CONSP (directory))
6402 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 6403
6fc2811b 6404 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 6405 {
6fc2811b
JR
6406 Lisp_Object pair[2];
6407 pair[0] = list;
6408 pair[1] = Qnil;
6409 GCPRO2 (directory, list);
6410 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
6411 list = Fnconc( 2, pair );
6412 UNGCPRO;
6413 }
6414 return list;
6415}
ee78dc32 6416
6fc2811b
JR
6417\f
6418DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 6419 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
6420 (color, frame)
6421 Lisp_Object color, frame;
6422{
6423 XColor foo;
6424 FRAME_PTR f = check_x_frame (frame);
ee78dc32 6425
b7826503 6426 CHECK_STRING (color);
ee78dc32 6427
d5db4077 6428 if (w32_defined_color (f, SDATA (color), &foo, 0))
6fc2811b
JR
6429 return Qt;
6430 else
6431 return Qnil;
6432}
ee78dc32 6433
2d764c78 6434DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 6435 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
6436 (color, frame)
6437 Lisp_Object color, frame;
6438{
6fc2811b 6439 XColor foo;
ee78dc32
GV
6440 FRAME_PTR f = check_x_frame (frame);
6441
b7826503 6442 CHECK_STRING (color);
ee78dc32 6443
d5db4077 6444 if (w32_defined_color (f, SDATA (color), &foo, 0))
ee78dc32
GV
6445 {
6446 Lisp_Object rgb[3];
6447
6fc2811b
JR
6448 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
6449 | GetRValue (foo.pixel));
6450 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
6451 | GetGValue (foo.pixel));
6452 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
6453 | GetBValue (foo.pixel));
ee78dc32
GV
6454 return Flist (3, rgb);
6455 }
6456 else
6457 return Qnil;
6458}
6459
2d764c78 6460DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 6461 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
6462 (display)
6463 Lisp_Object display;
6464{
fbd6baed 6465 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6466
6467 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6468 return Qnil;
6469
6470 return Qt;
6471}
6472
74e1aeec
JR
6473DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
6474 Sx_display_grayscale_p, 0, 1, 0,
6475 doc: /* Return t if the X display supports shades of gray.
6476Note that color displays do support shades of gray.
6477The optional argument DISPLAY specifies which display to ask about.
6478DISPLAY should be either a frame or a display name (a string).
6479If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6480 (display)
6481 Lisp_Object display;
6482{
fbd6baed 6483 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6484
6485 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6486 return Qnil;
6487
6488 return Qt;
6489}
6490
74e1aeec
JR
6491DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
6492 Sx_display_pixel_width, 0, 1, 0,
6493 doc: /* Returns the width in pixels of DISPLAY.
6494The optional argument DISPLAY specifies which display to ask about.
6495DISPLAY should be either a frame or a display name (a string).
6496If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6497 (display)
6498 Lisp_Object display;
6499{
fbd6baed 6500 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6501
6502 return make_number (dpyinfo->width);
6503}
6504
6505DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
6506 Sx_display_pixel_height, 0, 1, 0,
6507 doc: /* Returns the height in pixels of DISPLAY.
6508The optional argument DISPLAY specifies which display to ask about.
6509DISPLAY should be either a frame or a display name (a string).
6510If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6511 (display)
6512 Lisp_Object display;
6513{
fbd6baed 6514 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6515
6516 return make_number (dpyinfo->height);
6517}
6518
6519DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
6520 0, 1, 0,
6521 doc: /* Returns the number of bitplanes of DISPLAY.
6522The optional argument DISPLAY specifies which display to ask about.
6523DISPLAY should be either a frame or a display name (a string).
6524If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6525 (display)
6526 Lisp_Object display;
6527{
fbd6baed 6528 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6529
6530 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6531}
6532
6533DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
6534 0, 1, 0,
6535 doc: /* Returns the number of color cells of DISPLAY.
6536The optional argument DISPLAY specifies which display to ask about.
6537DISPLAY should be either a frame or a display name (a string).
6538If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6539 (display)
6540 Lisp_Object display;
6541{
fbd6baed 6542 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6543 HDC hdc;
6544 int cap;
6545
5ac45f98
GV
6546 hdc = GetDC (dpyinfo->root_window);
6547 if (dpyinfo->has_palette)
6548 cap = GetDeviceCaps (hdc,SIZEPALETTE);
6549 else
6550 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b 6551
007776bc
JB
6552 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
6553 and because probably is more meaningful on Windows anyway */
abf8c61b 6554 if (cap < 0)
007776bc 6555 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
7d0393cf 6556
ee78dc32 6557 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 6558
ee78dc32
GV
6559 return make_number (cap);
6560}
6561
6562DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6563 Sx_server_max_request_size,
74e1aeec
JR
6564 0, 1, 0,
6565 doc: /* Returns the maximum request size of the server of DISPLAY.
6566The optional argument DISPLAY specifies which display to ask about.
6567DISPLAY should be either a frame or a display name (a string).
6568If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6569 (display)
6570 Lisp_Object display;
6571{
fbd6baed 6572 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6573
6574 return make_number (1);
6575}
6576
6577DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
6578 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
6579The optional argument DISPLAY specifies which display to ask about.
6580DISPLAY should be either a frame or a display name (a string).
6581If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6582 (display)
6583 Lisp_Object display;
6584{
dfff8a69 6585 return build_string ("Microsoft Corp.");
ee78dc32
GV
6586}
6587
6588DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
6589 doc: /* Returns the version numbers of the server of DISPLAY.
6590The value is a list of three integers: the major and minor
6591version numbers, and the vendor-specific release
6592number. See also the function `x-server-vendor'.
6593
6594The optional argument DISPLAY specifies which display to ask about.
6595DISPLAY should be either a frame or a display name (a string).
6596If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6597 (display)
6598 Lisp_Object display;
6599{
fbd6baed 6600 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
6601 Fcons (make_number (w32_minor_version),
6602 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
6603}
6604
6605DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
6606 doc: /* Returns the number of screens on the server of DISPLAY.
6607The optional argument DISPLAY specifies which display to ask about.
6608DISPLAY should be either a frame or a display name (a string).
6609If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6610 (display)
6611 Lisp_Object display;
6612{
ee78dc32
GV
6613 return make_number (1);
6614}
6615
74e1aeec
JR
6616DEFUN ("x-display-mm-height", Fx_display_mm_height,
6617 Sx_display_mm_height, 0, 1, 0,
6618 doc: /* Returns the height in millimeters of DISPLAY.
6619The optional argument DISPLAY specifies which display to ask about.
6620DISPLAY should be either a frame or a display name (a string).
6621If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6622 (display)
6623 Lisp_Object display;
6624{
fbd6baed 6625 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6626 HDC hdc;
6627 int cap;
6628
5ac45f98 6629 hdc = GetDC (dpyinfo->root_window);
7d0393cf 6630
ee78dc32 6631 cap = GetDeviceCaps (hdc, VERTSIZE);
7d0393cf 6632
ee78dc32 6633 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 6634
ee78dc32
GV
6635 return make_number (cap);
6636}
6637
6638DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
6639 doc: /* Returns the width in millimeters of DISPLAY.
6640The optional argument DISPLAY specifies which display to ask about.
6641DISPLAY should be either a frame or a display name (a string).
6642If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6643 (display)
6644 Lisp_Object display;
6645{
fbd6baed 6646 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6647
6648 HDC hdc;
6649 int cap;
6650
5ac45f98 6651 hdc = GetDC (dpyinfo->root_window);
7d0393cf 6652
ee78dc32 6653 cap = GetDeviceCaps (hdc, HORZSIZE);
7d0393cf 6654
ee78dc32 6655 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 6656
ee78dc32
GV
6657 return make_number (cap);
6658}
6659
6660DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
6661 Sx_display_backing_store, 0, 1, 0,
6662 doc: /* Returns an indication of whether DISPLAY does backing store.
6663The value may be `always', `when-mapped', or `not-useful'.
6664The optional argument DISPLAY specifies which display to ask about.
6665DISPLAY should be either a frame or a display name (a string).
6666If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6667 (display)
6668 Lisp_Object display;
6669{
6670 return intern ("not-useful");
6671}
6672
6673DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
6674 Sx_display_visual_class, 0, 1, 0,
6675 doc: /* Returns the visual class of DISPLAY.
6676The value is one of the symbols `static-gray', `gray-scale',
6677`static-color', `pseudo-color', `true-color', or `direct-color'.
6678
6679The optional argument DISPLAY specifies which display to ask about.
6680DISPLAY should be either a frame or a display name (a string).
6681If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6682 (display)
6683 Lisp_Object display;
6684{
fbd6baed 6685 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 6686 Lisp_Object result = Qnil;
ee78dc32 6687
abf8c61b
AI
6688 if (dpyinfo->has_palette)
6689 result = intern ("pseudo-color");
6690 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
6691 result = intern ("static-grey");
6692 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
6693 result = intern ("static-color");
6694 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
6695 result = intern ("true-color");
ee78dc32 6696
abf8c61b 6697 return result;
ee78dc32
GV
6698}
6699
6700DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
6701 Sx_display_save_under, 0, 1, 0,
6702 doc: /* Returns t if DISPLAY supports the save-under feature.
6703The optional argument DISPLAY specifies which display to ask about.
6704DISPLAY should be either a frame or a display name (a string).
6705If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
6706 (display)
6707 Lisp_Object display;
6708{
6fc2811b
JR
6709 return Qnil;
6710}
6711\f
6712int
6713x_pixel_width (f)
6714 register struct frame *f;
6715{
be786000 6716 return FRAME_PIXEL_WIDTH (f);
6fc2811b
JR
6717}
6718
6719int
6720x_pixel_height (f)
6721 register struct frame *f;
6722{
be786000 6723 return FRAME_PIXEL_HEIGHT (f);
6fc2811b
JR
6724}
6725
6726int
6727x_char_width (f)
6728 register struct frame *f;
6729{
be786000 6730 return FRAME_COLUMN_WIDTH (f);
6fc2811b
JR
6731}
6732
6733int
6734x_char_height (f)
6735 register struct frame *f;
6736{
be786000 6737 return FRAME_LINE_HEIGHT (f);
6fc2811b
JR
6738}
6739
6740int
6741x_screen_planes (f)
6742 register struct frame *f;
6743{
6744 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
6745}
6746\f
6747/* Return the display structure for the display named NAME.
6748 Open a new connection if necessary. */
6749
6750struct w32_display_info *
6751x_display_info_for_name (name)
6752 Lisp_Object name;
6753{
6754 Lisp_Object names;
6755 struct w32_display_info *dpyinfo;
6756
b7826503 6757 CHECK_STRING (name);
6fc2811b
JR
6758
6759 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
6760 dpyinfo;
6761 dpyinfo = dpyinfo->next, names = XCDR (names))
6762 {
6763 Lisp_Object tem;
6764 tem = Fstring_equal (XCAR (XCAR (names)), name);
6765 if (!NILP (tem))
6766 return dpyinfo;
6767 }
6768
6769 /* Use this general default value to start with. */
6770 Vx_resource_name = Vinvocation_name;
6771
6772 validate_x_resource_name ();
6773
6774 dpyinfo = w32_term_init (name, (unsigned char *)0,
d5db4077 6775 (char *) SDATA (Vx_resource_name));
6fc2811b
JR
6776
6777 if (dpyinfo == 0)
d5db4077 6778 error ("Cannot connect to server %s", SDATA (name));
6fc2811b
JR
6779
6780 w32_in_use = 1;
6781 XSETFASTINT (Vwindow_system_version, 3);
6782
6783 return dpyinfo;
6784}
6785
6786DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
6787 1, 3, 0, doc: /* Open a connection to a server.
6788DISPLAY is the name of the display to connect to.
6789Optional second arg XRM-STRING is a string of resources in xrdb format.
6790If the optional third arg MUST-SUCCEED is non-nil,
6791terminate Emacs if we can't open the connection. */)
6fc2811b
JR
6792 (display, xrm_string, must_succeed)
6793 Lisp_Object display, xrm_string, must_succeed;
6794{
6795 unsigned char *xrm_option;
6796 struct w32_display_info *dpyinfo;
6797
74e1aeec
JR
6798 /* If initialization has already been done, return now to avoid
6799 overwriting critical parts of one_w32_display_info. */
6800 if (w32_in_use)
6801 return Qnil;
6802
b7826503 6803 CHECK_STRING (display);
6fc2811b 6804 if (! NILP (xrm_string))
b7826503 6805 CHECK_STRING (xrm_string);
6fc2811b
JR
6806
6807 if (! EQ (Vwindow_system, intern ("w32")))
6808 error ("Not using Microsoft Windows");
6809
6810 /* Allow color mapping to be defined externally; first look in user's
6811 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
6812 {
6813 Lisp_Object color_file;
6814 struct gcpro gcpro1;
6815
6816 color_file = build_string("~/rgb.txt");
6817
6818 GCPRO1 (color_file);
6819
6820 if (NILP (Ffile_readable_p (color_file)))
6821 color_file =
6822 Fexpand_file_name (build_string ("rgb.txt"),
6823 Fsymbol_value (intern ("data-directory")));
6824
6825 Vw32_color_map = Fw32_load_color_file (color_file);
6826
6827 UNGCPRO;
6828 }
6829 if (NILP (Vw32_color_map))
6830 Vw32_color_map = Fw32_default_color_map ();
6831
5a8a15ec
JR
6832 /* Merge in system logical colors. */
6833 add_system_logical_colors_to_map (&Vw32_color_map);
6834
6fc2811b 6835 if (! NILP (xrm_string))
d5db4077 6836 xrm_option = (unsigned char *) SDATA (xrm_string);
6fc2811b
JR
6837 else
6838 xrm_option = (unsigned char *) 0;
6839
6840 /* Use this general default value to start with. */
6841 /* First remove .exe suffix from invocation-name - it looks ugly. */
6842 {
6843 char basename[ MAX_PATH ], *str;
6844
d5db4077 6845 strcpy (basename, SDATA (Vinvocation_name));
6fc2811b
JR
6846 str = strrchr (basename, '.');
6847 if (str) *str = 0;
6848 Vinvocation_name = build_string (basename);
6849 }
6850 Vx_resource_name = Vinvocation_name;
6851
6852 validate_x_resource_name ();
6853
6854 /* This is what opens the connection and sets x_current_display.
6855 This also initializes many symbols, such as those used for input. */
6856 dpyinfo = w32_term_init (display, xrm_option,
d5db4077 6857 (char *) SDATA (Vx_resource_name));
6fc2811b
JR
6858
6859 if (dpyinfo == 0)
6860 {
6861 if (!NILP (must_succeed))
6862 fatal ("Cannot connect to server %s.\n",
d5db4077 6863 SDATA (display));
6fc2811b 6864 else
d5db4077 6865 error ("Cannot connect to server %s", SDATA (display));
6fc2811b
JR
6866 }
6867
6868 w32_in_use = 1;
6869
6870 XSETFASTINT (Vwindow_system_version, 3);
6871 return Qnil;
6872}
6873
6874DEFUN ("x-close-connection", Fx_close_connection,
6875 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
6876 doc: /* Close the connection to DISPLAY's server.
6877For DISPLAY, specify either a frame or a display name (a string).
6878If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
6879 (display)
6880 Lisp_Object display;
6881{
6882 struct w32_display_info *dpyinfo = check_x_display_info (display);
6883 int i;
6884
6885 if (dpyinfo->reference_count > 0)
6886 error ("Display still has frames on it");
6887
6888 BLOCK_INPUT;
6889 /* Free the fonts in the font table. */
6890 for (i = 0; i < dpyinfo->n_fonts; i++)
6891 if (dpyinfo->font_table[i].name)
6892 {
126f2e35
JR
6893 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
6894 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 6895 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
6896 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
6897 }
6898 x_destroy_all_bitmaps (dpyinfo);
6899
6900 x_delete_display (dpyinfo);
6901 UNBLOCK_INPUT;
6902
6903 return Qnil;
6904}
6905
6906DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 6907 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
6908 ()
6909{
6910 Lisp_Object tail, result;
6911
6912 result = Qnil;
6913 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
6914 result = Fcons (XCAR (XCAR (tail)), result);
6915
6916 return result;
6917}
6918
6919DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
6920 doc: /* This is a noop on W32 systems. */)
6921 (on, display)
6922 Lisp_Object display, on;
6fc2811b 6923{
6fc2811b
JR
6924 return Qnil;
6925}
6926
6927\f
6fc2811b
JR
6928/***********************************************************************
6929 Image types
6930 ***********************************************************************/
6931
6932/* Value is the number of elements of vector VECTOR. */
6933
6934#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
6935
6936/* List of supported image types. Use define_image_type to add new
6937 types. Use lookup_image_type to find a type for a given symbol. */
6938
6939static struct image_type *image_types;
6940
6fc2811b
JR
6941/* The symbol `xbm' which is used as the type symbol for XBM images. */
6942
6943Lisp_Object Qxbm;
6944
6945/* Keywords. */
6946
6fc2811b 6947extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
6948extern Lisp_Object QCdata, QCtype;
6949Lisp_Object QCascent, QCmargin, QCrelief;
a93f4566 6950Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 6951Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
6952
6953/* Other symbols. */
6954
3cf3436e 6955Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
6956
6957/* Time in seconds after which images should be removed from the cache
6958 if not displayed. */
6959
6960Lisp_Object Vimage_cache_eviction_delay;
6961
6962/* Function prototypes. */
6963
6964static void define_image_type P_ ((struct image_type *type));
6965static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
6966static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
6967static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 6968static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
6969static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
6970 Lisp_Object));
6971
dfff8a69 6972
6fc2811b
JR
6973/* Define a new image type from TYPE. This adds a copy of TYPE to
6974 image_types and adds the symbol *TYPE->type to Vimage_types. */
6975
6976static void
6977define_image_type (type)
6978 struct image_type *type;
6979{
6980 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
6981 The initialized data segment is read-only. */
6982 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
6983 bcopy (type, p, sizeof *p);
6984 p->next = image_types;
6985 image_types = p;
6986 Vimage_types = Fcons (*p->type, Vimage_types);
6987}
6988
6989
6990/* Look up image type SYMBOL, and return a pointer to its image_type
6991 structure. Value is null if SYMBOL is not a known image type. */
6992
6993static INLINE struct image_type *
6994lookup_image_type (symbol)
6995 Lisp_Object symbol;
6996{
6997 struct image_type *type;
6998
6999 for (type = image_types; type; type = type->next)
7000 if (EQ (symbol, *type->type))
7001 break;
7002
7003 return type;
7004}
7005
7006
7007/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7008 valid image specification is a list whose car is the symbol
7009 `image', and whose rest is a property list. The property list must
7010 contain a value for key `:type'. That value must be the name of a
7011 supported image type. The rest of the property list depends on the
7012 image type. */
7013
7014int
7015valid_image_p (object)
7016 Lisp_Object object;
7017{
7018 int valid_p = 0;
7d0393cf 7019
82cf95a7 7020 if (IMAGEP (object))
6fc2811b 7021 {
3cf3436e
JR
7022 Lisp_Object tem;
7023
7024 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
7025 if (EQ (XCAR (tem), QCtype))
7026 {
7027 tem = XCDR (tem);
7028 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
7029 {
7030 struct image_type *type;
7031 type = lookup_image_type (XCAR (tem));
7032 if (type)
7033 valid_p = type->valid_p (object);
7034 }
7035
7036 break;
7037 }
6fc2811b
JR
7038 }
7039
7040 return valid_p;
7041}
7042
7043
7044/* Log error message with format string FORMAT and argument ARG.
7045 Signaling an error, e.g. when an image cannot be loaded, is not a
7046 good idea because this would interrupt redisplay, and the error
7047 message display would lead to another redisplay. This function
7048 therefore simply displays a message. */
7049
7050static void
7051image_error (format, arg1, arg2)
7052 char *format;
7053 Lisp_Object arg1, arg2;
7054{
7055 add_to_log (format, arg1, arg2);
7056}
7057
7058
7059\f
7060/***********************************************************************
7061 Image specifications
7062 ***********************************************************************/
7063
7064enum image_value_type
7065{
7066 IMAGE_DONT_CHECK_VALUE_TYPE,
7067 IMAGE_STRING_VALUE,
3cf3436e 7068 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
7069 IMAGE_SYMBOL_VALUE,
7070 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 7071 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 7072 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 7073 IMAGE_ASCENT_VALUE,
6fc2811b
JR
7074 IMAGE_INTEGER_VALUE,
7075 IMAGE_FUNCTION_VALUE,
7076 IMAGE_NUMBER_VALUE,
7077 IMAGE_BOOL_VALUE
7078};
7079
7080/* Structure used when parsing image specifications. */
7081
7082struct image_keyword
7083{
7084 /* Name of keyword. */
7085 char *name;
7086
7087 /* The type of value allowed. */
7088 enum image_value_type type;
7089
7090 /* Non-zero means key must be present. */
7091 int mandatory_p;
7092
7093 /* Used to recognize duplicate keywords in a property list. */
7094 int count;
7095
7096 /* The value that was found. */
7097 Lisp_Object value;
7098};
7099
7100
7101static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7102 int, Lisp_Object));
7103static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7104
7105
7106/* Parse image spec SPEC according to KEYWORDS. A valid image spec
7107 has the format (image KEYWORD VALUE ...). One of the keyword/
7108 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7109 image_keywords structures of size NKEYWORDS describing other
7110 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7111
7112static int
7113parse_image_spec (spec, keywords, nkeywords, type)
7114 Lisp_Object spec;
7115 struct image_keyword *keywords;
7116 int nkeywords;
7117 Lisp_Object type;
7118{
7119 int i;
7120 Lisp_Object plist;
7121
82cf95a7 7122 if (!IMAGEP (spec))
6fc2811b
JR
7123 return 0;
7124
7125 plist = XCDR (spec);
7126 while (CONSP (plist))
7127 {
7128 Lisp_Object key, value;
7129
7130 /* First element of a pair must be a symbol. */
7131 key = XCAR (plist);
7132 plist = XCDR (plist);
7133 if (!SYMBOLP (key))
7134 return 0;
7135
7136 /* There must follow a value. */
7137 if (!CONSP (plist))
7138 return 0;
7139 value = XCAR (plist);
7140 plist = XCDR (plist);
7141
7142 /* Find key in KEYWORDS. Error if not found. */
7143 for (i = 0; i < nkeywords; ++i)
d5db4077 7144 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
6fc2811b
JR
7145 break;
7146
7147 if (i == nkeywords)
7148 continue;
7149
7150 /* Record that we recognized the keyword. If a keywords
7151 was found more than once, it's an error. */
7152 keywords[i].value = value;
7153 ++keywords[i].count;
7d0393cf 7154
6fc2811b
JR
7155 if (keywords[i].count > 1)
7156 return 0;
7157
7158 /* Check type of value against allowed type. */
7159 switch (keywords[i].type)
7160 {
7161 case IMAGE_STRING_VALUE:
7162 if (!STRINGP (value))
7163 return 0;
7164 break;
7165
3cf3436e
JR
7166 case IMAGE_STRING_OR_NIL_VALUE:
7167 if (!STRINGP (value) && !NILP (value))
7168 return 0;
7169 break;
7170
6fc2811b
JR
7171 case IMAGE_SYMBOL_VALUE:
7172 if (!SYMBOLP (value))
7173 return 0;
7174 break;
7175
7176 case IMAGE_POSITIVE_INTEGER_VALUE:
7177 if (!INTEGERP (value) || XINT (value) <= 0)
7178 return 0;
7179 break;
7180
8edb0a6f
JR
7181 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
7182 if (INTEGERP (value) && XINT (value) >= 0)
7183 break;
7184 if (CONSP (value)
7185 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
7186 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
7187 break;
7188 return 0;
7189
dfff8a69
JR
7190 case IMAGE_ASCENT_VALUE:
7191 if (SYMBOLP (value) && EQ (value, Qcenter))
7192 break;
7193 else if (INTEGERP (value)
7194 && XINT (value) >= 0
7195 && XINT (value) <= 100)
7196 break;
7197 return 0;
7198
6fc2811b
JR
7199 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7200 if (!INTEGERP (value) || XINT (value) < 0)
7201 return 0;
7202 break;
7203
7204 case IMAGE_DONT_CHECK_VALUE_TYPE:
7205 break;
7206
7207 case IMAGE_FUNCTION_VALUE:
7208 value = indirect_function (value);
7d0393cf 7209 if (SUBRP (value)
6fc2811b
JR
7210 || COMPILEDP (value)
7211 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7212 break;
7213 return 0;
7214
7215 case IMAGE_NUMBER_VALUE:
7216 if (!INTEGERP (value) && !FLOATP (value))
7217 return 0;
7218 break;
7219
7220 case IMAGE_INTEGER_VALUE:
7221 if (!INTEGERP (value))
7222 return 0;
7223 break;
7224
7225 case IMAGE_BOOL_VALUE:
7226 if (!NILP (value) && !EQ (value, Qt))
7227 return 0;
7228 break;
7229
7230 default:
7231 abort ();
7232 break;
7233 }
7234
7235 if (EQ (key, QCtype) && !EQ (type, value))
7236 return 0;
7237 }
7238
7239 /* Check that all mandatory fields are present. */
7240 for (i = 0; i < nkeywords; ++i)
7241 if (keywords[i].mandatory_p && keywords[i].count == 0)
7242 return 0;
7243
7244 return NILP (plist);
7245}
7246
7247
7248/* Return the value of KEY in image specification SPEC. Value is nil
7249 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7250 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7251
7252static Lisp_Object
7253image_spec_value (spec, key, found)
7254 Lisp_Object spec, key;
7255 int *found;
7256{
7257 Lisp_Object tail;
7d0393cf 7258
6fc2811b
JR
7259 xassert (valid_image_p (spec));
7260
7261 for (tail = XCDR (spec);
7262 CONSP (tail) && CONSP (XCDR (tail));
7263 tail = XCDR (XCDR (tail)))
7264 {
7265 if (EQ (XCAR (tail), key))
7266 {
7267 if (found)
7268 *found = 1;
7269 return XCAR (XCDR (tail));
7270 }
7271 }
7d0393cf 7272
6fc2811b
JR
7273 if (found)
7274 *found = 0;
7275 return Qnil;
7276}
7d0393cf 7277
6fc2811b 7278
ac849ba4
JR
7279DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
7280 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
7281PIXELS non-nil means return the size in pixels, otherwise return the
7282size in canonical character units.
7283FRAME is the frame on which the image will be displayed. FRAME nil
7284or omitted means use the selected frame. */)
7285 (spec, pixels, frame)
7286 Lisp_Object spec, pixels, frame;
7287{
7288 Lisp_Object size;
7289
7290 size = Qnil;
7291 if (valid_image_p (spec))
7292 {
7293 struct frame *f = check_x_frame (frame);
7294 int id = lookup_image (f, spec);
7295 struct image *img = IMAGE_FROM_ID (f, id);
7296 int width = img->width + 2 * img->hmargin;
7297 int height = img->height + 2 * img->vmargin;
7d0393cf 7298
ac849ba4 7299 if (NILP (pixels))
be786000
KS
7300 size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
7301 make_float ((double) height / FRAME_LINE_HEIGHT (f)));
ac849ba4
JR
7302 else
7303 size = Fcons (make_number (width), make_number (height));
7304 }
7305 else
7306 error ("Invalid image specification");
7307
7308 return size;
7309}
7310
7311
7312DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
7313 doc: /* Return t if image SPEC has a mask bitmap.
7314FRAME is the frame on which the image will be displayed. FRAME nil
7315or omitted means use the selected frame. */)
7316 (spec, frame)
7317 Lisp_Object spec, frame;
7318{
7319 Lisp_Object mask;
7320
7321 mask = Qnil;
7322 if (valid_image_p (spec))
7323 {
7324 struct frame *f = check_x_frame (frame);
7325 int id = lookup_image (f, spec);
7326 struct image *img = IMAGE_FROM_ID (f, id);
7327 if (img->mask)
7328 mask = Qt;
7329 }
7330 else
7331 error ("Invalid image specification");
7332
7333 return mask;
7334}
6fc2811b
JR
7335
7336\f
7337/***********************************************************************
7338 Image type independent image structures
7339 ***********************************************************************/
7340
7341static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7342static void free_image P_ ((struct frame *f, struct image *img));
197edd35 7343static void x_destroy_x_image P_ ((XImage *));
6fc2811b
JR
7344
7345
7346/* Allocate and return a new image structure for image specification
7347 SPEC. SPEC has a hash value of HASH. */
7348
7349static struct image *
7350make_image (spec, hash)
7351 Lisp_Object spec;
7352 unsigned hash;
7353{
7354 struct image *img = (struct image *) xmalloc (sizeof *img);
7d0393cf 7355
6fc2811b
JR
7356 xassert (valid_image_p (spec));
7357 bzero (img, sizeof *img);
7358 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7359 xassert (img->type != NULL);
7360 img->spec = spec;
7361 img->data.lisp_val = Qnil;
7362 img->ascent = DEFAULT_IMAGE_ASCENT;
7363 img->hash = hash;
7364 return img;
7365}
7366
7367
7368/* Free image IMG which was used on frame F, including its resources. */
7369
7370static void
7371free_image (f, img)
7372 struct frame *f;
7373 struct image *img;
7374{
7375 if (img)
7376 {
7377 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7378
7379 /* Remove IMG from the hash table of its cache. */
7380 if (img->prev)
7381 img->prev->next = img->next;
7382 else
7383 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7384
7385 if (img->next)
7386 img->next->prev = img->prev;
7387
7388 c->images[img->id] = NULL;
7389
7390 /* Free resources, then free IMG. */
7391 img->type->free (f, img);
7392 xfree (img);
7393 }
7394}
7395
7396
7397/* Prepare image IMG for display on frame F. Must be called before
7398 drawing an image. */
7399
7400void
7401prepare_image_for_display (f, img)
7402 struct frame *f;
7403 struct image *img;
7404{
7405 EMACS_TIME t;
7406
7407 /* We're about to display IMG, so set its timestamp to `now'. */
7408 EMACS_GET_TIME (t);
7409 img->timestamp = EMACS_SECS (t);
7410
7411 /* If IMG doesn't have a pixmap yet, load it now, using the image
7412 type dependent loader function. */
7413 if (img->pixmap == 0 && !img->load_failed_p)
7414 img->load_failed_p = img->type->load (f, img) == 0;
7415}
7d0393cf 7416
6fc2811b 7417
dfff8a69
JR
7418/* Value is the number of pixels for the ascent of image IMG when
7419 drawn in face FACE. */
7420
7421int
7422image_ascent (img, face)
7423 struct image *img;
7424 struct face *face;
7425{
8edb0a6f 7426 int height = img->height + img->vmargin;
dfff8a69
JR
7427 int ascent;
7428
7429 if (img->ascent == CENTERED_IMAGE_ASCENT)
7430 {
7431 if (face->font)
7432 ascent = height / 2 - (FONT_DESCENT(face->font)
7433 - FONT_BASE(face->font)) / 2;
7434 else
7435 ascent = height / 2;
7436 }
7437 else
ac849ba4 7438 ascent = (int) (height * img->ascent / 100.0);
dfff8a69
JR
7439
7440 return ascent;
7441}
7442
7443
6fc2811b 7444\f
a05e2bae
JR
7445/* Image background colors. */
7446
ac849ba4
JR
7447/* Find the "best" corner color of a bitmap. XIMG is assumed to a device
7448 context with the bitmap selected. */
7449static COLORREF
197edd35
JR
7450four_corners_best (img_dc, width, height)
7451 HDC img_dc;
a05e2bae
JR
7452 unsigned long width, height;
7453{
ac849ba4 7454 COLORREF corners[4], best;
a05e2bae
JR
7455 int i, best_count;
7456
197edd35
JR
7457 /* Get the colors at the corners of img_dc. */
7458 corners[0] = GetPixel (img_dc, 0, 0);
7459 corners[1] = GetPixel (img_dc, width - 1, 0);
7460 corners[2] = GetPixel (img_dc, width - 1, height - 1);
7461 corners[3] = GetPixel (img_dc, 0, height - 1);
a05e2bae
JR
7462
7463 /* Choose the most frequently found color as background. */
7464 for (i = best_count = 0; i < 4; ++i)
7465 {
7466 int j, n;
7d0393cf 7467
a05e2bae
JR
7468 for (j = n = 0; j < 4; ++j)
7469 if (corners[i] == corners[j])
7470 ++n;
7471
7472 if (n > best_count)
7473 best = corners[i], best_count = n;
7474 }
7475
7476 return best;
a05e2bae
JR
7477}
7478
7479/* Return the `background' field of IMG. If IMG doesn't have one yet,
197edd35
JR
7480 it is guessed heuristically. If non-zero, IMG_DC is an existing
7481 device context with the image selected to use for the heuristic. */
a05e2bae
JR
7482
7483unsigned long
197edd35 7484image_background (img, f, img_dc)
a05e2bae
JR
7485 struct image *img;
7486 struct frame *f;
197edd35 7487 HDC img_dc;
a05e2bae
JR
7488{
7489 if (! img->background_valid)
7490 /* IMG doesn't have a background yet, try to guess a reasonable value. */
7491 {
197edd35
JR
7492 int free_ximg = !img_dc;
7493 HGDIOBJ prev;
7494
7495 if (free_ximg)
7496 {
7497 HDC frame_dc = get_frame_dc (f);
7498 img_dc = CreateCompatibleDC (frame_dc);
7499 release_frame_dc (f, frame_dc);
a05e2bae 7500
197edd35
JR
7501 prev = SelectObject (img_dc, img->pixmap);
7502 }
a05e2bae 7503
197edd35 7504 img->background = four_corners_best (img_dc, img->width, img->height);
a05e2bae
JR
7505
7506 if (free_ximg)
197edd35
JR
7507 {
7508 SelectObject (img_dc, prev);
7509 DeleteDC (img_dc);
7510 }
a05e2bae
JR
7511
7512 img->background_valid = 1;
a05e2bae
JR
7513 }
7514
7515 return img->background;
7516}
7517
7518/* Return the `background_transparent' field of IMG. If IMG doesn't
7519 have one yet, it is guessed heuristically. If non-zero, MASK is an
7520 existing XImage object to use for the heuristic. */
7521
7522int
7523image_background_transparent (img, f, mask)
7524 struct image *img;
7525 struct frame *f;
197edd35 7526 HDC mask;
a05e2bae
JR
7527{
7528 if (! img->background_transparent_valid)
7529 /* IMG doesn't have a background yet, try to guess a reasonable value. */
7530 {
a05e2bae
JR
7531 if (img->mask)
7532 {
7533 int free_mask = !mask;
197edd35 7534 HGDIOBJ prev;
a05e2bae 7535
197edd35
JR
7536 if (free_mask)
7537 {
7538 HDC frame_dc = get_frame_dc (f);
7539 mask = CreateCompatibleDC (frame_dc);
7540 release_frame_dc (f, frame_dc);
7541
c922a224 7542 prev = SelectObject (mask, img->mask);
197edd35 7543 }
a05e2bae
JR
7544
7545 img->background_transparent
7546 = !four_corners_best (mask, img->width, img->height);
7547
7548 if (free_mask)
197edd35
JR
7549 {
7550 SelectObject (mask, prev);
7551 DeleteDC (mask);
7552 }
a05e2bae
JR
7553 }
7554 else
a05e2bae
JR
7555 img->background_transparent = 0;
7556
7557 img->background_transparent_valid = 1;
7558 }
7559
7560 return img->background_transparent;
7561}
7562
7563\f
6fc2811b
JR
7564/***********************************************************************
7565 Helper functions for X image types
7566 ***********************************************************************/
7567
a05e2bae
JR
7568static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
7569 int, int));
6fc2811b
JR
7570static void x_clear_image P_ ((struct frame *f, struct image *img));
7571static unsigned long x_alloc_image_color P_ ((struct frame *f,
7572 struct image *img,
7573 Lisp_Object color_name,
7574 unsigned long dflt));
7575
a05e2bae
JR
7576
7577/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
7578 free the pixmap if any. MASK_P non-zero means clear the mask
7579 pixmap if any. COLORS_P non-zero means free colors allocated for
7580 the image, if any. */
7581
7582static void
7583x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
7584 struct frame *f;
7585 struct image *img;
7586 int pixmap_p, mask_p, colors_p;
7587{
a05e2bae
JR
7588 if (pixmap_p && img->pixmap)
7589 {
ac849ba4
JR
7590 DeleteObject (img->pixmap);
7591 img->pixmap = NULL;
a05e2bae
JR
7592 img->background_valid = 0;
7593 }
7594
7595 if (mask_p && img->mask)
7596 {
ac849ba4
JR
7597 DeleteObject (img->mask);
7598 img->mask = NULL;
a05e2bae
JR
7599 img->background_transparent_valid = 0;
7600 }
7d0393cf 7601
a05e2bae
JR
7602 if (colors_p && img->ncolors)
7603 {
bf76fe9c 7604#if 0 /* TODO: color table support. */
a05e2bae 7605 x_free_colors (f, img->colors, img->ncolors);
bf76fe9c 7606#endif
a05e2bae
JR
7607 xfree (img->colors);
7608 img->colors = NULL;
7609 img->ncolors = 0;
7610 }
a05e2bae
JR
7611}
7612
6fc2811b
JR
7613/* Free X resources of image IMG which is used on frame F. */
7614
7615static void
7616x_clear_image (f, img)
7617 struct frame *f;
7618 struct image *img;
7619{
6fc2811b
JR
7620 if (img->pixmap)
7621 {
7622 BLOCK_INPUT;
ac849ba4 7623 DeleteObject (img->pixmap);
6fc2811b
JR
7624 img->pixmap = 0;
7625 UNBLOCK_INPUT;
7626 }
7627
7628 if (img->ncolors)
7629 {
ac849ba4
JR
7630#if 0 /* TODO: color table support */
7631
6fc2811b 7632 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7d0393cf 7633
6fc2811b
JR
7634 /* If display has an immutable color map, freeing colors is not
7635 necessary and some servers don't allow it. So don't do it. */
7636 if (class != StaticColor
7637 && class != StaticGray
7638 && class != TrueColor)
7639 {
7640 Colormap cmap;
7641 BLOCK_INPUT;
7642 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
7643 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
7644 img->ncolors, 0);
7645 UNBLOCK_INPUT;
7646 }
ac849ba4 7647#endif
7d0393cf 7648
6fc2811b
JR
7649 xfree (img->colors);
7650 img->colors = NULL;
7651 img->ncolors = 0;
7652 }
6fc2811b
JR
7653}
7654
7655
7656/* Allocate color COLOR_NAME for image IMG on frame F. If color
7657 cannot be allocated, use DFLT. Add a newly allocated color to
7658 IMG->colors, so that it can be freed again. Value is the pixel
7659 color. */
7660
7661static unsigned long
7662x_alloc_image_color (f, img, color_name, dflt)
7663 struct frame *f;
7664 struct image *img;
7665 Lisp_Object color_name;
7666 unsigned long dflt;
7667{
6fc2811b
JR
7668 XColor color;
7669 unsigned long result;
7670
7671 xassert (STRINGP (color_name));
7672
d5db4077 7673 if (w32_defined_color (f, SDATA (color_name), &color, 1))
6fc2811b
JR
7674 {
7675 /* This isn't called frequently so we get away with simply
7676 reallocating the color vector to the needed size, here. */
7677 ++img->ncolors;
7678 img->colors =
7679 (unsigned long *) xrealloc (img->colors,
7680 img->ncolors * sizeof *img->colors);
7681 img->colors[img->ncolors - 1] = color.pixel;
7682 result = color.pixel;
7683 }
7684 else
7685 result = dflt;
7686 return result;
6fc2811b
JR
7687}
7688
7689
7690\f
7691/***********************************************************************
7692 Image Cache
7693 ***********************************************************************/
7694
7695static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 7696static void postprocess_image P_ ((struct frame *, struct image *));
197edd35 7697static void x_disable_image P_ ((struct frame *, struct image *));
6fc2811b
JR
7698
7699
7700/* Return a new, initialized image cache that is allocated from the
7701 heap. Call free_image_cache to free an image cache. */
7702
7703struct image_cache *
7704make_image_cache ()
7705{
7706 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
7707 int size;
7d0393cf 7708
6fc2811b
JR
7709 bzero (c, sizeof *c);
7710 c->size = 50;
7711 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
7712 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
7713 c->buckets = (struct image **) xmalloc (size);
7714 bzero (c->buckets, size);
7715 return c;
7716}
7717
7718
7719/* Free image cache of frame F. Be aware that X frames share images
7720 caches. */
7721
7722void
7723free_image_cache (f)
7724 struct frame *f;
7725{
7726 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7727 if (c)
7728 {
7729 int i;
7730
7731 /* Cache should not be referenced by any frame when freed. */
7732 xassert (c->refcount == 0);
7d0393cf 7733
6fc2811b
JR
7734 for (i = 0; i < c->used; ++i)
7735 free_image (f, c->images[i]);
7736 xfree (c->images);
7737 xfree (c);
7738 xfree (c->buckets);
7739 FRAME_X_IMAGE_CACHE (f) = NULL;
7740 }
7741}
7742
7743
7744/* Clear image cache of frame F. FORCE_P non-zero means free all
7745 images. FORCE_P zero means clear only images that haven't been
7746 displayed for some time. Should be called from time to time to
dfff8a69
JR
7747 reduce the number of loaded images. If image-eviction-seconds is
7748 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
7749 at least that many seconds. */
7750
7751void
7752clear_image_cache (f, force_p)
7753 struct frame *f;
7754 int force_p;
7755{
7756 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7757
7758 if (c && INTEGERP (Vimage_cache_eviction_delay))
7759 {
7760 EMACS_TIME t;
7761 unsigned long old;
0327b4cc 7762 int i, nfreed;
6fc2811b
JR
7763
7764 EMACS_GET_TIME (t);
7765 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7d0393cf 7766
0327b4cc
JR
7767 /* Block input so that we won't be interrupted by a SIGIO
7768 while being in an inconsistent state. */
7769 BLOCK_INPUT;
7d0393cf 7770
0327b4cc 7771 for (i = nfreed = 0; i < c->used; ++i)
6fc2811b
JR
7772 {
7773 struct image *img = c->images[i];
7774 if (img != NULL
0327b4cc 7775 && (force_p || (img->timestamp < old)))
6fc2811b
JR
7776 {
7777 free_image (f, img);
0327b4cc 7778 ++nfreed;
6fc2811b
JR
7779 }
7780 }
7781
7782 /* We may be clearing the image cache because, for example,
7783 Emacs was iconified for a longer period of time. In that
7784 case, current matrices may still contain references to
7785 images freed above. So, clear these matrices. */
0327b4cc 7786 if (nfreed)
6fc2811b 7787 {
0327b4cc 7788 Lisp_Object tail, frame;
7d0393cf 7789
0327b4cc
JR
7790 FOR_EACH_FRAME (tail, frame)
7791 {
7792 struct frame *f = XFRAME (frame);
7793 if (FRAME_W32_P (f)
7794 && FRAME_X_IMAGE_CACHE (f) == c)
7795 clear_current_matrices (f);
7796 }
7797
6fc2811b
JR
7798 ++windows_or_buffers_changed;
7799 }
0327b4cc
JR
7800
7801 UNBLOCK_INPUT;
6fc2811b
JR
7802 }
7803}
7804
7805
7806DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
7807 0, 1, 0,
74e1aeec
JR
7808 doc: /* Clear the image cache of FRAME.
7809FRAME nil or omitted means use the selected frame.
7810FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
7811 (frame)
7812 Lisp_Object frame;
7813{
7814 if (EQ (frame, Qt))
7815 {
7816 Lisp_Object tail;
7d0393cf 7817
6fc2811b
JR
7818 FOR_EACH_FRAME (tail, frame)
7819 if (FRAME_W32_P (XFRAME (frame)))
7820 clear_image_cache (XFRAME (frame), 1);
7821 }
7822 else
7823 clear_image_cache (check_x_frame (frame), 1);
7824
7825 return Qnil;
7826}
7827
7828
3cf3436e
JR
7829/* Compute masks and transform image IMG on frame F, as specified
7830 by the image's specification, */
7831
7832static void
7833postprocess_image (f, img)
7834 struct frame *f;
7835 struct image *img;
7836{
3cf3436e
JR
7837 /* Manipulation of the image's mask. */
7838 if (img->pixmap)
7839 {
7840 Lisp_Object conversion, spec;
7841 Lisp_Object mask;
7842
7843 spec = img->spec;
7d0393cf 7844
3cf3436e
JR
7845 /* `:heuristic-mask t'
7846 `:mask heuristic'
7847 means build a mask heuristically.
7848 `:heuristic-mask (R G B)'
7849 `:mask (heuristic (R G B))'
7850 means build a mask from color (R G B) in the
7851 image.
7852 `:mask nil'
7853 means remove a mask, if any. */
7d0393cf 7854
3cf3436e
JR
7855 mask = image_spec_value (spec, QCheuristic_mask, NULL);
7856 if (!NILP (mask))
7857 x_build_heuristic_mask (f, img, mask);
7858 else
7859 {
7860 int found_p;
7d0393cf 7861
3cf3436e 7862 mask = image_spec_value (spec, QCmask, &found_p);
7d0393cf 7863
3cf3436e
JR
7864 if (EQ (mask, Qheuristic))
7865 x_build_heuristic_mask (f, img, Qt);
7866 else if (CONSP (mask)
7867 && EQ (XCAR (mask), Qheuristic))
7868 {
7869 if (CONSP (XCDR (mask)))
7870 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
7871 else
7872 x_build_heuristic_mask (f, img, XCDR (mask));
7873 }
7874 else if (NILP (mask) && found_p && img->mask)
7875 {
ac849ba4 7876 DeleteObject (img->mask);
3cf3436e
JR
7877 img->mask = NULL;
7878 }
7879 }
7d0393cf
JB
7880
7881
3cf3436e
JR
7882 /* Should we apply an image transformation algorithm? */
7883 conversion = image_spec_value (spec, QCconversion, NULL);
7884 if (EQ (conversion, Qdisabled))
7885 x_disable_image (f, img);
7886 else if (EQ (conversion, Qlaplace))
7887 x_laplace (f, img);
7888 else if (EQ (conversion, Qemboss))
7889 x_emboss (f, img);
7890 else if (CONSP (conversion)
7891 && EQ (XCAR (conversion), Qedge_detection))
7892 {
7893 Lisp_Object tem;
7894 tem = XCDR (conversion);
7895 if (CONSP (tem))
7896 x_edge_detection (f, img,
7897 Fplist_get (tem, QCmatrix),
7898 Fplist_get (tem, QCcolor_adjustment));
7899 }
7900 }
3cf3436e
JR
7901}
7902
7903
6fc2811b
JR
7904/* Return the id of image with Lisp specification SPEC on frame F.
7905 SPEC must be a valid Lisp image specification (see valid_image_p). */
7906
7907int
7908lookup_image (f, spec)
7909 struct frame *f;
7910 Lisp_Object spec;
7911{
7912 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7913 struct image *img;
7914 int i;
7915 unsigned hash;
7916 struct gcpro gcpro1;
7917 EMACS_TIME now;
7918
7919 /* F must be a window-system frame, and SPEC must be a valid image
7920 specification. */
7921 xassert (FRAME_WINDOW_P (f));
7922 xassert (valid_image_p (spec));
7d0393cf 7923
6fc2811b
JR
7924 GCPRO1 (spec);
7925
7926 /* Look up SPEC in the hash table of the image cache. */
7927 hash = sxhash (spec, 0);
7928 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
7929
7930 for (img = c->buckets[i]; img; img = img->next)
7931 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
7932 break;
7933
7934 /* If not found, create a new image and cache it. */
7935 if (img == NULL)
7936 {
3cf3436e
JR
7937 extern Lisp_Object Qpostscript;
7938
8edb0a6f 7939 BLOCK_INPUT;
6fc2811b
JR
7940 img = make_image (spec, hash);
7941 cache_image (f, img);
7942 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
7943
7944 /* If we can't load the image, and we don't have a width and
7945 height, use some arbitrary width and height so that we can
7946 draw a rectangle for it. */
7947 if (img->load_failed_p)
7948 {
7949 Lisp_Object value;
7950
7951 value = image_spec_value (spec, QCwidth, NULL);
7952 img->width = (INTEGERP (value)
7953 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
7954 value = image_spec_value (spec, QCheight, NULL);
7955 img->height = (INTEGERP (value)
7956 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
7957 }
7958 else
7959 {
7960 /* Handle image type independent image attributes
8f92c555 7961 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
a05e2bae
JR
7962 `:background COLOR'. */
7963 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
7964
7965 ascent = image_spec_value (spec, QCascent, NULL);
7966 if (INTEGERP (ascent))
7967 img->ascent = XFASTINT (ascent);
dfff8a69
JR
7968 else if (EQ (ascent, Qcenter))
7969 img->ascent = CENTERED_IMAGE_ASCENT;
7970
6fc2811b
JR
7971 margin = image_spec_value (spec, QCmargin, NULL);
7972 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
7973 img->vmargin = img->hmargin = XFASTINT (margin);
7974 else if (CONSP (margin) && INTEGERP (XCAR (margin))
7975 && INTEGERP (XCDR (margin)))
7976 {
7977 if (XINT (XCAR (margin)) > 0)
7978 img->hmargin = XFASTINT (XCAR (margin));
7979 if (XINT (XCDR (margin)) > 0)
7980 img->vmargin = XFASTINT (XCDR (margin));
7981 }
7d0393cf 7982
6fc2811b
JR
7983 relief = image_spec_value (spec, QCrelief, NULL);
7984 if (INTEGERP (relief))
7985 {
7986 img->relief = XINT (relief);
8edb0a6f
JR
7987 img->hmargin += abs (img->relief);
7988 img->vmargin += abs (img->relief);
6fc2811b
JR
7989 }
7990
a05e2bae
JR
7991 if (! img->background_valid)
7992 {
7993 bg = image_spec_value (img->spec, QCbackground, NULL);
7994 if (!NILP (bg))
7995 {
7996 img->background
7997 = x_alloc_image_color (f, img, bg,
7998 FRAME_BACKGROUND_PIXEL (f));
7999 img->background_valid = 1;
8000 }
8001 }
8002
3cf3436e
JR
8003 /* Do image transformations and compute masks, unless we
8004 don't have the image yet. */
8005 if (!EQ (*img->type->type, Qpostscript))
8006 postprocess_image (f, img);
6fc2811b 8007 }
3cf3436e 8008
8edb0a6f
JR
8009 UNBLOCK_INPUT;
8010 xassert (!interrupt_input_blocked);
6fc2811b
JR
8011 }
8012
8013 /* We're using IMG, so set its timestamp to `now'. */
8014 EMACS_GET_TIME (now);
8015 img->timestamp = EMACS_SECS (now);
7d0393cf 8016
6fc2811b 8017 UNGCPRO;
7d0393cf 8018
6fc2811b
JR
8019 /* Value is the image id. */
8020 return img->id;
8021}
8022
8023
8024/* Cache image IMG in the image cache of frame F. */
8025
8026static void
8027cache_image (f, img)
8028 struct frame *f;
8029 struct image *img;
8030{
8031 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8032 int i;
8033
8034 /* Find a free slot in c->images. */
8035 for (i = 0; i < c->used; ++i)
8036 if (c->images[i] == NULL)
8037 break;
8038
8039 /* If no free slot found, maybe enlarge c->images. */
8040 if (i == c->used && c->used == c->size)
8041 {
8042 c->size *= 2;
8043 c->images = (struct image **) xrealloc (c->images,
8044 c->size * sizeof *c->images);
8045 }
8046
8047 /* Add IMG to c->images, and assign IMG an id. */
8048 c->images[i] = img;
8049 img->id = i;
8050 if (i == c->used)
8051 ++c->used;
8052
8053 /* Add IMG to the cache's hash table. */
8054 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8055 img->next = c->buckets[i];
8056 if (img->next)
8057 img->next->prev = img;
8058 img->prev = NULL;
8059 c->buckets[i] = img;
8060}
8061
8062
8063/* Call FN on every image in the image cache of frame F. Used to mark
8064 Lisp Objects in the image cache. */
8065
8066void
8067forall_images_in_image_cache (f, fn)
8068 struct frame *f;
8069 void (*fn) P_ ((struct image *img));
8070{
8071 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8072 {
8073 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8074 if (c)
8075 {
8076 int i;
8077 for (i = 0; i < c->used; ++i)
8078 if (c->images[i])
8079 fn (c->images[i]);
8080 }
8081 }
8082}
8083
8084
8085\f
8086/***********************************************************************
8087 W32 support code
8088 ***********************************************************************/
8089
839b1909
JR
8090/* Macro for defining functions that will be loaded from image DLLs. */
8091#define DEF_IMGLIB_FN(func) FARPROC fn_##func
c922a224 8092
839b1909
JR
8093/* Macro for loading those image functions from the library. */
8094#define LOAD_IMGLIB_FN(lib,func) { \
8095 fn_##func = (void *) GetProcAddress (lib, #func); \
8096 if (!fn_##func) return 0; \
c922a224 8097 }
839b1909 8098
6fc2811b
JR
8099static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8100 XImage **, Pixmap *));
6fc2811b
JR
8101static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8102
8103
8104/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8105 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8106 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
ac849ba4
JR
8107 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
8108 DEPTH should indicate the bit depth of the image. Print error
8109 messages via image_error if an error occurs. Value is non-zero if
8110 successful. */
6fc2811b
JR
8111
8112static int
8113x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8114 struct frame *f;
8115 int width, height, depth;
8116 XImage **ximg;
8117 Pixmap *pixmap;
8118{
ac849ba4
JR
8119 BITMAPINFOHEADER *header;
8120 HDC hdc;
8121 int scanline_width_bits;
8122 int remainder;
8123 int palette_colors = 0;
6fc2811b 8124
ac849ba4
JR
8125 if (depth == 0)
8126 depth = 24;
6fc2811b 8127
ac849ba4
JR
8128 if (depth != 1 && depth != 4 && depth != 8
8129 && depth != 16 && depth != 24 && depth != 32)
8130 {
8131 image_error ("Invalid image bit depth specified", Qnil, Qnil);
8132 return 0;
8133 }
8134
8135 scanline_width_bits = width * depth;
8136 remainder = scanline_width_bits % 32;
8137
8138 if (remainder)
8139 scanline_width_bits += 32 - remainder;
8140
8141 /* Bitmaps with a depth less than 16 need a palette. */
8142 /* BITMAPINFO structure already contains the first RGBQUAD. */
8143 if (depth < 16)
8144 palette_colors = 1 << depth - 1;
8145
8146 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
6fc2811b
JR
8147 if (*ximg == NULL)
8148 {
ac849ba4 8149 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
6fc2811b
JR
8150 return 0;
8151 }
8152
ac849ba4
JR
8153 header = &((*ximg)->info.bmiHeader);
8154 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
8155 header->biSize = sizeof (*header);
8156 header->biWidth = width;
8157 header->biHeight = -height; /* negative indicates a top-down bitmap. */
8158 header->biPlanes = 1;
8159 header->biBitCount = depth;
8160 header->biCompression = BI_RGB;
8161 header->biClrUsed = palette_colors;
6fc2811b 8162
197edd35 8163 /* TODO: fill in palette. */
35624c03
JR
8164 if (depth == 1)
8165 {
8166 (*ximg)->info.bmiColors[0].rgbBlue = 0;
8167 (*ximg)->info.bmiColors[0].rgbGreen = 0;
8168 (*ximg)->info.bmiColors[0].rgbRed = 0;
8169 (*ximg)->info.bmiColors[0].rgbReserved = 0;
8170 (*ximg)->info.bmiColors[1].rgbBlue = 255;
8171 (*ximg)->info.bmiColors[1].rgbGreen = 255;
8172 (*ximg)->info.bmiColors[1].rgbRed = 255;
8173 (*ximg)->info.bmiColors[1].rgbReserved = 0;
8174 }
197edd35 8175
ac849ba4
JR
8176 hdc = get_frame_dc (f);
8177
8178 /* Create a DIBSection and raster array for the bitmap,
8179 and store its handle in *pixmap. */
197edd35
JR
8180 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
8181 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
ac849ba4
JR
8182 &((*ximg)->data), NULL, 0);
8183
8184 /* Realize display palette and garbage all frames. */
8185 release_frame_dc (f, hdc);
8186
8187 if (*pixmap == NULL)
6fc2811b 8188 {
ac849ba4
JR
8189 DWORD err = GetLastError();
8190 Lisp_Object errcode;
8191 /* All system errors are < 10000, so the following is safe. */
8192 XSETINT (errcode, (int) err);
8193 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
6fc2811b 8194 x_destroy_x_image (*ximg);
6fc2811b
JR
8195 return 0;
8196 }
ac849ba4 8197
6fc2811b
JR
8198 return 1;
8199}
8200
8201
8202/* Destroy XImage XIMG. Free XIMG->data. */
8203
8204static void
8205x_destroy_x_image (ximg)
8206 XImage *ximg;
8207{
8208 xassert (interrupt_input_blocked);
8209 if (ximg)
8210 {
ac849ba4 8211 /* Data will be freed by DestroyObject. */
6fc2811b 8212 ximg->data = NULL;
ac849ba4 8213 xfree (ximg);
6fc2811b
JR
8214 }
8215}
8216
8217
8218/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8219 are width and height of both the image and pixmap. */
8220
8221static void
8222x_put_x_image (f, ximg, pixmap, width, height)
8223 struct frame *f;
8224 XImage *ximg;
8225 Pixmap pixmap;
c9b2104d 8226 int width, height;
6fc2811b 8227{
197edd35
JR
8228#if 0 /* I don't think this is necessary looking at where it is used. */
8229 HDC hdc = get_frame_dc (f);
8230 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
8231 release_frame_dc (f, hdc);
6fc2811b 8232#endif
ac849ba4 8233}
6fc2811b
JR
8234
8235\f
8236/***********************************************************************
3cf3436e 8237 File Handling
6fc2811b
JR
8238 ***********************************************************************/
8239
8240static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
8241static char *slurp_file P_ ((char *, int *));
8242
6fc2811b
JR
8243
8244/* Find image file FILE. Look in data-directory, then
8245 x-bitmap-file-path. Value is the full name of the file found, or
8246 nil if not found. */
8247
8248static Lisp_Object
8249x_find_image_file (file)
8250 Lisp_Object file;
8251{
8252 Lisp_Object file_found, search_path;
8253 struct gcpro gcpro1, gcpro2;
8254 int fd;
8255
8256 file_found = Qnil;
8257 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8258 GCPRO2 (file_found, search_path);
8259
8260 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 8261 fd = openp (search_path, file, Qnil, &file_found, Qnil);
7d0393cf 8262
939d6465 8263 if (fd == -1)
6fc2811b
JR
8264 file_found = Qnil;
8265 else
8266 close (fd);
8267
8268 UNGCPRO;
8269 return file_found;
8270}
8271
8272
3cf3436e
JR
8273/* Read FILE into memory. Value is a pointer to a buffer allocated
8274 with xmalloc holding FILE's contents. Value is null if an error
8275 occurred. *SIZE is set to the size of the file. */
8276
8277static char *
8278slurp_file (file, size)
8279 char *file;
8280 int *size;
8281{
8282 FILE *fp = NULL;
8283 char *buf = NULL;
8284 struct stat st;
8285
8286 if (stat (file, &st) == 0
c45bb3b2 8287 && (fp = fopen (file, "rb")) != NULL
3cf3436e
JR
8288 && (buf = (char *) xmalloc (st.st_size),
8289 fread (buf, 1, st.st_size, fp) == st.st_size))
8290 {
8291 *size = st.st_size;
8292 fclose (fp);
8293 }
8294 else
8295 {
8296 if (fp)
8297 fclose (fp);
8298 if (buf)
8299 {
8300 xfree (buf);
8301 buf = NULL;
8302 }
8303 }
7d0393cf 8304
3cf3436e
JR
8305 return buf;
8306}
8307
8308
6fc2811b
JR
8309\f
8310/***********************************************************************
8311 XBM images
8312 ***********************************************************************/
8313
217e5be0 8314static int xbm_scan P_ ((char **, char *, char *, int *));
6fc2811b 8315static int xbm_load P_ ((struct frame *f, struct image *img));
217e5be0
JR
8316static int xbm_load_image P_ ((struct frame *f, struct image *img,
8317 char *, char *));
6fc2811b 8318static int xbm_image_p P_ ((Lisp_Object object));
217e5be0
JR
8319static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
8320 unsigned char **));
8321static int xbm_file_p P_ ((Lisp_Object));
6fc2811b
JR
8322
8323
8324/* Indices of image specification fields in xbm_format, below. */
8325
8326enum xbm_keyword_index
8327{
8328 XBM_TYPE,
8329 XBM_FILE,
8330 XBM_WIDTH,
8331 XBM_HEIGHT,
8332 XBM_DATA,
8333 XBM_FOREGROUND,
8334 XBM_BACKGROUND,
8335 XBM_ASCENT,
8336 XBM_MARGIN,
8337 XBM_RELIEF,
8338 XBM_ALGORITHM,
8339 XBM_HEURISTIC_MASK,
a05e2bae 8340 XBM_MASK,
6fc2811b
JR
8341 XBM_LAST
8342};
8343
8344/* Vector of image_keyword structures describing the format
8345 of valid XBM image specifications. */
8346
8347static struct image_keyword xbm_format[XBM_LAST] =
8348{
8349 {":type", IMAGE_SYMBOL_VALUE, 1},
8350 {":file", IMAGE_STRING_VALUE, 0},
8351 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8352 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8353 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
8354 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8355 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
8356 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 8357 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 8358 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 8359 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
8360 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8361 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6fc2811b
JR
8362};
8363
8364/* Structure describing the image type XBM. */
8365
8366static struct image_type xbm_type =
8367{
8368 &Qxbm,
8369 xbm_image_p,
8370 xbm_load,
8371 x_clear_image,
8372 NULL
8373};
8374
8375/* Tokens returned from xbm_scan. */
8376
8377enum xbm_token
8378{
8379 XBM_TK_IDENT = 256,
8380 XBM_TK_NUMBER
8381};
8382
7d0393cf 8383
6fc2811b
JR
8384/* Return non-zero if OBJECT is a valid XBM-type image specification.
8385 A valid specification is a list starting with the symbol `image'
8386 The rest of the list is a property list which must contain an
8387 entry `:type xbm..
8388
8389 If the specification specifies a file to load, it must contain
8390 an entry `:file FILENAME' where FILENAME is a string.
8391
8392 If the specification is for a bitmap loaded from memory it must
8393 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8394 WIDTH and HEIGHT are integers > 0. DATA may be:
8395
8396 1. a string large enough to hold the bitmap data, i.e. it must
8397 have a size >= (WIDTH + 7) / 8 * HEIGHT
8398
8399 2. a bool-vector of size >= WIDTH * HEIGHT
8400
8401 3. a vector of strings or bool-vectors, one for each line of the
8402 bitmap.
8403
217e5be0
JR
8404 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
8405 may not be specified in this case because they are defined in the
8406 XBM file.
8407
6fc2811b
JR
8408 Both the file and data forms may contain the additional entries
8409 `:background COLOR' and `:foreground COLOR'. If not present,
8410 foreground and background of the frame on which the image is
217e5be0 8411 displayed is used. */
6fc2811b
JR
8412
8413static int
8414xbm_image_p (object)
8415 Lisp_Object object;
8416{
8417 struct image_keyword kw[XBM_LAST];
7d0393cf 8418
6fc2811b
JR
8419 bcopy (xbm_format, kw, sizeof kw);
8420 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8421 return 0;
8422
8423 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8424
8425 if (kw[XBM_FILE].count)
8426 {
8427 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8428 return 0;
8429 }
217e5be0
JR
8430 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
8431 {
8432 /* In-memory XBM file. */
8433 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
8434 return 0;
8435 }
6fc2811b
JR
8436 else
8437 {
8438 Lisp_Object data;
8439 int width, height;
8440
8441 /* Entries for `:width', `:height' and `:data' must be present. */
8442 if (!kw[XBM_WIDTH].count
8443 || !kw[XBM_HEIGHT].count
8444 || !kw[XBM_DATA].count)
8445 return 0;
8446
8447 data = kw[XBM_DATA].value;
8448 width = XFASTINT (kw[XBM_WIDTH].value);
8449 height = XFASTINT (kw[XBM_HEIGHT].value);
7d0393cf 8450
6fc2811b
JR
8451 /* Check type of data, and width and height against contents of
8452 data. */
8453 if (VECTORP (data))
8454 {
8455 int i;
7d0393cf 8456
6fc2811b
JR
8457 /* Number of elements of the vector must be >= height. */
8458 if (XVECTOR (data)->size < height)
8459 return 0;
8460
8461 /* Each string or bool-vector in data must be large enough
8462 for one line of the image. */
8463 for (i = 0; i < height; ++i)
8464 {
8465 Lisp_Object elt = XVECTOR (data)->contents[i];
8466
8467 if (STRINGP (elt))
8468 {
d5db4077 8469 if (SCHARS (elt)
6fc2811b
JR
8470 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8471 return 0;
8472 }
8473 else if (BOOL_VECTOR_P (elt))
8474 {
8475 if (XBOOL_VECTOR (elt)->size < width)
8476 return 0;
8477 }
8478 else
8479 return 0;
8480 }
8481 }
8482 else if (STRINGP (data))
8483 {
d5db4077 8484 if (SCHARS (data)
6fc2811b
JR
8485 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8486 return 0;
8487 }
8488 else if (BOOL_VECTOR_P (data))
8489 {
8490 if (XBOOL_VECTOR (data)->size < width * height)
8491 return 0;
8492 }
8493 else
8494 return 0;
8495 }
8496
6fc2811b
JR
8497 return 1;
8498}
8499
8500
8501/* Scan a bitmap file. FP is the stream to read from. Value is
8502 either an enumerator from enum xbm_token, or a character for a
8503 single-character token, or 0 at end of file. If scanning an
8504 identifier, store the lexeme of the identifier in SVAL. If
8505 scanning a number, store its value in *IVAL. */
8506
8507static int
3cf3436e
JR
8508xbm_scan (s, end, sval, ival)
8509 char **s, *end;
6fc2811b
JR
8510 char *sval;
8511 int *ival;
8512{
8513 int c;
3cf3436e
JR
8514
8515 loop:
8516
6fc2811b 8517 /* Skip white space. */
af3f7be7 8518 while (*s < end && (c = *(*s)++, isspace (c)))
6fc2811b
JR
8519 ;
8520
3cf3436e 8521 if (*s >= end)
6fc2811b
JR
8522 c = 0;
8523 else if (isdigit (c))
8524 {
8525 int value = 0, digit;
7d0393cf 8526
3cf3436e 8527 if (c == '0' && *s < end)
6fc2811b 8528 {
3cf3436e 8529 c = *(*s)++;
6fc2811b
JR
8530 if (c == 'x' || c == 'X')
8531 {
3cf3436e 8532 while (*s < end)
6fc2811b 8533 {
3cf3436e 8534 c = *(*s)++;
6fc2811b
JR
8535 if (isdigit (c))
8536 digit = c - '0';
8537 else if (c >= 'a' && c <= 'f')
8538 digit = c - 'a' + 10;
8539 else if (c >= 'A' && c <= 'F')
8540 digit = c - 'A' + 10;
8541 else
8542 break;
8543 value = 16 * value + digit;
8544 }
8545 }
8546 else if (isdigit (c))
8547 {
8548 value = c - '0';
3cf3436e
JR
8549 while (*s < end
8550 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
8551 value = 8 * value + c - '0';
8552 }
8553 }
8554 else
8555 {
8556 value = c - '0';
3cf3436e
JR
8557 while (*s < end
8558 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
8559 value = 10 * value + c - '0';
8560 }
8561
3cf3436e
JR
8562 if (*s < end)
8563 *s = *s - 1;
6fc2811b
JR
8564 *ival = value;
8565 c = XBM_TK_NUMBER;
8566 }
8567 else if (isalpha (c) || c == '_')
8568 {
8569 *sval++ = c;
3cf3436e
JR
8570 while (*s < end
8571 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
8572 *sval++ = c;
8573 *sval = 0;
3cf3436e
JR
8574 if (*s < end)
8575 *s = *s - 1;
6fc2811b
JR
8576 c = XBM_TK_IDENT;
8577 }
3cf3436e
JR
8578 else if (c == '/' && **s == '*')
8579 {
8580 /* C-style comment. */
8581 ++*s;
8582 while (**s && (**s != '*' || *(*s + 1) != '/'))
8583 ++*s;
8584 if (**s)
8585 {
8586 *s += 2;
8587 goto loop;
8588 }
8589 }
6fc2811b
JR
8590
8591 return c;
8592}
8593
8594
217e5be0
JR
8595/* XBM bits seem to be backward within bytes compared with how
8596 Windows does things. */
8597static unsigned char reflect_byte (unsigned char orig)
8598{
8599 int i;
8600 unsigned char reflected = 0x00;
8601 for (i = 0; i < 8; i++)
8602 {
8603 if (orig & (0x01 << i))
8604 reflected |= 0x80 >> i;
8605 }
8606 return reflected;
8607}
8608
8609
af3f7be7
JR
8610/* Create a Windows bitmap from X bitmap data. */
8611static HBITMAP
8612w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
8613{
8614 int i, j, w1, w2;
8615 char *bits, *p;
8616 HBITMAP bmp;
8617
8618 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
8619 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
c736ffda 8620 bits = (char *) alloca (height * w2);
af3f7be7
JR
8621 bzero (bits, height * w2);
8622 for (i = 0; i < height; i++)
8623 {
8624 p = bits + i*w2;
8625 for (j = 0; j < w1; j++)
8626 *p++ = reflect_byte(*data++);
8627 }
8628 bmp = CreateBitmap (width, height, 1, 1, bits);
af3f7be7
JR
8629
8630 return bmp;
8631}
8632
8633
6fc2811b 8634/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
8635 X versions. CONTENTS is a pointer to a buffer to parse; END is the
8636 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
8637 the image. Return in *DATA the bitmap data allocated with xmalloc.
8638 Value is non-zero if successful. DATA null means just test if
8639 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
8640
8641static int
3cf3436e
JR
8642xbm_read_bitmap_data (contents, end, width, height, data)
8643 char *contents, *end;
6fc2811b
JR
8644 int *width, *height;
8645 unsigned char **data;
8646{
3cf3436e 8647 char *s = contents;
6fc2811b
JR
8648 char buffer[BUFSIZ];
8649 int padding_p = 0;
8650 int v10 = 0;
af3f7be7 8651 int bytes_per_line, i, nbytes;
6fc2811b
JR
8652 unsigned char *p;
8653 int value;
8654 int LA1;
8655
8656#define match() \
217e5be0 8657 LA1 = xbm_scan (&s, end, buffer, &value)
6fc2811b
JR
8658
8659#define expect(TOKEN) \
8660 if (LA1 != (TOKEN)) \
8661 goto failure; \
8662 else \
7d0393cf 8663 match ()
6fc2811b
JR
8664
8665#define expect_ident(IDENT) \
8666 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8667 match (); \
8668 else \
8669 goto failure
8670
6fc2811b 8671 *width = *height = -1;
3cf3436e
JR
8672 if (data)
8673 *data = NULL;
8674 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
8675
8676 /* Parse defines for width, height and hot-spots. */
8677 while (LA1 == '#')
8678 {
8679 match ();
8680 expect_ident ("define");
8681 expect (XBM_TK_IDENT);
8682
8683 if (LA1 == XBM_TK_NUMBER);
8684 {
8685 char *p = strrchr (buffer, '_');
8686 p = p ? p + 1 : buffer;
8687 if (strcmp (p, "width") == 0)
8688 *width = value;
8689 else if (strcmp (p, "height") == 0)
8690 *height = value;
8691 }
8692 expect (XBM_TK_NUMBER);
8693 }
8694
8695 if (*width < 0 || *height < 0)
8696 goto failure;
3cf3436e
JR
8697 else if (data == NULL)
8698 goto success;
6fc2811b
JR
8699
8700 /* Parse bits. Must start with `static'. */
8701 expect_ident ("static");
8702 if (LA1 == XBM_TK_IDENT)
8703 {
8704 if (strcmp (buffer, "unsigned") == 0)
8705 {
7d0393cf 8706 match ();
6fc2811b
JR
8707 expect_ident ("char");
8708 }
8709 else if (strcmp (buffer, "short") == 0)
8710 {
8711 match ();
8712 v10 = 1;
af3f7be7
JR
8713 if (*width % 16 && *width % 16 < 9)
8714 padding_p = 1;
6fc2811b
JR
8715 }
8716 else if (strcmp (buffer, "char") == 0)
8717 match ();
8718 else
8719 goto failure;
8720 }
7d0393cf 8721 else
6fc2811b
JR
8722 goto failure;
8723
8724 expect (XBM_TK_IDENT);
8725 expect ('[');
8726 expect (']');
8727 expect ('=');
8728 expect ('{');
8729
af3f7be7
JR
8730 bytes_per_line = (*width + 7) / 8 + padding_p;
8731 nbytes = bytes_per_line * *height;
8732 p = *data = (char *) xmalloc (nbytes);
6fc2811b
JR
8733
8734 if (v10)
8735 {
6fc2811b
JR
8736 for (i = 0; i < nbytes; i += 2)
8737 {
8738 int val = value;
8739 expect (XBM_TK_NUMBER);
8740
35624c03 8741 *p++ = ~ val;
af3f7be7 8742 if (!padding_p || ((i + 2) % bytes_per_line))
35624c03 8743 *p++ = ~ (value >> 8);
7d0393cf 8744
6fc2811b
JR
8745 if (LA1 == ',' || LA1 == '}')
8746 match ();
8747 else
8748 goto failure;
8749 }
8750 }
8751 else
8752 {
8753 for (i = 0; i < nbytes; ++i)
8754 {
8755 int val = value;
8756 expect (XBM_TK_NUMBER);
7d0393cf 8757
35624c03 8758 *p++ = ~ val;
217e5be0 8759
6fc2811b
JR
8760 if (LA1 == ',' || LA1 == '}')
8761 match ();
8762 else
8763 goto failure;
8764 }
8765 }
8766
3cf3436e 8767 success:
6fc2811b
JR
8768 return 1;
8769
8770 failure:
3cf3436e
JR
8771
8772 if (data && *data)
6fc2811b
JR
8773 {
8774 xfree (*data);
8775 *data = NULL;
8776 }
8777 return 0;
8778
8779#undef match
8780#undef expect
8781#undef expect_ident
8782}
8783
516eea8e
JR
8784static void convert_mono_to_color_image (f, img, foreground, background)
8785 struct frame *f;
8786 struct image *img;
8787 COLORREF foreground, background;
8788{
8789 HDC hdc, old_img_dc, new_img_dc;
8790 HGDIOBJ old_prev, new_prev;
8791 HBITMAP new_pixmap;
8792
8793 hdc = get_frame_dc (f);
8794 old_img_dc = CreateCompatibleDC (hdc);
8795 new_img_dc = CreateCompatibleDC (hdc);
8796 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
8797 release_frame_dc (f, hdc);
8798 old_prev = SelectObject (old_img_dc, img->pixmap);
8799 new_prev = SelectObject (new_img_dc, new_pixmap);
8800 SetTextColor (new_img_dc, foreground);
8801 SetBkColor (new_img_dc, background);
8802
8803 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
8804 0, 0, SRCCOPY);
8805
8806 SelectObject (old_img_dc, old_prev);
c922a224 8807 SelectObject (new_img_dc, new_prev);
516eea8e
JR
8808 DeleteDC (old_img_dc);
8809 DeleteDC (new_img_dc);
8810 DeleteObject (img->pixmap);
8811 if (new_pixmap == 0)
8812 fprintf (stderr, "Failed to convert image to color.\n");
8813 else
8814 img->pixmap = new_pixmap;
8815}
6fc2811b 8816
3cf3436e
JR
8817/* Load XBM image IMG which will be displayed on frame F from buffer
8818 CONTENTS. END is the end of the buffer. Value is non-zero if
8819 successful. */
6fc2811b
JR
8820
8821static int
3cf3436e 8822xbm_load_image (f, img, contents, end)
6fc2811b
JR
8823 struct frame *f;
8824 struct image *img;
3cf3436e 8825 char *contents, *end;
6fc2811b
JR
8826{
8827 int rc;
8828 unsigned char *data;
8829 int success_p = 0;
7d0393cf 8830
3cf3436e 8831 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
8832 if (rc)
8833 {
6fc2811b
JR
8834 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8835 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
516eea8e 8836 int non_default_colors = 0;
6fc2811b 8837 Lisp_Object value;
7d0393cf 8838
6fc2811b
JR
8839 xassert (img->width > 0 && img->height > 0);
8840
8841 /* Get foreground and background colors, maybe allocate colors. */
8842 value = image_spec_value (img->spec, QCforeground, NULL);
8843 if (!NILP (value))
516eea8e
JR
8844 {
8845 foreground = x_alloc_image_color (f, img, value, foreground);
8846 non_default_colors = 1;
8847 }
6fc2811b
JR
8848 value = image_spec_value (img->spec, QCbackground, NULL);
8849 if (!NILP (value))
a05e2bae
JR
8850 {
8851 background = x_alloc_image_color (f, img, value, background);
8852 img->background = background;
8853 img->background_valid = 1;
516eea8e 8854 non_default_colors = 1;
a05e2bae 8855 }
6fc2811b 8856 img->pixmap
af3f7be7 8857 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
ac849ba4 8858
516eea8e
JR
8859 /* If colors were specified, transfer the bitmap to a color one. */
8860 if (non_default_colors)
8861 convert_mono_to_color_image (f, img, foreground, background);
8862
6fc2811b
JR
8863 xfree (data);
8864
8865 if (img->pixmap == 0)
8866 {
8867 x_clear_image (f, img);
3cf3436e 8868 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
8869 }
8870 else
8871 success_p = 1;
6fc2811b
JR
8872 }
8873 else
8874 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8875
6fc2811b
JR
8876 return success_p;
8877}
8878
8879
3cf3436e
JR
8880/* Value is non-zero if DATA looks like an in-memory XBM file. */
8881
8882static int
8883xbm_file_p (data)
8884 Lisp_Object data;
8885{
8886 int w, h;
8887 return (STRINGP (data)
d5db4077
KR
8888 && xbm_read_bitmap_data (SDATA (data),
8889 (SDATA (data)
8890 + SBYTES (data)),
3cf3436e
JR
8891 &w, &h, NULL));
8892}
8893
7d0393cf 8894
6fc2811b
JR
8895/* Fill image IMG which is used on frame F with pixmap data. Value is
8896 non-zero if successful. */
8897
8898static int
8899xbm_load (f, img)
8900 struct frame *f;
8901 struct image *img;
8902{
8903 int success_p = 0;
8904 Lisp_Object file_name;
8905
8906 xassert (xbm_image_p (img->spec));
8907
8908 /* If IMG->spec specifies a file name, create a non-file spec from it. */
8909 file_name = image_spec_value (img->spec, QCfile, NULL);
8910 if (STRINGP (file_name))
3cf3436e
JR
8911 {
8912 Lisp_Object file;
8913 char *contents;
8914 int size;
8915 struct gcpro gcpro1;
8916
8917 file = x_find_image_file (file_name);
8918 GCPRO1 (file);
8919 if (!STRINGP (file))
8920 {
8921 image_error ("Cannot find image file `%s'", file_name, Qnil);
8922 UNGCPRO;
8923 return 0;
8924 }
8925
d5db4077 8926 contents = slurp_file (SDATA (file), &size);
3cf3436e
JR
8927 if (contents == NULL)
8928 {
8929 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8930 UNGCPRO;
8931 return 0;
8932 }
8933
8934 success_p = xbm_load_image (f, img, contents, contents + size);
8935 UNGCPRO;
8936 }
6fc2811b
JR
8937 else
8938 {
8939 struct image_keyword fmt[XBM_LAST];
8940 Lisp_Object data;
6fc2811b
JR
8941 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8942 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
516eea8e 8943 int non_default_colors = 0;
6fc2811b
JR
8944 char *bits;
8945 int parsed_p;
3cf3436e
JR
8946 int in_memory_file_p = 0;
8947
8948 /* See if data looks like an in-memory XBM file. */
8949 data = image_spec_value (img->spec, QCdata, NULL);
8950 in_memory_file_p = xbm_file_p (data);
6fc2811b 8951
217e5be0 8952 /* Parse the image specification. */
6fc2811b
JR
8953 bcopy (xbm_format, fmt, sizeof fmt);
8954 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
8955 xassert (parsed_p);
8956
8957 /* Get specified width, and height. */
3cf3436e
JR
8958 if (!in_memory_file_p)
8959 {
8960 img->width = XFASTINT (fmt[XBM_WIDTH].value);
8961 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
8962 xassert (img->width > 0 && img->height > 0);
8963 }
217e5be0 8964
6fc2811b 8965 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
8966 if (fmt[XBM_FOREGROUND].count
8967 && STRINGP (fmt[XBM_FOREGROUND].value))
516eea8e
JR
8968 {
8969 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
8970 foreground);
8971 non_default_colors = 1;
8972 }
8973
3cf3436e
JR
8974 if (fmt[XBM_BACKGROUND].count
8975 && STRINGP (fmt[XBM_BACKGROUND].value))
516eea8e
JR
8976 {
8977 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
8978 background);
8979 non_default_colors = 1;
8980 }
6fc2811b 8981
3cf3436e 8982 if (in_memory_file_p)
d5db4077
KR
8983 success_p = xbm_load_image (f, img, SDATA (data),
8984 (SDATA (data)
8985 + SBYTES (data)));
3cf3436e 8986 else
6fc2811b 8987 {
3cf3436e
JR
8988 if (VECTORP (data))
8989 {
8990 int i;
8991 char *p;
8992 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
7d0393cf 8993
3cf3436e
JR
8994 p = bits = (char *) alloca (nbytes * img->height);
8995 for (i = 0; i < img->height; ++i, p += nbytes)
8996 {
8997 Lisp_Object line = XVECTOR (data)->contents[i];
8998 if (STRINGP (line))
d5db4077 8999 bcopy (SDATA (line), p, nbytes);
3cf3436e
JR
9000 else
9001 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9002 }
9003 }
9004 else if (STRINGP (data))
d5db4077 9005 bits = SDATA (data);
3cf3436e
JR
9006 else
9007 bits = XBOOL_VECTOR (data)->data;
af3f7be7 9008
3cf3436e 9009 /* Create the pixmap. */
3cf3436e 9010 img->pixmap
af3f7be7
JR
9011 = w32_create_pixmap_from_bitmap_data (img->width, img->height,
9012 bits);
9013
516eea8e
JR
9014 /* If colors were specified, transfer the bitmap to a color one. */
9015 if (non_default_colors)
9016 convert_mono_to_color_image (f, img, foreground, background);
9017
3cf3436e
JR
9018 if (img->pixmap)
9019 success_p = 1;
9020 else
6fc2811b 9021 {
3cf3436e
JR
9022 image_error ("Unable to create pixmap for XBM image `%s'",
9023 img->spec, Qnil);
9024 x_clear_image (f, img);
6fc2811b
JR
9025 }
9026 }
6fc2811b
JR
9027 }
9028
9029 return success_p;
9030}
7d0393cf 9031
6fc2811b
JR
9032
9033\f
9034/***********************************************************************
9035 XPM images
9036 ***********************************************************************/
9037
7d0393cf 9038#if HAVE_XPM
6fc2811b
JR
9039
9040static int xpm_image_p P_ ((Lisp_Object object));
9041static int xpm_load P_ ((struct frame *f, struct image *img));
9042static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9043
c736ffda
JR
9044/* Indicate to xpm.h that we don't have Xlib. */
9045#define FOR_MSW
9046/* simx.h in xpm defines XColor and XImage differently than Emacs. */
9047#define XColor xpm_XColor
9048#define XImage xpm_XImage
9049#define PIXEL_ALREADY_TYPEDEFED
6fc2811b 9050#include "X11/xpm.h"
c736ffda
JR
9051#undef FOR_MSW
9052#undef XColor
9053#undef XImage
9054#undef PIXEL_ALREADY_TYPEDEFED
6fc2811b
JR
9055
9056/* The symbol `xpm' identifying XPM-format images. */
9057
9058Lisp_Object Qxpm;
9059
9060/* Indices of image specification fields in xpm_format, below. */
9061
9062enum xpm_keyword_index
9063{
9064 XPM_TYPE,
9065 XPM_FILE,
9066 XPM_DATA,
9067 XPM_ASCENT,
9068 XPM_MARGIN,
9069 XPM_RELIEF,
9070 XPM_ALGORITHM,
9071 XPM_HEURISTIC_MASK,
a05e2bae 9072 XPM_MASK,
6fc2811b 9073 XPM_COLOR_SYMBOLS,
a05e2bae 9074 XPM_BACKGROUND,
6fc2811b
JR
9075 XPM_LAST
9076};
9077
9078/* Vector of image_keyword structures describing the format
9079 of valid XPM image specifications. */
9080
9081static struct image_keyword xpm_format[XPM_LAST] =
9082{
9083 {":type", IMAGE_SYMBOL_VALUE, 1},
9084 {":file", IMAGE_STRING_VALUE, 0},
9085 {":data", IMAGE_STRING_VALUE, 0},
8f92c555 9086 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 9087 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9088 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9089 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 9090 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
9091 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9092 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9093 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
9094};
9095
197edd35 9096/* Structure describing the image type XPM. */
6fc2811b
JR
9097
9098static struct image_type xpm_type =
9099{
9100 &Qxpm,
9101 xpm_image_p,
9102 xpm_load,
9103 x_clear_image,
9104 NULL
9105};
9106
9107
c736ffda
JR
9108/* XPM library details. */
9109
9110DEF_IMGLIB_FN (XpmFreeAttributes);
9111DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
9112DEF_IMGLIB_FN (XpmReadFileToImage);
9113DEF_IMGLIB_FN (XImageFree);
9114
9115
9116static int
9117init_xpm_functions (library)
9118 HMODULE library;
9119{
9120 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
9121 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
9122 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
9123 LOAD_IMGLIB_FN (library, XImageFree);
9124
9125 return 1;
9126}
9127
6fc2811b
JR
9128/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9129 for XPM images. Such a list must consist of conses whose car and
9130 cdr are strings. */
9131
9132static int
9133xpm_valid_color_symbols_p (color_symbols)
9134 Lisp_Object color_symbols;
9135{
9136 while (CONSP (color_symbols))
9137 {
9138 Lisp_Object sym = XCAR (color_symbols);
9139 if (!CONSP (sym)
9140 || !STRINGP (XCAR (sym))
9141 || !STRINGP (XCDR (sym)))
9142 break;
9143 color_symbols = XCDR (color_symbols);
9144 }
9145
9146 return NILP (color_symbols);
9147}
9148
9149
9150/* Value is non-zero if OBJECT is a valid XPM image specification. */
9151
9152static int
9153xpm_image_p (object)
9154 Lisp_Object object;
9155{
9156 struct image_keyword fmt[XPM_LAST];
9157 bcopy (xpm_format, fmt, sizeof fmt);
9158 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9159 /* Either `:file' or `:data' must be present. */
9160 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9161 /* Either no `:color-symbols' or it's a list of conses
9162 whose car and cdr are strings. */
9163 && (fmt[XPM_COLOR_SYMBOLS].count == 0
8f92c555 9164 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
6fc2811b
JR
9165}
9166
9167
9168/* Load image IMG which will be displayed on frame F. Value is
9169 non-zero if successful. */
9170
9171static int
9172xpm_load (f, img)
9173 struct frame *f;
9174 struct image *img;
9175{
c736ffda
JR
9176 HDC hdc;
9177 int rc;
6fc2811b
JR
9178 XpmAttributes attrs;
9179 Lisp_Object specified_file, color_symbols;
c736ffda 9180 xpm_XImage * xpm_image, * xpm_mask;
6fc2811b
JR
9181
9182 /* Configure the XPM lib. Use the visual of frame F. Allocate
9183 close colors. Return colors allocated. */
9184 bzero (&attrs, sizeof attrs);
c736ffda
JR
9185 xpm_image = xpm_mask = NULL;
9186
9187#if 0
dfff8a69
JR
9188 attrs.visual = FRAME_X_VISUAL (f);
9189 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 9190 attrs.valuemask |= XpmVisual;
dfff8a69 9191 attrs.valuemask |= XpmColormap;
c736ffda 9192#endif
6fc2811b 9193 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 9194#ifdef XpmAllocCloseColors
6fc2811b
JR
9195 attrs.alloc_close_colors = 1;
9196 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
9197#else
9198 attrs.closeness = 600;
9199 attrs.valuemask |= XpmCloseness;
9200#endif
6fc2811b
JR
9201
9202 /* If image specification contains symbolic color definitions, add
9203 these to `attrs'. */
9204 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9205 if (CONSP (color_symbols))
9206 {
9207 Lisp_Object tail;
9208 XpmColorSymbol *xpm_syms;
9209 int i, size;
7d0393cf 9210
6fc2811b
JR
9211 attrs.valuemask |= XpmColorSymbols;
9212
9213 /* Count number of symbols. */
9214 attrs.numsymbols = 0;
9215 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9216 ++attrs.numsymbols;
9217
9218 /* Allocate an XpmColorSymbol array. */
9219 size = attrs.numsymbols * sizeof *xpm_syms;
9220 xpm_syms = (XpmColorSymbol *) alloca (size);
9221 bzero (xpm_syms, size);
9222 attrs.colorsymbols = xpm_syms;
9223
9224 /* Fill the color symbol array. */
9225 for (tail = color_symbols, i = 0;
9226 CONSP (tail);
9227 ++i, tail = XCDR (tail))
9228 {
9229 Lisp_Object name = XCAR (XCAR (tail));
9230 Lisp_Object color = XCDR (XCAR (tail));
d5db4077
KR
9231 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
9232 strcpy (xpm_syms[i].name, SDATA (name));
9233 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
9234 strcpy (xpm_syms[i].value, SDATA (color));
6fc2811b
JR
9235 }
9236 }
9237
9238 /* Create a pixmap for the image, either from a file, or from a
9239 string buffer containing data in the same format as an XPM file. */
c736ffda 9240
6fc2811b 9241 specified_file = image_spec_value (img->spec, QCfile, NULL);
177c0ea7 9242
c736ffda
JR
9243 {
9244 HDC frame_dc = get_frame_dc (f);
9245 hdc = CreateCompatibleDC (frame_dc);
9246 release_frame_dc (f, frame_dc);
9247 }
9248
6fc2811b
JR
9249 if (STRINGP (specified_file))
9250 {
9251 Lisp_Object file = x_find_image_file (specified_file);
9252 if (!STRINGP (file))
9253 {
9254 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6fc2811b
JR
9255 return 0;
9256 }
7d0393cf 9257
c736ffda
JR
9258 /* XpmReadFileToPixmap is not available in the Windows port of
9259 libxpm. But XpmReadFileToImage almost does what we want. */
9260 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
9261 &xpm_image, &xpm_mask,
9262 &attrs);
6fc2811b
JR
9263 }
9264 else
9265 {
9266 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
c736ffda
JR
9267 /* XpmCreatePixmapFromBuffer is not available in the Windows port
9268 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
9269 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
9270 &xpm_image, &xpm_mask,
9271 &attrs);
6fc2811b 9272 }
6fc2811b
JR
9273
9274 if (rc == XpmSuccess)
9275 {
c736ffda
JR
9276 int i;
9277
9278 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
9279 plus some duplicate attributes. */
9280 if (xpm_image && xpm_image->bitmap)
9281 {
9282 img->pixmap = xpm_image->bitmap;
9283 /* XImageFree in libXpm frees XImage struct without destroying
9284 the bitmap, which is what we want. */
9285 fn_XImageFree (xpm_image);
9286 }
9287 if (xpm_mask && xpm_mask->bitmap)
177c0ea7 9288 {
c736ffda
JR
9289 /* The mask appears to be inverted compared with what we expect.
9290 TODO: invert our expectations. See other places where we
9291 have to invert bits because our idea of masks is backwards. */
9292 HGDIOBJ old_obj;
9293 old_obj = SelectObject (hdc, xpm_mask->bitmap);
9294
9295 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
9296 SelectObject (hdc, old_obj);
9297
9298 img->mask = xpm_mask->bitmap;
177c0ea7 9299 fn_XImageFree (xpm_mask);
c736ffda
JR
9300 DeleteDC (hdc);
9301 }
9302
9303 DeleteDC (hdc);
9304
6fc2811b
JR
9305 /* Remember allocated colors. */
9306 img->ncolors = attrs.nalloc_pixels;
9307 img->colors = (unsigned long *) xmalloc (img->ncolors
9308 * sizeof *img->colors);
9309 for (i = 0; i < attrs.nalloc_pixels; ++i)
9310 img->colors[i] = attrs.alloc_pixels[i];
9311
9312 img->width = attrs.width;
9313 img->height = attrs.height;
9314 xassert (img->width > 0 && img->height > 0);
9315
9316 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
c736ffda 9317 fn_XpmFreeAttributes (&attrs);
6fc2811b
JR
9318 }
9319 else
9320 {
c736ffda
JR
9321 DeleteDC (hdc);
9322
6fc2811b
JR
9323 switch (rc)
9324 {
9325 case XpmOpenFailed:
9326 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9327 break;
7d0393cf 9328
6fc2811b
JR
9329 case XpmFileInvalid:
9330 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9331 break;
7d0393cf 9332
6fc2811b
JR
9333 case XpmNoMemory:
9334 image_error ("Out of memory (%s)", img->spec, Qnil);
9335 break;
7d0393cf 9336
6fc2811b
JR
9337 case XpmColorFailed:
9338 image_error ("Color allocation error (%s)", img->spec, Qnil);
9339 break;
7d0393cf 9340
6fc2811b
JR
9341 default:
9342 image_error ("Unknown error (%s)", img->spec, Qnil);
9343 break;
9344 }
9345 }
9346
9347 return rc == XpmSuccess;
9348}
9349
9350#endif /* HAVE_XPM != 0 */
9351
9352\f
767b1ff0 9353#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
9354/***********************************************************************
9355 Color table
9356 ***********************************************************************/
9357
9358/* An entry in the color table mapping an RGB color to a pixel color. */
9359
9360struct ct_color
9361{
9362 int r, g, b;
9363 unsigned long pixel;
9364
9365 /* Next in color table collision list. */
9366 struct ct_color *next;
9367};
9368
9369/* The bucket vector size to use. Must be prime. */
9370
9371#define CT_SIZE 101
9372
9373/* Value is a hash of the RGB color given by R, G, and B. */
9374
9375#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9376
9377/* The color hash table. */
9378
9379struct ct_color **ct_table;
9380
9381/* Number of entries in the color table. */
9382
9383int ct_colors_allocated;
9384
9385/* Function prototypes. */
9386
9387static void init_color_table P_ ((void));
9388static void free_color_table P_ ((void));
9389static unsigned long *colors_in_color_table P_ ((int *n));
9390static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9391static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9392
9393
9394/* Initialize the color table. */
9395
9396static void
9397init_color_table ()
9398{
9399 int size = CT_SIZE * sizeof (*ct_table);
9400 ct_table = (struct ct_color **) xmalloc (size);
9401 bzero (ct_table, size);
9402 ct_colors_allocated = 0;
9403}
9404
9405
9406/* Free memory associated with the color table. */
9407
9408static void
9409free_color_table ()
9410{
9411 int i;
9412 struct ct_color *p, *next;
9413
9414 for (i = 0; i < CT_SIZE; ++i)
9415 for (p = ct_table[i]; p; p = next)
9416 {
9417 next = p->next;
9418 xfree (p);
9419 }
9420
9421 xfree (ct_table);
9422 ct_table = NULL;
9423}
9424
9425
9426/* Value is a pixel color for RGB color R, G, B on frame F. If an
9427 entry for that color already is in the color table, return the
9428 pixel color of that entry. Otherwise, allocate a new color for R,
9429 G, B, and make an entry in the color table. */
9430
9431static unsigned long
9432lookup_rgb_color (f, r, g, b)
9433 struct frame *f;
9434 int r, g, b;
9435{
9436 unsigned hash = CT_HASH_RGB (r, g, b);
9437 int i = hash % CT_SIZE;
9438 struct ct_color *p;
9439
9440 for (p = ct_table[i]; p; p = p->next)
9441 if (p->r == r && p->g == g && p->b == b)
9442 break;
9443
9444 if (p == NULL)
9445 {
9446 COLORREF color;
9447 Colormap cmap;
9448 int rc;
9449
9450 color = PALETTERGB (r, g, b);
9451
9452 ++ct_colors_allocated;
9453
9454 p = (struct ct_color *) xmalloc (sizeof *p);
9455 p->r = r;
9456 p->g = g;
9457 p->b = b;
9458 p->pixel = color;
9459 p->next = ct_table[i];
9460 ct_table[i] = p;
9461 }
9462
9463 return p->pixel;
9464}
9465
9466
9467/* Look up pixel color PIXEL which is used on frame F in the color
9468 table. If not already present, allocate it. Value is PIXEL. */
9469
9470static unsigned long
9471lookup_pixel_color (f, pixel)
9472 struct frame *f;
9473 unsigned long pixel;
9474{
9475 int i = pixel % CT_SIZE;
9476 struct ct_color *p;
9477
9478 for (p = ct_table[i]; p; p = p->next)
9479 if (p->pixel == pixel)
9480 break;
9481
9482 if (p == NULL)
9483 {
9484 XColor color;
9485 Colormap cmap;
9486 int rc;
9487
9488 BLOCK_INPUT;
7d0393cf 9489
6fc2811b
JR
9490 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9491 color.pixel = pixel;
9492 XQueryColor (NULL, cmap, &color);
9493 rc = x_alloc_nearest_color (f, cmap, &color);
9494 UNBLOCK_INPUT;
9495
9496 if (rc)
9497 {
9498 ++ct_colors_allocated;
7d0393cf 9499
6fc2811b
JR
9500 p = (struct ct_color *) xmalloc (sizeof *p);
9501 p->r = color.red;
9502 p->g = color.green;
9503 p->b = color.blue;
9504 p->pixel = pixel;
9505 p->next = ct_table[i];
9506 ct_table[i] = p;
9507 }
9508 else
9509 return FRAME_FOREGROUND_PIXEL (f);
9510 }
9511 return p->pixel;
9512}
9513
9514
9515/* Value is a vector of all pixel colors contained in the color table,
9516 allocated via xmalloc. Set *N to the number of colors. */
9517
9518static unsigned long *
9519colors_in_color_table (n)
9520 int *n;
9521{
9522 int i, j;
9523 struct ct_color *p;
9524 unsigned long *colors;
9525
9526 if (ct_colors_allocated == 0)
9527 {
9528 *n = 0;
9529 colors = NULL;
9530 }
9531 else
9532 {
9533 colors = (unsigned long *) xmalloc (ct_colors_allocated
9534 * sizeof *colors);
9535 *n = ct_colors_allocated;
7d0393cf 9536
6fc2811b
JR
9537 for (i = j = 0; i < CT_SIZE; ++i)
9538 for (p = ct_table[i]; p; p = p->next)
9539 colors[j++] = p->pixel;
9540 }
9541
9542 return colors;
9543}
9544
767b1ff0 9545#endif /* TODO */
6fc2811b
JR
9546
9547\f
9548/***********************************************************************
9549 Algorithms
9550 ***********************************************************************/
3cf3436e
JR
9551static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
9552static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
9553static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
ac849ba4 9554static void XPutPixel (XImage *, int, int, COLORREF);
3cf3436e
JR
9555
9556/* Non-zero means draw a cross on images having `:conversion
9557 disabled'. */
6fc2811b 9558
3cf3436e 9559int cross_disabled_images;
6fc2811b 9560
3cf3436e
JR
9561/* Edge detection matrices for different edge-detection
9562 strategies. */
6fc2811b 9563
3cf3436e
JR
9564static int emboss_matrix[9] = {
9565 /* x - 1 x x + 1 */
9566 2, -1, 0, /* y - 1 */
9567 -1, 0, 1, /* y */
9568 0, 1, -2 /* y + 1 */
9569};
9570
9571static int laplace_matrix[9] = {
9572 /* x - 1 x x + 1 */
9573 1, 0, 0, /* y - 1 */
9574 0, 0, 0, /* y */
9575 0, 0, -1 /* y + 1 */
9576};
9577
9578/* Value is the intensity of the color whose red/green/blue values
9579 are R, G, and B. */
9580
9581#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
9582
9583
9584/* On frame F, return an array of XColor structures describing image
9585 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
9586 non-zero means also fill the red/green/blue members of the XColor
9587 structures. Value is a pointer to the array of XColors structures,
9588 allocated with xmalloc; it must be freed by the caller. */
9589
9590static XColor *
9591x_to_xcolors (f, img, rgb_p)
9592 struct frame *f;
9593 struct image *img;
9594 int rgb_p;
9595{
9596 int x, y;
9597 XColor *colors, *p;
197edd35
JR
9598 HDC hdc, bmpdc;
9599 HGDIOBJ prev;
3cf3436e
JR
9600
9601 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
197edd35
JR
9602
9603 /* Load the image into a memory device context. */
9604 hdc = get_frame_dc (f);
9605 bmpdc = CreateCompatibleDC (hdc);
9606 release_frame_dc (f, hdc);
9607 prev = SelectObject (bmpdc, img->pixmap);
3cf3436e
JR
9608
9609 /* Fill the `pixel' members of the XColor array. I wished there
9610 were an easy and portable way to circumvent XGetPixel. */
9611 p = colors;
9612 for (y = 0; y < img->height; ++y)
9613 {
9614 XColor *row = p;
7d0393cf 9615
3cf3436e 9616 for (x = 0; x < img->width; ++x, ++p)
197edd35
JR
9617 {
9618 /* TODO: palette support needed here? */
9619 p->pixel = GetPixel (bmpdc, x, y);
3cf3436e 9620
197edd35
JR
9621 if (rgb_p)
9622 {
9623 p->red = 256 * GetRValue (p->pixel);
9624 p->green = 256 * GetGValue (p->pixel);
9625 p->blue = 256 * GetBValue (p->pixel);
9626 }
9627 }
3cf3436e
JR
9628 }
9629
197edd35
JR
9630 SelectObject (bmpdc, prev);
9631 DeleteDC (bmpdc);
9632
3cf3436e
JR
9633 return colors;
9634}
9635
ac849ba4
JR
9636/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
9637 created with CreateDIBSection, with the pointer to the bit values
9638 stored in ximg->data. */
9639
9640static void XPutPixel (ximg, x, y, color)
9641 XImage * ximg;
9642 int x, y;
9643 COLORREF color;
9644{
9645 int width = ximg->info.bmiHeader.biWidth;
9646 int height = ximg->info.bmiHeader.biHeight;
ac849ba4
JR
9647 unsigned char * pixel;
9648
54eefef1
JR
9649 /* True color images. */
9650 if (ximg->info.bmiHeader.biBitCount == 24)
9651 {
9652 int rowbytes = width * 3;
9653 /* Ensure scanlines are aligned on 4 byte boundaries. */
9654 if (rowbytes % 4)
9655 rowbytes += 4 - (rowbytes % 4);
9656
9657 pixel = ximg->data + y * rowbytes + x * 3;
9658 /* Windows bitmaps are in BGR order. */
9659 *pixel = GetBValue (color);
9660 *(pixel + 1) = GetGValue (color);
9661 *(pixel + 2) = GetRValue (color);
9662 }
9663 /* Monochrome images. */
9664 else if (ximg->info.bmiHeader.biBitCount == 1)
9665 {
9666 int rowbytes = width / 8;
9667 /* Ensure scanlines are aligned on 4 byte boundaries. */
9668 if (rowbytes % 4)
9669 rowbytes += 4 - (rowbytes % 4);
9670 pixel = ximg->data + y * rowbytes + x / 8;
9671 /* Filter out palette info. */
9672 if (color & 0x00ffffff)
9673 *pixel = *pixel | (1 << x % 8);
9674 else
9675 *pixel = *pixel & ~(1 << x % 8);
9676 }
9677 else
7c402969 9678 image_error ("XPutPixel: palette image not supported", Qnil, Qnil);
ac849ba4
JR
9679}
9680
3cf3436e
JR
9681/* Create IMG->pixmap from an array COLORS of XColor structures, whose
9682 RGB members are set. F is the frame on which this all happens.
9683 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
9684
9685static void
3cf3436e 9686x_from_xcolors (f, img, colors)
6fc2811b 9687 struct frame *f;
3cf3436e 9688 struct image *img;
6fc2811b 9689 XColor *colors;
6fc2811b 9690{
3cf3436e
JR
9691 int x, y;
9692 XImage *oimg;
9693 Pixmap pixmap;
9694 XColor *p;
ac849ba4 9695#if 0 /* TODO: color tables. */
3cf3436e 9696 init_color_table ();
ac849ba4 9697#endif
3cf3436e
JR
9698 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9699 &oimg, &pixmap);
9700 p = colors;
9701 for (y = 0; y < img->height; ++y)
9702 for (x = 0; x < img->width; ++x, ++p)
9703 {
9704 unsigned long pixel;
ac849ba4 9705#if 0 /* TODO: color tables. */
3cf3436e 9706 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
ac849ba4 9707#else
197edd35 9708 pixel = PALETTERGB (p->red / 256, p->green / 256, p->blue / 256);
ac849ba4 9709#endif
3cf3436e
JR
9710 XPutPixel (oimg, x, y, pixel);
9711 }
6fc2811b 9712
3cf3436e
JR
9713 xfree (colors);
9714 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 9715
3cf3436e
JR
9716 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9717 x_destroy_x_image (oimg);
9718 img->pixmap = pixmap;
ac849ba4 9719#if 0 /* TODO: color tables. */
3cf3436e
JR
9720 img->colors = colors_in_color_table (&img->ncolors);
9721 free_color_table ();
ac849ba4 9722#endif
6fc2811b
JR
9723}
9724
9725
3cf3436e
JR
9726/* On frame F, perform edge-detection on image IMG.
9727
9728 MATRIX is a nine-element array specifying the transformation
9729 matrix. See emboss_matrix for an example.
7d0393cf 9730
3cf3436e
JR
9731 COLOR_ADJUST is a color adjustment added to each pixel of the
9732 outgoing image. */
6fc2811b
JR
9733
9734static void
3cf3436e 9735x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 9736 struct frame *f;
3cf3436e
JR
9737 struct image *img;
9738 int matrix[9], color_adjust;
6fc2811b 9739{
3cf3436e
JR
9740 XColor *colors = x_to_xcolors (f, img, 1);
9741 XColor *new, *p;
9742 int x, y, i, sum;
9743
9744 for (i = sum = 0; i < 9; ++i)
9745 sum += abs (matrix[i]);
9746
9747#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
9748
9749 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
9750
9751 for (y = 0; y < img->height; ++y)
9752 {
9753 p = COLOR (new, 0, y);
9754 p->red = p->green = p->blue = 0xffff/2;
9755 p = COLOR (new, img->width - 1, y);
9756 p->red = p->green = p->blue = 0xffff/2;
9757 }
7d0393cf 9758
3cf3436e
JR
9759 for (x = 1; x < img->width - 1; ++x)
9760 {
9761 p = COLOR (new, x, 0);
9762 p->red = p->green = p->blue = 0xffff/2;
9763 p = COLOR (new, x, img->height - 1);
9764 p->red = p->green = p->blue = 0xffff/2;
9765 }
9766
9767 for (y = 1; y < img->height - 1; ++y)
9768 {
9769 p = COLOR (new, 1, y);
7d0393cf 9770
3cf3436e
JR
9771 for (x = 1; x < img->width - 1; ++x, ++p)
9772 {
9773 int r, g, b, y1, x1;
9774
9775 r = g = b = i = 0;
9776 for (y1 = y - 1; y1 < y + 2; ++y1)
9777 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
9778 if (matrix[i])
9779 {
9780 XColor *t = COLOR (colors, x1, y1);
9781 r += matrix[i] * t->red;
9782 g += matrix[i] * t->green;
9783 b += matrix[i] * t->blue;
9784 }
9785
9786 r = (r / sum + color_adjust) & 0xffff;
9787 g = (g / sum + color_adjust) & 0xffff;
9788 b = (b / sum + color_adjust) & 0xffff;
9789 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
9790 }
9791 }
9792
9793 xfree (colors);
9794 x_from_xcolors (f, img, new);
9795
9796#undef COLOR
9797}
9798
9799
9800/* Perform the pre-defined `emboss' edge-detection on image IMG
9801 on frame F. */
9802
9803static void
9804x_emboss (f, img)
9805 struct frame *f;
9806 struct image *img;
9807{
9808 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 9809}
3cf3436e 9810
6fc2811b
JR
9811
9812/* Transform image IMG which is used on frame F with a Laplace
9813 edge-detection algorithm. The result is an image that can be used
9814 to draw disabled buttons, for example. */
9815
9816static void
9817x_laplace (f, img)
9818 struct frame *f;
9819 struct image *img;
9820{
3cf3436e
JR
9821 x_detect_edges (f, img, laplace_matrix, 45000);
9822}
6fc2811b 9823
6fc2811b 9824
3cf3436e
JR
9825/* Perform edge-detection on image IMG on frame F, with specified
9826 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 9827
3cf3436e 9828 MATRIX must be either
6fc2811b 9829
3cf3436e
JR
9830 - a list of at least 9 numbers in row-major form
9831 - a vector of at least 9 numbers
6fc2811b 9832
3cf3436e
JR
9833 COLOR_ADJUST nil means use a default; otherwise it must be a
9834 number. */
6fc2811b 9835
3cf3436e
JR
9836static void
9837x_edge_detection (f, img, matrix, color_adjust)
9838 struct frame *f;
9839 struct image *img;
9840 Lisp_Object matrix, color_adjust;
9841{
9842 int i = 0;
9843 int trans[9];
7d0393cf 9844
3cf3436e 9845 if (CONSP (matrix))
6fc2811b 9846 {
3cf3436e
JR
9847 for (i = 0;
9848 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
9849 ++i, matrix = XCDR (matrix))
9850 trans[i] = XFLOATINT (XCAR (matrix));
9851 }
9852 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
9853 {
9854 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
9855 trans[i] = XFLOATINT (AREF (matrix, i));
9856 }
9857
9858 if (NILP (color_adjust))
9859 color_adjust = make_number (0xffff / 2);
9860
9861 if (i == 9 && NUMBERP (color_adjust))
9862 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
9863}
9864
6fc2811b 9865
3cf3436e 9866/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 9867
3cf3436e
JR
9868static void
9869x_disable_image (f, img)
9870 struct frame *f;
9871 struct image *img;
9872{
ac849ba4 9873 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3cf3436e 9874
ac849ba4 9875 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
3cf3436e
JR
9876 {
9877 /* Color (or grayscale). Convert to gray, and equalize. Just
9878 drawing such images with a stipple can look very odd, so
9879 we're using this method instead. */
9880 XColor *colors = x_to_xcolors (f, img, 1);
9881 XColor *p, *end;
9882 const int h = 15000;
9883 const int l = 30000;
9884
9885 for (p = colors, end = colors + img->width * img->height;
9886 p < end;
9887 ++p)
6fc2811b 9888 {
3cf3436e
JR
9889 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
9890 int i2 = (0xffff - h - l) * i / 0xffff + l;
9891 p->red = p->green = p->blue = i2;
6fc2811b
JR
9892 }
9893
3cf3436e 9894 x_from_xcolors (f, img, colors);
6fc2811b
JR
9895 }
9896
3cf3436e
JR
9897 /* Draw a cross over the disabled image, if we must or if we
9898 should. */
ac849ba4 9899 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
3cf3436e 9900 {
197edd35
JR
9901 HDC hdc, bmpdc;
9902 HGDIOBJ prev;
9903
9904 hdc = get_frame_dc (f);
9905 bmpdc = CreateCompatibleDC (hdc);
9906 release_frame_dc (f, hdc);
9907
9908 prev = SelectObject (bmpdc, img->pixmap);
6fc2811b 9909
197edd35
JR
9910 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
9911 MoveToEx (bmpdc, 0, 0, NULL);
9912 LineTo (bmpdc, img->width - 1, img->height - 1);
9913 MoveToEx (bmpdc, 0, img->height - 1, NULL);
9914 LineTo (bmpdc, img->width - 1, 0);
6fc2811b 9915
3cf3436e
JR
9916 if (img->mask)
9917 {
197edd35
JR
9918 SelectObject (bmpdc, img->mask);
9919 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
9920 MoveToEx (bmpdc, 0, 0, NULL);
9921 LineTo (bmpdc, img->width - 1, img->height - 1);
9922 MoveToEx (bmpdc, 0, img->height - 1, NULL);
9923 LineTo (bmpdc, img->width - 1, 0);
3cf3436e 9924 }
197edd35
JR
9925 SelectObject (bmpdc, prev);
9926 DeleteDC (bmpdc);
3cf3436e 9927 }
6fc2811b
JR
9928}
9929
9930
9931/* Build a mask for image IMG which is used on frame F. FILE is the
9932 name of an image file, for error messages. HOW determines how to
9933 determine the background color of IMG. If it is a list '(R G B)',
9934 with R, G, and B being integers >= 0, take that as the color of the
9935 background. Otherwise, determine the background color of IMG
9936 heuristically. Value is non-zero if successful. */
9937
9938static int
9939x_build_heuristic_mask (f, img, how)
9940 struct frame *f;
9941 struct image *img;
9942 Lisp_Object how;
9943{
197edd35
JR
9944 HDC img_dc, frame_dc;
9945 HGDIOBJ prev;
9946 char *mask_img;
a05e2bae
JR
9947 int x, y, rc, use_img_background;
9948 unsigned long bg = 0;
197edd35 9949 int row_width;
a05e2bae
JR
9950
9951 if (img->mask)
9952 {
197edd35
JR
9953 DeleteObject (img->mask);
9954 img->mask = NULL;
a05e2bae
JR
9955 img->background_transparent_valid = 0;
9956 }
6fc2811b 9957
197edd35
JR
9958 /* Create the bit array serving as mask. */
9959 row_width = (img->width + 7) / 8;
9960 mask_img = xmalloc (row_width * img->height);
9961 bzero (mask_img, row_width * img->height);
6fc2811b 9962
197edd35
JR
9963 /* Create a memory device context for IMG->pixmap. */
9964 frame_dc = get_frame_dc (f);
9965 img_dc = CreateCompatibleDC (frame_dc);
9966 release_frame_dc (f, frame_dc);
9967 prev = SelectObject (img_dc, img->pixmap);
6fc2811b 9968
197edd35 9969 /* Determine the background color of img_dc. If HOW is `(R G B)'
a05e2bae
JR
9970 take that as color. Otherwise, use the image's background color. */
9971 use_img_background = 1;
7d0393cf 9972
6fc2811b
JR
9973 if (CONSP (how))
9974 {
a05e2bae 9975 int rgb[3], i;
6fc2811b 9976
a05e2bae 9977 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
9978 {
9979 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9980 how = XCDR (how);
9981 }
9982
9983 if (i == 3 && NILP (how))
9984 {
9985 char color_name[30];
6fc2811b 9986 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
0040b876 9987 bg = x_alloc_image_color (f, img, build_string (color_name), 0)
8f92c555 9988 & 0x00ffffff; /* Filter out palette info. */
a05e2bae 9989 use_img_background = 0;
6fc2811b
JR
9990 }
9991 }
7d0393cf 9992
a05e2bae 9993 if (use_img_background)
197edd35 9994 bg = four_corners_best (img_dc, img->width, img->height);
6fc2811b
JR
9995
9996 /* Set all bits in mask_img to 1 whose color in ximg is different
9997 from the background color bg. */
9998 for (y = 0; y < img->height; ++y)
9999 for (x = 0; x < img->width; ++x)
197edd35
JR
10000 {
10001 COLORREF p = GetPixel (img_dc, x, y);
10002 if (p != bg)
10003 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
10004 }
10005
10006 /* Create the mask image. */
10007 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
10008 mask_img);
6fc2811b 10009
a05e2bae 10010 /* Fill in the background_transparent field while we have the mask handy. */
197edd35
JR
10011 SelectObject (img_dc, img->mask);
10012
10013 image_background_transparent (img, f, img_dc);
a05e2bae 10014
6fc2811b 10015 /* Put mask_img into img->mask. */
54eefef1 10016 x_destroy_x_image ((XImage *)mask_img);
197edd35
JR
10017 SelectObject (img_dc, prev);
10018 DeleteDC (img_dc);
6fc2811b
JR
10019
10020 return 1;
10021}
217e5be0 10022
6fc2811b
JR
10023\f
10024/***********************************************************************
10025 PBM (mono, gray, color)
10026 ***********************************************************************/
6fc2811b
JR
10027
10028static int pbm_image_p P_ ((Lisp_Object object));
10029static int pbm_load P_ ((struct frame *f, struct image *img));
10030static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10031
10032/* The symbol `pbm' identifying images of this type. */
10033
10034Lisp_Object Qpbm;
10035
10036/* Indices of image specification fields in gs_format, below. */
10037
10038enum pbm_keyword_index
10039{
10040 PBM_TYPE,
10041 PBM_FILE,
10042 PBM_DATA,
10043 PBM_ASCENT,
10044 PBM_MARGIN,
10045 PBM_RELIEF,
10046 PBM_ALGORITHM,
10047 PBM_HEURISTIC_MASK,
a05e2bae
JR
10048 PBM_MASK,
10049 PBM_FOREGROUND,
10050 PBM_BACKGROUND,
6fc2811b
JR
10051 PBM_LAST
10052};
10053
10054/* Vector of image_keyword structures describing the format
10055 of valid user-defined image specifications. */
10056
10057static struct image_keyword pbm_format[PBM_LAST] =
10058{
10059 {":type", IMAGE_SYMBOL_VALUE, 1},
10060 {":file", IMAGE_STRING_VALUE, 0},
10061 {":data", IMAGE_STRING_VALUE, 0},
8f92c555 10062 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 10063 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10064 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10065 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
10066 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10067 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10068 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10069 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10070};
10071
10072/* Structure describing the image type `pbm'. */
10073
10074static struct image_type pbm_type =
10075{
10076 &Qpbm,
10077 pbm_image_p,
10078 pbm_load,
10079 x_clear_image,
10080 NULL
10081};
10082
10083
10084/* Return non-zero if OBJECT is a valid PBM image specification. */
10085
10086static int
10087pbm_image_p (object)
10088 Lisp_Object object;
10089{
10090 struct image_keyword fmt[PBM_LAST];
7d0393cf 10091
6fc2811b 10092 bcopy (pbm_format, fmt, sizeof fmt);
7d0393cf 10093
8f92c555 10094 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
6fc2811b
JR
10095 return 0;
10096
10097 /* Must specify either :data or :file. */
10098 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10099}
10100
10101
10102/* Scan a decimal number from *S and return it. Advance *S while
10103 reading the number. END is the end of the string. Value is -1 at
10104 end of input. */
10105
10106static int
10107pbm_scan_number (s, end)
10108 unsigned char **s, *end;
10109{
10110 int c, val = -1;
10111
10112 while (*s < end)
10113 {
10114 /* Skip white-space. */
10115 while (*s < end && (c = *(*s)++, isspace (c)))
10116 ;
10117
10118 if (c == '#')
10119 {
10120 /* Skip comment to end of line. */
10121 while (*s < end && (c = *(*s)++, c != '\n'))
10122 ;
10123 }
10124 else if (isdigit (c))
10125 {
10126 /* Read decimal number. */
10127 val = c - '0';
10128 while (*s < end && (c = *(*s)++, isdigit (c)))
10129 val = 10 * val + c - '0';
10130 break;
10131 }
10132 else
10133 break;
10134 }
10135
10136 return val;
10137}
10138
10139
10140/* Read FILE into memory. Value is a pointer to a buffer allocated
10141 with xmalloc holding FILE's contents. Value is null if an error
6f826971 10142 occurred. *SIZE is set to the size of the file. */
6fc2811b
JR
10143
10144static char *
10145pbm_read_file (file, size)
10146 Lisp_Object file;
10147 int *size;
10148{
10149 FILE *fp = NULL;
10150 char *buf = NULL;
10151 struct stat st;
10152
d5db4077 10153 if (stat (SDATA (file), &st) == 0
c45bb3b2 10154 && (fp = fopen (SDATA (file), "rb")) != NULL
6fc2811b
JR
10155 && (buf = (char *) xmalloc (st.st_size),
10156 fread (buf, 1, st.st_size, fp) == st.st_size))
10157 {
10158 *size = st.st_size;
10159 fclose (fp);
10160 }
10161 else
10162 {
10163 if (fp)
10164 fclose (fp);
10165 if (buf)
10166 {
10167 xfree (buf);
10168 buf = NULL;
10169 }
10170 }
7d0393cf 10171
6fc2811b
JR
10172 return buf;
10173}
10174
10175
10176/* Load PBM image IMG for use on frame F. */
10177
7d0393cf 10178static int
6fc2811b
JR
10179pbm_load (f, img)
10180 struct frame *f;
10181 struct image *img;
10182{
10183 int raw_p, x, y;
10184 int width, height, max_color_idx = 0;
10185 XImage *ximg;
10186 Lisp_Object file, specified_file;
10187 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10188 struct gcpro gcpro1;
10189 unsigned char *contents = NULL;
10190 unsigned char *end, *p;
10191 int size;
10192
10193 specified_file = image_spec_value (img->spec, QCfile, NULL);
10194 file = Qnil;
10195 GCPRO1 (file);
10196
10197 if (STRINGP (specified_file))
10198 {
10199 file = x_find_image_file (specified_file);
10200 if (!STRINGP (file))
10201 {
10202 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10203 UNGCPRO;
10204 return 0;
10205 }
10206
d5db4077 10207 contents = slurp_file (SDATA (file), &size);
6fc2811b
JR
10208 if (contents == NULL)
10209 {
10210 image_error ("Error reading `%s'", file, Qnil);
10211 UNGCPRO;
10212 return 0;
10213 }
10214
10215 p = contents;
10216 end = contents + size;
10217 }
10218 else
10219 {
10220 Lisp_Object data;
10221 data = image_spec_value (img->spec, QCdata, NULL);
d5db4077
KR
10222 p = SDATA (data);
10223 end = p + SBYTES (data);
6fc2811b
JR
10224 }
10225
10226 /* Check magic number. */
10227 if (end - p < 2 || *p++ != 'P')
10228 {
10229 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10230 error:
10231 xfree (contents);
10232 UNGCPRO;
10233 return 0;
10234 }
10235
6fc2811b
JR
10236 switch (*p++)
10237 {
10238 case '1':
10239 raw_p = 0, type = PBM_MONO;
10240 break;
7d0393cf 10241
6fc2811b
JR
10242 case '2':
10243 raw_p = 0, type = PBM_GRAY;
10244 break;
10245
10246 case '3':
10247 raw_p = 0, type = PBM_COLOR;
10248 break;
10249
10250 case '4':
10251 raw_p = 1, type = PBM_MONO;
10252 break;
7d0393cf 10253
6fc2811b
JR
10254 case '5':
10255 raw_p = 1, type = PBM_GRAY;
10256 break;
7d0393cf 10257
6fc2811b
JR
10258 case '6':
10259 raw_p = 1, type = PBM_COLOR;
10260 break;
10261
10262 default:
10263 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10264 goto error;
10265 }
10266
10267 /* Read width, height, maximum color-component. Characters
10268 starting with `#' up to the end of a line are ignored. */
10269 width = pbm_scan_number (&p, end);
10270 height = pbm_scan_number (&p, end);
10271
10272 if (type != PBM_MONO)
10273 {
10274 max_color_idx = pbm_scan_number (&p, end);
10275 if (raw_p && max_color_idx > 255)
10276 max_color_idx = 255;
10277 }
7d0393cf 10278
6fc2811b
JR
10279 if (width < 0
10280 || height < 0
10281 || (type != PBM_MONO && max_color_idx < 0))
10282 goto error;
10283
ac849ba4 10284 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
3cf3436e
JR
10285 goto error;
10286
ac849ba4 10287#if 0 /* TODO: color tables. */
6fc2811b
JR
10288 /* Initialize the color hash table. */
10289 init_color_table ();
ac849ba4 10290#endif
6fc2811b
JR
10291
10292 if (type == PBM_MONO)
10293 {
10294 int c = 0, g;
3cf3436e
JR
10295 struct image_keyword fmt[PBM_LAST];
10296 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
10297 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
10298
10299 /* Parse the image specification. */
10300 bcopy (pbm_format, fmt, sizeof fmt);
10301 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
7d0393cf 10302
3cf3436e
JR
10303 /* Get foreground and background colors, maybe allocate colors. */
10304 if (fmt[PBM_FOREGROUND].count
10305 && STRINGP (fmt[PBM_FOREGROUND].value))
10306 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
10307 if (fmt[PBM_BACKGROUND].count
10308 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
10309 {
10310 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
10311 img->background = bg;
10312 img->background_valid = 1;
10313 }
10314
6fc2811b
JR
10315 for (y = 0; y < height; ++y)
10316 for (x = 0; x < width; ++x)
10317 {
10318 if (raw_p)
10319 {
10320 if ((x & 7) == 0)
10321 c = *p++;
10322 g = c & 0x80;
10323 c <<= 1;
10324 }
10325 else
10326 g = pbm_scan_number (&p, end);
10327
3cf3436e 10328 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
10329 }
10330 }
10331 else
10332 {
10333 for (y = 0; y < height; ++y)
10334 for (x = 0; x < width; ++x)
10335 {
10336 int r, g, b;
7d0393cf 10337
6fc2811b
JR
10338 if (type == PBM_GRAY)
10339 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10340 else if (raw_p)
10341 {
10342 r = *p++;
10343 g = *p++;
10344 b = *p++;
10345 }
10346 else
10347 {
10348 r = pbm_scan_number (&p, end);
10349 g = pbm_scan_number (&p, end);
10350 b = pbm_scan_number (&p, end);
10351 }
7d0393cf 10352
6fc2811b
JR
10353 if (r < 0 || g < 0 || b < 0)
10354 {
ac849ba4 10355 x_destroy_x_image (ximg);
6fc2811b
JR
10356 image_error ("Invalid pixel value in image `%s'",
10357 img->spec, Qnil);
10358 goto error;
10359 }
7d0393cf 10360
6fc2811b 10361 /* RGB values are now in the range 0..max_color_idx.
ac849ba4
JR
10362 Scale this to the range 0..0xff supported by W32. */
10363 r = (int) ((double) r * 255 / max_color_idx);
10364 g = (int) ((double) g * 255 / max_color_idx);
10365 b = (int) ((double) b * 255 / max_color_idx);
10366 XPutPixel (ximg, x, y,
10367#if 0 /* TODO: color tables. */
10368 lookup_rgb_color (f, r, g, b));
10369#else
10370 PALETTERGB (r, g, b));
10371#endif
6fc2811b
JR
10372 }
10373 }
ac849ba4
JR
10374
10375#if 0 /* TODO: color tables. */
6fc2811b
JR
10376 /* Store in IMG->colors the colors allocated for the image, and
10377 free the color table. */
10378 img->colors = colors_in_color_table (&img->ncolors);
10379 free_color_table ();
ac849ba4 10380#endif
a05e2bae
JR
10381 /* Maybe fill in the background field while we have ximg handy. */
10382 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10383 IMAGE_BACKGROUND (img, f, ximg);
7d0393cf 10384
6fc2811b
JR
10385 /* Put the image into a pixmap. */
10386 x_put_x_image (f, ximg, img->pixmap, width, height);
10387 x_destroy_x_image (ximg);
7d0393cf 10388
6fc2811b
JR
10389 img->width = width;
10390 img->height = height;
10391
10392 UNGCPRO;
10393 xfree (contents);
10394 return 1;
10395}
6fc2811b
JR
10396
10397\f
10398/***********************************************************************
10399 PNG
10400 ***********************************************************************/
10401
10402#if HAVE_PNG
10403
10404#include <png.h>
10405
10406/* Function prototypes. */
10407
10408static int png_image_p P_ ((Lisp_Object object));
10409static int png_load P_ ((struct frame *f, struct image *img));
10410
10411/* The symbol `png' identifying images of this type. */
10412
10413Lisp_Object Qpng;
10414
10415/* Indices of image specification fields in png_format, below. */
10416
10417enum png_keyword_index
10418{
10419 PNG_TYPE,
10420 PNG_DATA,
10421 PNG_FILE,
10422 PNG_ASCENT,
10423 PNG_MARGIN,
10424 PNG_RELIEF,
10425 PNG_ALGORITHM,
10426 PNG_HEURISTIC_MASK,
a05e2bae
JR
10427 PNG_MASK,
10428 PNG_BACKGROUND,
6fc2811b
JR
10429 PNG_LAST
10430};
10431
10432/* Vector of image_keyword structures describing the format
10433 of valid user-defined image specifications. */
10434
10435static struct image_keyword png_format[PNG_LAST] =
10436{
10437 {":type", IMAGE_SYMBOL_VALUE, 1},
10438 {":data", IMAGE_STRING_VALUE, 0},
10439 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 10440 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 10441 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10442 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10443 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10444 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10445 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10446 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10447};
10448
10449/* Structure describing the image type `png'. */
10450
10451static struct image_type png_type =
10452{
10453 &Qpng,
10454 png_image_p,
10455 png_load,
10456 x_clear_image,
10457 NULL
10458};
10459
839b1909
JR
10460/* PNG library details. */
10461
10462DEF_IMGLIB_FN (png_get_io_ptr);
10463DEF_IMGLIB_FN (png_check_sig);
10464DEF_IMGLIB_FN (png_create_read_struct);
10465DEF_IMGLIB_FN (png_create_info_struct);
10466DEF_IMGLIB_FN (png_destroy_read_struct);
10467DEF_IMGLIB_FN (png_set_read_fn);
c922a224 10468DEF_IMGLIB_FN (png_init_io);
839b1909
JR
10469DEF_IMGLIB_FN (png_set_sig_bytes);
10470DEF_IMGLIB_FN (png_read_info);
10471DEF_IMGLIB_FN (png_get_IHDR);
10472DEF_IMGLIB_FN (png_get_valid);
10473DEF_IMGLIB_FN (png_set_strip_16);
10474DEF_IMGLIB_FN (png_set_expand);
10475DEF_IMGLIB_FN (png_set_gray_to_rgb);
10476DEF_IMGLIB_FN (png_set_background);
10477DEF_IMGLIB_FN (png_get_bKGD);
10478DEF_IMGLIB_FN (png_read_update_info);
10479DEF_IMGLIB_FN (png_get_channels);
10480DEF_IMGLIB_FN (png_get_rowbytes);
10481DEF_IMGLIB_FN (png_read_image);
10482DEF_IMGLIB_FN (png_read_end);
10483DEF_IMGLIB_FN (png_error);
10484
10485static int
10486init_png_functions (library)
10487 HMODULE library;
10488{
10489 LOAD_IMGLIB_FN (library, png_get_io_ptr);
10490 LOAD_IMGLIB_FN (library, png_check_sig);
10491 LOAD_IMGLIB_FN (library, png_create_read_struct);
10492 LOAD_IMGLIB_FN (library, png_create_info_struct);
10493 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
10494 LOAD_IMGLIB_FN (library, png_set_read_fn);
c922a224 10495 LOAD_IMGLIB_FN (library, png_init_io);
839b1909
JR
10496 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
10497 LOAD_IMGLIB_FN (library, png_read_info);
10498 LOAD_IMGLIB_FN (library, png_get_IHDR);
10499 LOAD_IMGLIB_FN (library, png_get_valid);
10500 LOAD_IMGLIB_FN (library, png_set_strip_16);
10501 LOAD_IMGLIB_FN (library, png_set_expand);
10502 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
10503 LOAD_IMGLIB_FN (library, png_set_background);
10504 LOAD_IMGLIB_FN (library, png_get_bKGD);
10505 LOAD_IMGLIB_FN (library, png_read_update_info);
10506 LOAD_IMGLIB_FN (library, png_get_channels);
10507 LOAD_IMGLIB_FN (library, png_get_rowbytes);
10508 LOAD_IMGLIB_FN (library, png_read_image);
10509 LOAD_IMGLIB_FN (library, png_read_end);
10510 LOAD_IMGLIB_FN (library, png_error);
10511 return 1;
10512}
6fc2811b
JR
10513
10514/* Return non-zero if OBJECT is a valid PNG image specification. */
10515
10516static int
10517png_image_p (object)
10518 Lisp_Object object;
10519{
10520 struct image_keyword fmt[PNG_LAST];
10521 bcopy (png_format, fmt, sizeof fmt);
c922a224 10522
8f92c555 10523 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
6fc2811b
JR
10524 return 0;
10525
10526 /* Must specify either the :data or :file keyword. */
10527 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
10528}
10529
10530
10531/* Error and warning handlers installed when the PNG library
10532 is initialized. */
10533
10534static void
10535my_png_error (png_ptr, msg)
10536 png_struct *png_ptr;
10537 char *msg;
10538{
10539 xassert (png_ptr != NULL);
10540 image_error ("PNG error: %s", build_string (msg), Qnil);
10541 longjmp (png_ptr->jmpbuf, 1);
10542}
10543
10544
10545static void
10546my_png_warning (png_ptr, msg)
10547 png_struct *png_ptr;
10548 char *msg;
10549{
10550 xassert (png_ptr != NULL);
10551 image_error ("PNG warning: %s", build_string (msg), Qnil);
10552}
10553
6fc2811b
JR
10554/* Memory source for PNG decoding. */
10555
10556struct png_memory_storage
10557{
10558 unsigned char *bytes; /* The data */
10559 size_t len; /* How big is it? */
10560 int index; /* Where are we? */
10561};
10562
10563
10564/* Function set as reader function when reading PNG image from memory.
10565 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10566 bytes from the input to DATA. */
10567
10568static void
10569png_read_from_memory (png_ptr, data, length)
10570 png_structp png_ptr;
10571 png_bytep data;
10572 png_size_t length;
10573{
10574 struct png_memory_storage *tbr
839b1909 10575 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
6fc2811b
JR
10576
10577 if (length > tbr->len - tbr->index)
839b1909 10578 fn_png_error (png_ptr, "Read error");
c922a224 10579
6fc2811b
JR
10580 bcopy (tbr->bytes + tbr->index, data, length);
10581 tbr->index = tbr->index + length;
10582}
10583
6fc2811b
JR
10584/* Load PNG image IMG for use on frame F. Value is non-zero if
10585 successful. */
10586
10587static int
10588png_load (f, img)
10589 struct frame *f;
10590 struct image *img;
10591{
10592 Lisp_Object file, specified_file;
10593 Lisp_Object specified_data;
10594 int x, y, i;
10595 XImage *ximg, *mask_img = NULL;
10596 struct gcpro gcpro1;
10597 png_struct *png_ptr = NULL;
10598 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 10599 FILE *volatile fp = NULL;
6fc2811b 10600 png_byte sig[8];
54eefef1
JR
10601 png_byte * volatile pixels = NULL;
10602 png_byte ** volatile rows = NULL;
6fc2811b
JR
10603 png_uint_32 width, height;
10604 int bit_depth, color_type, interlace_type;
10605 png_byte channels;
10606 png_uint_32 row_bytes;
10607 int transparent_p;
6fc2811b
JR
10608 double screen_gamma, image_gamma;
10609 int intent;
10610 struct png_memory_storage tbr; /* Data to be read */
10611
10612 /* Find out what file to load. */
10613 specified_file = image_spec_value (img->spec, QCfile, NULL);
10614 specified_data = image_spec_value (img->spec, QCdata, NULL);
10615 file = Qnil;
10616 GCPRO1 (file);
10617
10618 if (NILP (specified_data))
10619 {
10620 file = x_find_image_file (specified_file);
10621 if (!STRINGP (file))
54eefef1
JR
10622 {
10623 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10624 UNGCPRO;
10625 return 0;
10626 }
6fc2811b
JR
10627
10628 /* Open the image file. */
d5db4077 10629 fp = fopen (SDATA (file), "rb");
6fc2811b 10630 if (!fp)
54eefef1
JR
10631 {
10632 image_error ("Cannot open image file `%s'", file, Qnil);
10633 UNGCPRO;
10634 fclose (fp);
10635 return 0;
10636 }
6fc2811b
JR
10637
10638 /* Check PNG signature. */
10639 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
839b1909 10640 || !fn_png_check_sig (sig, sizeof sig))
54eefef1
JR
10641 {
10642 image_error ("Not a PNG file: `%s'", file, Qnil);
10643 UNGCPRO;
10644 fclose (fp);
10645 return 0;
10646 }
6fc2811b
JR
10647 }
10648 else
10649 {
10650 /* Read from memory. */
d5db4077
KR
10651 tbr.bytes = SDATA (specified_data);
10652 tbr.len = SBYTES (specified_data);
6fc2811b
JR
10653 tbr.index = 0;
10654
10655 /* Check PNG signature. */
10656 if (tbr.len < sizeof sig
839b1909 10657 || !fn_png_check_sig (tbr.bytes, sizeof sig))
6fc2811b
JR
10658 {
10659 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10660 UNGCPRO;
10661 return 0;
10662 }
10663
10664 /* Need to skip past the signature. */
10665 tbr.bytes += sizeof (sig);
10666 }
10667
6fc2811b 10668 /* Initialize read and info structs for PNG lib. */
839b1909
JR
10669 png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10670 my_png_error, my_png_warning);
6fc2811b
JR
10671 if (!png_ptr)
10672 {
10673 if (fp) fclose (fp);
10674 UNGCPRO;
10675 return 0;
10676 }
10677
839b1909 10678 info_ptr = fn_png_create_info_struct (png_ptr);
6fc2811b
JR
10679 if (!info_ptr)
10680 {
839b1909 10681 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
6fc2811b
JR
10682 if (fp) fclose (fp);
10683 UNGCPRO;
10684 return 0;
10685 }
10686
839b1909 10687 end_info = fn_png_create_info_struct (png_ptr);
6fc2811b
JR
10688 if (!end_info)
10689 {
839b1909 10690 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
6fc2811b
JR
10691 if (fp) fclose (fp);
10692 UNGCPRO;
10693 return 0;
10694 }
10695
10696 /* Set error jump-back. We come back here when the PNG library
10697 detects an error. */
10698 if (setjmp (png_ptr->jmpbuf))
10699 {
10700 error:
10701 if (png_ptr)
839b1909 10702 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6fc2811b
JR
10703 xfree (pixels);
10704 xfree (rows);
10705 if (fp) fclose (fp);
10706 UNGCPRO;
10707 return 0;
10708 }
10709
10710 /* Read image info. */
10711 if (!NILP (specified_data))
839b1909 10712 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
6fc2811b 10713 else
839b1909 10714 fn_png_init_io (png_ptr, fp);
6fc2811b 10715
839b1909
JR
10716 fn_png_set_sig_bytes (png_ptr, sizeof sig);
10717 fn_png_read_info (png_ptr, info_ptr);
10718 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10719 &interlace_type, NULL, NULL);
6fc2811b 10720
c922a224 10721 /* If image contains simply transparency data, we prefer to
6fc2811b 10722 construct a clipping mask. */
839b1909 10723 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
6fc2811b
JR
10724 transparent_p = 1;
10725 else
10726 transparent_p = 0;
10727
c922a224 10728 /* This function is easier to write if we only have to handle
6fc2811b
JR
10729 one data format: RGB or RGBA with 8 bits per channel. Let's
10730 transform other formats into that format. */
10731
10732 /* Strip more than 8 bits per channel. */
10733 if (bit_depth == 16)
839b1909 10734 fn_png_set_strip_16 (png_ptr);
6fc2811b
JR
10735
10736 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10737 if available. */
839b1909 10738 fn_png_set_expand (png_ptr);
6fc2811b
JR
10739
10740 /* Convert grayscale images to RGB. */
c922a224 10741 if (color_type == PNG_COLOR_TYPE_GRAY
6fc2811b 10742 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
839b1909 10743 fn_png_set_gray_to_rgb (png_ptr);
6fc2811b 10744
54eefef1 10745 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
6fc2811b 10746
54eefef1 10747#if 0 /* Avoid double gamma correction for PNG images. */
6fc2811b 10748 /* Tell the PNG lib to handle gamma correction for us. */
6fc2811b
JR
10749#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10750 if (png_get_sRGB (png_ptr, info_ptr, &intent))
54eefef1
JR
10751 /* The libpng documentation says this is right in this case. */
10752 png_set_gamma (png_ptr, screen_gamma, 0.45455);
6fc2811b
JR
10753 else
10754#endif
10755 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10756 /* Image contains gamma information. */
10757 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10758 else
54eefef1
JR
10759 /* Use the standard default for the image gamma. */
10760 png_set_gamma (png_ptr, screen_gamma, 0.45455);
10761#endif /* if 0 */
6fc2811b
JR
10762
10763 /* Handle alpha channel by combining the image with a background
10764 color. Do this only if a real alpha channel is supplied. For
10765 simple transparency, we prefer a clipping mask. */
10766 if (!transparent_p)
10767 {
54eefef1 10768 png_color_16 *image_bg;
a05e2bae
JR
10769 Lisp_Object specified_bg
10770 = image_spec_value (img->spec, QCbackground, NULL);
10771
a05e2bae
JR
10772 if (STRINGP (specified_bg))
10773 /* The user specified `:background', use that. */
10774 {
10775 COLORREF color;
d5db4077 10776 if (w32_defined_color (f, SDATA (specified_bg), &color, 0))
a05e2bae
JR
10777 {
10778 png_color_16 user_bg;
10779
10780 bzero (&user_bg, sizeof user_bg);
54eefef1
JR
10781 user_bg.red = 256 * GetRValue (color);
10782 user_bg.green = 256 * GetGValue (color);
10783 user_bg.blue = 256 * GetBValue (color);
6fc2811b 10784
839b1909
JR
10785 fn_png_set_background (png_ptr, &user_bg,
10786 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
a05e2bae
JR
10787 }
10788 }
839b1909 10789 else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
c922a224 10790 /* Image contains a background color with which to
6fc2811b 10791 combine the image. */
839b1909
JR
10792 fn_png_set_background (png_ptr, image_bg,
10793 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
6fc2811b
JR
10794 else
10795 {
10796 /* Image does not contain a background color with which
c922a224 10797 to combine the image data via an alpha channel. Use
6fc2811b 10798 the frame's background instead. */
54eefef1 10799 COLORREF color;
6fc2811b 10800 png_color_16 frame_background;
54eefef1
JR
10801 color = FRAME_BACKGROUND_PIXEL (f);
10802#if 0 /* TODO : Colormap support. */
10803 Colormap cmap;
6fc2811b 10804
a05e2bae 10805 cmap = FRAME_X_COLORMAP (f);
a05e2bae 10806 x_query_color (f, &color);
54eefef1 10807#endif
6fc2811b
JR
10808
10809 bzero (&frame_background, sizeof frame_background);
54eefef1
JR
10810 frame_background.red = 256 * GetRValue (color);
10811 frame_background.green = 256 * GetGValue (color);
10812 frame_background.blue = 256 * GetBValue (color);
6fc2811b 10813
839b1909
JR
10814 fn_png_set_background (png_ptr, &frame_background,
10815 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6fc2811b
JR
10816 }
10817 }
10818
10819 /* Update info structure. */
839b1909 10820 fn_png_read_update_info (png_ptr, info_ptr);
6fc2811b
JR
10821
10822 /* Get number of channels. Valid values are 1 for grayscale images
10823 and images with a palette, 2 for grayscale images with transparency
10824 information (alpha channel), 3 for RGB images, and 4 for RGB
10825 images with alpha channel, i.e. RGBA. If conversions above were
10826 sufficient we should only have 3 or 4 channels here. */
839b1909 10827 channels = fn_png_get_channels (png_ptr, info_ptr);
6fc2811b
JR
10828 xassert (channels == 3 || channels == 4);
10829
10830 /* Number of bytes needed for one row of the image. */
839b1909 10831 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
6fc2811b
JR
10832
10833 /* Allocate memory for the image. */
10834 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10835 rows = (png_byte **) xmalloc (height * sizeof *rows);
10836 for (i = 0; i < height; ++i)
10837 rows[i] = pixels + i * row_bytes;
10838
10839 /* Read the entire image. */
839b1909
JR
10840 fn_png_read_image (png_ptr, rows);
10841 fn_png_read_end (png_ptr, info_ptr);
6fc2811b
JR
10842 if (fp)
10843 {
10844 fclose (fp);
10845 fp = NULL;
10846 }
c922a224 10847
6fc2811b
JR
10848 /* Create the X image and pixmap. */
10849 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10850 &img->pixmap))
a05e2bae 10851 goto error;
c922a224 10852
6fc2811b
JR
10853 /* Create an image and pixmap serving as mask if the PNG image
10854 contains an alpha channel. */
10855 if (channels == 4
10856 && !transparent_p
10857 && !x_create_x_image_and_pixmap (f, width, height, 1,
10858 &mask_img, &img->mask))
10859 {
10860 x_destroy_x_image (ximg);
54eefef1 10861 DeleteObject (img->pixmap);
6fc2811b 10862 img->pixmap = 0;
6fc2811b
JR
10863 goto error;
10864 }
6fc2811b 10865 /* Fill the X image and mask from PNG data. */
54eefef1 10866#if 0 /* TODO: Color tables. */
6fc2811b 10867 init_color_table ();
54eefef1 10868#endif
6fc2811b
JR
10869
10870 for (y = 0; y < height; ++y)
10871 {
10872 png_byte *p = rows[y];
10873
10874 for (x = 0; x < width; ++x)
10875 {
10876 unsigned r, g, b;
10877
54eefef1
JR
10878 r = *p++;
10879 g = *p++;
10880 b = *p++;
10881#if 0 /* TODO: Color tables. */
6fc2811b 10882 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
54eefef1
JR
10883#else
10884 XPutPixel (ximg, x, y, PALETTERGB (r, g, b));
10885#endif
6fc2811b 10886 /* An alpha channel, aka mask channel, associates variable
c922a224
JB
10887 transparency with an image. Where other image formats
10888 support binary transparency---fully transparent or fully
6fc2811b
JR
10889 opaque---PNG allows up to 254 levels of partial transparency.
10890 The PNG library implements partial transparency by combining
10891 the image with a specified background color.
10892
10893 I'm not sure how to handle this here nicely: because the
10894 background on which the image is displayed may change, for
c922a224
JB
10895 real alpha channel support, it would be necessary to create
10896 a new image for each possible background.
6fc2811b
JR
10897
10898 What I'm doing now is that a mask is created if we have
10899 boolean transparency information. Otherwise I'm using
10900 the frame's background color to combine the image with. */
10901
10902 if (channels == 4)
10903 {
10904 if (mask_img)
10905 XPutPixel (mask_img, x, y, *p > 0);
10906 ++p;
10907 }
10908 }
10909 }
10910
a05e2bae
JR
10911 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10912 /* Set IMG's background color from the PNG image, unless the user
10913 overrode it. */
10914 {
10915 png_color_16 *bg;
839b1909 10916 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
a05e2bae 10917 {
54eefef1 10918#if 0 /* TODO: Color tables. */
a05e2bae 10919 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
54eefef1
JR
10920#else
10921 img->background = PALETTERGB (bg->red / 256, bg->green / 256,
10922 bg->blue / 256);
10923#endif
a05e2bae
JR
10924 img->background_valid = 1;
10925 }
10926 }
10927
54eefef1 10928#if 0 /* TODO: Color tables. */
6fc2811b
JR
10929 /* Remember colors allocated for this image. */
10930 img->colors = colors_in_color_table (&img->ncolors);
10931 free_color_table ();
54eefef1 10932#endif
6fc2811b
JR
10933
10934 /* Clean up. */
839b1909 10935 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6fc2811b
JR
10936 xfree (rows);
10937 xfree (pixels);
10938
10939 img->width = width;
10940 img->height = height;
10941
a05e2bae
JR
10942 /* Maybe fill in the background field while we have ximg handy. */
10943 IMAGE_BACKGROUND (img, f, ximg);
10944
6fc2811b
JR
10945 /* Put the image into the pixmap, then free the X image and its buffer. */
10946 x_put_x_image (f, ximg, img->pixmap, width, height);
10947 x_destroy_x_image (ximg);
10948
10949 /* Same for the mask. */
10950 if (mask_img)
10951 {
a05e2bae
JR
10952 /* Fill in the background_transparent field while we have the mask
10953 handy. */
10954 image_background_transparent (img, f, mask_img);
10955
6fc2811b
JR
10956 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10957 x_destroy_x_image (mask_img);
10958 }
10959
6fc2811b
JR
10960 UNGCPRO;
10961 return 1;
10962}
10963
10964#endif /* HAVE_PNG != 0 */
10965
10966
10967\f
10968/***********************************************************************
10969 JPEG
10970 ***********************************************************************/
10971
10972#if HAVE_JPEG
10973
10974/* Work around a warning about HAVE_STDLIB_H being redefined in
10975 jconfig.h. */
10976#ifdef HAVE_STDLIB_H
10977#define HAVE_STDLIB_H_1
10978#undef HAVE_STDLIB_H
10979#endif /* HAVE_STLIB_H */
10980
10981#include <jpeglib.h>
10982#include <jerror.h>
10983#include <setjmp.h>
10984
10985#ifdef HAVE_STLIB_H_1
10986#define HAVE_STDLIB_H 1
10987#endif
10988
10989static int jpeg_image_p P_ ((Lisp_Object object));
10990static int jpeg_load P_ ((struct frame *f, struct image *img));
10991
10992/* The symbol `jpeg' identifying images of this type. */
10993
10994Lisp_Object Qjpeg;
10995
10996/* Indices of image specification fields in gs_format, below. */
10997
10998enum jpeg_keyword_index
10999{
11000 JPEG_TYPE,
11001 JPEG_DATA,
11002 JPEG_FILE,
11003 JPEG_ASCENT,
11004 JPEG_MARGIN,
11005 JPEG_RELIEF,
11006 JPEG_ALGORITHM,
11007 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11008 JPEG_MASK,
11009 JPEG_BACKGROUND,
6fc2811b
JR
11010 JPEG_LAST
11011};
11012
11013/* Vector of image_keyword structures describing the format
11014 of valid user-defined image specifications. */
11015
11016static struct image_keyword jpeg_format[JPEG_LAST] =
11017{
11018 {":type", IMAGE_SYMBOL_VALUE, 1},
11019 {":data", IMAGE_STRING_VALUE, 0},
11020 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 11021 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 11022 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11023 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11024 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11025 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11026 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11027 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11028};
11029
11030/* Structure describing the image type `jpeg'. */
11031
11032static struct image_type jpeg_type =
11033{
11034 &Qjpeg,
11035 jpeg_image_p,
11036 jpeg_load,
11037 x_clear_image,
11038 NULL
11039};
11040
11041
afc390dc
JR
11042/* JPEG library details. */
11043DEF_IMGLIB_FN (jpeg_CreateDecompress);
11044DEF_IMGLIB_FN (jpeg_start_decompress);
11045DEF_IMGLIB_FN (jpeg_finish_decompress);
11046DEF_IMGLIB_FN (jpeg_destroy_decompress);
11047DEF_IMGLIB_FN (jpeg_read_header);
11048DEF_IMGLIB_FN (jpeg_read_scanlines);
11049DEF_IMGLIB_FN (jpeg_stdio_src);
11050DEF_IMGLIB_FN (jpeg_std_error);
11051DEF_IMGLIB_FN (jpeg_resync_to_restart);
11052
11053static int
11054init_jpeg_functions (library)
11055 HMODULE library;
11056{
11057 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
11058 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
11059 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
11060 LOAD_IMGLIB_FN (library, jpeg_read_header);
11061 LOAD_IMGLIB_FN (library, jpeg_stdio_src);
11062 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
11063 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
11064 LOAD_IMGLIB_FN (library, jpeg_std_error);
11065 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
11066 return 1;
11067}
11068
11069/* Wrapper since we can't directly assign the function pointer
11070 to another function pointer that was declared more completely easily. */
11071static boolean
11072jpeg_resync_to_restart_wrapper(cinfo, desired)
11073 j_decompress_ptr cinfo;
11074 int desired;
11075{
11076 return fn_jpeg_resync_to_restart (cinfo, desired);
11077}
11078
11079
6fc2811b
JR
11080/* Return non-zero if OBJECT is a valid JPEG image specification. */
11081
11082static int
11083jpeg_image_p (object)
11084 Lisp_Object object;
11085{
11086 struct image_keyword fmt[JPEG_LAST];
c922a224 11087
6fc2811b 11088 bcopy (jpeg_format, fmt, sizeof fmt);
c922a224 11089
8f92c555 11090 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
6fc2811b
JR
11091 return 0;
11092
11093 /* Must specify either the :data or :file keyword. */
11094 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11095}
11096
11097
11098struct my_jpeg_error_mgr
11099{
11100 struct jpeg_error_mgr pub;
11101 jmp_buf setjmp_buffer;
11102};
11103
afc390dc 11104
6fc2811b
JR
11105static void
11106my_error_exit (cinfo)
11107 j_common_ptr cinfo;
11108{
11109 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11110 longjmp (mgr->setjmp_buffer, 1);
11111}
11112
afc390dc 11113
6fc2811b
JR
11114/* Init source method for JPEG data source manager. Called by
11115 jpeg_read_header() before any data is actually read. See
11116 libjpeg.doc from the JPEG lib distribution. */
11117
11118static void
11119our_init_source (cinfo)
11120 j_decompress_ptr cinfo;
11121{
11122}
11123
11124
11125/* Fill input buffer method for JPEG data source manager. Called
11126 whenever more data is needed. We read the whole image in one step,
11127 so this only adds a fake end of input marker at the end. */
11128
11129static boolean
11130our_fill_input_buffer (cinfo)
11131 j_decompress_ptr cinfo;
11132{
11133 /* Insert a fake EOI marker. */
11134 struct jpeg_source_mgr *src = cinfo->src;
11135 static JOCTET buffer[2];
11136
11137 buffer[0] = (JOCTET) 0xFF;
11138 buffer[1] = (JOCTET) JPEG_EOI;
11139
11140 src->next_input_byte = buffer;
11141 src->bytes_in_buffer = 2;
11142 return TRUE;
11143}
11144
11145
11146/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11147 is the JPEG data source manager. */
11148
11149static void
11150our_skip_input_data (cinfo, num_bytes)
11151 j_decompress_ptr cinfo;
11152 long num_bytes;
11153{
11154 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11155
11156 if (src)
11157 {
11158 if (num_bytes > src->bytes_in_buffer)
11159 ERREXIT (cinfo, JERR_INPUT_EOF);
c922a224 11160
6fc2811b
JR
11161 src->bytes_in_buffer -= num_bytes;
11162 src->next_input_byte += num_bytes;
11163 }
11164}
11165
11166
11167/* Method to terminate data source. Called by
11168 jpeg_finish_decompress() after all data has been processed. */
11169
11170static void
11171our_term_source (cinfo)
11172 j_decompress_ptr cinfo;
11173{
11174}
11175
11176
11177/* Set up the JPEG lib for reading an image from DATA which contains
11178 LEN bytes. CINFO is the decompression info structure created for
11179 reading the image. */
11180
11181static void
11182jpeg_memory_src (cinfo, data, len)
11183 j_decompress_ptr cinfo;
11184 JOCTET *data;
11185 unsigned int len;
11186{
11187 struct jpeg_source_mgr *src;
11188
11189 if (cinfo->src == NULL)
11190 {
11191 /* First time for this JPEG object? */
11192 cinfo->src = (struct jpeg_source_mgr *)
11193 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11194 sizeof (struct jpeg_source_mgr));
11195 src = (struct jpeg_source_mgr *) cinfo->src;
11196 src->next_input_byte = data;
11197 }
c922a224 11198
6fc2811b
JR
11199 src = (struct jpeg_source_mgr *) cinfo->src;
11200 src->init_source = our_init_source;
11201 src->fill_input_buffer = our_fill_input_buffer;
11202 src->skip_input_data = our_skip_input_data;
afc390dc 11203 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
6fc2811b
JR
11204 src->term_source = our_term_source;
11205 src->bytes_in_buffer = len;
11206 src->next_input_byte = data;
11207}
11208
11209
11210/* Load image IMG for use on frame F. Patterned after example.c
11211 from the JPEG lib. */
11212
c922a224 11213static int
6fc2811b
JR
11214jpeg_load (f, img)
11215 struct frame *f;
11216 struct image *img;
11217{
11218 struct jpeg_decompress_struct cinfo;
11219 struct my_jpeg_error_mgr mgr;
11220 Lisp_Object file, specified_file;
11221 Lisp_Object specified_data;
a05e2bae 11222 FILE * volatile fp = NULL;
6fc2811b
JR
11223 JSAMPARRAY buffer;
11224 int row_stride, x, y;
11225 XImage *ximg = NULL;
11226 int rc;
11227 unsigned long *colors;
11228 int width, height;
11229 struct gcpro gcpro1;
11230
11231 /* Open the JPEG file. */
11232 specified_file = image_spec_value (img->spec, QCfile, NULL);
11233 specified_data = image_spec_value (img->spec, QCdata, NULL);
11234 file = Qnil;
11235 GCPRO1 (file);
11236
6fc2811b
JR
11237 if (NILP (specified_data))
11238 {
11239 file = x_find_image_file (specified_file);
11240 if (!STRINGP (file))
afc390dc
JR
11241 {
11242 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11243 UNGCPRO;
11244 return 0;
11245 }
c922a224 11246
c45bb3b2 11247 fp = fopen (SDATA (file), "rb");
6fc2811b 11248 if (fp == NULL)
afc390dc
JR
11249 {
11250 image_error ("Cannot open `%s'", file, Qnil);
11251 UNGCPRO;
11252 return 0;
11253 }
6fc2811b 11254 }
7d0393cf 11255
6fc2811b 11256 /* Customize libjpeg's error handling to call my_error_exit when an
afc390dc
JR
11257 error is detected. This function will perform a longjmp. */
11258 cinfo.err = fn_jpeg_std_error (&mgr.pub);
a05e2bae 11259 mgr.pub.error_exit = my_error_exit;
c922a224 11260
6fc2811b
JR
11261 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
11262 {
11263 if (rc == 1)
11264 {
11265 /* Called from my_error_exit. Display a JPEG error. */
11266 char buffer[JMSG_LENGTH_MAX];
11267 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11268 image_error ("Error reading JPEG image `%s': %s", img->spec,
11269 build_string (buffer));
11270 }
c922a224 11271
6fc2811b
JR
11272 /* Close the input file and destroy the JPEG object. */
11273 if (fp)
afc390dc
JR
11274 fclose ((FILE *) fp);
11275 fn_jpeg_destroy_decompress (&cinfo);
7d0393cf 11276
6fc2811b
JR
11277 /* If we already have an XImage, free that. */
11278 x_destroy_x_image (ximg);
11279
11280 /* Free pixmap and colors. */
11281 x_clear_image (f, img);
c922a224 11282
6fc2811b
JR
11283 UNGCPRO;
11284 return 0;
11285 }
11286
11287 /* Create the JPEG decompression object. Let it read from fp.
afc390dc
JR
11288 Read the JPEG image header. */
11289 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
6fc2811b
JR
11290
11291 if (NILP (specified_data))
afc390dc 11292 fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
6fc2811b 11293 else
d5db4077
KR
11294 jpeg_memory_src (&cinfo, SDATA (specified_data),
11295 SBYTES (specified_data));
6fc2811b 11296
afc390dc 11297 fn_jpeg_read_header (&cinfo, TRUE);
6fc2811b
JR
11298
11299 /* Customize decompression so that color quantization will be used.
afc390dc 11300 Start decompression. */
6fc2811b 11301 cinfo.quantize_colors = TRUE;
afc390dc 11302 fn_jpeg_start_decompress (&cinfo);
6fc2811b
JR
11303 width = img->width = cinfo.output_width;
11304 height = img->height = cinfo.output_height;
11305
6fc2811b 11306 /* Create X image and pixmap. */
afc390dc 11307 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
a05e2bae 11308 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
11309
11310 /* Allocate colors. When color quantization is used,
11311 cinfo.actual_number_of_colors has been set with the number of
11312 colors generated, and cinfo.colormap is a two-dimensional array
11313 of color indices in the range 0..cinfo.actual_number_of_colors.
11314 No more than 255 colors will be generated. */
11315 {
11316 int i, ir, ig, ib;
11317
11318 if (cinfo.out_color_components > 2)
11319 ir = 0, ig = 1, ib = 2;
11320 else if (cinfo.out_color_components > 1)
11321 ir = 0, ig = 1, ib = 0;
11322 else
11323 ir = 0, ig = 0, ib = 0;
11324
afc390dc 11325#if 0 /* TODO: Color tables. */
6fc2811b
JR
11326 /* Use the color table mechanism because it handles colors that
11327 cannot be allocated nicely. Such colors will be replaced with
11328 a default color, and we don't have to care about which colors
11329 can be freed safely, and which can't. */
11330 init_color_table ();
afc390dc 11331#endif
6fc2811b
JR
11332 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11333 * sizeof *colors);
c922a224 11334
6fc2811b
JR
11335 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11336 {
afc390dc
JR
11337 int r = cinfo.colormap[ir][i];
11338 int g = cinfo.colormap[ig][i];
11339 int b = cinfo.colormap[ib][i];
11340#if 0 /* TODO: Color tables. */
6fc2811b 11341 colors[i] = lookup_rgb_color (f, r, g, b);
afc390dc
JR
11342#else
11343 colors[i] = PALETTERGB (r, g, b);
11344#endif
6fc2811b
JR
11345 }
11346
afc390dc 11347#if 0 /* TODO: Color tables. */
6fc2811b
JR
11348 /* Remember those colors actually allocated. */
11349 img->colors = colors_in_color_table (&img->ncolors);
11350 free_color_table ();
afc390dc 11351#endif
6fc2811b
JR
11352 }
11353
11354 /* Read pixels. */
11355 row_stride = width * cinfo.output_components;
11356 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11357 row_stride, 1);
11358 for (y = 0; y < height; ++y)
11359 {
afc390dc 11360 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6fc2811b
JR
11361 for (x = 0; x < cinfo.output_width; ++x)
11362 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11363 }
11364
11365 /* Clean up. */
afc390dc
JR
11366 fn_jpeg_finish_decompress (&cinfo);
11367 fn_jpeg_destroy_decompress (&cinfo);
6fc2811b 11368 if (fp)
afc390dc 11369 fclose ((FILE *) fp);
7d0393cf 11370
a05e2bae
JR
11371 /* Maybe fill in the background field while we have ximg handy. */
11372 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11373 IMAGE_BACKGROUND (img, f, ximg);
c922a224 11374
6fc2811b
JR
11375 /* Put the image into the pixmap. */
11376 x_put_x_image (f, ximg, img->pixmap, width, height);
11377 x_destroy_x_image (ximg);
6fc2811b
JR
11378 UNGCPRO;
11379 return 1;
11380}
11381
11382#endif /* HAVE_JPEG */
11383
11384
11385\f
11386/***********************************************************************
11387 TIFF
11388 ***********************************************************************/
11389
11390#if HAVE_TIFF
11391
11392#include <tiffio.h>
11393
11394static int tiff_image_p P_ ((Lisp_Object object));
11395static int tiff_load P_ ((struct frame *f, struct image *img));
11396
11397/* The symbol `tiff' identifying images of this type. */
11398
11399Lisp_Object Qtiff;
11400
11401/* Indices of image specification fields in tiff_format, below. */
11402
11403enum tiff_keyword_index
11404{
11405 TIFF_TYPE,
11406 TIFF_DATA,
11407 TIFF_FILE,
11408 TIFF_ASCENT,
11409 TIFF_MARGIN,
11410 TIFF_RELIEF,
11411 TIFF_ALGORITHM,
11412 TIFF_HEURISTIC_MASK,
a05e2bae
JR
11413 TIFF_MASK,
11414 TIFF_BACKGROUND,
6fc2811b
JR
11415 TIFF_LAST
11416};
11417
11418/* Vector of image_keyword structures describing the format
11419 of valid user-defined image specifications. */
11420
11421static struct image_keyword tiff_format[TIFF_LAST] =
11422{
11423 {":type", IMAGE_SYMBOL_VALUE, 1},
11424 {":data", IMAGE_STRING_VALUE, 0},
11425 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 11426 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 11427 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11428 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11429 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11430 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11431 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11432 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11433};
11434
11435/* Structure describing the image type `tiff'. */
11436
11437static struct image_type tiff_type =
11438{
11439 &Qtiff,
11440 tiff_image_p,
11441 tiff_load,
11442 x_clear_image,
11443 NULL
11444};
11445
12b918b2
JB
11446/* TIFF library details. */
11447DEF_IMGLIB_FN (TIFFSetErrorHandler);
11448DEF_IMGLIB_FN (TIFFSetWarningHandler);
11449DEF_IMGLIB_FN (TIFFOpen);
11450DEF_IMGLIB_FN (TIFFClientOpen);
11451DEF_IMGLIB_FN (TIFFGetField);
11452DEF_IMGLIB_FN (TIFFReadRGBAImage);
11453DEF_IMGLIB_FN (TIFFClose);
11454
11455static int
11456init_tiff_functions (library)
11457 HMODULE library;
11458{
11459 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
11460 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
11461 LOAD_IMGLIB_FN (library, TIFFOpen);
11462 LOAD_IMGLIB_FN (library, TIFFClientOpen);
11463 LOAD_IMGLIB_FN (library, TIFFGetField);
11464 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
11465 LOAD_IMGLIB_FN (library, TIFFClose);
11466 return 1;
11467}
6fc2811b
JR
11468
11469/* Return non-zero if OBJECT is a valid TIFF image specification. */
11470
11471static int
11472tiff_image_p (object)
11473 Lisp_Object object;
11474{
11475 struct image_keyword fmt[TIFF_LAST];
11476 bcopy (tiff_format, fmt, sizeof fmt);
7d0393cf 11477
8f92c555 11478 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6fc2811b 11479 return 0;
7d0393cf 11480
6fc2811b
JR
11481 /* Must specify either the :data or :file keyword. */
11482 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11483}
11484
11485
11486/* Reading from a memory buffer for TIFF images Based on the PNG
11487 memory source, but we have to provide a lot of extra functions.
11488 Blah.
11489
11490 We really only need to implement read and seek, but I am not
11491 convinced that the TIFF library is smart enough not to destroy
11492 itself if we only hand it the function pointers we need to
11493 override. */
11494
11495typedef struct
11496{
11497 unsigned char *bytes;
11498 size_t len;
11499 int index;
11500}
11501tiff_memory_source;
11502
11503static size_t
11504tiff_read_from_memory (data, buf, size)
11505 thandle_t data;
11506 tdata_t buf;
11507 tsize_t size;
11508{
11509 tiff_memory_source *src = (tiff_memory_source *) data;
11510
11511 if (size > src->len - src->index)
11512 return (size_t) -1;
11513 bcopy (src->bytes + src->index, buf, size);
11514 src->index += size;
11515 return size;
11516}
11517
11518static size_t
11519tiff_write_from_memory (data, buf, size)
11520 thandle_t data;
11521 tdata_t buf;
11522 tsize_t size;
11523{
11524 return (size_t) -1;
11525}
11526
11527static toff_t
11528tiff_seek_in_memory (data, off, whence)
11529 thandle_t data;
11530 toff_t off;
11531 int whence;
11532{
11533 tiff_memory_source *src = (tiff_memory_source *) data;
11534 int idx;
11535
11536 switch (whence)
11537 {
11538 case SEEK_SET: /* Go from beginning of source. */
11539 idx = off;
11540 break;
7d0393cf 11541
6fc2811b
JR
11542 case SEEK_END: /* Go from end of source. */
11543 idx = src->len + off;
11544 break;
7d0393cf 11545
6fc2811b
JR
11546 case SEEK_CUR: /* Go from current position. */
11547 idx = src->index + off;
11548 break;
7d0393cf 11549
6fc2811b
JR
11550 default: /* Invalid `whence'. */
11551 return -1;
11552 }
7d0393cf 11553
6fc2811b
JR
11554 if (idx > src->len || idx < 0)
11555 return -1;
7d0393cf 11556
6fc2811b
JR
11557 src->index = idx;
11558 return src->index;
11559}
11560
11561static int
11562tiff_close_memory (data)
11563 thandle_t data;
11564{
11565 /* NOOP */
11566 return 0;
11567}
11568
11569static int
11570tiff_mmap_memory (data, pbase, psize)
11571 thandle_t data;
11572 tdata_t *pbase;
11573 toff_t *psize;
11574{
11575 /* It is already _IN_ memory. */
11576 return 0;
11577}
11578
11579static void
11580tiff_unmap_memory (data, base, size)
11581 thandle_t data;
11582 tdata_t base;
11583 toff_t size;
11584{
11585 /* We don't need to do this. */
11586}
11587
11588static toff_t
11589tiff_size_of_memory (data)
11590 thandle_t data;
11591{
11592 return ((tiff_memory_source *) data)->len;
11593}
11594
3cf3436e
JR
11595
11596static void
11597tiff_error_handler (title, format, ap)
11598 const char *title, *format;
11599 va_list ap;
11600{
11601 char buf[512];
11602 int len;
7d0393cf 11603
3cf3436e
JR
11604 len = sprintf (buf, "TIFF error: %s ", title);
11605 vsprintf (buf + len, format, ap);
11606 add_to_log (buf, Qnil, Qnil);
11607}
11608
11609
11610static void
11611tiff_warning_handler (title, format, ap)
11612 const char *title, *format;
11613 va_list ap;
11614{
11615 char buf[512];
11616 int len;
7d0393cf 11617
3cf3436e
JR
11618 len = sprintf (buf, "TIFF warning: %s ", title);
11619 vsprintf (buf + len, format, ap);
11620 add_to_log (buf, Qnil, Qnil);
11621}
11622
11623
6fc2811b
JR
11624/* Load TIFF image IMG for use on frame F. Value is non-zero if
11625 successful. */
11626
11627static int
11628tiff_load (f, img)
11629 struct frame *f;
11630 struct image *img;
11631{
11632 Lisp_Object file, specified_file;
11633 Lisp_Object specified_data;
11634 TIFF *tiff;
11635 int width, height, x, y;
11636 uint32 *buf;
11637 int rc;
11638 XImage *ximg;
11639 struct gcpro gcpro1;
11640 tiff_memory_source memsrc;
11641
11642 specified_file = image_spec_value (img->spec, QCfile, NULL);
11643 specified_data = image_spec_value (img->spec, QCdata, NULL);
11644 file = Qnil;
11645 GCPRO1 (file);
11646
12b918b2
JB
11647 fn_TIFFSetErrorHandler (tiff_error_handler);
11648 fn_TIFFSetWarningHandler (tiff_warning_handler);
3cf3436e 11649
6fc2811b
JR
11650 if (NILP (specified_data))
11651 {
11652 /* Read from a file */
11653 file = x_find_image_file (specified_file);
11654 if (!STRINGP (file))
3cf3436e
JR
11655 {
11656 image_error ("Cannot find image file `%s'", file, Qnil);
11657 UNGCPRO;
11658 return 0;
11659 }
7d0393cf 11660
6fc2811b 11661 /* Try to open the image file. */
12b918b2 11662 tiff = fn_TIFFOpen (SDATA (file), "r");
6fc2811b 11663 if (tiff == NULL)
3cf3436e
JR
11664 {
11665 image_error ("Cannot open `%s'", file, Qnil);
11666 UNGCPRO;
11667 return 0;
11668 }
6fc2811b
JR
11669 }
11670 else
11671 {
11672 /* Memory source! */
d5db4077
KR
11673 memsrc.bytes = SDATA (specified_data);
11674 memsrc.len = SBYTES (specified_data);
6fc2811b
JR
11675 memsrc.index = 0;
11676
12b918b2
JB
11677 tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
11678 (TIFFReadWriteProc) tiff_read_from_memory,
11679 (TIFFReadWriteProc) tiff_write_from_memory,
11680 tiff_seek_in_memory,
11681 tiff_close_memory,
11682 tiff_size_of_memory,
11683 tiff_mmap_memory,
11684 tiff_unmap_memory);
6fc2811b
JR
11685
11686 if (!tiff)
11687 {
11688 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
11689 UNGCPRO;
11690 return 0;
11691 }
11692 }
11693
11694 /* Get width and height of the image, and allocate a raster buffer
11695 of width x height 32-bit values. */
12b918b2
JB
11696 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11697 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
6fc2811b 11698 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
7d0393cf 11699
12b918b2
JB
11700 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
11701 fn_TIFFClose (tiff);
6fc2811b
JR
11702 if (!rc)
11703 {
11704 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11705 xfree (buf);
11706 UNGCPRO;
11707 return 0;
11708 }
11709
6fc2811b
JR
11710 /* Create the X image and pixmap. */
11711 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11712 {
6fc2811b
JR
11713 xfree (buf);
11714 UNGCPRO;
11715 return 0;
11716 }
11717
12b918b2 11718#if 0 /* TODO: Color tables. */
6fc2811b
JR
11719 /* Initialize the color table. */
11720 init_color_table ();
12b918b2 11721#endif
6fc2811b
JR
11722
11723 /* Process the pixel raster. Origin is in the lower-left corner. */
11724 for (y = 0; y < height; ++y)
11725 {
11726 uint32 *row = buf + y * width;
7d0393cf 11727
6fc2811b
JR
11728 for (x = 0; x < width; ++x)
11729 {
11730 uint32 abgr = row[x];
12b918b2
JB
11731 int r = TIFFGetR (abgr);
11732 int g = TIFFGetG (abgr);
11733 int b = TIFFGetB (abgr);
11734#if 0 /* TODO: Color tables. */
7d0393cf 11735 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12b918b2
JB
11736#else
11737 XPutPixel (ximg, x, height - 1 - y, PALETTERGB (r, g, b));
11738#endif
6fc2811b
JR
11739 }
11740 }
11741
12b918b2 11742#if 0 /* TODO: Color tables. */
6fc2811b
JR
11743 /* Remember the colors allocated for the image. Free the color table. */
11744 img->colors = colors_in_color_table (&img->ncolors);
11745 free_color_table ();
12b918b2 11746#endif
6fc2811b 11747
a05e2bae
JR
11748 img->width = width;
11749 img->height = height;
11750
11751 /* Maybe fill in the background field while we have ximg handy. */
11752 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11753 IMAGE_BACKGROUND (img, f, ximg);
11754
6fc2811b
JR
11755 /* Put the image into the pixmap, then free the X image and its buffer. */
11756 x_put_x_image (f, ximg, img->pixmap, width, height);
11757 x_destroy_x_image (ximg);
11758 xfree (buf);
6fc2811b
JR
11759
11760 UNGCPRO;
11761 return 1;
11762}
11763
11764#endif /* HAVE_TIFF != 0 */
11765
11766
11767\f
11768/***********************************************************************
11769 GIF
11770 ***********************************************************************/
11771
11772#if HAVE_GIF
11773
1ffb278b 11774#define DrawText gif_DrawText
6fc2811b 11775#include <gif_lib.h>
1ffb278b 11776#undef DrawText
6fc2811b
JR
11777
11778static int gif_image_p P_ ((Lisp_Object object));
11779static int gif_load P_ ((struct frame *f, struct image *img));
11780
11781/* The symbol `gif' identifying images of this type. */
11782
11783Lisp_Object Qgif;
11784
11785/* Indices of image specification fields in gif_format, below. */
11786
11787enum gif_keyword_index
11788{
11789 GIF_TYPE,
11790 GIF_DATA,
11791 GIF_FILE,
11792 GIF_ASCENT,
11793 GIF_MARGIN,
11794 GIF_RELIEF,
11795 GIF_ALGORITHM,
11796 GIF_HEURISTIC_MASK,
a05e2bae 11797 GIF_MASK,
6fc2811b 11798 GIF_IMAGE,
a05e2bae 11799 GIF_BACKGROUND,
6fc2811b
JR
11800 GIF_LAST
11801};
11802
11803/* Vector of image_keyword structures describing the format
11804 of valid user-defined image specifications. */
11805
11806static struct image_keyword gif_format[GIF_LAST] =
11807{
11808 {":type", IMAGE_SYMBOL_VALUE, 1},
11809 {":data", IMAGE_STRING_VALUE, 0},
11810 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 11811 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 11812 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11813 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11814 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 11815 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11816 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11817 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11818 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11819};
11820
11821/* Structure describing the image type `gif'. */
11822
11823static struct image_type gif_type =
11824{
11825 &Qgif,
11826 gif_image_p,
11827 gif_load,
11828 x_clear_image,
11829 NULL
11830};
11831
1ffb278b
JB
11832
11833/* GIF library details. */
11834DEF_IMGLIB_FN (DGifCloseFile);
11835DEF_IMGLIB_FN (DGifSlurp);
11836DEF_IMGLIB_FN (DGifOpen);
11837DEF_IMGLIB_FN (DGifOpenFileName);
11838
11839static int
11840init_gif_functions (library)
11841 HMODULE library;
11842{
11843 LOAD_IMGLIB_FN (library, DGifCloseFile);
11844 LOAD_IMGLIB_FN (library, DGifSlurp);
11845 LOAD_IMGLIB_FN (library, DGifOpen);
11846 LOAD_IMGLIB_FN (library, DGifOpenFileName);
11847 return 1;
11848}
11849
11850
6fc2811b
JR
11851/* Return non-zero if OBJECT is a valid GIF image specification. */
11852
11853static int
11854gif_image_p (object)
11855 Lisp_Object object;
11856{
11857 struct image_keyword fmt[GIF_LAST];
11858 bcopy (gif_format, fmt, sizeof fmt);
7d0393cf 11859
8f92c555 11860 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
6fc2811b 11861 return 0;
7d0393cf 11862
6fc2811b
JR
11863 /* Must specify either the :data or :file keyword. */
11864 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11865}
11866
11867/* Reading a GIF image from memory
11868 Based on the PNG memory stuff to a certain extent. */
11869
11870typedef struct
11871{
11872 unsigned char *bytes;
11873 size_t len;
11874 int index;
11875}
11876gif_memory_source;
11877
11878/* Make the current memory source available to gif_read_from_memory.
11879 It's done this way because not all versions of libungif support
11880 a UserData field in the GifFileType structure. */
11881static gif_memory_source *current_gif_memory_src;
11882
11883static int
11884gif_read_from_memory (file, buf, len)
11885 GifFileType *file;
11886 GifByteType *buf;
11887 int len;
11888{
11889 gif_memory_source *src = current_gif_memory_src;
11890
11891 if (len > src->len - src->index)
11892 return -1;
11893
11894 bcopy (src->bytes + src->index, buf, len);
11895 src->index += len;
11896 return len;
11897}
11898
11899
11900/* Load GIF image IMG for use on frame F. Value is non-zero if
11901 successful. */
11902
11903static int
11904gif_load (f, img)
11905 struct frame *f;
11906 struct image *img;
11907{
11908 Lisp_Object file, specified_file;
11909 Lisp_Object specified_data;
11910 int rc, width, height, x, y, i;
11911 XImage *ximg;
11912 ColorMapObject *gif_color_map;
11913 unsigned long pixel_colors[256];
11914 GifFileType *gif;
11915 struct gcpro gcpro1;
11916 Lisp_Object image;
11917 int ino, image_left, image_top, image_width, image_height;
11918 gif_memory_source memsrc;
11919 unsigned char *raster;
11920
11921 specified_file = image_spec_value (img->spec, QCfile, NULL);
11922 specified_data = image_spec_value (img->spec, QCdata, NULL);
11923 file = Qnil;
dfff8a69 11924 GCPRO1 (file);
6fc2811b
JR
11925
11926 if (NILP (specified_data))
11927 {
11928 file = x_find_image_file (specified_file);
6fc2811b
JR
11929 if (!STRINGP (file))
11930 {
11931 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11932 UNGCPRO;
11933 return 0;
11934 }
7d0393cf 11935
6fc2811b 11936 /* Open the GIF file. */
1ffb278b 11937 gif = fn_DGifOpenFileName (SDATA (file));
6fc2811b
JR
11938 if (gif == NULL)
11939 {
11940 image_error ("Cannot open `%s'", file, Qnil);
11941 UNGCPRO;
11942 return 0;
11943 }
11944 }
11945 else
11946 {
11947 /* Read from memory! */
11948 current_gif_memory_src = &memsrc;
d5db4077
KR
11949 memsrc.bytes = SDATA (specified_data);
11950 memsrc.len = SBYTES (specified_data);
6fc2811b
JR
11951 memsrc.index = 0;
11952
1ffb278b 11953 gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
6fc2811b
JR
11954 if (!gif)
11955 {
11956 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11957 UNGCPRO;
11958 return 0;
11959 }
11960 }
11961
11962 /* Read entire contents. */
1ffb278b 11963 rc = fn_DGifSlurp (gif);
6fc2811b
JR
11964 if (rc == GIF_ERROR)
11965 {
11966 image_error ("Error reading `%s'", img->spec, Qnil);
1ffb278b 11967 fn_DGifCloseFile (gif);
6fc2811b
JR
11968 UNGCPRO;
11969 return 0;
11970 }
11971
11972 image = image_spec_value (img->spec, QCindex, NULL);
11973 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11974 if (ino >= gif->ImageCount)
11975 {
11976 image_error ("Invalid image number `%s' in image `%s'",
11977 image, img->spec);
1ffb278b 11978 fn_DGifCloseFile (gif);
6fc2811b
JR
11979 UNGCPRO;
11980 return 0;
11981 }
11982
1ffb278b
JB
11983 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
11984 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
6fc2811b 11985
6fc2811b
JR
11986 /* Create the X image and pixmap. */
11987 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11988 {
1ffb278b 11989 fn_DGifCloseFile (gif);
6fc2811b
JR
11990 UNGCPRO;
11991 return 0;
11992 }
7d0393cf 11993
6fc2811b
JR
11994 /* Allocate colors. */
11995 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11996 if (!gif_color_map)
11997 gif_color_map = gif->SColorMap;
1ffb278b 11998#if 0 /* TODO: Color tables */
6fc2811b 11999 init_color_table ();
1ffb278b 12000#endif
6fc2811b 12001 bzero (pixel_colors, sizeof pixel_colors);
7d0393cf 12002
6fc2811b
JR
12003 for (i = 0; i < gif_color_map->ColorCount; ++i)
12004 {
1ffb278b
JB
12005 int r = gif_color_map->Colors[i].Red;
12006 int g = gif_color_map->Colors[i].Green;
12007 int b = gif_color_map->Colors[i].Blue;
12008#if 0 /* TODO: Color tables */
6fc2811b 12009 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
1ffb278b
JB
12010#else
12011 pixel_colors[i] = PALETTERGB (r, g, b);
12012#endif
6fc2811b
JR
12013 }
12014
1ffb278b 12015#if 0 /* TODO: Color tables */
6fc2811b
JR
12016 img->colors = colors_in_color_table (&img->ncolors);
12017 free_color_table ();
1ffb278b 12018#endif
6fc2811b
JR
12019
12020 /* Clear the part of the screen image that are not covered by
7d0393cf 12021 the image from the GIF file. Full animated GIF support
6fc2811b
JR
12022 requires more than can be done here (see the gif89 spec,
12023 disposal methods). Let's simply assume that the part
12024 not covered by a sub-image is in the frame's background color. */
12025 image_top = gif->SavedImages[ino].ImageDesc.Top;
12026 image_left = gif->SavedImages[ino].ImageDesc.Left;
12027 image_width = gif->SavedImages[ino].ImageDesc.Width;
12028 image_height = gif->SavedImages[ino].ImageDesc.Height;
12029
12030 for (y = 0; y < image_top; ++y)
12031 for (x = 0; x < width; ++x)
12032 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12033
12034 for (y = image_top + image_height; y < height; ++y)
12035 for (x = 0; x < width; ++x)
12036 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12037
12038 for (y = image_top; y < image_top + image_height; ++y)
12039 {
12040 for (x = 0; x < image_left; ++x)
12041 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12042 for (x = image_left + image_width; x < width; ++x)
12043 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12044 }
12045
12046 /* Read the GIF image into the X image. We use a local variable
12047 `raster' here because RasterBits below is a char *, and invites
12048 problems with bytes >= 0x80. */
12049 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12050
12051 if (gif->SavedImages[ino].ImageDesc.Interlace)
12052 {
12053 static int interlace_start[] = {0, 4, 2, 1};
12054 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12055 int pass;
6fc2811b
JR
12056 int row = interlace_start[0];
12057
12058 pass = 0;
12059
12060 for (y = 0; y < image_height; y++)
12061 {
12062 if (row >= image_height)
12063 {
12064 row = interlace_start[++pass];
12065 while (row >= image_height)
12066 row = interlace_start[++pass];
12067 }
7d0393cf 12068
6fc2811b
JR
12069 for (x = 0; x < image_width; x++)
12070 {
12071 int i = raster[(y * image_width) + x];
12072 XPutPixel (ximg, x + image_left, row + image_top,
12073 pixel_colors[i]);
12074 }
7d0393cf 12075
6fc2811b
JR
12076 row += interlace_increment[pass];
12077 }
12078 }
12079 else
12080 {
12081 for (y = 0; y < image_height; ++y)
12082 for (x = 0; x < image_width; ++x)
12083 {
12084 int i = raster[y* image_width + x];
12085 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12086 }
12087 }
7d0393cf 12088
1ffb278b 12089 fn_DGifCloseFile (gif);
a05e2bae
JR
12090
12091 /* Maybe fill in the background field while we have ximg handy. */
12092 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12093 IMAGE_BACKGROUND (img, f, ximg);
12094
6fc2811b
JR
12095 /* Put the image into the pixmap, then free the X image and its buffer. */
12096 x_put_x_image (f, ximg, img->pixmap, width, height);
12097 x_destroy_x_image (ximg);
7d0393cf 12098
6fc2811b
JR
12099 UNGCPRO;
12100 return 1;
12101}
12102
12103#endif /* HAVE_GIF != 0 */
12104
12105
12106\f
12107/***********************************************************************
12108 Ghostscript
12109 ***********************************************************************/
12110
3cf3436e
JR
12111Lisp_Object Qpostscript;
12112
839b1909
JR
12113/* Keyword symbols. */
12114
12115Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12116
6fc2811b
JR
12117#ifdef HAVE_GHOSTSCRIPT
12118static int gs_image_p P_ ((Lisp_Object object));
12119static int gs_load P_ ((struct frame *f, struct image *img));
12120static void gs_clear_image P_ ((struct frame *f, struct image *img));
12121
12122/* The symbol `postscript' identifying images of this type. */
12123
6fc2811b
JR
12124/* Keyword symbols. */
12125
12126Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12127
12128/* Indices of image specification fields in gs_format, below. */
12129
12130enum gs_keyword_index
12131{
12132 GS_TYPE,
12133 GS_PT_WIDTH,
12134 GS_PT_HEIGHT,
12135 GS_FILE,
12136 GS_LOADER,
12137 GS_BOUNDING_BOX,
12138 GS_ASCENT,
12139 GS_MARGIN,
12140 GS_RELIEF,
12141 GS_ALGORITHM,
12142 GS_HEURISTIC_MASK,
a05e2bae
JR
12143 GS_MASK,
12144 GS_BACKGROUND,
6fc2811b
JR
12145 GS_LAST
12146};
12147
12148/* Vector of image_keyword structures describing the format
12149 of valid user-defined image specifications. */
12150
12151static struct image_keyword gs_format[GS_LAST] =
12152{
12153 {":type", IMAGE_SYMBOL_VALUE, 1},
12154 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12155 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12156 {":file", IMAGE_STRING_VALUE, 1},
12157 {":loader", IMAGE_FUNCTION_VALUE, 0},
12158 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8f92c555 12159 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 12160 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12161 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12162 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12163 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12164 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12165 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12166};
12167
12168/* Structure describing the image type `ghostscript'. */
12169
12170static struct image_type gs_type =
12171{
12172 &Qpostscript,
12173 gs_image_p,
12174 gs_load,
12175 gs_clear_image,
12176 NULL
12177};
12178
12179
12180/* Free X resources of Ghostscript image IMG which is used on frame F. */
12181
12182static void
12183gs_clear_image (f, img)
12184 struct frame *f;
12185 struct image *img;
12186{
12187 /* IMG->data.ptr_val may contain a recorded colormap. */
12188 xfree (img->data.ptr_val);
12189 x_clear_image (f, img);
12190}
12191
12192
12193/* Return non-zero if OBJECT is a valid Ghostscript image
12194 specification. */
12195
12196static int
12197gs_image_p (object)
12198 Lisp_Object object;
12199{
12200 struct image_keyword fmt[GS_LAST];
12201 Lisp_Object tem;
12202 int i;
7d0393cf 12203
6fc2811b 12204 bcopy (gs_format, fmt, sizeof fmt);
7d0393cf 12205
8f92c555 12206 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
6fc2811b
JR
12207 return 0;
12208
12209 /* Bounding box must be a list or vector containing 4 integers. */
12210 tem = fmt[GS_BOUNDING_BOX].value;
12211 if (CONSP (tem))
12212 {
12213 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12214 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12215 return 0;
12216 if (!NILP (tem))
12217 return 0;
12218 }
12219 else if (VECTORP (tem))
12220 {
12221 if (XVECTOR (tem)->size != 4)
12222 return 0;
12223 for (i = 0; i < 4; ++i)
12224 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12225 return 0;
12226 }
12227 else
12228 return 0;
12229
12230 return 1;
12231}
12232
12233
12234/* Load Ghostscript image IMG for use on frame F. Value is non-zero
12235 if successful. */
12236
12237static int
12238gs_load (f, img)
12239 struct frame *f;
12240 struct image *img;
12241{
12242 char buffer[100];
12243 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12244 struct gcpro gcpro1, gcpro2;
12245 Lisp_Object frame;
12246 double in_width, in_height;
12247 Lisp_Object pixel_colors = Qnil;
12248
12249 /* Compute pixel size of pixmap needed from the given size in the
12250 image specification. Sizes in the specification are in pt. 1 pt
12251 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12252 info. */
12253 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12254 in_width = XFASTINT (pt_width) / 72.0;
12255 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12256 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12257 in_height = XFASTINT (pt_height) / 72.0;
12258 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12259
12260 /* Create the pixmap. */
12261 BLOCK_INPUT;
12262 xassert (img->pixmap == 0);
12263 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12264 img->width, img->height,
a05e2bae 12265 one_w32_display_info.n_cbits);
6fc2811b
JR
12266 UNBLOCK_INPUT;
12267
12268 if (!img->pixmap)
12269 {
12270 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12271 return 0;
12272 }
7d0393cf 12273
6fc2811b
JR
12274 /* Call the loader to fill the pixmap. It returns a process object
12275 if successful. We do not record_unwind_protect here because
12276 other places in redisplay like calling window scroll functions
12277 don't either. Let the Lisp loader use `unwind-protect' instead. */
12278 GCPRO2 (window_and_pixmap_id, pixel_colors);
12279
12280 sprintf (buffer, "%lu %lu",
12281 (unsigned long) FRAME_W32_WINDOW (f),
12282 (unsigned long) img->pixmap);
12283 window_and_pixmap_id = build_string (buffer);
7d0393cf 12284
6fc2811b
JR
12285 sprintf (buffer, "%lu %lu",
12286 FRAME_FOREGROUND_PIXEL (f),
12287 FRAME_BACKGROUND_PIXEL (f));
12288 pixel_colors = build_string (buffer);
7d0393cf 12289
6fc2811b
JR
12290 XSETFRAME (frame, f);
12291 loader = image_spec_value (img->spec, QCloader, NULL);
12292 if (NILP (loader))
12293 loader = intern ("gs-load-image");
12294
12295 img->data.lisp_val = call6 (loader, frame, img->spec,
12296 make_number (img->width),
12297 make_number (img->height),
12298 window_and_pixmap_id,
12299 pixel_colors);
12300 UNGCPRO;
12301 return PROCESSP (img->data.lisp_val);
12302}
12303
12304
12305/* Kill the Ghostscript process that was started to fill PIXMAP on
12306 frame F. Called from XTread_socket when receiving an event
12307 telling Emacs that Ghostscript has finished drawing. */
12308
12309void
12310x_kill_gs_process (pixmap, f)
12311 Pixmap pixmap;
12312 struct frame *f;
12313{
12314 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
12315 int class, i;
12316 struct image *img;
12317
12318 /* Find the image containing PIXMAP. */
12319 for (i = 0; i < c->used; ++i)
12320 if (c->images[i]->pixmap == pixmap)
12321 break;
12322
3cf3436e
JR
12323 /* Should someone in between have cleared the image cache, for
12324 instance, give up. */
12325 if (i == c->used)
12326 return;
12327
6fc2811b
JR
12328 /* Kill the GS process. We should have found PIXMAP in the image
12329 cache and its image should contain a process object. */
6fc2811b
JR
12330 img = c->images[i];
12331 xassert (PROCESSP (img->data.lisp_val));
12332 Fkill_process (img->data.lisp_val, Qnil);
12333 img->data.lisp_val = Qnil;
12334
12335 /* On displays with a mutable colormap, figure out the colors
12336 allocated for the image by looking at the pixels of an XImage for
12337 img->pixmap. */
12338 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
12339 if (class != StaticColor && class != StaticGray && class != TrueColor)
12340 {
12341 XImage *ximg;
12342
12343 BLOCK_INPUT;
12344
12345 /* Try to get an XImage for img->pixmep. */
12346 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
12347 0, 0, img->width, img->height, ~0, ZPixmap);
12348 if (ximg)
12349 {
12350 int x, y;
7d0393cf 12351
6fc2811b
JR
12352 /* Initialize the color table. */
12353 init_color_table ();
7d0393cf 12354
6fc2811b
JR
12355 /* For each pixel of the image, look its color up in the
12356 color table. After having done so, the color table will
12357 contain an entry for each color used by the image. */
12358 for (y = 0; y < img->height; ++y)
12359 for (x = 0; x < img->width; ++x)
12360 {
12361 unsigned long pixel = XGetPixel (ximg, x, y);
12362 lookup_pixel_color (f, pixel);
12363 }
12364
12365 /* Record colors in the image. Free color table and XImage. */
12366 img->colors = colors_in_color_table (&img->ncolors);
12367 free_color_table ();
12368 XDestroyImage (ximg);
12369
12370#if 0 /* This doesn't seem to be the case. If we free the colors
12371 here, we get a BadAccess later in x_clear_image when
12372 freeing the colors. */
12373 /* We have allocated colors once, but Ghostscript has also
12374 allocated colors on behalf of us. So, to get the
12375 reference counts right, free them once. */
12376 if (img->ncolors)
3cf3436e 12377 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 12378 img->colors, img->ncolors, 0);
6fc2811b
JR
12379#endif
12380 }
12381 else
12382 image_error ("Cannot get X image of `%s'; colors will not be freed",
12383 img->spec, Qnil);
7d0393cf 12384
6fc2811b
JR
12385 UNBLOCK_INPUT;
12386 }
3cf3436e
JR
12387
12388 /* Now that we have the pixmap, compute mask and transform the
12389 image if requested. */
12390 BLOCK_INPUT;
12391 postprocess_image (f, img);
12392 UNBLOCK_INPUT;
6fc2811b
JR
12393}
12394
12395#endif /* HAVE_GHOSTSCRIPT */
12396
12397\f
12398/***********************************************************************
12399 Window properties
12400 ***********************************************************************/
12401
12402DEFUN ("x-change-window-property", Fx_change_window_property,
12403 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
12404 doc: /* Change window property PROP to VALUE on the X window of FRAME.
12405PROP and VALUE must be strings. FRAME nil or omitted means use the
12406selected frame. Value is VALUE. */)
6fc2811b
JR
12407 (prop, value, frame)
12408 Lisp_Object frame, prop, value;
12409{
767b1ff0 12410#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12411 struct frame *f = check_x_frame (frame);
12412 Atom prop_atom;
12413
b7826503
PJ
12414 CHECK_STRING (prop);
12415 CHECK_STRING (value);
6fc2811b
JR
12416
12417 BLOCK_INPUT;
d5db4077 12418 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
12419 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12420 prop_atom, XA_STRING, 8, PropModeReplace,
d5db4077 12421 SDATA (value), SCHARS (value));
6fc2811b
JR
12422
12423 /* Make sure the property is set when we return. */
12424 XFlush (FRAME_W32_DISPLAY (f));
12425 UNBLOCK_INPUT;
12426
767b1ff0 12427#endif /* TODO */
6fc2811b
JR
12428
12429 return value;
12430}
12431
12432
12433DEFUN ("x-delete-window-property", Fx_delete_window_property,
12434 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
12435 doc: /* Remove window property PROP from X window of FRAME.
12436FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
12437 (prop, frame)
12438 Lisp_Object prop, frame;
12439{
767b1ff0 12440#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12441
12442 struct frame *f = check_x_frame (frame);
12443 Atom prop_atom;
12444
b7826503 12445 CHECK_STRING (prop);
6fc2811b 12446 BLOCK_INPUT;
d5db4077 12447 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
12448 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12449
12450 /* Make sure the property is removed when we return. */
12451 XFlush (FRAME_W32_DISPLAY (f));
12452 UNBLOCK_INPUT;
767b1ff0 12453#endif /* TODO */
6fc2811b
JR
12454
12455 return prop;
12456}
12457
12458
12459DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12460 1, 2, 0,
74e1aeec
JR
12461 doc: /* Value is the value of window property PROP on FRAME.
12462If FRAME is nil or omitted, use the selected frame. Value is nil
12463if FRAME hasn't a property with name PROP or if PROP has no string
12464value. */)
6fc2811b
JR
12465 (prop, frame)
12466 Lisp_Object prop, frame;
12467{
767b1ff0 12468#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12469
12470 struct frame *f = check_x_frame (frame);
12471 Atom prop_atom;
12472 int rc;
12473 Lisp_Object prop_value = Qnil;
12474 char *tmp_data = NULL;
12475 Atom actual_type;
12476 int actual_format;
12477 unsigned long actual_size, bytes_remaining;
12478
b7826503 12479 CHECK_STRING (prop);
6fc2811b 12480 BLOCK_INPUT;
d5db4077 12481 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
12482 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12483 prop_atom, 0, 0, False, XA_STRING,
12484 &actual_type, &actual_format, &actual_size,
12485 &bytes_remaining, (unsigned char **) &tmp_data);
12486 if (rc == Success)
12487 {
12488 int size = bytes_remaining;
12489
12490 XFree (tmp_data);
12491 tmp_data = NULL;
12492
12493 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12494 prop_atom, 0, bytes_remaining,
12495 False, XA_STRING,
7d0393cf
JB
12496 &actual_type, &actual_format,
12497 &actual_size, &bytes_remaining,
6fc2811b
JR
12498 (unsigned char **) &tmp_data);
12499 if (rc == Success)
12500 prop_value = make_string (tmp_data, size);
12501
12502 XFree (tmp_data);
12503 }
12504
12505 UNBLOCK_INPUT;
12506
12507 return prop_value;
12508
767b1ff0 12509#endif /* TODO */
6fc2811b
JR
12510 return Qnil;
12511}
12512
12513
12514\f
12515/***********************************************************************
12516 Busy cursor
12517 ***********************************************************************/
12518
f79e6790 12519/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 12520 an hourglass cursor on all frames. */
6fc2811b 12521
0af913d7 12522static struct atimer *hourglass_atimer;
6fc2811b 12523
0af913d7 12524/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 12525
0af913d7 12526static int hourglass_shown_p;
6fc2811b 12527
0af913d7 12528/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 12529
0af913d7 12530static Lisp_Object Vhourglass_delay;
6fc2811b 12531
0af913d7 12532/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
12533 cursor. */
12534
0af913d7 12535#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
12536
12537/* Function prototypes. */
12538
0af913d7
GM
12539static void show_hourglass P_ ((struct atimer *));
12540static void hide_hourglass P_ ((void));
f79e6790
JR
12541
12542
0af913d7 12543/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
12544
12545void
0af913d7 12546start_hourglass ()
f79e6790 12547{
767b1ff0 12548#if 0 /* TODO: cursor shape changes. */
f79e6790 12549 EMACS_TIME delay;
dfff8a69 12550 int secs, usecs = 0;
7d0393cf 12551
0af913d7 12552 cancel_hourglass ();
f79e6790 12553
0af913d7
GM
12554 if (INTEGERP (Vhourglass_delay)
12555 && XINT (Vhourglass_delay) > 0)
12556 secs = XFASTINT (Vhourglass_delay);
12557 else if (FLOATP (Vhourglass_delay)
12558 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
12559 {
12560 Lisp_Object tem;
0af913d7 12561 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 12562 secs = XFASTINT (tem);
0af913d7 12563 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 12564 }
f79e6790 12565 else
0af913d7 12566 secs = DEFAULT_HOURGLASS_DELAY;
7d0393cf 12567
dfff8a69 12568 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
12569 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
12570 show_hourglass, NULL);
f79e6790
JR
12571#endif
12572}
12573
12574
0af913d7
GM
12575/* Cancel the hourglass cursor timer if active, hide an hourglass
12576 cursor if shown. */
f79e6790
JR
12577
12578void
0af913d7 12579cancel_hourglass ()
f79e6790 12580{
0af913d7 12581 if (hourglass_atimer)
dfff8a69 12582 {
0af913d7
GM
12583 cancel_atimer (hourglass_atimer);
12584 hourglass_atimer = NULL;
dfff8a69 12585 }
7d0393cf 12586
0af913d7
GM
12587 if (hourglass_shown_p)
12588 hide_hourglass ();
f79e6790
JR
12589}
12590
12591
0af913d7
GM
12592/* Timer function of hourglass_atimer. TIMER is equal to
12593 hourglass_atimer.
f79e6790 12594
0af913d7
GM
12595 Display an hourglass cursor on all frames by mapping the frames'
12596 hourglass_window. Set the hourglass_p flag in the frames'
12597 output_data.x structure to indicate that an hourglass cursor is
12598 shown on the frames. */
f79e6790
JR
12599
12600static void
0af913d7 12601show_hourglass (timer)
f79e6790 12602 struct atimer *timer;
6fc2811b 12603{
767b1ff0 12604#if 0 /* TODO: cursor shape changes. */
f79e6790 12605 /* The timer implementation will cancel this timer automatically
0af913d7 12606 after this function has run. Set hourglass_atimer to null
f79e6790 12607 so that we know the timer doesn't have to be canceled. */
0af913d7 12608 hourglass_atimer = NULL;
f79e6790 12609
0af913d7 12610 if (!hourglass_shown_p)
6fc2811b
JR
12611 {
12612 Lisp_Object rest, frame;
7d0393cf 12613
f79e6790 12614 BLOCK_INPUT;
7d0393cf 12615
6fc2811b 12616 FOR_EACH_FRAME (rest, frame)
dc220243 12617 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
12618 {
12619 struct frame *f = XFRAME (frame);
7d0393cf 12620
0af913d7 12621 f->output_data.w32->hourglass_p = 1;
7d0393cf 12622
0af913d7 12623 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
12624 {
12625 unsigned long mask = CWCursor;
12626 XSetWindowAttributes attrs;
7d0393cf 12627
0af913d7 12628 attrs.cursor = f->output_data.w32->hourglass_cursor;
7d0393cf 12629
0af913d7 12630 f->output_data.w32->hourglass_window
f79e6790 12631 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
12632 FRAME_OUTER_WINDOW (f),
12633 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
12634 InputOnly,
12635 CopyFromParent,
6fc2811b
JR
12636 mask, &attrs);
12637 }
7d0393cf 12638
0af913d7
GM
12639 XMapRaised (FRAME_X_DISPLAY (f),
12640 f->output_data.w32->hourglass_window);
f79e6790 12641 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 12642 }
6fc2811b 12643
0af913d7 12644 hourglass_shown_p = 1;
f79e6790
JR
12645 UNBLOCK_INPUT;
12646 }
12647#endif
6fc2811b
JR
12648}
12649
12650
0af913d7 12651/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 12652
f79e6790 12653static void
0af913d7 12654hide_hourglass ()
f79e6790 12655{
767b1ff0 12656#if 0 /* TODO: cursor shape changes. */
0af913d7 12657 if (hourglass_shown_p)
6fc2811b 12658 {
f79e6790
JR
12659 Lisp_Object rest, frame;
12660
12661 BLOCK_INPUT;
12662 FOR_EACH_FRAME (rest, frame)
6fc2811b 12663 {
f79e6790 12664 struct frame *f = XFRAME (frame);
7d0393cf 12665
dc220243 12666 if (FRAME_W32_P (f)
f79e6790 12667 /* Watch out for newly created frames. */
0af913d7 12668 && f->output_data.x->hourglass_window)
f79e6790 12669 {
0af913d7
GM
12670 XUnmapWindow (FRAME_X_DISPLAY (f),
12671 f->output_data.x->hourglass_window);
12672 /* Sync here because XTread_socket looks at the
12673 hourglass_p flag that is reset to zero below. */
f79e6790 12674 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 12675 f->output_data.x->hourglass_p = 0;
f79e6790 12676 }
6fc2811b 12677 }
6fc2811b 12678
0af913d7 12679 hourglass_shown_p = 0;
f79e6790
JR
12680 UNBLOCK_INPUT;
12681 }
12682#endif
6fc2811b
JR
12683}
12684
12685
12686\f
12687/***********************************************************************
12688 Tool tips
12689 ***********************************************************************/
12690
12691static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
12692 Lisp_Object, Lisp_Object));
12693static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
12694 Lisp_Object, int, int, int *, int *));
7d0393cf 12695
3cf3436e 12696/* The frame of a currently visible tooltip. */
6fc2811b 12697
937e601e 12698Lisp_Object tip_frame;
6fc2811b
JR
12699
12700/* If non-nil, a timer started that hides the last tooltip when it
12701 fires. */
12702
12703Lisp_Object tip_timer;
12704Window tip_window;
12705
3cf3436e
JR
12706/* If non-nil, a vector of 3 elements containing the last args
12707 with which x-show-tip was called. See there. */
12708
12709Lisp_Object last_show_tip_args;
12710
12711/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
12712
12713Lisp_Object Vx_max_tooltip_size;
12714
12715
937e601e
AI
12716static Lisp_Object
12717unwind_create_tip_frame (frame)
12718 Lisp_Object frame;
12719{
c844a81a
GM
12720 Lisp_Object deleted;
12721
12722 deleted = unwind_create_frame (frame);
12723 if (EQ (deleted, Qt))
12724 {
12725 tip_window = NULL;
12726 tip_frame = Qnil;
12727 }
7d0393cf 12728
c844a81a 12729 return deleted;
937e601e
AI
12730}
12731
12732
6fc2811b 12733/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
12734 PARMS is a list of frame parameters. TEXT is the string to
12735 display in the tip frame. Value is the frame.
937e601e
AI
12736
12737 Note that functions called here, esp. x_default_parameter can
12738 signal errors, for instance when a specified color name is
12739 undefined. We have to make sure that we're in a consistent state
12740 when this happens. */
6fc2811b
JR
12741
12742static Lisp_Object
3cf3436e 12743x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 12744 struct w32_display_info *dpyinfo;
3cf3436e 12745 Lisp_Object parms, text;
6fc2811b 12746{
6fc2811b
JR
12747 struct frame *f;
12748 Lisp_Object frame, tem;
12749 Lisp_Object name;
12750 long window_prompting = 0;
12751 int width, height;
331379bf 12752 int count = SPECPDL_INDEX ();
6fc2811b
JR
12753 struct gcpro gcpro1, gcpro2, gcpro3;
12754 struct kboard *kb;
3cf3436e
JR
12755 int face_change_count_before = face_change_count;
12756 Lisp_Object buffer;
12757 struct buffer *old_buffer;
6fc2811b 12758
ca56d953 12759 check_w32 ();
6fc2811b
JR
12760
12761 /* Use this general default value to start with until we know if
12762 this frame has a specified name. */
12763 Vx_resource_name = Vinvocation_name;
12764
12765#ifdef MULTI_KBOARD
12766 kb = dpyinfo->kboard;
12767#else
12768 kb = &the_only_kboard;
12769#endif
12770
12771 /* Get the name of the frame to use for resource lookup. */
12772 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
12773 if (!STRINGP (name)
12774 && !EQ (name, Qunbound)
12775 && !NILP (name))
12776 error ("Invalid frame name--not a string or nil");
12777 Vx_resource_name = name;
12778
12779 frame = Qnil;
12780 GCPRO3 (parms, name, frame);
9eb16b62
JR
12781 /* Make a frame without minibuffer nor mode-line. */
12782 f = make_frame (0);
12783 f->wants_modeline = 0;
6fc2811b 12784 XSETFRAME (frame, f);
3cf3436e
JR
12785
12786 buffer = Fget_buffer_create (build_string (" *tip*"));
be786000 12787 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer, Qnil);
3cf3436e
JR
12788 old_buffer = current_buffer;
12789 set_buffer_internal_1 (XBUFFER (buffer));
12790 current_buffer->truncate_lines = Qnil;
12791 Ferase_buffer ();
12792 Finsert (1, &text);
12793 set_buffer_internal_1 (old_buffer);
7d0393cf 12794
6fc2811b 12795 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 12796 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 12797
3cf3436e
JR
12798 /* By setting the output method, we're essentially saying that
12799 the frame is live, as per FRAME_LIVE_P. If we get a signal
12800 from this point on, x_destroy_window might screw up reference
12801 counts etc. */
d88c567c 12802 f->output_method = output_w32;
6fc2811b
JR
12803 f->output_data.w32 =
12804 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12805 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
12806
12807 FRAME_FONTSET (f) = -1;
6fc2811b
JR
12808 f->icon_name = Qnil;
12809
ca56d953 12810#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
12811 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
12812 dpyinfo_refcount = dpyinfo->reference_count;
12813#endif /* GLYPH_DEBUG */
6fc2811b
JR
12814#ifdef MULTI_KBOARD
12815 FRAME_KBOARD (f) = kb;
12816#endif
12817 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12818 f->output_data.w32->explicit_parent = 0;
12819
12820 /* Set the name; the functions to which we pass f expect the name to
12821 be set. */
12822 if (EQ (name, Qunbound) || NILP (name))
12823 {
ca56d953 12824 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
12825 f->explicit_name = 0;
12826 }
12827 else
12828 {
12829 f->name = name;
12830 f->explicit_name = 1;
12831 /* use the frame's title when getting resources for this frame. */
12832 specbind (Qx_resource_name, name);
12833 }
12834
6fc2811b
JR
12835 /* Extract the window parameters from the supplied values
12836 that are needed to determine window geometry. */
12837 {
12838 Lisp_Object font;
12839
12840 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12841
12842 BLOCK_INPUT;
12843 /* First, try whatever font the caller has specified. */
12844 if (STRINGP (font))
12845 {
12846 tem = Fquery_fontset (font, Qnil);
12847 if (STRINGP (tem))
d5db4077 12848 font = x_new_fontset (f, SDATA (tem));
6fc2811b 12849 else
d5db4077 12850 font = x_new_font (f, SDATA (font));
6fc2811b 12851 }
7d0393cf 12852
6fc2811b
JR
12853 /* Try out a font which we hope has bold and italic variations. */
12854 if (!STRINGP (font))
ca56d953 12855 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 12856 if (! STRINGP (font))
ca56d953 12857 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
12858 /* If those didn't work, look for something which will at least work. */
12859 if (! STRINGP (font))
ca56d953 12860 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
12861 UNBLOCK_INPUT;
12862 if (! STRINGP (font))
ca56d953 12863 font = build_string ("Fixedsys");
6fc2811b
JR
12864
12865 x_default_parameter (f, parms, Qfont, font,
12866 "font", "Font", RES_TYPE_STRING);
12867 }
12868
12869 x_default_parameter (f, parms, Qborder_width, make_number (2),
12870 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
12871 /* This defaults to 2 in order to match xterm. We recognize either
12872 internalBorderWidth or internalBorder (which is what xterm calls
12873 it). */
12874 if (NILP (Fassq (Qinternal_border_width, parms)))
12875 {
12876 Lisp_Object value;
12877
12878 value = w32_get_arg (parms, Qinternal_border_width,
12879 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12880 if (! EQ (value, Qunbound))
12881 parms = Fcons (Fcons (Qinternal_border_width, value),
12882 parms);
12883 }
bfd6edcc 12884 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
12885 "internalBorderWidth", "internalBorderWidth",
12886 RES_TYPE_NUMBER);
12887
12888 /* Also do the stuff which must be set before the window exists. */
12889 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12890 "foreground", "Foreground", RES_TYPE_STRING);
12891 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12892 "background", "Background", RES_TYPE_STRING);
12893 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12894 "pointerColor", "Foreground", RES_TYPE_STRING);
12895 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12896 "cursorColor", "Foreground", RES_TYPE_STRING);
12897 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12898 "borderColor", "BorderColor", RES_TYPE_STRING);
12899
12900 /* Init faces before x_default_parameter is called for scroll-bar
12901 parameters because that function calls x_set_scroll_bar_width,
12902 which calls change_frame_size, which calls Fset_window_buffer,
12903 which runs hooks, which call Fvertical_motion. At the end, we
12904 end up in init_iterator with a null face cache, which should not
12905 happen. */
12906 init_frame_faces (f);
ca56d953
JR
12907
12908 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 12909 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 12910
6d906347 12911 window_prompting = x_figure_window_size (f, parms, 0);
6fc2811b 12912
9eb16b62 12913 /* No fringes on tip frame. */
be786000
KS
12914 f->fringe_cols = 0;
12915 f->left_fringe_width = 0;
12916 f->right_fringe_width = 0;
9eb16b62 12917
ca56d953
JR
12918 BLOCK_INPUT;
12919 my_create_tip_window (f);
12920 UNBLOCK_INPUT;
6fc2811b
JR
12921
12922 x_make_gc (f);
12923
12924 x_default_parameter (f, parms, Qauto_raise, Qnil,
12925 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12926 x_default_parameter (f, parms, Qauto_lower, Qnil,
12927 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12928 x_default_parameter (f, parms, Qcursor_type, Qbox,
12929 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12930
be786000 12931 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
6fc2811b 12932 Change will not be effected unless different from the current
be786000
KS
12933 FRAME_LINES (f). */
12934 width = FRAME_COLS (f);
12935 height = FRAME_LINES (f);
12936 FRAME_LINES (f) = 0;
12937 SET_FRAME_COLS (f, 0);
6fc2811b
JR
12938 change_frame_size (f, height, width, 1, 0, 0);
12939
cd1d850f
JPW
12940 /* Add `tooltip' frame parameter's default value. */
12941 if (NILP (Fframe_parameter (frame, intern ("tooltip"))))
12942 Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
12943 Qnil));
7d0393cf 12944
3cf3436e
JR
12945 /* Set up faces after all frame parameters are known. This call
12946 also merges in face attributes specified for new frames.
12947
12948 Frame parameters may be changed if .Xdefaults contains
12949 specifications for the default font. For example, if there is an
12950 `Emacs.default.attributeBackground: pink', the `background-color'
12951 attribute of the frame get's set, which let's the internal border
12952 of the tooltip frame appear in pink. Prevent this. */
12953 {
12954 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
12955
12956 /* Set tip_frame here, so that */
12957 tip_frame = frame;
12958 call1 (Qface_set_after_frame_default, frame);
7d0393cf 12959
3cf3436e
JR
12960 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
12961 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
12962 Qnil));
12963 }
7d0393cf 12964
6fc2811b
JR
12965 f->no_split = 1;
12966
12967 UNGCPRO;
12968
12969 /* It is now ok to make the frame official even if we get an error
12970 below. And the frame needs to be on Vframe_list or making it
12971 visible won't work. */
12972 Vframe_list = Fcons (frame, Vframe_list);
12973
12974 /* Now that the frame is official, it counts as a reference to
12975 its display. */
12976 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 12977
3cf3436e
JR
12978 /* Setting attributes of faces of the tooltip frame from resources
12979 and similar will increment face_change_count, which leads to the
12980 clearing of all current matrices. Since this isn't necessary
12981 here, avoid it by resetting face_change_count to the value it
12982 had before we created the tip frame. */
12983 face_change_count = face_change_count_before;
12984
12985 /* Discard the unwind_protect. */
6fc2811b 12986 return unbind_to (count, frame);
ee78dc32
GV
12987}
12988
3cf3436e
JR
12989
12990/* Compute where to display tip frame F. PARMS is the list of frame
12991 parameters for F. DX and DY are specified offsets from the current
12992 location of the mouse. WIDTH and HEIGHT are the width and height
12993 of the tooltip. Return coordinates relative to the root window of
12994 the display in *ROOT_X, and *ROOT_Y. */
12995
12996static void
12997compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
12998 struct frame *f;
12999 Lisp_Object parms, dx, dy;
13000 int width, height;
13001 int *root_x, *root_y;
13002{
3cf3436e 13003 Lisp_Object left, top;
7d0393cf 13004
3cf3436e
JR
13005 /* User-specified position? */
13006 left = Fcdr (Fassq (Qleft, parms));
13007 top = Fcdr (Fassq (Qtop, parms));
7d0393cf 13008
3cf3436e
JR
13009 /* Move the tooltip window where the mouse pointer is. Resize and
13010 show it. */
ca56d953 13011 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13012 {
ca56d953
JR
13013 POINT pt;
13014
3cf3436e 13015 BLOCK_INPUT;
ca56d953
JR
13016 GetCursorPos (&pt);
13017 *root_x = pt.x;
13018 *root_y = pt.y;
3cf3436e
JR
13019 UNBLOCK_INPUT;
13020 }
13021
13022 if (INTEGERP (top))
13023 *root_y = XINT (top);
13024 else if (*root_y + XINT (dy) - height < 0)
13025 *root_y -= XINT (dy);
13026 else
13027 {
13028 *root_y -= height;
13029 *root_y += XINT (dy);
13030 }
13031
13032 if (INTEGERP (left))
13033 *root_x = XINT (left);
72e4adef
JR
13034 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13035 /* It fits to the right of the pointer. */
13036 *root_x += XINT (dx);
13037 else if (width + XINT (dx) <= *root_x)
13038 /* It fits to the left of the pointer. */
3cf3436e
JR
13039 *root_x -= width + XINT (dx);
13040 else
72e4adef
JR
13041 /* Put it left justified on the screen -- it ought to fit that way. */
13042 *root_x = 0;
3cf3436e
JR
13043}
13044
13045
71eab8d1 13046DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13047 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13048A tooltip window is a small window displaying a string.
13049
13050FRAME nil or omitted means use the selected frame.
13051
13052PARMS is an optional list of frame parameters which can be
13053used to change the tooltip's appearance.
13054
ca56d953
JR
13055Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13056means use the default timeout of 5 seconds.
74e1aeec 13057
ca56d953 13058If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13059the tooltip is displayed at that x-position. Otherwise it is
13060displayed at the mouse position, with offset DX added (default is 5 if
13061DX isn't specified). Likewise for the y-position; if a `top' frame
13062parameter is specified, it determines the y-position of the tooltip
13063window, otherwise it is displayed at the mouse position, with offset
13064DY added (default is -10).
13065
13066A tooltip's maximum size is specified by `x-max-tooltip-size'.
13067Text larger than the specified size is clipped. */)
71eab8d1
AI
13068 (string, frame, parms, timeout, dx, dy)
13069 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13070{
6fc2811b
JR
13071 struct frame *f;
13072 struct window *w;
3cf3436e 13073 int root_x, root_y;
6fc2811b
JR
13074 struct buffer *old_buffer;
13075 struct text_pos pos;
13076 int i, width, height;
6fc2811b
JR
13077 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13078 int old_windows_or_buffers_changed = windows_or_buffers_changed;
331379bf 13079 int count = SPECPDL_INDEX ();
7d0393cf 13080
6fc2811b 13081 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13082
dfff8a69 13083 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13084
b7826503 13085 CHECK_STRING (string);
6fc2811b
JR
13086 f = check_x_frame (frame);
13087 if (NILP (timeout))
13088 timeout = make_number (5);
13089 else
b7826503 13090 CHECK_NATNUM (timeout);
ee78dc32 13091
71eab8d1
AI
13092 if (NILP (dx))
13093 dx = make_number (5);
13094 else
b7826503 13095 CHECK_NUMBER (dx);
7d0393cf 13096
71eab8d1 13097 if (NILP (dy))
dc220243 13098 dy = make_number (-10);
71eab8d1 13099 else
b7826503 13100 CHECK_NUMBER (dy);
71eab8d1 13101
dc220243
JR
13102 if (NILP (last_show_tip_args))
13103 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13104
13105 if (!NILP (tip_frame))
13106 {
13107 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13108 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13109 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13110
13111 if (EQ (frame, last_frame)
13112 && !NILP (Fequal (last_string, string))
13113 && !NILP (Fequal (last_parms, parms)))
13114 {
13115 struct frame *f = XFRAME (tip_frame);
7d0393cf 13116
dc220243
JR
13117 /* Only DX and DY have changed. */
13118 if (!NILP (tip_timer))
13119 {
13120 Lisp_Object timer = tip_timer;
13121 tip_timer = Qnil;
13122 call1 (Qcancel_timer, timer);
13123 }
13124
13125 BLOCK_INPUT;
be786000
KS
13126 compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
13127 FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
13128
13129 /* Put tooltip in topmost group and in position. */
ca56d953
JR
13130 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13131 root_x, root_y, 0, 0,
13132 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
13133
13134 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13135 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13136 0, 0, 0, 0,
13137 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13138
dc220243
JR
13139 UNBLOCK_INPUT;
13140 goto start_timer;
13141 }
13142 }
13143
6fc2811b
JR
13144 /* Hide a previous tip, if any. */
13145 Fx_hide_tip ();
ee78dc32 13146
dc220243
JR
13147 ASET (last_show_tip_args, 0, string);
13148 ASET (last_show_tip_args, 1, frame);
13149 ASET (last_show_tip_args, 2, parms);
13150
6fc2811b
JR
13151 /* Add default values to frame parameters. */
13152 if (NILP (Fassq (Qname, parms)))
13153 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13154 if (NILP (Fassq (Qinternal_border_width, parms)))
13155 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13156 if (NILP (Fassq (Qborder_width, parms)))
13157 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13158 if (NILP (Fassq (Qborder_color, parms)))
13159 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13160 if (NILP (Fassq (Qbackground_color, parms)))
13161 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13162 parms);
13163
0e3fcdef
JR
13164 /* Block input until the tip has been fully drawn, to avoid crashes
13165 when drawing tips in menus. */
13166 BLOCK_INPUT;
13167
6fc2811b
JR
13168 /* Create a frame for the tooltip, and record it in the global
13169 variable tip_frame. */
ca56d953 13170 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 13171 f = XFRAME (frame);
6fc2811b 13172
3cf3436e 13173 /* Set up the frame's root window. */
6fc2811b 13174 w = XWINDOW (FRAME_ROOT_WINDOW (f));
be786000 13175 w->left_col = w->top_line = make_number (0);
3cf3436e
JR
13176
13177 if (CONSP (Vx_max_tooltip_size)
13178 && INTEGERP (XCAR (Vx_max_tooltip_size))
13179 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13180 && INTEGERP (XCDR (Vx_max_tooltip_size))
13181 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13182 {
be786000
KS
13183 w->total_cols = XCAR (Vx_max_tooltip_size);
13184 w->total_lines = XCDR (Vx_max_tooltip_size);
3cf3436e
JR
13185 }
13186 else
13187 {
be786000
KS
13188 w->total_cols = make_number (80);
13189 w->total_lines = make_number (40);
3cf3436e 13190 }
7d0393cf 13191
be786000 13192 FRAME_TOTAL_COLS (f) = XINT (w->total_cols);
6fc2811b
JR
13193 adjust_glyphs (f);
13194 w->pseudo_window_p = 1;
13195
13196 /* Display the tooltip text in a temporary buffer. */
6fc2811b 13197 old_buffer = current_buffer;
3cf3436e
JR
13198 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13199 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
13200 clear_glyph_matrix (w->desired_matrix);
13201 clear_glyph_matrix (w->current_matrix);
13202 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13203 try_window (FRAME_ROOT_WINDOW (f), pos);
13204
13205 /* Compute width and height of the tooltip. */
13206 width = height = 0;
13207 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 13208 {
6fc2811b
JR
13209 struct glyph_row *row = &w->desired_matrix->rows[i];
13210 struct glyph *last;
13211 int row_width;
13212
13213 /* Stop at the first empty row at the end. */
13214 if (!row->enabled_p || !row->displays_text_p)
13215 break;
13216
13217 /* Let the row go over the full width of the frame. */
13218 row->full_width_p = 1;
13219
4e3a1c61
JR
13220#ifdef TODO /* Investigate why some fonts need more width than is
13221 calculated for some tooltips. */
6fc2811b
JR
13222 /* There's a glyph at the end of rows that is use to place
13223 the cursor there. Don't include the width of this glyph. */
13224 if (row->used[TEXT_AREA])
13225 {
13226 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13227 row_width = row->pixel_width - last->pixel_width;
13228 }
13229 else
4e3a1c61 13230#endif
6fc2811b 13231 row_width = row->pixel_width;
7d0393cf 13232
ca56d953 13233 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 13234 height += row->height;
6fc2811b 13235 width = max (width, row_width);
ee78dc32
GV
13236 }
13237
6fc2811b
JR
13238 /* Add the frame's internal border to the width and height the X
13239 window should have. */
13240 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13241 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 13242
6fc2811b
JR
13243 /* Move the tooltip window where the mouse pointer is. Resize and
13244 show it. */
3cf3436e 13245 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 13246
bfd6edcc
JR
13247 {
13248 /* Adjust Window size to take border into account. */
13249 RECT rect;
13250 rect.left = rect.top = 0;
13251 rect.right = width;
13252 rect.bottom = height;
13253 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
13254 FRAME_EXTERNAL_MENU_BAR (f));
13255
d65a9cdc 13256 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
13257 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13258 root_x, root_y, rect.right - rect.left,
13259 rect.bottom - rect.top, SWP_NOACTIVATE);
13260
d65a9cdc
JR
13261 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13262 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13263 0, 0, 0, 0,
13264 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13265
bfd6edcc
JR
13266 /* Let redisplay know that we have made the frame visible already. */
13267 f->async_visible = 1;
13268
13269 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
13270 }
ee78dc32 13271
6fc2811b
JR
13272 /* Draw into the window. */
13273 w->must_be_updated_p = 1;
13274 update_single_window (w, 1);
ee78dc32 13275
0e3fcdef
JR
13276 UNBLOCK_INPUT;
13277
6fc2811b
JR
13278 /* Restore original current buffer. */
13279 set_buffer_internal_1 (old_buffer);
13280 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 13281
dc220243 13282 start_timer:
6fc2811b
JR
13283 /* Let the tip disappear after timeout seconds. */
13284 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13285 intern ("x-hide-tip"));
ee78dc32 13286
dfff8a69 13287 UNGCPRO;
6fc2811b 13288 return unbind_to (count, Qnil);
ee78dc32
GV
13289}
13290
ee78dc32 13291
6fc2811b 13292DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
13293 doc: /* Hide the current tooltip window, if there is any.
13294Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
13295 ()
13296{
937e601e
AI
13297 int count;
13298 Lisp_Object deleted, frame, timer;
13299 struct gcpro gcpro1, gcpro2;
13300
13301 /* Return quickly if nothing to do. */
13302 if (NILP (tip_timer) && NILP (tip_frame))
13303 return Qnil;
7d0393cf 13304
937e601e
AI
13305 frame = tip_frame;
13306 timer = tip_timer;
13307 GCPRO2 (frame, timer);
13308 tip_frame = tip_timer = deleted = Qnil;
7d0393cf 13309
331379bf 13310 count = SPECPDL_INDEX ();
6fc2811b 13311 specbind (Qinhibit_redisplay, Qt);
937e601e 13312 specbind (Qinhibit_quit, Qt);
7d0393cf 13313
937e601e 13314 if (!NILP (timer))
dc220243 13315 call1 (Qcancel_timer, timer);
ee78dc32 13316
937e601e 13317 if (FRAMEP (frame))
6fc2811b 13318 {
937e601e
AI
13319 Fdelete_frame (frame, Qnil);
13320 deleted = Qt;
6fc2811b 13321 }
1edf84e7 13322
937e601e
AI
13323 UNGCPRO;
13324 return unbind_to (count, deleted);
6fc2811b 13325}
5ac45f98 13326
5ac45f98 13327
6fc2811b
JR
13328\f
13329/***********************************************************************
13330 File selection dialog
13331 ***********************************************************************/
6fc2811b
JR
13332extern Lisp_Object Qfile_name_history;
13333
1030b26b
JR
13334/* Callback for altering the behaviour of the Open File dialog.
13335 Makes the Filename text field contain "Current Directory" and be
13336 read-only when "Directories" is selected in the filter. This
13337 allows us to work around the fact that the standard Open File
13338 dialog does not support directories. */
13339UINT CALLBACK
13340file_dialog_callback (hwnd, msg, wParam, lParam)
13341 HWND hwnd;
13342 UINT msg;
13343 WPARAM wParam;
13344 LPARAM lParam;
13345{
13346 if (msg == WM_NOTIFY)
13347 {
13348 OFNOTIFY * notify = (OFNOTIFY *)lParam;
13349 /* Detect when the Filter dropdown is changed. */
13350 if (notify->hdr.code == CDN_TYPECHANGE)
13351 {
13352 HWND dialog = GetParent (hwnd);
13353 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
13354
13355 /* Directories is in index 2. */
13356 if (notify->lpOFN->nFilterIndex == 2)
13357 {
13358 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
13359 "Current Directory");
13360 EnableWindow (edit_control, FALSE);
13361 }
13362 else
13363 {
13364 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
13365 "");
13366 EnableWindow (edit_control, TRUE);
13367 }
13368 }
13369 }
13370 return 0;
13371}
13372
6fc2811b 13373DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
13374 doc: /* Read file name, prompting with PROMPT in directory DIR.
13375Use a file selection dialog.
13376Select DEFAULT-FILENAME in the dialog's file selection box, if
13377specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
13378 (prompt, dir, default_filename, mustmatch)
13379 Lisp_Object prompt, dir, default_filename, mustmatch;
13380{
13381 struct frame *f = SELECTED_FRAME ();
13382 Lisp_Object file = Qnil;
aed13378 13383 int count = SPECPDL_INDEX ();
6fc2811b
JR
13384 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
13385 char filename[MAX_PATH + 1];
13386 char init_dir[MAX_PATH + 1];
6fc2811b
JR
13387
13388 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
13389 CHECK_STRING (prompt);
13390 CHECK_STRING (dir);
6fc2811b
JR
13391
13392 /* Create the dialog with PROMPT as title, using DIR as initial
13393 directory and using "*" as pattern. */
13394 dir = Fexpand_file_name (dir, Qnil);
d5db4077 13395 strncpy (init_dir, SDATA (dir), MAX_PATH);
6fc2811b
JR
13396 init_dir[MAX_PATH] = '\0';
13397 unixtodos_filename (init_dir);
13398
13399 if (STRINGP (default_filename))
13400 {
13401 char *file_name_only;
d5db4077 13402 char *full_path_name = SDATA (default_filename);
5ac45f98 13403
6fc2811b 13404 unixtodos_filename (full_path_name);
5ac45f98 13405
6fc2811b
JR
13406 file_name_only = strrchr (full_path_name, '\\');
13407 if (!file_name_only)
13408 file_name_only = full_path_name;
13409 else
13410 {
13411 file_name_only++;
6fc2811b 13412 }
ee78dc32 13413
6fc2811b
JR
13414 strncpy (filename, file_name_only, MAX_PATH);
13415 filename[MAX_PATH] = '\0';
13416 }
ee78dc32 13417 else
6fc2811b 13418 filename[0] = '\0';
ee78dc32 13419
1030b26b
JR
13420 {
13421 OPENFILENAME file_details;
5ac45f98 13422
1030b26b
JR
13423 /* Prevent redisplay. */
13424 specbind (Qinhibit_redisplay, Qt);
13425 BLOCK_INPUT;
ee78dc32 13426
1030b26b
JR
13427 bzero (&file_details, sizeof (file_details));
13428 file_details.lStructSize = sizeof (file_details);
13429 file_details.hwndOwner = FRAME_W32_WINDOW (f);
13430 /* Undocumented Bug in Common File Dialog:
13431 If a filter is not specified, shell links are not resolved. */
13432 file_details.lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
13433 file_details.lpstrFile = filename;
13434 file_details.nMaxFile = sizeof (filename);
13435 file_details.lpstrInitialDir = init_dir;
d5db4077 13436 file_details.lpstrTitle = SDATA (prompt);
1030b26b
JR
13437 file_details.Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
13438 | OFN_EXPLORER | OFN_ENABLEHOOK);
13439 if (!NILP (mustmatch))
13440 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
13441
13442 file_details.lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
13443
13444 if (GetOpenFileName (&file_details))
13445 {
13446 dostounix_filename (filename);
13447 if (file_details.nFilterIndex == 2)
13448 {
13449 /* "Folder Only" selected - strip dummy file name. */
13450 char * last = strrchr (filename, '/');
13451 *last = '\0';
13452 }
6fc2811b 13453
1030b26b
JR
13454 file = DECODE_FILE(build_string (filename));
13455 }
13456 /* User cancelled the dialog without making a selection. */
13457 else if (!CommDlgExtendedError ())
13458 file = Qnil;
13459 /* An error occurred, fallback on reading from the mini-buffer. */
13460 else
13461 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
13462 dir, mustmatch, dir, Qfile_name_history,
13463 default_filename, Qnil);
13464
13465 UNBLOCK_INPUT;
13466 file = unbind_to (count, file);
13467 }
ee78dc32 13468
6fc2811b 13469 UNGCPRO;
1edf84e7 13470
6fc2811b
JR
13471 /* Make "Cancel" equivalent to C-g. */
13472 if (NILP (file))
13473 Fsignal (Qquit, Qnil);
ee78dc32 13474
dfff8a69 13475 return unbind_to (count, file);
6fc2811b 13476}
ee78dc32 13477
ee78dc32 13478
6fc2811b 13479\f
6fc2811b
JR
13480/***********************************************************************
13481 w32 specialized functions
13482 ***********************************************************************/
ee78dc32 13483
d84b082d 13484DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
13485 doc: /* Select a font using the W32 font dialog.
13486Returns an X font string corresponding to the selection. */)
d84b082d
JR
13487 (frame, include_proportional)
13488 Lisp_Object frame, include_proportional;
ee78dc32
GV
13489{
13490 FRAME_PTR f = check_x_frame (frame);
13491 CHOOSEFONT cf;
13492 LOGFONT lf;
f46e6225
GV
13493 TEXTMETRIC tm;
13494 HDC hdc;
13495 HANDLE oldobj;
ee78dc32
GV
13496 char buf[100];
13497
13498 bzero (&cf, sizeof (cf));
f46e6225 13499 bzero (&lf, sizeof (lf));
ee78dc32
GV
13500
13501 cf.lStructSize = sizeof (cf);
fbd6baed 13502 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
13503 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
13504
13505 /* Unless include_proportional is non-nil, limit the selection to
13506 monospaced fonts. */
13507 if (NILP (include_proportional))
13508 cf.Flags |= CF_FIXEDPITCHONLY;
13509
ee78dc32
GV
13510 cf.lpLogFont = &lf;
13511
f46e6225
GV
13512 /* Initialize as much of the font details as we can from the current
13513 default font. */
13514 hdc = GetDC (FRAME_W32_WINDOW (f));
13515 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
13516 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
13517 if (GetTextMetrics (hdc, &tm))
13518 {
13519 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
13520 lf.lfWeight = tm.tmWeight;
13521 lf.lfItalic = tm.tmItalic;
13522 lf.lfUnderline = tm.tmUnderlined;
13523 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
13524 lf.lfCharSet = tm.tmCharSet;
13525 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
13526 }
13527 SelectObject (hdc, oldobj);
6fc2811b 13528 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 13529
767b1ff0 13530 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 13531 return Qnil;
ee78dc32
GV
13532
13533 return build_string (buf);
13534}
13535
74e1aeec
JR
13536DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
13537 Sw32_send_sys_command, 1, 2, 0,
13538 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
13539Some useful values for command are #xf030 to maximise frame (#xf020
13540to minimize), #xf120 to restore frame to original size, and #xf100
13541to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
13542screen saver if defined.
13543
13544If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
13545 (command, frame)
13546 Lisp_Object command, frame;
13547{
1edf84e7
GV
13548 FRAME_PTR f = check_x_frame (frame);
13549
b7826503 13550 CHECK_NUMBER (command);
1edf84e7 13551
ce6059da 13552 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
13553
13554 return Qnil;
13555}
13556
55dcfc15 13557DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
13558 doc: /* Get Windows to perform OPERATION on DOCUMENT.
13559This is a wrapper around the ShellExecute system function, which
13560invokes the application registered to handle OPERATION for DOCUMENT.
13561OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
13562nil for the default action), and DOCUMENT is typically the name of a
13563document file or URL, but can also be a program executable to run or
13564a directory to open in the Windows Explorer.
13565
13566If DOCUMENT is a program executable, PARAMETERS can be a string
13567containing command line parameters, but otherwise should be nil.
13568
13569SHOW-FLAG can be used to control whether the invoked application is hidden
13570or minimized. If SHOW-FLAG is nil, the application is displayed normally,
13571otherwise it is an integer representing a ShowWindow flag:
13572
13573 0 - start hidden
13574 1 - start normally
13575 3 - start maximized
13576 6 - start minimized */)
55dcfc15
AI
13577 (operation, document, parameters, show_flag)
13578 Lisp_Object operation, document, parameters, show_flag;
13579{
13580 Lisp_Object current_dir;
13581
b7826503 13582 CHECK_STRING (document);
55dcfc15
AI
13583
13584 /* Encode filename and current directory. */
13585 current_dir = ENCODE_FILE (current_buffer->directory);
13586 document = ENCODE_FILE (document);
13587 if ((int) ShellExecute (NULL,
6fc2811b 13588 (STRINGP (operation) ?
d5db4077
KR
13589 SDATA (operation) : NULL),
13590 SDATA (document),
55dcfc15 13591 (STRINGP (parameters) ?
d5db4077
KR
13592 SDATA (parameters) : NULL),
13593 SDATA (current_dir),
55dcfc15
AI
13594 (INTEGERP (show_flag) ?
13595 XINT (show_flag) : SW_SHOWDEFAULT))
13596 > 32)
13597 return Qt;
90d97e64 13598 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
13599}
13600
ccc2d29c
GV
13601/* Lookup virtual keycode from string representing the name of a
13602 non-ascii keystroke into the corresponding virtual key, using
13603 lispy_function_keys. */
13604static int
13605lookup_vk_code (char *key)
13606{
13607 int i;
13608
13609 for (i = 0; i < 256; i++)
13610 if (lispy_function_keys[i] != 0
13611 && strcmp (lispy_function_keys[i], key) == 0)
13612 return i;
13613
13614 return -1;
13615}
13616
13617/* Convert a one-element vector style key sequence to a hot key
13618 definition. */
13619static int
13620w32_parse_hot_key (key)
13621 Lisp_Object key;
13622{
13623 /* Copied from Fdefine_key and store_in_keymap. */
13624 register Lisp_Object c;
13625 int vk_code;
13626 int lisp_modifiers;
13627 int w32_modifiers;
13628 struct gcpro gcpro1;
13629
b7826503 13630 CHECK_VECTOR (key);
ccc2d29c
GV
13631
13632 if (XFASTINT (Flength (key)) != 1)
13633 return Qnil;
13634
13635 GCPRO1 (key);
13636
13637 c = Faref (key, make_number (0));
13638
13639 if (CONSP (c) && lucid_event_type_list_p (c))
13640 c = Fevent_convert_list (c);
13641
13642 UNGCPRO;
13643
13644 if (! INTEGERP (c) && ! SYMBOLP (c))
13645 error ("Key definition is invalid");
13646
13647 /* Work out the base key and the modifiers. */
13648 if (SYMBOLP (c))
13649 {
13650 c = parse_modifiers (c);
13651 lisp_modifiers = Fcar (Fcdr (c));
13652 c = Fcar (c);
13653 if (!SYMBOLP (c))
13654 abort ();
d5db4077 13655 vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c)));
ccc2d29c
GV
13656 }
13657 else if (INTEGERP (c))
13658 {
13659 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13660 /* Many ascii characters are their own virtual key code. */
13661 vk_code = XINT (c) & CHARACTERBITS;
13662 }
13663
13664 if (vk_code < 0 || vk_code > 255)
13665 return Qnil;
13666
13667 if ((lisp_modifiers & meta_modifier) != 0
13668 && !NILP (Vw32_alt_is_meta))
13669 lisp_modifiers |= alt_modifier;
13670
71eab8d1
AI
13671 /* Supply defs missing from mingw32. */
13672#ifndef MOD_ALT
13673#define MOD_ALT 0x0001
13674#define MOD_CONTROL 0x0002
13675#define MOD_SHIFT 0x0004
13676#define MOD_WIN 0x0008
13677#endif
13678
ccc2d29c
GV
13679 /* Convert lisp modifiers to Windows hot-key form. */
13680 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
13681 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
13682 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
13683 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
13684
13685 return HOTKEY (vk_code, w32_modifiers);
13686}
13687
74e1aeec
JR
13688DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
13689 Sw32_register_hot_key, 1, 1, 0,
13690 doc: /* Register KEY as a hot-key combination.
13691Certain key combinations like Alt-Tab are reserved for system use on
13692Windows, and therefore are normally intercepted by the system. However,
13693most of these key combinations can be received by registering them as
13694hot-keys, overriding their special meaning.
13695
13696KEY must be a one element key definition in vector form that would be
13697acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
13698modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
13699is always interpreted as the Windows modifier keys.
13700
13701The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
13702 (key)
13703 Lisp_Object key;
13704{
13705 key = w32_parse_hot_key (key);
13706
13707 if (NILP (Fmemq (key, w32_grabbed_keys)))
13708 {
13709 /* Reuse an empty slot if possible. */
13710 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
13711
13712 /* Safe to add new key to list, even if we have focus. */
13713 if (NILP (item))
13714 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
13715 else
f3fbd155 13716 XSETCAR (item, key);
ccc2d29c
GV
13717
13718 /* Notify input thread about new hot-key definition, so that it
13719 takes effect without needing to switch focus. */
13720 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
13721 (WPARAM) key, 0);
13722 }
13723
13724 return key;
13725}
13726
74e1aeec
JR
13727DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
13728 Sw32_unregister_hot_key, 1, 1, 0,
13729 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
13730 (key)
13731 Lisp_Object key;
13732{
13733 Lisp_Object item;
13734
13735 if (!INTEGERP (key))
13736 key = w32_parse_hot_key (key);
13737
13738 item = Fmemq (key, w32_grabbed_keys);
13739
13740 if (!NILP (item))
13741 {
13742 /* Notify input thread about hot-key definition being removed, so
13743 that it takes effect without needing focus switch. */
13744 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
13745 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
13746 {
13747 MSG msg;
13748 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13749 }
13750 return Qt;
13751 }
13752 return Qnil;
13753}
13754
74e1aeec
JR
13755DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
13756 Sw32_registered_hot_keys, 0, 0, 0,
13757 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
13758 ()
13759{
13760 return Fcopy_sequence (w32_grabbed_keys);
13761}
13762
74e1aeec
JR
13763DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
13764 Sw32_reconstruct_hot_key, 1, 1, 0,
13765 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
13766 (hotkeyid)
13767 Lisp_Object hotkeyid;
13768{
13769 int vk_code, w32_modifiers;
13770 Lisp_Object key;
13771
b7826503 13772 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
13773
13774 vk_code = HOTKEY_VK_CODE (hotkeyid);
13775 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
13776
13777 if (lispy_function_keys[vk_code])
13778 key = intern (lispy_function_keys[vk_code]);
13779 else
13780 key = make_number (vk_code);
13781
13782 key = Fcons (key, Qnil);
13783 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 13784 key = Fcons (Qshift, key);
ccc2d29c 13785 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 13786 key = Fcons (Qctrl, key);
ccc2d29c 13787 if (w32_modifiers & MOD_ALT)
3ef68e6b 13788 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 13789 if (w32_modifiers & MOD_WIN)
3ef68e6b 13790 key = Fcons (Qhyper, key);
ccc2d29c
GV
13791
13792 return key;
13793}
adcc3809 13794
74e1aeec
JR
13795DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
13796 Sw32_toggle_lock_key, 1, 2, 0,
13797 doc: /* Toggle the state of the lock key KEY.
13798KEY can be `capslock', `kp-numlock', or `scroll'.
13799If the optional parameter NEW-STATE is a number, then the state of KEY
13800is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
13801 (key, new_state)
13802 Lisp_Object key, new_state;
13803{
13804 int vk_code;
adcc3809
GV
13805
13806 if (EQ (key, intern ("capslock")))
13807 vk_code = VK_CAPITAL;
13808 else if (EQ (key, intern ("kp-numlock")))
13809 vk_code = VK_NUMLOCK;
13810 else if (EQ (key, intern ("scroll")))
13811 vk_code = VK_SCROLL;
13812 else
13813 return Qnil;
13814
13815 if (!dwWindowsThreadId)
13816 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
13817
13818 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
13819 (WPARAM) vk_code, (LPARAM) new_state))
13820 {
13821 MSG msg;
13822 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13823 return make_number (msg.wParam);
13824 }
13825 return Qnil;
13826}
ee78dc32 13827\f
2254bcde 13828DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
13829 doc: /* Return storage information about the file system FILENAME is on.
13830Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
13831storage of the file system, FREE is the free storage, and AVAIL is the
13832storage available to a non-superuser. All 3 numbers are in bytes.
13833If the underlying system call fails, value is nil. */)
2254bcde
AI
13834 (filename)
13835 Lisp_Object filename;
13836{
13837 Lisp_Object encoded, value;
13838
b7826503 13839 CHECK_STRING (filename);
2254bcde
AI
13840 filename = Fexpand_file_name (filename, Qnil);
13841 encoded = ENCODE_FILE (filename);
13842
13843 value = Qnil;
13844
13845 /* Determining the required information on Windows turns out, sadly,
13846 to be more involved than one would hope. The original Win32 api
13847 call for this will return bogus information on some systems, but we
13848 must dynamically probe for the replacement api, since that was
13849 added rather late on. */
13850 {
13851 HMODULE hKernel = GetModuleHandle ("kernel32");
13852 BOOL (*pfn_GetDiskFreeSpaceEx)
13853 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
13854 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
13855
13856 /* On Windows, we may need to specify the root directory of the
13857 volume holding FILENAME. */
13858 char rootname[MAX_PATH];
d5db4077 13859 char *name = SDATA (encoded);
2254bcde
AI
13860
13861 /* find the root name of the volume if given */
13862 if (isalpha (name[0]) && name[1] == ':')
13863 {
13864 rootname[0] = name[0];
13865 rootname[1] = name[1];
13866 rootname[2] = '\\';
13867 rootname[3] = 0;
13868 }
13869 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
13870 {
13871 char *str = rootname;
13872 int slashes = 4;
13873 do
13874 {
13875 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
13876 break;
13877 *str++ = *name++;
13878 }
13879 while ( *name );
13880
13881 *str++ = '\\';
13882 *str = 0;
13883 }
13884
13885 if (pfn_GetDiskFreeSpaceEx)
13886 {
ac849ba4
JR
13887 /* Unsigned large integers cannot be cast to double, so
13888 use signed ones instead. */
2254bcde
AI
13889 LARGE_INTEGER availbytes;
13890 LARGE_INTEGER freebytes;
13891 LARGE_INTEGER totalbytes;
13892
13893 if (pfn_GetDiskFreeSpaceEx(rootname,
ac849ba4
JR
13894 (ULARGE_INTEGER *)&availbytes,
13895 (ULARGE_INTEGER *)&totalbytes,
13896 (ULARGE_INTEGER *)&freebytes))
2254bcde
AI
13897 value = list3 (make_float ((double) totalbytes.QuadPart),
13898 make_float ((double) freebytes.QuadPart),
13899 make_float ((double) availbytes.QuadPart));
13900 }
13901 else
13902 {
13903 DWORD sectors_per_cluster;
13904 DWORD bytes_per_sector;
13905 DWORD free_clusters;
13906 DWORD total_clusters;
13907
13908 if (GetDiskFreeSpace(rootname,
13909 &sectors_per_cluster,
13910 &bytes_per_sector,
13911 &free_clusters,
13912 &total_clusters))
13913 value = list3 (make_float ((double) total_clusters
13914 * sectors_per_cluster * bytes_per_sector),
13915 make_float ((double) free_clusters
13916 * sectors_per_cluster * bytes_per_sector),
13917 make_float ((double) free_clusters
13918 * sectors_per_cluster * bytes_per_sector));
13919 }
13920 }
13921
13922 return value;
13923}
13924\f
39a0e135
JR
13925DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
13926 0, 0, 0, doc: /* Return the name of Windows default printer device. */)
13927 ()
13928{
13929 static char pname_buf[256];
13930 int err;
13931 HANDLE hPrn;
13932 PRINTER_INFO_2 *ppi2 = NULL;
13933 DWORD dwNeeded = 0, dwReturned = 0;
13934
13935 /* Retrieve the default string from Win.ini (the registry).
13936 * String will be in form "printername,drivername,portname".
13937 * This is the most portable way to get the default printer. */
13938 if (GetProfileString ("windows", "device", ",,", pname_buf, sizeof (pname_buf)) <= 0)
13939 return Qnil;
13940 /* printername precedes first "," character */
13941 strtok (pname_buf, ",");
13942 /* We want to know more than the printer name */
13943 if (!OpenPrinter (pname_buf, &hPrn, NULL))
13944 return Qnil;
13945 GetPrinter (hPrn, 2, NULL, 0, &dwNeeded);
13946 if (dwNeeded == 0)
13947 {
13948 ClosePrinter (hPrn);
13949 return Qnil;
13950 }
13951 /* Allocate memory for the PRINTER_INFO_2 struct */
13952 ppi2 = (PRINTER_INFO_2 *) xmalloc (dwNeeded);
13953 if (!ppi2)
13954 {
13955 ClosePrinter (hPrn);
13956 return Qnil;
13957 }
13958 /* Call GetPrinter() again with big enouth memory block */
13959 err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned);
13960 ClosePrinter (hPrn);
13961 if (!err)
13962 {
13963 xfree(ppi2);
13964 return Qnil;
13965 }
13966
13967 if (ppi2)
13968 {
13969 if (ppi2->Attributes & PRINTER_ATTRIBUTE_SHARED && ppi2->pServerName)
13970 {
13971 /* a remote printer */
13972 if (*ppi2->pServerName == '\\')
13973 _snprintf(pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName,
13974 ppi2->pShareName);
13975 else
13976 _snprintf(pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName,
13977 ppi2->pShareName);
13978 pname_buf[sizeof (pname_buf) - 1] = '\0';
13979 }
13980 else
13981 {
13982 /* a local printer */
13983 strncpy(pname_buf, ppi2->pPortName, sizeof (pname_buf));
13984 pname_buf[sizeof (pname_buf) - 1] = '\0';
13985 /* `pPortName' can include several ports, delimited by ','.
13986 * we only use the first one. */
13987 strtok(pname_buf, ",");
13988 }
13989 xfree(ppi2);
13990 }
13991
13992 return build_string (pname_buf);
13993}
13994\f
0e3fcdef
JR
13995/***********************************************************************
13996 Initialization
13997 ***********************************************************************/
13998
6d906347
KS
13999/* Keep this list in the same order as frame_parms in frame.c.
14000 Use 0 for unsupported frame parameters. */
14001
14002frame_parm_handler w32_frame_parm_handlers[] =
14003{
14004 x_set_autoraise,
14005 x_set_autolower,
14006 x_set_background_color,
14007 x_set_border_color,
14008 x_set_border_width,
14009 x_set_cursor_color,
14010 x_set_cursor_type,
14011 x_set_font,
14012 x_set_foreground_color,
14013 x_set_icon_name,
14014 x_set_icon_type,
14015 x_set_internal_border_width,
14016 x_set_menu_bar_lines,
14017 x_set_mouse_color,
14018 x_explicitly_set_name,
14019 x_set_scroll_bar_width,
14020 x_set_title,
14021 x_set_unsplittable,
14022 x_set_vertical_scroll_bars,
14023 x_set_visibility,
14024 x_set_tool_bar_lines,
14025 0, /* x_set_scroll_bar_foreground, */
14026 0, /* x_set_scroll_bar_background, */
14027 x_set_screen_gamma,
14028 x_set_line_spacing,
14029 x_set_fringe_width,
14030 x_set_fringe_width,
14031 0, /* x_set_wait_for_wm, */
14032 x_set_fullscreen,
14033};
14034
0e3fcdef 14035void
fbd6baed 14036syms_of_w32fns ()
ee78dc32 14037{
afc390dc
JR
14038 globals_of_w32fns ();
14039 /* This is zero if not using MS-Windows. */
1edf84e7 14040 w32_in_use = 0;
9eb16b62
JR
14041 track_mouse_window = NULL;
14042
d285988b
JR
14043 w32_visible_system_caret_hwnd = NULL;
14044
ee78dc32
GV
14045 Qnone = intern ("none");
14046 staticpro (&Qnone);
ee78dc32
GV
14047 Qsuppress_icon = intern ("suppress-icon");
14048 staticpro (&Qsuppress_icon);
ee78dc32
GV
14049 Qundefined_color = intern ("undefined-color");
14050 staticpro (&Qundefined_color);
dfff8a69
JR
14051 Qcenter = intern ("center");
14052 staticpro (&Qcenter);
dc220243
JR
14053 Qcancel_timer = intern ("cancel-timer");
14054 staticpro (&Qcancel_timer);
ee78dc32 14055
adcc3809
GV
14056 Qhyper = intern ("hyper");
14057 staticpro (&Qhyper);
14058 Qsuper = intern ("super");
14059 staticpro (&Qsuper);
14060 Qmeta = intern ("meta");
14061 staticpro (&Qmeta);
14062 Qalt = intern ("alt");
14063 staticpro (&Qalt);
14064 Qctrl = intern ("ctrl");
14065 staticpro (&Qctrl);
14066 Qcontrol = intern ("control");
14067 staticpro (&Qcontrol);
14068 Qshift = intern ("shift");
14069 staticpro (&Qshift);
f7b9d4d1 14070 /* This is the end of symbol initialization. */
adcc3809 14071
6fc2811b
JR
14072 /* Text property `display' should be nonsticky by default. */
14073 Vtext_property_default_nonsticky
14074 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14075
14076
14077 Qlaplace = intern ("laplace");
14078 staticpro (&Qlaplace);
3cf3436e
JR
14079 Qemboss = intern ("emboss");
14080 staticpro (&Qemboss);
14081 Qedge_detection = intern ("edge-detection");
14082 staticpro (&Qedge_detection);
14083 Qheuristic = intern ("heuristic");
14084 staticpro (&Qheuristic);
14085 QCmatrix = intern (":matrix");
14086 staticpro (&QCmatrix);
14087 QCcolor_adjustment = intern (":color-adjustment");
14088 staticpro (&QCcolor_adjustment);
14089 QCmask = intern (":mask");
14090 staticpro (&QCmask);
6fc2811b 14091
ee78dc32
GV
14092 Fput (Qundefined_color, Qerror_conditions,
14093 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14094 Fput (Qundefined_color, Qerror_message,
14095 build_string ("Undefined color"));
14096
ccc2d29c
GV
14097 staticpro (&w32_grabbed_keys);
14098 w32_grabbed_keys = Qnil;
14099
fbd6baed 14100 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14101 doc: /* An array of color name mappings for windows. */);
fbd6baed 14102 Vw32_color_map = Qnil;
ee78dc32 14103
fbd6baed 14104 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14105 doc: /* Non-nil if alt key presses are passed on to Windows.
14106When non-nil, for example, alt pressed and released and then space will
14107open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14108 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14109
fbd6baed 14110 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14111 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14112When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14113 Vw32_alt_is_meta = Qt;
8c205c63 14114
7d081355 14115 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14116 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14117 XSETINT (Vw32_quit_key, 0);
14118
7d0393cf 14119 DEFVAR_LISP ("w32-pass-lwindow-to-system",
ccc2d29c 14120 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14121 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14122When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14123 Vw32_pass_lwindow_to_system = Qt;
14124
7d0393cf 14125 DEFVAR_LISP ("w32-pass-rwindow-to-system",
ccc2d29c 14126 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14127 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14128When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14129 Vw32_pass_rwindow_to_system = Qt;
14130
adcc3809
GV
14131 DEFVAR_INT ("w32-phantom-key-code",
14132 &Vw32_phantom_key_code,
74e1aeec
JR
14133 doc: /* Virtual key code used to generate \"phantom\" key presses.
14134Value is a number between 0 and 255.
14135
14136Phantom key presses are generated in order to stop the system from
14137acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14138`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14139 /* Although 255 is technically not a valid key code, it works and
14140 means that this hack won't interfere with any real key code. */
14141 Vw32_phantom_key_code = 255;
adcc3809 14142
7d0393cf 14143 DEFVAR_LISP ("w32-enable-num-lock",
ccc2d29c 14144 &Vw32_enable_num_lock,
74e1aeec
JR
14145 doc: /* Non-nil if Num Lock should act normally.
14146Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14147 Vw32_enable_num_lock = Qt;
14148
7d0393cf 14149 DEFVAR_LISP ("w32-enable-caps-lock",
ccc2d29c 14150 &Vw32_enable_caps_lock,
74e1aeec
JR
14151 doc: /* Non-nil if Caps Lock should act normally.
14152Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14153 Vw32_enable_caps_lock = Qt;
14154
14155 DEFVAR_LISP ("w32-scroll-lock-modifier",
14156 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14157 doc: /* Modifier to use for the Scroll Lock on state.
14158The value can be hyper, super, meta, alt, control or shift for the
14159respective modifier, or nil to see Scroll Lock as the key `scroll'.
14160Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14161 Vw32_scroll_lock_modifier = Qt;
14162
14163 DEFVAR_LISP ("w32-lwindow-modifier",
14164 &Vw32_lwindow_modifier,
74e1aeec
JR
14165 doc: /* Modifier to use for the left \"Windows\" key.
14166The value can be hyper, super, meta, alt, control or shift for the
14167respective modifier, or nil to appear as the key `lwindow'.
14168Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14169 Vw32_lwindow_modifier = Qnil;
14170
14171 DEFVAR_LISP ("w32-rwindow-modifier",
14172 &Vw32_rwindow_modifier,
74e1aeec
JR
14173 doc: /* Modifier to use for the right \"Windows\" key.
14174The value can be hyper, super, meta, alt, control or shift for the
14175respective modifier, or nil to appear as the key `rwindow'.
14176Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14177 Vw32_rwindow_modifier = Qnil;
14178
14179 DEFVAR_LISP ("w32-apps-modifier",
14180 &Vw32_apps_modifier,
74e1aeec
JR
14181 doc: /* Modifier to use for the \"Apps\" key.
14182The value can be hyper, super, meta, alt, control or shift for the
14183respective modifier, or nil to appear as the key `apps'.
14184Any other value will cause the key to be ignored. */);
ccc2d29c 14185 Vw32_apps_modifier = Qnil;
da36a4d6 14186
d84b082d 14187 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 14188 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 14189 w32_enable_synthesized_fonts = 0;
5ac45f98 14190
fbd6baed 14191 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 14192 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 14193 Vw32_enable_palette = Qt;
5ac45f98 14194
fbd6baed
GV
14195 DEFVAR_INT ("w32-mouse-button-tolerance",
14196 &Vw32_mouse_button_tolerance,
74e1aeec
JR
14197 doc: /* Analogue of double click interval for faking middle mouse events.
14198The value is the minimum time in milliseconds that must elapse between
14199left/right button down events before they are considered distinct events.
14200If both mouse buttons are depressed within this interval, a middle mouse
14201button down event is generated instead. */);
fbd6baed 14202 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 14203
fbd6baed
GV
14204 DEFVAR_INT ("w32-mouse-move-interval",
14205 &Vw32_mouse_move_interval,
74e1aeec
JR
14206 doc: /* Minimum interval between mouse move events.
14207The value is the minimum time in milliseconds that must elapse between
14208successive mouse move (or scroll bar drag) events before they are
14209reported as lisp events. */);
247be837 14210 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 14211
74214547
JR
14212 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
14213 &w32_pass_extra_mouse_buttons_to_system,
14214 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
14215Recent versions of Windows support mice with up to five buttons.
14216Since most applications don't support these extra buttons, most mouse
14217drivers will allow you to map them to functions at the system level.
14218If this variable is non-nil, Emacs will pass them on, allowing the
14219system to handle them. */);
14220 w32_pass_extra_mouse_buttons_to_system = 0;
14221
ee78dc32 14222 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
6e2d67d8 14223 doc: /* List of directories to search for window system bitmap files. */);
ee78dc32
GV
14224 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14225
14226 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
14227 doc: /* The shape of the pointer when over text.
14228Changing the value does not affect existing frames
14229unless you set the mouse color. */);
ee78dc32
GV
14230 Vx_pointer_shape = Qnil;
14231
ee78dc32
GV
14232 Vx_nontext_pointer_shape = Qnil;
14233
14234 Vx_mode_pointer_shape = Qnil;
14235
0af913d7 14236 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
14237 doc: /* The shape of the pointer when Emacs is busy.
14238This variable takes effect when you create a new frame
14239or when you set the mouse color. */);
0af913d7 14240 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 14241
0af913d7 14242 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 14243 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 14244 display_hourglass_p = 1;
7d0393cf 14245
0af913d7 14246 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
14247 doc: /* *Seconds to wait before displaying an hourglass pointer.
14248Value must be an integer or float. */);
0af913d7 14249 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 14250
6fc2811b 14251 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 14252 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
14253 doc: /* The shape of the pointer when over mouse-sensitive text.
14254This variable takes effect when you create a new frame
14255or when you set the mouse color. */);
ee78dc32
GV
14256 Vx_sensitive_text_pointer_shape = Qnil;
14257
4694d762
JR
14258 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14259 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
14260 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14261This variable takes effect when you create a new frame
14262or when you set the mouse color. */);
4694d762
JR
14263 Vx_window_horizontal_drag_shape = Qnil;
14264
ee78dc32 14265 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 14266 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
14267 Vx_cursor_fore_pixel = Qnil;
14268
3cf3436e 14269 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
14270 doc: /* Maximum size for tooltips.
14271Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e 14272 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
7d0393cf 14273
ee78dc32 14274 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
14275 doc: /* Non-nil if no window manager is in use.
14276Emacs doesn't try to figure this out; this is always nil
14277unless you set it to something else. */);
ee78dc32
GV
14278 /* We don't have any way to find this out, so set it to nil
14279 and maybe the user would like to set it to t. */
14280 Vx_no_window_manager = Qnil;
14281
4587b026
GV
14282 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14283 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
14284 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14285
14286Since Emacs gets width of a font matching with this regexp from
14287PIXEL_SIZE field of the name, font finding mechanism gets faster for
14288such a font. This is especially effective for such large fonts as
14289Chinese, Japanese, and Korean. */);
4587b026
GV
14290 Vx_pixel_size_width_font_regexp = Qnil;
14291
6fc2811b 14292 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
14293 doc: /* Time after which cached images are removed from the cache.
14294When an image has not been displayed this many seconds, remove it
14295from the image cache. Value must be an integer or nil with nil
14296meaning don't clear the cache. */);
6fc2811b
JR
14297 Vimage_cache_eviction_delay = make_number (30 * 60);
14298
33d52f9c
GV
14299 DEFVAR_LISP ("w32-bdf-filename-alist",
14300 &Vw32_bdf_filename_alist,
74e1aeec 14301 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
14302 Vw32_bdf_filename_alist = Qnil;
14303
1075afa9
GV
14304 DEFVAR_BOOL ("w32-strict-fontnames",
14305 &w32_strict_fontnames,
74e1aeec
JR
14306 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14307Default is nil, which allows old fontnames that are not XLFD compliant,
14308and allows third-party CJK display to work by specifying false charset
14309fields to trick Emacs into translating to Big5, SJIS etc.
14310Setting this to t will prevent wrong fonts being selected when
14311fontsets are automatically created. */);
1075afa9
GV
14312 w32_strict_fontnames = 0;
14313
c0611964
AI
14314 DEFVAR_BOOL ("w32-strict-painting",
14315 &w32_strict_painting,
74e1aeec
JR
14316 doc: /* Non-nil means use strict rules for repainting frames.
14317Set this to nil to get the old behaviour for repainting; this should
14318only be necessary if the default setting causes problems. */);
c0611964
AI
14319 w32_strict_painting = 1;
14320
dfff8a69
JR
14321 DEFVAR_LISP ("w32-charset-info-alist",
14322 &Vw32_charset_info_alist,
b3700ae7
JR
14323 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14324Each entry should be of the form:
74e1aeec
JR
14325
14326 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14327
14328where CHARSET_NAME is a string used in font names to identify the charset,
14329WINDOWS_CHARSET is a symbol that can be one of:
14330w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14331w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14332w32-charset-chinesebig5,
74e1aeec
JR
14333w32-charset-johab, w32-charset-hebrew,
14334w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14335w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14336w32-charset-russian, w32-charset-mac, w32-charset-baltic,
74e1aeec 14337w32-charset-unicode,
74e1aeec
JR
14338or w32-charset-oem.
14339CODEPAGE should be an integer specifying the codepage that should be used
14340to display the character set, t to do no translation and output as Unicode,
14341or nil to do no translation and output as 8 bit (or multibyte on far-east
14342versions of Windows) characters. */);
dfff8a69
JR
14343 Vw32_charset_info_alist = Qnil;
14344
14345 staticpro (&Qw32_charset_ansi);
14346 Qw32_charset_ansi = intern ("w32-charset-ansi");
14347 staticpro (&Qw32_charset_symbol);
14348 Qw32_charset_symbol = intern ("w32-charset-symbol");
14349 staticpro (&Qw32_charset_shiftjis);
14350 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
14351 staticpro (&Qw32_charset_hangeul);
14352 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
14353 staticpro (&Qw32_charset_chinesebig5);
14354 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
14355 staticpro (&Qw32_charset_gb2312);
14356 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
14357 staticpro (&Qw32_charset_oem);
14358 Qw32_charset_oem = intern ("w32-charset-oem");
14359
14360#ifdef JOHAB_CHARSET
14361 {
14362 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
14363 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
14364 doc: /* Internal variable. */);
dfff8a69
JR
14365
14366 staticpro (&Qw32_charset_johab);
14367 Qw32_charset_johab = intern ("w32-charset-johab");
14368 staticpro (&Qw32_charset_easteurope);
14369 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
14370 staticpro (&Qw32_charset_turkish);
14371 Qw32_charset_turkish = intern ("w32-charset-turkish");
14372 staticpro (&Qw32_charset_baltic);
14373 Qw32_charset_baltic = intern ("w32-charset-baltic");
14374 staticpro (&Qw32_charset_russian);
14375 Qw32_charset_russian = intern ("w32-charset-russian");
14376 staticpro (&Qw32_charset_arabic);
14377 Qw32_charset_arabic = intern ("w32-charset-arabic");
14378 staticpro (&Qw32_charset_greek);
14379 Qw32_charset_greek = intern ("w32-charset-greek");
14380 staticpro (&Qw32_charset_hebrew);
14381 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
14382 staticpro (&Qw32_charset_vietnamese);
14383 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
14384 staticpro (&Qw32_charset_thai);
14385 Qw32_charset_thai = intern ("w32-charset-thai");
14386 staticpro (&Qw32_charset_mac);
14387 Qw32_charset_mac = intern ("w32-charset-mac");
14388 }
14389#endif
14390
14391#ifdef UNICODE_CHARSET
14392 {
14393 static int w32_unicode_charset_defined = 1;
14394 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
14395 &w32_unicode_charset_defined,
14396 doc: /* Internal variable. */);
dfff8a69
JR
14397
14398 staticpro (&Qw32_charset_unicode);
14399 Qw32_charset_unicode = intern ("w32-charset-unicode");
14400#endif
14401
767b1ff0 14402#if 0 /* TODO: Port to W32 */
6fc2811b
JR
14403 defsubr (&Sx_change_window_property);
14404 defsubr (&Sx_delete_window_property);
14405 defsubr (&Sx_window_property);
14406#endif
2d764c78 14407 defsubr (&Sxw_display_color_p);
ee78dc32 14408 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
14409 defsubr (&Sxw_color_defined_p);
14410 defsubr (&Sxw_color_values);
ee78dc32
GV
14411 defsubr (&Sx_server_max_request_size);
14412 defsubr (&Sx_server_vendor);
14413 defsubr (&Sx_server_version);
14414 defsubr (&Sx_display_pixel_width);
14415 defsubr (&Sx_display_pixel_height);
14416 defsubr (&Sx_display_mm_width);
14417 defsubr (&Sx_display_mm_height);
14418 defsubr (&Sx_display_screens);
14419 defsubr (&Sx_display_planes);
14420 defsubr (&Sx_display_color_cells);
14421 defsubr (&Sx_display_visual_class);
14422 defsubr (&Sx_display_backing_store);
14423 defsubr (&Sx_display_save_under);
ee78dc32 14424 defsubr (&Sx_create_frame);
ee78dc32
GV
14425 defsubr (&Sx_open_connection);
14426 defsubr (&Sx_close_connection);
14427 defsubr (&Sx_display_list);
14428 defsubr (&Sx_synchronize);
14429
fbd6baed 14430 /* W32 specific functions */
ee78dc32 14431
1edf84e7 14432 defsubr (&Sw32_focus_frame);
fbd6baed
GV
14433 defsubr (&Sw32_select_font);
14434 defsubr (&Sw32_define_rgb_color);
14435 defsubr (&Sw32_default_color_map);
14436 defsubr (&Sw32_load_color_file);
1edf84e7 14437 defsubr (&Sw32_send_sys_command);
55dcfc15 14438 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
14439 defsubr (&Sw32_register_hot_key);
14440 defsubr (&Sw32_unregister_hot_key);
14441 defsubr (&Sw32_registered_hot_keys);
14442 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 14443 defsubr (&Sw32_toggle_lock_key);
33d52f9c 14444 defsubr (&Sw32_find_bdf_fonts);
4587b026 14445
2254bcde 14446 defsubr (&Sfile_system_info);
39a0e135 14447 defsubr (&Sdefault_printer_name);
2254bcde 14448
4587b026
GV
14449 /* Setting callback functions for fontset handler. */
14450 get_font_info_func = w32_get_font_info;
6fc2811b
JR
14451
14452#if 0 /* This function pointer doesn't seem to be used anywhere.
14453 And the pointer assigned has the wrong type, anyway. */
4587b026 14454 list_fonts_func = w32_list_fonts;
6fc2811b
JR
14455#endif
14456
4587b026
GV
14457 load_font_func = w32_load_font;
14458 find_ccl_program_func = w32_find_ccl_program;
14459 query_font_func = w32_query_font;
14460 set_frame_fontset_func = x_set_font;
14461 check_window_system_func = check_w32;
6fc2811b 14462
6fc2811b
JR
14463 /* Images. */
14464 Qxbm = intern ("xbm");
14465 staticpro (&Qxbm);
a93f4566
GM
14466 QCconversion = intern (":conversion");
14467 staticpro (&QCconversion);
6fc2811b
JR
14468 QCheuristic_mask = intern (":heuristic-mask");
14469 staticpro (&QCheuristic_mask);
14470 QCcolor_symbols = intern (":color-symbols");
14471 staticpro (&QCcolor_symbols);
6fc2811b
JR
14472 QCascent = intern (":ascent");
14473 staticpro (&QCascent);
14474 QCmargin = intern (":margin");
14475 staticpro (&QCmargin);
14476 QCrelief = intern (":relief");
14477 staticpro (&QCrelief);
14478 Qpostscript = intern ("postscript");
14479 staticpro (&Qpostscript);
14480 QCloader = intern (":loader");
14481 staticpro (&QCloader);
14482 QCbounding_box = intern (":bounding-box");
14483 staticpro (&QCbounding_box);
14484 QCpt_width = intern (":pt-width");
14485 staticpro (&QCpt_width);
14486 QCpt_height = intern (":pt-height");
14487 staticpro (&QCpt_height);
14488 QCindex = intern (":index");
14489 staticpro (&QCindex);
14490 Qpbm = intern ("pbm");
14491 staticpro (&Qpbm);
14492
14493#if HAVE_XPM
14494 Qxpm = intern ("xpm");
14495 staticpro (&Qxpm);
14496#endif
7d0393cf 14497
6fc2811b
JR
14498#if HAVE_JPEG
14499 Qjpeg = intern ("jpeg");
14500 staticpro (&Qjpeg);
7d0393cf 14501#endif
6fc2811b
JR
14502
14503#if HAVE_TIFF
14504 Qtiff = intern ("tiff");
14505 staticpro (&Qtiff);
7d0393cf 14506#endif
6fc2811b
JR
14507
14508#if HAVE_GIF
14509 Qgif = intern ("gif");
14510 staticpro (&Qgif);
14511#endif
14512
14513#if HAVE_PNG
14514 Qpng = intern ("png");
14515 staticpro (&Qpng);
14516#endif
14517
14518 defsubr (&Sclear_image_cache);
ac849ba4
JR
14519 defsubr (&Simage_size);
14520 defsubr (&Simage_mask_p);
6fc2811b 14521
0af913d7
GM
14522 hourglass_atimer = NULL;
14523 hourglass_shown_p = 0;
6fc2811b
JR
14524 defsubr (&Sx_show_tip);
14525 defsubr (&Sx_hide_tip);
6fc2811b 14526 tip_timer = Qnil;
57fa2774
JR
14527 staticpro (&tip_timer);
14528 tip_frame = Qnil;
14529 staticpro (&tip_frame);
6fc2811b 14530
ca56d953
JR
14531 last_show_tip_args = Qnil;
14532 staticpro (&last_show_tip_args);
14533
6fc2811b
JR
14534 defsubr (&Sx_file_dialog);
14535}
14536
c922a224 14537
9785d95b
BK
14538/*
14539 globals_of_w32fns is used to initialize those global variables that
14540 must always be initialized on startup even when the global variable
14541 initialized is non zero (see the function main in emacs.c).
14542 globals_of_w32fns is called from syms_of_w32fns when the global
14543 variable initialized is 0 and directly from main when initialized
14544 is non zero.
14545 */
14546void globals_of_w32fns ()
14547{
14548 HMODULE user32_lib = GetModuleHandle ("user32.dll");
ccc0fdaa
JR
14549 /*
14550 TrackMouseEvent not available in all versions of Windows, so must load
14551 it dynamically. Do it once, here, instead of every time it is used.
9785d95b 14552 */
ccc0fdaa
JR
14553 track_mouse_event_fn = (TrackMouseEvent_Proc)
14554 GetProcAddress (user32_lib, "TrackMouseEvent");
14555 /* ditto for GetClipboardSequenceNumber. */
14556 clipboard_sequence_fn = (ClipboardSequence_Proc)
14557 GetProcAddress (user32_lib, "GetClipboardSequenceNumber");
9785d95b 14558}
6fc2811b 14559
839b1909
JR
14560/* Initialize image types. Based on which libraries are available. */
14561static void
14562init_external_image_libraries ()
6fc2811b 14563{
afc390dc 14564 HINSTANCE library;
7d0393cf 14565
6fc2811b 14566#if HAVE_XPM
c736ffda
JR
14567 if ((library = LoadLibrary ("libXpm.dll")))
14568 {
14569 if (init_xpm_functions (library))
14570 define_image_type (&xpm_type);
14571 }
14572
6fc2811b 14573#endif
7d0393cf 14574
6fc2811b 14575#if HAVE_JPEG
afc390dc 14576 /* Try loading jpeg library under probable names. */
c922a224 14577 if ((library = LoadLibrary ("libjpeg.dll"))
100dcd40 14578 || (library = LoadLibrary ("jpeg-62.dll"))
c922a224 14579 || (library = LoadLibrary ("jpeg.dll")))
afc390dc
JR
14580 {
14581 if (init_jpeg_functions (library))
14582 define_image_type (&jpeg_type);
14583 }
6fc2811b 14584#endif
7d0393cf 14585
6fc2811b 14586#if HAVE_TIFF
12b918b2
JB
14587 if (library = LoadLibrary ("libtiff.dll"))
14588 {
14589 if (init_tiff_functions (library))
14590 define_image_type (&tiff_type);
14591 }
6fc2811b 14592#endif
919f1e88 14593
6fc2811b 14594#if HAVE_GIF
1ffb278b
JB
14595 if (library = LoadLibrary ("libungif.dll"))
14596 {
14597 if (init_gif_functions (library))
14598 define_image_type (&gif_type);
14599 }
6fc2811b 14600#endif
7d0393cf 14601
6fc2811b 14602#if HAVE_PNG
839b1909
JR
14603 /* Ensure zlib is loaded. Try debug version first. */
14604 if (!LoadLibrary ("zlibd.dll"))
14605 LoadLibrary ("zlib.dll");
14606
14607 /* Try loading libpng under probable names. */
afc390dc
JR
14608 if ((library = LoadLibrary ("libpng13d.dll"))
14609 || (library = LoadLibrary ("libpng13.dll"))
14610 || (library = LoadLibrary ("libpng12d.dll"))
14611 || (library = LoadLibrary ("libpng12.dll"))
14612 || (library = LoadLibrary ("libpng.dll")))
839b1909 14613 {
afc390dc 14614 if (init_png_functions (library))
839b1909
JR
14615 define_image_type (&png_type);
14616 }
6fc2811b 14617#endif
ee78dc32
GV
14618}
14619
839b1909
JR
14620void
14621init_xfns ()
14622{
14623 image_types = NULL;
14624 Vimage_types = Qnil;
14625
14626 define_image_type (&pbm_type);
14627 define_image_type (&xbm_type);
14628
14629#if 0 /* TODO : Ghostscript support for W32 */
14630 define_image_type (&gs_type);
14631#endif
14632
14633 /* Image types that rely on external libraries are loaded dynamically
14634 if the library is available. */
14635 init_external_image_libraries ();
14636}
14637
ee78dc32
GV
14638#undef abort
14639
7d0393cf 14640void
fbd6baed 14641w32_abort()
ee78dc32 14642{
5ac45f98
GV
14643 int button;
14644 button = MessageBox (NULL,
14645 "A fatal error has occurred!\n\n"
14646 "Select Abort to exit, Retry to debug, Ignore to continue",
14647 "Emacs Abort Dialog",
14648 MB_ICONEXCLAMATION | MB_TASKMODAL
14649 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
14650 switch (button)
14651 {
14652 case IDRETRY:
14653 DebugBreak ();
14654 break;
14655 case IDIGNORE:
14656 break;
14657 case IDABORT:
14658 default:
14659 abort ();
14660 break;
14661 }
ee78dc32 14662}
d573caac 14663
83c75055
GV
14664/* For convenience when debugging. */
14665int
14666w32_last_error()
14667{
14668 return GetLastError ();
14669}
ab5796a9
MB
14670
14671/* arch-tag: 707589ab-b9be-4638-8cdd-74629cc9b446
14672 (do not change this comment) */