(x_build_heuristic_mask): Filter palette info from color.
[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
ee78dc32 58extern void free_frame_menubar ();
9eb16b62 59extern void x_compute_fringe_widths P_ ((struct frame *, int));
6fc2811b 60extern double atof ();
9eb16b62
JR
61extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
62extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
63extern void w32_free_menu_strings P_ ((HWND));
64
5ac45f98 65extern int quit_char;
ee78dc32 66
ccc2d29c
GV
67extern char *lispy_function_keys[];
68
6fc2811b
JR
69/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
70 it, and including `bitmaps/gray' more than once is a problem when
71 config.h defines `static' as an empty replacement string. */
72
73int gray_bitmap_width = gray_width;
74int gray_bitmap_height = gray_height;
75unsigned char *gray_bitmap_bits = gray_bits;
76
ee78dc32 77/* The colormap for converting color names to RGB values */
fbd6baed 78Lisp_Object Vw32_color_map;
ee78dc32 79
da36a4d6 80/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 81Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 82
8c205c63
RS
83/* Non nil if alt key is translated to meta_modifier, nil if it is translated
84 to alt_modifier. */
fbd6baed 85Lisp_Object Vw32_alt_is_meta;
8c205c63 86
7d081355
AI
87/* If non-zero, the windows virtual key code for an alternative quit key. */
88Lisp_Object Vw32_quit_key;
89
ccc2d29c
GV
90/* Non nil if left window key events are passed on to Windows (this only
91 affects whether "tapping" the key opens the Start menu). */
92Lisp_Object Vw32_pass_lwindow_to_system;
93
94/* Non nil if right window key events are passed on to Windows (this
95 only affects whether "tapping" the key opens the Start menu). */
96Lisp_Object Vw32_pass_rwindow_to_system;
97
adcc3809
GV
98/* Virtual key code used to generate "phantom" key presses in order
99 to stop system from acting on Windows key events. */
100Lisp_Object Vw32_phantom_key_code;
101
ccc2d29c
GV
102/* Modifier associated with the left "Windows" key, or nil to act as a
103 normal key. */
104Lisp_Object Vw32_lwindow_modifier;
105
106/* Modifier associated with the right "Windows" key, or nil to act as a
107 normal key. */
108Lisp_Object Vw32_rwindow_modifier;
109
110/* Modifier associated with the "Apps" key, or nil to act as a normal
111 key. */
112Lisp_Object Vw32_apps_modifier;
113
114/* Value is nil if Num Lock acts as a function key. */
115Lisp_Object Vw32_enable_num_lock;
116
117/* Value is nil if Caps Lock acts as a function key. */
118Lisp_Object Vw32_enable_caps_lock;
119
120/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
121Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 122
7ce9aaca 123/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b 124 and italic versions of fonts. */
d84b082d 125int w32_enable_synthesized_fonts;
5ac45f98
GV
126
127/* Enable palette management. */
fbd6baed 128Lisp_Object Vw32_enable_palette;
5ac45f98
GV
129
130/* Control how close left/right button down events must be to
131 be converted to a middle button down event. */
fbd6baed 132Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 133
84fb1139
KH
134/* Minimum interval between mouse movement (and scroll bar drag)
135 events that are passed on to the event loop. */
fbd6baed 136Lisp_Object Vw32_mouse_move_interval;
84fb1139 137
74214547
JR
138/* Flag to indicate if XBUTTON events should be passed on to Windows. */
139int w32_pass_extra_mouse_buttons_to_system;
140
ee78dc32
GV
141/* The name we're using in resource queries. */
142Lisp_Object Vx_resource_name;
143
144/* Non nil if no window manager is in use. */
145Lisp_Object Vx_no_window_manager;
146
0af913d7 147/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 148
0af913d7 149int display_hourglass_p;
6fc2811b 150
ee78dc32
GV
151/* The background and shape of the mouse pointer, and shape when not
152 over text or in the modeline. */
dfff8a69 153
ee78dc32 154Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 155Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 156
ee78dc32 157/* The shape when over mouse-sensitive text. */
dfff8a69 158
ee78dc32
GV
159Lisp_Object Vx_sensitive_text_pointer_shape;
160
161/* Color of chars displayed in cursor box. */
dfff8a69 162
ee78dc32
GV
163Lisp_Object Vx_cursor_fore_pixel;
164
1edf84e7 165/* Nonzero if using Windows. */
dfff8a69 166
1edf84e7
GV
167static int w32_in_use;
168
ee78dc32 169/* Search path for bitmap files. */
dfff8a69 170
ee78dc32
GV
171Lisp_Object Vx_bitmap_file_path;
172
4587b026 173/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 174
4587b026
GV
175Lisp_Object Vx_pixel_size_width_font_regexp;
176
33d52f9c
GV
177/* Alist of bdf fonts and the files that define them. */
178Lisp_Object Vw32_bdf_filename_alist;
179
f46e6225 180/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
181int w32_strict_fontnames;
182
c0611964
AI
183/* A flag to control whether we should only repaint if GetUpdateRect
184 indicates there is an update region. */
185int w32_strict_painting;
186
dfff8a69
JR
187/* Associative list linking character set strings to Windows codepages. */
188Lisp_Object Vw32_charset_info_alist;
189
190/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
191#ifndef VIETNAMESE_CHARSET
192#define VIETNAMESE_CHARSET 163
193#endif
194
ee78dc32
GV
195Lisp_Object Qauto_raise;
196Lisp_Object Qauto_lower;
ee78dc32
GV
197Lisp_Object Qborder_color;
198Lisp_Object Qborder_width;
ab0bb234 199extern Lisp_Object Qbox;
ee78dc32
GV
200Lisp_Object Qcursor_color;
201Lisp_Object Qcursor_type;
ee78dc32
GV
202Lisp_Object Qgeometry;
203Lisp_Object Qicon_left;
204Lisp_Object Qicon_top;
205Lisp_Object Qicon_type;
206Lisp_Object Qicon_name;
207Lisp_Object Qinternal_border_width;
208Lisp_Object Qleft;
1026b400 209Lisp_Object Qright;
ee78dc32
GV
210Lisp_Object Qmouse_color;
211Lisp_Object Qnone;
212Lisp_Object Qparent_id;
213Lisp_Object Qscroll_bar_width;
214Lisp_Object Qsuppress_icon;
ee78dc32
GV
215Lisp_Object Qundefined_color;
216Lisp_Object Qvertical_scroll_bars;
217Lisp_Object Qvisibility;
218Lisp_Object Qwindow_id;
219Lisp_Object Qx_frame_parameter;
220Lisp_Object Qx_resource_name;
221Lisp_Object Quser_position;
222Lisp_Object Quser_size;
6fc2811b 223Lisp_Object Qscreen_gamma;
dfff8a69
JR
224Lisp_Object Qline_spacing;
225Lisp_Object Qcenter;
dc220243 226Lisp_Object Qcancel_timer;
adcc3809
GV
227Lisp_Object Qhyper;
228Lisp_Object Qsuper;
229Lisp_Object Qmeta;
230Lisp_Object Qalt;
231Lisp_Object Qctrl;
232Lisp_Object Qcontrol;
233Lisp_Object Qshift;
234
dfff8a69
JR
235Lisp_Object Qw32_charset_ansi;
236Lisp_Object Qw32_charset_default;
237Lisp_Object Qw32_charset_symbol;
238Lisp_Object Qw32_charset_shiftjis;
767b1ff0 239Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
240Lisp_Object Qw32_charset_gb2312;
241Lisp_Object Qw32_charset_chinesebig5;
242Lisp_Object Qw32_charset_oem;
243
71eab8d1
AI
244#ifndef JOHAB_CHARSET
245#define JOHAB_CHARSET 130
246#endif
dfff8a69
JR
247#ifdef JOHAB_CHARSET
248Lisp_Object Qw32_charset_easteurope;
249Lisp_Object Qw32_charset_turkish;
250Lisp_Object Qw32_charset_baltic;
251Lisp_Object Qw32_charset_russian;
252Lisp_Object Qw32_charset_arabic;
253Lisp_Object Qw32_charset_greek;
254Lisp_Object Qw32_charset_hebrew;
767b1ff0 255Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
256Lisp_Object Qw32_charset_thai;
257Lisp_Object Qw32_charset_johab;
258Lisp_Object Qw32_charset_mac;
259#endif
260
261#ifdef UNICODE_CHARSET
262Lisp_Object Qw32_charset_unicode;
263#endif
264
f7b9d4d1
JR
265Lisp_Object Qfullscreen;
266Lisp_Object Qfullwidth;
267Lisp_Object Qfullheight;
268Lisp_Object Qfullboth;
269
6fc2811b
JR
270extern Lisp_Object Qtop;
271extern Lisp_Object Qdisplay;
6fc2811b 272
5ac45f98
GV
273/* State variables for emulating a three button mouse. */
274#define LMOUSE 1
275#define MMOUSE 2
276#define RMOUSE 4
277
278static int button_state = 0;
fbd6baed 279static W32Msg saved_mouse_button_msg;
48094ace 280static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
fbd6baed 281static W32Msg saved_mouse_move_msg;
48094ace 282static unsigned mouse_move_timer = 0;
84fb1139 283
9eb16b62
JR
284/* Window that is tracking the mouse. */
285static HWND track_mouse_window;
f60ae425
BK
286
287typedef BOOL (WINAPI * TrackMouseEvent_Proc) (
288 IN OUT LPTRACKMOUSEEVENT lpEventTrack
289 );
290
291TrackMouseEvent_Proc track_mouse_event_fn=NULL;
9eb16b62 292
93fbe8b7 293/* W95 mousewheel handler */
7d0393cf 294unsigned int msh_mousewheel = 0;
93fbe8b7 295
48094ace 296/* Timers */
84fb1139
KH
297#define MOUSE_BUTTON_ID 1
298#define MOUSE_MOVE_ID 2
48094ace
JR
299#define MENU_FREE_ID 3
300/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
301 is received. */
302#define MENU_FREE_DELAY 1000
303static unsigned menu_free_timer = 0;
5ac45f98 304
ee78dc32 305/* The below are defined in frame.c. */
dfff8a69 306
ee78dc32 307extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 308extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 309extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
310
311extern Lisp_Object Vwindow_system_version;
312
4b817373
RS
313Lisp_Object Qface_set_after_frame_default;
314
937e601e
AI
315#ifdef GLYPH_DEBUG
316int image_cache_refcount, dpyinfo_refcount;
317#endif
318
319
fbd6baed
GV
320/* From w32term.c. */
321extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 322extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 323
65906840 324extern HWND w32_system_caret_hwnd;
93f2ca61 325
65906840
JR
326extern int w32_system_caret_height;
327extern int w32_system_caret_x;
328extern int w32_system_caret_y;
93f2ca61
JR
329extern int w32_use_visible_system_caret;
330
d285988b 331static HWND w32_visible_system_caret_hwnd;
65906840 332
ee78dc32 333\f
1edf84e7
GV
334/* Error if we are not connected to MS-Windows. */
335void
336check_w32 ()
337{
338 if (! w32_in_use)
339 error ("MS-Windows not in use or not initialized");
340}
341
342/* Nonzero if we can use mouse menus.
343 You should not call this unless HAVE_MENUS is defined. */
7d0393cf 344
1edf84e7
GV
345int
346have_menus_p ()
347{
348 return w32_in_use;
349}
350
ee78dc32 351/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 352 and checking validity for W32. */
ee78dc32
GV
353
354FRAME_PTR
355check_x_frame (frame)
356 Lisp_Object frame;
357{
358 FRAME_PTR f;
359
360 if (NILP (frame))
6fc2811b 361 frame = selected_frame;
b7826503 362 CHECK_LIVE_FRAME (frame);
6fc2811b 363 f = XFRAME (frame);
fbd6baed
GV
364 if (! FRAME_W32_P (f))
365 error ("non-w32 frame used");
ee78dc32
GV
366 return f;
367}
368
7d0393cf 369/* Let the user specify a display with a frame.
fbd6baed 370 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
371 the first display on the list. */
372
fbd6baed 373static struct w32_display_info *
ee78dc32
GV
374check_x_display_info (frame)
375 Lisp_Object frame;
376{
377 if (NILP (frame))
378 {
6fc2811b 379 struct frame *sf = XFRAME (selected_frame);
7d0393cf 380
6fc2811b
JR
381 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
382 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 383 else
fbd6baed 384 return &one_w32_display_info;
ee78dc32
GV
385 }
386 else if (STRINGP (frame))
387 return x_display_info_for_name (frame);
388 else
389 {
390 FRAME_PTR f;
391
b7826503 392 CHECK_LIVE_FRAME (frame);
ee78dc32 393 f = XFRAME (frame);
fbd6baed
GV
394 if (! FRAME_W32_P (f))
395 error ("non-w32 frame used");
396 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
397 }
398}
399\f
fbd6baed 400/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
401 It could be the frame's main window or an icon window. */
402
403/* This function can be called during GC, so use GC_xxx type test macros. */
404
405struct frame *
406x_window_to_frame (dpyinfo, wdesc)
fbd6baed 407 struct w32_display_info *dpyinfo;
ee78dc32
GV
408 HWND wdesc;
409{
410 Lisp_Object tail, frame;
411 struct frame *f;
412
8e713be6 413 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 414 {
8e713be6 415 frame = XCAR (tail);
ee78dc32
GV
416 if (!GC_FRAMEP (frame))
417 continue;
418 f = XFRAME (frame);
2d764c78 419 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 420 continue;
0af913d7 421 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
422 return f;
423
fbd6baed 424 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
425 return f;
426 }
427 return 0;
428}
429
430\f
431
432/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
433 id, which is just an int that this section returns. Bitmaps are
434 reference counted so they can be shared among frames.
435
436 Bitmap indices are guaranteed to be > 0, so a negative number can
437 be used to indicate no bitmap.
438
439 If you use x_create_bitmap_from_data, then you must keep track of
440 the bitmaps yourself. That is, creating a bitmap from the same
441 data more than once will not be caught. */
442
443
444/* Functions to access the contents of a bitmap, given an id. */
445
446int
447x_bitmap_height (f, id)
448 FRAME_PTR f;
449 int id;
450{
fbd6baed 451 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
452}
453
454int
455x_bitmap_width (f, id)
456 FRAME_PTR f;
457 int id;
458{
fbd6baed 459 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
460}
461
462int
463x_bitmap_pixmap (f, id)
464 FRAME_PTR f;
465 int id;
466{
fbd6baed 467 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
468}
469
470
471/* Allocate a new bitmap record. Returns index of new record. */
472
473static int
474x_allocate_bitmap_record (f)
475 FRAME_PTR f;
476{
fbd6baed 477 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
478 int i;
479
480 if (dpyinfo->bitmaps == NULL)
481 {
482 dpyinfo->bitmaps_size = 10;
483 dpyinfo->bitmaps
fbd6baed 484 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
485 dpyinfo->bitmaps_last = 1;
486 return 1;
487 }
488
489 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
490 return ++dpyinfo->bitmaps_last;
491
492 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
493 if (dpyinfo->bitmaps[i].refcount == 0)
494 return i + 1;
495
496 dpyinfo->bitmaps_size *= 2;
497 dpyinfo->bitmaps
fbd6baed
GV
498 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
499 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
500 return ++dpyinfo->bitmaps_last;
501}
502
503/* Add one reference to the reference count of the bitmap with id ID. */
504
505void
506x_reference_bitmap (f, id)
507 FRAME_PTR f;
508 int id;
509{
fbd6baed 510 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
511}
512
513/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
514
515int
516x_create_bitmap_from_data (f, bits, width, height)
517 struct frame *f;
518 char *bits;
519 unsigned int width, height;
520{
fbd6baed 521 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
522 Pixmap bitmap;
523 int id;
524
525 bitmap = CreateBitmap (width, height,
fbd6baed
GV
526 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
527 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
528 bits);
529
530 if (! bitmap)
531 return -1;
532
533 id = x_allocate_bitmap_record (f);
534 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
535 dpyinfo->bitmaps[id - 1].file = NULL;
536 dpyinfo->bitmaps[id - 1].hinst = NULL;
537 dpyinfo->bitmaps[id - 1].refcount = 1;
538 dpyinfo->bitmaps[id - 1].depth = 1;
539 dpyinfo->bitmaps[id - 1].height = height;
540 dpyinfo->bitmaps[id - 1].width = width;
541
542 return id;
543}
544
545/* Create bitmap from file FILE for frame F. */
546
547int
548x_create_bitmap_from_file (f, file)
549 struct frame *f;
550 Lisp_Object file;
551{
552 return -1;
767b1ff0 553#if 0 /* TODO : bitmap support */
fbd6baed 554 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 555 unsigned int width, height;
6fc2811b 556 HBITMAP bitmap;
ee78dc32
GV
557 int xhot, yhot, result, id;
558 Lisp_Object found;
559 int fd;
560 char *filename;
561 HINSTANCE hinst;
562
563 /* Look for an existing bitmap with the same name. */
564 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
565 {
566 if (dpyinfo->bitmaps[id].refcount
567 && dpyinfo->bitmaps[id].file
d5db4077 568 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
ee78dc32
GV
569 {
570 ++dpyinfo->bitmaps[id].refcount;
571 return id + 1;
572 }
573 }
574
575 /* Search bitmap-file-path for the file, if appropriate. */
de2413e9 576 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
ee78dc32
GV
577 if (fd < 0)
578 return -1;
6fc2811b 579 emacs_close (fd);
ee78dc32 580
d5db4077 581 filename = (char *) SDATA (found);
ee78dc32
GV
582
583 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
584
585 if (hinst == NULL)
586 return -1;
587
7d0393cf 588
fbd6baed 589 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
590 filename, &width, &height, &bitmap, &xhot, &yhot);
591 if (result != BitmapSuccess)
592 return -1;
593
594 id = x_allocate_bitmap_record (f);
595 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
596 dpyinfo->bitmaps[id - 1].refcount = 1;
d5db4077 597 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1);
ee78dc32
GV
598 dpyinfo->bitmaps[id - 1].depth = 1;
599 dpyinfo->bitmaps[id - 1].height = height;
600 dpyinfo->bitmaps[id - 1].width = width;
d5db4077 601 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
ee78dc32
GV
602
603 return id;
767b1ff0 604#endif /* TODO */
ee78dc32
GV
605}
606
607/* Remove reference to bitmap with id number ID. */
608
33d52f9c 609void
ee78dc32
GV
610x_destroy_bitmap (f, id)
611 FRAME_PTR f;
612 int id;
613{
fbd6baed 614 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
615
616 if (id > 0)
617 {
618 --dpyinfo->bitmaps[id - 1].refcount;
619 if (dpyinfo->bitmaps[id - 1].refcount == 0)
620 {
621 BLOCK_INPUT;
622 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
623 if (dpyinfo->bitmaps[id - 1].file)
624 {
6fc2811b 625 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
626 dpyinfo->bitmaps[id - 1].file = NULL;
627 }
628 UNBLOCK_INPUT;
629 }
630 }
631}
632
633/* Free all the bitmaps for the display specified by DPYINFO. */
634
635static void
636x_destroy_all_bitmaps (dpyinfo)
fbd6baed 637 struct w32_display_info *dpyinfo;
ee78dc32
GV
638{
639 int i;
640 for (i = 0; i < dpyinfo->bitmaps_last; i++)
641 if (dpyinfo->bitmaps[i].refcount > 0)
642 {
643 DeleteObject (dpyinfo->bitmaps[i].pixmap);
644 if (dpyinfo->bitmaps[i].file)
6fc2811b 645 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
646 }
647 dpyinfo->bitmaps_last = 0;
648}
649\f
fbd6baed 650/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
651 to the ways of passing the parameter values to the window system.
652
653 The name of a parameter, as a Lisp symbol,
654 has an `x-frame-parameter' property which is an integer in Lisp
655 but can be interpreted as an `enum x_frame_parm' in C. */
656
657enum x_frame_parm
658{
659 X_PARM_FOREGROUND_COLOR,
660 X_PARM_BACKGROUND_COLOR,
661 X_PARM_MOUSE_COLOR,
662 X_PARM_CURSOR_COLOR,
663 X_PARM_BORDER_COLOR,
664 X_PARM_ICON_TYPE,
665 X_PARM_FONT,
666 X_PARM_BORDER_WIDTH,
667 X_PARM_INTERNAL_BORDER_WIDTH,
668 X_PARM_NAME,
669 X_PARM_AUTORAISE,
670 X_PARM_AUTOLOWER,
671 X_PARM_VERT_SCROLL_BAR,
672 X_PARM_VISIBILITY,
673 X_PARM_MENU_BAR_LINES
674};
675
676
677struct x_frame_parm_table
678{
679 char *name;
6fc2811b 680 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
681};
682
ca56d953
JR
683BOOL my_show_window P_ ((struct frame *, HWND, int));
684void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
685static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
686static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
687static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 688/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 689void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 690static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
f7b9d4d1 691static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
692void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
693void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
694void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
695void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
698void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 700static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
701void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
702void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
703 Lisp_Object));
704void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
706void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
707void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
708 Lisp_Object));
709void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
710void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
711void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
712void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
713void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
714void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
715static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
716static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
717 Lisp_Object));
ee78dc32
GV
718
719static struct x_frame_parm_table x_frame_parms[] =
720{
72e4adef
JR
721 {"auto-raise", x_set_autoraise},
722 {"auto-lower", x_set_autolower},
723 {"background-color", x_set_background_color},
724 {"border-color", x_set_border_color},
725 {"border-width", x_set_border_width},
726 {"cursor-color", x_set_cursor_color},
727 {"cursor-type", x_set_cursor_type},
728 {"font", x_set_font},
729 {"foreground-color", x_set_foreground_color},
730 {"icon-name", x_set_icon_name},
731 {"icon-type", x_set_icon_type},
732 {"internal-border-width", x_set_internal_border_width},
733 {"menu-bar-lines", x_set_menu_bar_lines},
734 {"mouse-color", x_set_mouse_color},
735 {"name", x_explicitly_set_name},
736 {"scroll-bar-width", x_set_scroll_bar_width},
737 {"title", x_set_title},
738 {"unsplittable", x_set_unsplittable},
739 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
740 {"visibility", x_set_visibility},
741 {"tool-bar-lines", x_set_tool_bar_lines},
742 {"screen-gamma", x_set_screen_gamma},
743 {"line-spacing", x_set_line_spacing},
744 {"left-fringe", x_set_fringe_width},
f7b9d4d1
JR
745 {"right-fringe", x_set_fringe_width},
746 {"fullscreen", x_set_fullscreen},
ee78dc32
GV
747};
748
749/* Attach the `x-frame-parameter' properties to
fbd6baed 750 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 751
dfff8a69 752void
ee78dc32
GV
753init_x_parm_symbols ()
754{
755 int i;
756
757 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
758 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
759 make_number (i));
760}
761\f
f7b9d4d1
JR
762/* Really try to move where we want to be in case of fullscreen. Some WMs
763 moves the window where we tell them. Some (mwm, twm) moves the outer
764 window manager window there instead.
765 Try to compensate for those WM here. */
766static void
767x_fullscreen_move (f, new_top, new_left)
768 struct frame *f;
769 int new_top;
770 int new_left;
771{
772 if (new_top != f->output_data.w32->top_pos
773 || new_left != f->output_data.w32->left_pos)
774 {
775 int move_x = new_left;
776 int move_y = new_top;
777
778 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
779 x_set_offset (f, move_x, move_y, 1);
780 }
781}
782
dfff8a69 783/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
784 If a parameter is not specially recognized, do nothing;
785 otherwise call the `x_set_...' function for that parameter. */
786
787void
788x_set_frame_parameters (f, alist)
789 FRAME_PTR f;
790 Lisp_Object alist;
791{
792 Lisp_Object tail;
793
794 /* If both of these parameters are present, it's more efficient to
795 set them both at once. So we wait until we've looked at the
796 entire list before we set them. */
b839712d 797 int width, height;
ee78dc32
GV
798
799 /* Same here. */
800 Lisp_Object left, top;
801
802 /* Same with these. */
803 Lisp_Object icon_left, icon_top;
804
805 /* Record in these vectors all the parms specified. */
806 Lisp_Object *parms;
807 Lisp_Object *values;
a797a73d 808 int i, p;
ee78dc32
GV
809 int left_no_change = 0, top_no_change = 0;
810 int icon_left_no_change = 0, icon_top_no_change = 0;
f7b9d4d1 811 int fullscreen_is_being_set = 0;
ee78dc32 812
5878523b
RS
813 struct gcpro gcpro1, gcpro2;
814
ee78dc32
GV
815 i = 0;
816 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
817 i++;
818
819 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
820 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
821
822 /* Extract parm names and values into those vectors. */
823
824 i = 0;
825 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
826 {
6fc2811b 827 Lisp_Object elt;
ee78dc32
GV
828
829 elt = Fcar (tail);
830 parms[i] = Fcar (elt);
831 values[i] = Fcdr (elt);
832 i++;
833 }
5878523b
RS
834 /* TAIL and ALIST are not used again below here. */
835 alist = tail = Qnil;
836
837 GCPRO2 (*parms, *values);
838 gcpro1.nvars = i;
839 gcpro2.nvars = i;
840
841 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
842 because their values appear in VALUES and strings are not valid. */
b839712d 843 top = left = Qunbound;
ee78dc32
GV
844 icon_left = icon_top = Qunbound;
845
b839712d 846 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
847 if (FRAME_NEW_WIDTH (f))
848 width = FRAME_NEW_WIDTH (f);
849 else
850 width = FRAME_WIDTH (f);
851
852 if (FRAME_NEW_HEIGHT (f))
853 height = FRAME_NEW_HEIGHT (f);
854 else
855 height = FRAME_HEIGHT (f);
b839712d 856
a797a73d
GV
857 /* Process foreground_color and background_color before anything else.
858 They are independent of other properties, but other properties (e.g.,
859 cursor_color) are dependent upon them. */
41c1bdd9 860 /* Process default font as well, since fringe widths depends on it. */
7d0393cf 861 for (p = 0; p < i; p++)
a797a73d
GV
862 {
863 Lisp_Object prop, val;
864
865 prop = parms[p];
866 val = values[p];
41c1bdd9
KS
867 if (EQ (prop, Qforeground_color)
868 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
869 || EQ (prop, Qfont)
870 || EQ (prop, Qfullscreen))
a797a73d
GV
871 {
872 register Lisp_Object param_index, old_value;
873
a797a73d 874 old_value = get_frame_param (f, prop);
f7b9d4d1 875 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
a05e2bae
JR
876
877 if (NILP (Fequal (val, old_value)))
878 {
879 store_frame_param (f, prop, val);
7d0393cf 880
a05e2bae
JR
881 param_index = Fget (prop, Qx_frame_parameter);
882 if (NATNUMP (param_index)
883 && (XFASTINT (param_index)
884 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
885 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
886 }
a797a73d
GV
887 }
888 }
889
ee78dc32
GV
890 /* Now process them in reverse of specified order. */
891 for (i--; i >= 0; i--)
892 {
893 Lisp_Object prop, val;
894
895 prop = parms[i];
896 val = values[i];
897
b839712d
RS
898 if (EQ (prop, Qwidth) && NUMBERP (val))
899 width = XFASTINT (val);
900 else if (EQ (prop, Qheight) && NUMBERP (val))
901 height = XFASTINT (val);
ee78dc32
GV
902 else if (EQ (prop, Qtop))
903 top = val;
904 else if (EQ (prop, Qleft))
905 left = val;
906 else if (EQ (prop, Qicon_top))
907 icon_top = val;
908 else if (EQ (prop, Qicon_left))
909 icon_left = val;
41c1bdd9
KS
910 else if (EQ (prop, Qforeground_color)
911 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
912 || EQ (prop, Qfont)
913 || EQ (prop, Qfullscreen))
a797a73d
GV
914 /* Processed above. */
915 continue;
ee78dc32
GV
916 else
917 {
918 register Lisp_Object param_index, old_value;
919
ee78dc32 920 old_value = get_frame_param (f, prop);
a05e2bae 921
ee78dc32 922 store_frame_param (f, prop, val);
a05e2bae
JR
923
924 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
925 if (NATNUMP (param_index)
926 && (XFASTINT (param_index)
927 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 928 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
929 }
930 }
931
932 /* Don't die if just one of these was set. */
933 if (EQ (left, Qunbound))
934 {
935 left_no_change = 1;
fbd6baed
GV
936 if (f->output_data.w32->left_pos < 0)
937 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 938 else
fbd6baed 939 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
940 }
941 if (EQ (top, Qunbound))
942 {
943 top_no_change = 1;
fbd6baed
GV
944 if (f->output_data.w32->top_pos < 0)
945 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 946 else
fbd6baed 947 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
948 }
949
950 /* If one of the icon positions was not set, preserve or default it. */
951 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
952 {
953 icon_left_no_change = 1;
954 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
955 if (NILP (icon_left))
956 XSETINT (icon_left, 0);
957 }
958 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
959 {
960 icon_top_no_change = 1;
961 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
962 if (NILP (icon_top))
963 XSETINT (icon_top, 0);
964 }
965
f7b9d4d1
JR
966 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
967 {
968 /* If the frame is visible already and the fullscreen parameter is
969 being set, it is too late to set WM manager hints to specify
970 size and position.
971 Here we first get the width, height and position that applies to
972 fullscreen. We then move the frame to the appropriate
973 position. Resize of the frame is taken care of in the code after
974 this if-statement. */
975 int new_left, new_top;
7d0393cf 976
f7b9d4d1
JR
977 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
978 x_fullscreen_move (f, new_top, new_left);
979 }
980
ee78dc32
GV
981 /* Don't set these parameters unless they've been explicitly
982 specified. The window might be mapped or resized while we're in
983 this function, and we don't want to override that unless the lisp
984 code has asked for it.
985
986 Don't set these parameters unless they actually differ from the
987 window's current parameters; the window may not actually exist
988 yet. */
989 {
990 Lisp_Object frame;
991
992 check_frame_size (f, &height, &width);
993
994 XSETFRAME (frame, f);
995
dfff8a69
JR
996 if (width != FRAME_WIDTH (f)
997 || height != FRAME_HEIGHT (f)
998 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 999 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
1000
1001 if ((!NILP (left) || !NILP (top))
1002 && ! (left_no_change && top_no_change)
fbd6baed
GV
1003 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1004 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
1005 {
1006 int leftpos = 0;
1007 int toppos = 0;
1008
1009 /* Record the signs. */
fbd6baed 1010 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 1011 if (EQ (left, Qminus))
fbd6baed 1012 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
1013 else if (INTEGERP (left))
1014 {
1015 leftpos = XINT (left);
1016 if (leftpos < 0)
fbd6baed 1017 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1018 }
8e713be6
KR
1019 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1020 && CONSP (XCDR (left))
1021 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1022 {
8e713be6 1023 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 1024 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1025 }
8e713be6
KR
1026 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1027 && CONSP (XCDR (left))
1028 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1029 {
8e713be6 1030 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
1031 }
1032
1033 if (EQ (top, Qminus))
fbd6baed 1034 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
1035 else if (INTEGERP (top))
1036 {
1037 toppos = XINT (top);
1038 if (toppos < 0)
fbd6baed 1039 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1040 }
8e713be6
KR
1041 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1042 && CONSP (XCDR (top))
1043 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1044 {
8e713be6 1045 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 1046 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1047 }
8e713be6
KR
1048 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1049 && CONSP (XCDR (top))
1050 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1051 {
8e713be6 1052 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1053 }
1054
1055
1056 /* Store the numeric value of the position. */
fbd6baed
GV
1057 f->output_data.w32->top_pos = toppos;
1058 f->output_data.w32->left_pos = leftpos;
ee78dc32 1059
fbd6baed 1060 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1061
1062 /* Actually set that position, and convert to absolute. */
1063 x_set_offset (f, leftpos, toppos, -1);
1064 }
1065
1066 if ((!NILP (icon_left) || !NILP (icon_top))
1067 && ! (icon_left_no_change && icon_top_no_change))
1068 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1069 }
5878523b
RS
1070
1071 UNGCPRO;
ee78dc32
GV
1072}
1073
1074/* Store the screen positions of frame F into XPTR and YPTR.
1075 These are the positions of the containing window manager window,
1076 not Emacs's own window. */
1077
1078void
1079x_real_positions (f, xptr, yptr)
1080 FRAME_PTR f;
1081 int *xptr, *yptr;
1082{
1083 POINT pt;
f7b9d4d1 1084 RECT rect;
3c190163 1085
f7b9d4d1
JR
1086 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1087 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1088
1089 pt.x = rect.left;
1090 pt.y = rect.top;
ee78dc32 1091
fbd6baed 1092 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32 1093
f7b9d4d1
JR
1094 /* Remember x_pixels_diff and y_pixels_diff. */
1095 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1096 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1097
ee78dc32
GV
1098 *xptr = pt.x;
1099 *yptr = pt.y;
1100}
1101
1102/* Insert a description of internally-recorded parameters of frame X
1103 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1104 Only parameters that are specific to W32
ee78dc32
GV
1105 and whose values are not correctly recorded in the frame's
1106 param_alist need to be considered here. */
1107
dfff8a69 1108void
ee78dc32
GV
1109x_report_frame_params (f, alistptr)
1110 struct frame *f;
1111 Lisp_Object *alistptr;
1112{
1113 char buf[16];
1114 Lisp_Object tem;
1115
1116 /* Represent negative positions (off the top or left screen edge)
1117 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1118 XSETINT (tem, f->output_data.w32->left_pos);
1119 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1120 store_in_alist (alistptr, Qleft, tem);
1121 else
1122 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1123
fbd6baed
GV
1124 XSETINT (tem, f->output_data.w32->top_pos);
1125 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1126 store_in_alist (alistptr, Qtop, tem);
1127 else
1128 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1129
1130 store_in_alist (alistptr, Qborder_width,
fbd6baed 1131 make_number (f->output_data.w32->border_width));
ee78dc32 1132 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1133 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1134 store_in_alist (alistptr, Qleft_fringe,
1135 make_number (f->output_data.w32->left_fringe_width));
1136 store_in_alist (alistptr, Qright_fringe,
1137 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1138 store_in_alist (alistptr, Qscroll_bar_width,
1139 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1140 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1141 : 0));
fbd6baed 1142 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1143 store_in_alist (alistptr, Qwindow_id,
1144 build_string (buf));
1145 store_in_alist (alistptr, Qicon_name, f->icon_name);
1146 FRAME_SAMPLE_VISIBILITY (f);
1147 store_in_alist (alistptr, Qvisibility,
1148 (FRAME_VISIBLE_P (f) ? Qt
1149 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1150 store_in_alist (alistptr, Qdisplay,
8e713be6 1151 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1152}
1153\f
1154
74e1aeec
JR
1155DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1156 Sw32_define_rgb_color, 4, 4, 0,
1157 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1158This adds or updates a named color to w32-color-map, making it
1159available for use. The original entry's RGB ref is returned, or nil
1160if the entry is new. */)
5ac45f98
GV
1161 (red, green, blue, name)
1162 Lisp_Object red, green, blue, name;
ee78dc32 1163{
5ac45f98
GV
1164 Lisp_Object rgb;
1165 Lisp_Object oldrgb = Qnil;
1166 Lisp_Object entry;
1167
b7826503
PJ
1168 CHECK_NUMBER (red);
1169 CHECK_NUMBER (green);
1170 CHECK_NUMBER (blue);
1171 CHECK_STRING (name);
ee78dc32 1172
5ac45f98 1173 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1174
5ac45f98 1175 BLOCK_INPUT;
ee78dc32 1176
fbd6baed
GV
1177 /* replace existing entry in w32-color-map or add new entry. */
1178 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1179 if (NILP (entry))
1180 {
1181 entry = Fcons (name, rgb);
fbd6baed 1182 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1183 }
1184 else
1185 {
1186 oldrgb = Fcdr (entry);
1187 Fsetcdr (entry, rgb);
1188 }
1189
1190 UNBLOCK_INPUT;
1191
1192 return (oldrgb);
ee78dc32
GV
1193}
1194
74e1aeec
JR
1195DEFUN ("w32-load-color-file", Fw32_load_color_file,
1196 Sw32_load_color_file, 1, 1, 0,
1197 doc: /* Create an alist of color entries from an external file.
1198Assign this value to w32-color-map to replace the existing color map.
1199
1200The file should define one named RGB color per line like so:
1201 R G B name
1202where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1203 (filename)
1204 Lisp_Object filename;
1205{
1206 FILE *fp;
1207 Lisp_Object cmap = Qnil;
1208 Lisp_Object abspath;
1209
b7826503 1210 CHECK_STRING (filename);
5ac45f98
GV
1211 abspath = Fexpand_file_name (filename, Qnil);
1212
d5db4077 1213 fp = fopen (SDATA (filename), "rt");
5ac45f98
GV
1214 if (fp)
1215 {
1216 char buf[512];
1217 int red, green, blue;
1218 int num;
1219
1220 BLOCK_INPUT;
1221
1222 while (fgets (buf, sizeof (buf), fp) != NULL) {
1223 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1224 {
1225 char *name = buf + num;
1226 num = strlen (name) - 1;
1227 if (name[num] == '\n')
1228 name[num] = 0;
1229 cmap = Fcons (Fcons (build_string (name),
1230 make_number (RGB (red, green, blue))),
1231 cmap);
1232 }
1233 }
1234 fclose (fp);
1235
1236 UNBLOCK_INPUT;
1237 }
1238
1239 return cmap;
1240}
ee78dc32 1241
fbd6baed 1242/* The default colors for the w32 color map */
7d0393cf 1243typedef struct colormap_t
ee78dc32
GV
1244{
1245 char *name;
1246 COLORREF colorref;
1247} colormap_t;
1248
7d0393cf 1249colormap_t w32_color_map[] =
ee78dc32 1250{
1da8a614
GV
1251 {"snow" , PALETTERGB (255,250,250)},
1252 {"ghost white" , PALETTERGB (248,248,255)},
1253 {"GhostWhite" , PALETTERGB (248,248,255)},
1254 {"white smoke" , PALETTERGB (245,245,245)},
1255 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1256 {"gainsboro" , PALETTERGB (220,220,220)},
1257 {"floral white" , PALETTERGB (255,250,240)},
1258 {"FloralWhite" , PALETTERGB (255,250,240)},
1259 {"old lace" , PALETTERGB (253,245,230)},
1260 {"OldLace" , PALETTERGB (253,245,230)},
1261 {"linen" , PALETTERGB (250,240,230)},
1262 {"antique white" , PALETTERGB (250,235,215)},
1263 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1264 {"papaya whip" , PALETTERGB (255,239,213)},
1265 {"PapayaWhip" , PALETTERGB (255,239,213)},
1266 {"blanched almond" , PALETTERGB (255,235,205)},
1267 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1268 {"bisque" , PALETTERGB (255,228,196)},
1269 {"peach puff" , PALETTERGB (255,218,185)},
1270 {"PeachPuff" , PALETTERGB (255,218,185)},
1271 {"navajo white" , PALETTERGB (255,222,173)},
1272 {"NavajoWhite" , PALETTERGB (255,222,173)},
1273 {"moccasin" , PALETTERGB (255,228,181)},
1274 {"cornsilk" , PALETTERGB (255,248,220)},
1275 {"ivory" , PALETTERGB (255,255,240)},
1276 {"lemon chiffon" , PALETTERGB (255,250,205)},
1277 {"LemonChiffon" , PALETTERGB (255,250,205)},
1278 {"seashell" , PALETTERGB (255,245,238)},
1279 {"honeydew" , PALETTERGB (240,255,240)},
1280 {"mint cream" , PALETTERGB (245,255,250)},
1281 {"MintCream" , PALETTERGB (245,255,250)},
1282 {"azure" , PALETTERGB (240,255,255)},
1283 {"alice blue" , PALETTERGB (240,248,255)},
1284 {"AliceBlue" , PALETTERGB (240,248,255)},
1285 {"lavender" , PALETTERGB (230,230,250)},
1286 {"lavender blush" , PALETTERGB (255,240,245)},
1287 {"LavenderBlush" , PALETTERGB (255,240,245)},
1288 {"misty rose" , PALETTERGB (255,228,225)},
1289 {"MistyRose" , PALETTERGB (255,228,225)},
1290 {"white" , PALETTERGB (255,255,255)},
1291 {"black" , PALETTERGB ( 0, 0, 0)},
1292 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1293 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1294 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1295 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1296 {"dim gray" , PALETTERGB (105,105,105)},
1297 {"DimGray" , PALETTERGB (105,105,105)},
1298 {"dim grey" , PALETTERGB (105,105,105)},
1299 {"DimGrey" , PALETTERGB (105,105,105)},
1300 {"slate gray" , PALETTERGB (112,128,144)},
1301 {"SlateGray" , PALETTERGB (112,128,144)},
1302 {"slate grey" , PALETTERGB (112,128,144)},
1303 {"SlateGrey" , PALETTERGB (112,128,144)},
1304 {"light slate gray" , PALETTERGB (119,136,153)},
1305 {"LightSlateGray" , PALETTERGB (119,136,153)},
1306 {"light slate grey" , PALETTERGB (119,136,153)},
1307 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1308 {"gray" , PALETTERGB (190,190,190)},
1309 {"grey" , PALETTERGB (190,190,190)},
1310 {"light grey" , PALETTERGB (211,211,211)},
1311 {"LightGrey" , PALETTERGB (211,211,211)},
1312 {"light gray" , PALETTERGB (211,211,211)},
1313 {"LightGray" , PALETTERGB (211,211,211)},
1314 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1315 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1316 {"navy" , PALETTERGB ( 0, 0,128)},
1317 {"navy blue" , PALETTERGB ( 0, 0,128)},
1318 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1319 {"cornflower blue" , PALETTERGB (100,149,237)},
1320 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1321 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1322 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1323 {"slate blue" , PALETTERGB (106, 90,205)},
1324 {"SlateBlue" , PALETTERGB (106, 90,205)},
1325 {"medium slate blue" , PALETTERGB (123,104,238)},
1326 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1327 {"light slate blue" , PALETTERGB (132,112,255)},
1328 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1329 {"medium blue" , PALETTERGB ( 0, 0,205)},
1330 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1331 {"royal blue" , PALETTERGB ( 65,105,225)},
1332 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1333 {"blue" , PALETTERGB ( 0, 0,255)},
1334 {"dodger blue" , PALETTERGB ( 30,144,255)},
1335 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1336 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1337 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1338 {"sky blue" , PALETTERGB (135,206,235)},
1339 {"SkyBlue" , PALETTERGB (135,206,235)},
1340 {"light sky blue" , PALETTERGB (135,206,250)},
1341 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1342 {"steel blue" , PALETTERGB ( 70,130,180)},
1343 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1344 {"light steel blue" , PALETTERGB (176,196,222)},
1345 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1346 {"light blue" , PALETTERGB (173,216,230)},
1347 {"LightBlue" , PALETTERGB (173,216,230)},
1348 {"powder blue" , PALETTERGB (176,224,230)},
1349 {"PowderBlue" , PALETTERGB (176,224,230)},
1350 {"pale turquoise" , PALETTERGB (175,238,238)},
1351 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1352 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1353 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1354 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1355 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1356 {"turquoise" , PALETTERGB ( 64,224,208)},
1357 {"cyan" , PALETTERGB ( 0,255,255)},
1358 {"light cyan" , PALETTERGB (224,255,255)},
1359 {"LightCyan" , PALETTERGB (224,255,255)},
1360 {"cadet blue" , PALETTERGB ( 95,158,160)},
1361 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1362 {"medium aquamarine" , PALETTERGB (102,205,170)},
1363 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1364 {"aquamarine" , PALETTERGB (127,255,212)},
1365 {"dark green" , PALETTERGB ( 0,100, 0)},
1366 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1367 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1368 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1369 {"dark sea green" , PALETTERGB (143,188,143)},
1370 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1371 {"sea green" , PALETTERGB ( 46,139, 87)},
1372 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1373 {"medium sea green" , PALETTERGB ( 60,179,113)},
1374 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1375 {"light sea green" , PALETTERGB ( 32,178,170)},
1376 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1377 {"pale green" , PALETTERGB (152,251,152)},
1378 {"PaleGreen" , PALETTERGB (152,251,152)},
1379 {"spring green" , PALETTERGB ( 0,255,127)},
1380 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1381 {"lawn green" , PALETTERGB (124,252, 0)},
1382 {"LawnGreen" , PALETTERGB (124,252, 0)},
1383 {"green" , PALETTERGB ( 0,255, 0)},
1384 {"chartreuse" , PALETTERGB (127,255, 0)},
1385 {"medium spring green" , PALETTERGB ( 0,250,154)},
1386 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1387 {"green yellow" , PALETTERGB (173,255, 47)},
1388 {"GreenYellow" , PALETTERGB (173,255, 47)},
1389 {"lime green" , PALETTERGB ( 50,205, 50)},
1390 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1391 {"yellow green" , PALETTERGB (154,205, 50)},
1392 {"YellowGreen" , PALETTERGB (154,205, 50)},
1393 {"forest green" , PALETTERGB ( 34,139, 34)},
1394 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1395 {"olive drab" , PALETTERGB (107,142, 35)},
1396 {"OliveDrab" , PALETTERGB (107,142, 35)},
1397 {"dark khaki" , PALETTERGB (189,183,107)},
1398 {"DarkKhaki" , PALETTERGB (189,183,107)},
1399 {"khaki" , PALETTERGB (240,230,140)},
1400 {"pale goldenrod" , PALETTERGB (238,232,170)},
1401 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1402 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1403 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1404 {"light yellow" , PALETTERGB (255,255,224)},
1405 {"LightYellow" , PALETTERGB (255,255,224)},
1406 {"yellow" , PALETTERGB (255,255, 0)},
1407 {"gold" , PALETTERGB (255,215, 0)},
1408 {"light goldenrod" , PALETTERGB (238,221,130)},
1409 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1410 {"goldenrod" , PALETTERGB (218,165, 32)},
1411 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1412 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1413 {"rosy brown" , PALETTERGB (188,143,143)},
1414 {"RosyBrown" , PALETTERGB (188,143,143)},
1415 {"indian red" , PALETTERGB (205, 92, 92)},
1416 {"IndianRed" , PALETTERGB (205, 92, 92)},
1417 {"saddle brown" , PALETTERGB (139, 69, 19)},
1418 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1419 {"sienna" , PALETTERGB (160, 82, 45)},
1420 {"peru" , PALETTERGB (205,133, 63)},
1421 {"burlywood" , PALETTERGB (222,184,135)},
1422 {"beige" , PALETTERGB (245,245,220)},
1423 {"wheat" , PALETTERGB (245,222,179)},
1424 {"sandy brown" , PALETTERGB (244,164, 96)},
1425 {"SandyBrown" , PALETTERGB (244,164, 96)},
1426 {"tan" , PALETTERGB (210,180,140)},
1427 {"chocolate" , PALETTERGB (210,105, 30)},
1428 {"firebrick" , PALETTERGB (178,34, 34)},
1429 {"brown" , PALETTERGB (165,42, 42)},
1430 {"dark salmon" , PALETTERGB (233,150,122)},
1431 {"DarkSalmon" , PALETTERGB (233,150,122)},
1432 {"salmon" , PALETTERGB (250,128,114)},
1433 {"light salmon" , PALETTERGB (255,160,122)},
1434 {"LightSalmon" , PALETTERGB (255,160,122)},
1435 {"orange" , PALETTERGB (255,165, 0)},
1436 {"dark orange" , PALETTERGB (255,140, 0)},
1437 {"DarkOrange" , PALETTERGB (255,140, 0)},
1438 {"coral" , PALETTERGB (255,127, 80)},
1439 {"light coral" , PALETTERGB (240,128,128)},
1440 {"LightCoral" , PALETTERGB (240,128,128)},
1441 {"tomato" , PALETTERGB (255, 99, 71)},
1442 {"orange red" , PALETTERGB (255, 69, 0)},
1443 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1444 {"red" , PALETTERGB (255, 0, 0)},
1445 {"hot pink" , PALETTERGB (255,105,180)},
1446 {"HotPink" , PALETTERGB (255,105,180)},
1447 {"deep pink" , PALETTERGB (255, 20,147)},
1448 {"DeepPink" , PALETTERGB (255, 20,147)},
1449 {"pink" , PALETTERGB (255,192,203)},
1450 {"light pink" , PALETTERGB (255,182,193)},
1451 {"LightPink" , PALETTERGB (255,182,193)},
1452 {"pale violet red" , PALETTERGB (219,112,147)},
1453 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1454 {"maroon" , PALETTERGB (176, 48, 96)},
1455 {"medium violet red" , PALETTERGB (199, 21,133)},
1456 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1457 {"violet red" , PALETTERGB (208, 32,144)},
1458 {"VioletRed" , PALETTERGB (208, 32,144)},
1459 {"magenta" , PALETTERGB (255, 0,255)},
1460 {"violet" , PALETTERGB (238,130,238)},
1461 {"plum" , PALETTERGB (221,160,221)},
1462 {"orchid" , PALETTERGB (218,112,214)},
1463 {"medium orchid" , PALETTERGB (186, 85,211)},
1464 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1465 {"dark orchid" , PALETTERGB (153, 50,204)},
1466 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1467 {"dark violet" , PALETTERGB (148, 0,211)},
1468 {"DarkViolet" , PALETTERGB (148, 0,211)},
1469 {"blue violet" , PALETTERGB (138, 43,226)},
1470 {"BlueViolet" , PALETTERGB (138, 43,226)},
1471 {"purple" , PALETTERGB (160, 32,240)},
1472 {"medium purple" , PALETTERGB (147,112,219)},
1473 {"MediumPurple" , PALETTERGB (147,112,219)},
1474 {"thistle" , PALETTERGB (216,191,216)},
1475 {"gray0" , PALETTERGB ( 0, 0, 0)},
1476 {"grey0" , PALETTERGB ( 0, 0, 0)},
1477 {"dark grey" , PALETTERGB (169,169,169)},
1478 {"DarkGrey" , PALETTERGB (169,169,169)},
1479 {"dark gray" , PALETTERGB (169,169,169)},
1480 {"DarkGray" , PALETTERGB (169,169,169)},
1481 {"dark blue" , PALETTERGB ( 0, 0,139)},
1482 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1483 {"dark cyan" , PALETTERGB ( 0,139,139)},
1484 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1485 {"dark magenta" , PALETTERGB (139, 0,139)},
1486 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1487 {"dark red" , PALETTERGB (139, 0, 0)},
1488 {"DarkRed" , PALETTERGB (139, 0, 0)},
1489 {"light green" , PALETTERGB (144,238,144)},
1490 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1491};
1492
fbd6baed 1493DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1494 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1495 ()
1496{
1497 int i;
fbd6baed 1498 colormap_t *pc = w32_color_map;
ee78dc32 1499 Lisp_Object cmap;
7d0393cf 1500
ee78dc32 1501 BLOCK_INPUT;
7d0393cf 1502
ee78dc32 1503 cmap = Qnil;
7d0393cf
JB
1504
1505 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1506 pc++, i++)
1507 cmap = Fcons (Fcons (build_string (pc->name),
1508 make_number (pc->colorref)),
1509 cmap);
7d0393cf 1510
ee78dc32 1511 UNBLOCK_INPUT;
7d0393cf 1512
ee78dc32
GV
1513 return (cmap);
1514}
ee78dc32 1515
7d0393cf 1516Lisp_Object
fbd6baed 1517w32_to_x_color (rgb)
ee78dc32
GV
1518 Lisp_Object rgb;
1519{
1520 Lisp_Object color;
7d0393cf 1521
b7826503 1522 CHECK_NUMBER (rgb);
7d0393cf 1523
ee78dc32 1524 BLOCK_INPUT;
7d0393cf 1525
fbd6baed 1526 color = Frassq (rgb, Vw32_color_map);
7d0393cf 1527
ee78dc32 1528 UNBLOCK_INPUT;
7d0393cf 1529
ee78dc32
GV
1530 if (!NILP (color))
1531 return (Fcar (color));
1532 else
1533 return Qnil;
1534}
1535
5d7fed93
GV
1536COLORREF
1537w32_color_map_lookup (colorname)
1538 char *colorname;
1539{
1540 Lisp_Object tail, ret = Qnil;
1541
1542 BLOCK_INPUT;
1543
1544 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1545 {
1546 register Lisp_Object elt, tem;
1547
1548 elt = Fcar (tail);
1549 if (!CONSP (elt)) continue;
1550
1551 tem = Fcar (elt);
1552
d5db4077 1553 if (lstrcmpi (SDATA (tem), colorname) == 0)
5d7fed93
GV
1554 {
1555 ret = XUINT (Fcdr (elt));
1556 break;
1557 }
1558
1559 QUIT;
1560 }
1561
1562
1563 UNBLOCK_INPUT;
1564
1565 return ret;
1566}
1567
7d0393cf 1568COLORREF
fbd6baed 1569x_to_w32_color (colorname)
ee78dc32
GV
1570 char * colorname;
1571{
8edb0a6f
JR
1572 register Lisp_Object ret = Qnil;
1573
ee78dc32 1574 BLOCK_INPUT;
1edf84e7
GV
1575
1576 if (colorname[0] == '#')
1577 {
1578 /* Could be an old-style RGB Device specification. */
1579 char *color;
1580 int size;
1581 color = colorname + 1;
7d0393cf 1582
1edf84e7
GV
1583 size = strlen(color);
1584 if (size == 3 || size == 6 || size == 9 || size == 12)
1585 {
1586 UINT colorval;
1587 int i, pos;
1588 pos = 0;
1589 size /= 3;
1590 colorval = 0;
7d0393cf 1591
1edf84e7
GV
1592 for (i = 0; i < 3; i++)
1593 {
1594 char *end;
1595 char t;
1596 unsigned long value;
1597
1598 /* The check for 'x' in the following conditional takes into
1599 account the fact that strtol allows a "0x" in front of
1600 our numbers, and we don't. */
1601 if (!isxdigit(color[0]) || color[1] == 'x')
1602 break;
1603 t = color[size];
1604 color[size] = '\0';
1605 value = strtoul(color, &end, 16);
1606 color[size] = t;
1607 if (errno == ERANGE || end - color != size)
1608 break;
1609 switch (size)
1610 {
1611 case 1:
1612 value = value * 0x10;
1613 break;
1614 case 2:
1615 break;
1616 case 3:
1617 value /= 0x10;
1618 break;
1619 case 4:
1620 value /= 0x100;
1621 break;
1622 }
1623 colorval |= (value << pos);
1624 pos += 0x8;
1625 if (i == 2)
1626 {
1627 UNBLOCK_INPUT;
1628 return (colorval);
1629 }
1630 color = end;
1631 }
1632 }
1633 }
1634 else if (strnicmp(colorname, "rgb:", 4) == 0)
1635 {
1636 char *color;
1637 UINT colorval;
1638 int i, pos;
1639 pos = 0;
1640
1641 colorval = 0;
1642 color = colorname + 4;
1643 for (i = 0; i < 3; i++)
1644 {
1645 char *end;
1646 unsigned long value;
7d0393cf 1647
1edf84e7
GV
1648 /* The check for 'x' in the following conditional takes into
1649 account the fact that strtol allows a "0x" in front of
1650 our numbers, and we don't. */
1651 if (!isxdigit(color[0]) || color[1] == 'x')
1652 break;
1653 value = strtoul(color, &end, 16);
1654 if (errno == ERANGE)
1655 break;
1656 switch (end - color)
1657 {
1658 case 1:
1659 value = value * 0x10 + value;
1660 break;
1661 case 2:
1662 break;
1663 case 3:
1664 value /= 0x10;
1665 break;
1666 case 4:
1667 value /= 0x100;
1668 break;
1669 default:
1670 value = ULONG_MAX;
1671 }
1672 if (value == ULONG_MAX)
1673 break;
1674 colorval |= (value << pos);
1675 pos += 0x8;
1676 if (i == 2)
1677 {
1678 if (*end != '\0')
1679 break;
1680 UNBLOCK_INPUT;
1681 return (colorval);
1682 }
1683 if (*end != '/')
1684 break;
1685 color = end + 1;
1686 }
1687 }
1688 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1689 {
1690 /* This is an RGB Intensity specification. */
1691 char *color;
1692 UINT colorval;
1693 int i, pos;
1694 pos = 0;
1695
1696 colorval = 0;
1697 color = colorname + 5;
1698 for (i = 0; i < 3; i++)
1699 {
1700 char *end;
1701 double value;
1702 UINT val;
1703
1704 value = strtod(color, &end);
1705 if (errno == ERANGE)
1706 break;
1707 if (value < 0.0 || value > 1.0)
1708 break;
1709 val = (UINT)(0x100 * value);
7d0393cf 1710 /* We used 0x100 instead of 0xFF to give a continuous
1edf84e7
GV
1711 range between 0.0 and 1.0 inclusive. The next statement
1712 fixes the 1.0 case. */
1713 if (val == 0x100)
1714 val = 0xFF;
1715 colorval |= (val << pos);
1716 pos += 0x8;
1717 if (i == 2)
1718 {
1719 if (*end != '\0')
1720 break;
1721 UNBLOCK_INPUT;
1722 return (colorval);
1723 }
1724 if (*end != '/')
1725 break;
1726 color = end + 1;
1727 }
1728 }
1729 /* I am not going to attempt to handle any of the CIE color schemes
1730 or TekHVC, since I don't know the algorithms for conversion to
1731 RGB. */
f695b4b1
GV
1732
1733 /* If we fail to lookup the color name in w32_color_map, then check the
7d0393cf 1734 colorname to see if it can be crudely approximated: If the X color
f695b4b1
GV
1735 ends in a number (e.g., "darkseagreen2"), strip the number and
1736 return the result of looking up the base color name. */
1737 ret = w32_color_map_lookup (colorname);
7d0393cf 1738 if (NILP (ret))
ee78dc32 1739 {
f695b4b1 1740 int len = strlen (colorname);
ee78dc32 1741
7d0393cf 1742 if (isdigit (colorname[len - 1]))
f695b4b1 1743 {
8b77111c 1744 char *ptr, *approx = alloca (len + 1);
ee78dc32 1745
f695b4b1
GV
1746 strcpy (approx, colorname);
1747 ptr = &approx[len - 1];
7d0393cf 1748 while (ptr > approx && isdigit (*ptr))
f695b4b1 1749 *ptr-- = '\0';
ee78dc32 1750
f695b4b1 1751 ret = w32_color_map_lookup (approx);
ee78dc32 1752 }
ee78dc32 1753 }
7d0393cf 1754
ee78dc32 1755 UNBLOCK_INPUT;
ee78dc32
GV
1756 return ret;
1757}
1758
5ac45f98
GV
1759
1760void
fbd6baed 1761w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1762{
fbd6baed 1763 struct w32_palette_entry * list;
5ac45f98
GV
1764 LOGPALETTE * log_palette;
1765 HPALETTE new_palette;
1766 int i;
1767
1768 /* don't bother trying to create palette if not supported */
fbd6baed 1769 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1770 return;
1771
1772 log_palette = (LOGPALETTE *)
1773 alloca (sizeof (LOGPALETTE) +
fbd6baed 1774 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1775 log_palette->palVersion = 0x300;
fbd6baed 1776 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1777
fbd6baed 1778 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1779 for (i = 0;
fbd6baed 1780 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1781 i++, list = list->next)
1782 log_palette->palPalEntry[i] = list->entry;
1783
1784 new_palette = CreatePalette (log_palette);
1785
1786 enter_crit ();
1787
fbd6baed
GV
1788 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1789 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1790 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1791
1792 /* Realize display palette and garbage all frames. */
1793 release_frame_dc (f, get_frame_dc (f));
1794
1795 leave_crit ();
1796}
1797
fbd6baed
GV
1798#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1799#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1800 do \
1801 { \
1802 pe.peRed = GetRValue (color); \
1803 pe.peGreen = GetGValue (color); \
1804 pe.peBlue = GetBValue (color); \
1805 pe.peFlags = 0; \
1806 } while (0)
1807
1808#if 0
1809/* Keep these around in case we ever want to track color usage. */
1810void
fbd6baed 1811w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1812{
fbd6baed 1813 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1814
fbd6baed 1815 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1816 return;
1817
1818 /* check if color is already mapped */
1819 while (list)
1820 {
fbd6baed 1821 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1822 {
1823 ++list->refcount;
1824 return;
1825 }
1826 list = list->next;
1827 }
1828
1829 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1830 list = (struct w32_palette_entry *)
1831 xmalloc (sizeof (struct w32_palette_entry));
1832 SET_W32_COLOR (list->entry, color);
5ac45f98 1833 list->refcount = 1;
fbd6baed
GV
1834 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1835 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1836 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1837
1838 /* set flag that palette must be regenerated */
fbd6baed 1839 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1840}
1841
1842void
fbd6baed 1843w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1844{
fbd6baed
GV
1845 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1846 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1847
fbd6baed 1848 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1849 return;
1850
1851 /* check if color is already mapped */
1852 while (list)
1853 {
fbd6baed 1854 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1855 {
1856 if (--list->refcount == 0)
1857 {
1858 *prev = list->next;
1859 xfree (list);
fbd6baed 1860 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1861 break;
1862 }
1863 else
1864 return;
1865 }
1866 prev = &list->next;
1867 list = list->next;
1868 }
1869
1870 /* set flag that palette must be regenerated */
fbd6baed 1871 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1872}
1873#endif
1874
6fc2811b
JR
1875
1876/* Gamma-correct COLOR on frame F. */
1877
1878void
1879gamma_correct (f, color)
1880 struct frame *f;
1881 COLORREF *color;
1882{
1883 if (f->gamma)
1884 {
1885 *color = PALETTERGB (
1886 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1887 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1888 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1889 }
1890}
1891
1892
ee78dc32
GV
1893/* Decide if color named COLOR is valid for the display associated with
1894 the selected frame; if so, return the rgb values in COLOR_DEF.
1895 If ALLOC is nonzero, allocate a new colormap cell. */
1896
1897int
6fc2811b 1898w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1899 FRAME_PTR f;
1900 char *color;
6fc2811b 1901 XColor *color_def;
ee78dc32
GV
1902 int alloc;
1903{
1904 register Lisp_Object tem;
6fc2811b 1905 COLORREF w32_color_ref;
3c190163 1906
fbd6baed 1907 tem = x_to_w32_color (color);
3c190163 1908
7d0393cf 1909 if (!NILP (tem))
ee78dc32 1910 {
d88c567c
JR
1911 if (f)
1912 {
1913 /* Apply gamma correction. */
1914 w32_color_ref = XUINT (tem);
1915 gamma_correct (f, &w32_color_ref);
1916 XSETINT (tem, w32_color_ref);
1917 }
9badad41
JR
1918
1919 /* Map this color to the palette if it is enabled. */
fbd6baed 1920 if (!NILP (Vw32_enable_palette))
5ac45f98 1921 {
fbd6baed 1922 struct w32_palette_entry * entry =
d88c567c 1923 one_w32_display_info.color_list;
fbd6baed 1924 struct w32_palette_entry ** prev =
d88c567c 1925 &one_w32_display_info.color_list;
7d0393cf 1926
5ac45f98
GV
1927 /* check if color is already mapped */
1928 while (entry)
1929 {
fbd6baed 1930 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1931 break;
1932 prev = &entry->next;
1933 entry = entry->next;
1934 }
1935
1936 if (entry == NULL && alloc)
1937 {
1938 /* not already mapped, so add to list */
fbd6baed
GV
1939 entry = (struct w32_palette_entry *)
1940 xmalloc (sizeof (struct w32_palette_entry));
1941 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1942 entry->next = NULL;
1943 *prev = entry;
d88c567c 1944 one_w32_display_info.num_colors++;
5ac45f98
GV
1945
1946 /* set flag that palette must be regenerated */
d88c567c 1947 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1948 }
1949 }
1950 /* Ensure COLORREF value is snapped to nearest color in (default)
1951 palette by simulating the PALETTERGB macro. This works whether
1952 or not the display device has a palette. */
6fc2811b
JR
1953 w32_color_ref = XUINT (tem) | 0x2000000;
1954
6fc2811b 1955 color_def->pixel = w32_color_ref;
197edd35
JR
1956 color_def->red = GetRValue (w32_color_ref) * 256;
1957 color_def->green = GetGValue (w32_color_ref) * 256;
1958 color_def->blue = GetBValue (w32_color_ref) * 256;
6fc2811b 1959
ee78dc32 1960 return 1;
5ac45f98 1961 }
7d0393cf 1962 else
3c190163
GV
1963 {
1964 return 0;
1965 }
ee78dc32
GV
1966}
1967
1968/* Given a string ARG naming a color, compute a pixel value from it
1969 suitable for screen F.
1970 If F is not a color screen, return DEF (default) regardless of what
1971 ARG says. */
1972
1973int
1974x_decode_color (f, arg, def)
1975 FRAME_PTR f;
1976 Lisp_Object arg;
1977 int def;
1978{
6fc2811b 1979 XColor cdef;
ee78dc32 1980
b7826503 1981 CHECK_STRING (arg);
ee78dc32 1982
d5db4077 1983 if (strcmp (SDATA (arg), "black") == 0)
ee78dc32 1984 return BLACK_PIX_DEFAULT (f);
d5db4077 1985 else if (strcmp (SDATA (arg), "white") == 0)
ee78dc32
GV
1986 return WHITE_PIX_DEFAULT (f);
1987
fbd6baed 1988 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1989 return def;
1990
6fc2811b 1991 /* w32_defined_color is responsible for coping with failures
ee78dc32 1992 by looking for a near-miss. */
d5db4077 1993 if (w32_defined_color (f, SDATA (arg), &cdef, 1))
6fc2811b 1994 return cdef.pixel;
ee78dc32
GV
1995
1996 /* defined_color failed; return an ultimate default. */
1997 return def;
1998}
1999\f
dfff8a69
JR
2000/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2001 the previous value of that parameter, NEW_VALUE is the new value. */
2002
2003static void
2004x_set_line_spacing (f, new_value, old_value)
2005 struct frame *f;
2006 Lisp_Object new_value, old_value;
2007{
2008 if (NILP (new_value))
2009 f->extra_line_spacing = 0;
2010 else if (NATNUMP (new_value))
2011 f->extra_line_spacing = XFASTINT (new_value);
2012 else
1a948b17 2013 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
2014 Fcons (new_value, Qnil)));
2015 if (FRAME_VISIBLE_P (f))
2016 redraw_frame (f);
2017}
2018
2019
f7b9d4d1
JR
2020/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2021 the previous value of that parameter, NEW_VALUE is the new value. */
2022
2023static void
2024x_set_fullscreen (f, new_value, old_value)
2025 struct frame *f;
2026 Lisp_Object new_value, old_value;
2027{
2028 if (NILP (new_value))
2029 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2030 else if (EQ (new_value, Qfullboth))
2031 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2032 else if (EQ (new_value, Qfullwidth))
2033 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2034 else if (EQ (new_value, Qfullheight))
2035 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2036}
2037
2038
6fc2811b
JR
2039/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2040 the previous value of that parameter, NEW_VALUE is the new value. */
2041
2042static void
2043x_set_screen_gamma (f, new_value, old_value)
2044 struct frame *f;
2045 Lisp_Object new_value, old_value;
2046{
2047 if (NILP (new_value))
2048 f->gamma = 0;
2049 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2050 /* The value 0.4545 is the normal viewing gamma. */
2051 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2052 else
1a948b17 2053 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
2054 Fcons (new_value, Qnil)));
2055
2056 clear_face_cache (0);
2057}
2058
2059
ee78dc32
GV
2060/* Functions called only from `x_set_frame_param'
2061 to set individual parameters.
2062
fbd6baed 2063 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
2064 the frame is being created and its window does not exist yet.
2065 In that case, just record the parameter's new value
2066 in the standard place; do not attempt to change the window. */
2067
2068void
2069x_set_foreground_color (f, arg, oldval)
2070 struct frame *f;
2071 Lisp_Object arg, oldval;
2072{
3cf3436e
JR
2073 struct w32_output *x = f->output_data.w32;
2074 PIX_TYPE fg, old_fg;
2075
2076 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2077 old_fg = FRAME_FOREGROUND_PIXEL (f);
2078 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2079
fbd6baed 2080 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2081 {
3cf3436e
JR
2082 if (x->cursor_pixel == old_fg)
2083 x->cursor_pixel = fg;
2084
6fc2811b 2085 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2086 if (FRAME_VISIBLE_P (f))
2087 redraw_frame (f);
2088 }
2089}
2090
2091void
2092x_set_background_color (f, arg, oldval)
2093 struct frame *f;
2094 Lisp_Object arg, oldval;
2095{
6fc2811b 2096 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2097 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2098
fbd6baed 2099 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2100 {
6fc2811b
JR
2101 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2102 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2103
6fc2811b 2104 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2105
2106 if (FRAME_VISIBLE_P (f))
2107 redraw_frame (f);
2108 }
2109}
2110
2111void
2112x_set_mouse_color (f, arg, oldval)
2113 struct frame *f;
2114 Lisp_Object arg, oldval;
2115{
ee78dc32 2116 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2117 int count;
ee78dc32
GV
2118 int mask_color;
2119
2120 if (!EQ (Qnil, arg))
fbd6baed 2121 f->output_data.w32->mouse_pixel
ee78dc32 2122 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2123 mask_color = FRAME_BACKGROUND_PIXEL (f);
2124
2125 /* Don't let pointers be invisible. */
fbd6baed 2126 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2127 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2128 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2129
767b1ff0 2130#if 0 /* TODO : cursor changes */
ee78dc32
GV
2131 BLOCK_INPUT;
2132
2133 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2134 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2135
2136 if (!EQ (Qnil, Vx_pointer_shape))
2137 {
b7826503 2138 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2139 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2140 }
2141 else
fbd6baed
GV
2142 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2143 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2144
2145 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2146 {
b7826503 2147 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2148 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2149 XINT (Vx_nontext_pointer_shape));
2150 }
2151 else
fbd6baed
GV
2152 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2153 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2154
0af913d7 2155 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2156 {
b7826503 2157 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2158 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2159 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2160 }
2161 else
0af913d7 2162 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b 2163 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
7d0393cf 2164
6fc2811b 2165 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2166 if (!EQ (Qnil, Vx_mode_pointer_shape))
2167 {
b7826503 2168 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2169 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2170 XINT (Vx_mode_pointer_shape));
2171 }
2172 else
fbd6baed
GV
2173 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2174 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2175
2176 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2177 {
b7826503 2178 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2179 cross_cursor
fbd6baed 2180 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2181 XINT (Vx_sensitive_text_pointer_shape));
2182 }
2183 else
fbd6baed 2184 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2185
4694d762
JR
2186 if (!NILP (Vx_window_horizontal_drag_shape))
2187 {
b7826503 2188 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2189 horizontal_drag_cursor
2190 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2191 XINT (Vx_window_horizontal_drag_shape));
2192 }
2193 else
2194 horizontal_drag_cursor
2195 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2196
ee78dc32 2197 /* Check and report errors with the above calls. */
fbd6baed 2198 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2199 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2200
2201 {
2202 XColor fore_color, back_color;
2203
fbd6baed 2204 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2205 back_color.pixel = mask_color;
fbd6baed
GV
2206 XQueryColor (FRAME_W32_DISPLAY (f),
2207 DefaultColormap (FRAME_W32_DISPLAY (f),
2208 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2209 &fore_color);
fbd6baed
GV
2210 XQueryColor (FRAME_W32_DISPLAY (f),
2211 DefaultColormap (FRAME_W32_DISPLAY (f),
2212 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2213 &back_color);
fbd6baed 2214 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2215 &fore_color, &back_color);
fbd6baed 2216 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2217 &fore_color, &back_color);
fbd6baed 2218 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2219 &fore_color, &back_color);
fbd6baed 2220 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2221 &fore_color, &back_color);
0af913d7 2222 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2223 &fore_color, &back_color);
ee78dc32
GV
2224 }
2225
fbd6baed 2226 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2227 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2228
fbd6baed
GV
2229 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2230 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2231 f->output_data.w32->text_cursor = cursor;
2232
2233 if (nontext_cursor != f->output_data.w32->nontext_cursor
2234 && f->output_data.w32->nontext_cursor != 0)
2235 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2236 f->output_data.w32->nontext_cursor = nontext_cursor;
2237
0af913d7
GM
2238 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2239 && f->output_data.w32->hourglass_cursor != 0)
2240 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2241 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2242
fbd6baed
GV
2243 if (mode_cursor != f->output_data.w32->modeline_cursor
2244 && f->output_data.w32->modeline_cursor != 0)
2245 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2246 f->output_data.w32->modeline_cursor = mode_cursor;
7d0393cf 2247
fbd6baed
GV
2248 if (cross_cursor != f->output_data.w32->cross_cursor
2249 && f->output_data.w32->cross_cursor != 0)
2250 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2251 f->output_data.w32->cross_cursor = cross_cursor;
2252
2253 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2254 UNBLOCK_INPUT;
6fc2811b
JR
2255
2256 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2257#endif /* TODO */
ee78dc32
GV
2258}
2259
70a0239a
JR
2260/* Defined in w32term.c. */
2261void x_update_cursor (struct frame *f, int on_p);
2262
ee78dc32
GV
2263void
2264x_set_cursor_color (f, arg, oldval)
2265 struct frame *f;
2266 Lisp_Object arg, oldval;
2267{
70a0239a 2268 unsigned long fore_pixel, pixel;
ee78dc32 2269
dfff8a69 2270 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2271 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2272 WHITE_PIX_DEFAULT (f));
ee78dc32 2273 else
6fc2811b 2274 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2275
6759f872 2276 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
7d0393cf 2277
ee78dc32 2278 /* Make sure that the cursor color differs from the background color. */
70a0239a 2279 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2280 {
70a0239a
JR
2281 pixel = f->output_data.w32->mouse_pixel;
2282 if (pixel == fore_pixel)
6fc2811b 2283 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2284 }
70a0239a 2285
ac849ba4 2286 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
70a0239a 2287 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2288
fbd6baed 2289 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2290 {
0327b4cc
JR
2291 BLOCK_INPUT;
2292 /* Update frame's cursor_gc. */
2293 f->output_data.w32->cursor_gc->foreground = fore_pixel;
2294 f->output_data.w32->cursor_gc->background = pixel;
2295
2296 UNBLOCK_INPUT;
2297
ee78dc32
GV
2298 if (FRAME_VISIBLE_P (f))
2299 {
70a0239a
JR
2300 x_update_cursor (f, 0);
2301 x_update_cursor (f, 1);
ee78dc32
GV
2302 }
2303 }
6fc2811b
JR
2304
2305 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2306}
2307
33d52f9c
GV
2308/* Set the border-color of frame F to pixel value PIX.
2309 Note that this does not fully take effect if done before
7d0393cf 2310 F has a window. */
33d52f9c
GV
2311void
2312x_set_border_pixel (f, pix)
2313 struct frame *f;
2314 int pix;
2315{
2316 f->output_data.w32->border_pixel = pix;
2317
2318 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2319 {
2320 if (FRAME_VISIBLE_P (f))
2321 redraw_frame (f);
2322 }
2323}
2324
ee78dc32
GV
2325/* Set the border-color of frame F to value described by ARG.
2326 ARG can be a string naming a color.
2327 The border-color is used for the border that is drawn by the server.
2328 Note that this does not fully take effect if done before
2329 F has a window; it must be redone when the window is created. */
2330
2331void
2332x_set_border_color (f, arg, oldval)
2333 struct frame *f;
2334 Lisp_Object arg, oldval;
2335{
ee78dc32
GV
2336 int pix;
2337
b7826503 2338 CHECK_STRING (arg);
ee78dc32 2339 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2340 x_set_border_pixel (f, pix);
6fc2811b 2341 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2342}
2343
dfff8a69
JR
2344
2345void
2346x_set_cursor_type (f, arg, oldval)
2347 FRAME_PTR f;
2348 Lisp_Object arg, oldval;
2349{
50e363e6 2350 set_frame_cursor_types (f, arg);
ee78dc32
GV
2351
2352 /* Make sure the cursor gets redrawn. This is overkill, but how
2353 often do people change cursor types? */
2354 update_mode_lines++;
2355}
dfff8a69 2356\f
ee78dc32
GV
2357void
2358x_set_icon_type (f, arg, oldval)
2359 struct frame *f;
2360 Lisp_Object arg, oldval;
2361{
ee78dc32
GV
2362 int result;
2363
eb7576ce
GV
2364 if (NILP (arg) && NILP (oldval))
2365 return;
2366
7d0393cf 2367 if (STRINGP (arg) && STRINGP (oldval)
eb7576ce
GV
2368 && EQ (Fstring_equal (oldval, arg), Qt))
2369 return;
2370
2371 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2372 return;
2373
2374 BLOCK_INPUT;
ee78dc32 2375
eb7576ce 2376 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2377 if (result)
2378 {
2379 UNBLOCK_INPUT;
2380 error ("No icon window available");
2381 }
2382
ee78dc32 2383 UNBLOCK_INPUT;
ee78dc32
GV
2384}
2385
2386/* Return non-nil if frame F wants a bitmap icon. */
2387
2388Lisp_Object
2389x_icon_type (f)
2390 FRAME_PTR f;
2391{
2392 Lisp_Object tem;
2393
2394 tem = assq_no_quit (Qicon_type, f->param_alist);
2395 if (CONSP (tem))
8e713be6 2396 return XCDR (tem);
ee78dc32
GV
2397 else
2398 return Qnil;
2399}
2400
2401void
2402x_set_icon_name (f, arg, oldval)
2403 struct frame *f;
2404 Lisp_Object arg, oldval;
2405{
ee78dc32
GV
2406 if (STRINGP (arg))
2407 {
2408 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2409 return;
2410 }
2411 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2412 return;
2413
2414 f->icon_name = arg;
2415
2416#if 0
fbd6baed 2417 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2418 return;
2419
2420 BLOCK_INPUT;
2421
2422 result = x_text_icon (f,
d5db4077
KR
2423 (char *) SDATA ((!NILP (f->icon_name)
2424 ? f->icon_name
2425 : !NILP (f->title)
2426 ? f->title
2427 : f->name)));
ee78dc32
GV
2428
2429 if (result)
2430 {
2431 UNBLOCK_INPUT;
2432 error ("No icon window available");
2433 }
2434
2435 /* If the window was unmapped (and its icon was mapped),
2436 the new icon is not mapped, so map the window in its stead. */
2437 if (FRAME_VISIBLE_P (f))
2438 {
2439#ifdef USE_X_TOOLKIT
fbd6baed 2440 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2441#endif
fbd6baed 2442 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2443 }
2444
fbd6baed 2445 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2446 UNBLOCK_INPUT;
2447#endif
2448}
2449
2450extern Lisp_Object x_new_font ();
4587b026 2451extern Lisp_Object x_new_fontset();
ee78dc32
GV
2452
2453void
2454x_set_font (f, arg, oldval)
2455 struct frame *f;
2456 Lisp_Object arg, oldval;
2457{
2458 Lisp_Object result;
4587b026 2459 Lisp_Object fontset_name;
4b817373 2460 Lisp_Object frame;
3cf3436e 2461 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2462
b7826503 2463 CHECK_STRING (arg);
ee78dc32 2464
4587b026
GV
2465 fontset_name = Fquery_fontset (arg, Qnil);
2466
ee78dc32 2467 BLOCK_INPUT;
4587b026 2468 result = (STRINGP (fontset_name)
d5db4077
KR
2469 ? x_new_fontset (f, SDATA (fontset_name))
2470 : x_new_font (f, SDATA (arg)));
ee78dc32 2471 UNBLOCK_INPUT;
7d0393cf 2472
ee78dc32 2473 if (EQ (result, Qnil))
d5db4077 2474 error ("Font `%s' is not defined", SDATA (arg));
ee78dc32 2475 else if (EQ (result, Qt))
dfff8a69 2476 error ("The characters of the given font have varying widths");
ee78dc32
GV
2477 else if (STRINGP (result))
2478 {
3cf3436e
JR
2479 if (STRINGP (fontset_name))
2480 {
2481 /* Fontset names are built from ASCII font names, so the
2482 names may be equal despite there was a change. */
2483 if (old_fontset == FRAME_FONTSET (f))
2484 return;
2485 }
2486 else if (!NILP (Fequal (result, oldval)))
dc220243 2487 return;
3cf3436e 2488
ee78dc32 2489 store_frame_param (f, Qfont, result);
6fc2811b 2490 recompute_basic_faces (f);
ee78dc32
GV
2491 }
2492 else
2493 abort ();
4b817373 2494
6fc2811b
JR
2495 do_pending_window_change (0);
2496
2497 /* Don't call `face-set-after-frame-default' when faces haven't been
2498 initialized yet. This is the case when called from
2499 Fx_create_frame. In that case, the X widget or window doesn't
2500 exist either, and we can end up in x_report_frame_params with a
2501 null widget which gives a segfault. */
2502 if (FRAME_FACE_CACHE (f))
2503 {
2504 XSETFRAME (frame, f);
2505 call1 (Qface_set_after_frame_default, frame);
2506 }
ee78dc32
GV
2507}
2508
41c1bdd9
KS
2509static void
2510x_set_fringe_width (f, new_value, old_value)
2511 struct frame *f;
2512 Lisp_Object new_value, old_value;
2513{
2514 x_compute_fringe_widths (f, 1);
2515}
2516
ee78dc32
GV
2517void
2518x_set_border_width (f, arg, oldval)
2519 struct frame *f;
2520 Lisp_Object arg, oldval;
2521{
b7826503 2522 CHECK_NUMBER (arg);
ee78dc32 2523
fbd6baed 2524 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2525 return;
2526
fbd6baed 2527 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2528 error ("Cannot change the border width of a window");
2529
fbd6baed 2530 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2531}
2532
2533void
2534x_set_internal_border_width (f, arg, oldval)
2535 struct frame *f;
2536 Lisp_Object arg, oldval;
2537{
fbd6baed 2538 int old = f->output_data.w32->internal_border_width;
ee78dc32 2539
b7826503 2540 CHECK_NUMBER (arg);
fbd6baed
GV
2541 f->output_data.w32->internal_border_width = XINT (arg);
2542 if (f->output_data.w32->internal_border_width < 0)
2543 f->output_data.w32->internal_border_width = 0;
ee78dc32 2544
fbd6baed 2545 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2546 return;
2547
fbd6baed 2548 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2549 {
ee78dc32 2550 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2551 SET_FRAME_GARBAGED (f);
6fc2811b 2552 do_pending_window_change (0);
ee78dc32 2553 }
a05e2bae
JR
2554 else
2555 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2556}
2557
2558void
2559x_set_visibility (f, value, oldval)
2560 struct frame *f;
2561 Lisp_Object value, oldval;
2562{
2563 Lisp_Object frame;
2564 XSETFRAME (frame, f);
2565
2566 if (NILP (value))
2567 Fmake_frame_invisible (frame, Qt);
2568 else if (EQ (value, Qicon))
2569 Ficonify_frame (frame);
2570 else
2571 Fmake_frame_visible (frame);
2572}
2573
a1258667
JR
2574\f
2575/* Change window heights in windows rooted in WINDOW by N lines. */
2576
2577static void
2578x_change_window_heights (window, n)
2579 Lisp_Object window;
2580 int n;
2581{
2582 struct window *w = XWINDOW (window);
2583
2584 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2585 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2586
2587 if (INTEGERP (w->orig_top))
2588 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2589 if (INTEGERP (w->orig_height))
2590 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2591
2592 /* Handle just the top child in a vertical split. */
2593 if (!NILP (w->vchild))
2594 x_change_window_heights (w->vchild, n);
2595
2596 /* Adjust all children in a horizontal split. */
2597 for (window = w->hchild; !NILP (window); window = w->next)
2598 {
2599 w = XWINDOW (window);
2600 x_change_window_heights (window, n);
2601 }
2602}
2603
ee78dc32
GV
2604void
2605x_set_menu_bar_lines (f, value, oldval)
2606 struct frame *f;
2607 Lisp_Object value, oldval;
2608{
2609 int nlines;
2610 int olines = FRAME_MENU_BAR_LINES (f);
2611
2612 /* Right now, menu bars don't work properly in minibuf-only frames;
2613 most of the commands try to apply themselves to the minibuffer
6fc2811b 2614 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2615 in or split the minibuffer window. */
2616 if (FRAME_MINIBUF_ONLY_P (f))
2617 return;
2618
2619 if (INTEGERP (value))
2620 nlines = XINT (value);
2621 else
2622 nlines = 0;
2623
2624 FRAME_MENU_BAR_LINES (f) = 0;
2625 if (nlines)
2626 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2627 else
2628 {
2629 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2630 free_frame_menubar (f);
2631 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2632
2633 /* Adjust the frame size so that the client (text) dimensions
2634 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2635 set correctly. */
2636 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2637 do_pending_window_change (0);
ee78dc32 2638 }
6fc2811b
JR
2639 adjust_glyphs (f);
2640}
2641
2642
2643/* Set the number of lines used for the tool bar of frame F to VALUE.
2644 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2645 is the old number of tool bar lines. This function changes the
2646 height of all windows on frame F to match the new tool bar height.
2647 The frame's height doesn't change. */
2648
2649void
2650x_set_tool_bar_lines (f, value, oldval)
2651 struct frame *f;
2652 Lisp_Object value, oldval;
2653{
36f8209a
JR
2654 int delta, nlines, root_height;
2655 Lisp_Object root_window;
6fc2811b 2656
dc220243
JR
2657 /* Treat tool bars like menu bars. */
2658 if (FRAME_MINIBUF_ONLY_P (f))
2659 return;
2660
6fc2811b
JR
2661 /* Use VALUE only if an integer >= 0. */
2662 if (INTEGERP (value) && XINT (value) >= 0)
2663 nlines = XFASTINT (value);
2664 else
2665 nlines = 0;
2666
2667 /* Make sure we redisplay all windows in this frame. */
2668 ++windows_or_buffers_changed;
2669
2670 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2671
2672 /* Don't resize the tool-bar to more than we have room for. */
2673 root_window = FRAME_ROOT_WINDOW (f);
2674 root_height = XINT (XWINDOW (root_window)->height);
2675 if (root_height - delta < 1)
2676 {
2677 delta = root_height - 1;
2678 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2679 }
2680
6fc2811b 2681 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2682 x_change_window_heights (root_window, delta);
6fc2811b 2683 adjust_glyphs (f);
36f8209a
JR
2684
2685 /* We also have to make sure that the internal border at the top of
2686 the frame, below the menu bar or tool bar, is redrawn when the
2687 tool bar disappears. This is so because the internal border is
2688 below the tool bar if one is displayed, but is below the menu bar
2689 if there isn't a tool bar. The tool bar draws into the area
2690 below the menu bar. */
2691 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2692 {
2693 updating_frame = f;
2694 clear_frame ();
2695 clear_current_matrices (f);
2696 updating_frame = NULL;
2697 }
2698
2699 /* If the tool bar gets smaller, the internal border below it
2700 has to be cleared. It was formerly part of the display
2701 of the larger tool bar, and updating windows won't clear it. */
2702 if (delta < 0)
2703 {
2704 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2705 int width = PIXEL_WIDTH (f);
2706 int y = nlines * CANON_Y_UNIT (f);
2707
2708 BLOCK_INPUT;
2709 {
2710 HDC hdc = get_frame_dc (f);
2711 w32_clear_area (f, hdc, 0, y, width, height);
2712 release_frame_dc (f, hdc);
2713 }
2714 UNBLOCK_INPUT;
3cf3436e
JR
2715
2716 if (WINDOWP (f->tool_bar_window))
2717 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2718 }
ee78dc32
GV
2719}
2720
6fc2811b 2721
ee78dc32 2722/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2723 w32_id_name.
ee78dc32
GV
2724
2725 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2726 name; if NAME is a string, set F's name to NAME and set
2727 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2728
2729 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2730 suggesting a new name, which lisp code should override; if
2731 F->explicit_name is set, ignore the new name; otherwise, set it. */
2732
2733void
2734x_set_name (f, name, explicit)
2735 struct frame *f;
2736 Lisp_Object name;
2737 int explicit;
2738{
7d0393cf 2739 /* Make sure that requests from lisp code override requests from
ee78dc32
GV
2740 Emacs redisplay code. */
2741 if (explicit)
2742 {
2743 /* If we're switching from explicit to implicit, we had better
2744 update the mode lines and thereby update the title. */
2745 if (f->explicit_name && NILP (name))
2746 update_mode_lines = 1;
2747
2748 f->explicit_name = ! NILP (name);
2749 }
2750 else if (f->explicit_name)
2751 return;
2752
fbd6baed 2753 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2754 if (NILP (name))
2755 {
2756 /* Check for no change needed in this very common case
2757 before we do any consing. */
fbd6baed 2758 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
d5db4077 2759 SDATA (f->name)))
ee78dc32 2760 return;
fbd6baed 2761 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2762 }
2763 else
b7826503 2764 CHECK_STRING (name);
ee78dc32
GV
2765
2766 /* Don't change the name if it's already NAME. */
2767 if (! NILP (Fstring_equal (name, f->name)))
2768 return;
2769
1edf84e7
GV
2770 f->name = name;
2771
2772 /* For setting the frame title, the title parameter should override
2773 the name parameter. */
2774 if (! NILP (f->title))
2775 name = f->title;
2776
fbd6baed 2777 if (FRAME_W32_WINDOW (f))
ee78dc32 2778 {
6fc2811b 2779 if (STRING_MULTIBYTE (name))
dfff8a69 2780 name = ENCODE_SYSTEM (name);
6fc2811b 2781
ee78dc32 2782 BLOCK_INPUT;
d5db4077 2783 SetWindowText(FRAME_W32_WINDOW (f), SDATA (name));
ee78dc32
GV
2784 UNBLOCK_INPUT;
2785 }
ee78dc32
GV
2786}
2787
2788/* This function should be called when the user's lisp code has
2789 specified a name for the frame; the name will override any set by the
2790 redisplay code. */
2791void
2792x_explicitly_set_name (f, arg, oldval)
2793 FRAME_PTR f;
2794 Lisp_Object arg, oldval;
2795{
2796 x_set_name (f, arg, 1);
2797}
2798
2799/* This function should be called by Emacs redisplay code to set the
2800 name; names set this way will never override names set by the user's
2801 lisp code. */
2802void
2803x_implicitly_set_name (f, arg, oldval)
2804 FRAME_PTR f;
2805 Lisp_Object arg, oldval;
2806{
2807 x_set_name (f, arg, 0);
2808}
1edf84e7
GV
2809\f
2810/* Change the title of frame F to NAME.
2811 If NAME is nil, use the frame name as the title.
2812
2813 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2814 name; if NAME is a string, set F's name to NAME and set
2815 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2816
2817 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2818 suggesting a new name, which lisp code should override; if
2819 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2820
1edf84e7 2821void
6fc2811b 2822x_set_title (f, name, old_name)
1edf84e7 2823 struct frame *f;
6fc2811b 2824 Lisp_Object name, old_name;
1edf84e7
GV
2825{
2826 /* Don't change the title if it's already NAME. */
2827 if (EQ (name, f->title))
2828 return;
2829
2830 update_mode_lines = 1;
2831
2832 f->title = name;
2833
2834 if (NILP (name))
2835 name = f->name;
2836
2837 if (FRAME_W32_WINDOW (f))
2838 {
6fc2811b 2839 if (STRING_MULTIBYTE (name))
dfff8a69 2840 name = ENCODE_SYSTEM (name);
6fc2811b 2841
1edf84e7 2842 BLOCK_INPUT;
d5db4077 2843 SetWindowText(FRAME_W32_WINDOW (f), SDATA (name));
1edf84e7
GV
2844 UNBLOCK_INPUT;
2845 }
2846}
2847\f
ee78dc32
GV
2848void
2849x_set_autoraise (f, arg, oldval)
2850 struct frame *f;
2851 Lisp_Object arg, oldval;
2852{
2853 f->auto_raise = !EQ (Qnil, arg);
2854}
2855
2856void
2857x_set_autolower (f, arg, oldval)
2858 struct frame *f;
2859 Lisp_Object arg, oldval;
2860{
2861 f->auto_lower = !EQ (Qnil, arg);
2862}
2863
2864void
2865x_set_unsplittable (f, arg, oldval)
2866 struct frame *f;
2867 Lisp_Object arg, oldval;
2868{
2869 f->no_split = !NILP (arg);
2870}
2871
2872void
2873x_set_vertical_scroll_bars (f, arg, oldval)
2874 struct frame *f;
2875 Lisp_Object arg, oldval;
2876{
1026b400
RS
2877 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2878 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2879 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2880 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2881 {
1026b400
RS
2882 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2883 vertical_scroll_bar_none :
87996783
GV
2884 /* Put scroll bars on the right by default, as is conventional
2885 on MS-Windows. */
2886 EQ (Qleft, arg)
7d0393cf 2887 ? vertical_scroll_bar_left
87996783 2888 : vertical_scroll_bar_right;
ee78dc32
GV
2889
2890 /* We set this parameter before creating the window for the
2891 frame, so we can get the geometry right from the start.
2892 However, if the window hasn't been created yet, we shouldn't
2893 call x_set_window_size. */
fbd6baed 2894 if (FRAME_W32_WINDOW (f))
ee78dc32 2895 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2896 do_pending_window_change (0);
ee78dc32
GV
2897 }
2898}
2899
2900void
2901x_set_scroll_bar_width (f, arg, oldval)
2902 struct frame *f;
2903 Lisp_Object arg, oldval;
2904{
6fc2811b
JR
2905 int wid = FONT_WIDTH (f->output_data.w32->font);
2906
ee78dc32
GV
2907 if (NILP (arg))
2908 {
6fc2811b
JR
2909 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2910 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2911 wid - 1) / wid;
2912 if (FRAME_W32_WINDOW (f))
2913 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2914 do_pending_window_change (0);
ee78dc32
GV
2915 }
2916 else if (INTEGERP (arg) && XINT (arg) > 0
2917 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2918 {
ee78dc32 2919 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2920 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2921 + wid-1) / wid;
fbd6baed 2922 if (FRAME_W32_WINDOW (f))
ee78dc32 2923 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2924 do_pending_window_change (0);
ee78dc32 2925 }
6fc2811b
JR
2926 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2927 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
7d0393cf 2928 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2929}
2930\f
7d0393cf 2931/* Subroutines of creating a frame. */
ee78dc32
GV
2932
2933/* Make sure that Vx_resource_name is set to a reasonable value.
2934 Fix it up, or set it to `emacs' if it is too hopeless. */
2935
2936static void
2937validate_x_resource_name ()
2938{
6fc2811b 2939 int len = 0;
ee78dc32
GV
2940 /* Number of valid characters in the resource name. */
2941 int good_count = 0;
2942 /* Number of invalid characters in the resource name. */
2943 int bad_count = 0;
2944 Lisp_Object new;
2945 int i;
2946
2947 if (STRINGP (Vx_resource_name))
2948 {
d5db4077 2949 unsigned char *p = SDATA (Vx_resource_name);
ee78dc32
GV
2950 int i;
2951
d5db4077 2952 len = SBYTES (Vx_resource_name);
ee78dc32
GV
2953
2954 /* Only letters, digits, - and _ are valid in resource names.
2955 Count the valid characters and count the invalid ones. */
2956 for (i = 0; i < len; i++)
2957 {
2958 int c = p[i];
2959 if (! ((c >= 'a' && c <= 'z')
2960 || (c >= 'A' && c <= 'Z')
2961 || (c >= '0' && c <= '9')
2962 || c == '-' || c == '_'))
2963 bad_count++;
2964 else
2965 good_count++;
2966 }
2967 }
2968 else
2969 /* Not a string => completely invalid. */
2970 bad_count = 5, good_count = 0;
2971
2972 /* If name is valid already, return. */
2973 if (bad_count == 0)
2974 return;
2975
2976 /* If name is entirely invalid, or nearly so, use `emacs'. */
2977 if (good_count == 0
2978 || (good_count == 1 && bad_count > 0))
2979 {
2980 Vx_resource_name = build_string ("emacs");
2981 return;
2982 }
2983
2984 /* Name is partly valid. Copy it and replace the invalid characters
2985 with underscores. */
2986
2987 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2988
2989 for (i = 0; i < len; i++)
2990 {
d5db4077 2991 int c = SREF (new, i);
ee78dc32
GV
2992 if (! ((c >= 'a' && c <= 'z')
2993 || (c >= 'A' && c <= 'Z')
2994 || (c >= '0' && c <= '9')
2995 || c == '-' || c == '_'))
7960d5ab 2996 SSET (new, i, '_');
ee78dc32
GV
2997 }
2998}
2999
3000
3001extern char *x_get_string_resource ();
3002
3003DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
3004 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3005This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3006class, where INSTANCE is the name under which Emacs was invoked, or
3007the name specified by the `-name' or `-rn' command-line arguments.
3008
3009The optional arguments COMPONENT and SUBCLASS add to the key and the
3010class, respectively. You must specify both of them or neither.
3011If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3012and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
3013 (attribute, class, component, subclass)
3014 Lisp_Object attribute, class, component, subclass;
3015{
3016 register char *value;
3017 char *name_key;
3018 char *class_key;
3019
b7826503
PJ
3020 CHECK_STRING (attribute);
3021 CHECK_STRING (class);
ee78dc32
GV
3022
3023 if (!NILP (component))
b7826503 3024 CHECK_STRING (component);
ee78dc32 3025 if (!NILP (subclass))
b7826503 3026 CHECK_STRING (subclass);
ee78dc32
GV
3027 if (NILP (component) != NILP (subclass))
3028 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3029
3030 validate_x_resource_name ();
3031
3032 /* Allocate space for the components, the dots which separate them,
3033 and the final '\0'. Make them big enough for the worst case. */
d5db4077 3034 name_key = (char *) alloca (SBYTES (Vx_resource_name)
ee78dc32 3035 + (STRINGP (component)
d5db4077
KR
3036 ? SBYTES (component) : 0)
3037 + SBYTES (attribute)
ee78dc32
GV
3038 + 3);
3039
3040 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
d5db4077 3041 + SBYTES (class)
ee78dc32 3042 + (STRINGP (subclass)
d5db4077 3043 ? SBYTES (subclass) : 0)
ee78dc32
GV
3044 + 3);
3045
3046 /* Start with emacs.FRAMENAME for the name (the specific one)
3047 and with `Emacs' for the class key (the general one). */
d5db4077 3048 strcpy (name_key, SDATA (Vx_resource_name));
ee78dc32
GV
3049 strcpy (class_key, EMACS_CLASS);
3050
3051 strcat (class_key, ".");
d5db4077 3052 strcat (class_key, SDATA (class));
ee78dc32
GV
3053
3054 if (!NILP (component))
3055 {
3056 strcat (class_key, ".");
d5db4077 3057 strcat (class_key, SDATA (subclass));
ee78dc32
GV
3058
3059 strcat (name_key, ".");
d5db4077 3060 strcat (name_key, SDATA (component));
ee78dc32
GV
3061 }
3062
3063 strcat (name_key, ".");
d5db4077 3064 strcat (name_key, SDATA (attribute));
ee78dc32
GV
3065
3066 value = x_get_string_resource (Qnil,
3067 name_key, class_key);
3068
3069 if (value != (char *) 0)
3070 return build_string (value);
3071 else
3072 return Qnil;
3073}
3074
3075/* Used when C code wants a resource value. */
3076
3077char *
3078x_get_resource_string (attribute, class)
3079 char *attribute, *class;
3080{
ee78dc32
GV
3081 char *name_key;
3082 char *class_key;
6fc2811b 3083 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3084
3085 /* Allocate space for the components, the dots which separate them,
3086 and the final '\0'. */
d5db4077 3087 name_key = (char *) alloca (SBYTES (Vinvocation_name)
ee78dc32
GV
3088 + strlen (attribute) + 2);
3089 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3090 + strlen (class) + 2);
3091
3092 sprintf (name_key, "%s.%s",
d5db4077 3093 SDATA (Vinvocation_name),
ee78dc32
GV
3094 attribute);
3095 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3096
6fc2811b 3097 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3098}
3099
3100/* Types we might convert a resource string into. */
3101enum resource_types
6fc2811b
JR
3102{
3103 RES_TYPE_NUMBER,
3104 RES_TYPE_FLOAT,
3105 RES_TYPE_BOOLEAN,
3106 RES_TYPE_STRING,
3107 RES_TYPE_SYMBOL
3108};
ee78dc32
GV
3109
3110/* Return the value of parameter PARAM.
3111
3112 First search ALIST, then Vdefault_frame_alist, then the X defaults
3113 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3114
3115 Convert the resource to the type specified by desired_type.
3116
3117 If no default is specified, return Qunbound. If you call
6fc2811b 3118 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3119 and don't let it get stored in any Lisp-visible variables! */
3120
3121static Lisp_Object
6fc2811b 3122w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3123 Lisp_Object alist, param;
3124 char *attribute;
3125 char *class;
3126 enum resource_types type;
3127{
3128 register Lisp_Object tem;
3129
3130 tem = Fassq (param, alist);
3131 if (EQ (tem, Qnil))
3132 tem = Fassq (param, Vdefault_frame_alist);
3133 if (EQ (tem, Qnil))
3134 {
3135
3136 if (attribute)
3137 {
3138 tem = Fx_get_resource (build_string (attribute),
3139 build_string (class),
3140 Qnil, Qnil);
3141
3142 if (NILP (tem))
3143 return Qunbound;
3144
3145 switch (type)
3146 {
6fc2811b 3147 case RES_TYPE_NUMBER:
d5db4077 3148 return make_number (atoi (SDATA (tem)));
ee78dc32 3149
6fc2811b 3150 case RES_TYPE_FLOAT:
d5db4077 3151 return make_float (atof (SDATA (tem)));
6fc2811b
JR
3152
3153 case RES_TYPE_BOOLEAN:
ee78dc32 3154 tem = Fdowncase (tem);
d5db4077
KR
3155 if (!strcmp (SDATA (tem), "on")
3156 || !strcmp (SDATA (tem), "true"))
ee78dc32 3157 return Qt;
7d0393cf 3158 else
ee78dc32
GV
3159 return Qnil;
3160
6fc2811b 3161 case RES_TYPE_STRING:
ee78dc32
GV
3162 return tem;
3163
6fc2811b 3164 case RES_TYPE_SYMBOL:
ee78dc32
GV
3165 /* As a special case, we map the values `true' and `on'
3166 to Qt, and `false' and `off' to Qnil. */
3167 {
3168 Lisp_Object lower;
3169 lower = Fdowncase (tem);
d5db4077
KR
3170 if (!strcmp (SDATA (lower), "on")
3171 || !strcmp (SDATA (lower), "true"))
ee78dc32 3172 return Qt;
d5db4077
KR
3173 else if (!strcmp (SDATA (lower), "off")
3174 || !strcmp (SDATA (lower), "false"))
ee78dc32
GV
3175 return Qnil;
3176 else
3177 return Fintern (tem, Qnil);
3178 }
3179
3180 default:
3181 abort ();
3182 }
3183 }
3184 else
3185 return Qunbound;
3186 }
3187 return Fcdr (tem);
3188}
3189
3190/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3191 of the parameter named PROP (a Lisp symbol).
3192 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3193 on the frame named NAME.
3194 If that is not found either, use the value DEFLT. */
3195
3196static Lisp_Object
3197x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3198 struct frame *f;
3199 Lisp_Object alist;
3200 Lisp_Object prop;
3201 Lisp_Object deflt;
3202 char *xprop;
3203 char *xclass;
3204 enum resource_types type;
3205{
3206 Lisp_Object tem;
3207
6fc2811b 3208 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3209 if (EQ (tem, Qunbound))
3210 tem = deflt;
3211 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3212 return tem;
3213}
3214\f
3215DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3216 doc: /* Parse an X-style geometry string STRING.
3217Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3218The properties returned may include `top', `left', `height', and `width'.
3219The value of `left' or `top' may be an integer,
3220or a list (+ N) meaning N pixels relative to top/left corner,
3221or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3222 (string)
3223 Lisp_Object string;
3224{
3225 int geometry, x, y;
3226 unsigned int width, height;
3227 Lisp_Object result;
3228
b7826503 3229 CHECK_STRING (string);
ee78dc32 3230
d5db4077 3231 geometry = XParseGeometry ((char *) SDATA (string),
ee78dc32
GV
3232 &x, &y, &width, &height);
3233
3234 result = Qnil;
3235 if (geometry & XValue)
3236 {
3237 Lisp_Object element;
3238
3239 if (x >= 0 && (geometry & XNegative))
3240 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3241 else if (x < 0 && ! (geometry & XNegative))
3242 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3243 else
3244 element = Fcons (Qleft, make_number (x));
3245 result = Fcons (element, result);
3246 }
3247
3248 if (geometry & YValue)
3249 {
3250 Lisp_Object element;
3251
3252 if (y >= 0 && (geometry & YNegative))
3253 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3254 else if (y < 0 && ! (geometry & YNegative))
3255 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3256 else
3257 element = Fcons (Qtop, make_number (y));
3258 result = Fcons (element, result);
3259 }
3260
3261 if (geometry & WidthValue)
3262 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3263 if (geometry & HeightValue)
3264 result = Fcons (Fcons (Qheight, make_number (height)), result);
3265
3266 return result;
3267}
3268
3269/* Calculate the desired size and position of this window,
3270 and return the flags saying which aspects were specified.
3271
3272 This function does not make the coordinates positive. */
3273
3274#define DEFAULT_ROWS 40
3275#define DEFAULT_COLS 80
3276
3277static int
3278x_figure_window_size (f, parms)
3279 struct frame *f;
3280 Lisp_Object parms;
3281{
3282 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3283 long window_prompting = 0;
3284
3285 /* Default values if we fall through.
3286 Actually, if that happens we should get
3287 window manager prompting. */
1026b400 3288 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3289 f->height = DEFAULT_ROWS;
3290 /* Window managers expect that if program-specified
3291 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3292 f->output_data.w32->top_pos = 0;
3293 f->output_data.w32->left_pos = 0;
ee78dc32 3294
35b41202
JR
3295 /* Ensure that old new_width and new_height will not override the
3296 values set here. */
3297 FRAME_NEW_WIDTH (f) = 0;
3298 FRAME_NEW_HEIGHT (f) = 0;
3299
6fc2811b
JR
3300 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3301 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3302 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3303 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3304 {
3305 if (!EQ (tem0, Qunbound))
3306 {
b7826503 3307 CHECK_NUMBER (tem0);
ee78dc32
GV
3308 f->height = XINT (tem0);
3309 }
3310 if (!EQ (tem1, Qunbound))
3311 {
b7826503 3312 CHECK_NUMBER (tem1);
1026b400 3313 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3314 }
3315 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3316 window_prompting |= USSize;
3317 else
3318 window_prompting |= PSize;
3319 }
3320
fbd6baed 3321 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3322 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3323 ? 0
3324 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3325 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3326 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
f7b9d4d1 3327
41c1bdd9 3328 x_compute_fringe_widths (f, 0);
f7b9d4d1 3329
fbd6baed
GV
3330 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3331 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3332
6fc2811b
JR
3333 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3334 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3335 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3336 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3337 {
3338 if (EQ (tem0, Qminus))
3339 {
fbd6baed 3340 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3341 window_prompting |= YNegative;
3342 }
8e713be6
KR
3343 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3344 && CONSP (XCDR (tem0))
3345 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3346 {
8e713be6 3347 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3348 window_prompting |= YNegative;
3349 }
8e713be6
KR
3350 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3351 && CONSP (XCDR (tem0))
3352 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3353 {
8e713be6 3354 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3355 }
3356 else if (EQ (tem0, Qunbound))
fbd6baed 3357 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3358 else
3359 {
b7826503 3360 CHECK_NUMBER (tem0);
fbd6baed
GV
3361 f->output_data.w32->top_pos = XINT (tem0);
3362 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3363 window_prompting |= YNegative;
3364 }
3365
3366 if (EQ (tem1, Qminus))
3367 {
fbd6baed 3368 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3369 window_prompting |= XNegative;
3370 }
8e713be6
KR
3371 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3372 && CONSP (XCDR (tem1))
3373 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3374 {
8e713be6 3375 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3376 window_prompting |= XNegative;
3377 }
8e713be6
KR
3378 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3379 && CONSP (XCDR (tem1))
3380 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3381 {
8e713be6 3382 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3383 }
3384 else if (EQ (tem1, Qunbound))
fbd6baed 3385 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3386 else
3387 {
b7826503 3388 CHECK_NUMBER (tem1);
fbd6baed
GV
3389 f->output_data.w32->left_pos = XINT (tem1);
3390 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3391 window_prompting |= XNegative;
3392 }
3393
3394 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3395 window_prompting |= USPosition;
3396 else
3397 window_prompting |= PPosition;
3398 }
3399
f7b9d4d1
JR
3400 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3401 {
3402 int left, top;
3403 int width, height;
3404
3405 /* It takes both for some WM:s to place it where we want */
3406 window_prompting = USPosition | PPosition;
3407 x_fullscreen_adjust (f, &width, &height, &top, &left);
3408 f->width = width;
3409 f->height = height;
3410 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3411 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3412 f->output_data.w32->left_pos = left;
3413 f->output_data.w32->top_pos = top;
3414 }
3415
ee78dc32
GV
3416 return window_prompting;
3417}
3418
3419\f
3420
fbd6baed 3421extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32 3422
7d0393cf 3423BOOL
fbd6baed 3424w32_init_class (hinst)
ee78dc32
GV
3425 HINSTANCE hinst;
3426{
3427 WNDCLASS wc;
3428
5ac45f98 3429 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3430 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3431 wc.cbClsExtra = 0;
3432 wc.cbWndExtra = WND_EXTRA_BYTES;
3433 wc.hInstance = hinst;
3434 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3435 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3436 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3437 wc.lpszMenuName = NULL;
3438 wc.lpszClassName = EMACS_CLASS;
3439
3440 return (RegisterClass (&wc));
3441}
3442
7d0393cf 3443HWND
fbd6baed 3444w32_createscrollbar (f, bar)
ee78dc32
GV
3445 struct frame *f;
3446 struct scroll_bar * bar;
3447{
3448 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3449 /* Position and size of scroll bar. */
6fc2811b 3450 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7d0393cf 3451 XINT(bar->top),
6fc2811b
JR
3452 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3453 XINT(bar->height),
fbd6baed 3454 FRAME_W32_WINDOW (f),
ee78dc32
GV
3455 NULL,
3456 hinst,
3457 NULL));
3458}
3459
7d0393cf 3460void
fbd6baed 3461w32_createwindow (f)
ee78dc32
GV
3462 struct frame *f;
3463{
3464 HWND hwnd;
1edf84e7
GV
3465 RECT rect;
3466
3467 rect.left = rect.top = 0;
3468 rect.right = PIXEL_WIDTH (f);
3469 rect.bottom = PIXEL_HEIGHT (f);
7d0393cf 3470
1edf84e7
GV
3471 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3472 FRAME_EXTERNAL_MENU_BAR (f));
7d0393cf 3473
ee78dc32 3474 /* Do first time app init */
7d0393cf 3475
ee78dc32
GV
3476 if (!hprevinst)
3477 {
fbd6baed 3478 w32_init_class (hinst);
ee78dc32 3479 }
7d0393cf 3480
1edf84e7
GV
3481 FRAME_W32_WINDOW (f) = hwnd
3482 = CreateWindow (EMACS_CLASS,
3483 f->namebuf,
9ead1b60 3484 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3485 f->output_data.w32->left_pos,
3486 f->output_data.w32->top_pos,
3487 rect.right - rect.left,
3488 rect.bottom - rect.top,
3489 NULL,
3490 NULL,
3491 hinst,
3492 NULL);
3493
ee78dc32
GV
3494 if (hwnd)
3495 {
1edf84e7
GV
3496 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3497 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3498 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3499 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3500 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3501
cb9e33d4
RS
3502 /* Enable drag-n-drop. */
3503 DragAcceptFiles (hwnd, TRUE);
7d0393cf 3504
5ac45f98
GV
3505 /* Do this to discard the default setting specified by our parent. */
3506 ShowWindow (hwnd, SW_HIDE);
3c190163 3507 }
3c190163
GV
3508}
3509
7d0393cf 3510void
ee78dc32 3511my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3512 W32Msg * wmsg;
ee78dc32
GV
3513 HWND hwnd;
3514 UINT msg;
3515 WPARAM wParam;
3516 LPARAM lParam;
3517{
3518 wmsg->msg.hwnd = hwnd;
3519 wmsg->msg.message = msg;
3520 wmsg->msg.wParam = wParam;
3521 wmsg->msg.lParam = lParam;
3522 wmsg->msg.time = GetMessageTime ();
3523
3524 post_msg (wmsg);
3525}
3526
e9e23e23 3527/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3528 between left and right keys as advertised. We test for this
3529 support dynamically, and set a flag when the support is absent. If
3530 absent, we keep track of the left and right control and alt keys
3531 ourselves. This is particularly necessary on keyboards that rely
3532 upon the AltGr key, which is represented as having the left control
3533 and right alt keys pressed. For these keyboards, we need to know
3534 when the left alt key has been pressed in addition to the AltGr key
3535 so that we can properly support M-AltGr-key sequences (such as M-@
3536 on Swedish keyboards). */
3537
3538#define EMACS_LCONTROL 0
3539#define EMACS_RCONTROL 1
3540#define EMACS_LMENU 2
3541#define EMACS_RMENU 3
3542
3543static int modifiers[4];
3544static int modifiers_recorded;
3545static int modifier_key_support_tested;
3546
3547static void
3548test_modifier_support (unsigned int wparam)
3549{
3550 unsigned int l, r;
3551
3552 if (wparam != VK_CONTROL && wparam != VK_MENU)
3553 return;
3554 if (wparam == VK_CONTROL)
3555 {
3556 l = VK_LCONTROL;
3557 r = VK_RCONTROL;
3558 }
3559 else
3560 {
3561 l = VK_LMENU;
3562 r = VK_RMENU;
3563 }
3564 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3565 modifiers_recorded = 1;
3566 else
3567 modifiers_recorded = 0;
3568 modifier_key_support_tested = 1;
3569}
3570
3571static void
3572record_keydown (unsigned int wparam, unsigned int lparam)
3573{
3574 int i;
3575
3576 if (!modifier_key_support_tested)
3577 test_modifier_support (wparam);
3578
3579 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3580 return;
3581
3582 if (wparam == VK_CONTROL)
3583 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3584 else
3585 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3586
3587 modifiers[i] = 1;
3588}
3589
3590static void
3591record_keyup (unsigned int wparam, unsigned int lparam)
3592{
3593 int i;
3594
3595 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3596 return;
3597
3598 if (wparam == VK_CONTROL)
3599 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3600 else
3601 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3602
3603 modifiers[i] = 0;
3604}
3605
da36a4d6 3606/* Emacs can lose focus while a modifier key has been pressed. When
7d0393cf 3607 it regains focus, be conservative and clear all modifiers since
da36a4d6
GV
3608 we cannot reconstruct the left and right modifier state. */
3609static void
3610reset_modifiers ()
3611{
8681157a
RS
3612 SHORT ctrl, alt;
3613
adcc3809
GV
3614 if (GetFocus () == NULL)
3615 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3616 return;
8681157a
RS
3617
3618 ctrl = GetAsyncKeyState (VK_CONTROL);
3619 alt = GetAsyncKeyState (VK_MENU);
3620
8681157a
RS
3621 if (!(ctrl & 0x08000))
3622 /* Clear any recorded control modifier state. */
3623 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3624
3625 if (!(alt & 0x08000))
3626 /* Clear any recorded alt modifier state. */
3627 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3628
adcc3809
GV
3629 /* Update the state of all modifier keys, because modifiers used in
3630 hot-key combinations can get stuck on if Emacs loses focus as a
3631 result of a hot-key being pressed. */
3632 {
3633 BYTE keystate[256];
3634
3635#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3636
3637 GetKeyboardState (keystate);
3638 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3639 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3640 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3641 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3642 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3643 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3644 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3645 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3646 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3647 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3648 SetKeyboardState (keystate);
3649 }
da36a4d6
GV
3650}
3651
7830e24b
RS
3652/* Synchronize modifier state with what is reported with the current
3653 keystroke. Even if we cannot distinguish between left and right
3654 modifier keys, we know that, if no modifiers are set, then neither
3655 the left or right modifier should be set. */
3656static void
3657sync_modifiers ()
3658{
3659 if (!modifiers_recorded)
3660 return;
3661
7d0393cf 3662 if (!(GetKeyState (VK_CONTROL) & 0x8000))
7830e24b
RS
3663 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3664
7d0393cf 3665 if (!(GetKeyState (VK_MENU) & 0x8000))
7830e24b
RS
3666 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3667}
3668
a1a80b40
GV
3669static int
3670modifier_set (int vkey)
3671{
ccc2d29c 3672 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3673 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3674 if (!modifiers_recorded)
3675 return (GetKeyState (vkey) & 0x8000);
3676
3677 switch (vkey)
3678 {
3679 case VK_LCONTROL:
3680 return modifiers[EMACS_LCONTROL];
3681 case VK_RCONTROL:
3682 return modifiers[EMACS_RCONTROL];
3683 case VK_LMENU:
3684 return modifiers[EMACS_LMENU];
3685 case VK_RMENU:
3686 return modifiers[EMACS_RMENU];
a1a80b40
GV
3687 }
3688 return (GetKeyState (vkey) & 0x8000);
3689}
3690
ccc2d29c
GV
3691/* Convert between the modifier bits W32 uses and the modifier bits
3692 Emacs uses. */
3693
3694unsigned int
3695w32_key_to_modifier (int key)
3696{
3697 Lisp_Object key_mapping;
3698
3699 switch (key)
3700 {
3701 case VK_LWIN:
3702 key_mapping = Vw32_lwindow_modifier;
3703 break;
3704 case VK_RWIN:
3705 key_mapping = Vw32_rwindow_modifier;
3706 break;
3707 case VK_APPS:
3708 key_mapping = Vw32_apps_modifier;
3709 break;
3710 case VK_SCROLL:
3711 key_mapping = Vw32_scroll_lock_modifier;
3712 break;
3713 default:
3714 key_mapping = Qnil;
3715 }
3716
adcc3809
GV
3717 /* NB. This code runs in the input thread, asychronously to the lisp
3718 thread, so we must be careful to ensure access to lisp data is
3719 thread-safe. The following code is safe because the modifier
3720 variable values are updated atomically from lisp and symbols are
3721 not relocated by GC. Also, we don't have to worry about seeing GC
3722 markbits here. */
3723 if (EQ (key_mapping, Qhyper))
ccc2d29c 3724 return hyper_modifier;
adcc3809 3725 if (EQ (key_mapping, Qsuper))
ccc2d29c 3726 return super_modifier;
adcc3809 3727 if (EQ (key_mapping, Qmeta))
ccc2d29c 3728 return meta_modifier;
adcc3809 3729 if (EQ (key_mapping, Qalt))
ccc2d29c 3730 return alt_modifier;
adcc3809 3731 if (EQ (key_mapping, Qctrl))
ccc2d29c 3732 return ctrl_modifier;
adcc3809 3733 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3734 return ctrl_modifier;
adcc3809 3735 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3736 return shift_modifier;
3737
3738 /* Don't generate any modifier if not explicitly requested. */
3739 return 0;
3740}
3741
3742unsigned int
3743w32_get_modifiers ()
3744{
3745 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3746 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3747 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3748 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3749 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3750 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3751 (modifier_set (VK_MENU) ?
3752 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3753}
3754
a1a80b40
GV
3755/* We map the VK_* modifiers into console modifier constants
3756 so that we can use the same routines to handle both console
3757 and window input. */
3758
3759static int
ccc2d29c 3760construct_console_modifiers ()
a1a80b40
GV
3761{
3762 int mods;
3763
a1a80b40
GV
3764 mods = 0;
3765 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3766 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3767 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3768 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3769 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3770 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3771 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3772 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3773 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3774 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3775 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3776
3777 return mods;
3778}
3779
ccc2d29c
GV
3780static int
3781w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3782{
ccc2d29c
GV
3783 int mods;
3784
3785 /* Convert to emacs modifiers. */
3786 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3787
3788 return mods;
3789}
da36a4d6 3790
ccc2d29c
GV
3791unsigned int
3792map_keypad_keys (unsigned int virt_key, unsigned int extended)
3793{
3794 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3795 return virt_key;
da36a4d6 3796
ccc2d29c 3797 if (virt_key == VK_RETURN)
da36a4d6
GV
3798 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3799
ccc2d29c
GV
3800 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3801 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3802
3803 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3804 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3805
3806 if (virt_key == VK_CLEAR)
3807 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3808
3809 return virt_key;
3810}
3811
3812/* List of special key combinations which w32 would normally capture,
3813 but emacs should grab instead. Not directly visible to lisp, to
3814 simplify synchronization. Each item is an integer encoding a virtual
3815 key code and modifier combination to capture. */
3816Lisp_Object w32_grabbed_keys;
3817
3818#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3819#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3820#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3821#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3822
3823/* Register hot-keys for reserved key combinations when Emacs has
3824 keyboard focus, since this is the only way Emacs can receive key
3825 combinations like Alt-Tab which are used by the system. */
3826
3827static void
3828register_hot_keys (hwnd)
3829 HWND hwnd;
3830{
3831 Lisp_Object keylist;
3832
3833 /* Use GC_CONSP, since we are called asynchronously. */
3834 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3835 {
3836 Lisp_Object key = XCAR (keylist);
3837
3838 /* Deleted entries get set to nil. */
3839 if (!INTEGERP (key))
3840 continue;
3841
3842 RegisterHotKey (hwnd, HOTKEY_ID (key),
3843 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3844 }
3845}
3846
3847static void
3848unregister_hot_keys (hwnd)
3849 HWND hwnd;
3850{
3851 Lisp_Object keylist;
3852
3853 /* Use GC_CONSP, since we are called asynchronously. */
3854 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3855 {
3856 Lisp_Object key = XCAR (keylist);
3857
3858 if (!INTEGERP (key))
3859 continue;
3860
3861 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3862 }
3863}
3864
5ac45f98
GV
3865/* Main message dispatch loop. */
3866
1edf84e7
GV
3867static void
3868w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3869{
3870 MSG msg;
ccc2d29c
GV
3871 int result;
3872 HWND focus_window;
93fbe8b7
GV
3873
3874 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
7d0393cf 3875
5ac45f98
GV
3876 while (GetMessage (&msg, NULL, 0, 0))
3877 {
3878 if (msg.hwnd == NULL)
3879 {
3880 switch (msg.message)
3881 {
3ef68e6b
AI
3882 case WM_NULL:
3883 /* Produced by complete_deferred_msg; just ignore. */
3884 break;
5ac45f98 3885 case WM_EMACS_CREATEWINDOW:
fbd6baed 3886 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3887 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3888 abort ();
5ac45f98 3889 break;
dfdb4047
GV
3890 case WM_EMACS_SETLOCALE:
3891 SetThreadLocale (msg.wParam);
3892 /* Reply is not expected. */
3893 break;
ccc2d29c
GV
3894 case WM_EMACS_SETKEYBOARDLAYOUT:
3895 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3896 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3897 result, 0))
3898 abort ();
3899 break;
3900 case WM_EMACS_REGISTER_HOT_KEY:
3901 focus_window = GetFocus ();
3902 if (focus_window != NULL)
3903 RegisterHotKey (focus_window,
3904 HOTKEY_ID (msg.wParam),
3905 HOTKEY_MODIFIERS (msg.wParam),
3906 HOTKEY_VK_CODE (msg.wParam));
3907 /* Reply is not expected. */
3908 break;
3909 case WM_EMACS_UNREGISTER_HOT_KEY:
3910 focus_window = GetFocus ();
3911 if (focus_window != NULL)
3912 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3913 /* Mark item as erased. NB: this code must be
3914 thread-safe. The next line is okay because the cons
3915 cell is never made into garbage and is not relocated by
3916 GC. */
f3fbd155 3917 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3918 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3919 abort ();
3920 break;
adcc3809
GV
3921 case WM_EMACS_TOGGLE_LOCK_KEY:
3922 {
3923 int vk_code = (int) msg.wParam;
3924 int cur_state = (GetKeyState (vk_code) & 1);
3925 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3926
3927 /* NB: This code must be thread-safe. It is safe to
3928 call NILP because symbols are not relocated by GC,
3929 and pointer here is not touched by GC (so the markbit
3930 can't be set). Numbers are safe because they are
3931 immediate values. */
3932 if (NILP (new_state)
3933 || (NUMBERP (new_state)
8edb0a6f 3934 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3935 {
3936 one_w32_display_info.faked_key = vk_code;
3937
3938 keybd_event ((BYTE) vk_code,
3939 (BYTE) MapVirtualKey (vk_code, 0),
3940 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3941 keybd_event ((BYTE) vk_code,
3942 (BYTE) MapVirtualKey (vk_code, 0),
3943 KEYEVENTF_EXTENDEDKEY | 0, 0);
3944 keybd_event ((BYTE) vk_code,
3945 (BYTE) MapVirtualKey (vk_code, 0),
3946 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3947 cur_state = !cur_state;
3948 }
3949 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3950 cur_state, 0))
3951 abort ();
3952 }
3953 break;
1edf84e7 3954 default:
1edf84e7 3955 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3956 }
3957 }
3958 else
3959 {
3960 DispatchMessage (&msg);
3961 }
1edf84e7
GV
3962
3963 /* Exit nested loop when our deferred message has completed. */
3964 if (msg_buf->completed)
3965 break;
5ac45f98 3966 }
1edf84e7
GV
3967}
3968
3969deferred_msg * deferred_msg_head;
3970
3971static deferred_msg *
3972find_deferred_msg (HWND hwnd, UINT msg)
3973{
3974 deferred_msg * item;
3975
3976 /* Don't actually need synchronization for read access, since
3977 modification of single pointer is always atomic. */
3978 /* enter_crit (); */
3979
3980 for (item = deferred_msg_head; item != NULL; item = item->next)
3981 if (item->w32msg.msg.hwnd == hwnd
3982 && item->w32msg.msg.message == msg)
3983 break;
3984
3985 /* leave_crit (); */
3986
3987 return item;
3988}
3989
3990static LRESULT
3991send_deferred_msg (deferred_msg * msg_buf,
3992 HWND hwnd,
3993 UINT msg,
3994 WPARAM wParam,
3995 LPARAM lParam)
3996{
3997 /* Only input thread can send deferred messages. */
3998 if (GetCurrentThreadId () != dwWindowsThreadId)
3999 abort ();
4000
4001 /* It is an error to send a message that is already deferred. */
4002 if (find_deferred_msg (hwnd, msg) != NULL)
4003 abort ();
4004
4005 /* Enforced synchronization is not needed because this is the only
4006 function that alters deferred_msg_head, and the following critical
4007 section is guaranteed to only be serially reentered (since only the
4008 input thread can call us). */
4009
4010 /* enter_crit (); */
4011
4012 msg_buf->completed = 0;
4013 msg_buf->next = deferred_msg_head;
4014 deferred_msg_head = msg_buf;
4015 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4016
4017 /* leave_crit (); */
4018
4019 /* Start a new nested message loop to process other messages until
4020 this one is completed. */
4021 w32_msg_pump (msg_buf);
4022
4023 deferred_msg_head = msg_buf->next;
4024
4025 return msg_buf->result;
4026}
4027
4028void
4029complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4030{
4031 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4032
4033 if (msg_buf == NULL)
3ef68e6b
AI
4034 /* Message may have been cancelled, so don't abort(). */
4035 return;
1edf84e7
GV
4036
4037 msg_buf->result = result;
4038 msg_buf->completed = 1;
4039
4040 /* Ensure input thread is woken so it notices the completion. */
4041 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4042}
4043
3ef68e6b
AI
4044void
4045cancel_all_deferred_msgs ()
4046{
4047 deferred_msg * item;
4048
4049 /* Don't actually need synchronization for read access, since
4050 modification of single pointer is always atomic. */
4051 /* enter_crit (); */
4052
4053 for (item = deferred_msg_head; item != NULL; item = item->next)
4054 {
4055 item->result = 0;
4056 item->completed = 1;
4057 }
4058
4059 /* leave_crit (); */
4060
4061 /* Ensure input thread is woken so it notices the completion. */
4062 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4063}
1edf84e7 4064
7d0393cf 4065DWORD
1edf84e7
GV
4066w32_msg_worker (dw)
4067 DWORD dw;
4068{
4069 MSG msg;
4070 deferred_msg dummy_buf;
4071
4072 /* Ensure our message queue is created */
7d0393cf 4073
1edf84e7 4074 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
7d0393cf 4075
1edf84e7
GV
4076 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4077 abort ();
4078
4079 memset (&dummy_buf, 0, sizeof (dummy_buf));
4080 dummy_buf.w32msg.msg.hwnd = NULL;
4081 dummy_buf.w32msg.msg.message = WM_NULL;
4082
4083 /* This is the inital message loop which should only exit when the
4084 application quits. */
4085 w32_msg_pump (&dummy_buf);
4086
4087 return 0;
5ac45f98
GV
4088}
4089
3ef68e6b
AI
4090static void
4091post_character_message (hwnd, msg, wParam, lParam, modifiers)
4092 HWND hwnd;
4093 UINT msg;
4094 WPARAM wParam;
4095 LPARAM lParam;
4096 DWORD modifiers;
4097
4098{
4099 W32Msg wmsg;
4100
4101 wmsg.dwModifiers = modifiers;
4102
4103 /* Detect quit_char and set quit-flag directly. Note that we
4104 still need to post a message to ensure the main thread will be
4105 woken up if blocked in sys_select(), but we do NOT want to post
4106 the quit_char message itself (because it will usually be as if
4107 the user had typed quit_char twice). Instead, we post a dummy
4108 message that has no particular effect. */
4109 {
4110 int c = wParam;
4111 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4112 c = make_ctrl_char (c) & 0377;
7d081355
AI
4113 if (c == quit_char
4114 || (wmsg.dwModifiers == 0 &&
4115 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4116 {
4117 Vquit_flag = Qt;
4118
4119 /* The choice of message is somewhat arbitrary, as long as
4120 the main thread handler just ignores it. */
4121 msg = WM_NULL;
4122
4123 /* Interrupt any blocking system calls. */
4124 signal_quit ();
4125
4126 /* As a safety precaution, forcibly complete any deferred
4127 messages. This is a kludge, but I don't see any particularly
4128 clean way to handle the situation where a deferred message is
4129 "dropped" in the lisp thread, and will thus never be
4130 completed, eg. by the user trying to activate the menubar
4131 when the lisp thread is busy, and then typing C-g when the
4132 menubar doesn't open promptly (with the result that the
4133 menubar never responds at all because the deferred
4134 WM_INITMENU message is never completed). Another problem
4135 situation is when the lisp thread calls SendMessage (to send
4136 a window manager command) when a message has been deferred;
4137 the lisp thread gets blocked indefinitely waiting for the
4138 deferred message to be completed, which itself is waiting for
4139 the lisp thread to respond.
4140
4141 Note that we don't want to block the input thread waiting for
4142 a reponse from the lisp thread (although that would at least
4143 solve the deadlock problem above), because we want to be able
4144 to receive C-g to interrupt the lisp thread. */
4145 cancel_all_deferred_msgs ();
4146 }
4147 }
4148
4149 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4150}
4151
ee78dc32
GV
4152/* Main window procedure */
4153
7d0393cf 4154LRESULT CALLBACK
fbd6baed 4155w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4156 HWND hwnd;
4157 UINT msg;
4158 WPARAM wParam;
4159 LPARAM lParam;
4160{
4161 struct frame *f;
fbd6baed
GV
4162 struct w32_display_info *dpyinfo = &one_w32_display_info;
4163 W32Msg wmsg;
84fb1139 4164 int windows_translate;
576ba81c 4165 int key;
84fb1139 4166
a6085637
KH
4167 /* Note that it is okay to call x_window_to_frame, even though we are
4168 not running in the main lisp thread, because frame deletion
4169 requires the lisp thread to synchronize with this thread. Thus, if
4170 a frame struct is returned, it can be used without concern that the
4171 lisp thread might make it disappear while we are using it.
4172
4173 NB. Walking the frame list in this thread is safe (as long as
4174 writes of Lisp_Object slots are atomic, which they are on Windows).
4175 Although delete-frame can destructively modify the frame list while
4176 we are walking it, a garbage collection cannot occur until after
4177 delete-frame has synchronized with this thread.
4178
4179 It is also safe to use functions that make GDI calls, such as
fbd6baed 4180 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4181 from the frame struct using get_frame_dc which is thread-aware. */
4182
7d0393cf 4183 switch (msg)
ee78dc32
GV
4184 {
4185 case WM_ERASEBKGND:
a6085637
KH
4186 f = x_window_to_frame (dpyinfo, hwnd);
4187 if (f)
4188 {
9badad41 4189 HDC hdc = get_frame_dc (f);
a6085637 4190 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4191 w32_clear_rect (f, hdc, &wmsg.rect);
4192 release_frame_dc (f, hdc);
ce6059da
AI
4193
4194#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4195 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4196 f,
4197 wmsg.rect.left, wmsg.rect.top,
4198 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4199#endif /* W32_DEBUG_DISPLAY */
a6085637 4200 }
5ac45f98
GV
4201 return 1;
4202 case WM_PALETTECHANGED:
4203 /* ignore our own changes */
4204 if ((HWND)wParam != hwnd)
4205 {
a6085637
KH
4206 f = x_window_to_frame (dpyinfo, hwnd);
4207 if (f)
4208 /* get_frame_dc will realize our palette and force all
4209 frames to be redrawn if needed. */
4210 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4211 }
4212 return 0;
ee78dc32 4213 case WM_PAINT:
ce6059da 4214 {
55dcfc15
AI
4215 PAINTSTRUCT paintStruct;
4216 RECT update_rect;
aa35b6ad 4217 bzero (&update_rect, sizeof (update_rect));
55dcfc15 4218
18f0b342
AI
4219 f = x_window_to_frame (dpyinfo, hwnd);
4220 if (f == 0)
4221 {
4222 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4223 return 0;
4224 }
4225
55dcfc15
AI
4226 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4227 fails. Apparently this can happen under some
4228 circumstances. */
aa35b6ad 4229 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
55dcfc15
AI
4230 {
4231 enter_crit ();
4232 BeginPaint (hwnd, &paintStruct);
4233
aa35b6ad
JR
4234 /* The rectangles returned by GetUpdateRect and BeginPaint
4235 do not always match. Play it safe by assuming both areas
4236 are invalid. */
4237 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
55dcfc15
AI
4238
4239#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4240 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4241 f,
4242 wmsg.rect.left, wmsg.rect.top,
4243 wmsg.rect.right, wmsg.rect.bottom));
4244 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4245 update_rect.left, update_rect.top,
4246 update_rect.right, update_rect.bottom));
4247#endif
4248 EndPaint (hwnd, &paintStruct);
4249 leave_crit ();
4250
4251 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
7d0393cf 4252
55dcfc15
AI
4253 return 0;
4254 }
c0611964
AI
4255
4256 /* If GetUpdateRect returns 0 (meaning there is no update
4257 region), assume the whole window needs to be repainted. */
4258 GetClientRect(hwnd, &wmsg.rect);
4259 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4260 return 0;
ee78dc32 4261 }
a1a80b40 4262
ccc2d29c
GV
4263 case WM_INPUTLANGCHANGE:
4264 /* Inform lisp thread of keyboard layout changes. */
4265 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4266
4267 /* Clear dead keys in the keyboard state; for simplicity only
4268 preserve modifier key states. */
4269 {
4270 int i;
4271 BYTE keystate[256];
4272
4273 GetKeyboardState (keystate);
4274 for (i = 0; i < 256; i++)
4275 if (1
4276 && i != VK_SHIFT
4277 && i != VK_LSHIFT
4278 && i != VK_RSHIFT
4279 && i != VK_CAPITAL
4280 && i != VK_NUMLOCK
4281 && i != VK_SCROLL
4282 && i != VK_CONTROL
4283 && i != VK_LCONTROL
4284 && i != VK_RCONTROL
4285 && i != VK_MENU
4286 && i != VK_LMENU
4287 && i != VK_RMENU
4288 && i != VK_LWIN
4289 && i != VK_RWIN)
4290 keystate[i] = 0;
4291 SetKeyboardState (keystate);
4292 }
4293 goto dflt;
4294
4295 case WM_HOTKEY:
4296 /* Synchronize hot keys with normal input. */
4297 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4298 return (0);
4299
a1a80b40
GV
4300 case WM_KEYUP:
4301 case WM_SYSKEYUP:
4302 record_keyup (wParam, lParam);
4303 goto dflt;
4304
ee78dc32
GV
4305 case WM_KEYDOWN:
4306 case WM_SYSKEYDOWN:
ccc2d29c
GV
4307 /* Ignore keystrokes we fake ourself; see below. */
4308 if (dpyinfo->faked_key == wParam)
4309 {
4310 dpyinfo->faked_key = 0;
576ba81c
AI
4311 /* Make sure TranslateMessage sees them though (as long as
4312 they don't produce WM_CHAR messages). This ensures that
4313 indicator lights are toggled promptly on Windows 9x, for
4314 example. */
4315 if (lispy_function_keys[wParam] != 0)
4316 {
4317 windows_translate = 1;
4318 goto translate;
4319 }
4320 return 0;
ccc2d29c
GV
4321 }
4322
7830e24b
RS
4323 /* Synchronize modifiers with current keystroke. */
4324 sync_modifiers ();
a1a80b40 4325 record_keydown (wParam, lParam);
ccc2d29c 4326 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4327
4328 windows_translate = 0;
ccc2d29c
GV
4329
4330 switch (wParam)
4331 {
4332 case VK_LWIN:
4333 if (NILP (Vw32_pass_lwindow_to_system))
4334 {
4335 /* Prevent system from acting on keyup (which opens the
4336 Start menu if no other key was pressed) by simulating a
4337 press of Space which we will ignore. */
4338 if (GetAsyncKeyState (wParam) & 1)
4339 {
adcc3809 4340 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4341 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4342 else
576ba81c
AI
4343 key = VK_SPACE;
4344 dpyinfo->faked_key = key;
4345 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4346 }
4347 }
4348 if (!NILP (Vw32_lwindow_modifier))
4349 return 0;
4350 break;
4351 case VK_RWIN:
4352 if (NILP (Vw32_pass_rwindow_to_system))
4353 {
4354 if (GetAsyncKeyState (wParam) & 1)
4355 {
adcc3809 4356 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4357 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4358 else
576ba81c
AI
4359 key = VK_SPACE;
4360 dpyinfo->faked_key = key;
4361 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4362 }
4363 }
4364 if (!NILP (Vw32_rwindow_modifier))
4365 return 0;
4366 break;
576ba81c 4367 case VK_APPS:
ccc2d29c
GV
4368 if (!NILP (Vw32_apps_modifier))
4369 return 0;
4370 break;
4371 case VK_MENU:
7d0393cf 4372 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4373 /* Prevent DefWindowProc from activating the menu bar if an
4374 Alt key is pressed and released by itself. */
ccc2d29c 4375 return 0;
84fb1139 4376 windows_translate = 1;
ccc2d29c 4377 break;
7d0393cf 4378 case VK_CAPITAL:
ccc2d29c
GV
4379 /* Decide whether to treat as modifier or function key. */
4380 if (NILP (Vw32_enable_caps_lock))
4381 goto disable_lock_key;
adcc3809
GV
4382 windows_translate = 1;
4383 break;
ccc2d29c
GV
4384 case VK_NUMLOCK:
4385 /* Decide whether to treat as modifier or function key. */
4386 if (NILP (Vw32_enable_num_lock))
4387 goto disable_lock_key;
adcc3809
GV
4388 windows_translate = 1;
4389 break;
ccc2d29c
GV
4390 case VK_SCROLL:
4391 /* Decide whether to treat as modifier or function key. */
4392 if (NILP (Vw32_scroll_lock_modifier))
4393 goto disable_lock_key;
adcc3809
GV
4394 windows_translate = 1;
4395 break;
ccc2d29c 4396 disable_lock_key:
adcc3809
GV
4397 /* Ensure the appropriate lock key state (and indicator light)
4398 remains in the same state. We do this by faking another
4399 press of the relevant key. Apparently, this really is the
4400 only way to toggle the state of the indicator lights. */
4401 dpyinfo->faked_key = wParam;
4402 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4403 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4404 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4405 KEYEVENTF_EXTENDEDKEY | 0, 0);
4406 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4407 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4408 /* Ensure indicator lights are updated promptly on Windows 9x
4409 (TranslateMessage apparently does this), after forwarding
4410 input event. */
4411 post_character_message (hwnd, msg, wParam, lParam,
4412 w32_get_key_modifiers (wParam, lParam));
4413 windows_translate = 1;
ccc2d29c 4414 break;
7d0393cf 4415 case VK_CONTROL:
ccc2d29c
GV
4416 case VK_SHIFT:
4417 case VK_PROCESSKEY: /* Generated by IME. */
4418 windows_translate = 1;
4419 break;
adcc3809
GV
4420 case VK_CANCEL:
4421 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4422 which is confusing for purposes of key binding; convert
4423 VK_CANCEL events into VK_PAUSE events. */
4424 wParam = VK_PAUSE;
4425 break;
4426 case VK_PAUSE:
4427 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4428 for purposes of key binding; convert these back into
4429 VK_NUMLOCK events, at least when we want to see NumLock key
4430 presses. (Note that there is never any possibility that
4431 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4432 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4433 wParam = VK_NUMLOCK;
4434 break;
ccc2d29c
GV
4435 default:
4436 /* If not defined as a function key, change it to a WM_CHAR message. */
4437 if (lispy_function_keys[wParam] == 0)
4438 {
adcc3809
GV
4439 DWORD modifiers = construct_console_modifiers ();
4440
ccc2d29c
GV
4441 if (!NILP (Vw32_recognize_altgr)
4442 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4443 {
4444 /* Always let TranslateMessage handle AltGr key chords;
4445 for some reason, ToAscii doesn't always process AltGr
4446 chords correctly. */
4447 windows_translate = 1;
4448 }
adcc3809 4449 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4450 {
adcc3809
GV
4451 /* Handle key chords including any modifiers other
4452 than shift directly, in order to preserve as much
4453 modifier information as possible. */
ccc2d29c
GV
4454 if ('A' <= wParam && wParam <= 'Z')
4455 {
4456 /* Don't translate modified alphabetic keystrokes,
4457 so the user doesn't need to constantly switch
4458 layout to type control or meta keystrokes when
4459 the normal layout translates alphabetic
4460 characters to non-ascii characters. */
4461 if (!modifier_set (VK_SHIFT))
4462 wParam += ('a' - 'A');
4463 msg = WM_CHAR;
4464 }
4465 else
4466 {
4467 /* Try to handle other keystrokes by determining the
4468 base character (ie. translating the base key plus
4469 shift modifier). */
4470 int add;
4471 int isdead = 0;
4472 KEY_EVENT_RECORD key;
7d0393cf 4473
ccc2d29c
GV
4474 key.bKeyDown = TRUE;
4475 key.wRepeatCount = 1;
4476 key.wVirtualKeyCode = wParam;
4477 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4478 key.uChar.AsciiChar = 0;
adcc3809 4479 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4480
4481 add = w32_kbd_patch_key (&key);
4482 /* 0 means an unrecognised keycode, negative means
4483 dead key. Ignore both. */
4484 while (--add >= 0)
4485 {
4486 /* Forward asciified character sequence. */
4487 post_character_message
4488 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4489 w32_get_key_modifiers (wParam, lParam));
4490 w32_kbd_patch_key (&key);
4491 }
4492 return 0;
4493 }
4494 }
4495 else
4496 {
4497 /* Let TranslateMessage handle everything else. */
4498 windows_translate = 1;
4499 }
4500 }
4501 }
a1a80b40 4502
adcc3809 4503 translate:
84fb1139
KH
4504 if (windows_translate)
4505 {
e9e23e23 4506 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4507
e9e23e23
GV
4508 windows_msg.time = GetMessageTime ();
4509 TranslateMessage (&windows_msg);
84fb1139
KH
4510 goto dflt;
4511 }
4512
ee78dc32 4513 /* Fall through */
7d0393cf 4514
ee78dc32
GV
4515 case WM_SYSCHAR:
4516 case WM_CHAR:
ccc2d29c
GV
4517 post_character_message (hwnd, msg, wParam, lParam,
4518 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4519 break;
da36a4d6 4520
5ac45f98
GV
4521 /* Simulate middle mouse button events when left and right buttons
4522 are used together, but only if user has two button mouse. */
ee78dc32 4523 case WM_LBUTTONDOWN:
5ac45f98 4524 case WM_RBUTTONDOWN:
7ce9aaca 4525 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4526 goto handle_plain_button;
4527
4528 {
4529 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4530 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4531
3cb20f4a
RS
4532 if (button_state & this)
4533 return 0;
5ac45f98
GV
4534
4535 if (button_state == 0)
4536 SetCapture (hwnd);
4537
4538 button_state |= this;
4539
4540 if (button_state & other)
4541 {
84fb1139 4542 if (mouse_button_timer)
5ac45f98 4543 {
84fb1139
KH
4544 KillTimer (hwnd, mouse_button_timer);
4545 mouse_button_timer = 0;
5ac45f98
GV
4546
4547 /* Generate middle mouse event instead. */
4548 msg = WM_MBUTTONDOWN;
4549 button_state |= MMOUSE;
4550 }
4551 else if (button_state & MMOUSE)
4552 {
4553 /* Ignore button event if we've already generated a
4554 middle mouse down event. This happens if the
4555 user releases and press one of the two buttons
4556 after we've faked a middle mouse event. */
4557 return 0;
4558 }
4559 else
4560 {
4561 /* Flush out saved message. */
84fb1139 4562 post_msg (&saved_mouse_button_msg);
5ac45f98 4563 }
fbd6baed 4564 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4565 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4566
4567 /* Clear message buffer. */
84fb1139 4568 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4569 }
4570 else
4571 {
4572 /* Hold onto message for now. */
84fb1139 4573 mouse_button_timer =
adcc3809
GV
4574 SetTimer (hwnd, MOUSE_BUTTON_ID,
4575 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4576 saved_mouse_button_msg.msg.hwnd = hwnd;
4577 saved_mouse_button_msg.msg.message = msg;
4578 saved_mouse_button_msg.msg.wParam = wParam;
4579 saved_mouse_button_msg.msg.lParam = lParam;
4580 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4581 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4582 }
4583 }
4584 return 0;
4585
ee78dc32 4586 case WM_LBUTTONUP:
5ac45f98 4587 case WM_RBUTTONUP:
7ce9aaca 4588 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4589 goto handle_plain_button;
4590
4591 {
4592 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4593 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4594
3cb20f4a
RS
4595 if ((button_state & this) == 0)
4596 return 0;
5ac45f98
GV
4597
4598 button_state &= ~this;
4599
4600 if (button_state & MMOUSE)
4601 {
4602 /* Only generate event when second button is released. */
4603 if ((button_state & other) == 0)
4604 {
4605 msg = WM_MBUTTONUP;
4606 button_state &= ~MMOUSE;
4607
4608 if (button_state) abort ();
4609 }
4610 else
4611 return 0;
4612 }
4613 else
4614 {
4615 /* Flush out saved message if necessary. */
84fb1139 4616 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4617 {
84fb1139 4618 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4619 }
4620 }
fbd6baed 4621 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4622 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4623
4624 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4625 saved_mouse_button_msg.msg.hwnd = 0;
4626 KillTimer (hwnd, mouse_button_timer);
4627 mouse_button_timer = 0;
5ac45f98
GV
4628
4629 if (button_state == 0)
4630 ReleaseCapture ();
4631 }
4632 return 0;
4633
74214547
JR
4634 case WM_XBUTTONDOWN:
4635 case WM_XBUTTONUP:
4636 if (w32_pass_extra_mouse_buttons_to_system)
4637 goto dflt;
4638 /* else fall through and process them. */
ee78dc32
GV
4639 case WM_MBUTTONDOWN:
4640 case WM_MBUTTONUP:
5ac45f98 4641 handle_plain_button:
ee78dc32
GV
4642 {
4643 BOOL up;
1edf84e7 4644 int button;
ee78dc32 4645
74214547 4646 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
4647 {
4648 if (up) ReleaseCapture ();
4649 else SetCapture (hwnd);
7d0393cf 4650 button = (button == 0) ? LMOUSE :
1edf84e7
GV
4651 ((button == 1) ? MMOUSE : RMOUSE);
4652 if (up)
4653 button_state &= ~button;
4654 else
4655 button_state |= button;
ee78dc32
GV
4656 }
4657 }
7d0393cf 4658
fbd6baed 4659 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4660 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
4661
4662 /* Need to return true for XBUTTON messages, false for others,
4663 to indicate that we processed the message. */
4664 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 4665
5ac45f98 4666 case WM_MOUSEMOVE:
9eb16b62
JR
4667 /* If the mouse has just moved into the frame, start tracking
4668 it, so we will be notified when it leaves the frame. Mouse
4669 tracking only works under W98 and NT4 and later. On earlier
4670 versions, there is no way of telling when the mouse leaves the
4671 frame, so we just have to put up with help-echo and mouse
4672 highlighting remaining while the frame is not active. */
4673 if (track_mouse_event_fn && !track_mouse_window)
4674 {
4675 TRACKMOUSEEVENT tme;
4676 tme.cbSize = sizeof (tme);
4677 tme.dwFlags = TME_LEAVE;
4678 tme.hwndTrack = hwnd;
4679
4680 track_mouse_event_fn (&tme);
4681 track_mouse_window = hwnd;
4682 }
4683 case WM_VSCROLL:
fbd6baed 4684 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4685 || (msg == WM_MOUSEMOVE && button_state == 0))
4686 {
fbd6baed 4687 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4688 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4689 return 0;
4690 }
7d0393cf 4691
84fb1139
KH
4692 /* Hang onto mouse move and scroll messages for a bit, to avoid
4693 sending such events to Emacs faster than it can process them.
4694 If we get more events before the timer from the first message
4695 expires, we just replace the first message. */
4696
4697 if (saved_mouse_move_msg.msg.hwnd == 0)
4698 mouse_move_timer =
adcc3809
GV
4699 SetTimer (hwnd, MOUSE_MOVE_ID,
4700 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4701
4702 /* Hold onto message for now. */
4703 saved_mouse_move_msg.msg.hwnd = hwnd;
4704 saved_mouse_move_msg.msg.message = msg;
4705 saved_mouse_move_msg.msg.wParam = wParam;
4706 saved_mouse_move_msg.msg.lParam = lParam;
4707 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4708 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
7d0393cf 4709
84fb1139
KH
4710 return 0;
4711
1edf84e7
GV
4712 case WM_MOUSEWHEEL:
4713 wmsg.dwModifiers = w32_get_modifiers ();
4714 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4715 return 0;
4716
cb9e33d4
RS
4717 case WM_DROPFILES:
4718 wmsg.dwModifiers = w32_get_modifiers ();
4719 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4720 return 0;
4721
84fb1139
KH
4722 case WM_TIMER:
4723 /* Flush out saved messages if necessary. */
4724 if (wParam == mouse_button_timer)
5ac45f98 4725 {
84fb1139
KH
4726 if (saved_mouse_button_msg.msg.hwnd)
4727 {
4728 post_msg (&saved_mouse_button_msg);
4729 saved_mouse_button_msg.msg.hwnd = 0;
4730 }
4731 KillTimer (hwnd, mouse_button_timer);
4732 mouse_button_timer = 0;
4733 }
4734 else if (wParam == mouse_move_timer)
4735 {
4736 if (saved_mouse_move_msg.msg.hwnd)
4737 {
4738 post_msg (&saved_mouse_move_msg);
4739 saved_mouse_move_msg.msg.hwnd = 0;
4740 }
4741 KillTimer (hwnd, mouse_move_timer);
4742 mouse_move_timer = 0;
5ac45f98 4743 }
48094ace
JR
4744 else if (wParam == menu_free_timer)
4745 {
4746 KillTimer (hwnd, menu_free_timer);
4747 menu_free_timer = 0;
27605fa7 4748 f = x_window_to_frame (dpyinfo, hwnd);
48094ace
JR
4749 if (!f->output_data.w32->menu_command_in_progress)
4750 {
4751 /* Free memory used by owner-drawn and help-echo strings. */
4752 w32_free_menu_strings (hwnd);
4753 f->output_data.w32->menubar_active = 0;
4754 }
4755 }
5ac45f98 4756 return 0;
7d0393cf 4757
84fb1139
KH
4758 case WM_NCACTIVATE:
4759 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4760 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4761 The only indication we get that something happened is receiving
4762 this message afterwards. So this is a good time to reset our
4763 keyboard modifiers' state. */
4764 reset_modifiers ();
4765 goto dflt;
da36a4d6 4766
1edf84e7 4767 case WM_INITMENU:
487163ac
AI
4768 button_state = 0;
4769 ReleaseCapture ();
1edf84e7
GV
4770 /* We must ensure menu bar is fully constructed and up to date
4771 before allowing user interaction with it. To achieve this
4772 we send this message to the lisp thread and wait for a
4773 reply (whose value is not actually needed) to indicate that
4774 the menu bar is now ready for use, so we can now return.
4775
4776 To remain responsive in the meantime, we enter a nested message
4777 loop that can process all other messages.
4778
4779 However, we skip all this if the message results from calling
4780 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4781 thread a message because it is blocked on us at this point. We
4782 set menubar_active before calling TrackPopupMenu to indicate
4783 this (there is no possibility of confusion with real menubar
4784 being active). */
4785
4786 f = x_window_to_frame (dpyinfo, hwnd);
4787 if (f
4788 && (f->output_data.w32->menubar_active
4789 /* We can receive this message even in the absence of a
4790 menubar (ie. when the system menu is activated) - in this
4791 case we do NOT want to forward the message, otherwise it
4792 will cause the menubar to suddenly appear when the user
4793 had requested it to be turned off! */
4794 || f->output_data.w32->menubar_widget == NULL))
4795 return 0;
4796
4797 {
4798 deferred_msg msg_buf;
4799
4800 /* Detect if message has already been deferred; in this case
4801 we cannot return any sensible value to ignore this. */
4802 if (find_deferred_msg (hwnd, msg) != NULL)
4803 abort ();
4804
4805 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4806 }
4807
4808 case WM_EXITMENULOOP:
4809 f = x_window_to_frame (dpyinfo, hwnd);
4810
48094ace
JR
4811 /* If a menu command is not already in progress, check again
4812 after a short delay, since Windows often (always?) sends the
4813 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4814 if (f && !f->output_data.w32->menu_command_in_progress)
4815 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
1edf84e7
GV
4816 goto dflt;
4817
126f2e35 4818 case WM_MENUSELECT:
4e3a1c61
JR
4819 /* Direct handling of help_echo in menus. Should be safe now
4820 that we generate the help_echo by placing a help event in the
4821 keyboard buffer. */
ca56d953 4822 {
ca56d953
JR
4823 HMENU menu = (HMENU) lParam;
4824 UINT menu_item = (UINT) LOWORD (wParam);
4825 UINT flags = (UINT) HIWORD (wParam);
4826
4e3a1c61 4827 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4828 }
126f2e35
JR
4829 return 0;
4830
87996783
GV
4831 case WM_MEASUREITEM:
4832 f = x_window_to_frame (dpyinfo, hwnd);
4833 if (f)
4834 {
4835 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4836
4837 if (pMis->CtlType == ODT_MENU)
4838 {
4839 /* Work out dimensions for popup menu titles. */
4840 char * title = (char *) pMis->itemData;
4841 HDC hdc = GetDC (hwnd);
4842 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4843 LOGFONT menu_logfont;
4844 HFONT old_font;
4845 SIZE size;
4846
4847 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4848 menu_logfont.lfWeight = FW_BOLD;
4849 menu_font = CreateFontIndirect (&menu_logfont);
4850 old_font = SelectObject (hdc, menu_font);
4851
dfff8a69
JR
4852 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4853 if (title)
4854 {
4855 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4856 pMis->itemWidth = size.cx;
4857 if (pMis->itemHeight < size.cy)
4858 pMis->itemHeight = size.cy;
4859 }
4860 else
4861 pMis->itemWidth = 0;
87996783
GV
4862
4863 SelectObject (hdc, old_font);
4864 DeleteObject (menu_font);
4865 ReleaseDC (hwnd, hdc);
4866 return TRUE;
4867 }
4868 }
4869 return 0;
4870
4871 case WM_DRAWITEM:
4872 f = x_window_to_frame (dpyinfo, hwnd);
4873 if (f)
4874 {
4875 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4876
4877 if (pDis->CtlType == ODT_MENU)
4878 {
4879 /* Draw popup menu title. */
4880 char * title = (char *) pDis->itemData;
212da13b
JR
4881 if (title)
4882 {
4883 HDC hdc = pDis->hDC;
4884 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4885 LOGFONT menu_logfont;
4886 HFONT old_font;
4887
4888 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4889 menu_logfont.lfWeight = FW_BOLD;
4890 menu_font = CreateFontIndirect (&menu_logfont);
4891 old_font = SelectObject (hdc, menu_font);
4892
4893 /* Always draw title as if not selected. */
4894 ExtTextOut (hdc,
4895 pDis->rcItem.left
4896 + GetSystemMetrics (SM_CXMENUCHECK),
4897 pDis->rcItem.top,
4898 ETO_OPAQUE, &pDis->rcItem,
4899 title, strlen (title), NULL);
4900
4901 SelectObject (hdc, old_font);
4902 DeleteObject (menu_font);
4903 }
87996783
GV
4904 return TRUE;
4905 }
4906 }
4907 return 0;
4908
1edf84e7
GV
4909#if 0
4910 /* Still not right - can't distinguish between clicks in the
4911 client area of the frame from clicks forwarded from the scroll
4912 bars - may have to hook WM_NCHITTEST to remember the mouse
4913 position and then check if it is in the client area ourselves. */
4914 case WM_MOUSEACTIVATE:
4915 /* Discard the mouse click that activates a frame, allowing the
4916 user to click anywhere without changing point (or worse!).
4917 Don't eat mouse clicks on scrollbars though!! */
4918 if (LOWORD (lParam) == HTCLIENT )
4919 return MA_ACTIVATEANDEAT;
4920 goto dflt;
4921#endif
4922
9eb16b62
JR
4923 case WM_MOUSELEAVE:
4924 /* No longer tracking mouse. */
4925 track_mouse_window = NULL;
4926
1edf84e7 4927 case WM_ACTIVATEAPP:
ccc2d29c 4928 case WM_ACTIVATE:
1edf84e7
GV
4929 case WM_WINDOWPOSCHANGED:
4930 case WM_SHOWWINDOW:
4931 /* Inform lisp thread that a frame might have just been obscured
4932 or exposed, so should recheck visibility of all frames. */
4933 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4934 goto dflt;
4935
da36a4d6 4936 case WM_SETFOCUS:
f60ae425
BK
4937 /*
4938 Reinitialize the function pointer track_mouse_event_fn here.
4939 This is required even though it is initialized in syms_of_w32fns
4940 which is called in main (emacs.c).
4941 Reinitialize the function pointer track_mouse_event_fn here.
4942 Even though this function pointer is initialized in
4943 syms_of_w32fns which is called from main (emacs.c),
4944 we need to initialize it again here in order to prevent
4945 a crash that occurs in Windows 9x (possibly only when Emacs
4946 was built on Windows NT / 2000 / XP?) when handling the
4947 WM_MOUSEMOVE message.
4948 The crash occurs when attempting to call the Win32 API
4949 function TrackMouseEvent through the function pointer.
4950 It appears as if the function pointer that is obtained when
4951 syms_of_w32fns is called from main is no longer valid
4952 (possibly due to DLL relocation?).
4953 To resolve this issue, I have placed a call to reinitialize
4954 this function pointer here because this message gets received
4955 when the Emacs window gains focus.
4956 */
4957 track_mouse_event_fn =
4958 (TrackMouseEvent_Proc) GetProcAddress (
4959 GetModuleHandle ("user32.dll"),
4960 "TrackMouseEvent");
adcc3809
GV
4961 dpyinfo->faked_key = 0;
4962 reset_modifiers ();
ccc2d29c
GV
4963 register_hot_keys (hwnd);
4964 goto command;
8681157a 4965 case WM_KILLFOCUS:
ccc2d29c 4966 unregister_hot_keys (hwnd);
487163ac
AI
4967 button_state = 0;
4968 ReleaseCapture ();
65906840
JR
4969 /* Relinquish the system caret. */
4970 if (w32_system_caret_hwnd)
4971 {
93f2ca61 4972 w32_visible_system_caret_hwnd = NULL;
d285988b
JR
4973 w32_system_caret_hwnd = NULL;
4974 DestroyCaret ();
65906840 4975 }
48094ace
JR
4976 goto command;
4977 case WM_COMMAND:
4978 f = x_window_to_frame (dpyinfo, hwnd);
4979 if (f && HIWORD (wParam) == 0)
4980 {
4981 f->output_data.w32->menu_command_in_progress = 1;
4982 if (menu_free_timer)
4983 {
4984 KillTimer (hwnd, menu_free_timer);
7d0393cf 4985 menu_free_timer = 0;
48094ace
JR
4986 }
4987 }
ee78dc32
GV
4988 case WM_MOVE:
4989 case WM_SIZE:
ccc2d29c 4990 command:
fbd6baed 4991 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4992 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4993 goto dflt;
8847d890
RS
4994
4995 case WM_CLOSE:
fbd6baed 4996 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4997 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4998 return 0;
4999
ee78dc32 5000 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
5001 /* Don't restrict the sizing of tip frames. */
5002 if (hwnd == tip_window)
5003 return 0;
ee78dc32
GV
5004 {
5005 WINDOWPLACEMENT wp;
5006 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
5007
5008 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32 5009 GetWindowPlacement (hwnd, &wp);
7d0393cf 5010
1edf84e7 5011 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
5012 {
5013 RECT rect;
5014 int wdiff;
5015 int hdiff;
1edf84e7
GV
5016 DWORD font_width;
5017 DWORD line_height;
5018 DWORD internal_border;
5019 DWORD scrollbar_extra;
ee78dc32 5020 RECT wr;
7d0393cf 5021
5ac45f98 5022 wp.length = sizeof(wp);
ee78dc32 5023 GetWindowRect (hwnd, &wr);
7d0393cf 5024
3c190163 5025 enter_crit ();
7d0393cf 5026
1edf84e7
GV
5027 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5028 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5029 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5030 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
7d0393cf 5031
3c190163 5032 leave_crit ();
7d0393cf 5033
ee78dc32 5034 memset (&rect, 0, sizeof (rect));
7d0393cf 5035 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
ee78dc32
GV
5036 GetMenu (hwnd) != NULL);
5037
1edf84e7
GV
5038 /* Force width and height of client area to be exact
5039 multiples of the character cell dimensions. */
5040 wdiff = (lppos->cx - (rect.right - rect.left)
5041 - 2 * internal_border - scrollbar_extra)
5042 % font_width;
5043 hdiff = (lppos->cy - (rect.bottom - rect.top)
5044 - 2 * internal_border)
5045 % line_height;
7d0393cf 5046
ee78dc32
GV
5047 if (wdiff || hdiff)
5048 {
7d0393cf
JB
5049 /* For right/bottom sizing we can just fix the sizes.
5050 However for top/left sizing we will need to fix the X
ee78dc32 5051 and Y positions as well. */
7d0393cf 5052
ee78dc32
GV
5053 lppos->cx -= wdiff;
5054 lppos->cy -= hdiff;
7d0393cf
JB
5055
5056 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 5057 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
5058 {
5059 if (lppos->x != wr.left || lppos->y != wr.top)
5060 {
5061 lppos->x += wdiff;
5062 lppos->y += hdiff;
5063 }
5064 else
5065 {
5066 lppos->flags |= SWP_NOMOVE;
5067 }
5068 }
7d0393cf 5069
1edf84e7 5070 return 0;
ee78dc32
GV
5071 }
5072 }
5073 }
7d0393cf 5074
ee78dc32 5075 goto dflt;
1edf84e7 5076
b1f918f8
GV
5077 case WM_GETMINMAXINFO:
5078 /* Hack to correct bug that allows Emacs frames to be resized
5079 below the Minimum Tracking Size. */
5080 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
5081 /* Hack to allow resizing the Emacs frame above the screen size.
5082 Note that Windows 9x limits coordinates to 16-bits. */
5083 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5084 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
5085 return 0;
5086
1edf84e7
GV
5087 case WM_EMACS_CREATESCROLLBAR:
5088 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5089 (struct scroll_bar *) lParam);
5090
5ac45f98 5091 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
5092 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5093
dfdb4047 5094 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
5095 {
5096 HWND foreground_window;
5097 DWORD foreground_thread, retval;
5098
5099 /* On NT 5.0, and apparently Windows 98, it is necessary to
5100 attach to the thread that currently has focus in order to
5101 pull the focus away from it. */
5102 foreground_window = GetForegroundWindow ();
5103 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5104 if (!foreground_window
5105 || foreground_thread == GetCurrentThreadId ()
5106 || !AttachThreadInput (GetCurrentThreadId (),
5107 foreground_thread, TRUE))
5108 foreground_thread = 0;
5109
5110 retval = SetForegroundWindow ((HWND) wParam);
5111
5112 /* Detach from the previous foreground thread. */
5113 if (foreground_thread)
5114 AttachThreadInput (GetCurrentThreadId (),
5115 foreground_thread, FALSE);
5116
5117 return retval;
5118 }
dfdb4047 5119
5ac45f98
GV
5120 case WM_EMACS_SETWINDOWPOS:
5121 {
1edf84e7
GV
5122 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5123 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5124 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5125 }
1edf84e7 5126
ee78dc32 5127 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5128 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5129 return DestroyWindow ((HWND) wParam);
5130
93f2ca61
JR
5131 case WM_EMACS_HIDE_CARET:
5132 return HideCaret (hwnd);
5133
5134 case WM_EMACS_SHOW_CARET:
5135 return ShowCaret (hwnd);
5136
65906840
JR
5137 case WM_EMACS_DESTROY_CARET:
5138 w32_system_caret_hwnd = NULL;
93f2ca61 5139 w32_visible_system_caret_hwnd = NULL;
65906840
JR
5140 return DestroyCaret ();
5141
5142 case WM_EMACS_TRACK_CARET:
5143 /* If there is currently no system caret, create one. */
5144 if (w32_system_caret_hwnd == NULL)
5145 {
93f2ca61
JR
5146 /* Use the default caret width, and avoid changing it
5147 unneccesarily, as it confuses screen reader software. */
65906840 5148 w32_system_caret_hwnd = hwnd;
93f2ca61 5149 CreateCaret (hwnd, NULL, 0,
65906840
JR
5150 w32_system_caret_height);
5151 }
7d0393cf 5152
93f2ca61
JR
5153 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5154 return 0;
5155 /* Ensure visible caret gets turned on when requested. */
5156 else if (w32_use_visible_system_caret
5157 && w32_visible_system_caret_hwnd != hwnd)
5158 {
5159 w32_visible_system_caret_hwnd = hwnd;
5160 return ShowCaret (hwnd);
5161 }
5162 /* Ensure visible caret gets turned off when requested. */
5163 else if (!w32_use_visible_system_caret
5164 && w32_visible_system_caret_hwnd)
5165 {
5166 w32_visible_system_caret_hwnd = NULL;
5167 return HideCaret (hwnd);
5168 }
5169 else
5170 return 1;
65906840 5171
1edf84e7
GV
5172 case WM_EMACS_TRACKPOPUPMENU:
5173 {
5174 UINT flags;
5175 POINT *pos;
5176 int retval;
5177 pos = (POINT *)lParam;
5178 flags = TPM_CENTERALIGN;
5179 if (button_state & LMOUSE)
5180 flags |= TPM_LEFTBUTTON;
5181 else if (button_state & RMOUSE)
5182 flags |= TPM_RIGHTBUTTON;
7d0393cf 5183
87996783
GV
5184 /* Remember we did a SetCapture on the initial mouse down event,
5185 so for safety, we make sure the capture is cancelled now. */
5186 ReleaseCapture ();
490822ff 5187 button_state = 0;
87996783 5188
1edf84e7
GV
5189 /* Use menubar_active to indicate that WM_INITMENU is from
5190 TrackPopupMenu below, and should be ignored. */
5191 f = x_window_to_frame (dpyinfo, hwnd);
5192 if (f)
5193 f->output_data.w32->menubar_active = 1;
7d0393cf
JB
5194
5195 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
1edf84e7
GV
5196 0, hwnd, NULL))
5197 {
5198 MSG amsg;
5199 /* Eat any mouse messages during popupmenu */
5200 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5201 PM_REMOVE));
5202 /* Get the menu selection, if any */
5203 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5204 {
5205 retval = LOWORD (amsg.wParam);
5206 }
5207 else
5208 {
5209 retval = 0;
5210 }
1edf84e7
GV
5211 }
5212 else
5213 {
5214 retval = -1;
5215 }
5216
5217 return retval;
5218 }
5219
ee78dc32 5220 default:
93fbe8b7
GV
5221 /* Check for messages registered at runtime. */
5222 if (msg == msh_mousewheel)
5223 {
5224 wmsg.dwModifiers = w32_get_modifiers ();
5225 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5226 return 0;
5227 }
7d0393cf 5228
ee78dc32
GV
5229 dflt:
5230 return DefWindowProc (hwnd, msg, wParam, lParam);
5231 }
7d0393cf 5232
1edf84e7
GV
5233
5234 /* The most common default return code for handled messages is 0. */
5235 return 0;
ee78dc32
GV
5236}
5237
7d0393cf 5238void
ee78dc32
GV
5239my_create_window (f)
5240 struct frame * f;
5241{
5242 MSG msg;
5243
1edf84e7
GV
5244 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5245 abort ();
ee78dc32
GV
5246 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5247}
5248
ca56d953
JR
5249
5250/* Create a tooltip window. Unlike my_create_window, we do not do this
5251 indirectly via the Window thread, as we do not need to process Window
5252 messages for the tooltip. Creating tooltips indirectly also creates
5253 deadlocks when tooltips are created for menu items. */
7d0393cf 5254void
ca56d953
JR
5255my_create_tip_window (f)
5256 struct frame *f;
5257{
bfd6edcc 5258 RECT rect;
ca56d953 5259
bfd6edcc
JR
5260 rect.left = rect.top = 0;
5261 rect.right = PIXEL_WIDTH (f);
5262 rect.bottom = PIXEL_HEIGHT (f);
5263
5264 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5265 FRAME_EXTERNAL_MENU_BAR (f));
5266
5267 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5268 = CreateWindow (EMACS_CLASS,
5269 f->namebuf,
5270 f->output_data.w32->dwStyle,
5271 f->output_data.w32->left_pos,
5272 f->output_data.w32->top_pos,
bfd6edcc
JR
5273 rect.right - rect.left,
5274 rect.bottom - rect.top,
ca56d953
JR
5275 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5276 NULL,
5277 hinst,
5278 NULL);
5279
bfd6edcc 5280 if (tip_window)
ca56d953 5281 {
bfd6edcc
JR
5282 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5283 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5284 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5285 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5286
5287 /* Tip frames have no scrollbars. */
5288 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5289
5290 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5291 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5292 }
5293}
5294
5295
fbd6baed 5296/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5297
5298static void
fbd6baed 5299w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5300 struct frame *f;
5301 long window_prompting;
5302 int minibuffer_only;
5303{
5304 BLOCK_INPUT;
5305
5306 /* Use the resource name as the top-level window name
5307 for looking up resources. Make a non-Lisp copy
5308 for the window manager, so GC relocation won't bother it.
5309
5310 Elsewhere we specify the window name for the window manager. */
7d0393cf 5311
ee78dc32 5312 {
d5db4077 5313 char *str = (char *) SDATA (Vx_resource_name);
ee78dc32
GV
5314 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5315 strcpy (f->namebuf, str);
5316 }
5317
5318 my_create_window (f);
5319
5320 validate_x_resource_name ();
5321
5322 /* x_set_name normally ignores requests to set the name if the
5323 requested name is the same as the current name. This is the one
5324 place where that assumption isn't correct; f->name is set, but
5325 the server hasn't been told. */
5326 {
5327 Lisp_Object name;
5328 int explicit = f->explicit_name;
5329
5330 f->explicit_name = 0;
5331 name = f->name;
5332 f->name = Qnil;
5333 x_set_name (f, name, explicit);
5334 }
5335
5336 UNBLOCK_INPUT;
5337
5338 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5339 initialize_frame_menubar (f);
5340
fbd6baed 5341 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5342 error ("Unable to create window");
5343}
5344
5345/* Handle the icon stuff for this window. Perhaps later we might
5346 want an x_set_icon_position which can be called interactively as
5347 well. */
5348
5349static void
5350x_icon (f, parms)
5351 struct frame *f;
5352 Lisp_Object parms;
5353{
5354 Lisp_Object icon_x, icon_y;
5355
e9e23e23 5356 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5357 icons in the tray. */
6fc2811b
JR
5358 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5359 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5360 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5361 {
b7826503
PJ
5362 CHECK_NUMBER (icon_x);
5363 CHECK_NUMBER (icon_y);
ee78dc32
GV
5364 }
5365 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5366 error ("Both left and top icon corners of icon must be specified");
5367
5368 BLOCK_INPUT;
5369
5370 if (! EQ (icon_x, Qunbound))
5371 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5372
1edf84e7
GV
5373#if 0 /* TODO */
5374 /* Start up iconic or window? */
5375 x_wm_set_window_state
6fc2811b 5376 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5377 ? IconicState
5378 : NormalState));
5379
d5db4077 5380 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
1edf84e7 5381 ? f->icon_name
d5db4077 5382 : f->name)));
1edf84e7
GV
5383#endif
5384
ee78dc32
GV
5385 UNBLOCK_INPUT;
5386}
5387
6fc2811b
JR
5388
5389static void
5390x_make_gc (f)
5391 struct frame *f;
5392{
5393 XGCValues gc_values;
5394
5395 BLOCK_INPUT;
5396
5397 /* Create the GC's of this frame.
5398 Note that many default values are used. */
5399
5400 /* Normal video */
5401 gc_values.font = f->output_data.w32->font;
5402
5403 /* Cursor has cursor-color background, background-color foreground. */
5404 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5405 gc_values.background = f->output_data.w32->cursor_pixel;
5406 f->output_data.w32->cursor_gc
5407 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5408 (GCFont | GCForeground | GCBackground),
5409 &gc_values);
5410
5411 /* Reliefs. */
5412 f->output_data.w32->white_relief.gc = 0;
5413 f->output_data.w32->black_relief.gc = 0;
5414
5415 UNBLOCK_INPUT;
5416}
5417
5418
937e601e
AI
5419/* Handler for signals raised during x_create_frame and
5420 x_create_top_frame. FRAME is the frame which is partially
5421 constructed. */
5422
5423static Lisp_Object
5424unwind_create_frame (frame)
5425 Lisp_Object frame;
5426{
5427 struct frame *f = XFRAME (frame);
5428
5429 /* If frame is ``official'', nothing to do. */
5430 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5431 {
5432#ifdef GLYPH_DEBUG
5433 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5434#endif
7d0393cf 5435
937e601e
AI
5436 x_free_frame_resources (f);
5437
5438 /* Check that reference counts are indeed correct. */
5439 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5440 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5441
5442 return Qt;
937e601e 5443 }
7d0393cf 5444
937e601e
AI
5445 return Qnil;
5446}
5447
5448
ee78dc32
GV
5449DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5450 1, 1, 0,
74e1aeec
JR
5451 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5452Returns an Emacs frame object.
5453ALIST is an alist of frame parameters.
5454If the parameters specify that the frame should not have a minibuffer,
5455and do not specify a specific minibuffer window to use,
5456then `default-minibuffer-frame' must be a frame whose minibuffer can
5457be shared by the new frame.
5458
5459This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5460 (parms)
5461 Lisp_Object parms;
5462{
5463 struct frame *f;
5464 Lisp_Object frame, tem;
5465 Lisp_Object name;
5466 int minibuffer_only = 0;
5467 long window_prompting = 0;
5468 int width, height;
331379bf 5469 int count = SPECPDL_INDEX ();
1edf84e7 5470 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5471 Lisp_Object display;
6fc2811b 5472 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5473 Lisp_Object parent;
5474 struct kboard *kb;
5475
4587b026
GV
5476 check_w32 ();
5477
ee78dc32
GV
5478 /* Use this general default value to start with
5479 until we know if this frame has a specified name. */
5480 Vx_resource_name = Vinvocation_name;
5481
6fc2811b 5482 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5483 if (EQ (display, Qunbound))
5484 display = Qnil;
5485 dpyinfo = check_x_display_info (display);
5486#ifdef MULTI_KBOARD
5487 kb = dpyinfo->kboard;
5488#else
5489 kb = &the_only_kboard;
5490#endif
5491
6fc2811b 5492 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5493 if (!STRINGP (name)
5494 && ! EQ (name, Qunbound)
5495 && ! NILP (name))
5496 error ("Invalid frame name--not a string or nil");
5497
5498 if (STRINGP (name))
5499 Vx_resource_name = name;
5500
5501 /* See if parent window is specified. */
6fc2811b 5502 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5503 if (EQ (parent, Qunbound))
5504 parent = Qnil;
5505 if (! NILP (parent))
b7826503 5506 CHECK_NUMBER (parent);
ee78dc32 5507
1edf84e7
GV
5508 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5509 /* No need to protect DISPLAY because that's not used after passing
5510 it to make_frame_without_minibuffer. */
5511 frame = Qnil;
5512 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5513 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5514 RES_TYPE_SYMBOL);
ee78dc32
GV
5515 if (EQ (tem, Qnone) || NILP (tem))
5516 f = make_frame_without_minibuffer (Qnil, kb, display);
5517 else if (EQ (tem, Qonly))
5518 {
5519 f = make_minibuffer_frame ();
5520 minibuffer_only = 1;
5521 }
5522 else if (WINDOWP (tem))
5523 f = make_frame_without_minibuffer (tem, kb, display);
5524 else
5525 f = make_frame (1);
5526
1edf84e7
GV
5527 XSETFRAME (frame, f);
5528
ee78dc32
GV
5529 /* Note that Windows does support scroll bars. */
5530 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5531 /* By default, make scrollbars the system standard width. */
5532 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5533
fbd6baed 5534 f->output_method = output_w32;
6fc2811b
JR
5535 f->output_data.w32 =
5536 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5537 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5538 FRAME_FONTSET (f) = -1;
937e601e 5539 record_unwind_protect (unwind_create_frame, frame);
4587b026 5540
1edf84e7 5541 f->icon_name
6fc2811b 5542 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5543 if (! STRINGP (f->icon_name))
5544 f->icon_name = Qnil;
5545
fbd6baed 5546/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5547#ifdef MULTI_KBOARD
5548 FRAME_KBOARD (f) = kb;
5549#endif
5550
5551 /* Specify the parent under which to make this window. */
5552
5553 if (!NILP (parent))
5554 {
1660f34a 5555 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5556 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5557 }
5558 else
5559 {
fbd6baed
GV
5560 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5561 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5562 }
5563
ee78dc32
GV
5564 /* Set the name; the functions to which we pass f expect the name to
5565 be set. */
5566 if (EQ (name, Qunbound) || NILP (name))
5567 {
fbd6baed 5568 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5569 f->explicit_name = 0;
5570 }
5571 else
5572 {
5573 f->name = name;
5574 f->explicit_name = 1;
5575 /* use the frame's title when getting resources for this frame. */
5576 specbind (Qx_resource_name, name);
5577 }
5578
5579 /* Extract the window parameters from the supplied values
5580 that are needed to determine window geometry. */
5581 {
5582 Lisp_Object font;
5583
6fc2811b
JR
5584 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5585
ee78dc32
GV
5586 BLOCK_INPUT;
5587 /* First, try whatever font the caller has specified. */
5588 if (STRINGP (font))
4587b026
GV
5589 {
5590 tem = Fquery_fontset (font, Qnil);
5591 if (STRINGP (tem))
d5db4077 5592 font = x_new_fontset (f, SDATA (tem));
4587b026 5593 else
d5db4077 5594 font = x_new_font (f, SDATA (font));
4587b026 5595 }
ee78dc32
GV
5596 /* Try out a font which we hope has bold and italic variations. */
5597 if (!STRINGP (font))
e39649be 5598 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5599 if (! STRINGP (font))
6fc2811b 5600 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5601 /* If those didn't work, look for something which will at least work. */
5602 if (! STRINGP (font))
6fc2811b 5603 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5604 UNBLOCK_INPUT;
5605 if (! STRINGP (font))
1edf84e7 5606 font = build_string ("Fixedsys");
ee78dc32 5607
7d0393cf 5608 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5609 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5610 }
5611
5612 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5613 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5614 /* This defaults to 2 in order to match xterm. We recognize either
5615 internalBorderWidth or internalBorder (which is what xterm calls
5616 it). */
5617 if (NILP (Fassq (Qinternal_border_width, parms)))
5618 {
5619 Lisp_Object value;
5620
6fc2811b 5621 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5622 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5623 if (! EQ (value, Qunbound))
5624 parms = Fcons (Fcons (Qinternal_border_width, value),
5625 parms);
5626 }
1edf84e7 5627 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5628 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5629 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5630 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5631 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5632
5633 /* Also do the stuff which must be set before the window exists. */
5634 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5635 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5636 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5637 "background", "Background", RES_TYPE_STRING);
ee78dc32 5638 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5639 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5640 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5641 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5642 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5643 "borderColor", "BorderColor", RES_TYPE_STRING);
5644 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5645 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5646 x_default_parameter (f, parms, Qline_spacing, Qnil,
5647 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5648 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5649 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5650 x_default_parameter (f, parms, Qright_fringe, Qnil,
5651 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5652
ee78dc32 5653
6fc2811b
JR
5654 /* Init faces before x_default_parameter is called for scroll-bar
5655 parameters because that function calls x_set_scroll_bar_width,
5656 which calls change_frame_size, which calls Fset_window_buffer,
5657 which runs hooks, which call Fvertical_motion. At the end, we
5658 end up in init_iterator with a null face cache, which should not
5659 happen. */
5660 init_frame_faces (f);
7d0393cf 5661
ee78dc32 5662 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b 5663 "menuBar", "MenuBar", RES_TYPE_NUMBER);
d3109773 5664 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
6fc2811b 5665 "toolBar", "ToolBar", RES_TYPE_NUMBER);
919f1e88 5666
1edf84e7 5667 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5668 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5669 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5670 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
5671 x_default_parameter (f, parms, Qfullscreen, Qnil,
5672 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 5673
fbd6baed
GV
5674 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5675 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5676
5677 /* Add the tool-bar height to the initial frame height so that the
5678 user gets a text display area of the size he specified with -g or
5679 via .Xdefaults. Later changes of the tool-bar height don't
5680 change the frame size. This is done so that users can create
5681 tall Emacs frames without having to guess how tall the tool-bar
5682 will get. */
5683 if (FRAME_TOOL_BAR_LINES (f))
5684 {
5685 int margin, relief, bar_height;
7d0393cf 5686
a05e2bae 5687 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5688 ? tool_bar_button_relief
5689 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5690
5691 if (INTEGERP (Vtool_bar_button_margin)
5692 && XINT (Vtool_bar_button_margin) > 0)
5693 margin = XFASTINT (Vtool_bar_button_margin);
5694 else if (CONSP (Vtool_bar_button_margin)
5695 && INTEGERP (XCDR (Vtool_bar_button_margin))
5696 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5697 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5698 else
5699 margin = 0;
7d0393cf 5700
3cf3436e
JR
5701 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5702 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5703 }
5704
ee78dc32
GV
5705 window_prompting = x_figure_window_size (f, parms);
5706
5707 if (window_prompting & XNegative)
5708 {
5709 if (window_prompting & YNegative)
fbd6baed 5710 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5711 else
fbd6baed 5712 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5713 }
5714 else
5715 {
5716 if (window_prompting & YNegative)
fbd6baed 5717 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5718 else
fbd6baed 5719 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5720 }
5721
fbd6baed 5722 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5723
6fc2811b
JR
5724 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5725 f->no_split = minibuffer_only || EQ (tem, Qt);
5726
fbd6baed 5727 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5728 x_icon (f, parms);
6fc2811b
JR
5729
5730 x_make_gc (f);
5731
5732 /* Now consider the frame official. */
5733 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5734 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5735
5736 /* We need to do this after creating the window, so that the
5737 icon-creation functions can say whose icon they're describing. */
5738 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5739 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5740
5741 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5742 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5743 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5744 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5745 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5746 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5747 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5748 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5749
5750 /* Dimensions, especially f->height, must be done via change_frame_size.
5751 Change will not be effected unless different from the current
5752 f->height. */
5753 width = f->width;
5754 height = f->height;
dc220243 5755
1026b400
RS
5756 f->height = 0;
5757 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5758 change_frame_size (f, height, width, 1, 0, 0);
5759
6fc2811b
JR
5760 /* Tell the server what size and position, etc, we want, and how
5761 badly we want them. This should be done after we have the menu
5762 bar so that its size can be taken into account. */
ee78dc32
GV
5763 BLOCK_INPUT;
5764 x_wm_set_size_hint (f, window_prompting, 0);
5765 UNBLOCK_INPUT;
5766
815d969e
JR
5767 /* Avoid a bug that causes the new frame to never become visible if
5768 an echo area message is displayed during the following call1. */
5769 specbind(Qredisplay_dont_pause, Qt);
5770
4694d762
JR
5771 /* Set up faces after all frame parameters are known. This call
5772 also merges in face attributes specified for new frames. If we
5773 don't do this, the `menu' face for instance won't have the right
5774 colors, and the menu bar won't appear in the specified colors for
5775 new frames. */
5776 call1 (Qface_set_after_frame_default, frame);
5777
6fc2811b
JR
5778 /* Make the window appear on the frame and enable display, unless
5779 the caller says not to. However, with explicit parent, Emacs
5780 cannot control visibility, so don't try. */
fbd6baed 5781 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5782 {
5783 Lisp_Object visibility;
5784
6fc2811b 5785 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5786 if (EQ (visibility, Qunbound))
5787 visibility = Qt;
5788
5789 if (EQ (visibility, Qicon))
5790 x_iconify_frame (f);
5791 else if (! NILP (visibility))
5792 x_make_frame_visible (f);
5793 else
5794 /* Must have been Qnil. */
5795 ;
5796 }
6fc2811b 5797 UNGCPRO;
7d0393cf 5798
9e57df62
GM
5799 /* Make sure windows on this frame appear in calls to next-window
5800 and similar functions. */
5801 Vwindow_list = Qnil;
7d0393cf 5802
ee78dc32
GV
5803 return unbind_to (count, frame);
5804}
5805
5806/* FRAME is used only to get a handle on the X display. We don't pass the
5807 display info directly because we're called from frame.c, which doesn't
5808 know about that structure. */
5809Lisp_Object
5810x_get_focus_frame (frame)
5811 struct frame *frame;
5812{
fbd6baed 5813 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5814 Lisp_Object xfocus;
fbd6baed 5815 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5816 return Qnil;
5817
fbd6baed 5818 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5819 return xfocus;
5820}
1edf84e7
GV
5821
5822DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5823 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5824 (frame)
5825 Lisp_Object frame;
5826{
5827 x_focus_on_frame (check_x_frame (frame));
5828 return Qnil;
5829}
5830
ee78dc32 5831\f
767b1ff0
JR
5832/* Return the charset portion of a font name. */
5833char * xlfd_charset_of_font (char * fontname)
5834{
5835 char *charset, *encoding;
5836
5837 encoding = strrchr(fontname, '-');
ceb12877 5838 if (!encoding || encoding == fontname)
767b1ff0
JR
5839 return NULL;
5840
478ea067
AI
5841 for (charset = encoding - 1; charset >= fontname; charset--)
5842 if (*charset == '-')
5843 break;
767b1ff0 5844
478ea067 5845 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5846 return NULL;
5847
5848 return charset + 1;
5849}
5850
33d52f9c
GV
5851struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5852 int size, char* filename);
8edb0a6f 5853static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5854static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5855 char * charset);
5856static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5857
8edb0a6f 5858static struct font_info *
33d52f9c 5859w32_load_system_font (f,fontname,size)
55dcfc15
AI
5860 struct frame *f;
5861 char * fontname;
5862 int size;
ee78dc32 5863{
4587b026
GV
5864 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5865 Lisp_Object font_names;
5866
4587b026
GV
5867 /* Get a list of all the fonts that match this name. Once we
5868 have a list of matching fonts, we compare them against the fonts
5869 we already have loaded by comparing names. */
5870 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5871
5872 if (!NILP (font_names))
3c190163 5873 {
4587b026
GV
5874 Lisp_Object tail;
5875 int i;
4587b026
GV
5876
5877 /* First check if any are already loaded, as that is cheaper
5878 than loading another one. */
5879 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5880 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5881 if (dpyinfo->font_table[i].name
5882 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 5883 SDATA (XCAR (tail)))
6fc2811b 5884 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 5885 SDATA (XCAR (tail)))))
4587b026 5886 return (dpyinfo->font_table + i);
6fc2811b 5887
d5db4077 5888 fontname = (char *) SDATA (XCAR (font_names));
4587b026 5889 }
1075afa9 5890 else if (w32_strict_fontnames)
5ca0cd71
GV
5891 {
5892 /* If EnumFontFamiliesEx was available, we got a full list of
5893 fonts back so stop now to avoid the possibility of loading a
5894 random font. If we had to fall back to EnumFontFamilies, the
5895 list is incomplete, so continue whether the font we want was
5896 listed or not. */
5897 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5898 FARPROC enum_font_families_ex
1075afa9 5899 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5900 if (enum_font_families_ex)
5901 return NULL;
5902 }
4587b026
GV
5903
5904 /* Load the font and add it to the table. */
5905 {
767b1ff0 5906 char *full_name, *encoding, *charset;
4587b026
GV
5907 XFontStruct *font;
5908 struct font_info *fontp;
3c190163 5909 LOGFONT lf;
4587b026 5910 BOOL ok;
19c291d3 5911 int codepage;
6fc2811b 5912 int i;
5ac45f98 5913
4587b026 5914 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5915 return (NULL);
5ac45f98 5916
4587b026
GV
5917 if (!*lf.lfFaceName)
5918 /* If no name was specified for the font, we get a random font
5919 from CreateFontIndirect - this is not particularly
5920 desirable, especially since CreateFontIndirect does not
5921 fill out the missing name in lf, so we never know what we
5922 ended up with. */
5923 return NULL;
5924
c8d88d08 5925 lf.lfQuality = DEFAULT_QUALITY;
d65a9cdc 5926
3c190163 5927 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5928 bzero (font, sizeof (*font));
5ac45f98 5929
33d52f9c
GV
5930 /* Set bdf to NULL to indicate that this is a Windows font. */
5931 font->bdf = NULL;
5ac45f98 5932
3c190163 5933 BLOCK_INPUT;
5ac45f98
GV
5934
5935 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5936
7d0393cf 5937 if (font->hfont == NULL)
1a292d24
AI
5938 {
5939 ok = FALSE;
7d0393cf
JB
5940 }
5941 else
1a292d24
AI
5942 {
5943 HDC hdc;
5944 HANDLE oldobj;
19c291d3
AI
5945
5946 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5947
5948 hdc = GetDC (dpyinfo->root_window);
5949 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5950
1a292d24 5951 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5952 if (codepage == CP_UNICODE)
5953 font->double_byte_p = 1;
5954 else
8b77111c
AI
5955 {
5956 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5957 don't report themselves as double byte fonts, when
5958 patently they are. So instead of trusting
5959 GetFontLanguageInfo, we check the properties of the
5960 codepage directly, since that is ultimately what we are
5961 working from anyway. */
5962 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5963 CPINFO cpi = {0};
5964 GetCPInfo (codepage, &cpi);
5965 font->double_byte_p = cpi.MaxCharSize > 1;
5966 }
5c6682be 5967
1a292d24
AI
5968 SelectObject (hdc, oldobj);
5969 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5970 /* Fill out details in lf according to the font that was
5971 actually loaded. */
5972 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5973 lf.lfWidth = font->tm.tmAveCharWidth;
5974 lf.lfWeight = font->tm.tmWeight;
5975 lf.lfItalic = font->tm.tmItalic;
5976 lf.lfCharSet = font->tm.tmCharSet;
5977 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5978 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5979 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5980 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5981
5982 w32_cache_char_metrics (font);
1a292d24 5983 }
5ac45f98 5984
1a292d24 5985 UNBLOCK_INPUT;
5ac45f98 5986
4587b026
GV
5987 if (!ok)
5988 {
1a292d24
AI
5989 w32_unload_font (dpyinfo, font);
5990 return (NULL);
5991 }
ee78dc32 5992
6fc2811b
JR
5993 /* Find a free slot in the font table. */
5994 for (i = 0; i < dpyinfo->n_fonts; ++i)
5995 if (dpyinfo->font_table[i].name == NULL)
5996 break;
5997
5998 /* If no free slot found, maybe enlarge the font table. */
5999 if (i == dpyinfo->n_fonts
6000 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 6001 {
6fc2811b
JR
6002 int sz;
6003 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6004 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 6005 dpyinfo->font_table
6fc2811b 6006 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
6007 }
6008
6fc2811b
JR
6009 fontp = dpyinfo->font_table + i;
6010 if (i == dpyinfo->n_fonts)
6011 ++dpyinfo->n_fonts;
4587b026
GV
6012
6013 /* Now fill in the slots of *FONTP. */
6014 BLOCK_INPUT;
6015 fontp->font = font;
6fc2811b 6016 fontp->font_idx = i;
4587b026
GV
6017 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6018 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6019
767b1ff0
JR
6020 charset = xlfd_charset_of_font (fontname);
6021
19c291d3
AI
6022 /* Cache the W32 codepage for a font. This makes w32_encode_char
6023 (called for every glyph during redisplay) much faster. */
6024 fontp->codepage = codepage;
6025
4587b026
GV
6026 /* Work out the font's full name. */
6027 full_name = (char *)xmalloc (100);
767b1ff0 6028 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
6029 fontp->full_name = full_name;
6030 else
6031 {
6032 /* If all else fails - just use the name we used to load it. */
6033 xfree (full_name);
6034 fontp->full_name = fontp->name;
6035 }
6036
6037 fontp->size = FONT_WIDTH (font);
6038 fontp->height = FONT_HEIGHT (font);
6039
6040 /* The slot `encoding' specifies how to map a character
6041 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
6042 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6043 (0:0x20..0x7F, 1:0xA0..0xFF,
6044 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 6045 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 6046 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
6047 which is never used by any charset. If mapping can't be
6048 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
6049
6050 /* SJIS fonts need to be set to type 4, all others seem to work as
6051 type FONT_ENCODING_NOT_DECIDED. */
6052 encoding = strrchr (fontp->name, '-');
d84b082d 6053 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 6054 fontp->encoding[1] = 4;
33d52f9c 6055 else
1c885fe1 6056 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
6057
6058 /* The following three values are set to 0 under W32, which is
6059 what they get set to if XGetFontProperty fails under X. */
6060 fontp->baseline_offset = 0;
6061 fontp->relative_compose = 0;
33d52f9c 6062 fontp->default_ascent = 0;
4587b026 6063
6fc2811b
JR
6064 /* Set global flag fonts_changed_p to non-zero if the font loaded
6065 has a character with a smaller width than any other character
f7b9d4d1 6066 before, or if the font loaded has a smaller height than any
6fc2811b
JR
6067 other font loaded before. If this happens, it will make a
6068 glyph matrix reallocation necessary. */
f7b9d4d1 6069 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 6070 UNBLOCK_INPUT;
4587b026
GV
6071 return fontp;
6072 }
6073}
6074
33d52f9c
GV
6075/* Load font named FONTNAME of size SIZE for frame F, and return a
6076 pointer to the structure font_info while allocating it dynamically.
6077 If loading fails, return NULL. */
6078struct font_info *
6079w32_load_font (f,fontname,size)
6080struct frame *f;
6081char * fontname;
6082int size;
6083{
6084 Lisp_Object bdf_fonts;
6085 struct font_info *retval = NULL;
6086
8edb0a6f 6087 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
6088
6089 while (!retval && CONSP (bdf_fonts))
6090 {
6091 char *bdf_name, *bdf_file;
6092 Lisp_Object bdf_pair;
6093
d5db4077 6094 bdf_name = SDATA (XCAR (bdf_fonts));
8e713be6 6095 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
d5db4077 6096 bdf_file = SDATA (XCDR (bdf_pair));
33d52f9c
GV
6097
6098 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6099
8e713be6 6100 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
6101 }
6102
6103 if (retval)
6104 return retval;
6105
6106 return w32_load_system_font(f, fontname, size);
6107}
6108
6109
7d0393cf 6110void
fbd6baed
GV
6111w32_unload_font (dpyinfo, font)
6112 struct w32_display_info *dpyinfo;
ee78dc32
GV
6113 XFontStruct * font;
6114{
7d0393cf 6115 if (font)
ee78dc32 6116 {
c6be3860 6117 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
6118 if (font->bdf) w32_free_bdf_font (font->bdf);
6119
3c190163 6120 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
6121 xfree (font);
6122 }
6123}
6124
fbd6baed 6125/* The font conversion stuff between x and w32 */
ee78dc32
GV
6126
6127/* X font string is as follows (from faces.el)
6128 * (let ((- "[-?]")
6129 * (foundry "[^-]+")
6130 * (family "[^-]+")
6131 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6132 * (weight\? "\\([^-]*\\)") ; 1
6133 * (slant "\\([ior]\\)") ; 2
6134 * (slant\? "\\([^-]?\\)") ; 2
6135 * (swidth "\\([^-]*\\)") ; 3
6136 * (adstyle "[^-]*") ; 4
6137 * (pixelsize "[0-9]+")
6138 * (pointsize "[0-9][0-9]+")
6139 * (resx "[0-9][0-9]+")
6140 * (resy "[0-9][0-9]+")
6141 * (spacing "[cmp?*]")
6142 * (avgwidth "[0-9]+")
6143 * (registry "[^-]+")
6144 * (encoding "[^-]+")
6145 * )
ee78dc32 6146 */
ee78dc32 6147
7d0393cf 6148static LONG
fbd6baed 6149x_to_w32_weight (lpw)
ee78dc32
GV
6150 char * lpw;
6151{
6152 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6153
6154 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6155 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6156 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6157 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6158 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6159 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6160 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6161 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6162 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6163 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6164 else
5ac45f98 6165 return FW_DONTCARE;
ee78dc32
GV
6166}
6167
5ac45f98 6168
7d0393cf 6169static char *
fbd6baed 6170w32_to_x_weight (fnweight)
ee78dc32
GV
6171 int fnweight;
6172{
5ac45f98
GV
6173 if (fnweight >= FW_HEAVY) return "heavy";
6174 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6175 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6176 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6177 if (fnweight >= FW_MEDIUM) return "medium";
6178 if (fnweight >= FW_NORMAL) return "normal";
6179 if (fnweight >= FW_LIGHT) return "light";
6180 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6181 if (fnweight >= FW_THIN) return "thin";
6182 else
6183 return "*";
6184}
6185
8edb0a6f 6186static LONG
fbd6baed 6187x_to_w32_charset (lpcs)
5ac45f98
GV
6188 char * lpcs;
6189{
767b1ff0 6190 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6191 char *charset;
6192 int len = strlen (lpcs);
6193
6194 /* Support "*-#nnn" format for unknown charsets. */
6195 if (strncmp (lpcs, "*-#", 3) == 0)
6196 return atoi (lpcs + 3);
6197
6198 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6199 charset = alloca (len + 1);
6200 strcpy (charset, lpcs);
6201 lpcs = strchr (charset, '*');
6202 if (lpcs)
6203 *lpcs = 0;
4587b026 6204
dfff8a69
JR
6205 /* Look through w32-charset-info-alist for the character set.
6206 Format of each entry is
6207 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6208 */
8b77111c 6209 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6210
767b1ff0
JR
6211 if (NILP(this_entry))
6212 {
6213 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6214 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6215 return ANSI_CHARSET;
6216 else
6217 return DEFAULT_CHARSET;
6218 }
6219
6220 w32_charset = Fcar (Fcdr (this_entry));
6221
d84b082d 6222 /* Translate Lisp symbol to number. */
767b1ff0
JR
6223 if (w32_charset == Qw32_charset_ansi)
6224 return ANSI_CHARSET;
6225 if (w32_charset == Qw32_charset_symbol)
6226 return SYMBOL_CHARSET;
6227 if (w32_charset == Qw32_charset_shiftjis)
6228 return SHIFTJIS_CHARSET;
6229 if (w32_charset == Qw32_charset_hangeul)
6230 return HANGEUL_CHARSET;
6231 if (w32_charset == Qw32_charset_chinesebig5)
6232 return CHINESEBIG5_CHARSET;
6233 if (w32_charset == Qw32_charset_gb2312)
6234 return GB2312_CHARSET;
6235 if (w32_charset == Qw32_charset_oem)
6236 return OEM_CHARSET;
dfff8a69 6237#ifdef JOHAB_CHARSET
767b1ff0
JR
6238 if (w32_charset == Qw32_charset_johab)
6239 return JOHAB_CHARSET;
6240 if (w32_charset == Qw32_charset_easteurope)
6241 return EASTEUROPE_CHARSET;
6242 if (w32_charset == Qw32_charset_turkish)
6243 return TURKISH_CHARSET;
6244 if (w32_charset == Qw32_charset_baltic)
6245 return BALTIC_CHARSET;
6246 if (w32_charset == Qw32_charset_russian)
6247 return RUSSIAN_CHARSET;
6248 if (w32_charset == Qw32_charset_arabic)
6249 return ARABIC_CHARSET;
6250 if (w32_charset == Qw32_charset_greek)
6251 return GREEK_CHARSET;
6252 if (w32_charset == Qw32_charset_hebrew)
6253 return HEBREW_CHARSET;
6254 if (w32_charset == Qw32_charset_vietnamese)
6255 return VIETNAMESE_CHARSET;
6256 if (w32_charset == Qw32_charset_thai)
6257 return THAI_CHARSET;
6258 if (w32_charset == Qw32_charset_mac)
6259 return MAC_CHARSET;
dfff8a69 6260#endif /* JOHAB_CHARSET */
5ac45f98 6261#ifdef UNICODE_CHARSET
767b1ff0
JR
6262 if (w32_charset == Qw32_charset_unicode)
6263 return UNICODE_CHARSET;
5ac45f98 6264#endif
dfff8a69
JR
6265
6266 return DEFAULT_CHARSET;
5ac45f98
GV
6267}
6268
dfff8a69 6269
8edb0a6f 6270static char *
fbd6baed 6271w32_to_x_charset (fncharset)
5ac45f98
GV
6272 int fncharset;
6273{
5e905a57 6274 static char buf[32];
767b1ff0 6275 Lisp_Object charset_type;
1edf84e7 6276
5ac45f98
GV
6277 switch (fncharset)
6278 {
767b1ff0
JR
6279 case ANSI_CHARSET:
6280 /* Handle startup case of w32-charset-info-alist not
6281 being set up yet. */
6282 if (NILP(Vw32_charset_info_alist))
6283 return "iso8859-1";
6284 charset_type = Qw32_charset_ansi;
6285 break;
6286 case DEFAULT_CHARSET:
6287 charset_type = Qw32_charset_default;
6288 break;
6289 case SYMBOL_CHARSET:
6290 charset_type = Qw32_charset_symbol;
6291 break;
6292 case SHIFTJIS_CHARSET:
6293 charset_type = Qw32_charset_shiftjis;
6294 break;
6295 case HANGEUL_CHARSET:
6296 charset_type = Qw32_charset_hangeul;
6297 break;
6298 case GB2312_CHARSET:
6299 charset_type = Qw32_charset_gb2312;
6300 break;
6301 case CHINESEBIG5_CHARSET:
6302 charset_type = Qw32_charset_chinesebig5;
6303 break;
6304 case OEM_CHARSET:
6305 charset_type = Qw32_charset_oem;
6306 break;
4587b026
GV
6307
6308 /* More recent versions of Windows (95 and NT4.0) define more
6309 character sets. */
6310#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6311 case EASTEUROPE_CHARSET:
6312 charset_type = Qw32_charset_easteurope;
6313 break;
6314 case TURKISH_CHARSET:
6315 charset_type = Qw32_charset_turkish;
6316 break;
6317 case BALTIC_CHARSET:
6318 charset_type = Qw32_charset_baltic;
6319 break;
33d52f9c 6320 case RUSSIAN_CHARSET:
767b1ff0
JR
6321 charset_type = Qw32_charset_russian;
6322 break;
6323 case ARABIC_CHARSET:
6324 charset_type = Qw32_charset_arabic;
6325 break;
6326 case GREEK_CHARSET:
6327 charset_type = Qw32_charset_greek;
6328 break;
6329 case HEBREW_CHARSET:
6330 charset_type = Qw32_charset_hebrew;
6331 break;
6332 case VIETNAMESE_CHARSET:
6333 charset_type = Qw32_charset_vietnamese;
6334 break;
6335 case THAI_CHARSET:
6336 charset_type = Qw32_charset_thai;
6337 break;
6338 case MAC_CHARSET:
6339 charset_type = Qw32_charset_mac;
6340 break;
6341 case JOHAB_CHARSET:
6342 charset_type = Qw32_charset_johab;
6343 break;
4587b026
GV
6344#endif
6345
5ac45f98 6346#ifdef UNICODE_CHARSET
767b1ff0
JR
6347 case UNICODE_CHARSET:
6348 charset_type = Qw32_charset_unicode;
6349 break;
5ac45f98 6350#endif
767b1ff0
JR
6351 default:
6352 /* Encode numerical value of unknown charset. */
6353 sprintf (buf, "*-#%u", fncharset);
6354 return buf;
5ac45f98 6355 }
7d0393cf 6356
767b1ff0
JR
6357 {
6358 Lisp_Object rest;
6359 char * best_match = NULL;
6360
6361 /* Look through w32-charset-info-alist for the character set.
6362 Prefer ISO codepages, and prefer lower numbers in the ISO
6363 range. Only return charsets for codepages which are installed.
6364
6365 Format of each entry is
6366 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6367 */
6368 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6369 {
6370 char * x_charset;
6371 Lisp_Object w32_charset;
6372 Lisp_Object codepage;
6373
6374 Lisp_Object this_entry = XCAR (rest);
6375
6376 /* Skip invalid entries in alist. */
6377 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6378 || !CONSP (XCDR (this_entry))
6379 || !SYMBOLP (XCAR (XCDR (this_entry))))
6380 continue;
6381
d5db4077 6382 x_charset = SDATA (XCAR (this_entry));
767b1ff0
JR
6383 w32_charset = XCAR (XCDR (this_entry));
6384 codepage = XCDR (XCDR (this_entry));
6385
6386 /* Look for Same charset and a valid codepage (or non-int
6387 which means ignore). */
6388 if (w32_charset == charset_type
6389 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6390 || IsValidCodePage (XINT (codepage))))
6391 {
6392 /* If we don't have a match already, then this is the
6393 best. */
6394 if (!best_match)
6395 best_match = x_charset;
6396 /* If this is an ISO codepage, and the best so far isn't,
6397 then this is better. */
d84b082d
JR
6398 else if (strnicmp (best_match, "iso", 3) != 0
6399 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
6400 best_match = x_charset;
6401 /* If both are ISO8859 codepages, choose the one with the
6402 lowest number in the encoding field. */
d84b082d
JR
6403 else if (strnicmp (best_match, "iso8859-", 8) == 0
6404 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
6405 {
6406 int best_enc = atoi (best_match + 8);
6407 int this_enc = atoi (x_charset + 8);
6408 if (this_enc > 0 && this_enc < best_enc)
6409 best_match = x_charset;
7d0393cf 6410 }
767b1ff0
JR
6411 }
6412 }
6413
6414 /* If no match, encode the numeric value. */
6415 if (!best_match)
6416 {
6417 sprintf (buf, "*-#%u", fncharset);
6418 return buf;
6419 }
6420
5e905a57
JR
6421 strncpy(buf, best_match, 31);
6422 buf[31] = '\0';
767b1ff0
JR
6423 return buf;
6424 }
ee78dc32
GV
6425}
6426
dfff8a69 6427
d84b082d
JR
6428/* Return all the X charsets that map to a font. */
6429static Lisp_Object
6430w32_to_all_x_charsets (fncharset)
6431 int fncharset;
6432{
6433 static char buf[32];
6434 Lisp_Object charset_type;
6435 Lisp_Object retval = Qnil;
6436
6437 switch (fncharset)
6438 {
6439 case ANSI_CHARSET:
6440 /* Handle startup case of w32-charset-info-alist not
6441 being set up yet. */
6442 if (NILP(Vw32_charset_info_alist))
d86c35ee
JR
6443 return Fcons (build_string ("iso8859-1"), Qnil);
6444
d84b082d
JR
6445 charset_type = Qw32_charset_ansi;
6446 break;
6447 case DEFAULT_CHARSET:
6448 charset_type = Qw32_charset_default;
6449 break;
6450 case SYMBOL_CHARSET:
6451 charset_type = Qw32_charset_symbol;
6452 break;
6453 case SHIFTJIS_CHARSET:
6454 charset_type = Qw32_charset_shiftjis;
6455 break;
6456 case HANGEUL_CHARSET:
6457 charset_type = Qw32_charset_hangeul;
6458 break;
6459 case GB2312_CHARSET:
6460 charset_type = Qw32_charset_gb2312;
6461 break;
6462 case CHINESEBIG5_CHARSET:
6463 charset_type = Qw32_charset_chinesebig5;
6464 break;
6465 case OEM_CHARSET:
6466 charset_type = Qw32_charset_oem;
6467 break;
6468
6469 /* More recent versions of Windows (95 and NT4.0) define more
6470 character sets. */
6471#ifdef EASTEUROPE_CHARSET
6472 case EASTEUROPE_CHARSET:
6473 charset_type = Qw32_charset_easteurope;
6474 break;
6475 case TURKISH_CHARSET:
6476 charset_type = Qw32_charset_turkish;
6477 break;
6478 case BALTIC_CHARSET:
6479 charset_type = Qw32_charset_baltic;
6480 break;
6481 case RUSSIAN_CHARSET:
6482 charset_type = Qw32_charset_russian;
6483 break;
6484 case ARABIC_CHARSET:
6485 charset_type = Qw32_charset_arabic;
6486 break;
6487 case GREEK_CHARSET:
6488 charset_type = Qw32_charset_greek;
6489 break;
6490 case HEBREW_CHARSET:
6491 charset_type = Qw32_charset_hebrew;
6492 break;
6493 case VIETNAMESE_CHARSET:
6494 charset_type = Qw32_charset_vietnamese;
6495 break;
6496 case THAI_CHARSET:
6497 charset_type = Qw32_charset_thai;
6498 break;
6499 case MAC_CHARSET:
6500 charset_type = Qw32_charset_mac;
6501 break;
6502 case JOHAB_CHARSET:
6503 charset_type = Qw32_charset_johab;
6504 break;
6505#endif
6506
6507#ifdef UNICODE_CHARSET
6508 case UNICODE_CHARSET:
6509 charset_type = Qw32_charset_unicode;
6510 break;
6511#endif
6512 default:
6513 /* Encode numerical value of unknown charset. */
6514 sprintf (buf, "*-#%u", fncharset);
6515 return Fcons (build_string (buf), Qnil);
6516 }
7d0393cf 6517
d84b082d
JR
6518 {
6519 Lisp_Object rest;
6520 /* Look through w32-charset-info-alist for the character set.
6521 Only return charsets for codepages which are installed.
6522
6523 Format of each entry in Vw32_charset_info_alist is
6524 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6525 */
6526 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6527 {
6528 Lisp_Object x_charset;
6529 Lisp_Object w32_charset;
6530 Lisp_Object codepage;
6531
6532 Lisp_Object this_entry = XCAR (rest);
6533
6534 /* Skip invalid entries in alist. */
6535 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6536 || !CONSP (XCDR (this_entry))
6537 || !SYMBOLP (XCAR (XCDR (this_entry))))
6538 continue;
6539
6540 x_charset = XCAR (this_entry);
6541 w32_charset = XCAR (XCDR (this_entry));
6542 codepage = XCDR (XCDR (this_entry));
6543
6544 /* Look for Same charset and a valid codepage (or non-int
6545 which means ignore). */
6546 if (w32_charset == charset_type
6547 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6548 || IsValidCodePage (XINT (codepage))))
6549 {
6550 retval = Fcons (x_charset, retval);
6551 }
6552 }
6553
6554 /* If no match, encode the numeric value. */
6555 if (NILP (retval))
6556 {
6557 sprintf (buf, "*-#%u", fncharset);
6558 return Fcons (build_string (buf), Qnil);
6559 }
6560
6561 return retval;
6562 }
6563}
6564
dfff8a69
JR
6565/* Get the Windows codepage corresponding to the specified font. The
6566 charset info in the font name is used to look up
6567 w32-charset-to-codepage-alist. */
7d0393cf 6568int
dfff8a69
JR
6569w32_codepage_for_font (char *fontname)
6570{
767b1ff0
JR
6571 Lisp_Object codepage, entry;
6572 char *charset_str, *charset, *end;
dfff8a69 6573
767b1ff0 6574 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6575 return CP_DEFAULT;
6576
767b1ff0
JR
6577 /* Extract charset part of font string. */
6578 charset = xlfd_charset_of_font (fontname);
6579
6580 if (!charset)
ceb12877 6581 return CP_UNKNOWN;
767b1ff0 6582
8b77111c 6583 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6584 strcpy (charset_str, charset);
6585
8b77111c 6586#if 0
dfff8a69
JR
6587 /* Remove leading "*-". */
6588 if (strncmp ("*-", charset_str, 2) == 0)
6589 charset = charset_str + 2;
6590 else
8b77111c 6591#endif
dfff8a69
JR
6592 charset = charset_str;
6593
6594 /* Stop match at wildcard (including preceding '-'). */
6595 if (end = strchr (charset, '*'))
6596 {
6597 if (end > charset && *(end-1) == '-')
6598 end--;
6599 *end = '\0';
6600 }
6601
767b1ff0
JR
6602 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6603 if (NILP (entry))
ceb12877 6604 return CP_UNKNOWN;
767b1ff0
JR
6605
6606 codepage = Fcdr (Fcdr (entry));
6607
6608 if (NILP (codepage))
6609 return CP_8BIT;
6610 else if (XFASTINT (codepage) == XFASTINT (Qt))
6611 return CP_UNICODE;
6612 else if (INTEGERP (codepage))
dfff8a69
JR
6613 return XINT (codepage);
6614 else
ceb12877 6615 return CP_UNKNOWN;
dfff8a69
JR
6616}
6617
6618
7d0393cf 6619static BOOL
767b1ff0 6620w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6621 LOGFONT * lplogfont;
6622 char * lpxstr;
6623 int len;
767b1ff0 6624 char * specific_charset;
ee78dc32 6625{
6fc2811b 6626 char* fonttype;
f46e6225 6627 char *fontname;
3cb20f4a
RS
6628 char height_pixels[8];
6629 char height_dpi[8];
6630 char width_pixels[8];
4587b026 6631 char *fontname_dash;
ac849ba4
JR
6632 int display_resy = (int) one_w32_display_info.resy;
6633 int display_resx = (int) one_w32_display_info.resx;
f46e6225
GV
6634 int bufsz;
6635 struct coding_system coding;
3cb20f4a
RS
6636
6637 if (!lpxstr) abort ();
ee78dc32 6638
3cb20f4a
RS
6639 if (!lplogfont)
6640 return FALSE;
6641
6fc2811b
JR
6642 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6643 fonttype = "raster";
6644 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6645 fonttype = "outline";
6646 else
6647 fonttype = "unknown";
6648
1fa3a200 6649 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6650 &coding);
aab5ac44
KH
6651 coding.src_multibyte = 0;
6652 coding.dst_multibyte = 1;
f46e6225 6653 coding.mode |= CODING_MODE_LAST_BLOCK;
65413122
KH
6654 /* We explicitely disable composition handling because selection
6655 data should not contain any composition sequence. */
6656 coding.composing = COMPOSITION_DISABLED;
f46e6225
GV
6657 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6658
6659 fontname = alloca(sizeof(*fontname) * bufsz);
6660 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6661 strlen(lplogfont->lfFaceName), bufsz - 1);
6662 *(fontname + coding.produced) = '\0';
4587b026
GV
6663
6664 /* Replace dashes with underscores so the dashes are not
f46e6225 6665 misinterpreted. */
4587b026
GV
6666 fontname_dash = fontname;
6667 while (fontname_dash = strchr (fontname_dash, '-'))
6668 *fontname_dash = '_';
6669
3cb20f4a 6670 if (lplogfont->lfHeight)
ee78dc32 6671 {
3cb20f4a
RS
6672 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6673 sprintf (height_dpi, "%u",
33d52f9c 6674 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6675 }
6676 else
ee78dc32 6677 {
3cb20f4a
RS
6678 strcpy (height_pixels, "*");
6679 strcpy (height_dpi, "*");
ee78dc32 6680 }
3cb20f4a
RS
6681 if (lplogfont->lfWidth)
6682 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6683 else
6684 strcpy (width_pixels, "*");
6685
6686 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6687 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6688 fonttype, /* foundry */
4587b026
GV
6689 fontname, /* family */
6690 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6691 lplogfont->lfItalic?'i':'r', /* slant */
6692 /* setwidth name */
6693 /* add style name */
6694 height_pixels, /* pixel size */
6695 height_dpi, /* point size */
33d52f9c
GV
6696 display_resx, /* resx */
6697 display_resy, /* resy */
4587b026
GV
6698 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6699 ? 'p' : 'c', /* spacing */
6700 width_pixels, /* avg width */
767b1ff0 6701 specific_charset ? specific_charset
7d0393cf 6702 : w32_to_x_charset (lplogfont->lfCharSet)
767b1ff0 6703 /* charset registry and encoding */
3cb20f4a
RS
6704 );
6705
ee78dc32
GV
6706 lpxstr[len - 1] = 0; /* just to be sure */
6707 return (TRUE);
6708}
6709
7d0393cf 6710static BOOL
fbd6baed 6711x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6712 char * lpxstr;
6713 LOGFONT * lplogfont;
6714{
f46e6225
GV
6715 struct coding_system coding;
6716
ee78dc32 6717 if (!lplogfont) return (FALSE);
f46e6225 6718
ee78dc32 6719 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6720
1a292d24 6721 /* Set default value for each field. */
771c47d5 6722#if 1
ee78dc32
GV
6723 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6724 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6725 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6726#else
6727 /* go for maximum quality */
6728 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6729 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6730 lplogfont->lfQuality = PROOF_QUALITY;
6731#endif
6732
1a292d24
AI
6733 lplogfont->lfCharSet = DEFAULT_CHARSET;
6734 lplogfont->lfWeight = FW_DONTCARE;
6735 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6736
5ac45f98
GV
6737 if (!lpxstr)
6738 return FALSE;
6739
6740 /* Provide a simple escape mechanism for specifying Windows font names
6741 * directly -- if font spec does not beginning with '-', assume this
6742 * format:
6743 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6744 */
7d0393cf 6745
5ac45f98
GV
6746 if (*lpxstr == '-')
6747 {
33d52f9c
GV
6748 int fields, tem;
6749 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6750 width[10], resy[10], remainder[50];
5ac45f98 6751 char * encoding;
ac849ba4 6752 int dpi = (int) one_w32_display_info.resy;
5ac45f98
GV
6753
6754 fields = sscanf (lpxstr,
8b77111c 6755 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6756 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6757 if (fields == EOF)
6758 return (FALSE);
6759
6760 /* In the general case when wildcards cover more than one field,
6761 we don't know which field is which, so don't fill any in.
6762 However, we need to cope with this particular form, which is
6763 generated by font_list_1 (invoked by try_font_list):
6764 "-raster-6x10-*-gb2312*-*"
6765 and make sure to correctly parse the charset field. */
6766 if (fields == 3)
6767 {
6768 fields = sscanf (lpxstr,
6769 "-%*[^-]-%49[^-]-*-%49s",
6770 name, remainder);
6771 }
6772 else if (fields < 9)
6773 {
6774 fields = 0;
6775 remainder[0] = 0;
6776 }
6fc2811b 6777
5ac45f98
GV
6778 if (fields > 0 && name[0] != '*')
6779 {
8ea3e054
RS
6780 int bufsize;
6781 unsigned char *buf;
6782
f46e6225 6783 setup_coding_system
1fa3a200 6784 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6785 coding.src_multibyte = 1;
6786 coding.dst_multibyte = 1;
8ea3e054
RS
6787 bufsize = encoding_buffer_size (&coding, strlen (name));
6788 buf = (unsigned char *) alloca (bufsize);
f46e6225 6789 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6790 encode_coding (&coding, name, buf, strlen (name), bufsize);
6791 if (coding.produced >= LF_FACESIZE)
6792 coding.produced = LF_FACESIZE - 1;
6793 buf[coding.produced] = 0;
6794 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6795 }
6796 else
6797 {
6fc2811b 6798 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6799 }
6800
6801 fields--;
6802
fbd6baed 6803 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6804
6805 fields--;
6806
c8874f14 6807 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6808
6809 fields--;
6810
6811 if (fields > 0 && pixels[0] != '*')
6812 lplogfont->lfHeight = atoi (pixels);
6813
6814 fields--;
5ac45f98 6815 fields--;
33d52f9c
GV
6816 if (fields > 0 && resy[0] != '*')
6817 {
6fc2811b 6818 tem = atoi (resy);
33d52f9c
GV
6819 if (tem > 0) dpi = tem;
6820 }
5ac45f98 6821
33d52f9c
GV
6822 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6823 lplogfont->lfHeight = atoi (height) * dpi / 720;
6824
6825 if (fields > 0)
5ac45f98
GV
6826 lplogfont->lfPitchAndFamily =
6827 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6828
6829 fields--;
6830
6831 if (fields > 0 && width[0] != '*')
6832 lplogfont->lfWidth = atoi (width) / 10;
6833
6834 fields--;
6835
4587b026 6836 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6837 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6838 {
5ac45f98
GV
6839 int len = strlen (remainder);
6840 if (len > 0 && remainder[len-1] == '-')
6841 remainder[len-1] = 0;
ee78dc32 6842 }
5ac45f98 6843 encoding = remainder;
8b77111c 6844#if 0
5ac45f98
GV
6845 if (strncmp (encoding, "*-", 2) == 0)
6846 encoding += 2;
8b77111c
AI
6847#endif
6848 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6849 }
6850 else
6851 {
6852 int fields;
6853 char name[100], height[10], width[10], weight[20];
a1a80b40 6854
5ac45f98
GV
6855 fields = sscanf (lpxstr,
6856 "%99[^:]:%9[^:]:%9[^:]:%19s",
6857 name, height, width, weight);
6858
6859 if (fields == EOF) return (FALSE);
6860
6861 if (fields > 0)
6862 {
6863 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6864 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6865 }
6866 else
6867 {
6868 lplogfont->lfFaceName[0] = 0;
6869 }
6870
6871 fields--;
6872
6873 if (fields > 0)
6874 lplogfont->lfHeight = atoi (height);
6875
6876 fields--;
6877
6878 if (fields > 0)
6879 lplogfont->lfWidth = atoi (width);
6880
6881 fields--;
6882
fbd6baed 6883 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6884 }
6885
6886 /* This makes TrueType fonts work better. */
6887 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6888
ee78dc32
GV
6889 return (TRUE);
6890}
6891
d88c567c
JR
6892/* Strip the pixel height and point height from the given xlfd, and
6893 return the pixel height. If no pixel height is specified, calculate
6894 one from the point height, or if that isn't defined either, return
6895 0 (which usually signifies a scalable font).
6896*/
8edb0a6f
JR
6897static int
6898xlfd_strip_height (char *fontname)
d88c567c 6899{
8edb0a6f 6900 int pixel_height, field_number;
d88c567c
JR
6901 char *read_from, *write_to;
6902
6903 xassert (fontname);
6904
6905 pixel_height = field_number = 0;
6906 write_to = NULL;
6907
6908 /* Look for height fields. */
6909 for (read_from = fontname; *read_from; read_from++)
6910 {
6911 if (*read_from == '-')
6912 {
6913 field_number++;
6914 if (field_number == 7) /* Pixel height. */
6915 {
6916 read_from++;
6917 write_to = read_from;
6918
6919 /* Find end of field. */
6920 for (;*read_from && *read_from != '-'; read_from++)
6921 ;
6922
6923 /* Split the fontname at end of field. */
6924 if (*read_from)
6925 {
6926 *read_from = '\0';
6927 read_from++;
6928 }
6929 pixel_height = atoi (write_to);
6930 /* Blank out field. */
6931 if (read_from > write_to)
6932 {
6933 *write_to = '-';
6934 write_to++;
6935 }
767b1ff0 6936 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6937 return now. */
6938 else
6939 return pixel_height;
6940
6941 /* If we got a pixel height, the point height can be
6942 ignored. Just blank it out and break now. */
6943 if (pixel_height)
6944 {
6945 /* Find end of point size field. */
6946 for (; *read_from && *read_from != '-'; read_from++)
6947 ;
6948
6949 if (*read_from)
6950 read_from++;
6951
6952 /* Blank out the point size field. */
6953 if (read_from > write_to)
6954 {
6955 *write_to = '-';
6956 write_to++;
6957 }
6958 else
6959 return pixel_height;
6960
6961 break;
6962 }
6963 /* If the point height is already blank, break now. */
6964 if (*read_from == '-')
6965 {
6966 read_from++;
6967 break;
6968 }
6969 }
6970 else if (field_number == 8)
6971 {
6972 /* If we didn't get a pixel height, try to get the point
6973 height and convert that. */
6974 int point_size;
6975 char *point_size_start = read_from++;
6976
6977 /* Find end of field. */
6978 for (; *read_from && *read_from != '-'; read_from++)
6979 ;
6980
6981 if (*read_from)
6982 {
6983 *read_from = '\0';
6984 read_from++;
6985 }
6986
6987 point_size = atoi (point_size_start);
6988
6989 /* Convert to pixel height. */
6990 pixel_height = point_size
6991 * one_w32_display_info.height_in / 720;
6992
6993 /* Blank out this field and break. */
6994 *write_to = '-';
6995 write_to++;
6996 break;
6997 }
6998 }
6999 }
7000
7001 /* Shift the rest of the font spec into place. */
7002 if (write_to && read_from > write_to)
7003 {
7004 for (; *read_from; read_from++, write_to++)
7005 *write_to = *read_from;
7006 *write_to = '\0';
7007 }
7008
7009 return pixel_height;
7010}
7011
6fc2811b 7012/* Assume parameter 1 is fully qualified, no wildcards. */
7d0393cf 7013static BOOL
6fc2811b
JR
7014w32_font_match (fontname, pattern)
7015 char * fontname;
7016 char * pattern;
ee78dc32 7017{
e7c72122 7018 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 7019 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 7020 char *ptr;
ee78dc32 7021
d88c567c
JR
7022 /* Copy fontname so we can modify it during comparison. */
7023 strcpy (font_name_copy, fontname);
7024
6fc2811b
JR
7025 ptr = regex;
7026 *ptr++ = '^';
ee78dc32 7027
6fc2811b
JR
7028 /* Turn pattern into a regexp and do a regexp match. */
7029 for (; *pattern; pattern++)
7030 {
7031 if (*pattern == '?')
7032 *ptr++ = '.';
7033 else if (*pattern == '*')
7034 {
7035 *ptr++ = '.';
7036 *ptr++ = '*';
7037 }
33d52f9c 7038 else
6fc2811b 7039 *ptr++ = *pattern;
ee78dc32 7040 }
6fc2811b
JR
7041 *ptr = '$';
7042 *(ptr + 1) = '\0';
7043
d88c567c
JR
7044 /* Strip out font heights and compare them seperately, since
7045 rounding error can cause mismatches. This also allows a
7046 comparison between a font that declares only a pixel height and a
7047 pattern that declares the point height.
7048 */
7049 {
7050 int font_height, pattern_height;
7051
7052 font_height = xlfd_strip_height (font_name_copy);
7053 pattern_height = xlfd_strip_height (regex);
7054
7055 /* Compare now, and don't bother doing expensive regexp matching
7056 if the heights differ. */
7057 if (font_height && pattern_height && (font_height != pattern_height))
7058 return FALSE;
7059 }
7060
6fc2811b 7061 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 7062 font_name_copy) >= 0);
ee78dc32
GV
7063}
7064
5ca0cd71
GV
7065/* Callback functions, and a structure holding info they need, for
7066 listing system fonts on W32. We need one set of functions to do the
7067 job properly, but these don't work on NT 3.51 and earlier, so we
7068 have a second set which don't handle character sets properly to
7069 fall back on.
7070
7071 In both cases, there are two passes made. The first pass gets one
7072 font from each family, the second pass lists all the fonts from
7073 each family. */
7074
7d0393cf 7075typedef struct enumfont_t
ee78dc32
GV
7076{
7077 HDC hdc;
7078 int numFonts;
3cb20f4a 7079 LOGFONT logfont;
ee78dc32 7080 XFontStruct *size_ref;
23afac8f 7081 Lisp_Object pattern;
d84b082d 7082 Lisp_Object list;
ee78dc32
GV
7083} enumfont_t;
7084
d84b082d
JR
7085
7086static void
7087enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7088
7089
7d0393cf 7090static int CALLBACK
ee78dc32
GV
7091enum_font_cb2 (lplf, lptm, FontType, lpef)
7092 ENUMLOGFONT * lplf;
7093 NEWTEXTMETRIC * lptm;
7094 int FontType;
7095 enumfont_t * lpef;
7096{
66895301
JR
7097 /* Ignore struck out and underlined versions of fonts. */
7098 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7099 return 1;
7100
7101 /* Only return fonts with names starting with @ if they were
7102 explicitly specified, since Microsoft uses an initial @ to
7103 denote fonts for vertical writing, without providing a more
7104 convenient way of identifying them. */
7105 if (lplf->elfLogFont.lfFaceName[0] == '@'
7106 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
7107 return 1;
7108
4587b026
GV
7109 /* Check that the character set matches if it was specified */
7110 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7111 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 7112 return 1;
4587b026 7113
6358474d
JR
7114 if (FontType == RASTER_FONTTYPE)
7115 {
7116 /* DBCS raster fonts have problems displaying, so skip them. */
7117 int charset = lplf->elfLogFont.lfCharSet;
7118 if (charset == SHIFTJIS_CHARSET
7119 || charset == HANGEUL_CHARSET
7120 || charset == CHINESEBIG5_CHARSET
7121 || charset == GB2312_CHARSET
7122#ifdef JOHAB_CHARSET
7123 || charset == JOHAB_CHARSET
7124#endif
7125 )
7126 return 1;
7127 }
7128
ee78dc32
GV
7129 {
7130 char buf[100];
4587b026 7131 Lisp_Object width = Qnil;
d84b082d 7132 Lisp_Object charset_list = Qnil;
767b1ff0 7133 char *charset = NULL;
ee78dc32 7134
6fc2811b
JR
7135 /* Truetype fonts do not report their true metrics until loaded */
7136 if (FontType != RASTER_FONTTYPE)
3cb20f4a 7137 {
23afac8f 7138 if (!NILP (lpef->pattern))
6fc2811b
JR
7139 {
7140 /* Scalable fonts are as big as you want them to be. */
7141 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7142 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7143 width = make_number (lpef->logfont.lfWidth);
7144 }
7145 else
7146 {
7147 lplf->elfLogFont.lfHeight = 0;
7148 lplf->elfLogFont.lfWidth = 0;
7149 }
3cb20f4a 7150 }
6fc2811b 7151
f46e6225
GV
7152 /* Make sure the height used here is the same as everywhere
7153 else (ie character height, not cell height). */
6fc2811b
JR
7154 if (lplf->elfLogFont.lfHeight > 0)
7155 {
7156 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7157 if (FontType == RASTER_FONTTYPE)
7158 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7159 else
7160 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7161 }
4587b026 7162
23afac8f 7163 if (!NILP (lpef->pattern))
767b1ff0 7164 {
d5db4077 7165 charset = xlfd_charset_of_font (SDATA (lpef->pattern));
767b1ff0 7166
644cefdf
JR
7167 /* We already checked charsets above, but DEFAULT_CHARSET
7168 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7169 if (charset
7170 && strncmp (charset, "*-*", 3) != 0
7171 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7172 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7173 return 1;
767b1ff0
JR
7174 }
7175
d84b082d
JR
7176 if (charset)
7177 charset_list = Fcons (build_string (charset), Qnil);
7178 else
7179 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 7180
d84b082d
JR
7181 /* Loop through the charsets. */
7182 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 7183 {
d84b082d 7184 Lisp_Object this_charset = Fcar (charset_list);
d5db4077 7185 charset = SDATA (this_charset);
d84b082d
JR
7186
7187 /* List bold and italic variations if w32-enable-synthesized-fonts
7188 is non-nil and this is a plain font. */
7189 if (w32_enable_synthesized_fonts
7190 && lplf->elfLogFont.lfWeight == FW_NORMAL
7191 && lplf->elfLogFont.lfItalic == FALSE)
7192 {
7193 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7194 charset, width);
7195 /* bold. */
7196 lplf->elfLogFont.lfWeight = FW_BOLD;
7197 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7198 charset, width);
7199 /* bold italic. */
7200 lplf->elfLogFont.lfItalic = TRUE;
7201 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7202 charset, width);
7203 /* italic. */
7204 lplf->elfLogFont.lfWeight = FW_NORMAL;
7205 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7206 charset, width);
7207 }
7208 else
7209 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7210 charset, width);
ee78dc32
GV
7211 }
7212 }
6fc2811b 7213
5e905a57 7214 return 1;
ee78dc32
GV
7215}
7216
d84b082d
JR
7217static void
7218enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7219 enumfont_t * lpef;
7220 LOGFONT * logfont;
7221 char * match_charset;
7222 Lisp_Object width;
7223{
7224 char buf[100];
7225
7226 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7227 return;
7228
23afac8f 7229 if (NILP (lpef->pattern)
d5db4077 7230 || w32_font_match (buf, SDATA (lpef->pattern)))
d84b082d
JR
7231 {
7232 /* Check if we already listed this font. This may happen if
7233 w32_enable_synthesized_fonts is non-nil, and there are real
7234 bold and italic versions of the font. */
7235 Lisp_Object font_name = build_string (buf);
7236 if (NILP (Fmember (font_name, lpef->list)))
7237 {
23afac8f
JR
7238 Lisp_Object entry = Fcons (font_name, width);
7239 lpef->list = Fcons (entry, lpef->list);
d84b082d
JR
7240 lpef->numFonts++;
7241 }
7242 }
7243}
7244
7245
7d0393cf 7246static int CALLBACK
ee78dc32
GV
7247enum_font_cb1 (lplf, lptm, FontType, lpef)
7248 ENUMLOGFONT * lplf;
7249 NEWTEXTMETRIC * lptm;
7250 int FontType;
7251 enumfont_t * lpef;
7252{
7253 return EnumFontFamilies (lpef->hdc,
7254 lplf->elfLogFont.lfFaceName,
7255 (FONTENUMPROC) enum_font_cb2,
7256 (LPARAM) lpef);
7257}
7258
7259
8edb0a6f 7260static int CALLBACK
5ca0cd71
GV
7261enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7262 ENUMLOGFONTEX * lplf;
7263 NEWTEXTMETRICEX * lptm;
7264 int font_type;
7265 enumfont_t * lpef;
7266{
7267 /* We are not interested in the extra info we get back from the 'Ex
7268 version - only the fact that we get character set variations
7269 enumerated seperately. */
7270 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7271 font_type, lpef);
7272}
7273
8edb0a6f 7274static int CALLBACK
5ca0cd71
GV
7275enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7276 ENUMLOGFONTEX * lplf;
7277 NEWTEXTMETRICEX * lptm;
7278 int font_type;
7279 enumfont_t * lpef;
7280{
7281 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7282 FARPROC enum_font_families_ex
7283 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7284 /* We don't really expect EnumFontFamiliesEx to disappear once we
7285 get here, so don't bother handling it gracefully. */
7286 if (enum_font_families_ex == NULL)
7287 error ("gdi32.dll has disappeared!");
7288 return enum_font_families_ex (lpef->hdc,
7289 &lplf->elfLogFont,
7290 (FONTENUMPROC) enum_fontex_cb2,
7291 (LPARAM) lpef, 0);
7292}
7293
4587b026
GV
7294/* Interface to fontset handler. (adapted from mw32font.c in Meadow
7295 and xterm.c in Emacs 20.3) */
7296
8edb0a6f 7297static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
7298{
7299 char *fontname, *ptnstr;
7300 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 7301 int n_fonts = 0;
33d52f9c
GV
7302
7303 list = Vw32_bdf_filename_alist;
d5db4077 7304 ptnstr = SDATA (pattern);
33d52f9c 7305
8e713be6 7306 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 7307 {
8e713be6 7308 tem = XCAR (list);
33d52f9c 7309 if (CONSP (tem))
d5db4077 7310 fontname = SDATA (XCAR (tem));
33d52f9c 7311 else if (STRINGP (tem))
d5db4077 7312 fontname = SDATA (tem);
33d52f9c
GV
7313 else
7314 continue;
7315
7316 if (w32_font_match (fontname, ptnstr))
5ca0cd71 7317 {
8e713be6 7318 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7319 n_fonts++;
7320 if (n_fonts >= max_names)
7321 break;
7322 }
33d52f9c
GV
7323 }
7324
7325 return newlist;
7326}
7327
5ca0cd71 7328
4587b026
GV
7329/* Return a list of names of available fonts matching PATTERN on frame
7330 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7331 to be listed. Frame F NULL means we have not yet created any
7332 frame, which means we can't get proper size info, as we don't have
7333 a device context to use for GetTextMetrics.
7334 MAXNAMES sets a limit on how many fonts to match. */
7335
7336Lisp_Object
dc220243
JR
7337w32_list_fonts (f, pattern, size, maxnames)
7338 struct frame *f;
7339 Lisp_Object pattern;
7340 int size;
7341 int maxnames;
4587b026 7342{
6fc2811b 7343 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 7344 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 7345 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 7346 int n_fonts = 0;
396594fe 7347
4587b026
GV
7348 patterns = Fassoc (pattern, Valternate_fontname_alist);
7349 if (NILP (patterns))
7350 patterns = Fcons (pattern, Qnil);
7351
8e713be6 7352 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
7353 {
7354 enumfont_t ef;
767b1ff0 7355 int codepage;
4587b026 7356
8e713be6 7357 tpat = XCAR (patterns);
4587b026 7358
767b1ff0
JR
7359 if (!STRINGP (tpat))
7360 continue;
7361
7362 /* Avoid expensive EnumFontFamilies functions if we are not
7363 going to be able to output one of these anyway. */
d5db4077 7364 codepage = w32_codepage_for_font (SDATA (tpat));
767b1ff0 7365 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7366 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7367 && !IsValidCodePage(codepage))
767b1ff0
JR
7368 continue;
7369
4587b026
GV
7370 /* See if we cached the result for this particular query.
7371 The cache is an alist of the form:
7372 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7373 */
8e713be6 7374 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7375 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7376 {
7377 list = Fcdr_safe (list);
7378 /* We have a cached list. Don't have to get the list again. */
7379 goto label_cached;
7380 }
7381
7382 BLOCK_INPUT;
7383 /* At first, put PATTERN in the cache. */
23afac8f
JR
7384 ef.pattern = tpat;
7385 ef.list = Qnil;
4587b026 7386 ef.numFonts = 0;
33d52f9c 7387
5ca0cd71
GV
7388 /* Use EnumFontFamiliesEx where it is available, as it knows
7389 about character sets. Fall back to EnumFontFamilies for
7390 older versions of NT that don't support the 'Ex function. */
d5db4077 7391 x_to_w32_font (SDATA (tpat), &ef.logfont);
4587b026 7392 {
5ca0cd71
GV
7393 LOGFONT font_match_pattern;
7394 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7395 FARPROC enum_font_families_ex
7396 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7397
7398 /* We do our own pattern matching so we can handle wildcards. */
7399 font_match_pattern.lfFaceName[0] = 0;
7400 font_match_pattern.lfPitchAndFamily = 0;
7401 /* We can use the charset, because if it is a wildcard it will
7402 be DEFAULT_CHARSET anyway. */
7403 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7404
33d52f9c 7405 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7406
5ca0cd71
GV
7407 if (enum_font_families_ex)
7408 enum_font_families_ex (ef.hdc,
7409 &font_match_pattern,
7410 (FONTENUMPROC) enum_fontex_cb1,
7411 (LPARAM) &ef, 0);
7412 else
7413 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7414 (LPARAM)&ef);
4587b026 7415
33d52f9c 7416 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7417 }
7418
7419 UNBLOCK_INPUT;
23afac8f 7420 list = ef.list;
4587b026
GV
7421
7422 /* Make a list of the fonts we got back.
7423 Store that in the font cache for the display. */
f3fbd155
KR
7424 XSETCDR (dpyinfo->name_list_element,
7425 Fcons (Fcons (tpat, list),
7426 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7427
7428 label_cached:
7429 if (NILP (list)) continue; /* Try the remaining alternatives. */
7430
7431 newlist = second_best = Qnil;
7432
7d0393cf 7433 /* Make a list of the fonts that have the right width. */
8e713be6 7434 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7435 {
7436 int found_size;
8e713be6 7437 tem = XCAR (list);
4587b026
GV
7438
7439 if (!CONSP (tem))
7440 continue;
8e713be6 7441 if (NILP (XCAR (tem)))
4587b026
GV
7442 continue;
7443 if (!size)
7444 {
8e713be6 7445 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7446 n_fonts++;
7447 if (n_fonts >= maxnames)
7448 break;
7449 else
7450 continue;
4587b026 7451 }
8e713be6 7452 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7453 {
7454 /* Since we don't yet know the size of the font, we must
7455 load it and try GetTextMetrics. */
4587b026
GV
7456 W32FontStruct thisinfo;
7457 LOGFONT lf;
7458 HDC hdc;
7459 HANDLE oldobj;
7460
d5db4077 7461 if (!x_to_w32_font (SDATA (XCAR (tem)), &lf))
4587b026
GV
7462 continue;
7463
7464 BLOCK_INPUT;
33d52f9c 7465 thisinfo.bdf = NULL;
4587b026
GV
7466 thisinfo.hfont = CreateFontIndirect (&lf);
7467 if (thisinfo.hfont == NULL)
7468 continue;
7469
7470 hdc = GetDC (dpyinfo->root_window);
7471 oldobj = SelectObject (hdc, thisinfo.hfont);
7472 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7473 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7474 else
f3fbd155 7475 XSETCDR (tem, make_number (0));
4587b026
GV
7476 SelectObject (hdc, oldobj);
7477 ReleaseDC (dpyinfo->root_window, hdc);
7478 DeleteObject(thisinfo.hfont);
7479 UNBLOCK_INPUT;
7480 }
8e713be6 7481 found_size = XINT (XCDR (tem));
4587b026 7482 if (found_size == size)
5ca0cd71 7483 {
8e713be6 7484 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7485 n_fonts++;
7486 if (n_fonts >= maxnames)
7487 break;
7488 }
4587b026
GV
7489 /* keep track of the closest matching size in case
7490 no exact match is found. */
7491 else if (found_size > 0)
7492 {
7493 if (NILP (second_best))
7494 second_best = tem;
7d0393cf 7495
4587b026
GV
7496 else if (found_size < size)
7497 {
8e713be6
KR
7498 if (XINT (XCDR (second_best)) > size
7499 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7500 second_best = tem;
7501 }
7502 else
7503 {
8e713be6
KR
7504 if (XINT (XCDR (second_best)) > size
7505 && XINT (XCDR (second_best)) >
4587b026
GV
7506 found_size)
7507 second_best = tem;
7508 }
7509 }
7510 }
7511
7512 if (!NILP (newlist))
7513 break;
7514 else if (!NILP (second_best))
7515 {
8e713be6 7516 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7517 break;
7518 }
7519 }
7520
33d52f9c 7521 /* Include any bdf fonts. */
5ca0cd71 7522 if (n_fonts < maxnames)
33d52f9c
GV
7523 {
7524 Lisp_Object combined[2];
5ca0cd71 7525 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7526 combined[1] = newlist;
7527 newlist = Fnconc(2, combined);
7528 }
7529
4587b026
GV
7530 return newlist;
7531}
7532
5ca0cd71 7533
4587b026
GV
7534/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7535struct font_info *
7536w32_get_font_info (f, font_idx)
7537 FRAME_PTR f;
7538 int font_idx;
7539{
7540 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7541}
7542
7543
7544struct font_info*
7545w32_query_font (struct frame *f, char *fontname)
7546{
7547 int i;
7548 struct font_info *pfi;
7549
7550 pfi = FRAME_W32_FONT_TABLE (f);
7551
7552 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7553 {
7554 if (strcmp(pfi->name, fontname) == 0) return pfi;
7555 }
7556
7557 return NULL;
7558}
7559
7560/* Find a CCL program for a font specified by FONTP, and set the member
7561 `encoder' of the structure. */
7562
7563void
7564w32_find_ccl_program (fontp)
7565 struct font_info *fontp;
7566{
3545439c 7567 Lisp_Object list, elt;
4587b026 7568
8e713be6 7569 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7570 {
8e713be6 7571 elt = XCAR (list);
4587b026 7572 if (CONSP (elt)
8e713be6
KR
7573 && STRINGP (XCAR (elt))
7574 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7575 >= 0))
3545439c
KH
7576 break;
7577 }
7578 if (! NILP (list))
7579 {
17eedd00
KH
7580 struct ccl_program *ccl
7581 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7582
8e713be6 7583 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7584 xfree (ccl);
7585 else
7586 fontp->font_encoder = ccl;
4587b026
GV
7587 }
7588}
7589
7590\f
8edb0a6f
JR
7591/* Find BDF files in a specified directory. (use GCPRO when calling,
7592 as this calls lisp to get a directory listing). */
7593static Lisp_Object
7594w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7595{
7596 Lisp_Object filelist, list = Qnil;
7597 char fontname[100];
7598
7599 if (!STRINGP(directory))
7600 return Qnil;
7601
7602 filelist = Fdirectory_files (directory, Qt,
7603 build_string (".*\\.[bB][dD][fF]"), Qt);
7604
7605 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7606 {
7607 Lisp_Object filename = XCAR (filelist);
d5db4077 7608 if (w32_BDF_to_x_font (SDATA (filename), fontname, 100))
8edb0a6f
JR
7609 store_in_alist (&list, build_string (fontname), filename);
7610 }
7611 return list;
7612}
7613
6fc2811b
JR
7614DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7615 1, 1, 0,
b3700ae7
JR
7616 doc: /* Return a list of BDF fonts in DIR.
7617The list is suitable for appending to w32-bdf-filename-alist. Fonts
7618which do not contain an xlfd description will not be included in the
7619list. DIR may be a list of directories. */)
6fc2811b
JR
7620 (directory)
7621 Lisp_Object directory;
7622{
7623 Lisp_Object list = Qnil;
7624 struct gcpro gcpro1, gcpro2;
ee78dc32 7625
6fc2811b
JR
7626 if (!CONSP (directory))
7627 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7628
6fc2811b 7629 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7630 {
6fc2811b
JR
7631 Lisp_Object pair[2];
7632 pair[0] = list;
7633 pair[1] = Qnil;
7634 GCPRO2 (directory, list);
7635 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7636 list = Fnconc( 2, pair );
7637 UNGCPRO;
7638 }
7639 return list;
7640}
ee78dc32 7641
6fc2811b
JR
7642\f
7643DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7644 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7645 (color, frame)
7646 Lisp_Object color, frame;
7647{
7648 XColor foo;
7649 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7650
b7826503 7651 CHECK_STRING (color);
ee78dc32 7652
d5db4077 7653 if (w32_defined_color (f, SDATA (color), &foo, 0))
6fc2811b
JR
7654 return Qt;
7655 else
7656 return Qnil;
7657}
ee78dc32 7658
2d764c78 7659DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7660 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7661 (color, frame)
7662 Lisp_Object color, frame;
7663{
6fc2811b 7664 XColor foo;
ee78dc32
GV
7665 FRAME_PTR f = check_x_frame (frame);
7666
b7826503 7667 CHECK_STRING (color);
ee78dc32 7668
d5db4077 7669 if (w32_defined_color (f, SDATA (color), &foo, 0))
ee78dc32
GV
7670 {
7671 Lisp_Object rgb[3];
7672
6fc2811b
JR
7673 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7674 | GetRValue (foo.pixel));
7675 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7676 | GetGValue (foo.pixel));
7677 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7678 | GetBValue (foo.pixel));
ee78dc32
GV
7679 return Flist (3, rgb);
7680 }
7681 else
7682 return Qnil;
7683}
7684
2d764c78 7685DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7686 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7687 (display)
7688 Lisp_Object display;
7689{
fbd6baed 7690 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7691
7692 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7693 return Qnil;
7694
7695 return Qt;
7696}
7697
74e1aeec
JR
7698DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7699 Sx_display_grayscale_p, 0, 1, 0,
7700 doc: /* Return t if the X display supports shades of gray.
7701Note that color displays do support shades of gray.
7702The optional argument DISPLAY specifies which display to ask about.
7703DISPLAY should be either a frame or a display name (a string).
7704If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7705 (display)
7706 Lisp_Object display;
7707{
fbd6baed 7708 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7709
7710 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7711 return Qnil;
7712
7713 return Qt;
7714}
7715
74e1aeec
JR
7716DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7717 Sx_display_pixel_width, 0, 1, 0,
7718 doc: /* Returns the width in pixels of DISPLAY.
7719The optional argument DISPLAY specifies which display to ask about.
7720DISPLAY should be either a frame or a display name (a string).
7721If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7722 (display)
7723 Lisp_Object display;
7724{
fbd6baed 7725 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7726
7727 return make_number (dpyinfo->width);
7728}
7729
7730DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7731 Sx_display_pixel_height, 0, 1, 0,
7732 doc: /* Returns the height in pixels of DISPLAY.
7733The optional argument DISPLAY specifies which display to ask about.
7734DISPLAY should be either a frame or a display name (a string).
7735If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7736 (display)
7737 Lisp_Object display;
7738{
fbd6baed 7739 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7740
7741 return make_number (dpyinfo->height);
7742}
7743
7744DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7745 0, 1, 0,
7746 doc: /* Returns the number of bitplanes of DISPLAY.
7747The optional argument DISPLAY specifies which display to ask about.
7748DISPLAY should be either a frame or a display name (a string).
7749If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7750 (display)
7751 Lisp_Object display;
7752{
fbd6baed 7753 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7754
7755 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7756}
7757
7758DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7759 0, 1, 0,
7760 doc: /* Returns the number of color cells of DISPLAY.
7761The optional argument DISPLAY specifies which display to ask about.
7762DISPLAY should be either a frame or a display name (a string).
7763If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7764 (display)
7765 Lisp_Object display;
7766{
fbd6baed 7767 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7768 HDC hdc;
7769 int cap;
7770
5ac45f98
GV
7771 hdc = GetDC (dpyinfo->root_window);
7772 if (dpyinfo->has_palette)
7773 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7774 else
7775 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b 7776
007776bc
JB
7777 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7778 and because probably is more meaningful on Windows anyway */
abf8c61b 7779 if (cap < 0)
007776bc 7780 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
7d0393cf 7781
ee78dc32 7782 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 7783
ee78dc32
GV
7784 return make_number (cap);
7785}
7786
7787DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7788 Sx_server_max_request_size,
74e1aeec
JR
7789 0, 1, 0,
7790 doc: /* Returns the maximum request size of the server of DISPLAY.
7791The optional argument DISPLAY specifies which display to ask about.
7792DISPLAY should be either a frame or a display name (a string).
7793If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7794 (display)
7795 Lisp_Object display;
7796{
fbd6baed 7797 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7798
7799 return make_number (1);
7800}
7801
7802DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7803 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7804The optional argument DISPLAY specifies which display to ask about.
7805DISPLAY should be either a frame or a display name (a string).
7806If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7807 (display)
7808 Lisp_Object display;
7809{
dfff8a69 7810 return build_string ("Microsoft Corp.");
ee78dc32
GV
7811}
7812
7813DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7814 doc: /* Returns the version numbers of the server of DISPLAY.
7815The value is a list of three integers: the major and minor
7816version numbers, and the vendor-specific release
7817number. See also the function `x-server-vendor'.
7818
7819The optional argument DISPLAY specifies which display to ask about.
7820DISPLAY should be either a frame or a display name (a string).
7821If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7822 (display)
7823 Lisp_Object display;
7824{
fbd6baed 7825 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7826 Fcons (make_number (w32_minor_version),
7827 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7828}
7829
7830DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7831 doc: /* Returns the number of screens on the server of DISPLAY.
7832The optional argument DISPLAY specifies which display to ask about.
7833DISPLAY should be either a frame or a display name (a string).
7834If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7835 (display)
7836 Lisp_Object display;
7837{
ee78dc32
GV
7838 return make_number (1);
7839}
7840
74e1aeec
JR
7841DEFUN ("x-display-mm-height", Fx_display_mm_height,
7842 Sx_display_mm_height, 0, 1, 0,
7843 doc: /* Returns the height in millimeters of DISPLAY.
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 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7851 HDC hdc;
7852 int cap;
7853
5ac45f98 7854 hdc = GetDC (dpyinfo->root_window);
7d0393cf 7855
ee78dc32 7856 cap = GetDeviceCaps (hdc, VERTSIZE);
7d0393cf 7857
ee78dc32 7858 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 7859
ee78dc32
GV
7860 return make_number (cap);
7861}
7862
7863DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7864 doc: /* Returns the width in millimeters of DISPLAY.
7865The optional argument DISPLAY specifies which display to ask about.
7866DISPLAY should be either a frame or a display name (a string).
7867If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7868 (display)
7869 Lisp_Object display;
7870{
fbd6baed 7871 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7872
7873 HDC hdc;
7874 int cap;
7875
5ac45f98 7876 hdc = GetDC (dpyinfo->root_window);
7d0393cf 7877
ee78dc32 7878 cap = GetDeviceCaps (hdc, HORZSIZE);
7d0393cf 7879
ee78dc32 7880 ReleaseDC (dpyinfo->root_window, hdc);
7d0393cf 7881
ee78dc32
GV
7882 return make_number (cap);
7883}
7884
7885DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7886 Sx_display_backing_store, 0, 1, 0,
7887 doc: /* Returns an indication of whether DISPLAY does backing store.
7888The value may be `always', `when-mapped', or `not-useful'.
7889The optional argument DISPLAY specifies which display to ask about.
7890DISPLAY should be either a frame or a display name (a string).
7891If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7892 (display)
7893 Lisp_Object display;
7894{
7895 return intern ("not-useful");
7896}
7897
7898DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7899 Sx_display_visual_class, 0, 1, 0,
7900 doc: /* Returns the visual class of DISPLAY.
7901The value is one of the symbols `static-gray', `gray-scale',
7902`static-color', `pseudo-color', `true-color', or `direct-color'.
7903
7904The optional argument DISPLAY specifies which display to ask about.
7905DISPLAY should be either a frame or a display name (a string).
7906If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7907 (display)
7908 Lisp_Object display;
7909{
fbd6baed 7910 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7911 Lisp_Object result = Qnil;
ee78dc32 7912
abf8c61b
AI
7913 if (dpyinfo->has_palette)
7914 result = intern ("pseudo-color");
7915 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7916 result = intern ("static-grey");
7917 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7918 result = intern ("static-color");
7919 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7920 result = intern ("true-color");
ee78dc32 7921
abf8c61b 7922 return result;
ee78dc32
GV
7923}
7924
7925DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7926 Sx_display_save_under, 0, 1, 0,
7927 doc: /* Returns t if DISPLAY supports the save-under feature.
7928The optional argument DISPLAY specifies which display to ask about.
7929DISPLAY should be either a frame or a display name (a string).
7930If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7931 (display)
7932 Lisp_Object display;
7933{
6fc2811b
JR
7934 return Qnil;
7935}
7936\f
7937int
7938x_pixel_width (f)
7939 register struct frame *f;
7940{
7941 return PIXEL_WIDTH (f);
7942}
7943
7944int
7945x_pixel_height (f)
7946 register struct frame *f;
7947{
7948 return PIXEL_HEIGHT (f);
7949}
7950
7951int
7952x_char_width (f)
7953 register struct frame *f;
7954{
7955 return FONT_WIDTH (f->output_data.w32->font);
7956}
7957
7958int
7959x_char_height (f)
7960 register struct frame *f;
7961{
7962 return f->output_data.w32->line_height;
7963}
7964
7965int
7966x_screen_planes (f)
7967 register struct frame *f;
7968{
7969 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7970}
7971\f
7972/* Return the display structure for the display named NAME.
7973 Open a new connection if necessary. */
7974
7975struct w32_display_info *
7976x_display_info_for_name (name)
7977 Lisp_Object name;
7978{
7979 Lisp_Object names;
7980 struct w32_display_info *dpyinfo;
7981
b7826503 7982 CHECK_STRING (name);
6fc2811b
JR
7983
7984 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7985 dpyinfo;
7986 dpyinfo = dpyinfo->next, names = XCDR (names))
7987 {
7988 Lisp_Object tem;
7989 tem = Fstring_equal (XCAR (XCAR (names)), name);
7990 if (!NILP (tem))
7991 return dpyinfo;
7992 }
7993
7994 /* Use this general default value to start with. */
7995 Vx_resource_name = Vinvocation_name;
7996
7997 validate_x_resource_name ();
7998
7999 dpyinfo = w32_term_init (name, (unsigned char *)0,
d5db4077 8000 (char *) SDATA (Vx_resource_name));
6fc2811b
JR
8001
8002 if (dpyinfo == 0)
d5db4077 8003 error ("Cannot connect to server %s", SDATA (name));
6fc2811b
JR
8004
8005 w32_in_use = 1;
8006 XSETFASTINT (Vwindow_system_version, 3);
8007
8008 return dpyinfo;
8009}
8010
8011DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
8012 1, 3, 0, doc: /* Open a connection to a server.
8013DISPLAY is the name of the display to connect to.
8014Optional second arg XRM-STRING is a string of resources in xrdb format.
8015If the optional third arg MUST-SUCCEED is non-nil,
8016terminate Emacs if we can't open the connection. */)
6fc2811b
JR
8017 (display, xrm_string, must_succeed)
8018 Lisp_Object display, xrm_string, must_succeed;
8019{
8020 unsigned char *xrm_option;
8021 struct w32_display_info *dpyinfo;
8022
74e1aeec
JR
8023 /* If initialization has already been done, return now to avoid
8024 overwriting critical parts of one_w32_display_info. */
8025 if (w32_in_use)
8026 return Qnil;
8027
b7826503 8028 CHECK_STRING (display);
6fc2811b 8029 if (! NILP (xrm_string))
b7826503 8030 CHECK_STRING (xrm_string);
6fc2811b
JR
8031
8032 if (! EQ (Vwindow_system, intern ("w32")))
8033 error ("Not using Microsoft Windows");
8034
8035 /* Allow color mapping to be defined externally; first look in user's
8036 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8037 {
8038 Lisp_Object color_file;
8039 struct gcpro gcpro1;
8040
8041 color_file = build_string("~/rgb.txt");
8042
8043 GCPRO1 (color_file);
8044
8045 if (NILP (Ffile_readable_p (color_file)))
8046 color_file =
8047 Fexpand_file_name (build_string ("rgb.txt"),
8048 Fsymbol_value (intern ("data-directory")));
8049
8050 Vw32_color_map = Fw32_load_color_file (color_file);
8051
8052 UNGCPRO;
8053 }
8054 if (NILP (Vw32_color_map))
8055 Vw32_color_map = Fw32_default_color_map ();
8056
8057 if (! NILP (xrm_string))
d5db4077 8058 xrm_option = (unsigned char *) SDATA (xrm_string);
6fc2811b
JR
8059 else
8060 xrm_option = (unsigned char *) 0;
8061
8062 /* Use this general default value to start with. */
8063 /* First remove .exe suffix from invocation-name - it looks ugly. */
8064 {
8065 char basename[ MAX_PATH ], *str;
8066
d5db4077 8067 strcpy (basename, SDATA (Vinvocation_name));
6fc2811b
JR
8068 str = strrchr (basename, '.');
8069 if (str) *str = 0;
8070 Vinvocation_name = build_string (basename);
8071 }
8072 Vx_resource_name = Vinvocation_name;
8073
8074 validate_x_resource_name ();
8075
8076 /* This is what opens the connection and sets x_current_display.
8077 This also initializes many symbols, such as those used for input. */
8078 dpyinfo = w32_term_init (display, xrm_option,
d5db4077 8079 (char *) SDATA (Vx_resource_name));
6fc2811b
JR
8080
8081 if (dpyinfo == 0)
8082 {
8083 if (!NILP (must_succeed))
8084 fatal ("Cannot connect to server %s.\n",
d5db4077 8085 SDATA (display));
6fc2811b 8086 else
d5db4077 8087 error ("Cannot connect to server %s", SDATA (display));
6fc2811b
JR
8088 }
8089
8090 w32_in_use = 1;
8091
8092 XSETFASTINT (Vwindow_system_version, 3);
8093 return Qnil;
8094}
8095
8096DEFUN ("x-close-connection", Fx_close_connection,
8097 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
8098 doc: /* Close the connection to DISPLAY's server.
8099For DISPLAY, specify either a frame or a display name (a string).
8100If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
8101 (display)
8102 Lisp_Object display;
8103{
8104 struct w32_display_info *dpyinfo = check_x_display_info (display);
8105 int i;
8106
8107 if (dpyinfo->reference_count > 0)
8108 error ("Display still has frames on it");
8109
8110 BLOCK_INPUT;
8111 /* Free the fonts in the font table. */
8112 for (i = 0; i < dpyinfo->n_fonts; i++)
8113 if (dpyinfo->font_table[i].name)
8114 {
126f2e35
JR
8115 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8116 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 8117 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
8118 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8119 }
8120 x_destroy_all_bitmaps (dpyinfo);
8121
8122 x_delete_display (dpyinfo);
8123 UNBLOCK_INPUT;
8124
8125 return Qnil;
8126}
8127
8128DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 8129 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
8130 ()
8131{
8132 Lisp_Object tail, result;
8133
8134 result = Qnil;
8135 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8136 result = Fcons (XCAR (XCAR (tail)), result);
8137
8138 return result;
8139}
8140
8141DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
8142 doc: /* This is a noop on W32 systems. */)
8143 (on, display)
8144 Lisp_Object display, on;
6fc2811b 8145{
6fc2811b
JR
8146 return Qnil;
8147}
8148
8149\f
6fc2811b
JR
8150/***********************************************************************
8151 Image types
8152 ***********************************************************************/
8153
8154/* Value is the number of elements of vector VECTOR. */
8155
8156#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8157
8158/* List of supported image types. Use define_image_type to add new
8159 types. Use lookup_image_type to find a type for a given symbol. */
8160
8161static struct image_type *image_types;
8162
6fc2811b
JR
8163/* The symbol `image' which is the car of the lists used to represent
8164 images in Lisp. */
8165
8166extern Lisp_Object Qimage;
8167
8168/* The symbol `xbm' which is used as the type symbol for XBM images. */
8169
8170Lisp_Object Qxbm;
8171
8172/* Keywords. */
8173
6fc2811b 8174extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
8175extern Lisp_Object QCdata, QCtype;
8176Lisp_Object QCascent, QCmargin, QCrelief;
a93f4566 8177Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 8178Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
8179
8180/* Other symbols. */
8181
3cf3436e 8182Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
8183
8184/* Time in seconds after which images should be removed from the cache
8185 if not displayed. */
8186
8187Lisp_Object Vimage_cache_eviction_delay;
8188
8189/* Function prototypes. */
8190
8191static void define_image_type P_ ((struct image_type *type));
8192static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8193static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8194static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 8195static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
8196static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8197 Lisp_Object));
8198
dfff8a69 8199
6fc2811b
JR
8200/* Define a new image type from TYPE. This adds a copy of TYPE to
8201 image_types and adds the symbol *TYPE->type to Vimage_types. */
8202
8203static void
8204define_image_type (type)
8205 struct image_type *type;
8206{
8207 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8208 The initialized data segment is read-only. */
8209 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8210 bcopy (type, p, sizeof *p);
8211 p->next = image_types;
8212 image_types = p;
8213 Vimage_types = Fcons (*p->type, Vimage_types);
8214}
8215
8216
8217/* Look up image type SYMBOL, and return a pointer to its image_type
8218 structure. Value is null if SYMBOL is not a known image type. */
8219
8220static INLINE struct image_type *
8221lookup_image_type (symbol)
8222 Lisp_Object symbol;
8223{
8224 struct image_type *type;
8225
8226 for (type = image_types; type; type = type->next)
8227 if (EQ (symbol, *type->type))
8228 break;
8229
8230 return type;
8231}
8232
8233
8234/* Value is non-zero if OBJECT is a valid Lisp image specification. A
8235 valid image specification is a list whose car is the symbol
8236 `image', and whose rest is a property list. The property list must
8237 contain a value for key `:type'. That value must be the name of a
8238 supported image type. The rest of the property list depends on the
8239 image type. */
8240
8241int
8242valid_image_p (object)
8243 Lisp_Object object;
8244{
8245 int valid_p = 0;
7d0393cf 8246
6fc2811b
JR
8247 if (CONSP (object) && EQ (XCAR (object), Qimage))
8248 {
3cf3436e
JR
8249 Lisp_Object tem;
8250
8251 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8252 if (EQ (XCAR (tem), QCtype))
8253 {
8254 tem = XCDR (tem);
8255 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8256 {
8257 struct image_type *type;
8258 type = lookup_image_type (XCAR (tem));
8259 if (type)
8260 valid_p = type->valid_p (object);
8261 }
8262
8263 break;
8264 }
6fc2811b
JR
8265 }
8266
8267 return valid_p;
8268}
8269
8270
8271/* Log error message with format string FORMAT and argument ARG.
8272 Signaling an error, e.g. when an image cannot be loaded, is not a
8273 good idea because this would interrupt redisplay, and the error
8274 message display would lead to another redisplay. This function
8275 therefore simply displays a message. */
8276
8277static void
8278image_error (format, arg1, arg2)
8279 char *format;
8280 Lisp_Object arg1, arg2;
8281{
8282 add_to_log (format, arg1, arg2);
8283}
8284
8285
8286\f
8287/***********************************************************************
8288 Image specifications
8289 ***********************************************************************/
8290
8291enum image_value_type
8292{
8293 IMAGE_DONT_CHECK_VALUE_TYPE,
8294 IMAGE_STRING_VALUE,
3cf3436e 8295 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
8296 IMAGE_SYMBOL_VALUE,
8297 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8298 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8299 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8300 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8301 IMAGE_INTEGER_VALUE,
8302 IMAGE_FUNCTION_VALUE,
8303 IMAGE_NUMBER_VALUE,
8304 IMAGE_BOOL_VALUE
8305};
8306
8307/* Structure used when parsing image specifications. */
8308
8309struct image_keyword
8310{
8311 /* Name of keyword. */
8312 char *name;
8313
8314 /* The type of value allowed. */
8315 enum image_value_type type;
8316
8317 /* Non-zero means key must be present. */
8318 int mandatory_p;
8319
8320 /* Used to recognize duplicate keywords in a property list. */
8321 int count;
8322
8323 /* The value that was found. */
8324 Lisp_Object value;
8325};
8326
8327
8328static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8329 int, Lisp_Object));
8330static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8331
8332
8333/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8334 has the format (image KEYWORD VALUE ...). One of the keyword/
8335 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8336 image_keywords structures of size NKEYWORDS describing other
8337 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8338
8339static int
8340parse_image_spec (spec, keywords, nkeywords, type)
8341 Lisp_Object spec;
8342 struct image_keyword *keywords;
8343 int nkeywords;
8344 Lisp_Object type;
8345{
8346 int i;
8347 Lisp_Object plist;
8348
8349 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8350 return 0;
8351
8352 plist = XCDR (spec);
8353 while (CONSP (plist))
8354 {
8355 Lisp_Object key, value;
8356
8357 /* First element of a pair must be a symbol. */
8358 key = XCAR (plist);
8359 plist = XCDR (plist);
8360 if (!SYMBOLP (key))
8361 return 0;
8362
8363 /* There must follow a value. */
8364 if (!CONSP (plist))
8365 return 0;
8366 value = XCAR (plist);
8367 plist = XCDR (plist);
8368
8369 /* Find key in KEYWORDS. Error if not found. */
8370 for (i = 0; i < nkeywords; ++i)
d5db4077 8371 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
6fc2811b
JR
8372 break;
8373
8374 if (i == nkeywords)
8375 continue;
8376
8377 /* Record that we recognized the keyword. If a keywords
8378 was found more than once, it's an error. */
8379 keywords[i].value = value;
8380 ++keywords[i].count;
7d0393cf 8381
6fc2811b
JR
8382 if (keywords[i].count > 1)
8383 return 0;
8384
8385 /* Check type of value against allowed type. */
8386 switch (keywords[i].type)
8387 {
8388 case IMAGE_STRING_VALUE:
8389 if (!STRINGP (value))
8390 return 0;
8391 break;
8392
3cf3436e
JR
8393 case IMAGE_STRING_OR_NIL_VALUE:
8394 if (!STRINGP (value) && !NILP (value))
8395 return 0;
8396 break;
8397
6fc2811b
JR
8398 case IMAGE_SYMBOL_VALUE:
8399 if (!SYMBOLP (value))
8400 return 0;
8401 break;
8402
8403 case IMAGE_POSITIVE_INTEGER_VALUE:
8404 if (!INTEGERP (value) || XINT (value) <= 0)
8405 return 0;
8406 break;
8407
8edb0a6f
JR
8408 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8409 if (INTEGERP (value) && XINT (value) >= 0)
8410 break;
8411 if (CONSP (value)
8412 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8413 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8414 break;
8415 return 0;
8416
dfff8a69
JR
8417 case IMAGE_ASCENT_VALUE:
8418 if (SYMBOLP (value) && EQ (value, Qcenter))
8419 break;
8420 else if (INTEGERP (value)
8421 && XINT (value) >= 0
8422 && XINT (value) <= 100)
8423 break;
8424 return 0;
8425
6fc2811b
JR
8426 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8427 if (!INTEGERP (value) || XINT (value) < 0)
8428 return 0;
8429 break;
8430
8431 case IMAGE_DONT_CHECK_VALUE_TYPE:
8432 break;
8433
8434 case IMAGE_FUNCTION_VALUE:
8435 value = indirect_function (value);
7d0393cf 8436 if (SUBRP (value)
6fc2811b
JR
8437 || COMPILEDP (value)
8438 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8439 break;
8440 return 0;
8441
8442 case IMAGE_NUMBER_VALUE:
8443 if (!INTEGERP (value) && !FLOATP (value))
8444 return 0;
8445 break;
8446
8447 case IMAGE_INTEGER_VALUE:
8448 if (!INTEGERP (value))
8449 return 0;
8450 break;
8451
8452 case IMAGE_BOOL_VALUE:
8453 if (!NILP (value) && !EQ (value, Qt))
8454 return 0;
8455 break;
8456
8457 default:
8458 abort ();
8459 break;
8460 }
8461
8462 if (EQ (key, QCtype) && !EQ (type, value))
8463 return 0;
8464 }
8465
8466 /* Check that all mandatory fields are present. */
8467 for (i = 0; i < nkeywords; ++i)
8468 if (keywords[i].mandatory_p && keywords[i].count == 0)
8469 return 0;
8470
8471 return NILP (plist);
8472}
8473
8474
8475/* Return the value of KEY in image specification SPEC. Value is nil
8476 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8477 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8478
8479static Lisp_Object
8480image_spec_value (spec, key, found)
8481 Lisp_Object spec, key;
8482 int *found;
8483{
8484 Lisp_Object tail;
7d0393cf 8485
6fc2811b
JR
8486 xassert (valid_image_p (spec));
8487
8488 for (tail = XCDR (spec);
8489 CONSP (tail) && CONSP (XCDR (tail));
8490 tail = XCDR (XCDR (tail)))
8491 {
8492 if (EQ (XCAR (tail), key))
8493 {
8494 if (found)
8495 *found = 1;
8496 return XCAR (XCDR (tail));
8497 }
8498 }
7d0393cf 8499
6fc2811b
JR
8500 if (found)
8501 *found = 0;
8502 return Qnil;
8503}
7d0393cf 8504
6fc2811b 8505
ac849ba4
JR
8506DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8507 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8508PIXELS non-nil means return the size in pixels, otherwise return the
8509size in canonical character units.
8510FRAME is the frame on which the image will be displayed. FRAME nil
8511or omitted means use the selected frame. */)
8512 (spec, pixels, frame)
8513 Lisp_Object spec, pixels, frame;
8514{
8515 Lisp_Object size;
8516
8517 size = Qnil;
8518 if (valid_image_p (spec))
8519 {
8520 struct frame *f = check_x_frame (frame);
8521 int id = lookup_image (f, spec);
8522 struct image *img = IMAGE_FROM_ID (f, id);
8523 int width = img->width + 2 * img->hmargin;
8524 int height = img->height + 2 * img->vmargin;
7d0393cf 8525
ac849ba4
JR
8526 if (NILP (pixels))
8527 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8528 make_float ((double) height / CANON_Y_UNIT (f)));
8529 else
8530 size = Fcons (make_number (width), make_number (height));
8531 }
8532 else
8533 error ("Invalid image specification");
8534
8535 return size;
8536}
8537
8538
8539DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8540 doc: /* Return t if image SPEC has a mask bitmap.
8541FRAME is the frame on which the image will be displayed. FRAME nil
8542or omitted means use the selected frame. */)
8543 (spec, frame)
8544 Lisp_Object spec, frame;
8545{
8546 Lisp_Object mask;
8547
8548 mask = Qnil;
8549 if (valid_image_p (spec))
8550 {
8551 struct frame *f = check_x_frame (frame);
8552 int id = lookup_image (f, spec);
8553 struct image *img = IMAGE_FROM_ID (f, id);
8554 if (img->mask)
8555 mask = Qt;
8556 }
8557 else
8558 error ("Invalid image specification");
8559
8560 return mask;
8561}
6fc2811b
JR
8562
8563\f
8564/***********************************************************************
8565 Image type independent image structures
8566 ***********************************************************************/
8567
8568static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8569static void free_image P_ ((struct frame *f, struct image *img));
197edd35 8570static void x_destroy_x_image P_ ((XImage *));
6fc2811b
JR
8571
8572
8573/* Allocate and return a new image structure for image specification
8574 SPEC. SPEC has a hash value of HASH. */
8575
8576static struct image *
8577make_image (spec, hash)
8578 Lisp_Object spec;
8579 unsigned hash;
8580{
8581 struct image *img = (struct image *) xmalloc (sizeof *img);
7d0393cf 8582
6fc2811b
JR
8583 xassert (valid_image_p (spec));
8584 bzero (img, sizeof *img);
8585 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8586 xassert (img->type != NULL);
8587 img->spec = spec;
8588 img->data.lisp_val = Qnil;
8589 img->ascent = DEFAULT_IMAGE_ASCENT;
8590 img->hash = hash;
8591 return img;
8592}
8593
8594
8595/* Free image IMG which was used on frame F, including its resources. */
8596
8597static void
8598free_image (f, img)
8599 struct frame *f;
8600 struct image *img;
8601{
8602 if (img)
8603 {
8604 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8605
8606 /* Remove IMG from the hash table of its cache. */
8607 if (img->prev)
8608 img->prev->next = img->next;
8609 else
8610 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8611
8612 if (img->next)
8613 img->next->prev = img->prev;
8614
8615 c->images[img->id] = NULL;
8616
8617 /* Free resources, then free IMG. */
8618 img->type->free (f, img);
8619 xfree (img);
8620 }
8621}
8622
8623
8624/* Prepare image IMG for display on frame F. Must be called before
8625 drawing an image. */
8626
8627void
8628prepare_image_for_display (f, img)
8629 struct frame *f;
8630 struct image *img;
8631{
8632 EMACS_TIME t;
8633
8634 /* We're about to display IMG, so set its timestamp to `now'. */
8635 EMACS_GET_TIME (t);
8636 img->timestamp = EMACS_SECS (t);
8637
8638 /* If IMG doesn't have a pixmap yet, load it now, using the image
8639 type dependent loader function. */
8640 if (img->pixmap == 0 && !img->load_failed_p)
8641 img->load_failed_p = img->type->load (f, img) == 0;
8642}
7d0393cf 8643
6fc2811b 8644
dfff8a69
JR
8645/* Value is the number of pixels for the ascent of image IMG when
8646 drawn in face FACE. */
8647
8648int
8649image_ascent (img, face)
8650 struct image *img;
8651 struct face *face;
8652{
8edb0a6f 8653 int height = img->height + img->vmargin;
dfff8a69
JR
8654 int ascent;
8655
8656 if (img->ascent == CENTERED_IMAGE_ASCENT)
8657 {
8658 if (face->font)
8659 ascent = height / 2 - (FONT_DESCENT(face->font)
8660 - FONT_BASE(face->font)) / 2;
8661 else
8662 ascent = height / 2;
8663 }
8664 else
ac849ba4 8665 ascent = (int) (height * img->ascent / 100.0);
dfff8a69
JR
8666
8667 return ascent;
8668}
8669
8670
6fc2811b 8671\f
a05e2bae
JR
8672/* Image background colors. */
8673
ac849ba4
JR
8674/* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8675 context with the bitmap selected. */
8676static COLORREF
197edd35
JR
8677four_corners_best (img_dc, width, height)
8678 HDC img_dc;
a05e2bae
JR
8679 unsigned long width, height;
8680{
ac849ba4 8681 COLORREF corners[4], best;
a05e2bae
JR
8682 int i, best_count;
8683
197edd35
JR
8684 /* Get the colors at the corners of img_dc. */
8685 corners[0] = GetPixel (img_dc, 0, 0);
8686 corners[1] = GetPixel (img_dc, width - 1, 0);
8687 corners[2] = GetPixel (img_dc, width - 1, height - 1);
8688 corners[3] = GetPixel (img_dc, 0, height - 1);
a05e2bae
JR
8689
8690 /* Choose the most frequently found color as background. */
8691 for (i = best_count = 0; i < 4; ++i)
8692 {
8693 int j, n;
7d0393cf 8694
a05e2bae
JR
8695 for (j = n = 0; j < 4; ++j)
8696 if (corners[i] == corners[j])
8697 ++n;
8698
8699 if (n > best_count)
8700 best = corners[i], best_count = n;
8701 }
8702
8703 return best;
a05e2bae
JR
8704}
8705
8706/* Return the `background' field of IMG. If IMG doesn't have one yet,
197edd35
JR
8707 it is guessed heuristically. If non-zero, IMG_DC is an existing
8708 device context with the image selected to use for the heuristic. */
a05e2bae
JR
8709
8710unsigned long
197edd35 8711image_background (img, f, img_dc)
a05e2bae
JR
8712 struct image *img;
8713 struct frame *f;
197edd35 8714 HDC img_dc;
a05e2bae
JR
8715{
8716 if (! img->background_valid)
8717 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8718 {
197edd35
JR
8719 int free_ximg = !img_dc;
8720 HGDIOBJ prev;
8721
8722 if (free_ximg)
8723 {
8724 HDC frame_dc = get_frame_dc (f);
8725 img_dc = CreateCompatibleDC (frame_dc);
8726 release_frame_dc (f, frame_dc);
a05e2bae 8727
197edd35
JR
8728 prev = SelectObject (img_dc, img->pixmap);
8729 }
a05e2bae 8730
197edd35 8731 img->background = four_corners_best (img_dc, img->width, img->height);
a05e2bae
JR
8732
8733 if (free_ximg)
197edd35
JR
8734 {
8735 SelectObject (img_dc, prev);
8736 DeleteDC (img_dc);
8737 }
a05e2bae
JR
8738
8739 img->background_valid = 1;
a05e2bae
JR
8740 }
8741
8742 return img->background;
8743}
8744
8745/* Return the `background_transparent' field of IMG. If IMG doesn't
8746 have one yet, it is guessed heuristically. If non-zero, MASK is an
8747 existing XImage object to use for the heuristic. */
8748
8749int
8750image_background_transparent (img, f, mask)
8751 struct image *img;
8752 struct frame *f;
197edd35 8753 HDC mask;
a05e2bae
JR
8754{
8755 if (! img->background_transparent_valid)
8756 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8757 {
a05e2bae
JR
8758 if (img->mask)
8759 {
8760 int free_mask = !mask;
197edd35 8761 HGDIOBJ prev;
a05e2bae 8762
197edd35
JR
8763 if (free_mask)
8764 {
8765 HDC frame_dc = get_frame_dc (f);
8766 mask = CreateCompatibleDC (frame_dc);
8767 release_frame_dc (f, frame_dc);
8768
8769 prev = SelectObject (mask, img->mask);
8770 }
a05e2bae
JR
8771
8772 img->background_transparent
8773 = !four_corners_best (mask, img->width, img->height);
8774
8775 if (free_mask)
197edd35
JR
8776 {
8777 SelectObject (mask, prev);
8778 DeleteDC (mask);
8779 }
a05e2bae
JR
8780 }
8781 else
a05e2bae
JR
8782 img->background_transparent = 0;
8783
8784 img->background_transparent_valid = 1;
8785 }
8786
8787 return img->background_transparent;
8788}
8789
8790\f
6fc2811b
JR
8791/***********************************************************************
8792 Helper functions for X image types
8793 ***********************************************************************/
8794
a05e2bae
JR
8795static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8796 int, int));
6fc2811b
JR
8797static void x_clear_image P_ ((struct frame *f, struct image *img));
8798static unsigned long x_alloc_image_color P_ ((struct frame *f,
8799 struct image *img,
8800 Lisp_Object color_name,
8801 unsigned long dflt));
8802
a05e2bae
JR
8803
8804/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8805 free the pixmap if any. MASK_P non-zero means clear the mask
8806 pixmap if any. COLORS_P non-zero means free colors allocated for
8807 the image, if any. */
8808
8809static void
8810x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8811 struct frame *f;
8812 struct image *img;
8813 int pixmap_p, mask_p, colors_p;
8814{
a05e2bae
JR
8815 if (pixmap_p && img->pixmap)
8816 {
ac849ba4
JR
8817 DeleteObject (img->pixmap);
8818 img->pixmap = NULL;
a05e2bae
JR
8819 img->background_valid = 0;
8820 }
8821
8822 if (mask_p && img->mask)
8823 {
ac849ba4
JR
8824 DeleteObject (img->mask);
8825 img->mask = NULL;
a05e2bae
JR
8826 img->background_transparent_valid = 0;
8827 }
7d0393cf 8828
a05e2bae
JR
8829 if (colors_p && img->ncolors)
8830 {
bf76fe9c 8831#if 0 /* TODO: color table support. */
a05e2bae 8832 x_free_colors (f, img->colors, img->ncolors);
bf76fe9c 8833#endif
a05e2bae
JR
8834 xfree (img->colors);
8835 img->colors = NULL;
8836 img->ncolors = 0;
8837 }
a05e2bae
JR
8838}
8839
6fc2811b
JR
8840/* Free X resources of image IMG which is used on frame F. */
8841
8842static void
8843x_clear_image (f, img)
8844 struct frame *f;
8845 struct image *img;
8846{
6fc2811b
JR
8847 if (img->pixmap)
8848 {
8849 BLOCK_INPUT;
ac849ba4 8850 DeleteObject (img->pixmap);
6fc2811b
JR
8851 img->pixmap = 0;
8852 UNBLOCK_INPUT;
8853 }
8854
8855 if (img->ncolors)
8856 {
ac849ba4
JR
8857#if 0 /* TODO: color table support */
8858
6fc2811b 8859 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7d0393cf 8860
6fc2811b
JR
8861 /* If display has an immutable color map, freeing colors is not
8862 necessary and some servers don't allow it. So don't do it. */
8863 if (class != StaticColor
8864 && class != StaticGray
8865 && class != TrueColor)
8866 {
8867 Colormap cmap;
8868 BLOCK_INPUT;
8869 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8870 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8871 img->ncolors, 0);
8872 UNBLOCK_INPUT;
8873 }
ac849ba4 8874#endif
7d0393cf 8875
6fc2811b
JR
8876 xfree (img->colors);
8877 img->colors = NULL;
8878 img->ncolors = 0;
8879 }
6fc2811b
JR
8880}
8881
8882
8883/* Allocate color COLOR_NAME for image IMG on frame F. If color
8884 cannot be allocated, use DFLT. Add a newly allocated color to
8885 IMG->colors, so that it can be freed again. Value is the pixel
8886 color. */
8887
8888static unsigned long
8889x_alloc_image_color (f, img, color_name, dflt)
8890 struct frame *f;
8891 struct image *img;
8892 Lisp_Object color_name;
8893 unsigned long dflt;
8894{
6fc2811b
JR
8895 XColor color;
8896 unsigned long result;
8897
8898 xassert (STRINGP (color_name));
8899
d5db4077 8900 if (w32_defined_color (f, SDATA (color_name), &color, 1))
6fc2811b
JR
8901 {
8902 /* This isn't called frequently so we get away with simply
8903 reallocating the color vector to the needed size, here. */
8904 ++img->ncolors;
8905 img->colors =
8906 (unsigned long *) xrealloc (img->colors,
8907 img->ncolors * sizeof *img->colors);
8908 img->colors[img->ncolors - 1] = color.pixel;
8909 result = color.pixel;
8910 }
8911 else
8912 result = dflt;
8913 return result;
6fc2811b
JR
8914}
8915
8916
8917\f
8918/***********************************************************************
8919 Image Cache
8920 ***********************************************************************/
8921
8922static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8923static void postprocess_image P_ ((struct frame *, struct image *));
197edd35 8924static void x_disable_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8925
8926
8927/* Return a new, initialized image cache that is allocated from the
8928 heap. Call free_image_cache to free an image cache. */
8929
8930struct image_cache *
8931make_image_cache ()
8932{
8933 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8934 int size;
7d0393cf 8935
6fc2811b
JR
8936 bzero (c, sizeof *c);
8937 c->size = 50;
8938 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8939 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8940 c->buckets = (struct image **) xmalloc (size);
8941 bzero (c->buckets, size);
8942 return c;
8943}
8944
8945
8946/* Free image cache of frame F. Be aware that X frames share images
8947 caches. */
8948
8949void
8950free_image_cache (f)
8951 struct frame *f;
8952{
8953 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8954 if (c)
8955 {
8956 int i;
8957
8958 /* Cache should not be referenced by any frame when freed. */
8959 xassert (c->refcount == 0);
7d0393cf 8960
6fc2811b
JR
8961 for (i = 0; i < c->used; ++i)
8962 free_image (f, c->images[i]);
8963 xfree (c->images);
8964 xfree (c);
8965 xfree (c->buckets);
8966 FRAME_X_IMAGE_CACHE (f) = NULL;
8967 }
8968}
8969
8970
8971/* Clear image cache of frame F. FORCE_P non-zero means free all
8972 images. FORCE_P zero means clear only images that haven't been
8973 displayed for some time. Should be called from time to time to
dfff8a69
JR
8974 reduce the number of loaded images. If image-eviction-seconds is
8975 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8976 at least that many seconds. */
8977
8978void
8979clear_image_cache (f, force_p)
8980 struct frame *f;
8981 int force_p;
8982{
8983 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8984
8985 if (c && INTEGERP (Vimage_cache_eviction_delay))
8986 {
8987 EMACS_TIME t;
8988 unsigned long old;
0327b4cc 8989 int i, nfreed;
6fc2811b
JR
8990
8991 EMACS_GET_TIME (t);
8992 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7d0393cf 8993
0327b4cc
JR
8994 /* Block input so that we won't be interrupted by a SIGIO
8995 while being in an inconsistent state. */
8996 BLOCK_INPUT;
7d0393cf 8997
0327b4cc 8998 for (i = nfreed = 0; i < c->used; ++i)
6fc2811b
JR
8999 {
9000 struct image *img = c->images[i];
9001 if (img != NULL
0327b4cc 9002 && (force_p || (img->timestamp < old)))
6fc2811b
JR
9003 {
9004 free_image (f, img);
0327b4cc 9005 ++nfreed;
6fc2811b
JR
9006 }
9007 }
9008
9009 /* We may be clearing the image cache because, for example,
9010 Emacs was iconified for a longer period of time. In that
9011 case, current matrices may still contain references to
9012 images freed above. So, clear these matrices. */
0327b4cc 9013 if (nfreed)
6fc2811b 9014 {
0327b4cc 9015 Lisp_Object tail, frame;
7d0393cf 9016
0327b4cc
JR
9017 FOR_EACH_FRAME (tail, frame)
9018 {
9019 struct frame *f = XFRAME (frame);
9020 if (FRAME_W32_P (f)
9021 && FRAME_X_IMAGE_CACHE (f) == c)
9022 clear_current_matrices (f);
9023 }
9024
6fc2811b
JR
9025 ++windows_or_buffers_changed;
9026 }
0327b4cc
JR
9027
9028 UNBLOCK_INPUT;
6fc2811b
JR
9029 }
9030}
9031
9032
9033DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9034 0, 1, 0,
74e1aeec
JR
9035 doc: /* Clear the image cache of FRAME.
9036FRAME nil or omitted means use the selected frame.
9037FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
9038 (frame)
9039 Lisp_Object frame;
9040{
9041 if (EQ (frame, Qt))
9042 {
9043 Lisp_Object tail;
7d0393cf 9044
6fc2811b
JR
9045 FOR_EACH_FRAME (tail, frame)
9046 if (FRAME_W32_P (XFRAME (frame)))
9047 clear_image_cache (XFRAME (frame), 1);
9048 }
9049 else
9050 clear_image_cache (check_x_frame (frame), 1);
9051
9052 return Qnil;
9053}
9054
9055
3cf3436e
JR
9056/* Compute masks and transform image IMG on frame F, as specified
9057 by the image's specification, */
9058
9059static void
9060postprocess_image (f, img)
9061 struct frame *f;
9062 struct image *img;
9063{
3cf3436e
JR
9064 /* Manipulation of the image's mask. */
9065 if (img->pixmap)
9066 {
9067 Lisp_Object conversion, spec;
9068 Lisp_Object mask;
9069
9070 spec = img->spec;
7d0393cf 9071
3cf3436e
JR
9072 /* `:heuristic-mask t'
9073 `:mask heuristic'
9074 means build a mask heuristically.
9075 `:heuristic-mask (R G B)'
9076 `:mask (heuristic (R G B))'
9077 means build a mask from color (R G B) in the
9078 image.
9079 `:mask nil'
9080 means remove a mask, if any. */
7d0393cf 9081
3cf3436e
JR
9082 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9083 if (!NILP (mask))
9084 x_build_heuristic_mask (f, img, mask);
9085 else
9086 {
9087 int found_p;
7d0393cf 9088
3cf3436e 9089 mask = image_spec_value (spec, QCmask, &found_p);
7d0393cf 9090
3cf3436e
JR
9091 if (EQ (mask, Qheuristic))
9092 x_build_heuristic_mask (f, img, Qt);
9093 else if (CONSP (mask)
9094 && EQ (XCAR (mask), Qheuristic))
9095 {
9096 if (CONSP (XCDR (mask)))
9097 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9098 else
9099 x_build_heuristic_mask (f, img, XCDR (mask));
9100 }
9101 else if (NILP (mask) && found_p && img->mask)
9102 {
ac849ba4 9103 DeleteObject (img->mask);
3cf3436e
JR
9104 img->mask = NULL;
9105 }
9106 }
7d0393cf
JB
9107
9108
3cf3436e
JR
9109 /* Should we apply an image transformation algorithm? */
9110 conversion = image_spec_value (spec, QCconversion, NULL);
9111 if (EQ (conversion, Qdisabled))
9112 x_disable_image (f, img);
9113 else if (EQ (conversion, Qlaplace))
9114 x_laplace (f, img);
9115 else if (EQ (conversion, Qemboss))
9116 x_emboss (f, img);
9117 else if (CONSP (conversion)
9118 && EQ (XCAR (conversion), Qedge_detection))
9119 {
9120 Lisp_Object tem;
9121 tem = XCDR (conversion);
9122 if (CONSP (tem))
9123 x_edge_detection (f, img,
9124 Fplist_get (tem, QCmatrix),
9125 Fplist_get (tem, QCcolor_adjustment));
9126 }
9127 }
3cf3436e
JR
9128}
9129
9130
6fc2811b
JR
9131/* Return the id of image with Lisp specification SPEC on frame F.
9132 SPEC must be a valid Lisp image specification (see valid_image_p). */
9133
9134int
9135lookup_image (f, spec)
9136 struct frame *f;
9137 Lisp_Object spec;
9138{
9139 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9140 struct image *img;
9141 int i;
9142 unsigned hash;
9143 struct gcpro gcpro1;
9144 EMACS_TIME now;
9145
9146 /* F must be a window-system frame, and SPEC must be a valid image
9147 specification. */
9148 xassert (FRAME_WINDOW_P (f));
9149 xassert (valid_image_p (spec));
7d0393cf 9150
6fc2811b
JR
9151 GCPRO1 (spec);
9152
9153 /* Look up SPEC in the hash table of the image cache. */
9154 hash = sxhash (spec, 0);
9155 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9156
9157 for (img = c->buckets[i]; img; img = img->next)
9158 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9159 break;
9160
9161 /* If not found, create a new image and cache it. */
9162 if (img == NULL)
9163 {
3cf3436e
JR
9164 extern Lisp_Object Qpostscript;
9165
8edb0a6f 9166 BLOCK_INPUT;
6fc2811b
JR
9167 img = make_image (spec, hash);
9168 cache_image (f, img);
9169 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
9170
9171 /* If we can't load the image, and we don't have a width and
9172 height, use some arbitrary width and height so that we can
9173 draw a rectangle for it. */
9174 if (img->load_failed_p)
9175 {
9176 Lisp_Object value;
9177
9178 value = image_spec_value (spec, QCwidth, NULL);
9179 img->width = (INTEGERP (value)
9180 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9181 value = image_spec_value (spec, QCheight, NULL);
9182 img->height = (INTEGERP (value)
9183 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9184 }
9185 else
9186 {
9187 /* Handle image type independent image attributes
a05e2bae
JR
9188 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9189 `:background COLOR'. */
9190 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
9191
9192 ascent = image_spec_value (spec, QCascent, NULL);
9193 if (INTEGERP (ascent))
9194 img->ascent = XFASTINT (ascent);
dfff8a69
JR
9195 else if (EQ (ascent, Qcenter))
9196 img->ascent = CENTERED_IMAGE_ASCENT;
9197
6fc2811b
JR
9198 margin = image_spec_value (spec, QCmargin, NULL);
9199 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
9200 img->vmargin = img->hmargin = XFASTINT (margin);
9201 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9202 && INTEGERP (XCDR (margin)))
9203 {
9204 if (XINT (XCAR (margin)) > 0)
9205 img->hmargin = XFASTINT (XCAR (margin));
9206 if (XINT (XCDR (margin)) > 0)
9207 img->vmargin = XFASTINT (XCDR (margin));
9208 }
7d0393cf 9209
6fc2811b
JR
9210 relief = image_spec_value (spec, QCrelief, NULL);
9211 if (INTEGERP (relief))
9212 {
9213 img->relief = XINT (relief);
8edb0a6f
JR
9214 img->hmargin += abs (img->relief);
9215 img->vmargin += abs (img->relief);
6fc2811b
JR
9216 }
9217
a05e2bae
JR
9218 if (! img->background_valid)
9219 {
9220 bg = image_spec_value (img->spec, QCbackground, NULL);
9221 if (!NILP (bg))
9222 {
9223 img->background
9224 = x_alloc_image_color (f, img, bg,
9225 FRAME_BACKGROUND_PIXEL (f));
9226 img->background_valid = 1;
9227 }
9228 }
9229
3cf3436e
JR
9230 /* Do image transformations and compute masks, unless we
9231 don't have the image yet. */
9232 if (!EQ (*img->type->type, Qpostscript))
9233 postprocess_image (f, img);
6fc2811b 9234 }
3cf3436e 9235
8edb0a6f
JR
9236 UNBLOCK_INPUT;
9237 xassert (!interrupt_input_blocked);
6fc2811b
JR
9238 }
9239
9240 /* We're using IMG, so set its timestamp to `now'. */
9241 EMACS_GET_TIME (now);
9242 img->timestamp = EMACS_SECS (now);
7d0393cf 9243
6fc2811b 9244 UNGCPRO;
7d0393cf 9245
6fc2811b
JR
9246 /* Value is the image id. */
9247 return img->id;
9248}
9249
9250
9251/* Cache image IMG in the image cache of frame F. */
9252
9253static void
9254cache_image (f, img)
9255 struct frame *f;
9256 struct image *img;
9257{
9258 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9259 int i;
9260
9261 /* Find a free slot in c->images. */
9262 for (i = 0; i < c->used; ++i)
9263 if (c->images[i] == NULL)
9264 break;
9265
9266 /* If no free slot found, maybe enlarge c->images. */
9267 if (i == c->used && c->used == c->size)
9268 {
9269 c->size *= 2;
9270 c->images = (struct image **) xrealloc (c->images,
9271 c->size * sizeof *c->images);
9272 }
9273
9274 /* Add IMG to c->images, and assign IMG an id. */
9275 c->images[i] = img;
9276 img->id = i;
9277 if (i == c->used)
9278 ++c->used;
9279
9280 /* Add IMG to the cache's hash table. */
9281 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9282 img->next = c->buckets[i];
9283 if (img->next)
9284 img->next->prev = img;
9285 img->prev = NULL;
9286 c->buckets[i] = img;
9287}
9288
9289
9290/* Call FN on every image in the image cache of frame F. Used to mark
9291 Lisp Objects in the image cache. */
9292
9293void
9294forall_images_in_image_cache (f, fn)
9295 struct frame *f;
9296 void (*fn) P_ ((struct image *img));
9297{
9298 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9299 {
9300 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9301 if (c)
9302 {
9303 int i;
9304 for (i = 0; i < c->used; ++i)
9305 if (c->images[i])
9306 fn (c->images[i]);
9307 }
9308 }
9309}
9310
9311
9312\f
9313/***********************************************************************
9314 W32 support code
9315 ***********************************************************************/
9316
6fc2811b
JR
9317static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9318 XImage **, Pixmap *));
6fc2811b
JR
9319static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9320
9321
9322/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9323 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9324 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
ac849ba4
JR
9325 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9326 DEPTH should indicate the bit depth of the image. Print error
9327 messages via image_error if an error occurs. Value is non-zero if
9328 successful. */
6fc2811b
JR
9329
9330static int
9331x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9332 struct frame *f;
9333 int width, height, depth;
9334 XImage **ximg;
9335 Pixmap *pixmap;
9336{
ac849ba4
JR
9337 BITMAPINFOHEADER *header;
9338 HDC hdc;
9339 int scanline_width_bits;
9340 int remainder;
9341 int palette_colors = 0;
6fc2811b 9342
ac849ba4
JR
9343 if (depth == 0)
9344 depth = 24;
6fc2811b 9345
ac849ba4
JR
9346 if (depth != 1 && depth != 4 && depth != 8
9347 && depth != 16 && depth != 24 && depth != 32)
9348 {
9349 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9350 return 0;
9351 }
9352
9353 scanline_width_bits = width * depth;
9354 remainder = scanline_width_bits % 32;
9355
9356 if (remainder)
9357 scanline_width_bits += 32 - remainder;
9358
9359 /* Bitmaps with a depth less than 16 need a palette. */
9360 /* BITMAPINFO structure already contains the first RGBQUAD. */
9361 if (depth < 16)
9362 palette_colors = 1 << depth - 1;
9363
9364 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
6fc2811b
JR
9365 if (*ximg == NULL)
9366 {
ac849ba4 9367 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
6fc2811b
JR
9368 return 0;
9369 }
9370
ac849ba4
JR
9371 header = &((*ximg)->info.bmiHeader);
9372 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9373 header->biSize = sizeof (*header);
9374 header->biWidth = width;
9375 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9376 header->biPlanes = 1;
9377 header->biBitCount = depth;
9378 header->biCompression = BI_RGB;
9379 header->biClrUsed = palette_colors;
6fc2811b 9380
197edd35 9381 /* TODO: fill in palette. */
35624c03
JR
9382 if (depth == 1)
9383 {
9384 (*ximg)->info.bmiColors[0].rgbBlue = 0;
9385 (*ximg)->info.bmiColors[0].rgbGreen = 0;
9386 (*ximg)->info.bmiColors[0].rgbRed = 0;
9387 (*ximg)->info.bmiColors[0].rgbReserved = 0;
9388 (*ximg)->info.bmiColors[1].rgbBlue = 255;
9389 (*ximg)->info.bmiColors[1].rgbGreen = 255;
9390 (*ximg)->info.bmiColors[1].rgbRed = 255;
9391 (*ximg)->info.bmiColors[1].rgbReserved = 0;
9392 }
197edd35 9393
ac849ba4
JR
9394 hdc = get_frame_dc (f);
9395
9396 /* Create a DIBSection and raster array for the bitmap,
9397 and store its handle in *pixmap. */
197edd35
JR
9398 *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
9399 (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
ac849ba4
JR
9400 &((*ximg)->data), NULL, 0);
9401
9402 /* Realize display palette and garbage all frames. */
9403 release_frame_dc (f, hdc);
9404
9405 if (*pixmap == NULL)
6fc2811b 9406 {
ac849ba4
JR
9407 DWORD err = GetLastError();
9408 Lisp_Object errcode;
9409 /* All system errors are < 10000, so the following is safe. */
9410 XSETINT (errcode, (int) err);
9411 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
6fc2811b 9412 x_destroy_x_image (*ximg);
6fc2811b
JR
9413 return 0;
9414 }
ac849ba4 9415
6fc2811b
JR
9416 return 1;
9417}
9418
9419
9420/* Destroy XImage XIMG. Free XIMG->data. */
9421
9422static void
9423x_destroy_x_image (ximg)
9424 XImage *ximg;
9425{
9426 xassert (interrupt_input_blocked);
9427 if (ximg)
9428 {
ac849ba4 9429 /* Data will be freed by DestroyObject. */
6fc2811b 9430 ximg->data = NULL;
ac849ba4 9431 xfree (ximg);
6fc2811b
JR
9432 }
9433}
9434
9435
9436/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9437 are width and height of both the image and pixmap. */
9438
9439static void
9440x_put_x_image (f, ximg, pixmap, width, height)
9441 struct frame *f;
9442 XImage *ximg;
9443 Pixmap pixmap;
9444{
197edd35
JR
9445#if 0 /* I don't think this is necessary looking at where it is used. */
9446 HDC hdc = get_frame_dc (f);
9447 SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
9448 release_frame_dc (f, hdc);
6fc2811b 9449#endif
ac849ba4 9450}
6fc2811b
JR
9451
9452\f
9453/***********************************************************************
3cf3436e 9454 File Handling
6fc2811b
JR
9455 ***********************************************************************/
9456
9457static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9458static char *slurp_file P_ ((char *, int *));
9459
6fc2811b
JR
9460
9461/* Find image file FILE. Look in data-directory, then
9462 x-bitmap-file-path. Value is the full name of the file found, or
9463 nil if not found. */
9464
9465static Lisp_Object
9466x_find_image_file (file)
9467 Lisp_Object file;
9468{
9469 Lisp_Object file_found, search_path;
9470 struct gcpro gcpro1, gcpro2;
9471 int fd;
9472
9473 file_found = Qnil;
9474 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9475 GCPRO2 (file_found, search_path);
9476
9477 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 9478 fd = openp (search_path, file, Qnil, &file_found, Qnil);
7d0393cf 9479
939d6465 9480 if (fd == -1)
6fc2811b
JR
9481 file_found = Qnil;
9482 else
9483 close (fd);
9484
9485 UNGCPRO;
9486 return file_found;
9487}
9488
9489
3cf3436e
JR
9490/* Read FILE into memory. Value is a pointer to a buffer allocated
9491 with xmalloc holding FILE's contents. Value is null if an error
9492 occurred. *SIZE is set to the size of the file. */
9493
9494static char *
9495slurp_file (file, size)
9496 char *file;
9497 int *size;
9498{
9499 FILE *fp = NULL;
9500 char *buf = NULL;
9501 struct stat st;
9502
9503 if (stat (file, &st) == 0
9504 && (fp = fopen (file, "r")) != NULL
9505 && (buf = (char *) xmalloc (st.st_size),
9506 fread (buf, 1, st.st_size, fp) == st.st_size))
9507 {
9508 *size = st.st_size;
9509 fclose (fp);
9510 }
9511 else
9512 {
9513 if (fp)
9514 fclose (fp);
9515 if (buf)
9516 {
9517 xfree (buf);
9518 buf = NULL;
9519 }
9520 }
7d0393cf 9521
3cf3436e
JR
9522 return buf;
9523}
9524
9525
6fc2811b
JR
9526\f
9527/***********************************************************************
9528 XBM images
9529 ***********************************************************************/
9530
217e5be0 9531static int xbm_scan P_ ((char **, char *, char *, int *));
6fc2811b 9532static int xbm_load P_ ((struct frame *f, struct image *img));
217e5be0
JR
9533static int xbm_load_image P_ ((struct frame *f, struct image *img,
9534 char *, char *));
6fc2811b 9535static int xbm_image_p P_ ((Lisp_Object object));
217e5be0
JR
9536static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
9537 unsigned char **));
9538static int xbm_file_p P_ ((Lisp_Object));
6fc2811b
JR
9539
9540
9541/* Indices of image specification fields in xbm_format, below. */
9542
9543enum xbm_keyword_index
9544{
9545 XBM_TYPE,
9546 XBM_FILE,
9547 XBM_WIDTH,
9548 XBM_HEIGHT,
9549 XBM_DATA,
9550 XBM_FOREGROUND,
9551 XBM_BACKGROUND,
9552 XBM_ASCENT,
9553 XBM_MARGIN,
9554 XBM_RELIEF,
9555 XBM_ALGORITHM,
9556 XBM_HEURISTIC_MASK,
a05e2bae 9557 XBM_MASK,
6fc2811b
JR
9558 XBM_LAST
9559};
9560
9561/* Vector of image_keyword structures describing the format
9562 of valid XBM image specifications. */
9563
9564static struct image_keyword xbm_format[XBM_LAST] =
9565{
9566 {":type", IMAGE_SYMBOL_VALUE, 1},
9567 {":file", IMAGE_STRING_VALUE, 0},
9568 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9569 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9570 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9571 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9572 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9573 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 9574 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9575 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9576 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9577 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9578 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6fc2811b
JR
9579};
9580
9581/* Structure describing the image type XBM. */
9582
9583static struct image_type xbm_type =
9584{
9585 &Qxbm,
9586 xbm_image_p,
9587 xbm_load,
9588 x_clear_image,
9589 NULL
9590};
9591
9592/* Tokens returned from xbm_scan. */
9593
9594enum xbm_token
9595{
9596 XBM_TK_IDENT = 256,
9597 XBM_TK_NUMBER
9598};
9599
7d0393cf 9600
6fc2811b
JR
9601/* Return non-zero if OBJECT is a valid XBM-type image specification.
9602 A valid specification is a list starting with the symbol `image'
9603 The rest of the list is a property list which must contain an
9604 entry `:type xbm..
9605
9606 If the specification specifies a file to load, it must contain
9607 an entry `:file FILENAME' where FILENAME is a string.
9608
9609 If the specification is for a bitmap loaded from memory it must
9610 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9611 WIDTH and HEIGHT are integers > 0. DATA may be:
9612
9613 1. a string large enough to hold the bitmap data, i.e. it must
9614 have a size >= (WIDTH + 7) / 8 * HEIGHT
9615
9616 2. a bool-vector of size >= WIDTH * HEIGHT
9617
9618 3. a vector of strings or bool-vectors, one for each line of the
9619 bitmap.
9620
217e5be0
JR
9621 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
9622 may not be specified in this case because they are defined in the
9623 XBM file.
9624
6fc2811b
JR
9625 Both the file and data forms may contain the additional entries
9626 `:background COLOR' and `:foreground COLOR'. If not present,
9627 foreground and background of the frame on which the image is
217e5be0 9628 displayed is used. */
6fc2811b
JR
9629
9630static int
9631xbm_image_p (object)
9632 Lisp_Object object;
9633{
9634 struct image_keyword kw[XBM_LAST];
7d0393cf 9635
6fc2811b
JR
9636 bcopy (xbm_format, kw, sizeof kw);
9637 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9638 return 0;
9639
9640 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9641
9642 if (kw[XBM_FILE].count)
9643 {
9644 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9645 return 0;
9646 }
217e5be0
JR
9647 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
9648 {
9649 /* In-memory XBM file. */
9650 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
9651 return 0;
9652 }
6fc2811b
JR
9653 else
9654 {
9655 Lisp_Object data;
9656 int width, height;
9657
9658 /* Entries for `:width', `:height' and `:data' must be present. */
9659 if (!kw[XBM_WIDTH].count
9660 || !kw[XBM_HEIGHT].count
9661 || !kw[XBM_DATA].count)
9662 return 0;
9663
9664 data = kw[XBM_DATA].value;
9665 width = XFASTINT (kw[XBM_WIDTH].value);
9666 height = XFASTINT (kw[XBM_HEIGHT].value);
7d0393cf 9667
6fc2811b
JR
9668 /* Check type of data, and width and height against contents of
9669 data. */
9670 if (VECTORP (data))
9671 {
9672 int i;
7d0393cf 9673
6fc2811b
JR
9674 /* Number of elements of the vector must be >= height. */
9675 if (XVECTOR (data)->size < height)
9676 return 0;
9677
9678 /* Each string or bool-vector in data must be large enough
9679 for one line of the image. */
9680 for (i = 0; i < height; ++i)
9681 {
9682 Lisp_Object elt = XVECTOR (data)->contents[i];
9683
9684 if (STRINGP (elt))
9685 {
d5db4077 9686 if (SCHARS (elt)
6fc2811b
JR
9687 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9688 return 0;
9689 }
9690 else if (BOOL_VECTOR_P (elt))
9691 {
9692 if (XBOOL_VECTOR (elt)->size < width)
9693 return 0;
9694 }
9695 else
9696 return 0;
9697 }
9698 }
9699 else if (STRINGP (data))
9700 {
d5db4077 9701 if (SCHARS (data)
6fc2811b
JR
9702 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9703 return 0;
9704 }
9705 else if (BOOL_VECTOR_P (data))
9706 {
9707 if (XBOOL_VECTOR (data)->size < width * height)
9708 return 0;
9709 }
9710 else
9711 return 0;
9712 }
9713
6fc2811b
JR
9714 return 1;
9715}
9716
9717
9718/* Scan a bitmap file. FP is the stream to read from. Value is
9719 either an enumerator from enum xbm_token, or a character for a
9720 single-character token, or 0 at end of file. If scanning an
9721 identifier, store the lexeme of the identifier in SVAL. If
9722 scanning a number, store its value in *IVAL. */
9723
9724static int
3cf3436e
JR
9725xbm_scan (s, end, sval, ival)
9726 char **s, *end;
6fc2811b
JR
9727 char *sval;
9728 int *ival;
9729{
9730 int c;
3cf3436e
JR
9731
9732 loop:
9733
6fc2811b 9734 /* Skip white space. */
af3f7be7 9735 while (*s < end && (c = *(*s)++, isspace (c)))
6fc2811b
JR
9736 ;
9737
3cf3436e 9738 if (*s >= end)
6fc2811b
JR
9739 c = 0;
9740 else if (isdigit (c))
9741 {
9742 int value = 0, digit;
7d0393cf 9743
3cf3436e 9744 if (c == '0' && *s < end)
6fc2811b 9745 {
3cf3436e 9746 c = *(*s)++;
6fc2811b
JR
9747 if (c == 'x' || c == 'X')
9748 {
3cf3436e 9749 while (*s < end)
6fc2811b 9750 {
3cf3436e 9751 c = *(*s)++;
6fc2811b
JR
9752 if (isdigit (c))
9753 digit = c - '0';
9754 else if (c >= 'a' && c <= 'f')
9755 digit = c - 'a' + 10;
9756 else if (c >= 'A' && c <= 'F')
9757 digit = c - 'A' + 10;
9758 else
9759 break;
9760 value = 16 * value + digit;
9761 }
9762 }
9763 else if (isdigit (c))
9764 {
9765 value = c - '0';
3cf3436e
JR
9766 while (*s < end
9767 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9768 value = 8 * value + c - '0';
9769 }
9770 }
9771 else
9772 {
9773 value = c - '0';
3cf3436e
JR
9774 while (*s < end
9775 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9776 value = 10 * value + c - '0';
9777 }
9778
3cf3436e
JR
9779 if (*s < end)
9780 *s = *s - 1;
6fc2811b
JR
9781 *ival = value;
9782 c = XBM_TK_NUMBER;
9783 }
9784 else if (isalpha (c) || c == '_')
9785 {
9786 *sval++ = c;
3cf3436e
JR
9787 while (*s < end
9788 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9789 *sval++ = c;
9790 *sval = 0;
3cf3436e
JR
9791 if (*s < end)
9792 *s = *s - 1;
6fc2811b
JR
9793 c = XBM_TK_IDENT;
9794 }
3cf3436e
JR
9795 else if (c == '/' && **s == '*')
9796 {
9797 /* C-style comment. */
9798 ++*s;
9799 while (**s && (**s != '*' || *(*s + 1) != '/'))
9800 ++*s;
9801 if (**s)
9802 {
9803 *s += 2;
9804 goto loop;
9805 }
9806 }
6fc2811b
JR
9807
9808 return c;
9809}
9810
9811
217e5be0
JR
9812/* XBM bits seem to be backward within bytes compared with how
9813 Windows does things. */
9814static unsigned char reflect_byte (unsigned char orig)
9815{
9816 int i;
9817 unsigned char reflected = 0x00;
9818 for (i = 0; i < 8; i++)
9819 {
9820 if (orig & (0x01 << i))
9821 reflected |= 0x80 >> i;
9822 }
9823 return reflected;
9824}
9825
9826
af3f7be7
JR
9827/* Create a Windows bitmap from X bitmap data. */
9828static HBITMAP
9829w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
9830{
9831 int i, j, w1, w2;
9832 char *bits, *p;
9833 HBITMAP bmp;
9834
9835 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
9836 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
9837 bits = (char *) xmalloc (height * w2);
9838 bzero (bits, height * w2);
9839 for (i = 0; i < height; i++)
9840 {
9841 p = bits + i*w2;
9842 for (j = 0; j < w1; j++)
9843 *p++ = reflect_byte(*data++);
9844 }
9845 bmp = CreateBitmap (width, height, 1, 1, bits);
9846 xfree (bits);
9847
9848 return bmp;
9849}
9850
9851
6fc2811b 9852/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9853 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9854 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9855 the image. Return in *DATA the bitmap data allocated with xmalloc.
9856 Value is non-zero if successful. DATA null means just test if
9857 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9858
9859static int
3cf3436e
JR
9860xbm_read_bitmap_data (contents, end, width, height, data)
9861 char *contents, *end;
6fc2811b
JR
9862 int *width, *height;
9863 unsigned char **data;
9864{
3cf3436e 9865 char *s = contents;
6fc2811b
JR
9866 char buffer[BUFSIZ];
9867 int padding_p = 0;
9868 int v10 = 0;
af3f7be7 9869 int bytes_per_line, i, nbytes;
6fc2811b
JR
9870 unsigned char *p;
9871 int value;
9872 int LA1;
9873
9874#define match() \
217e5be0 9875 LA1 = xbm_scan (&s, end, buffer, &value)
6fc2811b
JR
9876
9877#define expect(TOKEN) \
9878 if (LA1 != (TOKEN)) \
9879 goto failure; \
9880 else \
7d0393cf 9881 match ()
6fc2811b
JR
9882
9883#define expect_ident(IDENT) \
9884 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9885 match (); \
9886 else \
9887 goto failure
9888
6fc2811b 9889 *width = *height = -1;
3cf3436e
JR
9890 if (data)
9891 *data = NULL;
9892 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9893
9894 /* Parse defines for width, height and hot-spots. */
9895 while (LA1 == '#')
9896 {
9897 match ();
9898 expect_ident ("define");
9899 expect (XBM_TK_IDENT);
9900
9901 if (LA1 == XBM_TK_NUMBER);
9902 {
9903 char *p = strrchr (buffer, '_');
9904 p = p ? p + 1 : buffer;
9905 if (strcmp (p, "width") == 0)
9906 *width = value;
9907 else if (strcmp (p, "height") == 0)
9908 *height = value;
9909 }
9910 expect (XBM_TK_NUMBER);
9911 }
9912
9913 if (*width < 0 || *height < 0)
9914 goto failure;
3cf3436e
JR
9915 else if (data == NULL)
9916 goto success;
6fc2811b
JR
9917
9918 /* Parse bits. Must start with `static'. */
9919 expect_ident ("static");
9920 if (LA1 == XBM_TK_IDENT)
9921 {
9922 if (strcmp (buffer, "unsigned") == 0)
9923 {
7d0393cf 9924 match ();
6fc2811b
JR
9925 expect_ident ("char");
9926 }
9927 else if (strcmp (buffer, "short") == 0)
9928 {
9929 match ();
9930 v10 = 1;
af3f7be7
JR
9931 if (*width % 16 && *width % 16 < 9)
9932 padding_p = 1;
6fc2811b
JR
9933 }
9934 else if (strcmp (buffer, "char") == 0)
9935 match ();
9936 else
9937 goto failure;
9938 }
7d0393cf 9939 else
6fc2811b
JR
9940 goto failure;
9941
9942 expect (XBM_TK_IDENT);
9943 expect ('[');
9944 expect (']');
9945 expect ('=');
9946 expect ('{');
9947
af3f7be7
JR
9948 bytes_per_line = (*width + 7) / 8 + padding_p;
9949 nbytes = bytes_per_line * *height;
9950 p = *data = (char *) xmalloc (nbytes);
6fc2811b
JR
9951
9952 if (v10)
9953 {
6fc2811b
JR
9954 for (i = 0; i < nbytes; i += 2)
9955 {
9956 int val = value;
9957 expect (XBM_TK_NUMBER);
9958
35624c03 9959 *p++ = ~ val;
af3f7be7 9960 if (!padding_p || ((i + 2) % bytes_per_line))
35624c03 9961 *p++ = ~ (value >> 8);
7d0393cf 9962
6fc2811b
JR
9963 if (LA1 == ',' || LA1 == '}')
9964 match ();
9965 else
9966 goto failure;
9967 }
9968 }
9969 else
9970 {
9971 for (i = 0; i < nbytes; ++i)
9972 {
9973 int val = value;
9974 expect (XBM_TK_NUMBER);
7d0393cf 9975
35624c03 9976 *p++ = ~ val;
217e5be0 9977
6fc2811b
JR
9978 if (LA1 == ',' || LA1 == '}')
9979 match ();
9980 else
9981 goto failure;
9982 }
9983 }
9984
3cf3436e 9985 success:
6fc2811b
JR
9986 return 1;
9987
9988 failure:
3cf3436e
JR
9989
9990 if (data && *data)
6fc2811b
JR
9991 {
9992 xfree (*data);
9993 *data = NULL;
9994 }
9995 return 0;
9996
9997#undef match
9998#undef expect
9999#undef expect_ident
10000}
10001
10002
3cf3436e
JR
10003/* Load XBM image IMG which will be displayed on frame F from buffer
10004 CONTENTS. END is the end of the buffer. Value is non-zero if
10005 successful. */
6fc2811b
JR
10006
10007static int
3cf3436e 10008xbm_load_image (f, img, contents, end)
6fc2811b
JR
10009 struct frame *f;
10010 struct image *img;
3cf3436e 10011 char *contents, *end;
6fc2811b
JR
10012{
10013 int rc;
10014 unsigned char *data;
10015 int success_p = 0;
7d0393cf 10016
3cf3436e 10017 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
10018 if (rc)
10019 {
6fc2811b
JR
10020 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10021 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10022 Lisp_Object value;
7d0393cf 10023
6fc2811b
JR
10024 xassert (img->width > 0 && img->height > 0);
10025
10026 /* Get foreground and background colors, maybe allocate colors. */
10027 value = image_spec_value (img->spec, QCforeground, NULL);
10028 if (!NILP (value))
10029 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
10030 value = image_spec_value (img->spec, QCbackground, NULL);
10031 if (!NILP (value))
a05e2bae
JR
10032 {
10033 background = x_alloc_image_color (f, img, value, background);
10034 img->background = background;
10035 img->background_valid = 1;
10036 }
6fc2811b 10037 img->pixmap
af3f7be7 10038 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
ac849ba4 10039
6fc2811b
JR
10040 xfree (data);
10041
10042 if (img->pixmap == 0)
10043 {
10044 x_clear_image (f, img);
3cf3436e 10045 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
10046 }
10047 else
10048 success_p = 1;
6fc2811b
JR
10049 }
10050 else
10051 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10052
6fc2811b
JR
10053 return success_p;
10054}
10055
10056
3cf3436e
JR
10057/* Value is non-zero if DATA looks like an in-memory XBM file. */
10058
10059static int
10060xbm_file_p (data)
10061 Lisp_Object data;
10062{
10063 int w, h;
10064 return (STRINGP (data)
d5db4077
KR
10065 && xbm_read_bitmap_data (SDATA (data),
10066 (SDATA (data)
10067 + SBYTES (data)),
3cf3436e
JR
10068 &w, &h, NULL));
10069}
10070
7d0393cf 10071
6fc2811b
JR
10072/* Fill image IMG which is used on frame F with pixmap data. Value is
10073 non-zero if successful. */
10074
10075static int
10076xbm_load (f, img)
10077 struct frame *f;
10078 struct image *img;
10079{
10080 int success_p = 0;
10081 Lisp_Object file_name;
10082
10083 xassert (xbm_image_p (img->spec));
10084
10085 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10086 file_name = image_spec_value (img->spec, QCfile, NULL);
10087 if (STRINGP (file_name))
3cf3436e
JR
10088 {
10089 Lisp_Object file;
10090 char *contents;
10091 int size;
10092 struct gcpro gcpro1;
10093
10094 file = x_find_image_file (file_name);
10095 GCPRO1 (file);
10096 if (!STRINGP (file))
10097 {
10098 image_error ("Cannot find image file `%s'", file_name, Qnil);
10099 UNGCPRO;
10100 return 0;
10101 }
10102
d5db4077 10103 contents = slurp_file (SDATA (file), &size);
3cf3436e
JR
10104 if (contents == NULL)
10105 {
10106 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10107 UNGCPRO;
10108 return 0;
10109 }
10110
10111 success_p = xbm_load_image (f, img, contents, contents + size);
10112 UNGCPRO;
10113 }
6fc2811b
JR
10114 else
10115 {
10116 struct image_keyword fmt[XBM_LAST];
10117 Lisp_Object data;
6fc2811b
JR
10118 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10119 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10120 char *bits;
10121 int parsed_p;
3cf3436e
JR
10122 int in_memory_file_p = 0;
10123
10124 /* See if data looks like an in-memory XBM file. */
10125 data = image_spec_value (img->spec, QCdata, NULL);
10126 in_memory_file_p = xbm_file_p (data);
6fc2811b 10127
217e5be0 10128 /* Parse the image specification. */
6fc2811b
JR
10129 bcopy (xbm_format, fmt, sizeof fmt);
10130 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10131 xassert (parsed_p);
10132
10133 /* Get specified width, and height. */
3cf3436e
JR
10134 if (!in_memory_file_p)
10135 {
10136 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10137 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10138 xassert (img->width > 0 && img->height > 0);
10139 }
217e5be0 10140
6fc2811b 10141 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
10142 if (fmt[XBM_FOREGROUND].count
10143 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
10144 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10145 foreground);
3cf3436e
JR
10146 if (fmt[XBM_BACKGROUND].count
10147 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
10148 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10149 background);
10150
3cf3436e 10151 if (in_memory_file_p)
d5db4077
KR
10152 success_p = xbm_load_image (f, img, SDATA (data),
10153 (SDATA (data)
10154 + SBYTES (data)));
3cf3436e 10155 else
6fc2811b 10156 {
3cf3436e
JR
10157 if (VECTORP (data))
10158 {
10159 int i;
10160 char *p;
10161 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
7d0393cf 10162
3cf3436e
JR
10163 p = bits = (char *) alloca (nbytes * img->height);
10164 for (i = 0; i < img->height; ++i, p += nbytes)
10165 {
10166 Lisp_Object line = XVECTOR (data)->contents[i];
10167 if (STRINGP (line))
d5db4077 10168 bcopy (SDATA (line), p, nbytes);
3cf3436e
JR
10169 else
10170 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10171 }
10172 }
10173 else if (STRINGP (data))
d5db4077 10174 bits = SDATA (data);
3cf3436e
JR
10175 else
10176 bits = XBOOL_VECTOR (data)->data;
af3f7be7 10177
3cf3436e 10178 /* Create the pixmap. */
3cf3436e 10179 img->pixmap
af3f7be7
JR
10180 = w32_create_pixmap_from_bitmap_data (img->width, img->height,
10181 bits);
10182
3cf3436e
JR
10183 if (img->pixmap)
10184 success_p = 1;
10185 else
6fc2811b 10186 {
3cf3436e
JR
10187 image_error ("Unable to create pixmap for XBM image `%s'",
10188 img->spec, Qnil);
10189 x_clear_image (f, img);
6fc2811b
JR
10190 }
10191 }
6fc2811b
JR
10192 }
10193
10194 return success_p;
10195}
7d0393cf 10196
6fc2811b
JR
10197
10198\f
10199/***********************************************************************
10200 XPM images
10201 ***********************************************************************/
10202
7d0393cf 10203#if HAVE_XPM
6fc2811b
JR
10204
10205static int xpm_image_p P_ ((Lisp_Object object));
10206static int xpm_load P_ ((struct frame *f, struct image *img));
10207static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10208
10209#include "X11/xpm.h"
10210
10211/* The symbol `xpm' identifying XPM-format images. */
10212
10213Lisp_Object Qxpm;
10214
10215/* Indices of image specification fields in xpm_format, below. */
10216
10217enum xpm_keyword_index
10218{
10219 XPM_TYPE,
10220 XPM_FILE,
10221 XPM_DATA,
10222 XPM_ASCENT,
10223 XPM_MARGIN,
10224 XPM_RELIEF,
10225 XPM_ALGORITHM,
10226 XPM_HEURISTIC_MASK,
a05e2bae 10227 XPM_MASK,
6fc2811b 10228 XPM_COLOR_SYMBOLS,
a05e2bae 10229 XPM_BACKGROUND,
6fc2811b
JR
10230 XPM_LAST
10231};
10232
10233/* Vector of image_keyword structures describing the format
10234 of valid XPM image specifications. */
10235
10236static struct image_keyword xpm_format[XPM_LAST] =
10237{
10238 {":type", IMAGE_SYMBOL_VALUE, 1},
10239 {":file", IMAGE_STRING_VALUE, 0},
10240 {":data", IMAGE_STRING_VALUE, 0},
10241 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10242 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10243 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10244 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 10245 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10246 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10247 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10248 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10249};
10250
197edd35 10251/* Structure describing the image type XPM. */
6fc2811b
JR
10252
10253static struct image_type xpm_type =
10254{
10255 &Qxpm,
10256 xpm_image_p,
10257 xpm_load,
10258 x_clear_image,
10259 NULL
10260};
10261
10262
10263/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10264 for XPM images. Such a list must consist of conses whose car and
10265 cdr are strings. */
10266
10267static int
10268xpm_valid_color_symbols_p (color_symbols)
10269 Lisp_Object color_symbols;
10270{
10271 while (CONSP (color_symbols))
10272 {
10273 Lisp_Object sym = XCAR (color_symbols);
10274 if (!CONSP (sym)
10275 || !STRINGP (XCAR (sym))
10276 || !STRINGP (XCDR (sym)))
10277 break;
10278 color_symbols = XCDR (color_symbols);
10279 }
10280
10281 return NILP (color_symbols);
10282}
10283
10284
10285/* Value is non-zero if OBJECT is a valid XPM image specification. */
10286
10287static int
10288xpm_image_p (object)
10289 Lisp_Object object;
10290{
10291 struct image_keyword fmt[XPM_LAST];
10292 bcopy (xpm_format, fmt, sizeof fmt);
10293 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10294 /* Either `:file' or `:data' must be present. */
10295 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10296 /* Either no `:color-symbols' or it's a list of conses
10297 whose car and cdr are strings. */
10298 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10299 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10300 && (fmt[XPM_ASCENT].count == 0
10301 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10302}
10303
10304
10305/* Load image IMG which will be displayed on frame F. Value is
10306 non-zero if successful. */
10307
10308static int
10309xpm_load (f, img)
10310 struct frame *f;
10311 struct image *img;
10312{
10313 int rc, i;
10314 XpmAttributes attrs;
10315 Lisp_Object specified_file, color_symbols;
10316
10317 /* Configure the XPM lib. Use the visual of frame F. Allocate
10318 close colors. Return colors allocated. */
10319 bzero (&attrs, sizeof attrs);
dfff8a69
JR
10320 attrs.visual = FRAME_X_VISUAL (f);
10321 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 10322 attrs.valuemask |= XpmVisual;
dfff8a69 10323 attrs.valuemask |= XpmColormap;
6fc2811b 10324 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 10325#ifdef XpmAllocCloseColors
6fc2811b
JR
10326 attrs.alloc_close_colors = 1;
10327 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
10328#else
10329 attrs.closeness = 600;
10330 attrs.valuemask |= XpmCloseness;
10331#endif
6fc2811b
JR
10332
10333 /* If image specification contains symbolic color definitions, add
10334 these to `attrs'. */
10335 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10336 if (CONSP (color_symbols))
10337 {
10338 Lisp_Object tail;
10339 XpmColorSymbol *xpm_syms;
10340 int i, size;
7d0393cf 10341
6fc2811b
JR
10342 attrs.valuemask |= XpmColorSymbols;
10343
10344 /* Count number of symbols. */
10345 attrs.numsymbols = 0;
10346 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10347 ++attrs.numsymbols;
10348
10349 /* Allocate an XpmColorSymbol array. */
10350 size = attrs.numsymbols * sizeof *xpm_syms;
10351 xpm_syms = (XpmColorSymbol *) alloca (size);
10352 bzero (xpm_syms, size);
10353 attrs.colorsymbols = xpm_syms;
10354
10355 /* Fill the color symbol array. */
10356 for (tail = color_symbols, i = 0;
10357 CONSP (tail);
10358 ++i, tail = XCDR (tail))
10359 {
10360 Lisp_Object name = XCAR (XCAR (tail));
10361 Lisp_Object color = XCDR (XCAR (tail));
d5db4077
KR
10362 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
10363 strcpy (xpm_syms[i].name, SDATA (name));
10364 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
10365 strcpy (xpm_syms[i].value, SDATA (color));
6fc2811b
JR
10366 }
10367 }
10368
10369 /* Create a pixmap for the image, either from a file, or from a
10370 string buffer containing data in the same format as an XPM file. */
10371 BLOCK_INPUT;
10372 specified_file = image_spec_value (img->spec, QCfile, NULL);
10373 if (STRINGP (specified_file))
10374 {
10375 Lisp_Object file = x_find_image_file (specified_file);
10376 if (!STRINGP (file))
10377 {
10378 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10379 UNBLOCK_INPUT;
10380 return 0;
10381 }
7d0393cf 10382
6fc2811b 10383 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
d5db4077 10384 SDATA (file), &img->pixmap, &img->mask,
6fc2811b
JR
10385 &attrs);
10386 }
10387 else
10388 {
10389 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10390 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
d5db4077 10391 SDATA (buffer),
6fc2811b
JR
10392 &img->pixmap, &img->mask,
10393 &attrs);
10394 }
10395 UNBLOCK_INPUT;
10396
10397 if (rc == XpmSuccess)
10398 {
10399 /* Remember allocated colors. */
10400 img->ncolors = attrs.nalloc_pixels;
10401 img->colors = (unsigned long *) xmalloc (img->ncolors
10402 * sizeof *img->colors);
10403 for (i = 0; i < attrs.nalloc_pixels; ++i)
10404 img->colors[i] = attrs.alloc_pixels[i];
10405
10406 img->width = attrs.width;
10407 img->height = attrs.height;
10408 xassert (img->width > 0 && img->height > 0);
10409
10410 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10411 BLOCK_INPUT;
10412 XpmFreeAttributes (&attrs);
10413 UNBLOCK_INPUT;
10414 }
10415 else
10416 {
10417 switch (rc)
10418 {
10419 case XpmOpenFailed:
10420 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10421 break;
7d0393cf 10422
6fc2811b
JR
10423 case XpmFileInvalid:
10424 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10425 break;
7d0393cf 10426
6fc2811b
JR
10427 case XpmNoMemory:
10428 image_error ("Out of memory (%s)", img->spec, Qnil);
10429 break;
7d0393cf 10430
6fc2811b
JR
10431 case XpmColorFailed:
10432 image_error ("Color allocation error (%s)", img->spec, Qnil);
10433 break;
7d0393cf 10434
6fc2811b
JR
10435 default:
10436 image_error ("Unknown error (%s)", img->spec, Qnil);
10437 break;
10438 }
10439 }
10440
10441 return rc == XpmSuccess;
10442}
10443
10444#endif /* HAVE_XPM != 0 */
10445
10446\f
767b1ff0 10447#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
10448/***********************************************************************
10449 Color table
10450 ***********************************************************************/
10451
10452/* An entry in the color table mapping an RGB color to a pixel color. */
10453
10454struct ct_color
10455{
10456 int r, g, b;
10457 unsigned long pixel;
10458
10459 /* Next in color table collision list. */
10460 struct ct_color *next;
10461};
10462
10463/* The bucket vector size to use. Must be prime. */
10464
10465#define CT_SIZE 101
10466
10467/* Value is a hash of the RGB color given by R, G, and B. */
10468
10469#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10470
10471/* The color hash table. */
10472
10473struct ct_color **ct_table;
10474
10475/* Number of entries in the color table. */
10476
10477int ct_colors_allocated;
10478
10479/* Function prototypes. */
10480
10481static void init_color_table P_ ((void));
10482static void free_color_table P_ ((void));
10483static unsigned long *colors_in_color_table P_ ((int *n));
10484static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10485static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10486
10487
10488/* Initialize the color table. */
10489
10490static void
10491init_color_table ()
10492{
10493 int size = CT_SIZE * sizeof (*ct_table);
10494 ct_table = (struct ct_color **) xmalloc (size);
10495 bzero (ct_table, size);
10496 ct_colors_allocated = 0;
10497}
10498
10499
10500/* Free memory associated with the color table. */
10501
10502static void
10503free_color_table ()
10504{
10505 int i;
10506 struct ct_color *p, *next;
10507
10508 for (i = 0; i < CT_SIZE; ++i)
10509 for (p = ct_table[i]; p; p = next)
10510 {
10511 next = p->next;
10512 xfree (p);
10513 }
10514
10515 xfree (ct_table);
10516 ct_table = NULL;
10517}
10518
10519
10520/* Value is a pixel color for RGB color R, G, B on frame F. If an
10521 entry for that color already is in the color table, return the
10522 pixel color of that entry. Otherwise, allocate a new color for R,
10523 G, B, and make an entry in the color table. */
10524
10525static unsigned long
10526lookup_rgb_color (f, r, g, b)
10527 struct frame *f;
10528 int r, g, b;
10529{
10530 unsigned hash = CT_HASH_RGB (r, g, b);
10531 int i = hash % CT_SIZE;
10532 struct ct_color *p;
10533
10534 for (p = ct_table[i]; p; p = p->next)
10535 if (p->r == r && p->g == g && p->b == b)
10536 break;
10537
10538 if (p == NULL)
10539 {
10540 COLORREF color;
10541 Colormap cmap;
10542 int rc;
10543
10544 color = PALETTERGB (r, g, b);
10545
10546 ++ct_colors_allocated;
10547
10548 p = (struct ct_color *) xmalloc (sizeof *p);
10549 p->r = r;
10550 p->g = g;
10551 p->b = b;
10552 p->pixel = color;
10553 p->next = ct_table[i];
10554 ct_table[i] = p;
10555 }
10556
10557 return p->pixel;
10558}
10559
10560
10561/* Look up pixel color PIXEL which is used on frame F in the color
10562 table. If not already present, allocate it. Value is PIXEL. */
10563
10564static unsigned long
10565lookup_pixel_color (f, pixel)
10566 struct frame *f;
10567 unsigned long pixel;
10568{
10569 int i = pixel % CT_SIZE;
10570 struct ct_color *p;
10571
10572 for (p = ct_table[i]; p; p = p->next)
10573 if (p->pixel == pixel)
10574 break;
10575
10576 if (p == NULL)
10577 {
10578 XColor color;
10579 Colormap cmap;
10580 int rc;
10581
10582 BLOCK_INPUT;
7d0393cf 10583
6fc2811b
JR
10584 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10585 color.pixel = pixel;
10586 XQueryColor (NULL, cmap, &color);
10587 rc = x_alloc_nearest_color (f, cmap, &color);
10588 UNBLOCK_INPUT;
10589
10590 if (rc)
10591 {
10592 ++ct_colors_allocated;
7d0393cf 10593
6fc2811b
JR
10594 p = (struct ct_color *) xmalloc (sizeof *p);
10595 p->r = color.red;
10596 p->g = color.green;
10597 p->b = color.blue;
10598 p->pixel = pixel;
10599 p->next = ct_table[i];
10600 ct_table[i] = p;
10601 }
10602 else
10603 return FRAME_FOREGROUND_PIXEL (f);
10604 }
10605 return p->pixel;
10606}
10607
10608
10609/* Value is a vector of all pixel colors contained in the color table,
10610 allocated via xmalloc. Set *N to the number of colors. */
10611
10612static unsigned long *
10613colors_in_color_table (n)
10614 int *n;
10615{
10616 int i, j;
10617 struct ct_color *p;
10618 unsigned long *colors;
10619
10620 if (ct_colors_allocated == 0)
10621 {
10622 *n = 0;
10623 colors = NULL;
10624 }
10625 else
10626 {
10627 colors = (unsigned long *) xmalloc (ct_colors_allocated
10628 * sizeof *colors);
10629 *n = ct_colors_allocated;
7d0393cf 10630
6fc2811b
JR
10631 for (i = j = 0; i < CT_SIZE; ++i)
10632 for (p = ct_table[i]; p; p = p->next)
10633 colors[j++] = p->pixel;
10634 }
10635
10636 return colors;
10637}
10638
767b1ff0 10639#endif /* TODO */
6fc2811b
JR
10640
10641\f
10642/***********************************************************************
10643 Algorithms
10644 ***********************************************************************/
3cf3436e
JR
10645static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10646static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10647static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
ac849ba4 10648static void XPutPixel (XImage *, int, int, COLORREF);
3cf3436e
JR
10649
10650/* Non-zero means draw a cross on images having `:conversion
10651 disabled'. */
6fc2811b 10652
3cf3436e 10653int cross_disabled_images;
6fc2811b 10654
3cf3436e
JR
10655/* Edge detection matrices for different edge-detection
10656 strategies. */
6fc2811b 10657
3cf3436e
JR
10658static int emboss_matrix[9] = {
10659 /* x - 1 x x + 1 */
10660 2, -1, 0, /* y - 1 */
10661 -1, 0, 1, /* y */
10662 0, 1, -2 /* y + 1 */
10663};
10664
10665static int laplace_matrix[9] = {
10666 /* x - 1 x x + 1 */
10667 1, 0, 0, /* y - 1 */
10668 0, 0, 0, /* y */
10669 0, 0, -1 /* y + 1 */
10670};
10671
10672/* Value is the intensity of the color whose red/green/blue values
10673 are R, G, and B. */
10674
10675#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10676
10677
10678/* On frame F, return an array of XColor structures describing image
10679 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10680 non-zero means also fill the red/green/blue members of the XColor
10681 structures. Value is a pointer to the array of XColors structures,
10682 allocated with xmalloc; it must be freed by the caller. */
10683
10684static XColor *
10685x_to_xcolors (f, img, rgb_p)
10686 struct frame *f;
10687 struct image *img;
10688 int rgb_p;
10689{
10690 int x, y;
10691 XColor *colors, *p;
197edd35
JR
10692 HDC hdc, bmpdc;
10693 HGDIOBJ prev;
3cf3436e
JR
10694
10695 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
197edd35
JR
10696
10697 /* Load the image into a memory device context. */
10698 hdc = get_frame_dc (f);
10699 bmpdc = CreateCompatibleDC (hdc);
10700 release_frame_dc (f, hdc);
10701 prev = SelectObject (bmpdc, img->pixmap);
3cf3436e
JR
10702
10703 /* Fill the `pixel' members of the XColor array. I wished there
10704 were an easy and portable way to circumvent XGetPixel. */
10705 p = colors;
10706 for (y = 0; y < img->height; ++y)
10707 {
10708 XColor *row = p;
7d0393cf 10709
3cf3436e 10710 for (x = 0; x < img->width; ++x, ++p)
197edd35
JR
10711 {
10712 /* TODO: palette support needed here? */
10713 p->pixel = GetPixel (bmpdc, x, y);
3cf3436e 10714
197edd35
JR
10715 if (rgb_p)
10716 {
10717 p->red = 256 * GetRValue (p->pixel);
10718 p->green = 256 * GetGValue (p->pixel);
10719 p->blue = 256 * GetBValue (p->pixel);
10720 }
10721 }
3cf3436e
JR
10722 }
10723
197edd35
JR
10724 SelectObject (bmpdc, prev);
10725 DeleteDC (bmpdc);
10726
3cf3436e
JR
10727 return colors;
10728}
10729
ac849ba4
JR
10730/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10731 created with CreateDIBSection, with the pointer to the bit values
10732 stored in ximg->data. */
10733
10734static void XPutPixel (ximg, x, y, color)
10735 XImage * ximg;
10736 int x, y;
10737 COLORREF color;
10738{
10739 int width = ximg->info.bmiHeader.biWidth;
10740 int height = ximg->info.bmiHeader.biHeight;
10741 int rowbytes = width * 3;
10742 unsigned char * pixel;
10743
10744 /* Don't support putting pixels in images with palettes. */
10745 xassert (ximg->info.bmiHeader.biBitCount == 24);
10746
10747 /* Ensure scanlines are aligned on 4 byte boundaries. */
10748 if (rowbytes % 4)
10749 rowbytes += 4 - (rowbytes % 4);
10750
10751 pixel = ximg->data + y * rowbytes + x * 3;
adda530b
JR
10752 /* Windows bitmaps are in BGR order. */
10753 *pixel = GetBValue (color);
35624c03 10754 *(pixel + 1) = GetGValue (color);
adda530b 10755 *(pixel + 2) = GetRValue (color);
ac849ba4
JR
10756}
10757
3cf3436e
JR
10758
10759/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10760 RGB members are set. F is the frame on which this all happens.
10761 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10762
10763static void
3cf3436e 10764x_from_xcolors (f, img, colors)
6fc2811b 10765 struct frame *f;
3cf3436e 10766 struct image *img;
6fc2811b 10767 XColor *colors;
6fc2811b 10768{
3cf3436e
JR
10769 int x, y;
10770 XImage *oimg;
10771 Pixmap pixmap;
10772 XColor *p;
ac849ba4 10773#if 0 /* TODO: color tables. */
3cf3436e 10774 init_color_table ();
ac849ba4 10775#endif
3cf3436e
JR
10776 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10777 &oimg, &pixmap);
10778 p = colors;
10779 for (y = 0; y < img->height; ++y)
10780 for (x = 0; x < img->width; ++x, ++p)
10781 {
10782 unsigned long pixel;
ac849ba4 10783#if 0 /* TODO: color tables. */
3cf3436e 10784 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
ac849ba4 10785#else
197edd35 10786 pixel = PALETTERGB (p->red / 256, p->green / 256, p->blue / 256);
ac849ba4 10787#endif
3cf3436e
JR
10788 XPutPixel (oimg, x, y, pixel);
10789 }
6fc2811b 10790
3cf3436e
JR
10791 xfree (colors);
10792 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10793
3cf3436e
JR
10794 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10795 x_destroy_x_image (oimg);
10796 img->pixmap = pixmap;
ac849ba4 10797#if 0 /* TODO: color tables. */
3cf3436e
JR
10798 img->colors = colors_in_color_table (&img->ncolors);
10799 free_color_table ();
ac849ba4 10800#endif
6fc2811b
JR
10801}
10802
10803
3cf3436e
JR
10804/* On frame F, perform edge-detection on image IMG.
10805
10806 MATRIX is a nine-element array specifying the transformation
10807 matrix. See emboss_matrix for an example.
7d0393cf 10808
3cf3436e
JR
10809 COLOR_ADJUST is a color adjustment added to each pixel of the
10810 outgoing image. */
6fc2811b
JR
10811
10812static void
3cf3436e 10813x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10814 struct frame *f;
3cf3436e
JR
10815 struct image *img;
10816 int matrix[9], color_adjust;
6fc2811b 10817{
3cf3436e
JR
10818 XColor *colors = x_to_xcolors (f, img, 1);
10819 XColor *new, *p;
10820 int x, y, i, sum;
10821
10822 for (i = sum = 0; i < 9; ++i)
10823 sum += abs (matrix[i]);
10824
10825#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10826
10827 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10828
10829 for (y = 0; y < img->height; ++y)
10830 {
10831 p = COLOR (new, 0, y);
10832 p->red = p->green = p->blue = 0xffff/2;
10833 p = COLOR (new, img->width - 1, y);
10834 p->red = p->green = p->blue = 0xffff/2;
10835 }
7d0393cf 10836
3cf3436e
JR
10837 for (x = 1; x < img->width - 1; ++x)
10838 {
10839 p = COLOR (new, x, 0);
10840 p->red = p->green = p->blue = 0xffff/2;
10841 p = COLOR (new, x, img->height - 1);
10842 p->red = p->green = p->blue = 0xffff/2;
10843 }
10844
10845 for (y = 1; y < img->height - 1; ++y)
10846 {
10847 p = COLOR (new, 1, y);
7d0393cf 10848
3cf3436e
JR
10849 for (x = 1; x < img->width - 1; ++x, ++p)
10850 {
10851 int r, g, b, y1, x1;
10852
10853 r = g = b = i = 0;
10854 for (y1 = y - 1; y1 < y + 2; ++y1)
10855 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10856 if (matrix[i])
10857 {
10858 XColor *t = COLOR (colors, x1, y1);
10859 r += matrix[i] * t->red;
10860 g += matrix[i] * t->green;
10861 b += matrix[i] * t->blue;
10862 }
10863
10864 r = (r / sum + color_adjust) & 0xffff;
10865 g = (g / sum + color_adjust) & 0xffff;
10866 b = (b / sum + color_adjust) & 0xffff;
10867 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10868 }
10869 }
10870
10871 xfree (colors);
10872 x_from_xcolors (f, img, new);
10873
10874#undef COLOR
10875}
10876
10877
10878/* Perform the pre-defined `emboss' edge-detection on image IMG
10879 on frame F. */
10880
10881static void
10882x_emboss (f, img)
10883 struct frame *f;
10884 struct image *img;
10885{
10886 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10887}
3cf3436e 10888
6fc2811b
JR
10889
10890/* Transform image IMG which is used on frame F with a Laplace
10891 edge-detection algorithm. The result is an image that can be used
10892 to draw disabled buttons, for example. */
10893
10894static void
10895x_laplace (f, img)
10896 struct frame *f;
10897 struct image *img;
10898{
3cf3436e
JR
10899 x_detect_edges (f, img, laplace_matrix, 45000);
10900}
6fc2811b 10901
6fc2811b 10902
3cf3436e
JR
10903/* Perform edge-detection on image IMG on frame F, with specified
10904 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10905
3cf3436e 10906 MATRIX must be either
6fc2811b 10907
3cf3436e
JR
10908 - a list of at least 9 numbers in row-major form
10909 - a vector of at least 9 numbers
6fc2811b 10910
3cf3436e
JR
10911 COLOR_ADJUST nil means use a default; otherwise it must be a
10912 number. */
6fc2811b 10913
3cf3436e
JR
10914static void
10915x_edge_detection (f, img, matrix, color_adjust)
10916 struct frame *f;
10917 struct image *img;
10918 Lisp_Object matrix, color_adjust;
10919{
10920 int i = 0;
10921 int trans[9];
7d0393cf 10922
3cf3436e 10923 if (CONSP (matrix))
6fc2811b 10924 {
3cf3436e
JR
10925 for (i = 0;
10926 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10927 ++i, matrix = XCDR (matrix))
10928 trans[i] = XFLOATINT (XCAR (matrix));
10929 }
10930 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10931 {
10932 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10933 trans[i] = XFLOATINT (AREF (matrix, i));
10934 }
10935
10936 if (NILP (color_adjust))
10937 color_adjust = make_number (0xffff / 2);
10938
10939 if (i == 9 && NUMBERP (color_adjust))
10940 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10941}
10942
6fc2811b 10943
3cf3436e 10944/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10945
3cf3436e
JR
10946static void
10947x_disable_image (f, img)
10948 struct frame *f;
10949 struct image *img;
10950{
ac849ba4 10951 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3cf3436e 10952
ac849ba4 10953 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
3cf3436e
JR
10954 {
10955 /* Color (or grayscale). Convert to gray, and equalize. Just
10956 drawing such images with a stipple can look very odd, so
10957 we're using this method instead. */
10958 XColor *colors = x_to_xcolors (f, img, 1);
10959 XColor *p, *end;
10960 const int h = 15000;
10961 const int l = 30000;
10962
10963 for (p = colors, end = colors + img->width * img->height;
10964 p < end;
10965 ++p)
6fc2811b 10966 {
3cf3436e
JR
10967 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10968 int i2 = (0xffff - h - l) * i / 0xffff + l;
10969 p->red = p->green = p->blue = i2;
6fc2811b
JR
10970 }
10971
3cf3436e 10972 x_from_xcolors (f, img, colors);
6fc2811b
JR
10973 }
10974
3cf3436e
JR
10975 /* Draw a cross over the disabled image, if we must or if we
10976 should. */
ac849ba4 10977 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
3cf3436e 10978 {
197edd35
JR
10979 HDC hdc, bmpdc;
10980 HGDIOBJ prev;
10981
10982 hdc = get_frame_dc (f);
10983 bmpdc = CreateCompatibleDC (hdc);
10984 release_frame_dc (f, hdc);
10985
10986 prev = SelectObject (bmpdc, img->pixmap);
6fc2811b 10987
197edd35
JR
10988 SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
10989 MoveToEx (bmpdc, 0, 0, NULL);
10990 LineTo (bmpdc, img->width - 1, img->height - 1);
10991 MoveToEx (bmpdc, 0, img->height - 1, NULL);
10992 LineTo (bmpdc, img->width - 1, 0);
6fc2811b 10993
3cf3436e
JR
10994 if (img->mask)
10995 {
197edd35
JR
10996 SelectObject (bmpdc, img->mask);
10997 SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
10998 MoveToEx (bmpdc, 0, 0, NULL);
10999 LineTo (bmpdc, img->width - 1, img->height - 1);
11000 MoveToEx (bmpdc, 0, img->height - 1, NULL);
11001 LineTo (bmpdc, img->width - 1, 0);
3cf3436e 11002 }
197edd35
JR
11003 SelectObject (bmpdc, prev);
11004 DeleteDC (bmpdc);
3cf3436e 11005 }
6fc2811b
JR
11006}
11007
11008
11009/* Build a mask for image IMG which is used on frame F. FILE is the
11010 name of an image file, for error messages. HOW determines how to
11011 determine the background color of IMG. If it is a list '(R G B)',
11012 with R, G, and B being integers >= 0, take that as the color of the
11013 background. Otherwise, determine the background color of IMG
11014 heuristically. Value is non-zero if successful. */
11015
11016static int
11017x_build_heuristic_mask (f, img, how)
11018 struct frame *f;
11019 struct image *img;
11020 Lisp_Object how;
11021{
197edd35
JR
11022 HDC img_dc, frame_dc;
11023 HGDIOBJ prev;
11024 char *mask_img;
a05e2bae
JR
11025 int x, y, rc, use_img_background;
11026 unsigned long bg = 0;
197edd35 11027 int row_width;
a05e2bae
JR
11028
11029 if (img->mask)
11030 {
197edd35
JR
11031 DeleteObject (img->mask);
11032 img->mask = NULL;
a05e2bae
JR
11033 img->background_transparent_valid = 0;
11034 }
6fc2811b 11035
197edd35
JR
11036 /* Create the bit array serving as mask. */
11037 row_width = (img->width + 7) / 8;
11038 mask_img = xmalloc (row_width * img->height);
11039 bzero (mask_img, row_width * img->height);
6fc2811b 11040
197edd35
JR
11041 /* Create a memory device context for IMG->pixmap. */
11042 frame_dc = get_frame_dc (f);
11043 img_dc = CreateCompatibleDC (frame_dc);
11044 release_frame_dc (f, frame_dc);
11045 prev = SelectObject (img_dc, img->pixmap);
6fc2811b 11046
197edd35 11047 /* Determine the background color of img_dc. If HOW is `(R G B)'
a05e2bae
JR
11048 take that as color. Otherwise, use the image's background color. */
11049 use_img_background = 1;
7d0393cf 11050
6fc2811b
JR
11051 if (CONSP (how))
11052 {
a05e2bae 11053 int rgb[3], i;
6fc2811b 11054
a05e2bae 11055 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
11056 {
11057 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
11058 how = XCDR (how);
11059 }
11060
11061 if (i == 3 && NILP (how))
11062 {
11063 char color_name[30];
6fc2811b 11064 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
0040b876
JR
11065 bg = x_alloc_image_color (f, img, build_string (color_name), 0)
11066 & 0xffffff; // Filter out palette info.
a05e2bae 11067 use_img_background = 0;
6fc2811b
JR
11068 }
11069 }
7d0393cf 11070
a05e2bae 11071 if (use_img_background)
197edd35 11072 bg = four_corners_best (img_dc, img->width, img->height);
6fc2811b
JR
11073
11074 /* Set all bits in mask_img to 1 whose color in ximg is different
11075 from the background color bg. */
11076 for (y = 0; y < img->height; ++y)
11077 for (x = 0; x < img->width; ++x)
197edd35
JR
11078 {
11079 COLORREF p = GetPixel (img_dc, x, y);
11080 if (p != bg)
11081 mask_img[y * row_width + x / 8] |= 1 << (x % 8);
11082 }
11083
11084 /* Create the mask image. */
11085 img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
11086 mask_img);
6fc2811b 11087
a05e2bae 11088 /* Fill in the background_transparent field while we have the mask handy. */
197edd35
JR
11089 SelectObject (img_dc, img->mask);
11090
11091 image_background_transparent (img, f, img_dc);
a05e2bae 11092
6fc2811b 11093 /* Put mask_img into img->mask. */
6fc2811b 11094 x_destroy_x_image (mask_img);
197edd35
JR
11095 SelectObject (img_dc, prev);
11096 DeleteDC (img_dc);
6fc2811b
JR
11097
11098 return 1;
11099}
217e5be0 11100
6fc2811b
JR
11101\f
11102/***********************************************************************
11103 PBM (mono, gray, color)
11104 ***********************************************************************/
6fc2811b
JR
11105
11106static int pbm_image_p P_ ((Lisp_Object object));
11107static int pbm_load P_ ((struct frame *f, struct image *img));
11108static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11109
11110/* The symbol `pbm' identifying images of this type. */
11111
11112Lisp_Object Qpbm;
11113
11114/* Indices of image specification fields in gs_format, below. */
11115
11116enum pbm_keyword_index
11117{
11118 PBM_TYPE,
11119 PBM_FILE,
11120 PBM_DATA,
11121 PBM_ASCENT,
11122 PBM_MARGIN,
11123 PBM_RELIEF,
11124 PBM_ALGORITHM,
11125 PBM_HEURISTIC_MASK,
a05e2bae
JR
11126 PBM_MASK,
11127 PBM_FOREGROUND,
11128 PBM_BACKGROUND,
6fc2811b
JR
11129 PBM_LAST
11130};
11131
11132/* Vector of image_keyword structures describing the format
11133 of valid user-defined image specifications. */
11134
11135static struct image_keyword pbm_format[PBM_LAST] =
11136{
11137 {":type", IMAGE_SYMBOL_VALUE, 1},
11138 {":file", IMAGE_STRING_VALUE, 0},
11139 {":data", IMAGE_STRING_VALUE, 0},
11140 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11141 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11142 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11143 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
11144 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11145 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11146 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11147 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11148};
11149
11150/* Structure describing the image type `pbm'. */
11151
11152static struct image_type pbm_type =
11153{
11154 &Qpbm,
11155 pbm_image_p,
11156 pbm_load,
11157 x_clear_image,
11158 NULL
11159};
11160
11161
11162/* Return non-zero if OBJECT is a valid PBM image specification. */
11163
11164static int
11165pbm_image_p (object)
11166 Lisp_Object object;
11167{
11168 struct image_keyword fmt[PBM_LAST];
7d0393cf 11169
6fc2811b 11170 bcopy (pbm_format, fmt, sizeof fmt);
7d0393cf 11171
6fc2811b 11172 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
7d0393cf 11173 || (fmt[PBM_ASCENT].count
6fc2811b
JR
11174 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11175 return 0;
11176
11177 /* Must specify either :data or :file. */
11178 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11179}
11180
11181
11182/* Scan a decimal number from *S and return it. Advance *S while
11183 reading the number. END is the end of the string. Value is -1 at
11184 end of input. */
11185
11186static int
11187pbm_scan_number (s, end)
11188 unsigned char **s, *end;
11189{
11190 int c, val = -1;
11191
11192 while (*s < end)
11193 {
11194 /* Skip white-space. */
11195 while (*s < end && (c = *(*s)++, isspace (c)))
11196 ;
11197
11198 if (c == '#')
11199 {
11200 /* Skip comment to end of line. */
11201 while (*s < end && (c = *(*s)++, c != '\n'))
11202 ;
11203 }
11204 else if (isdigit (c))
11205 {
11206 /* Read decimal number. */
11207 val = c - '0';
11208 while (*s < end && (c = *(*s)++, isdigit (c)))
11209 val = 10 * val + c - '0';
11210 break;
11211 }
11212 else
11213 break;
11214 }
11215
11216 return val;
11217}
11218
11219
11220/* Read FILE into memory. Value is a pointer to a buffer allocated
11221 with xmalloc holding FILE's contents. Value is null if an error
6f826971 11222 occurred. *SIZE is set to the size of the file. */
6fc2811b
JR
11223
11224static char *
11225pbm_read_file (file, size)
11226 Lisp_Object file;
11227 int *size;
11228{
11229 FILE *fp = NULL;
11230 char *buf = NULL;
11231 struct stat st;
11232
d5db4077
KR
11233 if (stat (SDATA (file), &st) == 0
11234 && (fp = fopen (SDATA (file), "r")) != NULL
6fc2811b
JR
11235 && (buf = (char *) xmalloc (st.st_size),
11236 fread (buf, 1, st.st_size, fp) == st.st_size))
11237 {
11238 *size = st.st_size;
11239 fclose (fp);
11240 }
11241 else
11242 {
11243 if (fp)
11244 fclose (fp);
11245 if (buf)
11246 {
11247 xfree (buf);
11248 buf = NULL;
11249 }
11250 }
7d0393cf 11251
6fc2811b
JR
11252 return buf;
11253}
11254
11255
11256/* Load PBM image IMG for use on frame F. */
11257
7d0393cf 11258static int
6fc2811b
JR
11259pbm_load (f, img)
11260 struct frame *f;
11261 struct image *img;
11262{
11263 int raw_p, x, y;
11264 int width, height, max_color_idx = 0;
11265 XImage *ximg;
11266 Lisp_Object file, specified_file;
11267 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11268 struct gcpro gcpro1;
11269 unsigned char *contents = NULL;
11270 unsigned char *end, *p;
11271 int size;
11272
11273 specified_file = image_spec_value (img->spec, QCfile, NULL);
11274 file = Qnil;
11275 GCPRO1 (file);
11276
11277 if (STRINGP (specified_file))
11278 {
11279 file = x_find_image_file (specified_file);
11280 if (!STRINGP (file))
11281 {
11282 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11283 UNGCPRO;
11284 return 0;
11285 }
11286
d5db4077 11287 contents = slurp_file (SDATA (file), &size);
6fc2811b
JR
11288 if (contents == NULL)
11289 {
11290 image_error ("Error reading `%s'", file, Qnil);
11291 UNGCPRO;
11292 return 0;
11293 }
11294
11295 p = contents;
11296 end = contents + size;
11297 }
11298 else
11299 {
11300 Lisp_Object data;
11301 data = image_spec_value (img->spec, QCdata, NULL);
d5db4077
KR
11302 p = SDATA (data);
11303 end = p + SBYTES (data);
6fc2811b
JR
11304 }
11305
11306 /* Check magic number. */
11307 if (end - p < 2 || *p++ != 'P')
11308 {
11309 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11310 error:
11311 xfree (contents);
11312 UNGCPRO;
11313 return 0;
11314 }
11315
6fc2811b
JR
11316 switch (*p++)
11317 {
11318 case '1':
11319 raw_p = 0, type = PBM_MONO;
11320 break;
7d0393cf 11321
6fc2811b
JR
11322 case '2':
11323 raw_p = 0, type = PBM_GRAY;
11324 break;
11325
11326 case '3':
11327 raw_p = 0, type = PBM_COLOR;
11328 break;
11329
11330 case '4':
11331 raw_p = 1, type = PBM_MONO;
11332 break;
7d0393cf 11333
6fc2811b
JR
11334 case '5':
11335 raw_p = 1, type = PBM_GRAY;
11336 break;
7d0393cf 11337
6fc2811b
JR
11338 case '6':
11339 raw_p = 1, type = PBM_COLOR;
11340 break;
11341
11342 default:
11343 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11344 goto error;
11345 }
11346
11347 /* Read width, height, maximum color-component. Characters
11348 starting with `#' up to the end of a line are ignored. */
11349 width = pbm_scan_number (&p, end);
11350 height = pbm_scan_number (&p, end);
11351
11352 if (type != PBM_MONO)
11353 {
11354 max_color_idx = pbm_scan_number (&p, end);
11355 if (raw_p && max_color_idx > 255)
11356 max_color_idx = 255;
11357 }
7d0393cf 11358
6fc2811b
JR
11359 if (width < 0
11360 || height < 0
11361 || (type != PBM_MONO && max_color_idx < 0))
11362 goto error;
11363
ac849ba4 11364 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
3cf3436e
JR
11365 goto error;
11366
ac849ba4 11367#if 0 /* TODO: color tables. */
6fc2811b
JR
11368 /* Initialize the color hash table. */
11369 init_color_table ();
ac849ba4 11370#endif
6fc2811b
JR
11371
11372 if (type == PBM_MONO)
11373 {
11374 int c = 0, g;
3cf3436e
JR
11375 struct image_keyword fmt[PBM_LAST];
11376 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11377 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11378
11379 /* Parse the image specification. */
11380 bcopy (pbm_format, fmt, sizeof fmt);
11381 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
7d0393cf 11382
3cf3436e
JR
11383 /* Get foreground and background colors, maybe allocate colors. */
11384 if (fmt[PBM_FOREGROUND].count
11385 && STRINGP (fmt[PBM_FOREGROUND].value))
11386 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11387 if (fmt[PBM_BACKGROUND].count
11388 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
11389 {
11390 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11391 img->background = bg;
11392 img->background_valid = 1;
11393 }
11394
6fc2811b
JR
11395 for (y = 0; y < height; ++y)
11396 for (x = 0; x < width; ++x)
11397 {
11398 if (raw_p)
11399 {
11400 if ((x & 7) == 0)
11401 c = *p++;
11402 g = c & 0x80;
11403 c <<= 1;
11404 }
11405 else
11406 g = pbm_scan_number (&p, end);
11407
3cf3436e 11408 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
11409 }
11410 }
11411 else
11412 {
11413 for (y = 0; y < height; ++y)
11414 for (x = 0; x < width; ++x)
11415 {
11416 int r, g, b;
7d0393cf 11417
6fc2811b
JR
11418 if (type == PBM_GRAY)
11419 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11420 else if (raw_p)
11421 {
11422 r = *p++;
11423 g = *p++;
11424 b = *p++;
11425 }
11426 else
11427 {
11428 r = pbm_scan_number (&p, end);
11429 g = pbm_scan_number (&p, end);
11430 b = pbm_scan_number (&p, end);
11431 }
7d0393cf 11432
6fc2811b
JR
11433 if (r < 0 || g < 0 || b < 0)
11434 {
ac849ba4 11435 x_destroy_x_image (ximg);
6fc2811b
JR
11436 image_error ("Invalid pixel value in image `%s'",
11437 img->spec, Qnil);
11438 goto error;
11439 }
7d0393cf 11440
6fc2811b 11441 /* RGB values are now in the range 0..max_color_idx.
ac849ba4
JR
11442 Scale this to the range 0..0xff supported by W32. */
11443 r = (int) ((double) r * 255 / max_color_idx);
11444 g = (int) ((double) g * 255 / max_color_idx);
11445 b = (int) ((double) b * 255 / max_color_idx);
11446 XPutPixel (ximg, x, y,
11447#if 0 /* TODO: color tables. */
11448 lookup_rgb_color (f, r, g, b));
11449#else
11450 PALETTERGB (r, g, b));
11451#endif
6fc2811b
JR
11452 }
11453 }
ac849ba4
JR
11454
11455#if 0 /* TODO: color tables. */
6fc2811b
JR
11456 /* Store in IMG->colors the colors allocated for the image, and
11457 free the color table. */
11458 img->colors = colors_in_color_table (&img->ncolors);
11459 free_color_table ();
ac849ba4 11460#endif
a05e2bae
JR
11461 /* Maybe fill in the background field while we have ximg handy. */
11462 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11463 IMAGE_BACKGROUND (img, f, ximg);
7d0393cf 11464
6fc2811b
JR
11465 /* Put the image into a pixmap. */
11466 x_put_x_image (f, ximg, img->pixmap, width, height);
11467 x_destroy_x_image (ximg);
7d0393cf 11468
6fc2811b
JR
11469 img->width = width;
11470 img->height = height;
11471
11472 UNGCPRO;
11473 xfree (contents);
11474 return 1;
11475}
6fc2811b
JR
11476
11477\f
11478/***********************************************************************
11479 PNG
11480 ***********************************************************************/
11481
11482#if HAVE_PNG
11483
11484#include <png.h>
11485
11486/* Function prototypes. */
11487
11488static int png_image_p P_ ((Lisp_Object object));
11489static int png_load P_ ((struct frame *f, struct image *img));
11490
11491/* The symbol `png' identifying images of this type. */
11492
11493Lisp_Object Qpng;
11494
11495/* Indices of image specification fields in png_format, below. */
11496
11497enum png_keyword_index
11498{
11499 PNG_TYPE,
11500 PNG_DATA,
11501 PNG_FILE,
11502 PNG_ASCENT,
11503 PNG_MARGIN,
11504 PNG_RELIEF,
11505 PNG_ALGORITHM,
11506 PNG_HEURISTIC_MASK,
a05e2bae
JR
11507 PNG_MASK,
11508 PNG_BACKGROUND,
6fc2811b
JR
11509 PNG_LAST
11510};
11511
11512/* Vector of image_keyword structures describing the format
11513 of valid user-defined image specifications. */
11514
11515static struct image_keyword png_format[PNG_LAST] =
11516{
11517 {":type", IMAGE_SYMBOL_VALUE, 1},
11518 {":data", IMAGE_STRING_VALUE, 0},
11519 {":file", IMAGE_STRING_VALUE, 0},
11520 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11521 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11522 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11523 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11524 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11525 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11526 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11527};
11528
11529/* Structure describing the image type `png'. */
11530
11531static struct image_type png_type =
11532{
11533 &Qpng,
11534 png_image_p,
11535 png_load,
11536 x_clear_image,
11537 NULL
11538};
11539
11540
11541/* Return non-zero if OBJECT is a valid PNG image specification. */
11542
11543static int
11544png_image_p (object)
11545 Lisp_Object object;
11546{
11547 struct image_keyword fmt[PNG_LAST];
11548 bcopy (png_format, fmt, sizeof fmt);
7d0393cf 11549
6fc2811b 11550 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
7d0393cf 11551 || (fmt[PNG_ASCENT].count
6fc2811b
JR
11552 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11553 return 0;
11554
11555 /* Must specify either the :data or :file keyword. */
11556 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11557}
11558
11559
11560/* Error and warning handlers installed when the PNG library
11561 is initialized. */
11562
11563static void
11564my_png_error (png_ptr, msg)
11565 png_struct *png_ptr;
11566 char *msg;
11567{
11568 xassert (png_ptr != NULL);
11569 image_error ("PNG error: %s", build_string (msg), Qnil);
11570 longjmp (png_ptr->jmpbuf, 1);
11571}
11572
11573
11574static void
11575my_png_warning (png_ptr, msg)
11576 png_struct *png_ptr;
11577 char *msg;
11578{
11579 xassert (png_ptr != NULL);
11580 image_error ("PNG warning: %s", build_string (msg), Qnil);
11581}
11582
6fc2811b
JR
11583/* Memory source for PNG decoding. */
11584
11585struct png_memory_storage
11586{
11587 unsigned char *bytes; /* The data */
11588 size_t len; /* How big is it? */
11589 int index; /* Where are we? */
11590};
11591
11592
11593/* Function set as reader function when reading PNG image from memory.
11594 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11595 bytes from the input to DATA. */
11596
11597static void
11598png_read_from_memory (png_ptr, data, length)
11599 png_structp png_ptr;
11600 png_bytep data;
11601 png_size_t length;
11602{
11603 struct png_memory_storage *tbr
11604 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11605
11606 if (length > tbr->len - tbr->index)
11607 png_error (png_ptr, "Read error");
7d0393cf 11608
6fc2811b
JR
11609 bcopy (tbr->bytes + tbr->index, data, length);
11610 tbr->index = tbr->index + length;
11611}
11612
6fc2811b
JR
11613/* Load PNG image IMG for use on frame F. Value is non-zero if
11614 successful. */
11615
11616static int
11617png_load (f, img)
11618 struct frame *f;
11619 struct image *img;
11620{
11621 Lisp_Object file, specified_file;
11622 Lisp_Object specified_data;
11623 int x, y, i;
11624 XImage *ximg, *mask_img = NULL;
11625 struct gcpro gcpro1;
11626 png_struct *png_ptr = NULL;
11627 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11628 FILE *volatile fp = NULL;
6fc2811b 11629 png_byte sig[8];
a05e2bae
JR
11630 png_byte *volatile pixels = NULL;
11631 png_byte **volatile rows = NULL;
6fc2811b
JR
11632 png_uint_32 width, height;
11633 int bit_depth, color_type, interlace_type;
11634 png_byte channels;
11635 png_uint_32 row_bytes;
11636 int transparent_p;
11637 char *gamma_str;
11638 double screen_gamma, image_gamma;
11639 int intent;
11640 struct png_memory_storage tbr; /* Data to be read */
11641
11642 /* Find out what file to load. */
11643 specified_file = image_spec_value (img->spec, QCfile, NULL);
11644 specified_data = image_spec_value (img->spec, QCdata, NULL);
11645 file = Qnil;
11646 GCPRO1 (file);
11647
11648 if (NILP (specified_data))
11649 {
11650 file = x_find_image_file (specified_file);
11651 if (!STRINGP (file))
11652 {
11653 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11654 UNGCPRO;
11655 return 0;
11656 }
11657
11658 /* Open the image file. */
d5db4077 11659 fp = fopen (SDATA (file), "rb");
6fc2811b
JR
11660 if (!fp)
11661 {
11662 image_error ("Cannot open image file `%s'", file, Qnil);
11663 UNGCPRO;
11664 fclose (fp);
11665 return 0;
11666 }
11667
11668 /* Check PNG signature. */
11669 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11670 || !png_check_sig (sig, sizeof sig))
11671 {
11672 image_error ("Not a PNG file:` %s'", file, Qnil);
11673 UNGCPRO;
11674 fclose (fp);
11675 return 0;
11676 }
11677 }
11678 else
11679 {
11680 /* Read from memory. */
d5db4077
KR
11681 tbr.bytes = SDATA (specified_data);
11682 tbr.len = SBYTES (specified_data);
6fc2811b
JR
11683 tbr.index = 0;
11684
11685 /* Check PNG signature. */
11686 if (tbr.len < sizeof sig
11687 || !png_check_sig (tbr.bytes, sizeof sig))
11688 {
11689 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11690 UNGCPRO;
11691 return 0;
11692 }
11693
11694 /* Need to skip past the signature. */
11695 tbr.bytes += sizeof (sig);
11696 }
11697
6fc2811b
JR
11698 /* Initialize read and info structs for PNG lib. */
11699 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11700 my_png_error, my_png_warning);
11701 if (!png_ptr)
11702 {
11703 if (fp) fclose (fp);
11704 UNGCPRO;
11705 return 0;
11706 }
11707
11708 info_ptr = png_create_info_struct (png_ptr);
11709 if (!info_ptr)
11710 {
11711 png_destroy_read_struct (&png_ptr, NULL, NULL);
11712 if (fp) fclose (fp);
11713 UNGCPRO;
11714 return 0;
11715 }
11716
11717 end_info = png_create_info_struct (png_ptr);
11718 if (!end_info)
11719 {
11720 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11721 if (fp) fclose (fp);
11722 UNGCPRO;
11723 return 0;
11724 }
11725
11726 /* Set error jump-back. We come back here when the PNG library
11727 detects an error. */
11728 if (setjmp (png_ptr->jmpbuf))
11729 {
11730 error:
11731 if (png_ptr)
11732 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11733 xfree (pixels);
11734 xfree (rows);
11735 if (fp) fclose (fp);
11736 UNGCPRO;
11737 return 0;
11738 }
11739
11740 /* Read image info. */
11741 if (!NILP (specified_data))
11742 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11743 else
11744 png_init_io (png_ptr, fp);
11745
11746 png_set_sig_bytes (png_ptr, sizeof sig);
11747 png_read_info (png_ptr, info_ptr);
11748 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11749 &interlace_type, NULL, NULL);
11750
7d0393cf 11751 /* If image contains simply transparency data, we prefer to
6fc2811b
JR
11752 construct a clipping mask. */
11753 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11754 transparent_p = 1;
11755 else
11756 transparent_p = 0;
11757
7d0393cf 11758 /* This function is easier to write if we only have to handle
6fc2811b
JR
11759 one data format: RGB or RGBA with 8 bits per channel. Let's
11760 transform other formats into that format. */
11761
11762 /* Strip more than 8 bits per channel. */
11763 if (bit_depth == 16)
11764 png_set_strip_16 (png_ptr);
11765
11766 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11767 if available. */
11768 png_set_expand (png_ptr);
11769
11770 /* Convert grayscale images to RGB. */
7d0393cf 11771 if (color_type == PNG_COLOR_TYPE_GRAY
6fc2811b
JR
11772 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11773 png_set_gray_to_rgb (png_ptr);
11774
11775 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11776 gamma_str = getenv ("SCREEN_GAMMA");
11777 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11778
11779 /* Tell the PNG lib to handle gamma correction for us. */
11780
11781#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11782 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11783 /* There is a special chunk in the image specifying the gamma. */
11784 png_set_sRGB (png_ptr, info_ptr, intent);
11785 else
11786#endif
11787 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11788 /* Image contains gamma information. */
11789 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11790 else
11791 /* Use a default of 0.5 for the image gamma. */
11792 png_set_gamma (png_ptr, screen_gamma, 0.5);
11793
11794 /* Handle alpha channel by combining the image with a background
11795 color. Do this only if a real alpha channel is supplied. For
11796 simple transparency, we prefer a clipping mask. */
11797 if (!transparent_p)
11798 {
11799 png_color_16 *image_background;
a05e2bae
JR
11800 Lisp_Object specified_bg
11801 = image_spec_value (img->spec, QCbackground, NULL);
11802
11803
11804 if (STRINGP (specified_bg))
11805 /* The user specified `:background', use that. */
11806 {
11807 COLORREF color;
d5db4077 11808 if (w32_defined_color (f, SDATA (specified_bg), &color, 0))
a05e2bae
JR
11809 {
11810 png_color_16 user_bg;
11811
11812 bzero (&user_bg, sizeof user_bg);
11813 user_bg.red = color.red;
11814 user_bg.green = color.green;
11815 user_bg.blue = color.blue;
6fc2811b 11816
a05e2bae
JR
11817 png_set_background (png_ptr, &user_bg,
11818 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11819 }
11820 }
11821 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
7d0393cf 11822 /* Image contains a background color with which to
6fc2811b
JR
11823 combine the image. */
11824 png_set_background (png_ptr, image_background,
11825 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11826 else
11827 {
11828 /* Image does not contain a background color with which
7d0393cf 11829 to combine the image data via an alpha channel. Use
6fc2811b
JR
11830 the frame's background instead. */
11831 XColor color;
11832 Colormap cmap;
11833 png_color_16 frame_background;
11834
a05e2bae 11835 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11836 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11837 x_query_color (f, &color);
6fc2811b
JR
11838
11839 bzero (&frame_background, sizeof frame_background);
11840 frame_background.red = color.red;
11841 frame_background.green = color.green;
11842 frame_background.blue = color.blue;
11843
11844 png_set_background (png_ptr, &frame_background,
11845 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11846 }
11847 }
11848
11849 /* Update info structure. */
11850 png_read_update_info (png_ptr, info_ptr);
11851
11852 /* Get number of channels. Valid values are 1 for grayscale images
11853 and images with a palette, 2 for grayscale images with transparency
11854 information (alpha channel), 3 for RGB images, and 4 for RGB
11855 images with alpha channel, i.e. RGBA. If conversions above were
11856 sufficient we should only have 3 or 4 channels here. */
11857 channels = png_get_channels (png_ptr, info_ptr);
11858 xassert (channels == 3 || channels == 4);
11859
11860 /* Number of bytes needed for one row of the image. */
11861 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11862
11863 /* Allocate memory for the image. */
11864 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11865 rows = (png_byte **) xmalloc (height * sizeof *rows);
11866 for (i = 0; i < height; ++i)
11867 rows[i] = pixels + i * row_bytes;
11868
11869 /* Read the entire image. */
11870 png_read_image (png_ptr, rows);
11871 png_read_end (png_ptr, info_ptr);
11872 if (fp)
11873 {
11874 fclose (fp);
11875 fp = NULL;
11876 }
11877
6fc2811b
JR
11878 /* Create the X image and pixmap. */
11879 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11880 &img->pixmap))
a05e2bae 11881 goto error;
7d0393cf 11882
6fc2811b
JR
11883 /* Create an image and pixmap serving as mask if the PNG image
11884 contains an alpha channel. */
11885 if (channels == 4
11886 && !transparent_p
11887 && !x_create_x_image_and_pixmap (f, width, height, 1,
11888 &mask_img, &img->mask))
11889 {
11890 x_destroy_x_image (ximg);
11891 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11892 img->pixmap = 0;
6fc2811b
JR
11893 goto error;
11894 }
11895
11896 /* Fill the X image and mask from PNG data. */
11897 init_color_table ();
11898
11899 for (y = 0; y < height; ++y)
11900 {
11901 png_byte *p = rows[y];
11902
11903 for (x = 0; x < width; ++x)
11904 {
11905 unsigned r, g, b;
11906
11907 r = *p++ << 8;
11908 g = *p++ << 8;
11909 b = *p++ << 8;
11910 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11911
11912 /* An alpha channel, aka mask channel, associates variable
7d0393cf
JB
11913 transparency with an image. Where other image formats
11914 support binary transparency---fully transparent or fully
6fc2811b
JR
11915 opaque---PNG allows up to 254 levels of partial transparency.
11916 The PNG library implements partial transparency by combining
11917 the image with a specified background color.
11918
11919 I'm not sure how to handle this here nicely: because the
11920 background on which the image is displayed may change, for
7d0393cf
JB
11921 real alpha channel support, it would be necessary to create
11922 a new image for each possible background.
6fc2811b
JR
11923
11924 What I'm doing now is that a mask is created if we have
11925 boolean transparency information. Otherwise I'm using
11926 the frame's background color to combine the image with. */
11927
11928 if (channels == 4)
11929 {
11930 if (mask_img)
11931 XPutPixel (mask_img, x, y, *p > 0);
11932 ++p;
11933 }
11934 }
11935 }
11936
a05e2bae
JR
11937 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11938 /* Set IMG's background color from the PNG image, unless the user
11939 overrode it. */
11940 {
11941 png_color_16 *bg;
11942 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11943 {
11944 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11945 img->background_valid = 1;
11946 }
11947 }
11948
6fc2811b
JR
11949 /* Remember colors allocated for this image. */
11950 img->colors = colors_in_color_table (&img->ncolors);
11951 free_color_table ();
11952
11953 /* Clean up. */
11954 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11955 xfree (rows);
11956 xfree (pixels);
11957
11958 img->width = width;
11959 img->height = height;
11960
a05e2bae
JR
11961 /* Maybe fill in the background field while we have ximg handy. */
11962 IMAGE_BACKGROUND (img, f, ximg);
11963
6fc2811b
JR
11964 /* Put the image into the pixmap, then free the X image and its buffer. */
11965 x_put_x_image (f, ximg, img->pixmap, width, height);
11966 x_destroy_x_image (ximg);
11967
11968 /* Same for the mask. */
11969 if (mask_img)
11970 {
a05e2bae
JR
11971 /* Fill in the background_transparent field while we have the mask
11972 handy. */
11973 image_background_transparent (img, f, mask_img);
11974
6fc2811b
JR
11975 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11976 x_destroy_x_image (mask_img);
11977 }
11978
6fc2811b
JR
11979 UNGCPRO;
11980 return 1;
11981}
11982
11983#endif /* HAVE_PNG != 0 */
11984
11985
11986\f
11987/***********************************************************************
11988 JPEG
11989 ***********************************************************************/
11990
11991#if HAVE_JPEG
11992
11993/* Work around a warning about HAVE_STDLIB_H being redefined in
11994 jconfig.h. */
11995#ifdef HAVE_STDLIB_H
11996#define HAVE_STDLIB_H_1
11997#undef HAVE_STDLIB_H
11998#endif /* HAVE_STLIB_H */
11999
12000#include <jpeglib.h>
12001#include <jerror.h>
12002#include <setjmp.h>
12003
12004#ifdef HAVE_STLIB_H_1
12005#define HAVE_STDLIB_H 1
12006#endif
12007
12008static int jpeg_image_p P_ ((Lisp_Object object));
12009static int jpeg_load P_ ((struct frame *f, struct image *img));
12010
12011/* The symbol `jpeg' identifying images of this type. */
12012
12013Lisp_Object Qjpeg;
12014
12015/* Indices of image specification fields in gs_format, below. */
12016
12017enum jpeg_keyword_index
12018{
12019 JPEG_TYPE,
12020 JPEG_DATA,
12021 JPEG_FILE,
12022 JPEG_ASCENT,
12023 JPEG_MARGIN,
12024 JPEG_RELIEF,
12025 JPEG_ALGORITHM,
12026 JPEG_HEURISTIC_MASK,
a05e2bae
JR
12027 JPEG_MASK,
12028 JPEG_BACKGROUND,
6fc2811b
JR
12029 JPEG_LAST
12030};
12031
12032/* Vector of image_keyword structures describing the format
12033 of valid user-defined image specifications. */
12034
12035static struct image_keyword jpeg_format[JPEG_LAST] =
12036{
12037 {":type", IMAGE_SYMBOL_VALUE, 1},
12038 {":data", IMAGE_STRING_VALUE, 0},
12039 {":file", IMAGE_STRING_VALUE, 0},
12040 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12041 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12042 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12043 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12044 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12045 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12046 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12047};
12048
12049/* Structure describing the image type `jpeg'. */
12050
12051static struct image_type jpeg_type =
12052{
12053 &Qjpeg,
12054 jpeg_image_p,
12055 jpeg_load,
12056 x_clear_image,
12057 NULL
12058};
12059
12060
12061/* Return non-zero if OBJECT is a valid JPEG image specification. */
12062
12063static int
12064jpeg_image_p (object)
12065 Lisp_Object object;
12066{
12067 struct image_keyword fmt[JPEG_LAST];
7d0393cf 12068
6fc2811b 12069 bcopy (jpeg_format, fmt, sizeof fmt);
7d0393cf 12070
6fc2811b 12071 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
7d0393cf 12072 || (fmt[JPEG_ASCENT].count
6fc2811b
JR
12073 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
12074 return 0;
12075
12076 /* Must specify either the :data or :file keyword. */
12077 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
12078}
12079
12080
12081struct my_jpeg_error_mgr
12082{
12083 struct jpeg_error_mgr pub;
12084 jmp_buf setjmp_buffer;
12085};
12086
12087static void
12088my_error_exit (cinfo)
12089 j_common_ptr cinfo;
12090{
12091 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12092 longjmp (mgr->setjmp_buffer, 1);
12093}
12094
6fc2811b
JR
12095/* Init source method for JPEG data source manager. Called by
12096 jpeg_read_header() before any data is actually read. See
12097 libjpeg.doc from the JPEG lib distribution. */
12098
12099static void
12100our_init_source (cinfo)
12101 j_decompress_ptr cinfo;
12102{
12103}
12104
12105
12106/* Fill input buffer method for JPEG data source manager. Called
12107 whenever more data is needed. We read the whole image in one step,
12108 so this only adds a fake end of input marker at the end. */
12109
12110static boolean
12111our_fill_input_buffer (cinfo)
12112 j_decompress_ptr cinfo;
12113{
12114 /* Insert a fake EOI marker. */
12115 struct jpeg_source_mgr *src = cinfo->src;
12116 static JOCTET buffer[2];
12117
12118 buffer[0] = (JOCTET) 0xFF;
12119 buffer[1] = (JOCTET) JPEG_EOI;
12120
12121 src->next_input_byte = buffer;
12122 src->bytes_in_buffer = 2;
12123 return TRUE;
12124}
12125
12126
12127/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12128 is the JPEG data source manager. */
12129
12130static void
12131our_skip_input_data (cinfo, num_bytes)
12132 j_decompress_ptr cinfo;
12133 long num_bytes;
12134{
12135 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12136
12137 if (src)
12138 {
12139 if (num_bytes > src->bytes_in_buffer)
12140 ERREXIT (cinfo, JERR_INPUT_EOF);
7d0393cf 12141
6fc2811b
JR
12142 src->bytes_in_buffer -= num_bytes;
12143 src->next_input_byte += num_bytes;
12144 }
12145}
12146
12147
12148/* Method to terminate data source. Called by
12149 jpeg_finish_decompress() after all data has been processed. */
12150
12151static void
12152our_term_source (cinfo)
12153 j_decompress_ptr cinfo;
12154{
12155}
12156
12157
12158/* Set up the JPEG lib for reading an image from DATA which contains
12159 LEN bytes. CINFO is the decompression info structure created for
12160 reading the image. */
12161
12162static void
12163jpeg_memory_src (cinfo, data, len)
12164 j_decompress_ptr cinfo;
12165 JOCTET *data;
12166 unsigned int len;
12167{
12168 struct jpeg_source_mgr *src;
12169
12170 if (cinfo->src == NULL)
12171 {
12172 /* First time for this JPEG object? */
12173 cinfo->src = (struct jpeg_source_mgr *)
12174 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12175 sizeof (struct jpeg_source_mgr));
12176 src = (struct jpeg_source_mgr *) cinfo->src;
12177 src->next_input_byte = data;
12178 }
7d0393cf 12179
6fc2811b
JR
12180 src = (struct jpeg_source_mgr *) cinfo->src;
12181 src->init_source = our_init_source;
12182 src->fill_input_buffer = our_fill_input_buffer;
12183 src->skip_input_data = our_skip_input_data;
12184 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12185 src->term_source = our_term_source;
12186 src->bytes_in_buffer = len;
12187 src->next_input_byte = data;
12188}
12189
12190
12191/* Load image IMG for use on frame F. Patterned after example.c
12192 from the JPEG lib. */
12193
7d0393cf 12194static int
6fc2811b
JR
12195jpeg_load (f, img)
12196 struct frame *f;
12197 struct image *img;
12198{
12199 struct jpeg_decompress_struct cinfo;
12200 struct my_jpeg_error_mgr mgr;
12201 Lisp_Object file, specified_file;
12202 Lisp_Object specified_data;
a05e2bae 12203 FILE * volatile fp = NULL;
6fc2811b
JR
12204 JSAMPARRAY buffer;
12205 int row_stride, x, y;
12206 XImage *ximg = NULL;
12207 int rc;
12208 unsigned long *colors;
12209 int width, height;
12210 struct gcpro gcpro1;
12211
12212 /* Open the JPEG file. */
12213 specified_file = image_spec_value (img->spec, QCfile, NULL);
12214 specified_data = image_spec_value (img->spec, QCdata, NULL);
12215 file = Qnil;
12216 GCPRO1 (file);
12217
6fc2811b
JR
12218 if (NILP (specified_data))
12219 {
12220 file = x_find_image_file (specified_file);
12221 if (!STRINGP (file))
12222 {
12223 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12224 UNGCPRO;
12225 return 0;
12226 }
7d0393cf 12227
d5db4077 12228 fp = fopen (SDATA (file), "r");
6fc2811b
JR
12229 if (fp == NULL)
12230 {
12231 image_error ("Cannot open `%s'", file, Qnil);
12232 UNGCPRO;
12233 return 0;
12234 }
12235 }
7d0393cf 12236
6fc2811b
JR
12237 /* Customize libjpeg's error handling to call my_error_exit when an
12238 error is detected. This function will perform a longjmp. */
6fc2811b 12239 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 12240 mgr.pub.error_exit = my_error_exit;
7d0393cf 12241
6fc2811b
JR
12242 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12243 {
12244 if (rc == 1)
12245 {
12246 /* Called from my_error_exit. Display a JPEG error. */
12247 char buffer[JMSG_LENGTH_MAX];
12248 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12249 image_error ("Error reading JPEG image `%s': %s", img->spec,
12250 build_string (buffer));
12251 }
7d0393cf 12252
6fc2811b
JR
12253 /* Close the input file and destroy the JPEG object. */
12254 if (fp)
12255 fclose (fp);
12256 jpeg_destroy_decompress (&cinfo);
7d0393cf 12257
6fc2811b
JR
12258 /* If we already have an XImage, free that. */
12259 x_destroy_x_image (ximg);
12260
12261 /* Free pixmap and colors. */
12262 x_clear_image (f, img);
7d0393cf 12263
6fc2811b
JR
12264 UNGCPRO;
12265 return 0;
12266 }
12267
12268 /* Create the JPEG decompression object. Let it read from fp.
12269 Read the JPEG image header. */
12270 jpeg_create_decompress (&cinfo);
12271
12272 if (NILP (specified_data))
12273 jpeg_stdio_src (&cinfo, fp);
12274 else
d5db4077
KR
12275 jpeg_memory_src (&cinfo, SDATA (specified_data),
12276 SBYTES (specified_data));
6fc2811b
JR
12277
12278 jpeg_read_header (&cinfo, TRUE);
12279
12280 /* Customize decompression so that color quantization will be used.
12281 Start decompression. */
12282 cinfo.quantize_colors = TRUE;
12283 jpeg_start_decompress (&cinfo);
12284 width = img->width = cinfo.output_width;
12285 height = img->height = cinfo.output_height;
12286
6fc2811b
JR
12287 /* Create X image and pixmap. */
12288 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12289 &img->pixmap))
a05e2bae 12290 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
12291
12292 /* Allocate colors. When color quantization is used,
12293 cinfo.actual_number_of_colors has been set with the number of
12294 colors generated, and cinfo.colormap is a two-dimensional array
12295 of color indices in the range 0..cinfo.actual_number_of_colors.
12296 No more than 255 colors will be generated. */
12297 {
12298 int i, ir, ig, ib;
12299
12300 if (cinfo.out_color_components > 2)
12301 ir = 0, ig = 1, ib = 2;
12302 else if (cinfo.out_color_components > 1)
12303 ir = 0, ig = 1, ib = 0;
12304 else
12305 ir = 0, ig = 0, ib = 0;
12306
12307 /* Use the color table mechanism because it handles colors that
12308 cannot be allocated nicely. Such colors will be replaced with
12309 a default color, and we don't have to care about which colors
12310 can be freed safely, and which can't. */
12311 init_color_table ();
12312 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12313 * sizeof *colors);
7d0393cf 12314
6fc2811b
JR
12315 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12316 {
12317 /* Multiply RGB values with 255 because X expects RGB values
12318 in the range 0..0xffff. */
12319 int r = cinfo.colormap[ir][i] << 8;
12320 int g = cinfo.colormap[ig][i] << 8;
12321 int b = cinfo.colormap[ib][i] << 8;
12322 colors[i] = lookup_rgb_color (f, r, g, b);
12323 }
12324
12325 /* Remember those colors actually allocated. */
12326 img->colors = colors_in_color_table (&img->ncolors);
12327 free_color_table ();
12328 }
12329
12330 /* Read pixels. */
12331 row_stride = width * cinfo.output_components;
12332 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12333 row_stride, 1);
12334 for (y = 0; y < height; ++y)
12335 {
12336 jpeg_read_scanlines (&cinfo, buffer, 1);
12337 for (x = 0; x < cinfo.output_width; ++x)
12338 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12339 }
12340
12341 /* Clean up. */
12342 jpeg_finish_decompress (&cinfo);
12343 jpeg_destroy_decompress (&cinfo);
12344 if (fp)
12345 fclose (fp);
7d0393cf 12346
a05e2bae
JR
12347 /* Maybe fill in the background field while we have ximg handy. */
12348 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12349 IMAGE_BACKGROUND (img, f, ximg);
7d0393cf 12350
6fc2811b
JR
12351 /* Put the image into the pixmap. */
12352 x_put_x_image (f, ximg, img->pixmap, width, height);
12353 x_destroy_x_image (ximg);
12354 UNBLOCK_INPUT;
12355 UNGCPRO;
12356 return 1;
12357}
12358
12359#endif /* HAVE_JPEG */
12360
12361
12362\f
12363/***********************************************************************
12364 TIFF
12365 ***********************************************************************/
12366
12367#if HAVE_TIFF
12368
12369#include <tiffio.h>
12370
12371static int tiff_image_p P_ ((Lisp_Object object));
12372static int tiff_load P_ ((struct frame *f, struct image *img));
12373
12374/* The symbol `tiff' identifying images of this type. */
12375
12376Lisp_Object Qtiff;
12377
12378/* Indices of image specification fields in tiff_format, below. */
12379
12380enum tiff_keyword_index
12381{
12382 TIFF_TYPE,
12383 TIFF_DATA,
12384 TIFF_FILE,
12385 TIFF_ASCENT,
12386 TIFF_MARGIN,
12387 TIFF_RELIEF,
12388 TIFF_ALGORITHM,
12389 TIFF_HEURISTIC_MASK,
a05e2bae
JR
12390 TIFF_MASK,
12391 TIFF_BACKGROUND,
6fc2811b
JR
12392 TIFF_LAST
12393};
12394
12395/* Vector of image_keyword structures describing the format
12396 of valid user-defined image specifications. */
12397
12398static struct image_keyword tiff_format[TIFF_LAST] =
12399{
12400 {":type", IMAGE_SYMBOL_VALUE, 1},
12401 {":data", IMAGE_STRING_VALUE, 0},
12402 {":file", IMAGE_STRING_VALUE, 0},
12403 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12404 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12405 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12406 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12407 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12408 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12409 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12410};
12411
12412/* Structure describing the image type `tiff'. */
12413
12414static struct image_type tiff_type =
12415{
12416 &Qtiff,
12417 tiff_image_p,
12418 tiff_load,
12419 x_clear_image,
12420 NULL
12421};
12422
12423
12424/* Return non-zero if OBJECT is a valid TIFF image specification. */
12425
12426static int
12427tiff_image_p (object)
12428 Lisp_Object object;
12429{
12430 struct image_keyword fmt[TIFF_LAST];
12431 bcopy (tiff_format, fmt, sizeof fmt);
7d0393cf 12432
6fc2811b 12433 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
7d0393cf 12434 || (fmt[TIFF_ASCENT].count
6fc2811b
JR
12435 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12436 return 0;
7d0393cf 12437
6fc2811b
JR
12438 /* Must specify either the :data or :file keyword. */
12439 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12440}
12441
12442
12443/* Reading from a memory buffer for TIFF images Based on the PNG
12444 memory source, but we have to provide a lot of extra functions.
12445 Blah.
12446
12447 We really only need to implement read and seek, but I am not
12448 convinced that the TIFF library is smart enough not to destroy
12449 itself if we only hand it the function pointers we need to
12450 override. */
12451
12452typedef struct
12453{
12454 unsigned char *bytes;
12455 size_t len;
12456 int index;
12457}
12458tiff_memory_source;
12459
12460static size_t
12461tiff_read_from_memory (data, buf, size)
12462 thandle_t data;
12463 tdata_t buf;
12464 tsize_t size;
12465{
12466 tiff_memory_source *src = (tiff_memory_source *) data;
12467
12468 if (size > src->len - src->index)
12469 return (size_t) -1;
12470 bcopy (src->bytes + src->index, buf, size);
12471 src->index += size;
12472 return size;
12473}
12474
12475static size_t
12476tiff_write_from_memory (data, buf, size)
12477 thandle_t data;
12478 tdata_t buf;
12479 tsize_t size;
12480{
12481 return (size_t) -1;
12482}
12483
12484static toff_t
12485tiff_seek_in_memory (data, off, whence)
12486 thandle_t data;
12487 toff_t off;
12488 int whence;
12489{
12490 tiff_memory_source *src = (tiff_memory_source *) data;
12491 int idx;
12492
12493 switch (whence)
12494 {
12495 case SEEK_SET: /* Go from beginning of source. */
12496 idx = off;
12497 break;
7d0393cf 12498
6fc2811b
JR
12499 case SEEK_END: /* Go from end of source. */
12500 idx = src->len + off;
12501 break;
7d0393cf 12502
6fc2811b
JR
12503 case SEEK_CUR: /* Go from current position. */
12504 idx = src->index + off;
12505 break;
7d0393cf 12506
6fc2811b
JR
12507 default: /* Invalid `whence'. */
12508 return -1;
12509 }
7d0393cf 12510
6fc2811b
JR
12511 if (idx > src->len || idx < 0)
12512 return -1;
7d0393cf 12513
6fc2811b
JR
12514 src->index = idx;
12515 return src->index;
12516}
12517
12518static int
12519tiff_close_memory (data)
12520 thandle_t data;
12521{
12522 /* NOOP */
12523 return 0;
12524}
12525
12526static int
12527tiff_mmap_memory (data, pbase, psize)
12528 thandle_t data;
12529 tdata_t *pbase;
12530 toff_t *psize;
12531{
12532 /* It is already _IN_ memory. */
12533 return 0;
12534}
12535
12536static void
12537tiff_unmap_memory (data, base, size)
12538 thandle_t data;
12539 tdata_t base;
12540 toff_t size;
12541{
12542 /* We don't need to do this. */
12543}
12544
12545static toff_t
12546tiff_size_of_memory (data)
12547 thandle_t data;
12548{
12549 return ((tiff_memory_source *) data)->len;
12550}
12551
3cf3436e
JR
12552
12553static void
12554tiff_error_handler (title, format, ap)
12555 const char *title, *format;
12556 va_list ap;
12557{
12558 char buf[512];
12559 int len;
7d0393cf 12560
3cf3436e
JR
12561 len = sprintf (buf, "TIFF error: %s ", title);
12562 vsprintf (buf + len, format, ap);
12563 add_to_log (buf, Qnil, Qnil);
12564}
12565
12566
12567static void
12568tiff_warning_handler (title, format, ap)
12569 const char *title, *format;
12570 va_list ap;
12571{
12572 char buf[512];
12573 int len;
7d0393cf 12574
3cf3436e
JR
12575 len = sprintf (buf, "TIFF warning: %s ", title);
12576 vsprintf (buf + len, format, ap);
12577 add_to_log (buf, Qnil, Qnil);
12578}
12579
12580
6fc2811b
JR
12581/* Load TIFF image IMG for use on frame F. Value is non-zero if
12582 successful. */
12583
12584static int
12585tiff_load (f, img)
12586 struct frame *f;
12587 struct image *img;
12588{
12589 Lisp_Object file, specified_file;
12590 Lisp_Object specified_data;
12591 TIFF *tiff;
12592 int width, height, x, y;
12593 uint32 *buf;
12594 int rc;
12595 XImage *ximg;
12596 struct gcpro gcpro1;
12597 tiff_memory_source memsrc;
12598
12599 specified_file = image_spec_value (img->spec, QCfile, NULL);
12600 specified_data = image_spec_value (img->spec, QCdata, NULL);
12601 file = Qnil;
12602 GCPRO1 (file);
12603
3cf3436e
JR
12604 TIFFSetErrorHandler (tiff_error_handler);
12605 TIFFSetWarningHandler (tiff_warning_handler);
12606
6fc2811b
JR
12607 if (NILP (specified_data))
12608 {
12609 /* Read from a file */
12610 file = x_find_image_file (specified_file);
12611 if (!STRINGP (file))
3cf3436e
JR
12612 {
12613 image_error ("Cannot find image file `%s'", file, Qnil);
12614 UNGCPRO;
12615 return 0;
12616 }
7d0393cf 12617
6fc2811b 12618 /* Try to open the image file. */
d5db4077 12619 tiff = TIFFOpen (SDATA (file), "r");
6fc2811b 12620 if (tiff == NULL)
3cf3436e
JR
12621 {
12622 image_error ("Cannot open `%s'", file, Qnil);
12623 UNGCPRO;
12624 return 0;
12625 }
6fc2811b
JR
12626 }
12627 else
12628 {
12629 /* Memory source! */
d5db4077
KR
12630 memsrc.bytes = SDATA (specified_data);
12631 memsrc.len = SBYTES (specified_data);
6fc2811b
JR
12632 memsrc.index = 0;
12633
12634 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12635 (TIFFReadWriteProc) tiff_read_from_memory,
12636 (TIFFReadWriteProc) tiff_write_from_memory,
12637 tiff_seek_in_memory,
12638 tiff_close_memory,
12639 tiff_size_of_memory,
12640 tiff_mmap_memory,
12641 tiff_unmap_memory);
12642
12643 if (!tiff)
12644 {
12645 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12646 UNGCPRO;
12647 return 0;
12648 }
12649 }
12650
12651 /* Get width and height of the image, and allocate a raster buffer
12652 of width x height 32-bit values. */
12653 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12654 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12655 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
7d0393cf 12656
6fc2811b
JR
12657 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12658 TIFFClose (tiff);
12659 if (!rc)
12660 {
12661 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12662 xfree (buf);
12663 UNGCPRO;
12664 return 0;
12665 }
12666
6fc2811b
JR
12667 /* Create the X image and pixmap. */
12668 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12669 {
6fc2811b
JR
12670 xfree (buf);
12671 UNGCPRO;
12672 return 0;
12673 }
12674
12675 /* Initialize the color table. */
12676 init_color_table ();
12677
12678 /* Process the pixel raster. Origin is in the lower-left corner. */
12679 for (y = 0; y < height; ++y)
12680 {
12681 uint32 *row = buf + y * width;
7d0393cf 12682
6fc2811b
JR
12683 for (x = 0; x < width; ++x)
12684 {
12685 uint32 abgr = row[x];
12686 int r = TIFFGetR (abgr) << 8;
12687 int g = TIFFGetG (abgr) << 8;
12688 int b = TIFFGetB (abgr) << 8;
7d0393cf 12689 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
6fc2811b
JR
12690 }
12691 }
12692
12693 /* Remember the colors allocated for the image. Free the color table. */
12694 img->colors = colors_in_color_table (&img->ncolors);
12695 free_color_table ();
12696
a05e2bae
JR
12697 img->width = width;
12698 img->height = height;
12699
12700 /* Maybe fill in the background field while we have ximg handy. */
12701 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12702 IMAGE_BACKGROUND (img, f, ximg);
12703
6fc2811b
JR
12704 /* Put the image into the pixmap, then free the X image and its buffer. */
12705 x_put_x_image (f, ximg, img->pixmap, width, height);
12706 x_destroy_x_image (ximg);
12707 xfree (buf);
6fc2811b
JR
12708
12709 UNGCPRO;
12710 return 1;
12711}
12712
12713#endif /* HAVE_TIFF != 0 */
12714
12715
12716\f
12717/***********************************************************************
12718 GIF
12719 ***********************************************************************/
12720
12721#if HAVE_GIF
12722
12723#include <gif_lib.h>
12724
12725static int gif_image_p P_ ((Lisp_Object object));
12726static int gif_load P_ ((struct frame *f, struct image *img));
12727
12728/* The symbol `gif' identifying images of this type. */
12729
12730Lisp_Object Qgif;
12731
12732/* Indices of image specification fields in gif_format, below. */
12733
12734enum gif_keyword_index
12735{
12736 GIF_TYPE,
12737 GIF_DATA,
12738 GIF_FILE,
12739 GIF_ASCENT,
12740 GIF_MARGIN,
12741 GIF_RELIEF,
12742 GIF_ALGORITHM,
12743 GIF_HEURISTIC_MASK,
a05e2bae 12744 GIF_MASK,
6fc2811b 12745 GIF_IMAGE,
a05e2bae 12746 GIF_BACKGROUND,
6fc2811b
JR
12747 GIF_LAST
12748};
12749
12750/* Vector of image_keyword structures describing the format
12751 of valid user-defined image specifications. */
12752
12753static struct image_keyword gif_format[GIF_LAST] =
12754{
12755 {":type", IMAGE_SYMBOL_VALUE, 1},
12756 {":data", IMAGE_STRING_VALUE, 0},
12757 {":file", IMAGE_STRING_VALUE, 0},
12758 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12759 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12760 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12761 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12762 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12763 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12764 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12765 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12766};
12767
12768/* Structure describing the image type `gif'. */
12769
12770static struct image_type gif_type =
12771{
12772 &Qgif,
12773 gif_image_p,
12774 gif_load,
12775 x_clear_image,
12776 NULL
12777};
12778
12779/* Return non-zero if OBJECT is a valid GIF image specification. */
12780
12781static int
12782gif_image_p (object)
12783 Lisp_Object object;
12784{
12785 struct image_keyword fmt[GIF_LAST];
12786 bcopy (gif_format, fmt, sizeof fmt);
7d0393cf 12787
6fc2811b 12788 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
7d0393cf 12789 || (fmt[GIF_ASCENT].count
6fc2811b
JR
12790 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12791 return 0;
7d0393cf 12792
6fc2811b
JR
12793 /* Must specify either the :data or :file keyword. */
12794 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12795}
12796
12797/* Reading a GIF image from memory
12798 Based on the PNG memory stuff to a certain extent. */
12799
12800typedef struct
12801{
12802 unsigned char *bytes;
12803 size_t len;
12804 int index;
12805}
12806gif_memory_source;
12807
12808/* Make the current memory source available to gif_read_from_memory.
12809 It's done this way because not all versions of libungif support
12810 a UserData field in the GifFileType structure. */
12811static gif_memory_source *current_gif_memory_src;
12812
12813static int
12814gif_read_from_memory (file, buf, len)
12815 GifFileType *file;
12816 GifByteType *buf;
12817 int len;
12818{
12819 gif_memory_source *src = current_gif_memory_src;
12820
12821 if (len > src->len - src->index)
12822 return -1;
12823
12824 bcopy (src->bytes + src->index, buf, len);
12825 src->index += len;
12826 return len;
12827}
12828
12829
12830/* Load GIF image IMG for use on frame F. Value is non-zero if
12831 successful. */
12832
12833static int
12834gif_load (f, img)
12835 struct frame *f;
12836 struct image *img;
12837{
12838 Lisp_Object file, specified_file;
12839 Lisp_Object specified_data;
12840 int rc, width, height, x, y, i;
12841 XImage *ximg;
12842 ColorMapObject *gif_color_map;
12843 unsigned long pixel_colors[256];
12844 GifFileType *gif;
12845 struct gcpro gcpro1;
12846 Lisp_Object image;
12847 int ino, image_left, image_top, image_width, image_height;
12848 gif_memory_source memsrc;
12849 unsigned char *raster;
12850
12851 specified_file = image_spec_value (img->spec, QCfile, NULL);
12852 specified_data = image_spec_value (img->spec, QCdata, NULL);
12853 file = Qnil;
dfff8a69 12854 GCPRO1 (file);
6fc2811b
JR
12855
12856 if (NILP (specified_data))
12857 {
12858 file = x_find_image_file (specified_file);
6fc2811b
JR
12859 if (!STRINGP (file))
12860 {
12861 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12862 UNGCPRO;
12863 return 0;
12864 }
7d0393cf 12865
6fc2811b 12866 /* Open the GIF file. */
d5db4077 12867 gif = DGifOpenFileName (SDATA (file));
6fc2811b
JR
12868 if (gif == NULL)
12869 {
12870 image_error ("Cannot open `%s'", file, Qnil);
12871 UNGCPRO;
12872 return 0;
12873 }
12874 }
12875 else
12876 {
12877 /* Read from memory! */
12878 current_gif_memory_src = &memsrc;
d5db4077
KR
12879 memsrc.bytes = SDATA (specified_data);
12880 memsrc.len = SBYTES (specified_data);
6fc2811b
JR
12881 memsrc.index = 0;
12882
12883 gif = DGifOpen(&memsrc, gif_read_from_memory);
12884 if (!gif)
12885 {
12886 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12887 UNGCPRO;
12888 return 0;
12889 }
12890 }
12891
12892 /* Read entire contents. */
12893 rc = DGifSlurp (gif);
12894 if (rc == GIF_ERROR)
12895 {
12896 image_error ("Error reading `%s'", img->spec, Qnil);
12897 DGifCloseFile (gif);
12898 UNGCPRO;
12899 return 0;
12900 }
12901
12902 image = image_spec_value (img->spec, QCindex, NULL);
12903 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12904 if (ino >= gif->ImageCount)
12905 {
12906 image_error ("Invalid image number `%s' in image `%s'",
12907 image, img->spec);
12908 DGifCloseFile (gif);
12909 UNGCPRO;
12910 return 0;
12911 }
12912
12913 width = img->width = gif->SWidth;
12914 height = img->height = gif->SHeight;
12915
6fc2811b
JR
12916 /* Create the X image and pixmap. */
12917 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12918 {
6fc2811b
JR
12919 DGifCloseFile (gif);
12920 UNGCPRO;
12921 return 0;
12922 }
7d0393cf 12923
6fc2811b
JR
12924 /* Allocate colors. */
12925 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12926 if (!gif_color_map)
12927 gif_color_map = gif->SColorMap;
12928 init_color_table ();
12929 bzero (pixel_colors, sizeof pixel_colors);
7d0393cf 12930
6fc2811b
JR
12931 for (i = 0; i < gif_color_map->ColorCount; ++i)
12932 {
12933 int r = gif_color_map->Colors[i].Red << 8;
12934 int g = gif_color_map->Colors[i].Green << 8;
12935 int b = gif_color_map->Colors[i].Blue << 8;
12936 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12937 }
12938
12939 img->colors = colors_in_color_table (&img->ncolors);
12940 free_color_table ();
12941
12942 /* Clear the part of the screen image that are not covered by
7d0393cf 12943 the image from the GIF file. Full animated GIF support
6fc2811b
JR
12944 requires more than can be done here (see the gif89 spec,
12945 disposal methods). Let's simply assume that the part
12946 not covered by a sub-image is in the frame's background color. */
12947 image_top = gif->SavedImages[ino].ImageDesc.Top;
12948 image_left = gif->SavedImages[ino].ImageDesc.Left;
12949 image_width = gif->SavedImages[ino].ImageDesc.Width;
12950 image_height = gif->SavedImages[ino].ImageDesc.Height;
12951
12952 for (y = 0; y < image_top; ++y)
12953 for (x = 0; x < width; ++x)
12954 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12955
12956 for (y = image_top + image_height; y < height; ++y)
12957 for (x = 0; x < width; ++x)
12958 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12959
12960 for (y = image_top; y < image_top + image_height; ++y)
12961 {
12962 for (x = 0; x < image_left; ++x)
12963 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12964 for (x = image_left + image_width; x < width; ++x)
12965 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12966 }
12967
12968 /* Read the GIF image into the X image. We use a local variable
12969 `raster' here because RasterBits below is a char *, and invites
12970 problems with bytes >= 0x80. */
12971 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12972
12973 if (gif->SavedImages[ino].ImageDesc.Interlace)
12974 {
12975 static int interlace_start[] = {0, 4, 2, 1};
12976 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12977 int pass;
6fc2811b
JR
12978 int row = interlace_start[0];
12979
12980 pass = 0;
12981
12982 for (y = 0; y < image_height; y++)
12983 {
12984 if (row >= image_height)
12985 {
12986 row = interlace_start[++pass];
12987 while (row >= image_height)
12988 row = interlace_start[++pass];
12989 }
7d0393cf 12990
6fc2811b
JR
12991 for (x = 0; x < image_width; x++)
12992 {
12993 int i = raster[(y * image_width) + x];
12994 XPutPixel (ximg, x + image_left, row + image_top,
12995 pixel_colors[i]);
12996 }
7d0393cf 12997
6fc2811b
JR
12998 row += interlace_increment[pass];
12999 }
13000 }
13001 else
13002 {
13003 for (y = 0; y < image_height; ++y)
13004 for (x = 0; x < image_width; ++x)
13005 {
13006 int i = raster[y* image_width + x];
13007 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
13008 }
13009 }
7d0393cf 13010
6fc2811b 13011 DGifCloseFile (gif);
a05e2bae
JR
13012
13013 /* Maybe fill in the background field while we have ximg handy. */
13014 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
13015 IMAGE_BACKGROUND (img, f, ximg);
13016
6fc2811b
JR
13017 /* Put the image into the pixmap, then free the X image and its buffer. */
13018 x_put_x_image (f, ximg, img->pixmap, width, height);
13019 x_destroy_x_image (ximg);
7d0393cf 13020
6fc2811b
JR
13021 UNGCPRO;
13022 return 1;
13023}
13024
13025#endif /* HAVE_GIF != 0 */
13026
13027
13028\f
13029/***********************************************************************
13030 Ghostscript
13031 ***********************************************************************/
13032
3cf3436e
JR
13033Lisp_Object Qpostscript;
13034
6fc2811b
JR
13035#ifdef HAVE_GHOSTSCRIPT
13036static int gs_image_p P_ ((Lisp_Object object));
13037static int gs_load P_ ((struct frame *f, struct image *img));
13038static void gs_clear_image P_ ((struct frame *f, struct image *img));
13039
13040/* The symbol `postscript' identifying images of this type. */
13041
6fc2811b
JR
13042/* Keyword symbols. */
13043
13044Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
13045
13046/* Indices of image specification fields in gs_format, below. */
13047
13048enum gs_keyword_index
13049{
13050 GS_TYPE,
13051 GS_PT_WIDTH,
13052 GS_PT_HEIGHT,
13053 GS_FILE,
13054 GS_LOADER,
13055 GS_BOUNDING_BOX,
13056 GS_ASCENT,
13057 GS_MARGIN,
13058 GS_RELIEF,
13059 GS_ALGORITHM,
13060 GS_HEURISTIC_MASK,
a05e2bae
JR
13061 GS_MASK,
13062 GS_BACKGROUND,
6fc2811b
JR
13063 GS_LAST
13064};
13065
13066/* Vector of image_keyword structures describing the format
13067 of valid user-defined image specifications. */
13068
13069static struct image_keyword gs_format[GS_LAST] =
13070{
13071 {":type", IMAGE_SYMBOL_VALUE, 1},
13072 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13073 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13074 {":file", IMAGE_STRING_VALUE, 1},
13075 {":loader", IMAGE_FUNCTION_VALUE, 0},
13076 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
13077 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 13078 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 13079 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 13080 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
13081 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13082 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13083 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
13084};
13085
13086/* Structure describing the image type `ghostscript'. */
13087
13088static struct image_type gs_type =
13089{
13090 &Qpostscript,
13091 gs_image_p,
13092 gs_load,
13093 gs_clear_image,
13094 NULL
13095};
13096
13097
13098/* Free X resources of Ghostscript image IMG which is used on frame F. */
13099
13100static void
13101gs_clear_image (f, img)
13102 struct frame *f;
13103 struct image *img;
13104{
13105 /* IMG->data.ptr_val may contain a recorded colormap. */
13106 xfree (img->data.ptr_val);
13107 x_clear_image (f, img);
13108}
13109
13110
13111/* Return non-zero if OBJECT is a valid Ghostscript image
13112 specification. */
13113
13114static int
13115gs_image_p (object)
13116 Lisp_Object object;
13117{
13118 struct image_keyword fmt[GS_LAST];
13119 Lisp_Object tem;
13120 int i;
7d0393cf 13121
6fc2811b 13122 bcopy (gs_format, fmt, sizeof fmt);
7d0393cf 13123
6fc2811b 13124 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
7d0393cf 13125 || (fmt[GS_ASCENT].count
6fc2811b
JR
13126 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13127 return 0;
13128
13129 /* Bounding box must be a list or vector containing 4 integers. */
13130 tem = fmt[GS_BOUNDING_BOX].value;
13131 if (CONSP (tem))
13132 {
13133 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13134 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13135 return 0;
13136 if (!NILP (tem))
13137 return 0;
13138 }
13139 else if (VECTORP (tem))
13140 {
13141 if (XVECTOR (tem)->size != 4)
13142 return 0;
13143 for (i = 0; i < 4; ++i)
13144 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13145 return 0;
13146 }
13147 else
13148 return 0;
13149
13150 return 1;
13151}
13152
13153
13154/* Load Ghostscript image IMG for use on frame F. Value is non-zero
13155 if successful. */
13156
13157static int
13158gs_load (f, img)
13159 struct frame *f;
13160 struct image *img;
13161{
13162 char buffer[100];
13163 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13164 struct gcpro gcpro1, gcpro2;
13165 Lisp_Object frame;
13166 double in_width, in_height;
13167 Lisp_Object pixel_colors = Qnil;
13168
13169 /* Compute pixel size of pixmap needed from the given size in the
13170 image specification. Sizes in the specification are in pt. 1 pt
13171 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13172 info. */
13173 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13174 in_width = XFASTINT (pt_width) / 72.0;
13175 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13176 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13177 in_height = XFASTINT (pt_height) / 72.0;
13178 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13179
13180 /* Create the pixmap. */
13181 BLOCK_INPUT;
13182 xassert (img->pixmap == 0);
13183 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13184 img->width, img->height,
a05e2bae 13185 one_w32_display_info.n_cbits);
6fc2811b
JR
13186 UNBLOCK_INPUT;
13187
13188 if (!img->pixmap)
13189 {
13190 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13191 return 0;
13192 }
7d0393cf 13193
6fc2811b
JR
13194 /* Call the loader to fill the pixmap. It returns a process object
13195 if successful. We do not record_unwind_protect here because
13196 other places in redisplay like calling window scroll functions
13197 don't either. Let the Lisp loader use `unwind-protect' instead. */
13198 GCPRO2 (window_and_pixmap_id, pixel_colors);
13199
13200 sprintf (buffer, "%lu %lu",
13201 (unsigned long) FRAME_W32_WINDOW (f),
13202 (unsigned long) img->pixmap);
13203 window_and_pixmap_id = build_string (buffer);
7d0393cf 13204
6fc2811b
JR
13205 sprintf (buffer, "%lu %lu",
13206 FRAME_FOREGROUND_PIXEL (f),
13207 FRAME_BACKGROUND_PIXEL (f));
13208 pixel_colors = build_string (buffer);
7d0393cf 13209
6fc2811b
JR
13210 XSETFRAME (frame, f);
13211 loader = image_spec_value (img->spec, QCloader, NULL);
13212 if (NILP (loader))
13213 loader = intern ("gs-load-image");
13214
13215 img->data.lisp_val = call6 (loader, frame, img->spec,
13216 make_number (img->width),
13217 make_number (img->height),
13218 window_and_pixmap_id,
13219 pixel_colors);
13220 UNGCPRO;
13221 return PROCESSP (img->data.lisp_val);
13222}
13223
13224
13225/* Kill the Ghostscript process that was started to fill PIXMAP on
13226 frame F. Called from XTread_socket when receiving an event
13227 telling Emacs that Ghostscript has finished drawing. */
13228
13229void
13230x_kill_gs_process (pixmap, f)
13231 Pixmap pixmap;
13232 struct frame *f;
13233{
13234 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13235 int class, i;
13236 struct image *img;
13237
13238 /* Find the image containing PIXMAP. */
13239 for (i = 0; i < c->used; ++i)
13240 if (c->images[i]->pixmap == pixmap)
13241 break;
13242
3cf3436e
JR
13243 /* Should someone in between have cleared the image cache, for
13244 instance, give up. */
13245 if (i == c->used)
13246 return;
13247
6fc2811b
JR
13248 /* Kill the GS process. We should have found PIXMAP in the image
13249 cache and its image should contain a process object. */
6fc2811b
JR
13250 img = c->images[i];
13251 xassert (PROCESSP (img->data.lisp_val));
13252 Fkill_process (img->data.lisp_val, Qnil);
13253 img->data.lisp_val = Qnil;
13254
13255 /* On displays with a mutable colormap, figure out the colors
13256 allocated for the image by looking at the pixels of an XImage for
13257 img->pixmap. */
13258 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13259 if (class != StaticColor && class != StaticGray && class != TrueColor)
13260 {
13261 XImage *ximg;
13262
13263 BLOCK_INPUT;
13264
13265 /* Try to get an XImage for img->pixmep. */
13266 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13267 0, 0, img->width, img->height, ~0, ZPixmap);
13268 if (ximg)
13269 {
13270 int x, y;
7d0393cf 13271
6fc2811b
JR
13272 /* Initialize the color table. */
13273 init_color_table ();
7d0393cf 13274
6fc2811b
JR
13275 /* For each pixel of the image, look its color up in the
13276 color table. After having done so, the color table will
13277 contain an entry for each color used by the image. */
13278 for (y = 0; y < img->height; ++y)
13279 for (x = 0; x < img->width; ++x)
13280 {
13281 unsigned long pixel = XGetPixel (ximg, x, y);
13282 lookup_pixel_color (f, pixel);
13283 }
13284
13285 /* Record colors in the image. Free color table and XImage. */
13286 img->colors = colors_in_color_table (&img->ncolors);
13287 free_color_table ();
13288 XDestroyImage (ximg);
13289
13290#if 0 /* This doesn't seem to be the case. If we free the colors
13291 here, we get a BadAccess later in x_clear_image when
13292 freeing the colors. */
13293 /* We have allocated colors once, but Ghostscript has also
13294 allocated colors on behalf of us. So, to get the
13295 reference counts right, free them once. */
13296 if (img->ncolors)
3cf3436e 13297 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 13298 img->colors, img->ncolors, 0);
6fc2811b
JR
13299#endif
13300 }
13301 else
13302 image_error ("Cannot get X image of `%s'; colors will not be freed",
13303 img->spec, Qnil);
7d0393cf 13304
6fc2811b
JR
13305 UNBLOCK_INPUT;
13306 }
3cf3436e
JR
13307
13308 /* Now that we have the pixmap, compute mask and transform the
13309 image if requested. */
13310 BLOCK_INPUT;
13311 postprocess_image (f, img);
13312 UNBLOCK_INPUT;
6fc2811b
JR
13313}
13314
13315#endif /* HAVE_GHOSTSCRIPT */
13316
13317\f
13318/***********************************************************************
13319 Window properties
13320 ***********************************************************************/
13321
13322DEFUN ("x-change-window-property", Fx_change_window_property,
13323 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
13324 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13325PROP and VALUE must be strings. FRAME nil or omitted means use the
13326selected frame. Value is VALUE. */)
6fc2811b
JR
13327 (prop, value, frame)
13328 Lisp_Object frame, prop, value;
13329{
767b1ff0 13330#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13331 struct frame *f = check_x_frame (frame);
13332 Atom prop_atom;
13333
b7826503
PJ
13334 CHECK_STRING (prop);
13335 CHECK_STRING (value);
6fc2811b
JR
13336
13337 BLOCK_INPUT;
d5db4077 13338 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
13339 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13340 prop_atom, XA_STRING, 8, PropModeReplace,
d5db4077 13341 SDATA (value), SCHARS (value));
6fc2811b
JR
13342
13343 /* Make sure the property is set when we return. */
13344 XFlush (FRAME_W32_DISPLAY (f));
13345 UNBLOCK_INPUT;
13346
767b1ff0 13347#endif /* TODO */
6fc2811b
JR
13348
13349 return value;
13350}
13351
13352
13353DEFUN ("x-delete-window-property", Fx_delete_window_property,
13354 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
13355 doc: /* Remove window property PROP from X window of FRAME.
13356FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
13357 (prop, frame)
13358 Lisp_Object prop, frame;
13359{
767b1ff0 13360#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13361
13362 struct frame *f = check_x_frame (frame);
13363 Atom prop_atom;
13364
b7826503 13365 CHECK_STRING (prop);
6fc2811b 13366 BLOCK_INPUT;
d5db4077 13367 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
13368 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13369
13370 /* Make sure the property is removed when we return. */
13371 XFlush (FRAME_W32_DISPLAY (f));
13372 UNBLOCK_INPUT;
767b1ff0 13373#endif /* TODO */
6fc2811b
JR
13374
13375 return prop;
13376}
13377
13378
13379DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13380 1, 2, 0,
74e1aeec
JR
13381 doc: /* Value is the value of window property PROP on FRAME.
13382If FRAME is nil or omitted, use the selected frame. Value is nil
13383if FRAME hasn't a property with name PROP or if PROP has no string
13384value. */)
6fc2811b
JR
13385 (prop, frame)
13386 Lisp_Object prop, frame;
13387{
767b1ff0 13388#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13389
13390 struct frame *f = check_x_frame (frame);
13391 Atom prop_atom;
13392 int rc;
13393 Lisp_Object prop_value = Qnil;
13394 char *tmp_data = NULL;
13395 Atom actual_type;
13396 int actual_format;
13397 unsigned long actual_size, bytes_remaining;
13398
b7826503 13399 CHECK_STRING (prop);
6fc2811b 13400 BLOCK_INPUT;
d5db4077 13401 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
6fc2811b
JR
13402 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13403 prop_atom, 0, 0, False, XA_STRING,
13404 &actual_type, &actual_format, &actual_size,
13405 &bytes_remaining, (unsigned char **) &tmp_data);
13406 if (rc == Success)
13407 {
13408 int size = bytes_remaining;
13409
13410 XFree (tmp_data);
13411 tmp_data = NULL;
13412
13413 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13414 prop_atom, 0, bytes_remaining,
13415 False, XA_STRING,
7d0393cf
JB
13416 &actual_type, &actual_format,
13417 &actual_size, &bytes_remaining,
6fc2811b
JR
13418 (unsigned char **) &tmp_data);
13419 if (rc == Success)
13420 prop_value = make_string (tmp_data, size);
13421
13422 XFree (tmp_data);
13423 }
13424
13425 UNBLOCK_INPUT;
13426
13427 return prop_value;
13428
767b1ff0 13429#endif /* TODO */
6fc2811b
JR
13430 return Qnil;
13431}
13432
13433
13434\f
13435/***********************************************************************
13436 Busy cursor
13437 ***********************************************************************/
13438
f79e6790 13439/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 13440 an hourglass cursor on all frames. */
6fc2811b 13441
0af913d7 13442static struct atimer *hourglass_atimer;
6fc2811b 13443
0af913d7 13444/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 13445
0af913d7 13446static int hourglass_shown_p;
6fc2811b 13447
0af913d7 13448/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 13449
0af913d7 13450static Lisp_Object Vhourglass_delay;
6fc2811b 13451
0af913d7 13452/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
13453 cursor. */
13454
0af913d7 13455#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
13456
13457/* Function prototypes. */
13458
0af913d7
GM
13459static void show_hourglass P_ ((struct atimer *));
13460static void hide_hourglass P_ ((void));
f79e6790
JR
13461
13462
0af913d7 13463/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
13464
13465void
0af913d7 13466start_hourglass ()
f79e6790 13467{
767b1ff0 13468#if 0 /* TODO: cursor shape changes. */
f79e6790 13469 EMACS_TIME delay;
dfff8a69 13470 int secs, usecs = 0;
7d0393cf 13471
0af913d7 13472 cancel_hourglass ();
f79e6790 13473
0af913d7
GM
13474 if (INTEGERP (Vhourglass_delay)
13475 && XINT (Vhourglass_delay) > 0)
13476 secs = XFASTINT (Vhourglass_delay);
13477 else if (FLOATP (Vhourglass_delay)
13478 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
13479 {
13480 Lisp_Object tem;
0af913d7 13481 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 13482 secs = XFASTINT (tem);
0af913d7 13483 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 13484 }
f79e6790 13485 else
0af913d7 13486 secs = DEFAULT_HOURGLASS_DELAY;
7d0393cf 13487
dfff8a69 13488 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
13489 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13490 show_hourglass, NULL);
f79e6790
JR
13491#endif
13492}
13493
13494
0af913d7
GM
13495/* Cancel the hourglass cursor timer if active, hide an hourglass
13496 cursor if shown. */
f79e6790
JR
13497
13498void
0af913d7 13499cancel_hourglass ()
f79e6790 13500{
0af913d7 13501 if (hourglass_atimer)
dfff8a69 13502 {
0af913d7
GM
13503 cancel_atimer (hourglass_atimer);
13504 hourglass_atimer = NULL;
dfff8a69 13505 }
7d0393cf 13506
0af913d7
GM
13507 if (hourglass_shown_p)
13508 hide_hourglass ();
f79e6790
JR
13509}
13510
13511
0af913d7
GM
13512/* Timer function of hourglass_atimer. TIMER is equal to
13513 hourglass_atimer.
f79e6790 13514
0af913d7
GM
13515 Display an hourglass cursor on all frames by mapping the frames'
13516 hourglass_window. Set the hourglass_p flag in the frames'
13517 output_data.x structure to indicate that an hourglass cursor is
13518 shown on the frames. */
f79e6790
JR
13519
13520static void
0af913d7 13521show_hourglass (timer)
f79e6790 13522 struct atimer *timer;
6fc2811b 13523{
767b1ff0 13524#if 0 /* TODO: cursor shape changes. */
f79e6790 13525 /* The timer implementation will cancel this timer automatically
0af913d7 13526 after this function has run. Set hourglass_atimer to null
f79e6790 13527 so that we know the timer doesn't have to be canceled. */
0af913d7 13528 hourglass_atimer = NULL;
f79e6790 13529
0af913d7 13530 if (!hourglass_shown_p)
6fc2811b
JR
13531 {
13532 Lisp_Object rest, frame;
7d0393cf 13533
f79e6790 13534 BLOCK_INPUT;
7d0393cf 13535
6fc2811b 13536 FOR_EACH_FRAME (rest, frame)
dc220243 13537 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13538 {
13539 struct frame *f = XFRAME (frame);
7d0393cf 13540
0af913d7 13541 f->output_data.w32->hourglass_p = 1;
7d0393cf 13542
0af913d7 13543 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13544 {
13545 unsigned long mask = CWCursor;
13546 XSetWindowAttributes attrs;
7d0393cf 13547
0af913d7 13548 attrs.cursor = f->output_data.w32->hourglass_cursor;
7d0393cf 13549
0af913d7 13550 f->output_data.w32->hourglass_window
f79e6790 13551 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13552 FRAME_OUTER_WINDOW (f),
13553 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13554 InputOnly,
13555 CopyFromParent,
6fc2811b
JR
13556 mask, &attrs);
13557 }
7d0393cf 13558
0af913d7
GM
13559 XMapRaised (FRAME_X_DISPLAY (f),
13560 f->output_data.w32->hourglass_window);
f79e6790 13561 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13562 }
6fc2811b 13563
0af913d7 13564 hourglass_shown_p = 1;
f79e6790
JR
13565 UNBLOCK_INPUT;
13566 }
13567#endif
6fc2811b
JR
13568}
13569
13570
0af913d7 13571/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13572
f79e6790 13573static void
0af913d7 13574hide_hourglass ()
f79e6790 13575{
767b1ff0 13576#if 0 /* TODO: cursor shape changes. */
0af913d7 13577 if (hourglass_shown_p)
6fc2811b 13578 {
f79e6790
JR
13579 Lisp_Object rest, frame;
13580
13581 BLOCK_INPUT;
13582 FOR_EACH_FRAME (rest, frame)
6fc2811b 13583 {
f79e6790 13584 struct frame *f = XFRAME (frame);
7d0393cf 13585
dc220243 13586 if (FRAME_W32_P (f)
f79e6790 13587 /* Watch out for newly created frames. */
0af913d7 13588 && f->output_data.x->hourglass_window)
f79e6790 13589 {
0af913d7
GM
13590 XUnmapWindow (FRAME_X_DISPLAY (f),
13591 f->output_data.x->hourglass_window);
13592 /* Sync here because XTread_socket looks at the
13593 hourglass_p flag that is reset to zero below. */
f79e6790 13594 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13595 f->output_data.x->hourglass_p = 0;
f79e6790 13596 }
6fc2811b 13597 }
6fc2811b 13598
0af913d7 13599 hourglass_shown_p = 0;
f79e6790
JR
13600 UNBLOCK_INPUT;
13601 }
13602#endif
6fc2811b
JR
13603}
13604
13605
13606\f
13607/***********************************************************************
13608 Tool tips
13609 ***********************************************************************/
13610
13611static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13612 Lisp_Object, Lisp_Object));
13613static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13614 Lisp_Object, int, int, int *, int *));
7d0393cf 13615
3cf3436e 13616/* The frame of a currently visible tooltip. */
6fc2811b 13617
937e601e 13618Lisp_Object tip_frame;
6fc2811b
JR
13619
13620/* If non-nil, a timer started that hides the last tooltip when it
13621 fires. */
13622
13623Lisp_Object tip_timer;
13624Window tip_window;
13625
3cf3436e
JR
13626/* If non-nil, a vector of 3 elements containing the last args
13627 with which x-show-tip was called. See there. */
13628
13629Lisp_Object last_show_tip_args;
13630
13631/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13632
13633Lisp_Object Vx_max_tooltip_size;
13634
13635
937e601e
AI
13636static Lisp_Object
13637unwind_create_tip_frame (frame)
13638 Lisp_Object frame;
13639{
c844a81a
GM
13640 Lisp_Object deleted;
13641
13642 deleted = unwind_create_frame (frame);
13643 if (EQ (deleted, Qt))
13644 {
13645 tip_window = NULL;
13646 tip_frame = Qnil;
13647 }
7d0393cf 13648
c844a81a 13649 return deleted;
937e601e
AI
13650}
13651
13652
6fc2811b 13653/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13654 PARMS is a list of frame parameters. TEXT is the string to
13655 display in the tip frame. Value is the frame.
937e601e
AI
13656
13657 Note that functions called here, esp. x_default_parameter can
13658 signal errors, for instance when a specified color name is
13659 undefined. We have to make sure that we're in a consistent state
13660 when this happens. */
6fc2811b
JR
13661
13662static Lisp_Object
3cf3436e 13663x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13664 struct w32_display_info *dpyinfo;
3cf3436e 13665 Lisp_Object parms, text;
6fc2811b 13666{
6fc2811b
JR
13667 struct frame *f;
13668 Lisp_Object frame, tem;
13669 Lisp_Object name;
13670 long window_prompting = 0;
13671 int width, height;
331379bf 13672 int count = SPECPDL_INDEX ();
6fc2811b
JR
13673 struct gcpro gcpro1, gcpro2, gcpro3;
13674 struct kboard *kb;
3cf3436e
JR
13675 int face_change_count_before = face_change_count;
13676 Lisp_Object buffer;
13677 struct buffer *old_buffer;
6fc2811b 13678
ca56d953 13679 check_w32 ();
6fc2811b
JR
13680
13681 /* Use this general default value to start with until we know if
13682 this frame has a specified name. */
13683 Vx_resource_name = Vinvocation_name;
13684
13685#ifdef MULTI_KBOARD
13686 kb = dpyinfo->kboard;
13687#else
13688 kb = &the_only_kboard;
13689#endif
13690
13691 /* Get the name of the frame to use for resource lookup. */
13692 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13693 if (!STRINGP (name)
13694 && !EQ (name, Qunbound)
13695 && !NILP (name))
13696 error ("Invalid frame name--not a string or nil");
13697 Vx_resource_name = name;
13698
13699 frame = Qnil;
13700 GCPRO3 (parms, name, frame);
9eb16b62
JR
13701 /* Make a frame without minibuffer nor mode-line. */
13702 f = make_frame (0);
13703 f->wants_modeline = 0;
6fc2811b 13704 XSETFRAME (frame, f);
3cf3436e
JR
13705
13706 buffer = Fget_buffer_create (build_string (" *tip*"));
13707 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13708 old_buffer = current_buffer;
13709 set_buffer_internal_1 (XBUFFER (buffer));
13710 current_buffer->truncate_lines = Qnil;
13711 Ferase_buffer ();
13712 Finsert (1, &text);
13713 set_buffer_internal_1 (old_buffer);
7d0393cf 13714
6fc2811b 13715 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13716 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13717
3cf3436e
JR
13718 /* By setting the output method, we're essentially saying that
13719 the frame is live, as per FRAME_LIVE_P. If we get a signal
13720 from this point on, x_destroy_window might screw up reference
13721 counts etc. */
d88c567c 13722 f->output_method = output_w32;
6fc2811b
JR
13723 f->output_data.w32 =
13724 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13725 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13726
13727 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13728 f->icon_name = Qnil;
13729
ca56d953 13730#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13731 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13732 dpyinfo_refcount = dpyinfo->reference_count;
13733#endif /* GLYPH_DEBUG */
6fc2811b
JR
13734#ifdef MULTI_KBOARD
13735 FRAME_KBOARD (f) = kb;
13736#endif
13737 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13738 f->output_data.w32->explicit_parent = 0;
13739
13740 /* Set the name; the functions to which we pass f expect the name to
13741 be set. */
13742 if (EQ (name, Qunbound) || NILP (name))
13743 {
ca56d953 13744 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13745 f->explicit_name = 0;
13746 }
13747 else
13748 {
13749 f->name = name;
13750 f->explicit_name = 1;
13751 /* use the frame's title when getting resources for this frame. */
13752 specbind (Qx_resource_name, name);
13753 }
13754
6fc2811b
JR
13755 /* Extract the window parameters from the supplied values
13756 that are needed to determine window geometry. */
13757 {
13758 Lisp_Object font;
13759
13760 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13761
13762 BLOCK_INPUT;
13763 /* First, try whatever font the caller has specified. */
13764 if (STRINGP (font))
13765 {
13766 tem = Fquery_fontset (font, Qnil);
13767 if (STRINGP (tem))
d5db4077 13768 font = x_new_fontset (f, SDATA (tem));
6fc2811b 13769 else
d5db4077 13770 font = x_new_font (f, SDATA (font));
6fc2811b 13771 }
7d0393cf 13772
6fc2811b
JR
13773 /* Try out a font which we hope has bold and italic variations. */
13774 if (!STRINGP (font))
ca56d953 13775 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13776 if (! STRINGP (font))
ca56d953 13777 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13778 /* If those didn't work, look for something which will at least work. */
13779 if (! STRINGP (font))
ca56d953 13780 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13781 UNBLOCK_INPUT;
13782 if (! STRINGP (font))
ca56d953 13783 font = build_string ("Fixedsys");
6fc2811b
JR
13784
13785 x_default_parameter (f, parms, Qfont, font,
13786 "font", "Font", RES_TYPE_STRING);
13787 }
13788
13789 x_default_parameter (f, parms, Qborder_width, make_number (2),
13790 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13791 /* This defaults to 2 in order to match xterm. We recognize either
13792 internalBorderWidth or internalBorder (which is what xterm calls
13793 it). */
13794 if (NILP (Fassq (Qinternal_border_width, parms)))
13795 {
13796 Lisp_Object value;
13797
13798 value = w32_get_arg (parms, Qinternal_border_width,
13799 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13800 if (! EQ (value, Qunbound))
13801 parms = Fcons (Fcons (Qinternal_border_width, value),
13802 parms);
13803 }
bfd6edcc 13804 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13805 "internalBorderWidth", "internalBorderWidth",
13806 RES_TYPE_NUMBER);
13807
13808 /* Also do the stuff which must be set before the window exists. */
13809 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13810 "foreground", "Foreground", RES_TYPE_STRING);
13811 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13812 "background", "Background", RES_TYPE_STRING);
13813 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13814 "pointerColor", "Foreground", RES_TYPE_STRING);
13815 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13816 "cursorColor", "Foreground", RES_TYPE_STRING);
13817 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13818 "borderColor", "BorderColor", RES_TYPE_STRING);
13819
13820 /* Init faces before x_default_parameter is called for scroll-bar
13821 parameters because that function calls x_set_scroll_bar_width,
13822 which calls change_frame_size, which calls Fset_window_buffer,
13823 which runs hooks, which call Fvertical_motion. At the end, we
13824 end up in init_iterator with a null face cache, which should not
13825 happen. */
13826 init_frame_faces (f);
ca56d953
JR
13827
13828 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13829 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13830
6fc2811b
JR
13831 window_prompting = x_figure_window_size (f, parms);
13832
9eb16b62
JR
13833 /* No fringes on tip frame. */
13834 f->output_data.w32->fringes_extra = 0;
13835 f->output_data.w32->fringe_cols = 0;
13836 f->output_data.w32->left_fringe_width = 0;
13837 f->output_data.w32->right_fringe_width = 0;
13838
6fc2811b
JR
13839 if (window_prompting & XNegative)
13840 {
13841 if (window_prompting & YNegative)
13842 f->output_data.w32->win_gravity = SouthEastGravity;
13843 else
13844 f->output_data.w32->win_gravity = NorthEastGravity;
13845 }
13846 else
13847 {
13848 if (window_prompting & YNegative)
13849 f->output_data.w32->win_gravity = SouthWestGravity;
13850 else
13851 f->output_data.w32->win_gravity = NorthWestGravity;
13852 }
13853
13854 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13855
13856 BLOCK_INPUT;
13857 my_create_tip_window (f);
13858 UNBLOCK_INPUT;
6fc2811b
JR
13859
13860 x_make_gc (f);
13861
13862 x_default_parameter (f, parms, Qauto_raise, Qnil,
13863 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13864 x_default_parameter (f, parms, Qauto_lower, Qnil,
13865 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13866 x_default_parameter (f, parms, Qcursor_type, Qbox,
13867 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13868
13869 /* Dimensions, especially f->height, must be done via change_frame_size.
13870 Change will not be effected unless different from the current
13871 f->height. */
13872 width = f->width;
13873 height = f->height;
13874 f->height = 0;
13875 SET_FRAME_WIDTH (f, 0);
13876 change_frame_size (f, height, width, 1, 0, 0);
13877
cd1d850f
JPW
13878 /* Add `tooltip' frame parameter's default value. */
13879 if (NILP (Fframe_parameter (frame, intern ("tooltip"))))
13880 Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
13881 Qnil));
7d0393cf 13882
3cf3436e
JR
13883 /* Set up faces after all frame parameters are known. This call
13884 also merges in face attributes specified for new frames.
13885
13886 Frame parameters may be changed if .Xdefaults contains
13887 specifications for the default font. For example, if there is an
13888 `Emacs.default.attributeBackground: pink', the `background-color'
13889 attribute of the frame get's set, which let's the internal border
13890 of the tooltip frame appear in pink. Prevent this. */
13891 {
13892 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13893
13894 /* Set tip_frame here, so that */
13895 tip_frame = frame;
13896 call1 (Qface_set_after_frame_default, frame);
7d0393cf 13897
3cf3436e
JR
13898 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13899 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13900 Qnil));
13901 }
7d0393cf 13902
6fc2811b
JR
13903 f->no_split = 1;
13904
13905 UNGCPRO;
13906
13907 /* It is now ok to make the frame official even if we get an error
13908 below. And the frame needs to be on Vframe_list or making it
13909 visible won't work. */
13910 Vframe_list = Fcons (frame, Vframe_list);
13911
13912 /* Now that the frame is official, it counts as a reference to
13913 its display. */
13914 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13915
3cf3436e
JR
13916 /* Setting attributes of faces of the tooltip frame from resources
13917 and similar will increment face_change_count, which leads to the
13918 clearing of all current matrices. Since this isn't necessary
13919 here, avoid it by resetting face_change_count to the value it
13920 had before we created the tip frame. */
13921 face_change_count = face_change_count_before;
13922
13923 /* Discard the unwind_protect. */
6fc2811b 13924 return unbind_to (count, frame);
ee78dc32
GV
13925}
13926
3cf3436e
JR
13927
13928/* Compute where to display tip frame F. PARMS is the list of frame
13929 parameters for F. DX and DY are specified offsets from the current
13930 location of the mouse. WIDTH and HEIGHT are the width and height
13931 of the tooltip. Return coordinates relative to the root window of
13932 the display in *ROOT_X, and *ROOT_Y. */
13933
13934static void
13935compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13936 struct frame *f;
13937 Lisp_Object parms, dx, dy;
13938 int width, height;
13939 int *root_x, *root_y;
13940{
3cf3436e 13941 Lisp_Object left, top;
7d0393cf 13942
3cf3436e
JR
13943 /* User-specified position? */
13944 left = Fcdr (Fassq (Qleft, parms));
13945 top = Fcdr (Fassq (Qtop, parms));
7d0393cf 13946
3cf3436e
JR
13947 /* Move the tooltip window where the mouse pointer is. Resize and
13948 show it. */
ca56d953 13949 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13950 {
ca56d953
JR
13951 POINT pt;
13952
3cf3436e 13953 BLOCK_INPUT;
ca56d953
JR
13954 GetCursorPos (&pt);
13955 *root_x = pt.x;
13956 *root_y = pt.y;
3cf3436e
JR
13957 UNBLOCK_INPUT;
13958 }
13959
13960 if (INTEGERP (top))
13961 *root_y = XINT (top);
13962 else if (*root_y + XINT (dy) - height < 0)
13963 *root_y -= XINT (dy);
13964 else
13965 {
13966 *root_y -= height;
13967 *root_y += XINT (dy);
13968 }
13969
13970 if (INTEGERP (left))
13971 *root_x = XINT (left);
72e4adef
JR
13972 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13973 /* It fits to the right of the pointer. */
13974 *root_x += XINT (dx);
13975 else if (width + XINT (dx) <= *root_x)
13976 /* It fits to the left of the pointer. */
3cf3436e
JR
13977 *root_x -= width + XINT (dx);
13978 else
72e4adef
JR
13979 /* Put it left justified on the screen -- it ought to fit that way. */
13980 *root_x = 0;
3cf3436e
JR
13981}
13982
13983
71eab8d1 13984DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13985 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13986A tooltip window is a small window displaying a string.
13987
13988FRAME nil or omitted means use the selected frame.
13989
13990PARMS is an optional list of frame parameters which can be
13991used to change the tooltip's appearance.
13992
ca56d953
JR
13993Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13994means use the default timeout of 5 seconds.
74e1aeec 13995
ca56d953 13996If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13997the tooltip is displayed at that x-position. Otherwise it is
13998displayed at the mouse position, with offset DX added (default is 5 if
13999DX isn't specified). Likewise for the y-position; if a `top' frame
14000parameter is specified, it determines the y-position of the tooltip
14001window, otherwise it is displayed at the mouse position, with offset
14002DY added (default is -10).
14003
14004A tooltip's maximum size is specified by `x-max-tooltip-size'.
14005Text larger than the specified size is clipped. */)
71eab8d1
AI
14006 (string, frame, parms, timeout, dx, dy)
14007 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 14008{
6fc2811b
JR
14009 struct frame *f;
14010 struct window *w;
3cf3436e 14011 int root_x, root_y;
6fc2811b
JR
14012 struct buffer *old_buffer;
14013 struct text_pos pos;
14014 int i, width, height;
6fc2811b
JR
14015 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
14016 int old_windows_or_buffers_changed = windows_or_buffers_changed;
331379bf 14017 int count = SPECPDL_INDEX ();
7d0393cf 14018
6fc2811b 14019 specbind (Qinhibit_redisplay, Qt);
ee78dc32 14020
dfff8a69 14021 GCPRO4 (string, parms, frame, timeout);
ee78dc32 14022
b7826503 14023 CHECK_STRING (string);
6fc2811b
JR
14024 f = check_x_frame (frame);
14025 if (NILP (timeout))
14026 timeout = make_number (5);
14027 else
b7826503 14028 CHECK_NATNUM (timeout);
ee78dc32 14029
71eab8d1
AI
14030 if (NILP (dx))
14031 dx = make_number (5);
14032 else
b7826503 14033 CHECK_NUMBER (dx);
7d0393cf 14034
71eab8d1 14035 if (NILP (dy))
dc220243 14036 dy = make_number (-10);
71eab8d1 14037 else
b7826503 14038 CHECK_NUMBER (dy);
71eab8d1 14039
dc220243
JR
14040 if (NILP (last_show_tip_args))
14041 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
14042
14043 if (!NILP (tip_frame))
14044 {
14045 Lisp_Object last_string = AREF (last_show_tip_args, 0);
14046 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
14047 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
14048
14049 if (EQ (frame, last_frame)
14050 && !NILP (Fequal (last_string, string))
14051 && !NILP (Fequal (last_parms, parms)))
14052 {
14053 struct frame *f = XFRAME (tip_frame);
7d0393cf 14054
dc220243
JR
14055 /* Only DX and DY have changed. */
14056 if (!NILP (tip_timer))
14057 {
14058 Lisp_Object timer = tip_timer;
14059 tip_timer = Qnil;
14060 call1 (Qcancel_timer, timer);
14061 }
14062
14063 BLOCK_INPUT;
ca56d953
JR
14064 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
14065 PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
14066
14067 /* Put tooltip in topmost group and in position. */
ca56d953
JR
14068 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14069 root_x, root_y, 0, 0,
14070 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
14071
14072 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14073 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14074 0, 0, 0, 0,
14075 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14076
dc220243
JR
14077 UNBLOCK_INPUT;
14078 goto start_timer;
14079 }
14080 }
14081
6fc2811b
JR
14082 /* Hide a previous tip, if any. */
14083 Fx_hide_tip ();
ee78dc32 14084
dc220243
JR
14085 ASET (last_show_tip_args, 0, string);
14086 ASET (last_show_tip_args, 1, frame);
14087 ASET (last_show_tip_args, 2, parms);
14088
6fc2811b
JR
14089 /* Add default values to frame parameters. */
14090 if (NILP (Fassq (Qname, parms)))
14091 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14092 if (NILP (Fassq (Qinternal_border_width, parms)))
14093 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14094 if (NILP (Fassq (Qborder_width, parms)))
14095 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14096 if (NILP (Fassq (Qborder_color, parms)))
14097 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14098 if (NILP (Fassq (Qbackground_color, parms)))
14099 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14100 parms);
14101
0e3fcdef
JR
14102 /* Block input until the tip has been fully drawn, to avoid crashes
14103 when drawing tips in menus. */
14104 BLOCK_INPUT;
14105
6fc2811b
JR
14106 /* Create a frame for the tooltip, and record it in the global
14107 variable tip_frame. */
ca56d953 14108 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 14109 f = XFRAME (frame);
6fc2811b 14110
3cf3436e 14111 /* Set up the frame's root window. */
6fc2811b
JR
14112 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14113 w->left = w->top = make_number (0);
3cf3436e
JR
14114
14115 if (CONSP (Vx_max_tooltip_size)
14116 && INTEGERP (XCAR (Vx_max_tooltip_size))
14117 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14118 && INTEGERP (XCDR (Vx_max_tooltip_size))
14119 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14120 {
14121 w->width = XCAR (Vx_max_tooltip_size);
14122 w->height = XCDR (Vx_max_tooltip_size);
14123 }
14124 else
14125 {
14126 w->width = make_number (80);
14127 w->height = make_number (40);
14128 }
7d0393cf 14129
3cf3436e 14130 f->window_width = XINT (w->width);
6fc2811b
JR
14131 adjust_glyphs (f);
14132 w->pseudo_window_p = 1;
14133
14134 /* Display the tooltip text in a temporary buffer. */
6fc2811b 14135 old_buffer = current_buffer;
3cf3436e
JR
14136 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14137 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
14138 clear_glyph_matrix (w->desired_matrix);
14139 clear_glyph_matrix (w->current_matrix);
14140 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14141 try_window (FRAME_ROOT_WINDOW (f), pos);
14142
14143 /* Compute width and height of the tooltip. */
14144 width = height = 0;
14145 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 14146 {
6fc2811b
JR
14147 struct glyph_row *row = &w->desired_matrix->rows[i];
14148 struct glyph *last;
14149 int row_width;
14150
14151 /* Stop at the first empty row at the end. */
14152 if (!row->enabled_p || !row->displays_text_p)
14153 break;
14154
14155 /* Let the row go over the full width of the frame. */
14156 row->full_width_p = 1;
14157
4e3a1c61
JR
14158#ifdef TODO /* Investigate why some fonts need more width than is
14159 calculated for some tooltips. */
6fc2811b
JR
14160 /* There's a glyph at the end of rows that is use to place
14161 the cursor there. Don't include the width of this glyph. */
14162 if (row->used[TEXT_AREA])
14163 {
14164 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14165 row_width = row->pixel_width - last->pixel_width;
14166 }
14167 else
4e3a1c61 14168#endif
6fc2811b 14169 row_width = row->pixel_width;
7d0393cf 14170
ca56d953 14171 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 14172 height += row->height;
6fc2811b 14173 width = max (width, row_width);
ee78dc32
GV
14174 }
14175
6fc2811b
JR
14176 /* Add the frame's internal border to the width and height the X
14177 window should have. */
14178 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14179 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 14180
6fc2811b
JR
14181 /* Move the tooltip window where the mouse pointer is. Resize and
14182 show it. */
3cf3436e 14183 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 14184
bfd6edcc
JR
14185 {
14186 /* Adjust Window size to take border into account. */
14187 RECT rect;
14188 rect.left = rect.top = 0;
14189 rect.right = width;
14190 rect.bottom = height;
14191 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14192 FRAME_EXTERNAL_MENU_BAR (f));
14193
d65a9cdc 14194 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
14195 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14196 root_x, root_y, rect.right - rect.left,
14197 rect.bottom - rect.top, SWP_NOACTIVATE);
14198
d65a9cdc
JR
14199 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14200 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14201 0, 0, 0, 0,
14202 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14203
bfd6edcc
JR
14204 /* Let redisplay know that we have made the frame visible already. */
14205 f->async_visible = 1;
14206
14207 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14208 }
ee78dc32 14209
6fc2811b
JR
14210 /* Draw into the window. */
14211 w->must_be_updated_p = 1;
14212 update_single_window (w, 1);
ee78dc32 14213
0e3fcdef
JR
14214 UNBLOCK_INPUT;
14215
6fc2811b
JR
14216 /* Restore original current buffer. */
14217 set_buffer_internal_1 (old_buffer);
14218 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 14219
dc220243 14220 start_timer:
6fc2811b
JR
14221 /* Let the tip disappear after timeout seconds. */
14222 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14223 intern ("x-hide-tip"));
ee78dc32 14224
dfff8a69 14225 UNGCPRO;
6fc2811b 14226 return unbind_to (count, Qnil);
ee78dc32
GV
14227}
14228
ee78dc32 14229
6fc2811b 14230DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
14231 doc: /* Hide the current tooltip window, if there is any.
14232Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
14233 ()
14234{
937e601e
AI
14235 int count;
14236 Lisp_Object deleted, frame, timer;
14237 struct gcpro gcpro1, gcpro2;
14238
14239 /* Return quickly if nothing to do. */
14240 if (NILP (tip_timer) && NILP (tip_frame))
14241 return Qnil;
7d0393cf 14242
937e601e
AI
14243 frame = tip_frame;
14244 timer = tip_timer;
14245 GCPRO2 (frame, timer);
14246 tip_frame = tip_timer = deleted = Qnil;
7d0393cf 14247
331379bf 14248 count = SPECPDL_INDEX ();
6fc2811b 14249 specbind (Qinhibit_redisplay, Qt);
937e601e 14250 specbind (Qinhibit_quit, Qt);
7d0393cf 14251
937e601e 14252 if (!NILP (timer))
dc220243 14253 call1 (Qcancel_timer, timer);
ee78dc32 14254
937e601e 14255 if (FRAMEP (frame))
6fc2811b 14256 {
937e601e
AI
14257 Fdelete_frame (frame, Qnil);
14258 deleted = Qt;
6fc2811b 14259 }
1edf84e7 14260
937e601e
AI
14261 UNGCPRO;
14262 return unbind_to (count, deleted);
6fc2811b 14263}
5ac45f98 14264
5ac45f98 14265
6fc2811b
JR
14266\f
14267/***********************************************************************
14268 File selection dialog
14269 ***********************************************************************/
6fc2811b
JR
14270extern Lisp_Object Qfile_name_history;
14271
1030b26b
JR
14272/* Callback for altering the behaviour of the Open File dialog.
14273 Makes the Filename text field contain "Current Directory" and be
14274 read-only when "Directories" is selected in the filter. This
14275 allows us to work around the fact that the standard Open File
14276 dialog does not support directories. */
14277UINT CALLBACK
14278file_dialog_callback (hwnd, msg, wParam, lParam)
14279 HWND hwnd;
14280 UINT msg;
14281 WPARAM wParam;
14282 LPARAM lParam;
14283{
14284 if (msg == WM_NOTIFY)
14285 {
14286 OFNOTIFY * notify = (OFNOTIFY *)lParam;
14287 /* Detect when the Filter dropdown is changed. */
14288 if (notify->hdr.code == CDN_TYPECHANGE)
14289 {
14290 HWND dialog = GetParent (hwnd);
14291 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
14292
14293 /* Directories is in index 2. */
14294 if (notify->lpOFN->nFilterIndex == 2)
14295 {
14296 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14297 "Current Directory");
14298 EnableWindow (edit_control, FALSE);
14299 }
14300 else
14301 {
14302 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14303 "");
14304 EnableWindow (edit_control, TRUE);
14305 }
14306 }
14307 }
14308 return 0;
14309}
14310
6fc2811b 14311DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
14312 doc: /* Read file name, prompting with PROMPT in directory DIR.
14313Use a file selection dialog.
14314Select DEFAULT-FILENAME in the dialog's file selection box, if
14315specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
14316 (prompt, dir, default_filename, mustmatch)
14317 Lisp_Object prompt, dir, default_filename, mustmatch;
14318{
14319 struct frame *f = SELECTED_FRAME ();
14320 Lisp_Object file = Qnil;
aed13378 14321 int count = SPECPDL_INDEX ();
6fc2811b
JR
14322 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14323 char filename[MAX_PATH + 1];
14324 char init_dir[MAX_PATH + 1];
6fc2811b
JR
14325
14326 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
14327 CHECK_STRING (prompt);
14328 CHECK_STRING (dir);
6fc2811b
JR
14329
14330 /* Create the dialog with PROMPT as title, using DIR as initial
14331 directory and using "*" as pattern. */
14332 dir = Fexpand_file_name (dir, Qnil);
d5db4077 14333 strncpy (init_dir, SDATA (dir), MAX_PATH);
6fc2811b
JR
14334 init_dir[MAX_PATH] = '\0';
14335 unixtodos_filename (init_dir);
14336
14337 if (STRINGP (default_filename))
14338 {
14339 char *file_name_only;
d5db4077 14340 char *full_path_name = SDATA (default_filename);
5ac45f98 14341
6fc2811b 14342 unixtodos_filename (full_path_name);
5ac45f98 14343
6fc2811b
JR
14344 file_name_only = strrchr (full_path_name, '\\');
14345 if (!file_name_only)
14346 file_name_only = full_path_name;
14347 else
14348 {
14349 file_name_only++;
6fc2811b 14350 }
ee78dc32 14351
6fc2811b
JR
14352 strncpy (filename, file_name_only, MAX_PATH);
14353 filename[MAX_PATH] = '\0';
14354 }
ee78dc32 14355 else
6fc2811b 14356 filename[0] = '\0';
ee78dc32 14357
1030b26b
JR
14358 {
14359 OPENFILENAME file_details;
5ac45f98 14360
1030b26b
JR
14361 /* Prevent redisplay. */
14362 specbind (Qinhibit_redisplay, Qt);
14363 BLOCK_INPUT;
ee78dc32 14364
1030b26b
JR
14365 bzero (&file_details, sizeof (file_details));
14366 file_details.lStructSize = sizeof (file_details);
14367 file_details.hwndOwner = FRAME_W32_WINDOW (f);
14368 /* Undocumented Bug in Common File Dialog:
14369 If a filter is not specified, shell links are not resolved. */
14370 file_details.lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
14371 file_details.lpstrFile = filename;
14372 file_details.nMaxFile = sizeof (filename);
14373 file_details.lpstrInitialDir = init_dir;
d5db4077 14374 file_details.lpstrTitle = SDATA (prompt);
1030b26b
JR
14375 file_details.Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
14376 | OFN_EXPLORER | OFN_ENABLEHOOK);
14377 if (!NILP (mustmatch))
14378 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
14379
14380 file_details.lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
14381
14382 if (GetOpenFileName (&file_details))
14383 {
14384 dostounix_filename (filename);
14385 if (file_details.nFilterIndex == 2)
14386 {
14387 /* "Folder Only" selected - strip dummy file name. */
14388 char * last = strrchr (filename, '/');
14389 *last = '\0';
14390 }
6fc2811b 14391
1030b26b
JR
14392 file = DECODE_FILE(build_string (filename));
14393 }
14394 /* User cancelled the dialog without making a selection. */
14395 else if (!CommDlgExtendedError ())
14396 file = Qnil;
14397 /* An error occurred, fallback on reading from the mini-buffer. */
14398 else
14399 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14400 dir, mustmatch, dir, Qfile_name_history,
14401 default_filename, Qnil);
14402
14403 UNBLOCK_INPUT;
14404 file = unbind_to (count, file);
14405 }
ee78dc32 14406
6fc2811b 14407 UNGCPRO;
1edf84e7 14408
6fc2811b
JR
14409 /* Make "Cancel" equivalent to C-g. */
14410 if (NILP (file))
14411 Fsignal (Qquit, Qnil);
ee78dc32 14412
dfff8a69 14413 return unbind_to (count, file);
6fc2811b 14414}
ee78dc32 14415
ee78dc32 14416
6fc2811b 14417\f
6fc2811b
JR
14418/***********************************************************************
14419 w32 specialized functions
14420 ***********************************************************************/
ee78dc32 14421
d84b082d 14422DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
14423 doc: /* Select a font using the W32 font dialog.
14424Returns an X font string corresponding to the selection. */)
d84b082d
JR
14425 (frame, include_proportional)
14426 Lisp_Object frame, include_proportional;
ee78dc32
GV
14427{
14428 FRAME_PTR f = check_x_frame (frame);
14429 CHOOSEFONT cf;
14430 LOGFONT lf;
f46e6225
GV
14431 TEXTMETRIC tm;
14432 HDC hdc;
14433 HANDLE oldobj;
ee78dc32
GV
14434 char buf[100];
14435
14436 bzero (&cf, sizeof (cf));
f46e6225 14437 bzero (&lf, sizeof (lf));
ee78dc32
GV
14438
14439 cf.lStructSize = sizeof (cf);
fbd6baed 14440 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
14441 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14442
14443 /* Unless include_proportional is non-nil, limit the selection to
14444 monospaced fonts. */
14445 if (NILP (include_proportional))
14446 cf.Flags |= CF_FIXEDPITCHONLY;
14447
ee78dc32
GV
14448 cf.lpLogFont = &lf;
14449
f46e6225
GV
14450 /* Initialize as much of the font details as we can from the current
14451 default font. */
14452 hdc = GetDC (FRAME_W32_WINDOW (f));
14453 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14454 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14455 if (GetTextMetrics (hdc, &tm))
14456 {
14457 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14458 lf.lfWeight = tm.tmWeight;
14459 lf.lfItalic = tm.tmItalic;
14460 lf.lfUnderline = tm.tmUnderlined;
14461 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
14462 lf.lfCharSet = tm.tmCharSet;
14463 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14464 }
14465 SelectObject (hdc, oldobj);
6fc2811b 14466 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 14467
767b1ff0 14468 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 14469 return Qnil;
ee78dc32
GV
14470
14471 return build_string (buf);
14472}
14473
74e1aeec
JR
14474DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14475 Sw32_send_sys_command, 1, 2, 0,
14476 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
14477Some useful values for command are #xf030 to maximise frame (#xf020
14478to minimize), #xf120 to restore frame to original size, and #xf100
14479to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
14480screen saver if defined.
14481
14482If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
14483 (command, frame)
14484 Lisp_Object command, frame;
14485{
1edf84e7
GV
14486 FRAME_PTR f = check_x_frame (frame);
14487
b7826503 14488 CHECK_NUMBER (command);
1edf84e7 14489
ce6059da 14490 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
14491
14492 return Qnil;
14493}
14494
55dcfc15 14495DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
14496 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14497This is a wrapper around the ShellExecute system function, which
14498invokes the application registered to handle OPERATION for DOCUMENT.
14499OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14500nil for the default action), and DOCUMENT is typically the name of a
14501document file or URL, but can also be a program executable to run or
14502a directory to open in the Windows Explorer.
14503
14504If DOCUMENT is a program executable, PARAMETERS can be a string
14505containing command line parameters, but otherwise should be nil.
14506
14507SHOW-FLAG can be used to control whether the invoked application is hidden
14508or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14509otherwise it is an integer representing a ShowWindow flag:
14510
14511 0 - start hidden
14512 1 - start normally
14513 3 - start maximized
14514 6 - start minimized */)
55dcfc15
AI
14515 (operation, document, parameters, show_flag)
14516 Lisp_Object operation, document, parameters, show_flag;
14517{
14518 Lisp_Object current_dir;
14519
b7826503 14520 CHECK_STRING (document);
55dcfc15
AI
14521
14522 /* Encode filename and current directory. */
14523 current_dir = ENCODE_FILE (current_buffer->directory);
14524 document = ENCODE_FILE (document);
14525 if ((int) ShellExecute (NULL,
6fc2811b 14526 (STRINGP (operation) ?
d5db4077
KR
14527 SDATA (operation) : NULL),
14528 SDATA (document),
55dcfc15 14529 (STRINGP (parameters) ?
d5db4077
KR
14530 SDATA (parameters) : NULL),
14531 SDATA (current_dir),
55dcfc15
AI
14532 (INTEGERP (show_flag) ?
14533 XINT (show_flag) : SW_SHOWDEFAULT))
14534 > 32)
14535 return Qt;
90d97e64 14536 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
14537}
14538
ccc2d29c
GV
14539/* Lookup virtual keycode from string representing the name of a
14540 non-ascii keystroke into the corresponding virtual key, using
14541 lispy_function_keys. */
14542static int
14543lookup_vk_code (char *key)
14544{
14545 int i;
14546
14547 for (i = 0; i < 256; i++)
14548 if (lispy_function_keys[i] != 0
14549 && strcmp (lispy_function_keys[i], key) == 0)
14550 return i;
14551
14552 return -1;
14553}
14554
14555/* Convert a one-element vector style key sequence to a hot key
14556 definition. */
14557static int
14558w32_parse_hot_key (key)
14559 Lisp_Object key;
14560{
14561 /* Copied from Fdefine_key and store_in_keymap. */
14562 register Lisp_Object c;
14563 int vk_code;
14564 int lisp_modifiers;
14565 int w32_modifiers;
14566 struct gcpro gcpro1;
14567
b7826503 14568 CHECK_VECTOR (key);
ccc2d29c
GV
14569
14570 if (XFASTINT (Flength (key)) != 1)
14571 return Qnil;
14572
14573 GCPRO1 (key);
14574
14575 c = Faref (key, make_number (0));
14576
14577 if (CONSP (c) && lucid_event_type_list_p (c))
14578 c = Fevent_convert_list (c);
14579
14580 UNGCPRO;
14581
14582 if (! INTEGERP (c) && ! SYMBOLP (c))
14583 error ("Key definition is invalid");
14584
14585 /* Work out the base key and the modifiers. */
14586 if (SYMBOLP (c))
14587 {
14588 c = parse_modifiers (c);
14589 lisp_modifiers = Fcar (Fcdr (c));
14590 c = Fcar (c);
14591 if (!SYMBOLP (c))
14592 abort ();
d5db4077 14593 vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c)));
ccc2d29c
GV
14594 }
14595 else if (INTEGERP (c))
14596 {
14597 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14598 /* Many ascii characters are their own virtual key code. */
14599 vk_code = XINT (c) & CHARACTERBITS;
14600 }
14601
14602 if (vk_code < 0 || vk_code > 255)
14603 return Qnil;
14604
14605 if ((lisp_modifiers & meta_modifier) != 0
14606 && !NILP (Vw32_alt_is_meta))
14607 lisp_modifiers |= alt_modifier;
14608
71eab8d1
AI
14609 /* Supply defs missing from mingw32. */
14610#ifndef MOD_ALT
14611#define MOD_ALT 0x0001
14612#define MOD_CONTROL 0x0002
14613#define MOD_SHIFT 0x0004
14614#define MOD_WIN 0x0008
14615#endif
14616
ccc2d29c
GV
14617 /* Convert lisp modifiers to Windows hot-key form. */
14618 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14619 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14620 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14621 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14622
14623 return HOTKEY (vk_code, w32_modifiers);
14624}
14625
74e1aeec
JR
14626DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14627 Sw32_register_hot_key, 1, 1, 0,
14628 doc: /* Register KEY as a hot-key combination.
14629Certain key combinations like Alt-Tab are reserved for system use on
14630Windows, and therefore are normally intercepted by the system. However,
14631most of these key combinations can be received by registering them as
14632hot-keys, overriding their special meaning.
14633
14634KEY must be a one element key definition in vector form that would be
14635acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14636modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14637is always interpreted as the Windows modifier keys.
14638
14639The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14640 (key)
14641 Lisp_Object key;
14642{
14643 key = w32_parse_hot_key (key);
14644
14645 if (NILP (Fmemq (key, w32_grabbed_keys)))
14646 {
14647 /* Reuse an empty slot if possible. */
14648 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14649
14650 /* Safe to add new key to list, even if we have focus. */
14651 if (NILP (item))
14652 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14653 else
f3fbd155 14654 XSETCAR (item, key);
ccc2d29c
GV
14655
14656 /* Notify input thread about new hot-key definition, so that it
14657 takes effect without needing to switch focus. */
14658 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14659 (WPARAM) key, 0);
14660 }
14661
14662 return key;
14663}
14664
74e1aeec
JR
14665DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14666 Sw32_unregister_hot_key, 1, 1, 0,
14667 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14668 (key)
14669 Lisp_Object key;
14670{
14671 Lisp_Object item;
14672
14673 if (!INTEGERP (key))
14674 key = w32_parse_hot_key (key);
14675
14676 item = Fmemq (key, w32_grabbed_keys);
14677
14678 if (!NILP (item))
14679 {
14680 /* Notify input thread about hot-key definition being removed, so
14681 that it takes effect without needing focus switch. */
14682 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14683 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14684 {
14685 MSG msg;
14686 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14687 }
14688 return Qt;
14689 }
14690 return Qnil;
14691}
14692
74e1aeec
JR
14693DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14694 Sw32_registered_hot_keys, 0, 0, 0,
14695 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14696 ()
14697{
14698 return Fcopy_sequence (w32_grabbed_keys);
14699}
14700
74e1aeec
JR
14701DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14702 Sw32_reconstruct_hot_key, 1, 1, 0,
14703 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14704 (hotkeyid)
14705 Lisp_Object hotkeyid;
14706{
14707 int vk_code, w32_modifiers;
14708 Lisp_Object key;
14709
b7826503 14710 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14711
14712 vk_code = HOTKEY_VK_CODE (hotkeyid);
14713 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14714
14715 if (lispy_function_keys[vk_code])
14716 key = intern (lispy_function_keys[vk_code]);
14717 else
14718 key = make_number (vk_code);
14719
14720 key = Fcons (key, Qnil);
14721 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14722 key = Fcons (Qshift, key);
ccc2d29c 14723 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14724 key = Fcons (Qctrl, key);
ccc2d29c 14725 if (w32_modifiers & MOD_ALT)
3ef68e6b 14726 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14727 if (w32_modifiers & MOD_WIN)
3ef68e6b 14728 key = Fcons (Qhyper, key);
ccc2d29c
GV
14729
14730 return key;
14731}
adcc3809 14732
74e1aeec
JR
14733DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14734 Sw32_toggle_lock_key, 1, 2, 0,
14735 doc: /* Toggle the state of the lock key KEY.
14736KEY can be `capslock', `kp-numlock', or `scroll'.
14737If the optional parameter NEW-STATE is a number, then the state of KEY
14738is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14739 (key, new_state)
14740 Lisp_Object key, new_state;
14741{
14742 int vk_code;
adcc3809
GV
14743
14744 if (EQ (key, intern ("capslock")))
14745 vk_code = VK_CAPITAL;
14746 else if (EQ (key, intern ("kp-numlock")))
14747 vk_code = VK_NUMLOCK;
14748 else if (EQ (key, intern ("scroll")))
14749 vk_code = VK_SCROLL;
14750 else
14751 return Qnil;
14752
14753 if (!dwWindowsThreadId)
14754 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14755
14756 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14757 (WPARAM) vk_code, (LPARAM) new_state))
14758 {
14759 MSG msg;
14760 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14761 return make_number (msg.wParam);
14762 }
14763 return Qnil;
14764}
ee78dc32 14765\f
2254bcde 14766DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14767 doc: /* Return storage information about the file system FILENAME is on.
14768Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14769storage of the file system, FREE is the free storage, and AVAIL is the
14770storage available to a non-superuser. All 3 numbers are in bytes.
14771If the underlying system call fails, value is nil. */)
2254bcde
AI
14772 (filename)
14773 Lisp_Object filename;
14774{
14775 Lisp_Object encoded, value;
14776
b7826503 14777 CHECK_STRING (filename);
2254bcde
AI
14778 filename = Fexpand_file_name (filename, Qnil);
14779 encoded = ENCODE_FILE (filename);
14780
14781 value = Qnil;
14782
14783 /* Determining the required information on Windows turns out, sadly,
14784 to be more involved than one would hope. The original Win32 api
14785 call for this will return bogus information on some systems, but we
14786 must dynamically probe for the replacement api, since that was
14787 added rather late on. */
14788 {
14789 HMODULE hKernel = GetModuleHandle ("kernel32");
14790 BOOL (*pfn_GetDiskFreeSpaceEx)
14791 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14792 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14793
14794 /* On Windows, we may need to specify the root directory of the
14795 volume holding FILENAME. */
14796 char rootname[MAX_PATH];
d5db4077 14797 char *name = SDATA (encoded);
2254bcde
AI
14798
14799 /* find the root name of the volume if given */
14800 if (isalpha (name[0]) && name[1] == ':')
14801 {
14802 rootname[0] = name[0];
14803 rootname[1] = name[1];
14804 rootname[2] = '\\';
14805 rootname[3] = 0;
14806 }
14807 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14808 {
14809 char *str = rootname;
14810 int slashes = 4;
14811 do
14812 {
14813 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14814 break;
14815 *str++ = *name++;
14816 }
14817 while ( *name );
14818
14819 *str++ = '\\';
14820 *str = 0;
14821 }
14822
14823 if (pfn_GetDiskFreeSpaceEx)
14824 {
ac849ba4
JR
14825 /* Unsigned large integers cannot be cast to double, so
14826 use signed ones instead. */
2254bcde
AI
14827 LARGE_INTEGER availbytes;
14828 LARGE_INTEGER freebytes;
14829 LARGE_INTEGER totalbytes;
14830
14831 if (pfn_GetDiskFreeSpaceEx(rootname,
ac849ba4
JR
14832 (ULARGE_INTEGER *)&availbytes,
14833 (ULARGE_INTEGER *)&totalbytes,
14834 (ULARGE_INTEGER *)&freebytes))
2254bcde
AI
14835 value = list3 (make_float ((double) totalbytes.QuadPart),
14836 make_float ((double) freebytes.QuadPart),
14837 make_float ((double) availbytes.QuadPart));
14838 }
14839 else
14840 {
14841 DWORD sectors_per_cluster;
14842 DWORD bytes_per_sector;
14843 DWORD free_clusters;
14844 DWORD total_clusters;
14845
14846 if (GetDiskFreeSpace(rootname,
14847 &sectors_per_cluster,
14848 &bytes_per_sector,
14849 &free_clusters,
14850 &total_clusters))
14851 value = list3 (make_float ((double) total_clusters
14852 * sectors_per_cluster * bytes_per_sector),
14853 make_float ((double) free_clusters
14854 * sectors_per_cluster * bytes_per_sector),
14855 make_float ((double) free_clusters
14856 * sectors_per_cluster * bytes_per_sector));
14857 }
14858 }
14859
14860 return value;
14861}
14862\f
0e3fcdef
JR
14863/***********************************************************************
14864 Initialization
14865 ***********************************************************************/
14866
14867void
fbd6baed 14868syms_of_w32fns ()
ee78dc32 14869{
9eb16b62
JR
14870 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14871
1edf84e7
GV
14872 /* This is zero if not using MS-Windows. */
14873 w32_in_use = 0;
14874
9eb16b62
JR
14875 /* TrackMouseEvent not available in all versions of Windows, so must load
14876 it dynamically. Do it once, here, instead of every time it is used. */
f60ae425 14877 track_mouse_event_fn = (TrackMouseEvent_Proc) GetProcAddress (user32_lib, "TrackMouseEvent");
9eb16b62
JR
14878 track_mouse_window = NULL;
14879
d285988b
JR
14880 w32_visible_system_caret_hwnd = NULL;
14881
ee78dc32
GV
14882 Qauto_raise = intern ("auto-raise");
14883 staticpro (&Qauto_raise);
14884 Qauto_lower = intern ("auto-lower");
14885 staticpro (&Qauto_lower);
ee78dc32
GV
14886 Qborder_color = intern ("border-color");
14887 staticpro (&Qborder_color);
14888 Qborder_width = intern ("border-width");
14889 staticpro (&Qborder_width);
ee78dc32
GV
14890 Qcursor_color = intern ("cursor-color");
14891 staticpro (&Qcursor_color);
14892 Qcursor_type = intern ("cursor-type");
14893 staticpro (&Qcursor_type);
ee78dc32
GV
14894 Qgeometry = intern ("geometry");
14895 staticpro (&Qgeometry);
14896 Qicon_left = intern ("icon-left");
14897 staticpro (&Qicon_left);
14898 Qicon_top = intern ("icon-top");
14899 staticpro (&Qicon_top);
14900 Qicon_type = intern ("icon-type");
14901 staticpro (&Qicon_type);
14902 Qicon_name = intern ("icon-name");
14903 staticpro (&Qicon_name);
14904 Qinternal_border_width = intern ("internal-border-width");
14905 staticpro (&Qinternal_border_width);
14906 Qleft = intern ("left");
14907 staticpro (&Qleft);
1026b400
RS
14908 Qright = intern ("right");
14909 staticpro (&Qright);
ee78dc32
GV
14910 Qmouse_color = intern ("mouse-color");
14911 staticpro (&Qmouse_color);
14912 Qnone = intern ("none");
14913 staticpro (&Qnone);
14914 Qparent_id = intern ("parent-id");
14915 staticpro (&Qparent_id);
14916 Qscroll_bar_width = intern ("scroll-bar-width");
14917 staticpro (&Qscroll_bar_width);
14918 Qsuppress_icon = intern ("suppress-icon");
14919 staticpro (&Qsuppress_icon);
ee78dc32
GV
14920 Qundefined_color = intern ("undefined-color");
14921 staticpro (&Qundefined_color);
14922 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14923 staticpro (&Qvertical_scroll_bars);
14924 Qvisibility = intern ("visibility");
14925 staticpro (&Qvisibility);
14926 Qwindow_id = intern ("window-id");
14927 staticpro (&Qwindow_id);
14928 Qx_frame_parameter = intern ("x-frame-parameter");
14929 staticpro (&Qx_frame_parameter);
14930 Qx_resource_name = intern ("x-resource-name");
14931 staticpro (&Qx_resource_name);
14932 Quser_position = intern ("user-position");
14933 staticpro (&Quser_position);
14934 Quser_size = intern ("user-size");
14935 staticpro (&Quser_size);
6fc2811b
JR
14936 Qscreen_gamma = intern ("screen-gamma");
14937 staticpro (&Qscreen_gamma);
dfff8a69
JR
14938 Qline_spacing = intern ("line-spacing");
14939 staticpro (&Qline_spacing);
14940 Qcenter = intern ("center");
14941 staticpro (&Qcenter);
dc220243
JR
14942 Qcancel_timer = intern ("cancel-timer");
14943 staticpro (&Qcancel_timer);
f7b9d4d1
JR
14944 Qfullscreen = intern ("fullscreen");
14945 staticpro (&Qfullscreen);
14946 Qfullwidth = intern ("fullwidth");
14947 staticpro (&Qfullwidth);
14948 Qfullheight = intern ("fullheight");
14949 staticpro (&Qfullheight);
14950 Qfullboth = intern ("fullboth");
14951 staticpro (&Qfullboth);
ee78dc32 14952
adcc3809
GV
14953 Qhyper = intern ("hyper");
14954 staticpro (&Qhyper);
14955 Qsuper = intern ("super");
14956 staticpro (&Qsuper);
14957 Qmeta = intern ("meta");
14958 staticpro (&Qmeta);
14959 Qalt = intern ("alt");
14960 staticpro (&Qalt);
14961 Qctrl = intern ("ctrl");
14962 staticpro (&Qctrl);
14963 Qcontrol = intern ("control");
14964 staticpro (&Qcontrol);
14965 Qshift = intern ("shift");
14966 staticpro (&Qshift);
f7b9d4d1 14967 /* This is the end of symbol initialization. */
adcc3809 14968
6fc2811b
JR
14969 /* Text property `display' should be nonsticky by default. */
14970 Vtext_property_default_nonsticky
14971 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14972
14973
14974 Qlaplace = intern ("laplace");
14975 staticpro (&Qlaplace);
3cf3436e
JR
14976 Qemboss = intern ("emboss");
14977 staticpro (&Qemboss);
14978 Qedge_detection = intern ("edge-detection");
14979 staticpro (&Qedge_detection);
14980 Qheuristic = intern ("heuristic");
14981 staticpro (&Qheuristic);
14982 QCmatrix = intern (":matrix");
14983 staticpro (&QCmatrix);
14984 QCcolor_adjustment = intern (":color-adjustment");
14985 staticpro (&QCcolor_adjustment);
14986 QCmask = intern (":mask");
14987 staticpro (&QCmask);
6fc2811b 14988
4b817373
RS
14989 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14990 staticpro (&Qface_set_after_frame_default);
14991
ee78dc32
GV
14992 Fput (Qundefined_color, Qerror_conditions,
14993 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14994 Fput (Qundefined_color, Qerror_message,
14995 build_string ("Undefined color"));
14996
ccc2d29c
GV
14997 staticpro (&w32_grabbed_keys);
14998 w32_grabbed_keys = Qnil;
14999
fbd6baed 15000 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 15001 doc: /* An array of color name mappings for windows. */);
fbd6baed 15002 Vw32_color_map = Qnil;
ee78dc32 15003
fbd6baed 15004 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
15005 doc: /* Non-nil if alt key presses are passed on to Windows.
15006When non-nil, for example, alt pressed and released and then space will
15007open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 15008 Vw32_pass_alt_to_system = Qnil;
da36a4d6 15009
fbd6baed 15010 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
15011 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
15012When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 15013 Vw32_alt_is_meta = Qt;
8c205c63 15014
7d081355 15015 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 15016 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
15017 XSETINT (Vw32_quit_key, 0);
15018
7d0393cf 15019 DEFVAR_LISP ("w32-pass-lwindow-to-system",
ccc2d29c 15020 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
15021 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
15022When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
15023 Vw32_pass_lwindow_to_system = Qt;
15024
7d0393cf 15025 DEFVAR_LISP ("w32-pass-rwindow-to-system",
ccc2d29c 15026 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
15027 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
15028When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
15029 Vw32_pass_rwindow_to_system = Qt;
15030
adcc3809
GV
15031 DEFVAR_INT ("w32-phantom-key-code",
15032 &Vw32_phantom_key_code,
74e1aeec
JR
15033 doc: /* Virtual key code used to generate \"phantom\" key presses.
15034Value is a number between 0 and 255.
15035
15036Phantom key presses are generated in order to stop the system from
15037acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
15038`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
15039 /* Although 255 is technically not a valid key code, it works and
15040 means that this hack won't interfere with any real key code. */
15041 Vw32_phantom_key_code = 255;
adcc3809 15042
7d0393cf 15043 DEFVAR_LISP ("w32-enable-num-lock",
ccc2d29c 15044 &Vw32_enable_num_lock,
74e1aeec
JR
15045 doc: /* Non-nil if Num Lock should act normally.
15046Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
15047 Vw32_enable_num_lock = Qt;
15048
7d0393cf 15049 DEFVAR_LISP ("w32-enable-caps-lock",
ccc2d29c 15050 &Vw32_enable_caps_lock,
74e1aeec
JR
15051 doc: /* Non-nil if Caps Lock should act normally.
15052Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
15053 Vw32_enable_caps_lock = Qt;
15054
15055 DEFVAR_LISP ("w32-scroll-lock-modifier",
15056 &Vw32_scroll_lock_modifier,
74e1aeec
JR
15057 doc: /* Modifier to use for the Scroll Lock on state.
15058The value can be hyper, super, meta, alt, control or shift for the
15059respective modifier, or nil to see Scroll Lock as the key `scroll'.
15060Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15061 Vw32_scroll_lock_modifier = Qt;
15062
15063 DEFVAR_LISP ("w32-lwindow-modifier",
15064 &Vw32_lwindow_modifier,
74e1aeec
JR
15065 doc: /* Modifier to use for the left \"Windows\" key.
15066The value can be hyper, super, meta, alt, control or shift for the
15067respective modifier, or nil to appear as the key `lwindow'.
15068Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15069 Vw32_lwindow_modifier = Qnil;
15070
15071 DEFVAR_LISP ("w32-rwindow-modifier",
15072 &Vw32_rwindow_modifier,
74e1aeec
JR
15073 doc: /* Modifier to use for the right \"Windows\" key.
15074The value can be hyper, super, meta, alt, control or shift for the
15075respective modifier, or nil to appear as the key `rwindow'.
15076Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15077 Vw32_rwindow_modifier = Qnil;
15078
15079 DEFVAR_LISP ("w32-apps-modifier",
15080 &Vw32_apps_modifier,
74e1aeec
JR
15081 doc: /* Modifier to use for the \"Apps\" key.
15082The value can be hyper, super, meta, alt, control or shift for the
15083respective modifier, or nil to appear as the key `apps'.
15084Any other value will cause the key to be ignored. */);
ccc2d29c 15085 Vw32_apps_modifier = Qnil;
da36a4d6 15086
d84b082d 15087 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 15088 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 15089 w32_enable_synthesized_fonts = 0;
5ac45f98 15090
fbd6baed 15091 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 15092 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 15093 Vw32_enable_palette = Qt;
5ac45f98 15094
fbd6baed
GV
15095 DEFVAR_INT ("w32-mouse-button-tolerance",
15096 &Vw32_mouse_button_tolerance,
74e1aeec
JR
15097 doc: /* Analogue of double click interval for faking middle mouse events.
15098The value is the minimum time in milliseconds that must elapse between
15099left/right button down events before they are considered distinct events.
15100If both mouse buttons are depressed within this interval, a middle mouse
15101button down event is generated instead. */);
fbd6baed 15102 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 15103
fbd6baed
GV
15104 DEFVAR_INT ("w32-mouse-move-interval",
15105 &Vw32_mouse_move_interval,
74e1aeec
JR
15106 doc: /* Minimum interval between mouse move events.
15107The value is the minimum time in milliseconds that must elapse between
15108successive mouse move (or scroll bar drag) events before they are
15109reported as lisp events. */);
247be837 15110 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 15111
74214547
JR
15112 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
15113 &w32_pass_extra_mouse_buttons_to_system,
15114 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
15115Recent versions of Windows support mice with up to five buttons.
15116Since most applications don't support these extra buttons, most mouse
15117drivers will allow you to map them to functions at the system level.
15118If this variable is non-nil, Emacs will pass them on, allowing the
15119system to handle them. */);
15120 w32_pass_extra_mouse_buttons_to_system = 0;
15121
ee78dc32
GV
15122 init_x_parm_symbols ();
15123
15124 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 15125 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
15126 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15127
15128 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
15129 doc: /* The shape of the pointer when over text.
15130Changing the value does not affect existing frames
15131unless you set the mouse color. */);
ee78dc32
GV
15132 Vx_pointer_shape = Qnil;
15133
15134 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
15135 doc: /* The name Emacs uses to look up resources; for internal use only.
15136`x-get-resource' uses this as the first component of the instance name
15137when requesting resource values.
15138Emacs initially sets `x-resource-name' to the name under which Emacs
15139was invoked, or to the value specified with the `-name' or `-rn'
15140switches, if present. */);
ee78dc32
GV
15141 Vx_resource_name = Qnil;
15142
15143 Vx_nontext_pointer_shape = Qnil;
15144
15145 Vx_mode_pointer_shape = Qnil;
15146
0af913d7 15147 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
15148 doc: /* The shape of the pointer when Emacs is busy.
15149This variable takes effect when you create a new frame
15150or when you set the mouse color. */);
0af913d7 15151 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 15152
0af913d7 15153 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 15154 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 15155 display_hourglass_p = 1;
7d0393cf 15156
0af913d7 15157 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
15158 doc: /* *Seconds to wait before displaying an hourglass pointer.
15159Value must be an integer or float. */);
0af913d7 15160 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 15161
6fc2811b 15162 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 15163 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
15164 doc: /* The shape of the pointer when over mouse-sensitive text.
15165This variable takes effect when you create a new frame
15166or when you set the mouse color. */);
ee78dc32
GV
15167 Vx_sensitive_text_pointer_shape = Qnil;
15168
4694d762
JR
15169 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15170 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
15171 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15172This variable takes effect when you create a new frame
15173or when you set the mouse color. */);
4694d762
JR
15174 Vx_window_horizontal_drag_shape = Qnil;
15175
ee78dc32 15176 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 15177 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
15178 Vx_cursor_fore_pixel = Qnil;
15179
3cf3436e 15180 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
15181 doc: /* Maximum size for tooltips.
15182Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e 15183 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
7d0393cf 15184
ee78dc32 15185 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
15186 doc: /* Non-nil if no window manager is in use.
15187Emacs doesn't try to figure this out; this is always nil
15188unless you set it to something else. */);
ee78dc32
GV
15189 /* We don't have any way to find this out, so set it to nil
15190 and maybe the user would like to set it to t. */
15191 Vx_no_window_manager = Qnil;
15192
4587b026
GV
15193 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15194 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
15195 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15196
15197Since Emacs gets width of a font matching with this regexp from
15198PIXEL_SIZE field of the name, font finding mechanism gets faster for
15199such a font. This is especially effective for such large fonts as
15200Chinese, Japanese, and Korean. */);
4587b026
GV
15201 Vx_pixel_size_width_font_regexp = Qnil;
15202
6fc2811b 15203 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
15204 doc: /* Time after which cached images are removed from the cache.
15205When an image has not been displayed this many seconds, remove it
15206from the image cache. Value must be an integer or nil with nil
15207meaning don't clear the cache. */);
6fc2811b
JR
15208 Vimage_cache_eviction_delay = make_number (30 * 60);
15209
33d52f9c
GV
15210 DEFVAR_LISP ("w32-bdf-filename-alist",
15211 &Vw32_bdf_filename_alist,
74e1aeec 15212 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
15213 Vw32_bdf_filename_alist = Qnil;
15214
1075afa9
GV
15215 DEFVAR_BOOL ("w32-strict-fontnames",
15216 &w32_strict_fontnames,
74e1aeec
JR
15217 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15218Default is nil, which allows old fontnames that are not XLFD compliant,
15219and allows third-party CJK display to work by specifying false charset
15220fields to trick Emacs into translating to Big5, SJIS etc.
15221Setting this to t will prevent wrong fonts being selected when
15222fontsets are automatically created. */);
1075afa9
GV
15223 w32_strict_fontnames = 0;
15224
c0611964
AI
15225 DEFVAR_BOOL ("w32-strict-painting",
15226 &w32_strict_painting,
74e1aeec
JR
15227 doc: /* Non-nil means use strict rules for repainting frames.
15228Set this to nil to get the old behaviour for repainting; this should
15229only be necessary if the default setting causes problems. */);
c0611964
AI
15230 w32_strict_painting = 1;
15231
dfff8a69
JR
15232 DEFVAR_LISP ("w32-charset-info-alist",
15233 &Vw32_charset_info_alist,
b3700ae7
JR
15234 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15235Each entry should be of the form:
74e1aeec
JR
15236
15237 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15238
15239where CHARSET_NAME is a string used in font names to identify the charset,
15240WINDOWS_CHARSET is a symbol that can be one of:
15241w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15242w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15243w32-charset-chinesebig5,
dfff8a69 15244#ifdef JOHAB_CHARSET
74e1aeec
JR
15245w32-charset-johab, w32-charset-hebrew,
15246w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15247w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15248w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
15249#endif
15250#ifdef UNICODE_CHARSET
74e1aeec 15251w32-charset-unicode,
dfff8a69 15252#endif
74e1aeec
JR
15253or w32-charset-oem.
15254CODEPAGE should be an integer specifying the codepage that should be used
15255to display the character set, t to do no translation and output as Unicode,
15256or nil to do no translation and output as 8 bit (or multibyte on far-east
15257versions of Windows) characters. */);
dfff8a69
JR
15258 Vw32_charset_info_alist = Qnil;
15259
15260 staticpro (&Qw32_charset_ansi);
15261 Qw32_charset_ansi = intern ("w32-charset-ansi");
15262 staticpro (&Qw32_charset_symbol);
15263 Qw32_charset_symbol = intern ("w32-charset-symbol");
15264 staticpro (&Qw32_charset_shiftjis);
15265 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
15266 staticpro (&Qw32_charset_hangeul);
15267 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
15268 staticpro (&Qw32_charset_chinesebig5);
15269 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15270 staticpro (&Qw32_charset_gb2312);
15271 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15272 staticpro (&Qw32_charset_oem);
15273 Qw32_charset_oem = intern ("w32-charset-oem");
15274
15275#ifdef JOHAB_CHARSET
15276 {
15277 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
15278 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15279 doc: /* Internal variable. */);
dfff8a69
JR
15280
15281 staticpro (&Qw32_charset_johab);
15282 Qw32_charset_johab = intern ("w32-charset-johab");
15283 staticpro (&Qw32_charset_easteurope);
15284 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15285 staticpro (&Qw32_charset_turkish);
15286 Qw32_charset_turkish = intern ("w32-charset-turkish");
15287 staticpro (&Qw32_charset_baltic);
15288 Qw32_charset_baltic = intern ("w32-charset-baltic");
15289 staticpro (&Qw32_charset_russian);
15290 Qw32_charset_russian = intern ("w32-charset-russian");
15291 staticpro (&Qw32_charset_arabic);
15292 Qw32_charset_arabic = intern ("w32-charset-arabic");
15293 staticpro (&Qw32_charset_greek);
15294 Qw32_charset_greek = intern ("w32-charset-greek");
15295 staticpro (&Qw32_charset_hebrew);
15296 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
15297 staticpro (&Qw32_charset_vietnamese);
15298 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
15299 staticpro (&Qw32_charset_thai);
15300 Qw32_charset_thai = intern ("w32-charset-thai");
15301 staticpro (&Qw32_charset_mac);
15302 Qw32_charset_mac = intern ("w32-charset-mac");
15303 }
15304#endif
15305
15306#ifdef UNICODE_CHARSET
15307 {
15308 static int w32_unicode_charset_defined = 1;
15309 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
15310 &w32_unicode_charset_defined,
15311 doc: /* Internal variable. */);
dfff8a69
JR
15312
15313 staticpro (&Qw32_charset_unicode);
15314 Qw32_charset_unicode = intern ("w32-charset-unicode");
15315#endif
15316
ee78dc32 15317 defsubr (&Sx_get_resource);
767b1ff0 15318#if 0 /* TODO: Port to W32 */
6fc2811b
JR
15319 defsubr (&Sx_change_window_property);
15320 defsubr (&Sx_delete_window_property);
15321 defsubr (&Sx_window_property);
15322#endif
2d764c78 15323 defsubr (&Sxw_display_color_p);
ee78dc32 15324 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
15325 defsubr (&Sxw_color_defined_p);
15326 defsubr (&Sxw_color_values);
ee78dc32
GV
15327 defsubr (&Sx_server_max_request_size);
15328 defsubr (&Sx_server_vendor);
15329 defsubr (&Sx_server_version);
15330 defsubr (&Sx_display_pixel_width);
15331 defsubr (&Sx_display_pixel_height);
15332 defsubr (&Sx_display_mm_width);
15333 defsubr (&Sx_display_mm_height);
15334 defsubr (&Sx_display_screens);
15335 defsubr (&Sx_display_planes);
15336 defsubr (&Sx_display_color_cells);
15337 defsubr (&Sx_display_visual_class);
15338 defsubr (&Sx_display_backing_store);
15339 defsubr (&Sx_display_save_under);
15340 defsubr (&Sx_parse_geometry);
15341 defsubr (&Sx_create_frame);
ee78dc32
GV
15342 defsubr (&Sx_open_connection);
15343 defsubr (&Sx_close_connection);
15344 defsubr (&Sx_display_list);
15345 defsubr (&Sx_synchronize);
15346
fbd6baed 15347 /* W32 specific functions */
ee78dc32 15348
1edf84e7 15349 defsubr (&Sw32_focus_frame);
fbd6baed
GV
15350 defsubr (&Sw32_select_font);
15351 defsubr (&Sw32_define_rgb_color);
15352 defsubr (&Sw32_default_color_map);
15353 defsubr (&Sw32_load_color_file);
1edf84e7 15354 defsubr (&Sw32_send_sys_command);
55dcfc15 15355 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
15356 defsubr (&Sw32_register_hot_key);
15357 defsubr (&Sw32_unregister_hot_key);
15358 defsubr (&Sw32_registered_hot_keys);
15359 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 15360 defsubr (&Sw32_toggle_lock_key);
33d52f9c 15361 defsubr (&Sw32_find_bdf_fonts);
4587b026 15362
2254bcde
AI
15363 defsubr (&Sfile_system_info);
15364
4587b026
GV
15365 /* Setting callback functions for fontset handler. */
15366 get_font_info_func = w32_get_font_info;
6fc2811b
JR
15367
15368#if 0 /* This function pointer doesn't seem to be used anywhere.
15369 And the pointer assigned has the wrong type, anyway. */
4587b026 15370 list_fonts_func = w32_list_fonts;
6fc2811b
JR
15371#endif
15372
4587b026
GV
15373 load_font_func = w32_load_font;
15374 find_ccl_program_func = w32_find_ccl_program;
15375 query_font_func = w32_query_font;
15376 set_frame_fontset_func = x_set_font;
15377 check_window_system_func = check_w32;
6fc2811b 15378
6fc2811b
JR
15379 /* Images. */
15380 Qxbm = intern ("xbm");
15381 staticpro (&Qxbm);
a93f4566
GM
15382 QCconversion = intern (":conversion");
15383 staticpro (&QCconversion);
6fc2811b
JR
15384 QCheuristic_mask = intern (":heuristic-mask");
15385 staticpro (&QCheuristic_mask);
15386 QCcolor_symbols = intern (":color-symbols");
15387 staticpro (&QCcolor_symbols);
6fc2811b
JR
15388 QCascent = intern (":ascent");
15389 staticpro (&QCascent);
15390 QCmargin = intern (":margin");
15391 staticpro (&QCmargin);
15392 QCrelief = intern (":relief");
15393 staticpro (&QCrelief);
15394 Qpostscript = intern ("postscript");
15395 staticpro (&Qpostscript);
ac849ba4 15396#if 0 /* TODO: These need entries at top of file. */
6fc2811b
JR
15397 QCloader = intern (":loader");
15398 staticpro (&QCloader);
15399 QCbounding_box = intern (":bounding-box");
15400 staticpro (&QCbounding_box);
15401 QCpt_width = intern (":pt-width");
15402 staticpro (&QCpt_width);
15403 QCpt_height = intern (":pt-height");
15404 staticpro (&QCpt_height);
ac849ba4 15405#endif
6fc2811b
JR
15406 QCindex = intern (":index");
15407 staticpro (&QCindex);
15408 Qpbm = intern ("pbm");
15409 staticpro (&Qpbm);
15410
15411#if HAVE_XPM
15412 Qxpm = intern ("xpm");
15413 staticpro (&Qxpm);
15414#endif
7d0393cf 15415
6fc2811b
JR
15416#if HAVE_JPEG
15417 Qjpeg = intern ("jpeg");
15418 staticpro (&Qjpeg);
7d0393cf 15419#endif
6fc2811b
JR
15420
15421#if HAVE_TIFF
15422 Qtiff = intern ("tiff");
15423 staticpro (&Qtiff);
7d0393cf 15424#endif
6fc2811b
JR
15425
15426#if HAVE_GIF
15427 Qgif = intern ("gif");
15428 staticpro (&Qgif);
15429#endif
15430
15431#if HAVE_PNG
15432 Qpng = intern ("png");
15433 staticpro (&Qpng);
15434#endif
15435
15436 defsubr (&Sclear_image_cache);
ac849ba4
JR
15437 defsubr (&Simage_size);
15438 defsubr (&Simage_mask_p);
6fc2811b
JR
15439
15440#if GLYPH_DEBUG
15441 defsubr (&Simagep);
15442 defsubr (&Slookup_image);
15443#endif
6fc2811b 15444
0af913d7
GM
15445 hourglass_atimer = NULL;
15446 hourglass_shown_p = 0;
6fc2811b
JR
15447 defsubr (&Sx_show_tip);
15448 defsubr (&Sx_hide_tip);
6fc2811b 15449 tip_timer = Qnil;
57fa2774
JR
15450 staticpro (&tip_timer);
15451 tip_frame = Qnil;
15452 staticpro (&tip_frame);
6fc2811b 15453
ca56d953
JR
15454 last_show_tip_args = Qnil;
15455 staticpro (&last_show_tip_args);
15456
6fc2811b
JR
15457 defsubr (&Sx_file_dialog);
15458}
15459
15460
15461void
15462init_xfns ()
15463{
15464 image_types = NULL;
15465 Vimage_types = Qnil;
15466
ac849ba4 15467 define_image_type (&pbm_type);
6fc2811b 15468 define_image_type (&xbm_type);
217e5be0 15469#if 0 /* TODO : Image support for W32 */
6fc2811b 15470 define_image_type (&gs_type);
ac849ba4 15471#endif
7d0393cf 15472
6fc2811b
JR
15473#if HAVE_XPM
15474 define_image_type (&xpm_type);
15475#endif
7d0393cf 15476
6fc2811b
JR
15477#if HAVE_JPEG
15478 define_image_type (&jpeg_type);
15479#endif
7d0393cf 15480
6fc2811b
JR
15481#if HAVE_TIFF
15482 define_image_type (&tiff_type);
15483#endif
919f1e88 15484
6fc2811b
JR
15485#if HAVE_GIF
15486 define_image_type (&gif_type);
15487#endif
7d0393cf 15488
6fc2811b
JR
15489#if HAVE_PNG
15490 define_image_type (&png_type);
15491#endif
ee78dc32
GV
15492}
15493
15494#undef abort
15495
7d0393cf 15496void
fbd6baed 15497w32_abort()
ee78dc32 15498{
5ac45f98
GV
15499 int button;
15500 button = MessageBox (NULL,
15501 "A fatal error has occurred!\n\n"
15502 "Select Abort to exit, Retry to debug, Ignore to continue",
15503 "Emacs Abort Dialog",
15504 MB_ICONEXCLAMATION | MB_TASKMODAL
15505 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15506 switch (button)
15507 {
15508 case IDRETRY:
15509 DebugBreak ();
15510 break;
15511 case IDIGNORE:
15512 break;
15513 case IDABORT:
15514 default:
15515 abort ();
15516 break;
15517 }
ee78dc32 15518}
d573caac 15519
83c75055
GV
15520/* For convenience when debugging. */
15521int
15522w32_last_error()
15523{
15524 return GetLastError ();
15525}