(enum fringe_bitmap_type): Define here.
[bpt/emacs.git] / src / w32fns.c
CommitLineData
e9e23e23 1/* Graphical user interface functions for the Microsoft W32 API.
a93f4566 2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
6fc2811b 3 Free Software Foundation, Inc.
ee78dc32
GV
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
ee78dc32
GV
21
22/* Added by Kevin Gallo */
23
ee78dc32 24#include <config.h>
1edf84e7
GV
25
26#include <signal.h>
ee78dc32 27#include <stdio.h>
1edf84e7
GV
28#include <limits.h>
29#include <errno.h>
ee78dc32
GV
30
31#include "lisp.h"
4587b026 32#include "charset.h"
71eab8d1 33#include "dispextern.h"
ee78dc32 34#include "w32term.h"
c7501041 35#include "keyboard.h"
ee78dc32
GV
36#include "frame.h"
37#include "window.h"
38#include "buffer.h"
126f2e35 39#include "fontset.h"
6fc2811b 40#include "intervals.h"
ee78dc32 41#include "blockinput.h"
57bda87a 42#include "epaths.h"
489f9371 43#include "w32heap.h"
ee78dc32 44#include "termhooks.h"
4587b026 45#include "coding.h"
3545439c 46#include "ccl.h"
6fc2811b
JR
47#include "systime.h"
48
49#include "bitmaps/gray.xbm"
ee78dc32
GV
50
51#include <commdlg.h>
cb9e33d4 52#include <shellapi.h>
6fc2811b 53#include <ctype.h>
ee78dc32 54
1030b26b
JR
55#include <dlgs.h>
56#define FILE_NAME_TEXT_FIELD edt1
57
9785d95b
BK
58void syms_of_w32fns ();
59void globals_of_w32fns ();
839b1909 60static void init_external_image_libraries ();
9785d95b 61
ee78dc32 62extern void free_frame_menubar ();
9eb16b62 63extern void x_compute_fringe_widths P_ ((struct frame *, int));
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/* The name we're using in resource queries. */
146Lisp_Object Vx_resource_name;
147
148/* Non nil if no window manager is in use. */
149Lisp_Object Vx_no_window_manager;
150
0af913d7 151/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 152
0af913d7 153int display_hourglass_p;
6fc2811b 154
ee78dc32
GV
155/* The background and shape of the mouse pointer, and shape when not
156 over text or in the modeline. */
dfff8a69 157
ee78dc32 158Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
c9b2104d 159Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape, Vx_hand_shape;
6fc2811b 160
ee78dc32 161/* The shape when over mouse-sensitive text. */
dfff8a69 162
ee78dc32
GV
163Lisp_Object Vx_sensitive_text_pointer_shape;
164
c9b2104d
JR
165#ifndef IDC_HAND
166#define IDC_HAND MAKEINTRESOURCE(32649)
167#endif
168
ee78dc32 169/* Color of chars displayed in cursor box. */
dfff8a69 170
ee78dc32
GV
171Lisp_Object Vx_cursor_fore_pixel;
172
1edf84e7 173/* Nonzero if using Windows. */
dfff8a69 174
1edf84e7
GV
175static int w32_in_use;
176
ee78dc32 177/* Search path for bitmap files. */
dfff8a69 178
ee78dc32
GV
179Lisp_Object Vx_bitmap_file_path;
180
4587b026 181/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 182
4587b026
GV
183Lisp_Object Vx_pixel_size_width_font_regexp;
184
33d52f9c
GV
185/* Alist of bdf fonts and the files that define them. */
186Lisp_Object Vw32_bdf_filename_alist;
187
f46e6225 188/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
189int w32_strict_fontnames;
190
c0611964
AI
191/* A flag to control whether we should only repaint if GetUpdateRect
192 indicates there is an update region. */
193int w32_strict_painting;
194
dfff8a69
JR
195/* Associative list linking character set strings to Windows codepages. */
196Lisp_Object Vw32_charset_info_alist;
197
198/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
199#ifndef VIETNAMESE_CHARSET
200#define VIETNAMESE_CHARSET 163
201#endif
202
ee78dc32
GV
203Lisp_Object Qauto_raise;
204Lisp_Object Qauto_lower;
ee78dc32
GV
205Lisp_Object Qborder_color;
206Lisp_Object Qborder_width;
ab0bb234 207extern Lisp_Object Qbox;
ee78dc32
GV
208Lisp_Object Qcursor_color;
209Lisp_Object Qcursor_type;
ee78dc32
GV
210Lisp_Object Qgeometry;
211Lisp_Object Qicon_left;
212Lisp_Object Qicon_top;
213Lisp_Object Qicon_type;
214Lisp_Object Qicon_name;
215Lisp_Object Qinternal_border_width;
216Lisp_Object Qleft;
1026b400 217Lisp_Object Qright;
ee78dc32
GV
218Lisp_Object Qmouse_color;
219Lisp_Object Qnone;
220Lisp_Object Qparent_id;
221Lisp_Object Qscroll_bar_width;
222Lisp_Object Qsuppress_icon;
ee78dc32
GV
223Lisp_Object Qundefined_color;
224Lisp_Object Qvertical_scroll_bars;
225Lisp_Object Qvisibility;
226Lisp_Object Qwindow_id;
227Lisp_Object Qx_frame_parameter;
228Lisp_Object Qx_resource_name;
229Lisp_Object Quser_position;
230Lisp_Object Quser_size;
6fc2811b 231Lisp_Object Qscreen_gamma;
dfff8a69
JR
232Lisp_Object Qline_spacing;
233Lisp_Object Qcenter;
dc220243 234Lisp_Object Qcancel_timer;
adcc3809
GV
235Lisp_Object Qhyper;
236Lisp_Object Qsuper;
237Lisp_Object Qmeta;
238Lisp_Object Qalt;
239Lisp_Object Qctrl;
240Lisp_Object Qcontrol;
241Lisp_Object Qshift;
242
dfff8a69
JR
243Lisp_Object Qw32_charset_ansi;
244Lisp_Object Qw32_charset_default;
245Lisp_Object Qw32_charset_symbol;
246Lisp_Object Qw32_charset_shiftjis;
767b1ff0 247Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
248Lisp_Object Qw32_charset_gb2312;
249Lisp_Object Qw32_charset_chinesebig5;
250Lisp_Object Qw32_charset_oem;
251
71eab8d1
AI
252#ifndef JOHAB_CHARSET
253#define JOHAB_CHARSET 130
254#endif
dfff8a69
JR
255#ifdef JOHAB_CHARSET
256Lisp_Object Qw32_charset_easteurope;
257Lisp_Object Qw32_charset_turkish;
258Lisp_Object Qw32_charset_baltic;
259Lisp_Object Qw32_charset_russian;
260Lisp_Object Qw32_charset_arabic;
261Lisp_Object Qw32_charset_greek;
262Lisp_Object Qw32_charset_hebrew;
767b1ff0 263Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
264Lisp_Object Qw32_charset_thai;
265Lisp_Object Qw32_charset_johab;
266Lisp_Object Qw32_charset_mac;
267#endif
268
269#ifdef UNICODE_CHARSET
270Lisp_Object Qw32_charset_unicode;
271#endif
272
f7b9d4d1
JR
273Lisp_Object Qfullscreen;
274Lisp_Object Qfullwidth;
275Lisp_Object Qfullheight;
276Lisp_Object Qfullboth;
277
6fc2811b
JR
278extern Lisp_Object Qtop;
279extern Lisp_Object Qdisplay;
6fc2811b 280
5ac45f98
GV
281/* State variables for emulating a three button mouse. */
282#define LMOUSE 1
283#define MMOUSE 2
284#define RMOUSE 4
285
286static int button_state = 0;
fbd6baed 287static W32Msg saved_mouse_button_msg;
48094ace 288static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
fbd6baed 289static W32Msg saved_mouse_move_msg;
48094ace 290static unsigned mouse_move_timer = 0;
84fb1139 291
9eb16b62
JR
292/* Window that is tracking the mouse. */
293static HWND track_mouse_window;
f60ae425
BK
294
295typedef BOOL (WINAPI * TrackMouseEvent_Proc) (
296 IN OUT LPTRACKMOUSEEVENT lpEventTrack
297 );
298
299TrackMouseEvent_Proc track_mouse_event_fn=NULL;
9eb16b62 300
93fbe8b7 301/* W95 mousewheel handler */
7d0393cf 302unsigned int msh_mousewheel = 0;
93fbe8b7 303
48094ace 304/* Timers */
84fb1139
KH
305#define MOUSE_BUTTON_ID 1
306#define MOUSE_MOVE_ID 2
48094ace
JR
307#define MENU_FREE_ID 3
308/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
309 is received. */
310#define MENU_FREE_DELAY 1000
311static unsigned menu_free_timer = 0;
5ac45f98 312
ee78dc32 313/* The below are defined in frame.c. */
dfff8a69 314
ee78dc32 315extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 316extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 317extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
318
319extern Lisp_Object Vwindow_system_version;
320
4b817373
RS
321Lisp_Object Qface_set_after_frame_default;
322
937e601e
AI
323#ifdef GLYPH_DEBUG
324int image_cache_refcount, dpyinfo_refcount;
325#endif
326
327
fbd6baed
GV
328/* From w32term.c. */
329extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 330extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 331
65906840 332extern HWND w32_system_caret_hwnd;
93f2ca61 333
65906840
JR
334extern int w32_system_caret_height;
335extern int w32_system_caret_x;
336extern int w32_system_caret_y;
93f2ca61
JR
337extern int w32_use_visible_system_caret;
338
d285988b 339static HWND w32_visible_system_caret_hwnd;
65906840 340
ee78dc32 341\f
1edf84e7
GV
342/* Error if we are not connected to MS-Windows. */
343void
344check_w32 ()
345{
346 if (! w32_in_use)
347 error ("MS-Windows not in use or not initialized");
348}
349
350/* Nonzero if we can use mouse menus.
351 You should not call this unless HAVE_MENUS is defined. */
7d0393cf 352
1edf84e7
GV
353int
354have_menus_p ()
355{
356 return w32_in_use;
357}
358
ee78dc32 359/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 360 and checking validity for W32. */
ee78dc32
GV
361
362FRAME_PTR
363check_x_frame (frame)
364 Lisp_Object frame;
365{
366 FRAME_PTR f;
367
368 if (NILP (frame))
6fc2811b 369 frame = selected_frame;
b7826503 370 CHECK_LIVE_FRAME (frame);
6fc2811b 371 f = XFRAME (frame);
fbd6baed
GV
372 if (! FRAME_W32_P (f))
373 error ("non-w32 frame used");
ee78dc32
GV
374 return f;
375}
376
7d0393cf 377/* Let the user specify a display with a frame.
fbd6baed 378 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
379 the first display on the list. */
380
fbd6baed 381static struct w32_display_info *
ee78dc32
GV
382check_x_display_info (frame)
383 Lisp_Object frame;
384{
385 if (NILP (frame))
386 {
6fc2811b 387 struct frame *sf = XFRAME (selected_frame);
7d0393cf 388
6fc2811b
JR
389 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
390 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 391 else
fbd6baed 392 return &one_w32_display_info;
ee78dc32
GV
393 }
394 else if (STRINGP (frame))
395 return x_display_info_for_name (frame);
396 else
397 {
398 FRAME_PTR f;
399
b7826503 400 CHECK_LIVE_FRAME (frame);
ee78dc32 401 f = XFRAME (frame);
fbd6baed
GV
402 if (! FRAME_W32_P (f))
403 error ("non-w32 frame used");
404 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
405 }
406}
407\f
fbd6baed 408/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
409 It could be the frame's main window or an icon window. */
410
411/* This function can be called during GC, so use GC_xxx type test macros. */
412
413struct frame *
414x_window_to_frame (dpyinfo, wdesc)
fbd6baed 415 struct w32_display_info *dpyinfo;
ee78dc32
GV
416 HWND wdesc;
417{
418 Lisp_Object tail, frame;
419 struct frame *f;
420
8e713be6 421 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 422 {
8e713be6 423 frame = XCAR (tail);
ee78dc32
GV
424 if (!GC_FRAMEP (frame))
425 continue;
426 f = XFRAME (frame);
2d764c78 427 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 428 continue;
0af913d7 429 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
430 return f;
431
fbd6baed 432 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
433 return f;
434 }
435 return 0;
436}
437
438\f
439
440/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
441 id, which is just an int that this section returns. Bitmaps are
442 reference counted so they can be shared among frames.
443
444 Bitmap indices are guaranteed to be > 0, so a negative number can
445 be used to indicate no bitmap.
446
447 If you use x_create_bitmap_from_data, then you must keep track of
448 the bitmaps yourself. That is, creating a bitmap from the same
449 data more than once will not be caught. */
450
451
452/* Functions to access the contents of a bitmap, given an id. */
453
454int
455x_bitmap_height (f, id)
456 FRAME_PTR f;
457 int id;
458{
fbd6baed 459 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
460}
461
462int
463x_bitmap_width (f, id)
464 FRAME_PTR f;
465 int id;
466{
fbd6baed 467 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
468}
469
470int
471x_bitmap_pixmap (f, id)
472 FRAME_PTR f;
473 int id;
474{
fbd6baed 475 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
476}
477
478
479/* Allocate a new bitmap record. Returns index of new record. */
480
481static int
482x_allocate_bitmap_record (f)
483 FRAME_PTR f;
484{
fbd6baed 485 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
486 int i;
487
488 if (dpyinfo->bitmaps == NULL)
489 {
490 dpyinfo->bitmaps_size = 10;
491 dpyinfo->bitmaps
fbd6baed 492 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
493 dpyinfo->bitmaps_last = 1;
494 return 1;
495 }
496
497 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
498 return ++dpyinfo->bitmaps_last;
499
500 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
501 if (dpyinfo->bitmaps[i].refcount == 0)
502 return i + 1;
503
504 dpyinfo->bitmaps_size *= 2;
505 dpyinfo->bitmaps
fbd6baed
GV
506 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
507 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
508 return ++dpyinfo->bitmaps_last;
509}
510
511/* Add one reference to the reference count of the bitmap with id ID. */
512
513void
514x_reference_bitmap (f, id)
515 FRAME_PTR f;
516 int id;
517{
fbd6baed 518 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
519}
520
521/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
522
523int
524x_create_bitmap_from_data (f, bits, width, height)
525 struct frame *f;
526 char *bits;
527 unsigned int width, height;
528{
fbd6baed 529 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
530 Pixmap bitmap;
531 int id;
532
533 bitmap = CreateBitmap (width, height,
fbd6baed
GV
534 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
535 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
536 bits);
537
538 if (! bitmap)
539 return -1;
540
541 id = x_allocate_bitmap_record (f);
542 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
543 dpyinfo->bitmaps[id - 1].file = NULL;
544 dpyinfo->bitmaps[id - 1].hinst = NULL;
545 dpyinfo->bitmaps[id - 1].refcount = 1;
546 dpyinfo->bitmaps[id - 1].depth = 1;
547 dpyinfo->bitmaps[id - 1].height = height;
548 dpyinfo->bitmaps[id - 1].width = width;
549
550 return id;
551}
552
553/* Create bitmap from file FILE for frame F. */
554
555int
556x_create_bitmap_from_file (f, file)
557 struct frame *f;
558 Lisp_Object file;
559{
560 return -1;
767b1ff0 561#if 0 /* TODO : bitmap support */
fbd6baed 562 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 563 unsigned int width, height;
6fc2811b 564 HBITMAP bitmap;
ee78dc32
GV
565 int xhot, yhot, result, id;
566 Lisp_Object found;
567 int fd;
568 char *filename;
569 HINSTANCE hinst;
570
571 /* Look for an existing bitmap with the same name. */
572 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
573 {
574 if (dpyinfo->bitmaps[id].refcount
575 && dpyinfo->bitmaps[id].file
d5db4077 576 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
ee78dc32
GV
577 {
578 ++dpyinfo->bitmaps[id].refcount;
579 return id + 1;
580 }
581 }
582
583 /* Search bitmap-file-path for the file, if appropriate. */
de2413e9 584 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
ee78dc32
GV
585 if (fd < 0)
586 return -1;
6fc2811b 587 emacs_close (fd);
ee78dc32 588
d5db4077 589 filename = (char *) SDATA (found);
ee78dc32
GV
590
591 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
592
593 if (hinst == NULL)
594 return -1;
595
7d0393cf 596
fbd6baed 597 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
598 filename, &width, &height, &bitmap, &xhot, &yhot);
599 if (result != BitmapSuccess)
600 return -1;
601
602 id = x_allocate_bitmap_record (f);
603 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
604 dpyinfo->bitmaps[id - 1].refcount = 1;
d5db4077 605 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1);
ee78dc32
GV
606 dpyinfo->bitmaps[id - 1].depth = 1;
607 dpyinfo->bitmaps[id - 1].height = height;
608 dpyinfo->bitmaps[id - 1].width = width;
d5db4077 609 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
ee78dc32
GV
610
611 return id;
767b1ff0 612#endif /* TODO */
ee78dc32
GV
613}
614
615/* Remove reference to bitmap with id number ID. */
616
33d52f9c 617void
ee78dc32
GV
618x_destroy_bitmap (f, id)
619 FRAME_PTR f;
620 int id;
621{
fbd6baed 622 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
623
624 if (id > 0)
625 {
626 --dpyinfo->bitmaps[id - 1].refcount;
627 if (dpyinfo->bitmaps[id - 1].refcount == 0)
628 {
629 BLOCK_INPUT;
630 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
631 if (dpyinfo->bitmaps[id - 1].file)
632 {
6fc2811b 633 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
634 dpyinfo->bitmaps[id - 1].file = NULL;
635 }
636 UNBLOCK_INPUT;
637 }
638 }
639}
640
641/* Free all the bitmaps for the display specified by DPYINFO. */
642
643static void
644x_destroy_all_bitmaps (dpyinfo)
fbd6baed 645 struct w32_display_info *dpyinfo;
ee78dc32
GV
646{
647 int i;
648 for (i = 0; i < dpyinfo->bitmaps_last; i++)
649 if (dpyinfo->bitmaps[i].refcount > 0)
650 {
651 DeleteObject (dpyinfo->bitmaps[i].pixmap);
652 if (dpyinfo->bitmaps[i].file)
6fc2811b 653 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
654 }
655 dpyinfo->bitmaps_last = 0;
656}
657\f
fbd6baed 658/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
659 to the ways of passing the parameter values to the window system.
660
661 The name of a parameter, as a Lisp symbol,
662 has an `x-frame-parameter' property which is an integer in Lisp
663 but can be interpreted as an `enum x_frame_parm' in C. */
664
665enum x_frame_parm
666{
667 X_PARM_FOREGROUND_COLOR,
668 X_PARM_BACKGROUND_COLOR,
669 X_PARM_MOUSE_COLOR,
670 X_PARM_CURSOR_COLOR,
671 X_PARM_BORDER_COLOR,
672 X_PARM_ICON_TYPE,
673 X_PARM_FONT,
674 X_PARM_BORDER_WIDTH,
675 X_PARM_INTERNAL_BORDER_WIDTH,
676 X_PARM_NAME,
677 X_PARM_AUTORAISE,
678 X_PARM_AUTOLOWER,
679 X_PARM_VERT_SCROLL_BAR,
680 X_PARM_VISIBILITY,
681 X_PARM_MENU_BAR_LINES
682};
683
684
685struct x_frame_parm_table
686{
687 char *name;
6fc2811b 688 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
689};
690
ca56d953
JR
691BOOL my_show_window P_ ((struct frame *, HWND, int));
692void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
693static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
694static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
695static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 696/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 697void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 698static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
f7b9d4d1 699static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
700void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
701void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
702void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
703void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
704void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
706void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
707void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 708static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
709void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
710void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
711 Lisp_Object));
712void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
713void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
714void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
715void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
716 Lisp_Object));
717void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
718void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
719void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
720void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
721void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
722void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
723static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
724static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
725 Lisp_Object));
ee78dc32
GV
726
727static struct x_frame_parm_table x_frame_parms[] =
728{
72e4adef
JR
729 {"auto-raise", x_set_autoraise},
730 {"auto-lower", x_set_autolower},
731 {"background-color", x_set_background_color},
732 {"border-color", x_set_border_color},
733 {"border-width", x_set_border_width},
734 {"cursor-color", x_set_cursor_color},
735 {"cursor-type", x_set_cursor_type},
736 {"font", x_set_font},
737 {"foreground-color", x_set_foreground_color},
738 {"icon-name", x_set_icon_name},
739 {"icon-type", x_set_icon_type},
740 {"internal-border-width", x_set_internal_border_width},
741 {"menu-bar-lines", x_set_menu_bar_lines},
742 {"mouse-color", x_set_mouse_color},
743 {"name", x_explicitly_set_name},
744 {"scroll-bar-width", x_set_scroll_bar_width},
745 {"title", x_set_title},
746 {"unsplittable", x_set_unsplittable},
747 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
748 {"visibility", x_set_visibility},
749 {"tool-bar-lines", x_set_tool_bar_lines},
750 {"screen-gamma", x_set_screen_gamma},
751 {"line-spacing", x_set_line_spacing},
752 {"left-fringe", x_set_fringe_width},
f7b9d4d1
JR
753 {"right-fringe", x_set_fringe_width},
754 {"fullscreen", x_set_fullscreen},
ee78dc32
GV
755};
756
757/* Attach the `x-frame-parameter' properties to
fbd6baed 758 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 759
dfff8a69 760void
ee78dc32
GV
761init_x_parm_symbols ()
762{
763 int i;
764
765 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
766 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
767 make_number (i));
768}
769\f
f7b9d4d1
JR
770/* Really try to move where we want to be in case of fullscreen. Some WMs
771 moves the window where we tell them. Some (mwm, twm) moves the outer
772 window manager window there instead.
773 Try to compensate for those WM here. */
774static void
775x_fullscreen_move (f, new_top, new_left)
776 struct frame *f;
777 int new_top;
778 int new_left;
779{
780 if (new_top != f->output_data.w32->top_pos
781 || new_left != f->output_data.w32->left_pos)
782 {
783 int move_x = new_left;
784 int move_y = new_top;
785
786 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
787 x_set_offset (f, move_x, move_y, 1);
788 }
789}
790
dfff8a69 791/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
792 If a parameter is not specially recognized, do nothing;
793 otherwise call the `x_set_...' function for that parameter. */
794
795void
796x_set_frame_parameters (f, alist)
797 FRAME_PTR f;
798 Lisp_Object alist;
799{
800 Lisp_Object tail;
801
802 /* If both of these parameters are present, it's more efficient to
803 set them both at once. So we wait until we've looked at the
804 entire list before we set them. */
b839712d 805 int width, height;
ee78dc32
GV
806
807 /* Same here. */
808 Lisp_Object left, top;
809
810 /* Same with these. */
811 Lisp_Object icon_left, icon_top;
812
813 /* Record in these vectors all the parms specified. */
814 Lisp_Object *parms;
815 Lisp_Object *values;
a797a73d 816 int i, p;
ee78dc32
GV
817 int left_no_change = 0, top_no_change = 0;
818 int icon_left_no_change = 0, icon_top_no_change = 0;
f7b9d4d1 819 int fullscreen_is_being_set = 0;
ee78dc32 820
5878523b
RS
821 struct gcpro gcpro1, gcpro2;
822
ee78dc32
GV
823 i = 0;
824 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
825 i++;
826
827 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
828 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
829
830 /* Extract parm names and values into those vectors. */
831
832 i = 0;
833 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
834 {
6fc2811b 835 Lisp_Object elt;
ee78dc32
GV
836
837 elt = Fcar (tail);
838 parms[i] = Fcar (elt);
839 values[i] = Fcdr (elt);
840 i++;
841 }
5878523b
RS
842 /* TAIL and ALIST are not used again below here. */
843 alist = tail = Qnil;
844
845 GCPRO2 (*parms, *values);
846 gcpro1.nvars = i;
847 gcpro2.nvars = i;
848
849 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
850 because their values appear in VALUES and strings are not valid. */
b839712d 851 top = left = Qunbound;
ee78dc32
GV
852 icon_left = icon_top = Qunbound;
853
b839712d 854 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
855 if (FRAME_NEW_WIDTH (f))
856 width = FRAME_NEW_WIDTH (f);
857 else
858 width = FRAME_WIDTH (f);
859
860 if (FRAME_NEW_HEIGHT (f))
861 height = FRAME_NEW_HEIGHT (f);
862 else
863 height = FRAME_HEIGHT (f);
b839712d 864
a797a73d
GV
865 /* Process foreground_color and background_color before anything else.
866 They are independent of other properties, but other properties (e.g.,
867 cursor_color) are dependent upon them. */
41c1bdd9 868 /* Process default font as well, since fringe widths depends on it. */
7d0393cf 869 for (p = 0; p < i; p++)
a797a73d
GV
870 {
871 Lisp_Object prop, val;
872
873 prop = parms[p];
874 val = values[p];
41c1bdd9
KS
875 if (EQ (prop, Qforeground_color)
876 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
877 || EQ (prop, Qfont)
878 || EQ (prop, Qfullscreen))
a797a73d
GV
879 {
880 register Lisp_Object param_index, old_value;
881
a797a73d 882 old_value = get_frame_param (f, prop);
f7b9d4d1 883 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
a05e2bae
JR
884
885 if (NILP (Fequal (val, old_value)))
886 {
887 store_frame_param (f, prop, val);
7d0393cf 888
a05e2bae
JR
889 param_index = Fget (prop, Qx_frame_parameter);
890 if (NATNUMP (param_index)
891 && (XFASTINT (param_index)
892 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
893 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
894 }
a797a73d
GV
895 }
896 }
897
ee78dc32
GV
898 /* Now process them in reverse of specified order. */
899 for (i--; i >= 0; i--)
900 {
901 Lisp_Object prop, val;
902
903 prop = parms[i];
904 val = values[i];
905
b839712d
RS
906 if (EQ (prop, Qwidth) && NUMBERP (val))
907 width = XFASTINT (val);
908 else if (EQ (prop, Qheight) && NUMBERP (val))
909 height = XFASTINT (val);
ee78dc32
GV
910 else if (EQ (prop, Qtop))
911 top = val;
912 else if (EQ (prop, Qleft))
913 left = val;
914 else if (EQ (prop, Qicon_top))
915 icon_top = val;
916 else if (EQ (prop, Qicon_left))
917 icon_left = val;
41c1bdd9
KS
918 else if (EQ (prop, Qforeground_color)
919 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
920 || EQ (prop, Qfont)
921 || EQ (prop, Qfullscreen))
a797a73d
GV
922 /* Processed above. */
923 continue;
ee78dc32
GV
924 else
925 {
926 register Lisp_Object param_index, old_value;
927
ee78dc32 928 old_value = get_frame_param (f, prop);
a05e2bae 929
ee78dc32 930 store_frame_param (f, prop, val);
a05e2bae
JR
931
932 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
933 if (NATNUMP (param_index)
934 && (XFASTINT (param_index)
935 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 936 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
937 }
938 }
939
940 /* Don't die if just one of these was set. */
941 if (EQ (left, Qunbound))
942 {
943 left_no_change = 1;
fbd6baed
GV
944 if (f->output_data.w32->left_pos < 0)
945 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 946 else
fbd6baed 947 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
948 }
949 if (EQ (top, Qunbound))
950 {
951 top_no_change = 1;
fbd6baed
GV
952 if (f->output_data.w32->top_pos < 0)
953 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 954 else
fbd6baed 955 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
956 }
957
958 /* If one of the icon positions was not set, preserve or default it. */
959 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
960 {
961 icon_left_no_change = 1;
962 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
963 if (NILP (icon_left))
964 XSETINT (icon_left, 0);
965 }
966 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
967 {
968 icon_top_no_change = 1;
969 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
970 if (NILP (icon_top))
971 XSETINT (icon_top, 0);
972 }
973
f7b9d4d1
JR
974 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
975 {
976 /* If the frame is visible already and the fullscreen parameter is
977 being set, it is too late to set WM manager hints to specify
978 size and position.
979 Here we first get the width, height and position that applies to
980 fullscreen. We then move the frame to the appropriate
981 position. Resize of the frame is taken care of in the code after
982 this if-statement. */
983 int new_left, new_top;
7d0393cf 984
f7b9d4d1
JR
985 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
986 x_fullscreen_move (f, new_top, new_left);
987 }
988
ee78dc32
GV
989 /* Don't set these parameters unless they've been explicitly
990 specified. The window might be mapped or resized while we're in
991 this function, and we don't want to override that unless the lisp
992 code has asked for it.
993
994 Don't set these parameters unless they actually differ from the
995 window's current parameters; the window may not actually exist
996 yet. */
997 {
998 Lisp_Object frame;
999
1000 check_frame_size (f, &height, &width);
1001
1002 XSETFRAME (frame, f);
1003
dfff8a69
JR
1004 if (width != FRAME_WIDTH (f)
1005 || height != FRAME_HEIGHT (f)
1006 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 1007 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
1008
1009 if ((!NILP (left) || !NILP (top))
1010 && ! (left_no_change && top_no_change)
fbd6baed
GV
1011 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1012 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
1013 {
1014 int leftpos = 0;
1015 int toppos = 0;
1016
1017 /* Record the signs. */
fbd6baed 1018 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 1019 if (EQ (left, Qminus))
fbd6baed 1020 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
1021 else if (INTEGERP (left))
1022 {
1023 leftpos = XINT (left);
1024 if (leftpos < 0)
fbd6baed 1025 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1026 }
8e713be6
KR
1027 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1028 && CONSP (XCDR (left))
1029 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1030 {
8e713be6 1031 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 1032 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1033 }
8e713be6
KR
1034 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1035 && CONSP (XCDR (left))
1036 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1037 {
8e713be6 1038 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
1039 }
1040
1041 if (EQ (top, Qminus))
fbd6baed 1042 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
1043 else if (INTEGERP (top))
1044 {
1045 toppos = XINT (top);
1046 if (toppos < 0)
fbd6baed 1047 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1048 }
8e713be6
KR
1049 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1050 && CONSP (XCDR (top))
1051 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1052 {
8e713be6 1053 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 1054 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1055 }
8e713be6
KR
1056 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1057 && CONSP (XCDR (top))
1058 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1059 {
8e713be6 1060 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1061 }
1062
1063
1064 /* Store the numeric value of the position. */
fbd6baed
GV
1065 f->output_data.w32->top_pos = toppos;
1066 f->output_data.w32->left_pos = leftpos;
ee78dc32 1067
fbd6baed 1068 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1069
1070 /* Actually set that position, and convert to absolute. */
1071 x_set_offset (f, leftpos, toppos, -1);
1072 }
1073
1074 if ((!NILP (icon_left) || !NILP (icon_top))
1075 && ! (icon_left_no_change && icon_top_no_change))
1076 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1077 }
5878523b
RS
1078
1079 UNGCPRO;
ee78dc32
GV
1080}
1081
1082/* Store the screen positions of frame F into XPTR and YPTR.
1083 These are the positions of the containing window manager window,
1084 not Emacs's own window. */
1085
1086void
1087x_real_positions (f, xptr, yptr)
1088 FRAME_PTR f;
1089 int *xptr, *yptr;
1090{
1091 POINT pt;
f7b9d4d1 1092 RECT rect;
3c190163 1093
f7b9d4d1
JR
1094 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1095 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1096
1097 pt.x = rect.left;
1098 pt.y = rect.top;
ee78dc32 1099
fbd6baed 1100 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32 1101
f7b9d4d1
JR
1102 /* Remember x_pixels_diff and y_pixels_diff. */
1103 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1104 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1105
ee78dc32
GV
1106 *xptr = pt.x;
1107 *yptr = pt.y;
1108}
1109
1110/* Insert a description of internally-recorded parameters of frame X
1111 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1112 Only parameters that are specific to W32
ee78dc32
GV
1113 and whose values are not correctly recorded in the frame's
1114 param_alist need to be considered here. */
1115
dfff8a69 1116void
ee78dc32
GV
1117x_report_frame_params (f, alistptr)
1118 struct frame *f;
1119 Lisp_Object *alistptr;
1120{
1121 char buf[16];
1122 Lisp_Object tem;
1123
1124 /* Represent negative positions (off the top or left screen edge)
1125 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1126 XSETINT (tem, f->output_data.w32->left_pos);
1127 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1128 store_in_alist (alistptr, Qleft, tem);
1129 else
1130 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1131
fbd6baed
GV
1132 XSETINT (tem, f->output_data.w32->top_pos);
1133 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1134 store_in_alist (alistptr, Qtop, tem);
1135 else
1136 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1137
1138 store_in_alist (alistptr, Qborder_width,
fbd6baed 1139 make_number (f->output_data.w32->border_width));
ee78dc32 1140 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1141 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1142 store_in_alist (alistptr, Qleft_fringe,
1143 make_number (f->output_data.w32->left_fringe_width));
1144 store_in_alist (alistptr, Qright_fringe,
1145 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1146 store_in_alist (alistptr, Qscroll_bar_width,
1147 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1148 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1149 : 0));
fbd6baed 1150 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1151 store_in_alist (alistptr, Qwindow_id,
1152 build_string (buf));
1153 store_in_alist (alistptr, Qicon_name, f->icon_name);
1154 FRAME_SAMPLE_VISIBILITY (f);
1155 store_in_alist (alistptr, Qvisibility,
1156 (FRAME_VISIBLE_P (f) ? Qt
1157 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1158 store_in_alist (alistptr, Qdisplay,
8e713be6 1159 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1160}
1161\f
1162
74e1aeec
JR
1163DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1164 Sw32_define_rgb_color, 4, 4, 0,
1165 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1166This adds or updates a named color to w32-color-map, making it
1167available for use. The original entry's RGB ref is returned, or nil
1168if the entry is new. */)
5ac45f98
GV
1169 (red, green, blue, name)
1170 Lisp_Object red, green, blue, name;
ee78dc32 1171{
5ac45f98
GV
1172 Lisp_Object rgb;
1173 Lisp_Object oldrgb = Qnil;
1174 Lisp_Object entry;
1175
b7826503
PJ
1176 CHECK_NUMBER (red);
1177 CHECK_NUMBER (green);
1178 CHECK_NUMBER (blue);
1179 CHECK_STRING (name);
ee78dc32 1180
5ac45f98 1181 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1182
5ac45f98 1183 BLOCK_INPUT;
ee78dc32 1184
fbd6baed
GV
1185 /* replace existing entry in w32-color-map or add new entry. */
1186 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1187 if (NILP (entry))
1188 {
1189 entry = Fcons (name, rgb);
fbd6baed 1190 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1191 }
1192 else
1193 {
1194 oldrgb = Fcdr (entry);
1195 Fsetcdr (entry, rgb);
1196 }
1197
1198 UNBLOCK_INPUT;
1199
1200 return (oldrgb);
ee78dc32
GV
1201}
1202
74e1aeec
JR
1203DEFUN ("w32-load-color-file", Fw32_load_color_file,
1204 Sw32_load_color_file, 1, 1, 0,
1205 doc: /* Create an alist of color entries from an external file.
1206Assign this value to w32-color-map to replace the existing color map.
1207
1208The file should define one named RGB color per line like so:
1209 R G B name
1210where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1211 (filename)
1212 Lisp_Object filename;
1213{
1214 FILE *fp;
1215 Lisp_Object cmap = Qnil;
1216 Lisp_Object abspath;
1217
b7826503 1218 CHECK_STRING (filename);
5ac45f98
GV
1219 abspath = Fexpand_file_name (filename, Qnil);
1220
d5db4077 1221 fp = fopen (SDATA (filename), "rt");
5ac45f98
GV
1222 if (fp)
1223 {
1224 char buf[512];
1225 int red, green, blue;
1226 int num;
1227
1228 BLOCK_INPUT;
1229
1230 while (fgets (buf, sizeof (buf), fp) != NULL) {
1231 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1232 {
1233 char *name = buf + num;
1234 num = strlen (name) - 1;
1235 if (name[num] == '\n')
1236 name[num] = 0;
1237 cmap = Fcons (Fcons (build_string (name),
1238 make_number (RGB (red, green, blue))),
1239 cmap);
1240 }
1241 }
1242 fclose (fp);
1243
1244 UNBLOCK_INPUT;
1245 }
1246
1247 return cmap;
1248}
ee78dc32 1249
fbd6baed 1250/* The default colors for the w32 color map */
7d0393cf 1251typedef struct colormap_t
ee78dc32
GV
1252{
1253 char *name;
1254 COLORREF colorref;
1255} colormap_t;
1256
7d0393cf 1257colormap_t w32_color_map[] =
ee78dc32 1258{
1da8a614
GV
1259 {"snow" , PALETTERGB (255,250,250)},
1260 {"ghost white" , PALETTERGB (248,248,255)},
1261 {"GhostWhite" , PALETTERGB (248,248,255)},
1262 {"white smoke" , PALETTERGB (245,245,245)},
1263 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1264 {"gainsboro" , PALETTERGB (220,220,220)},
1265 {"floral white" , PALETTERGB (255,250,240)},
1266 {"FloralWhite" , PALETTERGB (255,250,240)},
1267 {"old lace" , PALETTERGB (253,245,230)},
1268 {"OldLace" , PALETTERGB (253,245,230)},
1269 {"linen" , PALETTERGB (250,240,230)},
1270 {"antique white" , PALETTERGB (250,235,215)},
1271 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1272 {"papaya whip" , PALETTERGB (255,239,213)},
1273 {"PapayaWhip" , PALETTERGB (255,239,213)},
1274 {"blanched almond" , PALETTERGB (255,235,205)},
1275 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1276 {"bisque" , PALETTERGB (255,228,196)},
1277 {"peach puff" , PALETTERGB (255,218,185)},
1278 {"PeachPuff" , PALETTERGB (255,218,185)},
1279 {"navajo white" , PALETTERGB (255,222,173)},
1280 {"NavajoWhite" , PALETTERGB (255,222,173)},
1281 {"moccasin" , PALETTERGB (255,228,181)},
1282 {"cornsilk" , PALETTERGB (255,248,220)},
1283 {"ivory" , PALETTERGB (255,255,240)},
1284 {"lemon chiffon" , PALETTERGB (255,250,205)},
1285 {"LemonChiffon" , PALETTERGB (255,250,205)},
1286 {"seashell" , PALETTERGB (255,245,238)},
1287 {"honeydew" , PALETTERGB (240,255,240)},
1288 {"mint cream" , PALETTERGB (245,255,250)},
1289 {"MintCream" , PALETTERGB (245,255,250)},
1290 {"azure" , PALETTERGB (240,255,255)},
1291 {"alice blue" , PALETTERGB (240,248,255)},
1292 {"AliceBlue" , PALETTERGB (240,248,255)},
1293 {"lavender" , PALETTERGB (230,230,250)},
1294 {"lavender blush" , PALETTERGB (255,240,245)},
1295 {"LavenderBlush" , PALETTERGB (255,240,245)},
1296 {"misty rose" , PALETTERGB (255,228,225)},
1297 {"MistyRose" , PALETTERGB (255,228,225)},
1298 {"white" , PALETTERGB (255,255,255)},
1299 {"black" , PALETTERGB ( 0, 0, 0)},
1300 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1301 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1302 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1303 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1304 {"dim gray" , PALETTERGB (105,105,105)},
1305 {"DimGray" , PALETTERGB (105,105,105)},
1306 {"dim grey" , PALETTERGB (105,105,105)},
1307 {"DimGrey" , PALETTERGB (105,105,105)},
1308 {"slate gray" , PALETTERGB (112,128,144)},
1309 {"SlateGray" , PALETTERGB (112,128,144)},
1310 {"slate grey" , PALETTERGB (112,128,144)},
1311 {"SlateGrey" , PALETTERGB (112,128,144)},
1312 {"light slate gray" , PALETTERGB (119,136,153)},
1313 {"LightSlateGray" , PALETTERGB (119,136,153)},
1314 {"light slate grey" , PALETTERGB (119,136,153)},
1315 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1316 {"gray" , PALETTERGB (190,190,190)},
1317 {"grey" , PALETTERGB (190,190,190)},
1318 {"light grey" , PALETTERGB (211,211,211)},
1319 {"LightGrey" , PALETTERGB (211,211,211)},
1320 {"light gray" , PALETTERGB (211,211,211)},
1321 {"LightGray" , PALETTERGB (211,211,211)},
1322 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1323 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1324 {"navy" , PALETTERGB ( 0, 0,128)},
1325 {"navy blue" , PALETTERGB ( 0, 0,128)},
1326 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1327 {"cornflower blue" , PALETTERGB (100,149,237)},
1328 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1329 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1330 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1331 {"slate blue" , PALETTERGB (106, 90,205)},
1332 {"SlateBlue" , PALETTERGB (106, 90,205)},
1333 {"medium slate blue" , PALETTERGB (123,104,238)},
1334 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1335 {"light slate blue" , PALETTERGB (132,112,255)},
1336 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1337 {"medium blue" , PALETTERGB ( 0, 0,205)},
1338 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1339 {"royal blue" , PALETTERGB ( 65,105,225)},
1340 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1341 {"blue" , PALETTERGB ( 0, 0,255)},
1342 {"dodger blue" , PALETTERGB ( 30,144,255)},
1343 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1344 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1345 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1346 {"sky blue" , PALETTERGB (135,206,235)},
1347 {"SkyBlue" , PALETTERGB (135,206,235)},
1348 {"light sky blue" , PALETTERGB (135,206,250)},
1349 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1350 {"steel blue" , PALETTERGB ( 70,130,180)},
1351 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1352 {"light steel blue" , PALETTERGB (176,196,222)},
1353 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1354 {"light blue" , PALETTERGB (173,216,230)},
1355 {"LightBlue" , PALETTERGB (173,216,230)},
1356 {"powder blue" , PALETTERGB (176,224,230)},
1357 {"PowderBlue" , PALETTERGB (176,224,230)},
1358 {"pale turquoise" , PALETTERGB (175,238,238)},
1359 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1360 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1361 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1362 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1363 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1364 {"turquoise" , PALETTERGB ( 64,224,208)},
1365 {"cyan" , PALETTERGB ( 0,255,255)},
1366 {"light cyan" , PALETTERGB (224,255,255)},
1367 {"LightCyan" , PALETTERGB (224,255,255)},
1368 {"cadet blue" , PALETTERGB ( 95,158,160)},
1369 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1370 {"medium aquamarine" , PALETTERGB (102,205,170)},
1371 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1372 {"aquamarine" , PALETTERGB (127,255,212)},
1373 {"dark green" , PALETTERGB ( 0,100, 0)},
1374 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1375 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1376 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1377 {"dark sea green" , PALETTERGB (143,188,143)},
1378 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1379 {"sea green" , PALETTERGB ( 46,139, 87)},
1380 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1381 {"medium sea green" , PALETTERGB ( 60,179,113)},
1382 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1383 {"light sea green" , PALETTERGB ( 32,178,170)},
1384 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1385 {"pale green" , PALETTERGB (152,251,152)},
1386 {"PaleGreen" , PALETTERGB (152,251,152)},
1387 {"spring green" , PALETTERGB ( 0,255,127)},
1388 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1389 {"lawn green" , PALETTERGB (124,252, 0)},
1390 {"LawnGreen" , PALETTERGB (124,252, 0)},
1391 {"green" , PALETTERGB ( 0,255, 0)},
1392 {"chartreuse" , PALETTERGB (127,255, 0)},
1393 {"medium spring green" , PALETTERGB ( 0,250,154)},
1394 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1395 {"green yellow" , PALETTERGB (173,255, 47)},
1396 {"GreenYellow" , PALETTERGB (173,255, 47)},
1397 {"lime green" , PALETTERGB ( 50,205, 50)},
1398 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1399 {"yellow green" , PALETTERGB (154,205, 50)},
1400 {"YellowGreen" , PALETTERGB (154,205, 50)},
1401 {"forest green" , PALETTERGB ( 34,139, 34)},
1402 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1403 {"olive drab" , PALETTERGB (107,142, 35)},
1404 {"OliveDrab" , PALETTERGB (107,142, 35)},
1405 {"dark khaki" , PALETTERGB (189,183,107)},
1406 {"DarkKhaki" , PALETTERGB (189,183,107)},
1407 {"khaki" , PALETTERGB (240,230,140)},
1408 {"pale goldenrod" , PALETTERGB (238,232,170)},
1409 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1410 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1411 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1412 {"light yellow" , PALETTERGB (255,255,224)},
1413 {"LightYellow" , PALETTERGB (255,255,224)},
1414 {"yellow" , PALETTERGB (255,255, 0)},
1415 {"gold" , PALETTERGB (255,215, 0)},
1416 {"light goldenrod" , PALETTERGB (238,221,130)},
1417 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1418 {"goldenrod" , PALETTERGB (218,165, 32)},
1419 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1420 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1421 {"rosy brown" , PALETTERGB (188,143,143)},
1422 {"RosyBrown" , PALETTERGB (188,143,143)},
1423 {"indian red" , PALETTERGB (205, 92, 92)},
1424 {"IndianRed" , PALETTERGB (205, 92, 92)},
1425 {"saddle brown" , PALETTERGB (139, 69, 19)},
1426 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1427 {"sienna" , PALETTERGB (160, 82, 45)},
1428 {"peru" , PALETTERGB (205,133, 63)},
1429 {"burlywood" , PALETTERGB (222,184,135)},
1430 {"beige" , PALETTERGB (245,245,220)},
1431 {"wheat" , PALETTERGB (245,222,179)},
1432 {"sandy brown" , PALETTERGB (244,164, 96)},
1433 {"SandyBrown" , PALETTERGB (244,164, 96)},
1434 {"tan" , PALETTERGB (210,180,140)},
1435 {"chocolate" , PALETTERGB (210,105, 30)},
1436 {"firebrick" , PALETTERGB (178,34, 34)},
1437 {"brown" , PALETTERGB (165,42, 42)},
1438 {"dark salmon" , PALETTERGB (233,150,122)},
1439 {"DarkSalmon" , PALETTERGB (233,150,122)},
1440 {"salmon" , PALETTERGB (250,128,114)},
1441 {"light salmon" , PALETTERGB (255,160,122)},
1442 {"LightSalmon" , PALETTERGB (255,160,122)},
1443 {"orange" , PALETTERGB (255,165, 0)},
1444 {"dark orange" , PALETTERGB (255,140, 0)},
1445 {"DarkOrange" , PALETTERGB (255,140, 0)},
1446 {"coral" , PALETTERGB (255,127, 80)},
1447 {"light coral" , PALETTERGB (240,128,128)},
1448 {"LightCoral" , PALETTERGB (240,128,128)},
1449 {"tomato" , PALETTERGB (255, 99, 71)},
1450 {"orange red" , PALETTERGB (255, 69, 0)},
1451 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1452 {"red" , PALETTERGB (255, 0, 0)},
1453 {"hot pink" , PALETTERGB (255,105,180)},
1454 {"HotPink" , PALETTERGB (255,105,180)},
1455 {"deep pink" , PALETTERGB (255, 20,147)},
1456 {"DeepPink" , PALETTERGB (255, 20,147)},
1457 {"pink" , PALETTERGB (255,192,203)},
1458 {"light pink" , PALETTERGB (255,182,193)},
1459 {"LightPink" , PALETTERGB (255,182,193)},
1460 {"pale violet red" , PALETTERGB (219,112,147)},
1461 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1462 {"maroon" , PALETTERGB (176, 48, 96)},
1463 {"medium violet red" , PALETTERGB (199, 21,133)},
1464 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1465 {"violet red" , PALETTERGB (208, 32,144)},
1466 {"VioletRed" , PALETTERGB (208, 32,144)},
1467 {"magenta" , PALETTERGB (255, 0,255)},
1468 {"violet" , PALETTERGB (238,130,238)},
1469 {"plum" , PALETTERGB (221,160,221)},
1470 {"orchid" , PALETTERGB (218,112,214)},
1471 {"medium orchid" , PALETTERGB (186, 85,211)},
1472 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1473 {"dark orchid" , PALETTERGB (153, 50,204)},
1474 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1475 {"dark violet" , PALETTERGB (148, 0,211)},
1476 {"DarkViolet" , PALETTERGB (148, 0,211)},
1477 {"blue violet" , PALETTERGB (138, 43,226)},
1478 {"BlueViolet" , PALETTERGB (138, 43,226)},
1479 {"purple" , PALETTERGB (160, 32,240)},
1480 {"medium purple" , PALETTERGB (147,112,219)},
1481 {"MediumPurple" , PALETTERGB (147,112,219)},
1482 {"thistle" , PALETTERGB (216,191,216)},
1483 {"gray0" , PALETTERGB ( 0, 0, 0)},
1484 {"grey0" , PALETTERGB ( 0, 0, 0)},
1485 {"dark grey" , PALETTERGB (169,169,169)},
1486 {"DarkGrey" , PALETTERGB (169,169,169)},
1487 {"dark gray" , PALETTERGB (169,169,169)},
1488 {"DarkGray" , PALETTERGB (169,169,169)},
1489 {"dark blue" , PALETTERGB ( 0, 0,139)},
1490 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1491 {"dark cyan" , PALETTERGB ( 0,139,139)},
1492 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1493 {"dark magenta" , PALETTERGB (139, 0,139)},
1494 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1495 {"dark red" , PALETTERGB (139, 0, 0)},
1496 {"DarkRed" , PALETTERGB (139, 0, 0)},
1497 {"light green" , PALETTERGB (144,238,144)},
1498 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1499};
1500
fbd6baed 1501DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1502 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1503 ()
1504{
1505 int i;
fbd6baed 1506 colormap_t *pc = w32_color_map;
ee78dc32 1507 Lisp_Object cmap;
7d0393cf 1508
ee78dc32 1509 BLOCK_INPUT;
7d0393cf 1510
ee78dc32 1511 cmap = Qnil;
7d0393cf
JB
1512
1513 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1514 pc++, i++)
1515 cmap = Fcons (Fcons (build_string (pc->name),
1516 make_number (pc->colorref)),
1517 cmap);
7d0393cf 1518
ee78dc32 1519 UNBLOCK_INPUT;
7d0393cf 1520
ee78dc32
GV
1521 return (cmap);
1522}
ee78dc32 1523
7d0393cf 1524Lisp_Object
fbd6baed 1525w32_to_x_color (rgb)
ee78dc32
GV
1526 Lisp_Object rgb;
1527{
1528 Lisp_Object color;
7d0393cf 1529
b7826503 1530 CHECK_NUMBER (rgb);
7d0393cf 1531
ee78dc32 1532 BLOCK_INPUT;
7d0393cf 1533
fbd6baed 1534 color = Frassq (rgb, Vw32_color_map);
7d0393cf 1535
ee78dc32 1536 UNBLOCK_INPUT;
7d0393cf 1537
ee78dc32
GV
1538 if (!NILP (color))
1539 return (Fcar (color));
1540 else
1541 return Qnil;
1542}
1543
5d7fed93
GV
1544COLORREF
1545w32_color_map_lookup (colorname)
1546 char *colorname;
1547{
1548 Lisp_Object tail, ret = Qnil;
1549
1550 BLOCK_INPUT;
1551
1552 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1553 {
1554 register Lisp_Object elt, tem;
1555
1556 elt = Fcar (tail);
1557 if (!CONSP (elt)) continue;
1558
1559 tem = Fcar (elt);
1560
d5db4077 1561 if (lstrcmpi (SDATA (tem), colorname) == 0)
5d7fed93
GV
1562 {
1563 ret = XUINT (Fcdr (elt));
1564 break;
1565 }
1566
1567 QUIT;
1568 }
1569
1570
1571 UNBLOCK_INPUT;
1572
1573 return ret;
1574}
1575
7d0393cf 1576COLORREF
fbd6baed 1577x_to_w32_color (colorname)
ee78dc32
GV
1578 char * colorname;
1579{
8edb0a6f
JR
1580 register Lisp_Object ret = Qnil;
1581
ee78dc32 1582 BLOCK_INPUT;
1edf84e7
GV
1583
1584 if (colorname[0] == '#')
1585 {
1586 /* Could be an old-style RGB Device specification. */
1587 char *color;
1588 int size;
1589 color = colorname + 1;
7d0393cf 1590
1edf84e7
GV
1591 size = strlen(color);
1592 if (size == 3 || size == 6 || size == 9 || size == 12)
1593 {
1594 UINT colorval;
1595 int i, pos;
1596 pos = 0;
1597 size /= 3;
1598 colorval = 0;
7d0393cf 1599
1edf84e7
GV
1600 for (i = 0; i < 3; i++)
1601 {
1602 char *end;
1603 char t;
1604 unsigned long value;
1605
1606 /* The check for 'x' in the following conditional takes into
1607 account the fact that strtol allows a "0x" in front of
1608 our numbers, and we don't. */
1609 if (!isxdigit(color[0]) || color[1] == 'x')
1610 break;
1611 t = color[size];
1612 color[size] = '\0';
1613 value = strtoul(color, &end, 16);
1614 color[size] = t;
1615 if (errno == ERANGE || end - color != size)
1616 break;
1617 switch (size)
1618 {
1619 case 1:
1620 value = value * 0x10;
1621 break;
1622 case 2:
1623 break;
1624 case 3:
1625 value /= 0x10;
1626 break;
1627 case 4:
1628 value /= 0x100;
1629 break;
1630 }
1631 colorval |= (value << pos);
1632 pos += 0x8;
1633 if (i == 2)
1634 {
1635 UNBLOCK_INPUT;
1636 return (colorval);
1637 }
1638 color = end;
1639 }
1640 }
1641 }
1642 else if (strnicmp(colorname, "rgb:", 4) == 0)
1643 {
1644 char *color;
1645 UINT colorval;
1646 int i, pos;
1647 pos = 0;
1648
1649 colorval = 0;
1650 color = colorname + 4;
1651 for (i = 0; i < 3; i++)
1652 {
1653 char *end;
1654 unsigned long value;
7d0393cf 1655
1edf84e7
GV
1656 /* The check for 'x' in the following conditional takes into
1657 account the fact that strtol allows a "0x" in front of
1658 our numbers, and we don't. */
1659 if (!isxdigit(color[0]) || color[1] == 'x')
1660 break;
1661 value = strtoul(color, &end, 16);
1662 if (errno == ERANGE)
1663 break;
1664 switch (end - color)
1665 {
1666 case 1:
1667 value = value * 0x10 + value;
1668 break;
1669 case 2:
1670 break;
1671 case 3:
1672 value /= 0x10;
1673 break;
1674 case 4:
1675 value /= 0x100;
1676 break;
1677 default:
1678 value = ULONG_MAX;
1679 }
1680 if (value == ULONG_MAX)
1681 break;
1682 colorval |= (value << pos);
1683 pos += 0x8;
1684 if (i == 2)
1685 {
1686 if (*end != '\0')
1687 break;
1688 UNBLOCK_INPUT;
1689 return (colorval);
1690 }
1691 if (*end != '/')
1692 break;
1693 color = end + 1;
1694 }
1695 }
1696 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1697 {
1698 /* This is an RGB Intensity specification. */
1699 char *color;
1700 UINT colorval;
1701 int i, pos;
1702 pos = 0;
1703
1704 colorval = 0;
1705 color = colorname + 5;
1706 for (i = 0; i < 3; i++)
1707 {
1708 char *end;
1709 double value;
1710 UINT val;
1711
1712 value = strtod(color, &end);
1713 if (errno == ERANGE)
1714 break;
1715 if (value < 0.0 || value > 1.0)
1716 break;
1717 val = (UINT)(0x100 * value);
7d0393cf 1718 /* We used 0x100 instead of 0xFF to give a continuous
1edf84e7
GV
1719 range between 0.0 and 1.0 inclusive. The next statement
1720 fixes the 1.0 case. */
1721 if (val == 0x100)
1722 val = 0xFF;
1723 colorval |= (val << pos);
1724 pos += 0x8;
1725 if (i == 2)
1726 {
1727 if (*end != '\0')
1728 break;
1729 UNBLOCK_INPUT;
1730 return (colorval);
1731 }
1732 if (*end != '/')
1733 break;
1734 color = end + 1;
1735 }
1736 }
1737 /* I am not going to attempt to handle any of the CIE color schemes
1738 or TekHVC, since I don't know the algorithms for conversion to
1739 RGB. */
f695b4b1
GV
1740
1741 /* If we fail to lookup the color name in w32_color_map, then check the
7d0393cf 1742 colorname to see if it can be crudely approximated: If the X color
f695b4b1
GV
1743 ends in a number (e.g., "darkseagreen2"), strip the number and
1744 return the result of looking up the base color name. */
1745 ret = w32_color_map_lookup (colorname);
7d0393cf 1746 if (NILP (ret))
ee78dc32 1747 {
f695b4b1 1748 int len = strlen (colorname);
ee78dc32 1749
7d0393cf 1750 if (isdigit (colorname[len - 1]))
f695b4b1 1751 {
8b77111c 1752 char *ptr, *approx = alloca (len + 1);
ee78dc32 1753
f695b4b1
GV
1754 strcpy (approx, colorname);
1755 ptr = &approx[len - 1];
7d0393cf 1756 while (ptr > approx && isdigit (*ptr))
f695b4b1 1757 *ptr-- = '\0';
ee78dc32 1758
f695b4b1 1759 ret = w32_color_map_lookup (approx);
ee78dc32 1760 }
ee78dc32 1761 }
7d0393cf 1762
ee78dc32 1763 UNBLOCK_INPUT;
ee78dc32
GV
1764 return ret;
1765}
1766
5ac45f98
GV
1767
1768void
fbd6baed 1769w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1770{
fbd6baed 1771 struct w32_palette_entry * list;
5ac45f98
GV
1772 LOGPALETTE * log_palette;
1773 HPALETTE new_palette;
1774 int i;
1775
1776 /* don't bother trying to create palette if not supported */
fbd6baed 1777 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1778 return;
1779
1780 log_palette = (LOGPALETTE *)
1781 alloca (sizeof (LOGPALETTE) +
fbd6baed 1782 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1783 log_palette->palVersion = 0x300;
fbd6baed 1784 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1785
fbd6baed 1786 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1787 for (i = 0;
fbd6baed 1788 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1789 i++, list = list->next)
1790 log_palette->palPalEntry[i] = list->entry;
1791
1792 new_palette = CreatePalette (log_palette);
1793
1794 enter_crit ();
1795
fbd6baed
GV
1796 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1797 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1798 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1799
1800 /* Realize display palette and garbage all frames. */
1801 release_frame_dc (f, get_frame_dc (f));
1802
1803 leave_crit ();
1804}
1805
fbd6baed
GV
1806#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1807#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1808 do \
1809 { \
1810 pe.peRed = GetRValue (color); \
1811 pe.peGreen = GetGValue (color); \
1812 pe.peBlue = GetBValue (color); \
1813 pe.peFlags = 0; \
1814 } while (0)
1815
1816#if 0
1817/* Keep these around in case we ever want to track color usage. */
1818void
fbd6baed 1819w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1820{
fbd6baed 1821 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1822
fbd6baed 1823 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1824 return;
1825
1826 /* check if color is already mapped */
1827 while (list)
1828 {
fbd6baed 1829 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1830 {
1831 ++list->refcount;
1832 return;
1833 }
1834 list = list->next;
1835 }
1836
1837 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1838 list = (struct w32_palette_entry *)
1839 xmalloc (sizeof (struct w32_palette_entry));
1840 SET_W32_COLOR (list->entry, color);
5ac45f98 1841 list->refcount = 1;
fbd6baed
GV
1842 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1843 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1844 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1845
1846 /* set flag that palette must be regenerated */
fbd6baed 1847 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1848}
1849
1850void
fbd6baed 1851w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1852{
fbd6baed
GV
1853 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1854 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1855
fbd6baed 1856 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1857 return;
1858
1859 /* check if color is already mapped */
1860 while (list)
1861 {
fbd6baed 1862 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1863 {
1864 if (--list->refcount == 0)
1865 {
1866 *prev = list->next;
1867 xfree (list);
fbd6baed 1868 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1869 break;
1870 }
1871 else
1872 return;
1873 }
1874 prev = &list->next;
1875 list = list->next;
1876 }
1877
1878 /* set flag that palette must be regenerated */
fbd6baed 1879 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1880}
1881#endif
1882
6fc2811b
JR
1883
1884/* Gamma-correct COLOR on frame F. */
1885
1886void
1887gamma_correct (f, color)
1888 struct frame *f;
1889 COLORREF *color;
1890{
1891 if (f->gamma)
1892 {
1893 *color = PALETTERGB (
1894 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1895 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1896 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1897 }
1898}
1899
1900
ee78dc32
GV
1901/* Decide if color named COLOR is valid for the display associated with
1902 the selected frame; if so, return the rgb values in COLOR_DEF.
1903 If ALLOC is nonzero, allocate a new colormap cell. */
1904
1905int
6fc2811b 1906w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1907 FRAME_PTR f;
1908 char *color;
6fc2811b 1909 XColor *color_def;
ee78dc32
GV
1910 int alloc;
1911{
1912 register Lisp_Object tem;
6fc2811b 1913 COLORREF w32_color_ref;
3c190163 1914
fbd6baed 1915 tem = x_to_w32_color (color);
3c190163 1916
7d0393cf 1917 if (!NILP (tem))
ee78dc32 1918 {
d88c567c
JR
1919 if (f)
1920 {
1921 /* Apply gamma correction. */
1922 w32_color_ref = XUINT (tem);
1923 gamma_correct (f, &w32_color_ref);
1924 XSETINT (tem, w32_color_ref);
1925 }
9badad41
JR
1926
1927 /* Map this color to the palette if it is enabled. */
fbd6baed 1928 if (!NILP (Vw32_enable_palette))
5ac45f98 1929 {
fbd6baed 1930 struct w32_palette_entry * entry =
d88c567c 1931 one_w32_display_info.color_list;
fbd6baed 1932 struct w32_palette_entry ** prev =
d88c567c 1933 &one_w32_display_info.color_list;
7d0393cf 1934
5ac45f98
GV
1935 /* check if color is already mapped */
1936 while (entry)
1937 {
fbd6baed 1938 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1939 break;
1940 prev = &entry->next;
1941 entry = entry->next;
1942 }
1943
1944 if (entry == NULL && alloc)
1945 {
1946 /* not already mapped, so add to list */
fbd6baed
GV
1947 entry = (struct w32_palette_entry *)
1948 xmalloc (sizeof (struct w32_palette_entry));
1949 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1950 entry->next = NULL;
1951 *prev = entry;
d88c567c 1952 one_w32_display_info.num_colors++;
5ac45f98
GV
1953
1954 /* set flag that palette must be regenerated */
d88c567c 1955 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1956 }
1957 }
1958 /* Ensure COLORREF value is snapped to nearest color in (default)
1959 palette by simulating the PALETTERGB macro. This works whether
1960 or not the display device has a palette. */
6fc2811b
JR
1961 w32_color_ref = XUINT (tem) | 0x2000000;
1962
6fc2811b 1963 color_def->pixel = w32_color_ref;
197edd35
JR
1964 color_def->red = GetRValue (w32_color_ref) * 256;
1965 color_def->green = GetGValue (w32_color_ref) * 256;
1966 color_def->blue = GetBValue (w32_color_ref) * 256;
6fc2811b 1967
ee78dc32 1968 return 1;
5ac45f98 1969 }
7d0393cf 1970 else
3c190163
GV
1971 {
1972 return 0;
1973 }
ee78dc32
GV
1974}
1975
1976/* Given a string ARG naming a color, compute a pixel value from it
1977 suitable for screen F.
1978 If F is not a color screen, return DEF (default) regardless of what
1979 ARG says. */
1980
1981int
1982x_decode_color (f, arg, def)
1983 FRAME_PTR f;
1984 Lisp_Object arg;
1985 int def;
1986{
6fc2811b 1987 XColor cdef;
ee78dc32 1988
b7826503 1989 CHECK_STRING (arg);
ee78dc32 1990
d5db4077 1991 if (strcmp (SDATA (arg), "black") == 0)
ee78dc32 1992 return BLACK_PIX_DEFAULT (f);
d5db4077 1993 else if (strcmp (SDATA (arg), "white") == 0)
ee78dc32
GV
1994 return WHITE_PIX_DEFAULT (f);
1995
fbd6baed 1996 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1997 return def;
1998
6fc2811b 1999 /* w32_defined_color is responsible for coping with failures
ee78dc32 2000 by looking for a near-miss. */
d5db4077 2001 if (w32_defined_color (f, SDATA (arg), &cdef, 1))
6fc2811b 2002 return cdef.pixel;
ee78dc32
GV
2003
2004 /* defined_color failed; return an ultimate default. */
2005 return def;
2006}
2007\f
dfff8a69
JR
2008/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2009 the previous value of that parameter, NEW_VALUE is the new value. */
2010
2011static void
2012x_set_line_spacing (f, new_value, old_value)
2013 struct frame *f;
2014 Lisp_Object new_value, old_value;
2015{
2016 if (NILP (new_value))
2017 f->extra_line_spacing = 0;
2018 else if (NATNUMP (new_value))
2019 f->extra_line_spacing = XFASTINT (new_value);
2020 else
1a948b17 2021 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
2022 Fcons (new_value, Qnil)));
2023 if (FRAME_VISIBLE_P (f))
2024 redraw_frame (f);
2025}
2026
2027
f7b9d4d1
JR
2028/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2029 the previous value of that parameter, NEW_VALUE is the new value. */
2030
2031static void
2032x_set_fullscreen (f, new_value, old_value)
2033 struct frame *f;
2034 Lisp_Object new_value, old_value;
2035{
2036 if (NILP (new_value))
2037 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2038 else if (EQ (new_value, Qfullboth))
2039 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2040 else if (EQ (new_value, Qfullwidth))
2041 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2042 else if (EQ (new_value, Qfullheight))
2043 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2044}
2045
2046
6fc2811b
JR
2047/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2048 the previous value of that parameter, NEW_VALUE is the new value. */
2049
2050static void
2051x_set_screen_gamma (f, new_value, old_value)
2052 struct frame *f;
2053 Lisp_Object new_value, old_value;
2054{
2055 if (NILP (new_value))
2056 f->gamma = 0;
2057 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2058 /* The value 0.4545 is the normal viewing gamma. */
2059 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2060 else
1a948b17 2061 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
2062 Fcons (new_value, Qnil)));
2063
2064 clear_face_cache (0);
2065}
2066
2067
ee78dc32
GV
2068/* Functions called only from `x_set_frame_param'
2069 to set individual parameters.
2070
fbd6baed 2071 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
2072 the frame is being created and its window does not exist yet.
2073 In that case, just record the parameter's new value
2074 in the standard place; do not attempt to change the window. */
2075
2076void
2077x_set_foreground_color (f, arg, oldval)
2078 struct frame *f;
2079 Lisp_Object arg, oldval;
2080{
3cf3436e
JR
2081 struct w32_output *x = f->output_data.w32;
2082 PIX_TYPE fg, old_fg;
2083
2084 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2085 old_fg = FRAME_FOREGROUND_PIXEL (f);
2086 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2087
fbd6baed 2088 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2089 {
3cf3436e
JR
2090 if (x->cursor_pixel == old_fg)
2091 x->cursor_pixel = fg;
2092
6fc2811b 2093 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2094 if (FRAME_VISIBLE_P (f))
2095 redraw_frame (f);
2096 }
2097}
2098
2099void
2100x_set_background_color (f, arg, oldval)
2101 struct frame *f;
2102 Lisp_Object arg, oldval;
2103{
6fc2811b 2104 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2105 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2106
fbd6baed 2107 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2108 {
6fc2811b
JR
2109 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2110 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2111
6fc2811b 2112 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2113
2114 if (FRAME_VISIBLE_P (f))
2115 redraw_frame (f);
2116 }
2117}
2118
2119void
2120x_set_mouse_color (f, arg, oldval)
2121 struct frame *f;
2122 Lisp_Object arg, oldval;
2123{
ee78dc32 2124 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2125 int count;
ee78dc32
GV
2126 int mask_color;
2127
2128 if (!EQ (Qnil, arg))
fbd6baed 2129 f->output_data.w32->mouse_pixel
ee78dc32 2130 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2131 mask_color = FRAME_BACKGROUND_PIXEL (f);
2132
2133 /* Don't let pointers be invisible. */
fbd6baed 2134 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2135 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2136 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2137
767b1ff0 2138#if 0 /* TODO : cursor changes */
ee78dc32
GV
2139 BLOCK_INPUT;
2140
2141 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2142 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2143
2144 if (!EQ (Qnil, Vx_pointer_shape))
2145 {
b7826503 2146 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2147 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2148 }
2149 else
fbd6baed
GV
2150 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2151 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2152
2153 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2154 {
b7826503 2155 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2156 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2157 XINT (Vx_nontext_pointer_shape));
2158 }
2159 else
fbd6baed
GV
2160 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2161 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2162
0af913d7 2163 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2164 {
b7826503 2165 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2166 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2167 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2168 }
2169 else
0af913d7 2170 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b 2171 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
7d0393cf 2172
6fc2811b 2173 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2174 if (!EQ (Qnil, Vx_mode_pointer_shape))
2175 {
b7826503 2176 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2177 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2178 XINT (Vx_mode_pointer_shape));
2179 }
2180 else
fbd6baed
GV
2181 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2182 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2183
2184 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2185 {
b7826503 2186 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2187 cross_cursor
fbd6baed 2188 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2189 XINT (Vx_sensitive_text_pointer_shape));
2190 }
2191 else
fbd6baed 2192 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2193
4694d762
JR
2194 if (!NILP (Vx_window_horizontal_drag_shape))
2195 {
b7826503 2196 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2197 horizontal_drag_cursor
2198 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2199 XINT (Vx_window_horizontal_drag_shape));
2200 }
2201 else
2202 horizontal_drag_cursor
2203 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
c9b2104d 2204 /* TODO: hand_cursor */
4694d762 2205
ee78dc32 2206 /* Check and report errors with the above calls. */
fbd6baed 2207 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2208 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2209
2210 {
2211 XColor fore_color, back_color;
2212
fbd6baed 2213 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2214 back_color.pixel = mask_color;
fbd6baed
GV
2215 XQueryColor (FRAME_W32_DISPLAY (f),
2216 DefaultColormap (FRAME_W32_DISPLAY (f),
2217 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2218 &fore_color);
fbd6baed
GV
2219 XQueryColor (FRAME_W32_DISPLAY (f),
2220 DefaultColormap (FRAME_W32_DISPLAY (f),
2221 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2222 &back_color);
fbd6baed 2223 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2224 &fore_color, &back_color);
fbd6baed 2225 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2226 &fore_color, &back_color);
fbd6baed 2227 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2228 &fore_color, &back_color);
fbd6baed 2229 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2230 &fore_color, &back_color);
0af913d7 2231 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2232 &fore_color, &back_color);
c9b2104d 2233 /* TODO: hand_cursor */
ee78dc32
GV
2234 }
2235
fbd6baed 2236 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2237 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2238
fbd6baed
GV
2239 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2240 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2241 f->output_data.w32->text_cursor = cursor;
2242
2243 if (nontext_cursor != f->output_data.w32->nontext_cursor
2244 && f->output_data.w32->nontext_cursor != 0)
2245 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2246 f->output_data.w32->nontext_cursor = nontext_cursor;
2247
0af913d7
GM
2248 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2249 && f->output_data.w32->hourglass_cursor != 0)
2250 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2251 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2252
fbd6baed
GV
2253 if (mode_cursor != f->output_data.w32->modeline_cursor
2254 && f->output_data.w32->modeline_cursor != 0)
2255 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2256 f->output_data.w32->modeline_cursor = mode_cursor;
7d0393cf 2257
fbd6baed
GV
2258 if (cross_cursor != f->output_data.w32->cross_cursor
2259 && f->output_data.w32->cross_cursor != 0)
2260 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2261 f->output_data.w32->cross_cursor = cross_cursor;
c9b2104d 2262 /* TODO: hand_cursor */
fbd6baed
GV
2263
2264 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2265 UNBLOCK_INPUT;
6fc2811b
JR
2266
2267 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2268#endif /* TODO */
ee78dc32
GV
2269}
2270
70a0239a
JR
2271/* Defined in w32term.c. */
2272void x_update_cursor (struct frame *f, int on_p);
2273
ee78dc32
GV
2274void
2275x_set_cursor_color (f, arg, oldval)
2276 struct frame *f;
2277 Lisp_Object arg, oldval;
2278{
70a0239a 2279 unsigned long fore_pixel, pixel;
ee78dc32 2280
dfff8a69 2281 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2282 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2283 WHITE_PIX_DEFAULT (f));
ee78dc32 2284 else
6fc2811b 2285 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2286
6759f872 2287 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
7d0393cf 2288
ee78dc32 2289 /* Make sure that the cursor color differs from the background color. */
70a0239a 2290 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2291 {
70a0239a
JR
2292 pixel = f->output_data.w32->mouse_pixel;
2293 if (pixel == fore_pixel)
6fc2811b 2294 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2295 }
70a0239a 2296
ac849ba4 2297 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
70a0239a 2298 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2299
fbd6baed 2300 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2301 {
0327b4cc
JR
2302 BLOCK_INPUT;
2303 /* Update frame's cursor_gc. */
2304 f->output_data.w32->cursor_gc->foreground = fore_pixel;
2305 f->output_data.w32->cursor_gc->background = pixel;
2306
2307 UNBLOCK_INPUT;
2308
ee78dc32
GV
2309 if (FRAME_VISIBLE_P (f))
2310 {
70a0239a
JR
2311 x_update_cursor (f, 0);
2312 x_update_cursor (f, 1);
ee78dc32
GV
2313 }
2314 }
6fc2811b
JR
2315
2316 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2317}
2318
33d52f9c
GV
2319/* Set the border-color of frame F to pixel value PIX.
2320 Note that this does not fully take effect if done before
7d0393cf 2321 F has a window. */
33d52f9c
GV
2322void
2323x_set_border_pixel (f, pix)
2324 struct frame *f;
2325 int pix;
2326{
2327 f->output_data.w32->border_pixel = pix;
2328
2329 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2330 {
2331 if (FRAME_VISIBLE_P (f))
2332 redraw_frame (f);
2333 }
2334}
2335
ee78dc32
GV
2336/* Set the border-color of frame F to value described by ARG.
2337 ARG can be a string naming a color.
2338 The border-color is used for the border that is drawn by the server.
2339 Note that this does not fully take effect if done before
2340 F has a window; it must be redone when the window is created. */
2341
2342void
2343x_set_border_color (f, arg, oldval)
2344 struct frame *f;
2345 Lisp_Object arg, oldval;
2346{
ee78dc32
GV
2347 int pix;
2348
b7826503 2349 CHECK_STRING (arg);
ee78dc32 2350 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2351 x_set_border_pixel (f, pix);
6fc2811b 2352 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2353}
2354
dfff8a69
JR
2355
2356void
2357x_set_cursor_type (f, arg, oldval)
2358 FRAME_PTR f;
2359 Lisp_Object arg, oldval;
2360{
50e363e6 2361 set_frame_cursor_types (f, arg);
ee78dc32 2362
623cdbf2 2363 /* Make sure the cursor gets redrawn. */
c922a224 2364 cursor_type_changed = 1;
ee78dc32 2365}
dfff8a69 2366\f
ee78dc32
GV
2367void
2368x_set_icon_type (f, arg, oldval)
2369 struct frame *f;
2370 Lisp_Object arg, oldval;
2371{
ee78dc32
GV
2372 int result;
2373
eb7576ce
GV
2374 if (NILP (arg) && NILP (oldval))
2375 return;
2376
7d0393cf 2377 if (STRINGP (arg) && STRINGP (oldval)
eb7576ce
GV
2378 && EQ (Fstring_equal (oldval, arg), Qt))
2379 return;
2380
2381 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2382 return;
2383
2384 BLOCK_INPUT;
ee78dc32 2385
eb7576ce 2386 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2387 if (result)
2388 {
2389 UNBLOCK_INPUT;
2390 error ("No icon window available");
2391 }
2392
ee78dc32 2393 UNBLOCK_INPUT;
ee78dc32
GV
2394}
2395
2396/* Return non-nil if frame F wants a bitmap icon. */
2397
2398Lisp_Object
2399x_icon_type (f)
2400 FRAME_PTR f;
2401{
2402 Lisp_Object tem;
2403
2404 tem = assq_no_quit (Qicon_type, f->param_alist);
2405 if (CONSP (tem))
8e713be6 2406 return XCDR (tem);
ee78dc32
GV
2407 else
2408 return Qnil;
2409}
2410
2411void
2412x_set_icon_name (f, arg, oldval)
2413 struct frame *f;
2414 Lisp_Object arg, oldval;
2415{
ee78dc32
GV
2416 if (STRINGP (arg))
2417 {
2418 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2419 return;
2420 }
2421 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2422 return;
2423
2424 f->icon_name = arg;
2425
2426#if 0
fbd6baed 2427 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2428 return;
2429
2430 BLOCK_INPUT;
2431
2432 result = x_text_icon (f,
d5db4077
KR
2433 (char *) SDATA ((!NILP (f->icon_name)
2434 ? f->icon_name
2435 : !NILP (f->title)
2436 ? f->title
2437 : f->name)));
ee78dc32
GV
2438
2439 if (result)
2440 {
2441 UNBLOCK_INPUT;
2442 error ("No icon window available");
2443 }
2444
2445 /* If the window was unmapped (and its icon was mapped),
2446 the new icon is not mapped, so map the window in its stead. */
2447 if (FRAME_VISIBLE_P (f))
2448 {
2449#ifdef USE_X_TOOLKIT
fbd6baed 2450 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2451#endif
fbd6baed 2452 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2453 }
2454
fbd6baed 2455 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2456 UNBLOCK_INPUT;
2457#endif
2458}
2459
2460extern Lisp_Object x_new_font ();
4587b026 2461extern Lisp_Object x_new_fontset();
ee78dc32
GV
2462
2463void
2464x_set_font (f, arg, oldval)
2465 struct frame *f;
2466 Lisp_Object arg, oldval;
2467{
2468 Lisp_Object result;
4587b026 2469 Lisp_Object fontset_name;
4b817373 2470 Lisp_Object frame;
3cf3436e 2471 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2472
b7826503 2473 CHECK_STRING (arg);
ee78dc32 2474
4587b026
GV
2475 fontset_name = Fquery_fontset (arg, Qnil);
2476
ee78dc32 2477 BLOCK_INPUT;
4587b026 2478 result = (STRINGP (fontset_name)
d5db4077
KR
2479 ? x_new_fontset (f, SDATA (fontset_name))
2480 : x_new_font (f, SDATA (arg)));
ee78dc32 2481 UNBLOCK_INPUT;
7d0393cf 2482
ee78dc32 2483 if (EQ (result, Qnil))
d5db4077 2484 error ("Font `%s' is not defined", SDATA (arg));
ee78dc32 2485 else if (EQ (result, Qt))
dfff8a69 2486 error ("The characters of the given font have varying widths");
ee78dc32
GV
2487 else if (STRINGP (result))
2488 {
3cf3436e
JR
2489 if (STRINGP (fontset_name))
2490 {
2491 /* Fontset names are built from ASCII font names, so the
2492 names may be equal despite there was a change. */
2493 if (old_fontset == FRAME_FONTSET (f))
2494 return;
2495 }
2496 else if (!NILP (Fequal (result, oldval)))
dc220243 2497 return;
3cf3436e 2498
ee78dc32 2499 store_frame_param (f, Qfont, result);
6fc2811b 2500 recompute_basic_faces (f);
ee78dc32
GV
2501 }
2502 else
2503 abort ();
4b817373 2504
6fc2811b
JR
2505 do_pending_window_change (0);
2506
2507 /* Don't call `face-set-after-frame-default' when faces haven't been
2508 initialized yet. This is the case when called from
2509 Fx_create_frame. In that case, the X widget or window doesn't
2510 exist either, and we can end up in x_report_frame_params with a
2511 null widget which gives a segfault. */
2512 if (FRAME_FACE_CACHE (f))
2513 {
2514 XSETFRAME (frame, f);
2515 call1 (Qface_set_after_frame_default, frame);
2516 }
ee78dc32
GV
2517}
2518
41c1bdd9
KS
2519static void
2520x_set_fringe_width (f, new_value, old_value)
2521 struct frame *f;
2522 Lisp_Object new_value, old_value;
2523{
2524 x_compute_fringe_widths (f, 1);
2525}
2526
ee78dc32
GV
2527void
2528x_set_border_width (f, arg, oldval)
2529 struct frame *f;
2530 Lisp_Object arg, oldval;
2531{
b7826503 2532 CHECK_NUMBER (arg);
ee78dc32 2533
fbd6baed 2534 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2535 return;
2536
fbd6baed 2537 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2538 error ("Cannot change the border width of a window");
2539
fbd6baed 2540 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2541}
2542
2543void
2544x_set_internal_border_width (f, arg, oldval)
2545 struct frame *f;
2546 Lisp_Object arg, oldval;
2547{
fbd6baed 2548 int old = f->output_data.w32->internal_border_width;
ee78dc32 2549
b7826503 2550 CHECK_NUMBER (arg);
fbd6baed
GV
2551 f->output_data.w32->internal_border_width = XINT (arg);
2552 if (f->output_data.w32->internal_border_width < 0)
2553 f->output_data.w32->internal_border_width = 0;
ee78dc32 2554
fbd6baed 2555 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2556 return;
2557
fbd6baed 2558 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2559 {
ee78dc32 2560 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2561 SET_FRAME_GARBAGED (f);
6fc2811b 2562 do_pending_window_change (0);
ee78dc32 2563 }
a05e2bae
JR
2564 else
2565 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2566}
2567
2568void
2569x_set_visibility (f, value, oldval)
2570 struct frame *f;
2571 Lisp_Object value, oldval;
2572{
2573 Lisp_Object frame;
2574 XSETFRAME (frame, f);
2575
2576 if (NILP (value))
2577 Fmake_frame_invisible (frame, Qt);
2578 else if (EQ (value, Qicon))
2579 Ficonify_frame (frame);
2580 else
2581 Fmake_frame_visible (frame);
2582}
2583
a1258667
JR
2584\f
2585/* Change window heights in windows rooted in WINDOW by N lines. */
2586
2587static void
2588x_change_window_heights (window, n)
2589 Lisp_Object window;
2590 int n;
2591{
2592 struct window *w = XWINDOW (window);
2593
2594 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2595 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2596
2597 if (INTEGERP (w->orig_top))
2598 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2599 if (INTEGERP (w->orig_height))
2600 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2601
2602 /* Handle just the top child in a vertical split. */
2603 if (!NILP (w->vchild))
2604 x_change_window_heights (w->vchild, n);
2605
2606 /* Adjust all children in a horizontal split. */
2607 for (window = w->hchild; !NILP (window); window = w->next)
2608 {
2609 w = XWINDOW (window);
2610 x_change_window_heights (window, n);
2611 }
2612}
2613
ee78dc32
GV
2614void
2615x_set_menu_bar_lines (f, value, oldval)
2616 struct frame *f;
2617 Lisp_Object value, oldval;
2618{
2619 int nlines;
2620 int olines = FRAME_MENU_BAR_LINES (f);
2621
2622 /* Right now, menu bars don't work properly in minibuf-only frames;
2623 most of the commands try to apply themselves to the minibuffer
6fc2811b 2624 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2625 in or split the minibuffer window. */
2626 if (FRAME_MINIBUF_ONLY_P (f))
2627 return;
2628
2629 if (INTEGERP (value))
2630 nlines = XINT (value);
2631 else
2632 nlines = 0;
2633
2634 FRAME_MENU_BAR_LINES (f) = 0;
2635 if (nlines)
2636 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2637 else
2638 {
2639 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2640 free_frame_menubar (f);
2641 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2642
2643 /* Adjust the frame size so that the client (text) dimensions
2644 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2645 set correctly. */
2646 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2647 do_pending_window_change (0);
ee78dc32 2648 }
6fc2811b
JR
2649 adjust_glyphs (f);
2650}
2651
2652
2653/* Set the number of lines used for the tool bar of frame F to VALUE.
2654 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2655 is the old number of tool bar lines. This function changes the
2656 height of all windows on frame F to match the new tool bar height.
2657 The frame's height doesn't change. */
2658
2659void
2660x_set_tool_bar_lines (f, value, oldval)
2661 struct frame *f;
2662 Lisp_Object value, oldval;
2663{
36f8209a
JR
2664 int delta, nlines, root_height;
2665 Lisp_Object root_window;
6fc2811b 2666
dc220243
JR
2667 /* Treat tool bars like menu bars. */
2668 if (FRAME_MINIBUF_ONLY_P (f))
2669 return;
2670
6fc2811b
JR
2671 /* Use VALUE only if an integer >= 0. */
2672 if (INTEGERP (value) && XINT (value) >= 0)
2673 nlines = XFASTINT (value);
2674 else
2675 nlines = 0;
2676
2677 /* Make sure we redisplay all windows in this frame. */
2678 ++windows_or_buffers_changed;
2679
2680 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2681
2682 /* Don't resize the tool-bar to more than we have room for. */
2683 root_window = FRAME_ROOT_WINDOW (f);
2684 root_height = XINT (XWINDOW (root_window)->height);
2685 if (root_height - delta < 1)
2686 {
2687 delta = root_height - 1;
2688 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2689 }
2690
6fc2811b 2691 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2692 x_change_window_heights (root_window, delta);
6fc2811b 2693 adjust_glyphs (f);
36f8209a
JR
2694
2695 /* We also have to make sure that the internal border at the top of
2696 the frame, below the menu bar or tool bar, is redrawn when the
2697 tool bar disappears. This is so because the internal border is
2698 below the tool bar if one is displayed, but is below the menu bar
2699 if there isn't a tool bar. The tool bar draws into the area
2700 below the menu bar. */
2701 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2702 {
2703 updating_frame = f;
2704 clear_frame ();
2705 clear_current_matrices (f);
2706 updating_frame = NULL;
2707 }
2708
2709 /* If the tool bar gets smaller, the internal border below it
2710 has to be cleared. It was formerly part of the display
2711 of the larger tool bar, and updating windows won't clear it. */
2712 if (delta < 0)
2713 {
2714 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2715 int width = PIXEL_WIDTH (f);
2716 int y = nlines * CANON_Y_UNIT (f);
2717
2718 BLOCK_INPUT;
2719 {
2720 HDC hdc = get_frame_dc (f);
2721 w32_clear_area (f, hdc, 0, y, width, height);
2722 release_frame_dc (f, hdc);
2723 }
2724 UNBLOCK_INPUT;
3cf3436e
JR
2725
2726 if (WINDOWP (f->tool_bar_window))
2727 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2728 }
ee78dc32
GV
2729}
2730
6fc2811b 2731
ee78dc32 2732/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2733 w32_id_name.
ee78dc32
GV
2734
2735 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2736 name; if NAME is a string, set F's name to NAME and set
2737 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2738
2739 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2740 suggesting a new name, which lisp code should override; if
2741 F->explicit_name is set, ignore the new name; otherwise, set it. */
2742
2743void
2744x_set_name (f, name, explicit)
2745 struct frame *f;
2746 Lisp_Object name;
2747 int explicit;
2748{
7d0393cf 2749 /* Make sure that requests from lisp code override requests from
ee78dc32
GV
2750 Emacs redisplay code. */
2751 if (explicit)
2752 {
2753 /* If we're switching from explicit to implicit, we had better
2754 update the mode lines and thereby update the title. */
2755 if (f->explicit_name && NILP (name))
2756 update_mode_lines = 1;
2757
2758 f->explicit_name = ! NILP (name);
2759 }
2760 else if (f->explicit_name)
2761 return;
2762
fbd6baed 2763 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2764 if (NILP (name))
2765 {
2766 /* Check for no change needed in this very common case
2767 before we do any consing. */
fbd6baed 2768 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
d5db4077 2769 SDATA (f->name)))
ee78dc32 2770 return;
fbd6baed 2771 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2772 }
2773 else
b7826503 2774 CHECK_STRING (name);
ee78dc32
GV
2775
2776 /* Don't change the name if it's already NAME. */
2777 if (! NILP (Fstring_equal (name, f->name)))
2778 return;
2779
1edf84e7
GV
2780 f->name = name;
2781
2782 /* For setting the frame title, the title parameter should override
2783 the name parameter. */
2784 if (! NILP (f->title))
2785 name = f->title;
2786
fbd6baed 2787 if (FRAME_W32_WINDOW (f))
ee78dc32 2788 {
6fc2811b 2789 if (STRING_MULTIBYTE (name))
dfff8a69 2790 name = ENCODE_SYSTEM (name);
6fc2811b 2791
ee78dc32 2792 BLOCK_INPUT;
d5db4077 2793 SetWindowText(FRAME_W32_WINDOW (f), SDATA (name));
ee78dc32
GV
2794 UNBLOCK_INPUT;
2795 }
ee78dc32
GV
2796}
2797
2798/* This function should be called when the user's lisp code has
2799 specified a name for the frame; the name will override any set by the
2800 redisplay code. */
2801void
2802x_explicitly_set_name (f, arg, oldval)
2803 FRAME_PTR f;
2804 Lisp_Object arg, oldval;
2805{
2806 x_set_name (f, arg, 1);
2807}
2808
2809/* This function should be called by Emacs redisplay code to set the
2810 name; names set this way will never override names set by the user's
2811 lisp code. */
2812void
2813x_implicitly_set_name (f, arg, oldval)
2814 FRAME_PTR f;
2815 Lisp_Object arg, oldval;
2816{
2817 x_set_name (f, arg, 0);
2818}
1edf84e7
GV
2819\f
2820/* Change the title of frame F to NAME.
2821 If NAME is nil, use the frame name as the title.
2822
2823 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2824 name; if NAME is a string, set F's name to NAME and set
2825 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2826
2827 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2828 suggesting a new name, which lisp code should override; if
2829 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2830
1edf84e7 2831void
6fc2811b 2832x_set_title (f, name, old_name)
1edf84e7 2833 struct frame *f;
6fc2811b 2834 Lisp_Object name, old_name;
1edf84e7
GV
2835{
2836 /* Don't change the title if it's already NAME. */
2837 if (EQ (name, f->title))
2838 return;
2839
2840 update_mode_lines = 1;
2841
2842 f->title = name;
2843
2844 if (NILP (name))
2845 name = f->name;
2846
2847 if (FRAME_W32_WINDOW (f))
2848 {
6fc2811b 2849 if (STRING_MULTIBYTE (name))
dfff8a69 2850 name = ENCODE_SYSTEM (name);
6fc2811b 2851
1edf84e7 2852 BLOCK_INPUT;
d5db4077 2853 SetWindowText(FRAME_W32_WINDOW (f), SDATA (name));
1edf84e7
GV
2854 UNBLOCK_INPUT;
2855 }
2856}
2857\f
ee78dc32
GV
2858void
2859x_set_autoraise (f, arg, oldval)
2860 struct frame *f;
2861 Lisp_Object arg, oldval;
2862{
2863 f->auto_raise = !EQ (Qnil, arg);
2864}
2865
2866void
2867x_set_autolower (f, arg, oldval)
2868 struct frame *f;
2869 Lisp_Object arg, oldval;
2870{
2871 f->auto_lower = !EQ (Qnil, arg);
2872}
2873
2874void
2875x_set_unsplittable (f, arg, oldval)
2876 struct frame *f;
2877 Lisp_Object arg, oldval;
2878{
2879 f->no_split = !NILP (arg);
2880}
2881
2882void
2883x_set_vertical_scroll_bars (f, arg, oldval)
2884 struct frame *f;
2885 Lisp_Object arg, oldval;
2886{
1026b400
RS
2887 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2888 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2889 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2890 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2891 {
1026b400
RS
2892 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2893 vertical_scroll_bar_none :
87996783
GV
2894 /* Put scroll bars on the right by default, as is conventional
2895 on MS-Windows. */
2896 EQ (Qleft, arg)
7d0393cf 2897 ? vertical_scroll_bar_left
87996783 2898 : vertical_scroll_bar_right;
ee78dc32
GV
2899
2900 /* We set this parameter before creating the window for the
2901 frame, so we can get the geometry right from the start.
2902 However, if the window hasn't been created yet, we shouldn't
2903 call x_set_window_size. */
fbd6baed 2904 if (FRAME_W32_WINDOW (f))
ee78dc32 2905 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2906 do_pending_window_change (0);
ee78dc32
GV
2907 }
2908}
2909
2910void
2911x_set_scroll_bar_width (f, arg, oldval)
2912 struct frame *f;
2913 Lisp_Object arg, oldval;
2914{
6fc2811b
JR
2915 int wid = FONT_WIDTH (f->output_data.w32->font);
2916
ee78dc32
GV
2917 if (NILP (arg))
2918 {
6fc2811b
JR
2919 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2920 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2921 wid - 1) / wid;
2922 if (FRAME_W32_WINDOW (f))
2923 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2924 do_pending_window_change (0);
ee78dc32
GV
2925 }
2926 else if (INTEGERP (arg) && XINT (arg) > 0
2927 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2928 {
ee78dc32 2929 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2930 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2931 + wid-1) / wid;
fbd6baed 2932 if (FRAME_W32_WINDOW (f))
ee78dc32 2933 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2934 do_pending_window_change (0);
ee78dc32 2935 }
6fc2811b
JR
2936 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2937 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
7d0393cf 2938 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2939}
2940\f
7d0393cf 2941/* Subroutines of creating a frame. */
ee78dc32
GV
2942
2943/* Make sure that Vx_resource_name is set to a reasonable value.
2944 Fix it up, or set it to `emacs' if it is too hopeless. */
2945
2946static void
2947validate_x_resource_name ()
2948{
6fc2811b 2949 int len = 0;
ee78dc32
GV
2950 /* Number of valid characters in the resource name. */
2951 int good_count = 0;
2952 /* Number of invalid characters in the resource name. */
2953 int bad_count = 0;
2954 Lisp_Object new;
2955 int i;
2956
2957 if (STRINGP (Vx_resource_name))
2958 {
d5db4077 2959 unsigned char *p = SDATA (Vx_resource_name);
ee78dc32
GV
2960 int i;
2961
d5db4077 2962 len = SBYTES (Vx_resource_name);
ee78dc32
GV
2963
2964 /* Only letters, digits, - and _ are valid in resource names.
2965 Count the valid characters and count the invalid ones. */
2966 for (i = 0; i < len; i++)
2967 {
2968 int c = p[i];
2969 if (! ((c >= 'a' && c <= 'z')
2970 || (c >= 'A' && c <= 'Z')
2971 || (c >= '0' && c <= '9')
2972 || c == '-' || c == '_'))
2973 bad_count++;
2974 else
2975 good_count++;
2976 }
2977 }
2978 else
2979 /* Not a string => completely invalid. */
2980 bad_count = 5, good_count = 0;
2981
2982 /* If name is valid already, return. */
2983 if (bad_count == 0)
2984 return;
2985
2986 /* If name is entirely invalid, or nearly so, use `emacs'. */
2987 if (good_count == 0
2988 || (good_count == 1 && bad_count > 0))
2989 {
2990 Vx_resource_name = build_string ("emacs");
2991 return;
2992 }
2993
2994 /* Name is partly valid. Copy it and replace the invalid characters
2995 with underscores. */
2996
2997 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2998
2999 for (i = 0; i < len; i++)
3000 {
d5db4077 3001 int c = SREF (new, i);
ee78dc32
GV
3002 if (! ((c >= 'a' && c <= 'z')
3003 || (c >= 'A' && c <= 'Z')
3004 || (c >= '0' && c <= '9')
3005 || c == '-' || c == '_'))
7960d5ab 3006 SSET (new, i, '_');
ee78dc32
GV
3007 }
3008}
3009
3010
3011extern char *x_get_string_resource ();
3012
3013DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
3014 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3015This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3016class, where INSTANCE is the name under which Emacs was invoked, or
3017the name specified by the `-name' or `-rn' command-line arguments.
3018
3019The optional arguments COMPONENT and SUBCLASS add to the key and the
3020class, respectively. You must specify both of them or neither.
3021If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3022and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
3023 (attribute, class, component, subclass)
3024 Lisp_Object attribute, class, component, subclass;
3025{
3026 register char *value;
3027 char *name_key;
3028 char *class_key;
3029
b7826503
PJ
3030 CHECK_STRING (attribute);
3031 CHECK_STRING (class);
ee78dc32
GV
3032
3033 if (!NILP (component))
b7826503 3034 CHECK_STRING (component);
ee78dc32 3035 if (!NILP (subclass))
b7826503 3036 CHECK_STRING (subclass);
ee78dc32
GV
3037 if (NILP (component) != NILP (subclass))
3038 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3039
3040 validate_x_resource_name ();
3041
3042 /* Allocate space for the components, the dots which separate them,
3043 and the final '\0'. Make them big enough for the worst case. */
d5db4077 3044 name_key = (char *) alloca (SBYTES (Vx_resource_name)
ee78dc32 3045 + (STRINGP (component)
d5db4077
KR
3046 ? SBYTES (component) : 0)
3047 + SBYTES (attribute)
ee78dc32
GV
3048 + 3);
3049
3050 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
d5db4077 3051 + SBYTES (class)
ee78dc32 3052 + (STRINGP (subclass)
d5db4077 3053 ? SBYTES (subclass) : 0)
ee78dc32
GV
3054 + 3);
3055
3056 /* Start with emacs.FRAMENAME for the name (the specific one)
3057 and with `Emacs' for the class key (the general one). */
d5db4077 3058 strcpy (name_key, SDATA (Vx_resource_name));
ee78dc32
GV
3059 strcpy (class_key, EMACS_CLASS);
3060
3061 strcat (class_key, ".");
d5db4077 3062 strcat (class_key, SDATA (class));
ee78dc32
GV
3063
3064 if (!NILP (component))
3065 {
3066 strcat (class_key, ".");
d5db4077 3067 strcat (class_key, SDATA (subclass));
ee78dc32
GV
3068
3069 strcat (name_key, ".");
d5db4077 3070 strcat (name_key, SDATA (component));
ee78dc32
GV
3071 }
3072
3073 strcat (name_key, ".");
d5db4077 3074 strcat (name_key, SDATA (attribute));
ee78dc32 3075
e5af3c25 3076 value = x_get_string_resource (check_x_display_info (Qnil)->xrdb,
ee78dc32
GV
3077 name_key, class_key);
3078
3079 if (value != (char *) 0)
3080 return build_string (value);
3081 else
3082 return Qnil;
3083}
3084
3085/* Used when C code wants a resource value. */
3086
3087char *
3088x_get_resource_string (attribute, class)
3089 char *attribute, *class;
3090{
ee78dc32
GV
3091 char *name_key;
3092 char *class_key;
6fc2811b 3093 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3094
3095 /* Allocate space for the components, the dots which separate them,
3096 and the final '\0'. */
d5db4077 3097 name_key = (char *) alloca (SBYTES (Vinvocation_name)
ee78dc32
GV
3098 + strlen (attribute) + 2);
3099 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3100 + strlen (class) + 2);
3101
3102 sprintf (name_key, "%s.%s",
d5db4077 3103 SDATA (Vinvocation_name),
ee78dc32
GV
3104 attribute);
3105 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3106
e5af3c25
JB
3107 return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
3108 name_key, class_key);
ee78dc32
GV
3109}
3110
3111/* Types we might convert a resource string into. */
3112enum resource_types
6fc2811b
JR
3113{
3114 RES_TYPE_NUMBER,
3115 RES_TYPE_FLOAT,
3116 RES_TYPE_BOOLEAN,
3117 RES_TYPE_STRING,
3118 RES_TYPE_SYMBOL
3119};
ee78dc32
GV
3120
3121/* Return the value of parameter PARAM.
3122
3123 First search ALIST, then Vdefault_frame_alist, then the X defaults
3124 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3125
3126 Convert the resource to the type specified by desired_type.
3127
3128 If no default is specified, return Qunbound. If you call
6fc2811b 3129 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3130 and don't let it get stored in any Lisp-visible variables! */
3131
3132static Lisp_Object
6fc2811b 3133w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3134 Lisp_Object alist, param;
3135 char *attribute;
3136 char *class;
3137 enum resource_types type;
3138{
3139 register Lisp_Object tem;
3140
3141 tem = Fassq (param, alist);
3142 if (EQ (tem, Qnil))
3143 tem = Fassq (param, Vdefault_frame_alist);
3144 if (EQ (tem, Qnil))
3145 {
3146
3147 if (attribute)
3148 {
3149 tem = Fx_get_resource (build_string (attribute),
3150 build_string (class),
3151 Qnil, Qnil);
3152
3153 if (NILP (tem))
3154 return Qunbound;
3155
3156 switch (type)
3157 {
6fc2811b 3158 case RES_TYPE_NUMBER:
d5db4077 3159 return make_number (atoi (SDATA (tem)));
ee78dc32 3160
6fc2811b 3161 case RES_TYPE_FLOAT:
d5db4077 3162 return make_float (atof (SDATA (tem)));
6fc2811b
JR
3163
3164 case RES_TYPE_BOOLEAN:
ee78dc32 3165 tem = Fdowncase (tem);
d5db4077
KR
3166 if (!strcmp (SDATA (tem), "on")
3167 || !strcmp (SDATA (tem), "true"))
ee78dc32 3168 return Qt;
7d0393cf 3169 else
ee78dc32
GV
3170 return Qnil;
3171
6fc2811b 3172 case RES_TYPE_STRING:
ee78dc32
GV
3173 return tem;
3174
6fc2811b 3175 case RES_TYPE_SYMBOL:
ee78dc32
GV
3176 /* As a special case, we map the values `true' and `on'
3177 to Qt, and `false' and `off' to Qnil. */
3178 {
3179 Lisp_Object lower;
3180 lower = Fdowncase (tem);
d5db4077
KR
3181 if (!strcmp (SDATA (lower), "on")
3182 || !strcmp (SDATA (lower), "true"))
ee78dc32 3183 return Qt;
d5db4077
KR
3184 else if (!strcmp (SDATA (lower), "off")
3185 || !strcmp (SDATA (lower), "false"))
ee78dc32
GV
3186 return Qnil;
3187 else
3188 return Fintern (tem, Qnil);
3189 }
3190
3191 default:
3192 abort ();
3193 }
3194 }
3195 else
3196 return Qunbound;
3197 }
3198 return Fcdr (tem);
3199}
3200
3201/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3202 of the parameter named PROP (a Lisp symbol).
3203 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3204 on the frame named NAME.
3205 If that is not found either, use the value DEFLT. */
3206
3207static Lisp_Object
3208x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3209 struct frame *f;
3210 Lisp_Object alist;
3211 Lisp_Object prop;
3212 Lisp_Object deflt;
3213 char *xprop;
3214 char *xclass;
3215 enum resource_types type;
3216{
3217 Lisp_Object tem;
3218
6fc2811b 3219 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3220 if (EQ (tem, Qunbound))
3221 tem = deflt;
3222 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3223 return tem;
3224}
3225\f
3226DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3227 doc: /* Parse an X-style geometry string STRING.
3228Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3229The properties returned may include `top', `left', `height', and `width'.
3230The value of `left' or `top' may be an integer,
3231or a list (+ N) meaning N pixels relative to top/left corner,
3232or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3233 (string)
3234 Lisp_Object string;
3235{
3236 int geometry, x, y;
3237 unsigned int width, height;
3238 Lisp_Object result;
3239
b7826503 3240 CHECK_STRING (string);
ee78dc32 3241
d5db4077 3242 geometry = XParseGeometry ((char *) SDATA (string),
ee78dc32
GV
3243 &x, &y, &width, &height);
3244
3245 result = Qnil;
3246 if (geometry & XValue)
3247 {
3248 Lisp_Object element;
3249
3250 if (x >= 0 && (geometry & XNegative))
3251 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3252 else if (x < 0 && ! (geometry & XNegative))
3253 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3254 else
3255 element = Fcons (Qleft, make_number (x));
3256 result = Fcons (element, result);
3257 }
3258
3259 if (geometry & YValue)
3260 {
3261 Lisp_Object element;
3262
3263 if (y >= 0 && (geometry & YNegative))
3264 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3265 else if (y < 0 && ! (geometry & YNegative))
3266 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3267 else
3268 element = Fcons (Qtop, make_number (y));
3269 result = Fcons (element, result);
3270 }
3271
3272 if (geometry & WidthValue)
3273 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3274 if (geometry & HeightValue)
3275 result = Fcons (Fcons (Qheight, make_number (height)), result);
3276
3277 return result;
3278}
3279
3280/* Calculate the desired size and position of this window,
3281 and return the flags saying which aspects were specified.
3282
3283 This function does not make the coordinates positive. */
3284
3285#define DEFAULT_ROWS 40
3286#define DEFAULT_COLS 80
3287
3288static int
3289x_figure_window_size (f, parms)
3290 struct frame *f;
3291 Lisp_Object parms;
3292{
3293 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3294 long window_prompting = 0;
3295
3296 /* Default values if we fall through.
3297 Actually, if that happens we should get
3298 window manager prompting. */
1026b400 3299 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3300 f->height = DEFAULT_ROWS;
3301 /* Window managers expect that if program-specified
3302 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3303 f->output_data.w32->top_pos = 0;
3304 f->output_data.w32->left_pos = 0;
ee78dc32 3305
35b41202
JR
3306 /* Ensure that old new_width and new_height will not override the
3307 values set here. */
3308 FRAME_NEW_WIDTH (f) = 0;
3309 FRAME_NEW_HEIGHT (f) = 0;
3310
6fc2811b
JR
3311 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3312 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3313 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3314 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3315 {
3316 if (!EQ (tem0, Qunbound))
3317 {
b7826503 3318 CHECK_NUMBER (tem0);
ee78dc32
GV
3319 f->height = XINT (tem0);
3320 }
3321 if (!EQ (tem1, Qunbound))
3322 {
b7826503 3323 CHECK_NUMBER (tem1);
1026b400 3324 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3325 }
3326 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3327 window_prompting |= USSize;
3328 else
3329 window_prompting |= PSize;
3330 }
3331
fbd6baed 3332 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3333 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3334 ? 0
3335 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3336 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3337 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
f7b9d4d1 3338
41c1bdd9 3339 x_compute_fringe_widths (f, 0);
f7b9d4d1 3340
fbd6baed
GV
3341 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3342 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3343
6fc2811b
JR
3344 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3345 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3346 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3347 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3348 {
3349 if (EQ (tem0, Qminus))
3350 {
fbd6baed 3351 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3352 window_prompting |= YNegative;
3353 }
8e713be6
KR
3354 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3355 && CONSP (XCDR (tem0))
3356 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3357 {
8e713be6 3358 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3359 window_prompting |= YNegative;
3360 }
8e713be6
KR
3361 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3362 && CONSP (XCDR (tem0))
3363 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3364 {
8e713be6 3365 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3366 }
3367 else if (EQ (tem0, Qunbound))
fbd6baed 3368 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3369 else
3370 {
b7826503 3371 CHECK_NUMBER (tem0);
fbd6baed
GV
3372 f->output_data.w32->top_pos = XINT (tem0);
3373 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3374 window_prompting |= YNegative;
3375 }
3376
3377 if (EQ (tem1, Qminus))
3378 {
fbd6baed 3379 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3380 window_prompting |= XNegative;
3381 }
8e713be6
KR
3382 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3383 && CONSP (XCDR (tem1))
3384 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3385 {
8e713be6 3386 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3387 window_prompting |= XNegative;
3388 }
8e713be6
KR
3389 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3390 && CONSP (XCDR (tem1))
3391 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3392 {
8e713be6 3393 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3394 }
3395 else if (EQ (tem1, Qunbound))
fbd6baed 3396 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3397 else
3398 {
b7826503 3399 CHECK_NUMBER (tem1);
fbd6baed
GV
3400 f->output_data.w32->left_pos = XINT (tem1);
3401 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3402 window_prompting |= XNegative;
3403 }
3404
3405 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3406 window_prompting |= USPosition;
3407 else
3408 window_prompting |= PPosition;
3409 }
3410
f7b9d4d1
JR
3411 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3412 {
3413 int left, top;
3414 int width, height;
3415
3416 /* It takes both for some WM:s to place it where we want */
3417 window_prompting = USPosition | PPosition;
3418 x_fullscreen_adjust (f, &width, &height, &top, &left);
3419 f->width = width;
3420 f->height = height;
3421 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3422 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3423 f->output_data.w32->left_pos = left;
3424 f->output_data.w32->top_pos = top;
3425 }
3426
ee78dc32
GV
3427 return window_prompting;
3428}
3429
3430\f
c9b2104d
JR
3431Cursor
3432w32_load_cursor (LPCTSTR name)
3433{
3434 /* Try first to load cursor from application resource. */
3435 Cursor cursor = LoadImage ((HINSTANCE) GetModuleHandle(NULL),
3436 name, IMAGE_CURSOR, 0, 0,
3437 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
3438 if (!cursor)
3439 {
3440 /* Then try to load a shared predefined cursor. */
3441 cursor = LoadImage (NULL, name, IMAGE_CURSOR, 0, 0,
3442 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
3443 }
3444 return cursor;
3445}
ee78dc32 3446
fbd6baed 3447extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32 3448
7d0393cf 3449BOOL
fbd6baed 3450w32_init_class (hinst)
ee78dc32
GV
3451 HINSTANCE hinst;
3452{
3453 WNDCLASS wc;
3454
5ac45f98 3455 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3456 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3457 wc.cbClsExtra = 0;
3458 wc.cbWndExtra = WND_EXTRA_BYTES;
3459 wc.hInstance = hinst;
3460 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
c9b2104d 3461 wc.hCursor = w32_load_cursor (IDC_ARROW);
4587b026 3462 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3463 wc.lpszMenuName = NULL;
3464 wc.lpszClassName = EMACS_CLASS;
3465
3466 return (RegisterClass (&wc));
3467}
3468
7d0393cf 3469HWND
fbd6baed 3470w32_createscrollbar (f, bar)
ee78dc32
GV
3471 struct frame *f;
3472 struct scroll_bar * bar;
3473{
3474 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3475 /* Position and size of scroll bar. */
6fc2811b 3476 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7d0393cf 3477 XINT(bar->top),
6fc2811b
JR
3478 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3479 XINT(bar->height),
fbd6baed 3480 FRAME_W32_WINDOW (f),
ee78dc32
GV
3481 NULL,
3482 hinst,
3483 NULL));
3484}
3485
7d0393cf 3486void
fbd6baed 3487w32_createwindow (f)
ee78dc32
GV
3488 struct frame *f;
3489{
3490 HWND hwnd;
1edf84e7
GV
3491 RECT rect;
3492
3493 rect.left = rect.top = 0;
3494 rect.right = PIXEL_WIDTH (f);
3495 rect.bottom = PIXEL_HEIGHT (f);
7d0393cf 3496
1edf84e7
GV
3497 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3498 FRAME_EXTERNAL_MENU_BAR (f));
7d0393cf 3499
ee78dc32 3500 /* Do first time app init */
7d0393cf 3501
ee78dc32
GV
3502 if (!hprevinst)
3503 {
fbd6baed 3504 w32_init_class (hinst);
ee78dc32 3505 }
7d0393cf 3506
1edf84e7
GV
3507 FRAME_W32_WINDOW (f) = hwnd
3508 = CreateWindow (EMACS_CLASS,
3509 f->namebuf,
9ead1b60 3510 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3511 f->output_data.w32->left_pos,
3512 f->output_data.w32->top_pos,
3513 rect.right - rect.left,
3514 rect.bottom - rect.top,
3515 NULL,
3516 NULL,
3517 hinst,
3518 NULL);
3519
ee78dc32
GV
3520 if (hwnd)
3521 {
1edf84e7
GV
3522 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3523 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3524 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3525 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3526 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3527
cb9e33d4
RS
3528 /* Enable drag-n-drop. */
3529 DragAcceptFiles (hwnd, TRUE);
7d0393cf 3530
5ac45f98
GV
3531 /* Do this to discard the default setting specified by our parent. */
3532 ShowWindow (hwnd, SW_HIDE);
3c190163 3533 }
3c190163
GV
3534}
3535
7d0393cf 3536void
ee78dc32 3537my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3538 W32Msg * wmsg;
ee78dc32
GV
3539 HWND hwnd;
3540 UINT msg;
3541 WPARAM wParam;
3542 LPARAM lParam;
3543{
3544 wmsg->msg.hwnd = hwnd;
3545 wmsg->msg.message = msg;
3546 wmsg->msg.wParam = wParam;
3547 wmsg->msg.lParam = lParam;
3548 wmsg->msg.time = GetMessageTime ();
3549
3550 post_msg (wmsg);
3551}
3552
e9e23e23 3553/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3554 between left and right keys as advertised. We test for this
3555 support dynamically, and set a flag when the support is absent. If
3556 absent, we keep track of the left and right control and alt keys
3557 ourselves. This is particularly necessary on keyboards that rely
3558 upon the AltGr key, which is represented as having the left control
3559 and right alt keys pressed. For these keyboards, we need to know
3560 when the left alt key has been pressed in addition to the AltGr key
3561 so that we can properly support M-AltGr-key sequences (such as M-@
3562 on Swedish keyboards). */
3563
3564#define EMACS_LCONTROL 0
3565#define EMACS_RCONTROL 1
3566#define EMACS_LMENU 2
3567#define EMACS_RMENU 3
3568
3569static int modifiers[4];
3570static int modifiers_recorded;
3571static int modifier_key_support_tested;
3572
3573static void
3574test_modifier_support (unsigned int wparam)
3575{
3576 unsigned int l, r;
3577
3578 if (wparam != VK_CONTROL && wparam != VK_MENU)
3579 return;
3580 if (wparam == VK_CONTROL)
3581 {
3582 l = VK_LCONTROL;
3583 r = VK_RCONTROL;
3584 }
3585 else
3586 {
3587 l = VK_LMENU;
3588 r = VK_RMENU;
3589 }
3590 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3591 modifiers_recorded = 1;
3592 else
3593 modifiers_recorded = 0;
3594 modifier_key_support_tested = 1;
3595}
3596
3597static void
3598record_keydown (unsigned int wparam, unsigned int lparam)
3599{
3600 int i;
3601
3602 if (!modifier_key_support_tested)
3603 test_modifier_support (wparam);
3604
3605 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3606 return;
3607
3608 if (wparam == VK_CONTROL)
3609 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3610 else
3611 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3612
3613 modifiers[i] = 1;
3614}
3615
3616static void
3617record_keyup (unsigned int wparam, unsigned int lparam)
3618{
3619 int i;
3620
3621 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3622 return;
3623
3624 if (wparam == VK_CONTROL)
3625 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3626 else
3627 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3628
3629 modifiers[i] = 0;
3630}
3631
da36a4d6 3632/* Emacs can lose focus while a modifier key has been pressed. When
7d0393cf 3633 it regains focus, be conservative and clear all modifiers since
da36a4d6
GV
3634 we cannot reconstruct the left and right modifier state. */
3635static void
3636reset_modifiers ()
3637{
8681157a
RS
3638 SHORT ctrl, alt;
3639
adcc3809
GV
3640 if (GetFocus () == NULL)
3641 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3642 return;
8681157a
RS
3643
3644 ctrl = GetAsyncKeyState (VK_CONTROL);
3645 alt = GetAsyncKeyState (VK_MENU);
3646
8681157a
RS
3647 if (!(ctrl & 0x08000))
3648 /* Clear any recorded control modifier state. */
3649 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3650
3651 if (!(alt & 0x08000))
3652 /* Clear any recorded alt modifier state. */
3653 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3654
adcc3809
GV
3655 /* Update the state of all modifier keys, because modifiers used in
3656 hot-key combinations can get stuck on if Emacs loses focus as a
3657 result of a hot-key being pressed. */
3658 {
3659 BYTE keystate[256];
3660
3661#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3662
3663 GetKeyboardState (keystate);
3664 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3665 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3666 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3667 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3668 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3669 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3670 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3671 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3672 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3673 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3674 SetKeyboardState (keystate);
3675 }
da36a4d6
GV
3676}
3677
7830e24b
RS
3678/* Synchronize modifier state with what is reported with the current
3679 keystroke. Even if we cannot distinguish between left and right
3680 modifier keys, we know that, if no modifiers are set, then neither
3681 the left or right modifier should be set. */
3682static void
3683sync_modifiers ()
3684{
3685 if (!modifiers_recorded)
3686 return;
3687
7d0393cf 3688 if (!(GetKeyState (VK_CONTROL) & 0x8000))
7830e24b
RS
3689 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3690
7d0393cf 3691 if (!(GetKeyState (VK_MENU) & 0x8000))
7830e24b
RS
3692 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3693}
3694
a1a80b40
GV
3695static int
3696modifier_set (int vkey)
3697{
ccc2d29c 3698 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3699 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3700 if (!modifiers_recorded)
3701 return (GetKeyState (vkey) & 0x8000);
3702
3703 switch (vkey)
3704 {
3705 case VK_LCONTROL:
3706 return modifiers[EMACS_LCONTROL];
3707 case VK_RCONTROL:
3708 return modifiers[EMACS_RCONTROL];
3709 case VK_LMENU:
3710 return modifiers[EMACS_LMENU];
3711 case VK_RMENU:
3712 return modifiers[EMACS_RMENU];
a1a80b40
GV
3713 }
3714 return (GetKeyState (vkey) & 0x8000);
3715}
3716
ccc2d29c
GV
3717/* Convert between the modifier bits W32 uses and the modifier bits
3718 Emacs uses. */
3719
3720unsigned int
3721w32_key_to_modifier (int key)
3722{
3723 Lisp_Object key_mapping;
3724
3725 switch (key)
3726 {
3727 case VK_LWIN:
3728 key_mapping = Vw32_lwindow_modifier;
3729 break;
3730 case VK_RWIN:
3731 key_mapping = Vw32_rwindow_modifier;
3732 break;
3733 case VK_APPS:
3734 key_mapping = Vw32_apps_modifier;
3735 break;
3736 case VK_SCROLL:
3737 key_mapping = Vw32_scroll_lock_modifier;
3738 break;
3739 default:
3740 key_mapping = Qnil;
3741 }
3742
adcc3809
GV
3743 /* NB. This code runs in the input thread, asychronously to the lisp
3744 thread, so we must be careful to ensure access to lisp data is
3745 thread-safe. The following code is safe because the modifier
3746 variable values are updated atomically from lisp and symbols are
3747 not relocated by GC. Also, we don't have to worry about seeing GC
3748 markbits here. */
3749 if (EQ (key_mapping, Qhyper))
ccc2d29c 3750 return hyper_modifier;
adcc3809 3751 if (EQ (key_mapping, Qsuper))
ccc2d29c 3752 return super_modifier;
adcc3809 3753 if (EQ (key_mapping, Qmeta))
ccc2d29c 3754 return meta_modifier;
adcc3809 3755 if (EQ (key_mapping, Qalt))
ccc2d29c 3756 return alt_modifier;
adcc3809 3757 if (EQ (key_mapping, Qctrl))
ccc2d29c 3758 return ctrl_modifier;
adcc3809 3759 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3760 return ctrl_modifier;
adcc3809 3761 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3762 return shift_modifier;
3763
3764 /* Don't generate any modifier if not explicitly requested. */
3765 return 0;
3766}
3767
3768unsigned int
3769w32_get_modifiers ()
3770{
3771 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3772 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3773 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3774 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3775 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3776 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3777 (modifier_set (VK_MENU) ?
3778 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3779}
3780
a1a80b40
GV
3781/* We map the VK_* modifiers into console modifier constants
3782 so that we can use the same routines to handle both console
3783 and window input. */
3784
3785static int
ccc2d29c 3786construct_console_modifiers ()
a1a80b40
GV
3787{
3788 int mods;
3789
a1a80b40
GV
3790 mods = 0;
3791 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3792 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3793 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3794 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3795 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3796 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3797 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3798 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3799 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3800 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3801 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3802
3803 return mods;
3804}
3805
ccc2d29c
GV
3806static int
3807w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3808{
ccc2d29c
GV
3809 int mods;
3810
3811 /* Convert to emacs modifiers. */
3812 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3813
3814 return mods;
3815}
da36a4d6 3816
ccc2d29c
GV
3817unsigned int
3818map_keypad_keys (unsigned int virt_key, unsigned int extended)
3819{
3820 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3821 return virt_key;
da36a4d6 3822
ccc2d29c 3823 if (virt_key == VK_RETURN)
da36a4d6
GV
3824 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3825
ccc2d29c
GV
3826 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3827 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3828
3829 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3830 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3831
3832 if (virt_key == VK_CLEAR)
3833 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3834
3835 return virt_key;
3836}
3837
3838/* List of special key combinations which w32 would normally capture,
3839 but emacs should grab instead. Not directly visible to lisp, to
3840 simplify synchronization. Each item is an integer encoding a virtual
3841 key code and modifier combination to capture. */
3842Lisp_Object w32_grabbed_keys;
3843
3844#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3845#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3846#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3847#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3848
3849/* Register hot-keys for reserved key combinations when Emacs has
3850 keyboard focus, since this is the only way Emacs can receive key
3851 combinations like Alt-Tab which are used by the system. */
3852
3853static void
3854register_hot_keys (hwnd)
3855 HWND hwnd;
3856{
3857 Lisp_Object keylist;
3858
3859 /* Use GC_CONSP, since we are called asynchronously. */
3860 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3861 {
3862 Lisp_Object key = XCAR (keylist);
3863
3864 /* Deleted entries get set to nil. */
3865 if (!INTEGERP (key))
3866 continue;
3867
3868 RegisterHotKey (hwnd, HOTKEY_ID (key),
3869 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3870 }
3871}
3872
3873static void
3874unregister_hot_keys (hwnd)
3875 HWND hwnd;
3876{
3877 Lisp_Object keylist;
3878
3879 /* Use GC_CONSP, since we are called asynchronously. */
3880 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3881 {
3882 Lisp_Object key = XCAR (keylist);
3883
3884 if (!INTEGERP (key))
3885 continue;
3886
3887 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3888 }
3889}
3890
5ac45f98
GV
3891/* Main message dispatch loop. */
3892
1edf84e7
GV
3893static void
3894w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3895{
3896 MSG msg;
ccc2d29c
GV
3897 int result;
3898 HWND focus_window;
93fbe8b7
GV
3899
3900 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
7d0393cf 3901
5ac45f98
GV
3902 while (GetMessage (&msg, NULL, 0, 0))
3903 {
3904 if (msg.hwnd == NULL)
3905 {
3906 switch (msg.message)
3907 {
3ef68e6b
AI
3908 case WM_NULL:
3909 /* Produced by complete_deferred_msg; just ignore. */
3910 break;
5ac45f98 3911 case WM_EMACS_CREATEWINDOW:
fbd6baed 3912 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3913 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3914 abort ();
5ac45f98 3915 break;
dfdb4047
GV
3916 case WM_EMACS_SETLOCALE:
3917 SetThreadLocale (msg.wParam);
3918 /* Reply is not expected. */
3919 break;
ccc2d29c
GV
3920 case WM_EMACS_SETKEYBOARDLAYOUT:
3921 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3922 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3923 result, 0))
3924 abort ();
3925 break;
3926 case WM_EMACS_REGISTER_HOT_KEY:
3927 focus_window = GetFocus ();
3928 if (focus_window != NULL)
3929 RegisterHotKey (focus_window,
3930 HOTKEY_ID (msg.wParam),
3931 HOTKEY_MODIFIERS (msg.wParam),
3932 HOTKEY_VK_CODE (msg.wParam));
3933 /* Reply is not expected. */
3934 break;
3935 case WM_EMACS_UNREGISTER_HOT_KEY:
3936 focus_window = GetFocus ();
3937 if (focus_window != NULL)
3938 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3939 /* Mark item as erased. NB: this code must be
3940 thread-safe. The next line is okay because the cons
3941 cell is never made into garbage and is not relocated by
3942 GC. */
f3fbd155 3943 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3944 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3945 abort ();
3946 break;
adcc3809
GV
3947 case WM_EMACS_TOGGLE_LOCK_KEY:
3948 {
3949 int vk_code = (int) msg.wParam;
3950 int cur_state = (GetKeyState (vk_code) & 1);
3951 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3952
3953 /* NB: This code must be thread-safe. It is safe to
3954 call NILP because symbols are not relocated by GC,
3955 and pointer here is not touched by GC (so the markbit
3956 can't be set). Numbers are safe because they are
3957 immediate values. */
3958 if (NILP (new_state)
3959 || (NUMBERP (new_state)
8edb0a6f 3960 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3961 {
3962 one_w32_display_info.faked_key = vk_code;
3963
3964 keybd_event ((BYTE) vk_code,
3965 (BYTE) MapVirtualKey (vk_code, 0),
3966 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3967 keybd_event ((BYTE) vk_code,
3968 (BYTE) MapVirtualKey (vk_code, 0),
3969 KEYEVENTF_EXTENDEDKEY | 0, 0);
3970 keybd_event ((BYTE) vk_code,
3971 (BYTE) MapVirtualKey (vk_code, 0),
3972 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3973 cur_state = !cur_state;
3974 }
3975 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3976 cur_state, 0))
3977 abort ();
3978 }
3979 break;
1edf84e7 3980 default:
1edf84e7 3981 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3982 }
3983 }
3984 else
3985 {
3986 DispatchMessage (&msg);
3987 }
1edf84e7
GV
3988
3989 /* Exit nested loop when our deferred message has completed. */
3990 if (msg_buf->completed)
3991 break;
5ac45f98 3992 }
1edf84e7
GV
3993}
3994
3995deferred_msg * deferred_msg_head;
3996
3997static deferred_msg *
3998find_deferred_msg (HWND hwnd, UINT msg)
3999{
4000 deferred_msg * item;
4001
4002 /* Don't actually need synchronization for read access, since
4003 modification of single pointer is always atomic. */
4004 /* enter_crit (); */
4005
4006 for (item = deferred_msg_head; item != NULL; item = item->next)
4007 if (item->w32msg.msg.hwnd == hwnd
4008 && item->w32msg.msg.message == msg)
4009 break;
4010
4011 /* leave_crit (); */
4012
4013 return item;
4014}
4015
4016static LRESULT
4017send_deferred_msg (deferred_msg * msg_buf,
4018 HWND hwnd,
4019 UINT msg,
4020 WPARAM wParam,
4021 LPARAM lParam)
4022{
4023 /* Only input thread can send deferred messages. */
4024 if (GetCurrentThreadId () != dwWindowsThreadId)
4025 abort ();
4026
4027 /* It is an error to send a message that is already deferred. */
4028 if (find_deferred_msg (hwnd, msg) != NULL)
4029 abort ();
4030
4031 /* Enforced synchronization is not needed because this is the only
4032 function that alters deferred_msg_head, and the following critical
4033 section is guaranteed to only be serially reentered (since only the
4034 input thread can call us). */
4035
4036 /* enter_crit (); */
4037
4038 msg_buf->completed = 0;
4039 msg_buf->next = deferred_msg_head;
4040 deferred_msg_head = msg_buf;
4041 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4042
4043 /* leave_crit (); */
4044
4045 /* Start a new nested message loop to process other messages until
4046 this one is completed. */
4047 w32_msg_pump (msg_buf);
4048
4049 deferred_msg_head = msg_buf->next;
4050
4051 return msg_buf->result;
4052}
4053
4054void
4055complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4056{
4057 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4058
4059 if (msg_buf == NULL)
3ef68e6b
AI
4060 /* Message may have been cancelled, so don't abort(). */
4061 return;
1edf84e7
GV
4062
4063 msg_buf->result = result;
4064 msg_buf->completed = 1;
4065
4066 /* Ensure input thread is woken so it notices the completion. */
4067 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4068}
4069
3ef68e6b
AI
4070void
4071cancel_all_deferred_msgs ()
4072{
4073 deferred_msg * item;
4074
4075 /* Don't actually need synchronization for read access, since
4076 modification of single pointer is always atomic. */
4077 /* enter_crit (); */
4078
4079 for (item = deferred_msg_head; item != NULL; item = item->next)
4080 {
4081 item->result = 0;
4082 item->completed = 1;
4083 }
4084
4085 /* leave_crit (); */
4086
4087 /* Ensure input thread is woken so it notices the completion. */
4088 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4089}
1edf84e7 4090
7d0393cf 4091DWORD
1edf84e7
GV
4092w32_msg_worker (dw)
4093 DWORD dw;
4094{
4095 MSG msg;
4096 deferred_msg dummy_buf;
4097
4098 /* Ensure our message queue is created */
7d0393cf 4099
1edf84e7 4100 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
7d0393cf 4101
1edf84e7
GV
4102 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4103 abort ();
4104
4105 memset (&dummy_buf, 0, sizeof (dummy_buf));
4106 dummy_buf.w32msg.msg.hwnd = NULL;
4107 dummy_buf.w32msg.msg.message = WM_NULL;
4108
4109 /* This is the inital message loop which should only exit when the
4110 application quits. */
4111 w32_msg_pump (&dummy_buf);
4112
4113 return 0;
5ac45f98
GV
4114}
4115
3ef68e6b
AI
4116static void
4117post_character_message (hwnd, msg, wParam, lParam, modifiers)
4118 HWND hwnd;
4119 UINT msg;
4120 WPARAM wParam;
4121 LPARAM lParam;
4122 DWORD modifiers;
4123
4124{
4125 W32Msg wmsg;
4126
4127 wmsg.dwModifiers = modifiers;
4128
4129 /* Detect quit_char and set quit-flag directly. Note that we
4130 still need to post a message to ensure the main thread will be
4131 woken up if blocked in sys_select(), but we do NOT want to post
4132 the quit_char message itself (because it will usually be as if
4133 the user had typed quit_char twice). Instead, we post a dummy
4134 message that has no particular effect. */
4135 {
4136 int c = wParam;
4137 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4138 c = make_ctrl_char (c) & 0377;
7d081355
AI
4139 if (c == quit_char
4140 || (wmsg.dwModifiers == 0 &&
4141 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4142 {
4143 Vquit_flag = Qt;
4144
4145 /* The choice of message is somewhat arbitrary, as long as
4146 the main thread handler just ignores it. */
4147 msg = WM_NULL;
4148
4149 /* Interrupt any blocking system calls. */
4150 signal_quit ();
4151
4152 /* As a safety precaution, forcibly complete any deferred
4153 messages. This is a kludge, but I don't see any particularly
4154 clean way to handle the situation where a deferred message is
4155 "dropped" in the lisp thread, and will thus never be
4156 completed, eg. by the user trying to activate the menubar
4157 when the lisp thread is busy, and then typing C-g when the
4158 menubar doesn't open promptly (with the result that the
4159 menubar never responds at all because the deferred
4160 WM_INITMENU message is never completed). Another problem
4161 situation is when the lisp thread calls SendMessage (to send
4162 a window manager command) when a message has been deferred;
4163 the lisp thread gets blocked indefinitely waiting for the
4164 deferred message to be completed, which itself is waiting for
4165 the lisp thread to respond.
4166
4167 Note that we don't want to block the input thread waiting for
4168 a reponse from the lisp thread (although that would at least
4169 solve the deadlock problem above), because we want to be able
4170 to receive C-g to interrupt the lisp thread. */
4171 cancel_all_deferred_msgs ();
4172 }
4173 }
4174
4175 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4176}
4177
ee78dc32
GV
4178/* Main window procedure */
4179
7d0393cf 4180LRESULT CALLBACK
fbd6baed 4181w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4182 HWND hwnd;
4183 UINT msg;
4184 WPARAM wParam;
4185 LPARAM lParam;
4186{
4187 struct frame *f;
fbd6baed
GV
4188 struct w32_display_info *dpyinfo = &one_w32_display_info;
4189 W32Msg wmsg;
84fb1139 4190 int windows_translate;
576ba81c 4191 int key;
84fb1139 4192
a6085637
KH
4193 /* Note that it is okay to call x_window_to_frame, even though we are
4194 not running in the main lisp thread, because frame deletion
4195 requires the lisp thread to synchronize with this thread. Thus, if
4196 a frame struct is returned, it can be used without concern that the
4197 lisp thread might make it disappear while we are using it.
4198
4199 NB. Walking the frame list in this thread is safe (as long as
4200 writes of Lisp_Object slots are atomic, which they are on Windows).
4201 Although delete-frame can destructively modify the frame list while
4202 we are walking it, a garbage collection cannot occur until after
4203 delete-frame has synchronized with this thread.
4204
4205 It is also safe to use functions that make GDI calls, such as
fbd6baed 4206 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4207 from the frame struct using get_frame_dc which is thread-aware. */
4208
7d0393cf 4209 switch (msg)
ee78dc32
GV
4210 {
4211 case WM_ERASEBKGND:
a6085637
KH
4212 f = x_window_to_frame (dpyinfo, hwnd);
4213 if (f)
4214 {
9badad41 4215 HDC hdc = get_frame_dc (f);
a6085637 4216 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4217 w32_clear_rect (f, hdc, &wmsg.rect);
4218 release_frame_dc (f, hdc);
ce6059da
AI
4219
4220#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4221 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4222 f,
4223 wmsg.rect.left, wmsg.rect.top,
4224 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4225#endif /* W32_DEBUG_DISPLAY */
a6085637 4226 }
5ac45f98
GV
4227 return 1;
4228 case WM_PALETTECHANGED:
4229 /* ignore our own changes */
4230 if ((HWND)wParam != hwnd)
4231 {
a6085637
KH
4232 f = x_window_to_frame (dpyinfo, hwnd);
4233 if (f)
4234 /* get_frame_dc will realize our palette and force all
4235 frames to be redrawn if needed. */
4236 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4237 }
4238 return 0;
ee78dc32 4239 case WM_PAINT:
ce6059da 4240 {
55dcfc15
AI
4241 PAINTSTRUCT paintStruct;
4242 RECT update_rect;
aa35b6ad 4243 bzero (&update_rect, sizeof (update_rect));
55dcfc15 4244
18f0b342
AI
4245 f = x_window_to_frame (dpyinfo, hwnd);
4246 if (f == 0)
4247 {
4248 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4249 return 0;
4250 }
4251
55dcfc15
AI
4252 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4253 fails. Apparently this can happen under some
4254 circumstances. */
aa35b6ad 4255 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
55dcfc15
AI
4256 {
4257 enter_crit ();
4258 BeginPaint (hwnd, &paintStruct);
4259
aa35b6ad
JR
4260 /* The rectangles returned by GetUpdateRect and BeginPaint
4261 do not always match. Play it safe by assuming both areas
4262 are invalid. */
4263 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
55dcfc15
AI
4264
4265#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4266 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4267 f,
4268 wmsg.rect.left, wmsg.rect.top,
4269 wmsg.rect.right, wmsg.rect.bottom));
4270 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4271 update_rect.left, update_rect.top,
4272 update_rect.right, update_rect.bottom));
4273#endif
4274 EndPaint (hwnd, &paintStruct);
4275 leave_crit ();
4276
4277 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
7d0393cf 4278
55dcfc15
AI
4279 return 0;
4280 }
c0611964
AI
4281
4282 /* If GetUpdateRect returns 0 (meaning there is no update
4283 region), assume the whole window needs to be repainted. */
4284 GetClientRect(hwnd, &wmsg.rect);
4285 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4286 return 0;
ee78dc32 4287 }
a1a80b40 4288
ccc2d29c
GV
4289 case WM_INPUTLANGCHANGE:
4290 /* Inform lisp thread of keyboard layout changes. */
4291 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4292
4293 /* Clear dead keys in the keyboard state; for simplicity only
4294 preserve modifier key states. */
4295 {
4296 int i;
4297 BYTE keystate[256];
4298
4299 GetKeyboardState (keystate);
4300 for (i = 0; i < 256; i++)
4301 if (1
4302 && i != VK_SHIFT
4303 && i != VK_LSHIFT
4304 && i != VK_RSHIFT
4305 && i != VK_CAPITAL
4306 && i != VK_NUMLOCK
4307 && i != VK_SCROLL
4308 && i != VK_CONTROL
4309 && i != VK_LCONTROL
4310 && i != VK_RCONTROL
4311 && i != VK_MENU
4312 && i != VK_LMENU
4313 && i != VK_RMENU
4314 && i != VK_LWIN
4315 && i != VK_RWIN)
4316 keystate[i] = 0;
4317 SetKeyboardState (keystate);
4318 }
4319 goto dflt;
4320
4321 case WM_HOTKEY:
4322 /* Synchronize hot keys with normal input. */
4323 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4324 return (0);
4325
a1a80b40
GV
4326 case WM_KEYUP:
4327 case WM_SYSKEYUP:
4328 record_keyup (wParam, lParam);
4329 goto dflt;
4330
ee78dc32
GV
4331 case WM_KEYDOWN:
4332 case WM_SYSKEYDOWN:
ccc2d29c
GV
4333 /* Ignore keystrokes we fake ourself; see below. */
4334 if (dpyinfo->faked_key == wParam)
4335 {
4336 dpyinfo->faked_key = 0;
576ba81c
AI
4337 /* Make sure TranslateMessage sees them though (as long as
4338 they don't produce WM_CHAR messages). This ensures that
4339 indicator lights are toggled promptly on Windows 9x, for
4340 example. */
4341 if (lispy_function_keys[wParam] != 0)
4342 {
4343 windows_translate = 1;
4344 goto translate;
4345 }
4346 return 0;
ccc2d29c
GV
4347 }
4348
7830e24b
RS
4349 /* Synchronize modifiers with current keystroke. */
4350 sync_modifiers ();
a1a80b40 4351 record_keydown (wParam, lParam);
ccc2d29c 4352 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4353
4354 windows_translate = 0;
ccc2d29c
GV
4355
4356 switch (wParam)
4357 {
4358 case VK_LWIN:
4359 if (NILP (Vw32_pass_lwindow_to_system))
4360 {
4361 /* Prevent system from acting on keyup (which opens the
4362 Start menu if no other key was pressed) by simulating a
4363 press of Space which we will ignore. */
4364 if (GetAsyncKeyState (wParam) & 1)
4365 {
adcc3809 4366 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4367 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4368 else
576ba81c
AI
4369 key = VK_SPACE;
4370 dpyinfo->faked_key = key;
4371 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4372 }
4373 }
4374 if (!NILP (Vw32_lwindow_modifier))
4375 return 0;
4376 break;
4377 case VK_RWIN:
4378 if (NILP (Vw32_pass_rwindow_to_system))
4379 {
4380 if (GetAsyncKeyState (wParam) & 1)
4381 {
adcc3809 4382 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4383 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4384 else
576ba81c
AI
4385 key = VK_SPACE;
4386 dpyinfo->faked_key = key;
4387 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4388 }
4389 }
4390 if (!NILP (Vw32_rwindow_modifier))
4391 return 0;
4392 break;
576ba81c 4393 case VK_APPS:
ccc2d29c
GV
4394 if (!NILP (Vw32_apps_modifier))
4395 return 0;
4396 break;
4397 case VK_MENU:
7d0393cf 4398 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4399 /* Prevent DefWindowProc from activating the menu bar if an
4400 Alt key is pressed and released by itself. */
ccc2d29c 4401 return 0;
84fb1139 4402 windows_translate = 1;
ccc2d29c 4403 break;
7d0393cf 4404 case VK_CAPITAL:
ccc2d29c
GV
4405 /* Decide whether to treat as modifier or function key. */
4406 if (NILP (Vw32_enable_caps_lock))
4407 goto disable_lock_key;
adcc3809
GV
4408 windows_translate = 1;
4409 break;
ccc2d29c
GV
4410 case VK_NUMLOCK:
4411 /* Decide whether to treat as modifier or function key. */
4412 if (NILP (Vw32_enable_num_lock))
4413 goto disable_lock_key;
adcc3809
GV
4414 windows_translate = 1;
4415 break;
ccc2d29c
GV
4416 case VK_SCROLL:
4417 /* Decide whether to treat as modifier or function key. */
4418 if (NILP (Vw32_scroll_lock_modifier))
4419 goto disable_lock_key;
adcc3809
GV
4420 windows_translate = 1;
4421 break;
ccc2d29c 4422 disable_lock_key:
adcc3809
GV
4423 /* Ensure the appropriate lock key state (and indicator light)
4424 remains in the same state. We do this by faking another
4425 press of the relevant key. Apparently, this really is the
4426 only way to toggle the state of the indicator lights. */
4427 dpyinfo->faked_key = wParam;
4428 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4429 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4430 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4431 KEYEVENTF_EXTENDEDKEY | 0, 0);
4432 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4433 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4434 /* Ensure indicator lights are updated promptly on Windows 9x
4435 (TranslateMessage apparently does this), after forwarding
4436 input event. */
4437 post_character_message (hwnd, msg, wParam, lParam,
4438 w32_get_key_modifiers (wParam, lParam));
4439 windows_translate = 1;
ccc2d29c 4440 break;
7d0393cf 4441 case VK_CONTROL:
ccc2d29c
GV
4442 case VK_SHIFT:
4443 case VK_PROCESSKEY: /* Generated by IME. */
4444 windows_translate = 1;
4445 break;
adcc3809
GV
4446 case VK_CANCEL:
4447 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4448 which is confusing for purposes of key binding; convert
4449 VK_CANCEL events into VK_PAUSE events. */
4450 wParam = VK_PAUSE;
4451 break;
4452 case VK_PAUSE:
4453 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4454 for purposes of key binding; convert these back into
4455 VK_NUMLOCK events, at least when we want to see NumLock key
4456 presses. (Note that there is never any possibility that
4457 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4458 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4459 wParam = VK_NUMLOCK;
4460 break;
ccc2d29c
GV
4461 default:
4462 /* If not defined as a function key, change it to a WM_CHAR message. */
4463 if (lispy_function_keys[wParam] == 0)
4464 {
adcc3809
GV
4465 DWORD modifiers = construct_console_modifiers ();
4466
ccc2d29c
GV
4467 if (!NILP (Vw32_recognize_altgr)
4468 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4469 {
4470 /* Always let TranslateMessage handle AltGr key chords;
4471 for some reason, ToAscii doesn't always process AltGr
4472 chords correctly. */
4473 windows_translate = 1;
4474 }
adcc3809 4475 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4476 {
adcc3809
GV
4477 /* Handle key chords including any modifiers other
4478 than shift directly, in order to preserve as much
4479 modifier information as possible. */
ccc2d29c
GV
4480 if ('A' <= wParam && wParam <= 'Z')
4481 {
4482 /* Don't translate modified alphabetic keystrokes,
4483 so the user doesn't need to constantly switch
4484 layout to type control or meta keystrokes when
4485 the normal layout translates alphabetic
4486 characters to non-ascii characters. */
4487 if (!modifier_set (VK_SHIFT))
4488 wParam += ('a' - 'A');
4489 msg = WM_CHAR;
4490 }
4491 else
4492 {
4493 /* Try to handle other keystrokes by determining the
4494 base character (ie. translating the base key plus
4495 shift modifier). */
4496 int add;
4497 int isdead = 0;
4498 KEY_EVENT_RECORD key;
7d0393cf 4499
ccc2d29c
GV
4500 key.bKeyDown = TRUE;
4501 key.wRepeatCount = 1;
4502 key.wVirtualKeyCode = wParam;
4503 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4504 key.uChar.AsciiChar = 0;
adcc3809 4505 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4506
4507 add = w32_kbd_patch_key (&key);
4508 /* 0 means an unrecognised keycode, negative means
4509 dead key. Ignore both. */
4510 while (--add >= 0)
4511 {
4512 /* Forward asciified character sequence. */
4513 post_character_message
4514 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4515 w32_get_key_modifiers (wParam, lParam));
4516 w32_kbd_patch_key (&key);
4517 }
4518 return 0;
4519 }
4520 }
4521 else
4522 {
4523 /* Let TranslateMessage handle everything else. */
4524 windows_translate = 1;
4525 }
4526 }
4527 }
a1a80b40 4528
adcc3809 4529 translate:
84fb1139
KH
4530 if (windows_translate)
4531 {
e9e23e23 4532 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4533
e9e23e23
GV
4534 windows_msg.time = GetMessageTime ();
4535 TranslateMessage (&windows_msg);
84fb1139
KH
4536 goto dflt;
4537 }
4538
ee78dc32 4539 /* Fall through */
7d0393cf 4540
ee78dc32
GV
4541 case WM_SYSCHAR:
4542 case WM_CHAR:
ccc2d29c
GV
4543 post_character_message (hwnd, msg, wParam, lParam,
4544 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4545 break;
da36a4d6 4546
5ac45f98
GV
4547 /* Simulate middle mouse button events when left and right buttons
4548 are used together, but only if user has two button mouse. */
ee78dc32 4549 case WM_LBUTTONDOWN:
5ac45f98 4550 case WM_RBUTTONDOWN:
7ce9aaca 4551 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4552 goto handle_plain_button;
4553
4554 {
4555 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4556 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4557
3cb20f4a
RS
4558 if (button_state & this)
4559 return 0;
5ac45f98
GV
4560
4561 if (button_state == 0)
4562 SetCapture (hwnd);
4563
4564 button_state |= this;
4565
4566 if (button_state & other)
4567 {
84fb1139 4568 if (mouse_button_timer)
5ac45f98 4569 {
84fb1139
KH
4570 KillTimer (hwnd, mouse_button_timer);
4571 mouse_button_timer = 0;
5ac45f98
GV
4572
4573 /* Generate middle mouse event instead. */
4574 msg = WM_MBUTTONDOWN;
4575 button_state |= MMOUSE;
4576 }
4577 else if (button_state & MMOUSE)
4578 {
4579 /* Ignore button event if we've already generated a
4580 middle mouse down event. This happens if the
4581 user releases and press one of the two buttons
4582 after we've faked a middle mouse event. */
4583 return 0;
4584 }
4585 else
4586 {
4587 /* Flush out saved message. */
84fb1139 4588 post_msg (&saved_mouse_button_msg);
5ac45f98 4589 }
fbd6baed 4590 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4591 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4592
4593 /* Clear message buffer. */
84fb1139 4594 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4595 }
4596 else
4597 {
4598 /* Hold onto message for now. */
84fb1139 4599 mouse_button_timer =
adcc3809
GV
4600 SetTimer (hwnd, MOUSE_BUTTON_ID,
4601 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4602 saved_mouse_button_msg.msg.hwnd = hwnd;
4603 saved_mouse_button_msg.msg.message = msg;
4604 saved_mouse_button_msg.msg.wParam = wParam;
4605 saved_mouse_button_msg.msg.lParam = lParam;
4606 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4607 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4608 }
4609 }
4610 return 0;
4611
ee78dc32 4612 case WM_LBUTTONUP:
5ac45f98 4613 case WM_RBUTTONUP:
7ce9aaca 4614 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4615 goto handle_plain_button;
4616
4617 {
4618 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4619 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4620
3cb20f4a
RS
4621 if ((button_state & this) == 0)
4622 return 0;
5ac45f98
GV
4623
4624 button_state &= ~this;
4625
4626 if (button_state & MMOUSE)
4627 {
4628 /* Only generate event when second button is released. */
4629 if ((button_state & other) == 0)
4630 {
4631 msg = WM_MBUTTONUP;
4632 button_state &= ~MMOUSE;
4633
4634 if (button_state) abort ();
4635 }
4636 else
4637 return 0;
4638 }
4639 else
4640 {
4641 /* Flush out saved message if necessary. */
84fb1139 4642 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4643 {
84fb1139 4644 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4645 }
4646 }
fbd6baed 4647 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4648 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4649
4650 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4651 saved_mouse_button_msg.msg.hwnd = 0;
4652 KillTimer (hwnd, mouse_button_timer);
4653 mouse_button_timer = 0;
5ac45f98
GV
4654
4655 if (button_state == 0)
4656 ReleaseCapture ();
4657 }
4658 return 0;
4659
74214547
JR
4660 case WM_XBUTTONDOWN:
4661 case WM_XBUTTONUP:
4662 if (w32_pass_extra_mouse_buttons_to_system)
4663 goto dflt;
4664 /* else fall through and process them. */
ee78dc32
GV
4665 case WM_MBUTTONDOWN:
4666 case WM_MBUTTONUP:
5ac45f98 4667 handle_plain_button:
ee78dc32
GV
4668 {
4669 BOOL up;
1edf84e7 4670 int button;
ee78dc32 4671
74214547 4672 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
4673 {
4674 if (up) ReleaseCapture ();
4675 else SetCapture (hwnd);
7d0393cf 4676 button = (button == 0) ? LMOUSE :
1edf84e7
GV
4677 ((button == 1) ? MMOUSE : RMOUSE);
4678 if (up)
4679 button_state &= ~button;
4680 else
4681 button_state |= button;
ee78dc32
GV
4682 }
4683 }
7d0393cf 4684
fbd6baed 4685 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4686 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
4687
4688 /* Need to return true for XBUTTON messages, false for others,
4689 to indicate that we processed the message. */
4690 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 4691
5ac45f98 4692 case WM_MOUSEMOVE:
9eb16b62
JR
4693 /* If the mouse has just moved into the frame, start tracking
4694 it, so we will be notified when it leaves the frame. Mouse
4695 tracking only works under W98 and NT4 and later. On earlier
4696 versions, there is no way of telling when the mouse leaves the
4697 frame, so we just have to put up with help-echo and mouse
4698 highlighting remaining while the frame is not active. */
4699 if (track_mouse_event_fn && !track_mouse_window)
4700 {
4701 TRACKMOUSEEVENT tme;
4702 tme.cbSize = sizeof (tme);
4703 tme.dwFlags = TME_LEAVE;
4704 tme.hwndTrack = hwnd;
4705
4706 track_mouse_event_fn (&tme);
4707 track_mouse_window = hwnd;
4708 }
4709 case WM_VSCROLL:
fbd6baed 4710 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4711 || (msg == WM_MOUSEMOVE && button_state == 0))
4712 {
fbd6baed 4713 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4714 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4715 return 0;
4716 }
7d0393cf 4717
84fb1139
KH
4718 /* Hang onto mouse move and scroll messages for a bit, to avoid
4719 sending such events to Emacs faster than it can process them.
4720 If we get more events before the timer from the first message
4721 expires, we just replace the first message. */
4722
4723 if (saved_mouse_move_msg.msg.hwnd == 0)
4724 mouse_move_timer =
adcc3809
GV
4725 SetTimer (hwnd, MOUSE_MOVE_ID,
4726 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4727
4728 /* Hold onto message for now. */
4729 saved_mouse_move_msg.msg.hwnd = hwnd;
4730 saved_mouse_move_msg.msg.message = msg;
4731 saved_mouse_move_msg.msg.wParam = wParam;
4732 saved_mouse_move_msg.msg.lParam = lParam;
4733 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4734 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
7d0393cf 4735
84fb1139
KH
4736 return 0;
4737
1edf84e7
GV
4738 case WM_MOUSEWHEEL:
4739 wmsg.dwModifiers = w32_get_modifiers ();
4740 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4741 return 0;
4742
cb9e33d4
RS
4743 case WM_DROPFILES:
4744 wmsg.dwModifiers = w32_get_modifiers ();
4745 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4746 return 0;
4747
84fb1139
KH
4748 case WM_TIMER:
4749 /* Flush out saved messages if necessary. */
4750 if (wParam == mouse_button_timer)
5ac45f98 4751 {
84fb1139
KH
4752 if (saved_mouse_button_msg.msg.hwnd)
4753 {
4754 post_msg (&saved_mouse_button_msg);
4755 saved_mouse_button_msg.msg.hwnd = 0;
4756 }
4757 KillTimer (hwnd, mouse_button_timer);
4758 mouse_button_timer = 0;
4759 }
4760 else if (wParam == mouse_move_timer)
4761 {
4762 if (saved_mouse_move_msg.msg.hwnd)
4763 {
4764 post_msg (&saved_mouse_move_msg);
4765 saved_mouse_move_msg.msg.hwnd = 0;
4766 }
4767 KillTimer (hwnd, mouse_move_timer);
4768 mouse_move_timer = 0;
5ac45f98 4769 }
48094ace
JR
4770 else if (wParam == menu_free_timer)
4771 {
4772 KillTimer (hwnd, menu_free_timer);
4773 menu_free_timer = 0;
27605fa7 4774 f = x_window_to_frame (dpyinfo, hwnd);
48094ace
JR
4775 if (!f->output_data.w32->menu_command_in_progress)
4776 {
4777 /* Free memory used by owner-drawn and help-echo strings. */
4778 w32_free_menu_strings (hwnd);
4779 f->output_data.w32->menubar_active = 0;
4780 }
4781 }
5ac45f98 4782 return 0;
7d0393cf 4783
84fb1139
KH
4784 case WM_NCACTIVATE:
4785 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4786 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4787 The only indication we get that something happened is receiving
4788 this message afterwards. So this is a good time to reset our
4789 keyboard modifiers' state. */
4790 reset_modifiers ();
4791 goto dflt;
da36a4d6 4792
1edf84e7 4793 case WM_INITMENU:
487163ac
AI
4794 button_state = 0;
4795 ReleaseCapture ();
1edf84e7
GV
4796 /* We must ensure menu bar is fully constructed and up to date
4797 before allowing user interaction with it. To achieve this
4798 we send this message to the lisp thread and wait for a
4799 reply (whose value is not actually needed) to indicate that
4800 the menu bar is now ready for use, so we can now return.
4801
4802 To remain responsive in the meantime, we enter a nested message
4803 loop that can process all other messages.
4804
4805 However, we skip all this if the message results from calling
4806 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4807 thread a message because it is blocked on us at this point. We
4808 set menubar_active before calling TrackPopupMenu to indicate
4809 this (there is no possibility of confusion with real menubar
4810 being active). */
4811
4812 f = x_window_to_frame (dpyinfo, hwnd);
4813 if (f
4814 && (f->output_data.w32->menubar_active
4815 /* We can receive this message even in the absence of a
4816 menubar (ie. when the system menu is activated) - in this
4817 case we do NOT want to forward the message, otherwise it
4818 will cause the menubar to suddenly appear when the user
4819 had requested it to be turned off! */
4820 || f->output_data.w32->menubar_widget == NULL))
4821 return 0;
4822
4823 {
4824 deferred_msg msg_buf;
4825
4826 /* Detect if message has already been deferred; in this case
4827 we cannot return any sensible value to ignore this. */
4828 if (find_deferred_msg (hwnd, msg) != NULL)
4829 abort ();
4830
4831 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4832 }
4833
4834 case WM_EXITMENULOOP:
4835 f = x_window_to_frame (dpyinfo, hwnd);
4836
48094ace
JR
4837 /* If a menu command is not already in progress, check again
4838 after a short delay, since Windows often (always?) sends the
4839 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4840 if (f && !f->output_data.w32->menu_command_in_progress)
4841 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
1edf84e7
GV
4842 goto dflt;
4843
126f2e35 4844 case WM_MENUSELECT:
4e3a1c61
JR
4845 /* Direct handling of help_echo in menus. Should be safe now
4846 that we generate the help_echo by placing a help event in the
4847 keyboard buffer. */
ca56d953 4848 {
ca56d953
JR
4849 HMENU menu = (HMENU) lParam;
4850 UINT menu_item = (UINT) LOWORD (wParam);
4851 UINT flags = (UINT) HIWORD (wParam);
4852
4e3a1c61 4853 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4854 }
126f2e35
JR
4855 return 0;
4856
87996783
GV
4857 case WM_MEASUREITEM:
4858 f = x_window_to_frame (dpyinfo, hwnd);
4859 if (f)
4860 {
4861 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4862
4863 if (pMis->CtlType == ODT_MENU)
4864 {
4865 /* Work out dimensions for popup menu titles. */
4866 char * title = (char *) pMis->itemData;
4867 HDC hdc = GetDC (hwnd);
4868 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4869 LOGFONT menu_logfont;
4870 HFONT old_font;
4871 SIZE size;
4872
4873 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4874 menu_logfont.lfWeight = FW_BOLD;
4875 menu_font = CreateFontIndirect (&menu_logfont);
4876 old_font = SelectObject (hdc, menu_font);
4877
dfff8a69
JR
4878 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4879 if (title)
4880 {
4881 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4882 pMis->itemWidth = size.cx;
4883 if (pMis->itemHeight < size.cy)
4884 pMis->itemHeight = size.cy;
4885 }
4886 else
4887 pMis->itemWidth = 0;
87996783
GV
4888
4889 SelectObject (hdc, old_font);
4890 DeleteObject (menu_font);
4891 ReleaseDC (hwnd, hdc);
4892 return TRUE;
4893 }
4894 }
4895 return 0;
4896
4897 case WM_DRAWITEM:
4898 f = x_window_to_frame (dpyinfo, hwnd);
4899 if (f)
4900 {
4901 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4902
4903 if (pDis->CtlType == ODT_MENU)
4904 {
4905 /* Draw popup menu title. */
4906 char * title = (char *) pDis->itemData;
212da13b
JR
4907 if (title)
4908 {
4909 HDC hdc = pDis->hDC;
4910 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4911 LOGFONT menu_logfont;
4912 HFONT old_font;
4913
4914 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4915 menu_logfont.lfWeight = FW_BOLD;
4916 menu_font = CreateFontIndirect (&menu_logfont);
4917 old_font = SelectObject (hdc, menu_font);
4918
4919 /* Always draw title as if not selected. */
4920 ExtTextOut (hdc,
4921 pDis->rcItem.left
4922 + GetSystemMetrics (SM_CXMENUCHECK),
4923 pDis->rcItem.top,
4924 ETO_OPAQUE, &pDis->rcItem,
4925 title, strlen (title), NULL);
4926
4927 SelectObject (hdc, old_font);
4928 DeleteObject (menu_font);
4929 }
87996783
GV
4930 return TRUE;
4931 }
4932 }
4933 return 0;
4934
1edf84e7
GV
4935#if 0
4936 /* Still not right - can't distinguish between clicks in the
4937 client area of the frame from clicks forwarded from the scroll
4938 bars - may have to hook WM_NCHITTEST to remember the mouse
4939 position and then check if it is in the client area ourselves. */
4940 case WM_MOUSEACTIVATE:
4941 /* Discard the mouse click that activates a frame, allowing the
4942 user to click anywhere without changing point (or worse!).
4943 Don't eat mouse clicks on scrollbars though!! */
4944 if (LOWORD (lParam) == HTCLIENT )
4945 return MA_ACTIVATEANDEAT;
4946 goto dflt;
4947#endif
4948
9eb16b62
JR
4949 case WM_MOUSELEAVE:
4950 /* No longer tracking mouse. */
4951 track_mouse_window = NULL;
4952
1edf84e7 4953 case WM_ACTIVATEAPP:
ccc2d29c 4954 case WM_ACTIVATE:
1edf84e7
GV
4955 case WM_WINDOWPOSCHANGED:
4956 case WM_SHOWWINDOW:
4957 /* Inform lisp thread that a frame might have just been obscured
4958 or exposed, so should recheck visibility of all frames. */
4959 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4960 goto dflt;
4961
da36a4d6 4962 case WM_SETFOCUS:
adcc3809
GV
4963 dpyinfo->faked_key = 0;
4964 reset_modifiers ();
ccc2d29c
GV
4965 register_hot_keys (hwnd);
4966 goto command;
8681157a 4967 case WM_KILLFOCUS:
ccc2d29c 4968 unregister_hot_keys (hwnd);
487163ac
AI
4969 button_state = 0;
4970 ReleaseCapture ();
65906840
JR
4971 /* Relinquish the system caret. */
4972 if (w32_system_caret_hwnd)
4973 {
93f2ca61 4974 w32_visible_system_caret_hwnd = NULL;
d285988b
JR
4975 w32_system_caret_hwnd = NULL;
4976 DestroyCaret ();
65906840 4977 }
48094ace
JR
4978 goto command;
4979 case WM_COMMAND:
4980 f = x_window_to_frame (dpyinfo, hwnd);
4981 if (f && HIWORD (wParam) == 0)
4982 {
4983 f->output_data.w32->menu_command_in_progress = 1;
4984 if (menu_free_timer)
4985 {
4986 KillTimer (hwnd, menu_free_timer);
7d0393cf 4987 menu_free_timer = 0;
48094ace
JR
4988 }
4989 }
ee78dc32
GV
4990 case WM_MOVE:
4991 case WM_SIZE:
ccc2d29c 4992 command:
fbd6baed 4993 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4994 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4995 goto dflt;
8847d890
RS
4996
4997 case WM_CLOSE:
fbd6baed 4998 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4999 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5000 return 0;
5001
ee78dc32 5002 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
5003 /* Don't restrict the sizing of tip frames. */
5004 if (hwnd == tip_window)
5005 return 0;
ee78dc32
GV
5006 {
5007 WINDOWPLACEMENT wp;
5008 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
5009
5010 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32 5011 GetWindowPlacement (hwnd, &wp);
7d0393cf 5012
1edf84e7 5013 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
5014 {
5015 RECT rect;
5016 int wdiff;
5017 int hdiff;
1edf84e7
GV
5018 DWORD font_width;
5019 DWORD line_height;
5020 DWORD internal_border;
5021 DWORD scrollbar_extra;
ee78dc32 5022 RECT wr;
7d0393cf 5023
5ac45f98 5024 wp.length = sizeof(wp);
ee78dc32 5025 GetWindowRect (hwnd, &wr);
7d0393cf 5026
3c190163 5027 enter_crit ();
7d0393cf 5028
1edf84e7
GV
5029 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5030 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5031 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5032 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
7d0393cf 5033
3c190163 5034 leave_crit ();
7d0393cf 5035
ee78dc32 5036 memset (&rect, 0, sizeof (rect));
7d0393cf 5037 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
ee78dc32
GV
5038 GetMenu (hwnd) != NULL);
5039
1edf84e7
GV
5040 /* Force width and height of client area to be exact
5041 multiples of the character cell dimensions. */
5042 wdiff = (lppos->cx - (rect.right - rect.left)
5043 - 2 * internal_border - scrollbar_extra)
5044 % font_width;
5045 hdiff = (lppos->cy - (rect.bottom - rect.top)
5046 - 2 * internal_border)
5047 % line_height;
7d0393cf 5048
ee78dc32
GV
5049 if (wdiff || hdiff)
5050 {
7d0393cf
JB
5051 /* For right/bottom sizing we can just fix the sizes.
5052 However for top/left sizing we will need to fix the X
ee78dc32 5053 and Y positions as well. */
7d0393cf 5054
ee78dc32
GV
5055 lppos->cx -= wdiff;
5056 lppos->cy -= hdiff;
7d0393cf
JB
5057
5058 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 5059 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
5060 {
5061 if (lppos->x != wr.left || lppos->y != wr.top)
5062 {
5063 lppos->x += wdiff;
5064 lppos->y += hdiff;
5065 }
5066 else
5067 {
5068 lppos->flags |= SWP_NOMOVE;
5069 }
5070 }
7d0393cf 5071
1edf84e7 5072 return 0;
ee78dc32
GV
5073 }
5074 }
5075 }
7d0393cf 5076
ee78dc32 5077 goto dflt;
1edf84e7 5078
b1f918f8
GV
5079 case WM_GETMINMAXINFO:
5080 /* Hack to correct bug that allows Emacs frames to be resized
5081 below the Minimum Tracking Size. */
5082 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
5083 /* Hack to allow resizing the Emacs frame above the screen size.
5084 Note that Windows 9x limits coordinates to 16-bits. */
5085 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5086 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
5087 return 0;
5088
c9b2104d
JR
5089 case WM_SETCURSOR:
5090 if (LOWORD (lParam) == HTCLIENT)
5091 return 0;
5092
5093 goto dflt;
c922a224 5094
c9b2104d
JR
5095 case WM_EMACS_SETCURSOR:
5096 {
5097 Cursor cursor = (Cursor) wParam;
5098 if (cursor)
5099 SetCursor (cursor);
5100 return 0;
5101 }
c922a224 5102
1edf84e7
GV
5103 case WM_EMACS_CREATESCROLLBAR:
5104 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5105 (struct scroll_bar *) lParam);
5106
5ac45f98 5107 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
5108 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5109
dfdb4047 5110 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
5111 {
5112 HWND foreground_window;
5113 DWORD foreground_thread, retval;
5114
5115 /* On NT 5.0, and apparently Windows 98, it is necessary to
5116 attach to the thread that currently has focus in order to
5117 pull the focus away from it. */
5118 foreground_window = GetForegroundWindow ();
5119 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5120 if (!foreground_window
5121 || foreground_thread == GetCurrentThreadId ()
5122 || !AttachThreadInput (GetCurrentThreadId (),
5123 foreground_thread, TRUE))
5124 foreground_thread = 0;
5125
5126 retval = SetForegroundWindow ((HWND) wParam);
5127
5128 /* Detach from the previous foreground thread. */
5129 if (foreground_thread)
5130 AttachThreadInput (GetCurrentThreadId (),
5131 foreground_thread, FALSE);
5132
5133 return retval;
5134 }
dfdb4047 5135
5ac45f98
GV
5136 case WM_EMACS_SETWINDOWPOS:
5137 {
1edf84e7
GV
5138 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5139 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5140 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5141 }
1edf84e7 5142
ee78dc32 5143 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5144 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5145 return DestroyWindow ((HWND) wParam);
5146
93f2ca61
JR
5147 case WM_EMACS_HIDE_CARET:
5148 return HideCaret (hwnd);
5149
5150 case WM_EMACS_SHOW_CARET:
5151 return ShowCaret (hwnd);
5152
65906840
JR
5153 case WM_EMACS_DESTROY_CARET:
5154 w32_system_caret_hwnd = NULL;
93f2ca61 5155 w32_visible_system_caret_hwnd = NULL;
65906840
JR
5156 return DestroyCaret ();
5157
5158 case WM_EMACS_TRACK_CARET:
5159 /* If there is currently no system caret, create one. */
5160 if (w32_system_caret_hwnd == NULL)
5161 {
93f2ca61
JR
5162 /* Use the default caret width, and avoid changing it
5163 unneccesarily, as it confuses screen reader software. */
65906840 5164 w32_system_caret_hwnd = hwnd;
93f2ca61 5165 CreateCaret (hwnd, NULL, 0,
65906840
JR
5166 w32_system_caret_height);
5167 }
7d0393cf 5168
93f2ca61
JR
5169 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5170 return 0;
5171 /* Ensure visible caret gets turned on when requested. */
5172 else if (w32_use_visible_system_caret
5173 && w32_visible_system_caret_hwnd != hwnd)
5174 {
5175 w32_visible_system_caret_hwnd = hwnd;
5176 return ShowCaret (hwnd);
5177 }
5178 /* Ensure visible caret gets turned off when requested. */
5179 else if (!w32_use_visible_system_caret
5180 && w32_visible_system_caret_hwnd)
5181 {
5182 w32_visible_system_caret_hwnd = NULL;
5183 return HideCaret (hwnd);
5184 }
5185 else
5186 return 1;
65906840 5187
1edf84e7
GV
5188 case WM_EMACS_TRACKPOPUPMENU:
5189 {
5190 UINT flags;
5191 POINT *pos;
5192 int retval;
5193 pos = (POINT *)lParam;
5194 flags = TPM_CENTERALIGN;
5195 if (button_state & LMOUSE)
5196 flags |= TPM_LEFTBUTTON;
5197 else if (button_state & RMOUSE)
5198 flags |= TPM_RIGHTBUTTON;
7d0393cf 5199
87996783
GV
5200 /* Remember we did a SetCapture on the initial mouse down event,
5201 so for safety, we make sure the capture is cancelled now. */
5202 ReleaseCapture ();
490822ff 5203 button_state = 0;
87996783 5204
1edf84e7
GV
5205 /* Use menubar_active to indicate that WM_INITMENU is from
5206 TrackPopupMenu below, and should be ignored. */
5207 f = x_window_to_frame (dpyinfo, hwnd);
5208 if (f)
5209 f->output_data.w32->menubar_active = 1;
7d0393cf
JB
5210
5211 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
1edf84e7
GV
5212 0, hwnd, NULL))
5213 {
5214 MSG amsg;
5215 /* Eat any mouse messages during popupmenu */
5216 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5217 PM_REMOVE));
5218 /* Get the menu selection, if any */
5219 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5220 {
5221 retval = LOWORD (amsg.wParam);
5222 }
5223 else
5224 {
5225 retval = 0;
5226 }
1edf84e7
GV
5227 }
5228 else
5229 {
5230 retval = -1;
5231 }
5232
5233 return retval;
5234 }
5235
ee78dc32 5236 default:
93fbe8b7
GV
5237 /* Check for messages registered at runtime. */
5238 if (msg == msh_mousewheel)
5239 {
5240 wmsg.dwModifiers = w32_get_modifiers ();
5241 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5242 return 0;
5243 }
7d0393cf 5244
ee78dc32
GV
5245 dflt:
5246 return DefWindowProc (hwnd, msg, wParam, lParam);
5247 }
7d0393cf 5248
1edf84e7
GV
5249
5250 /* The most common default return code for handled messages is 0. */
5251 return 0;
ee78dc32
GV
5252}
5253
7d0393cf 5254void
ee78dc32
GV
5255my_create_window (f)
5256 struct frame * f;
5257{
5258 MSG msg;
5259
1edf84e7
GV
5260 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5261 abort ();
ee78dc32
GV
5262 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5263}
5264
ca56d953
JR
5265
5266/* Create a tooltip window. Unlike my_create_window, we do not do this
5267 indirectly via the Window thread, as we do not need to process Window
5268 messages for the tooltip. Creating tooltips indirectly also creates
5269 deadlocks when tooltips are created for menu items. */
7d0393cf 5270void
ca56d953
JR
5271my_create_tip_window (f)
5272 struct frame *f;
5273{
bfd6edcc 5274 RECT rect;
ca56d953 5275
bfd6edcc
JR
5276 rect.left = rect.top = 0;
5277 rect.right = PIXEL_WIDTH (f);
5278 rect.bottom = PIXEL_HEIGHT (f);
5279
5280 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5281 FRAME_EXTERNAL_MENU_BAR (f));
5282
5283 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5284 = CreateWindow (EMACS_CLASS,
5285 f->namebuf,
5286 f->output_data.w32->dwStyle,
5287 f->output_data.w32->left_pos,
5288 f->output_data.w32->top_pos,
bfd6edcc
JR
5289 rect.right - rect.left,
5290 rect.bottom - rect.top,
ca56d953
JR
5291 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5292 NULL,
5293 hinst,
5294 NULL);
5295
bfd6edcc 5296 if (tip_window)
ca56d953 5297 {
bfd6edcc
JR
5298 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5299 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5300 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5301 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5302
5303 /* Tip frames have no scrollbars. */
5304 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5305
5306 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5307 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5308 }
5309}
5310
5311
fbd6baed 5312/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5313
5314static void
fbd6baed 5315w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5316 struct frame *f;
5317 long window_prompting;
5318 int minibuffer_only;
5319{
5320 BLOCK_INPUT;
5321
5322 /* Use the resource name as the top-level window name
5323 for looking up resources. Make a non-Lisp copy
5324 for the window manager, so GC relocation won't bother it.
5325
5326 Elsewhere we specify the window name for the window manager. */
7d0393cf 5327
ee78dc32 5328 {
d5db4077 5329 char *str = (char *) SDATA (Vx_resource_name);
ee78dc32
GV
5330 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5331 strcpy (f->namebuf, str);
5332 }
5333
5334 my_create_window (f);
5335
5336 validate_x_resource_name ();
5337
5338 /* x_set_name normally ignores requests to set the name if the
5339 requested name is the same as the current name. This is the one
5340 place where that assumption isn't correct; f->name is set, but
5341 the server hasn't been told. */
5342 {
5343 Lisp_Object name;
5344 int explicit = f->explicit_name;
5345
5346 f->explicit_name = 0;
5347 name = f->name;
5348 f->name = Qnil;
5349 x_set_name (f, name, explicit);
5350 }
5351
5352 UNBLOCK_INPUT;
5353
5354 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5355 initialize_frame_menubar (f);
5356
fbd6baed 5357 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5358 error ("Unable to create window");
5359}
5360
5361/* Handle the icon stuff for this window. Perhaps later we might
5362 want an x_set_icon_position which can be called interactively as
5363 well. */
5364
5365static void
5366x_icon (f, parms)
5367 struct frame *f;
5368 Lisp_Object parms;
5369{
5370 Lisp_Object icon_x, icon_y;
5371
e9e23e23 5372 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5373 icons in the tray. */
6fc2811b
JR
5374 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5375 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5376 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5377 {
b7826503
PJ
5378 CHECK_NUMBER (icon_x);
5379 CHECK_NUMBER (icon_y);
ee78dc32
GV
5380 }
5381 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5382 error ("Both left and top icon corners of icon must be specified");
5383
5384 BLOCK_INPUT;
5385
5386 if (! EQ (icon_x, Qunbound))
5387 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5388
1edf84e7
GV
5389#if 0 /* TODO */
5390 /* Start up iconic or window? */
5391 x_wm_set_window_state
6fc2811b 5392 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5393 ? IconicState
5394 : NormalState));
5395
d5db4077 5396 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
1edf84e7 5397 ? f->icon_name
d5db4077 5398 : f->name)));
1edf84e7
GV
5399#endif
5400
ee78dc32
GV
5401 UNBLOCK_INPUT;
5402}
5403
6fc2811b
JR
5404
5405static void
5406x_make_gc (f)
5407 struct frame *f;
5408{
5409 XGCValues gc_values;
5410
5411 BLOCK_INPUT;
5412
5413 /* Create the GC's of this frame.
5414 Note that many default values are used. */
5415
5416 /* Normal video */
5417 gc_values.font = f->output_data.w32->font;
5418
5419 /* Cursor has cursor-color background, background-color foreground. */
5420 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5421 gc_values.background = f->output_data.w32->cursor_pixel;
5422 f->output_data.w32->cursor_gc
5423 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5424 (GCFont | GCForeground | GCBackground),
5425 &gc_values);
5426
5427 /* Reliefs. */
5428 f->output_data.w32->white_relief.gc = 0;
5429 f->output_data.w32->black_relief.gc = 0;
5430
5431 UNBLOCK_INPUT;
5432}
5433
5434
937e601e
AI
5435/* Handler for signals raised during x_create_frame and
5436 x_create_top_frame. FRAME is the frame which is partially
5437 constructed. */
5438
5439static Lisp_Object
5440unwind_create_frame (frame)
5441 Lisp_Object frame;
5442{
5443 struct frame *f = XFRAME (frame);
5444
5445 /* If frame is ``official'', nothing to do. */
5446 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5447 {
5448#ifdef GLYPH_DEBUG
5449 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5450#endif
7d0393cf 5451
937e601e
AI
5452 x_free_frame_resources (f);
5453
5454 /* Check that reference counts are indeed correct. */
5455 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5456 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5457
5458 return Qt;
937e601e 5459 }
7d0393cf 5460
937e601e
AI
5461 return Qnil;
5462}
5463
5464
ee78dc32
GV
5465DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5466 1, 1, 0,
74e1aeec
JR
5467 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5468Returns an Emacs frame object.
5469ALIST is an alist of frame parameters.
5470If the parameters specify that the frame should not have a minibuffer,
5471and do not specify a specific minibuffer window to use,
5472then `default-minibuffer-frame' must be a frame whose minibuffer can
5473be shared by the new frame.
5474
5475This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5476 (parms)
5477 Lisp_Object parms;
5478{
5479 struct frame *f;
5480 Lisp_Object frame, tem;
5481 Lisp_Object name;
5482 int minibuffer_only = 0;
5483 long window_prompting = 0;
5484 int width, height;
331379bf 5485 int count = SPECPDL_INDEX ();
1edf84e7 5486 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5487 Lisp_Object display;
6fc2811b 5488 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5489 Lisp_Object parent;
5490 struct kboard *kb;
5491
4587b026
GV
5492 check_w32 ();
5493
ee78dc32
GV
5494 /* Use this general default value to start with
5495 until we know if this frame has a specified name. */
5496 Vx_resource_name = Vinvocation_name;
5497
6fc2811b 5498 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5499 if (EQ (display, Qunbound))
5500 display = Qnil;
5501 dpyinfo = check_x_display_info (display);
5502#ifdef MULTI_KBOARD
5503 kb = dpyinfo->kboard;
5504#else
5505 kb = &the_only_kboard;
5506#endif
5507
6fc2811b 5508 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5509 if (!STRINGP (name)
5510 && ! EQ (name, Qunbound)
5511 && ! NILP (name))
5512 error ("Invalid frame name--not a string or nil");
5513
5514 if (STRINGP (name))
5515 Vx_resource_name = name;
5516
5517 /* See if parent window is specified. */
6fc2811b 5518 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5519 if (EQ (parent, Qunbound))
5520 parent = Qnil;
5521 if (! NILP (parent))
b7826503 5522 CHECK_NUMBER (parent);
ee78dc32 5523
1edf84e7
GV
5524 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5525 /* No need to protect DISPLAY because that's not used after passing
5526 it to make_frame_without_minibuffer. */
5527 frame = Qnil;
5528 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5529 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5530 RES_TYPE_SYMBOL);
ee78dc32
GV
5531 if (EQ (tem, Qnone) || NILP (tem))
5532 f = make_frame_without_minibuffer (Qnil, kb, display);
5533 else if (EQ (tem, Qonly))
5534 {
5535 f = make_minibuffer_frame ();
5536 minibuffer_only = 1;
5537 }
5538 else if (WINDOWP (tem))
5539 f = make_frame_without_minibuffer (tem, kb, display);
5540 else
5541 f = make_frame (1);
5542
1edf84e7
GV
5543 XSETFRAME (frame, f);
5544
ee78dc32
GV
5545 /* Note that Windows does support scroll bars. */
5546 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5547 /* By default, make scrollbars the system standard width. */
5548 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5549
fbd6baed 5550 f->output_method = output_w32;
6fc2811b
JR
5551 f->output_data.w32 =
5552 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5553 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5554 FRAME_FONTSET (f) = -1;
937e601e 5555 record_unwind_protect (unwind_create_frame, frame);
4587b026 5556
1edf84e7 5557 f->icon_name
6fc2811b 5558 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5559 if (! STRINGP (f->icon_name))
5560 f->icon_name = Qnil;
5561
fbd6baed 5562/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5563#ifdef MULTI_KBOARD
5564 FRAME_KBOARD (f) = kb;
5565#endif
5566
5567 /* Specify the parent under which to make this window. */
5568
5569 if (!NILP (parent))
5570 {
1660f34a 5571 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5572 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5573 }
5574 else
5575 {
fbd6baed
GV
5576 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5577 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5578 }
5579
ee78dc32
GV
5580 /* Set the name; the functions to which we pass f expect the name to
5581 be set. */
5582 if (EQ (name, Qunbound) || NILP (name))
5583 {
fbd6baed 5584 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5585 f->explicit_name = 0;
5586 }
5587 else
5588 {
5589 f->name = name;
5590 f->explicit_name = 1;
5591 /* use the frame's title when getting resources for this frame. */
5592 specbind (Qx_resource_name, name);
5593 }
5594
5595 /* Extract the window parameters from the supplied values
5596 that are needed to determine window geometry. */
5597 {
5598 Lisp_Object font;
5599
6fc2811b
JR
5600 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5601
ee78dc32
GV
5602 BLOCK_INPUT;
5603 /* First, try whatever font the caller has specified. */
5604 if (STRINGP (font))
4587b026
GV
5605 {
5606 tem = Fquery_fontset (font, Qnil);
5607 if (STRINGP (tem))
d5db4077 5608 font = x_new_fontset (f, SDATA (tem));
4587b026 5609 else
d5db4077 5610 font = x_new_font (f, SDATA (font));
4587b026 5611 }
ee78dc32
GV
5612 /* Try out a font which we hope has bold and italic variations. */
5613 if (!STRINGP (font))
e39649be 5614 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5615 if (! STRINGP (font))
6fc2811b 5616 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5617 /* If those didn't work, look for something which will at least work. */
5618 if (! STRINGP (font))
6fc2811b 5619 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5620 UNBLOCK_INPUT;
5621 if (! STRINGP (font))
1edf84e7 5622 font = build_string ("Fixedsys");
ee78dc32 5623
7d0393cf 5624 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5625 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5626 }
5627
5628 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5629 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5630 /* This defaults to 2 in order to match xterm. We recognize either
5631 internalBorderWidth or internalBorder (which is what xterm calls
5632 it). */
5633 if (NILP (Fassq (Qinternal_border_width, parms)))
5634 {
5635 Lisp_Object value;
5636
6fc2811b 5637 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5638 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5639 if (! EQ (value, Qunbound))
5640 parms = Fcons (Fcons (Qinternal_border_width, value),
5641 parms);
5642 }
1edf84e7 5643 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5644 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5645 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5646 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5647 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5648
5649 /* Also do the stuff which must be set before the window exists. */
5650 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5651 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5652 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5653 "background", "Background", RES_TYPE_STRING);
ee78dc32 5654 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5655 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5656 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5657 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5658 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5659 "borderColor", "BorderColor", RES_TYPE_STRING);
5660 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5661 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5662 x_default_parameter (f, parms, Qline_spacing, Qnil,
5663 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5664 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5665 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5666 x_default_parameter (f, parms, Qright_fringe, Qnil,
5667 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5668
ee78dc32 5669
6fc2811b
JR
5670 /* Init faces before x_default_parameter is called for scroll-bar
5671 parameters because that function calls x_set_scroll_bar_width,
5672 which calls change_frame_size, which calls Fset_window_buffer,
5673 which runs hooks, which call Fvertical_motion. At the end, we
5674 end up in init_iterator with a null face cache, which should not
5675 happen. */
5676 init_frame_faces (f);
7d0393cf 5677
ee78dc32 5678 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b 5679 "menuBar", "MenuBar", RES_TYPE_NUMBER);
d3109773 5680 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
6fc2811b 5681 "toolBar", "ToolBar", RES_TYPE_NUMBER);
919f1e88 5682
1edf84e7 5683 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5684 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5685 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5686 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
5687 x_default_parameter (f, parms, Qfullscreen, Qnil,
5688 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 5689
fbd6baed
GV
5690 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5691 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e 5692
c9b2104d
JR
5693 f->output_data.w32->text_cursor = w32_load_cursor (IDC_IBEAM);
5694 f->output_data.w32->nontext_cursor = w32_load_cursor (IDC_ARROW);
5695 f->output_data.w32->modeline_cursor = w32_load_cursor (IDC_ARROW);
5696 f->output_data.w32->cross_cursor = w32_load_cursor (IDC_CROSS);
5697 f->output_data.w32->hourglass_cursor = w32_load_cursor (IDC_WAIT);
5698 f->output_data.w32->horizontal_drag_cursor = w32_load_cursor (IDC_SIZEWE);
5699 f->output_data.w32->hand_cursor = w32_load_cursor (IDC_HAND);
5700
3cf3436e
JR
5701 /* Add the tool-bar height to the initial frame height so that the
5702 user gets a text display area of the size he specified with -g or
5703 via .Xdefaults. Later changes of the tool-bar height don't
5704 change the frame size. This is done so that users can create
5705 tall Emacs frames without having to guess how tall the tool-bar
5706 will get. */
5707 if (FRAME_TOOL_BAR_LINES (f))
5708 {
5709 int margin, relief, bar_height;
7d0393cf 5710
a05e2bae 5711 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5712 ? tool_bar_button_relief
5713 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5714
5715 if (INTEGERP (Vtool_bar_button_margin)
5716 && XINT (Vtool_bar_button_margin) > 0)
5717 margin = XFASTINT (Vtool_bar_button_margin);
5718 else if (CONSP (Vtool_bar_button_margin)
5719 && INTEGERP (XCDR (Vtool_bar_button_margin))
5720 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5721 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5722 else
5723 margin = 0;
7d0393cf 5724
3cf3436e
JR
5725 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5726 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5727 }
5728
ee78dc32
GV
5729 window_prompting = x_figure_window_size (f, parms);
5730
5731 if (window_prompting & XNegative)
5732 {
5733 if (window_prompting & YNegative)
fbd6baed 5734 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5735 else
fbd6baed 5736 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5737 }
5738 else
5739 {
5740 if (window_prompting & YNegative)
fbd6baed 5741 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5742 else
fbd6baed 5743 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5744 }
5745
fbd6baed 5746 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5747
6fc2811b
JR
5748 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5749 f->no_split = minibuffer_only || EQ (tem, Qt);
5750
fbd6baed 5751 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5752 x_icon (f, parms);
6fc2811b
JR
5753
5754 x_make_gc (f);
5755
5756 /* Now consider the frame official. */
5757 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5758 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5759
5760 /* We need to do this after creating the window, so that the
5761 icon-creation functions can say whose icon they're describing. */
5762 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5763 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5764
5765 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5766 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5767 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5768 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5769 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5770 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5771 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5772 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5773
5774 /* Dimensions, especially f->height, must be done via change_frame_size.
5775 Change will not be effected unless different from the current
5776 f->height. */
5777 width = f->width;
5778 height = f->height;
dc220243 5779
1026b400
RS
5780 f->height = 0;
5781 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5782 change_frame_size (f, height, width, 1, 0, 0);
5783
6fc2811b
JR
5784 /* Tell the server what size and position, etc, we want, and how
5785 badly we want them. This should be done after we have the menu
5786 bar so that its size can be taken into account. */
ee78dc32
GV
5787 BLOCK_INPUT;
5788 x_wm_set_size_hint (f, window_prompting, 0);
5789 UNBLOCK_INPUT;
5790
815d969e
JR
5791 /* Avoid a bug that causes the new frame to never become visible if
5792 an echo area message is displayed during the following call1. */
5793 specbind(Qredisplay_dont_pause, Qt);
5794
4694d762
JR
5795 /* Set up faces after all frame parameters are known. This call
5796 also merges in face attributes specified for new frames. If we
5797 don't do this, the `menu' face for instance won't have the right
5798 colors, and the menu bar won't appear in the specified colors for
5799 new frames. */
5800 call1 (Qface_set_after_frame_default, frame);
5801
6fc2811b
JR
5802 /* Make the window appear on the frame and enable display, unless
5803 the caller says not to. However, with explicit parent, Emacs
5804 cannot control visibility, so don't try. */
fbd6baed 5805 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5806 {
5807 Lisp_Object visibility;
5808
6fc2811b 5809 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5810 if (EQ (visibility, Qunbound))
5811 visibility = Qt;
5812
5813 if (EQ (visibility, Qicon))
5814 x_iconify_frame (f);
5815 else if (! NILP (visibility))
5816 x_make_frame_visible (f);
5817 else
5818 /* Must have been Qnil. */
5819 ;
5820 }
6fc2811b 5821 UNGCPRO;
7d0393cf 5822
9e57df62
GM
5823 /* Make sure windows on this frame appear in calls to next-window
5824 and similar functions. */
5825 Vwindow_list = Qnil;
7d0393cf 5826
ee78dc32
GV
5827 return unbind_to (count, frame);
5828}
5829
5830/* FRAME is used only to get a handle on the X display. We don't pass the
5831 display info directly because we're called from frame.c, which doesn't
5832 know about that structure. */
5833Lisp_Object
5834x_get_focus_frame (frame)
5835 struct frame *frame;
5836{
fbd6baed 5837 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5838 Lisp_Object xfocus;
fbd6baed 5839 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5840 return Qnil;
5841
fbd6baed 5842 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5843 return xfocus;
5844}
1edf84e7
GV
5845
5846DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5847 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5848 (frame)
5849 Lisp_Object frame;
5850{
5851 x_focus_on_frame (check_x_frame (frame));
5852 return Qnil;
5853}
5854
ee78dc32 5855\f
767b1ff0
JR
5856/* Return the charset portion of a font name. */
5857char * xlfd_charset_of_font (char * fontname)
5858{
5859 char *charset, *encoding;
5860
5861 encoding = strrchr(fontname, '-');
ceb12877 5862 if (!encoding || encoding == fontname)
767b1ff0
JR
5863 return NULL;
5864
478ea067
AI
5865 for (charset = encoding - 1; charset >= fontname; charset--)
5866 if (*charset == '-')
5867 break;
767b1ff0 5868
478ea067 5869 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5870 return NULL;
5871
5872 return charset + 1;
5873}
5874
33d52f9c
GV
5875struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5876 int size, char* filename);
8edb0a6f 5877static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5878static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5879 char * charset);
5880static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5881
8edb0a6f 5882static struct font_info *
33d52f9c 5883w32_load_system_font (f,fontname,size)
55dcfc15
AI
5884 struct frame *f;
5885 char * fontname;
5886 int size;
ee78dc32 5887{
4587b026
GV
5888 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5889 Lisp_Object font_names;
5890
4587b026
GV
5891 /* Get a list of all the fonts that match this name. Once we
5892 have a list of matching fonts, we compare them against the fonts
5893 we already have loaded by comparing names. */
5894 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5895
5896 if (!NILP (font_names))
3c190163 5897 {
4587b026
GV
5898 Lisp_Object tail;
5899 int i;
4587b026
GV
5900
5901 /* First check if any are already loaded, as that is cheaper
5902 than loading another one. */
5903 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5904 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5905 if (dpyinfo->font_table[i].name
5906 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 5907 SDATA (XCAR (tail)))
6fc2811b 5908 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 5909 SDATA (XCAR (tail)))))
4587b026 5910 return (dpyinfo->font_table + i);
6fc2811b 5911
d5db4077 5912 fontname = (char *) SDATA (XCAR (font_names));
4587b026 5913 }
1075afa9 5914 else if (w32_strict_fontnames)
5ca0cd71
GV
5915 {
5916 /* If EnumFontFamiliesEx was available, we got a full list of
5917 fonts back so stop now to avoid the possibility of loading a
5918 random font. If we had to fall back to EnumFontFamilies, the
5919 list is incomplete, so continue whether the font we want was
5920 listed or not. */
5921 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5922 FARPROC enum_font_families_ex
1075afa9 5923 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5924 if (enum_font_families_ex)
5925 return NULL;
5926 }
4587b026
GV
5927
5928 /* Load the font and add it to the table. */
5929 {
767b1ff0 5930 char *full_name, *encoding, *charset;
4587b026
GV
5931 XFontStruct *font;
5932 struct font_info *fontp;
3c190163 5933 LOGFONT lf;
4587b026 5934 BOOL ok;
19c291d3 5935 int codepage;
6fc2811b 5936 int i;
5ac45f98 5937
4587b026 5938 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5939 return (NULL);
5ac45f98 5940
4587b026
GV
5941 if (!*lf.lfFaceName)
5942 /* If no name was specified for the font, we get a random font
5943 from CreateFontIndirect - this is not particularly
5944 desirable, especially since CreateFontIndirect does not
5945 fill out the missing name in lf, so we never know what we
5946 ended up with. */
5947 return NULL;
5948
c8d88d08 5949 lf.lfQuality = DEFAULT_QUALITY;
d65a9cdc 5950
3c190163 5951 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5952 bzero (font, sizeof (*font));
5ac45f98 5953
33d52f9c
GV
5954 /* Set bdf to NULL to indicate that this is a Windows font. */
5955 font->bdf = NULL;
5ac45f98 5956
3c190163 5957 BLOCK_INPUT;
5ac45f98
GV
5958
5959 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5960
7d0393cf 5961 if (font->hfont == NULL)
1a292d24
AI
5962 {
5963 ok = FALSE;
7d0393cf
JB
5964 }
5965 else
1a292d24
AI
5966 {
5967 HDC hdc;
5968 HANDLE oldobj;
19c291d3
AI
5969
5970 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5971
5972 hdc = GetDC (dpyinfo->root_window);
5973 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5974
1a292d24 5975 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5976 if (codepage == CP_UNICODE)
5977 font->double_byte_p = 1;
5978 else
8b77111c
AI
5979 {
5980 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5981 don't report themselves as double byte fonts, when
5982 patently they are. So instead of trusting
5983 GetFontLanguageInfo, we check the properties of the
5984 codepage directly, since that is ultimately what we are
5985 working from anyway. */
5986 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5987 CPINFO cpi = {0};
5988 GetCPInfo (codepage, &cpi);
5989 font->double_byte_p = cpi.MaxCharSize > 1;
5990 }
5c6682be 5991
1a292d24
AI
5992 SelectObject (hdc, oldobj);
5993 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5994 /* Fill out details in lf according to the font that was
5995 actually loaded. */
5996 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5997 lf.lfWidth = font->tm.tmAveCharWidth;
5998 lf.lfWeight = font->tm.tmWeight;
5999 lf.lfItalic = font->tm.tmItalic;
6000 lf.lfCharSet = font->tm.tmCharSet;
6001 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 6002 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
6003 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
6004 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
6005
6006 w32_cache_char_metrics (font);
1a292d24 6007 }
5ac45f98 6008
1a292d24 6009 UNBLOCK_INPUT;
5ac45f98 6010
4587b026
GV
6011 if (!ok)
6012 {
1a292d24
AI
6013 w32_unload_font (dpyinfo, font);
6014 return (NULL);
6015 }
ee78dc32 6016
6fc2811b
JR
6017 /* Find a free slot in the font table. */
6018 for (i = 0; i < dpyinfo->n_fonts; ++i)
6019 if (dpyinfo->font_table[i].name == NULL)
6020 break;
6021
6022 /* If no free slot found, maybe enlarge the font table. */
6023 if (i == dpyinfo->n_fonts
6024 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 6025 {
6fc2811b
JR
6026 int sz;
6027 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6028 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 6029 dpyinfo->font_table
6fc2811b 6030 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
6031 }
6032
6fc2811b
JR
6033 fontp = dpyinfo->font_table + i;
6034 if (i == dpyinfo->n_fonts)
6035 ++dpyinfo->n_fonts;
4587b026
GV
6036
6037 /* Now fill in the slots of *FONTP. */
6038 BLOCK_INPUT;
6039 fontp->font = font;
6fc2811b 6040 fontp->font_idx = i;
4587b026
GV
6041 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6042 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6043
767b1ff0
JR
6044 charset = xlfd_charset_of_font (fontname);
6045
19c291d3
AI
6046 /* Cache the W32 codepage for a font. This makes w32_encode_char
6047 (called for every glyph during redisplay) much faster. */
6048 fontp->codepage = codepage;
6049
4587b026
GV
6050 /* Work out the font's full name. */
6051 full_name = (char *)xmalloc (100);
767b1ff0 6052 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
6053 fontp->full_name = full_name;
6054 else
6055 {
6056 /* If all else fails - just use the name we used to load it. */
6057 xfree (full_name);
6058 fontp->full_name = fontp->name;
6059 }
6060
6061 fontp->size = FONT_WIDTH (font);
6062 fontp->height = FONT_HEIGHT (font);
6063
6064 /* The slot `encoding' specifies how to map a character
6065 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
6066 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6067 (0:0x20..0x7F, 1:0xA0..0xFF,
6068 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 6069 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 6070 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
6071 which is never used by any charset. If mapping can't be
6072 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
6073
6074 /* SJIS fonts need to be set to type 4, all others seem to work as
6075 type FONT_ENCODING_NOT_DECIDED. */
6076 encoding = strrchr (fontp->name, '-');
d84b082d 6077 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 6078 fontp->encoding[1] = 4;
33d52f9c 6079 else
1c885fe1 6080 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
6081
6082 /* The following three values are set to 0 under W32, which is
6083 what they get set to if XGetFontProperty fails under X. */
6084 fontp->baseline_offset = 0;
6085 fontp->relative_compose = 0;
33d52f9c 6086 fontp->default_ascent = 0;
4587b026 6087
6fc2811b
JR
6088 /* Set global flag fonts_changed_p to non-zero if the font loaded
6089 has a character with a smaller width than any other character
f7b9d4d1 6090 before, or if the font loaded has a smaller height than any
6fc2811b
JR
6091 other font loaded before. If this happens, it will make a
6092 glyph matrix reallocation necessary. */
f7b9d4d1 6093 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 6094 UNBLOCK_INPUT;
4587b026
GV
6095 return fontp;
6096 }
6097}
6098
33d52f9c
GV
6099/* Load font named FONTNAME of size SIZE for frame F, and return a
6100 pointer to the structure font_info while allocating it dynamically.
6101 If loading fails, return NULL. */
6102struct font_info *
6103w32_load_font (f,fontname,size)
6104struct frame *f;
6105char * fontname;
6106int size;
6107{
6108 Lisp_Object bdf_fonts;
6109 struct font_info *retval = NULL;
6110
8edb0a6f 6111 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
6112
6113 while (!retval && CONSP (bdf_fonts))
6114 {
6115 char *bdf_name, *bdf_file;
6116 Lisp_Object bdf_pair;
6117
d5db4077 6118 bdf_name = SDATA (XCAR (bdf_fonts));
8e713be6 6119 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
d5db4077 6120 bdf_file = SDATA (XCDR (bdf_pair));
33d52f9c
GV
6121
6122 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6123
8e713be6 6124 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
6125 }
6126
6127 if (retval)
6128 return retval;
6129
6130 return w32_load_system_font(f, fontname, size);
6131}
6132
6133
7d0393cf 6134void
fbd6baed
GV
6135w32_unload_font (dpyinfo, font)
6136 struct w32_display_info *dpyinfo;
ee78dc32
GV
6137 XFontStruct * font;
6138{
7d0393cf 6139 if (font)
ee78dc32 6140 {
c6be3860 6141 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
6142 if (font->bdf) w32_free_bdf_font (font->bdf);
6143
3c190163 6144 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
6145 xfree (font);
6146 }
6147}
6148
fbd6baed 6149/* The font conversion stuff between x and w32 */
ee78dc32
GV
6150
6151/* X font string is as follows (from faces.el)
6152 * (let ((- "[-?]")
6153 * (foundry "[^-]+")
6154 * (family "[^-]+")
6155 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6156 * (weight\? "\\([^-]*\\)") ; 1
6157 * (slant "\\([ior]\\)") ; 2
6158 * (slant\? "\\([^-]?\\)") ; 2
6159 * (swidth "\\([^-]*\\)") ; 3
6160 * (adstyle "[^-]*") ; 4
6161 * (pixelsize "[0-9]+")
6162 * (pointsize "[0-9][0-9]+")
6163 * (resx "[0-9][0-9]+")
6164 * (resy "[0-9][0-9]+")
6165 * (spacing "[cmp?*]")
6166 * (avgwidth "[0-9]+")
6167 * (registry "[^-]+")
6168 * (encoding "[^-]+")
6169 * )
ee78dc32 6170 */
ee78dc32 6171
7d0393cf 6172static LONG
fbd6baed 6173x_to_w32_weight (lpw)
ee78dc32
GV
6174 char * lpw;
6175{
6176 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6177
6178 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6179 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6180 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6181 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6182 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6183 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6184 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6185 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6186 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6187 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6188 else
5ac45f98 6189 return FW_DONTCARE;
ee78dc32
GV
6190}
6191
5ac45f98 6192
7d0393cf 6193static char *
fbd6baed 6194w32_to_x_weight (fnweight)
ee78dc32
GV
6195 int fnweight;
6196{
5ac45f98
GV
6197 if (fnweight >= FW_HEAVY) return "heavy";
6198 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6199 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6200 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6201 if (fnweight >= FW_MEDIUM) return "medium";
6202 if (fnweight >= FW_NORMAL) return "normal";
6203 if (fnweight >= FW_LIGHT) return "light";
6204 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6205 if (fnweight >= FW_THIN) return "thin";
6206 else
6207 return "*";
6208}
6209
8edb0a6f 6210static LONG
fbd6baed 6211x_to_w32_charset (lpcs)
5ac45f98
GV
6212 char * lpcs;
6213{
767b1ff0 6214 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6215 char *charset;
6216 int len = strlen (lpcs);
6217
6218 /* Support "*-#nnn" format for unknown charsets. */
6219 if (strncmp (lpcs, "*-#", 3) == 0)
6220 return atoi (lpcs + 3);
6221
6222 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6223 charset = alloca (len + 1);
6224 strcpy (charset, lpcs);
6225 lpcs = strchr (charset, '*');
6226 if (lpcs)
6227 *lpcs = 0;
4587b026 6228
dfff8a69
JR
6229 /* Look through w32-charset-info-alist for the character set.
6230 Format of each entry is
6231 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6232 */
8b77111c 6233 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6234
767b1ff0
JR
6235 if (NILP(this_entry))
6236 {
6237 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6238 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6239 return ANSI_CHARSET;
6240 else
6241 return DEFAULT_CHARSET;
6242 }
6243
6244 w32_charset = Fcar (Fcdr (this_entry));
6245
d84b082d 6246 /* Translate Lisp symbol to number. */
767b1ff0
JR
6247 if (w32_charset == Qw32_charset_ansi)
6248 return ANSI_CHARSET;
6249 if (w32_charset == Qw32_charset_symbol)
6250 return SYMBOL_CHARSET;
6251 if (w32_charset == Qw32_charset_shiftjis)
6252 return SHIFTJIS_CHARSET;
6253 if (w32_charset == Qw32_charset_hangeul)
6254 return HANGEUL_CHARSET;
6255 if (w32_charset == Qw32_charset_chinesebig5)
6256 return CHINESEBIG5_CHARSET;
6257 if (w32_charset == Qw32_charset_gb2312)
6258 return GB2312_CHARSET;
6259 if (w32_charset == Qw32_charset_oem)
6260 return OEM_CHARSET;
dfff8a69 6261#ifdef JOHAB_CHARSET
767b1ff0
JR
6262 if (w32_charset == Qw32_charset_johab)
6263 return JOHAB_CHARSET;
6264 if (w32_charset == Qw32_charset_easteurope)
6265 return EASTEUROPE_CHARSET;
6266 if (w32_charset == Qw32_charset_turkish)
6267 return TURKISH_CHARSET;
6268 if (w32_charset == Qw32_charset_baltic)
6269 return BALTIC_CHARSET;
6270 if (w32_charset == Qw32_charset_russian)
6271 return RUSSIAN_CHARSET;
6272 if (w32_charset == Qw32_charset_arabic)
6273 return ARABIC_CHARSET;
6274 if (w32_charset == Qw32_charset_greek)
6275 return GREEK_CHARSET;
6276 if (w32_charset == Qw32_charset_hebrew)
6277 return HEBREW_CHARSET;
6278 if (w32_charset == Qw32_charset_vietnamese)
6279 return VIETNAMESE_CHARSET;
6280 if (w32_charset == Qw32_charset_thai)
6281 return THAI_CHARSET;
6282 if (w32_charset == Qw32_charset_mac)
6283 return MAC_CHARSET;
dfff8a69 6284#endif /* JOHAB_CHARSET */
5ac45f98 6285#ifdef UNICODE_CHARSET
767b1ff0
JR
6286 if (w32_charset == Qw32_charset_unicode)
6287 return UNICODE_CHARSET;
5ac45f98 6288#endif
dfff8a69
JR
6289
6290 return DEFAULT_CHARSET;
5ac45f98
GV
6291}
6292
dfff8a69 6293
8edb0a6f 6294static char *
fbd6baed 6295w32_to_x_charset (fncharset)
5ac45f98
GV
6296 int fncharset;
6297{
5e905a57 6298 static char buf[32];
767b1ff0 6299 Lisp_Object charset_type;
1edf84e7 6300
5ac45f98
GV
6301 switch (fncharset)
6302 {
767b1ff0
JR
6303 case ANSI_CHARSET:
6304 /* Handle startup case of w32-charset-info-alist not
6305 being set up yet. */
6306 if (NILP(Vw32_charset_info_alist))
6307 return "iso8859-1";
6308 charset_type = Qw32_charset_ansi;
6309 break;
6310 case DEFAULT_CHARSET:
6311 charset_type = Qw32_charset_default;
6312 break;
6313 case SYMBOL_CHARSET:
6314 charset_type = Qw32_charset_symbol;
6315 break;
6316 case SHIFTJIS_CHARSET:
6317 charset_type = Qw32_charset_shiftjis;
6318 break;
6319 case HANGEUL_CHARSET:
6320 charset_type = Qw32_charset_hangeul;
6321 break;
6322 case GB2312_CHARSET:
6323 charset_type = Qw32_charset_gb2312;
6324 break;
6325 case CHINESEBIG5_CHARSET:
6326 charset_type = Qw32_charset_chinesebig5;
6327 break;
6328 case OEM_CHARSET:
6329 charset_type = Qw32_charset_oem;
6330 break;
4587b026
GV
6331
6332 /* More recent versions of Windows (95 and NT4.0) define more
6333 character sets. */
6334#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6335 case EASTEUROPE_CHARSET:
6336 charset_type = Qw32_charset_easteurope;
6337 break;
6338 case TURKISH_CHARSET:
6339 charset_type = Qw32_charset_turkish;
6340 break;
6341 case BALTIC_CHARSET:
6342 charset_type = Qw32_charset_baltic;
6343 break;
33d52f9c 6344 case RUSSIAN_CHARSET:
767b1ff0
JR
6345 charset_type = Qw32_charset_russian;
6346 break;
6347 case ARABIC_CHARSET:
6348 charset_type = Qw32_charset_arabic;
6349 break;
6350 case GREEK_CHARSET:
6351 charset_type = Qw32_charset_greek;
6352 break;
6353 case HEBREW_CHARSET:
6354 charset_type = Qw32_charset_hebrew;
6355 break;
6356 case VIETNAMESE_CHARSET:
6357 charset_type = Qw32_charset_vietnamese;
6358 break;
6359 case THAI_CHARSET:
6360 charset_type = Qw32_charset_thai;
6361 break;
6362 case MAC_CHARSET:
6363 charset_type = Qw32_charset_mac;
6364 break;
6365 case JOHAB_CHARSET:
6366 charset_type = Qw32_charset_johab;
6367 break;
4587b026
GV
6368#endif
6369
5ac45f98 6370#ifdef UNICODE_CHARSET
767b1ff0
JR
6371 case UNICODE_CHARSET:
6372 charset_type = Qw32_charset_unicode;
6373 break;
5ac45f98 6374#endif
767b1ff0
JR
6375 default:
6376 /* Encode numerical value of unknown charset. */
6377 sprintf (buf, "*-#%u", fncharset);
6378 return buf;
5ac45f98 6379 }
7d0393cf 6380
767b1ff0
JR
6381 {
6382 Lisp_Object rest;
6383 char * best_match = NULL;
6384
6385 /* Look through w32-charset-info-alist for the character set.
6386 Prefer ISO codepages, and prefer lower numbers in the ISO
6387 range. Only return charsets for codepages which are installed.
6388
6389 Format of each entry is
6390 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6391 */
6392 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6393 {
6394 char * x_charset;
6395 Lisp_Object w32_charset;
6396 Lisp_Object codepage;
6397
6398 Lisp_Object this_entry = XCAR (rest);
6399
6400 /* Skip invalid entries in alist. */
6401 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6402 || !CONSP (XCDR (this_entry))
6403 || !SYMBOLP (XCAR (XCDR (this_entry))))
6404 continue;
6405
d5db4077 6406 x_charset = SDATA (XCAR (this_entry));
767b1ff0
JR
6407 w32_charset = XCAR (XCDR (this_entry));
6408 codepage = XCDR (XCDR (this_entry));
6409
6410 /* Look for Same charset and a valid codepage (or non-int
6411 which means ignore). */
6412 if (w32_charset == charset_type
6413 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6414 || IsValidCodePage (XINT (codepage))))
6415 {
6416 /* If we don't have a match already, then this is the
6417 best. */
6418 if (!best_match)
6419 best_match = x_charset;
6420 /* If this is an ISO codepage, and the best so far isn't,
6421 then this is better. */
d84b082d
JR
6422 else if (strnicmp (best_match, "iso", 3) != 0
6423 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
6424 best_match = x_charset;
6425 /* If both are ISO8859 codepages, choose the one with the
6426 lowest number in the encoding field. */
d84b082d
JR
6427 else if (strnicmp (best_match, "iso8859-", 8) == 0
6428 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
6429 {
6430 int best_enc = atoi (best_match + 8);
6431 int this_enc = atoi (x_charset + 8);
6432 if (this_enc > 0 && this_enc < best_enc)
6433 best_match = x_charset;
7d0393cf 6434 }
767b1ff0
JR
6435 }
6436 }
6437
6438 /* If no match, encode the numeric value. */
6439 if (!best_match)
6440 {
6441 sprintf (buf, "*-#%u", fncharset);
6442 return buf;
6443 }
6444
5e905a57
JR
6445 strncpy(buf, best_match, 31);
6446 buf[31] = '\0';
767b1ff0
JR
6447 return buf;
6448 }
ee78dc32
GV
6449}
6450
dfff8a69 6451
d84b082d
JR
6452/* Return all the X charsets that map to a font. */
6453static Lisp_Object
6454w32_to_all_x_charsets (fncharset)
6455 int fncharset;
6456{
6457 static char buf[32];
6458 Lisp_Object charset_type;
6459 Lisp_Object retval = Qnil;
6460
6461 switch (fncharset)
6462 {
6463 case ANSI_CHARSET:
6464 /* Handle startup case of w32-charset-info-alist not
6465 being set up yet. */
6466 if (NILP(Vw32_charset_info_alist))
d86c35ee
JR
6467 return Fcons (build_string ("iso8859-1"), Qnil);
6468
d84b082d
JR
6469 charset_type = Qw32_charset_ansi;
6470 break;
6471 case DEFAULT_CHARSET:
6472 charset_type = Qw32_charset_default;
6473 break;
6474 case SYMBOL_CHARSET:
6475 charset_type = Qw32_charset_symbol;
6476 break;
6477 case SHIFTJIS_CHARSET:
6478 charset_type = Qw32_charset_shiftjis;
6479 break;
6480 case HANGEUL_CHARSET:
6481 charset_type = Qw32_charset_hangeul;
6482 break;
6483 case GB2312_CHARSET:
6484 charset_type = Qw32_charset_gb2312;
6485 break;
6486 case CHINESEBIG5_CHARSET:
6487 charset_type = Qw32_charset_chinesebig5;
6488 break;
6489 case OEM_CHARSET:
6490 charset_type = Qw32_charset_oem;
6491 break;
6492
6493 /* More recent versions of Windows (95 and NT4.0) define more
6494 character sets. */
6495#ifdef EASTEUROPE_CHARSET
6496 case EASTEUROPE_CHARSET:
6497 charset_type = Qw32_charset_easteurope;
6498 break;
6499 case TURKISH_CHARSET:
6500 charset_type = Qw32_charset_turkish;
6501 break;
6502 case BALTIC_CHARSET:
6503 charset_type = Qw32_charset_baltic;
6504 break;
6505 case RUSSIAN_CHARSET:
6506 charset_type = Qw32_charset_russian;
6507 break;
6508 case ARABIC_CHARSET:
6509 charset_type = Qw32_charset_arabic;
6510 break;
6511 case GREEK_CHARSET:
6512 charset_type = Qw32_charset_greek;
6513 break;
6514 case HEBREW_CHARSET:
6515 charset_type = Qw32_charset_hebrew;
6516 break;
6517 case VIETNAMESE_CHARSET:
6518 charset_type = Qw32_charset_vietnamese;
6519 break;
6520 case THAI_CHARSET:
6521 charset_type = Qw32_charset_thai;
6522 break;
6523 case MAC_CHARSET:
6524 charset_type = Qw32_charset_mac;
6525 break;
6526 case JOHAB_CHARSET:
6527 charset_type = Qw32_charset_johab;
6528 break;
6529#endif
6530
6531#ifdef UNICODE_CHARSET
6532 case UNICODE_CHARSET:
6533 charset_type = Qw32_charset_unicode;
6534 break;
6535#endif
6536 default:
6537 /* Encode numerical value of unknown charset. */
6538 sprintf (buf, "*-#%u", fncharset);
6539 return Fcons (build_string (buf), Qnil);
6540 }
7d0393cf 6541
d84b082d
JR
6542 {
6543 Lisp_Object rest;
6544 /* Look through w32-charset-info-alist for the character set.
6545 Only return charsets for codepages which are installed.
6546
6547 Format of each entry in Vw32_charset_info_alist is
6548 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6549 */
6550 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6551 {
6552 Lisp_Object x_charset;
6553 Lisp_Object w32_charset;
6554 Lisp_Object codepage;
6555
6556 Lisp_Object this_entry = XCAR (rest);
6557
6558 /* Skip invalid entries in alist. */
6559 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6560 || !CONSP (XCDR (this_entry))
6561 || !SYMBOLP (XCAR (XCDR (this_entry))))
6562 continue;
6563
6564 x_charset = XCAR (this_entry);
6565 w32_charset = XCAR (XCDR (this_entry));
6566 codepage = XCDR (XCDR (this_entry));
6567
6568 /* Look for Same charset and a valid codepage (or non-int
6569 which means ignore). */
6570 if (w32_charset == charset_type
6571 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6572 || IsValidCodePage (XINT (codepage))))
6573 {
6574 retval = Fcons (x_charset, retval);
6575 }
6576 }
6577
6578 /* If no match, encode the numeric value. */
6579 if (NILP (retval))
6580 {
6581 sprintf (buf, "*-#%u", fncharset);
6582 return Fcons (build_string (buf), Qnil);
6583 }
6584
6585 return retval;
6586 }
6587}
6588
dfff8a69
JR
6589/* Get the Windows codepage corresponding to the specified font. The
6590 charset info in the font name is used to look up
6591 w32-charset-to-codepage-alist. */
7d0393cf 6592int
dfff8a69
JR
6593w32_codepage_for_font (char *fontname)
6594{
767b1ff0
JR
6595 Lisp_Object codepage, entry;
6596 char *charset_str, *charset, *end;
dfff8a69 6597
767b1ff0 6598 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6599 return CP_DEFAULT;
6600
767b1ff0
JR
6601 /* Extract charset part of font string. */
6602 charset = xlfd_charset_of_font (fontname);
6603
6604 if (!charset)
ceb12877 6605 return CP_UNKNOWN;
767b1ff0 6606
8b77111c 6607 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6608 strcpy (charset_str, charset);
6609
8b77111c 6610#if 0
dfff8a69
JR
6611 /* Remove leading "*-". */
6612 if (strncmp ("*-", charset_str, 2) == 0)
6613 charset = charset_str + 2;
6614 else
8b77111c 6615#endif
dfff8a69
JR
6616 charset = charset_str;
6617
6618 /* Stop match at wildcard (including preceding '-'). */
6619 if (end = strchr (charset, '*'))
6620 {
6621 if (end > charset && *(end-1) == '-')
6622 end--;
6623 *end = '\0';
6624 }
6625
767b1ff0
JR
6626 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6627 if (NILP (entry))
ceb12877 6628 return CP_UNKNOWN;
767b1ff0
JR
6629
6630 codepage = Fcdr (Fcdr (entry));
6631
6632 if (NILP (codepage))
6633 return CP_8BIT;
6634 else if (XFASTINT (codepage) == XFASTINT (Qt))
6635 return CP_UNICODE;
6636 else if (INTEGERP (codepage))
dfff8a69
JR
6637 return XINT (codepage);
6638 else
ceb12877 6639 return CP_UNKNOWN;
dfff8a69
JR
6640}
6641
6642
7d0393cf 6643static BOOL
767b1ff0 6644w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6645 LOGFONT * lplogfont;
6646 char * lpxstr;
6647 int len;
767b1ff0 6648 char * specific_charset;
ee78dc32 6649{
6fc2811b 6650 char* fonttype;
f46e6225 6651 char *fontname;
3cb20f4a
RS
6652 char height_pixels[8];
6653 char height_dpi[8];
6654 char width_pixels[8];
4587b026 6655 char *fontname_dash;
ac849ba4
JR
6656 int display_resy = (int) one_w32_display_info.resy;
6657 int display_resx = (int) one_w32_display_info.resx;
f46e6225
GV
6658 int bufsz;
6659 struct coding_system coding;
3cb20f4a
RS
6660
6661 if (!lpxstr) abort ();
ee78dc32 6662
3cb20f4a
RS
6663 if (!lplogfont)
6664 return FALSE;
6665
6fc2811b
JR
6666 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6667 fonttype = "raster";
6668 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6669 fonttype = "outline";
6670 else
6671 fonttype = "unknown";
6672
1fa3a200 6673 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6674 &coding);
aab5ac44
KH
6675 coding.src_multibyte = 0;
6676 coding.dst_multibyte = 1;
f46e6225 6677 coding.mode |= CODING_MODE_LAST_BLOCK;
65413122
KH
6678 /* We explicitely disable composition handling because selection
6679 data should not contain any composition sequence. */
6680 coding.composing = COMPOSITION_DISABLED;
f46e6225
GV
6681 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6682
6683 fontname = alloca(sizeof(*fontname) * bufsz);
6684 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6685 strlen(lplogfont->lfFaceName), bufsz - 1);
6686 *(fontname + coding.produced) = '\0';
4587b026
GV
6687
6688 /* Replace dashes with underscores so the dashes are not
f46e6225 6689 misinterpreted. */
4587b026
GV
6690 fontname_dash = fontname;
6691 while (fontname_dash = strchr (fontname_dash, '-'))
6692 *fontname_dash = '_';
6693
3cb20f4a 6694 if (lplogfont->lfHeight)
ee78dc32 6695 {
3cb20f4a
RS
6696 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6697 sprintf (height_dpi, "%u",
33d52f9c 6698 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6699 }
6700 else
ee78dc32 6701 {
3cb20f4a
RS
6702 strcpy (height_pixels, "*");
6703 strcpy (height_dpi, "*");
ee78dc32 6704 }
3cb20f4a
RS
6705 if (lplogfont->lfWidth)
6706 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6707 else
6708 strcpy (width_pixels, "*");
6709
6710 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6711 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6712 fonttype, /* foundry */
4587b026
GV
6713 fontname, /* family */
6714 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6715 lplogfont->lfItalic?'i':'r', /* slant */
6716 /* setwidth name */
6717 /* add style name */
6718 height_pixels, /* pixel size */
6719 height_dpi, /* point size */
33d52f9c
GV
6720 display_resx, /* resx */
6721 display_resy, /* resy */
4587b026
GV
6722 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6723 ? 'p' : 'c', /* spacing */
6724 width_pixels, /* avg width */
767b1ff0 6725 specific_charset ? specific_charset
7d0393cf 6726 : w32_to_x_charset (lplogfont->lfCharSet)
767b1ff0 6727 /* charset registry and encoding */
3cb20f4a
RS
6728 );
6729
ee78dc32
GV
6730 lpxstr[len - 1] = 0; /* just to be sure */
6731 return (TRUE);
6732}
6733
7d0393cf 6734static BOOL
fbd6baed 6735x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6736 char * lpxstr;
6737 LOGFONT * lplogfont;
6738{
f46e6225
GV
6739 struct coding_system coding;
6740
ee78dc32 6741 if (!lplogfont) return (FALSE);
f46e6225 6742
ee78dc32 6743 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6744
1a292d24 6745 /* Set default value for each field. */
771c47d5 6746#if 1
ee78dc32
GV
6747 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6748 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6749 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6750#else
6751 /* go for maximum quality */
6752 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6753 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6754 lplogfont->lfQuality = PROOF_QUALITY;
6755#endif
6756
1a292d24
AI
6757 lplogfont->lfCharSet = DEFAULT_CHARSET;
6758 lplogfont->lfWeight = FW_DONTCARE;
6759 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6760
5ac45f98
GV
6761 if (!lpxstr)
6762 return FALSE;
6763
6764 /* Provide a simple escape mechanism for specifying Windows font names
6765 * directly -- if font spec does not beginning with '-', assume this
6766 * format:
6767 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6768 */
7d0393cf 6769
5ac45f98
GV
6770 if (*lpxstr == '-')
6771 {
33d52f9c
GV
6772 int fields, tem;
6773 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6774 width[10], resy[10], remainder[50];
5ac45f98 6775 char * encoding;
ac849ba4 6776 int dpi = (int) one_w32_display_info.resy;
5ac45f98
GV
6777
6778 fields = sscanf (lpxstr,
8b77111c 6779 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6780 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6781 if (fields == EOF)
6782 return (FALSE);
6783
6784 /* In the general case when wildcards cover more than one field,
6785 we don't know which field is which, so don't fill any in.
6786 However, we need to cope with this particular form, which is
6787 generated by font_list_1 (invoked by try_font_list):
6788 "-raster-6x10-*-gb2312*-*"
6789 and make sure to correctly parse the charset field. */
6790 if (fields == 3)
6791 {
6792 fields = sscanf (lpxstr,
6793 "-%*[^-]-%49[^-]-*-%49s",
6794 name, remainder);
6795 }
6796 else if (fields < 9)
6797 {
6798 fields = 0;
6799 remainder[0] = 0;
6800 }
6fc2811b 6801
5ac45f98
GV
6802 if (fields > 0 && name[0] != '*')
6803 {
8ea3e054
RS
6804 int bufsize;
6805 unsigned char *buf;
6806
f46e6225 6807 setup_coding_system
1fa3a200 6808 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6809 coding.src_multibyte = 1;
6810 coding.dst_multibyte = 1;
8ea3e054
RS
6811 bufsize = encoding_buffer_size (&coding, strlen (name));
6812 buf = (unsigned char *) alloca (bufsize);
f46e6225 6813 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6814 encode_coding (&coding, name, buf, strlen (name), bufsize);
6815 if (coding.produced >= LF_FACESIZE)
6816 coding.produced = LF_FACESIZE - 1;
6817 buf[coding.produced] = 0;
6818 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6819 }
6820 else
6821 {
6fc2811b 6822 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6823 }
6824
6825 fields--;
6826
fbd6baed 6827 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6828
6829 fields--;
6830
c8874f14 6831 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6832
6833 fields--;
6834
6835 if (fields > 0 && pixels[0] != '*')
6836 lplogfont->lfHeight = atoi (pixels);
6837
6838 fields--;
5ac45f98 6839 fields--;
33d52f9c
GV
6840 if (fields > 0 && resy[0] != '*')
6841 {
6fc2811b 6842 tem = atoi (resy);
33d52f9c
GV
6843 if (tem > 0) dpi = tem;
6844 }
5ac45f98 6845
33d52f9c
GV
6846 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6847 lplogfont->lfHeight = atoi (height) * dpi / 720;
6848
6849 if (fields > 0)
5ac45f98
GV
6850 lplogfont->lfPitchAndFamily =
6851 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6852
6853 fields--;
6854
6855 if (fields > 0 && width[0] != '*')
6856 lplogfont->lfWidth = atoi (width) / 10;
6857
6858 fields--;
6859
4587b026 6860 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6861 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6862 {
5ac45f98
GV
6863 int len = strlen (remainder);
6864 if (len > 0 && remainder[len-1] == '-')
6865 remainder[len-1] = 0;
ee78dc32 6866 }
5ac45f98 6867 encoding = remainder;
8b77111c 6868#if 0
5ac45f98
GV
6869 if (strncmp (encoding, "*-", 2) == 0)
6870 encoding += 2;
8b77111c
AI
6871#endif
6872 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6873 }
6874 else
6875 {
6876 int fields;
6877 char name[100], height[10], width[10], weight[20];
a1a80b40 6878
5ac45f98
GV
6879 fields = sscanf (lpxstr,
6880 "%99[^:]:%9[^:]:%9[^:]:%19s",
6881 name, height, width, weight);
6882
6883 if (fields == EOF) return (FALSE);
6884
6885 if (fields > 0)
6886 {
6887 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6888 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6889 }
6890 else
6891 {
6892 lplogfont->lfFaceName[0] = 0;
6893 }
6894
6895 fields--;
6896
6897 if (fields > 0)
6898 lplogfont->lfHeight = atoi (height);
6899
6900 fields--;
6901
6902 if (fields > 0)
6903 lplogfont->lfWidth = atoi (width);
6904
6905 fields--;
6906
fbd6baed 6907 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6908 }
6909
6910 /* This makes TrueType fonts work better. */
6911 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6912
ee78dc32
GV
6913 return (TRUE);
6914}
6915
d88c567c
JR
6916/* Strip the pixel height and point height from the given xlfd, and
6917 return the pixel height. If no pixel height is specified, calculate
6918 one from the point height, or if that isn't defined either, return
6919 0 (which usually signifies a scalable font).
6920*/
8edb0a6f
JR
6921static int
6922xlfd_strip_height (char *fontname)
d88c567c 6923{
8edb0a6f 6924 int pixel_height, field_number;
d88c567c
JR
6925 char *read_from, *write_to;
6926
6927 xassert (fontname);
6928
6929 pixel_height = field_number = 0;
6930 write_to = NULL;
6931
6932 /* Look for height fields. */
6933 for (read_from = fontname; *read_from; read_from++)
6934 {
6935 if (*read_from == '-')
6936 {
6937 field_number++;
6938 if (field_number == 7) /* Pixel height. */
6939 {
6940 read_from++;
6941 write_to = read_from;
6942
6943 /* Find end of field. */
6944 for (;*read_from && *read_from != '-'; read_from++)
6945 ;
6946
6947 /* Split the fontname at end of field. */
6948 if (*read_from)
6949 {
6950 *read_from = '\0';
6951 read_from++;
6952 }
6953 pixel_height = atoi (write_to);
6954 /* Blank out field. */
6955 if (read_from > write_to)
6956 {
6957 *write_to = '-';
6958 write_to++;
6959 }
767b1ff0 6960 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6961 return now. */
6962 else
6963 return pixel_height;
6964
6965 /* If we got a pixel height, the point height can be
6966 ignored. Just blank it out and break now. */
6967 if (pixel_height)
6968 {
6969 /* Find end of point size field. */
6970 for (; *read_from && *read_from != '-'; read_from++)
6971 ;
6972
6973 if (*read_from)
6974 read_from++;
6975
6976 /* Blank out the point size field. */
6977 if (read_from > write_to)
6978 {
6979 *write_to = '-';
6980 write_to++;
6981 }
6982 else
6983 return pixel_height;
6984
6985 break;
6986 }
6987 /* If the point height is already blank, break now. */
6988 if (*read_from == '-')
6989 {
6990 read_from++;
6991 break;
6992 }
6993 }
6994 else if (field_number == 8)
6995 {
6996 /* If we didn't get a pixel height, try to get the point
6997 height and convert that. */
6998 int point_size;
6999 char *point_size_start = read_from++;
7000
7001 /* Find end of field. */
7002 for (; *read_from && *read_from != '-'; read_from++)
7003 ;
7004
7005 if (*read_from)
7006 {
7007 *read_from = '\0';
7008 read_from++;
7009 }
7010
7011 point_size = atoi (point_size_start);
7012
7013 /* Convert to pixel height. */
7014 pixel_height = point_size
7015 * one_w32_display_info.height_in / 720;
7016
7017 /* Blank out this field and break. */
7018 *write_to = '-';
7019 write_to++;
7020 break;
7021 }
7022 }
7023 }
7024
7025 /* Shift the rest of the font spec into place. */
7026 if (write_to && read_from > write_to)
7027 {
7028 for (; *read_from; read_from++, write_to++)
7029 *write_to = *read_from;
7030 *write_to = '\0';
7031 }
7032
7033 return pixel_height;
7034}
7035
6fc2811b 7036/* Assume parameter 1 is fully qualified, no wildcards. */
7d0393cf 7037static BOOL
6fc2811b
JR
7038w32_font_match (fontname, pattern)
7039 char * fontname;
7040 char * pattern;
ee78dc32 7041{
e7c72122 7042 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 7043 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 7044 char *ptr;
ee78dc32 7045
d88c567c
JR
7046 /* Copy fontname so we can modify it during comparison. */
7047 strcpy (font_name_copy, fontname);
7048
6fc2811b
JR
7049 ptr = regex;
7050 *ptr++ = '^';
ee78dc32 7051
6fc2811b
JR
7052 /* Turn pattern into a regexp and do a regexp match. */
7053 for (; *pattern; pattern++)
7054 {
7055 if (*pattern == '?')
7056 *ptr++ = '.';
7057 else if (*pattern == '*')
7058 {
7059 *ptr++ = '.';
7060 *ptr++ = '*';
7061 }
33d52f9c 7062 else
6fc2811b 7063 *ptr++ = *pattern;
ee78dc32 7064 }
6fc2811b
JR
7065 *ptr = '$';
7066 *(ptr + 1) = '\0';
7067
d88c567c
JR
7068 /* Strip out font heights and compare them seperately, since
7069 rounding error can cause mismatches. This also allows a
7070 comparison between a font that declares only a pixel height and a
7071 pattern that declares the point height.
7072 */
7073 {
7074 int font_height, pattern_height;
7075
7076 font_height = xlfd_strip_height (font_name_copy);
7077 pattern_height = xlfd_strip_height (regex);
7078
7079 /* Compare now, and don't bother doing expensive regexp matching
7080 if the heights differ. */
7081 if (font_height && pattern_height && (font_height != pattern_height))
7082 return FALSE;
7083 }
7084
6fc2811b 7085 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 7086 font_name_copy) >= 0);
ee78dc32
GV
7087}
7088
5ca0cd71
GV
7089/* Callback functions, and a structure holding info they need, for
7090 listing system fonts on W32. We need one set of functions to do the
7091 job properly, but these don't work on NT 3.51 and earlier, so we
7092 have a second set which don't handle character sets properly to
7093 fall back on.
7094
7095 In both cases, there are two passes made. The first pass gets one
7096 font from each family, the second pass lists all the fonts from
7097 each family. */
7098
7d0393cf 7099typedef struct enumfont_t
ee78dc32
GV
7100{
7101 HDC hdc;
7102 int numFonts;
3cb20f4a 7103 LOGFONT logfont;
ee78dc32 7104 XFontStruct *size_ref;
23afac8f 7105 Lisp_Object pattern;
d84b082d 7106 Lisp_Object list;
ee78dc32
GV
7107} enumfont_t;
7108
d84b082d
JR
7109
7110static void
7111enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7112
7113
7d0393cf 7114static int CALLBACK
ee78dc32
GV
7115enum_font_cb2 (lplf, lptm, FontType, lpef)
7116 ENUMLOGFONT * lplf;
7117 NEWTEXTMETRIC * lptm;
7118 int FontType;
7119 enumfont_t * lpef;
7120{
66895301
JR
7121 /* Ignore struck out and underlined versions of fonts. */
7122 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7123 return 1;
7124
7125 /* Only return fonts with names starting with @ if they were
7126 explicitly specified, since Microsoft uses an initial @ to
7127 denote fonts for vertical writing, without providing a more
7128 convenient way of identifying them. */
7129 if (lplf->elfLogFont.lfFaceName[0] == '@'
7130 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
7131 return 1;
7132
4587b026
GV
7133 /* Check that the character set matches if it was specified */
7134 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7135 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 7136 return 1;
4587b026 7137
6358474d
JR
7138 if (FontType == RASTER_FONTTYPE)
7139 {
7140 /* DBCS raster fonts have problems displaying, so skip them. */
7141 int charset = lplf->elfLogFont.lfCharSet;
7142 if (charset == SHIFTJIS_CHARSET
7143 || charset == HANGEUL_CHARSET
7144 || charset == CHINESEBIG5_CHARSET
7145 || charset == GB2312_CHARSET
7146#ifdef JOHAB_CHARSET
7147 || charset == JOHAB_CHARSET
7148#endif
7149 )
7150 return 1;
7151 }
7152
ee78dc32
GV
7153 {
7154 char buf[100];
4587b026 7155 Lisp_Object width = Qnil;
d84b082d 7156 Lisp_Object charset_list = Qnil;
767b1ff0 7157 char *charset = NULL;
ee78dc32 7158
6fc2811b
JR
7159 /* Truetype fonts do not report their true metrics until loaded */
7160 if (FontType != RASTER_FONTTYPE)
3cb20f4a 7161 {
23afac8f 7162 if (!NILP (lpef->pattern))
6fc2811b
JR
7163 {
7164 /* Scalable fonts are as big as you want them to be. */
7165 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7166 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7167 width = make_number (lpef->logfont.lfWidth);
7168 }
7169 else
7170 {
7171 lplf->elfLogFont.lfHeight = 0;
7172 lplf->elfLogFont.lfWidth = 0;
7173 }
3cb20f4a 7174 }
6fc2811b 7175
f46e6225
GV
7176 /* Make sure the height used here is the same as everywhere
7177 else (ie character height, not cell height). */
6fc2811b
JR
7178 if (lplf->elfLogFont.lfHeight > 0)
7179 {
7180 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7181 if (FontType == RASTER_FONTTYPE)
7182 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7183 else
7184 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7185 }
4587b026 7186
23afac8f 7187 if (!NILP (lpef->pattern))
767b1ff0 7188 {
d5db4077 7189 charset = xlfd_charset_of_font (SDATA (lpef->pattern));
767b1ff0 7190
644cefdf
JR
7191 /* We already checked charsets above, but DEFAULT_CHARSET
7192 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7193 if (charset
7194 && strncmp (charset, "*-*", 3) != 0
7195 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7196 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7197 return 1;
767b1ff0
JR
7198 }
7199
d84b082d
JR
7200 if (charset)
7201 charset_list = Fcons (build_string (charset), Qnil);
7202 else
7203 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 7204
d84b082d
JR
7205 /* Loop through the charsets. */
7206 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 7207 {
d84b082d 7208 Lisp_Object this_charset = Fcar (charset_list);
d5db4077 7209 charset = SDATA (this_charset);
d84b082d
JR
7210
7211 /* List bold and italic variations if w32-enable-synthesized-fonts
7212 is non-nil and this is a plain font. */
7213 if (w32_enable_synthesized_fonts
7214 && lplf->elfLogFont.lfWeight == FW_NORMAL
7215 && lplf->elfLogFont.lfItalic == FALSE)
7216 {
7217 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7218 charset, width);
7219 /* bold. */
7220 lplf->elfLogFont.lfWeight = FW_BOLD;
7221 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7222 charset, width);
7223 /* bold italic. */
7224 lplf->elfLogFont.lfItalic = TRUE;
7225 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7226 charset, width);
7227 /* italic. */
7228 lplf->elfLogFont.lfWeight = FW_NORMAL;
7229 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7230 charset, width);
7231 }
7232 else
7233 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7234 charset, width);
ee78dc32
GV
7235 }
7236 }
6fc2811b 7237
5e905a57 7238 return 1;
ee78dc32
GV
7239}
7240
d84b082d
JR
7241static void
7242enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7243 enumfont_t * lpef;
7244 LOGFONT * logfont;
7245 char * match_charset;
7246 Lisp_Object width;
7247{
7248 char buf[100];
7249
7250 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7251 return;
7252
23afac8f 7253 if (NILP (lpef->pattern)
d5db4077 7254 || w32_font_match (buf, SDATA (lpef->pattern)))
d84b082d
JR
7255 {
7256 /* Check if we already listed this font. This may happen if
7257 w32_enable_synthesized_fonts is non-nil, and there are real
7258 bold and italic versions of the font. */
7259 Lisp_Object font_name = build_string (buf);
7260 if (NILP (Fmember (font_name, lpef->list)))
7261 {
23afac8f
JR
7262 Lisp_Object entry = Fcons (font_name, width);
7263 lpef->list = Fcons (entry, lpef->list);
d84b082d
JR
7264 lpef->numFonts++;
7265 }
7266 }
7267}
7268
7269
7d0393cf 7270static int CALLBACK
ee78dc32
GV
7271enum_font_cb1 (lplf, lptm, FontType, lpef)
7272 ENUMLOGFONT * lplf;
7273 NEWTEXTMETRIC * lptm;
7274 int FontType;
7275 enumfont_t * lpef;
7276{
7277 return EnumFontFamilies (lpef->hdc,
7278 lplf->elfLogFont.lfFaceName,
7279 (FONTENUMPROC) enum_font_cb2,
7280 (LPARAM) lpef);
7281}
7282
7283
8edb0a6f 7284static int CALLBACK
5ca0cd71
GV
7285enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7286 ENUMLOGFONTEX * lplf;
7287 NEWTEXTMETRICEX * lptm;
7288 int font_type;
7289 enumfont_t * lpef;
7290{
7291 /* We are not interested in the extra info we get back from the 'Ex
7292 version - only the fact that we get character set variations
7293 enumerated seperately. */
7294 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7295 font_type, lpef);
7296}
7297
8edb0a6f 7298static int CALLBACK
5ca0cd71
GV
7299enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7300 ENUMLOGFONTEX * lplf;
7301 NEWTEXTMETRICEX * lptm;
7302 int font_type;
7303 enumfont_t * lpef;
7304{
7305 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7306 FARPROC enum_font_families_ex
7307 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7308 /* We don't really expect EnumFontFamiliesEx to disappear once we
7309 get here, so don't bother handling it gracefully. */
7310 if (enum_font_families_ex == NULL)
7311 error ("gdi32.dll has disappeared!");
7312 return enum_font_families_ex (lpef->hdc,
7313 &lplf->elfLogFont,
7314 (FONTENUMPROC) enum_fontex_cb2,
7315 (LPARAM) lpef, 0);
7316}
7317
4587b026
GV
7318/* Interface to fontset handler. (adapted from mw32font.c in Meadow
7319 and xterm.c in Emacs 20.3) */
7320
8edb0a6f 7321static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
7322{
7323 char *fontname, *ptnstr;
7324 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 7325 int n_fonts = 0;
33d52f9c
GV
7326
7327 list = Vw32_bdf_filename_alist;
d5db4077 7328 ptnstr = SDATA (pattern);
33d52f9c 7329
8e713be6 7330 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 7331 {
8e713be6 7332 tem = XCAR (list);
33d52f9c 7333 if (CONSP (tem))
d5db4077 7334 fontname = SDATA (XCAR (tem));
33d52f9c 7335 else if (STRINGP (tem))
d5db4077 7336 fontname = SDATA (tem);
33d52f9c
GV
7337 else
7338 continue;
7339
7340 if (w32_font_match (fontname, ptnstr))
5ca0cd71 7341 {
8e713be6 7342 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71 7343 n_fonts++;
bd11cc09 7344 if (max_names >= 0 && n_fonts >= max_names)
5ca0cd71
GV
7345 break;
7346 }
33d52f9c
GV
7347 }
7348
7349 return newlist;
7350}
7351
5ca0cd71 7352
4587b026
GV
7353/* Return a list of names of available fonts matching PATTERN on frame
7354 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7355 to be listed. Frame F NULL means we have not yet created any
7356 frame, which means we can't get proper size info, as we don't have
7357 a device context to use for GetTextMetrics.
bd11cc09
JR
7358 MAXNAMES sets a limit on how many fonts to match. If MAXNAMES is
7359 negative, then all matching fonts are returned. */
4587b026
GV
7360
7361Lisp_Object
dc220243
JR
7362w32_list_fonts (f, pattern, size, maxnames)
7363 struct frame *f;
7364 Lisp_Object pattern;
7365 int size;
7366 int maxnames;
4587b026 7367{
6fc2811b 7368 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 7369 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 7370 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 7371 int n_fonts = 0;
396594fe 7372
4587b026
GV
7373 patterns = Fassoc (pattern, Valternate_fontname_alist);
7374 if (NILP (patterns))
7375 patterns = Fcons (pattern, Qnil);
7376
8e713be6 7377 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
7378 {
7379 enumfont_t ef;
767b1ff0 7380 int codepage;
4587b026 7381
8e713be6 7382 tpat = XCAR (patterns);
4587b026 7383
767b1ff0
JR
7384 if (!STRINGP (tpat))
7385 continue;
7386
7387 /* Avoid expensive EnumFontFamilies functions if we are not
7388 going to be able to output one of these anyway. */
d5db4077 7389 codepage = w32_codepage_for_font (SDATA (tpat));
767b1ff0 7390 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7391 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7392 && !IsValidCodePage(codepage))
767b1ff0
JR
7393 continue;
7394
4587b026
GV
7395 /* See if we cached the result for this particular query.
7396 The cache is an alist of the form:
7397 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7398 */
8e713be6 7399 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7400 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7401 {
7402 list = Fcdr_safe (list);
7403 /* We have a cached list. Don't have to get the list again. */
7404 goto label_cached;
7405 }
7406
7407 BLOCK_INPUT;
7408 /* At first, put PATTERN in the cache. */
23afac8f
JR
7409 ef.pattern = tpat;
7410 ef.list = Qnil;
4587b026 7411 ef.numFonts = 0;
33d52f9c 7412
5ca0cd71
GV
7413 /* Use EnumFontFamiliesEx where it is available, as it knows
7414 about character sets. Fall back to EnumFontFamilies for
7415 older versions of NT that don't support the 'Ex function. */
d5db4077 7416 x_to_w32_font (SDATA (tpat), &ef.logfont);
4587b026 7417 {
5ca0cd71
GV
7418 LOGFONT font_match_pattern;
7419 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7420 FARPROC enum_font_families_ex
7421 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7422
7423 /* We do our own pattern matching so we can handle wildcards. */
7424 font_match_pattern.lfFaceName[0] = 0;
7425 font_match_pattern.lfPitchAndFamily = 0;
7426 /* We can use the charset, because if it is a wildcard it will
7427 be DEFAULT_CHARSET anyway. */
7428 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7429
33d52f9c 7430 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7431
5ca0cd71
GV
7432 if (enum_font_families_ex)
7433 enum_font_families_ex (ef.hdc,
7434 &font_match_pattern,
7435 (FONTENUMPROC) enum_fontex_cb1,
7436 (LPARAM) &ef, 0);
7437 else
7438 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7439 (LPARAM)&ef);
4587b026 7440
33d52f9c 7441 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7442 }
7443
7444 UNBLOCK_INPUT;
23afac8f 7445 list = ef.list;
4587b026
GV
7446
7447 /* Make a list of the fonts we got back.
7448 Store that in the font cache for the display. */
f3fbd155
KR
7449 XSETCDR (dpyinfo->name_list_element,
7450 Fcons (Fcons (tpat, list),
7451 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7452
7453 label_cached:
7454 if (NILP (list)) continue; /* Try the remaining alternatives. */
7455
7456 newlist = second_best = Qnil;
7457
7d0393cf 7458 /* Make a list of the fonts that have the right width. */
8e713be6 7459 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7460 {
7461 int found_size;
8e713be6 7462 tem = XCAR (list);
4587b026
GV
7463
7464 if (!CONSP (tem))
7465 continue;
8e713be6 7466 if (NILP (XCAR (tem)))
4587b026
GV
7467 continue;
7468 if (!size)
7469 {
8e713be6 7470 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71 7471 n_fonts++;
bd11cc09 7472 if (maxnames >= 0 && n_fonts >= maxnames)
5ca0cd71
GV
7473 break;
7474 else
7475 continue;
4587b026 7476 }
8e713be6 7477 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7478 {
7479 /* Since we don't yet know the size of the font, we must
7480 load it and try GetTextMetrics. */
4587b026
GV
7481 W32FontStruct thisinfo;
7482 LOGFONT lf;
7483 HDC hdc;
7484 HANDLE oldobj;
7485
d5db4077 7486 if (!x_to_w32_font (SDATA (XCAR (tem)), &lf))
4587b026
GV
7487 continue;
7488
7489 BLOCK_INPUT;
33d52f9c 7490 thisinfo.bdf = NULL;
4587b026
GV
7491 thisinfo.hfont = CreateFontIndirect (&lf);
7492 if (thisinfo.hfont == NULL)
7493 continue;
7494
7495 hdc = GetDC (dpyinfo->root_window);
7496 oldobj = SelectObject (hdc, thisinfo.hfont);
7497 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7498 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7499 else
f3fbd155 7500 XSETCDR (tem, make_number (0));
4587b026
GV
7501 SelectObject (hdc, oldobj);
7502 ReleaseDC (dpyinfo->root_window, hdc);
7503 DeleteObject(thisinfo.hfont);
7504 UNBLOCK_INPUT;
7505 }
8e713be6 7506 found_size = XINT (XCDR (tem));
4587b026 7507 if (found_size == size)
5ca0cd71 7508 {
8e713be6 7509 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71 7510 n_fonts++;
bd11cc09 7511 if (maxnames >= 0 && n_fonts >= maxnames)
5ca0cd71
GV
7512 break;
7513 }
4587b026
GV
7514 /* keep track of the closest matching size in case
7515 no exact match is found. */
7516 else if (found_size > 0)
7517 {
7518 if (NILP (second_best))
7519 second_best = tem;
7d0393cf 7520
4587b026
GV
7521 else if (found_size < size)
7522 {
8e713be6
KR
7523 if (XINT (XCDR (second_best)) > size
7524 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7525 second_best = tem;
7526 }
7527 else
7528 {
8e713be6
KR
7529 if (XINT (XCDR (second_best)) > size
7530 && XINT (XCDR (second_best)) >
4587b026
GV
7531 found_size)
7532 second_best = tem;
7533 }
7534 }
7535 }
7536
7537 if (!NILP (newlist))
7538 break;
7539 else if (!NILP (second_best))
7540 {
8e713be6 7541 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7542 break;
7543 }
7544 }
7545
33d52f9c 7546 /* Include any bdf fonts. */
bd11cc09 7547 if (n_fonts < maxnames || maxnames < 0)
33d52f9c
GV
7548 {
7549 Lisp_Object combined[2];
5ca0cd71 7550 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7551 combined[1] = newlist;
7552 newlist = Fnconc(2, combined);
7553 }
7554
4587b026
GV
7555 return newlist;
7556}
7557
5ca0cd71 7558
4587b026
GV
7559/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7560struct font_info *
7561w32_get_font_info (f, font_idx)
7562 FRAME_PTR f;
7563 int font_idx;
7564{
7565 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7566}
7567
7568
7569struct font_info*
7570w32_query_font (struct frame *f, char *fontname)
7571{
7572 int i;
7573 struct font_info *pfi;
7574
7575 pfi = FRAME_W32_FONT_TABLE (f);
7576
7577 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7578 {
7579 if (strcmp(pfi->name, fontname) == 0) return pfi;
7580 }
7581
7582 return NULL;
7583}
7584
7585/* Find a CCL program for a font specified by FONTP, and set the member
7586 `encoder' of the structure. */
7587
7588void
7589w32_find_ccl_program (fontp)
7590 struct font_info *fontp;
7591{
3545439c 7592 Lisp_Object list, elt;
4587b026 7593
8e713be6 7594 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7595 {
8e713be6 7596 elt = XCAR (list);
4587b026 7597 if (CONSP (elt)
8e713be6
KR
7598 && STRINGP (XCAR (elt))
7599 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7600 >= 0))
3545439c
KH
7601 break;
7602 }
7603 if (! NILP (list))
7604 {
17eedd00
KH
7605 struct ccl_program *ccl
7606 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7607
8e713be6 7608 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7609 xfree (ccl);
7610 else
7611 fontp->font_encoder = ccl;
4587b026
GV
7612 }
7613}
7614
7615\f
8edb0a6f
JR
7616/* Find BDF files in a specified directory. (use GCPRO when calling,
7617 as this calls lisp to get a directory listing). */
7618static Lisp_Object
7619w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7620{
7621 Lisp_Object filelist, list = Qnil;
7622 char fontname[100];
7623
7624 if (!STRINGP(directory))
7625 return Qnil;
7626
7627 filelist = Fdirectory_files (directory, Qt,
7628 build_string (".*\\.[bB][dD][fF]"), Qt);
7629
7630 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7631 {
7632 Lisp_Object filename = XCAR (filelist);
d5db4077 7633 if (w32_BDF_to_x_font (SDATA (filename), fontname, 100))
8edb0a6f
JR
7634 store_in_alist (&list, build_string (fontname), filename);
7635 }
7636 return list;
7637}
7638
6fc2811b
JR
7639DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7640 1, 1, 0,
b3700ae7
JR
7641 doc: /* Return a list of BDF fonts in DIR.
7642The list is suitable for appending to w32-bdf-filename-alist. Fonts
7643which do not contain an xlfd description will not be included in the
7644list. DIR may be a list of directories. */)
6fc2811b
JR
7645 (directory)
7646 Lisp_Object directory;
7647{
7648 Lisp_Object list = Qnil;
7649 struct gcpro gcpro1, gcpro2;
ee78dc32 7650
6fc2811b
JR
7651 if (!CONSP (directory))
7652 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7653
6fc2811b 7654 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7655 {
6fc2811b
JR
7656 Lisp_Object pair[2];
7657 pair[0] = list;
7658 pair[1] = Qnil;
7659 GCPRO2 (directory, list);
7660 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7661 list = Fnconc( 2, pair );
7662 UNGCPRO;
7663 }
7664 return list;
7665}
ee78dc32 7666
6fc2811b
JR
7667\f
7668DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7669 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7670 (color, frame)
7671 Lisp_Object color, frame;
7672{
7673 XColor foo;
7674 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7675
b7826503 7676 CHECK_STRING (color);
ee78dc32 7677
d5db4077 7678 if (w32_defined_color (f, SDATA (color), &foo, 0))
6fc2811b
JR
7679 return Qt;
7680 else
7681 return Qnil;
7682}
ee78dc32 7683
2d764c78 7684DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7685 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7686 (color, frame)
7687 Lisp_Object color, frame;
7688{
6fc2811b 7689 XColor foo;
ee78dc32
GV
7690 FRAME_PTR f = check_x_frame (frame);
7691
b7826503 7692 CHECK_STRING (color);
ee78dc32 7693
d5db4077 7694 if (w32_defined_color (f, SDATA (color), &foo, 0))
ee78dc32
GV
7695 {
7696 Lisp_Object rgb[3];
7697
6fc2811b
JR
7698 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7699 | GetRValue (foo.pixel));
7700 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7701 | GetGValue (foo.pixel));
7702 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7703 | GetBValue (foo.pixel));
ee78dc32
GV
7704 return Flist (3, rgb);
7705 }
7706 else
7707 return Qnil;
7708}
7709
2d764c78 7710DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7711 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7712 (display)
7713 Lisp_Object display;
7714{
fbd6baed 7715 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7716
7717 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7718 return Qnil;
7719
7720 return Qt;
7721}
7722
74e1aeec
JR
7723DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7724 Sx_display_grayscale_p, 0, 1, 0,
7725 doc: /* Return t if the X display supports shades of gray.
7726Note that color displays do support shades of gray.
7727The optional argument DISPLAY specifies which display to ask about.
7728DISPLAY should be either a frame or a display name (a string).
7729If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7730 (display)
7731 Lisp_Object display;
7732{
fbd6baed 7733 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7734
7735 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7736 return Qnil;
7737
7738 return Qt;
7739}
7740
74e1aeec
JR
7741DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7742 Sx_display_pixel_width, 0, 1, 0,
7743 doc: /* Returns the width in pixels of DISPLAY.
7744The optional argument DISPLAY specifies which display to ask about.
7745DISPLAY should be either a frame or a display name (a string).
7746If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7747 (display)
7748 Lisp_Object display;
7749{
fbd6baed 7750 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7751
7752 return make_number (dpyinfo->width);
7753}
7754
7755DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7756 Sx_display_pixel_height, 0, 1, 0,
7757 doc: /* Returns the height in pixels of DISPLAY.
7758The optional argument DISPLAY specifies which display to ask about.
7759DISPLAY should be either a frame or a display name (a string).
7760If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7761 (display)
7762 Lisp_Object display;
7763{
fbd6baed 7764 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7765
7766 return make_number (dpyinfo->height);
7767}
7768
7769DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7770 0, 1, 0,
7771 doc: /* Returns the number of bitplanes of DISPLAY.
7772The optional argument DISPLAY specifies which display to ask about.
7773DISPLAY should be either a frame or a display name (a string).
7774If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7775 (display)
7776 Lisp_Object display;
7777{
fbd6baed 7778 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7779
7780 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7781}
7782
7783DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7784 0, 1, 0,
7785 doc: /* Returns the number of color cells of DISPLAY.
7786The optional argument DISPLAY specifies which display to ask about.
7787DISPLAY should be either a frame or a display name (a string).
7788If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7789 (display)
7790 Lisp_Object display;
7791{
fbd6baed 7792 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7793 HDC hdc;
7794 int cap;
7795
5ac45f98
GV
7796 hdc = GetDC (dpyinfo->root_window);
7797 if (dpyinfo->has_palette)
7798 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7799 else
7800 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b 7801
007776bc
JB
7802 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7803 and because probably is more meaningful on Windows anyway */
abf8c61b 7804 if (cap < 0)
007776bc 7805 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
7d0393cf 7806
ee78dc32 7807 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 7808
ee78dc32
GV
7809 return make_number (cap);
7810}
7811
7812DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7813 Sx_server_max_request_size,
74e1aeec
JR
7814 0, 1, 0,
7815 doc: /* Returns the maximum request size of the server of DISPLAY.
7816The optional argument DISPLAY specifies which display to ask about.
7817DISPLAY should be either a frame or a display name (a string).
7818If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7819 (display)
7820 Lisp_Object display;
7821{
fbd6baed 7822 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7823
7824 return make_number (1);
7825}
7826
7827DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7828 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7829The optional argument DISPLAY specifies which display to ask about.
7830DISPLAY should be either a frame or a display name (a string).
7831If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7832 (display)
7833 Lisp_Object display;
7834{
dfff8a69 7835 return build_string ("Microsoft Corp.");
ee78dc32
GV
7836}
7837
7838DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7839 doc: /* Returns the version numbers of the server of DISPLAY.
7840The value is a list of three integers: the major and minor
7841version numbers, and the vendor-specific release
7842number. See also the function `x-server-vendor'.
7843
7844The optional argument DISPLAY specifies which display to ask about.
7845DISPLAY should be either a frame or a display name (a string).
7846If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7847 (display)
7848 Lisp_Object display;
7849{
fbd6baed 7850 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7851 Fcons (make_number (w32_minor_version),
7852 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7853}
7854
7855DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7856 doc: /* Returns the number of screens on the server of DISPLAY.
7857The optional argument DISPLAY specifies which display to ask about.
7858DISPLAY should be either a frame or a display name (a string).
7859If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7860 (display)
7861 Lisp_Object display;
7862{
ee78dc32
GV
7863 return make_number (1);
7864}
7865
74e1aeec
JR
7866DEFUN ("x-display-mm-height", Fx_display_mm_height,
7867 Sx_display_mm_height, 0, 1, 0,
7868 doc: /* Returns the height in millimeters of DISPLAY.
7869The optional argument DISPLAY specifies which display to ask about.
7870DISPLAY should be either a frame or a display name (a string).
7871If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7872 (display)
7873 Lisp_Object display;
7874{
fbd6baed 7875 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7876 HDC hdc;
7877 int cap;
7878
5ac45f98 7879 hdc = GetDC (dpyinfo->root_window);
7d0393cf 7880
ee78dc32 7881 cap = GetDeviceCaps (hdc, VERTSIZE);
7d0393cf 7882
ee78dc32 7883 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 7884
ee78dc32
GV
7885 return make_number (cap);
7886}
7887
7888DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7889 doc: /* Returns the width in millimeters of DISPLAY.
7890The optional argument DISPLAY specifies which display to ask about.
7891DISPLAY should be either a frame or a display name (a string).
7892If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7893 (display)
7894 Lisp_Object display;
7895{
fbd6baed 7896 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7897
7898 HDC hdc;
7899 int cap;
7900
5ac45f98 7901 hdc = GetDC (dpyinfo->root_window);
7d0393cf 7902
ee78dc32 7903 cap = GetDeviceCaps (hdc, HORZSIZE);
7d0393cf 7904
ee78dc32 7905 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 7906
ee78dc32
GV
7907 return make_number (cap);
7908}
7909
7910DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7911 Sx_display_backing_store, 0, 1, 0,
7912 doc: /* Returns an indication of whether DISPLAY does backing store.
7913The value may be `always', `when-mapped', or `not-useful'.
7914The optional argument DISPLAY specifies which display to ask about.
7915DISPLAY should be either a frame or a display name (a string).
7916If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7917 (display)
7918 Lisp_Object display;
7919{
7920 return intern ("not-useful");
7921}
7922
7923DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7924 Sx_display_visual_class, 0, 1, 0,
7925 doc: /* Returns the visual class of DISPLAY.
7926The value is one of the symbols `static-gray', `gray-scale',
7927`static-color', `pseudo-color', `true-color', or `direct-color'.
7928
7929The optional argument DISPLAY specifies which display to ask about.
7930DISPLAY should be either a frame or a display name (a string).
7931If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7932 (display)
7933 Lisp_Object display;
7934{
fbd6baed 7935 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7936 Lisp_Object result = Qnil;
ee78dc32 7937
abf8c61b
AI
7938 if (dpyinfo->has_palette)
7939 result = intern ("pseudo-color");
7940 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7941 result = intern ("static-grey");
7942 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7943 result = intern ("static-color");
7944 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7945 result = intern ("true-color");
ee78dc32 7946
abf8c61b 7947 return result;
ee78dc32
GV
7948}
7949
7950DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7951 Sx_display_save_under, 0, 1, 0,
7952 doc: /* Returns t if DISPLAY supports the save-under feature.
7953The optional argument DISPLAY specifies which display to ask about.
7954DISPLAY should be either a frame or a display name (a string).
7955If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7956 (display)
7957 Lisp_Object display;
7958{
6fc2811b
JR
7959 return Qnil;
7960}
7961\f
7962int
7963x_pixel_width (f)
7964 register struct frame *f;
7965{
7966 return PIXEL_WIDTH (f);
7967}
7968
7969int
7970x_pixel_height (f)
7971 register struct frame *f;
7972{
7973 return PIXEL_HEIGHT (f);
7974}
7975
7976int
7977x_char_width (f)
7978 register struct frame *f;
7979{
7980 return FONT_WIDTH (f->output_data.w32->font);
7981}
7982
7983int
7984x_char_height (f)
7985 register struct frame *f;
7986{
7987 return f->output_data.w32->line_height;
7988}
7989
7990int
7991x_screen_planes (f)
7992 register struct frame *f;
7993{
7994 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7995}
7996\f
7997/* Return the display structure for the display named NAME.
7998 Open a new connection if necessary. */
7999
8000struct w32_display_info *
8001x_display_info_for_name (name)
8002 Lisp_Object name;
8003{
8004 Lisp_Object names;
8005 struct w32_display_info *dpyinfo;
8006
b7826503 8007 CHECK_STRING (name);
6fc2811b
JR
8008
8009 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
8010 dpyinfo;
8011 dpyinfo = dpyinfo->next, names = XCDR (names))
8012 {
8013 Lisp_Object tem;
8014 tem = Fstring_equal (XCAR (XCAR (names)), name);
8015 if (!NILP (tem))
8016 return dpyinfo;
8017 }
8018
8019 /* Use this general default value to start with. */
8020 Vx_resource_name = Vinvocation_name;
8021
8022 validate_x_resource_name ();
8023
8024 dpyinfo = w32_term_init (name, (unsigned char *)0,
d5db4077 8025 (char *) SDATA (Vx_resource_name));
6fc2811b
JR
8026
8027 if (dpyinfo == 0)
d5db4077 8028 error ("Cannot connect to server %s", SDATA (name));
6fc2811b
JR
8029
8030 w32_in_use = 1;
8031 XSETFASTINT (Vwindow_system_version, 3);
8032
8033 return dpyinfo;
8034}
8035
8036DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
8037 1, 3, 0, doc: /* Open a connection to a server.
8038DISPLAY is the name of the display to connect to.
8039Optional second arg XRM-STRING is a string of resources in xrdb format.
8040If the optional third arg MUST-SUCCEED is non-nil,
8041terminate Emacs if we can't open the connection. */)
6fc2811b
JR
8042 (display, xrm_string, must_succeed)
8043 Lisp_Object display, xrm_string, must_succeed;
8044{
8045 unsigned char *xrm_option;
8046 struct w32_display_info *dpyinfo;
8047
74e1aeec
JR
8048 /* If initialization has already been done, return now to avoid
8049 overwriting critical parts of one_w32_display_info. */
8050 if (w32_in_use)
8051 return Qnil;
8052
b7826503 8053 CHECK_STRING (display);
6fc2811b 8054 if (! NILP (xrm_string))
b7826503 8055 CHECK_STRING (xrm_string);
6fc2811b
JR
8056
8057 if (! EQ (Vwindow_system, intern ("w32")))
8058 error ("Not using Microsoft Windows");
8059
8060 /* Allow color mapping to be defined externally; first look in user's
8061 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8062 {
8063 Lisp_Object color_file;
8064 struct gcpro gcpro1;
8065
8066 color_file = build_string("~/rgb.txt");
8067
8068 GCPRO1 (color_file);
8069
8070 if (NILP (Ffile_readable_p (color_file)))
8071 color_file =
8072 Fexpand_file_name (build_string ("rgb.txt"),
8073 Fsymbol_value (intern ("data-directory")));
8074
8075 Vw32_color_map = Fw32_load_color_file (color_file);
8076
8077 UNGCPRO;
8078 }
8079 if (NILP (Vw32_color_map))
8080 Vw32_color_map = Fw32_default_color_map ();
8081
8082 if (! NILP (xrm_string))
d5db4077 8083 xrm_option = (unsigned char *) SDATA (xrm_string);
6fc2811b
JR
8084 else
8085 xrm_option = (unsigned char *) 0;
8086
8087 /* Use this general default value to start with. */
8088 /* First remove .exe suffix from invocation-name - it looks ugly. */
8089 {
8090 char basename[ MAX_PATH ], *str;
8091
d5db4077 8092 strcpy (basename, SDATA (Vinvocation_name));
6fc2811b
JR
8093 str = strrchr (basename, '.');
8094 if (str) *str = 0;
8095 Vinvocation_name = build_string (basename);
8096 }
8097 Vx_resource_name = Vinvocation_name;
8098
8099 validate_x_resource_name ();
8100
8101 /* This is what opens the connection and sets x_current_display.
8102 This also initializes many symbols, such as those used for input. */
8103 dpyinfo = w32_term_init (display, xrm_option,
d5db4077 8104 (char *) SDATA (Vx_resource_name));
6fc2811b
JR
8105
8106 if (dpyinfo == 0)
8107 {
8108 if (!NILP (must_succeed))
8109 fatal ("Cannot connect to server %s.\n",
d5db4077 8110 SDATA (display));
6fc2811b 8111 else
d5db4077 8112 error ("Cannot connect to server %s", SDATA (display));
6fc2811b
JR
8113 }
8114
8115 w32_in_use = 1;
8116
8117 XSETFASTINT (Vwindow_system_version, 3);
8118 return Qnil;
8119}
8120
8121DEFUN ("x-close-connection", Fx_close_connection,
8122 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
8123 doc: /* Close the connection to DISPLAY's server.
8124For DISPLAY, specify either a frame or a display name (a string).
8125If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
8126 (display)
8127 Lisp_Object display;
8128{
8129 struct w32_display_info *dpyinfo = check_x_display_info (display);
8130 int i;
8131
8132 if (dpyinfo->reference_count > 0)
8133 error ("Display still has frames on it");
8134
8135 BLOCK_INPUT;
8136 /* Free the fonts in the font table. */
8137 for (i = 0; i < dpyinfo->n_fonts; i++)
8138 if (dpyinfo->font_table[i].name)
8139 {
126f2e35
JR
8140 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8141 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 8142 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
8143 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8144 }
8145 x_destroy_all_bitmaps (dpyinfo);
8146
8147 x_delete_display (dpyinfo);
8148 UNBLOCK_INPUT;
8149
8150 return Qnil;
8151}
8152
8153DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 8154 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
8155 ()
8156{
8157 Lisp_Object tail, result;
8158
8159 result = Qnil;
8160 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8161 result = Fcons (XCAR (XCAR (tail)), result);
8162
8163 return result;
8164}
8165
8166DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
8167 doc: /* This is a noop on W32 systems. */)
8168 (on, display)
8169 Lisp_Object display, on;
6fc2811b 8170{
6fc2811b
JR
8171 return Qnil;
8172}
8173
8174\f
6fc2811b
JR
8175/***********************************************************************
8176 Image types
8177 ***********************************************************************/
8178
8179/* Value is the number of elements of vector VECTOR. */
8180
8181#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8182
8183/* List of supported image types. Use define_image_type to add new
8184 types. Use lookup_image_type to find a type for a given symbol. */
8185
8186static struct image_type *image_types;
8187
6fc2811b
JR
8188/* The symbol `image' which is the car of the lists used to represent
8189 images in Lisp. */
8190
8191extern Lisp_Object Qimage;
8192
8193/* The symbol `xbm' which is used as the type symbol for XBM images. */
8194
8195Lisp_Object Qxbm;
8196
8197/* Keywords. */
8198
6fc2811b 8199extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
8200extern Lisp_Object QCdata, QCtype;
8201Lisp_Object QCascent, QCmargin, QCrelief;
a93f4566 8202Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 8203Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
8204
8205/* Other symbols. */
8206
3cf3436e 8207Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
8208
8209/* Time in seconds after which images should be removed from the cache
8210 if not displayed. */
8211
8212Lisp_Object Vimage_cache_eviction_delay;
8213
8214/* Function prototypes. */
8215
8216static void define_image_type P_ ((struct image_type *type));
8217static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8218static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8219static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 8220static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
8221static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8222 Lisp_Object));
8223
dfff8a69 8224
6fc2811b
JR
8225/* Define a new image type from TYPE. This adds a copy of TYPE to
8226 image_types and adds the symbol *TYPE->type to Vimage_types. */
8227
8228static void
8229define_image_type (type)
8230 struct image_type *type;
8231{
8232 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8233 The initialized data segment is read-only. */
8234 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8235 bcopy (type, p, sizeof *p);
8236 p->next = image_types;
8237 image_types = p;
8238 Vimage_types = Fcons (*p->type, Vimage_types);
8239}
8240
8241
8242/* Look up image type SYMBOL, and return a pointer to its image_type
8243 structure. Value is null if SYMBOL is not a known image type. */
8244
8245static INLINE struct image_type *
8246lookup_image_type (symbol)
8247 Lisp_Object symbol;
8248{
8249 struct image_type *type;
8250
8251 for (type = image_types; type; type = type->next)
8252 if (EQ (symbol, *type->type))
8253 break;
8254
8255 return type;
8256}
8257
8258
8259/* Value is non-zero if OBJECT is a valid Lisp image specification. A
8260 valid image specification is a list whose car is the symbol
8261 `image', and whose rest is a property list. The property list must
8262 contain a value for key `:type'. That value must be the name of a
8263 supported image type. The rest of the property list depends on the
8264 image type. */
8265
8266int
8267valid_image_p (object)
8268 Lisp_Object object;
8269{
8270 int valid_p = 0;
7d0393cf 8271
6fc2811b
JR
8272 if (CONSP (object) && EQ (XCAR (object), Qimage))
8273 {
3cf3436e
JR
8274 Lisp_Object tem;
8275
8276 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8277 if (EQ (XCAR (tem), QCtype))
8278 {
8279 tem = XCDR (tem);
8280 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8281 {
8282 struct image_type *type;
8283 type = lookup_image_type (XCAR (tem));
8284 if (type)
8285 valid_p = type->valid_p (object);
8286 }
8287
8288 break;
8289 }
6fc2811b
JR
8290 }
8291
8292 return valid_p;
8293}
8294
8295
8296/* Log error message with format string FORMAT and argument ARG.
8297 Signaling an error, e.g. when an image cannot be loaded, is not a
8298 good idea because this would interrupt redisplay, and the error
8299 message display would lead to another redisplay. This function
8300 therefore simply displays a message. */
8301
8302static void
8303image_error (format, arg1, arg2)
8304 char *format;
8305 Lisp_Object arg1, arg2;
8306{
8307 add_to_log (format, arg1, arg2);
8308}
8309
8310
8311\f
8312/***********************************************************************
8313 Image specifications
8314 ***********************************************************************/
8315
8316enum image_value_type
8317{
8318 IMAGE_DONT_CHECK_VALUE_TYPE,
8319 IMAGE_STRING_VALUE,
3cf3436e 8320 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
8321 IMAGE_SYMBOL_VALUE,
8322 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8323 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8324 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8325 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8326 IMAGE_INTEGER_VALUE,
8327 IMAGE_FUNCTION_VALUE,
8328 IMAGE_NUMBER_VALUE,
8329 IMAGE_BOOL_VALUE
8330};
8331
8332/* Structure used when parsing image specifications. */
8333
8334struct image_keyword
8335{
8336 /* Name of keyword. */
8337 char *name;
8338
8339 /* The type of value allowed. */
8340 enum image_value_type type;
8341
8342 /* Non-zero means key must be present. */
8343 int mandatory_p;
8344
8345 /* Used to recognize duplicate keywords in a property list. */
8346 int count;
8347
8348 /* The value that was found. */
8349 Lisp_Object value;
8350};
8351
8352
8353static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8354 int, Lisp_Object));
8355static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8356
8357
8358/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8359 has the format (image KEYWORD VALUE ...). One of the keyword/
8360 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8361 image_keywords structures of size NKEYWORDS describing other
8362 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8363
8364static int
8365parse_image_spec (spec, keywords, nkeywords, type)
8366 Lisp_Object spec;
8367 struct image_keyword *keywords;
8368 int nkeywords;
8369 Lisp_Object type;
8370{
8371 int i;
8372 Lisp_Object plist;
8373
8374 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8375 return 0;
8376
8377 plist = XCDR (spec);
8378 while (CONSP (plist))
8379 {
8380 Lisp_Object key, value;
8381
8382 /* First element of a pair must be a symbol. */
8383 key = XCAR (plist);
8384 plist = XCDR (plist);
8385 if (!SYMBOLP (key))
8386 return 0;
8387
8388 /* There must follow a value. */
8389 if (!CONSP (plist))
8390 return 0;
8391 value = XCAR (plist);
8392 plist = XCDR (plist);
8393
8394 /* Find key in KEYWORDS. Error if not found. */
8395 for (i = 0; i < nkeywords; ++i)
d5db4077 8396 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
6fc2811b
JR
8397 break;
8398
8399 if (i == nkeywords)
8400 continue;
8401
8402 /* Record that we recognized the keyword. If a keywords
8403 was found more than once, it's an error. */
8404 keywords[i].value = value;
8405 ++keywords[i].count;
7d0393cf 8406
6fc2811b
JR
8407 if (keywords[i].count > 1)
8408 return 0;
8409
8410 /* Check type of value against allowed type. */
8411 switch (keywords[i].type)
8412 {
8413 case IMAGE_STRING_VALUE:
8414 if (!STRINGP (value))
8415 return 0;
8416 break;
8417
3cf3436e
JR
8418 case IMAGE_STRING_OR_NIL_VALUE:
8419 if (!STRINGP (value) && !NILP (value))
8420 return 0;
8421 break;
8422
6fc2811b
JR
8423 case IMAGE_SYMBOL_VALUE:
8424 if (!SYMBOLP (value))
8425 return 0;
8426 break;
8427
8428 case IMAGE_POSITIVE_INTEGER_VALUE:
8429 if (!INTEGERP (value) || XINT (value) <= 0)
8430 return 0;
8431 break;
8432
8edb0a6f
JR
8433 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8434 if (INTEGERP (value) && XINT (value) >= 0)
8435 break;
8436 if (CONSP (value)
8437 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8438 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8439 break;
8440 return 0;
8441
dfff8a69
JR
8442 case IMAGE_ASCENT_VALUE:
8443 if (SYMBOLP (value) && EQ (value, Qcenter))
8444 break;
8445 else if (INTEGERP (value)
8446 && XINT (value) >= 0
8447 && XINT (value) <= 100)
8448 break;
8449 return 0;
8450
6fc2811b
JR
8451 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8452 if (!INTEGERP (value) || XINT (value) < 0)
8453 return 0;
8454 break;
8455
8456 case IMAGE_DONT_CHECK_VALUE_TYPE:
8457 break;
8458
8459 case IMAGE_FUNCTION_VALUE:
8460 value = indirect_function (value);
7d0393cf 8461 if (SUBRP (value)
6fc2811b
JR
8462 || COMPILEDP (value)
8463 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8464 break;
8465 return 0;
8466
8467 case IMAGE_NUMBER_VALUE:
8468 if (!INTEGERP (value) && !FLOATP (value))
8469 return 0;
8470 break;
8471
8472 case IMAGE_INTEGER_VALUE:
8473 if (!INTEGERP (value))
8474 return 0;
8475 break;
8476
8477 case IMAGE_BOOL_VALUE:
8478 if (!NILP (value) && !EQ (value, Qt))
8479 return 0;
8480 break;
8481
8482 default:
8483 abort ();
8484 break;
8485 }
8486
8487 if (EQ (key, QCtype) && !EQ (type, value))
8488 return 0;
8489 }
8490
8491 /* Check that all mandatory fields are present. */
8492 for (i = 0; i < nkeywords; ++i)
8493 if (keywords[i].mandatory_p && keywords[i].count == 0)
8494 return 0;
8495
8496 return NILP (plist);
8497}
8498
8499
8500/* Return the value of KEY in image specification SPEC. Value is nil
8501 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8502 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8503
8504static Lisp_Object
8505image_spec_value (spec, key, found)
8506 Lisp_Object spec, key;
8507 int *found;
8508{
8509 Lisp_Object tail;
7d0393cf 8510
6fc2811b
JR
8511 xassert (valid_image_p (spec));
8512
8513 for (tail = XCDR (spec);
8514 CONSP (tail) && CONSP (XCDR (tail));
8515 tail = XCDR (XCDR (tail)))
8516 {
8517 if (EQ (XCAR (tail), key))
8518 {
8519 if (found)
8520 *found = 1;
8521 return XCAR (XCDR (tail));
8522 }
8523 }
7d0393cf 8524
6fc2811b
JR
8525 if (found)
8526 *found = 0;
8527 return Qnil;
8528}
7d0393cf 8529
6fc2811b 8530
ac849ba4
JR
8531DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8532 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8533PIXELS non-nil means return the size in pixels, otherwise return the
8534size in canonical character units.
8535FRAME is the frame on which the image will be displayed. FRAME nil
8536or omitted means use the selected frame. */)
8537 (spec, pixels, frame)
8538 Lisp_Object spec, pixels, frame;
8539{
8540 Lisp_Object size;
8541
8542 size = Qnil;
8543 if (valid_image_p (spec))
8544 {
8545 struct frame *f = check_x_frame (frame);
8546 int id = lookup_image (f, spec);
8547 struct image *img = IMAGE_FROM_ID (f, id);
8548 int width = img->width + 2 * img->hmargin;
8549 int height = img->height + 2 * img->vmargin;
7d0393cf 8550
ac849ba4
JR
8551 if (NILP (pixels))
8552 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8553 make_float ((double) height / CANON_Y_UNIT (f)));
8554 else
8555 size = Fcons (make_number (width), make_number (height));
8556 }
8557 else
8558 error ("Invalid image specification");
8559
8560 return size;
8561}
8562
8563
8564DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8565 doc: /* Return t if image SPEC has a mask bitmap.
8566FRAME is the frame on which the image will be displayed. FRAME nil
8567or omitted means use the selected frame. */)
8568 (spec, frame)
8569 Lisp_Object spec, frame;
8570{
8571 Lisp_Object mask;
8572
8573 mask = Qnil;
8574 if (valid_image_p (spec))
8575 {
8576 struct frame *f = check_x_frame (frame);
8577 int id = lookup_image (f, spec);
8578 struct image *img = IMAGE_FROM_ID (f, id);
8579 if (img->mask)
8580 mask = Qt;
8581 }
8582 else
8583 error ("Invalid image specification");
8584
8585 return mask;
8586}
6fc2811b
JR
8587
8588\f
8589/***********************************************************************
8590 Image type independent image structures
8591 ***********************************************************************/
8592
8593static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8594static void free_image P_ ((struct frame *f, struct image *img));
197edd35 8595static void x_destroy_x_image P_ ((XImage *));
6fc2811b
JR
8596
8597
8598/* Allocate and return a new image structure for image specification
8599 SPEC. SPEC has a hash value of HASH. */
8600
8601static struct image *
8602make_image (spec, hash)
8603 Lisp_Object spec;
8604 unsigned hash;
8605{
8606 struct image *img = (struct image *) xmalloc (sizeof *img);
7d0393cf 8607
6fc2811b
JR
8608 xassert (valid_image_p (spec));
8609 bzero (img, sizeof *img);
8610 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8611 xassert (img->type != NULL);
8612 img->spec = spec;
8613 img->data.lisp_val = Qnil;
8614 img->ascent = DEFAULT_IMAGE_ASCENT;
8615 img->hash = hash;
8616 return img;
8617}
8618
8619
8620/* Free image IMG which was used on frame F, including its resources. */
8621
8622static void
8623free_image (f, img)
8624 struct frame *f;
8625 struct image *img;
8626{
8627 if (img)
8628 {
8629 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8630
8631 /* Remove IMG from the hash table of its cache. */
8632 if (img->prev)
8633 img->prev->next = img->next;
8634 else
8635 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8636
8637 if (img->next)
8638 img->next->prev = img->prev;
8639
8640 c->images[img->id] = NULL;
8641
8642 /* Free resources, then free IMG. */
8643 img->type->free (f, img);
8644 xfree (img);
8645 }
8646}
8647
8648
8649/* Prepare image IMG for display on frame F. Must be called before
8650 drawing an image. */
8651
8652void
8653prepare_image_for_display (f, img)
8654 struct frame *f;
8655 struct image *img;
8656{
8657 EMACS_TIME t;
8658
8659 /* We're about to display IMG, so set its timestamp to `now'. */
8660 EMACS_GET_TIME (t);
8661 img->timestamp = EMACS_SECS (t);
8662
8663 /* If IMG doesn't have a pixmap yet, load it now, using the image
8664 type dependent loader function. */
8665 if (img->pixmap == 0 && !img->load_failed_p)
8666 img->load_failed_p = img->type->load (f, img) == 0;
8667}
7d0393cf 8668
6fc2811b 8669
dfff8a69
JR
8670/* Value is the number of pixels for the ascent of image IMG when
8671 drawn in face FACE. */
8672
8673int
8674image_ascent (img, face)
8675 struct image *img;
8676 struct face *face;
8677{
8edb0a6f 8678 int height = img->height + img->vmargin;
dfff8a69
JR
8679 int ascent;
8680
8681 if (img->ascent == CENTERED_IMAGE_ASCENT)
8682 {
8683 if (face->font)
8684 ascent = height / 2 - (FONT_DESCENT(face->font)
8685 - FONT_BASE(face->font)) / 2;
8686 else
8687 ascent = height / 2;
8688 }
8689 else
ac849ba4 8690 ascent = (int) (height * img->ascent / 100.0);
dfff8a69
JR
8691
8692 return ascent;
8693}
8694
8695
6fc2811b 8696\f
a05e2bae
JR
8697/* Image background colors. */
8698
ac849ba4
JR
8699/* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8700 context with the bitmap selected. */
8701static COLORREF
197edd35
JR
8702four_corners_best (img_dc, width, height)
8703 HDC img_dc;
a05e2bae
JR
8704 unsigned long width, height;
8705{
ac849ba4 8706 COLORREF corners[4], best;
a05e2bae
JR
8707 int i, best_count;
8708
197edd35
JR
8709 /* Get the colors at the corners of img_dc. */
8710 corners[0] = GetPixel (img_dc, 0, 0);
8711 corners[1] = GetPixel (img_dc, width - 1, 0);
8712 corners[2] = GetPixel (img_dc, width - 1, height - 1);
8713 corners[3] = GetPixel (img_dc, 0, height - 1);
a05e2bae
JR
8714
8715 /* Choose the most frequently found color as background. */
8716 for (i = best_count = 0; i < 4; ++i)
8717 {
8718 int j, n;
7d0393cf 8719
a05e2bae
JR
8720 for (j = n = 0; j < 4; ++j)
8721 if (corners[i] == corners[j])
8722 ++n;
8723
8724 if (n > best_count)
8725 best = corners[i], best_count = n;
8726 }
8727
8728 return best;
a05e2bae
JR
8729}
8730
8731/* Return the `background' field of IMG. If IMG doesn't have one yet,
197edd35
JR
8732 it is guessed heuristically. If non-zero, IMG_DC is an existing
8733 device context with the image selected to use for the heuristic. */
a05e2bae
JR
8734
8735unsigned long
197edd35 8736image_background (img, f, img_dc)
a05e2bae
JR
8737 struct image *img;
8738 struct frame *f;
197edd35 8739 HDC img_dc;
a05e2bae
JR
8740{
8741 if (! img->background_valid)
8742 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8743 {
197edd35
JR
8744 int free_ximg = !img_dc;
8745 HGDIOBJ prev;
8746
8747 if (free_ximg)
8748 {
8749 HDC frame_dc = get_frame_dc (f);
8750 img_dc = CreateCompatibleDC (frame_dc);
8751 release_frame_dc (f, frame_dc);
a05e2bae 8752
197edd35
JR
8753 prev = SelectObject (img_dc, img->pixmap);
8754 }
a05e2bae 8755
197edd35 8756 img->background = four_corners_best (img_dc, img->width, img->height);
a05e2bae
JR
8757
8758 if (free_ximg)
197edd35
JR
8759 {
8760 SelectObject (img_dc, prev);
8761 DeleteDC (img_dc);
8762 }
a05e2bae
JR
8763
8764 img->background_valid = 1;
a05e2bae
JR
8765 }
8766
8767 return img->background;
8768}
8769
8770/* Return the `background_transparent' field of IMG. If IMG doesn't
8771 have one yet, it is guessed heuristically. If non-zero, MASK is an
8772 existing XImage object to use for the heuristic. */
8773
8774int
8775image_background_transparent (img, f, mask)
8776 struct image *img;
8777 struct frame *f;
197edd35 8778 HDC mask;
a05e2bae
JR
8779{
8780 if (! img->background_transparent_valid)
8781 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8782 {
a05e2bae
JR
8783 if (img->mask)
8784 {
8785 int free_mask = !mask;
197edd35 8786 HGDIOBJ prev;
a05e2bae 8787
197edd35
JR
8788 if (free_mask)
8789 {
8790 HDC frame_dc = get_frame_dc (f);
8791 mask = CreateCompatibleDC (frame_dc);
8792 release_frame_dc (f, frame_dc);
8793
c922a224 8794 prev = SelectObject (mask, img->mask);
197edd35 8795 }
a05e2bae
JR
8796
8797 img->background_transparent
8798 = !four_corners_best (mask, img->width, img->height);
8799
8800 if (free_mask)
197edd35
JR
8801 {
8802 SelectObject (mask, prev);
8803 DeleteDC (mask);
8804 }
a05e2bae
JR
8805 }
8806 else
a05e2bae
JR
8807 img->background_transparent = 0;
8808
8809 img->background_transparent_valid = 1;
8810 }
8811
8812 return img->background_transparent;
8813}
8814
8815\f
6fc2811b
JR
8816/***********************************************************************
8817 Helper functions for X image types
8818 ***********************************************************************/
8819
a05e2bae
JR
8820static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8821 int, int));
6fc2811b
JR
8822static void x_clear_image P_ ((struct frame *f, struct image *img));
8823static unsigned long x_alloc_image_color P_ ((struct frame *f,
8824 struct image *img,
8825 Lisp_Object color_name,
8826 unsigned long dflt));
8827
a05e2bae
JR
8828
8829/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8830 free the pixmap if any. MASK_P non-zero means clear the mask
8831 pixmap if any. COLORS_P non-zero means free colors allocated for
8832 the image, if any. */
8833
8834static void
8835x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8836 struct frame *f;
8837 struct image *img;
8838 int pixmap_p, mask_p, colors_p;
8839{
a05e2bae
JR
8840 if (pixmap_p && img->pixmap)
8841 {
ac849ba4
JR
8842 DeleteObject (img->pixmap);
8843 img->pixmap = NULL;
a05e2bae
JR
8844 img->background_valid = 0;
8845 }
8846
8847 if (mask_p && img->mask)
8848 {
ac849ba4
JR
8849 DeleteObject (img->mask);
8850 img->mask = NULL;
a05e2bae
JR
8851 img->background_transparent_valid = 0;
8852 }
7d0393cf 8853
a05e2bae
JR
8854 if (colors_p && img->ncolors)
8855 {
bf76fe9c 8856#if 0 /* TODO: color table support. */
a05e2bae 8857 x_free_colors (f, img->colors, img->ncolors);
bf76fe9c 8858#endif
a05e2bae
JR
8859 xfree (img->colors);
8860 img->colors = NULL;
8861 img->ncolors = 0;
8862 }
a05e2bae
JR
8863}
8864
6fc2811b
JR
8865/* Free X resources of image IMG which is used on frame F. */
8866
8867static void
8868x_clear_image (f, img)
8869 struct frame *f;
8870 struct image *img;
8871{
6fc2811b
JR
8872 if (img->pixmap)
8873 {
8874 BLOCK_INPUT;
ac849ba4 8875 DeleteObject (img->pixmap);
6fc2811b
JR
8876 img->pixmap = 0;
8877 UNBLOCK_INPUT;
8878 }
8879
8880 if (img->ncolors)
8881 {
ac849ba4
JR
8882#if 0 /* TODO: color table support */
8883
6fc2811b 8884 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7d0393cf 8885
6fc2811b
JR
8886 /* If display has an immutable color map, freeing colors is not
8887 necessary and some servers don't allow it. So don't do it. */
8888 if (class != StaticColor
8889 && class != StaticGray
8890 && class != TrueColor)
8891 {
8892 Colormap cmap;
8893 BLOCK_INPUT;
8894 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8895 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8896 img->ncolors, 0);
8897 UNBLOCK_INPUT;
8898 }
ac849ba4 8899#endif
7d0393cf 8900
6fc2811b
JR
8901 xfree (img->colors);
8902 img->colors = NULL;
8903 img->ncolors = 0;
8904 }
6fc2811b
JR
8905}
8906
8907
8908/* Allocate color COLOR_NAME for image IMG on frame F. If color
8909 cannot be allocated, use DFLT. Add a newly allocated color to
8910 IMG->colors, so that it can be freed again. Value is the pixel
8911 color. */
8912
8913static unsigned long
8914x_alloc_image_color (f, img, color_name, dflt)
8915 struct frame *f;
8916 struct image *img;
8917 Lisp_Object color_name;
8918 unsigned long dflt;
8919{
6fc2811b
JR
8920 XColor color;
8921 unsigned long result;
8922
8923 xassert (STRINGP (color_name));
8924
d5db4077 8925 if (w32_defined_color (f, SDATA (color_name), &color, 1))
6fc2811b
JR
8926 {
8927 /* This isn't called frequently so we get away with simply
8928 reallocating the color vector to the needed size, here. */
8929 ++img->ncolors;
8930 img->colors =
8931 (unsigned long *) xrealloc (img->colors,
8932 img->ncolors * sizeof *img->colors);
8933 img->colors[img->ncolors - 1] = color.pixel;
8934 result = color.pixel;
8935 }
8936 else
8937 result = dflt;
8938 return result;
6fc2811b
JR
8939}
8940
8941
8942\f
8943/***********************************************************************
8944 Image Cache
8945 ***********************************************************************/
8946
8947static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8948static void postprocess_image P_ ((struct frame *, struct image *));
197edd35 8949static void x_disable_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8950
8951
8952/* Return a new, initialized image cache that is allocated from the
8953 heap. Call free_image_cache to free an image cache. */
8954
8955struct image_cache *
8956make_image_cache ()
8957{
8958 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8959 int size;
7d0393cf 8960
6fc2811b
JR
8961 bzero (c, sizeof *c);
8962 c->size = 50;
8963 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8964 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8965 c->buckets = (struct image **) xmalloc (size);
8966 bzero (c->buckets, size);
8967 return c;
8968}
8969
8970
8971/* Free image cache of frame F. Be aware that X frames share images
8972 caches. */
8973
8974void
8975free_image_cache (f)
8976 struct frame *f;
8977{
8978 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8979 if (c)
8980 {
8981 int i;
8982
8983 /* Cache should not be referenced by any frame when freed. */
8984 xassert (c->refcount == 0);
7d0393cf 8985
6fc2811b
JR
8986 for (i = 0; i < c->used; ++i)
8987 free_image (f, c->images[i]);
8988 xfree (c->images);
8989 xfree (c);
8990 xfree (c->buckets);
8991 FRAME_X_IMAGE_CACHE (f) = NULL;
8992 }
8993}
8994
8995
8996/* Clear image cache of frame F. FORCE_P non-zero means free all
8997 images. FORCE_P zero means clear only images that haven't been
8998 displayed for some time. Should be called from time to time to
dfff8a69
JR
8999 reduce the number of loaded images. If image-eviction-seconds is
9000 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
9001 at least that many seconds. */
9002
9003void
9004clear_image_cache (f, force_p)
9005 struct frame *f;
9006 int force_p;
9007{
9008 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9009
9010 if (c && INTEGERP (Vimage_cache_eviction_delay))
9011 {
9012 EMACS_TIME t;
9013 unsigned long old;
0327b4cc 9014 int i, nfreed;
6fc2811b
JR
9015
9016 EMACS_GET_TIME (t);
9017 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7d0393cf 9018
0327b4cc
JR
9019 /* Block input so that we won't be interrupted by a SIGIO
9020 while being in an inconsistent state. */
9021 BLOCK_INPUT;
7d0393cf 9022
0327b4cc 9023 for (i = nfreed = 0; i < c->used; ++i)
6fc2811b
JR
9024 {
9025 struct image *img = c->images[i];
9026 if (img != NULL
0327b4cc 9027 && (force_p || (img->timestamp < old)))
6fc2811b
JR
9028 {
9029 free_image (f, img);
0327b4cc 9030 ++nfreed;
6fc2811b
JR
9031 }
9032 }
9033
9034 /* We may be clearing the image cache because, for example,
9035 Emacs was iconified for a longer period of time. In that
9036 case, current matrices may still contain references to
9037 images freed above. So, clear these matrices. */
0327b4cc 9038 if (nfreed)
6fc2811b 9039 {
0327b4cc 9040 Lisp_Object tail, frame;
7d0393cf 9041
0327b4cc
JR
9042 FOR_EACH_FRAME (tail, frame)
9043 {
9044 struct frame *f = XFRAME (frame);
9045 if (FRAME_W32_P (f)
9046 && FRAME_X_IMAGE_CACHE (f) == c)
9047 clear_current_matrices (f);
9048 }
9049
6fc2811b
JR
9050 ++windows_or_buffers_changed;
9051 }
0327b4cc
JR
9052
9053 UNBLOCK_INPUT;
6fc2811b
JR
9054 }
9055}
9056
9057
9058DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9059 0, 1, 0,
74e1aeec
JR
9060 doc: /* Clear the image cache of FRAME.
9061FRAME nil or omitted means use the selected frame.
9062FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
9063 (frame)
9064 Lisp_Object frame;
9065{
9066 if (EQ (frame, Qt))
9067 {
9068 Lisp_Object tail;
7d0393cf 9069
6fc2811b
JR
9070 FOR_EACH_FRAME (tail, frame)
9071 if (FRAME_W32_P (XFRAME (frame)))
9072 clear_image_cache (XFRAME (frame), 1);
9073 }
9074 else
9075 clear_image_cache (check_x_frame (frame), 1);
9076
9077 return Qnil;
9078}
9079
9080
3cf3436e
JR
9081/* Compute masks and transform image IMG on frame F, as specified
9082 by the image's specification, */
9083
9084static void
9085postprocess_image (f, img)
9086 struct frame *f;
9087 struct image *img;
9088{
3cf3436e
JR
9089 /* Manipulation of the image's mask. */
9090 if (img->pixmap)
9091 {
9092 Lisp_Object conversion, spec;
9093 Lisp_Object mask;
9094
9095 spec = img->spec;
7d0393cf 9096
3cf3436e
JR
9097 /* `:heuristic-mask t'
9098 `:mask heuristic'
9099 means build a mask heuristically.
9100 `:heuristic-mask (R G B)'
9101 `:mask (heuristic (R G B))'
9102 means build a mask from color (R G B) in the
9103 image.
9104 `:mask nil'
9105 means remove a mask, if any. */
7d0393cf 9106
3cf3436e
JR
9107 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9108 if (!NILP (mask))
9109 x_build_heuristic_mask (f, img, mask);
9110 else
9111 {
9112 int found_p;
7d0393cf 9113
3cf3436e 9114 mask = image_spec_value (spec, QCmask, &found_p);
7d0393cf 9115
3cf3436e
JR
9116 if (EQ (mask, Qheuristic))
9117 x_build_heuristic_mask (f, img, Qt);
9118 else if (CONSP (mask)
9119 && EQ (XCAR (mask), Qheuristic))
9120 {
9121 if (CONSP (XCDR (mask)))
9122 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9123 else
9124 x_build_heuristic_mask (f, img, XCDR (mask));
9125 }
9126 else if (NILP (mask) && found_p && img->mask)
9127 {
ac849ba4 9128 DeleteObject (img->mask);
3cf3436e
JR
9129 img->mask = NULL;
9130 }
9131 }
7d0393cf
JB
9132
9133
3cf3436e
JR
9134 /* Should we apply an image transformation algorithm? */
9135 conversion = image_spec_value (spec, QCconversion, NULL);
9136 if (EQ (conversion, Qdisabled))
9137 x_disable_image (f, img);
9138 else if (EQ (conversion, Qlaplace))
9139 x_laplace (f, img);
9140 else if (EQ (conversion, Qemboss))
9141 x_emboss (f, img);
9142 else if (CONSP (conversion)
9143 && EQ (XCAR (conversion), Qedge_detection))
9144 {
9145 Lisp_Object tem;
9146 tem = XCDR (conversion);
9147 if (CONSP (tem))
9148 x_edge_detection (f, img,
9149 Fplist_get (tem, QCmatrix),
9150 Fplist_get (tem, QCcolor_adjustment));
9151 }
9152 }
3cf3436e
JR
9153}
9154
9155
6fc2811b
JR
9156/* Return the id of image with Lisp specification SPEC on frame F.
9157 SPEC must be a valid Lisp image specification (see valid_image_p). */
9158
9159int
9160lookup_image (f, spec)
9161 struct frame *f;
9162 Lisp_Object spec;
9163{
9164 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9165 struct image *img;
9166 int i;
9167 unsigned hash;
9168 struct gcpro gcpro1;
9169 EMACS_TIME now;
9170
9171 /* F must be a window-system frame, and SPEC must be a valid image
9172 specification. */
9173 xassert (FRAME_WINDOW_P (f));
9174 xassert (valid_image_p (spec));
7d0393cf 9175
6fc2811b
JR
9176 GCPRO1 (spec);
9177
9178 /* Look up SPEC in the hash table of the image cache. */
9179 hash = sxhash (spec, 0);
9180 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9181
9182 for (img = c->buckets[i]; img; img = img->next)
9183 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9184 break;
9185
9186 /* If not found, create a new image and cache it. */
9187 if (img == NULL)
9188 {
3cf3436e
JR
9189 extern Lisp_Object Qpostscript;
9190
8edb0a6f 9191 BLOCK_INPUT;
6fc2811b
JR
9192 img = make_image (spec, hash);
9193 cache_image (f, img);
9194 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
9195
9196 /* If we can't load the image, and we don't have a width and
9197 height, use some arbitrary width and height so that we can
9198 draw a rectangle for it. */
9199 if (img->load_failed_p)
9200 {
9201 Lisp_Object value;
9202
9203 value = image_spec_value (spec, QCwidth, NULL);
9204 img->width = (INTEGERP (value)
9205 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9206 value = image_spec_value (spec, QCheight, NULL);
9207 img->height = (INTEGERP (value)
9208 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9209 }
9210 else
9211 {
9212 /* Handle image type independent image attributes
8f92c555 9213 `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
a05e2bae
JR
9214 `:background COLOR'. */
9215 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
9216
9217 ascent = image_spec_value (spec, QCascent, NULL);
9218 if (INTEGERP (ascent))
9219 img->ascent = XFASTINT (ascent);
dfff8a69
JR
9220 else if (EQ (ascent, Qcenter))
9221 img->ascent = CENTERED_IMAGE_ASCENT;
9222
6fc2811b
JR
9223 margin = image_spec_value (spec, QCmargin, NULL);
9224 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
9225 img->vmargin = img->hmargin = XFASTINT (margin);
9226 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9227 && INTEGERP (XCDR (margin)))
9228 {
9229 if (XINT (XCAR (margin)) > 0)
9230 img->hmargin = XFASTINT (XCAR (margin));
9231 if (XINT (XCDR (margin)) > 0)
9232 img->vmargin = XFASTINT (XCDR (margin));
9233 }
7d0393cf 9234
6fc2811b
JR
9235 relief = image_spec_value (spec, QCrelief, NULL);
9236 if (INTEGERP (relief))
9237 {
9238 img->relief = XINT (relief);
8edb0a6f
JR
9239 img->hmargin += abs (img->relief);
9240 img->vmargin += abs (img->relief);
6fc2811b
JR
9241 }
9242
a05e2bae
JR
9243 if (! img->background_valid)
9244 {
9245 bg = image_spec_value (img->spec, QCbackground, NULL);
9246 if (!NILP (bg))
9247 {
9248 img->background
9249 = x_alloc_image_color (f, img, bg,
9250 FRAME_BACKGROUND_PIXEL (f));
9251 img->background_valid = 1;
9252 }
9253 }
9254
3cf3436e
JR
9255 /* Do image transformations and compute masks, unless we
9256 don't have the image yet. */
9257 if (!EQ (*img->type->type, Qpostscript))
9258 postprocess_image (f, img);
6fc2811b 9259 }
3cf3436e 9260
8edb0a6f
JR
9261 UNBLOCK_INPUT;
9262 xassert (!interrupt_input_blocked);
6fc2811b
JR
9263 }
9264
9265 /* We're using IMG, so set its timestamp to `now'. */
9266 EMACS_GET_TIME (now);
9267 img->timestamp = EMACS_SECS (now);
7d0393cf 9268
6fc2811b 9269 UNGCPRO;
7d0393cf 9270
6fc2811b
JR
9271 /* Value is the image id. */
9272 return img->id;
9273}
9274
9275
9276/* Cache image IMG in the image cache of frame F. */
9277
9278static void
9279cache_image (f, img)
9280 struct frame *f;
9281 struct image *img;
9282{
9283 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9284 int i;
9285
9286 /* Find a free slot in c->images. */
9287 for (i = 0; i < c->used; ++i)
9288 if (c->images[i] == NULL)
9289 break;
9290
9291 /* If no free slot found, maybe enlarge c->images. */
9292 if (i == c->used && c->used == c->size)
9293 {
9294 c->size *= 2;
9295 c->images = (struct image **) xrealloc (c->images,
9296 c->size * sizeof *c->images);
9297 }
9298
9299 /* Add IMG to c->images, and assign IMG an id. */
9300 c->images[i] = img;
9301 img->id = i;
9302 if (i == c->used)
9303 ++c->used;
9304
9305 /* Add IMG to the cache's hash table. */
9306 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9307 img->next = c->buckets[i];
9308 if (img->next)
9309 img->next->prev = img;
9310 img->prev = NULL;
9311 c->buckets[i] = img;
9312}
9313
9314
9315/* Call FN on every image in the image cache of frame F. Used to mark
9316 Lisp Objects in the image cache. */
9317
9318void
9319forall_images_in_image_cache (f, fn)
9320 struct frame *f;
9321 void (*fn) P_ ((struct image *img));
9322{
9323 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9324 {
9325 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9326 if (c)
9327 {
9328 int i;
9329 for (i = 0; i < c->used; ++i)
9330 if (c->images[i])
9331 fn (c->images[i]);
9332 }
9333 }
9334}
9335
9336
9337\f
9338/***********************************************************************
9339 W32 support code
9340 ***********************************************************************/
9341
839b1909
JR
9342/* Macro for defining functions that will be loaded from image DLLs. */
9343#define DEF_IMGLIB_FN(func) FARPROC fn_##func
c922a224 9344
839b1909
JR
9345/* Macro for loading those image functions from the library. */
9346#define LOAD_IMGLIB_FN(lib,func) { \
9347 fn_##func = (void *) GetProcAddress (lib, #func); \
9348 if (!fn_##func) return 0; \
c922a224 9349 }
839b1909 9350
6fc2811b
JR
9351static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9352 XImage **, Pixmap *));
6fc2811b
JR
9353static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9354
9355
9356/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9357 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9358 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
ac849ba4
JR
9359 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9360 DEPTH should indicate the bit depth of the image. Print error
9361 messages via image_error if an error occurs. Value is non-zero if
9362 successful. */
6fc2811b
JR
9363
9364static int
9365x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9366 struct frame *f;
9367 int width, height, depth;
9368 XImage **ximg;
9369 Pixmap *pixmap;
9370{
ac849ba4
JR
9371 BITMAPINFOHEADER *header;
9372 HDC hdc;
9373 int scanline_width_bits;
9374 int remainder;
9375 int palette_colors = 0;
6fc2811b 9376
ac849ba4
JR
9377 if (depth == 0)
9378 depth = 24;
6fc2811b 9379
ac849ba4
JR
9380 if (depth != 1 && depth != 4 && depth != 8
9381 && depth != 16 && depth != 24 && depth != 32)
9382 {
9383 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9384 return 0;
9385 }
9386
9387 scanline_width_bits = width * depth;
9388 remainder = scanline_width_bits % 32;
9389
9390 if (remainder)
9391 scanline_width_bits += 32 - remainder;
9392
9393 /* Bitmaps with a depth less than 16 need a palette. */
9394 /* BITMAPINFO structure already contains the first RGBQUAD. */
9395 if (depth < 16)
9396 palette_colors = 1 << depth - 1;
9397
9398 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
6fc2811b
JR
9399 if (*ximg == NULL)
9400 {
ac849ba4 9401 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
6fc2811b
JR
9402 return 0;
9403 }
9404
ac849ba4
JR
9405 header = &((*ximg)->info.bmiHeader);
9406 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9407 header->biSize = sizeof (*header);
9408 header->biWidth = width;
9409 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9410 header->biPlanes = 1;
9411 header->biBitCount = depth;
9412 header->biCompression = BI_RGB;
9413 header->biClrUsed = palette_colors;
6fc2811b 9414
197edd35 9415 /* TODO: fill in palette. */
35624c03
JR
9416 if (depth == 1)
9417 {
9418 (*ximg)->info.bmiColors[0].rgbBlue = 0;
9419 (*ximg)->info.bmiColors[0].rgbGreen = 0;
9420 (*ximg)->info.bmiColors[0].rgbRed = 0;
9421 (*ximg)->info.bmiColors[0].rgbReserved = 0;
9422 (*ximg)->info.bmiColors[1].rgbBlue = 255;
9423 (*ximg)->info.bmiColors[1].rgbGreen = 255;
9424 (*ximg)->info.bmiColors[1].rgbRed = 255;
9425 (*ximg)->info.bmiColors[1].rgbReserved = 0;
9426 }
197edd35 9427
ac849ba4
JR
9428 hdc = get_frame_dc (f);
9429
9430 /* Create a DIBSection and raster array for the bitmap,
9431 and store its handle in *pixmap. */
197edd35
JR
9432 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
9433 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
ac849ba4
JR
9434 &((*ximg)->data), NULL, 0);
9435
9436 /* Realize display palette and garbage all frames. */
9437 release_frame_dc (f, hdc);
9438
9439 if (*pixmap == NULL)
6fc2811b 9440 {
ac849ba4
JR
9441 DWORD err = GetLastError();
9442 Lisp_Object errcode;
9443 /* All system errors are < 10000, so the following is safe. */
9444 XSETINT (errcode, (int) err);
9445 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
6fc2811b 9446 x_destroy_x_image (*ximg);
6fc2811b
JR
9447 return 0;
9448 }
ac849ba4 9449
6fc2811b
JR
9450 return 1;
9451}
9452
9453
9454/* Destroy XImage XIMG. Free XIMG->data. */
9455
9456static void
9457x_destroy_x_image (ximg)
9458 XImage *ximg;
9459{
9460 xassert (interrupt_input_blocked);
9461 if (ximg)
9462 {
ac849ba4 9463 /* Data will be freed by DestroyObject. */
6fc2811b 9464 ximg->data = NULL;
ac849ba4 9465 xfree (ximg);
6fc2811b
JR
9466 }
9467}
9468
9469
9470/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9471 are width and height of both the image and pixmap. */
9472
9473static void
9474x_put_x_image (f, ximg, pixmap, width, height)
9475 struct frame *f;
9476 XImage *ximg;
9477 Pixmap pixmap;
c9b2104d 9478 int width, height;
6fc2811b 9479{
197edd35
JR
9480#if 0 /* I don't think this is necessary looking at where it is used. */
9481 HDC hdc = get_frame_dc (f);
9482 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
9483 release_frame_dc (f, hdc);
6fc2811b 9484#endif
ac849ba4 9485}
6fc2811b
JR
9486
9487\f
9488/***********************************************************************
3cf3436e 9489 File Handling
6fc2811b
JR
9490 ***********************************************************************/
9491
9492static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9493static char *slurp_file P_ ((char *, int *));
9494
6fc2811b
JR
9495
9496/* Find image file FILE. Look in data-directory, then
9497 x-bitmap-file-path. Value is the full name of the file found, or
9498 nil if not found. */
9499
9500static Lisp_Object
9501x_find_image_file (file)
9502 Lisp_Object file;
9503{
9504 Lisp_Object file_found, search_path;
9505 struct gcpro gcpro1, gcpro2;
9506 int fd;
9507
9508 file_found = Qnil;
9509 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9510 GCPRO2 (file_found, search_path);
9511
9512 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 9513 fd = openp (search_path, file, Qnil, &file_found, Qnil);
7d0393cf 9514
939d6465 9515 if (fd == -1)
6fc2811b
JR
9516 file_found = Qnil;
9517 else
9518 close (fd);
9519
9520 UNGCPRO;
9521 return file_found;
9522}
9523
9524
3cf3436e
JR
9525/* Read FILE into memory. Value is a pointer to a buffer allocated
9526 with xmalloc holding FILE's contents. Value is null if an error
9527 occurred. *SIZE is set to the size of the file. */
9528
9529static char *
9530slurp_file (file, size)
9531 char *file;
9532 int *size;
9533{
9534 FILE *fp = NULL;
9535 char *buf = NULL;
9536 struct stat st;
9537
9538 if (stat (file, &st) == 0
9539 && (fp = fopen (file, "r")) != NULL
9540 && (buf = (char *) xmalloc (st.st_size),
9541 fread (buf, 1, st.st_size, fp) == st.st_size))
9542 {
9543 *size = st.st_size;
9544 fclose (fp);
9545 }
9546 else
9547 {
9548 if (fp)
9549 fclose (fp);
9550 if (buf)
9551 {
9552 xfree (buf);
9553 buf = NULL;
9554 }
9555 }
7d0393cf 9556
3cf3436e
JR
9557 return buf;
9558}
9559
9560
6fc2811b
JR
9561\f
9562/***********************************************************************
9563 XBM images
9564 ***********************************************************************/
9565
217e5be0 9566static int xbm_scan P_ ((char **, char *, char *, int *));
6fc2811b 9567static int xbm_load P_ ((struct frame *f, struct image *img));
217e5be0
JR
9568static int xbm_load_image P_ ((struct frame *f, struct image *img,
9569 char *, char *));
6fc2811b 9570static int xbm_image_p P_ ((Lisp_Object object));
217e5be0
JR
9571static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
9572 unsigned char **));
9573static int xbm_file_p P_ ((Lisp_Object));
6fc2811b
JR
9574
9575
9576/* Indices of image specification fields in xbm_format, below. */
9577
9578enum xbm_keyword_index
9579{
9580 XBM_TYPE,
9581 XBM_FILE,
9582 XBM_WIDTH,
9583 XBM_HEIGHT,
9584 XBM_DATA,
9585 XBM_FOREGROUND,
9586 XBM_BACKGROUND,
9587 XBM_ASCENT,
9588 XBM_MARGIN,
9589 XBM_RELIEF,
9590 XBM_ALGORITHM,
9591 XBM_HEURISTIC_MASK,
a05e2bae 9592 XBM_MASK,
6fc2811b
JR
9593 XBM_LAST
9594};
9595
9596/* Vector of image_keyword structures describing the format
9597 of valid XBM image specifications. */
9598
9599static struct image_keyword xbm_format[XBM_LAST] =
9600{
9601 {":type", IMAGE_SYMBOL_VALUE, 1},
9602 {":file", IMAGE_STRING_VALUE, 0},
9603 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9604 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9605 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9606 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9607 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9608 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 9609 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9610 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9611 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9612 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9613 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6fc2811b
JR
9614};
9615
9616/* Structure describing the image type XBM. */
9617
9618static struct image_type xbm_type =
9619{
9620 &Qxbm,
9621 xbm_image_p,
9622 xbm_load,
9623 x_clear_image,
9624 NULL
9625};
9626
9627/* Tokens returned from xbm_scan. */
9628
9629enum xbm_token
9630{
9631 XBM_TK_IDENT = 256,
9632 XBM_TK_NUMBER
9633};
9634
7d0393cf 9635
6fc2811b
JR
9636/* Return non-zero if OBJECT is a valid XBM-type image specification.
9637 A valid specification is a list starting with the symbol `image'
9638 The rest of the list is a property list which must contain an
9639 entry `:type xbm..
9640
9641 If the specification specifies a file to load, it must contain
9642 an entry `:file FILENAME' where FILENAME is a string.
9643
9644 If the specification is for a bitmap loaded from memory it must
9645 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9646 WIDTH and HEIGHT are integers > 0. DATA may be:
9647
9648 1. a string large enough to hold the bitmap data, i.e. it must
9649 have a size >= (WIDTH + 7) / 8 * HEIGHT
9650
9651 2. a bool-vector of size >= WIDTH * HEIGHT
9652
9653 3. a vector of strings or bool-vectors, one for each line of the
9654 bitmap.
9655
217e5be0
JR
9656 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
9657 may not be specified in this case because they are defined in the
9658 XBM file.
9659
6fc2811b
JR
9660 Both the file and data forms may contain the additional entries
9661 `:background COLOR' and `:foreground COLOR'. If not present,
9662 foreground and background of the frame on which the image is
217e5be0 9663 displayed is used. */
6fc2811b
JR
9664
9665static int
9666xbm_image_p (object)
9667 Lisp_Object object;
9668{
9669 struct image_keyword kw[XBM_LAST];
7d0393cf 9670
6fc2811b
JR
9671 bcopy (xbm_format, kw, sizeof kw);
9672 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9673 return 0;
9674
9675 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9676
9677 if (kw[XBM_FILE].count)
9678 {
9679 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9680 return 0;
9681 }
217e5be0
JR
9682 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
9683 {
9684 /* In-memory XBM file. */
9685 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
9686 return 0;
9687 }
6fc2811b
JR
9688 else
9689 {
9690 Lisp_Object data;
9691 int width, height;
9692
9693 /* Entries for `:width', `:height' and `:data' must be present. */
9694 if (!kw[XBM_WIDTH].count
9695 || !kw[XBM_HEIGHT].count
9696 || !kw[XBM_DATA].count)
9697 return 0;
9698
9699 data = kw[XBM_DATA].value;
9700 width = XFASTINT (kw[XBM_WIDTH].value);
9701 height = XFASTINT (kw[XBM_HEIGHT].value);
7d0393cf 9702
6fc2811b
JR
9703 /* Check type of data, and width and height against contents of
9704 data. */
9705 if (VECTORP (data))
9706 {
9707 int i;
7d0393cf 9708
6fc2811b
JR
9709 /* Number of elements of the vector must be >= height. */
9710 if (XVECTOR (data)->size < height)
9711 return 0;
9712
9713 /* Each string or bool-vector in data must be large enough
9714 for one line of the image. */
9715 for (i = 0; i < height; ++i)
9716 {
9717 Lisp_Object elt = XVECTOR (data)->contents[i];
9718
9719 if (STRINGP (elt))
9720 {
d5db4077 9721 if (SCHARS (elt)
6fc2811b
JR
9722 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9723 return 0;
9724 }
9725 else if (BOOL_VECTOR_P (elt))
9726 {
9727 if (XBOOL_VECTOR (elt)->size < width)
9728 return 0;
9729 }
9730 else
9731 return 0;
9732 }
9733 }
9734 else if (STRINGP (data))
9735 {
d5db4077 9736 if (SCHARS (data)
6fc2811b
JR
9737 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9738 return 0;
9739 }
9740 else if (BOOL_VECTOR_P (data))
9741 {
9742 if (XBOOL_VECTOR (data)->size < width * height)
9743 return 0;
9744 }
9745 else
9746 return 0;
9747 }
9748
6fc2811b
JR
9749 return 1;
9750}
9751
9752
9753/* Scan a bitmap file. FP is the stream to read from. Value is
9754 either an enumerator from enum xbm_token, or a character for a
9755 single-character token, or 0 at end of file. If scanning an
9756 identifier, store the lexeme of the identifier in SVAL. If
9757 scanning a number, store its value in *IVAL. */
9758
9759static int
3cf3436e
JR
9760xbm_scan (s, end, sval, ival)
9761 char **s, *end;
6fc2811b
JR
9762 char *sval;
9763 int *ival;
9764{
9765 int c;
3cf3436e
JR
9766
9767 loop:
9768
6fc2811b 9769 /* Skip white space. */
af3f7be7 9770 while (*s < end && (c = *(*s)++, isspace (c)))
6fc2811b
JR
9771 ;
9772
3cf3436e 9773 if (*s >= end)
6fc2811b
JR
9774 c = 0;
9775 else if (isdigit (c))
9776 {
9777 int value = 0, digit;
7d0393cf 9778
3cf3436e 9779 if (c == '0' && *s < end)
6fc2811b 9780 {
3cf3436e 9781 c = *(*s)++;
6fc2811b
JR
9782 if (c == 'x' || c == 'X')
9783 {
3cf3436e 9784 while (*s < end)
6fc2811b 9785 {
3cf3436e 9786 c = *(*s)++;
6fc2811b
JR
9787 if (isdigit (c))
9788 digit = c - '0';
9789 else if (c >= 'a' && c <= 'f')
9790 digit = c - 'a' + 10;
9791 else if (c >= 'A' && c <= 'F')
9792 digit = c - 'A' + 10;
9793 else
9794 break;
9795 value = 16 * value + digit;
9796 }
9797 }
9798 else if (isdigit (c))
9799 {
9800 value = c - '0';
3cf3436e
JR
9801 while (*s < end
9802 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9803 value = 8 * value + c - '0';
9804 }
9805 }
9806 else
9807 {
9808 value = c - '0';
3cf3436e
JR
9809 while (*s < end
9810 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9811 value = 10 * value + c - '0';
9812 }
9813
3cf3436e
JR
9814 if (*s < end)
9815 *s = *s - 1;
6fc2811b
JR
9816 *ival = value;
9817 c = XBM_TK_NUMBER;
9818 }
9819 else if (isalpha (c) || c == '_')
9820 {
9821 *sval++ = c;
3cf3436e
JR
9822 while (*s < end
9823 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9824 *sval++ = c;
9825 *sval = 0;
3cf3436e
JR
9826 if (*s < end)
9827 *s = *s - 1;
6fc2811b
JR
9828 c = XBM_TK_IDENT;
9829 }
3cf3436e
JR
9830 else if (c == '/' && **s == '*')
9831 {
9832 /* C-style comment. */
9833 ++*s;
9834 while (**s && (**s != '*' || *(*s + 1) != '/'))
9835 ++*s;
9836 if (**s)
9837 {
9838 *s += 2;
9839 goto loop;
9840 }
9841 }
6fc2811b
JR
9842
9843 return c;
9844}
9845
9846
217e5be0
JR
9847/* XBM bits seem to be backward within bytes compared with how
9848 Windows does things. */
9849static unsigned char reflect_byte (unsigned char orig)
9850{
9851 int i;
9852 unsigned char reflected = 0x00;
9853 for (i = 0; i < 8; i++)
9854 {
9855 if (orig & (0x01 << i))
9856 reflected |= 0x80 >> i;
9857 }
9858 return reflected;
9859}
9860
9861
af3f7be7
JR
9862/* Create a Windows bitmap from X bitmap data. */
9863static HBITMAP
9864w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
9865{
9866 int i, j, w1, w2;
9867 char *bits, *p;
9868 HBITMAP bmp;
9869
9870 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
9871 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
c736ffda 9872 bits = (char *) alloca (height * w2);
af3f7be7
JR
9873 bzero (bits, height * w2);
9874 for (i = 0; i < height; i++)
9875 {
9876 p = bits + i*w2;
9877 for (j = 0; j < w1; j++)
9878 *p++ = reflect_byte(*data++);
9879 }
9880 bmp = CreateBitmap (width, height, 1, 1, bits);
af3f7be7
JR
9881
9882 return bmp;
9883}
9884
9885
6fc2811b 9886/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9887 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9888 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9889 the image. Return in *DATA the bitmap data allocated with xmalloc.
9890 Value is non-zero if successful. DATA null means just test if
9891 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9892
9893static int
3cf3436e
JR
9894xbm_read_bitmap_data (contents, end, width, height, data)
9895 char *contents, *end;
6fc2811b
JR
9896 int *width, *height;
9897 unsigned char **data;
9898{
3cf3436e 9899 char *s = contents;
6fc2811b
JR
9900 char buffer[BUFSIZ];
9901 int padding_p = 0;
9902 int v10 = 0;
af3f7be7 9903 int bytes_per_line, i, nbytes;
6fc2811b
JR
9904 unsigned char *p;
9905 int value;
9906 int LA1;
9907
9908#define match() \
217e5be0 9909 LA1 = xbm_scan (&s, end, buffer, &value)
6fc2811b
JR
9910
9911#define expect(TOKEN) \
9912 if (LA1 != (TOKEN)) \
9913 goto failure; \
9914 else \
7d0393cf 9915 match ()
6fc2811b
JR
9916
9917#define expect_ident(IDENT) \
9918 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9919 match (); \
9920 else \
9921 goto failure
9922
6fc2811b 9923 *width = *height = -1;
3cf3436e
JR
9924 if (data)
9925 *data = NULL;
9926 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9927
9928 /* Parse defines for width, height and hot-spots. */
9929 while (LA1 == '#')
9930 {
9931 match ();
9932 expect_ident ("define");
9933 expect (XBM_TK_IDENT);
9934
9935 if (LA1 == XBM_TK_NUMBER);
9936 {
9937 char *p = strrchr (buffer, '_');
9938 p = p ? p + 1 : buffer;
9939 if (strcmp (p, "width") == 0)
9940 *width = value;
9941 else if (strcmp (p, "height") == 0)
9942 *height = value;
9943 }
9944 expect (XBM_TK_NUMBER);
9945 }
9946
9947 if (*width < 0 || *height < 0)
9948 goto failure;
3cf3436e
JR
9949 else if (data == NULL)
9950 goto success;
6fc2811b
JR
9951
9952 /* Parse bits. Must start with `static'. */
9953 expect_ident ("static");
9954 if (LA1 == XBM_TK_IDENT)
9955 {
9956 if (strcmp (buffer, "unsigned") == 0)
9957 {
7d0393cf 9958 match ();
6fc2811b
JR
9959 expect_ident ("char");
9960 }
9961 else if (strcmp (buffer, "short") == 0)
9962 {
9963 match ();
9964 v10 = 1;
af3f7be7
JR
9965 if (*width % 16 && *width % 16 < 9)
9966 padding_p = 1;
6fc2811b
JR
9967 }
9968 else if (strcmp (buffer, "char") == 0)
9969 match ();
9970 else
9971 goto failure;
9972 }
7d0393cf 9973 else
6fc2811b
JR
9974 goto failure;
9975
9976 expect (XBM_TK_IDENT);
9977 expect ('[');
9978 expect (']');
9979 expect ('=');
9980 expect ('{');
9981
af3f7be7
JR
9982 bytes_per_line = (*width + 7) / 8 + padding_p;
9983 nbytes = bytes_per_line * *height;
9984 p = *data = (char *) xmalloc (nbytes);
6fc2811b
JR
9985
9986 if (v10)
9987 {
6fc2811b
JR
9988 for (i = 0; i < nbytes; i += 2)
9989 {
9990 int val = value;
9991 expect (XBM_TK_NUMBER);
9992
35624c03 9993 *p++ = ~ val;
af3f7be7 9994 if (!padding_p || ((i + 2) % bytes_per_line))
35624c03 9995 *p++ = ~ (value >> 8);
7d0393cf 9996
6fc2811b
JR
9997 if (LA1 == ',' || LA1 == '}')
9998 match ();
9999 else
10000 goto failure;
10001 }
10002 }
10003 else
10004 {
10005 for (i = 0; i < nbytes; ++i)
10006 {
10007 int val = value;
10008 expect (XBM_TK_NUMBER);
7d0393cf 10009
35624c03 10010 *p++ = ~ val;
217e5be0 10011
6fc2811b
JR
10012 if (LA1 == ',' || LA1 == '}')
10013 match ();
10014 else
10015 goto failure;
10016 }
10017 }
10018
3cf3436e 10019 success:
6fc2811b
JR
10020 return 1;
10021
10022 failure:
3cf3436e
JR
10023
10024 if (data && *data)
6fc2811b
JR
10025 {
10026 xfree (*data);
10027 *data = NULL;
10028 }
10029 return 0;
10030
10031#undef match
10032#undef expect
10033#undef expect_ident
10034}
10035
516eea8e
JR
10036static void convert_mono_to_color_image (f, img, foreground, background)
10037 struct frame *f;
10038 struct image *img;
10039 COLORREF foreground, background;
10040{
10041 HDC hdc, old_img_dc, new_img_dc;
10042 HGDIOBJ old_prev, new_prev;
10043 HBITMAP new_pixmap;
10044
10045 hdc = get_frame_dc (f);
10046 old_img_dc = CreateCompatibleDC (hdc);
10047 new_img_dc = CreateCompatibleDC (hdc);
10048 new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height);
10049 release_frame_dc (f, hdc);
10050 old_prev = SelectObject (old_img_dc, img->pixmap);
10051 new_prev = SelectObject (new_img_dc, new_pixmap);
10052 SetTextColor (new_img_dc, foreground);
10053 SetBkColor (new_img_dc, background);
10054
10055 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
10056 0, 0, SRCCOPY);
10057
10058 SelectObject (old_img_dc, old_prev);
c922a224 10059 SelectObject (new_img_dc, new_prev);
516eea8e
JR
10060 DeleteDC (old_img_dc);
10061 DeleteDC (new_img_dc);
10062 DeleteObject (img->pixmap);
10063 if (new_pixmap == 0)
10064 fprintf (stderr, "Failed to convert image to color.\n");
10065 else
10066 img->pixmap = new_pixmap;
10067}
6fc2811b 10068
3cf3436e
JR
10069/* Load XBM image IMG which will be displayed on frame F from buffer
10070 CONTENTS. END is the end of the buffer. Value is non-zero if
10071 successful. */
6fc2811b
JR
10072
10073static int
3cf3436e 10074xbm_load_image (f, img, contents, end)
6fc2811b
JR
10075 struct frame *f;
10076 struct image *img;
3cf3436e 10077 char *contents, *end;
6fc2811b
JR
10078{
10079 int rc;
10080 unsigned char *data;
10081 int success_p = 0;
7d0393cf 10082
3cf3436e 10083 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
10084 if (rc)
10085 {
6fc2811b
JR
10086 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10087 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
516eea8e 10088 int non_default_colors = 0;
6fc2811b 10089 Lisp_Object value;
7d0393cf 10090
6fc2811b
JR
10091 xassert (img->width > 0 && img->height > 0);
10092
10093 /* Get foreground and background colors, maybe allocate colors. */
10094 value = image_spec_value (img->spec, QCforeground, NULL);
10095 if (!NILP (value))
516eea8e
JR
10096 {
10097 foreground = x_alloc_image_color (f, img, value, foreground);
10098 non_default_colors = 1;
10099 }
6fc2811b
JR
10100 value = image_spec_value (img->spec, QCbackground, NULL);
10101 if (!NILP (value))
a05e2bae
JR
10102 {
10103 background = x_alloc_image_color (f, img, value, background);
10104 img->background = background;
10105 img->background_valid = 1;
516eea8e 10106 non_default_colors = 1;
a05e2bae 10107 }
6fc2811b 10108 img->pixmap
af3f7be7 10109 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
ac849ba4 10110
516eea8e
JR
10111 /* If colors were specified, transfer the bitmap to a color one. */
10112 if (non_default_colors)
10113 convert_mono_to_color_image (f, img, foreground, background);
10114
6fc2811b
JR
10115 xfree (data);
10116
10117 if (img->pixmap == 0)
10118 {
10119 x_clear_image (f, img);
3cf3436e 10120 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
10121 }
10122 else
10123 success_p = 1;
6fc2811b
JR
10124 }
10125 else
10126 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10127
6fc2811b
JR
10128 return success_p;
10129}
10130
10131
3cf3436e
JR
10132/* Value is non-zero if DATA looks like an in-memory XBM file. */
10133
10134static int
10135xbm_file_p (data)
10136 Lisp_Object data;
10137{
10138 int w, h;
10139 return (STRINGP (data)
d5db4077
KR
10140 && xbm_read_bitmap_data (SDATA (data),
10141 (SDATA (data)
10142 + SBYTES (data)),
3cf3436e
JR
10143 &w, &h, NULL));
10144}
10145
7d0393cf 10146
6fc2811b
JR
10147/* Fill image IMG which is used on frame F with pixmap data. Value is
10148 non-zero if successful. */
10149
10150static int
10151xbm_load (f, img)
10152 struct frame *f;
10153 struct image *img;
10154{
10155 int success_p = 0;
10156 Lisp_Object file_name;
10157
10158 xassert (xbm_image_p (img->spec));
10159
10160 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10161 file_name = image_spec_value (img->spec, QCfile, NULL);
10162 if (STRINGP (file_name))
3cf3436e
JR
10163 {
10164 Lisp_Object file;
10165 char *contents;
10166 int size;
10167 struct gcpro gcpro1;
10168
10169 file = x_find_image_file (file_name);
10170 GCPRO1 (file);
10171 if (!STRINGP (file))
10172 {
10173 image_error ("Cannot find image file `%s'", file_name, Qnil);
10174 UNGCPRO;
10175 return 0;
10176 }
10177
d5db4077 10178 contents = slurp_file (SDATA (file), &size);
3cf3436e
JR
10179 if (contents == NULL)
10180 {
10181 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10182 UNGCPRO;
10183 return 0;
10184 }
10185
10186 success_p = xbm_load_image (f, img, contents, contents + size);
10187 UNGCPRO;
10188 }
6fc2811b
JR
10189 else
10190 {
10191 struct image_keyword fmt[XBM_LAST];
10192 Lisp_Object data;
6fc2811b
JR
10193 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10194 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
516eea8e 10195 int non_default_colors = 0;
6fc2811b
JR
10196 char *bits;
10197 int parsed_p;
3cf3436e
JR
10198 int in_memory_file_p = 0;
10199
10200 /* See if data looks like an in-memory XBM file. */
10201 data = image_spec_value (img->spec, QCdata, NULL);
10202 in_memory_file_p = xbm_file_p (data);
6fc2811b 10203
217e5be0 10204 /* Parse the image specification. */
6fc2811b
JR
10205 bcopy (xbm_format, fmt, sizeof fmt);
10206 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10207 xassert (parsed_p);
10208
10209 /* Get specified width, and height. */
3cf3436e
JR
10210 if (!in_memory_file_p)
10211 {
10212 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10213 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10214 xassert (img->width > 0 && img->height > 0);
10215 }
217e5be0 10216
6fc2811b 10217 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
10218 if (fmt[XBM_FOREGROUND].count
10219 && STRINGP (fmt[XBM_FOREGROUND].value))
516eea8e
JR
10220 {
10221 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10222 foreground);
10223 non_default_colors = 1;
10224 }
10225
3cf3436e
JR
10226 if (fmt[XBM_BACKGROUND].count
10227 && STRINGP (fmt[XBM_BACKGROUND].value))
516eea8e
JR
10228 {
10229 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10230 background);
10231 non_default_colors = 1;
10232 }
6fc2811b 10233
3cf3436e 10234 if (in_memory_file_p)
d5db4077
KR
10235 success_p = xbm_load_image (f, img, SDATA (data),
10236 (SDATA (data)
10237 + SBYTES (data)));
3cf3436e 10238 else
6fc2811b 10239 {
3cf3436e
JR
10240 if (VECTORP (data))
10241 {
10242 int i;
10243 char *p;
10244 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
7d0393cf 10245
3cf3436e
JR
10246 p = bits = (char *) alloca (nbytes * img->height);
10247 for (i = 0; i < img->height; ++i, p += nbytes)
10248 {
10249 Lisp_Object line = XVECTOR (data)->contents[i];
10250 if (STRINGP (line))
d5db4077 10251 bcopy (SDATA (line), p, nbytes);
3cf3436e
JR
10252 else
10253 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10254 }
10255 }
10256 else if (STRINGP (data))
d5db4077 10257 bits = SDATA (data);
3cf3436e
JR
10258 else
10259 bits = XBOOL_VECTOR (data)->data;
af3f7be7 10260
3cf3436e 10261 /* Create the pixmap. */
3cf3436e 10262 img->pixmap
af3f7be7
JR
10263 = w32_create_pixmap_from_bitmap_data (img->width, img->height,
10264 bits);
10265
516eea8e
JR
10266 /* If colors were specified, transfer the bitmap to a color one. */
10267 if (non_default_colors)
10268 convert_mono_to_color_image (f, img, foreground, background);
10269
3cf3436e
JR
10270 if (img->pixmap)
10271 success_p = 1;
10272 else
6fc2811b 10273 {
3cf3436e
JR
10274 image_error ("Unable to create pixmap for XBM image `%s'",
10275 img->spec, Qnil);
10276 x_clear_image (f, img);
6fc2811b
JR
10277 }
10278 }
6fc2811b
JR
10279 }
10280
10281 return success_p;
10282}
7d0393cf 10283
6fc2811b
JR
10284
10285\f
10286/***********************************************************************
10287 XPM images
10288 ***********************************************************************/
10289
7d0393cf 10290#if HAVE_XPM
6fc2811b
JR
10291
10292static int xpm_image_p P_ ((Lisp_Object object));
10293static int xpm_load P_ ((struct frame *f, struct image *img));
10294static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10295
c736ffda
JR
10296/* Indicate to xpm.h that we don't have Xlib. */
10297#define FOR_MSW
10298/* simx.h in xpm defines XColor and XImage differently than Emacs. */
10299#define XColor xpm_XColor
10300#define XImage xpm_XImage
10301#define PIXEL_ALREADY_TYPEDEFED
6fc2811b 10302#include "X11/xpm.h"
c736ffda
JR
10303#undef FOR_MSW
10304#undef XColor
10305#undef XImage
10306#undef PIXEL_ALREADY_TYPEDEFED
6fc2811b
JR
10307
10308/* The symbol `xpm' identifying XPM-format images. */
10309
10310Lisp_Object Qxpm;
10311
10312/* Indices of image specification fields in xpm_format, below. */
10313
10314enum xpm_keyword_index
10315{
10316 XPM_TYPE,
10317 XPM_FILE,
10318 XPM_DATA,
10319 XPM_ASCENT,
10320 XPM_MARGIN,
10321 XPM_RELIEF,
10322 XPM_ALGORITHM,
10323 XPM_HEURISTIC_MASK,
a05e2bae 10324 XPM_MASK,
6fc2811b 10325 XPM_COLOR_SYMBOLS,
a05e2bae 10326 XPM_BACKGROUND,
6fc2811b
JR
10327 XPM_LAST
10328};
10329
10330/* Vector of image_keyword structures describing the format
10331 of valid XPM image specifications. */
10332
10333static struct image_keyword xpm_format[XPM_LAST] =
10334{
10335 {":type", IMAGE_SYMBOL_VALUE, 1},
10336 {":file", IMAGE_STRING_VALUE, 0},
10337 {":data", IMAGE_STRING_VALUE, 0},
8f92c555 10338 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 10339 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10340 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10341 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 10342 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10343 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10344 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10345 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10346};
10347
197edd35 10348/* Structure describing the image type XPM. */
6fc2811b
JR
10349
10350static struct image_type xpm_type =
10351{
10352 &Qxpm,
10353 xpm_image_p,
10354 xpm_load,
10355 x_clear_image,
10356 NULL
10357};
10358
10359
c736ffda
JR
10360/* XPM library details. */
10361
10362DEF_IMGLIB_FN (XpmFreeAttributes);
10363DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
10364DEF_IMGLIB_FN (XpmReadFileToImage);
10365DEF_IMGLIB_FN (XImageFree);
10366
10367
10368static int
10369init_xpm_functions (library)
10370 HMODULE library;
10371{
10372 LOAD_IMGLIB_FN (library, XpmFreeAttributes);
10373 LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
10374 LOAD_IMGLIB_FN (library, XpmReadFileToImage);
10375 LOAD_IMGLIB_FN (library, XImageFree);
10376
10377 return 1;
10378}
10379
6fc2811b
JR
10380/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10381 for XPM images. Such a list must consist of conses whose car and
10382 cdr are strings. */
10383
10384static int
10385xpm_valid_color_symbols_p (color_symbols)
10386 Lisp_Object color_symbols;
10387{
10388 while (CONSP (color_symbols))
10389 {
10390 Lisp_Object sym = XCAR (color_symbols);
10391 if (!CONSP (sym)
10392 || !STRINGP (XCAR (sym))
10393 || !STRINGP (XCDR (sym)))
10394 break;
10395 color_symbols = XCDR (color_symbols);
10396 }
10397
10398 return NILP (color_symbols);
10399}
10400
10401
10402/* Value is non-zero if OBJECT is a valid XPM image specification. */
10403
10404static int
10405xpm_image_p (object)
10406 Lisp_Object object;
10407{
10408 struct image_keyword fmt[XPM_LAST];
10409 bcopy (xpm_format, fmt, sizeof fmt);
10410 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10411 /* Either `:file' or `:data' must be present. */
10412 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10413 /* Either no `:color-symbols' or it's a list of conses
10414 whose car and cdr are strings. */
10415 && (fmt[XPM_COLOR_SYMBOLS].count == 0
8f92c555 10416 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
6fc2811b
JR
10417}
10418
10419
10420/* Load image IMG which will be displayed on frame F. Value is
10421 non-zero if successful. */
10422
10423static int
10424xpm_load (f, img)
10425 struct frame *f;
10426 struct image *img;
10427{
c736ffda
JR
10428 HDC hdc;
10429 int rc;
6fc2811b
JR
10430 XpmAttributes attrs;
10431 Lisp_Object specified_file, color_symbols;
c736ffda 10432 xpm_XImage * xpm_image, * xpm_mask;
6fc2811b
JR
10433
10434 /* Configure the XPM lib. Use the visual of frame F. Allocate
10435 close colors. Return colors allocated. */
10436 bzero (&attrs, sizeof attrs);
c736ffda
JR
10437 xpm_image = xpm_mask = NULL;
10438
10439#if 0
dfff8a69
JR
10440 attrs.visual = FRAME_X_VISUAL (f);
10441 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 10442 attrs.valuemask |= XpmVisual;
dfff8a69 10443 attrs.valuemask |= XpmColormap;
c736ffda 10444#endif
6fc2811b 10445 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 10446#ifdef XpmAllocCloseColors
6fc2811b
JR
10447 attrs.alloc_close_colors = 1;
10448 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
10449#else
10450 attrs.closeness = 600;
10451 attrs.valuemask |= XpmCloseness;
10452#endif
6fc2811b
JR
10453
10454 /* If image specification contains symbolic color definitions, add
10455 these to `attrs'. */
10456 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10457 if (CONSP (color_symbols))
10458 {
10459 Lisp_Object tail;
10460 XpmColorSymbol *xpm_syms;
10461 int i, size;
7d0393cf 10462
6fc2811b
JR
10463 attrs.valuemask |= XpmColorSymbols;
10464
10465 /* Count number of symbols. */
10466 attrs.numsymbols = 0;
10467 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10468 ++attrs.numsymbols;
10469
10470 /* Allocate an XpmColorSymbol array. */
10471 size = attrs.numsymbols * sizeof *xpm_syms;
10472 xpm_syms = (XpmColorSymbol *) alloca (size);
10473 bzero (xpm_syms, size);
10474 attrs.colorsymbols = xpm_syms;
10475
10476 /* Fill the color symbol array. */
10477 for (tail = color_symbols, i = 0;
10478 CONSP (tail);
10479 ++i, tail = XCDR (tail))
10480 {
10481 Lisp_Object name = XCAR (XCAR (tail));
10482 Lisp_Object color = XCDR (XCAR (tail));
d5db4077
KR
10483 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
10484 strcpy (xpm_syms[i].name, SDATA (name));
10485 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
10486 strcpy (xpm_syms[i].value, SDATA (color));
6fc2811b
JR
10487 }
10488 }
10489
10490 /* Create a pixmap for the image, either from a file, or from a
10491 string buffer containing data in the same format as an XPM file. */
c736ffda 10492
6fc2811b 10493 specified_file = image_spec_value (img->spec, QCfile, NULL);
177c0ea7 10494
c736ffda
JR
10495 {
10496 HDC frame_dc = get_frame_dc (f);
10497 hdc = CreateCompatibleDC (frame_dc);
10498 release_frame_dc (f, frame_dc);
10499 }
10500
6fc2811b
JR
10501 if (STRINGP (specified_file))
10502 {
10503 Lisp_Object file = x_find_image_file (specified_file);
10504 if (!STRINGP (file))
10505 {
10506 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6fc2811b
JR
10507 return 0;
10508 }
7d0393cf 10509
c736ffda
JR
10510 /* XpmReadFileToPixmap is not available in the Windows port of
10511 libxpm. But XpmReadFileToImage almost does what we want. */
10512 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
10513 &xpm_image, &xpm_mask,
10514 &attrs);
6fc2811b
JR
10515 }
10516 else
10517 {
10518 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
c736ffda
JR
10519 /* XpmCreatePixmapFromBuffer is not available in the Windows port
10520 of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
10521 rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer),
10522 &xpm_image, &xpm_mask,
10523 &attrs);
6fc2811b 10524 }
6fc2811b
JR
10525
10526 if (rc == XpmSuccess)
10527 {
c736ffda
JR
10528 int i;
10529
10530 /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap,
10531 plus some duplicate attributes. */
10532 if (xpm_image && xpm_image->bitmap)
10533 {
10534 img->pixmap = xpm_image->bitmap;
10535 /* XImageFree in libXpm frees XImage struct without destroying
10536 the bitmap, which is what we want. */
10537 fn_XImageFree (xpm_image);
10538 }
10539 if (xpm_mask && xpm_mask->bitmap)
177c0ea7 10540 {
c736ffda
JR
10541 /* The mask appears to be inverted compared with what we expect.
10542 TODO: invert our expectations. See other places where we
10543 have to invert bits because our idea of masks is backwards. */
10544 HGDIOBJ old_obj;
10545 old_obj = SelectObject (hdc, xpm_mask->bitmap);
10546
10547 PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT);
10548 SelectObject (hdc, old_obj);
10549
10550 img->mask = xpm_mask->bitmap;
177c0ea7 10551 fn_XImageFree (xpm_mask);
c736ffda
JR
10552 DeleteDC (hdc);
10553 }
10554
10555 DeleteDC (hdc);
10556
6fc2811b
JR
10557 /* Remember allocated colors. */
10558 img->ncolors = attrs.nalloc_pixels;
10559 img->colors = (unsigned long *) xmalloc (img->ncolors
10560 * sizeof *img->colors);
10561 for (i = 0; i < attrs.nalloc_pixels; ++i)
10562 img->colors[i] = attrs.alloc_pixels[i];
10563
10564 img->width = attrs.width;
10565 img->height = attrs.height;
10566 xassert (img->width > 0 && img->height > 0);
10567
10568 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
c736ffda 10569 fn_XpmFreeAttributes (&attrs);
6fc2811b
JR
10570 }
10571 else
10572 {
c736ffda
JR
10573 DeleteDC (hdc);
10574
6fc2811b
JR
10575 switch (rc)
10576 {
10577 case XpmOpenFailed:
10578 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10579 break;
7d0393cf 10580
6fc2811b
JR
10581 case XpmFileInvalid:
10582 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10583 break;
7d0393cf 10584
6fc2811b
JR
10585 case XpmNoMemory:
10586 image_error ("Out of memory (%s)", img->spec, Qnil);
10587 break;
7d0393cf 10588
6fc2811b
JR
10589 case XpmColorFailed:
10590 image_error ("Color allocation error (%s)", img->spec, Qnil);
10591 break;
7d0393cf 10592
6fc2811b
JR
10593 default:
10594 image_error ("Unknown error (%s)", img->spec, Qnil);
10595 break;
10596 }
10597 }
10598
10599 return rc == XpmSuccess;
10600}
10601
10602#endif /* HAVE_XPM != 0 */
10603
10604\f
767b1ff0 10605#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
10606/***********************************************************************
10607 Color table
10608 ***********************************************************************/
10609
10610/* An entry in the color table mapping an RGB color to a pixel color. */
10611
10612struct ct_color
10613{
10614 int r, g, b;
10615 unsigned long pixel;
10616
10617 /* Next in color table collision list. */
10618 struct ct_color *next;
10619};
10620
10621/* The bucket vector size to use. Must be prime. */
10622
10623#define CT_SIZE 101
10624
10625/* Value is a hash of the RGB color given by R, G, and B. */
10626
10627#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10628
10629/* The color hash table. */
10630
10631struct ct_color **ct_table;
10632
10633/* Number of entries in the color table. */
10634
10635int ct_colors_allocated;
10636
10637/* Function prototypes. */
10638
10639static void init_color_table P_ ((void));
10640static void free_color_table P_ ((void));
10641static unsigned long *colors_in_color_table P_ ((int *n));
10642static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10643static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10644
10645
10646/* Initialize the color table. */
10647
10648static void
10649init_color_table ()
10650{
10651 int size = CT_SIZE * sizeof (*ct_table);
10652 ct_table = (struct ct_color **) xmalloc (size);
10653 bzero (ct_table, size);
10654 ct_colors_allocated = 0;
10655}
10656
10657
10658/* Free memory associated with the color table. */
10659
10660static void
10661free_color_table ()
10662{
10663 int i;
10664 struct ct_color *p, *next;
10665
10666 for (i = 0; i < CT_SIZE; ++i)
10667 for (p = ct_table[i]; p; p = next)
10668 {
10669 next = p->next;
10670 xfree (p);
10671 }
10672
10673 xfree (ct_table);
10674 ct_table = NULL;
10675}
10676
10677
10678/* Value is a pixel color for RGB color R, G, B on frame F. If an
10679 entry for that color already is in the color table, return the
10680 pixel color of that entry. Otherwise, allocate a new color for R,
10681 G, B, and make an entry in the color table. */
10682
10683static unsigned long
10684lookup_rgb_color (f, r, g, b)
10685 struct frame *f;
10686 int r, g, b;
10687{
10688 unsigned hash = CT_HASH_RGB (r, g, b);
10689 int i = hash % CT_SIZE;
10690 struct ct_color *p;
10691
10692 for (p = ct_table[i]; p; p = p->next)
10693 if (p->r == r && p->g == g && p->b == b)
10694 break;
10695
10696 if (p == NULL)
10697 {
10698 COLORREF color;
10699 Colormap cmap;
10700 int rc;
10701
10702 color = PALETTERGB (r, g, b);
10703
10704 ++ct_colors_allocated;
10705
10706 p = (struct ct_color *) xmalloc (sizeof *p);
10707 p->r = r;
10708 p->g = g;
10709 p->b = b;
10710 p->pixel = color;
10711 p->next = ct_table[i];
10712 ct_table[i] = p;
10713 }
10714
10715 return p->pixel;
10716}
10717
10718
10719/* Look up pixel color PIXEL which is used on frame F in the color
10720 table. If not already present, allocate it. Value is PIXEL. */
10721
10722static unsigned long
10723lookup_pixel_color (f, pixel)
10724 struct frame *f;
10725 unsigned long pixel;
10726{
10727 int i = pixel % CT_SIZE;
10728 struct ct_color *p;
10729
10730 for (p = ct_table[i]; p; p = p->next)
10731 if (p->pixel == pixel)
10732 break;
10733
10734 if (p == NULL)
10735 {
10736 XColor color;
10737 Colormap cmap;
10738 int rc;
10739
10740 BLOCK_INPUT;
7d0393cf 10741
6fc2811b
JR
10742 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10743 color.pixel = pixel;
10744 XQueryColor (NULL, cmap, &color);
10745 rc = x_alloc_nearest_color (f, cmap, &color);
10746 UNBLOCK_INPUT;
10747
10748 if (rc)
10749 {
10750 ++ct_colors_allocated;
7d0393cf 10751
6fc2811b
JR
10752 p = (struct ct_color *) xmalloc (sizeof *p);
10753 p->r = color.red;
10754 p->g = color.green;
10755 p->b = color.blue;
10756 p->pixel = pixel;
10757 p->next = ct_table[i];
10758 ct_table[i] = p;
10759 }
10760 else
10761 return FRAME_FOREGROUND_PIXEL (f);
10762 }
10763 return p->pixel;
10764}
10765
10766
10767/* Value is a vector of all pixel colors contained in the color table,
10768 allocated via xmalloc. Set *N to the number of colors. */
10769
10770static unsigned long *
10771colors_in_color_table (n)
10772 int *n;
10773{
10774 int i, j;
10775 struct ct_color *p;
10776 unsigned long *colors;
10777
10778 if (ct_colors_allocated == 0)
10779 {
10780 *n = 0;
10781 colors = NULL;
10782 }
10783 else
10784 {
10785 colors = (unsigned long *) xmalloc (ct_colors_allocated
10786 * sizeof *colors);
10787 *n = ct_colors_allocated;
7d0393cf 10788
6fc2811b
JR
10789 for (i = j = 0; i < CT_SIZE; ++i)
10790 for (p = ct_table[i]; p; p = p->next)
10791 colors[j++] = p->pixel;
10792 }
10793
10794 return colors;
10795}
10796
767b1ff0 10797#endif /* TODO */
6fc2811b
JR
10798
10799\f
10800/***********************************************************************
10801 Algorithms
10802 ***********************************************************************/
3cf3436e
JR
10803static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10804static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10805static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
ac849ba4 10806static void XPutPixel (XImage *, int, int, COLORREF);
3cf3436e
JR
10807
10808/* Non-zero means draw a cross on images having `:conversion
10809 disabled'. */
6fc2811b 10810
3cf3436e 10811int cross_disabled_images;
6fc2811b 10812
3cf3436e
JR
10813/* Edge detection matrices for different edge-detection
10814 strategies. */
6fc2811b 10815
3cf3436e
JR
10816static int emboss_matrix[9] = {
10817 /* x - 1 x x + 1 */
10818 2, -1, 0, /* y - 1 */
10819 -1, 0, 1, /* y */
10820 0, 1, -2 /* y + 1 */
10821};
10822
10823static int laplace_matrix[9] = {
10824 /* x - 1 x x + 1 */
10825 1, 0, 0, /* y - 1 */
10826 0, 0, 0, /* y */
10827 0, 0, -1 /* y + 1 */
10828};
10829
10830/* Value is the intensity of the color whose red/green/blue values
10831 are R, G, and B. */
10832
10833#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10834
10835
10836/* On frame F, return an array of XColor structures describing image
10837 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10838 non-zero means also fill the red/green/blue members of the XColor
10839 structures. Value is a pointer to the array of XColors structures,
10840 allocated with xmalloc; it must be freed by the caller. */
10841
10842static XColor *
10843x_to_xcolors (f, img, rgb_p)
10844 struct frame *f;
10845 struct image *img;
10846 int rgb_p;
10847{
10848 int x, y;
10849 XColor *colors, *p;
197edd35
JR
10850 HDC hdc, bmpdc;
10851 HGDIOBJ prev;
3cf3436e
JR
10852
10853 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
197edd35
JR
10854
10855 /* Load the image into a memory device context. */
10856 hdc = get_frame_dc (f);
10857 bmpdc = CreateCompatibleDC (hdc);
10858 release_frame_dc (f, hdc);
10859 prev = SelectObject (bmpdc, img->pixmap);
3cf3436e
JR
10860
10861 /* Fill the `pixel' members of the XColor array. I wished there
10862 were an easy and portable way to circumvent XGetPixel. */
10863 p = colors;
10864 for (y = 0; y < img->height; ++y)
10865 {
10866 XColor *row = p;
7d0393cf 10867
3cf3436e 10868 for (x = 0; x < img->width; ++x, ++p)
197edd35
JR
10869 {
10870 /* TODO: palette support needed here? */
10871 p->pixel = GetPixel (bmpdc, x, y);
3cf3436e 10872
197edd35
JR
10873 if (rgb_p)
10874 {
10875 p->red = 256 * GetRValue (p->pixel);
10876 p->green = 256 * GetGValue (p->pixel);
10877 p->blue = 256 * GetBValue (p->pixel);
10878 }
10879 }
3cf3436e
JR
10880 }
10881
197edd35
JR
10882 SelectObject (bmpdc, prev);
10883 DeleteDC (bmpdc);
10884
3cf3436e
JR
10885 return colors;
10886}
10887
ac849ba4
JR
10888/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10889 created with CreateDIBSection, with the pointer to the bit values
10890 stored in ximg->data. */
10891
10892static void XPutPixel (ximg, x, y, color)
10893 XImage * ximg;
10894 int x, y;
10895 COLORREF color;
10896{
10897 int width = ximg->info.bmiHeader.biWidth;
10898 int height = ximg->info.bmiHeader.biHeight;
ac849ba4
JR
10899 unsigned char * pixel;
10900
54eefef1
JR
10901 /* True color images. */
10902 if (ximg->info.bmiHeader.biBitCount == 24)
10903 {
10904 int rowbytes = width * 3;
10905 /* Ensure scanlines are aligned on 4 byte boundaries. */
10906 if (rowbytes % 4)
10907 rowbytes += 4 - (rowbytes % 4);
10908
10909 pixel = ximg->data + y * rowbytes + x * 3;
10910 /* Windows bitmaps are in BGR order. */
10911 *pixel = GetBValue (color);
10912 *(pixel + 1) = GetGValue (color);
10913 *(pixel + 2) = GetRValue (color);
10914 }
10915 /* Monochrome images. */
10916 else if (ximg->info.bmiHeader.biBitCount == 1)
10917 {
10918 int rowbytes = width / 8;
10919 /* Ensure scanlines are aligned on 4 byte boundaries. */
10920 if (rowbytes % 4)
10921 rowbytes += 4 - (rowbytes % 4);
10922 pixel = ximg->data + y * rowbytes + x / 8;
10923 /* Filter out palette info. */
10924 if (color & 0x00ffffff)
10925 *pixel = *pixel | (1 << x % 8);
10926 else
10927 *pixel = *pixel & ~(1 << x % 8);
10928 }
10929 else
839b1909 10930 image_error ("XPutPixel: palette image not supported.", Qnil, Qnil);
ac849ba4
JR
10931}
10932
3cf3436e
JR
10933/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10934 RGB members are set. F is the frame on which this all happens.
10935 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10936
10937static void
3cf3436e 10938x_from_xcolors (f, img, colors)
6fc2811b 10939 struct frame *f;
3cf3436e 10940 struct image *img;
6fc2811b 10941 XColor *colors;
6fc2811b 10942{
3cf3436e
JR
10943 int x, y;
10944 XImage *oimg;
10945 Pixmap pixmap;
10946 XColor *p;
ac849ba4 10947#if 0 /* TODO: color tables. */
3cf3436e 10948 init_color_table ();
ac849ba4 10949#endif
3cf3436e
JR
10950 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10951 &oimg, &pixmap);
10952 p = colors;
10953 for (y = 0; y < img->height; ++y)
10954 for (x = 0; x < img->width; ++x, ++p)
10955 {
10956 unsigned long pixel;
ac849ba4 10957#if 0 /* TODO: color tables. */
3cf3436e 10958 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
ac849ba4 10959#else
197edd35 10960 pixel = PALETTERGB (p->red / 256, p->green / 256, p->blue / 256);
ac849ba4 10961#endif
3cf3436e
JR
10962 XPutPixel (oimg, x, y, pixel);
10963 }
6fc2811b 10964
3cf3436e
JR
10965 xfree (colors);
10966 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10967
3cf3436e
JR
10968 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10969 x_destroy_x_image (oimg);
10970 img->pixmap = pixmap;
ac849ba4 10971#if 0 /* TODO: color tables. */
3cf3436e
JR
10972 img->colors = colors_in_color_table (&img->ncolors);
10973 free_color_table ();
ac849ba4 10974#endif
6fc2811b
JR
10975}
10976
10977
3cf3436e
JR
10978/* On frame F, perform edge-detection on image IMG.
10979
10980 MATRIX is a nine-element array specifying the transformation
10981 matrix. See emboss_matrix for an example.
7d0393cf 10982
3cf3436e
JR
10983 COLOR_ADJUST is a color adjustment added to each pixel of the
10984 outgoing image. */
6fc2811b
JR
10985
10986static void
3cf3436e 10987x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10988 struct frame *f;
3cf3436e
JR
10989 struct image *img;
10990 int matrix[9], color_adjust;
6fc2811b 10991{
3cf3436e
JR
10992 XColor *colors = x_to_xcolors (f, img, 1);
10993 XColor *new, *p;
10994 int x, y, i, sum;
10995
10996 for (i = sum = 0; i < 9; ++i)
10997 sum += abs (matrix[i]);
10998
10999#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
11000
11001 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
11002
11003 for (y = 0; y < img->height; ++y)
11004 {
11005 p = COLOR (new, 0, y);
11006 p->red = p->green = p->blue = 0xffff/2;
11007 p = COLOR (new, img->width - 1, y);
11008 p->red = p->green = p->blue = 0xffff/2;
11009 }
7d0393cf 11010
3cf3436e
JR
11011 for (x = 1; x < img->width - 1; ++x)
11012 {
11013 p = COLOR (new, x, 0);
11014 p->red = p->green = p->blue = 0xffff/2;
11015 p = COLOR (new, x, img->height - 1);
11016 p->red = p->green = p->blue = 0xffff/2;
11017 }
11018
11019 for (y = 1; y < img->height - 1; ++y)
11020 {
11021 p = COLOR (new, 1, y);
7d0393cf 11022
3cf3436e
JR
11023 for (x = 1; x < img->width - 1; ++x, ++p)
11024 {
11025 int r, g, b, y1, x1;
11026
11027 r = g = b = i = 0;
11028 for (y1 = y - 1; y1 < y + 2; ++y1)
11029 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
11030 if (matrix[i])
11031 {
11032 XColor *t = COLOR (colors, x1, y1);
11033 r += matrix[i] * t->red;
11034 g += matrix[i] * t->green;
11035 b += matrix[i] * t->blue;
11036 }
11037
11038 r = (r / sum + color_adjust) & 0xffff;
11039 g = (g / sum + color_adjust) & 0xffff;
11040 b = (b / sum + color_adjust) & 0xffff;
11041 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
11042 }
11043 }
11044
11045 xfree (colors);
11046 x_from_xcolors (f, img, new);
11047
11048#undef COLOR
11049}
11050
11051
11052/* Perform the pre-defined `emboss' edge-detection on image IMG
11053 on frame F. */
11054
11055static void
11056x_emboss (f, img)
11057 struct frame *f;
11058 struct image *img;
11059{
11060 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 11061}
3cf3436e 11062
6fc2811b
JR
11063
11064/* Transform image IMG which is used on frame F with a Laplace
11065 edge-detection algorithm. The result is an image that can be used
11066 to draw disabled buttons, for example. */
11067
11068static void
11069x_laplace (f, img)
11070 struct frame *f;
11071 struct image *img;
11072{
3cf3436e
JR
11073 x_detect_edges (f, img, laplace_matrix, 45000);
11074}
6fc2811b 11075
6fc2811b 11076
3cf3436e
JR
11077/* Perform edge-detection on image IMG on frame F, with specified
11078 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 11079
3cf3436e 11080 MATRIX must be either
6fc2811b 11081
3cf3436e
JR
11082 - a list of at least 9 numbers in row-major form
11083 - a vector of at least 9 numbers
6fc2811b 11084
3cf3436e
JR
11085 COLOR_ADJUST nil means use a default; otherwise it must be a
11086 number. */
6fc2811b 11087
3cf3436e
JR
11088static void
11089x_edge_detection (f, img, matrix, color_adjust)
11090 struct frame *f;
11091 struct image *img;
11092 Lisp_Object matrix, color_adjust;
11093{
11094 int i = 0;
11095 int trans[9];
7d0393cf 11096
3cf3436e 11097 if (CONSP (matrix))
6fc2811b 11098 {
3cf3436e
JR
11099 for (i = 0;
11100 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
11101 ++i, matrix = XCDR (matrix))
11102 trans[i] = XFLOATINT (XCAR (matrix));
11103 }
11104 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
11105 {
11106 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
11107 trans[i] = XFLOATINT (AREF (matrix, i));
11108 }
11109
11110 if (NILP (color_adjust))
11111 color_adjust = make_number (0xffff / 2);
11112
11113 if (i == 9 && NUMBERP (color_adjust))
11114 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
11115}
11116
6fc2811b 11117
3cf3436e 11118/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 11119
3cf3436e
JR
11120static void
11121x_disable_image (f, img)
11122 struct frame *f;
11123 struct image *img;
11124{
ac849ba4 11125 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3cf3436e 11126
ac849ba4 11127 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
3cf3436e
JR
11128 {
11129 /* Color (or grayscale). Convert to gray, and equalize. Just
11130 drawing such images with a stipple can look very odd, so
11131 we're using this method instead. */
11132 XColor *colors = x_to_xcolors (f, img, 1);
11133 XColor *p, *end;
11134 const int h = 15000;
11135 const int l = 30000;
11136
11137 for (p = colors, end = colors + img->width * img->height;
11138 p < end;
11139 ++p)
6fc2811b 11140 {
3cf3436e
JR
11141 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
11142 int i2 = (0xffff - h - l) * i / 0xffff + l;
11143 p->red = p->green = p->blue = i2;
6fc2811b
JR
11144 }
11145
3cf3436e 11146 x_from_xcolors (f, img, colors);
6fc2811b
JR
11147 }
11148
3cf3436e
JR
11149 /* Draw a cross over the disabled image, if we must or if we
11150 should. */
ac849ba4 11151 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
3cf3436e 11152 {
197edd35
JR
11153 HDC hdc, bmpdc;
11154 HGDIOBJ prev;
11155
11156 hdc = get_frame_dc (f);
11157 bmpdc = CreateCompatibleDC (hdc);
11158 release_frame_dc (f, hdc);
11159
11160 prev = SelectObject (bmpdc, img->pixmap);
6fc2811b 11161
197edd35
JR
11162 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
11163 MoveToEx (bmpdc, 0, 0, NULL);
11164 LineTo (bmpdc, img->width - 1, img->height - 1);
11165 MoveToEx (bmpdc, 0, img->height - 1, NULL);
11166 LineTo (bmpdc, img->width - 1, 0);
6fc2811b 11167
3cf3436e
JR
11168 if (img->mask)
11169 {
197edd35
JR
11170 SelectObject (bmpdc, img->mask);
11171 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
11172 MoveToEx (bmpdc, 0, 0, NULL);
11173 LineTo (bmpdc, img->width - 1, img->height - 1);
11174 MoveToEx (bmpdc, 0, img->height - 1, NULL);
11175 LineTo (bmpdc, img->width - 1, 0);
3cf3436e 11176 }
197edd35
JR
11177 SelectObject (bmpdc, prev);
11178 DeleteDC (bmpdc);
3cf3436e 11179 }
6fc2811b
JR
11180}
11181
11182
11183/* Build a mask for image IMG which is used on frame F. FILE is the
11184 name of an image file, for error messages. HOW determines how to
11185 determine the background color of IMG. If it is a list '(R G B)',
11186 with R, G, and B being integers >= 0, take that as the color of the
11187 background. Otherwise, determine the background color of IMG
11188 heuristically. Value is non-zero if successful. */
11189
11190static int
11191x_build_heuristic_mask (f, img, how)
11192 struct frame *f;
11193 struct image *img;
11194 Lisp_Object how;
11195{
197edd35
JR
11196 HDC img_dc, frame_dc;
11197 HGDIOBJ prev;
11198 char *mask_img;
a05e2bae
JR
11199 int x, y, rc, use_img_background;
11200 unsigned long bg = 0;
197edd35 11201 int row_width;
a05e2bae
JR
11202
11203 if (img->mask)
11204 {
197edd35
JR
11205 DeleteObject (img->mask);
11206 img->mask = NULL;
a05e2bae
JR
11207 img->background_transparent_valid = 0;
11208 }
6fc2811b 11209
197edd35
JR
11210 /* Create the bit array serving as mask. */
11211 row_width = (img->width + 7) / 8;
11212 mask_img = xmalloc (row_width * img->height);
11213 bzero (mask_img, row_width * img->height);
6fc2811b 11214
197edd35
JR
11215 /* Create a memory device context for IMG->pixmap. */
11216 frame_dc = get_frame_dc (f);
11217 img_dc = CreateCompatibleDC (frame_dc);
11218 release_frame_dc (f, frame_dc);
11219 prev = SelectObject (img_dc, img->pixmap);
6fc2811b 11220
197edd35 11221 /* Determine the background color of img_dc. If HOW is `(R G B)'
a05e2bae
JR
11222 take that as color. Otherwise, use the image's background color. */
11223 use_img_background = 1;
7d0393cf 11224
6fc2811b
JR
11225 if (CONSP (how))
11226 {
a05e2bae 11227 int rgb[3], i;
6fc2811b 11228
a05e2bae 11229 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
11230 {
11231 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
11232 how = XCDR (how);
11233 }
11234
11235 if (i == 3 && NILP (how))
11236 {
11237 char color_name[30];
6fc2811b 11238 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
0040b876 11239 bg = x_alloc_image_color (f, img, build_string (color_name), 0)
8f92c555 11240 & 0x00ffffff; /* Filter out palette info. */
a05e2bae 11241 use_img_background = 0;
6fc2811b
JR
11242 }
11243 }
7d0393cf 11244
a05e2bae 11245 if (use_img_background)
197edd35 11246 bg = four_corners_best (img_dc, img->width, img->height);
6fc2811b
JR
11247
11248 /* Set all bits in mask_img to 1 whose color in ximg is different
11249 from the background color bg. */
11250 for (y = 0; y < img->height; ++y)
11251 for (x = 0; x < img->width; ++x)
197edd35
JR
11252 {
11253 COLORREF p = GetPixel (img_dc, x, y);
11254 if (p != bg)
11255 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
11256 }
11257
11258 /* Create the mask image. */
11259 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
11260 mask_img);
6fc2811b 11261
a05e2bae 11262 /* Fill in the background_transparent field while we have the mask handy. */
197edd35
JR
11263 SelectObject (img_dc, img->mask);
11264
11265 image_background_transparent (img, f, img_dc);
a05e2bae 11266
6fc2811b 11267 /* Put mask_img into img->mask. */
54eefef1 11268 x_destroy_x_image ((XImage *)mask_img);
197edd35
JR
11269 SelectObject (img_dc, prev);
11270 DeleteDC (img_dc);
6fc2811b
JR
11271
11272 return 1;
11273}
217e5be0 11274
6fc2811b
JR
11275\f
11276/***********************************************************************
11277 PBM (mono, gray, color)
11278 ***********************************************************************/
6fc2811b
JR
11279
11280static int pbm_image_p P_ ((Lisp_Object object));
11281static int pbm_load P_ ((struct frame *f, struct image *img));
11282static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11283
11284/* The symbol `pbm' identifying images of this type. */
11285
11286Lisp_Object Qpbm;
11287
11288/* Indices of image specification fields in gs_format, below. */
11289
11290enum pbm_keyword_index
11291{
11292 PBM_TYPE,
11293 PBM_FILE,
11294 PBM_DATA,
11295 PBM_ASCENT,
11296 PBM_MARGIN,
11297 PBM_RELIEF,
11298 PBM_ALGORITHM,
11299 PBM_HEURISTIC_MASK,
a05e2bae
JR
11300 PBM_MASK,
11301 PBM_FOREGROUND,
11302 PBM_BACKGROUND,
6fc2811b
JR
11303 PBM_LAST
11304};
11305
11306/* Vector of image_keyword structures describing the format
11307 of valid user-defined image specifications. */
11308
11309static struct image_keyword pbm_format[PBM_LAST] =
11310{
11311 {":type", IMAGE_SYMBOL_VALUE, 1},
11312 {":file", IMAGE_STRING_VALUE, 0},
11313 {":data", IMAGE_STRING_VALUE, 0},
8f92c555 11314 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 11315 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11316 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11317 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
11318 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11319 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11320 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11321 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11322};
11323
11324/* Structure describing the image type `pbm'. */
11325
11326static struct image_type pbm_type =
11327{
11328 &Qpbm,
11329 pbm_image_p,
11330 pbm_load,
11331 x_clear_image,
11332 NULL
11333};
11334
11335
11336/* Return non-zero if OBJECT is a valid PBM image specification. */
11337
11338static int
11339pbm_image_p (object)
11340 Lisp_Object object;
11341{
11342 struct image_keyword fmt[PBM_LAST];
7d0393cf 11343
6fc2811b 11344 bcopy (pbm_format, fmt, sizeof fmt);
7d0393cf 11345
8f92c555 11346 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
6fc2811b
JR
11347 return 0;
11348
11349 /* Must specify either :data or :file. */
11350 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11351}
11352
11353
11354/* Scan a decimal number from *S and return it. Advance *S while
11355 reading the number. END is the end of the string. Value is -1 at
11356 end of input. */
11357
11358static int
11359pbm_scan_number (s, end)
11360 unsigned char **s, *end;
11361{
11362 int c, val = -1;
11363
11364 while (*s < end)
11365 {
11366 /* Skip white-space. */
11367 while (*s < end && (c = *(*s)++, isspace (c)))
11368 ;
11369
11370 if (c == '#')
11371 {
11372 /* Skip comment to end of line. */
11373 while (*s < end && (c = *(*s)++, c != '\n'))
11374 ;
11375 }
11376 else if (isdigit (c))
11377 {
11378 /* Read decimal number. */
11379 val = c - '0';
11380 while (*s < end && (c = *(*s)++, isdigit (c)))
11381 val = 10 * val + c - '0';
11382 break;
11383 }
11384 else
11385 break;
11386 }
11387
11388 return val;
11389}
11390
11391
11392/* Read FILE into memory. Value is a pointer to a buffer allocated
11393 with xmalloc holding FILE's contents. Value is null if an error
6f826971 11394 occurred. *SIZE is set to the size of the file. */
6fc2811b
JR
11395
11396static char *
11397pbm_read_file (file, size)
11398 Lisp_Object file;
11399 int *size;
11400{
11401 FILE *fp = NULL;
11402 char *buf = NULL;
11403 struct stat st;
11404
d5db4077
KR
11405 if (stat (SDATA (file), &st) == 0
11406 && (fp = fopen (SDATA (file), "r")) != NULL
6fc2811b
JR
11407 && (buf = (char *) xmalloc (st.st_size),
11408 fread (buf, 1, st.st_size, fp) == st.st_size))
11409 {
11410 *size = st.st_size;
11411 fclose (fp);
11412 }
11413 else
11414 {
11415 if (fp)
11416 fclose (fp);
11417 if (buf)
11418 {
11419 xfree (buf);
11420 buf = NULL;
11421 }
11422 }
7d0393cf 11423
6fc2811b
JR
11424 return buf;
11425}
11426
11427
11428/* Load PBM image IMG for use on frame F. */
11429
7d0393cf 11430static int
6fc2811b
JR
11431pbm_load (f, img)
11432 struct frame *f;
11433 struct image *img;
11434{
11435 int raw_p, x, y;
11436 int width, height, max_color_idx = 0;
11437 XImage *ximg;
11438 Lisp_Object file, specified_file;
11439 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11440 struct gcpro gcpro1;
11441 unsigned char *contents = NULL;
11442 unsigned char *end, *p;
11443 int size;
11444
11445 specified_file = image_spec_value (img->spec, QCfile, NULL);
11446 file = Qnil;
11447 GCPRO1 (file);
11448
11449 if (STRINGP (specified_file))
11450 {
11451 file = x_find_image_file (specified_file);
11452 if (!STRINGP (file))
11453 {
11454 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11455 UNGCPRO;
11456 return 0;
11457 }
11458
d5db4077 11459 contents = slurp_file (SDATA (file), &size);
6fc2811b
JR
11460 if (contents == NULL)
11461 {
11462 image_error ("Error reading `%s'", file, Qnil);
11463 UNGCPRO;
11464 return 0;
11465 }
11466
11467 p = contents;
11468 end = contents + size;
11469 }
11470 else
11471 {
11472 Lisp_Object data;
11473 data = image_spec_value (img->spec, QCdata, NULL);
d5db4077
KR
11474 p = SDATA (data);
11475 end = p + SBYTES (data);
6fc2811b
JR
11476 }
11477
11478 /* Check magic number. */
11479 if (end - p < 2 || *p++ != 'P')
11480 {
11481 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11482 error:
11483 xfree (contents);
11484 UNGCPRO;
11485 return 0;
11486 }
11487
6fc2811b
JR
11488 switch (*p++)
11489 {
11490 case '1':
11491 raw_p = 0, type = PBM_MONO;
11492 break;
7d0393cf 11493
6fc2811b
JR
11494 case '2':
11495 raw_p = 0, type = PBM_GRAY;
11496 break;
11497
11498 case '3':
11499 raw_p = 0, type = PBM_COLOR;
11500 break;
11501
11502 case '4':
11503 raw_p = 1, type = PBM_MONO;
11504 break;
7d0393cf 11505
6fc2811b
JR
11506 case '5':
11507 raw_p = 1, type = PBM_GRAY;
11508 break;
7d0393cf 11509
6fc2811b
JR
11510 case '6':
11511 raw_p = 1, type = PBM_COLOR;
11512 break;
11513
11514 default:
11515 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11516 goto error;
11517 }
11518
11519 /* Read width, height, maximum color-component. Characters
11520 starting with `#' up to the end of a line are ignored. */
11521 width = pbm_scan_number (&p, end);
11522 height = pbm_scan_number (&p, end);
11523
11524 if (type != PBM_MONO)
11525 {
11526 max_color_idx = pbm_scan_number (&p, end);
11527 if (raw_p && max_color_idx > 255)
11528 max_color_idx = 255;
11529 }
7d0393cf 11530
6fc2811b
JR
11531 if (width < 0
11532 || height < 0
11533 || (type != PBM_MONO && max_color_idx < 0))
11534 goto error;
11535
ac849ba4 11536 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
3cf3436e
JR
11537 goto error;
11538
ac849ba4 11539#if 0 /* TODO: color tables. */
6fc2811b
JR
11540 /* Initialize the color hash table. */
11541 init_color_table ();
ac849ba4 11542#endif
6fc2811b
JR
11543
11544 if (type == PBM_MONO)
11545 {
11546 int c = 0, g;
3cf3436e
JR
11547 struct image_keyword fmt[PBM_LAST];
11548 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11549 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11550
11551 /* Parse the image specification. */
11552 bcopy (pbm_format, fmt, sizeof fmt);
11553 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
7d0393cf 11554
3cf3436e
JR
11555 /* Get foreground and background colors, maybe allocate colors. */
11556 if (fmt[PBM_FOREGROUND].count
11557 && STRINGP (fmt[PBM_FOREGROUND].value))
11558 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11559 if (fmt[PBM_BACKGROUND].count
11560 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
11561 {
11562 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11563 img->background = bg;
11564 img->background_valid = 1;
11565 }
11566
6fc2811b
JR
11567 for (y = 0; y < height; ++y)
11568 for (x = 0; x < width; ++x)
11569 {
11570 if (raw_p)
11571 {
11572 if ((x & 7) == 0)
11573 c = *p++;
11574 g = c & 0x80;
11575 c <<= 1;
11576 }
11577 else
11578 g = pbm_scan_number (&p, end);
11579
3cf3436e 11580 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
11581 }
11582 }
11583 else
11584 {
11585 for (y = 0; y < height; ++y)
11586 for (x = 0; x < width; ++x)
11587 {
11588 int r, g, b;
7d0393cf 11589
6fc2811b
JR
11590 if (type == PBM_GRAY)
11591 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11592 else if (raw_p)
11593 {
11594 r = *p++;
11595 g = *p++;
11596 b = *p++;
11597 }
11598 else
11599 {
11600 r = pbm_scan_number (&p, end);
11601 g = pbm_scan_number (&p, end);
11602 b = pbm_scan_number (&p, end);
11603 }
7d0393cf 11604
6fc2811b
JR
11605 if (r < 0 || g < 0 || b < 0)
11606 {
ac849ba4 11607 x_destroy_x_image (ximg);
6fc2811b
JR
11608 image_error ("Invalid pixel value in image `%s'",
11609 img->spec, Qnil);
11610 goto error;
11611 }
7d0393cf 11612
6fc2811b 11613 /* RGB values are now in the range 0..max_color_idx.
ac849ba4
JR
11614 Scale this to the range 0..0xff supported by W32. */
11615 r = (int) ((double) r * 255 / max_color_idx);
11616 g = (int) ((double) g * 255 / max_color_idx);
11617 b = (int) ((double) b * 255 / max_color_idx);
11618 XPutPixel (ximg, x, y,
11619#if 0 /* TODO: color tables. */
11620 lookup_rgb_color (f, r, g, b));
11621#else
11622 PALETTERGB (r, g, b));
11623#endif
6fc2811b
JR
11624 }
11625 }
ac849ba4
JR
11626
11627#if 0 /* TODO: color tables. */
6fc2811b
JR
11628 /* Store in IMG->colors the colors allocated for the image, and
11629 free the color table. */
11630 img->colors = colors_in_color_table (&img->ncolors);
11631 free_color_table ();
ac849ba4 11632#endif
a05e2bae
JR
11633 /* Maybe fill in the background field while we have ximg handy. */
11634 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11635 IMAGE_BACKGROUND (img, f, ximg);
7d0393cf 11636
6fc2811b
JR
11637 /* Put the image into a pixmap. */
11638 x_put_x_image (f, ximg, img->pixmap, width, height);
11639 x_destroy_x_image (ximg);
7d0393cf 11640
6fc2811b
JR
11641 img->width = width;
11642 img->height = height;
11643
11644 UNGCPRO;
11645 xfree (contents);
11646 return 1;
11647}
6fc2811b
JR
11648
11649\f
11650/***********************************************************************
11651 PNG
11652 ***********************************************************************/
11653
11654#if HAVE_PNG
11655
11656#include <png.h>
11657
11658/* Function prototypes. */
11659
11660static int png_image_p P_ ((Lisp_Object object));
11661static int png_load P_ ((struct frame *f, struct image *img));
11662
11663/* The symbol `png' identifying images of this type. */
11664
11665Lisp_Object Qpng;
11666
11667/* Indices of image specification fields in png_format, below. */
11668
11669enum png_keyword_index
11670{
11671 PNG_TYPE,
11672 PNG_DATA,
11673 PNG_FILE,
11674 PNG_ASCENT,
11675 PNG_MARGIN,
11676 PNG_RELIEF,
11677 PNG_ALGORITHM,
11678 PNG_HEURISTIC_MASK,
a05e2bae
JR
11679 PNG_MASK,
11680 PNG_BACKGROUND,
6fc2811b
JR
11681 PNG_LAST
11682};
11683
11684/* Vector of image_keyword structures describing the format
11685 of valid user-defined image specifications. */
11686
11687static struct image_keyword png_format[PNG_LAST] =
11688{
11689 {":type", IMAGE_SYMBOL_VALUE, 1},
11690 {":data", IMAGE_STRING_VALUE, 0},
11691 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 11692 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 11693 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11694 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11695 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11696 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11697 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11698 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11699};
11700
11701/* Structure describing the image type `png'. */
11702
11703static struct image_type png_type =
11704{
11705 &Qpng,
11706 png_image_p,
11707 png_load,
11708 x_clear_image,
11709 NULL
11710};
11711
839b1909
JR
11712/* PNG library details. */
11713
11714DEF_IMGLIB_FN (png_get_io_ptr);
11715DEF_IMGLIB_FN (png_check_sig);
11716DEF_IMGLIB_FN (png_create_read_struct);
11717DEF_IMGLIB_FN (png_create_info_struct);
11718DEF_IMGLIB_FN (png_destroy_read_struct);
11719DEF_IMGLIB_FN (png_set_read_fn);
c922a224 11720DEF_IMGLIB_FN (png_init_io);
839b1909
JR
11721DEF_IMGLIB_FN (png_set_sig_bytes);
11722DEF_IMGLIB_FN (png_read_info);
11723DEF_IMGLIB_FN (png_get_IHDR);
11724DEF_IMGLIB_FN (png_get_valid);
11725DEF_IMGLIB_FN (png_set_strip_16);
11726DEF_IMGLIB_FN (png_set_expand);
11727DEF_IMGLIB_FN (png_set_gray_to_rgb);
11728DEF_IMGLIB_FN (png_set_background);
11729DEF_IMGLIB_FN (png_get_bKGD);
11730DEF_IMGLIB_FN (png_read_update_info);
11731DEF_IMGLIB_FN (png_get_channels);
11732DEF_IMGLIB_FN (png_get_rowbytes);
11733DEF_IMGLIB_FN (png_read_image);
11734DEF_IMGLIB_FN (png_read_end);
11735DEF_IMGLIB_FN (png_error);
11736
11737static int
11738init_png_functions (library)
11739 HMODULE library;
11740{
11741 LOAD_IMGLIB_FN (library, png_get_io_ptr);
11742 LOAD_IMGLIB_FN (library, png_check_sig);
11743 LOAD_IMGLIB_FN (library, png_create_read_struct);
11744 LOAD_IMGLIB_FN (library, png_create_info_struct);
11745 LOAD_IMGLIB_FN (library, png_destroy_read_struct);
11746 LOAD_IMGLIB_FN (library, png_set_read_fn);
c922a224 11747 LOAD_IMGLIB_FN (library, png_init_io);
839b1909
JR
11748 LOAD_IMGLIB_FN (library, png_set_sig_bytes);
11749 LOAD_IMGLIB_FN (library, png_read_info);
11750 LOAD_IMGLIB_FN (library, png_get_IHDR);
11751 LOAD_IMGLIB_FN (library, png_get_valid);
11752 LOAD_IMGLIB_FN (library, png_set_strip_16);
11753 LOAD_IMGLIB_FN (library, png_set_expand);
11754 LOAD_IMGLIB_FN (library, png_set_gray_to_rgb);
11755 LOAD_IMGLIB_FN (library, png_set_background);
11756 LOAD_IMGLIB_FN (library, png_get_bKGD);
11757 LOAD_IMGLIB_FN (library, png_read_update_info);
11758 LOAD_IMGLIB_FN (library, png_get_channels);
11759 LOAD_IMGLIB_FN (library, png_get_rowbytes);
11760 LOAD_IMGLIB_FN (library, png_read_image);
11761 LOAD_IMGLIB_FN (library, png_read_end);
11762 LOAD_IMGLIB_FN (library, png_error);
11763 return 1;
11764}
6fc2811b
JR
11765
11766/* Return non-zero if OBJECT is a valid PNG image specification. */
11767
11768static int
11769png_image_p (object)
11770 Lisp_Object object;
11771{
11772 struct image_keyword fmt[PNG_LAST];
11773 bcopy (png_format, fmt, sizeof fmt);
c922a224 11774
8f92c555 11775 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
6fc2811b
JR
11776 return 0;
11777
11778 /* Must specify either the :data or :file keyword. */
11779 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11780}
11781
11782
11783/* Error and warning handlers installed when the PNG library
11784 is initialized. */
11785
11786static void
11787my_png_error (png_ptr, msg)
11788 png_struct *png_ptr;
11789 char *msg;
11790{
11791 xassert (png_ptr != NULL);
11792 image_error ("PNG error: %s", build_string (msg), Qnil);
11793 longjmp (png_ptr->jmpbuf, 1);
11794}
11795
11796
11797static void
11798my_png_warning (png_ptr, msg)
11799 png_struct *png_ptr;
11800 char *msg;
11801{
11802 xassert (png_ptr != NULL);
11803 image_error ("PNG warning: %s", build_string (msg), Qnil);
11804}
11805
6fc2811b
JR
11806/* Memory source for PNG decoding. */
11807
11808struct png_memory_storage
11809{
11810 unsigned char *bytes; /* The data */
11811 size_t len; /* How big is it? */
11812 int index; /* Where are we? */
11813};
11814
11815
11816/* Function set as reader function when reading PNG image from memory.
11817 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11818 bytes from the input to DATA. */
11819
11820static void
11821png_read_from_memory (png_ptr, data, length)
11822 png_structp png_ptr;
11823 png_bytep data;
11824 png_size_t length;
11825{
11826 struct png_memory_storage *tbr
839b1909 11827 = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
6fc2811b
JR
11828
11829 if (length > tbr->len - tbr->index)
839b1909 11830 fn_png_error (png_ptr, "Read error");
c922a224 11831
6fc2811b
JR
11832 bcopy (tbr->bytes + tbr->index, data, length);
11833 tbr->index = tbr->index + length;
11834}
11835
6fc2811b
JR
11836/* Load PNG image IMG for use on frame F. Value is non-zero if
11837 successful. */
11838
11839static int
11840png_load (f, img)
11841 struct frame *f;
11842 struct image *img;
11843{
11844 Lisp_Object file, specified_file;
11845 Lisp_Object specified_data;
11846 int x, y, i;
11847 XImage *ximg, *mask_img = NULL;
11848 struct gcpro gcpro1;
11849 png_struct *png_ptr = NULL;
11850 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11851 FILE *volatile fp = NULL;
6fc2811b 11852 png_byte sig[8];
54eefef1
JR
11853 png_byte * volatile pixels = NULL;
11854 png_byte ** volatile rows = NULL;
6fc2811b
JR
11855 png_uint_32 width, height;
11856 int bit_depth, color_type, interlace_type;
11857 png_byte channels;
11858 png_uint_32 row_bytes;
11859 int transparent_p;
6fc2811b
JR
11860 double screen_gamma, image_gamma;
11861 int intent;
11862 struct png_memory_storage tbr; /* Data to be read */
11863
11864 /* Find out what file to load. */
11865 specified_file = image_spec_value (img->spec, QCfile, NULL);
11866 specified_data = image_spec_value (img->spec, QCdata, NULL);
11867 file = Qnil;
11868 GCPRO1 (file);
11869
11870 if (NILP (specified_data))
11871 {
11872 file = x_find_image_file (specified_file);
11873 if (!STRINGP (file))
54eefef1
JR
11874 {
11875 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11876 UNGCPRO;
11877 return 0;
11878 }
6fc2811b
JR
11879
11880 /* Open the image file. */
d5db4077 11881 fp = fopen (SDATA (file), "rb");
6fc2811b 11882 if (!fp)
54eefef1
JR
11883 {
11884 image_error ("Cannot open image file `%s'", file, Qnil);
11885 UNGCPRO;
11886 fclose (fp);
11887 return 0;
11888 }
6fc2811b
JR
11889
11890 /* Check PNG signature. */
11891 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
839b1909 11892 || !fn_png_check_sig (sig, sizeof sig))
54eefef1
JR
11893 {
11894 image_error ("Not a PNG file: `%s'", file, Qnil);
11895 UNGCPRO;
11896 fclose (fp);
11897 return 0;
11898 }
6fc2811b
JR
11899 }
11900 else
11901 {
11902 /* Read from memory. */
d5db4077
KR
11903 tbr.bytes = SDATA (specified_data);
11904 tbr.len = SBYTES (specified_data);
6fc2811b
JR
11905 tbr.index = 0;
11906
11907 /* Check PNG signature. */
11908 if (tbr.len < sizeof sig
839b1909 11909 || !fn_png_check_sig (tbr.bytes, sizeof sig))
6fc2811b
JR
11910 {
11911 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11912 UNGCPRO;
11913 return 0;
11914 }
11915
11916 /* Need to skip past the signature. */
11917 tbr.bytes += sizeof (sig);
11918 }
11919
6fc2811b 11920 /* Initialize read and info structs for PNG lib. */
839b1909
JR
11921 png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11922 my_png_error, my_png_warning);
6fc2811b
JR
11923 if (!png_ptr)
11924 {
11925 if (fp) fclose (fp);
11926 UNGCPRO;
11927 return 0;
11928 }
11929
839b1909 11930 info_ptr = fn_png_create_info_struct (png_ptr);
6fc2811b
JR
11931 if (!info_ptr)
11932 {
839b1909 11933 fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
6fc2811b
JR
11934 if (fp) fclose (fp);
11935 UNGCPRO;
11936 return 0;
11937 }
11938
839b1909 11939 end_info = fn_png_create_info_struct (png_ptr);
6fc2811b
JR
11940 if (!end_info)
11941 {
839b1909 11942 fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
6fc2811b
JR
11943 if (fp) fclose (fp);
11944 UNGCPRO;
11945 return 0;
11946 }
11947
11948 /* Set error jump-back. We come back here when the PNG library
11949 detects an error. */
11950 if (setjmp (png_ptr->jmpbuf))
11951 {
11952 error:
11953 if (png_ptr)
839b1909 11954 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6fc2811b
JR
11955 xfree (pixels);
11956 xfree (rows);
11957 if (fp) fclose (fp);
11958 UNGCPRO;
11959 return 0;
11960 }
11961
11962 /* Read image info. */
11963 if (!NILP (specified_data))
839b1909 11964 fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
6fc2811b 11965 else
839b1909 11966 fn_png_init_io (png_ptr, fp);
6fc2811b 11967
839b1909
JR
11968 fn_png_set_sig_bytes (png_ptr, sizeof sig);
11969 fn_png_read_info (png_ptr, info_ptr);
11970 fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11971 &interlace_type, NULL, NULL);
6fc2811b 11972
c922a224 11973 /* If image contains simply transparency data, we prefer to
6fc2811b 11974 construct a clipping mask. */
839b1909 11975 if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
6fc2811b
JR
11976 transparent_p = 1;
11977 else
11978 transparent_p = 0;
11979
c922a224 11980 /* This function is easier to write if we only have to handle
6fc2811b
JR
11981 one data format: RGB or RGBA with 8 bits per channel. Let's
11982 transform other formats into that format. */
11983
11984 /* Strip more than 8 bits per channel. */
11985 if (bit_depth == 16)
839b1909 11986 fn_png_set_strip_16 (png_ptr);
6fc2811b
JR
11987
11988 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11989 if available. */
839b1909 11990 fn_png_set_expand (png_ptr);
6fc2811b
JR
11991
11992 /* Convert grayscale images to RGB. */
c922a224 11993 if (color_type == PNG_COLOR_TYPE_GRAY
6fc2811b 11994 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
839b1909 11995 fn_png_set_gray_to_rgb (png_ptr);
6fc2811b 11996
54eefef1 11997 screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
6fc2811b 11998
54eefef1 11999#if 0 /* Avoid double gamma correction for PNG images. */
6fc2811b 12000 /* Tell the PNG lib to handle gamma correction for us. */
6fc2811b
JR
12001#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
12002 if (png_get_sRGB (png_ptr, info_ptr, &intent))
54eefef1
JR
12003 /* The libpng documentation says this is right in this case. */
12004 png_set_gamma (png_ptr, screen_gamma, 0.45455);
6fc2811b
JR
12005 else
12006#endif
12007 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
12008 /* Image contains gamma information. */
12009 png_set_gamma (png_ptr, screen_gamma, image_gamma);
12010 else
54eefef1
JR
12011 /* Use the standard default for the image gamma. */
12012 png_set_gamma (png_ptr, screen_gamma, 0.45455);
12013#endif /* if 0 */
6fc2811b
JR
12014
12015 /* Handle alpha channel by combining the image with a background
12016 color. Do this only if a real alpha channel is supplied. For
12017 simple transparency, we prefer a clipping mask. */
12018 if (!transparent_p)
12019 {
54eefef1 12020 png_color_16 *image_bg;
a05e2bae
JR
12021 Lisp_Object specified_bg
12022 = image_spec_value (img->spec, QCbackground, NULL);
12023
a05e2bae
JR
12024 if (STRINGP (specified_bg))
12025 /* The user specified `:background', use that. */
12026 {
12027 COLORREF color;
d5db4077 12028 if (w32_defined_color (f, SDATA (specified_bg), &color, 0))
a05e2bae
JR
12029 {
12030 png_color_16 user_bg;
12031
12032 bzero (&user_bg, sizeof user_bg);
54eefef1
JR
12033 user_bg.red = 256 * GetRValue (color);
12034 user_bg.green = 256 * GetGValue (color);
12035 user_bg.blue = 256 * GetBValue (color);
6fc2811b 12036
839b1909
JR
12037 fn_png_set_background (png_ptr, &user_bg,
12038 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
a05e2bae
JR
12039 }
12040 }
839b1909 12041 else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
c922a224 12042 /* Image contains a background color with which to
6fc2811b 12043 combine the image. */
839b1909
JR
12044 fn_png_set_background (png_ptr, image_bg,
12045 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
6fc2811b
JR
12046 else
12047 {
12048 /* Image does not contain a background color with which
c922a224 12049 to combine the image data via an alpha channel. Use
6fc2811b 12050 the frame's background instead. */
54eefef1 12051 COLORREF color;
6fc2811b 12052 png_color_16 frame_background;
54eefef1
JR
12053 color = FRAME_BACKGROUND_PIXEL (f);
12054#if 0 /* TODO : Colormap support. */
12055 Colormap cmap;
6fc2811b 12056
a05e2bae 12057 cmap = FRAME_X_COLORMAP (f);
a05e2bae 12058 x_query_color (f, &color);
54eefef1 12059#endif
6fc2811b
JR
12060
12061 bzero (&frame_background, sizeof frame_background);
54eefef1
JR
12062 frame_background.red = 256 * GetRValue (color);
12063 frame_background.green = 256 * GetGValue (color);
12064 frame_background.blue = 256 * GetBValue (color);
6fc2811b 12065
839b1909
JR
12066 fn_png_set_background (png_ptr, &frame_background,
12067 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
6fc2811b
JR
12068 }
12069 }
12070
12071 /* Update info structure. */
839b1909 12072 fn_png_read_update_info (png_ptr, info_ptr);
6fc2811b
JR
12073
12074 /* Get number of channels. Valid values are 1 for grayscale images
12075 and images with a palette, 2 for grayscale images with transparency
12076 information (alpha channel), 3 for RGB images, and 4 for RGB
12077 images with alpha channel, i.e. RGBA. If conversions above were
12078 sufficient we should only have 3 or 4 channels here. */
839b1909 12079 channels = fn_png_get_channels (png_ptr, info_ptr);
6fc2811b
JR
12080 xassert (channels == 3 || channels == 4);
12081
12082 /* Number of bytes needed for one row of the image. */
839b1909 12083 row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
6fc2811b
JR
12084
12085 /* Allocate memory for the image. */
12086 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
12087 rows = (png_byte **) xmalloc (height * sizeof *rows);
12088 for (i = 0; i < height; ++i)
12089 rows[i] = pixels + i * row_bytes;
12090
12091 /* Read the entire image. */
839b1909
JR
12092 fn_png_read_image (png_ptr, rows);
12093 fn_png_read_end (png_ptr, info_ptr);
6fc2811b
JR
12094 if (fp)
12095 {
12096 fclose (fp);
12097 fp = NULL;
12098 }
c922a224 12099
6fc2811b
JR
12100 /* Create the X image and pixmap. */
12101 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12102 &img->pixmap))
a05e2bae 12103 goto error;
c922a224 12104
6fc2811b
JR
12105 /* Create an image and pixmap serving as mask if the PNG image
12106 contains an alpha channel. */
12107 if (channels == 4
12108 && !transparent_p
12109 && !x_create_x_image_and_pixmap (f, width, height, 1,
12110 &mask_img, &img->mask))
12111 {
12112 x_destroy_x_image (ximg);
54eefef1 12113 DeleteObject (img->pixmap);
6fc2811b 12114 img->pixmap = 0;
6fc2811b
JR
12115 goto error;
12116 }
6fc2811b 12117 /* Fill the X image and mask from PNG data. */
54eefef1 12118#if 0 /* TODO: Color tables. */
6fc2811b 12119 init_color_table ();
54eefef1 12120#endif
6fc2811b
JR
12121
12122 for (y = 0; y < height; ++y)
12123 {
12124 png_byte *p = rows[y];
12125
12126 for (x = 0; x < width; ++x)
12127 {
12128 unsigned r, g, b;
12129
54eefef1
JR
12130 r = *p++;
12131 g = *p++;
12132 b = *p++;
12133#if 0 /* TODO: Color tables. */
6fc2811b 12134 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
54eefef1
JR
12135#else
12136 XPutPixel (ximg, x, y, PALETTERGB (r, g, b));
12137#endif
6fc2811b 12138 /* An alpha channel, aka mask channel, associates variable
c922a224
JB
12139 transparency with an image. Where other image formats
12140 support binary transparency---fully transparent or fully
6fc2811b
JR
12141 opaque---PNG allows up to 254 levels of partial transparency.
12142 The PNG library implements partial transparency by combining
12143 the image with a specified background color.
12144
12145 I'm not sure how to handle this here nicely: because the
12146 background on which the image is displayed may change, for
c922a224
JB
12147 real alpha channel support, it would be necessary to create
12148 a new image for each possible background.
6fc2811b
JR
12149
12150 What I'm doing now is that a mask is created if we have
12151 boolean transparency information. Otherwise I'm using
12152 the frame's background color to combine the image with. */
12153
12154 if (channels == 4)
12155 {
12156 if (mask_img)
12157 XPutPixel (mask_img, x, y, *p > 0);
12158 ++p;
12159 }
12160 }
12161 }
12162
a05e2bae
JR
12163 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12164 /* Set IMG's background color from the PNG image, unless the user
12165 overrode it. */
12166 {
12167 png_color_16 *bg;
839b1909 12168 if (fn_png_get_bKGD (png_ptr, info_ptr, &bg))
a05e2bae 12169 {
54eefef1 12170#if 0 /* TODO: Color tables. */
a05e2bae 12171 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
54eefef1
JR
12172#else
12173 img->background = PALETTERGB (bg->red / 256, bg->green / 256,
12174 bg->blue / 256);
12175#endif
a05e2bae
JR
12176 img->background_valid = 1;
12177 }
12178 }
12179
54eefef1 12180#if 0 /* TODO: Color tables. */
6fc2811b
JR
12181 /* Remember colors allocated for this image. */
12182 img->colors = colors_in_color_table (&img->ncolors);
12183 free_color_table ();
54eefef1 12184#endif
6fc2811b
JR
12185
12186 /* Clean up. */
839b1909 12187 fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
6fc2811b
JR
12188 xfree (rows);
12189 xfree (pixels);
12190
12191 img->width = width;
12192 img->height = height;
12193
a05e2bae
JR
12194 /* Maybe fill in the background field while we have ximg handy. */
12195 IMAGE_BACKGROUND (img, f, ximg);
12196
6fc2811b
JR
12197 /* Put the image into the pixmap, then free the X image and its buffer. */
12198 x_put_x_image (f, ximg, img->pixmap, width, height);
12199 x_destroy_x_image (ximg);
12200
12201 /* Same for the mask. */
12202 if (mask_img)
12203 {
a05e2bae
JR
12204 /* Fill in the background_transparent field while we have the mask
12205 handy. */
12206 image_background_transparent (img, f, mask_img);
12207
6fc2811b
JR
12208 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
12209 x_destroy_x_image (mask_img);
12210 }
12211
6fc2811b
JR
12212 UNGCPRO;
12213 return 1;
12214}
12215
12216#endif /* HAVE_PNG != 0 */
12217
12218
12219\f
12220/***********************************************************************
12221 JPEG
12222 ***********************************************************************/
12223
12224#if HAVE_JPEG
12225
12226/* Work around a warning about HAVE_STDLIB_H being redefined in
12227 jconfig.h. */
12228#ifdef HAVE_STDLIB_H
12229#define HAVE_STDLIB_H_1
12230#undef HAVE_STDLIB_H
12231#endif /* HAVE_STLIB_H */
12232
12233#include <jpeglib.h>
12234#include <jerror.h>
12235#include <setjmp.h>
12236
12237#ifdef HAVE_STLIB_H_1
12238#define HAVE_STDLIB_H 1
12239#endif
12240
12241static int jpeg_image_p P_ ((Lisp_Object object));
12242static int jpeg_load P_ ((struct frame *f, struct image *img));
12243
12244/* The symbol `jpeg' identifying images of this type. */
12245
12246Lisp_Object Qjpeg;
12247
12248/* Indices of image specification fields in gs_format, below. */
12249
12250enum jpeg_keyword_index
12251{
12252 JPEG_TYPE,
12253 JPEG_DATA,
12254 JPEG_FILE,
12255 JPEG_ASCENT,
12256 JPEG_MARGIN,
12257 JPEG_RELIEF,
12258 JPEG_ALGORITHM,
12259 JPEG_HEURISTIC_MASK,
a05e2bae
JR
12260 JPEG_MASK,
12261 JPEG_BACKGROUND,
6fc2811b
JR
12262 JPEG_LAST
12263};
12264
12265/* Vector of image_keyword structures describing the format
12266 of valid user-defined image specifications. */
12267
12268static struct image_keyword jpeg_format[JPEG_LAST] =
12269{
12270 {":type", IMAGE_SYMBOL_VALUE, 1},
12271 {":data", IMAGE_STRING_VALUE, 0},
12272 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 12273 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 12274 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12275 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12276 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12277 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12278 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12279 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12280};
12281
12282/* Structure describing the image type `jpeg'. */
12283
12284static struct image_type jpeg_type =
12285{
12286 &Qjpeg,
12287 jpeg_image_p,
12288 jpeg_load,
12289 x_clear_image,
12290 NULL
12291};
12292
12293
afc390dc
JR
12294/* JPEG library details. */
12295DEF_IMGLIB_FN (jpeg_CreateDecompress);
12296DEF_IMGLIB_FN (jpeg_start_decompress);
12297DEF_IMGLIB_FN (jpeg_finish_decompress);
12298DEF_IMGLIB_FN (jpeg_destroy_decompress);
12299DEF_IMGLIB_FN (jpeg_read_header);
12300DEF_IMGLIB_FN (jpeg_read_scanlines);
12301DEF_IMGLIB_FN (jpeg_stdio_src);
12302DEF_IMGLIB_FN (jpeg_std_error);
12303DEF_IMGLIB_FN (jpeg_resync_to_restart);
12304
12305static int
12306init_jpeg_functions (library)
12307 HMODULE library;
12308{
12309 LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
12310 LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
12311 LOAD_IMGLIB_FN (library, jpeg_start_decompress);
12312 LOAD_IMGLIB_FN (library, jpeg_read_header);
12313 LOAD_IMGLIB_FN (library, jpeg_stdio_src);
12314 LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
12315 LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
12316 LOAD_IMGLIB_FN (library, jpeg_std_error);
12317 LOAD_IMGLIB_FN (library, jpeg_resync_to_restart);
12318 return 1;
12319}
12320
12321/* Wrapper since we can't directly assign the function pointer
12322 to another function pointer that was declared more completely easily. */
12323static boolean
12324jpeg_resync_to_restart_wrapper(cinfo, desired)
12325 j_decompress_ptr cinfo;
12326 int desired;
12327{
12328 return fn_jpeg_resync_to_restart (cinfo, desired);
12329}
12330
12331
6fc2811b
JR
12332/* Return non-zero if OBJECT is a valid JPEG image specification. */
12333
12334static int
12335jpeg_image_p (object)
12336 Lisp_Object object;
12337{
12338 struct image_keyword fmt[JPEG_LAST];
c922a224 12339
6fc2811b 12340 bcopy (jpeg_format, fmt, sizeof fmt);
c922a224 12341
8f92c555 12342 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
6fc2811b
JR
12343 return 0;
12344
12345 /* Must specify either the :data or :file keyword. */
12346 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
12347}
12348
12349
12350struct my_jpeg_error_mgr
12351{
12352 struct jpeg_error_mgr pub;
12353 jmp_buf setjmp_buffer;
12354};
12355
afc390dc 12356
6fc2811b
JR
12357static void
12358my_error_exit (cinfo)
12359 j_common_ptr cinfo;
12360{
12361 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12362 longjmp (mgr->setjmp_buffer, 1);
12363}
12364
afc390dc 12365
6fc2811b
JR
12366/* Init source method for JPEG data source manager. Called by
12367 jpeg_read_header() before any data is actually read. See
12368 libjpeg.doc from the JPEG lib distribution. */
12369
12370static void
12371our_init_source (cinfo)
12372 j_decompress_ptr cinfo;
12373{
12374}
12375
12376
12377/* Fill input buffer method for JPEG data source manager. Called
12378 whenever more data is needed. We read the whole image in one step,
12379 so this only adds a fake end of input marker at the end. */
12380
12381static boolean
12382our_fill_input_buffer (cinfo)
12383 j_decompress_ptr cinfo;
12384{
12385 /* Insert a fake EOI marker. */
12386 struct jpeg_source_mgr *src = cinfo->src;
12387 static JOCTET buffer[2];
12388
12389 buffer[0] = (JOCTET) 0xFF;
12390 buffer[1] = (JOCTET) JPEG_EOI;
12391
12392 src->next_input_byte = buffer;
12393 src->bytes_in_buffer = 2;
12394 return TRUE;
12395}
12396
12397
12398/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12399 is the JPEG data source manager. */
12400
12401static void
12402our_skip_input_data (cinfo, num_bytes)
12403 j_decompress_ptr cinfo;
12404 long num_bytes;
12405{
12406 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12407
12408 if (src)
12409 {
12410 if (num_bytes > src->bytes_in_buffer)
12411 ERREXIT (cinfo, JERR_INPUT_EOF);
c922a224 12412
6fc2811b
JR
12413 src->bytes_in_buffer -= num_bytes;
12414 src->next_input_byte += num_bytes;
12415 }
12416}
12417
12418
12419/* Method to terminate data source. Called by
12420 jpeg_finish_decompress() after all data has been processed. */
12421
12422static void
12423our_term_source (cinfo)
12424 j_decompress_ptr cinfo;
12425{
12426}
12427
12428
12429/* Set up the JPEG lib for reading an image from DATA which contains
12430 LEN bytes. CINFO is the decompression info structure created for
12431 reading the image. */
12432
12433static void
12434jpeg_memory_src (cinfo, data, len)
12435 j_decompress_ptr cinfo;
12436 JOCTET *data;
12437 unsigned int len;
12438{
12439 struct jpeg_source_mgr *src;
12440
12441 if (cinfo->src == NULL)
12442 {
12443 /* First time for this JPEG object? */
12444 cinfo->src = (struct jpeg_source_mgr *)
12445 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12446 sizeof (struct jpeg_source_mgr));
12447 src = (struct jpeg_source_mgr *) cinfo->src;
12448 src->next_input_byte = data;
12449 }
c922a224 12450
6fc2811b
JR
12451 src = (struct jpeg_source_mgr *) cinfo->src;
12452 src->init_source = our_init_source;
12453 src->fill_input_buffer = our_fill_input_buffer;
12454 src->skip_input_data = our_skip_input_data;
afc390dc 12455 src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
6fc2811b
JR
12456 src->term_source = our_term_source;
12457 src->bytes_in_buffer = len;
12458 src->next_input_byte = data;
12459}
12460
12461
12462/* Load image IMG for use on frame F. Patterned after example.c
12463 from the JPEG lib. */
12464
c922a224 12465static int
6fc2811b
JR
12466jpeg_load (f, img)
12467 struct frame *f;
12468 struct image *img;
12469{
12470 struct jpeg_decompress_struct cinfo;
12471 struct my_jpeg_error_mgr mgr;
12472 Lisp_Object file, specified_file;
12473 Lisp_Object specified_data;
a05e2bae 12474 FILE * volatile fp = NULL;
6fc2811b
JR
12475 JSAMPARRAY buffer;
12476 int row_stride, x, y;
12477 XImage *ximg = NULL;
12478 int rc;
12479 unsigned long *colors;
12480 int width, height;
12481 struct gcpro gcpro1;
12482
12483 /* Open the JPEG file. */
12484 specified_file = image_spec_value (img->spec, QCfile, NULL);
12485 specified_data = image_spec_value (img->spec, QCdata, NULL);
12486 file = Qnil;
12487 GCPRO1 (file);
12488
6fc2811b
JR
12489 if (NILP (specified_data))
12490 {
12491 file = x_find_image_file (specified_file);
12492 if (!STRINGP (file))
afc390dc
JR
12493 {
12494 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12495 UNGCPRO;
12496 return 0;
12497 }
c922a224 12498
d5db4077 12499 fp = fopen (SDATA (file), "r");
6fc2811b 12500 if (fp == NULL)
afc390dc
JR
12501 {
12502 image_error ("Cannot open `%s'", file, Qnil);
12503 UNGCPRO;
12504 return 0;
12505 }
6fc2811b 12506 }
7d0393cf 12507
6fc2811b 12508 /* Customize libjpeg's error handling to call my_error_exit when an
afc390dc
JR
12509 error is detected. This function will perform a longjmp. */
12510 cinfo.err = fn_jpeg_std_error (&mgr.pub);
a05e2bae 12511 mgr.pub.error_exit = my_error_exit;
c922a224 12512
6fc2811b
JR
12513 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12514 {
12515 if (rc == 1)
12516 {
12517 /* Called from my_error_exit. Display a JPEG error. */
12518 char buffer[JMSG_LENGTH_MAX];
12519 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12520 image_error ("Error reading JPEG image `%s': %s", img->spec,
12521 build_string (buffer));
12522 }
c922a224 12523
6fc2811b
JR
12524 /* Close the input file and destroy the JPEG object. */
12525 if (fp)
afc390dc
JR
12526 fclose ((FILE *) fp);
12527 fn_jpeg_destroy_decompress (&cinfo);
7d0393cf 12528
6fc2811b
JR
12529 /* If we already have an XImage, free that. */
12530 x_destroy_x_image (ximg);
12531
12532 /* Free pixmap and colors. */
12533 x_clear_image (f, img);
c922a224 12534
6fc2811b
JR
12535 UNGCPRO;
12536 return 0;
12537 }
12538
12539 /* Create the JPEG decompression object. Let it read from fp.
afc390dc
JR
12540 Read the JPEG image header. */
12541 fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
6fc2811b
JR
12542
12543 if (NILP (specified_data))
afc390dc 12544 fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
6fc2811b 12545 else
d5db4077
KR
12546 jpeg_memory_src (&cinfo, SDATA (specified_data),
12547 SBYTES (specified_data));
6fc2811b 12548
afc390dc 12549 fn_jpeg_read_header (&cinfo, TRUE);
6fc2811b
JR
12550
12551 /* Customize decompression so that color quantization will be used.
afc390dc 12552 Start decompression. */
6fc2811b 12553 cinfo.quantize_colors = TRUE;
afc390dc 12554 fn_jpeg_start_decompress (&cinfo);
6fc2811b
JR
12555 width = img->width = cinfo.output_width;
12556 height = img->height = cinfo.output_height;
12557
6fc2811b 12558 /* Create X image and pixmap. */
afc390dc 12559 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
a05e2bae 12560 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
12561
12562 /* Allocate colors. When color quantization is used,
12563 cinfo.actual_number_of_colors has been set with the number of
12564 colors generated, and cinfo.colormap is a two-dimensional array
12565 of color indices in the range 0..cinfo.actual_number_of_colors.
12566 No more than 255 colors will be generated. */
12567 {
12568 int i, ir, ig, ib;
12569
12570 if (cinfo.out_color_components > 2)
12571 ir = 0, ig = 1, ib = 2;
12572 else if (cinfo.out_color_components > 1)
12573 ir = 0, ig = 1, ib = 0;
12574 else
12575 ir = 0, ig = 0, ib = 0;
12576
afc390dc 12577#if 0 /* TODO: Color tables. */
6fc2811b
JR
12578 /* Use the color table mechanism because it handles colors that
12579 cannot be allocated nicely. Such colors will be replaced with
12580 a default color, and we don't have to care about which colors
12581 can be freed safely, and which can't. */
12582 init_color_table ();
afc390dc 12583#endif
6fc2811b
JR
12584 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12585 * sizeof *colors);
c922a224 12586
6fc2811b
JR
12587 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12588 {
afc390dc
JR
12589 int r = cinfo.colormap[ir][i];
12590 int g = cinfo.colormap[ig][i];
12591 int b = cinfo.colormap[ib][i];
12592#if 0 /* TODO: Color tables. */
6fc2811b 12593 colors[i] = lookup_rgb_color (f, r, g, b);
afc390dc
JR
12594#else
12595 colors[i] = PALETTERGB (r, g, b);
12596#endif
6fc2811b
JR
12597 }
12598
afc390dc 12599#if 0 /* TODO: Color tables. */
6fc2811b
JR
12600 /* Remember those colors actually allocated. */
12601 img->colors = colors_in_color_table (&img->ncolors);
12602 free_color_table ();
afc390dc 12603#endif
6fc2811b
JR
12604 }
12605
12606 /* Read pixels. */
12607 row_stride = width * cinfo.output_components;
12608 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12609 row_stride, 1);
12610 for (y = 0; y < height; ++y)
12611 {
afc390dc 12612 fn_jpeg_read_scanlines (&cinfo, buffer, 1);
6fc2811b
JR
12613 for (x = 0; x < cinfo.output_width; ++x)
12614 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12615 }
12616
12617 /* Clean up. */
afc390dc
JR
12618 fn_jpeg_finish_decompress (&cinfo);
12619 fn_jpeg_destroy_decompress (&cinfo);
6fc2811b 12620 if (fp)
afc390dc 12621 fclose ((FILE *) fp);
7d0393cf 12622
a05e2bae
JR
12623 /* Maybe fill in the background field while we have ximg handy. */
12624 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12625 IMAGE_BACKGROUND (img, f, ximg);
c922a224 12626
6fc2811b
JR
12627 /* Put the image into the pixmap. */
12628 x_put_x_image (f, ximg, img->pixmap, width, height);
12629 x_destroy_x_image (ximg);
6fc2811b
JR
12630 UNGCPRO;
12631 return 1;
12632}
12633
12634#endif /* HAVE_JPEG */
12635
12636
12637\f
12638/***********************************************************************
12639 TIFF
12640 ***********************************************************************/
12641
12642#if HAVE_TIFF
12643
12644#include <tiffio.h>
12645
12646static int tiff_image_p P_ ((Lisp_Object object));
12647static int tiff_load P_ ((struct frame *f, struct image *img));
12648
12649/* The symbol `tiff' identifying images of this type. */
12650
12651Lisp_Object Qtiff;
12652
12653/* Indices of image specification fields in tiff_format, below. */
12654
12655enum tiff_keyword_index
12656{
12657 TIFF_TYPE,
12658 TIFF_DATA,
12659 TIFF_FILE,
12660 TIFF_ASCENT,
12661 TIFF_MARGIN,
12662 TIFF_RELIEF,
12663 TIFF_ALGORITHM,
12664 TIFF_HEURISTIC_MASK,
a05e2bae
JR
12665 TIFF_MASK,
12666 TIFF_BACKGROUND,
6fc2811b
JR
12667 TIFF_LAST
12668};
12669
12670/* Vector of image_keyword structures describing the format
12671 of valid user-defined image specifications. */
12672
12673static struct image_keyword tiff_format[TIFF_LAST] =
12674{
12675 {":type", IMAGE_SYMBOL_VALUE, 1},
12676 {":data", IMAGE_STRING_VALUE, 0},
12677 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 12678 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 12679 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12680 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12681 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12682 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12683 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12684 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12685};
12686
12687/* Structure describing the image type `tiff'. */
12688
12689static struct image_type tiff_type =
12690{
12691 &Qtiff,
12692 tiff_image_p,
12693 tiff_load,
12694 x_clear_image,
12695 NULL
12696};
12697
12b918b2
JB
12698/* TIFF library details. */
12699DEF_IMGLIB_FN (TIFFSetErrorHandler);
12700DEF_IMGLIB_FN (TIFFSetWarningHandler);
12701DEF_IMGLIB_FN (TIFFOpen);
12702DEF_IMGLIB_FN (TIFFClientOpen);
12703DEF_IMGLIB_FN (TIFFGetField);
12704DEF_IMGLIB_FN (TIFFReadRGBAImage);
12705DEF_IMGLIB_FN (TIFFClose);
12706
12707static int
12708init_tiff_functions (library)
12709 HMODULE library;
12710{
12711 LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
12712 LOAD_IMGLIB_FN (library, TIFFSetWarningHandler);
12713 LOAD_IMGLIB_FN (library, TIFFOpen);
12714 LOAD_IMGLIB_FN (library, TIFFClientOpen);
12715 LOAD_IMGLIB_FN (library, TIFFGetField);
12716 LOAD_IMGLIB_FN (library, TIFFReadRGBAImage);
12717 LOAD_IMGLIB_FN (library, TIFFClose);
12718 return 1;
12719}
6fc2811b
JR
12720
12721/* Return non-zero if OBJECT is a valid TIFF image specification. */
12722
12723static int
12724tiff_image_p (object)
12725 Lisp_Object object;
12726{
12727 struct image_keyword fmt[TIFF_LAST];
12728 bcopy (tiff_format, fmt, sizeof fmt);
7d0393cf 12729
8f92c555 12730 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
6fc2811b 12731 return 0;
7d0393cf 12732
6fc2811b
JR
12733 /* Must specify either the :data or :file keyword. */
12734 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12735}
12736
12737
12738/* Reading from a memory buffer for TIFF images Based on the PNG
12739 memory source, but we have to provide a lot of extra functions.
12740 Blah.
12741
12742 We really only need to implement read and seek, but I am not
12743 convinced that the TIFF library is smart enough not to destroy
12744 itself if we only hand it the function pointers we need to
12745 override. */
12746
12747typedef struct
12748{
12749 unsigned char *bytes;
12750 size_t len;
12751 int index;
12752}
12753tiff_memory_source;
12754
12755static size_t
12756tiff_read_from_memory (data, buf, size)
12757 thandle_t data;
12758 tdata_t buf;
12759 tsize_t size;
12760{
12761 tiff_memory_source *src = (tiff_memory_source *) data;
12762
12763 if (size > src->len - src->index)
12764 return (size_t) -1;
12765 bcopy (src->bytes + src->index, buf, size);
12766 src->index += size;
12767 return size;
12768}
12769
12770static size_t
12771tiff_write_from_memory (data, buf, size)
12772 thandle_t data;
12773 tdata_t buf;
12774 tsize_t size;
12775{
12776 return (size_t) -1;
12777}
12778
12779static toff_t
12780tiff_seek_in_memory (data, off, whence)
12781 thandle_t data;
12782 toff_t off;
12783 int whence;
12784{
12785 tiff_memory_source *src = (tiff_memory_source *) data;
12786 int idx;
12787
12788 switch (whence)
12789 {
12790 case SEEK_SET: /* Go from beginning of source. */
12791 idx = off;
12792 break;
7d0393cf 12793
6fc2811b
JR
12794 case SEEK_END: /* Go from end of source. */
12795 idx = src->len + off;
12796 break;
7d0393cf 12797
6fc2811b
JR
12798 case SEEK_CUR: /* Go from current position. */
12799 idx = src->index + off;
12800 break;
7d0393cf 12801
6fc2811b
JR
12802 default: /* Invalid `whence'. */
12803 return -1;
12804 }
7d0393cf 12805
6fc2811b
JR
12806 if (idx > src->len || idx < 0)
12807 return -1;
7d0393cf 12808
6fc2811b
JR
12809 src->index = idx;
12810 return src->index;
12811}
12812
12813static int
12814tiff_close_memory (data)
12815 thandle_t data;
12816{
12817 /* NOOP */
12818 return 0;
12819}
12820
12821static int
12822tiff_mmap_memory (data, pbase, psize)
12823 thandle_t data;
12824 tdata_t *pbase;
12825 toff_t *psize;
12826{
12827 /* It is already _IN_ memory. */
12828 return 0;
12829}
12830
12831static void
12832tiff_unmap_memory (data, base, size)
12833 thandle_t data;
12834 tdata_t base;
12835 toff_t size;
12836{
12837 /* We don't need to do this. */
12838}
12839
12840static toff_t
12841tiff_size_of_memory (data)
12842 thandle_t data;
12843{
12844 return ((tiff_memory_source *) data)->len;
12845}
12846
3cf3436e
JR
12847
12848static void
12849tiff_error_handler (title, format, ap)
12850 const char *title, *format;
12851 va_list ap;
12852{
12853 char buf[512];
12854 int len;
7d0393cf 12855
3cf3436e
JR
12856 len = sprintf (buf, "TIFF error: %s ", title);
12857 vsprintf (buf + len, format, ap);
12858 add_to_log (buf, Qnil, Qnil);
12859}
12860
12861
12862static void
12863tiff_warning_handler (title, format, ap)
12864 const char *title, *format;
12865 va_list ap;
12866{
12867 char buf[512];
12868 int len;
7d0393cf 12869
3cf3436e
JR
12870 len = sprintf (buf, "TIFF warning: %s ", title);
12871 vsprintf (buf + len, format, ap);
12872 add_to_log (buf, Qnil, Qnil);
12873}
12874
12875
6fc2811b
JR
12876/* Load TIFF image IMG for use on frame F. Value is non-zero if
12877 successful. */
12878
12879static int
12880tiff_load (f, img)
12881 struct frame *f;
12882 struct image *img;
12883{
12884 Lisp_Object file, specified_file;
12885 Lisp_Object specified_data;
12886 TIFF *tiff;
12887 int width, height, x, y;
12888 uint32 *buf;
12889 int rc;
12890 XImage *ximg;
12891 struct gcpro gcpro1;
12892 tiff_memory_source memsrc;
12893
12894 specified_file = image_spec_value (img->spec, QCfile, NULL);
12895 specified_data = image_spec_value (img->spec, QCdata, NULL);
12896 file = Qnil;
12897 GCPRO1 (file);
12898
12b918b2
JB
12899 fn_TIFFSetErrorHandler (tiff_error_handler);
12900 fn_TIFFSetWarningHandler (tiff_warning_handler);
3cf3436e 12901
6fc2811b
JR
12902 if (NILP (specified_data))
12903 {
12904 /* Read from a file */
12905 file = x_find_image_file (specified_file);
12906 if (!STRINGP (file))
3cf3436e
JR
12907 {
12908 image_error ("Cannot find image file `%s'", file, Qnil);
12909 UNGCPRO;
12910 return 0;
12911 }
7d0393cf 12912
6fc2811b 12913 /* Try to open the image file. */
12b918b2 12914 tiff = fn_TIFFOpen (SDATA (file), "r");
6fc2811b 12915 if (tiff == NULL)
3cf3436e
JR
12916 {
12917 image_error ("Cannot open `%s'", file, Qnil);
12918 UNGCPRO;
12919 return 0;
12920 }
6fc2811b
JR
12921 }
12922 else
12923 {
12924 /* Memory source! */
d5db4077
KR
12925 memsrc.bytes = SDATA (specified_data);
12926 memsrc.len = SBYTES (specified_data);
6fc2811b
JR
12927 memsrc.index = 0;
12928
12b918b2
JB
12929 tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
12930 (TIFFReadWriteProc) tiff_read_from_memory,
12931 (TIFFReadWriteProc) tiff_write_from_memory,
12932 tiff_seek_in_memory,
12933 tiff_close_memory,
12934 tiff_size_of_memory,
12935 tiff_mmap_memory,
12936 tiff_unmap_memory);
6fc2811b
JR
12937
12938 if (!tiff)
12939 {
12940 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12941 UNGCPRO;
12942 return 0;
12943 }
12944 }
12945
12946 /* Get width and height of the image, and allocate a raster buffer
12947 of width x height 32-bit values. */
12b918b2
JB
12948 fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12949 fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
6fc2811b 12950 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
7d0393cf 12951
12b918b2
JB
12952 rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
12953 fn_TIFFClose (tiff);
6fc2811b
JR
12954 if (!rc)
12955 {
12956 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12957 xfree (buf);
12958 UNGCPRO;
12959 return 0;
12960 }
12961
6fc2811b
JR
12962 /* Create the X image and pixmap. */
12963 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12964 {
6fc2811b
JR
12965 xfree (buf);
12966 UNGCPRO;
12967 return 0;
12968 }
12969
12b918b2 12970#if 0 /* TODO: Color tables. */
6fc2811b
JR
12971 /* Initialize the color table. */
12972 init_color_table ();
12b918b2 12973#endif
6fc2811b
JR
12974
12975 /* Process the pixel raster. Origin is in the lower-left corner. */
12976 for (y = 0; y < height; ++y)
12977 {
12978 uint32 *row = buf + y * width;
7d0393cf 12979
6fc2811b
JR
12980 for (x = 0; x < width; ++x)
12981 {
12982 uint32 abgr = row[x];
12b918b2
JB
12983 int r = TIFFGetR (abgr);
12984 int g = TIFFGetG (abgr);
12985 int b = TIFFGetB (abgr);
12986#if 0 /* TODO: Color tables. */
7d0393cf 12987 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12b918b2
JB
12988#else
12989 XPutPixel (ximg, x, height - 1 - y, PALETTERGB (r, g, b));
12990#endif
6fc2811b
JR
12991 }
12992 }
12993
12b918b2 12994#if 0 /* TODO: Color tables. */
6fc2811b
JR
12995 /* Remember the colors allocated for the image. Free the color table. */
12996 img->colors = colors_in_color_table (&img->ncolors);
12997 free_color_table ();
12b918b2 12998#endif
6fc2811b 12999
a05e2bae
JR
13000 img->width = width;
13001 img->height = height;
13002
13003 /* Maybe fill in the background field while we have ximg handy. */
13004 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
13005 IMAGE_BACKGROUND (img, f, ximg);
13006
6fc2811b
JR
13007 /* Put the image into the pixmap, then free the X image and its buffer. */
13008 x_put_x_image (f, ximg, img->pixmap, width, height);
13009 x_destroy_x_image (ximg);
13010 xfree (buf);
6fc2811b
JR
13011
13012 UNGCPRO;
13013 return 1;
13014}
13015
13016#endif /* HAVE_TIFF != 0 */
13017
13018
13019\f
13020/***********************************************************************
13021 GIF
13022 ***********************************************************************/
13023
13024#if HAVE_GIF
13025
1ffb278b 13026#define DrawText gif_DrawText
6fc2811b 13027#include <gif_lib.h>
1ffb278b 13028#undef DrawText
6fc2811b
JR
13029
13030static int gif_image_p P_ ((Lisp_Object object));
13031static int gif_load P_ ((struct frame *f, struct image *img));
13032
13033/* The symbol `gif' identifying images of this type. */
13034
13035Lisp_Object Qgif;
13036
13037/* Indices of image specification fields in gif_format, below. */
13038
13039enum gif_keyword_index
13040{
13041 GIF_TYPE,
13042 GIF_DATA,
13043 GIF_FILE,
13044 GIF_ASCENT,
13045 GIF_MARGIN,
13046 GIF_RELIEF,
13047 GIF_ALGORITHM,
13048 GIF_HEURISTIC_MASK,
a05e2bae 13049 GIF_MASK,
6fc2811b 13050 GIF_IMAGE,
a05e2bae 13051 GIF_BACKGROUND,
6fc2811b
JR
13052 GIF_LAST
13053};
13054
13055/* Vector of image_keyword structures describing the format
13056 of valid user-defined image specifications. */
13057
13058static struct image_keyword gif_format[GIF_LAST] =
13059{
13060 {":type", IMAGE_SYMBOL_VALUE, 1},
13061 {":data", IMAGE_STRING_VALUE, 0},
13062 {":file", IMAGE_STRING_VALUE, 0},
8f92c555 13063 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 13064 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 13065 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 13066 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 13067 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
13068 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13069 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
13070 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
13071};
13072
13073/* Structure describing the image type `gif'. */
13074
13075static struct image_type gif_type =
13076{
13077 &Qgif,
13078 gif_image_p,
13079 gif_load,
13080 x_clear_image,
13081 NULL
13082};
13083
1ffb278b
JB
13084
13085/* GIF library details. */
13086DEF_IMGLIB_FN (DGifCloseFile);
13087DEF_IMGLIB_FN (DGifSlurp);
13088DEF_IMGLIB_FN (DGifOpen);
13089DEF_IMGLIB_FN (DGifOpenFileName);
13090
13091static int
13092init_gif_functions (library)
13093 HMODULE library;
13094{
13095 LOAD_IMGLIB_FN (library, DGifCloseFile);
13096 LOAD_IMGLIB_FN (library, DGifSlurp);
13097 LOAD_IMGLIB_FN (library, DGifOpen);
13098 LOAD_IMGLIB_FN (library, DGifOpenFileName);
13099 return 1;
13100}
13101
13102
6fc2811b
JR
13103/* Return non-zero if OBJECT is a valid GIF image specification. */
13104
13105static int
13106gif_image_p (object)
13107 Lisp_Object object;
13108{
13109 struct image_keyword fmt[GIF_LAST];
13110 bcopy (gif_format, fmt, sizeof fmt);
7d0393cf 13111
8f92c555 13112 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
6fc2811b 13113 return 0;
7d0393cf 13114
6fc2811b
JR
13115 /* Must specify either the :data or :file keyword. */
13116 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
13117}
13118
13119/* Reading a GIF image from memory
13120 Based on the PNG memory stuff to a certain extent. */
13121
13122typedef struct
13123{
13124 unsigned char *bytes;
13125 size_t len;
13126 int index;
13127}
13128gif_memory_source;
13129
13130/* Make the current memory source available to gif_read_from_memory.
13131 It's done this way because not all versions of libungif support
13132 a UserData field in the GifFileType structure. */
13133static gif_memory_source *current_gif_memory_src;
13134
13135static int
13136gif_read_from_memory (file, buf, len)
13137 GifFileType *file;
13138 GifByteType *buf;
13139 int len;
13140{
13141 gif_memory_source *src = current_gif_memory_src;
13142
13143 if (len > src->len - src->index)
13144 return -1;
13145
13146 bcopy (src->bytes + src->index, buf, len);
13147 src->index += len;
13148 return len;
13149}
13150
13151
13152/* Load GIF image IMG for use on frame F. Value is non-zero if
13153 successful. */
13154
13155static int
13156gif_load (f, img)
13157 struct frame *f;
13158 struct image *img;
13159{
13160 Lisp_Object file, specified_file;
13161 Lisp_Object specified_data;
13162 int rc, width, height, x, y, i;
13163 XImage *ximg;
13164 ColorMapObject *gif_color_map;
13165 unsigned long pixel_colors[256];
13166 GifFileType *gif;
13167 struct gcpro gcpro1;
13168 Lisp_Object image;
13169 int ino, image_left, image_top, image_width, image_height;
13170 gif_memory_source memsrc;
13171 unsigned char *raster;
13172
13173 specified_file = image_spec_value (img->spec, QCfile, NULL);
13174 specified_data = image_spec_value (img->spec, QCdata, NULL);
13175 file = Qnil;
dfff8a69 13176 GCPRO1 (file);
6fc2811b
JR
13177
13178 if (NILP (specified_data))
13179 {
13180 file = x_find_image_file (specified_file);
6fc2811b
JR
13181 if (!STRINGP (file))
13182 {
13183 image_error ("Cannot find image file `%s'", specified_file, Qnil);
13184 UNGCPRO;
13185 return 0;
13186 }
7d0393cf 13187
6fc2811b 13188 /* Open the GIF file. */
1ffb278b 13189 gif = fn_DGifOpenFileName (SDATA (file));
6fc2811b
JR
13190 if (gif == NULL)
13191 {
13192 image_error ("Cannot open `%s'", file, Qnil);
13193 UNGCPRO;
13194 return 0;
13195 }
13196 }
13197 else
13198 {
13199 /* Read from memory! */
13200 current_gif_memory_src = &memsrc;
d5db4077
KR
13201 memsrc.bytes = SDATA (specified_data);
13202 memsrc.len = SBYTES (specified_data);
6fc2811b
JR
13203 memsrc.index = 0;
13204
1ffb278b 13205 gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
6fc2811b
JR
13206 if (!gif)
13207 {
13208 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
13209 UNGCPRO;
13210 return 0;
13211 }
13212 }
13213
13214 /* Read entire contents. */
1ffb278b 13215 rc = fn_DGifSlurp (gif);
6fc2811b
JR
13216 if (rc == GIF_ERROR)
13217 {
13218 image_error ("Error reading `%s'", img->spec, Qnil);
1ffb278b 13219 fn_DGifCloseFile (gif);
6fc2811b
JR
13220 UNGCPRO;
13221 return 0;
13222 }
13223
13224 image = image_spec_value (img->spec, QCindex, NULL);
13225 ino = INTEGERP (image) ? XFASTINT (image) : 0;
13226 if (ino >= gif->ImageCount)
13227 {
13228 image_error ("Invalid image number `%s' in image `%s'",
13229 image, img->spec);
1ffb278b 13230 fn_DGifCloseFile (gif);
6fc2811b
JR
13231 UNGCPRO;
13232 return 0;
13233 }
13234
1ffb278b
JB
13235 width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
13236 height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
6fc2811b 13237
6fc2811b
JR
13238 /* Create the X image and pixmap. */
13239 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
13240 {
1ffb278b 13241 fn_DGifCloseFile (gif);
6fc2811b
JR
13242 UNGCPRO;
13243 return 0;
13244 }
7d0393cf 13245
6fc2811b
JR
13246 /* Allocate colors. */
13247 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
13248 if (!gif_color_map)
13249 gif_color_map = gif->SColorMap;
1ffb278b 13250#if 0 /* TODO: Color tables */
6fc2811b 13251 init_color_table ();
1ffb278b 13252#endif
6fc2811b 13253 bzero (pixel_colors, sizeof pixel_colors);
7d0393cf 13254
6fc2811b
JR
13255 for (i = 0; i < gif_color_map->ColorCount; ++i)
13256 {
1ffb278b
JB
13257 int r = gif_color_map->Colors[i].Red;
13258 int g = gif_color_map->Colors[i].Green;
13259 int b = gif_color_map->Colors[i].Blue;
13260#if 0 /* TODO: Color tables */
6fc2811b 13261 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
1ffb278b
JB
13262#else
13263 pixel_colors[i] = PALETTERGB (r, g, b);
13264#endif
6fc2811b
JR
13265 }
13266
1ffb278b 13267#if 0 /* TODO: Color tables */
6fc2811b
JR
13268 img->colors = colors_in_color_table (&img->ncolors);
13269 free_color_table ();
1ffb278b 13270#endif
6fc2811b
JR
13271
13272 /* Clear the part of the screen image that are not covered by
7d0393cf 13273 the image from the GIF file. Full animated GIF support
6fc2811b
JR
13274 requires more than can be done here (see the gif89 spec,
13275 disposal methods). Let's simply assume that the part
13276 not covered by a sub-image is in the frame's background color. */
13277 image_top = gif->SavedImages[ino].ImageDesc.Top;
13278 image_left = gif->SavedImages[ino].ImageDesc.Left;
13279 image_width = gif->SavedImages[ino].ImageDesc.Width;
13280 image_height = gif->SavedImages[ino].ImageDesc.Height;
13281
13282 for (y = 0; y < image_top; ++y)
13283 for (x = 0; x < width; ++x)
13284 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
13285
13286 for (y = image_top + image_height; y < height; ++y)
13287 for (x = 0; x < width; ++x)
13288 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
13289
13290 for (y = image_top; y < image_top + image_height; ++y)
13291 {
13292 for (x = 0; x < image_left; ++x)
13293 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
13294 for (x = image_left + image_width; x < width; ++x)
13295 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
13296 }
13297
13298 /* Read the GIF image into the X image. We use a local variable
13299 `raster' here because RasterBits below is a char *, and invites
13300 problems with bytes >= 0x80. */
13301 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
13302
13303 if (gif->SavedImages[ino].ImageDesc.Interlace)
13304 {
13305 static int interlace_start[] = {0, 4, 2, 1};
13306 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 13307 int pass;
6fc2811b
JR
13308 int row = interlace_start[0];
13309
13310 pass = 0;
13311
13312 for (y = 0; y < image_height; y++)
13313 {
13314 if (row >= image_height)
13315 {
13316 row = interlace_start[++pass];
13317 while (row >= image_height)
13318 row = interlace_start[++pass];
13319 }
7d0393cf 13320
6fc2811b
JR
13321 for (x = 0; x < image_width; x++)
13322 {
13323 int i = raster[(y * image_width) + x];
13324 XPutPixel (ximg, x + image_left, row + image_top,
13325 pixel_colors[i]);
13326 }
7d0393cf 13327
6fc2811b
JR
13328 row += interlace_increment[pass];
13329 }
13330 }
13331 else
13332 {
13333 for (y = 0; y < image_height; ++y)
13334 for (x = 0; x < image_width; ++x)
13335 {
13336 int i = raster[y* image_width + x];
13337 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
13338 }
13339 }
7d0393cf 13340
1ffb278b 13341 fn_DGifCloseFile (gif);
a05e2bae
JR
13342
13343 /* Maybe fill in the background field while we have ximg handy. */
13344 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
13345 IMAGE_BACKGROUND (img, f, ximg);
13346
6fc2811b
JR
13347 /* Put the image into the pixmap, then free the X image and its buffer. */
13348 x_put_x_image (f, ximg, img->pixmap, width, height);
13349 x_destroy_x_image (ximg);
7d0393cf 13350
6fc2811b
JR
13351 UNGCPRO;
13352 return 1;
13353}
13354
13355#endif /* HAVE_GIF != 0 */
13356
13357
13358\f
13359/***********************************************************************
13360 Ghostscript
13361 ***********************************************************************/
13362
3cf3436e
JR
13363Lisp_Object Qpostscript;
13364
839b1909
JR
13365/* Keyword symbols. */
13366
13367Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
13368
6fc2811b
JR
13369#ifdef HAVE_GHOSTSCRIPT
13370static int gs_image_p P_ ((Lisp_Object object));
13371static int gs_load P_ ((struct frame *f, struct image *img));
13372static void gs_clear_image P_ ((struct frame *f, struct image *img));
13373
13374/* The symbol `postscript' identifying images of this type. */
13375
6fc2811b
JR
13376/* Keyword symbols. */
13377
13378Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
13379
13380/* Indices of image specification fields in gs_format, below. */
13381
13382enum gs_keyword_index
13383{
13384 GS_TYPE,
13385 GS_PT_WIDTH,
13386 GS_PT_HEIGHT,
13387 GS_FILE,
13388 GS_LOADER,
13389 GS_BOUNDING_BOX,
13390 GS_ASCENT,
13391 GS_MARGIN,
13392 GS_RELIEF,
13393 GS_ALGORITHM,
13394 GS_HEURISTIC_MASK,
a05e2bae
JR
13395 GS_MASK,
13396 GS_BACKGROUND,
6fc2811b
JR
13397 GS_LAST
13398};
13399
13400/* Vector of image_keyword structures describing the format
13401 of valid user-defined image specifications. */
13402
13403static struct image_keyword gs_format[GS_LAST] =
13404{
13405 {":type", IMAGE_SYMBOL_VALUE, 1},
13406 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13407 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13408 {":file", IMAGE_STRING_VALUE, 1},
13409 {":loader", IMAGE_FUNCTION_VALUE, 0},
13410 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8f92c555 13411 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 13412 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 13413 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 13414 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
13415 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13416 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13417 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
13418};
13419
13420/* Structure describing the image type `ghostscript'. */
13421
13422static struct image_type gs_type =
13423{
13424 &Qpostscript,
13425 gs_image_p,
13426 gs_load,
13427 gs_clear_image,
13428 NULL
13429};
13430
13431
13432/* Free X resources of Ghostscript image IMG which is used on frame F. */
13433
13434static void
13435gs_clear_image (f, img)
13436 struct frame *f;
13437 struct image *img;
13438{
13439 /* IMG->data.ptr_val may contain a recorded colormap. */
13440 xfree (img->data.ptr_val);
13441 x_clear_image (f, img);
13442}
13443
13444
13445/* Return non-zero if OBJECT is a valid Ghostscript image
13446 specification. */
13447
13448static int
13449gs_image_p (object)
13450 Lisp_Object object;
13451{
13452 struct image_keyword fmt[GS_LAST];
13453 Lisp_Object tem;
13454 int i;
7d0393cf 13455
6fc2811b 13456 bcopy (gs_format, fmt, sizeof fmt);
7d0393cf 13457
8f92c555 13458 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
6fc2811b
JR
13459 return 0;
13460
13461 /* Bounding box must be a list or vector containing 4 integers. */
13462 tem = fmt[GS_BOUNDING_BOX].value;
13463 if (CONSP (tem))
13464 {
13465 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13466 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13467 return 0;
13468 if (!NILP (tem))
13469 return 0;
13470 }
13471 else if (VECTORP (tem))
13472 {
13473 if (XVECTOR (tem)->size != 4)
13474 return 0;
13475 for (i = 0; i < 4; ++i)
13476 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13477 return 0;
13478 }
13479 else
13480 return 0;
13481
13482 return 1;
13483}
13484
13485
13486/* Load Ghostscript image IMG for use on frame F. Value is non-zero
13487 if successful. */
13488
13489static int
13490gs_load (f, img)
13491 struct frame *f;
13492 struct image *img;
13493{
13494 char buffer[100];
13495 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13496 struct gcpro gcpro1, gcpro2;
13497 Lisp_Object frame;
13498 double in_width, in_height;
13499 Lisp_Object pixel_colors = Qnil;
13500
13501 /* Compute pixel size of pixmap needed from the given size in the
13502 image specification. Sizes in the specification are in pt. 1 pt
13503 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13504 info. */
13505 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13506 in_width = XFASTINT (pt_width) / 72.0;
13507 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13508 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13509 in_height = XFASTINT (pt_height) / 72.0;
13510 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13511
13512 /* Create the pixmap. */
13513 BLOCK_INPUT;
13514 xassert (img->pixmap == 0);
13515 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13516 img->width, img->height,
a05e2bae 13517 one_w32_display_info.n_cbits);
6fc2811b
JR
13518 UNBLOCK_INPUT;
13519
13520 if (!img->pixmap)
13521 {
13522 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13523 return 0;
13524 }
7d0393cf 13525
6fc2811b
JR
13526 /* Call the loader to fill the pixmap. It returns a process object
13527 if successful. We do not record_unwind_protect here because
13528 other places in redisplay like calling window scroll functions
13529 don't either. Let the Lisp loader use `unwind-protect' instead. */
13530 GCPRO2 (window_and_pixmap_id, pixel_colors);
13531
13532 sprintf (buffer, "%lu %lu",
13533 (unsigned long) FRAME_W32_WINDOW (f),
13534 (unsigned long) img->pixmap);
13535 window_and_pixmap_id = build_string (buffer);
7d0393cf 13536
6fc2811b
JR
13537 sprintf (buffer, "%lu %lu",
13538 FRAME_FOREGROUND_PIXEL (f),
13539 FRAME_BACKGROUND_PIXEL (f));
13540 pixel_colors = build_string (buffer);
7d0393cf 13541
6fc2811b
JR
13542 XSETFRAME (frame, f);
13543 loader = image_spec_value (img->spec, QCloader, NULL);
13544 if (NILP (loader))
13545 loader = intern ("gs-load-image");
13546
13547 img->data.lisp_val = call6 (loader, frame, img->spec,
13548 make_number (img->width),
13549 make_number (img->height),
13550 window_and_pixmap_id,
13551 pixel_colors);
13552 UNGCPRO;
13553 return PROCESSP (img->data.lisp_val);
13554}
13555
13556
13557/* Kill the Ghostscript process that was started to fill PIXMAP on
13558 frame F. Called from XTread_socket when receiving an event
13559 telling Emacs that Ghostscript has finished drawing. */
13560
13561void
13562x_kill_gs_process (pixmap, f)
13563 Pixmap pixmap;
13564 struct frame *f;
13565{
13566 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13567 int class, i;
13568 struct image *img;
13569
13570 /* Find the image containing PIXMAP. */
13571 for (i = 0; i < c->used; ++i)
13572 if (c->images[i]->pixmap == pixmap)
13573 break;
13574
3cf3436e
JR
13575 /* Should someone in between have cleared the image cache, for
13576 instance, give up. */
13577 if (i == c->used)
13578 return;
13579
6fc2811b
JR
13580 /* Kill the GS process. We should have found PIXMAP in the image
13581 cache and its image should contain a process object. */
6fc2811b
JR
13582 img = c->images[i];
13583 xassert (PROCESSP (img->data.lisp_val));
13584 Fkill_process (img->data.lisp_val, Qnil);
13585 img->data.lisp_val = Qnil;
13586
13587 /* On displays with a mutable colormap, figure out the colors
13588 allocated for the image by looking at the pixels of an XImage for
13589 img->pixmap. */
13590 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13591 if (class != StaticColor && class != StaticGray && class != TrueColor)
13592 {
13593 XImage *ximg;
13594
13595 BLOCK_INPUT;
13596
13597 /* Try to get an XImage for img->pixmep. */
13598 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13599 0, 0, img->width, img->height, ~0, ZPixmap);
13600 if (ximg)
13601 {
13602 int x, y;
7d0393cf 13603
6fc2811b
JR
13604 /* Initialize the color table. */
13605 init_color_table ();
7d0393cf 13606
6fc2811b
JR
13607 /* For each pixel of the image, look its color up in the
13608 color table. After having done so, the color table will
13609 contain an entry for each color used by the image. */
13610 for (y = 0; y < img->height; ++y)
13611 for (x = 0; x < img->width; ++x)
13612 {
13613 unsigned long pixel = XGetPixel (ximg, x, y);
13614 lookup_pixel_color (f, pixel);
13615 }
13616
13617 /* Record colors in the image. Free color table and XImage. */
13618 img->colors = colors_in_color_table (&img->ncolors);
13619 free_color_table ();
13620 XDestroyImage (ximg);
13621
13622#if 0 /* This doesn't seem to be the case. If we free the colors
13623 here, we get a BadAccess later in x_clear_image when
13624 freeing the colors. */
13625 /* We have allocated colors once, but Ghostscript has also
13626 allocated colors on behalf of us. So, to get the
13627 reference counts right, free them once. */
13628 if (img->ncolors)
3cf3436e 13629 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 13630 img->colors, img->ncolors, 0);
6fc2811b
JR
13631#endif
13632 }
13633 else
13634 image_error ("Cannot get X image of `%s'; colors will not be freed",
13635 img->spec, Qnil);
7d0393cf 13636
6fc2811b
JR
13637 UNBLOCK_INPUT;
13638 }
3cf3436e
JR
13639
13640 /* Now that we have the pixmap, compute mask and transform the
13641 image if requested. */
13642 BLOCK_INPUT;
13643 postprocess_image (f, img);
13644 UNBLOCK_INPUT;
6fc2811b
JR
13645}
13646
13647#endif /* HAVE_GHOSTSCRIPT */
13648
13649\f
13650/***********************************************************************
13651 Window properties
13652 ***********************************************************************/
13653
13654DEFUN ("x-change-window-property", Fx_change_window_property,
13655 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
13656 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13657PROP and VALUE must be strings. FRAME nil or omitted means use the
13658selected frame. Value is VALUE. */)
6fc2811b
JR
13659 (prop, value, frame)
13660 Lisp_Object frame, prop, value;
13661{
767b1ff0 13662#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13663 struct frame *f = check_x_frame (frame);
13664 Atom prop_atom;
13665
b7826503
PJ
13666 CHECK_STRING (prop);
13667 CHECK_STRING (value);
6fc2811b
JR
13668
13669 BLOCK_INPUT;
d5db4077 13670 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
13671 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13672 prop_atom, XA_STRING, 8, PropModeReplace,
d5db4077 13673 SDATA (value), SCHARS (value));
6fc2811b
JR
13674
13675 /* Make sure the property is set when we return. */
13676 XFlush (FRAME_W32_DISPLAY (f));
13677 UNBLOCK_INPUT;
13678
767b1ff0 13679#endif /* TODO */
6fc2811b
JR
13680
13681 return value;
13682}
13683
13684
13685DEFUN ("x-delete-window-property", Fx_delete_window_property,
13686 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
13687 doc: /* Remove window property PROP from X window of FRAME.
13688FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
13689 (prop, frame)
13690 Lisp_Object prop, frame;
13691{
767b1ff0 13692#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13693
13694 struct frame *f = check_x_frame (frame);
13695 Atom prop_atom;
13696
b7826503 13697 CHECK_STRING (prop);
6fc2811b 13698 BLOCK_INPUT;
d5db4077 13699 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
13700 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13701
13702 /* Make sure the property is removed when we return. */
13703 XFlush (FRAME_W32_DISPLAY (f));
13704 UNBLOCK_INPUT;
767b1ff0 13705#endif /* TODO */
6fc2811b
JR
13706
13707 return prop;
13708}
13709
13710
13711DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13712 1, 2, 0,
74e1aeec
JR
13713 doc: /* Value is the value of window property PROP on FRAME.
13714If FRAME is nil or omitted, use the selected frame. Value is nil
13715if FRAME hasn't a property with name PROP or if PROP has no string
13716value. */)
6fc2811b
JR
13717 (prop, frame)
13718 Lisp_Object prop, frame;
13719{
767b1ff0 13720#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13721
13722 struct frame *f = check_x_frame (frame);
13723 Atom prop_atom;
13724 int rc;
13725 Lisp_Object prop_value = Qnil;
13726 char *tmp_data = NULL;
13727 Atom actual_type;
13728 int actual_format;
13729 unsigned long actual_size, bytes_remaining;
13730
b7826503 13731 CHECK_STRING (prop);
6fc2811b 13732 BLOCK_INPUT;
d5db4077 13733 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
13734 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13735 prop_atom, 0, 0, False, XA_STRING,
13736 &actual_type, &actual_format, &actual_size,
13737 &bytes_remaining, (unsigned char **) &tmp_data);
13738 if (rc == Success)
13739 {
13740 int size = bytes_remaining;
13741
13742 XFree (tmp_data);
13743 tmp_data = NULL;
13744
13745 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13746 prop_atom, 0, bytes_remaining,
13747 False, XA_STRING,
7d0393cf
JB
13748 &actual_type, &actual_format,
13749 &actual_size, &bytes_remaining,
6fc2811b
JR
13750 (unsigned char **) &tmp_data);
13751 if (rc == Success)
13752 prop_value = make_string (tmp_data, size);
13753
13754 XFree (tmp_data);
13755 }
13756
13757 UNBLOCK_INPUT;
13758
13759 return prop_value;
13760
767b1ff0 13761#endif /* TODO */
6fc2811b
JR
13762 return Qnil;
13763}
13764
13765
13766\f
13767/***********************************************************************
13768 Busy cursor
13769 ***********************************************************************/
13770
f79e6790 13771/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 13772 an hourglass cursor on all frames. */
6fc2811b 13773
0af913d7 13774static struct atimer *hourglass_atimer;
6fc2811b 13775
0af913d7 13776/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 13777
0af913d7 13778static int hourglass_shown_p;
6fc2811b 13779
0af913d7 13780/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 13781
0af913d7 13782static Lisp_Object Vhourglass_delay;
6fc2811b 13783
0af913d7 13784/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
13785 cursor. */
13786
0af913d7 13787#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
13788
13789/* Function prototypes. */
13790
0af913d7
GM
13791static void show_hourglass P_ ((struct atimer *));
13792static void hide_hourglass P_ ((void));
f79e6790
JR
13793
13794
0af913d7 13795/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
13796
13797void
0af913d7 13798start_hourglass ()
f79e6790 13799{
767b1ff0 13800#if 0 /* TODO: cursor shape changes. */
f79e6790 13801 EMACS_TIME delay;
dfff8a69 13802 int secs, usecs = 0;
7d0393cf 13803
0af913d7 13804 cancel_hourglass ();
f79e6790 13805
0af913d7
GM
13806 if (INTEGERP (Vhourglass_delay)
13807 && XINT (Vhourglass_delay) > 0)
13808 secs = XFASTINT (Vhourglass_delay);
13809 else if (FLOATP (Vhourglass_delay)
13810 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
13811 {
13812 Lisp_Object tem;
0af913d7 13813 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 13814 secs = XFASTINT (tem);
0af913d7 13815 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 13816 }
f79e6790 13817 else
0af913d7 13818 secs = DEFAULT_HOURGLASS_DELAY;
7d0393cf 13819
dfff8a69 13820 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
13821 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13822 show_hourglass, NULL);
f79e6790
JR
13823#endif
13824}
13825
13826
0af913d7
GM
13827/* Cancel the hourglass cursor timer if active, hide an hourglass
13828 cursor if shown. */
f79e6790
JR
13829
13830void
0af913d7 13831cancel_hourglass ()
f79e6790 13832{
0af913d7 13833 if (hourglass_atimer)
dfff8a69 13834 {
0af913d7
GM
13835 cancel_atimer (hourglass_atimer);
13836 hourglass_atimer = NULL;
dfff8a69 13837 }
7d0393cf 13838
0af913d7
GM
13839 if (hourglass_shown_p)
13840 hide_hourglass ();
f79e6790
JR
13841}
13842
13843
0af913d7
GM
13844/* Timer function of hourglass_atimer. TIMER is equal to
13845 hourglass_atimer.
f79e6790 13846
0af913d7
GM
13847 Display an hourglass cursor on all frames by mapping the frames'
13848 hourglass_window. Set the hourglass_p flag in the frames'
13849 output_data.x structure to indicate that an hourglass cursor is
13850 shown on the frames. */
f79e6790
JR
13851
13852static void
0af913d7 13853show_hourglass (timer)
f79e6790 13854 struct atimer *timer;
6fc2811b 13855{
767b1ff0 13856#if 0 /* TODO: cursor shape changes. */
f79e6790 13857 /* The timer implementation will cancel this timer automatically
0af913d7 13858 after this function has run. Set hourglass_atimer to null
f79e6790 13859 so that we know the timer doesn't have to be canceled. */
0af913d7 13860 hourglass_atimer = NULL;
f79e6790 13861
0af913d7 13862 if (!hourglass_shown_p)
6fc2811b
JR
13863 {
13864 Lisp_Object rest, frame;
7d0393cf 13865
f79e6790 13866 BLOCK_INPUT;
7d0393cf 13867
6fc2811b 13868 FOR_EACH_FRAME (rest, frame)
dc220243 13869 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13870 {
13871 struct frame *f = XFRAME (frame);
7d0393cf 13872
0af913d7 13873 f->output_data.w32->hourglass_p = 1;
7d0393cf 13874
0af913d7 13875 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13876 {
13877 unsigned long mask = CWCursor;
13878 XSetWindowAttributes attrs;
7d0393cf 13879
0af913d7 13880 attrs.cursor = f->output_data.w32->hourglass_cursor;
7d0393cf 13881
0af913d7 13882 f->output_data.w32->hourglass_window
f79e6790 13883 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13884 FRAME_OUTER_WINDOW (f),
13885 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13886 InputOnly,
13887 CopyFromParent,
6fc2811b
JR
13888 mask, &attrs);
13889 }
7d0393cf 13890
0af913d7
GM
13891 XMapRaised (FRAME_X_DISPLAY (f),
13892 f->output_data.w32->hourglass_window);
f79e6790 13893 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13894 }
6fc2811b 13895
0af913d7 13896 hourglass_shown_p = 1;
f79e6790
JR
13897 UNBLOCK_INPUT;
13898 }
13899#endif
6fc2811b
JR
13900}
13901
13902
0af913d7 13903/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13904
f79e6790 13905static void
0af913d7 13906hide_hourglass ()
f79e6790 13907{
767b1ff0 13908#if 0 /* TODO: cursor shape changes. */
0af913d7 13909 if (hourglass_shown_p)
6fc2811b 13910 {
f79e6790
JR
13911 Lisp_Object rest, frame;
13912
13913 BLOCK_INPUT;
13914 FOR_EACH_FRAME (rest, frame)
6fc2811b 13915 {
f79e6790 13916 struct frame *f = XFRAME (frame);
7d0393cf 13917
dc220243 13918 if (FRAME_W32_P (f)
f79e6790 13919 /* Watch out for newly created frames. */
0af913d7 13920 && f->output_data.x->hourglass_window)
f79e6790 13921 {
0af913d7
GM
13922 XUnmapWindow (FRAME_X_DISPLAY (f),
13923 f->output_data.x->hourglass_window);
13924 /* Sync here because XTread_socket looks at the
13925 hourglass_p flag that is reset to zero below. */
f79e6790 13926 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13927 f->output_data.x->hourglass_p = 0;
f79e6790 13928 }
6fc2811b 13929 }
6fc2811b 13930
0af913d7 13931 hourglass_shown_p = 0;
f79e6790
JR
13932 UNBLOCK_INPUT;
13933 }
13934#endif
6fc2811b
JR
13935}
13936
13937
13938\f
13939/***********************************************************************
13940 Tool tips
13941 ***********************************************************************/
13942
13943static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13944 Lisp_Object, Lisp_Object));
13945static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13946 Lisp_Object, int, int, int *, int *));
7d0393cf 13947
3cf3436e 13948/* The frame of a currently visible tooltip. */
6fc2811b 13949
937e601e 13950Lisp_Object tip_frame;
6fc2811b
JR
13951
13952/* If non-nil, a timer started that hides the last tooltip when it
13953 fires. */
13954
13955Lisp_Object tip_timer;
13956Window tip_window;
13957
3cf3436e
JR
13958/* If non-nil, a vector of 3 elements containing the last args
13959 with which x-show-tip was called. See there. */
13960
13961Lisp_Object last_show_tip_args;
13962
13963/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13964
13965Lisp_Object Vx_max_tooltip_size;
13966
13967
937e601e
AI
13968static Lisp_Object
13969unwind_create_tip_frame (frame)
13970 Lisp_Object frame;
13971{
c844a81a
GM
13972 Lisp_Object deleted;
13973
13974 deleted = unwind_create_frame (frame);
13975 if (EQ (deleted, Qt))
13976 {
13977 tip_window = NULL;
13978 tip_frame = Qnil;
13979 }
7d0393cf 13980
c844a81a 13981 return deleted;
937e601e
AI
13982}
13983
13984
6fc2811b 13985/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13986 PARMS is a list of frame parameters. TEXT is the string to
13987 display in the tip frame. Value is the frame.
937e601e
AI
13988
13989 Note that functions called here, esp. x_default_parameter can
13990 signal errors, for instance when a specified color name is
13991 undefined. We have to make sure that we're in a consistent state
13992 when this happens. */
6fc2811b
JR
13993
13994static Lisp_Object
3cf3436e 13995x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13996 struct w32_display_info *dpyinfo;
3cf3436e 13997 Lisp_Object parms, text;
6fc2811b 13998{
6fc2811b
JR
13999 struct frame *f;
14000 Lisp_Object frame, tem;
14001 Lisp_Object name;
14002 long window_prompting = 0;
14003 int width, height;
331379bf 14004 int count = SPECPDL_INDEX ();
6fc2811b
JR
14005 struct gcpro gcpro1, gcpro2, gcpro3;
14006 struct kboard *kb;
3cf3436e
JR
14007 int face_change_count_before = face_change_count;
14008 Lisp_Object buffer;
14009 struct buffer *old_buffer;
6fc2811b 14010
ca56d953 14011 check_w32 ();
6fc2811b
JR
14012
14013 /* Use this general default value to start with until we know if
14014 this frame has a specified name. */
14015 Vx_resource_name = Vinvocation_name;
14016
14017#ifdef MULTI_KBOARD
14018 kb = dpyinfo->kboard;
14019#else
14020 kb = &the_only_kboard;
14021#endif
14022
14023 /* Get the name of the frame to use for resource lookup. */
14024 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
14025 if (!STRINGP (name)
14026 && !EQ (name, Qunbound)
14027 && !NILP (name))
14028 error ("Invalid frame name--not a string or nil");
14029 Vx_resource_name = name;
14030
14031 frame = Qnil;
14032 GCPRO3 (parms, name, frame);
9eb16b62
JR
14033 /* Make a frame without minibuffer nor mode-line. */
14034 f = make_frame (0);
14035 f->wants_modeline = 0;
6fc2811b 14036 XSETFRAME (frame, f);
3cf3436e
JR
14037
14038 buffer = Fget_buffer_create (build_string (" *tip*"));
14039 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
14040 old_buffer = current_buffer;
14041 set_buffer_internal_1 (XBUFFER (buffer));
14042 current_buffer->truncate_lines = Qnil;
14043 Ferase_buffer ();
14044 Finsert (1, &text);
14045 set_buffer_internal_1 (old_buffer);
7d0393cf 14046
6fc2811b 14047 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 14048 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 14049
3cf3436e
JR
14050 /* By setting the output method, we're essentially saying that
14051 the frame is live, as per FRAME_LIVE_P. If we get a signal
14052 from this point on, x_destroy_window might screw up reference
14053 counts etc. */
d88c567c 14054 f->output_method = output_w32;
6fc2811b
JR
14055 f->output_data.w32 =
14056 (struct w32_output *) xmalloc (sizeof (struct w32_output));
14057 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
14058
14059 FRAME_FONTSET (f) = -1;
6fc2811b
JR
14060 f->icon_name = Qnil;
14061
ca56d953 14062#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
14063 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
14064 dpyinfo_refcount = dpyinfo->reference_count;
14065#endif /* GLYPH_DEBUG */
6fc2811b
JR
14066#ifdef MULTI_KBOARD
14067 FRAME_KBOARD (f) = kb;
14068#endif
14069 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
14070 f->output_data.w32->explicit_parent = 0;
14071
14072 /* Set the name; the functions to which we pass f expect the name to
14073 be set. */
14074 if (EQ (name, Qunbound) || NILP (name))
14075 {
ca56d953 14076 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
14077 f->explicit_name = 0;
14078 }
14079 else
14080 {
14081 f->name = name;
14082 f->explicit_name = 1;
14083 /* use the frame's title when getting resources for this frame. */
14084 specbind (Qx_resource_name, name);
14085 }
14086
6fc2811b
JR
14087 /* Extract the window parameters from the supplied values
14088 that are needed to determine window geometry. */
14089 {
14090 Lisp_Object font;
14091
14092 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
14093
14094 BLOCK_INPUT;
14095 /* First, try whatever font the caller has specified. */
14096 if (STRINGP (font))
14097 {
14098 tem = Fquery_fontset (font, Qnil);
14099 if (STRINGP (tem))
d5db4077 14100 font = x_new_fontset (f, SDATA (tem));
6fc2811b 14101 else
d5db4077 14102 font = x_new_font (f, SDATA (font));
6fc2811b 14103 }
7d0393cf 14104
6fc2811b
JR
14105 /* Try out a font which we hope has bold and italic variations. */
14106 if (!STRINGP (font))
ca56d953 14107 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 14108 if (! STRINGP (font))
ca56d953 14109 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
14110 /* If those didn't work, look for something which will at least work. */
14111 if (! STRINGP (font))
ca56d953 14112 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
14113 UNBLOCK_INPUT;
14114 if (! STRINGP (font))
ca56d953 14115 font = build_string ("Fixedsys");
6fc2811b
JR
14116
14117 x_default_parameter (f, parms, Qfont, font,
14118 "font", "Font", RES_TYPE_STRING);
14119 }
14120
14121 x_default_parameter (f, parms, Qborder_width, make_number (2),
14122 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
14123 /* This defaults to 2 in order to match xterm. We recognize either
14124 internalBorderWidth or internalBorder (which is what xterm calls
14125 it). */
14126 if (NILP (Fassq (Qinternal_border_width, parms)))
14127 {
14128 Lisp_Object value;
14129
14130 value = w32_get_arg (parms, Qinternal_border_width,
14131 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
14132 if (! EQ (value, Qunbound))
14133 parms = Fcons (Fcons (Qinternal_border_width, value),
14134 parms);
14135 }
bfd6edcc 14136 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
14137 "internalBorderWidth", "internalBorderWidth",
14138 RES_TYPE_NUMBER);
14139
14140 /* Also do the stuff which must be set before the window exists. */
14141 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
14142 "foreground", "Foreground", RES_TYPE_STRING);
14143 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
14144 "background", "Background", RES_TYPE_STRING);
14145 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
14146 "pointerColor", "Foreground", RES_TYPE_STRING);
14147 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
14148 "cursorColor", "Foreground", RES_TYPE_STRING);
14149 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
14150 "borderColor", "BorderColor", RES_TYPE_STRING);
14151
14152 /* Init faces before x_default_parameter is called for scroll-bar
14153 parameters because that function calls x_set_scroll_bar_width,
14154 which calls change_frame_size, which calls Fset_window_buffer,
14155 which runs hooks, which call Fvertical_motion. At the end, we
14156 end up in init_iterator with a null face cache, which should not
14157 happen. */
14158 init_frame_faces (f);
ca56d953
JR
14159
14160 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 14161 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 14162
6fc2811b
JR
14163 window_prompting = x_figure_window_size (f, parms);
14164
9eb16b62
JR
14165 /* No fringes on tip frame. */
14166 f->output_data.w32->fringes_extra = 0;
14167 f->output_data.w32->fringe_cols = 0;
14168 f->output_data.w32->left_fringe_width = 0;
14169 f->output_data.w32->right_fringe_width = 0;
14170
6fc2811b
JR
14171 if (window_prompting & XNegative)
14172 {
14173 if (window_prompting & YNegative)
14174 f->output_data.w32->win_gravity = SouthEastGravity;
14175 else
14176 f->output_data.w32->win_gravity = NorthEastGravity;
14177 }
14178 else
14179 {
14180 if (window_prompting & YNegative)
14181 f->output_data.w32->win_gravity = SouthWestGravity;
14182 else
14183 f->output_data.w32->win_gravity = NorthWestGravity;
14184 }
14185
14186 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
14187
14188 BLOCK_INPUT;
14189 my_create_tip_window (f);
14190 UNBLOCK_INPUT;
6fc2811b
JR
14191
14192 x_make_gc (f);
14193
14194 x_default_parameter (f, parms, Qauto_raise, Qnil,
14195 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
14196 x_default_parameter (f, parms, Qauto_lower, Qnil,
14197 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
14198 x_default_parameter (f, parms, Qcursor_type, Qbox,
14199 "cursorType", "CursorType", RES_TYPE_SYMBOL);
14200
14201 /* Dimensions, especially f->height, must be done via change_frame_size.
14202 Change will not be effected unless different from the current
14203 f->height. */
14204 width = f->width;
14205 height = f->height;
14206 f->height = 0;
14207 SET_FRAME_WIDTH (f, 0);
14208 change_frame_size (f, height, width, 1, 0, 0);
14209
cd1d850f
JPW
14210 /* Add `tooltip' frame parameter's default value. */
14211 if (NILP (Fframe_parameter (frame, intern ("tooltip"))))
14212 Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
14213 Qnil));
7d0393cf 14214
3cf3436e
JR
14215 /* Set up faces after all frame parameters are known. This call
14216 also merges in face attributes specified for new frames.
14217
14218 Frame parameters may be changed if .Xdefaults contains
14219 specifications for the default font. For example, if there is an
14220 `Emacs.default.attributeBackground: pink', the `background-color'
14221 attribute of the frame get's set, which let's the internal border
14222 of the tooltip frame appear in pink. Prevent this. */
14223 {
14224 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
14225
14226 /* Set tip_frame here, so that */
14227 tip_frame = frame;
14228 call1 (Qface_set_after_frame_default, frame);
7d0393cf 14229
3cf3436e
JR
14230 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
14231 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
14232 Qnil));
14233 }
7d0393cf 14234
6fc2811b
JR
14235 f->no_split = 1;
14236
14237 UNGCPRO;
14238
14239 /* It is now ok to make the frame official even if we get an error
14240 below. And the frame needs to be on Vframe_list or making it
14241 visible won't work. */
14242 Vframe_list = Fcons (frame, Vframe_list);
14243
14244 /* Now that the frame is official, it counts as a reference to
14245 its display. */
14246 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 14247
3cf3436e
JR
14248 /* Setting attributes of faces of the tooltip frame from resources
14249 and similar will increment face_change_count, which leads to the
14250 clearing of all current matrices. Since this isn't necessary
14251 here, avoid it by resetting face_change_count to the value it
14252 had before we created the tip frame. */
14253 face_change_count = face_change_count_before;
14254
14255 /* Discard the unwind_protect. */
6fc2811b 14256 return unbind_to (count, frame);
ee78dc32
GV
14257}
14258
3cf3436e
JR
14259
14260/* Compute where to display tip frame F. PARMS is the list of frame
14261 parameters for F. DX and DY are specified offsets from the current
14262 location of the mouse. WIDTH and HEIGHT are the width and height
14263 of the tooltip. Return coordinates relative to the root window of
14264 the display in *ROOT_X, and *ROOT_Y. */
14265
14266static void
14267compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
14268 struct frame *f;
14269 Lisp_Object parms, dx, dy;
14270 int width, height;
14271 int *root_x, *root_y;
14272{
3cf3436e 14273 Lisp_Object left, top;
7d0393cf 14274
3cf3436e
JR
14275 /* User-specified position? */
14276 left = Fcdr (Fassq (Qleft, parms));
14277 top = Fcdr (Fassq (Qtop, parms));
7d0393cf 14278
3cf3436e
JR
14279 /* Move the tooltip window where the mouse pointer is. Resize and
14280 show it. */
ca56d953 14281 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 14282 {
ca56d953
JR
14283 POINT pt;
14284
3cf3436e 14285 BLOCK_INPUT;
ca56d953
JR
14286 GetCursorPos (&pt);
14287 *root_x = pt.x;
14288 *root_y = pt.y;
3cf3436e
JR
14289 UNBLOCK_INPUT;
14290 }
14291
14292 if (INTEGERP (top))
14293 *root_y = XINT (top);
14294 else if (*root_y + XINT (dy) - height < 0)
14295 *root_y -= XINT (dy);
14296 else
14297 {
14298 *root_y -= height;
14299 *root_y += XINT (dy);
14300 }
14301
14302 if (INTEGERP (left))
14303 *root_x = XINT (left);
72e4adef
JR
14304 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
14305 /* It fits to the right of the pointer. */
14306 *root_x += XINT (dx);
14307 else if (width + XINT (dx) <= *root_x)
14308 /* It fits to the left of the pointer. */
3cf3436e
JR
14309 *root_x -= width + XINT (dx);
14310 else
72e4adef
JR
14311 /* Put it left justified on the screen -- it ought to fit that way. */
14312 *root_x = 0;
3cf3436e
JR
14313}
14314
14315
71eab8d1 14316DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
14317 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
14318A tooltip window is a small window displaying a string.
14319
14320FRAME nil or omitted means use the selected frame.
14321
14322PARMS is an optional list of frame parameters which can be
14323used to change the tooltip's appearance.
14324
ca56d953
JR
14325Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
14326means use the default timeout of 5 seconds.
74e1aeec 14327
ca56d953 14328If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
14329the tooltip is displayed at that x-position. Otherwise it is
14330displayed at the mouse position, with offset DX added (default is 5 if
14331DX isn't specified). Likewise for the y-position; if a `top' frame
14332parameter is specified, it determines the y-position of the tooltip
14333window, otherwise it is displayed at the mouse position, with offset
14334DY added (default is -10).
14335
14336A tooltip's maximum size is specified by `x-max-tooltip-size'.
14337Text larger than the specified size is clipped. */)
71eab8d1
AI
14338 (string, frame, parms, timeout, dx, dy)
14339 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 14340{
6fc2811b
JR
14341 struct frame *f;
14342 struct window *w;
3cf3436e 14343 int root_x, root_y;
6fc2811b
JR
14344 struct buffer *old_buffer;
14345 struct text_pos pos;
14346 int i, width, height;
6fc2811b
JR
14347 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
14348 int old_windows_or_buffers_changed = windows_or_buffers_changed;
331379bf 14349 int count = SPECPDL_INDEX ();
7d0393cf 14350
6fc2811b 14351 specbind (Qinhibit_redisplay, Qt);
ee78dc32 14352
dfff8a69 14353 GCPRO4 (string, parms, frame, timeout);
ee78dc32 14354
b7826503 14355 CHECK_STRING (string);
6fc2811b
JR
14356 f = check_x_frame (frame);
14357 if (NILP (timeout))
14358 timeout = make_number (5);
14359 else
b7826503 14360 CHECK_NATNUM (timeout);
ee78dc32 14361
71eab8d1
AI
14362 if (NILP (dx))
14363 dx = make_number (5);
14364 else
b7826503 14365 CHECK_NUMBER (dx);
7d0393cf 14366
71eab8d1 14367 if (NILP (dy))
dc220243 14368 dy = make_number (-10);
71eab8d1 14369 else
b7826503 14370 CHECK_NUMBER (dy);
71eab8d1 14371
dc220243
JR
14372 if (NILP (last_show_tip_args))
14373 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
14374
14375 if (!NILP (tip_frame))
14376 {
14377 Lisp_Object last_string = AREF (last_show_tip_args, 0);
14378 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
14379 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
14380
14381 if (EQ (frame, last_frame)
14382 && !NILP (Fequal (last_string, string))
14383 && !NILP (Fequal (last_parms, parms)))
14384 {
14385 struct frame *f = XFRAME (tip_frame);
7d0393cf 14386
dc220243
JR
14387 /* Only DX and DY have changed. */
14388 if (!NILP (tip_timer))
14389 {
14390 Lisp_Object timer = tip_timer;
14391 tip_timer = Qnil;
14392 call1 (Qcancel_timer, timer);
14393 }
14394
14395 BLOCK_INPUT;
ca56d953
JR
14396 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
14397 PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
14398
14399 /* Put tooltip in topmost group and in position. */
ca56d953
JR
14400 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14401 root_x, root_y, 0, 0,
14402 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
14403
14404 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14405 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14406 0, 0, 0, 0,
14407 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14408
dc220243
JR
14409 UNBLOCK_INPUT;
14410 goto start_timer;
14411 }
14412 }
14413
6fc2811b
JR
14414 /* Hide a previous tip, if any. */
14415 Fx_hide_tip ();
ee78dc32 14416
dc220243
JR
14417 ASET (last_show_tip_args, 0, string);
14418 ASET (last_show_tip_args, 1, frame);
14419 ASET (last_show_tip_args, 2, parms);
14420
6fc2811b
JR
14421 /* Add default values to frame parameters. */
14422 if (NILP (Fassq (Qname, parms)))
14423 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14424 if (NILP (Fassq (Qinternal_border_width, parms)))
14425 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14426 if (NILP (Fassq (Qborder_width, parms)))
14427 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14428 if (NILP (Fassq (Qborder_color, parms)))
14429 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14430 if (NILP (Fassq (Qbackground_color, parms)))
14431 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14432 parms);
14433
0e3fcdef
JR
14434 /* Block input until the tip has been fully drawn, to avoid crashes
14435 when drawing tips in menus. */
14436 BLOCK_INPUT;
14437
6fc2811b
JR
14438 /* Create a frame for the tooltip, and record it in the global
14439 variable tip_frame. */
ca56d953 14440 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 14441 f = XFRAME (frame);
6fc2811b 14442
3cf3436e 14443 /* Set up the frame's root window. */
6fc2811b
JR
14444 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14445 w->left = w->top = make_number (0);
3cf3436e
JR
14446
14447 if (CONSP (Vx_max_tooltip_size)
14448 && INTEGERP (XCAR (Vx_max_tooltip_size))
14449 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14450 && INTEGERP (XCDR (Vx_max_tooltip_size))
14451 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14452 {
14453 w->width = XCAR (Vx_max_tooltip_size);
14454 w->height = XCDR (Vx_max_tooltip_size);
14455 }
14456 else
14457 {
14458 w->width = make_number (80);
14459 w->height = make_number (40);
14460 }
7d0393cf 14461
3cf3436e 14462 f->window_width = XINT (w->width);
6fc2811b
JR
14463 adjust_glyphs (f);
14464 w->pseudo_window_p = 1;
14465
14466 /* Display the tooltip text in a temporary buffer. */
6fc2811b 14467 old_buffer = current_buffer;
3cf3436e
JR
14468 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14469 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
14470 clear_glyph_matrix (w->desired_matrix);
14471 clear_glyph_matrix (w->current_matrix);
14472 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14473 try_window (FRAME_ROOT_WINDOW (f), pos);
14474
14475 /* Compute width and height of the tooltip. */
14476 width = height = 0;
14477 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 14478 {
6fc2811b
JR
14479 struct glyph_row *row = &w->desired_matrix->rows[i];
14480 struct glyph *last;
14481 int row_width;
14482
14483 /* Stop at the first empty row at the end. */
14484 if (!row->enabled_p || !row->displays_text_p)
14485 break;
14486
14487 /* Let the row go over the full width of the frame. */
14488 row->full_width_p = 1;
14489
4e3a1c61
JR
14490#ifdef TODO /* Investigate why some fonts need more width than is
14491 calculated for some tooltips. */
6fc2811b
JR
14492 /* There's a glyph at the end of rows that is use to place
14493 the cursor there. Don't include the width of this glyph. */
14494 if (row->used[TEXT_AREA])
14495 {
14496 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14497 row_width = row->pixel_width - last->pixel_width;
14498 }
14499 else
4e3a1c61 14500#endif
6fc2811b 14501 row_width = row->pixel_width;
7d0393cf 14502
ca56d953 14503 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 14504 height += row->height;
6fc2811b 14505 width = max (width, row_width);
ee78dc32
GV
14506 }
14507
6fc2811b
JR
14508 /* Add the frame's internal border to the width and height the X
14509 window should have. */
14510 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14511 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 14512
6fc2811b
JR
14513 /* Move the tooltip window where the mouse pointer is. Resize and
14514 show it. */
3cf3436e 14515 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 14516
bfd6edcc
JR
14517 {
14518 /* Adjust Window size to take border into account. */
14519 RECT rect;
14520 rect.left = rect.top = 0;
14521 rect.right = width;
14522 rect.bottom = height;
14523 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14524 FRAME_EXTERNAL_MENU_BAR (f));
14525
d65a9cdc 14526 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
14527 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14528 root_x, root_y, rect.right - rect.left,
14529 rect.bottom - rect.top, SWP_NOACTIVATE);
14530
d65a9cdc
JR
14531 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14532 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14533 0, 0, 0, 0,
14534 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14535
bfd6edcc
JR
14536 /* Let redisplay know that we have made the frame visible already. */
14537 f->async_visible = 1;
14538
14539 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14540 }
ee78dc32 14541
6fc2811b
JR
14542 /* Draw into the window. */
14543 w->must_be_updated_p = 1;
14544 update_single_window (w, 1);
ee78dc32 14545
0e3fcdef
JR
14546 UNBLOCK_INPUT;
14547
6fc2811b
JR
14548 /* Restore original current buffer. */
14549 set_buffer_internal_1 (old_buffer);
14550 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 14551
dc220243 14552 start_timer:
6fc2811b
JR
14553 /* Let the tip disappear after timeout seconds. */
14554 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14555 intern ("x-hide-tip"));
ee78dc32 14556
dfff8a69 14557 UNGCPRO;
6fc2811b 14558 return unbind_to (count, Qnil);
ee78dc32
GV
14559}
14560
ee78dc32 14561
6fc2811b 14562DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
14563 doc: /* Hide the current tooltip window, if there is any.
14564Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
14565 ()
14566{
937e601e
AI
14567 int count;
14568 Lisp_Object deleted, frame, timer;
14569 struct gcpro gcpro1, gcpro2;
14570
14571 /* Return quickly if nothing to do. */
14572 if (NILP (tip_timer) && NILP (tip_frame))
14573 return Qnil;
7d0393cf 14574
937e601e
AI
14575 frame = tip_frame;
14576 timer = tip_timer;
14577 GCPRO2 (frame, timer);
14578 tip_frame = tip_timer = deleted = Qnil;
7d0393cf 14579
331379bf 14580 count = SPECPDL_INDEX ();
6fc2811b 14581 specbind (Qinhibit_redisplay, Qt);
937e601e 14582 specbind (Qinhibit_quit, Qt);
7d0393cf 14583
937e601e 14584 if (!NILP (timer))
dc220243 14585 call1 (Qcancel_timer, timer);
ee78dc32 14586
937e601e 14587 if (FRAMEP (frame))
6fc2811b 14588 {
937e601e
AI
14589 Fdelete_frame (frame, Qnil);
14590 deleted = Qt;
6fc2811b 14591 }
1edf84e7 14592
937e601e
AI
14593 UNGCPRO;
14594 return unbind_to (count, deleted);
6fc2811b 14595}
5ac45f98 14596
5ac45f98 14597
6fc2811b
JR
14598\f
14599/***********************************************************************
14600 File selection dialog
14601 ***********************************************************************/
6fc2811b
JR
14602extern Lisp_Object Qfile_name_history;
14603
1030b26b
JR
14604/* Callback for altering the behaviour of the Open File dialog.
14605 Makes the Filename text field contain "Current Directory" and be
14606 read-only when "Directories" is selected in the filter. This
14607 allows us to work around the fact that the standard Open File
14608 dialog does not support directories. */
14609UINT CALLBACK
14610file_dialog_callback (hwnd, msg, wParam, lParam)
14611 HWND hwnd;
14612 UINT msg;
14613 WPARAM wParam;
14614 LPARAM lParam;
14615{
14616 if (msg == WM_NOTIFY)
14617 {
14618 OFNOTIFY * notify = (OFNOTIFY *)lParam;
14619 /* Detect when the Filter dropdown is changed. */
14620 if (notify->hdr.code == CDN_TYPECHANGE)
14621 {
14622 HWND dialog = GetParent (hwnd);
14623 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
14624
14625 /* Directories is in index 2. */
14626 if (notify->lpOFN->nFilterIndex == 2)
14627 {
14628 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14629 "Current Directory");
14630 EnableWindow (edit_control, FALSE);
14631 }
14632 else
14633 {
14634 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14635 "");
14636 EnableWindow (edit_control, TRUE);
14637 }
14638 }
14639 }
14640 return 0;
14641}
14642
6fc2811b 14643DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
14644 doc: /* Read file name, prompting with PROMPT in directory DIR.
14645Use a file selection dialog.
14646Select DEFAULT-FILENAME in the dialog's file selection box, if
14647specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
14648 (prompt, dir, default_filename, mustmatch)
14649 Lisp_Object prompt, dir, default_filename, mustmatch;
14650{
14651 struct frame *f = SELECTED_FRAME ();
14652 Lisp_Object file = Qnil;
aed13378 14653 int count = SPECPDL_INDEX ();
6fc2811b
JR
14654 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14655 char filename[MAX_PATH + 1];
14656 char init_dir[MAX_PATH + 1];
6fc2811b
JR
14657
14658 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
14659 CHECK_STRING (prompt);
14660 CHECK_STRING (dir);
6fc2811b
JR
14661
14662 /* Create the dialog with PROMPT as title, using DIR as initial
14663 directory and using "*" as pattern. */
14664 dir = Fexpand_file_name (dir, Qnil);
d5db4077 14665 strncpy (init_dir, SDATA (dir), MAX_PATH);
6fc2811b
JR
14666 init_dir[MAX_PATH] = '\0';
14667 unixtodos_filename (init_dir);
14668
14669 if (STRINGP (default_filename))
14670 {
14671 char *file_name_only;
d5db4077 14672 char *full_path_name = SDATA (default_filename);
5ac45f98 14673
6fc2811b 14674 unixtodos_filename (full_path_name);
5ac45f98 14675
6fc2811b
JR
14676 file_name_only = strrchr (full_path_name, '\\');
14677 if (!file_name_only)
14678 file_name_only = full_path_name;
14679 else
14680 {
14681 file_name_only++;
6fc2811b 14682 }
ee78dc32 14683
6fc2811b
JR
14684 strncpy (filename, file_name_only, MAX_PATH);
14685 filename[MAX_PATH] = '\0';
14686 }
ee78dc32 14687 else
6fc2811b 14688 filename[0] = '\0';
ee78dc32 14689
1030b26b
JR
14690 {
14691 OPENFILENAME file_details;
5ac45f98 14692
1030b26b
JR
14693 /* Prevent redisplay. */
14694 specbind (Qinhibit_redisplay, Qt);
14695 BLOCK_INPUT;
ee78dc32 14696
1030b26b
JR
14697 bzero (&file_details, sizeof (file_details));
14698 file_details.lStructSize = sizeof (file_details);
14699 file_details.hwndOwner = FRAME_W32_WINDOW (f);
14700 /* Undocumented Bug in Common File Dialog:
14701 If a filter is not specified, shell links are not resolved. */
14702 file_details.lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
14703 file_details.lpstrFile = filename;
14704 file_details.nMaxFile = sizeof (filename);
14705 file_details.lpstrInitialDir = init_dir;
d5db4077 14706 file_details.lpstrTitle = SDATA (prompt);
1030b26b
JR
14707 file_details.Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
14708 | OFN_EXPLORER | OFN_ENABLEHOOK);
14709 if (!NILP (mustmatch))
14710 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
14711
14712 file_details.lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
14713
14714 if (GetOpenFileName (&file_details))
14715 {
14716 dostounix_filename (filename);
14717 if (file_details.nFilterIndex == 2)
14718 {
14719 /* "Folder Only" selected - strip dummy file name. */
14720 char * last = strrchr (filename, '/');
14721 *last = '\0';
14722 }
6fc2811b 14723
1030b26b
JR
14724 file = DECODE_FILE(build_string (filename));
14725 }
14726 /* User cancelled the dialog without making a selection. */
14727 else if (!CommDlgExtendedError ())
14728 file = Qnil;
14729 /* An error occurred, fallback on reading from the mini-buffer. */
14730 else
14731 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14732 dir, mustmatch, dir, Qfile_name_history,
14733 default_filename, Qnil);
14734
14735 UNBLOCK_INPUT;
14736 file = unbind_to (count, file);
14737 }
ee78dc32 14738
6fc2811b 14739 UNGCPRO;
1edf84e7 14740
6fc2811b
JR
14741 /* Make "Cancel" equivalent to C-g. */
14742 if (NILP (file))
14743 Fsignal (Qquit, Qnil);
ee78dc32 14744
dfff8a69 14745 return unbind_to (count, file);
6fc2811b 14746}
ee78dc32 14747
ee78dc32 14748
6fc2811b 14749\f
6fc2811b
JR
14750/***********************************************************************
14751 w32 specialized functions
14752 ***********************************************************************/
ee78dc32 14753
d84b082d 14754DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
14755 doc: /* Select a font using the W32 font dialog.
14756Returns an X font string corresponding to the selection. */)
d84b082d
JR
14757 (frame, include_proportional)
14758 Lisp_Object frame, include_proportional;
ee78dc32
GV
14759{
14760 FRAME_PTR f = check_x_frame (frame);
14761 CHOOSEFONT cf;
14762 LOGFONT lf;
f46e6225
GV
14763 TEXTMETRIC tm;
14764 HDC hdc;
14765 HANDLE oldobj;
ee78dc32
GV
14766 char buf[100];
14767
14768 bzero (&cf, sizeof (cf));
f46e6225 14769 bzero (&lf, sizeof (lf));
ee78dc32
GV
14770
14771 cf.lStructSize = sizeof (cf);
fbd6baed 14772 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
14773 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14774
14775 /* Unless include_proportional is non-nil, limit the selection to
14776 monospaced fonts. */
14777 if (NILP (include_proportional))
14778 cf.Flags |= CF_FIXEDPITCHONLY;
14779
ee78dc32
GV
14780 cf.lpLogFont = &lf;
14781
f46e6225
GV
14782 /* Initialize as much of the font details as we can from the current
14783 default font. */
14784 hdc = GetDC (FRAME_W32_WINDOW (f));
14785 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14786 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14787 if (GetTextMetrics (hdc, &tm))
14788 {
14789 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14790 lf.lfWeight = tm.tmWeight;
14791 lf.lfItalic = tm.tmItalic;
14792 lf.lfUnderline = tm.tmUnderlined;
14793 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
14794 lf.lfCharSet = tm.tmCharSet;
14795 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14796 }
14797 SelectObject (hdc, oldobj);
6fc2811b 14798 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 14799
767b1ff0 14800 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 14801 return Qnil;
ee78dc32
GV
14802
14803 return build_string (buf);
14804}
14805
74e1aeec
JR
14806DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14807 Sw32_send_sys_command, 1, 2, 0,
14808 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
14809Some useful values for command are #xf030 to maximise frame (#xf020
14810to minimize), #xf120 to restore frame to original size, and #xf100
14811to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
14812screen saver if defined.
14813
14814If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
14815 (command, frame)
14816 Lisp_Object command, frame;
14817{
1edf84e7
GV
14818 FRAME_PTR f = check_x_frame (frame);
14819
b7826503 14820 CHECK_NUMBER (command);
1edf84e7 14821
ce6059da 14822 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
14823
14824 return Qnil;
14825}
14826
55dcfc15 14827DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
14828 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14829This is a wrapper around the ShellExecute system function, which
14830invokes the application registered to handle OPERATION for DOCUMENT.
14831OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14832nil for the default action), and DOCUMENT is typically the name of a
14833document file or URL, but can also be a program executable to run or
14834a directory to open in the Windows Explorer.
14835
14836If DOCUMENT is a program executable, PARAMETERS can be a string
14837containing command line parameters, but otherwise should be nil.
14838
14839SHOW-FLAG can be used to control whether the invoked application is hidden
14840or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14841otherwise it is an integer representing a ShowWindow flag:
14842
14843 0 - start hidden
14844 1 - start normally
14845 3 - start maximized
14846 6 - start minimized */)
55dcfc15
AI
14847 (operation, document, parameters, show_flag)
14848 Lisp_Object operation, document, parameters, show_flag;
14849{
14850 Lisp_Object current_dir;
14851
b7826503 14852 CHECK_STRING (document);
55dcfc15
AI
14853
14854 /* Encode filename and current directory. */
14855 current_dir = ENCODE_FILE (current_buffer->directory);
14856 document = ENCODE_FILE (document);
14857 if ((int) ShellExecute (NULL,
6fc2811b 14858 (STRINGP (operation) ?
d5db4077
KR
14859 SDATA (operation) : NULL),
14860 SDATA (document),
55dcfc15 14861 (STRINGP (parameters) ?
d5db4077
KR
14862 SDATA (parameters) : NULL),
14863 SDATA (current_dir),
55dcfc15
AI
14864 (INTEGERP (show_flag) ?
14865 XINT (show_flag) : SW_SHOWDEFAULT))
14866 > 32)
14867 return Qt;
90d97e64 14868 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
14869}
14870
ccc2d29c
GV
14871/* Lookup virtual keycode from string representing the name of a
14872 non-ascii keystroke into the corresponding virtual key, using
14873 lispy_function_keys. */
14874static int
14875lookup_vk_code (char *key)
14876{
14877 int i;
14878
14879 for (i = 0; i < 256; i++)
14880 if (lispy_function_keys[i] != 0
14881 && strcmp (lispy_function_keys[i], key) == 0)
14882 return i;
14883
14884 return -1;
14885}
14886
14887/* Convert a one-element vector style key sequence to a hot key
14888 definition. */
14889static int
14890w32_parse_hot_key (key)
14891 Lisp_Object key;
14892{
14893 /* Copied from Fdefine_key and store_in_keymap. */
14894 register Lisp_Object c;
14895 int vk_code;
14896 int lisp_modifiers;
14897 int w32_modifiers;
14898 struct gcpro gcpro1;
14899
b7826503 14900 CHECK_VECTOR (key);
ccc2d29c
GV
14901
14902 if (XFASTINT (Flength (key)) != 1)
14903 return Qnil;
14904
14905 GCPRO1 (key);
14906
14907 c = Faref (key, make_number (0));
14908
14909 if (CONSP (c) && lucid_event_type_list_p (c))
14910 c = Fevent_convert_list (c);
14911
14912 UNGCPRO;
14913
14914 if (! INTEGERP (c) && ! SYMBOLP (c))
14915 error ("Key definition is invalid");
14916
14917 /* Work out the base key and the modifiers. */
14918 if (SYMBOLP (c))
14919 {
14920 c = parse_modifiers (c);
14921 lisp_modifiers = Fcar (Fcdr (c));
14922 c = Fcar (c);
14923 if (!SYMBOLP (c))
14924 abort ();
d5db4077 14925 vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c)));
ccc2d29c
GV
14926 }
14927 else if (INTEGERP (c))
14928 {
14929 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14930 /* Many ascii characters are their own virtual key code. */
14931 vk_code = XINT (c) & CHARACTERBITS;
14932 }
14933
14934 if (vk_code < 0 || vk_code > 255)
14935 return Qnil;
14936
14937 if ((lisp_modifiers & meta_modifier) != 0
14938 && !NILP (Vw32_alt_is_meta))
14939 lisp_modifiers |= alt_modifier;
14940
71eab8d1
AI
14941 /* Supply defs missing from mingw32. */
14942#ifndef MOD_ALT
14943#define MOD_ALT 0x0001
14944#define MOD_CONTROL 0x0002
14945#define MOD_SHIFT 0x0004
14946#define MOD_WIN 0x0008
14947#endif
14948
ccc2d29c
GV
14949 /* Convert lisp modifiers to Windows hot-key form. */
14950 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14951 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14952 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14953 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14954
14955 return HOTKEY (vk_code, w32_modifiers);
14956}
14957
74e1aeec
JR
14958DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14959 Sw32_register_hot_key, 1, 1, 0,
14960 doc: /* Register KEY as a hot-key combination.
14961Certain key combinations like Alt-Tab are reserved for system use on
14962Windows, and therefore are normally intercepted by the system. However,
14963most of these key combinations can be received by registering them as
14964hot-keys, overriding their special meaning.
14965
14966KEY must be a one element key definition in vector form that would be
14967acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14968modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14969is always interpreted as the Windows modifier keys.
14970
14971The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14972 (key)
14973 Lisp_Object key;
14974{
14975 key = w32_parse_hot_key (key);
14976
14977 if (NILP (Fmemq (key, w32_grabbed_keys)))
14978 {
14979 /* Reuse an empty slot if possible. */
14980 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14981
14982 /* Safe to add new key to list, even if we have focus. */
14983 if (NILP (item))
14984 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14985 else
f3fbd155 14986 XSETCAR (item, key);
ccc2d29c
GV
14987
14988 /* Notify input thread about new hot-key definition, so that it
14989 takes effect without needing to switch focus. */
14990 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14991 (WPARAM) key, 0);
14992 }
14993
14994 return key;
14995}
14996
74e1aeec
JR
14997DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14998 Sw32_unregister_hot_key, 1, 1, 0,
14999 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
15000 (key)
15001 Lisp_Object key;
15002{
15003 Lisp_Object item;
15004
15005 if (!INTEGERP (key))
15006 key = w32_parse_hot_key (key);
15007
15008 item = Fmemq (key, w32_grabbed_keys);
15009
15010 if (!NILP (item))
15011 {
15012 /* Notify input thread about hot-key definition being removed, so
15013 that it takes effect without needing focus switch. */
15014 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
15015 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
15016 {
15017 MSG msg;
15018 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
15019 }
15020 return Qt;
15021 }
15022 return Qnil;
15023}
15024
74e1aeec
JR
15025DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
15026 Sw32_registered_hot_keys, 0, 0, 0,
15027 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
15028 ()
15029{
15030 return Fcopy_sequence (w32_grabbed_keys);
15031}
15032
74e1aeec
JR
15033DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
15034 Sw32_reconstruct_hot_key, 1, 1, 0,
15035 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
15036 (hotkeyid)
15037 Lisp_Object hotkeyid;
15038{
15039 int vk_code, w32_modifiers;
15040 Lisp_Object key;
15041
b7826503 15042 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
15043
15044 vk_code = HOTKEY_VK_CODE (hotkeyid);
15045 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
15046
15047 if (lispy_function_keys[vk_code])
15048 key = intern (lispy_function_keys[vk_code]);
15049 else
15050 key = make_number (vk_code);
15051
15052 key = Fcons (key, Qnil);
15053 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 15054 key = Fcons (Qshift, key);
ccc2d29c 15055 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 15056 key = Fcons (Qctrl, key);
ccc2d29c 15057 if (w32_modifiers & MOD_ALT)
3ef68e6b 15058 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 15059 if (w32_modifiers & MOD_WIN)
3ef68e6b 15060 key = Fcons (Qhyper, key);
ccc2d29c
GV
15061
15062 return key;
15063}
adcc3809 15064
74e1aeec
JR
15065DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
15066 Sw32_toggle_lock_key, 1, 2, 0,
15067 doc: /* Toggle the state of the lock key KEY.
15068KEY can be `capslock', `kp-numlock', or `scroll'.
15069If the optional parameter NEW-STATE is a number, then the state of KEY
15070is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
15071 (key, new_state)
15072 Lisp_Object key, new_state;
15073{
15074 int vk_code;
adcc3809
GV
15075
15076 if (EQ (key, intern ("capslock")))
15077 vk_code = VK_CAPITAL;
15078 else if (EQ (key, intern ("kp-numlock")))
15079 vk_code = VK_NUMLOCK;
15080 else if (EQ (key, intern ("scroll")))
15081 vk_code = VK_SCROLL;
15082 else
15083 return Qnil;
15084
15085 if (!dwWindowsThreadId)
15086 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
15087
15088 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
15089 (WPARAM) vk_code, (LPARAM) new_state))
15090 {
15091 MSG msg;
15092 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
15093 return make_number (msg.wParam);
15094 }
15095 return Qnil;
15096}
ee78dc32 15097\f
2254bcde 15098DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
15099 doc: /* Return storage information about the file system FILENAME is on.
15100Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
15101storage of the file system, FREE is the free storage, and AVAIL is the
15102storage available to a non-superuser. All 3 numbers are in bytes.
15103If the underlying system call fails, value is nil. */)
2254bcde
AI
15104 (filename)
15105 Lisp_Object filename;
15106{
15107 Lisp_Object encoded, value;
15108
b7826503 15109 CHECK_STRING (filename);
2254bcde
AI
15110 filename = Fexpand_file_name (filename, Qnil);
15111 encoded = ENCODE_FILE (filename);
15112
15113 value = Qnil;
15114
15115 /* Determining the required information on Windows turns out, sadly,
15116 to be more involved than one would hope. The original Win32 api
15117 call for this will return bogus information on some systems, but we
15118 must dynamically probe for the replacement api, since that was
15119 added rather late on. */
15120 {
15121 HMODULE hKernel = GetModuleHandle ("kernel32");
15122 BOOL (*pfn_GetDiskFreeSpaceEx)
15123 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
15124 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
15125
15126 /* On Windows, we may need to specify the root directory of the
15127 volume holding FILENAME. */
15128 char rootname[MAX_PATH];
d5db4077 15129 char *name = SDATA (encoded);
2254bcde
AI
15130
15131 /* find the root name of the volume if given */
15132 if (isalpha (name[0]) && name[1] == ':')
15133 {
15134 rootname[0] = name[0];
15135 rootname[1] = name[1];
15136 rootname[2] = '\\';
15137 rootname[3] = 0;
15138 }
15139 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
15140 {
15141 char *str = rootname;
15142 int slashes = 4;
15143 do
15144 {
15145 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
15146 break;
15147 *str++ = *name++;
15148 }
15149 while ( *name );
15150
15151 *str++ = '\\';
15152 *str = 0;
15153 }
15154
15155 if (pfn_GetDiskFreeSpaceEx)
15156 {
ac849ba4
JR
15157 /* Unsigned large integers cannot be cast to double, so
15158 use signed ones instead. */
2254bcde
AI
15159 LARGE_INTEGER availbytes;
15160 LARGE_INTEGER freebytes;
15161 LARGE_INTEGER totalbytes;
15162
15163 if (pfn_GetDiskFreeSpaceEx(rootname,
ac849ba4
JR
15164 (ULARGE_INTEGER *)&availbytes,
15165 (ULARGE_INTEGER *)&totalbytes,
15166 (ULARGE_INTEGER *)&freebytes))
2254bcde
AI
15167 value = list3 (make_float ((double) totalbytes.QuadPart),
15168 make_float ((double) freebytes.QuadPart),
15169 make_float ((double) availbytes.QuadPart));
15170 }
15171 else
15172 {
15173 DWORD sectors_per_cluster;
15174 DWORD bytes_per_sector;
15175 DWORD free_clusters;
15176 DWORD total_clusters;
15177
15178 if (GetDiskFreeSpace(rootname,
15179 &sectors_per_cluster,
15180 &bytes_per_sector,
15181 &free_clusters,
15182 &total_clusters))
15183 value = list3 (make_float ((double) total_clusters
15184 * sectors_per_cluster * bytes_per_sector),
15185 make_float ((double) free_clusters
15186 * sectors_per_cluster * bytes_per_sector),
15187 make_float ((double) free_clusters
15188 * sectors_per_cluster * bytes_per_sector));
15189 }
15190 }
15191
15192 return value;
15193}
15194\f
0e3fcdef
JR
15195/***********************************************************************
15196 Initialization
15197 ***********************************************************************/
15198
15199void
fbd6baed 15200syms_of_w32fns ()
ee78dc32 15201{
afc390dc
JR
15202 globals_of_w32fns ();
15203 /* This is zero if not using MS-Windows. */
1edf84e7 15204 w32_in_use = 0;
9eb16b62
JR
15205 track_mouse_window = NULL;
15206
d285988b
JR
15207 w32_visible_system_caret_hwnd = NULL;
15208
ee78dc32
GV
15209 Qauto_raise = intern ("auto-raise");
15210 staticpro (&Qauto_raise);
15211 Qauto_lower = intern ("auto-lower");
15212 staticpro (&Qauto_lower);
ee78dc32
GV
15213 Qborder_color = intern ("border-color");
15214 staticpro (&Qborder_color);
15215 Qborder_width = intern ("border-width");
15216 staticpro (&Qborder_width);
ee78dc32
GV
15217 Qcursor_color = intern ("cursor-color");
15218 staticpro (&Qcursor_color);
15219 Qcursor_type = intern ("cursor-type");
15220 staticpro (&Qcursor_type);
ee78dc32
GV
15221 Qgeometry = intern ("geometry");
15222 staticpro (&Qgeometry);
15223 Qicon_left = intern ("icon-left");
15224 staticpro (&Qicon_left);
15225 Qicon_top = intern ("icon-top");
15226 staticpro (&Qicon_top);
15227 Qicon_type = intern ("icon-type");
15228 staticpro (&Qicon_type);
15229 Qicon_name = intern ("icon-name");
15230 staticpro (&Qicon_name);
15231 Qinternal_border_width = intern ("internal-border-width");
15232 staticpro (&Qinternal_border_width);
15233 Qleft = intern ("left");
15234 staticpro (&Qleft);
1026b400
RS
15235 Qright = intern ("right");
15236 staticpro (&Qright);
ee78dc32
GV
15237 Qmouse_color = intern ("mouse-color");
15238 staticpro (&Qmouse_color);
15239 Qnone = intern ("none");
15240 staticpro (&Qnone);
15241 Qparent_id = intern ("parent-id");
15242 staticpro (&Qparent_id);
15243 Qscroll_bar_width = intern ("scroll-bar-width");
15244 staticpro (&Qscroll_bar_width);
15245 Qsuppress_icon = intern ("suppress-icon");
15246 staticpro (&Qsuppress_icon);
ee78dc32
GV
15247 Qundefined_color = intern ("undefined-color");
15248 staticpro (&Qundefined_color);
15249 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
15250 staticpro (&Qvertical_scroll_bars);
15251 Qvisibility = intern ("visibility");
15252 staticpro (&Qvisibility);
15253 Qwindow_id = intern ("window-id");
15254 staticpro (&Qwindow_id);
15255 Qx_frame_parameter = intern ("x-frame-parameter");
15256 staticpro (&Qx_frame_parameter);
15257 Qx_resource_name = intern ("x-resource-name");
15258 staticpro (&Qx_resource_name);
15259 Quser_position = intern ("user-position");
15260 staticpro (&Quser_position);
15261 Quser_size = intern ("user-size");
15262 staticpro (&Quser_size);
6fc2811b
JR
15263 Qscreen_gamma = intern ("screen-gamma");
15264 staticpro (&Qscreen_gamma);
dfff8a69
JR
15265 Qline_spacing = intern ("line-spacing");
15266 staticpro (&Qline_spacing);
15267 Qcenter = intern ("center");
15268 staticpro (&Qcenter);
dc220243
JR
15269 Qcancel_timer = intern ("cancel-timer");
15270 staticpro (&Qcancel_timer);
f7b9d4d1
JR
15271 Qfullscreen = intern ("fullscreen");
15272 staticpro (&Qfullscreen);
15273 Qfullwidth = intern ("fullwidth");
15274 staticpro (&Qfullwidth);
15275 Qfullheight = intern ("fullheight");
15276 staticpro (&Qfullheight);
15277 Qfullboth = intern ("fullboth");
15278 staticpro (&Qfullboth);
ee78dc32 15279
adcc3809
GV
15280 Qhyper = intern ("hyper");
15281 staticpro (&Qhyper);
15282 Qsuper = intern ("super");
15283 staticpro (&Qsuper);
15284 Qmeta = intern ("meta");
15285 staticpro (&Qmeta);
15286 Qalt = intern ("alt");
15287 staticpro (&Qalt);
15288 Qctrl = intern ("ctrl");
15289 staticpro (&Qctrl);
15290 Qcontrol = intern ("control");
15291 staticpro (&Qcontrol);
15292 Qshift = intern ("shift");
15293 staticpro (&Qshift);
f7b9d4d1 15294 /* This is the end of symbol initialization. */
adcc3809 15295
6fc2811b
JR
15296 /* Text property `display' should be nonsticky by default. */
15297 Vtext_property_default_nonsticky
15298 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
15299
15300
15301 Qlaplace = intern ("laplace");
15302 staticpro (&Qlaplace);
3cf3436e
JR
15303 Qemboss = intern ("emboss");
15304 staticpro (&Qemboss);
15305 Qedge_detection = intern ("edge-detection");
15306 staticpro (&Qedge_detection);
15307 Qheuristic = intern ("heuristic");
15308 staticpro (&Qheuristic);
15309 QCmatrix = intern (":matrix");
15310 staticpro (&QCmatrix);
15311 QCcolor_adjustment = intern (":color-adjustment");
15312 staticpro (&QCcolor_adjustment);
15313 QCmask = intern (":mask");
15314 staticpro (&QCmask);
6fc2811b 15315
4b817373
RS
15316 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
15317 staticpro (&Qface_set_after_frame_default);
15318
ee78dc32
GV
15319 Fput (Qundefined_color, Qerror_conditions,
15320 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
15321 Fput (Qundefined_color, Qerror_message,
15322 build_string ("Undefined color"));
15323
ccc2d29c
GV
15324 staticpro (&w32_grabbed_keys);
15325 w32_grabbed_keys = Qnil;
15326
fbd6baed 15327 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 15328 doc: /* An array of color name mappings for windows. */);
fbd6baed 15329 Vw32_color_map = Qnil;
ee78dc32 15330
fbd6baed 15331 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
15332 doc: /* Non-nil if alt key presses are passed on to Windows.
15333When non-nil, for example, alt pressed and released and then space will
15334open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 15335 Vw32_pass_alt_to_system = Qnil;
da36a4d6 15336
fbd6baed 15337 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
15338 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
15339When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 15340 Vw32_alt_is_meta = Qt;
8c205c63 15341
7d081355 15342 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 15343 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
15344 XSETINT (Vw32_quit_key, 0);
15345
7d0393cf 15346 DEFVAR_LISP ("w32-pass-lwindow-to-system",
ccc2d29c 15347 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
15348 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
15349When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
15350 Vw32_pass_lwindow_to_system = Qt;
15351
7d0393cf 15352 DEFVAR_LISP ("w32-pass-rwindow-to-system",
ccc2d29c 15353 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
15354 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
15355When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
15356 Vw32_pass_rwindow_to_system = Qt;
15357
adcc3809
GV
15358 DEFVAR_INT ("w32-phantom-key-code",
15359 &Vw32_phantom_key_code,
74e1aeec
JR
15360 doc: /* Virtual key code used to generate \"phantom\" key presses.
15361Value is a number between 0 and 255.
15362
15363Phantom key presses are generated in order to stop the system from
15364acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
15365`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
15366 /* Although 255 is technically not a valid key code, it works and
15367 means that this hack won't interfere with any real key code. */
15368 Vw32_phantom_key_code = 255;
adcc3809 15369
7d0393cf 15370 DEFVAR_LISP ("w32-enable-num-lock",
ccc2d29c 15371 &Vw32_enable_num_lock,
74e1aeec
JR
15372 doc: /* Non-nil if Num Lock should act normally.
15373Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
15374 Vw32_enable_num_lock = Qt;
15375
7d0393cf 15376 DEFVAR_LISP ("w32-enable-caps-lock",
ccc2d29c 15377 &Vw32_enable_caps_lock,
74e1aeec
JR
15378 doc: /* Non-nil if Caps Lock should act normally.
15379Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
15380 Vw32_enable_caps_lock = Qt;
15381
15382 DEFVAR_LISP ("w32-scroll-lock-modifier",
15383 &Vw32_scroll_lock_modifier,
74e1aeec
JR
15384 doc: /* Modifier to use for the Scroll Lock on state.
15385The value can be hyper, super, meta, alt, control or shift for the
15386respective modifier, or nil to see Scroll Lock as the key `scroll'.
15387Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15388 Vw32_scroll_lock_modifier = Qt;
15389
15390 DEFVAR_LISP ("w32-lwindow-modifier",
15391 &Vw32_lwindow_modifier,
74e1aeec
JR
15392 doc: /* Modifier to use for the left \"Windows\" key.
15393The value can be hyper, super, meta, alt, control or shift for the
15394respective modifier, or nil to appear as the key `lwindow'.
15395Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15396 Vw32_lwindow_modifier = Qnil;
15397
15398 DEFVAR_LISP ("w32-rwindow-modifier",
15399 &Vw32_rwindow_modifier,
74e1aeec
JR
15400 doc: /* Modifier to use for the right \"Windows\" key.
15401The value can be hyper, super, meta, alt, control or shift for the
15402respective modifier, or nil to appear as the key `rwindow'.
15403Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15404 Vw32_rwindow_modifier = Qnil;
15405
15406 DEFVAR_LISP ("w32-apps-modifier",
15407 &Vw32_apps_modifier,
74e1aeec
JR
15408 doc: /* Modifier to use for the \"Apps\" key.
15409The value can be hyper, super, meta, alt, control or shift for the
15410respective modifier, or nil to appear as the key `apps'.
15411Any other value will cause the key to be ignored. */);
ccc2d29c 15412 Vw32_apps_modifier = Qnil;
da36a4d6 15413
d84b082d 15414 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 15415 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 15416 w32_enable_synthesized_fonts = 0;
5ac45f98 15417
fbd6baed 15418 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 15419 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 15420 Vw32_enable_palette = Qt;
5ac45f98 15421
fbd6baed
GV
15422 DEFVAR_INT ("w32-mouse-button-tolerance",
15423 &Vw32_mouse_button_tolerance,
74e1aeec
JR
15424 doc: /* Analogue of double click interval for faking middle mouse events.
15425The value is the minimum time in milliseconds that must elapse between
15426left/right button down events before they are considered distinct events.
15427If both mouse buttons are depressed within this interval, a middle mouse
15428button down event is generated instead. */);
fbd6baed 15429 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 15430
fbd6baed
GV
15431 DEFVAR_INT ("w32-mouse-move-interval",
15432 &Vw32_mouse_move_interval,
74e1aeec
JR
15433 doc: /* Minimum interval between mouse move events.
15434The value is the minimum time in milliseconds that must elapse between
15435successive mouse move (or scroll bar drag) events before they are
15436reported as lisp events. */);
247be837 15437 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 15438
74214547
JR
15439 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
15440 &w32_pass_extra_mouse_buttons_to_system,
15441 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
15442Recent versions of Windows support mice with up to five buttons.
15443Since most applications don't support these extra buttons, most mouse
15444drivers will allow you to map them to functions at the system level.
15445If this variable is non-nil, Emacs will pass them on, allowing the
15446system to handle them. */);
15447 w32_pass_extra_mouse_buttons_to_system = 0;
15448
ee78dc32
GV
15449 init_x_parm_symbols ();
15450
15451 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
6e2d67d8 15452 doc: /* List of directories to search for window system bitmap files. */);
ee78dc32
GV
15453 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15454
15455 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
15456 doc: /* The shape of the pointer when over text.
15457Changing the value does not affect existing frames
15458unless you set the mouse color. */);
ee78dc32
GV
15459 Vx_pointer_shape = Qnil;
15460
15461 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
15462 doc: /* The name Emacs uses to look up resources; for internal use only.
15463`x-get-resource' uses this as the first component of the instance name
15464when requesting resource values.
15465Emacs initially sets `x-resource-name' to the name under which Emacs
15466was invoked, or to the value specified with the `-name' or `-rn'
15467switches, if present. */);
ee78dc32
GV
15468 Vx_resource_name = Qnil;
15469
15470 Vx_nontext_pointer_shape = Qnil;
15471
15472 Vx_mode_pointer_shape = Qnil;
15473
0af913d7 15474 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
15475 doc: /* The shape of the pointer when Emacs is busy.
15476This variable takes effect when you create a new frame
15477or when you set the mouse color. */);
0af913d7 15478 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 15479
0af913d7 15480 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 15481 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 15482 display_hourglass_p = 1;
7d0393cf 15483
0af913d7 15484 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
15485 doc: /* *Seconds to wait before displaying an hourglass pointer.
15486Value must be an integer or float. */);
0af913d7 15487 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 15488
6fc2811b 15489 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 15490 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
15491 doc: /* The shape of the pointer when over mouse-sensitive text.
15492This variable takes effect when you create a new frame
15493or when you set the mouse color. */);
ee78dc32
GV
15494 Vx_sensitive_text_pointer_shape = Qnil;
15495
4694d762
JR
15496 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15497 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
15498 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15499This variable takes effect when you create a new frame
15500or when you set the mouse color. */);
4694d762
JR
15501 Vx_window_horizontal_drag_shape = Qnil;
15502
ee78dc32 15503 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 15504 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
15505 Vx_cursor_fore_pixel = Qnil;
15506
3cf3436e 15507 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
15508 doc: /* Maximum size for tooltips.
15509Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e 15510 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
7d0393cf 15511
ee78dc32 15512 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
15513 doc: /* Non-nil if no window manager is in use.
15514Emacs doesn't try to figure this out; this is always nil
15515unless you set it to something else. */);
ee78dc32
GV
15516 /* We don't have any way to find this out, so set it to nil
15517 and maybe the user would like to set it to t. */
15518 Vx_no_window_manager = Qnil;
15519
4587b026
GV
15520 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15521 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
15522 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15523
15524Since Emacs gets width of a font matching with this regexp from
15525PIXEL_SIZE field of the name, font finding mechanism gets faster for
15526such a font. This is especially effective for such large fonts as
15527Chinese, Japanese, and Korean. */);
4587b026
GV
15528 Vx_pixel_size_width_font_regexp = Qnil;
15529
6fc2811b 15530 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
15531 doc: /* Time after which cached images are removed from the cache.
15532When an image has not been displayed this many seconds, remove it
15533from the image cache. Value must be an integer or nil with nil
15534meaning don't clear the cache. */);
6fc2811b
JR
15535 Vimage_cache_eviction_delay = make_number (30 * 60);
15536
33d52f9c
GV
15537 DEFVAR_LISP ("w32-bdf-filename-alist",
15538 &Vw32_bdf_filename_alist,
74e1aeec 15539 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
15540 Vw32_bdf_filename_alist = Qnil;
15541
1075afa9
GV
15542 DEFVAR_BOOL ("w32-strict-fontnames",
15543 &w32_strict_fontnames,
74e1aeec
JR
15544 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15545Default is nil, which allows old fontnames that are not XLFD compliant,
15546and allows third-party CJK display to work by specifying false charset
15547fields to trick Emacs into translating to Big5, SJIS etc.
15548Setting this to t will prevent wrong fonts being selected when
15549fontsets are automatically created. */);
1075afa9
GV
15550 w32_strict_fontnames = 0;
15551
c0611964
AI
15552 DEFVAR_BOOL ("w32-strict-painting",
15553 &w32_strict_painting,
74e1aeec
JR
15554 doc: /* Non-nil means use strict rules for repainting frames.
15555Set this to nil to get the old behaviour for repainting; this should
15556only be necessary if the default setting causes problems. */);
c0611964
AI
15557 w32_strict_painting = 1;
15558
dfff8a69
JR
15559 DEFVAR_LISP ("w32-charset-info-alist",
15560 &Vw32_charset_info_alist,
b3700ae7
JR
15561 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15562Each entry should be of the form:
74e1aeec
JR
15563
15564 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15565
15566where CHARSET_NAME is a string used in font names to identify the charset,
15567WINDOWS_CHARSET is a symbol that can be one of:
15568w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15569w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15570w32-charset-chinesebig5,
dfff8a69 15571#ifdef JOHAB_CHARSET
74e1aeec
JR
15572w32-charset-johab, w32-charset-hebrew,
15573w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15574w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15575w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
15576#endif
15577#ifdef UNICODE_CHARSET
74e1aeec 15578w32-charset-unicode,
dfff8a69 15579#endif
74e1aeec
JR
15580or w32-charset-oem.
15581CODEPAGE should be an integer specifying the codepage that should be used
15582to display the character set, t to do no translation and output as Unicode,
15583or nil to do no translation and output as 8 bit (or multibyte on far-east
15584versions of Windows) characters. */);
dfff8a69
JR
15585 Vw32_charset_info_alist = Qnil;
15586
15587 staticpro (&Qw32_charset_ansi);
15588 Qw32_charset_ansi = intern ("w32-charset-ansi");
15589 staticpro (&Qw32_charset_symbol);
15590 Qw32_charset_symbol = intern ("w32-charset-symbol");
15591 staticpro (&Qw32_charset_shiftjis);
15592 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
15593 staticpro (&Qw32_charset_hangeul);
15594 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
15595 staticpro (&Qw32_charset_chinesebig5);
15596 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15597 staticpro (&Qw32_charset_gb2312);
15598 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15599 staticpro (&Qw32_charset_oem);
15600 Qw32_charset_oem = intern ("w32-charset-oem");
15601
15602#ifdef JOHAB_CHARSET
15603 {
15604 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
15605 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15606 doc: /* Internal variable. */);
dfff8a69
JR
15607
15608 staticpro (&Qw32_charset_johab);
15609 Qw32_charset_johab = intern ("w32-charset-johab");
15610 staticpro (&Qw32_charset_easteurope);
15611 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15612 staticpro (&Qw32_charset_turkish);
15613 Qw32_charset_turkish = intern ("w32-charset-turkish");
15614 staticpro (&Qw32_charset_baltic);
15615 Qw32_charset_baltic = intern ("w32-charset-baltic");
15616 staticpro (&Qw32_charset_russian);
15617 Qw32_charset_russian = intern ("w32-charset-russian");
15618 staticpro (&Qw32_charset_arabic);
15619 Qw32_charset_arabic = intern ("w32-charset-arabic");
15620 staticpro (&Qw32_charset_greek);
15621 Qw32_charset_greek = intern ("w32-charset-greek");
15622 staticpro (&Qw32_charset_hebrew);
15623 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
15624 staticpro (&Qw32_charset_vietnamese);
15625 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
15626 staticpro (&Qw32_charset_thai);
15627 Qw32_charset_thai = intern ("w32-charset-thai");
15628 staticpro (&Qw32_charset_mac);
15629 Qw32_charset_mac = intern ("w32-charset-mac");
15630 }
15631#endif
15632
15633#ifdef UNICODE_CHARSET
15634 {
15635 static int w32_unicode_charset_defined = 1;
15636 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
15637 &w32_unicode_charset_defined,
15638 doc: /* Internal variable. */);
dfff8a69
JR
15639
15640 staticpro (&Qw32_charset_unicode);
15641 Qw32_charset_unicode = intern ("w32-charset-unicode");
15642#endif
15643
ee78dc32 15644 defsubr (&Sx_get_resource);
767b1ff0 15645#if 0 /* TODO: Port to W32 */
6fc2811b
JR
15646 defsubr (&Sx_change_window_property);
15647 defsubr (&Sx_delete_window_property);
15648 defsubr (&Sx_window_property);
15649#endif
2d764c78 15650 defsubr (&Sxw_display_color_p);
ee78dc32 15651 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
15652 defsubr (&Sxw_color_defined_p);
15653 defsubr (&Sxw_color_values);
ee78dc32
GV
15654 defsubr (&Sx_server_max_request_size);
15655 defsubr (&Sx_server_vendor);
15656 defsubr (&Sx_server_version);
15657 defsubr (&Sx_display_pixel_width);
15658 defsubr (&Sx_display_pixel_height);
15659 defsubr (&Sx_display_mm_width);
15660 defsubr (&Sx_display_mm_height);
15661 defsubr (&Sx_display_screens);
15662 defsubr (&Sx_display_planes);
15663 defsubr (&Sx_display_color_cells);
15664 defsubr (&Sx_display_visual_class);
15665 defsubr (&Sx_display_backing_store);
15666 defsubr (&Sx_display_save_under);
15667 defsubr (&Sx_parse_geometry);
15668 defsubr (&Sx_create_frame);
ee78dc32
GV
15669 defsubr (&Sx_open_connection);
15670 defsubr (&Sx_close_connection);
15671 defsubr (&Sx_display_list);
15672 defsubr (&Sx_synchronize);
15673
fbd6baed 15674 /* W32 specific functions */
ee78dc32 15675
1edf84e7 15676 defsubr (&Sw32_focus_frame);
fbd6baed
GV
15677 defsubr (&Sw32_select_font);
15678 defsubr (&Sw32_define_rgb_color);
15679 defsubr (&Sw32_default_color_map);
15680 defsubr (&Sw32_load_color_file);
1edf84e7 15681 defsubr (&Sw32_send_sys_command);
55dcfc15 15682 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
15683 defsubr (&Sw32_register_hot_key);
15684 defsubr (&Sw32_unregister_hot_key);
15685 defsubr (&Sw32_registered_hot_keys);
15686 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 15687 defsubr (&Sw32_toggle_lock_key);
33d52f9c 15688 defsubr (&Sw32_find_bdf_fonts);
4587b026 15689
2254bcde
AI
15690 defsubr (&Sfile_system_info);
15691
4587b026
GV
15692 /* Setting callback functions for fontset handler. */
15693 get_font_info_func = w32_get_font_info;
6fc2811b
JR
15694
15695#if 0 /* This function pointer doesn't seem to be used anywhere.
15696 And the pointer assigned has the wrong type, anyway. */
4587b026 15697 list_fonts_func = w32_list_fonts;
6fc2811b
JR
15698#endif
15699
4587b026
GV
15700 load_font_func = w32_load_font;
15701 find_ccl_program_func = w32_find_ccl_program;
15702 query_font_func = w32_query_font;
15703 set_frame_fontset_func = x_set_font;
15704 check_window_system_func = check_w32;
6fc2811b 15705
6fc2811b
JR
15706 /* Images. */
15707 Qxbm = intern ("xbm");
15708 staticpro (&Qxbm);
a93f4566
GM
15709 QCconversion = intern (":conversion");
15710 staticpro (&QCconversion);
6fc2811b
JR
15711 QCheuristic_mask = intern (":heuristic-mask");
15712 staticpro (&QCheuristic_mask);
15713 QCcolor_symbols = intern (":color-symbols");
15714 staticpro (&QCcolor_symbols);
6fc2811b
JR
15715 QCascent = intern (":ascent");
15716 staticpro (&QCascent);
15717 QCmargin = intern (":margin");
15718 staticpro (&QCmargin);
15719 QCrelief = intern (":relief");
15720 staticpro (&QCrelief);
15721 Qpostscript = intern ("postscript");
15722 staticpro (&Qpostscript);
15723 QCloader = intern (":loader");
15724 staticpro (&QCloader);
15725 QCbounding_box = intern (":bounding-box");
15726 staticpro (&QCbounding_box);
15727 QCpt_width = intern (":pt-width");
15728 staticpro (&QCpt_width);
15729 QCpt_height = intern (":pt-height");
15730 staticpro (&QCpt_height);
15731 QCindex = intern (":index");
15732 staticpro (&QCindex);
15733 Qpbm = intern ("pbm");
15734 staticpro (&Qpbm);
15735
15736#if HAVE_XPM
15737 Qxpm = intern ("xpm");
15738 staticpro (&Qxpm);
15739#endif
7d0393cf 15740
6fc2811b
JR
15741#if HAVE_JPEG
15742 Qjpeg = intern ("jpeg");
15743 staticpro (&Qjpeg);
7d0393cf 15744#endif
6fc2811b
JR
15745
15746#if HAVE_TIFF
15747 Qtiff = intern ("tiff");
15748 staticpro (&Qtiff);
7d0393cf 15749#endif
6fc2811b
JR
15750
15751#if HAVE_GIF
15752 Qgif = intern ("gif");
15753 staticpro (&Qgif);
15754#endif
15755
15756#if HAVE_PNG
15757 Qpng = intern ("png");
15758 staticpro (&Qpng);
15759#endif
15760
15761 defsubr (&Sclear_image_cache);
ac849ba4
JR
15762 defsubr (&Simage_size);
15763 defsubr (&Simage_mask_p);
6fc2811b
JR
15764
15765#if GLYPH_DEBUG
15766 defsubr (&Simagep);
15767 defsubr (&Slookup_image);
15768#endif
6fc2811b 15769
0af913d7
GM
15770 hourglass_atimer = NULL;
15771 hourglass_shown_p = 0;
6fc2811b
JR
15772 defsubr (&Sx_show_tip);
15773 defsubr (&Sx_hide_tip);
6fc2811b 15774 tip_timer = Qnil;
57fa2774
JR
15775 staticpro (&tip_timer);
15776 tip_frame = Qnil;
15777 staticpro (&tip_frame);
6fc2811b 15778
ca56d953
JR
15779 last_show_tip_args = Qnil;
15780 staticpro (&last_show_tip_args);
15781
6fc2811b
JR
15782 defsubr (&Sx_file_dialog);
15783}
15784
c922a224 15785
9785d95b
BK
15786/*
15787 globals_of_w32fns is used to initialize those global variables that
15788 must always be initialized on startup even when the global variable
15789 initialized is non zero (see the function main in emacs.c).
15790 globals_of_w32fns is called from syms_of_w32fns when the global
15791 variable initialized is 0 and directly from main when initialized
15792 is non zero.
15793 */
15794void globals_of_w32fns ()
15795{
15796 HMODULE user32_lib = GetModuleHandle ("user32.dll");
15797 /*
15798 TrackMouseEvent not available in all versions of Windows, so must load
15799 it dynamically. Do it once, here, instead of every time it is used.
15800 */
15801 track_mouse_event_fn = (TrackMouseEvent_Proc) GetProcAddress (user32_lib, "TrackMouseEvent");
15802}
6fc2811b 15803
839b1909
JR
15804/* Initialize image types. Based on which libraries are available. */
15805static void
15806init_external_image_libraries ()
6fc2811b 15807{
afc390dc 15808 HINSTANCE library;
7d0393cf 15809
6fc2811b 15810#if HAVE_XPM
c736ffda
JR
15811 if ((library = LoadLibrary ("libXpm.dll")))
15812 {
15813 if (init_xpm_functions (library))
15814 define_image_type (&xpm_type);
15815 }
15816
6fc2811b 15817#endif
7d0393cf 15818
6fc2811b 15819#if HAVE_JPEG
afc390dc 15820 /* Try loading jpeg library under probable names. */
c922a224 15821 if ((library = LoadLibrary ("libjpeg.dll"))
100dcd40 15822 || (library = LoadLibrary ("jpeg-62.dll"))
c922a224 15823 || (library = LoadLibrary ("jpeg.dll")))
afc390dc
JR
15824 {
15825 if (init_jpeg_functions (library))
15826 define_image_type (&jpeg_type);
15827 }
6fc2811b 15828#endif
7d0393cf 15829
6fc2811b 15830#if HAVE_TIFF
12b918b2
JB
15831 if (library = LoadLibrary ("libtiff.dll"))
15832 {
15833 if (init_tiff_functions (library))
15834 define_image_type (&tiff_type);
15835 }
6fc2811b 15836#endif
919f1e88 15837
6fc2811b 15838#if HAVE_GIF
1ffb278b
JB
15839 if (library = LoadLibrary ("libungif.dll"))
15840 {
15841 if (init_gif_functions (library))
15842 define_image_type (&gif_type);
15843 }
6fc2811b 15844#endif
7d0393cf 15845
6fc2811b 15846#if HAVE_PNG
839b1909
JR
15847 /* Ensure zlib is loaded. Try debug version first. */
15848 if (!LoadLibrary ("zlibd.dll"))
15849 LoadLibrary ("zlib.dll");
15850
15851 /* Try loading libpng under probable names. */
afc390dc
JR
15852 if ((library = LoadLibrary ("libpng13d.dll"))
15853 || (library = LoadLibrary ("libpng13.dll"))
15854 || (library = LoadLibrary ("libpng12d.dll"))
15855 || (library = LoadLibrary ("libpng12.dll"))
15856 || (library = LoadLibrary ("libpng.dll")))
839b1909 15857 {
afc390dc 15858 if (init_png_functions (library))
839b1909
JR
15859 define_image_type (&png_type);
15860 }
6fc2811b 15861#endif
ee78dc32
GV
15862}
15863
839b1909
JR
15864void
15865init_xfns ()
15866{
15867 image_types = NULL;
15868 Vimage_types = Qnil;
15869
15870 define_image_type (&pbm_type);
15871 define_image_type (&xbm_type);
15872
15873#if 0 /* TODO : Ghostscript support for W32 */
15874 define_image_type (&gs_type);
15875#endif
15876
15877 /* Image types that rely on external libraries are loaded dynamically
15878 if the library is available. */
15879 init_external_image_libraries ();
15880}
15881
ee78dc32
GV
15882#undef abort
15883
7d0393cf 15884void
fbd6baed 15885w32_abort()
ee78dc32 15886{
5ac45f98
GV
15887 int button;
15888 button = MessageBox (NULL,
15889 "A fatal error has occurred!\n\n"
15890 "Select Abort to exit, Retry to debug, Ignore to continue",
15891 "Emacs Abort Dialog",
15892 MB_ICONEXCLAMATION | MB_TASKMODAL
15893 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15894 switch (button)
15895 {
15896 case IDRETRY:
15897 DebugBreak ();
15898 break;
15899 case IDIGNORE:
15900 break;
15901 case IDABORT:
15902 default:
15903 abort ();
15904 break;
15905 }
ee78dc32 15906}
d573caac 15907
83c75055
GV
15908/* For convenience when debugging. */
15909int
15910w32_last_error()
15911{
15912 return GetLastError ();
15913}