(ido-make-merged-file-list): Fix last change again.
[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
6fc2811b
JR
67/* A definition of XColor for non-X frames. */
68#ifndef HAVE_X_WINDOWS
69typedef struct {
70 unsigned long pixel;
71 unsigned short red, green, blue;
72 char flags;
73 char pad;
74} XColor;
75#endif
76
ccc2d29c
GV
77extern char *lispy_function_keys[];
78
6fc2811b
JR
79/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
80 it, and including `bitmaps/gray' more than once is a problem when
81 config.h defines `static' as an empty replacement string. */
82
83int gray_bitmap_width = gray_width;
84int gray_bitmap_height = gray_height;
85unsigned char *gray_bitmap_bits = gray_bits;
86
ee78dc32 87/* The colormap for converting color names to RGB values */
fbd6baed 88Lisp_Object Vw32_color_map;
ee78dc32 89
da36a4d6 90/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 91Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 92
8c205c63
RS
93/* Non nil if alt key is translated to meta_modifier, nil if it is translated
94 to alt_modifier. */
fbd6baed 95Lisp_Object Vw32_alt_is_meta;
8c205c63 96
7d081355
AI
97/* If non-zero, the windows virtual key code for an alternative quit key. */
98Lisp_Object Vw32_quit_key;
99
ccc2d29c
GV
100/* Non nil if left window key events are passed on to Windows (this only
101 affects whether "tapping" the key opens the Start menu). */
102Lisp_Object Vw32_pass_lwindow_to_system;
103
104/* Non nil if right window key events are passed on to Windows (this
105 only affects whether "tapping" the key opens the Start menu). */
106Lisp_Object Vw32_pass_rwindow_to_system;
107
adcc3809
GV
108/* Virtual key code used to generate "phantom" key presses in order
109 to stop system from acting on Windows key events. */
110Lisp_Object Vw32_phantom_key_code;
111
ccc2d29c
GV
112/* Modifier associated with the left "Windows" key, or nil to act as a
113 normal key. */
114Lisp_Object Vw32_lwindow_modifier;
115
116/* Modifier associated with the right "Windows" key, or nil to act as a
117 normal key. */
118Lisp_Object Vw32_rwindow_modifier;
119
120/* Modifier associated with the "Apps" key, or nil to act as a normal
121 key. */
122Lisp_Object Vw32_apps_modifier;
123
124/* Value is nil if Num Lock acts as a function key. */
125Lisp_Object Vw32_enable_num_lock;
126
127/* Value is nil if Caps Lock acts as a function key. */
128Lisp_Object Vw32_enable_caps_lock;
129
130/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
131Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 132
7ce9aaca 133/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b 134 and italic versions of fonts. */
d84b082d 135int w32_enable_synthesized_fonts;
5ac45f98
GV
136
137/* Enable palette management. */
fbd6baed 138Lisp_Object Vw32_enable_palette;
5ac45f98
GV
139
140/* Control how close left/right button down events must be to
141 be converted to a middle button down event. */
fbd6baed 142Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 143
84fb1139
KH
144/* Minimum interval between mouse movement (and scroll bar drag)
145 events that are passed on to the event loop. */
fbd6baed 146Lisp_Object Vw32_mouse_move_interval;
84fb1139 147
74214547
JR
148/* Flag to indicate if XBUTTON events should be passed on to Windows. */
149int w32_pass_extra_mouse_buttons_to_system;
150
ee78dc32
GV
151/* The name we're using in resource queries. */
152Lisp_Object Vx_resource_name;
153
154/* Non nil if no window manager is in use. */
155Lisp_Object Vx_no_window_manager;
156
0af913d7 157/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 158
0af913d7 159int display_hourglass_p;
6fc2811b 160
ee78dc32
GV
161/* The background and shape of the mouse pointer, and shape when not
162 over text or in the modeline. */
dfff8a69 163
ee78dc32 164Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 165Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 166
ee78dc32 167/* The shape when over mouse-sensitive text. */
dfff8a69 168
ee78dc32
GV
169Lisp_Object Vx_sensitive_text_pointer_shape;
170
171/* Color of chars displayed in cursor box. */
dfff8a69 172
ee78dc32
GV
173Lisp_Object Vx_cursor_fore_pixel;
174
1edf84e7 175/* Nonzero if using Windows. */
dfff8a69 176
1edf84e7
GV
177static int w32_in_use;
178
ee78dc32 179/* Search path for bitmap files. */
dfff8a69 180
ee78dc32
GV
181Lisp_Object Vx_bitmap_file_path;
182
4587b026 183/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 184
4587b026
GV
185Lisp_Object Vx_pixel_size_width_font_regexp;
186
33d52f9c
GV
187/* Alist of bdf fonts and the files that define them. */
188Lisp_Object Vw32_bdf_filename_alist;
189
f46e6225 190/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
191int w32_strict_fontnames;
192
c0611964
AI
193/* A flag to control whether we should only repaint if GetUpdateRect
194 indicates there is an update region. */
195int w32_strict_painting;
196
dfff8a69
JR
197/* Associative list linking character set strings to Windows codepages. */
198Lisp_Object Vw32_charset_info_alist;
199
200/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
201#ifndef VIETNAMESE_CHARSET
202#define VIETNAMESE_CHARSET 163
203#endif
204
ee78dc32
GV
205Lisp_Object Qauto_raise;
206Lisp_Object Qauto_lower;
23afac8f 207Lisp_Object Qbar, Qhbar;
ee78dc32
GV
208Lisp_Object Qborder_color;
209Lisp_Object Qborder_width;
210Lisp_Object Qbox;
211Lisp_Object Qcursor_color;
212Lisp_Object Qcursor_type;
ee78dc32
GV
213Lisp_Object Qgeometry;
214Lisp_Object Qicon_left;
215Lisp_Object Qicon_top;
216Lisp_Object Qicon_type;
217Lisp_Object Qicon_name;
218Lisp_Object Qinternal_border_width;
219Lisp_Object Qleft;
1026b400 220Lisp_Object Qright;
ee78dc32
GV
221Lisp_Object Qmouse_color;
222Lisp_Object Qnone;
223Lisp_Object Qparent_id;
224Lisp_Object Qscroll_bar_width;
225Lisp_Object Qsuppress_icon;
ee78dc32
GV
226Lisp_Object Qundefined_color;
227Lisp_Object Qvertical_scroll_bars;
228Lisp_Object Qvisibility;
229Lisp_Object Qwindow_id;
230Lisp_Object Qx_frame_parameter;
231Lisp_Object Qx_resource_name;
232Lisp_Object Quser_position;
233Lisp_Object Quser_size;
6fc2811b 234Lisp_Object Qscreen_gamma;
dfff8a69
JR
235Lisp_Object Qline_spacing;
236Lisp_Object Qcenter;
dc220243 237Lisp_Object Qcancel_timer;
adcc3809
GV
238Lisp_Object Qhyper;
239Lisp_Object Qsuper;
240Lisp_Object Qmeta;
241Lisp_Object Qalt;
242Lisp_Object Qctrl;
243Lisp_Object Qcontrol;
244Lisp_Object Qshift;
245
dfff8a69
JR
246Lisp_Object Qw32_charset_ansi;
247Lisp_Object Qw32_charset_default;
248Lisp_Object Qw32_charset_symbol;
249Lisp_Object Qw32_charset_shiftjis;
767b1ff0 250Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
251Lisp_Object Qw32_charset_gb2312;
252Lisp_Object Qw32_charset_chinesebig5;
253Lisp_Object Qw32_charset_oem;
254
71eab8d1
AI
255#ifndef JOHAB_CHARSET
256#define JOHAB_CHARSET 130
257#endif
dfff8a69
JR
258#ifdef JOHAB_CHARSET
259Lisp_Object Qw32_charset_easteurope;
260Lisp_Object Qw32_charset_turkish;
261Lisp_Object Qw32_charset_baltic;
262Lisp_Object Qw32_charset_russian;
263Lisp_Object Qw32_charset_arabic;
264Lisp_Object Qw32_charset_greek;
265Lisp_Object Qw32_charset_hebrew;
767b1ff0 266Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
267Lisp_Object Qw32_charset_thai;
268Lisp_Object Qw32_charset_johab;
269Lisp_Object Qw32_charset_mac;
270#endif
271
272#ifdef UNICODE_CHARSET
273Lisp_Object Qw32_charset_unicode;
274#endif
275
f7b9d4d1
JR
276Lisp_Object Qfullscreen;
277Lisp_Object Qfullwidth;
278Lisp_Object Qfullheight;
279Lisp_Object Qfullboth;
280
6fc2811b
JR
281extern Lisp_Object Qtop;
282extern Lisp_Object Qdisplay;
6fc2811b 283
5ac45f98
GV
284/* State variables for emulating a three button mouse. */
285#define LMOUSE 1
286#define MMOUSE 2
287#define RMOUSE 4
288
289static int button_state = 0;
fbd6baed 290static W32Msg saved_mouse_button_msg;
48094ace 291static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
fbd6baed 292static W32Msg saved_mouse_move_msg;
48094ace 293static unsigned mouse_move_timer = 0;
84fb1139 294
9eb16b62
JR
295/* Window that is tracking the mouse. */
296static HWND track_mouse_window;
297FARPROC track_mouse_event_fn;
298
93fbe8b7
GV
299/* W95 mousewheel handler */
300unsigned int msh_mousewheel = 0;
301
48094ace 302/* Timers */
84fb1139
KH
303#define MOUSE_BUTTON_ID 1
304#define MOUSE_MOVE_ID 2
48094ace
JR
305#define MENU_FREE_ID 3
306/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
307 is received. */
308#define MENU_FREE_DELAY 1000
309static unsigned menu_free_timer = 0;
5ac45f98 310
ee78dc32 311/* The below are defined in frame.c. */
dfff8a69 312
ee78dc32 313extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 314extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 315extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
316
317extern Lisp_Object Vwindow_system_version;
318
4b817373
RS
319Lisp_Object Qface_set_after_frame_default;
320
937e601e
AI
321#ifdef GLYPH_DEBUG
322int image_cache_refcount, dpyinfo_refcount;
323#endif
324
325
fbd6baed
GV
326/* From w32term.c. */
327extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 328extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 329
65906840 330extern HWND w32_system_caret_hwnd;
93f2ca61 331
65906840
JR
332extern int w32_system_caret_height;
333extern int w32_system_caret_x;
334extern int w32_system_caret_y;
93f2ca61
JR
335extern int w32_use_visible_system_caret;
336
d285988b 337static HWND w32_visible_system_caret_hwnd;
65906840 338
ee78dc32 339\f
1edf84e7
GV
340/* Error if we are not connected to MS-Windows. */
341void
342check_w32 ()
343{
344 if (! w32_in_use)
345 error ("MS-Windows not in use or not initialized");
346}
347
348/* Nonzero if we can use mouse menus.
349 You should not call this unless HAVE_MENUS is defined. */
350
351int
352have_menus_p ()
353{
354 return w32_in_use;
355}
356
ee78dc32 357/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 358 and checking validity for W32. */
ee78dc32
GV
359
360FRAME_PTR
361check_x_frame (frame)
362 Lisp_Object frame;
363{
364 FRAME_PTR f;
365
366 if (NILP (frame))
6fc2811b 367 frame = selected_frame;
b7826503 368 CHECK_LIVE_FRAME (frame);
6fc2811b 369 f = XFRAME (frame);
fbd6baed
GV
370 if (! FRAME_W32_P (f))
371 error ("non-w32 frame used");
ee78dc32
GV
372 return f;
373}
374
375/* Let the user specify an display with a frame.
fbd6baed 376 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
377 the first display on the list. */
378
fbd6baed 379static struct w32_display_info *
ee78dc32
GV
380check_x_display_info (frame)
381 Lisp_Object frame;
382{
383 if (NILP (frame))
384 {
6fc2811b
JR
385 struct frame *sf = XFRAME (selected_frame);
386
387 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
388 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 389 else
fbd6baed 390 return &one_w32_display_info;
ee78dc32
GV
391 }
392 else if (STRINGP (frame))
393 return x_display_info_for_name (frame);
394 else
395 {
396 FRAME_PTR f;
397
b7826503 398 CHECK_LIVE_FRAME (frame);
ee78dc32 399 f = XFRAME (frame);
fbd6baed
GV
400 if (! FRAME_W32_P (f))
401 error ("non-w32 frame used");
402 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
403 }
404}
405\f
fbd6baed 406/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
407 It could be the frame's main window or an icon window. */
408
409/* This function can be called during GC, so use GC_xxx type test macros. */
410
411struct frame *
412x_window_to_frame (dpyinfo, wdesc)
fbd6baed 413 struct w32_display_info *dpyinfo;
ee78dc32
GV
414 HWND wdesc;
415{
416 Lisp_Object tail, frame;
417 struct frame *f;
418
8e713be6 419 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 420 {
8e713be6 421 frame = XCAR (tail);
ee78dc32
GV
422 if (!GC_FRAMEP (frame))
423 continue;
424 f = XFRAME (frame);
2d764c78 425 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 426 continue;
0af913d7 427 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
428 return f;
429
fbd6baed 430 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
431 return f;
432 }
433 return 0;
434}
435
436\f
437
438/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
439 id, which is just an int that this section returns. Bitmaps are
440 reference counted so they can be shared among frames.
441
442 Bitmap indices are guaranteed to be > 0, so a negative number can
443 be used to indicate no bitmap.
444
445 If you use x_create_bitmap_from_data, then you must keep track of
446 the bitmaps yourself. That is, creating a bitmap from the same
447 data more than once will not be caught. */
448
449
450/* Functions to access the contents of a bitmap, given an id. */
451
452int
453x_bitmap_height (f, id)
454 FRAME_PTR f;
455 int id;
456{
fbd6baed 457 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
458}
459
460int
461x_bitmap_width (f, id)
462 FRAME_PTR f;
463 int id;
464{
fbd6baed 465 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
466}
467
468int
469x_bitmap_pixmap (f, id)
470 FRAME_PTR f;
471 int id;
472{
fbd6baed 473 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
474}
475
476
477/* Allocate a new bitmap record. Returns index of new record. */
478
479static int
480x_allocate_bitmap_record (f)
481 FRAME_PTR f;
482{
fbd6baed 483 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
484 int i;
485
486 if (dpyinfo->bitmaps == NULL)
487 {
488 dpyinfo->bitmaps_size = 10;
489 dpyinfo->bitmaps
fbd6baed 490 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
491 dpyinfo->bitmaps_last = 1;
492 return 1;
493 }
494
495 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
496 return ++dpyinfo->bitmaps_last;
497
498 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
499 if (dpyinfo->bitmaps[i].refcount == 0)
500 return i + 1;
501
502 dpyinfo->bitmaps_size *= 2;
503 dpyinfo->bitmaps
fbd6baed
GV
504 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
505 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
506 return ++dpyinfo->bitmaps_last;
507}
508
509/* Add one reference to the reference count of the bitmap with id ID. */
510
511void
512x_reference_bitmap (f, id)
513 FRAME_PTR f;
514 int id;
515{
fbd6baed 516 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
517}
518
519/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
520
521int
522x_create_bitmap_from_data (f, bits, width, height)
523 struct frame *f;
524 char *bits;
525 unsigned int width, height;
526{
fbd6baed 527 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
528 Pixmap bitmap;
529 int id;
530
531 bitmap = CreateBitmap (width, height,
fbd6baed
GV
532 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
533 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
534 bits);
535
536 if (! bitmap)
537 return -1;
538
539 id = x_allocate_bitmap_record (f);
540 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
541 dpyinfo->bitmaps[id - 1].file = NULL;
542 dpyinfo->bitmaps[id - 1].hinst = NULL;
543 dpyinfo->bitmaps[id - 1].refcount = 1;
544 dpyinfo->bitmaps[id - 1].depth = 1;
545 dpyinfo->bitmaps[id - 1].height = height;
546 dpyinfo->bitmaps[id - 1].width = width;
547
548 return id;
549}
550
551/* Create bitmap from file FILE for frame F. */
552
553int
554x_create_bitmap_from_file (f, file)
555 struct frame *f;
556 Lisp_Object file;
557{
558 return -1;
767b1ff0 559#if 0 /* TODO : bitmap support */
fbd6baed 560 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 561 unsigned int width, height;
6fc2811b 562 HBITMAP bitmap;
ee78dc32
GV
563 int xhot, yhot, result, id;
564 Lisp_Object found;
565 int fd;
566 char *filename;
567 HINSTANCE hinst;
568
569 /* Look for an existing bitmap with the same name. */
570 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
571 {
572 if (dpyinfo->bitmaps[id].refcount
573 && dpyinfo->bitmaps[id].file
574 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
575 {
576 ++dpyinfo->bitmaps[id].refcount;
577 return id + 1;
578 }
579 }
580
581 /* Search bitmap-file-path for the file, if appropriate. */
de2413e9 582 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
ee78dc32
GV
583 if (fd < 0)
584 return -1;
6fc2811b 585 emacs_close (fd);
ee78dc32
GV
586
587 filename = (char *) XSTRING (found)->data;
588
589 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
590
591 if (hinst == NULL)
592 return -1;
593
594
fbd6baed 595 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
596 filename, &width, &height, &bitmap, &xhot, &yhot);
597 if (result != BitmapSuccess)
598 return -1;
599
600 id = x_allocate_bitmap_record (f);
601 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
602 dpyinfo->bitmaps[id - 1].refcount = 1;
603 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
604 dpyinfo->bitmaps[id - 1].depth = 1;
605 dpyinfo->bitmaps[id - 1].height = height;
606 dpyinfo->bitmaps[id - 1].width = width;
607 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
608
609 return id;
767b1ff0 610#endif /* TODO */
ee78dc32
GV
611}
612
613/* Remove reference to bitmap with id number ID. */
614
33d52f9c 615void
ee78dc32
GV
616x_destroy_bitmap (f, id)
617 FRAME_PTR f;
618 int id;
619{
fbd6baed 620 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
621
622 if (id > 0)
623 {
624 --dpyinfo->bitmaps[id - 1].refcount;
625 if (dpyinfo->bitmaps[id - 1].refcount == 0)
626 {
627 BLOCK_INPUT;
628 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
629 if (dpyinfo->bitmaps[id - 1].file)
630 {
6fc2811b 631 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
632 dpyinfo->bitmaps[id - 1].file = NULL;
633 }
634 UNBLOCK_INPUT;
635 }
636 }
637}
638
639/* Free all the bitmaps for the display specified by DPYINFO. */
640
641static void
642x_destroy_all_bitmaps (dpyinfo)
fbd6baed 643 struct w32_display_info *dpyinfo;
ee78dc32
GV
644{
645 int i;
646 for (i = 0; i < dpyinfo->bitmaps_last; i++)
647 if (dpyinfo->bitmaps[i].refcount > 0)
648 {
649 DeleteObject (dpyinfo->bitmaps[i].pixmap);
650 if (dpyinfo->bitmaps[i].file)
6fc2811b 651 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
652 }
653 dpyinfo->bitmaps_last = 0;
654}
655\f
fbd6baed 656/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
657 to the ways of passing the parameter values to the window system.
658
659 The name of a parameter, as a Lisp symbol,
660 has an `x-frame-parameter' property which is an integer in Lisp
661 but can be interpreted as an `enum x_frame_parm' in C. */
662
663enum x_frame_parm
664{
665 X_PARM_FOREGROUND_COLOR,
666 X_PARM_BACKGROUND_COLOR,
667 X_PARM_MOUSE_COLOR,
668 X_PARM_CURSOR_COLOR,
669 X_PARM_BORDER_COLOR,
670 X_PARM_ICON_TYPE,
671 X_PARM_FONT,
672 X_PARM_BORDER_WIDTH,
673 X_PARM_INTERNAL_BORDER_WIDTH,
674 X_PARM_NAME,
675 X_PARM_AUTORAISE,
676 X_PARM_AUTOLOWER,
677 X_PARM_VERT_SCROLL_BAR,
678 X_PARM_VISIBILITY,
679 X_PARM_MENU_BAR_LINES
680};
681
682
683struct x_frame_parm_table
684{
685 char *name;
6fc2811b 686 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
687};
688
ca56d953
JR
689BOOL my_show_window P_ ((struct frame *, HWND, int));
690void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
691static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
692static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
693static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 694/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 695void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 696static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
f7b9d4d1 697static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
698void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
701void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
702void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
703void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
704void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 706static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
707void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
708void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
709 Lisp_Object));
710void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
711void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
712void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
713void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
714 Lisp_Object));
715void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
716void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
717void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
718void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
719void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
720void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
721static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
722static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
723 Lisp_Object));
ee78dc32
GV
724
725static struct x_frame_parm_table x_frame_parms[] =
726{
72e4adef
JR
727 {"auto-raise", x_set_autoraise},
728 {"auto-lower", x_set_autolower},
729 {"background-color", x_set_background_color},
730 {"border-color", x_set_border_color},
731 {"border-width", x_set_border_width},
732 {"cursor-color", x_set_cursor_color},
733 {"cursor-type", x_set_cursor_type},
734 {"font", x_set_font},
735 {"foreground-color", x_set_foreground_color},
736 {"icon-name", x_set_icon_name},
737 {"icon-type", x_set_icon_type},
738 {"internal-border-width", x_set_internal_border_width},
739 {"menu-bar-lines", x_set_menu_bar_lines},
740 {"mouse-color", x_set_mouse_color},
741 {"name", x_explicitly_set_name},
742 {"scroll-bar-width", x_set_scroll_bar_width},
743 {"title", x_set_title},
744 {"unsplittable", x_set_unsplittable},
745 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
746 {"visibility", x_set_visibility},
747 {"tool-bar-lines", x_set_tool_bar_lines},
748 {"screen-gamma", x_set_screen_gamma},
749 {"line-spacing", x_set_line_spacing},
750 {"left-fringe", x_set_fringe_width},
f7b9d4d1
JR
751 {"right-fringe", x_set_fringe_width},
752 {"fullscreen", x_set_fullscreen},
ee78dc32
GV
753};
754
755/* Attach the `x-frame-parameter' properties to
fbd6baed 756 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 757
dfff8a69 758void
ee78dc32
GV
759init_x_parm_symbols ()
760{
761 int i;
762
763 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
764 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
765 make_number (i));
766}
767\f
f7b9d4d1
JR
768/* Really try to move where we want to be in case of fullscreen. Some WMs
769 moves the window where we tell them. Some (mwm, twm) moves the outer
770 window manager window there instead.
771 Try to compensate for those WM here. */
772static void
773x_fullscreen_move (f, new_top, new_left)
774 struct frame *f;
775 int new_top;
776 int new_left;
777{
778 if (new_top != f->output_data.w32->top_pos
779 || new_left != f->output_data.w32->left_pos)
780 {
781 int move_x = new_left;
782 int move_y = new_top;
783
784 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
785 x_set_offset (f, move_x, move_y, 1);
786 }
787}
788
dfff8a69 789/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
790 If a parameter is not specially recognized, do nothing;
791 otherwise call the `x_set_...' function for that parameter. */
792
793void
794x_set_frame_parameters (f, alist)
795 FRAME_PTR f;
796 Lisp_Object alist;
797{
798 Lisp_Object tail;
799
800 /* If both of these parameters are present, it's more efficient to
801 set them both at once. So we wait until we've looked at the
802 entire list before we set them. */
b839712d 803 int width, height;
ee78dc32
GV
804
805 /* Same here. */
806 Lisp_Object left, top;
807
808 /* Same with these. */
809 Lisp_Object icon_left, icon_top;
810
811 /* Record in these vectors all the parms specified. */
812 Lisp_Object *parms;
813 Lisp_Object *values;
a797a73d 814 int i, p;
ee78dc32
GV
815 int left_no_change = 0, top_no_change = 0;
816 int icon_left_no_change = 0, icon_top_no_change = 0;
f7b9d4d1 817 int fullscreen_is_being_set = 0;
ee78dc32 818
5878523b
RS
819 struct gcpro gcpro1, gcpro2;
820
ee78dc32
GV
821 i = 0;
822 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
823 i++;
824
825 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
826 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
827
828 /* Extract parm names and values into those vectors. */
829
830 i = 0;
831 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
832 {
6fc2811b 833 Lisp_Object elt;
ee78dc32
GV
834
835 elt = Fcar (tail);
836 parms[i] = Fcar (elt);
837 values[i] = Fcdr (elt);
838 i++;
839 }
5878523b
RS
840 /* TAIL and ALIST are not used again below here. */
841 alist = tail = Qnil;
842
843 GCPRO2 (*parms, *values);
844 gcpro1.nvars = i;
845 gcpro2.nvars = i;
846
847 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
848 because their values appear in VALUES and strings are not valid. */
b839712d 849 top = left = Qunbound;
ee78dc32
GV
850 icon_left = icon_top = Qunbound;
851
b839712d 852 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
853 if (FRAME_NEW_WIDTH (f))
854 width = FRAME_NEW_WIDTH (f);
855 else
856 width = FRAME_WIDTH (f);
857
858 if (FRAME_NEW_HEIGHT (f))
859 height = FRAME_NEW_HEIGHT (f);
860 else
861 height = FRAME_HEIGHT (f);
b839712d 862
a797a73d
GV
863 /* Process foreground_color and background_color before anything else.
864 They are independent of other properties, but other properties (e.g.,
865 cursor_color) are dependent upon them. */
41c1bdd9 866 /* Process default font as well, since fringe widths depends on it. */
a797a73d
GV
867 for (p = 0; p < i; p++)
868 {
869 Lisp_Object prop, val;
870
871 prop = parms[p];
872 val = values[p];
41c1bdd9
KS
873 if (EQ (prop, Qforeground_color)
874 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
875 || EQ (prop, Qfont)
876 || EQ (prop, Qfullscreen))
a797a73d
GV
877 {
878 register Lisp_Object param_index, old_value;
879
a797a73d 880 old_value = get_frame_param (f, prop);
f7b9d4d1 881 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
a05e2bae
JR
882
883 if (NILP (Fequal (val, old_value)))
884 {
885 store_frame_param (f, prop, val);
886
887 param_index = Fget (prop, Qx_frame_parameter);
888 if (NATNUMP (param_index)
889 && (XFASTINT (param_index)
890 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
891 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
892 }
a797a73d
GV
893 }
894 }
895
ee78dc32
GV
896 /* Now process them in reverse of specified order. */
897 for (i--; i >= 0; i--)
898 {
899 Lisp_Object prop, val;
900
901 prop = parms[i];
902 val = values[i];
903
b839712d
RS
904 if (EQ (prop, Qwidth) && NUMBERP (val))
905 width = XFASTINT (val);
906 else if (EQ (prop, Qheight) && NUMBERP (val))
907 height = XFASTINT (val);
ee78dc32
GV
908 else if (EQ (prop, Qtop))
909 top = val;
910 else if (EQ (prop, Qleft))
911 left = val;
912 else if (EQ (prop, Qicon_top))
913 icon_top = val;
914 else if (EQ (prop, Qicon_left))
915 icon_left = val;
41c1bdd9
KS
916 else if (EQ (prop, Qforeground_color)
917 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
918 || EQ (prop, Qfont)
919 || EQ (prop, Qfullscreen))
a797a73d
GV
920 /* Processed above. */
921 continue;
ee78dc32
GV
922 else
923 {
924 register Lisp_Object param_index, old_value;
925
ee78dc32 926 old_value = get_frame_param (f, prop);
a05e2bae 927
ee78dc32 928 store_frame_param (f, prop, val);
a05e2bae
JR
929
930 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
931 if (NATNUMP (param_index)
932 && (XFASTINT (param_index)
933 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 934 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
935 }
936 }
937
938 /* Don't die if just one of these was set. */
939 if (EQ (left, Qunbound))
940 {
941 left_no_change = 1;
fbd6baed
GV
942 if (f->output_data.w32->left_pos < 0)
943 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 944 else
fbd6baed 945 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
946 }
947 if (EQ (top, Qunbound))
948 {
949 top_no_change = 1;
fbd6baed
GV
950 if (f->output_data.w32->top_pos < 0)
951 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 952 else
fbd6baed 953 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
954 }
955
956 /* If one of the icon positions was not set, preserve or default it. */
957 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
958 {
959 icon_left_no_change = 1;
960 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
961 if (NILP (icon_left))
962 XSETINT (icon_left, 0);
963 }
964 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
965 {
966 icon_top_no_change = 1;
967 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
968 if (NILP (icon_top))
969 XSETINT (icon_top, 0);
970 }
971
f7b9d4d1
JR
972 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
973 {
974 /* If the frame is visible already and the fullscreen parameter is
975 being set, it is too late to set WM manager hints to specify
976 size and position.
977 Here we first get the width, height and position that applies to
978 fullscreen. We then move the frame to the appropriate
979 position. Resize of the frame is taken care of in the code after
980 this if-statement. */
981 int new_left, new_top;
982
983 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
984 x_fullscreen_move (f, new_top, new_left);
985 }
986
ee78dc32
GV
987 /* Don't set these parameters unless they've been explicitly
988 specified. The window might be mapped or resized while we're in
989 this function, and we don't want to override that unless the lisp
990 code has asked for it.
991
992 Don't set these parameters unless they actually differ from the
993 window's current parameters; the window may not actually exist
994 yet. */
995 {
996 Lisp_Object frame;
997
998 check_frame_size (f, &height, &width);
999
1000 XSETFRAME (frame, f);
1001
dfff8a69
JR
1002 if (width != FRAME_WIDTH (f)
1003 || height != FRAME_HEIGHT (f)
1004 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 1005 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
1006
1007 if ((!NILP (left) || !NILP (top))
1008 && ! (left_no_change && top_no_change)
fbd6baed
GV
1009 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1010 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
1011 {
1012 int leftpos = 0;
1013 int toppos = 0;
1014
1015 /* Record the signs. */
fbd6baed 1016 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 1017 if (EQ (left, Qminus))
fbd6baed 1018 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
1019 else if (INTEGERP (left))
1020 {
1021 leftpos = XINT (left);
1022 if (leftpos < 0)
fbd6baed 1023 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1024 }
8e713be6
KR
1025 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1026 && CONSP (XCDR (left))
1027 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1028 {
8e713be6 1029 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 1030 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1031 }
8e713be6
KR
1032 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1033 && CONSP (XCDR (left))
1034 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1035 {
8e713be6 1036 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
1037 }
1038
1039 if (EQ (top, Qminus))
fbd6baed 1040 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
1041 else if (INTEGERP (top))
1042 {
1043 toppos = XINT (top);
1044 if (toppos < 0)
fbd6baed 1045 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1046 }
8e713be6
KR
1047 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1048 && CONSP (XCDR (top))
1049 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1050 {
8e713be6 1051 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 1052 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1053 }
8e713be6
KR
1054 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1055 && CONSP (XCDR (top))
1056 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1057 {
8e713be6 1058 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1059 }
1060
1061
1062 /* Store the numeric value of the position. */
fbd6baed
GV
1063 f->output_data.w32->top_pos = toppos;
1064 f->output_data.w32->left_pos = leftpos;
ee78dc32 1065
fbd6baed 1066 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1067
1068 /* Actually set that position, and convert to absolute. */
1069 x_set_offset (f, leftpos, toppos, -1);
1070 }
1071
1072 if ((!NILP (icon_left) || !NILP (icon_top))
1073 && ! (icon_left_no_change && icon_top_no_change))
1074 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1075 }
5878523b
RS
1076
1077 UNGCPRO;
ee78dc32
GV
1078}
1079
1080/* Store the screen positions of frame F into XPTR and YPTR.
1081 These are the positions of the containing window manager window,
1082 not Emacs's own window. */
1083
1084void
1085x_real_positions (f, xptr, yptr)
1086 FRAME_PTR f;
1087 int *xptr, *yptr;
1088{
1089 POINT pt;
f7b9d4d1 1090 RECT rect;
3c190163 1091
f7b9d4d1
JR
1092 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1093 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1094
1095 pt.x = rect.left;
1096 pt.y = rect.top;
ee78dc32 1097
fbd6baed 1098 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32 1099
f7b9d4d1
JR
1100 /* Remember x_pixels_diff and y_pixels_diff. */
1101 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1102 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1103
ee78dc32
GV
1104 *xptr = pt.x;
1105 *yptr = pt.y;
1106}
1107
1108/* Insert a description of internally-recorded parameters of frame X
1109 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1110 Only parameters that are specific to W32
ee78dc32
GV
1111 and whose values are not correctly recorded in the frame's
1112 param_alist need to be considered here. */
1113
dfff8a69 1114void
ee78dc32
GV
1115x_report_frame_params (f, alistptr)
1116 struct frame *f;
1117 Lisp_Object *alistptr;
1118{
1119 char buf[16];
1120 Lisp_Object tem;
1121
1122 /* Represent negative positions (off the top or left screen edge)
1123 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1124 XSETINT (tem, f->output_data.w32->left_pos);
1125 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1126 store_in_alist (alistptr, Qleft, tem);
1127 else
1128 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1129
fbd6baed
GV
1130 XSETINT (tem, f->output_data.w32->top_pos);
1131 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1132 store_in_alist (alistptr, Qtop, tem);
1133 else
1134 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1135
1136 store_in_alist (alistptr, Qborder_width,
fbd6baed 1137 make_number (f->output_data.w32->border_width));
ee78dc32 1138 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1139 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1140 store_in_alist (alistptr, Qleft_fringe,
1141 make_number (f->output_data.w32->left_fringe_width));
1142 store_in_alist (alistptr, Qright_fringe,
1143 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1144 store_in_alist (alistptr, Qscroll_bar_width,
1145 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1146 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1147 : 0));
fbd6baed 1148 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1149 store_in_alist (alistptr, Qwindow_id,
1150 build_string (buf));
1151 store_in_alist (alistptr, Qicon_name, f->icon_name);
1152 FRAME_SAMPLE_VISIBILITY (f);
1153 store_in_alist (alistptr, Qvisibility,
1154 (FRAME_VISIBLE_P (f) ? Qt
1155 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1156 store_in_alist (alistptr, Qdisplay,
8e713be6 1157 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1158}
1159\f
1160
74e1aeec
JR
1161DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1162 Sw32_define_rgb_color, 4, 4, 0,
1163 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1164This adds or updates a named color to w32-color-map, making it
1165available for use. The original entry's RGB ref is returned, or nil
1166if the entry is new. */)
5ac45f98
GV
1167 (red, green, blue, name)
1168 Lisp_Object red, green, blue, name;
ee78dc32 1169{
5ac45f98
GV
1170 Lisp_Object rgb;
1171 Lisp_Object oldrgb = Qnil;
1172 Lisp_Object entry;
1173
b7826503
PJ
1174 CHECK_NUMBER (red);
1175 CHECK_NUMBER (green);
1176 CHECK_NUMBER (blue);
1177 CHECK_STRING (name);
ee78dc32 1178
5ac45f98 1179 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1180
5ac45f98 1181 BLOCK_INPUT;
ee78dc32 1182
fbd6baed
GV
1183 /* replace existing entry in w32-color-map or add new entry. */
1184 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1185 if (NILP (entry))
1186 {
1187 entry = Fcons (name, rgb);
fbd6baed 1188 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1189 }
1190 else
1191 {
1192 oldrgb = Fcdr (entry);
1193 Fsetcdr (entry, rgb);
1194 }
1195
1196 UNBLOCK_INPUT;
1197
1198 return (oldrgb);
ee78dc32
GV
1199}
1200
74e1aeec
JR
1201DEFUN ("w32-load-color-file", Fw32_load_color_file,
1202 Sw32_load_color_file, 1, 1, 0,
1203 doc: /* Create an alist of color entries from an external file.
1204Assign this value to w32-color-map to replace the existing color map.
1205
1206The file should define one named RGB color per line like so:
1207 R G B name
1208where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1209 (filename)
1210 Lisp_Object filename;
1211{
1212 FILE *fp;
1213 Lisp_Object cmap = Qnil;
1214 Lisp_Object abspath;
1215
b7826503 1216 CHECK_STRING (filename);
5ac45f98
GV
1217 abspath = Fexpand_file_name (filename, Qnil);
1218
1219 fp = fopen (XSTRING (filename)->data, "rt");
1220 if (fp)
1221 {
1222 char buf[512];
1223 int red, green, blue;
1224 int num;
1225
1226 BLOCK_INPUT;
1227
1228 while (fgets (buf, sizeof (buf), fp) != NULL) {
1229 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1230 {
1231 char *name = buf + num;
1232 num = strlen (name) - 1;
1233 if (name[num] == '\n')
1234 name[num] = 0;
1235 cmap = Fcons (Fcons (build_string (name),
1236 make_number (RGB (red, green, blue))),
1237 cmap);
1238 }
1239 }
1240 fclose (fp);
1241
1242 UNBLOCK_INPUT;
1243 }
1244
1245 return cmap;
1246}
ee78dc32 1247
fbd6baed 1248/* The default colors for the w32 color map */
ee78dc32
GV
1249typedef struct colormap_t
1250{
1251 char *name;
1252 COLORREF colorref;
1253} colormap_t;
1254
fbd6baed 1255colormap_t w32_color_map[] =
ee78dc32 1256{
1da8a614
GV
1257 {"snow" , PALETTERGB (255,250,250)},
1258 {"ghost white" , PALETTERGB (248,248,255)},
1259 {"GhostWhite" , PALETTERGB (248,248,255)},
1260 {"white smoke" , PALETTERGB (245,245,245)},
1261 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1262 {"gainsboro" , PALETTERGB (220,220,220)},
1263 {"floral white" , PALETTERGB (255,250,240)},
1264 {"FloralWhite" , PALETTERGB (255,250,240)},
1265 {"old lace" , PALETTERGB (253,245,230)},
1266 {"OldLace" , PALETTERGB (253,245,230)},
1267 {"linen" , PALETTERGB (250,240,230)},
1268 {"antique white" , PALETTERGB (250,235,215)},
1269 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1270 {"papaya whip" , PALETTERGB (255,239,213)},
1271 {"PapayaWhip" , PALETTERGB (255,239,213)},
1272 {"blanched almond" , PALETTERGB (255,235,205)},
1273 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1274 {"bisque" , PALETTERGB (255,228,196)},
1275 {"peach puff" , PALETTERGB (255,218,185)},
1276 {"PeachPuff" , PALETTERGB (255,218,185)},
1277 {"navajo white" , PALETTERGB (255,222,173)},
1278 {"NavajoWhite" , PALETTERGB (255,222,173)},
1279 {"moccasin" , PALETTERGB (255,228,181)},
1280 {"cornsilk" , PALETTERGB (255,248,220)},
1281 {"ivory" , PALETTERGB (255,255,240)},
1282 {"lemon chiffon" , PALETTERGB (255,250,205)},
1283 {"LemonChiffon" , PALETTERGB (255,250,205)},
1284 {"seashell" , PALETTERGB (255,245,238)},
1285 {"honeydew" , PALETTERGB (240,255,240)},
1286 {"mint cream" , PALETTERGB (245,255,250)},
1287 {"MintCream" , PALETTERGB (245,255,250)},
1288 {"azure" , PALETTERGB (240,255,255)},
1289 {"alice blue" , PALETTERGB (240,248,255)},
1290 {"AliceBlue" , PALETTERGB (240,248,255)},
1291 {"lavender" , PALETTERGB (230,230,250)},
1292 {"lavender blush" , PALETTERGB (255,240,245)},
1293 {"LavenderBlush" , PALETTERGB (255,240,245)},
1294 {"misty rose" , PALETTERGB (255,228,225)},
1295 {"MistyRose" , PALETTERGB (255,228,225)},
1296 {"white" , PALETTERGB (255,255,255)},
1297 {"black" , PALETTERGB ( 0, 0, 0)},
1298 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1299 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1300 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1301 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1302 {"dim gray" , PALETTERGB (105,105,105)},
1303 {"DimGray" , PALETTERGB (105,105,105)},
1304 {"dim grey" , PALETTERGB (105,105,105)},
1305 {"DimGrey" , PALETTERGB (105,105,105)},
1306 {"slate gray" , PALETTERGB (112,128,144)},
1307 {"SlateGray" , PALETTERGB (112,128,144)},
1308 {"slate grey" , PALETTERGB (112,128,144)},
1309 {"SlateGrey" , PALETTERGB (112,128,144)},
1310 {"light slate gray" , PALETTERGB (119,136,153)},
1311 {"LightSlateGray" , PALETTERGB (119,136,153)},
1312 {"light slate grey" , PALETTERGB (119,136,153)},
1313 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1314 {"gray" , PALETTERGB (190,190,190)},
1315 {"grey" , PALETTERGB (190,190,190)},
1316 {"light grey" , PALETTERGB (211,211,211)},
1317 {"LightGrey" , PALETTERGB (211,211,211)},
1318 {"light gray" , PALETTERGB (211,211,211)},
1319 {"LightGray" , PALETTERGB (211,211,211)},
1320 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1321 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1322 {"navy" , PALETTERGB ( 0, 0,128)},
1323 {"navy blue" , PALETTERGB ( 0, 0,128)},
1324 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1325 {"cornflower blue" , PALETTERGB (100,149,237)},
1326 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1327 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1328 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1329 {"slate blue" , PALETTERGB (106, 90,205)},
1330 {"SlateBlue" , PALETTERGB (106, 90,205)},
1331 {"medium slate blue" , PALETTERGB (123,104,238)},
1332 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1333 {"light slate blue" , PALETTERGB (132,112,255)},
1334 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1335 {"medium blue" , PALETTERGB ( 0, 0,205)},
1336 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1337 {"royal blue" , PALETTERGB ( 65,105,225)},
1338 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1339 {"blue" , PALETTERGB ( 0, 0,255)},
1340 {"dodger blue" , PALETTERGB ( 30,144,255)},
1341 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1342 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1343 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1344 {"sky blue" , PALETTERGB (135,206,235)},
1345 {"SkyBlue" , PALETTERGB (135,206,235)},
1346 {"light sky blue" , PALETTERGB (135,206,250)},
1347 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1348 {"steel blue" , PALETTERGB ( 70,130,180)},
1349 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1350 {"light steel blue" , PALETTERGB (176,196,222)},
1351 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1352 {"light blue" , PALETTERGB (173,216,230)},
1353 {"LightBlue" , PALETTERGB (173,216,230)},
1354 {"powder blue" , PALETTERGB (176,224,230)},
1355 {"PowderBlue" , PALETTERGB (176,224,230)},
1356 {"pale turquoise" , PALETTERGB (175,238,238)},
1357 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1358 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1359 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1360 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1361 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1362 {"turquoise" , PALETTERGB ( 64,224,208)},
1363 {"cyan" , PALETTERGB ( 0,255,255)},
1364 {"light cyan" , PALETTERGB (224,255,255)},
1365 {"LightCyan" , PALETTERGB (224,255,255)},
1366 {"cadet blue" , PALETTERGB ( 95,158,160)},
1367 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1368 {"medium aquamarine" , PALETTERGB (102,205,170)},
1369 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1370 {"aquamarine" , PALETTERGB (127,255,212)},
1371 {"dark green" , PALETTERGB ( 0,100, 0)},
1372 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1373 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1374 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1375 {"dark sea green" , PALETTERGB (143,188,143)},
1376 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1377 {"sea green" , PALETTERGB ( 46,139, 87)},
1378 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1379 {"medium sea green" , PALETTERGB ( 60,179,113)},
1380 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1381 {"light sea green" , PALETTERGB ( 32,178,170)},
1382 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1383 {"pale green" , PALETTERGB (152,251,152)},
1384 {"PaleGreen" , PALETTERGB (152,251,152)},
1385 {"spring green" , PALETTERGB ( 0,255,127)},
1386 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1387 {"lawn green" , PALETTERGB (124,252, 0)},
1388 {"LawnGreen" , PALETTERGB (124,252, 0)},
1389 {"green" , PALETTERGB ( 0,255, 0)},
1390 {"chartreuse" , PALETTERGB (127,255, 0)},
1391 {"medium spring green" , PALETTERGB ( 0,250,154)},
1392 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1393 {"green yellow" , PALETTERGB (173,255, 47)},
1394 {"GreenYellow" , PALETTERGB (173,255, 47)},
1395 {"lime green" , PALETTERGB ( 50,205, 50)},
1396 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1397 {"yellow green" , PALETTERGB (154,205, 50)},
1398 {"YellowGreen" , PALETTERGB (154,205, 50)},
1399 {"forest green" , PALETTERGB ( 34,139, 34)},
1400 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1401 {"olive drab" , PALETTERGB (107,142, 35)},
1402 {"OliveDrab" , PALETTERGB (107,142, 35)},
1403 {"dark khaki" , PALETTERGB (189,183,107)},
1404 {"DarkKhaki" , PALETTERGB (189,183,107)},
1405 {"khaki" , PALETTERGB (240,230,140)},
1406 {"pale goldenrod" , PALETTERGB (238,232,170)},
1407 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1408 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1409 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1410 {"light yellow" , PALETTERGB (255,255,224)},
1411 {"LightYellow" , PALETTERGB (255,255,224)},
1412 {"yellow" , PALETTERGB (255,255, 0)},
1413 {"gold" , PALETTERGB (255,215, 0)},
1414 {"light goldenrod" , PALETTERGB (238,221,130)},
1415 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1416 {"goldenrod" , PALETTERGB (218,165, 32)},
1417 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1418 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1419 {"rosy brown" , PALETTERGB (188,143,143)},
1420 {"RosyBrown" , PALETTERGB (188,143,143)},
1421 {"indian red" , PALETTERGB (205, 92, 92)},
1422 {"IndianRed" , PALETTERGB (205, 92, 92)},
1423 {"saddle brown" , PALETTERGB (139, 69, 19)},
1424 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1425 {"sienna" , PALETTERGB (160, 82, 45)},
1426 {"peru" , PALETTERGB (205,133, 63)},
1427 {"burlywood" , PALETTERGB (222,184,135)},
1428 {"beige" , PALETTERGB (245,245,220)},
1429 {"wheat" , PALETTERGB (245,222,179)},
1430 {"sandy brown" , PALETTERGB (244,164, 96)},
1431 {"SandyBrown" , PALETTERGB (244,164, 96)},
1432 {"tan" , PALETTERGB (210,180,140)},
1433 {"chocolate" , PALETTERGB (210,105, 30)},
1434 {"firebrick" , PALETTERGB (178,34, 34)},
1435 {"brown" , PALETTERGB (165,42, 42)},
1436 {"dark salmon" , PALETTERGB (233,150,122)},
1437 {"DarkSalmon" , PALETTERGB (233,150,122)},
1438 {"salmon" , PALETTERGB (250,128,114)},
1439 {"light salmon" , PALETTERGB (255,160,122)},
1440 {"LightSalmon" , PALETTERGB (255,160,122)},
1441 {"orange" , PALETTERGB (255,165, 0)},
1442 {"dark orange" , PALETTERGB (255,140, 0)},
1443 {"DarkOrange" , PALETTERGB (255,140, 0)},
1444 {"coral" , PALETTERGB (255,127, 80)},
1445 {"light coral" , PALETTERGB (240,128,128)},
1446 {"LightCoral" , PALETTERGB (240,128,128)},
1447 {"tomato" , PALETTERGB (255, 99, 71)},
1448 {"orange red" , PALETTERGB (255, 69, 0)},
1449 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1450 {"red" , PALETTERGB (255, 0, 0)},
1451 {"hot pink" , PALETTERGB (255,105,180)},
1452 {"HotPink" , PALETTERGB (255,105,180)},
1453 {"deep pink" , PALETTERGB (255, 20,147)},
1454 {"DeepPink" , PALETTERGB (255, 20,147)},
1455 {"pink" , PALETTERGB (255,192,203)},
1456 {"light pink" , PALETTERGB (255,182,193)},
1457 {"LightPink" , PALETTERGB (255,182,193)},
1458 {"pale violet red" , PALETTERGB (219,112,147)},
1459 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1460 {"maroon" , PALETTERGB (176, 48, 96)},
1461 {"medium violet red" , PALETTERGB (199, 21,133)},
1462 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1463 {"violet red" , PALETTERGB (208, 32,144)},
1464 {"VioletRed" , PALETTERGB (208, 32,144)},
1465 {"magenta" , PALETTERGB (255, 0,255)},
1466 {"violet" , PALETTERGB (238,130,238)},
1467 {"plum" , PALETTERGB (221,160,221)},
1468 {"orchid" , PALETTERGB (218,112,214)},
1469 {"medium orchid" , PALETTERGB (186, 85,211)},
1470 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1471 {"dark orchid" , PALETTERGB (153, 50,204)},
1472 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1473 {"dark violet" , PALETTERGB (148, 0,211)},
1474 {"DarkViolet" , PALETTERGB (148, 0,211)},
1475 {"blue violet" , PALETTERGB (138, 43,226)},
1476 {"BlueViolet" , PALETTERGB (138, 43,226)},
1477 {"purple" , PALETTERGB (160, 32,240)},
1478 {"medium purple" , PALETTERGB (147,112,219)},
1479 {"MediumPurple" , PALETTERGB (147,112,219)},
1480 {"thistle" , PALETTERGB (216,191,216)},
1481 {"gray0" , PALETTERGB ( 0, 0, 0)},
1482 {"grey0" , PALETTERGB ( 0, 0, 0)},
1483 {"dark grey" , PALETTERGB (169,169,169)},
1484 {"DarkGrey" , PALETTERGB (169,169,169)},
1485 {"dark gray" , PALETTERGB (169,169,169)},
1486 {"DarkGray" , PALETTERGB (169,169,169)},
1487 {"dark blue" , PALETTERGB ( 0, 0,139)},
1488 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1489 {"dark cyan" , PALETTERGB ( 0,139,139)},
1490 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1491 {"dark magenta" , PALETTERGB (139, 0,139)},
1492 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1493 {"dark red" , PALETTERGB (139, 0, 0)},
1494 {"DarkRed" , PALETTERGB (139, 0, 0)},
1495 {"light green" , PALETTERGB (144,238,144)},
1496 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1497};
1498
fbd6baed 1499DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1500 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1501 ()
1502{
1503 int i;
fbd6baed 1504 colormap_t *pc = w32_color_map;
ee78dc32
GV
1505 Lisp_Object cmap;
1506
1507 BLOCK_INPUT;
1508
1509 cmap = Qnil;
1510
fbd6baed 1511 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1512 pc++, i++)
1513 cmap = Fcons (Fcons (build_string (pc->name),
1514 make_number (pc->colorref)),
1515 cmap);
1516
1517 UNBLOCK_INPUT;
1518
1519 return (cmap);
1520}
ee78dc32
GV
1521
1522Lisp_Object
fbd6baed 1523w32_to_x_color (rgb)
ee78dc32
GV
1524 Lisp_Object rgb;
1525{
1526 Lisp_Object color;
1527
b7826503 1528 CHECK_NUMBER (rgb);
ee78dc32
GV
1529
1530 BLOCK_INPUT;
1531
fbd6baed 1532 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1533
1534 UNBLOCK_INPUT;
1535
1536 if (!NILP (color))
1537 return (Fcar (color));
1538 else
1539 return Qnil;
1540}
1541
5d7fed93
GV
1542COLORREF
1543w32_color_map_lookup (colorname)
1544 char *colorname;
1545{
1546 Lisp_Object tail, ret = Qnil;
1547
1548 BLOCK_INPUT;
1549
1550 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1551 {
1552 register Lisp_Object elt, tem;
1553
1554 elt = Fcar (tail);
1555 if (!CONSP (elt)) continue;
1556
1557 tem = Fcar (elt);
1558
1559 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1560 {
1561 ret = XUINT (Fcdr (elt));
1562 break;
1563 }
1564
1565 QUIT;
1566 }
1567
1568
1569 UNBLOCK_INPUT;
1570
1571 return ret;
1572}
1573
ee78dc32 1574COLORREF
fbd6baed 1575x_to_w32_color (colorname)
ee78dc32
GV
1576 char * colorname;
1577{
8edb0a6f
JR
1578 register Lisp_Object ret = Qnil;
1579
ee78dc32 1580 BLOCK_INPUT;
1edf84e7
GV
1581
1582 if (colorname[0] == '#')
1583 {
1584 /* Could be an old-style RGB Device specification. */
1585 char *color;
1586 int size;
1587 color = colorname + 1;
1588
1589 size = strlen(color);
1590 if (size == 3 || size == 6 || size == 9 || size == 12)
1591 {
1592 UINT colorval;
1593 int i, pos;
1594 pos = 0;
1595 size /= 3;
1596 colorval = 0;
1597
1598 for (i = 0; i < 3; i++)
1599 {
1600 char *end;
1601 char t;
1602 unsigned long value;
1603
1604 /* The check for 'x' in the following conditional takes into
1605 account the fact that strtol allows a "0x" in front of
1606 our numbers, and we don't. */
1607 if (!isxdigit(color[0]) || color[1] == 'x')
1608 break;
1609 t = color[size];
1610 color[size] = '\0';
1611 value = strtoul(color, &end, 16);
1612 color[size] = t;
1613 if (errno == ERANGE || end - color != size)
1614 break;
1615 switch (size)
1616 {
1617 case 1:
1618 value = value * 0x10;
1619 break;
1620 case 2:
1621 break;
1622 case 3:
1623 value /= 0x10;
1624 break;
1625 case 4:
1626 value /= 0x100;
1627 break;
1628 }
1629 colorval |= (value << pos);
1630 pos += 0x8;
1631 if (i == 2)
1632 {
1633 UNBLOCK_INPUT;
1634 return (colorval);
1635 }
1636 color = end;
1637 }
1638 }
1639 }
1640 else if (strnicmp(colorname, "rgb:", 4) == 0)
1641 {
1642 char *color;
1643 UINT colorval;
1644 int i, pos;
1645 pos = 0;
1646
1647 colorval = 0;
1648 color = colorname + 4;
1649 for (i = 0; i < 3; i++)
1650 {
1651 char *end;
1652 unsigned long value;
1653
1654 /* The check for 'x' in the following conditional takes into
1655 account the fact that strtol allows a "0x" in front of
1656 our numbers, and we don't. */
1657 if (!isxdigit(color[0]) || color[1] == 'x')
1658 break;
1659 value = strtoul(color, &end, 16);
1660 if (errno == ERANGE)
1661 break;
1662 switch (end - color)
1663 {
1664 case 1:
1665 value = value * 0x10 + value;
1666 break;
1667 case 2:
1668 break;
1669 case 3:
1670 value /= 0x10;
1671 break;
1672 case 4:
1673 value /= 0x100;
1674 break;
1675 default:
1676 value = ULONG_MAX;
1677 }
1678 if (value == ULONG_MAX)
1679 break;
1680 colorval |= (value << pos);
1681 pos += 0x8;
1682 if (i == 2)
1683 {
1684 if (*end != '\0')
1685 break;
1686 UNBLOCK_INPUT;
1687 return (colorval);
1688 }
1689 if (*end != '/')
1690 break;
1691 color = end + 1;
1692 }
1693 }
1694 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1695 {
1696 /* This is an RGB Intensity specification. */
1697 char *color;
1698 UINT colorval;
1699 int i, pos;
1700 pos = 0;
1701
1702 colorval = 0;
1703 color = colorname + 5;
1704 for (i = 0; i < 3; i++)
1705 {
1706 char *end;
1707 double value;
1708 UINT val;
1709
1710 value = strtod(color, &end);
1711 if (errno == ERANGE)
1712 break;
1713 if (value < 0.0 || value > 1.0)
1714 break;
1715 val = (UINT)(0x100 * value);
1716 /* We used 0x100 instead of 0xFF to give an continuous
1717 range between 0.0 and 1.0 inclusive. The next statement
1718 fixes the 1.0 case. */
1719 if (val == 0x100)
1720 val = 0xFF;
1721 colorval |= (val << pos);
1722 pos += 0x8;
1723 if (i == 2)
1724 {
1725 if (*end != '\0')
1726 break;
1727 UNBLOCK_INPUT;
1728 return (colorval);
1729 }
1730 if (*end != '/')
1731 break;
1732 color = end + 1;
1733 }
1734 }
1735 /* I am not going to attempt to handle any of the CIE color schemes
1736 or TekHVC, since I don't know the algorithms for conversion to
1737 RGB. */
f695b4b1
GV
1738
1739 /* If we fail to lookup the color name in w32_color_map, then check the
1740 colorname to see if it can be crudely approximated: If the X color
1741 ends in a number (e.g., "darkseagreen2"), strip the number and
1742 return the result of looking up the base color name. */
1743 ret = w32_color_map_lookup (colorname);
1744 if (NILP (ret))
ee78dc32 1745 {
f695b4b1 1746 int len = strlen (colorname);
ee78dc32 1747
f695b4b1
GV
1748 if (isdigit (colorname[len - 1]))
1749 {
8b77111c 1750 char *ptr, *approx = alloca (len + 1);
ee78dc32 1751
f695b4b1
GV
1752 strcpy (approx, colorname);
1753 ptr = &approx[len - 1];
1754 while (ptr > approx && isdigit (*ptr))
1755 *ptr-- = '\0';
ee78dc32 1756
f695b4b1 1757 ret = w32_color_map_lookup (approx);
ee78dc32 1758 }
ee78dc32
GV
1759 }
1760
1761 UNBLOCK_INPUT;
ee78dc32
GV
1762 return ret;
1763}
1764
5ac45f98
GV
1765
1766void
fbd6baed 1767w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1768{
fbd6baed 1769 struct w32_palette_entry * list;
5ac45f98
GV
1770 LOGPALETTE * log_palette;
1771 HPALETTE new_palette;
1772 int i;
1773
1774 /* don't bother trying to create palette if not supported */
fbd6baed 1775 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1776 return;
1777
1778 log_palette = (LOGPALETTE *)
1779 alloca (sizeof (LOGPALETTE) +
fbd6baed 1780 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1781 log_palette->palVersion = 0x300;
fbd6baed 1782 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1783
fbd6baed 1784 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1785 for (i = 0;
fbd6baed 1786 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1787 i++, list = list->next)
1788 log_palette->palPalEntry[i] = list->entry;
1789
1790 new_palette = CreatePalette (log_palette);
1791
1792 enter_crit ();
1793
fbd6baed
GV
1794 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1795 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1796 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1797
1798 /* Realize display palette and garbage all frames. */
1799 release_frame_dc (f, get_frame_dc (f));
1800
1801 leave_crit ();
1802}
1803
fbd6baed
GV
1804#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1805#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1806 do \
1807 { \
1808 pe.peRed = GetRValue (color); \
1809 pe.peGreen = GetGValue (color); \
1810 pe.peBlue = GetBValue (color); \
1811 pe.peFlags = 0; \
1812 } while (0)
1813
1814#if 0
1815/* Keep these around in case we ever want to track color usage. */
1816void
fbd6baed 1817w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1818{
fbd6baed 1819 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1820
fbd6baed 1821 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1822 return;
1823
1824 /* check if color is already mapped */
1825 while (list)
1826 {
fbd6baed 1827 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1828 {
1829 ++list->refcount;
1830 return;
1831 }
1832 list = list->next;
1833 }
1834
1835 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1836 list = (struct w32_palette_entry *)
1837 xmalloc (sizeof (struct w32_palette_entry));
1838 SET_W32_COLOR (list->entry, color);
5ac45f98 1839 list->refcount = 1;
fbd6baed
GV
1840 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1841 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1842 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1843
1844 /* set flag that palette must be regenerated */
fbd6baed 1845 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1846}
1847
1848void
fbd6baed 1849w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1850{
fbd6baed
GV
1851 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1852 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1853
fbd6baed 1854 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1855 return;
1856
1857 /* check if color is already mapped */
1858 while (list)
1859 {
fbd6baed 1860 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1861 {
1862 if (--list->refcount == 0)
1863 {
1864 *prev = list->next;
1865 xfree (list);
fbd6baed 1866 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1867 break;
1868 }
1869 else
1870 return;
1871 }
1872 prev = &list->next;
1873 list = list->next;
1874 }
1875
1876 /* set flag that palette must be regenerated */
fbd6baed 1877 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1878}
1879#endif
1880
6fc2811b
JR
1881
1882/* Gamma-correct COLOR on frame F. */
1883
1884void
1885gamma_correct (f, color)
1886 struct frame *f;
1887 COLORREF *color;
1888{
1889 if (f->gamma)
1890 {
1891 *color = PALETTERGB (
1892 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1893 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1894 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1895 }
1896}
1897
1898
ee78dc32
GV
1899/* Decide if color named COLOR is valid for the display associated with
1900 the selected frame; if so, return the rgb values in COLOR_DEF.
1901 If ALLOC is nonzero, allocate a new colormap cell. */
1902
1903int
6fc2811b 1904w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1905 FRAME_PTR f;
1906 char *color;
6fc2811b 1907 XColor *color_def;
ee78dc32
GV
1908 int alloc;
1909{
1910 register Lisp_Object tem;
6fc2811b 1911 COLORREF w32_color_ref;
3c190163 1912
fbd6baed 1913 tem = x_to_w32_color (color);
3c190163 1914
ee78dc32
GV
1915 if (!NILP (tem))
1916 {
d88c567c
JR
1917 if (f)
1918 {
1919 /* Apply gamma correction. */
1920 w32_color_ref = XUINT (tem);
1921 gamma_correct (f, &w32_color_ref);
1922 XSETINT (tem, w32_color_ref);
1923 }
9badad41
JR
1924
1925 /* Map this color to the palette if it is enabled. */
fbd6baed 1926 if (!NILP (Vw32_enable_palette))
5ac45f98 1927 {
fbd6baed 1928 struct w32_palette_entry * entry =
d88c567c 1929 one_w32_display_info.color_list;
fbd6baed 1930 struct w32_palette_entry ** prev =
d88c567c 1931 &one_w32_display_info.color_list;
5ac45f98
GV
1932
1933 /* check if color is already mapped */
1934 while (entry)
1935 {
fbd6baed 1936 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1937 break;
1938 prev = &entry->next;
1939 entry = entry->next;
1940 }
1941
1942 if (entry == NULL && alloc)
1943 {
1944 /* not already mapped, so add to list */
fbd6baed
GV
1945 entry = (struct w32_palette_entry *)
1946 xmalloc (sizeof (struct w32_palette_entry));
1947 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1948 entry->next = NULL;
1949 *prev = entry;
d88c567c 1950 one_w32_display_info.num_colors++;
5ac45f98
GV
1951
1952 /* set flag that palette must be regenerated */
d88c567c 1953 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1954 }
1955 }
1956 /* Ensure COLORREF value is snapped to nearest color in (default)
1957 palette by simulating the PALETTERGB macro. This works whether
1958 or not the display device has a palette. */
6fc2811b
JR
1959 w32_color_ref = XUINT (tem) | 0x2000000;
1960
6fc2811b
JR
1961 color_def->pixel = w32_color_ref;
1962 color_def->red = GetRValue (w32_color_ref);
1963 color_def->green = GetGValue (w32_color_ref);
1964 color_def->blue = GetBValue (w32_color_ref);
1965
ee78dc32 1966 return 1;
5ac45f98 1967 }
7fb46567 1968 else
3c190163
GV
1969 {
1970 return 0;
1971 }
ee78dc32
GV
1972}
1973
1974/* Given a string ARG naming a color, compute a pixel value from it
1975 suitable for screen F.
1976 If F is not a color screen, return DEF (default) regardless of what
1977 ARG says. */
1978
1979int
1980x_decode_color (f, arg, def)
1981 FRAME_PTR f;
1982 Lisp_Object arg;
1983 int def;
1984{
6fc2811b 1985 XColor cdef;
ee78dc32 1986
b7826503 1987 CHECK_STRING (arg);
ee78dc32
GV
1988
1989 if (strcmp (XSTRING (arg)->data, "black") == 0)
1990 return BLACK_PIX_DEFAULT (f);
1991 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1992 return WHITE_PIX_DEFAULT (f);
1993
fbd6baed 1994 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1995 return def;
1996
6fc2811b 1997 /* w32_defined_color is responsible for coping with failures
ee78dc32 1998 by looking for a near-miss. */
6fc2811b
JR
1999 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
2000 return cdef.pixel;
ee78dc32
GV
2001
2002 /* defined_color failed; return an ultimate default. */
2003 return def;
2004}
2005\f
dfff8a69
JR
2006/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2007 the previous value of that parameter, NEW_VALUE is the new value. */
2008
2009static void
2010x_set_line_spacing (f, new_value, old_value)
2011 struct frame *f;
2012 Lisp_Object new_value, old_value;
2013{
2014 if (NILP (new_value))
2015 f->extra_line_spacing = 0;
2016 else if (NATNUMP (new_value))
2017 f->extra_line_spacing = XFASTINT (new_value);
2018 else
1a948b17 2019 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
2020 Fcons (new_value, Qnil)));
2021 if (FRAME_VISIBLE_P (f))
2022 redraw_frame (f);
2023}
2024
2025
f7b9d4d1
JR
2026/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2027 the previous value of that parameter, NEW_VALUE is the new value. */
2028
2029static void
2030x_set_fullscreen (f, new_value, old_value)
2031 struct frame *f;
2032 Lisp_Object new_value, old_value;
2033{
2034 if (NILP (new_value))
2035 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2036 else if (EQ (new_value, Qfullboth))
2037 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2038 else if (EQ (new_value, Qfullwidth))
2039 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2040 else if (EQ (new_value, Qfullheight))
2041 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2042}
2043
2044
6fc2811b
JR
2045/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2046 the previous value of that parameter, NEW_VALUE is the new value. */
2047
2048static void
2049x_set_screen_gamma (f, new_value, old_value)
2050 struct frame *f;
2051 Lisp_Object new_value, old_value;
2052{
2053 if (NILP (new_value))
2054 f->gamma = 0;
2055 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2056 /* The value 0.4545 is the normal viewing gamma. */
2057 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2058 else
1a948b17 2059 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
2060 Fcons (new_value, Qnil)));
2061
2062 clear_face_cache (0);
2063}
2064
2065
ee78dc32
GV
2066/* Functions called only from `x_set_frame_param'
2067 to set individual parameters.
2068
fbd6baed 2069 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
2070 the frame is being created and its window does not exist yet.
2071 In that case, just record the parameter's new value
2072 in the standard place; do not attempt to change the window. */
2073
2074void
2075x_set_foreground_color (f, arg, oldval)
2076 struct frame *f;
2077 Lisp_Object arg, oldval;
2078{
3cf3436e
JR
2079 struct w32_output *x = f->output_data.w32;
2080 PIX_TYPE fg, old_fg;
2081
2082 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2083 old_fg = FRAME_FOREGROUND_PIXEL (f);
2084 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2085
fbd6baed 2086 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2087 {
3cf3436e
JR
2088 if (x->cursor_pixel == old_fg)
2089 x->cursor_pixel = fg;
2090
6fc2811b 2091 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2092 if (FRAME_VISIBLE_P (f))
2093 redraw_frame (f);
2094 }
2095}
2096
2097void
2098x_set_background_color (f, arg, oldval)
2099 struct frame *f;
2100 Lisp_Object arg, oldval;
2101{
6fc2811b 2102 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2103 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2104
fbd6baed 2105 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2106 {
6fc2811b
JR
2107 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2108 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2109
6fc2811b 2110 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2111
2112 if (FRAME_VISIBLE_P (f))
2113 redraw_frame (f);
2114 }
2115}
2116
2117void
2118x_set_mouse_color (f, arg, oldval)
2119 struct frame *f;
2120 Lisp_Object arg, oldval;
2121{
ee78dc32 2122 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2123 int count;
ee78dc32
GV
2124 int mask_color;
2125
2126 if (!EQ (Qnil, arg))
fbd6baed 2127 f->output_data.w32->mouse_pixel
ee78dc32 2128 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2129 mask_color = FRAME_BACKGROUND_PIXEL (f);
2130
2131 /* Don't let pointers be invisible. */
fbd6baed 2132 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2133 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2134 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2135
767b1ff0 2136#if 0 /* TODO : cursor changes */
ee78dc32
GV
2137 BLOCK_INPUT;
2138
2139 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2140 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2141
2142 if (!EQ (Qnil, Vx_pointer_shape))
2143 {
b7826503 2144 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2145 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2146 }
2147 else
fbd6baed
GV
2148 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2149 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2150
2151 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2152 {
b7826503 2153 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2154 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2155 XINT (Vx_nontext_pointer_shape));
2156 }
2157 else
fbd6baed
GV
2158 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2159 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2160
0af913d7 2161 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2162 {
b7826503 2163 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2164 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2165 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2166 }
2167 else
0af913d7 2168 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b
JR
2169 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2170
2171 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2172 if (!EQ (Qnil, Vx_mode_pointer_shape))
2173 {
b7826503 2174 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2175 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2176 XINT (Vx_mode_pointer_shape));
2177 }
2178 else
fbd6baed
GV
2179 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2180 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2181
2182 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2183 {
b7826503 2184 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2185 cross_cursor
fbd6baed 2186 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2187 XINT (Vx_sensitive_text_pointer_shape));
2188 }
2189 else
fbd6baed 2190 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2191
4694d762
JR
2192 if (!NILP (Vx_window_horizontal_drag_shape))
2193 {
b7826503 2194 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2195 horizontal_drag_cursor
2196 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2197 XINT (Vx_window_horizontal_drag_shape));
2198 }
2199 else
2200 horizontal_drag_cursor
2201 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2202
ee78dc32 2203 /* Check and report errors with the above calls. */
fbd6baed 2204 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2205 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2206
2207 {
2208 XColor fore_color, back_color;
2209
fbd6baed 2210 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2211 back_color.pixel = mask_color;
fbd6baed
GV
2212 XQueryColor (FRAME_W32_DISPLAY (f),
2213 DefaultColormap (FRAME_W32_DISPLAY (f),
2214 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2215 &fore_color);
fbd6baed
GV
2216 XQueryColor (FRAME_W32_DISPLAY (f),
2217 DefaultColormap (FRAME_W32_DISPLAY (f),
2218 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2219 &back_color);
fbd6baed 2220 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2221 &fore_color, &back_color);
fbd6baed 2222 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2223 &fore_color, &back_color);
fbd6baed 2224 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2225 &fore_color, &back_color);
fbd6baed 2226 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2227 &fore_color, &back_color);
0af913d7 2228 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2229 &fore_color, &back_color);
ee78dc32
GV
2230 }
2231
fbd6baed 2232 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2233 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2234
fbd6baed
GV
2235 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2236 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2237 f->output_data.w32->text_cursor = cursor;
2238
2239 if (nontext_cursor != f->output_data.w32->nontext_cursor
2240 && f->output_data.w32->nontext_cursor != 0)
2241 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2242 f->output_data.w32->nontext_cursor = nontext_cursor;
2243
0af913d7
GM
2244 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2245 && f->output_data.w32->hourglass_cursor != 0)
2246 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2247 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2248
fbd6baed
GV
2249 if (mode_cursor != f->output_data.w32->modeline_cursor
2250 && f->output_data.w32->modeline_cursor != 0)
2251 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2252 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2253
fbd6baed
GV
2254 if (cross_cursor != f->output_data.w32->cross_cursor
2255 && f->output_data.w32->cross_cursor != 0)
2256 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2257 f->output_data.w32->cross_cursor = cross_cursor;
2258
2259 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2260 UNBLOCK_INPUT;
6fc2811b
JR
2261
2262 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2263#endif /* TODO */
ee78dc32
GV
2264}
2265
70a0239a
JR
2266/* Defined in w32term.c. */
2267void x_update_cursor (struct frame *f, int on_p);
2268
ee78dc32
GV
2269void
2270x_set_cursor_color (f, arg, oldval)
2271 struct frame *f;
2272 Lisp_Object arg, oldval;
2273{
70a0239a 2274 unsigned long fore_pixel, pixel;
ee78dc32 2275
dfff8a69 2276 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2277 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2278 WHITE_PIX_DEFAULT (f));
ee78dc32 2279 else
6fc2811b 2280 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2281
6759f872 2282 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2283
2284 /* Make sure that the cursor color differs from the background color. */
70a0239a 2285 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2286 {
70a0239a
JR
2287 pixel = f->output_data.w32->mouse_pixel;
2288 if (pixel == fore_pixel)
6fc2811b 2289 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2290 }
70a0239a 2291
ac849ba4 2292 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
70a0239a 2293 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2294
fbd6baed 2295 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2296 {
0327b4cc
JR
2297 BLOCK_INPUT;
2298 /* Update frame's cursor_gc. */
2299 f->output_data.w32->cursor_gc->foreground = fore_pixel;
2300 f->output_data.w32->cursor_gc->background = pixel;
2301
2302 UNBLOCK_INPUT;
2303
ee78dc32
GV
2304 if (FRAME_VISIBLE_P (f))
2305 {
70a0239a
JR
2306 x_update_cursor (f, 0);
2307 x_update_cursor (f, 1);
ee78dc32
GV
2308 }
2309 }
6fc2811b
JR
2310
2311 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2312}
2313
33d52f9c
GV
2314/* Set the border-color of frame F to pixel value PIX.
2315 Note that this does not fully take effect if done before
2316 F has an window. */
2317void
2318x_set_border_pixel (f, pix)
2319 struct frame *f;
2320 int pix;
2321{
2322 f->output_data.w32->border_pixel = pix;
2323
2324 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2325 {
2326 if (FRAME_VISIBLE_P (f))
2327 redraw_frame (f);
2328 }
2329}
2330
ee78dc32
GV
2331/* Set the border-color of frame F to value described by ARG.
2332 ARG can be a string naming a color.
2333 The border-color is used for the border that is drawn by the server.
2334 Note that this does not fully take effect if done before
2335 F has a window; it must be redone when the window is created. */
2336
2337void
2338x_set_border_color (f, arg, oldval)
2339 struct frame *f;
2340 Lisp_Object arg, oldval;
2341{
ee78dc32
GV
2342 int pix;
2343
b7826503 2344 CHECK_STRING (arg);
ee78dc32 2345 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2346 x_set_border_pixel (f, pix);
6fc2811b 2347 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2348}
2349
dfff8a69
JR
2350/* Value is the internal representation of the specified cursor type
2351 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2352 of the bar cursor. */
2353
2354enum text_cursor_kinds
2355x_specified_cursor_type (arg, width)
2356 Lisp_Object arg;
2357 int *width;
ee78dc32 2358{
dfff8a69
JR
2359 enum text_cursor_kinds type;
2360
ee78dc32
GV
2361 if (EQ (arg, Qbar))
2362 {
dfff8a69
JR
2363 type = BAR_CURSOR;
2364 *width = 2;
ee78dc32 2365 }
dfff8a69
JR
2366 else if (CONSP (arg)
2367 && EQ (XCAR (arg), Qbar)
2368 && INTEGERP (XCDR (arg))
2369 && XINT (XCDR (arg)) >= 0)
ee78dc32 2370 {
dfff8a69
JR
2371 type = BAR_CURSOR;
2372 *width = XINT (XCDR (arg));
ee78dc32 2373 }
23afac8f
JR
2374 else if (EQ (arg, Qhbar))
2375 {
2376 type = HBAR_CURSOR;
2377 *width = 2;
2378 }
2379 else if (CONSP (arg)
2380 && EQ (XCAR (arg), Qhbar)
2381 && INTEGERP (XCDR (arg))
2382 && XINT (XCDR (arg)) >= 0)
2383 {
2384 type = HBAR_CURSOR;
2385 *width = XINT (XCDR (arg));
2386 }
dfff8a69
JR
2387 else if (NILP (arg))
2388 type = NO_CURSOR;
ee78dc32
GV
2389 else
2390 /* Treat anything unknown as "box cursor".
2391 It was bad to signal an error; people have trouble fixing
2392 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2393 type = FILLED_BOX_CURSOR;
2394
2395 return type;
2396}
2397
2398void
2399x_set_cursor_type (f, arg, oldval)
2400 FRAME_PTR f;
2401 Lisp_Object arg, oldval;
2402{
2403 int width;
2404
2405 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2406 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2407
2408 /* Make sure the cursor gets redrawn. This is overkill, but how
2409 often do people change cursor types? */
2410 update_mode_lines++;
2411}
dfff8a69 2412\f
ee78dc32
GV
2413void
2414x_set_icon_type (f, arg, oldval)
2415 struct frame *f;
2416 Lisp_Object arg, oldval;
2417{
ee78dc32
GV
2418 int result;
2419
eb7576ce
GV
2420 if (NILP (arg) && NILP (oldval))
2421 return;
2422
2423 if (STRINGP (arg) && STRINGP (oldval)
2424 && EQ (Fstring_equal (oldval, arg), Qt))
2425 return;
2426
2427 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2428 return;
2429
2430 BLOCK_INPUT;
ee78dc32 2431
eb7576ce 2432 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2433 if (result)
2434 {
2435 UNBLOCK_INPUT;
2436 error ("No icon window available");
2437 }
2438
ee78dc32 2439 UNBLOCK_INPUT;
ee78dc32
GV
2440}
2441
2442/* Return non-nil if frame F wants a bitmap icon. */
2443
2444Lisp_Object
2445x_icon_type (f)
2446 FRAME_PTR f;
2447{
2448 Lisp_Object tem;
2449
2450 tem = assq_no_quit (Qicon_type, f->param_alist);
2451 if (CONSP (tem))
8e713be6 2452 return XCDR (tem);
ee78dc32
GV
2453 else
2454 return Qnil;
2455}
2456
2457void
2458x_set_icon_name (f, arg, oldval)
2459 struct frame *f;
2460 Lisp_Object arg, oldval;
2461{
ee78dc32
GV
2462 if (STRINGP (arg))
2463 {
2464 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2465 return;
2466 }
2467 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2468 return;
2469
2470 f->icon_name = arg;
2471
2472#if 0
fbd6baed 2473 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2474 return;
2475
2476 BLOCK_INPUT;
2477
2478 result = x_text_icon (f,
1edf84e7 2479 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2480 ? f->icon_name
1edf84e7
GV
2481 : !NILP (f->title)
2482 ? f->title
ee78dc32
GV
2483 : f->name))->data);
2484
2485 if (result)
2486 {
2487 UNBLOCK_INPUT;
2488 error ("No icon window available");
2489 }
2490
2491 /* If the window was unmapped (and its icon was mapped),
2492 the new icon is not mapped, so map the window in its stead. */
2493 if (FRAME_VISIBLE_P (f))
2494 {
2495#ifdef USE_X_TOOLKIT
fbd6baed 2496 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2497#endif
fbd6baed 2498 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2499 }
2500
fbd6baed 2501 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2502 UNBLOCK_INPUT;
2503#endif
2504}
2505
2506extern Lisp_Object x_new_font ();
4587b026 2507extern Lisp_Object x_new_fontset();
ee78dc32
GV
2508
2509void
2510x_set_font (f, arg, oldval)
2511 struct frame *f;
2512 Lisp_Object arg, oldval;
2513{
2514 Lisp_Object result;
4587b026 2515 Lisp_Object fontset_name;
4b817373 2516 Lisp_Object frame;
3cf3436e 2517 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2518
b7826503 2519 CHECK_STRING (arg);
ee78dc32 2520
4587b026
GV
2521 fontset_name = Fquery_fontset (arg, Qnil);
2522
ee78dc32 2523 BLOCK_INPUT;
4587b026
GV
2524 result = (STRINGP (fontset_name)
2525 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2526 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2527 UNBLOCK_INPUT;
2528
2529 if (EQ (result, Qnil))
dfff8a69 2530 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2531 else if (EQ (result, Qt))
dfff8a69 2532 error ("The characters of the given font have varying widths");
ee78dc32
GV
2533 else if (STRINGP (result))
2534 {
3cf3436e
JR
2535 if (STRINGP (fontset_name))
2536 {
2537 /* Fontset names are built from ASCII font names, so the
2538 names may be equal despite there was a change. */
2539 if (old_fontset == FRAME_FONTSET (f))
2540 return;
2541 }
2542 else if (!NILP (Fequal (result, oldval)))
dc220243 2543 return;
3cf3436e 2544
ee78dc32 2545 store_frame_param (f, Qfont, result);
6fc2811b 2546 recompute_basic_faces (f);
ee78dc32
GV
2547 }
2548 else
2549 abort ();
4b817373 2550
6fc2811b
JR
2551 do_pending_window_change (0);
2552
2553 /* Don't call `face-set-after-frame-default' when faces haven't been
2554 initialized yet. This is the case when called from
2555 Fx_create_frame. In that case, the X widget or window doesn't
2556 exist either, and we can end up in x_report_frame_params with a
2557 null widget which gives a segfault. */
2558 if (FRAME_FACE_CACHE (f))
2559 {
2560 XSETFRAME (frame, f);
2561 call1 (Qface_set_after_frame_default, frame);
2562 }
ee78dc32
GV
2563}
2564
41c1bdd9
KS
2565static void
2566x_set_fringe_width (f, new_value, old_value)
2567 struct frame *f;
2568 Lisp_Object new_value, old_value;
2569{
2570 x_compute_fringe_widths (f, 1);
2571}
2572
ee78dc32
GV
2573void
2574x_set_border_width (f, arg, oldval)
2575 struct frame *f;
2576 Lisp_Object arg, oldval;
2577{
b7826503 2578 CHECK_NUMBER (arg);
ee78dc32 2579
fbd6baed 2580 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2581 return;
2582
fbd6baed 2583 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2584 error ("Cannot change the border width of a window");
2585
fbd6baed 2586 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2587}
2588
2589void
2590x_set_internal_border_width (f, arg, oldval)
2591 struct frame *f;
2592 Lisp_Object arg, oldval;
2593{
fbd6baed 2594 int old = f->output_data.w32->internal_border_width;
ee78dc32 2595
b7826503 2596 CHECK_NUMBER (arg);
fbd6baed
GV
2597 f->output_data.w32->internal_border_width = XINT (arg);
2598 if (f->output_data.w32->internal_border_width < 0)
2599 f->output_data.w32->internal_border_width = 0;
ee78dc32 2600
fbd6baed 2601 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2602 return;
2603
fbd6baed 2604 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2605 {
ee78dc32 2606 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2607 SET_FRAME_GARBAGED (f);
6fc2811b 2608 do_pending_window_change (0);
ee78dc32 2609 }
a05e2bae
JR
2610 else
2611 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2612}
2613
2614void
2615x_set_visibility (f, value, oldval)
2616 struct frame *f;
2617 Lisp_Object value, oldval;
2618{
2619 Lisp_Object frame;
2620 XSETFRAME (frame, f);
2621
2622 if (NILP (value))
2623 Fmake_frame_invisible (frame, Qt);
2624 else if (EQ (value, Qicon))
2625 Ficonify_frame (frame);
2626 else
2627 Fmake_frame_visible (frame);
2628}
2629
a1258667
JR
2630\f
2631/* Change window heights in windows rooted in WINDOW by N lines. */
2632
2633static void
2634x_change_window_heights (window, n)
2635 Lisp_Object window;
2636 int n;
2637{
2638 struct window *w = XWINDOW (window);
2639
2640 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2641 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2642
2643 if (INTEGERP (w->orig_top))
2644 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2645 if (INTEGERP (w->orig_height))
2646 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2647
2648 /* Handle just the top child in a vertical split. */
2649 if (!NILP (w->vchild))
2650 x_change_window_heights (w->vchild, n);
2651
2652 /* Adjust all children in a horizontal split. */
2653 for (window = w->hchild; !NILP (window); window = w->next)
2654 {
2655 w = XWINDOW (window);
2656 x_change_window_heights (window, n);
2657 }
2658}
2659
ee78dc32
GV
2660void
2661x_set_menu_bar_lines (f, value, oldval)
2662 struct frame *f;
2663 Lisp_Object value, oldval;
2664{
2665 int nlines;
2666 int olines = FRAME_MENU_BAR_LINES (f);
2667
2668 /* Right now, menu bars don't work properly in minibuf-only frames;
2669 most of the commands try to apply themselves to the minibuffer
6fc2811b 2670 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2671 in or split the minibuffer window. */
2672 if (FRAME_MINIBUF_ONLY_P (f))
2673 return;
2674
2675 if (INTEGERP (value))
2676 nlines = XINT (value);
2677 else
2678 nlines = 0;
2679
2680 FRAME_MENU_BAR_LINES (f) = 0;
2681 if (nlines)
2682 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2683 else
2684 {
2685 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2686 free_frame_menubar (f);
2687 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2688
2689 /* Adjust the frame size so that the client (text) dimensions
2690 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2691 set correctly. */
2692 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2693 do_pending_window_change (0);
ee78dc32 2694 }
6fc2811b
JR
2695 adjust_glyphs (f);
2696}
2697
2698
2699/* Set the number of lines used for the tool bar of frame F to VALUE.
2700 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2701 is the old number of tool bar lines. This function changes the
2702 height of all windows on frame F to match the new tool bar height.
2703 The frame's height doesn't change. */
2704
2705void
2706x_set_tool_bar_lines (f, value, oldval)
2707 struct frame *f;
2708 Lisp_Object value, oldval;
2709{
36f8209a
JR
2710 int delta, nlines, root_height;
2711 Lisp_Object root_window;
6fc2811b 2712
dc220243
JR
2713 /* Treat tool bars like menu bars. */
2714 if (FRAME_MINIBUF_ONLY_P (f))
2715 return;
2716
6fc2811b
JR
2717 /* Use VALUE only if an integer >= 0. */
2718 if (INTEGERP (value) && XINT (value) >= 0)
2719 nlines = XFASTINT (value);
2720 else
2721 nlines = 0;
2722
2723 /* Make sure we redisplay all windows in this frame. */
2724 ++windows_or_buffers_changed;
2725
2726 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2727
2728 /* Don't resize the tool-bar to more than we have room for. */
2729 root_window = FRAME_ROOT_WINDOW (f);
2730 root_height = XINT (XWINDOW (root_window)->height);
2731 if (root_height - delta < 1)
2732 {
2733 delta = root_height - 1;
2734 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2735 }
2736
6fc2811b 2737 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2738 x_change_window_heights (root_window, delta);
6fc2811b 2739 adjust_glyphs (f);
36f8209a
JR
2740
2741 /* We also have to make sure that the internal border at the top of
2742 the frame, below the menu bar or tool bar, is redrawn when the
2743 tool bar disappears. This is so because the internal border is
2744 below the tool bar if one is displayed, but is below the menu bar
2745 if there isn't a tool bar. The tool bar draws into the area
2746 below the menu bar. */
2747 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2748 {
2749 updating_frame = f;
2750 clear_frame ();
2751 clear_current_matrices (f);
2752 updating_frame = NULL;
2753 }
2754
2755 /* If the tool bar gets smaller, the internal border below it
2756 has to be cleared. It was formerly part of the display
2757 of the larger tool bar, and updating windows won't clear it. */
2758 if (delta < 0)
2759 {
2760 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2761 int width = PIXEL_WIDTH (f);
2762 int y = nlines * CANON_Y_UNIT (f);
2763
2764 BLOCK_INPUT;
2765 {
2766 HDC hdc = get_frame_dc (f);
2767 w32_clear_area (f, hdc, 0, y, width, height);
2768 release_frame_dc (f, hdc);
2769 }
2770 UNBLOCK_INPUT;
3cf3436e
JR
2771
2772 if (WINDOWP (f->tool_bar_window))
2773 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2774 }
ee78dc32
GV
2775}
2776
6fc2811b 2777
ee78dc32 2778/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2779 w32_id_name.
ee78dc32
GV
2780
2781 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2782 name; if NAME is a string, set F's name to NAME and set
2783 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2784
2785 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2786 suggesting a new name, which lisp code should override; if
2787 F->explicit_name is set, ignore the new name; otherwise, set it. */
2788
2789void
2790x_set_name (f, name, explicit)
2791 struct frame *f;
2792 Lisp_Object name;
2793 int explicit;
2794{
2795 /* Make sure that requests from lisp code override requests from
2796 Emacs redisplay code. */
2797 if (explicit)
2798 {
2799 /* If we're switching from explicit to implicit, we had better
2800 update the mode lines and thereby update the title. */
2801 if (f->explicit_name && NILP (name))
2802 update_mode_lines = 1;
2803
2804 f->explicit_name = ! NILP (name);
2805 }
2806 else if (f->explicit_name)
2807 return;
2808
fbd6baed 2809 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2810 if (NILP (name))
2811 {
2812 /* Check for no change needed in this very common case
2813 before we do any consing. */
fbd6baed 2814 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2815 XSTRING (f->name)->data))
2816 return;
fbd6baed 2817 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2818 }
2819 else
b7826503 2820 CHECK_STRING (name);
ee78dc32
GV
2821
2822 /* Don't change the name if it's already NAME. */
2823 if (! NILP (Fstring_equal (name, f->name)))
2824 return;
2825
1edf84e7
GV
2826 f->name = name;
2827
2828 /* For setting the frame title, the title parameter should override
2829 the name parameter. */
2830 if (! NILP (f->title))
2831 name = f->title;
2832
fbd6baed 2833 if (FRAME_W32_WINDOW (f))
ee78dc32 2834 {
6fc2811b 2835 if (STRING_MULTIBYTE (name))
dfff8a69 2836 name = ENCODE_SYSTEM (name);
6fc2811b 2837
ee78dc32 2838 BLOCK_INPUT;
fbd6baed 2839 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2840 UNBLOCK_INPUT;
2841 }
ee78dc32
GV
2842}
2843
2844/* This function should be called when the user's lisp code has
2845 specified a name for the frame; the name will override any set by the
2846 redisplay code. */
2847void
2848x_explicitly_set_name (f, arg, oldval)
2849 FRAME_PTR f;
2850 Lisp_Object arg, oldval;
2851{
2852 x_set_name (f, arg, 1);
2853}
2854
2855/* This function should be called by Emacs redisplay code to set the
2856 name; names set this way will never override names set by the user's
2857 lisp code. */
2858void
2859x_implicitly_set_name (f, arg, oldval)
2860 FRAME_PTR f;
2861 Lisp_Object arg, oldval;
2862{
2863 x_set_name (f, arg, 0);
2864}
1edf84e7
GV
2865\f
2866/* Change the title of frame F to NAME.
2867 If NAME is nil, use the frame name as the title.
2868
2869 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2870 name; if NAME is a string, set F's name to NAME and set
2871 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2872
2873 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2874 suggesting a new name, which lisp code should override; if
2875 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2876
1edf84e7 2877void
6fc2811b 2878x_set_title (f, name, old_name)
1edf84e7 2879 struct frame *f;
6fc2811b 2880 Lisp_Object name, old_name;
1edf84e7
GV
2881{
2882 /* Don't change the title if it's already NAME. */
2883 if (EQ (name, f->title))
2884 return;
2885
2886 update_mode_lines = 1;
2887
2888 f->title = name;
2889
2890 if (NILP (name))
2891 name = f->name;
2892
2893 if (FRAME_W32_WINDOW (f))
2894 {
6fc2811b 2895 if (STRING_MULTIBYTE (name))
dfff8a69 2896 name = ENCODE_SYSTEM (name);
6fc2811b 2897
1edf84e7
GV
2898 BLOCK_INPUT;
2899 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2900 UNBLOCK_INPUT;
2901 }
2902}
2903\f
ee78dc32
GV
2904void
2905x_set_autoraise (f, arg, oldval)
2906 struct frame *f;
2907 Lisp_Object arg, oldval;
2908{
2909 f->auto_raise = !EQ (Qnil, arg);
2910}
2911
2912void
2913x_set_autolower (f, arg, oldval)
2914 struct frame *f;
2915 Lisp_Object arg, oldval;
2916{
2917 f->auto_lower = !EQ (Qnil, arg);
2918}
2919
2920void
2921x_set_unsplittable (f, arg, oldval)
2922 struct frame *f;
2923 Lisp_Object arg, oldval;
2924{
2925 f->no_split = !NILP (arg);
2926}
2927
2928void
2929x_set_vertical_scroll_bars (f, arg, oldval)
2930 struct frame *f;
2931 Lisp_Object arg, oldval;
2932{
1026b400
RS
2933 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2934 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2935 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2936 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2937 {
1026b400
RS
2938 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2939 vertical_scroll_bar_none :
87996783
GV
2940 /* Put scroll bars on the right by default, as is conventional
2941 on MS-Windows. */
2942 EQ (Qleft, arg)
2943 ? vertical_scroll_bar_left
2944 : vertical_scroll_bar_right;
ee78dc32
GV
2945
2946 /* We set this parameter before creating the window for the
2947 frame, so we can get the geometry right from the start.
2948 However, if the window hasn't been created yet, we shouldn't
2949 call x_set_window_size. */
fbd6baed 2950 if (FRAME_W32_WINDOW (f))
ee78dc32 2951 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2952 do_pending_window_change (0);
ee78dc32
GV
2953 }
2954}
2955
2956void
2957x_set_scroll_bar_width (f, arg, oldval)
2958 struct frame *f;
2959 Lisp_Object arg, oldval;
2960{
6fc2811b
JR
2961 int wid = FONT_WIDTH (f->output_data.w32->font);
2962
ee78dc32
GV
2963 if (NILP (arg))
2964 {
6fc2811b
JR
2965 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2966 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2967 wid - 1) / wid;
2968 if (FRAME_W32_WINDOW (f))
2969 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2970 do_pending_window_change (0);
ee78dc32
GV
2971 }
2972 else if (INTEGERP (arg) && XINT (arg) > 0
2973 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2974 {
ee78dc32 2975 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2976 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2977 + wid-1) / wid;
fbd6baed 2978 if (FRAME_W32_WINDOW (f))
ee78dc32 2979 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2980 do_pending_window_change (0);
ee78dc32 2981 }
6fc2811b
JR
2982 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2983 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2984 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2985}
2986\f
2987/* Subroutines of creating an frame. */
2988
2989/* Make sure that Vx_resource_name is set to a reasonable value.
2990 Fix it up, or set it to `emacs' if it is too hopeless. */
2991
2992static void
2993validate_x_resource_name ()
2994{
6fc2811b 2995 int len = 0;
ee78dc32
GV
2996 /* Number of valid characters in the resource name. */
2997 int good_count = 0;
2998 /* Number of invalid characters in the resource name. */
2999 int bad_count = 0;
3000 Lisp_Object new;
3001 int i;
3002
3003 if (STRINGP (Vx_resource_name))
3004 {
3005 unsigned char *p = XSTRING (Vx_resource_name)->data;
3006 int i;
3007
dfff8a69 3008 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
3009
3010 /* Only letters, digits, - and _ are valid in resource names.
3011 Count the valid characters and count the invalid ones. */
3012 for (i = 0; i < len; i++)
3013 {
3014 int c = p[i];
3015 if (! ((c >= 'a' && c <= 'z')
3016 || (c >= 'A' && c <= 'Z')
3017 || (c >= '0' && c <= '9')
3018 || c == '-' || c == '_'))
3019 bad_count++;
3020 else
3021 good_count++;
3022 }
3023 }
3024 else
3025 /* Not a string => completely invalid. */
3026 bad_count = 5, good_count = 0;
3027
3028 /* If name is valid already, return. */
3029 if (bad_count == 0)
3030 return;
3031
3032 /* If name is entirely invalid, or nearly so, use `emacs'. */
3033 if (good_count == 0
3034 || (good_count == 1 && bad_count > 0))
3035 {
3036 Vx_resource_name = build_string ("emacs");
3037 return;
3038 }
3039
3040 /* Name is partly valid. Copy it and replace the invalid characters
3041 with underscores. */
3042
3043 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3044
3045 for (i = 0; i < len; i++)
3046 {
3047 int c = XSTRING (new)->data[i];
3048 if (! ((c >= 'a' && c <= 'z')
3049 || (c >= 'A' && c <= 'Z')
3050 || (c >= '0' && c <= '9')
3051 || c == '-' || c == '_'))
3052 XSTRING (new)->data[i] = '_';
3053 }
3054}
3055
3056
3057extern char *x_get_string_resource ();
3058
3059DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
3060 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3061This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3062class, where INSTANCE is the name under which Emacs was invoked, or
3063the name specified by the `-name' or `-rn' command-line arguments.
3064
3065The optional arguments COMPONENT and SUBCLASS add to the key and the
3066class, respectively. You must specify both of them or neither.
3067If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3068and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
3069 (attribute, class, component, subclass)
3070 Lisp_Object attribute, class, component, subclass;
3071{
3072 register char *value;
3073 char *name_key;
3074 char *class_key;
3075
b7826503
PJ
3076 CHECK_STRING (attribute);
3077 CHECK_STRING (class);
ee78dc32
GV
3078
3079 if (!NILP (component))
b7826503 3080 CHECK_STRING (component);
ee78dc32 3081 if (!NILP (subclass))
b7826503 3082 CHECK_STRING (subclass);
ee78dc32
GV
3083 if (NILP (component) != NILP (subclass))
3084 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3085
3086 validate_x_resource_name ();
3087
3088 /* Allocate space for the components, the dots which separate them,
3089 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 3090 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 3091 + (STRINGP (component)
dfff8a69
JR
3092 ? STRING_BYTES (XSTRING (component)) : 0)
3093 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
3094 + 3);
3095
3096 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 3097 + STRING_BYTES (XSTRING (class))
ee78dc32 3098 + (STRINGP (subclass)
dfff8a69 3099 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
3100 + 3);
3101
3102 /* Start with emacs.FRAMENAME for the name (the specific one)
3103 and with `Emacs' for the class key (the general one). */
3104 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3105 strcpy (class_key, EMACS_CLASS);
3106
3107 strcat (class_key, ".");
3108 strcat (class_key, XSTRING (class)->data);
3109
3110 if (!NILP (component))
3111 {
3112 strcat (class_key, ".");
3113 strcat (class_key, XSTRING (subclass)->data);
3114
3115 strcat (name_key, ".");
3116 strcat (name_key, XSTRING (component)->data);
3117 }
3118
3119 strcat (name_key, ".");
3120 strcat (name_key, XSTRING (attribute)->data);
3121
3122 value = x_get_string_resource (Qnil,
3123 name_key, class_key);
3124
3125 if (value != (char *) 0)
3126 return build_string (value);
3127 else
3128 return Qnil;
3129}
3130
3131/* Used when C code wants a resource value. */
3132
3133char *
3134x_get_resource_string (attribute, class)
3135 char *attribute, *class;
3136{
ee78dc32
GV
3137 char *name_key;
3138 char *class_key;
6fc2811b 3139 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3140
3141 /* Allocate space for the components, the dots which separate them,
3142 and the final '\0'. */
dfff8a69 3143 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3144 + strlen (attribute) + 2);
3145 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3146 + strlen (class) + 2);
3147
3148 sprintf (name_key, "%s.%s",
3149 XSTRING (Vinvocation_name)->data,
3150 attribute);
3151 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3152
6fc2811b 3153 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3154}
3155
3156/* Types we might convert a resource string into. */
3157enum resource_types
6fc2811b
JR
3158{
3159 RES_TYPE_NUMBER,
3160 RES_TYPE_FLOAT,
3161 RES_TYPE_BOOLEAN,
3162 RES_TYPE_STRING,
3163 RES_TYPE_SYMBOL
3164};
ee78dc32
GV
3165
3166/* Return the value of parameter PARAM.
3167
3168 First search ALIST, then Vdefault_frame_alist, then the X defaults
3169 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3170
3171 Convert the resource to the type specified by desired_type.
3172
3173 If no default is specified, return Qunbound. If you call
6fc2811b 3174 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3175 and don't let it get stored in any Lisp-visible variables! */
3176
3177static Lisp_Object
6fc2811b 3178w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3179 Lisp_Object alist, param;
3180 char *attribute;
3181 char *class;
3182 enum resource_types type;
3183{
3184 register Lisp_Object tem;
3185
3186 tem = Fassq (param, alist);
3187 if (EQ (tem, Qnil))
3188 tem = Fassq (param, Vdefault_frame_alist);
3189 if (EQ (tem, Qnil))
3190 {
3191
3192 if (attribute)
3193 {
3194 tem = Fx_get_resource (build_string (attribute),
3195 build_string (class),
3196 Qnil, Qnil);
3197
3198 if (NILP (tem))
3199 return Qunbound;
3200
3201 switch (type)
3202 {
6fc2811b 3203 case RES_TYPE_NUMBER:
ee78dc32
GV
3204 return make_number (atoi (XSTRING (tem)->data));
3205
6fc2811b
JR
3206 case RES_TYPE_FLOAT:
3207 return make_float (atof (XSTRING (tem)->data));
3208
3209 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3210 tem = Fdowncase (tem);
3211 if (!strcmp (XSTRING (tem)->data, "on")
3212 || !strcmp (XSTRING (tem)->data, "true"))
3213 return Qt;
3214 else
3215 return Qnil;
3216
6fc2811b 3217 case RES_TYPE_STRING:
ee78dc32
GV
3218 return tem;
3219
6fc2811b 3220 case RES_TYPE_SYMBOL:
ee78dc32
GV
3221 /* As a special case, we map the values `true' and `on'
3222 to Qt, and `false' and `off' to Qnil. */
3223 {
3224 Lisp_Object lower;
3225 lower = Fdowncase (tem);
3226 if (!strcmp (XSTRING (lower)->data, "on")
3227 || !strcmp (XSTRING (lower)->data, "true"))
3228 return Qt;
3229 else if (!strcmp (XSTRING (lower)->data, "off")
3230 || !strcmp (XSTRING (lower)->data, "false"))
3231 return Qnil;
3232 else
3233 return Fintern (tem, Qnil);
3234 }
3235
3236 default:
3237 abort ();
3238 }
3239 }
3240 else
3241 return Qunbound;
3242 }
3243 return Fcdr (tem);
3244}
3245
3246/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3247 of the parameter named PROP (a Lisp symbol).
3248 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3249 on the frame named NAME.
3250 If that is not found either, use the value DEFLT. */
3251
3252static Lisp_Object
3253x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3254 struct frame *f;
3255 Lisp_Object alist;
3256 Lisp_Object prop;
3257 Lisp_Object deflt;
3258 char *xprop;
3259 char *xclass;
3260 enum resource_types type;
3261{
3262 Lisp_Object tem;
3263
6fc2811b 3264 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3265 if (EQ (tem, Qunbound))
3266 tem = deflt;
3267 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3268 return tem;
3269}
3270\f
3271DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3272 doc: /* Parse an X-style geometry string STRING.
3273Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3274The properties returned may include `top', `left', `height', and `width'.
3275The value of `left' or `top' may be an integer,
3276or a list (+ N) meaning N pixels relative to top/left corner,
3277or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3278 (string)
3279 Lisp_Object string;
3280{
3281 int geometry, x, y;
3282 unsigned int width, height;
3283 Lisp_Object result;
3284
b7826503 3285 CHECK_STRING (string);
ee78dc32
GV
3286
3287 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3288 &x, &y, &width, &height);
3289
3290 result = Qnil;
3291 if (geometry & XValue)
3292 {
3293 Lisp_Object element;
3294
3295 if (x >= 0 && (geometry & XNegative))
3296 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3297 else if (x < 0 && ! (geometry & XNegative))
3298 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3299 else
3300 element = Fcons (Qleft, make_number (x));
3301 result = Fcons (element, result);
3302 }
3303
3304 if (geometry & YValue)
3305 {
3306 Lisp_Object element;
3307
3308 if (y >= 0 && (geometry & YNegative))
3309 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3310 else if (y < 0 && ! (geometry & YNegative))
3311 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3312 else
3313 element = Fcons (Qtop, make_number (y));
3314 result = Fcons (element, result);
3315 }
3316
3317 if (geometry & WidthValue)
3318 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3319 if (geometry & HeightValue)
3320 result = Fcons (Fcons (Qheight, make_number (height)), result);
3321
3322 return result;
3323}
3324
3325/* Calculate the desired size and position of this window,
3326 and return the flags saying which aspects were specified.
3327
3328 This function does not make the coordinates positive. */
3329
3330#define DEFAULT_ROWS 40
3331#define DEFAULT_COLS 80
3332
3333static int
3334x_figure_window_size (f, parms)
3335 struct frame *f;
3336 Lisp_Object parms;
3337{
3338 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3339 long window_prompting = 0;
3340
3341 /* Default values if we fall through.
3342 Actually, if that happens we should get
3343 window manager prompting. */
1026b400 3344 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3345 f->height = DEFAULT_ROWS;
3346 /* Window managers expect that if program-specified
3347 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3348 f->output_data.w32->top_pos = 0;
3349 f->output_data.w32->left_pos = 0;
ee78dc32 3350
35b41202
JR
3351 /* Ensure that old new_width and new_height will not override the
3352 values set here. */
3353 FRAME_NEW_WIDTH (f) = 0;
3354 FRAME_NEW_HEIGHT (f) = 0;
3355
6fc2811b
JR
3356 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3357 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3358 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3359 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3360 {
3361 if (!EQ (tem0, Qunbound))
3362 {
b7826503 3363 CHECK_NUMBER (tem0);
ee78dc32
GV
3364 f->height = XINT (tem0);
3365 }
3366 if (!EQ (tem1, Qunbound))
3367 {
b7826503 3368 CHECK_NUMBER (tem1);
1026b400 3369 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3370 }
3371 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3372 window_prompting |= USSize;
3373 else
3374 window_prompting |= PSize;
3375 }
3376
fbd6baed 3377 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3378 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3379 ? 0
3380 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3381 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3382 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
f7b9d4d1 3383
41c1bdd9 3384 x_compute_fringe_widths (f, 0);
f7b9d4d1 3385
fbd6baed
GV
3386 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3387 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3388
6fc2811b
JR
3389 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3390 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3391 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3392 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3393 {
3394 if (EQ (tem0, Qminus))
3395 {
fbd6baed 3396 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3397 window_prompting |= YNegative;
3398 }
8e713be6
KR
3399 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3400 && CONSP (XCDR (tem0))
3401 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3402 {
8e713be6 3403 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3404 window_prompting |= YNegative;
3405 }
8e713be6
KR
3406 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3407 && CONSP (XCDR (tem0))
3408 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3409 {
8e713be6 3410 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3411 }
3412 else if (EQ (tem0, Qunbound))
fbd6baed 3413 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3414 else
3415 {
b7826503 3416 CHECK_NUMBER (tem0);
fbd6baed
GV
3417 f->output_data.w32->top_pos = XINT (tem0);
3418 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3419 window_prompting |= YNegative;
3420 }
3421
3422 if (EQ (tem1, Qminus))
3423 {
fbd6baed 3424 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3425 window_prompting |= XNegative;
3426 }
8e713be6
KR
3427 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3428 && CONSP (XCDR (tem1))
3429 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3430 {
8e713be6 3431 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3432 window_prompting |= XNegative;
3433 }
8e713be6
KR
3434 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3435 && CONSP (XCDR (tem1))
3436 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3437 {
8e713be6 3438 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3439 }
3440 else if (EQ (tem1, Qunbound))
fbd6baed 3441 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3442 else
3443 {
b7826503 3444 CHECK_NUMBER (tem1);
fbd6baed
GV
3445 f->output_data.w32->left_pos = XINT (tem1);
3446 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3447 window_prompting |= XNegative;
3448 }
3449
3450 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3451 window_prompting |= USPosition;
3452 else
3453 window_prompting |= PPosition;
3454 }
3455
f7b9d4d1
JR
3456 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3457 {
3458 int left, top;
3459 int width, height;
3460
3461 /* It takes both for some WM:s to place it where we want */
3462 window_prompting = USPosition | PPosition;
3463 x_fullscreen_adjust (f, &width, &height, &top, &left);
3464 f->width = width;
3465 f->height = height;
3466 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3467 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3468 f->output_data.w32->left_pos = left;
3469 f->output_data.w32->top_pos = top;
3470 }
3471
ee78dc32
GV
3472 return window_prompting;
3473}
3474
3475\f
3476
fbd6baed 3477extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3478
3479BOOL
fbd6baed 3480w32_init_class (hinst)
ee78dc32
GV
3481 HINSTANCE hinst;
3482{
3483 WNDCLASS wc;
3484
5ac45f98 3485 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3486 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3487 wc.cbClsExtra = 0;
3488 wc.cbWndExtra = WND_EXTRA_BYTES;
3489 wc.hInstance = hinst;
3490 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3491 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3492 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3493 wc.lpszMenuName = NULL;
3494 wc.lpszClassName = EMACS_CLASS;
3495
3496 return (RegisterClass (&wc));
3497}
3498
3499HWND
fbd6baed 3500w32_createscrollbar (f, bar)
ee78dc32
GV
3501 struct frame *f;
3502 struct scroll_bar * bar;
3503{
3504 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3505 /* Position and size of scroll bar. */
6fc2811b
JR
3506 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3507 XINT(bar->top),
3508 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3509 XINT(bar->height),
fbd6baed 3510 FRAME_W32_WINDOW (f),
ee78dc32
GV
3511 NULL,
3512 hinst,
3513 NULL));
3514}
3515
3516void
fbd6baed 3517w32_createwindow (f)
ee78dc32
GV
3518 struct frame *f;
3519{
3520 HWND hwnd;
1edf84e7
GV
3521 RECT rect;
3522
3523 rect.left = rect.top = 0;
3524 rect.right = PIXEL_WIDTH (f);
3525 rect.bottom = PIXEL_HEIGHT (f);
3526
3527 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3528 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3529
3530 /* Do first time app init */
3531
3532 if (!hprevinst)
3533 {
fbd6baed 3534 w32_init_class (hinst);
ee78dc32
GV
3535 }
3536
1edf84e7
GV
3537 FRAME_W32_WINDOW (f) = hwnd
3538 = CreateWindow (EMACS_CLASS,
3539 f->namebuf,
9ead1b60 3540 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3541 f->output_data.w32->left_pos,
3542 f->output_data.w32->top_pos,
3543 rect.right - rect.left,
3544 rect.bottom - rect.top,
3545 NULL,
3546 NULL,
3547 hinst,
3548 NULL);
3549
ee78dc32
GV
3550 if (hwnd)
3551 {
1edf84e7
GV
3552 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3553 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3554 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3555 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3556 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3557
cb9e33d4
RS
3558 /* Enable drag-n-drop. */
3559 DragAcceptFiles (hwnd, TRUE);
3560
5ac45f98
GV
3561 /* Do this to discard the default setting specified by our parent. */
3562 ShowWindow (hwnd, SW_HIDE);
3c190163 3563 }
3c190163
GV
3564}
3565
ee78dc32
GV
3566void
3567my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3568 W32Msg * wmsg;
ee78dc32
GV
3569 HWND hwnd;
3570 UINT msg;
3571 WPARAM wParam;
3572 LPARAM lParam;
3573{
3574 wmsg->msg.hwnd = hwnd;
3575 wmsg->msg.message = msg;
3576 wmsg->msg.wParam = wParam;
3577 wmsg->msg.lParam = lParam;
3578 wmsg->msg.time = GetMessageTime ();
3579
3580 post_msg (wmsg);
3581}
3582
e9e23e23 3583/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3584 between left and right keys as advertised. We test for this
3585 support dynamically, and set a flag when the support is absent. If
3586 absent, we keep track of the left and right control and alt keys
3587 ourselves. This is particularly necessary on keyboards that rely
3588 upon the AltGr key, which is represented as having the left control
3589 and right alt keys pressed. For these keyboards, we need to know
3590 when the left alt key has been pressed in addition to the AltGr key
3591 so that we can properly support M-AltGr-key sequences (such as M-@
3592 on Swedish keyboards). */
3593
3594#define EMACS_LCONTROL 0
3595#define EMACS_RCONTROL 1
3596#define EMACS_LMENU 2
3597#define EMACS_RMENU 3
3598
3599static int modifiers[4];
3600static int modifiers_recorded;
3601static int modifier_key_support_tested;
3602
3603static void
3604test_modifier_support (unsigned int wparam)
3605{
3606 unsigned int l, r;
3607
3608 if (wparam != VK_CONTROL && wparam != VK_MENU)
3609 return;
3610 if (wparam == VK_CONTROL)
3611 {
3612 l = VK_LCONTROL;
3613 r = VK_RCONTROL;
3614 }
3615 else
3616 {
3617 l = VK_LMENU;
3618 r = VK_RMENU;
3619 }
3620 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3621 modifiers_recorded = 1;
3622 else
3623 modifiers_recorded = 0;
3624 modifier_key_support_tested = 1;
3625}
3626
3627static void
3628record_keydown (unsigned int wparam, unsigned int lparam)
3629{
3630 int i;
3631
3632 if (!modifier_key_support_tested)
3633 test_modifier_support (wparam);
3634
3635 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3636 return;
3637
3638 if (wparam == VK_CONTROL)
3639 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3640 else
3641 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3642
3643 modifiers[i] = 1;
3644}
3645
3646static void
3647record_keyup (unsigned int wparam, unsigned int lparam)
3648{
3649 int i;
3650
3651 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3652 return;
3653
3654 if (wparam == VK_CONTROL)
3655 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3656 else
3657 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3658
3659 modifiers[i] = 0;
3660}
3661
da36a4d6
GV
3662/* Emacs can lose focus while a modifier key has been pressed. When
3663 it regains focus, be conservative and clear all modifiers since
3664 we cannot reconstruct the left and right modifier state. */
3665static void
3666reset_modifiers ()
3667{
8681157a
RS
3668 SHORT ctrl, alt;
3669
adcc3809
GV
3670 if (GetFocus () == NULL)
3671 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3672 return;
8681157a
RS
3673
3674 ctrl = GetAsyncKeyState (VK_CONTROL);
3675 alt = GetAsyncKeyState (VK_MENU);
3676
8681157a
RS
3677 if (!(ctrl & 0x08000))
3678 /* Clear any recorded control modifier state. */
3679 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3680
3681 if (!(alt & 0x08000))
3682 /* Clear any recorded alt modifier state. */
3683 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3684
adcc3809
GV
3685 /* Update the state of all modifier keys, because modifiers used in
3686 hot-key combinations can get stuck on if Emacs loses focus as a
3687 result of a hot-key being pressed. */
3688 {
3689 BYTE keystate[256];
3690
3691#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3692
3693 GetKeyboardState (keystate);
3694 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3695 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3696 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3697 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3698 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3699 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3700 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3701 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3702 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3703 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3704 SetKeyboardState (keystate);
3705 }
da36a4d6
GV
3706}
3707
7830e24b
RS
3708/* Synchronize modifier state with what is reported with the current
3709 keystroke. Even if we cannot distinguish between left and right
3710 modifier keys, we know that, if no modifiers are set, then neither
3711 the left or right modifier should be set. */
3712static void
3713sync_modifiers ()
3714{
3715 if (!modifiers_recorded)
3716 return;
3717
3718 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3719 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3720
3721 if (!(GetKeyState (VK_MENU) & 0x8000))
3722 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3723}
3724
a1a80b40
GV
3725static int
3726modifier_set (int vkey)
3727{
ccc2d29c 3728 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3729 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3730 if (!modifiers_recorded)
3731 return (GetKeyState (vkey) & 0x8000);
3732
3733 switch (vkey)
3734 {
3735 case VK_LCONTROL:
3736 return modifiers[EMACS_LCONTROL];
3737 case VK_RCONTROL:
3738 return modifiers[EMACS_RCONTROL];
3739 case VK_LMENU:
3740 return modifiers[EMACS_LMENU];
3741 case VK_RMENU:
3742 return modifiers[EMACS_RMENU];
a1a80b40
GV
3743 }
3744 return (GetKeyState (vkey) & 0x8000);
3745}
3746
ccc2d29c
GV
3747/* Convert between the modifier bits W32 uses and the modifier bits
3748 Emacs uses. */
3749
3750unsigned int
3751w32_key_to_modifier (int key)
3752{
3753 Lisp_Object key_mapping;
3754
3755 switch (key)
3756 {
3757 case VK_LWIN:
3758 key_mapping = Vw32_lwindow_modifier;
3759 break;
3760 case VK_RWIN:
3761 key_mapping = Vw32_rwindow_modifier;
3762 break;
3763 case VK_APPS:
3764 key_mapping = Vw32_apps_modifier;
3765 break;
3766 case VK_SCROLL:
3767 key_mapping = Vw32_scroll_lock_modifier;
3768 break;
3769 default:
3770 key_mapping = Qnil;
3771 }
3772
adcc3809
GV
3773 /* NB. This code runs in the input thread, asychronously to the lisp
3774 thread, so we must be careful to ensure access to lisp data is
3775 thread-safe. The following code is safe because the modifier
3776 variable values are updated atomically from lisp and symbols are
3777 not relocated by GC. Also, we don't have to worry about seeing GC
3778 markbits here. */
3779 if (EQ (key_mapping, Qhyper))
ccc2d29c 3780 return hyper_modifier;
adcc3809 3781 if (EQ (key_mapping, Qsuper))
ccc2d29c 3782 return super_modifier;
adcc3809 3783 if (EQ (key_mapping, Qmeta))
ccc2d29c 3784 return meta_modifier;
adcc3809 3785 if (EQ (key_mapping, Qalt))
ccc2d29c 3786 return alt_modifier;
adcc3809 3787 if (EQ (key_mapping, Qctrl))
ccc2d29c 3788 return ctrl_modifier;
adcc3809 3789 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3790 return ctrl_modifier;
adcc3809 3791 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3792 return shift_modifier;
3793
3794 /* Don't generate any modifier if not explicitly requested. */
3795 return 0;
3796}
3797
3798unsigned int
3799w32_get_modifiers ()
3800{
3801 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3802 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3803 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3804 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3805 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3806 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3807 (modifier_set (VK_MENU) ?
3808 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3809}
3810
a1a80b40
GV
3811/* We map the VK_* modifiers into console modifier constants
3812 so that we can use the same routines to handle both console
3813 and window input. */
3814
3815static int
ccc2d29c 3816construct_console_modifiers ()
a1a80b40
GV
3817{
3818 int mods;
3819
a1a80b40
GV
3820 mods = 0;
3821 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3822 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3823 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3824 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3825 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3826 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3827 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3828 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3829 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3830 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3831 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3832
3833 return mods;
3834}
3835
ccc2d29c
GV
3836static int
3837w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3838{
ccc2d29c
GV
3839 int mods;
3840
3841 /* Convert to emacs modifiers. */
3842 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3843
3844 return mods;
3845}
da36a4d6 3846
ccc2d29c
GV
3847unsigned int
3848map_keypad_keys (unsigned int virt_key, unsigned int extended)
3849{
3850 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3851 return virt_key;
da36a4d6 3852
ccc2d29c 3853 if (virt_key == VK_RETURN)
da36a4d6
GV
3854 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3855
ccc2d29c
GV
3856 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3857 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3858
3859 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3860 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3861
3862 if (virt_key == VK_CLEAR)
3863 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3864
3865 return virt_key;
3866}
3867
3868/* List of special key combinations which w32 would normally capture,
3869 but emacs should grab instead. Not directly visible to lisp, to
3870 simplify synchronization. Each item is an integer encoding a virtual
3871 key code and modifier combination to capture. */
3872Lisp_Object w32_grabbed_keys;
3873
3874#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3875#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3876#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3877#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3878
3879/* Register hot-keys for reserved key combinations when Emacs has
3880 keyboard focus, since this is the only way Emacs can receive key
3881 combinations like Alt-Tab which are used by the system. */
3882
3883static void
3884register_hot_keys (hwnd)
3885 HWND hwnd;
3886{
3887 Lisp_Object keylist;
3888
3889 /* Use GC_CONSP, since we are called asynchronously. */
3890 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3891 {
3892 Lisp_Object key = XCAR (keylist);
3893
3894 /* Deleted entries get set to nil. */
3895 if (!INTEGERP (key))
3896 continue;
3897
3898 RegisterHotKey (hwnd, HOTKEY_ID (key),
3899 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3900 }
3901}
3902
3903static void
3904unregister_hot_keys (hwnd)
3905 HWND hwnd;
3906{
3907 Lisp_Object keylist;
3908
3909 /* Use GC_CONSP, since we are called asynchronously. */
3910 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3911 {
3912 Lisp_Object key = XCAR (keylist);
3913
3914 if (!INTEGERP (key))
3915 continue;
3916
3917 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3918 }
3919}
3920
5ac45f98
GV
3921/* Main message dispatch loop. */
3922
1edf84e7
GV
3923static void
3924w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3925{
3926 MSG msg;
ccc2d29c
GV
3927 int result;
3928 HWND focus_window;
93fbe8b7
GV
3929
3930 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3931
5ac45f98
GV
3932 while (GetMessage (&msg, NULL, 0, 0))
3933 {
3934 if (msg.hwnd == NULL)
3935 {
3936 switch (msg.message)
3937 {
3ef68e6b
AI
3938 case WM_NULL:
3939 /* Produced by complete_deferred_msg; just ignore. */
3940 break;
5ac45f98 3941 case WM_EMACS_CREATEWINDOW:
fbd6baed 3942 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3943 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3944 abort ();
5ac45f98 3945 break;
dfdb4047
GV
3946 case WM_EMACS_SETLOCALE:
3947 SetThreadLocale (msg.wParam);
3948 /* Reply is not expected. */
3949 break;
ccc2d29c
GV
3950 case WM_EMACS_SETKEYBOARDLAYOUT:
3951 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3952 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3953 result, 0))
3954 abort ();
3955 break;
3956 case WM_EMACS_REGISTER_HOT_KEY:
3957 focus_window = GetFocus ();
3958 if (focus_window != NULL)
3959 RegisterHotKey (focus_window,
3960 HOTKEY_ID (msg.wParam),
3961 HOTKEY_MODIFIERS (msg.wParam),
3962 HOTKEY_VK_CODE (msg.wParam));
3963 /* Reply is not expected. */
3964 break;
3965 case WM_EMACS_UNREGISTER_HOT_KEY:
3966 focus_window = GetFocus ();
3967 if (focus_window != NULL)
3968 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3969 /* Mark item as erased. NB: this code must be
3970 thread-safe. The next line is okay because the cons
3971 cell is never made into garbage and is not relocated by
3972 GC. */
f3fbd155 3973 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3974 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3975 abort ();
3976 break;
adcc3809
GV
3977 case WM_EMACS_TOGGLE_LOCK_KEY:
3978 {
3979 int vk_code = (int) msg.wParam;
3980 int cur_state = (GetKeyState (vk_code) & 1);
3981 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3982
3983 /* NB: This code must be thread-safe. It is safe to
3984 call NILP because symbols are not relocated by GC,
3985 and pointer here is not touched by GC (so the markbit
3986 can't be set). Numbers are safe because they are
3987 immediate values. */
3988 if (NILP (new_state)
3989 || (NUMBERP (new_state)
8edb0a6f 3990 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3991 {
3992 one_w32_display_info.faked_key = vk_code;
3993
3994 keybd_event ((BYTE) vk_code,
3995 (BYTE) MapVirtualKey (vk_code, 0),
3996 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3997 keybd_event ((BYTE) vk_code,
3998 (BYTE) MapVirtualKey (vk_code, 0),
3999 KEYEVENTF_EXTENDEDKEY | 0, 0);
4000 keybd_event ((BYTE) vk_code,
4001 (BYTE) MapVirtualKey (vk_code, 0),
4002 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4003 cur_state = !cur_state;
4004 }
4005 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
4006 cur_state, 0))
4007 abort ();
4008 }
4009 break;
1edf84e7 4010 default:
1edf84e7 4011 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
4012 }
4013 }
4014 else
4015 {
4016 DispatchMessage (&msg);
4017 }
1edf84e7
GV
4018
4019 /* Exit nested loop when our deferred message has completed. */
4020 if (msg_buf->completed)
4021 break;
5ac45f98 4022 }
1edf84e7
GV
4023}
4024
4025deferred_msg * deferred_msg_head;
4026
4027static deferred_msg *
4028find_deferred_msg (HWND hwnd, UINT msg)
4029{
4030 deferred_msg * item;
4031
4032 /* Don't actually need synchronization for read access, since
4033 modification of single pointer is always atomic. */
4034 /* enter_crit (); */
4035
4036 for (item = deferred_msg_head; item != NULL; item = item->next)
4037 if (item->w32msg.msg.hwnd == hwnd
4038 && item->w32msg.msg.message == msg)
4039 break;
4040
4041 /* leave_crit (); */
4042
4043 return item;
4044}
4045
4046static LRESULT
4047send_deferred_msg (deferred_msg * msg_buf,
4048 HWND hwnd,
4049 UINT msg,
4050 WPARAM wParam,
4051 LPARAM lParam)
4052{
4053 /* Only input thread can send deferred messages. */
4054 if (GetCurrentThreadId () != dwWindowsThreadId)
4055 abort ();
4056
4057 /* It is an error to send a message that is already deferred. */
4058 if (find_deferred_msg (hwnd, msg) != NULL)
4059 abort ();
4060
4061 /* Enforced synchronization is not needed because this is the only
4062 function that alters deferred_msg_head, and the following critical
4063 section is guaranteed to only be serially reentered (since only the
4064 input thread can call us). */
4065
4066 /* enter_crit (); */
4067
4068 msg_buf->completed = 0;
4069 msg_buf->next = deferred_msg_head;
4070 deferred_msg_head = msg_buf;
4071 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4072
4073 /* leave_crit (); */
4074
4075 /* Start a new nested message loop to process other messages until
4076 this one is completed. */
4077 w32_msg_pump (msg_buf);
4078
4079 deferred_msg_head = msg_buf->next;
4080
4081 return msg_buf->result;
4082}
4083
4084void
4085complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4086{
4087 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4088
4089 if (msg_buf == NULL)
3ef68e6b
AI
4090 /* Message may have been cancelled, so don't abort(). */
4091 return;
1edf84e7
GV
4092
4093 msg_buf->result = result;
4094 msg_buf->completed = 1;
4095
4096 /* Ensure input thread is woken so it notices the completion. */
4097 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4098}
4099
3ef68e6b
AI
4100void
4101cancel_all_deferred_msgs ()
4102{
4103 deferred_msg * item;
4104
4105 /* Don't actually need synchronization for read access, since
4106 modification of single pointer is always atomic. */
4107 /* enter_crit (); */
4108
4109 for (item = deferred_msg_head; item != NULL; item = item->next)
4110 {
4111 item->result = 0;
4112 item->completed = 1;
4113 }
4114
4115 /* leave_crit (); */
4116
4117 /* Ensure input thread is woken so it notices the completion. */
4118 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4119}
1edf84e7
GV
4120
4121DWORD
4122w32_msg_worker (dw)
4123 DWORD dw;
4124{
4125 MSG msg;
4126 deferred_msg dummy_buf;
4127
4128 /* Ensure our message queue is created */
4129
4130 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 4131
1edf84e7
GV
4132 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4133 abort ();
4134
4135 memset (&dummy_buf, 0, sizeof (dummy_buf));
4136 dummy_buf.w32msg.msg.hwnd = NULL;
4137 dummy_buf.w32msg.msg.message = WM_NULL;
4138
4139 /* This is the inital message loop which should only exit when the
4140 application quits. */
4141 w32_msg_pump (&dummy_buf);
4142
4143 return 0;
5ac45f98
GV
4144}
4145
3ef68e6b
AI
4146static void
4147post_character_message (hwnd, msg, wParam, lParam, modifiers)
4148 HWND hwnd;
4149 UINT msg;
4150 WPARAM wParam;
4151 LPARAM lParam;
4152 DWORD modifiers;
4153
4154{
4155 W32Msg wmsg;
4156
4157 wmsg.dwModifiers = modifiers;
4158
4159 /* Detect quit_char and set quit-flag directly. Note that we
4160 still need to post a message to ensure the main thread will be
4161 woken up if blocked in sys_select(), but we do NOT want to post
4162 the quit_char message itself (because it will usually be as if
4163 the user had typed quit_char twice). Instead, we post a dummy
4164 message that has no particular effect. */
4165 {
4166 int c = wParam;
4167 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4168 c = make_ctrl_char (c) & 0377;
7d081355
AI
4169 if (c == quit_char
4170 || (wmsg.dwModifiers == 0 &&
4171 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4172 {
4173 Vquit_flag = Qt;
4174
4175 /* The choice of message is somewhat arbitrary, as long as
4176 the main thread handler just ignores it. */
4177 msg = WM_NULL;
4178
4179 /* Interrupt any blocking system calls. */
4180 signal_quit ();
4181
4182 /* As a safety precaution, forcibly complete any deferred
4183 messages. This is a kludge, but I don't see any particularly
4184 clean way to handle the situation where a deferred message is
4185 "dropped" in the lisp thread, and will thus never be
4186 completed, eg. by the user trying to activate the menubar
4187 when the lisp thread is busy, and then typing C-g when the
4188 menubar doesn't open promptly (with the result that the
4189 menubar never responds at all because the deferred
4190 WM_INITMENU message is never completed). Another problem
4191 situation is when the lisp thread calls SendMessage (to send
4192 a window manager command) when a message has been deferred;
4193 the lisp thread gets blocked indefinitely waiting for the
4194 deferred message to be completed, which itself is waiting for
4195 the lisp thread to respond.
4196
4197 Note that we don't want to block the input thread waiting for
4198 a reponse from the lisp thread (although that would at least
4199 solve the deadlock problem above), because we want to be able
4200 to receive C-g to interrupt the lisp thread. */
4201 cancel_all_deferred_msgs ();
4202 }
4203 }
4204
4205 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4206}
4207
ee78dc32
GV
4208/* Main window procedure */
4209
ee78dc32 4210LRESULT CALLBACK
fbd6baed 4211w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4212 HWND hwnd;
4213 UINT msg;
4214 WPARAM wParam;
4215 LPARAM lParam;
4216{
4217 struct frame *f;
fbd6baed
GV
4218 struct w32_display_info *dpyinfo = &one_w32_display_info;
4219 W32Msg wmsg;
84fb1139 4220 int windows_translate;
576ba81c 4221 int key;
84fb1139 4222
a6085637
KH
4223 /* Note that it is okay to call x_window_to_frame, even though we are
4224 not running in the main lisp thread, because frame deletion
4225 requires the lisp thread to synchronize with this thread. Thus, if
4226 a frame struct is returned, it can be used without concern that the
4227 lisp thread might make it disappear while we are using it.
4228
4229 NB. Walking the frame list in this thread is safe (as long as
4230 writes of Lisp_Object slots are atomic, which they are on Windows).
4231 Although delete-frame can destructively modify the frame list while
4232 we are walking it, a garbage collection cannot occur until after
4233 delete-frame has synchronized with this thread.
4234
4235 It is also safe to use functions that make GDI calls, such as
fbd6baed 4236 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4237 from the frame struct using get_frame_dc which is thread-aware. */
4238
ee78dc32
GV
4239 switch (msg)
4240 {
4241 case WM_ERASEBKGND:
a6085637
KH
4242 f = x_window_to_frame (dpyinfo, hwnd);
4243 if (f)
4244 {
9badad41 4245 HDC hdc = get_frame_dc (f);
a6085637 4246 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4247 w32_clear_rect (f, hdc, &wmsg.rect);
4248 release_frame_dc (f, hdc);
ce6059da
AI
4249
4250#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4251 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4252 f,
4253 wmsg.rect.left, wmsg.rect.top,
4254 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4255#endif /* W32_DEBUG_DISPLAY */
a6085637 4256 }
5ac45f98
GV
4257 return 1;
4258 case WM_PALETTECHANGED:
4259 /* ignore our own changes */
4260 if ((HWND)wParam != hwnd)
4261 {
a6085637
KH
4262 f = x_window_to_frame (dpyinfo, hwnd);
4263 if (f)
4264 /* get_frame_dc will realize our palette and force all
4265 frames to be redrawn if needed. */
4266 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4267 }
4268 return 0;
ee78dc32 4269 case WM_PAINT:
ce6059da 4270 {
55dcfc15
AI
4271 PAINTSTRUCT paintStruct;
4272 RECT update_rect;
aa35b6ad 4273 bzero (&update_rect, sizeof (update_rect));
55dcfc15 4274
18f0b342
AI
4275 f = x_window_to_frame (dpyinfo, hwnd);
4276 if (f == 0)
4277 {
4278 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4279 return 0;
4280 }
4281
55dcfc15
AI
4282 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4283 fails. Apparently this can happen under some
4284 circumstances. */
aa35b6ad 4285 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
55dcfc15
AI
4286 {
4287 enter_crit ();
4288 BeginPaint (hwnd, &paintStruct);
4289
aa35b6ad
JR
4290 /* The rectangles returned by GetUpdateRect and BeginPaint
4291 do not always match. Play it safe by assuming both areas
4292 are invalid. */
4293 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
55dcfc15
AI
4294
4295#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4296 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4297 f,
4298 wmsg.rect.left, wmsg.rect.top,
4299 wmsg.rect.right, wmsg.rect.bottom));
4300 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4301 update_rect.left, update_rect.top,
4302 update_rect.right, update_rect.bottom));
4303#endif
4304 EndPaint (hwnd, &paintStruct);
4305 leave_crit ();
4306
4307 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4308
4309 return 0;
4310 }
c0611964
AI
4311
4312 /* If GetUpdateRect returns 0 (meaning there is no update
4313 region), assume the whole window needs to be repainted. */
4314 GetClientRect(hwnd, &wmsg.rect);
4315 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4316 return 0;
ee78dc32 4317 }
a1a80b40 4318
ccc2d29c
GV
4319 case WM_INPUTLANGCHANGE:
4320 /* Inform lisp thread of keyboard layout changes. */
4321 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4322
4323 /* Clear dead keys in the keyboard state; for simplicity only
4324 preserve modifier key states. */
4325 {
4326 int i;
4327 BYTE keystate[256];
4328
4329 GetKeyboardState (keystate);
4330 for (i = 0; i < 256; i++)
4331 if (1
4332 && i != VK_SHIFT
4333 && i != VK_LSHIFT
4334 && i != VK_RSHIFT
4335 && i != VK_CAPITAL
4336 && i != VK_NUMLOCK
4337 && i != VK_SCROLL
4338 && i != VK_CONTROL
4339 && i != VK_LCONTROL
4340 && i != VK_RCONTROL
4341 && i != VK_MENU
4342 && i != VK_LMENU
4343 && i != VK_RMENU
4344 && i != VK_LWIN
4345 && i != VK_RWIN)
4346 keystate[i] = 0;
4347 SetKeyboardState (keystate);
4348 }
4349 goto dflt;
4350
4351 case WM_HOTKEY:
4352 /* Synchronize hot keys with normal input. */
4353 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4354 return (0);
4355
a1a80b40
GV
4356 case WM_KEYUP:
4357 case WM_SYSKEYUP:
4358 record_keyup (wParam, lParam);
4359 goto dflt;
4360
ee78dc32
GV
4361 case WM_KEYDOWN:
4362 case WM_SYSKEYDOWN:
ccc2d29c
GV
4363 /* Ignore keystrokes we fake ourself; see below. */
4364 if (dpyinfo->faked_key == wParam)
4365 {
4366 dpyinfo->faked_key = 0;
576ba81c
AI
4367 /* Make sure TranslateMessage sees them though (as long as
4368 they don't produce WM_CHAR messages). This ensures that
4369 indicator lights are toggled promptly on Windows 9x, for
4370 example. */
4371 if (lispy_function_keys[wParam] != 0)
4372 {
4373 windows_translate = 1;
4374 goto translate;
4375 }
4376 return 0;
ccc2d29c
GV
4377 }
4378
7830e24b
RS
4379 /* Synchronize modifiers with current keystroke. */
4380 sync_modifiers ();
a1a80b40 4381 record_keydown (wParam, lParam);
ccc2d29c 4382 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4383
4384 windows_translate = 0;
ccc2d29c
GV
4385
4386 switch (wParam)
4387 {
4388 case VK_LWIN:
4389 if (NILP (Vw32_pass_lwindow_to_system))
4390 {
4391 /* Prevent system from acting on keyup (which opens the
4392 Start menu if no other key was pressed) by simulating a
4393 press of Space which we will ignore. */
4394 if (GetAsyncKeyState (wParam) & 1)
4395 {
adcc3809 4396 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4397 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4398 else
576ba81c
AI
4399 key = VK_SPACE;
4400 dpyinfo->faked_key = key;
4401 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4402 }
4403 }
4404 if (!NILP (Vw32_lwindow_modifier))
4405 return 0;
4406 break;
4407 case VK_RWIN:
4408 if (NILP (Vw32_pass_rwindow_to_system))
4409 {
4410 if (GetAsyncKeyState (wParam) & 1)
4411 {
adcc3809 4412 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4413 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4414 else
576ba81c
AI
4415 key = VK_SPACE;
4416 dpyinfo->faked_key = key;
4417 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4418 }
4419 }
4420 if (!NILP (Vw32_rwindow_modifier))
4421 return 0;
4422 break;
576ba81c 4423 case VK_APPS:
ccc2d29c
GV
4424 if (!NILP (Vw32_apps_modifier))
4425 return 0;
4426 break;
4427 case VK_MENU:
4428 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4429 /* Prevent DefWindowProc from activating the menu bar if an
4430 Alt key is pressed and released by itself. */
ccc2d29c 4431 return 0;
84fb1139 4432 windows_translate = 1;
ccc2d29c
GV
4433 break;
4434 case VK_CAPITAL:
4435 /* Decide whether to treat as modifier or function key. */
4436 if (NILP (Vw32_enable_caps_lock))
4437 goto disable_lock_key;
adcc3809
GV
4438 windows_translate = 1;
4439 break;
ccc2d29c
GV
4440 case VK_NUMLOCK:
4441 /* Decide whether to treat as modifier or function key. */
4442 if (NILP (Vw32_enable_num_lock))
4443 goto disable_lock_key;
adcc3809
GV
4444 windows_translate = 1;
4445 break;
ccc2d29c
GV
4446 case VK_SCROLL:
4447 /* Decide whether to treat as modifier or function key. */
4448 if (NILP (Vw32_scroll_lock_modifier))
4449 goto disable_lock_key;
adcc3809
GV
4450 windows_translate = 1;
4451 break;
ccc2d29c 4452 disable_lock_key:
adcc3809
GV
4453 /* Ensure the appropriate lock key state (and indicator light)
4454 remains in the same state. We do this by faking another
4455 press of the relevant key. Apparently, this really is the
4456 only way to toggle the state of the indicator lights. */
4457 dpyinfo->faked_key = wParam;
4458 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4459 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4460 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4461 KEYEVENTF_EXTENDEDKEY | 0, 0);
4462 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4463 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4464 /* Ensure indicator lights are updated promptly on Windows 9x
4465 (TranslateMessage apparently does this), after forwarding
4466 input event. */
4467 post_character_message (hwnd, msg, wParam, lParam,
4468 w32_get_key_modifiers (wParam, lParam));
4469 windows_translate = 1;
ccc2d29c
GV
4470 break;
4471 case VK_CONTROL:
4472 case VK_SHIFT:
4473 case VK_PROCESSKEY: /* Generated by IME. */
4474 windows_translate = 1;
4475 break;
adcc3809
GV
4476 case VK_CANCEL:
4477 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4478 which is confusing for purposes of key binding; convert
4479 VK_CANCEL events into VK_PAUSE events. */
4480 wParam = VK_PAUSE;
4481 break;
4482 case VK_PAUSE:
4483 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4484 for purposes of key binding; convert these back into
4485 VK_NUMLOCK events, at least when we want to see NumLock key
4486 presses. (Note that there is never any possibility that
4487 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4488 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4489 wParam = VK_NUMLOCK;
4490 break;
ccc2d29c
GV
4491 default:
4492 /* If not defined as a function key, change it to a WM_CHAR message. */
4493 if (lispy_function_keys[wParam] == 0)
4494 {
adcc3809
GV
4495 DWORD modifiers = construct_console_modifiers ();
4496
ccc2d29c
GV
4497 if (!NILP (Vw32_recognize_altgr)
4498 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4499 {
4500 /* Always let TranslateMessage handle AltGr key chords;
4501 for some reason, ToAscii doesn't always process AltGr
4502 chords correctly. */
4503 windows_translate = 1;
4504 }
adcc3809 4505 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4506 {
adcc3809
GV
4507 /* Handle key chords including any modifiers other
4508 than shift directly, in order to preserve as much
4509 modifier information as possible. */
ccc2d29c
GV
4510 if ('A' <= wParam && wParam <= 'Z')
4511 {
4512 /* Don't translate modified alphabetic keystrokes,
4513 so the user doesn't need to constantly switch
4514 layout to type control or meta keystrokes when
4515 the normal layout translates alphabetic
4516 characters to non-ascii characters. */
4517 if (!modifier_set (VK_SHIFT))
4518 wParam += ('a' - 'A');
4519 msg = WM_CHAR;
4520 }
4521 else
4522 {
4523 /* Try to handle other keystrokes by determining the
4524 base character (ie. translating the base key plus
4525 shift modifier). */
4526 int add;
4527 int isdead = 0;
4528 KEY_EVENT_RECORD key;
4529
4530 key.bKeyDown = TRUE;
4531 key.wRepeatCount = 1;
4532 key.wVirtualKeyCode = wParam;
4533 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4534 key.uChar.AsciiChar = 0;
adcc3809 4535 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4536
4537 add = w32_kbd_patch_key (&key);
4538 /* 0 means an unrecognised keycode, negative means
4539 dead key. Ignore both. */
4540 while (--add >= 0)
4541 {
4542 /* Forward asciified character sequence. */
4543 post_character_message
4544 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4545 w32_get_key_modifiers (wParam, lParam));
4546 w32_kbd_patch_key (&key);
4547 }
4548 return 0;
4549 }
4550 }
4551 else
4552 {
4553 /* Let TranslateMessage handle everything else. */
4554 windows_translate = 1;
4555 }
4556 }
4557 }
a1a80b40 4558
adcc3809 4559 translate:
84fb1139
KH
4560 if (windows_translate)
4561 {
e9e23e23 4562 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4563
e9e23e23
GV
4564 windows_msg.time = GetMessageTime ();
4565 TranslateMessage (&windows_msg);
84fb1139
KH
4566 goto dflt;
4567 }
4568
ee78dc32
GV
4569 /* Fall through */
4570
4571 case WM_SYSCHAR:
4572 case WM_CHAR:
ccc2d29c
GV
4573 post_character_message (hwnd, msg, wParam, lParam,
4574 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4575 break;
da36a4d6 4576
5ac45f98
GV
4577 /* Simulate middle mouse button events when left and right buttons
4578 are used together, but only if user has two button mouse. */
ee78dc32 4579 case WM_LBUTTONDOWN:
5ac45f98 4580 case WM_RBUTTONDOWN:
7ce9aaca 4581 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4582 goto handle_plain_button;
4583
4584 {
4585 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4586 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4587
3cb20f4a
RS
4588 if (button_state & this)
4589 return 0;
5ac45f98
GV
4590
4591 if (button_state == 0)
4592 SetCapture (hwnd);
4593
4594 button_state |= this;
4595
4596 if (button_state & other)
4597 {
84fb1139 4598 if (mouse_button_timer)
5ac45f98 4599 {
84fb1139
KH
4600 KillTimer (hwnd, mouse_button_timer);
4601 mouse_button_timer = 0;
5ac45f98
GV
4602
4603 /* Generate middle mouse event instead. */
4604 msg = WM_MBUTTONDOWN;
4605 button_state |= MMOUSE;
4606 }
4607 else if (button_state & MMOUSE)
4608 {
4609 /* Ignore button event if we've already generated a
4610 middle mouse down event. This happens if the
4611 user releases and press one of the two buttons
4612 after we've faked a middle mouse event. */
4613 return 0;
4614 }
4615 else
4616 {
4617 /* Flush out saved message. */
84fb1139 4618 post_msg (&saved_mouse_button_msg);
5ac45f98 4619 }
fbd6baed 4620 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4621 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4622
4623 /* Clear message buffer. */
84fb1139 4624 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4625 }
4626 else
4627 {
4628 /* Hold onto message for now. */
84fb1139 4629 mouse_button_timer =
adcc3809
GV
4630 SetTimer (hwnd, MOUSE_BUTTON_ID,
4631 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4632 saved_mouse_button_msg.msg.hwnd = hwnd;
4633 saved_mouse_button_msg.msg.message = msg;
4634 saved_mouse_button_msg.msg.wParam = wParam;
4635 saved_mouse_button_msg.msg.lParam = lParam;
4636 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4637 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4638 }
4639 }
4640 return 0;
4641
ee78dc32 4642 case WM_LBUTTONUP:
5ac45f98 4643 case WM_RBUTTONUP:
7ce9aaca 4644 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4645 goto handle_plain_button;
4646
4647 {
4648 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4649 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4650
3cb20f4a
RS
4651 if ((button_state & this) == 0)
4652 return 0;
5ac45f98
GV
4653
4654 button_state &= ~this;
4655
4656 if (button_state & MMOUSE)
4657 {
4658 /* Only generate event when second button is released. */
4659 if ((button_state & other) == 0)
4660 {
4661 msg = WM_MBUTTONUP;
4662 button_state &= ~MMOUSE;
4663
4664 if (button_state) abort ();
4665 }
4666 else
4667 return 0;
4668 }
4669 else
4670 {
4671 /* Flush out saved message if necessary. */
84fb1139 4672 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4673 {
84fb1139 4674 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4675 }
4676 }
fbd6baed 4677 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4678 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4679
4680 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4681 saved_mouse_button_msg.msg.hwnd = 0;
4682 KillTimer (hwnd, mouse_button_timer);
4683 mouse_button_timer = 0;
5ac45f98
GV
4684
4685 if (button_state == 0)
4686 ReleaseCapture ();
4687 }
4688 return 0;
4689
74214547
JR
4690 case WM_XBUTTONDOWN:
4691 case WM_XBUTTONUP:
4692 if (w32_pass_extra_mouse_buttons_to_system)
4693 goto dflt;
4694 /* else fall through and process them. */
ee78dc32
GV
4695 case WM_MBUTTONDOWN:
4696 case WM_MBUTTONUP:
5ac45f98 4697 handle_plain_button:
ee78dc32
GV
4698 {
4699 BOOL up;
1edf84e7 4700 int button;
ee78dc32 4701
74214547 4702 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
4703 {
4704 if (up) ReleaseCapture ();
4705 else SetCapture (hwnd);
1edf84e7
GV
4706 button = (button == 0) ? LMOUSE :
4707 ((button == 1) ? MMOUSE : RMOUSE);
4708 if (up)
4709 button_state &= ~button;
4710 else
4711 button_state |= button;
ee78dc32
GV
4712 }
4713 }
4714
fbd6baed 4715 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4716 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
4717
4718 /* Need to return true for XBUTTON messages, false for others,
4719 to indicate that we processed the message. */
4720 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 4721
5ac45f98 4722 case WM_MOUSEMOVE:
9eb16b62
JR
4723 /* If the mouse has just moved into the frame, start tracking
4724 it, so we will be notified when it leaves the frame. Mouse
4725 tracking only works under W98 and NT4 and later. On earlier
4726 versions, there is no way of telling when the mouse leaves the
4727 frame, so we just have to put up with help-echo and mouse
4728 highlighting remaining while the frame is not active. */
4729 if (track_mouse_event_fn && !track_mouse_window)
4730 {
4731 TRACKMOUSEEVENT tme;
4732 tme.cbSize = sizeof (tme);
4733 tme.dwFlags = TME_LEAVE;
4734 tme.hwndTrack = hwnd;
4735
4736 track_mouse_event_fn (&tme);
4737 track_mouse_window = hwnd;
4738 }
4739 case WM_VSCROLL:
fbd6baed 4740 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4741 || (msg == WM_MOUSEMOVE && button_state == 0))
4742 {
fbd6baed 4743 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4744 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4745 return 0;
4746 }
4747
4748 /* Hang onto mouse move and scroll messages for a bit, to avoid
4749 sending such events to Emacs faster than it can process them.
4750 If we get more events before the timer from the first message
4751 expires, we just replace the first message. */
4752
4753 if (saved_mouse_move_msg.msg.hwnd == 0)
4754 mouse_move_timer =
adcc3809
GV
4755 SetTimer (hwnd, MOUSE_MOVE_ID,
4756 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4757
4758 /* Hold onto message for now. */
4759 saved_mouse_move_msg.msg.hwnd = hwnd;
4760 saved_mouse_move_msg.msg.message = msg;
4761 saved_mouse_move_msg.msg.wParam = wParam;
4762 saved_mouse_move_msg.msg.lParam = lParam;
4763 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4764 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4765
4766 return 0;
4767
1edf84e7
GV
4768 case WM_MOUSEWHEEL:
4769 wmsg.dwModifiers = w32_get_modifiers ();
4770 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4771 return 0;
4772
cb9e33d4
RS
4773 case WM_DROPFILES:
4774 wmsg.dwModifiers = w32_get_modifiers ();
4775 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4776 return 0;
4777
84fb1139
KH
4778 case WM_TIMER:
4779 /* Flush out saved messages if necessary. */
4780 if (wParam == mouse_button_timer)
5ac45f98 4781 {
84fb1139
KH
4782 if (saved_mouse_button_msg.msg.hwnd)
4783 {
4784 post_msg (&saved_mouse_button_msg);
4785 saved_mouse_button_msg.msg.hwnd = 0;
4786 }
4787 KillTimer (hwnd, mouse_button_timer);
4788 mouse_button_timer = 0;
4789 }
4790 else if (wParam == mouse_move_timer)
4791 {
4792 if (saved_mouse_move_msg.msg.hwnd)
4793 {
4794 post_msg (&saved_mouse_move_msg);
4795 saved_mouse_move_msg.msg.hwnd = 0;
4796 }
4797 KillTimer (hwnd, mouse_move_timer);
4798 mouse_move_timer = 0;
5ac45f98 4799 }
48094ace
JR
4800 else if (wParam == menu_free_timer)
4801 {
4802 KillTimer (hwnd, menu_free_timer);
4803 menu_free_timer = 0;
27605fa7 4804 f = x_window_to_frame (dpyinfo, hwnd);
48094ace
JR
4805 if (!f->output_data.w32->menu_command_in_progress)
4806 {
4807 /* Free memory used by owner-drawn and help-echo strings. */
4808 w32_free_menu_strings (hwnd);
4809 f->output_data.w32->menubar_active = 0;
4810 }
4811 }
5ac45f98 4812 return 0;
84fb1139
KH
4813
4814 case WM_NCACTIVATE:
4815 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4816 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4817 The only indication we get that something happened is receiving
4818 this message afterwards. So this is a good time to reset our
4819 keyboard modifiers' state. */
4820 reset_modifiers ();
4821 goto dflt;
da36a4d6 4822
1edf84e7 4823 case WM_INITMENU:
487163ac
AI
4824 button_state = 0;
4825 ReleaseCapture ();
1edf84e7
GV
4826 /* We must ensure menu bar is fully constructed and up to date
4827 before allowing user interaction with it. To achieve this
4828 we send this message to the lisp thread and wait for a
4829 reply (whose value is not actually needed) to indicate that
4830 the menu bar is now ready for use, so we can now return.
4831
4832 To remain responsive in the meantime, we enter a nested message
4833 loop that can process all other messages.
4834
4835 However, we skip all this if the message results from calling
4836 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4837 thread a message because it is blocked on us at this point. We
4838 set menubar_active before calling TrackPopupMenu to indicate
4839 this (there is no possibility of confusion with real menubar
4840 being active). */
4841
4842 f = x_window_to_frame (dpyinfo, hwnd);
4843 if (f
4844 && (f->output_data.w32->menubar_active
4845 /* We can receive this message even in the absence of a
4846 menubar (ie. when the system menu is activated) - in this
4847 case we do NOT want to forward the message, otherwise it
4848 will cause the menubar to suddenly appear when the user
4849 had requested it to be turned off! */
4850 || f->output_data.w32->menubar_widget == NULL))
4851 return 0;
4852
4853 {
4854 deferred_msg msg_buf;
4855
4856 /* Detect if message has already been deferred; in this case
4857 we cannot return any sensible value to ignore this. */
4858 if (find_deferred_msg (hwnd, msg) != NULL)
4859 abort ();
4860
4861 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4862 }
4863
4864 case WM_EXITMENULOOP:
4865 f = x_window_to_frame (dpyinfo, hwnd);
4866
48094ace
JR
4867 /* If a menu command is not already in progress, check again
4868 after a short delay, since Windows often (always?) sends the
4869 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4870 if (f && !f->output_data.w32->menu_command_in_progress)
4871 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
1edf84e7
GV
4872 goto dflt;
4873
126f2e35 4874 case WM_MENUSELECT:
4e3a1c61
JR
4875 /* Direct handling of help_echo in menus. Should be safe now
4876 that we generate the help_echo by placing a help event in the
4877 keyboard buffer. */
ca56d953 4878 {
ca56d953
JR
4879 HMENU menu = (HMENU) lParam;
4880 UINT menu_item = (UINT) LOWORD (wParam);
4881 UINT flags = (UINT) HIWORD (wParam);
4882
4e3a1c61 4883 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4884 }
126f2e35
JR
4885 return 0;
4886
87996783
GV
4887 case WM_MEASUREITEM:
4888 f = x_window_to_frame (dpyinfo, hwnd);
4889 if (f)
4890 {
4891 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4892
4893 if (pMis->CtlType == ODT_MENU)
4894 {
4895 /* Work out dimensions for popup menu titles. */
4896 char * title = (char *) pMis->itemData;
4897 HDC hdc = GetDC (hwnd);
4898 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4899 LOGFONT menu_logfont;
4900 HFONT old_font;
4901 SIZE size;
4902
4903 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4904 menu_logfont.lfWeight = FW_BOLD;
4905 menu_font = CreateFontIndirect (&menu_logfont);
4906 old_font = SelectObject (hdc, menu_font);
4907
dfff8a69
JR
4908 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4909 if (title)
4910 {
4911 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4912 pMis->itemWidth = size.cx;
4913 if (pMis->itemHeight < size.cy)
4914 pMis->itemHeight = size.cy;
4915 }
4916 else
4917 pMis->itemWidth = 0;
87996783
GV
4918
4919 SelectObject (hdc, old_font);
4920 DeleteObject (menu_font);
4921 ReleaseDC (hwnd, hdc);
4922 return TRUE;
4923 }
4924 }
4925 return 0;
4926
4927 case WM_DRAWITEM:
4928 f = x_window_to_frame (dpyinfo, hwnd);
4929 if (f)
4930 {
4931 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4932
4933 if (pDis->CtlType == ODT_MENU)
4934 {
4935 /* Draw popup menu title. */
4936 char * title = (char *) pDis->itemData;
212da13b
JR
4937 if (title)
4938 {
4939 HDC hdc = pDis->hDC;
4940 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4941 LOGFONT menu_logfont;
4942 HFONT old_font;
4943
4944 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4945 menu_logfont.lfWeight = FW_BOLD;
4946 menu_font = CreateFontIndirect (&menu_logfont);
4947 old_font = SelectObject (hdc, menu_font);
4948
4949 /* Always draw title as if not selected. */
4950 ExtTextOut (hdc,
4951 pDis->rcItem.left
4952 + GetSystemMetrics (SM_CXMENUCHECK),
4953 pDis->rcItem.top,
4954 ETO_OPAQUE, &pDis->rcItem,
4955 title, strlen (title), NULL);
4956
4957 SelectObject (hdc, old_font);
4958 DeleteObject (menu_font);
4959 }
87996783
GV
4960 return TRUE;
4961 }
4962 }
4963 return 0;
4964
1edf84e7
GV
4965#if 0
4966 /* Still not right - can't distinguish between clicks in the
4967 client area of the frame from clicks forwarded from the scroll
4968 bars - may have to hook WM_NCHITTEST to remember the mouse
4969 position and then check if it is in the client area ourselves. */
4970 case WM_MOUSEACTIVATE:
4971 /* Discard the mouse click that activates a frame, allowing the
4972 user to click anywhere without changing point (or worse!).
4973 Don't eat mouse clicks on scrollbars though!! */
4974 if (LOWORD (lParam) == HTCLIENT )
4975 return MA_ACTIVATEANDEAT;
4976 goto dflt;
4977#endif
4978
9eb16b62
JR
4979 case WM_MOUSELEAVE:
4980 /* No longer tracking mouse. */
4981 track_mouse_window = NULL;
4982
1edf84e7 4983 case WM_ACTIVATEAPP:
ccc2d29c 4984 case WM_ACTIVATE:
1edf84e7
GV
4985 case WM_WINDOWPOSCHANGED:
4986 case WM_SHOWWINDOW:
4987 /* Inform lisp thread that a frame might have just been obscured
4988 or exposed, so should recheck visibility of all frames. */
4989 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4990 goto dflt;
4991
da36a4d6 4992 case WM_SETFOCUS:
adcc3809
GV
4993 dpyinfo->faked_key = 0;
4994 reset_modifiers ();
ccc2d29c
GV
4995 register_hot_keys (hwnd);
4996 goto command;
8681157a 4997 case WM_KILLFOCUS:
ccc2d29c 4998 unregister_hot_keys (hwnd);
487163ac
AI
4999 button_state = 0;
5000 ReleaseCapture ();
65906840
JR
5001 /* Relinquish the system caret. */
5002 if (w32_system_caret_hwnd)
5003 {
93f2ca61 5004 w32_visible_system_caret_hwnd = NULL;
d285988b
JR
5005 w32_system_caret_hwnd = NULL;
5006 DestroyCaret ();
65906840 5007 }
48094ace
JR
5008 goto command;
5009 case WM_COMMAND:
5010 f = x_window_to_frame (dpyinfo, hwnd);
5011 if (f && HIWORD (wParam) == 0)
5012 {
5013 f->output_data.w32->menu_command_in_progress = 1;
5014 if (menu_free_timer)
5015 {
5016 KillTimer (hwnd, menu_free_timer);
5017 menu_free_timer = 0;
5018 }
5019 }
ee78dc32
GV
5020 case WM_MOVE:
5021 case WM_SIZE:
ccc2d29c 5022 command:
fbd6baed 5023 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
5024 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5025 goto dflt;
8847d890
RS
5026
5027 case WM_CLOSE:
fbd6baed 5028 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
5029 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5030 return 0;
5031
ee78dc32 5032 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
5033 /* Don't restrict the sizing of tip frames. */
5034 if (hwnd == tip_window)
5035 return 0;
ee78dc32
GV
5036 {
5037 WINDOWPLACEMENT wp;
5038 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
5039
5040 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
5041 GetWindowPlacement (hwnd, &wp);
5042
1edf84e7 5043 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
5044 {
5045 RECT rect;
5046 int wdiff;
5047 int hdiff;
1edf84e7
GV
5048 DWORD font_width;
5049 DWORD line_height;
5050 DWORD internal_border;
5051 DWORD scrollbar_extra;
ee78dc32
GV
5052 RECT wr;
5053
5ac45f98 5054 wp.length = sizeof(wp);
ee78dc32
GV
5055 GetWindowRect (hwnd, &wr);
5056
3c190163 5057 enter_crit ();
ee78dc32 5058
1edf84e7
GV
5059 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5060 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5061 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5062 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 5063
3c190163 5064 leave_crit ();
ee78dc32
GV
5065
5066 memset (&rect, 0, sizeof (rect));
5067 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
5068 GetMenu (hwnd) != NULL);
5069
1edf84e7
GV
5070 /* Force width and height of client area to be exact
5071 multiples of the character cell dimensions. */
5072 wdiff = (lppos->cx - (rect.right - rect.left)
5073 - 2 * internal_border - scrollbar_extra)
5074 % font_width;
5075 hdiff = (lppos->cy - (rect.bottom - rect.top)
5076 - 2 * internal_border)
5077 % line_height;
ee78dc32
GV
5078
5079 if (wdiff || hdiff)
5080 {
5081 /* For right/bottom sizing we can just fix the sizes.
5082 However for top/left sizing we will need to fix the X
5083 and Y positions as well. */
5084
5085 lppos->cx -= wdiff;
5086 lppos->cy -= hdiff;
5087
5088 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 5089 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
5090 {
5091 if (lppos->x != wr.left || lppos->y != wr.top)
5092 {
5093 lppos->x += wdiff;
5094 lppos->y += hdiff;
5095 }
5096 else
5097 {
5098 lppos->flags |= SWP_NOMOVE;
5099 }
5100 }
5101
1edf84e7 5102 return 0;
ee78dc32
GV
5103 }
5104 }
5105 }
ee78dc32
GV
5106
5107 goto dflt;
1edf84e7 5108
b1f918f8
GV
5109 case WM_GETMINMAXINFO:
5110 /* Hack to correct bug that allows Emacs frames to be resized
5111 below the Minimum Tracking Size. */
5112 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
5113 /* Hack to allow resizing the Emacs frame above the screen size.
5114 Note that Windows 9x limits coordinates to 16-bits. */
5115 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5116 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
5117 return 0;
5118
1edf84e7
GV
5119 case WM_EMACS_CREATESCROLLBAR:
5120 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5121 (struct scroll_bar *) lParam);
5122
5ac45f98 5123 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
5124 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5125
dfdb4047 5126 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
5127 {
5128 HWND foreground_window;
5129 DWORD foreground_thread, retval;
5130
5131 /* On NT 5.0, and apparently Windows 98, it is necessary to
5132 attach to the thread that currently has focus in order to
5133 pull the focus away from it. */
5134 foreground_window = GetForegroundWindow ();
5135 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5136 if (!foreground_window
5137 || foreground_thread == GetCurrentThreadId ()
5138 || !AttachThreadInput (GetCurrentThreadId (),
5139 foreground_thread, TRUE))
5140 foreground_thread = 0;
5141
5142 retval = SetForegroundWindow ((HWND) wParam);
5143
5144 /* Detach from the previous foreground thread. */
5145 if (foreground_thread)
5146 AttachThreadInput (GetCurrentThreadId (),
5147 foreground_thread, FALSE);
5148
5149 return retval;
5150 }
dfdb4047 5151
5ac45f98
GV
5152 case WM_EMACS_SETWINDOWPOS:
5153 {
1edf84e7
GV
5154 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5155 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5156 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5157 }
1edf84e7 5158
ee78dc32 5159 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5160 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5161 return DestroyWindow ((HWND) wParam);
5162
93f2ca61
JR
5163 case WM_EMACS_HIDE_CARET:
5164 return HideCaret (hwnd);
5165
5166 case WM_EMACS_SHOW_CARET:
5167 return ShowCaret (hwnd);
5168
65906840
JR
5169 case WM_EMACS_DESTROY_CARET:
5170 w32_system_caret_hwnd = NULL;
93f2ca61 5171 w32_visible_system_caret_hwnd = NULL;
65906840
JR
5172 return DestroyCaret ();
5173
5174 case WM_EMACS_TRACK_CARET:
5175 /* If there is currently no system caret, create one. */
5176 if (w32_system_caret_hwnd == NULL)
5177 {
93f2ca61
JR
5178 /* Use the default caret width, and avoid changing it
5179 unneccesarily, as it confuses screen reader software. */
65906840 5180 w32_system_caret_hwnd = hwnd;
93f2ca61 5181 CreateCaret (hwnd, NULL, 0,
65906840
JR
5182 w32_system_caret_height);
5183 }
93f2ca61
JR
5184
5185 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5186 return 0;
5187 /* Ensure visible caret gets turned on when requested. */
5188 else if (w32_use_visible_system_caret
5189 && w32_visible_system_caret_hwnd != hwnd)
5190 {
5191 w32_visible_system_caret_hwnd = hwnd;
5192 return ShowCaret (hwnd);
5193 }
5194 /* Ensure visible caret gets turned off when requested. */
5195 else if (!w32_use_visible_system_caret
5196 && w32_visible_system_caret_hwnd)
5197 {
5198 w32_visible_system_caret_hwnd = NULL;
5199 return HideCaret (hwnd);
5200 }
5201 else
5202 return 1;
65906840 5203
1edf84e7
GV
5204 case WM_EMACS_TRACKPOPUPMENU:
5205 {
5206 UINT flags;
5207 POINT *pos;
5208 int retval;
5209 pos = (POINT *)lParam;
5210 flags = TPM_CENTERALIGN;
5211 if (button_state & LMOUSE)
5212 flags |= TPM_LEFTBUTTON;
5213 else if (button_state & RMOUSE)
5214 flags |= TPM_RIGHTBUTTON;
5215
87996783
GV
5216 /* Remember we did a SetCapture on the initial mouse down event,
5217 so for safety, we make sure the capture is cancelled now. */
5218 ReleaseCapture ();
490822ff 5219 button_state = 0;
87996783 5220
1edf84e7
GV
5221 /* Use menubar_active to indicate that WM_INITMENU is from
5222 TrackPopupMenu below, and should be ignored. */
5223 f = x_window_to_frame (dpyinfo, hwnd);
5224 if (f)
5225 f->output_data.w32->menubar_active = 1;
5226
5227 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5228 0, hwnd, NULL))
5229 {
5230 MSG amsg;
5231 /* Eat any mouse messages during popupmenu */
5232 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5233 PM_REMOVE));
5234 /* Get the menu selection, if any */
5235 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5236 {
5237 retval = LOWORD (amsg.wParam);
5238 }
5239 else
5240 {
5241 retval = 0;
5242 }
1edf84e7
GV
5243 }
5244 else
5245 {
5246 retval = -1;
5247 }
5248
5249 return retval;
5250 }
5251
ee78dc32 5252 default:
93fbe8b7
GV
5253 /* Check for messages registered at runtime. */
5254 if (msg == msh_mousewheel)
5255 {
5256 wmsg.dwModifiers = w32_get_modifiers ();
5257 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5258 return 0;
5259 }
5260
ee78dc32
GV
5261 dflt:
5262 return DefWindowProc (hwnd, msg, wParam, lParam);
5263 }
5264
1edf84e7
GV
5265
5266 /* The most common default return code for handled messages is 0. */
5267 return 0;
ee78dc32
GV
5268}
5269
5270void
5271my_create_window (f)
5272 struct frame * f;
5273{
5274 MSG msg;
5275
1edf84e7
GV
5276 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5277 abort ();
ee78dc32
GV
5278 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5279}
5280
ca56d953
JR
5281
5282/* Create a tooltip window. Unlike my_create_window, we do not do this
5283 indirectly via the Window thread, as we do not need to process Window
5284 messages for the tooltip. Creating tooltips indirectly also creates
5285 deadlocks when tooltips are created for menu items. */
5286void
5287my_create_tip_window (f)
5288 struct frame *f;
5289{
bfd6edcc 5290 RECT rect;
ca56d953 5291
bfd6edcc
JR
5292 rect.left = rect.top = 0;
5293 rect.right = PIXEL_WIDTH (f);
5294 rect.bottom = PIXEL_HEIGHT (f);
5295
5296 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5297 FRAME_EXTERNAL_MENU_BAR (f));
5298
5299 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5300 = CreateWindow (EMACS_CLASS,
5301 f->namebuf,
5302 f->output_data.w32->dwStyle,
5303 f->output_data.w32->left_pos,
5304 f->output_data.w32->top_pos,
bfd6edcc
JR
5305 rect.right - rect.left,
5306 rect.bottom - rect.top,
ca56d953
JR
5307 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5308 NULL,
5309 hinst,
5310 NULL);
5311
bfd6edcc 5312 if (tip_window)
ca56d953 5313 {
bfd6edcc
JR
5314 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5315 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5316 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5317 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5318
5319 /* Tip frames have no scrollbars. */
5320 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5321
5322 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5323 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5324 }
5325}
5326
5327
fbd6baed 5328/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5329
5330static void
fbd6baed 5331w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5332 struct frame *f;
5333 long window_prompting;
5334 int minibuffer_only;
5335{
5336 BLOCK_INPUT;
5337
5338 /* Use the resource name as the top-level window name
5339 for looking up resources. Make a non-Lisp copy
5340 for the window manager, so GC relocation won't bother it.
5341
5342 Elsewhere we specify the window name for the window manager. */
5343
5344 {
5345 char *str = (char *) XSTRING (Vx_resource_name)->data;
5346 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5347 strcpy (f->namebuf, str);
5348 }
5349
5350 my_create_window (f);
5351
5352 validate_x_resource_name ();
5353
5354 /* x_set_name normally ignores requests to set the name if the
5355 requested name is the same as the current name. This is the one
5356 place where that assumption isn't correct; f->name is set, but
5357 the server hasn't been told. */
5358 {
5359 Lisp_Object name;
5360 int explicit = f->explicit_name;
5361
5362 f->explicit_name = 0;
5363 name = f->name;
5364 f->name = Qnil;
5365 x_set_name (f, name, explicit);
5366 }
5367
5368 UNBLOCK_INPUT;
5369
5370 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5371 initialize_frame_menubar (f);
5372
fbd6baed 5373 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5374 error ("Unable to create window");
5375}
5376
5377/* Handle the icon stuff for this window. Perhaps later we might
5378 want an x_set_icon_position which can be called interactively as
5379 well. */
5380
5381static void
5382x_icon (f, parms)
5383 struct frame *f;
5384 Lisp_Object parms;
5385{
5386 Lisp_Object icon_x, icon_y;
5387
e9e23e23 5388 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5389 icons in the tray. */
6fc2811b
JR
5390 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5391 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5392 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5393 {
b7826503
PJ
5394 CHECK_NUMBER (icon_x);
5395 CHECK_NUMBER (icon_y);
ee78dc32
GV
5396 }
5397 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5398 error ("Both left and top icon corners of icon must be specified");
5399
5400 BLOCK_INPUT;
5401
5402 if (! EQ (icon_x, Qunbound))
5403 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5404
1edf84e7
GV
5405#if 0 /* TODO */
5406 /* Start up iconic or window? */
5407 x_wm_set_window_state
6fc2811b 5408 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5409 ? IconicState
5410 : NormalState));
5411
5412 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5413 ? f->icon_name
5414 : f->name))->data);
5415#endif
5416
ee78dc32
GV
5417 UNBLOCK_INPUT;
5418}
5419
6fc2811b
JR
5420
5421static void
5422x_make_gc (f)
5423 struct frame *f;
5424{
5425 XGCValues gc_values;
5426
5427 BLOCK_INPUT;
5428
5429 /* Create the GC's of this frame.
5430 Note that many default values are used. */
5431
5432 /* Normal video */
5433 gc_values.font = f->output_data.w32->font;
5434
5435 /* Cursor has cursor-color background, background-color foreground. */
5436 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5437 gc_values.background = f->output_data.w32->cursor_pixel;
5438 f->output_data.w32->cursor_gc
5439 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5440 (GCFont | GCForeground | GCBackground),
5441 &gc_values);
5442
5443 /* Reliefs. */
5444 f->output_data.w32->white_relief.gc = 0;
5445 f->output_data.w32->black_relief.gc = 0;
5446
5447 UNBLOCK_INPUT;
5448}
5449
5450
937e601e
AI
5451/* Handler for signals raised during x_create_frame and
5452 x_create_top_frame. FRAME is the frame which is partially
5453 constructed. */
5454
5455static Lisp_Object
5456unwind_create_frame (frame)
5457 Lisp_Object frame;
5458{
5459 struct frame *f = XFRAME (frame);
5460
5461 /* If frame is ``official'', nothing to do. */
5462 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5463 {
5464#ifdef GLYPH_DEBUG
5465 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5466#endif
5467
5468 x_free_frame_resources (f);
5469
5470 /* Check that reference counts are indeed correct. */
5471 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5472 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5473
5474 return Qt;
937e601e
AI
5475 }
5476
5477 return Qnil;
5478}
5479
5480
ee78dc32
GV
5481DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5482 1, 1, 0,
74e1aeec
JR
5483 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5484Returns an Emacs frame object.
5485ALIST is an alist of frame parameters.
5486If the parameters specify that the frame should not have a minibuffer,
5487and do not specify a specific minibuffer window to use,
5488then `default-minibuffer-frame' must be a frame whose minibuffer can
5489be shared by the new frame.
5490
5491This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5492 (parms)
5493 Lisp_Object parms;
5494{
5495 struct frame *f;
5496 Lisp_Object frame, tem;
5497 Lisp_Object name;
5498 int minibuffer_only = 0;
5499 long window_prompting = 0;
5500 int width, height;
331379bf 5501 int count = SPECPDL_INDEX ();
1edf84e7 5502 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5503 Lisp_Object display;
6fc2811b 5504 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5505 Lisp_Object parent;
5506 struct kboard *kb;
5507
4587b026
GV
5508 check_w32 ();
5509
ee78dc32
GV
5510 /* Use this general default value to start with
5511 until we know if this frame has a specified name. */
5512 Vx_resource_name = Vinvocation_name;
5513
6fc2811b 5514 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5515 if (EQ (display, Qunbound))
5516 display = Qnil;
5517 dpyinfo = check_x_display_info (display);
5518#ifdef MULTI_KBOARD
5519 kb = dpyinfo->kboard;
5520#else
5521 kb = &the_only_kboard;
5522#endif
5523
6fc2811b 5524 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5525 if (!STRINGP (name)
5526 && ! EQ (name, Qunbound)
5527 && ! NILP (name))
5528 error ("Invalid frame name--not a string or nil");
5529
5530 if (STRINGP (name))
5531 Vx_resource_name = name;
5532
5533 /* See if parent window is specified. */
6fc2811b 5534 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5535 if (EQ (parent, Qunbound))
5536 parent = Qnil;
5537 if (! NILP (parent))
b7826503 5538 CHECK_NUMBER (parent);
ee78dc32 5539
1edf84e7
GV
5540 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5541 /* No need to protect DISPLAY because that's not used after passing
5542 it to make_frame_without_minibuffer. */
5543 frame = Qnil;
5544 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5545 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5546 RES_TYPE_SYMBOL);
ee78dc32
GV
5547 if (EQ (tem, Qnone) || NILP (tem))
5548 f = make_frame_without_minibuffer (Qnil, kb, display);
5549 else if (EQ (tem, Qonly))
5550 {
5551 f = make_minibuffer_frame ();
5552 minibuffer_only = 1;
5553 }
5554 else if (WINDOWP (tem))
5555 f = make_frame_without_minibuffer (tem, kb, display);
5556 else
5557 f = make_frame (1);
5558
1edf84e7
GV
5559 XSETFRAME (frame, f);
5560
ee78dc32
GV
5561 /* Note that Windows does support scroll bars. */
5562 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5563 /* By default, make scrollbars the system standard width. */
5564 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5565
fbd6baed 5566 f->output_method = output_w32;
6fc2811b
JR
5567 f->output_data.w32 =
5568 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5569 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5570 FRAME_FONTSET (f) = -1;
937e601e 5571 record_unwind_protect (unwind_create_frame, frame);
4587b026 5572
1edf84e7 5573 f->icon_name
6fc2811b 5574 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5575 if (! STRINGP (f->icon_name))
5576 f->icon_name = Qnil;
5577
fbd6baed 5578/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5579#ifdef MULTI_KBOARD
5580 FRAME_KBOARD (f) = kb;
5581#endif
5582
5583 /* Specify the parent under which to make this window. */
5584
5585 if (!NILP (parent))
5586 {
1660f34a 5587 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5588 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5589 }
5590 else
5591 {
fbd6baed
GV
5592 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5593 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5594 }
5595
ee78dc32
GV
5596 /* Set the name; the functions to which we pass f expect the name to
5597 be set. */
5598 if (EQ (name, Qunbound) || NILP (name))
5599 {
fbd6baed 5600 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5601 f->explicit_name = 0;
5602 }
5603 else
5604 {
5605 f->name = name;
5606 f->explicit_name = 1;
5607 /* use the frame's title when getting resources for this frame. */
5608 specbind (Qx_resource_name, name);
5609 }
5610
5611 /* Extract the window parameters from the supplied values
5612 that are needed to determine window geometry. */
5613 {
5614 Lisp_Object font;
5615
6fc2811b
JR
5616 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5617
ee78dc32
GV
5618 BLOCK_INPUT;
5619 /* First, try whatever font the caller has specified. */
5620 if (STRINGP (font))
4587b026
GV
5621 {
5622 tem = Fquery_fontset (font, Qnil);
5623 if (STRINGP (tem))
5624 font = x_new_fontset (f, XSTRING (tem)->data);
5625 else
1075afa9 5626 font = x_new_font (f, XSTRING (font)->data);
4587b026 5627 }
ee78dc32
GV
5628 /* Try out a font which we hope has bold and italic variations. */
5629 if (!STRINGP (font))
e39649be 5630 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5631 if (! STRINGP (font))
6fc2811b 5632 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5633 /* If those didn't work, look for something which will at least work. */
5634 if (! STRINGP (font))
6fc2811b 5635 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5636 UNBLOCK_INPUT;
5637 if (! STRINGP (font))
1edf84e7 5638 font = build_string ("Fixedsys");
ee78dc32
GV
5639
5640 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5641 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5642 }
5643
5644 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5645 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5646 /* This defaults to 2 in order to match xterm. We recognize either
5647 internalBorderWidth or internalBorder (which is what xterm calls
5648 it). */
5649 if (NILP (Fassq (Qinternal_border_width, parms)))
5650 {
5651 Lisp_Object value;
5652
6fc2811b 5653 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5654 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5655 if (! EQ (value, Qunbound))
5656 parms = Fcons (Fcons (Qinternal_border_width, value),
5657 parms);
5658 }
1edf84e7 5659 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5660 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5661 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5662 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5663 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5664
5665 /* Also do the stuff which must be set before the window exists. */
5666 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5667 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5668 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5669 "background", "Background", RES_TYPE_STRING);
ee78dc32 5670 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5671 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5672 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5673 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5674 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5675 "borderColor", "BorderColor", RES_TYPE_STRING);
5676 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5677 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5678 x_default_parameter (f, parms, Qline_spacing, Qnil,
5679 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5680 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5681 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5682 x_default_parameter (f, parms, Qright_fringe, Qnil,
5683 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5684
ee78dc32 5685
6fc2811b
JR
5686 /* Init faces before x_default_parameter is called for scroll-bar
5687 parameters because that function calls x_set_scroll_bar_width,
5688 which calls change_frame_size, which calls Fset_window_buffer,
5689 which runs hooks, which call Fvertical_motion. At the end, we
5690 end up in init_iterator with a null face cache, which should not
5691 happen. */
5692 init_frame_faces (f);
5693
ee78dc32 5694 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b 5695 "menuBar", "MenuBar", RES_TYPE_NUMBER);
d3109773 5696 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
6fc2811b 5697 "toolBar", "ToolBar", RES_TYPE_NUMBER);
919f1e88 5698
1edf84e7 5699 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5700 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5701 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5702 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
5703 x_default_parameter (f, parms, Qfullscreen, Qnil,
5704 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 5705
fbd6baed
GV
5706 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5707 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5708
5709 /* Add the tool-bar height to the initial frame height so that the
5710 user gets a text display area of the size he specified with -g or
5711 via .Xdefaults. Later changes of the tool-bar height don't
5712 change the frame size. This is done so that users can create
5713 tall Emacs frames without having to guess how tall the tool-bar
5714 will get. */
5715 if (FRAME_TOOL_BAR_LINES (f))
5716 {
5717 int margin, relief, bar_height;
5718
a05e2bae 5719 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5720 ? tool_bar_button_relief
5721 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5722
5723 if (INTEGERP (Vtool_bar_button_margin)
5724 && XINT (Vtool_bar_button_margin) > 0)
5725 margin = XFASTINT (Vtool_bar_button_margin);
5726 else if (CONSP (Vtool_bar_button_margin)
5727 && INTEGERP (XCDR (Vtool_bar_button_margin))
5728 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5729 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5730 else
5731 margin = 0;
5732
5733 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5734 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5735 }
5736
ee78dc32
GV
5737 window_prompting = x_figure_window_size (f, parms);
5738
5739 if (window_prompting & XNegative)
5740 {
5741 if (window_prompting & YNegative)
fbd6baed 5742 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5743 else
fbd6baed 5744 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5745 }
5746 else
5747 {
5748 if (window_prompting & YNegative)
fbd6baed 5749 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5750 else
fbd6baed 5751 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5752 }
5753
fbd6baed 5754 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5755
6fc2811b
JR
5756 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5757 f->no_split = minibuffer_only || EQ (tem, Qt);
5758
fbd6baed 5759 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5760 x_icon (f, parms);
6fc2811b
JR
5761
5762 x_make_gc (f);
5763
5764 /* Now consider the frame official. */
5765 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5766 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5767
5768 /* We need to do this after creating the window, so that the
5769 icon-creation functions can say whose icon they're describing. */
5770 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5771 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5772
5773 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5774 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5775 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5776 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5777 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5778 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5779 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5780 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5781
5782 /* Dimensions, especially f->height, must be done via change_frame_size.
5783 Change will not be effected unless different from the current
5784 f->height. */
5785 width = f->width;
5786 height = f->height;
dc220243 5787
1026b400
RS
5788 f->height = 0;
5789 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5790 change_frame_size (f, height, width, 1, 0, 0);
5791
6fc2811b
JR
5792 /* Tell the server what size and position, etc, we want, and how
5793 badly we want them. This should be done after we have the menu
5794 bar so that its size can be taken into account. */
ee78dc32
GV
5795 BLOCK_INPUT;
5796 x_wm_set_size_hint (f, window_prompting, 0);
5797 UNBLOCK_INPUT;
5798
815d969e
JR
5799 /* Avoid a bug that causes the new frame to never become visible if
5800 an echo area message is displayed during the following call1. */
5801 specbind(Qredisplay_dont_pause, Qt);
5802
4694d762
JR
5803 /* Set up faces after all frame parameters are known. This call
5804 also merges in face attributes specified for new frames. If we
5805 don't do this, the `menu' face for instance won't have the right
5806 colors, and the menu bar won't appear in the specified colors for
5807 new frames. */
5808 call1 (Qface_set_after_frame_default, frame);
5809
6fc2811b
JR
5810 /* Make the window appear on the frame and enable display, unless
5811 the caller says not to. However, with explicit parent, Emacs
5812 cannot control visibility, so don't try. */
fbd6baed 5813 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5814 {
5815 Lisp_Object visibility;
5816
6fc2811b 5817 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5818 if (EQ (visibility, Qunbound))
5819 visibility = Qt;
5820
5821 if (EQ (visibility, Qicon))
5822 x_iconify_frame (f);
5823 else if (! NILP (visibility))
5824 x_make_frame_visible (f);
5825 else
5826 /* Must have been Qnil. */
5827 ;
5828 }
6fc2811b 5829 UNGCPRO;
9e57df62
GM
5830
5831 /* Make sure windows on this frame appear in calls to next-window
5832 and similar functions. */
5833 Vwindow_list = Qnil;
5834
ee78dc32
GV
5835 return unbind_to (count, frame);
5836}
5837
5838/* FRAME is used only to get a handle on the X display. We don't pass the
5839 display info directly because we're called from frame.c, which doesn't
5840 know about that structure. */
5841Lisp_Object
5842x_get_focus_frame (frame)
5843 struct frame *frame;
5844{
fbd6baed 5845 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5846 Lisp_Object xfocus;
fbd6baed 5847 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5848 return Qnil;
5849
fbd6baed 5850 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5851 return xfocus;
5852}
1edf84e7
GV
5853
5854DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5855 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5856 (frame)
5857 Lisp_Object frame;
5858{
5859 x_focus_on_frame (check_x_frame (frame));
5860 return Qnil;
5861}
5862
ee78dc32 5863\f
767b1ff0
JR
5864/* Return the charset portion of a font name. */
5865char * xlfd_charset_of_font (char * fontname)
5866{
5867 char *charset, *encoding;
5868
5869 encoding = strrchr(fontname, '-');
ceb12877 5870 if (!encoding || encoding == fontname)
767b1ff0
JR
5871 return NULL;
5872
478ea067
AI
5873 for (charset = encoding - 1; charset >= fontname; charset--)
5874 if (*charset == '-')
5875 break;
767b1ff0 5876
478ea067 5877 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5878 return NULL;
5879
5880 return charset + 1;
5881}
5882
33d52f9c
GV
5883struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5884 int size, char* filename);
8edb0a6f 5885static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5886static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5887 char * charset);
5888static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5889
8edb0a6f 5890static struct font_info *
33d52f9c 5891w32_load_system_font (f,fontname,size)
55dcfc15
AI
5892 struct frame *f;
5893 char * fontname;
5894 int size;
ee78dc32 5895{
4587b026
GV
5896 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5897 Lisp_Object font_names;
5898
4587b026
GV
5899 /* Get a list of all the fonts that match this name. Once we
5900 have a list of matching fonts, we compare them against the fonts
5901 we already have loaded by comparing names. */
5902 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5903
5904 if (!NILP (font_names))
3c190163 5905 {
4587b026
GV
5906 Lisp_Object tail;
5907 int i;
4587b026
GV
5908
5909 /* First check if any are already loaded, as that is cheaper
5910 than loading another one. */
5911 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5912 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5913 if (dpyinfo->font_table[i].name
5914 && (!strcmp (dpyinfo->font_table[i].name,
5915 XSTRING (XCAR (tail))->data)
5916 || !strcmp (dpyinfo->font_table[i].full_name,
5917 XSTRING (XCAR (tail))->data)))
4587b026 5918 return (dpyinfo->font_table + i);
6fc2811b 5919
8e713be6 5920 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5921 }
1075afa9 5922 else if (w32_strict_fontnames)
5ca0cd71
GV
5923 {
5924 /* If EnumFontFamiliesEx was available, we got a full list of
5925 fonts back so stop now to avoid the possibility of loading a
5926 random font. If we had to fall back to EnumFontFamilies, the
5927 list is incomplete, so continue whether the font we want was
5928 listed or not. */
5929 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5930 FARPROC enum_font_families_ex
1075afa9 5931 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5932 if (enum_font_families_ex)
5933 return NULL;
5934 }
4587b026
GV
5935
5936 /* Load the font and add it to the table. */
5937 {
767b1ff0 5938 char *full_name, *encoding, *charset;
4587b026
GV
5939 XFontStruct *font;
5940 struct font_info *fontp;
3c190163 5941 LOGFONT lf;
4587b026 5942 BOOL ok;
19c291d3 5943 int codepage;
6fc2811b 5944 int i;
5ac45f98 5945
4587b026 5946 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5947 return (NULL);
5ac45f98 5948
4587b026
GV
5949 if (!*lf.lfFaceName)
5950 /* If no name was specified for the font, we get a random font
5951 from CreateFontIndirect - this is not particularly
5952 desirable, especially since CreateFontIndirect does not
5953 fill out the missing name in lf, so we never know what we
5954 ended up with. */
5955 return NULL;
5956
d65a9cdc
JR
5957 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5958 since those fonts leave garbage behind. */
5959 lf.lfQuality = ANTIALIASED_QUALITY;
5960
3c190163 5961 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5962 bzero (font, sizeof (*font));
5ac45f98 5963
33d52f9c
GV
5964 /* Set bdf to NULL to indicate that this is a Windows font. */
5965 font->bdf = NULL;
5ac45f98 5966
3c190163 5967 BLOCK_INPUT;
5ac45f98
GV
5968
5969 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5970
1a292d24
AI
5971 if (font->hfont == NULL)
5972 {
5973 ok = FALSE;
5974 }
5975 else
5976 {
5977 HDC hdc;
5978 HANDLE oldobj;
19c291d3
AI
5979
5980 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5981
5982 hdc = GetDC (dpyinfo->root_window);
5983 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5984
1a292d24 5985 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5986 if (codepage == CP_UNICODE)
5987 font->double_byte_p = 1;
5988 else
8b77111c
AI
5989 {
5990 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5991 don't report themselves as double byte fonts, when
5992 patently they are. So instead of trusting
5993 GetFontLanguageInfo, we check the properties of the
5994 codepage directly, since that is ultimately what we are
5995 working from anyway. */
5996 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5997 CPINFO cpi = {0};
5998 GetCPInfo (codepage, &cpi);
5999 font->double_byte_p = cpi.MaxCharSize > 1;
6000 }
5c6682be 6001
1a292d24
AI
6002 SelectObject (hdc, oldobj);
6003 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
6004 /* Fill out details in lf according to the font that was
6005 actually loaded. */
6006 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
6007 lf.lfWidth = font->tm.tmAveCharWidth;
6008 lf.lfWeight = font->tm.tmWeight;
6009 lf.lfItalic = font->tm.tmItalic;
6010 lf.lfCharSet = font->tm.tmCharSet;
6011 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 6012 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
6013 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
6014 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
6015
6016 w32_cache_char_metrics (font);
1a292d24 6017 }
5ac45f98 6018
1a292d24 6019 UNBLOCK_INPUT;
5ac45f98 6020
4587b026
GV
6021 if (!ok)
6022 {
1a292d24
AI
6023 w32_unload_font (dpyinfo, font);
6024 return (NULL);
6025 }
ee78dc32 6026
6fc2811b
JR
6027 /* Find a free slot in the font table. */
6028 for (i = 0; i < dpyinfo->n_fonts; ++i)
6029 if (dpyinfo->font_table[i].name == NULL)
6030 break;
6031
6032 /* If no free slot found, maybe enlarge the font table. */
6033 if (i == dpyinfo->n_fonts
6034 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 6035 {
6fc2811b
JR
6036 int sz;
6037 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6038 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 6039 dpyinfo->font_table
6fc2811b 6040 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
6041 }
6042
6fc2811b
JR
6043 fontp = dpyinfo->font_table + i;
6044 if (i == dpyinfo->n_fonts)
6045 ++dpyinfo->n_fonts;
4587b026
GV
6046
6047 /* Now fill in the slots of *FONTP. */
6048 BLOCK_INPUT;
6049 fontp->font = font;
6fc2811b 6050 fontp->font_idx = i;
4587b026
GV
6051 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6052 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6053
767b1ff0
JR
6054 charset = xlfd_charset_of_font (fontname);
6055
19c291d3
AI
6056 /* Cache the W32 codepage for a font. This makes w32_encode_char
6057 (called for every glyph during redisplay) much faster. */
6058 fontp->codepage = codepage;
6059
4587b026
GV
6060 /* Work out the font's full name. */
6061 full_name = (char *)xmalloc (100);
767b1ff0 6062 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
6063 fontp->full_name = full_name;
6064 else
6065 {
6066 /* If all else fails - just use the name we used to load it. */
6067 xfree (full_name);
6068 fontp->full_name = fontp->name;
6069 }
6070
6071 fontp->size = FONT_WIDTH (font);
6072 fontp->height = FONT_HEIGHT (font);
6073
6074 /* The slot `encoding' specifies how to map a character
6075 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
6076 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6077 (0:0x20..0x7F, 1:0xA0..0xFF,
6078 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 6079 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 6080 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
6081 which is never used by any charset. If mapping can't be
6082 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
6083
6084 /* SJIS fonts need to be set to type 4, all others seem to work as
6085 type FONT_ENCODING_NOT_DECIDED. */
6086 encoding = strrchr (fontp->name, '-');
d84b082d 6087 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 6088 fontp->encoding[1] = 4;
33d52f9c 6089 else
1c885fe1 6090 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
6091
6092 /* The following three values are set to 0 under W32, which is
6093 what they get set to if XGetFontProperty fails under X. */
6094 fontp->baseline_offset = 0;
6095 fontp->relative_compose = 0;
33d52f9c 6096 fontp->default_ascent = 0;
4587b026 6097
6fc2811b
JR
6098 /* Set global flag fonts_changed_p to non-zero if the font loaded
6099 has a character with a smaller width than any other character
f7b9d4d1 6100 before, or if the font loaded has a smaller height than any
6fc2811b
JR
6101 other font loaded before. If this happens, it will make a
6102 glyph matrix reallocation necessary. */
f7b9d4d1 6103 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 6104 UNBLOCK_INPUT;
4587b026
GV
6105 return fontp;
6106 }
6107}
6108
33d52f9c
GV
6109/* Load font named FONTNAME of size SIZE for frame F, and return a
6110 pointer to the structure font_info while allocating it dynamically.
6111 If loading fails, return NULL. */
6112struct font_info *
6113w32_load_font (f,fontname,size)
6114struct frame *f;
6115char * fontname;
6116int size;
6117{
6118 Lisp_Object bdf_fonts;
6119 struct font_info *retval = NULL;
6120
8edb0a6f 6121 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
6122
6123 while (!retval && CONSP (bdf_fonts))
6124 {
6125 char *bdf_name, *bdf_file;
6126 Lisp_Object bdf_pair;
6127
8e713be6
KR
6128 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6129 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6130 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
6131
6132 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6133
8e713be6 6134 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
6135 }
6136
6137 if (retval)
6138 return retval;
6139
6140 return w32_load_system_font(f, fontname, size);
6141}
6142
6143
ee78dc32 6144void
fbd6baed
GV
6145w32_unload_font (dpyinfo, font)
6146 struct w32_display_info *dpyinfo;
ee78dc32
GV
6147 XFontStruct * font;
6148{
6149 if (font)
6150 {
c6be3860 6151 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
6152 if (font->bdf) w32_free_bdf_font (font->bdf);
6153
3c190163 6154 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
6155 xfree (font);
6156 }
6157}
6158
fbd6baed 6159/* The font conversion stuff between x and w32 */
ee78dc32
GV
6160
6161/* X font string is as follows (from faces.el)
6162 * (let ((- "[-?]")
6163 * (foundry "[^-]+")
6164 * (family "[^-]+")
6165 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6166 * (weight\? "\\([^-]*\\)") ; 1
6167 * (slant "\\([ior]\\)") ; 2
6168 * (slant\? "\\([^-]?\\)") ; 2
6169 * (swidth "\\([^-]*\\)") ; 3
6170 * (adstyle "[^-]*") ; 4
6171 * (pixelsize "[0-9]+")
6172 * (pointsize "[0-9][0-9]+")
6173 * (resx "[0-9][0-9]+")
6174 * (resy "[0-9][0-9]+")
6175 * (spacing "[cmp?*]")
6176 * (avgwidth "[0-9]+")
6177 * (registry "[^-]+")
6178 * (encoding "[^-]+")
6179 * )
ee78dc32 6180 */
ee78dc32 6181
8edb0a6f 6182static LONG
fbd6baed 6183x_to_w32_weight (lpw)
ee78dc32
GV
6184 char * lpw;
6185{
6186 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6187
6188 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6189 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6190 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6191 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6192 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6193 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6194 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6195 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6196 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6197 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6198 else
5ac45f98 6199 return FW_DONTCARE;
ee78dc32
GV
6200}
6201
5ac45f98 6202
8edb0a6f 6203static char *
fbd6baed 6204w32_to_x_weight (fnweight)
ee78dc32
GV
6205 int fnweight;
6206{
5ac45f98
GV
6207 if (fnweight >= FW_HEAVY) return "heavy";
6208 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6209 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6210 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6211 if (fnweight >= FW_MEDIUM) return "medium";
6212 if (fnweight >= FW_NORMAL) return "normal";
6213 if (fnweight >= FW_LIGHT) return "light";
6214 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6215 if (fnweight >= FW_THIN) return "thin";
6216 else
6217 return "*";
6218}
6219
8edb0a6f 6220static LONG
fbd6baed 6221x_to_w32_charset (lpcs)
5ac45f98
GV
6222 char * lpcs;
6223{
767b1ff0 6224 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6225 char *charset;
6226 int len = strlen (lpcs);
6227
6228 /* Support "*-#nnn" format for unknown charsets. */
6229 if (strncmp (lpcs, "*-#", 3) == 0)
6230 return atoi (lpcs + 3);
6231
6232 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6233 charset = alloca (len + 1);
6234 strcpy (charset, lpcs);
6235 lpcs = strchr (charset, '*');
6236 if (lpcs)
6237 *lpcs = 0;
4587b026 6238
dfff8a69
JR
6239 /* Look through w32-charset-info-alist for the character set.
6240 Format of each entry is
6241 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6242 */
8b77111c 6243 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6244
767b1ff0
JR
6245 if (NILP(this_entry))
6246 {
6247 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6248 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6249 return ANSI_CHARSET;
6250 else
6251 return DEFAULT_CHARSET;
6252 }
6253
6254 w32_charset = Fcar (Fcdr (this_entry));
6255
d84b082d 6256 /* Translate Lisp symbol to number. */
767b1ff0
JR
6257 if (w32_charset == Qw32_charset_ansi)
6258 return ANSI_CHARSET;
6259 if (w32_charset == Qw32_charset_symbol)
6260 return SYMBOL_CHARSET;
6261 if (w32_charset == Qw32_charset_shiftjis)
6262 return SHIFTJIS_CHARSET;
6263 if (w32_charset == Qw32_charset_hangeul)
6264 return HANGEUL_CHARSET;
6265 if (w32_charset == Qw32_charset_chinesebig5)
6266 return CHINESEBIG5_CHARSET;
6267 if (w32_charset == Qw32_charset_gb2312)
6268 return GB2312_CHARSET;
6269 if (w32_charset == Qw32_charset_oem)
6270 return OEM_CHARSET;
dfff8a69 6271#ifdef JOHAB_CHARSET
767b1ff0
JR
6272 if (w32_charset == Qw32_charset_johab)
6273 return JOHAB_CHARSET;
6274 if (w32_charset == Qw32_charset_easteurope)
6275 return EASTEUROPE_CHARSET;
6276 if (w32_charset == Qw32_charset_turkish)
6277 return TURKISH_CHARSET;
6278 if (w32_charset == Qw32_charset_baltic)
6279 return BALTIC_CHARSET;
6280 if (w32_charset == Qw32_charset_russian)
6281 return RUSSIAN_CHARSET;
6282 if (w32_charset == Qw32_charset_arabic)
6283 return ARABIC_CHARSET;
6284 if (w32_charset == Qw32_charset_greek)
6285 return GREEK_CHARSET;
6286 if (w32_charset == Qw32_charset_hebrew)
6287 return HEBREW_CHARSET;
6288 if (w32_charset == Qw32_charset_vietnamese)
6289 return VIETNAMESE_CHARSET;
6290 if (w32_charset == Qw32_charset_thai)
6291 return THAI_CHARSET;
6292 if (w32_charset == Qw32_charset_mac)
6293 return MAC_CHARSET;
dfff8a69 6294#endif /* JOHAB_CHARSET */
5ac45f98 6295#ifdef UNICODE_CHARSET
767b1ff0
JR
6296 if (w32_charset == Qw32_charset_unicode)
6297 return UNICODE_CHARSET;
5ac45f98 6298#endif
dfff8a69
JR
6299
6300 return DEFAULT_CHARSET;
5ac45f98
GV
6301}
6302
dfff8a69 6303
8edb0a6f 6304static char *
fbd6baed 6305w32_to_x_charset (fncharset)
5ac45f98
GV
6306 int fncharset;
6307{
5e905a57 6308 static char buf[32];
767b1ff0 6309 Lisp_Object charset_type;
1edf84e7 6310
5ac45f98
GV
6311 switch (fncharset)
6312 {
767b1ff0
JR
6313 case ANSI_CHARSET:
6314 /* Handle startup case of w32-charset-info-alist not
6315 being set up yet. */
6316 if (NILP(Vw32_charset_info_alist))
6317 return "iso8859-1";
6318 charset_type = Qw32_charset_ansi;
6319 break;
6320 case DEFAULT_CHARSET:
6321 charset_type = Qw32_charset_default;
6322 break;
6323 case SYMBOL_CHARSET:
6324 charset_type = Qw32_charset_symbol;
6325 break;
6326 case SHIFTJIS_CHARSET:
6327 charset_type = Qw32_charset_shiftjis;
6328 break;
6329 case HANGEUL_CHARSET:
6330 charset_type = Qw32_charset_hangeul;
6331 break;
6332 case GB2312_CHARSET:
6333 charset_type = Qw32_charset_gb2312;
6334 break;
6335 case CHINESEBIG5_CHARSET:
6336 charset_type = Qw32_charset_chinesebig5;
6337 break;
6338 case OEM_CHARSET:
6339 charset_type = Qw32_charset_oem;
6340 break;
4587b026
GV
6341
6342 /* More recent versions of Windows (95 and NT4.0) define more
6343 character sets. */
6344#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6345 case EASTEUROPE_CHARSET:
6346 charset_type = Qw32_charset_easteurope;
6347 break;
6348 case TURKISH_CHARSET:
6349 charset_type = Qw32_charset_turkish;
6350 break;
6351 case BALTIC_CHARSET:
6352 charset_type = Qw32_charset_baltic;
6353 break;
33d52f9c 6354 case RUSSIAN_CHARSET:
767b1ff0
JR
6355 charset_type = Qw32_charset_russian;
6356 break;
6357 case ARABIC_CHARSET:
6358 charset_type = Qw32_charset_arabic;
6359 break;
6360 case GREEK_CHARSET:
6361 charset_type = Qw32_charset_greek;
6362 break;
6363 case HEBREW_CHARSET:
6364 charset_type = Qw32_charset_hebrew;
6365 break;
6366 case VIETNAMESE_CHARSET:
6367 charset_type = Qw32_charset_vietnamese;
6368 break;
6369 case THAI_CHARSET:
6370 charset_type = Qw32_charset_thai;
6371 break;
6372 case MAC_CHARSET:
6373 charset_type = Qw32_charset_mac;
6374 break;
6375 case JOHAB_CHARSET:
6376 charset_type = Qw32_charset_johab;
6377 break;
4587b026
GV
6378#endif
6379
5ac45f98 6380#ifdef UNICODE_CHARSET
767b1ff0
JR
6381 case UNICODE_CHARSET:
6382 charset_type = Qw32_charset_unicode;
6383 break;
5ac45f98 6384#endif
767b1ff0
JR
6385 default:
6386 /* Encode numerical value of unknown charset. */
6387 sprintf (buf, "*-#%u", fncharset);
6388 return buf;
5ac45f98 6389 }
767b1ff0
JR
6390
6391 {
6392 Lisp_Object rest;
6393 char * best_match = NULL;
6394
6395 /* Look through w32-charset-info-alist for the character set.
6396 Prefer ISO codepages, and prefer lower numbers in the ISO
6397 range. Only return charsets for codepages which are installed.
6398
6399 Format of each entry is
6400 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6401 */
6402 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6403 {
6404 char * x_charset;
6405 Lisp_Object w32_charset;
6406 Lisp_Object codepage;
6407
6408 Lisp_Object this_entry = XCAR (rest);
6409
6410 /* Skip invalid entries in alist. */
6411 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6412 || !CONSP (XCDR (this_entry))
6413 || !SYMBOLP (XCAR (XCDR (this_entry))))
6414 continue;
6415
6416 x_charset = XSTRING (XCAR (this_entry))->data;
6417 w32_charset = XCAR (XCDR (this_entry));
6418 codepage = XCDR (XCDR (this_entry));
6419
6420 /* Look for Same charset and a valid codepage (or non-int
6421 which means ignore). */
6422 if (w32_charset == charset_type
6423 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6424 || IsValidCodePage (XINT (codepage))))
6425 {
6426 /* If we don't have a match already, then this is the
6427 best. */
6428 if (!best_match)
6429 best_match = x_charset;
6430 /* If this is an ISO codepage, and the best so far isn't,
6431 then this is better. */
d84b082d
JR
6432 else if (strnicmp (best_match, "iso", 3) != 0
6433 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
6434 best_match = x_charset;
6435 /* If both are ISO8859 codepages, choose the one with the
6436 lowest number in the encoding field. */
d84b082d
JR
6437 else if (strnicmp (best_match, "iso8859-", 8) == 0
6438 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
6439 {
6440 int best_enc = atoi (best_match + 8);
6441 int this_enc = atoi (x_charset + 8);
6442 if (this_enc > 0 && this_enc < best_enc)
6443 best_match = x_charset;
6444 }
6445 }
6446 }
6447
6448 /* If no match, encode the numeric value. */
6449 if (!best_match)
6450 {
6451 sprintf (buf, "*-#%u", fncharset);
6452 return buf;
6453 }
6454
5e905a57
JR
6455 strncpy(buf, best_match, 31);
6456 buf[31] = '\0';
767b1ff0
JR
6457 return buf;
6458 }
ee78dc32
GV
6459}
6460
dfff8a69 6461
d84b082d
JR
6462/* Return all the X charsets that map to a font. */
6463static Lisp_Object
6464w32_to_all_x_charsets (fncharset)
6465 int fncharset;
6466{
6467 static char buf[32];
6468 Lisp_Object charset_type;
6469 Lisp_Object retval = Qnil;
6470
6471 switch (fncharset)
6472 {
6473 case ANSI_CHARSET:
6474 /* Handle startup case of w32-charset-info-alist not
6475 being set up yet. */
6476 if (NILP(Vw32_charset_info_alist))
d86c35ee
JR
6477 return Fcons (build_string ("iso8859-1"), Qnil);
6478
d84b082d
JR
6479 charset_type = Qw32_charset_ansi;
6480 break;
6481 case DEFAULT_CHARSET:
6482 charset_type = Qw32_charset_default;
6483 break;
6484 case SYMBOL_CHARSET:
6485 charset_type = Qw32_charset_symbol;
6486 break;
6487 case SHIFTJIS_CHARSET:
6488 charset_type = Qw32_charset_shiftjis;
6489 break;
6490 case HANGEUL_CHARSET:
6491 charset_type = Qw32_charset_hangeul;
6492 break;
6493 case GB2312_CHARSET:
6494 charset_type = Qw32_charset_gb2312;
6495 break;
6496 case CHINESEBIG5_CHARSET:
6497 charset_type = Qw32_charset_chinesebig5;
6498 break;
6499 case OEM_CHARSET:
6500 charset_type = Qw32_charset_oem;
6501 break;
6502
6503 /* More recent versions of Windows (95 and NT4.0) define more
6504 character sets. */
6505#ifdef EASTEUROPE_CHARSET
6506 case EASTEUROPE_CHARSET:
6507 charset_type = Qw32_charset_easteurope;
6508 break;
6509 case TURKISH_CHARSET:
6510 charset_type = Qw32_charset_turkish;
6511 break;
6512 case BALTIC_CHARSET:
6513 charset_type = Qw32_charset_baltic;
6514 break;
6515 case RUSSIAN_CHARSET:
6516 charset_type = Qw32_charset_russian;
6517 break;
6518 case ARABIC_CHARSET:
6519 charset_type = Qw32_charset_arabic;
6520 break;
6521 case GREEK_CHARSET:
6522 charset_type = Qw32_charset_greek;
6523 break;
6524 case HEBREW_CHARSET:
6525 charset_type = Qw32_charset_hebrew;
6526 break;
6527 case VIETNAMESE_CHARSET:
6528 charset_type = Qw32_charset_vietnamese;
6529 break;
6530 case THAI_CHARSET:
6531 charset_type = Qw32_charset_thai;
6532 break;
6533 case MAC_CHARSET:
6534 charset_type = Qw32_charset_mac;
6535 break;
6536 case JOHAB_CHARSET:
6537 charset_type = Qw32_charset_johab;
6538 break;
6539#endif
6540
6541#ifdef UNICODE_CHARSET
6542 case UNICODE_CHARSET:
6543 charset_type = Qw32_charset_unicode;
6544 break;
6545#endif
6546 default:
6547 /* Encode numerical value of unknown charset. */
6548 sprintf (buf, "*-#%u", fncharset);
6549 return Fcons (build_string (buf), Qnil);
6550 }
6551
6552 {
6553 Lisp_Object rest;
6554 /* Look through w32-charset-info-alist for the character set.
6555 Only return charsets for codepages which are installed.
6556
6557 Format of each entry in Vw32_charset_info_alist is
6558 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6559 */
6560 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6561 {
6562 Lisp_Object x_charset;
6563 Lisp_Object w32_charset;
6564 Lisp_Object codepage;
6565
6566 Lisp_Object this_entry = XCAR (rest);
6567
6568 /* Skip invalid entries in alist. */
6569 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6570 || !CONSP (XCDR (this_entry))
6571 || !SYMBOLP (XCAR (XCDR (this_entry))))
6572 continue;
6573
6574 x_charset = XCAR (this_entry);
6575 w32_charset = XCAR (XCDR (this_entry));
6576 codepage = XCDR (XCDR (this_entry));
6577
6578 /* Look for Same charset and a valid codepage (or non-int
6579 which means ignore). */
6580 if (w32_charset == charset_type
6581 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6582 || IsValidCodePage (XINT (codepage))))
6583 {
6584 retval = Fcons (x_charset, retval);
6585 }
6586 }
6587
6588 /* If no match, encode the numeric value. */
6589 if (NILP (retval))
6590 {
6591 sprintf (buf, "*-#%u", fncharset);
6592 return Fcons (build_string (buf), Qnil);
6593 }
6594
6595 return retval;
6596 }
6597}
6598
dfff8a69
JR
6599/* Get the Windows codepage corresponding to the specified font. The
6600 charset info in the font name is used to look up
6601 w32-charset-to-codepage-alist. */
6602int
6603w32_codepage_for_font (char *fontname)
6604{
767b1ff0
JR
6605 Lisp_Object codepage, entry;
6606 char *charset_str, *charset, *end;
dfff8a69 6607
767b1ff0 6608 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6609 return CP_DEFAULT;
6610
767b1ff0
JR
6611 /* Extract charset part of font string. */
6612 charset = xlfd_charset_of_font (fontname);
6613
6614 if (!charset)
ceb12877 6615 return CP_UNKNOWN;
767b1ff0 6616
8b77111c 6617 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6618 strcpy (charset_str, charset);
6619
8b77111c 6620#if 0
dfff8a69
JR
6621 /* Remove leading "*-". */
6622 if (strncmp ("*-", charset_str, 2) == 0)
6623 charset = charset_str + 2;
6624 else
8b77111c 6625#endif
dfff8a69
JR
6626 charset = charset_str;
6627
6628 /* Stop match at wildcard (including preceding '-'). */
6629 if (end = strchr (charset, '*'))
6630 {
6631 if (end > charset && *(end-1) == '-')
6632 end--;
6633 *end = '\0';
6634 }
6635
767b1ff0
JR
6636 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6637 if (NILP (entry))
ceb12877 6638 return CP_UNKNOWN;
767b1ff0
JR
6639
6640 codepage = Fcdr (Fcdr (entry));
6641
6642 if (NILP (codepage))
6643 return CP_8BIT;
6644 else if (XFASTINT (codepage) == XFASTINT (Qt))
6645 return CP_UNICODE;
6646 else if (INTEGERP (codepage))
dfff8a69
JR
6647 return XINT (codepage);
6648 else
ceb12877 6649 return CP_UNKNOWN;
dfff8a69
JR
6650}
6651
6652
8edb0a6f 6653static BOOL
767b1ff0 6654w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6655 LOGFONT * lplogfont;
6656 char * lpxstr;
6657 int len;
767b1ff0 6658 char * specific_charset;
ee78dc32 6659{
6fc2811b 6660 char* fonttype;
f46e6225 6661 char *fontname;
3cb20f4a
RS
6662 char height_pixels[8];
6663 char height_dpi[8];
6664 char width_pixels[8];
4587b026 6665 char *fontname_dash;
ac849ba4
JR
6666 int display_resy = (int) one_w32_display_info.resy;
6667 int display_resx = (int) one_w32_display_info.resx;
f46e6225
GV
6668 int bufsz;
6669 struct coding_system coding;
3cb20f4a
RS
6670
6671 if (!lpxstr) abort ();
ee78dc32 6672
3cb20f4a
RS
6673 if (!lplogfont)
6674 return FALSE;
6675
6fc2811b
JR
6676 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6677 fonttype = "raster";
6678 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6679 fonttype = "outline";
6680 else
6681 fonttype = "unknown";
6682
1fa3a200 6683 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6684 &coding);
aab5ac44
KH
6685 coding.src_multibyte = 0;
6686 coding.dst_multibyte = 1;
f46e6225 6687 coding.mode |= CODING_MODE_LAST_BLOCK;
65413122
KH
6688 /* We explicitely disable composition handling because selection
6689 data should not contain any composition sequence. */
6690 coding.composing = COMPOSITION_DISABLED;
f46e6225
GV
6691 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6692
6693 fontname = alloca(sizeof(*fontname) * bufsz);
6694 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6695 strlen(lplogfont->lfFaceName), bufsz - 1);
6696 *(fontname + coding.produced) = '\0';
4587b026
GV
6697
6698 /* Replace dashes with underscores so the dashes are not
f46e6225 6699 misinterpreted. */
4587b026
GV
6700 fontname_dash = fontname;
6701 while (fontname_dash = strchr (fontname_dash, '-'))
6702 *fontname_dash = '_';
6703
3cb20f4a 6704 if (lplogfont->lfHeight)
ee78dc32 6705 {
3cb20f4a
RS
6706 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6707 sprintf (height_dpi, "%u",
33d52f9c 6708 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6709 }
6710 else
ee78dc32 6711 {
3cb20f4a
RS
6712 strcpy (height_pixels, "*");
6713 strcpy (height_dpi, "*");
ee78dc32 6714 }
3cb20f4a
RS
6715 if (lplogfont->lfWidth)
6716 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6717 else
6718 strcpy (width_pixels, "*");
6719
6720 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6721 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6722 fonttype, /* foundry */
4587b026
GV
6723 fontname, /* family */
6724 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6725 lplogfont->lfItalic?'i':'r', /* slant */
6726 /* setwidth name */
6727 /* add style name */
6728 height_pixels, /* pixel size */
6729 height_dpi, /* point size */
33d52f9c
GV
6730 display_resx, /* resx */
6731 display_resy, /* resy */
4587b026
GV
6732 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6733 ? 'p' : 'c', /* spacing */
6734 width_pixels, /* avg width */
767b1ff0
JR
6735 specific_charset ? specific_charset
6736 : w32_to_x_charset (lplogfont->lfCharSet)
6737 /* charset registry and encoding */
3cb20f4a
RS
6738 );
6739
ee78dc32
GV
6740 lpxstr[len - 1] = 0; /* just to be sure */
6741 return (TRUE);
6742}
6743
8edb0a6f 6744static BOOL
fbd6baed 6745x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6746 char * lpxstr;
6747 LOGFONT * lplogfont;
6748{
f46e6225
GV
6749 struct coding_system coding;
6750
ee78dc32 6751 if (!lplogfont) return (FALSE);
f46e6225 6752
ee78dc32 6753 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6754
1a292d24 6755 /* Set default value for each field. */
771c47d5 6756#if 1
ee78dc32
GV
6757 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6758 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6759 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6760#else
6761 /* go for maximum quality */
6762 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6763 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6764 lplogfont->lfQuality = PROOF_QUALITY;
6765#endif
6766
1a292d24
AI
6767 lplogfont->lfCharSet = DEFAULT_CHARSET;
6768 lplogfont->lfWeight = FW_DONTCARE;
6769 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6770
5ac45f98
GV
6771 if (!lpxstr)
6772 return FALSE;
6773
6774 /* Provide a simple escape mechanism for specifying Windows font names
6775 * directly -- if font spec does not beginning with '-', assume this
6776 * format:
6777 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6778 */
ee78dc32 6779
5ac45f98
GV
6780 if (*lpxstr == '-')
6781 {
33d52f9c
GV
6782 int fields, tem;
6783 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6784 width[10], resy[10], remainder[50];
5ac45f98 6785 char * encoding;
ac849ba4 6786 int dpi = (int) one_w32_display_info.resy;
5ac45f98
GV
6787
6788 fields = sscanf (lpxstr,
8b77111c 6789 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6790 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6791 if (fields == EOF)
6792 return (FALSE);
6793
6794 /* In the general case when wildcards cover more than one field,
6795 we don't know which field is which, so don't fill any in.
6796 However, we need to cope with this particular form, which is
6797 generated by font_list_1 (invoked by try_font_list):
6798 "-raster-6x10-*-gb2312*-*"
6799 and make sure to correctly parse the charset field. */
6800 if (fields == 3)
6801 {
6802 fields = sscanf (lpxstr,
6803 "-%*[^-]-%49[^-]-*-%49s",
6804 name, remainder);
6805 }
6806 else if (fields < 9)
6807 {
6808 fields = 0;
6809 remainder[0] = 0;
6810 }
6fc2811b 6811
5ac45f98
GV
6812 if (fields > 0 && name[0] != '*')
6813 {
8ea3e054
RS
6814 int bufsize;
6815 unsigned char *buf;
6816
f46e6225 6817 setup_coding_system
1fa3a200 6818 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6819 coding.src_multibyte = 1;
6820 coding.dst_multibyte = 1;
8ea3e054
RS
6821 bufsize = encoding_buffer_size (&coding, strlen (name));
6822 buf = (unsigned char *) alloca (bufsize);
f46e6225 6823 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6824 encode_coding (&coding, name, buf, strlen (name), bufsize);
6825 if (coding.produced >= LF_FACESIZE)
6826 coding.produced = LF_FACESIZE - 1;
6827 buf[coding.produced] = 0;
6828 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6829 }
6830 else
6831 {
6fc2811b 6832 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6833 }
6834
6835 fields--;
6836
fbd6baed 6837 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6838
6839 fields--;
6840
c8874f14 6841 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6842
6843 fields--;
6844
6845 if (fields > 0 && pixels[0] != '*')
6846 lplogfont->lfHeight = atoi (pixels);
6847
6848 fields--;
5ac45f98 6849 fields--;
33d52f9c
GV
6850 if (fields > 0 && resy[0] != '*')
6851 {
6fc2811b 6852 tem = atoi (resy);
33d52f9c
GV
6853 if (tem > 0) dpi = tem;
6854 }
5ac45f98 6855
33d52f9c
GV
6856 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6857 lplogfont->lfHeight = atoi (height) * dpi / 720;
6858
6859 if (fields > 0)
5ac45f98
GV
6860 lplogfont->lfPitchAndFamily =
6861 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6862
6863 fields--;
6864
6865 if (fields > 0 && width[0] != '*')
6866 lplogfont->lfWidth = atoi (width) / 10;
6867
6868 fields--;
6869
4587b026 6870 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6871 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6872 {
5ac45f98
GV
6873 int len = strlen (remainder);
6874 if (len > 0 && remainder[len-1] == '-')
6875 remainder[len-1] = 0;
ee78dc32 6876 }
5ac45f98 6877 encoding = remainder;
8b77111c 6878#if 0
5ac45f98
GV
6879 if (strncmp (encoding, "*-", 2) == 0)
6880 encoding += 2;
8b77111c
AI
6881#endif
6882 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6883 }
6884 else
6885 {
6886 int fields;
6887 char name[100], height[10], width[10], weight[20];
a1a80b40 6888
5ac45f98
GV
6889 fields = sscanf (lpxstr,
6890 "%99[^:]:%9[^:]:%9[^:]:%19s",
6891 name, height, width, weight);
6892
6893 if (fields == EOF) return (FALSE);
6894
6895 if (fields > 0)
6896 {
6897 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6898 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6899 }
6900 else
6901 {
6902 lplogfont->lfFaceName[0] = 0;
6903 }
6904
6905 fields--;
6906
6907 if (fields > 0)
6908 lplogfont->lfHeight = atoi (height);
6909
6910 fields--;
6911
6912 if (fields > 0)
6913 lplogfont->lfWidth = atoi (width);
6914
6915 fields--;
6916
fbd6baed 6917 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6918 }
6919
6920 /* This makes TrueType fonts work better. */
6921 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6922
ee78dc32
GV
6923 return (TRUE);
6924}
6925
d88c567c
JR
6926/* Strip the pixel height and point height from the given xlfd, and
6927 return the pixel height. If no pixel height is specified, calculate
6928 one from the point height, or if that isn't defined either, return
6929 0 (which usually signifies a scalable font).
6930*/
8edb0a6f
JR
6931static int
6932xlfd_strip_height (char *fontname)
d88c567c 6933{
8edb0a6f 6934 int pixel_height, field_number;
d88c567c
JR
6935 char *read_from, *write_to;
6936
6937 xassert (fontname);
6938
6939 pixel_height = field_number = 0;
6940 write_to = NULL;
6941
6942 /* Look for height fields. */
6943 for (read_from = fontname; *read_from; read_from++)
6944 {
6945 if (*read_from == '-')
6946 {
6947 field_number++;
6948 if (field_number == 7) /* Pixel height. */
6949 {
6950 read_from++;
6951 write_to = read_from;
6952
6953 /* Find end of field. */
6954 for (;*read_from && *read_from != '-'; read_from++)
6955 ;
6956
6957 /* Split the fontname at end of field. */
6958 if (*read_from)
6959 {
6960 *read_from = '\0';
6961 read_from++;
6962 }
6963 pixel_height = atoi (write_to);
6964 /* Blank out field. */
6965 if (read_from > write_to)
6966 {
6967 *write_to = '-';
6968 write_to++;
6969 }
767b1ff0 6970 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6971 return now. */
6972 else
6973 return pixel_height;
6974
6975 /* If we got a pixel height, the point height can be
6976 ignored. Just blank it out and break now. */
6977 if (pixel_height)
6978 {
6979 /* Find end of point size field. */
6980 for (; *read_from && *read_from != '-'; read_from++)
6981 ;
6982
6983 if (*read_from)
6984 read_from++;
6985
6986 /* Blank out the point size field. */
6987 if (read_from > write_to)
6988 {
6989 *write_to = '-';
6990 write_to++;
6991 }
6992 else
6993 return pixel_height;
6994
6995 break;
6996 }
6997 /* If the point height is already blank, break now. */
6998 if (*read_from == '-')
6999 {
7000 read_from++;
7001 break;
7002 }
7003 }
7004 else if (field_number == 8)
7005 {
7006 /* If we didn't get a pixel height, try to get the point
7007 height and convert that. */
7008 int point_size;
7009 char *point_size_start = read_from++;
7010
7011 /* Find end of field. */
7012 for (; *read_from && *read_from != '-'; read_from++)
7013 ;
7014
7015 if (*read_from)
7016 {
7017 *read_from = '\0';
7018 read_from++;
7019 }
7020
7021 point_size = atoi (point_size_start);
7022
7023 /* Convert to pixel height. */
7024 pixel_height = point_size
7025 * one_w32_display_info.height_in / 720;
7026
7027 /* Blank out this field and break. */
7028 *write_to = '-';
7029 write_to++;
7030 break;
7031 }
7032 }
7033 }
7034
7035 /* Shift the rest of the font spec into place. */
7036 if (write_to && read_from > write_to)
7037 {
7038 for (; *read_from; read_from++, write_to++)
7039 *write_to = *read_from;
7040 *write_to = '\0';
7041 }
7042
7043 return pixel_height;
7044}
7045
6fc2811b 7046/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 7047static BOOL
6fc2811b
JR
7048w32_font_match (fontname, pattern)
7049 char * fontname;
7050 char * pattern;
ee78dc32 7051{
e7c72122 7052 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 7053 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 7054 char *ptr;
ee78dc32 7055
d88c567c
JR
7056 /* Copy fontname so we can modify it during comparison. */
7057 strcpy (font_name_copy, fontname);
7058
6fc2811b
JR
7059 ptr = regex;
7060 *ptr++ = '^';
ee78dc32 7061
6fc2811b
JR
7062 /* Turn pattern into a regexp and do a regexp match. */
7063 for (; *pattern; pattern++)
7064 {
7065 if (*pattern == '?')
7066 *ptr++ = '.';
7067 else if (*pattern == '*')
7068 {
7069 *ptr++ = '.';
7070 *ptr++ = '*';
7071 }
33d52f9c 7072 else
6fc2811b 7073 *ptr++ = *pattern;
ee78dc32 7074 }
6fc2811b
JR
7075 *ptr = '$';
7076 *(ptr + 1) = '\0';
7077
d88c567c
JR
7078 /* Strip out font heights and compare them seperately, since
7079 rounding error can cause mismatches. This also allows a
7080 comparison between a font that declares only a pixel height and a
7081 pattern that declares the point height.
7082 */
7083 {
7084 int font_height, pattern_height;
7085
7086 font_height = xlfd_strip_height (font_name_copy);
7087 pattern_height = xlfd_strip_height (regex);
7088
7089 /* Compare now, and don't bother doing expensive regexp matching
7090 if the heights differ. */
7091 if (font_height && pattern_height && (font_height != pattern_height))
7092 return FALSE;
7093 }
7094
6fc2811b 7095 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 7096 font_name_copy) >= 0);
ee78dc32
GV
7097}
7098
5ca0cd71
GV
7099/* Callback functions, and a structure holding info they need, for
7100 listing system fonts on W32. We need one set of functions to do the
7101 job properly, but these don't work on NT 3.51 and earlier, so we
7102 have a second set which don't handle character sets properly to
7103 fall back on.
7104
7105 In both cases, there are two passes made. The first pass gets one
7106 font from each family, the second pass lists all the fonts from
7107 each family. */
7108
ee78dc32
GV
7109typedef struct enumfont_t
7110{
7111 HDC hdc;
7112 int numFonts;
3cb20f4a 7113 LOGFONT logfont;
ee78dc32 7114 XFontStruct *size_ref;
23afac8f 7115 Lisp_Object pattern;
d84b082d 7116 Lisp_Object list;
ee78dc32
GV
7117} enumfont_t;
7118
d84b082d
JR
7119
7120static void
7121enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7122
7123
8edb0a6f 7124static int CALLBACK
ee78dc32
GV
7125enum_font_cb2 (lplf, lptm, FontType, lpef)
7126 ENUMLOGFONT * lplf;
7127 NEWTEXTMETRIC * lptm;
7128 int FontType;
7129 enumfont_t * lpef;
7130{
66895301
JR
7131 /* Ignore struck out and underlined versions of fonts. */
7132 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7133 return 1;
7134
7135 /* Only return fonts with names starting with @ if they were
7136 explicitly specified, since Microsoft uses an initial @ to
7137 denote fonts for vertical writing, without providing a more
7138 convenient way of identifying them. */
7139 if (lplf->elfLogFont.lfFaceName[0] == '@'
7140 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
7141 return 1;
7142
4587b026
GV
7143 /* Check that the character set matches if it was specified */
7144 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7145 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 7146 return 1;
4587b026 7147
6358474d
JR
7148 if (FontType == RASTER_FONTTYPE)
7149 {
7150 /* DBCS raster fonts have problems displaying, so skip them. */
7151 int charset = lplf->elfLogFont.lfCharSet;
7152 if (charset == SHIFTJIS_CHARSET
7153 || charset == HANGEUL_CHARSET
7154 || charset == CHINESEBIG5_CHARSET
7155 || charset == GB2312_CHARSET
7156#ifdef JOHAB_CHARSET
7157 || charset == JOHAB_CHARSET
7158#endif
7159 )
7160 return 1;
7161 }
7162
ee78dc32
GV
7163 {
7164 char buf[100];
4587b026 7165 Lisp_Object width = Qnil;
d84b082d 7166 Lisp_Object charset_list = Qnil;
767b1ff0 7167 char *charset = NULL;
ee78dc32 7168
6fc2811b
JR
7169 /* Truetype fonts do not report their true metrics until loaded */
7170 if (FontType != RASTER_FONTTYPE)
3cb20f4a 7171 {
23afac8f 7172 if (!NILP (lpef->pattern))
6fc2811b
JR
7173 {
7174 /* Scalable fonts are as big as you want them to be. */
7175 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7176 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7177 width = make_number (lpef->logfont.lfWidth);
7178 }
7179 else
7180 {
7181 lplf->elfLogFont.lfHeight = 0;
7182 lplf->elfLogFont.lfWidth = 0;
7183 }
3cb20f4a 7184 }
6fc2811b 7185
f46e6225
GV
7186 /* Make sure the height used here is the same as everywhere
7187 else (ie character height, not cell height). */
6fc2811b
JR
7188 if (lplf->elfLogFont.lfHeight > 0)
7189 {
7190 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7191 if (FontType == RASTER_FONTTYPE)
7192 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7193 else
7194 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7195 }
4587b026 7196
23afac8f 7197 if (!NILP (lpef->pattern))
767b1ff0 7198 {
23afac8f 7199 charset = xlfd_charset_of_font (XSTRING(lpef->pattern)->data);
767b1ff0 7200
644cefdf
JR
7201 /* We already checked charsets above, but DEFAULT_CHARSET
7202 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7203 if (charset
7204 && strncmp (charset, "*-*", 3) != 0
7205 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7206 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7207 return 1;
767b1ff0
JR
7208 }
7209
d84b082d
JR
7210 if (charset)
7211 charset_list = Fcons (build_string (charset), Qnil);
7212 else
7213 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 7214
d84b082d
JR
7215 /* Loop through the charsets. */
7216 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 7217 {
d84b082d
JR
7218 Lisp_Object this_charset = Fcar (charset_list);
7219 charset = XSTRING (this_charset)->data;
7220
7221 /* List bold and italic variations if w32-enable-synthesized-fonts
7222 is non-nil and this is a plain font. */
7223 if (w32_enable_synthesized_fonts
7224 && lplf->elfLogFont.lfWeight == FW_NORMAL
7225 && lplf->elfLogFont.lfItalic == FALSE)
7226 {
7227 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7228 charset, width);
7229 /* bold. */
7230 lplf->elfLogFont.lfWeight = FW_BOLD;
7231 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7232 charset, width);
7233 /* bold italic. */
7234 lplf->elfLogFont.lfItalic = TRUE;
7235 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7236 charset, width);
7237 /* italic. */
7238 lplf->elfLogFont.lfWeight = FW_NORMAL;
7239 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7240 charset, width);
7241 }
7242 else
7243 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7244 charset, width);
ee78dc32
GV
7245 }
7246 }
6fc2811b 7247
5e905a57 7248 return 1;
ee78dc32
GV
7249}
7250
d84b082d
JR
7251static void
7252enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7253 enumfont_t * lpef;
7254 LOGFONT * logfont;
7255 char * match_charset;
7256 Lisp_Object width;
7257{
7258 char buf[100];
7259
7260 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7261 return;
7262
23afac8f
JR
7263 if (NILP (lpef->pattern)
7264 || w32_font_match (buf, XSTRING (lpef->pattern)->data))
d84b082d
JR
7265 {
7266 /* Check if we already listed this font. This may happen if
7267 w32_enable_synthesized_fonts is non-nil, and there are real
7268 bold and italic versions of the font. */
7269 Lisp_Object font_name = build_string (buf);
7270 if (NILP (Fmember (font_name, lpef->list)))
7271 {
23afac8f
JR
7272 Lisp_Object entry = Fcons (font_name, width);
7273 lpef->list = Fcons (entry, lpef->list);
d84b082d
JR
7274 lpef->numFonts++;
7275 }
7276 }
7277}
7278
7279
8edb0a6f 7280static int CALLBACK
ee78dc32
GV
7281enum_font_cb1 (lplf, lptm, FontType, lpef)
7282 ENUMLOGFONT * lplf;
7283 NEWTEXTMETRIC * lptm;
7284 int FontType;
7285 enumfont_t * lpef;
7286{
7287 return EnumFontFamilies (lpef->hdc,
7288 lplf->elfLogFont.lfFaceName,
7289 (FONTENUMPROC) enum_font_cb2,
7290 (LPARAM) lpef);
7291}
7292
7293
8edb0a6f 7294static int CALLBACK
5ca0cd71
GV
7295enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7296 ENUMLOGFONTEX * lplf;
7297 NEWTEXTMETRICEX * lptm;
7298 int font_type;
7299 enumfont_t * lpef;
7300{
7301 /* We are not interested in the extra info we get back from the 'Ex
7302 version - only the fact that we get character set variations
7303 enumerated seperately. */
7304 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7305 font_type, lpef);
7306}
7307
8edb0a6f 7308static int CALLBACK
5ca0cd71
GV
7309enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7310 ENUMLOGFONTEX * lplf;
7311 NEWTEXTMETRICEX * lptm;
7312 int font_type;
7313 enumfont_t * lpef;
7314{
7315 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7316 FARPROC enum_font_families_ex
7317 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7318 /* We don't really expect EnumFontFamiliesEx to disappear once we
7319 get here, so don't bother handling it gracefully. */
7320 if (enum_font_families_ex == NULL)
7321 error ("gdi32.dll has disappeared!");
7322 return enum_font_families_ex (lpef->hdc,
7323 &lplf->elfLogFont,
7324 (FONTENUMPROC) enum_fontex_cb2,
7325 (LPARAM) lpef, 0);
7326}
7327
4587b026
GV
7328/* Interface to fontset handler. (adapted from mw32font.c in Meadow
7329 and xterm.c in Emacs 20.3) */
7330
8edb0a6f 7331static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
7332{
7333 char *fontname, *ptnstr;
7334 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 7335 int n_fonts = 0;
33d52f9c
GV
7336
7337 list = Vw32_bdf_filename_alist;
7338 ptnstr = XSTRING (pattern)->data;
7339
8e713be6 7340 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 7341 {
8e713be6 7342 tem = XCAR (list);
33d52f9c 7343 if (CONSP (tem))
8e713be6 7344 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
7345 else if (STRINGP (tem))
7346 fontname = XSTRING (tem)->data;
7347 else
7348 continue;
7349
7350 if (w32_font_match (fontname, ptnstr))
5ca0cd71 7351 {
8e713be6 7352 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7353 n_fonts++;
7354 if (n_fonts >= max_names)
7355 break;
7356 }
33d52f9c
GV
7357 }
7358
7359 return newlist;
7360}
7361
5ca0cd71 7362
4587b026
GV
7363/* Return a list of names of available fonts matching PATTERN on frame
7364 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7365 to be listed. Frame F NULL means we have not yet created any
7366 frame, which means we can't get proper size info, as we don't have
7367 a device context to use for GetTextMetrics.
7368 MAXNAMES sets a limit on how many fonts to match. */
7369
7370Lisp_Object
dc220243
JR
7371w32_list_fonts (f, pattern, size, maxnames)
7372 struct frame *f;
7373 Lisp_Object pattern;
7374 int size;
7375 int maxnames;
4587b026 7376{
6fc2811b 7377 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 7378 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 7379 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 7380 int n_fonts = 0;
396594fe 7381
4587b026
GV
7382 patterns = Fassoc (pattern, Valternate_fontname_alist);
7383 if (NILP (patterns))
7384 patterns = Fcons (pattern, Qnil);
7385
8e713be6 7386 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
7387 {
7388 enumfont_t ef;
767b1ff0 7389 int codepage;
4587b026 7390
8e713be6 7391 tpat = XCAR (patterns);
4587b026 7392
767b1ff0
JR
7393 if (!STRINGP (tpat))
7394 continue;
7395
7396 /* Avoid expensive EnumFontFamilies functions if we are not
7397 going to be able to output one of these anyway. */
7398 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7399 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7400 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7401 && !IsValidCodePage(codepage))
767b1ff0
JR
7402 continue;
7403
4587b026
GV
7404 /* See if we cached the result for this particular query.
7405 The cache is an alist of the form:
7406 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7407 */
8e713be6 7408 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7409 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7410 {
7411 list = Fcdr_safe (list);
7412 /* We have a cached list. Don't have to get the list again. */
7413 goto label_cached;
7414 }
7415
7416 BLOCK_INPUT;
7417 /* At first, put PATTERN in the cache. */
23afac8f
JR
7418 ef.pattern = tpat;
7419 ef.list = Qnil;
4587b026 7420 ef.numFonts = 0;
33d52f9c 7421
5ca0cd71
GV
7422 /* Use EnumFontFamiliesEx where it is available, as it knows
7423 about character sets. Fall back to EnumFontFamilies for
7424 older versions of NT that don't support the 'Ex function. */
767b1ff0 7425 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7426 {
5ca0cd71
GV
7427 LOGFONT font_match_pattern;
7428 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7429 FARPROC enum_font_families_ex
7430 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7431
7432 /* We do our own pattern matching so we can handle wildcards. */
7433 font_match_pattern.lfFaceName[0] = 0;
7434 font_match_pattern.lfPitchAndFamily = 0;
7435 /* We can use the charset, because if it is a wildcard it will
7436 be DEFAULT_CHARSET anyway. */
7437 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7438
33d52f9c 7439 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7440
5ca0cd71
GV
7441 if (enum_font_families_ex)
7442 enum_font_families_ex (ef.hdc,
7443 &font_match_pattern,
7444 (FONTENUMPROC) enum_fontex_cb1,
7445 (LPARAM) &ef, 0);
7446 else
7447 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7448 (LPARAM)&ef);
4587b026 7449
33d52f9c 7450 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7451 }
7452
7453 UNBLOCK_INPUT;
23afac8f 7454 list = ef.list;
4587b026
GV
7455
7456 /* Make a list of the fonts we got back.
7457 Store that in the font cache for the display. */
f3fbd155
KR
7458 XSETCDR (dpyinfo->name_list_element,
7459 Fcons (Fcons (tpat, list),
7460 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7461
7462 label_cached:
7463 if (NILP (list)) continue; /* Try the remaining alternatives. */
7464
7465 newlist = second_best = Qnil;
7466
7467 /* Make a list of the fonts that have the right width. */
8e713be6 7468 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7469 {
7470 int found_size;
8e713be6 7471 tem = XCAR (list);
4587b026
GV
7472
7473 if (!CONSP (tem))
7474 continue;
8e713be6 7475 if (NILP (XCAR (tem)))
4587b026
GV
7476 continue;
7477 if (!size)
7478 {
8e713be6 7479 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7480 n_fonts++;
7481 if (n_fonts >= maxnames)
7482 break;
7483 else
7484 continue;
4587b026 7485 }
8e713be6 7486 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7487 {
7488 /* Since we don't yet know the size of the font, we must
7489 load it and try GetTextMetrics. */
4587b026
GV
7490 W32FontStruct thisinfo;
7491 LOGFONT lf;
7492 HDC hdc;
7493 HANDLE oldobj;
7494
8e713be6 7495 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7496 continue;
7497
7498 BLOCK_INPUT;
33d52f9c 7499 thisinfo.bdf = NULL;
4587b026
GV
7500 thisinfo.hfont = CreateFontIndirect (&lf);
7501 if (thisinfo.hfont == NULL)
7502 continue;
7503
7504 hdc = GetDC (dpyinfo->root_window);
7505 oldobj = SelectObject (hdc, thisinfo.hfont);
7506 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7507 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7508 else
f3fbd155 7509 XSETCDR (tem, make_number (0));
4587b026
GV
7510 SelectObject (hdc, oldobj);
7511 ReleaseDC (dpyinfo->root_window, hdc);
7512 DeleteObject(thisinfo.hfont);
7513 UNBLOCK_INPUT;
7514 }
8e713be6 7515 found_size = XINT (XCDR (tem));
4587b026 7516 if (found_size == size)
5ca0cd71 7517 {
8e713be6 7518 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7519 n_fonts++;
7520 if (n_fonts >= maxnames)
7521 break;
7522 }
4587b026
GV
7523 /* keep track of the closest matching size in case
7524 no exact match is found. */
7525 else if (found_size > 0)
7526 {
7527 if (NILP (second_best))
7528 second_best = tem;
5ca0cd71 7529
4587b026
GV
7530 else if (found_size < size)
7531 {
8e713be6
KR
7532 if (XINT (XCDR (second_best)) > size
7533 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7534 second_best = tem;
7535 }
7536 else
7537 {
8e713be6
KR
7538 if (XINT (XCDR (second_best)) > size
7539 && XINT (XCDR (second_best)) >
4587b026
GV
7540 found_size)
7541 second_best = tem;
7542 }
7543 }
7544 }
7545
7546 if (!NILP (newlist))
7547 break;
7548 else if (!NILP (second_best))
7549 {
8e713be6 7550 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7551 break;
7552 }
7553 }
7554
33d52f9c 7555 /* Include any bdf fonts. */
5ca0cd71 7556 if (n_fonts < maxnames)
33d52f9c
GV
7557 {
7558 Lisp_Object combined[2];
5ca0cd71 7559 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7560 combined[1] = newlist;
7561 newlist = Fnconc(2, combined);
7562 }
7563
4587b026
GV
7564 return newlist;
7565}
7566
5ca0cd71 7567
4587b026
GV
7568/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7569struct font_info *
7570w32_get_font_info (f, font_idx)
7571 FRAME_PTR f;
7572 int font_idx;
7573{
7574 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7575}
7576
7577
7578struct font_info*
7579w32_query_font (struct frame *f, char *fontname)
7580{
7581 int i;
7582 struct font_info *pfi;
7583
7584 pfi = FRAME_W32_FONT_TABLE (f);
7585
7586 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7587 {
7588 if (strcmp(pfi->name, fontname) == 0) return pfi;
7589 }
7590
7591 return NULL;
7592}
7593
7594/* Find a CCL program for a font specified by FONTP, and set the member
7595 `encoder' of the structure. */
7596
7597void
7598w32_find_ccl_program (fontp)
7599 struct font_info *fontp;
7600{
3545439c 7601 Lisp_Object list, elt;
4587b026 7602
8e713be6 7603 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7604 {
8e713be6 7605 elt = XCAR (list);
4587b026 7606 if (CONSP (elt)
8e713be6
KR
7607 && STRINGP (XCAR (elt))
7608 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7609 >= 0))
3545439c
KH
7610 break;
7611 }
7612 if (! NILP (list))
7613 {
17eedd00
KH
7614 struct ccl_program *ccl
7615 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7616
8e713be6 7617 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7618 xfree (ccl);
7619 else
7620 fontp->font_encoder = ccl;
4587b026
GV
7621 }
7622}
7623
7624\f
8edb0a6f
JR
7625/* Find BDF files in a specified directory. (use GCPRO when calling,
7626 as this calls lisp to get a directory listing). */
7627static Lisp_Object
7628w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7629{
7630 Lisp_Object filelist, list = Qnil;
7631 char fontname[100];
7632
7633 if (!STRINGP(directory))
7634 return Qnil;
7635
7636 filelist = Fdirectory_files (directory, Qt,
7637 build_string (".*\\.[bB][dD][fF]"), Qt);
7638
7639 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7640 {
7641 Lisp_Object filename = XCAR (filelist);
7642 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7643 store_in_alist (&list, build_string (fontname), filename);
7644 }
7645 return list;
7646}
7647
6fc2811b
JR
7648DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7649 1, 1, 0,
b3700ae7
JR
7650 doc: /* Return a list of BDF fonts in DIR.
7651The list is suitable for appending to w32-bdf-filename-alist. Fonts
7652which do not contain an xlfd description will not be included in the
7653list. DIR may be a list of directories. */)
6fc2811b
JR
7654 (directory)
7655 Lisp_Object directory;
7656{
7657 Lisp_Object list = Qnil;
7658 struct gcpro gcpro1, gcpro2;
ee78dc32 7659
6fc2811b
JR
7660 if (!CONSP (directory))
7661 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7662
6fc2811b 7663 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7664 {
6fc2811b
JR
7665 Lisp_Object pair[2];
7666 pair[0] = list;
7667 pair[1] = Qnil;
7668 GCPRO2 (directory, list);
7669 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7670 list = Fnconc( 2, pair );
7671 UNGCPRO;
7672 }
7673 return list;
7674}
ee78dc32 7675
6fc2811b
JR
7676\f
7677DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7678 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7679 (color, frame)
7680 Lisp_Object color, frame;
7681{
7682 XColor foo;
7683 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7684
b7826503 7685 CHECK_STRING (color);
ee78dc32 7686
6fc2811b
JR
7687 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7688 return Qt;
7689 else
7690 return Qnil;
7691}
ee78dc32 7692
2d764c78 7693DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7694 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7695 (color, frame)
7696 Lisp_Object color, frame;
7697{
6fc2811b 7698 XColor foo;
ee78dc32
GV
7699 FRAME_PTR f = check_x_frame (frame);
7700
b7826503 7701 CHECK_STRING (color);
ee78dc32 7702
6fc2811b 7703 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7704 {
7705 Lisp_Object rgb[3];
7706
6fc2811b
JR
7707 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7708 | GetRValue (foo.pixel));
7709 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7710 | GetGValue (foo.pixel));
7711 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7712 | GetBValue (foo.pixel));
ee78dc32
GV
7713 return Flist (3, rgb);
7714 }
7715 else
7716 return Qnil;
7717}
7718
2d764c78 7719DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7720 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7721 (display)
7722 Lisp_Object display;
7723{
fbd6baed 7724 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7725
7726 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7727 return Qnil;
7728
7729 return Qt;
7730}
7731
74e1aeec
JR
7732DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7733 Sx_display_grayscale_p, 0, 1, 0,
7734 doc: /* Return t if the X display supports shades of gray.
7735Note that color displays do support shades of gray.
7736The optional argument DISPLAY specifies which display to ask about.
7737DISPLAY should be either a frame or a display name (a string).
7738If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7739 (display)
7740 Lisp_Object display;
7741{
fbd6baed 7742 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7743
7744 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7745 return Qnil;
7746
7747 return Qt;
7748}
7749
74e1aeec
JR
7750DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7751 Sx_display_pixel_width, 0, 1, 0,
7752 doc: /* Returns the width in pixels of DISPLAY.
7753The optional argument DISPLAY specifies which display to ask about.
7754DISPLAY should be either a frame or a display name (a string).
7755If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7756 (display)
7757 Lisp_Object display;
7758{
fbd6baed 7759 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7760
7761 return make_number (dpyinfo->width);
7762}
7763
7764DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7765 Sx_display_pixel_height, 0, 1, 0,
7766 doc: /* Returns the height in pixels of DISPLAY.
7767The optional argument DISPLAY specifies which display to ask about.
7768DISPLAY should be either a frame or a display name (a string).
7769If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7770 (display)
7771 Lisp_Object display;
7772{
fbd6baed 7773 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7774
7775 return make_number (dpyinfo->height);
7776}
7777
7778DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7779 0, 1, 0,
7780 doc: /* Returns the number of bitplanes of DISPLAY.
7781The optional argument DISPLAY specifies which display to ask about.
7782DISPLAY should be either a frame or a display name (a string).
7783If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7784 (display)
7785 Lisp_Object display;
7786{
fbd6baed 7787 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7788
7789 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7790}
7791
7792DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7793 0, 1, 0,
7794 doc: /* Returns the number of color cells of DISPLAY.
7795The optional argument DISPLAY specifies which display to ask about.
7796DISPLAY should be either a frame or a display name (a string).
7797If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7798 (display)
7799 Lisp_Object display;
7800{
fbd6baed 7801 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7802 HDC hdc;
7803 int cap;
7804
5ac45f98
GV
7805 hdc = GetDC (dpyinfo->root_window);
7806 if (dpyinfo->has_palette)
7807 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7808 else
7809 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b 7810
007776bc
JB
7811 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7812 and because probably is more meaningful on Windows anyway */
abf8c61b 7813 if (cap < 0)
007776bc 7814 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
ee78dc32
GV
7815
7816 ReleaseDC (dpyinfo->root_window, hdc);
7817
7818 return make_number (cap);
7819}
7820
7821DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7822 Sx_server_max_request_size,
74e1aeec
JR
7823 0, 1, 0,
7824 doc: /* Returns the maximum request size of the server of DISPLAY.
7825The optional argument DISPLAY specifies which display to ask about.
7826DISPLAY should be either a frame or a display name (a string).
7827If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7828 (display)
7829 Lisp_Object display;
7830{
fbd6baed 7831 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7832
7833 return make_number (1);
7834}
7835
7836DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7837 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7838The optional argument DISPLAY specifies which display to ask about.
7839DISPLAY should be either a frame or a display name (a string).
7840If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7841 (display)
7842 Lisp_Object display;
7843{
dfff8a69 7844 return build_string ("Microsoft Corp.");
ee78dc32
GV
7845}
7846
7847DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7848 doc: /* Returns the version numbers of the server of DISPLAY.
7849The value is a list of three integers: the major and minor
7850version numbers, and the vendor-specific release
7851number. See also the function `x-server-vendor'.
7852
7853The optional argument DISPLAY specifies which display to ask about.
7854DISPLAY should be either a frame or a display name (a string).
7855If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7856 (display)
7857 Lisp_Object display;
7858{
fbd6baed 7859 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7860 Fcons (make_number (w32_minor_version),
7861 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7862}
7863
7864DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7865 doc: /* Returns the number of screens on the server of DISPLAY.
7866The optional argument DISPLAY specifies which display to ask about.
7867DISPLAY should be either a frame or a display name (a string).
7868If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7869 (display)
7870 Lisp_Object display;
7871{
ee78dc32
GV
7872 return make_number (1);
7873}
7874
74e1aeec
JR
7875DEFUN ("x-display-mm-height", Fx_display_mm_height,
7876 Sx_display_mm_height, 0, 1, 0,
7877 doc: /* Returns the height in millimeters of DISPLAY.
7878The optional argument DISPLAY specifies which display to ask about.
7879DISPLAY should be either a frame or a display name (a string).
7880If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7881 (display)
7882 Lisp_Object display;
7883{
fbd6baed 7884 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7885 HDC hdc;
7886 int cap;
7887
5ac45f98 7888 hdc = GetDC (dpyinfo->root_window);
3c190163 7889
ee78dc32 7890 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7891
ee78dc32
GV
7892 ReleaseDC (dpyinfo->root_window, hdc);
7893
7894 return make_number (cap);
7895}
7896
7897DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7898 doc: /* Returns the width in millimeters of DISPLAY.
7899The optional argument DISPLAY specifies which display to ask about.
7900DISPLAY should be either a frame or a display name (a string).
7901If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7902 (display)
7903 Lisp_Object display;
7904{
fbd6baed 7905 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7906
7907 HDC hdc;
7908 int cap;
7909
5ac45f98 7910 hdc = GetDC (dpyinfo->root_window);
3c190163 7911
ee78dc32 7912 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7913
ee78dc32
GV
7914 ReleaseDC (dpyinfo->root_window, hdc);
7915
7916 return make_number (cap);
7917}
7918
7919DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7920 Sx_display_backing_store, 0, 1, 0,
7921 doc: /* Returns an indication of whether DISPLAY does backing store.
7922The value may be `always', `when-mapped', or `not-useful'.
7923The optional argument DISPLAY specifies which display to ask about.
7924DISPLAY should be either a frame or a display name (a string).
7925If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7926 (display)
7927 Lisp_Object display;
7928{
7929 return intern ("not-useful");
7930}
7931
7932DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7933 Sx_display_visual_class, 0, 1, 0,
7934 doc: /* Returns the visual class of DISPLAY.
7935The value is one of the symbols `static-gray', `gray-scale',
7936`static-color', `pseudo-color', `true-color', or `direct-color'.
7937
7938The optional argument DISPLAY specifies which display to ask about.
7939DISPLAY should be either a frame or a display name (a string).
7940If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7941 (display)
7942 Lisp_Object display;
7943{
fbd6baed 7944 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7945 Lisp_Object result = Qnil;
ee78dc32 7946
abf8c61b
AI
7947 if (dpyinfo->has_palette)
7948 result = intern ("pseudo-color");
7949 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7950 result = intern ("static-grey");
7951 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7952 result = intern ("static-color");
7953 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7954 result = intern ("true-color");
ee78dc32 7955
abf8c61b 7956 return result;
ee78dc32
GV
7957}
7958
7959DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7960 Sx_display_save_under, 0, 1, 0,
7961 doc: /* Returns t if DISPLAY supports the save-under feature.
7962The optional argument DISPLAY specifies which display to ask about.
7963DISPLAY should be either a frame or a display name (a string).
7964If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7965 (display)
7966 Lisp_Object display;
7967{
6fc2811b
JR
7968 return Qnil;
7969}
7970\f
7971int
7972x_pixel_width (f)
7973 register struct frame *f;
7974{
7975 return PIXEL_WIDTH (f);
7976}
7977
7978int
7979x_pixel_height (f)
7980 register struct frame *f;
7981{
7982 return PIXEL_HEIGHT (f);
7983}
7984
7985int
7986x_char_width (f)
7987 register struct frame *f;
7988{
7989 return FONT_WIDTH (f->output_data.w32->font);
7990}
7991
7992int
7993x_char_height (f)
7994 register struct frame *f;
7995{
7996 return f->output_data.w32->line_height;
7997}
7998
7999int
8000x_screen_planes (f)
8001 register struct frame *f;
8002{
8003 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
8004}
8005\f
8006/* Return the display structure for the display named NAME.
8007 Open a new connection if necessary. */
8008
8009struct w32_display_info *
8010x_display_info_for_name (name)
8011 Lisp_Object name;
8012{
8013 Lisp_Object names;
8014 struct w32_display_info *dpyinfo;
8015
b7826503 8016 CHECK_STRING (name);
6fc2811b
JR
8017
8018 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
8019 dpyinfo;
8020 dpyinfo = dpyinfo->next, names = XCDR (names))
8021 {
8022 Lisp_Object tem;
8023 tem = Fstring_equal (XCAR (XCAR (names)), name);
8024 if (!NILP (tem))
8025 return dpyinfo;
8026 }
8027
8028 /* Use this general default value to start with. */
8029 Vx_resource_name = Vinvocation_name;
8030
8031 validate_x_resource_name ();
8032
8033 dpyinfo = w32_term_init (name, (unsigned char *)0,
8034 (char *) XSTRING (Vx_resource_name)->data);
8035
8036 if (dpyinfo == 0)
8037 error ("Cannot connect to server %s", XSTRING (name)->data);
8038
8039 w32_in_use = 1;
8040 XSETFASTINT (Vwindow_system_version, 3);
8041
8042 return dpyinfo;
8043}
8044
8045DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
8046 1, 3, 0, doc: /* Open a connection to a server.
8047DISPLAY is the name of the display to connect to.
8048Optional second arg XRM-STRING is a string of resources in xrdb format.
8049If the optional third arg MUST-SUCCEED is non-nil,
8050terminate Emacs if we can't open the connection. */)
6fc2811b
JR
8051 (display, xrm_string, must_succeed)
8052 Lisp_Object display, xrm_string, must_succeed;
8053{
8054 unsigned char *xrm_option;
8055 struct w32_display_info *dpyinfo;
8056
74e1aeec
JR
8057 /* If initialization has already been done, return now to avoid
8058 overwriting critical parts of one_w32_display_info. */
8059 if (w32_in_use)
8060 return Qnil;
8061
b7826503 8062 CHECK_STRING (display);
6fc2811b 8063 if (! NILP (xrm_string))
b7826503 8064 CHECK_STRING (xrm_string);
6fc2811b
JR
8065
8066 if (! EQ (Vwindow_system, intern ("w32")))
8067 error ("Not using Microsoft Windows");
8068
8069 /* Allow color mapping to be defined externally; first look in user's
8070 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8071 {
8072 Lisp_Object color_file;
8073 struct gcpro gcpro1;
8074
8075 color_file = build_string("~/rgb.txt");
8076
8077 GCPRO1 (color_file);
8078
8079 if (NILP (Ffile_readable_p (color_file)))
8080 color_file =
8081 Fexpand_file_name (build_string ("rgb.txt"),
8082 Fsymbol_value (intern ("data-directory")));
8083
8084 Vw32_color_map = Fw32_load_color_file (color_file);
8085
8086 UNGCPRO;
8087 }
8088 if (NILP (Vw32_color_map))
8089 Vw32_color_map = Fw32_default_color_map ();
8090
8091 if (! NILP (xrm_string))
8092 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8093 else
8094 xrm_option = (unsigned char *) 0;
8095
8096 /* Use this general default value to start with. */
8097 /* First remove .exe suffix from invocation-name - it looks ugly. */
8098 {
8099 char basename[ MAX_PATH ], *str;
8100
8101 strcpy (basename, XSTRING (Vinvocation_name)->data);
8102 str = strrchr (basename, '.');
8103 if (str) *str = 0;
8104 Vinvocation_name = build_string (basename);
8105 }
8106 Vx_resource_name = Vinvocation_name;
8107
8108 validate_x_resource_name ();
8109
8110 /* This is what opens the connection and sets x_current_display.
8111 This also initializes many symbols, such as those used for input. */
8112 dpyinfo = w32_term_init (display, xrm_option,
8113 (char *) XSTRING (Vx_resource_name)->data);
8114
8115 if (dpyinfo == 0)
8116 {
8117 if (!NILP (must_succeed))
8118 fatal ("Cannot connect to server %s.\n",
8119 XSTRING (display)->data);
8120 else
8121 error ("Cannot connect to server %s", XSTRING (display)->data);
8122 }
8123
8124 w32_in_use = 1;
8125
8126 XSETFASTINT (Vwindow_system_version, 3);
8127 return Qnil;
8128}
8129
8130DEFUN ("x-close-connection", Fx_close_connection,
8131 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
8132 doc: /* Close the connection to DISPLAY's server.
8133For DISPLAY, specify either a frame or a display name (a string).
8134If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
8135 (display)
8136 Lisp_Object display;
8137{
8138 struct w32_display_info *dpyinfo = check_x_display_info (display);
8139 int i;
8140
8141 if (dpyinfo->reference_count > 0)
8142 error ("Display still has frames on it");
8143
8144 BLOCK_INPUT;
8145 /* Free the fonts in the font table. */
8146 for (i = 0; i < dpyinfo->n_fonts; i++)
8147 if (dpyinfo->font_table[i].name)
8148 {
126f2e35
JR
8149 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8150 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 8151 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
8152 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8153 }
8154 x_destroy_all_bitmaps (dpyinfo);
8155
8156 x_delete_display (dpyinfo);
8157 UNBLOCK_INPUT;
8158
8159 return Qnil;
8160}
8161
8162DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 8163 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
8164 ()
8165{
8166 Lisp_Object tail, result;
8167
8168 result = Qnil;
8169 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8170 result = Fcons (XCAR (XCAR (tail)), result);
8171
8172 return result;
8173}
8174
8175DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
8176 doc: /* This is a noop on W32 systems. */)
8177 (on, display)
8178 Lisp_Object display, on;
6fc2811b 8179{
6fc2811b
JR
8180 return Qnil;
8181}
8182
8183\f
6fc2811b
JR
8184/***********************************************************************
8185 Image types
8186 ***********************************************************************/
8187
8188/* Value is the number of elements of vector VECTOR. */
8189
8190#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8191
8192/* List of supported image types. Use define_image_type to add new
8193 types. Use lookup_image_type to find a type for a given symbol. */
8194
8195static struct image_type *image_types;
8196
6fc2811b
JR
8197/* The symbol `image' which is the car of the lists used to represent
8198 images in Lisp. */
8199
8200extern Lisp_Object Qimage;
8201
8202/* The symbol `xbm' which is used as the type symbol for XBM images. */
8203
8204Lisp_Object Qxbm;
8205
8206/* Keywords. */
8207
6fc2811b 8208extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
8209extern Lisp_Object QCdata, QCtype;
8210Lisp_Object QCascent, QCmargin, QCrelief;
a93f4566 8211Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 8212Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
8213
8214/* Other symbols. */
8215
3cf3436e 8216Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
8217
8218/* Time in seconds after which images should be removed from the cache
8219 if not displayed. */
8220
8221Lisp_Object Vimage_cache_eviction_delay;
8222
8223/* Function prototypes. */
8224
8225static void define_image_type P_ ((struct image_type *type));
8226static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8227static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8228static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 8229static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
8230static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8231 Lisp_Object));
8232
dfff8a69 8233
6fc2811b
JR
8234/* Define a new image type from TYPE. This adds a copy of TYPE to
8235 image_types and adds the symbol *TYPE->type to Vimage_types. */
8236
8237static void
8238define_image_type (type)
8239 struct image_type *type;
8240{
8241 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8242 The initialized data segment is read-only. */
8243 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8244 bcopy (type, p, sizeof *p);
8245 p->next = image_types;
8246 image_types = p;
8247 Vimage_types = Fcons (*p->type, Vimage_types);
8248}
8249
8250
8251/* Look up image type SYMBOL, and return a pointer to its image_type
8252 structure. Value is null if SYMBOL is not a known image type. */
8253
8254static INLINE struct image_type *
8255lookup_image_type (symbol)
8256 Lisp_Object symbol;
8257{
8258 struct image_type *type;
8259
8260 for (type = image_types; type; type = type->next)
8261 if (EQ (symbol, *type->type))
8262 break;
8263
8264 return type;
8265}
8266
8267
8268/* Value is non-zero if OBJECT is a valid Lisp image specification. A
8269 valid image specification is a list whose car is the symbol
8270 `image', and whose rest is a property list. The property list must
8271 contain a value for key `:type'. That value must be the name of a
8272 supported image type. The rest of the property list depends on the
8273 image type. */
8274
8275int
8276valid_image_p (object)
8277 Lisp_Object object;
8278{
8279 int valid_p = 0;
8280
8281 if (CONSP (object) && EQ (XCAR (object), Qimage))
8282 {
3cf3436e
JR
8283 Lisp_Object tem;
8284
8285 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8286 if (EQ (XCAR (tem), QCtype))
8287 {
8288 tem = XCDR (tem);
8289 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8290 {
8291 struct image_type *type;
8292 type = lookup_image_type (XCAR (tem));
8293 if (type)
8294 valid_p = type->valid_p (object);
8295 }
8296
8297 break;
8298 }
6fc2811b
JR
8299 }
8300
8301 return valid_p;
8302}
8303
8304
8305/* Log error message with format string FORMAT and argument ARG.
8306 Signaling an error, e.g. when an image cannot be loaded, is not a
8307 good idea because this would interrupt redisplay, and the error
8308 message display would lead to another redisplay. This function
8309 therefore simply displays a message. */
8310
8311static void
8312image_error (format, arg1, arg2)
8313 char *format;
8314 Lisp_Object arg1, arg2;
8315{
8316 add_to_log (format, arg1, arg2);
8317}
8318
8319
8320\f
8321/***********************************************************************
8322 Image specifications
8323 ***********************************************************************/
8324
8325enum image_value_type
8326{
8327 IMAGE_DONT_CHECK_VALUE_TYPE,
8328 IMAGE_STRING_VALUE,
3cf3436e 8329 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
8330 IMAGE_SYMBOL_VALUE,
8331 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8332 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8333 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8334 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8335 IMAGE_INTEGER_VALUE,
8336 IMAGE_FUNCTION_VALUE,
8337 IMAGE_NUMBER_VALUE,
8338 IMAGE_BOOL_VALUE
8339};
8340
8341/* Structure used when parsing image specifications. */
8342
8343struct image_keyword
8344{
8345 /* Name of keyword. */
8346 char *name;
8347
8348 /* The type of value allowed. */
8349 enum image_value_type type;
8350
8351 /* Non-zero means key must be present. */
8352 int mandatory_p;
8353
8354 /* Used to recognize duplicate keywords in a property list. */
8355 int count;
8356
8357 /* The value that was found. */
8358 Lisp_Object value;
8359};
8360
8361
8362static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8363 int, Lisp_Object));
8364static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8365
8366
8367/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8368 has the format (image KEYWORD VALUE ...). One of the keyword/
8369 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8370 image_keywords structures of size NKEYWORDS describing other
8371 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8372
8373static int
8374parse_image_spec (spec, keywords, nkeywords, type)
8375 Lisp_Object spec;
8376 struct image_keyword *keywords;
8377 int nkeywords;
8378 Lisp_Object type;
8379{
8380 int i;
8381 Lisp_Object plist;
8382
8383 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8384 return 0;
8385
8386 plist = XCDR (spec);
8387 while (CONSP (plist))
8388 {
8389 Lisp_Object key, value;
8390
8391 /* First element of a pair must be a symbol. */
8392 key = XCAR (plist);
8393 plist = XCDR (plist);
8394 if (!SYMBOLP (key))
8395 return 0;
8396
8397 /* There must follow a value. */
8398 if (!CONSP (plist))
8399 return 0;
8400 value = XCAR (plist);
8401 plist = XCDR (plist);
8402
8403 /* Find key in KEYWORDS. Error if not found. */
8404 for (i = 0; i < nkeywords; ++i)
38b76195 8405 if (strcmp (keywords[i].name, XSTRING (SYMBOL_NAME (key))->data) == 0)
6fc2811b
JR
8406 break;
8407
8408 if (i == nkeywords)
8409 continue;
8410
8411 /* Record that we recognized the keyword. If a keywords
8412 was found more than once, it's an error. */
8413 keywords[i].value = value;
8414 ++keywords[i].count;
8415
8416 if (keywords[i].count > 1)
8417 return 0;
8418
8419 /* Check type of value against allowed type. */
8420 switch (keywords[i].type)
8421 {
8422 case IMAGE_STRING_VALUE:
8423 if (!STRINGP (value))
8424 return 0;
8425 break;
8426
3cf3436e
JR
8427 case IMAGE_STRING_OR_NIL_VALUE:
8428 if (!STRINGP (value) && !NILP (value))
8429 return 0;
8430 break;
8431
6fc2811b
JR
8432 case IMAGE_SYMBOL_VALUE:
8433 if (!SYMBOLP (value))
8434 return 0;
8435 break;
8436
8437 case IMAGE_POSITIVE_INTEGER_VALUE:
8438 if (!INTEGERP (value) || XINT (value) <= 0)
8439 return 0;
8440 break;
8441
8edb0a6f
JR
8442 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8443 if (INTEGERP (value) && XINT (value) >= 0)
8444 break;
8445 if (CONSP (value)
8446 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8447 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8448 break;
8449 return 0;
8450
dfff8a69
JR
8451 case IMAGE_ASCENT_VALUE:
8452 if (SYMBOLP (value) && EQ (value, Qcenter))
8453 break;
8454 else if (INTEGERP (value)
8455 && XINT (value) >= 0
8456 && XINT (value) <= 100)
8457 break;
8458 return 0;
8459
6fc2811b
JR
8460 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8461 if (!INTEGERP (value) || XINT (value) < 0)
8462 return 0;
8463 break;
8464
8465 case IMAGE_DONT_CHECK_VALUE_TYPE:
8466 break;
8467
8468 case IMAGE_FUNCTION_VALUE:
8469 value = indirect_function (value);
8470 if (SUBRP (value)
8471 || COMPILEDP (value)
8472 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8473 break;
8474 return 0;
8475
8476 case IMAGE_NUMBER_VALUE:
8477 if (!INTEGERP (value) && !FLOATP (value))
8478 return 0;
8479 break;
8480
8481 case IMAGE_INTEGER_VALUE:
8482 if (!INTEGERP (value))
8483 return 0;
8484 break;
8485
8486 case IMAGE_BOOL_VALUE:
8487 if (!NILP (value) && !EQ (value, Qt))
8488 return 0;
8489 break;
8490
8491 default:
8492 abort ();
8493 break;
8494 }
8495
8496 if (EQ (key, QCtype) && !EQ (type, value))
8497 return 0;
8498 }
8499
8500 /* Check that all mandatory fields are present. */
8501 for (i = 0; i < nkeywords; ++i)
8502 if (keywords[i].mandatory_p && keywords[i].count == 0)
8503 return 0;
8504
8505 return NILP (plist);
8506}
8507
8508
8509/* Return the value of KEY in image specification SPEC. Value is nil
8510 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8511 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8512
8513static Lisp_Object
8514image_spec_value (spec, key, found)
8515 Lisp_Object spec, key;
8516 int *found;
8517{
8518 Lisp_Object tail;
8519
8520 xassert (valid_image_p (spec));
8521
8522 for (tail = XCDR (spec);
8523 CONSP (tail) && CONSP (XCDR (tail));
8524 tail = XCDR (XCDR (tail)))
8525 {
8526 if (EQ (XCAR (tail), key))
8527 {
8528 if (found)
8529 *found = 1;
8530 return XCAR (XCDR (tail));
8531 }
8532 }
8533
8534 if (found)
8535 *found = 0;
8536 return Qnil;
8537}
8538
8539
ac849ba4
JR
8540DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8541 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8542PIXELS non-nil means return the size in pixels, otherwise return the
8543size in canonical character units.
8544FRAME is the frame on which the image will be displayed. FRAME nil
8545or omitted means use the selected frame. */)
8546 (spec, pixels, frame)
8547 Lisp_Object spec, pixels, frame;
8548{
8549 Lisp_Object size;
8550
8551 size = Qnil;
8552 if (valid_image_p (spec))
8553 {
8554 struct frame *f = check_x_frame (frame);
8555 int id = lookup_image (f, spec);
8556 struct image *img = IMAGE_FROM_ID (f, id);
8557 int width = img->width + 2 * img->hmargin;
8558 int height = img->height + 2 * img->vmargin;
8559
8560 if (NILP (pixels))
8561 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8562 make_float ((double) height / CANON_Y_UNIT (f)));
8563 else
8564 size = Fcons (make_number (width), make_number (height));
8565 }
8566 else
8567 error ("Invalid image specification");
8568
8569 return size;
8570}
8571
8572
8573DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8574 doc: /* Return t if image SPEC has a mask bitmap.
8575FRAME is the frame on which the image will be displayed. FRAME nil
8576or omitted means use the selected frame. */)
8577 (spec, frame)
8578 Lisp_Object spec, frame;
8579{
8580 Lisp_Object mask;
8581
8582 mask = Qnil;
8583 if (valid_image_p (spec))
8584 {
8585 struct frame *f = check_x_frame (frame);
8586 int id = lookup_image (f, spec);
8587 struct image *img = IMAGE_FROM_ID (f, id);
8588 if (img->mask)
8589 mask = Qt;
8590 }
8591 else
8592 error ("Invalid image specification");
8593
8594 return mask;
8595}
6fc2811b
JR
8596
8597\f
8598/***********************************************************************
8599 Image type independent image structures
8600 ***********************************************************************/
8601
8602static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8603static void free_image P_ ((struct frame *f, struct image *img));
8604
8605
8606/* Allocate and return a new image structure for image specification
8607 SPEC. SPEC has a hash value of HASH. */
8608
8609static struct image *
8610make_image (spec, hash)
8611 Lisp_Object spec;
8612 unsigned hash;
8613{
8614 struct image *img = (struct image *) xmalloc (sizeof *img);
8615
8616 xassert (valid_image_p (spec));
8617 bzero (img, sizeof *img);
8618 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8619 xassert (img->type != NULL);
8620 img->spec = spec;
8621 img->data.lisp_val = Qnil;
8622 img->ascent = DEFAULT_IMAGE_ASCENT;
8623 img->hash = hash;
8624 return img;
8625}
8626
8627
8628/* Free image IMG which was used on frame F, including its resources. */
8629
8630static void
8631free_image (f, img)
8632 struct frame *f;
8633 struct image *img;
8634{
8635 if (img)
8636 {
8637 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8638
8639 /* Remove IMG from the hash table of its cache. */
8640 if (img->prev)
8641 img->prev->next = img->next;
8642 else
8643 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8644
8645 if (img->next)
8646 img->next->prev = img->prev;
8647
8648 c->images[img->id] = NULL;
8649
8650 /* Free resources, then free IMG. */
8651 img->type->free (f, img);
8652 xfree (img);
8653 }
8654}
8655
8656
8657/* Prepare image IMG for display on frame F. Must be called before
8658 drawing an image. */
8659
8660void
8661prepare_image_for_display (f, img)
8662 struct frame *f;
8663 struct image *img;
8664{
8665 EMACS_TIME t;
8666
8667 /* We're about to display IMG, so set its timestamp to `now'. */
8668 EMACS_GET_TIME (t);
8669 img->timestamp = EMACS_SECS (t);
8670
8671 /* If IMG doesn't have a pixmap yet, load it now, using the image
8672 type dependent loader function. */
8673 if (img->pixmap == 0 && !img->load_failed_p)
8674 img->load_failed_p = img->type->load (f, img) == 0;
8675}
8676
8677
dfff8a69
JR
8678/* Value is the number of pixels for the ascent of image IMG when
8679 drawn in face FACE. */
8680
8681int
8682image_ascent (img, face)
8683 struct image *img;
8684 struct face *face;
8685{
8edb0a6f 8686 int height = img->height + img->vmargin;
dfff8a69
JR
8687 int ascent;
8688
8689 if (img->ascent == CENTERED_IMAGE_ASCENT)
8690 {
8691 if (face->font)
8692 ascent = height / 2 - (FONT_DESCENT(face->font)
8693 - FONT_BASE(face->font)) / 2;
8694 else
8695 ascent = height / 2;
8696 }
8697 else
ac849ba4 8698 ascent = (int) (height * img->ascent / 100.0);
dfff8a69
JR
8699
8700 return ascent;
8701}
8702
8703
6fc2811b 8704\f
a05e2bae
JR
8705/* Image background colors. */
8706
ac849ba4
JR
8707/* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8708 context with the bitmap selected. */
8709static COLORREF
a05e2bae 8710four_corners_best (ximg, width, height)
ac849ba4 8711 HDC ximg;
a05e2bae
JR
8712 unsigned long width, height;
8713{
ac849ba4 8714 COLORREF corners[4], best;
a05e2bae
JR
8715 int i, best_count;
8716
8717 /* Get the colors at the corners of ximg. */
ac849ba4
JR
8718 corners[0] = GetPixel (ximg, 0, 0);
8719 corners[1] = GetPixel (ximg, width - 1, 0);
8720 corners[2] = GetPixel (ximg, width - 1, height - 1);
8721 corners[3] = GetPixel (ximg, 0, height - 1);
a05e2bae
JR
8722
8723 /* Choose the most frequently found color as background. */
8724 for (i = best_count = 0; i < 4; ++i)
8725 {
8726 int j, n;
8727
8728 for (j = n = 0; j < 4; ++j)
8729 if (corners[i] == corners[j])
8730 ++n;
8731
8732 if (n > best_count)
8733 best = corners[i], best_count = n;
8734 }
8735
8736 return best;
a05e2bae
JR
8737}
8738
8739/* Return the `background' field of IMG. If IMG doesn't have one yet,
8740 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8741 object to use for the heuristic. */
8742
8743unsigned long
8744image_background (img, f, ximg)
8745 struct image *img;
8746 struct frame *f;
8747 XImage *ximg;
8748{
8749 if (! img->background_valid)
8750 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8751 {
8752#if 0 /* TODO: Image support. */
8753 int free_ximg = !ximg;
8754
8755 if (! ximg)
8756 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8757 0, 0, img->width, img->height, ~0, ZPixmap);
8758
8759 img->background = four_corners_best (ximg, img->width, img->height);
8760
8761 if (free_ximg)
8762 XDestroyImage (ximg);
8763
8764 img->background_valid = 1;
8765#endif
8766 }
8767
8768 return img->background;
8769}
8770
8771/* Return the `background_transparent' field of IMG. If IMG doesn't
8772 have one yet, it is guessed heuristically. If non-zero, MASK is an
8773 existing XImage object to use for the heuristic. */
8774
8775int
8776image_background_transparent (img, f, mask)
8777 struct image *img;
8778 struct frame *f;
8779 XImage *mask;
8780{
8781 if (! img->background_transparent_valid)
8782 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8783 {
8784#if 0 /* TODO: Image support. */
8785 if (img->mask)
8786 {
8787 int free_mask = !mask;
8788
8789 if (! mask)
8790 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8791 0, 0, img->width, img->height, ~0, ZPixmap);
8792
8793 img->background_transparent
8794 = !four_corners_best (mask, img->width, img->height);
8795
8796 if (free_mask)
8797 XDestroyImage (mask);
8798 }
8799 else
8800#endif
8801 img->background_transparent = 0;
8802
8803 img->background_transparent_valid = 1;
8804 }
8805
8806 return img->background_transparent;
8807}
8808
8809\f
6fc2811b
JR
8810/***********************************************************************
8811 Helper functions for X image types
8812 ***********************************************************************/
8813
a05e2bae
JR
8814static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8815 int, int));
6fc2811b
JR
8816static void x_clear_image P_ ((struct frame *f, struct image *img));
8817static unsigned long x_alloc_image_color P_ ((struct frame *f,
8818 struct image *img,
8819 Lisp_Object color_name,
8820 unsigned long dflt));
8821
a05e2bae
JR
8822
8823/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8824 free the pixmap if any. MASK_P non-zero means clear the mask
8825 pixmap if any. COLORS_P non-zero means free colors allocated for
8826 the image, if any. */
8827
8828static void
8829x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8830 struct frame *f;
8831 struct image *img;
8832 int pixmap_p, mask_p, colors_p;
8833{
a05e2bae
JR
8834 if (pixmap_p && img->pixmap)
8835 {
ac849ba4
JR
8836 DeleteObject (img->pixmap);
8837 img->pixmap = NULL;
a05e2bae
JR
8838 img->background_valid = 0;
8839 }
8840
8841 if (mask_p && img->mask)
8842 {
ac849ba4
JR
8843 DeleteObject (img->mask);
8844 img->mask = NULL;
a05e2bae
JR
8845 img->background_transparent_valid = 0;
8846 }
8847
8848 if (colors_p && img->ncolors)
8849 {
bf76fe9c 8850#if 0 /* TODO: color table support. */
a05e2bae 8851 x_free_colors (f, img->colors, img->ncolors);
bf76fe9c 8852#endif
a05e2bae
JR
8853 xfree (img->colors);
8854 img->colors = NULL;
8855 img->ncolors = 0;
8856 }
a05e2bae
JR
8857}
8858
6fc2811b
JR
8859/* Free X resources of image IMG which is used on frame F. */
8860
8861static void
8862x_clear_image (f, img)
8863 struct frame *f;
8864 struct image *img;
8865{
6fc2811b
JR
8866 if (img->pixmap)
8867 {
8868 BLOCK_INPUT;
ac849ba4 8869 DeleteObject (img->pixmap);
6fc2811b
JR
8870 img->pixmap = 0;
8871 UNBLOCK_INPUT;
8872 }
8873
8874 if (img->ncolors)
8875 {
ac849ba4
JR
8876#if 0 /* TODO: color table support */
8877
6fc2811b
JR
8878 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8879
8880 /* If display has an immutable color map, freeing colors is not
8881 necessary and some servers don't allow it. So don't do it. */
8882 if (class != StaticColor
8883 && class != StaticGray
8884 && class != TrueColor)
8885 {
8886 Colormap cmap;
8887 BLOCK_INPUT;
8888 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8889 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8890 img->ncolors, 0);
8891 UNBLOCK_INPUT;
8892 }
ac849ba4 8893#endif
6fc2811b
JR
8894
8895 xfree (img->colors);
8896 img->colors = NULL;
8897 img->ncolors = 0;
8898 }
6fc2811b
JR
8899}
8900
8901
8902/* Allocate color COLOR_NAME for image IMG on frame F. If color
8903 cannot be allocated, use DFLT. Add a newly allocated color to
8904 IMG->colors, so that it can be freed again. Value is the pixel
8905 color. */
8906
8907static unsigned long
8908x_alloc_image_color (f, img, color_name, dflt)
8909 struct frame *f;
8910 struct image *img;
8911 Lisp_Object color_name;
8912 unsigned long dflt;
8913{
6fc2811b
JR
8914 XColor color;
8915 unsigned long result;
8916
8917 xassert (STRINGP (color_name));
8918
8919 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8920 {
8921 /* This isn't called frequently so we get away with simply
8922 reallocating the color vector to the needed size, here. */
8923 ++img->ncolors;
8924 img->colors =
8925 (unsigned long *) xrealloc (img->colors,
8926 img->ncolors * sizeof *img->colors);
8927 img->colors[img->ncolors - 1] = color.pixel;
8928 result = color.pixel;
8929 }
8930 else
8931 result = dflt;
8932 return result;
6fc2811b
JR
8933}
8934
8935
8936\f
8937/***********************************************************************
8938 Image Cache
8939 ***********************************************************************/
8940
8941static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8942static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8943
8944
8945/* Return a new, initialized image cache that is allocated from the
8946 heap. Call free_image_cache to free an image cache. */
8947
8948struct image_cache *
8949make_image_cache ()
8950{
8951 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8952 int size;
8953
8954 bzero (c, sizeof *c);
8955 c->size = 50;
8956 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8957 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8958 c->buckets = (struct image **) xmalloc (size);
8959 bzero (c->buckets, size);
8960 return c;
8961}
8962
8963
8964/* Free image cache of frame F. Be aware that X frames share images
8965 caches. */
8966
8967void
8968free_image_cache (f)
8969 struct frame *f;
8970{
8971 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8972 if (c)
8973 {
8974 int i;
8975
8976 /* Cache should not be referenced by any frame when freed. */
8977 xassert (c->refcount == 0);
8978
8979 for (i = 0; i < c->used; ++i)
8980 free_image (f, c->images[i]);
8981 xfree (c->images);
8982 xfree (c);
8983 xfree (c->buckets);
8984 FRAME_X_IMAGE_CACHE (f) = NULL;
8985 }
8986}
8987
8988
8989/* Clear image cache of frame F. FORCE_P non-zero means free all
8990 images. FORCE_P zero means clear only images that haven't been
8991 displayed for some time. Should be called from time to time to
dfff8a69
JR
8992 reduce the number of loaded images. If image-eviction-seconds is
8993 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8994 at least that many seconds. */
8995
8996void
8997clear_image_cache (f, force_p)
8998 struct frame *f;
8999 int force_p;
9000{
9001 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9002
9003 if (c && INTEGERP (Vimage_cache_eviction_delay))
9004 {
9005 EMACS_TIME t;
9006 unsigned long old;
0327b4cc 9007 int i, nfreed;
6fc2811b
JR
9008
9009 EMACS_GET_TIME (t);
9010 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
9011
0327b4cc
JR
9012 /* Block input so that we won't be interrupted by a SIGIO
9013 while being in an inconsistent state. */
9014 BLOCK_INPUT;
9015
9016 for (i = nfreed = 0; i < c->used; ++i)
6fc2811b
JR
9017 {
9018 struct image *img = c->images[i];
9019 if (img != NULL
0327b4cc 9020 && (force_p || (img->timestamp < old)))
6fc2811b
JR
9021 {
9022 free_image (f, img);
0327b4cc 9023 ++nfreed;
6fc2811b
JR
9024 }
9025 }
9026
9027 /* We may be clearing the image cache because, for example,
9028 Emacs was iconified for a longer period of time. In that
9029 case, current matrices may still contain references to
9030 images freed above. So, clear these matrices. */
0327b4cc 9031 if (nfreed)
6fc2811b 9032 {
0327b4cc
JR
9033 Lisp_Object tail, frame;
9034
9035 FOR_EACH_FRAME (tail, frame)
9036 {
9037 struct frame *f = XFRAME (frame);
9038 if (FRAME_W32_P (f)
9039 && FRAME_X_IMAGE_CACHE (f) == c)
9040 clear_current_matrices (f);
9041 }
9042
6fc2811b
JR
9043 ++windows_or_buffers_changed;
9044 }
0327b4cc
JR
9045
9046 UNBLOCK_INPUT;
6fc2811b
JR
9047 }
9048}
9049
9050
9051DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9052 0, 1, 0,
74e1aeec
JR
9053 doc: /* Clear the image cache of FRAME.
9054FRAME nil or omitted means use the selected frame.
9055FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
9056 (frame)
9057 Lisp_Object frame;
9058{
9059 if (EQ (frame, Qt))
9060 {
9061 Lisp_Object tail;
9062
9063 FOR_EACH_FRAME (tail, frame)
9064 if (FRAME_W32_P (XFRAME (frame)))
9065 clear_image_cache (XFRAME (frame), 1);
9066 }
9067 else
9068 clear_image_cache (check_x_frame (frame), 1);
9069
9070 return Qnil;
9071}
9072
9073
3cf3436e
JR
9074/* Compute masks and transform image IMG on frame F, as specified
9075 by the image's specification, */
9076
9077static void
9078postprocess_image (f, img)
9079 struct frame *f;
9080 struct image *img;
9081{
9082#if 0 /* TODO: image support. */
9083 /* Manipulation of the image's mask. */
9084 if (img->pixmap)
9085 {
9086 Lisp_Object conversion, spec;
9087 Lisp_Object mask;
9088
9089 spec = img->spec;
9090
9091 /* `:heuristic-mask t'
9092 `:mask heuristic'
9093 means build a mask heuristically.
9094 `:heuristic-mask (R G B)'
9095 `:mask (heuristic (R G B))'
9096 means build a mask from color (R G B) in the
9097 image.
9098 `:mask nil'
9099 means remove a mask, if any. */
9100
9101 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9102 if (!NILP (mask))
9103 x_build_heuristic_mask (f, img, mask);
9104 else
9105 {
9106 int found_p;
9107
9108 mask = image_spec_value (spec, QCmask, &found_p);
9109
9110 if (EQ (mask, Qheuristic))
9111 x_build_heuristic_mask (f, img, Qt);
9112 else if (CONSP (mask)
9113 && EQ (XCAR (mask), Qheuristic))
9114 {
9115 if (CONSP (XCDR (mask)))
9116 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9117 else
9118 x_build_heuristic_mask (f, img, XCDR (mask));
9119 }
9120 else if (NILP (mask) && found_p && img->mask)
9121 {
ac849ba4 9122 DeleteObject (img->mask);
3cf3436e
JR
9123 img->mask = NULL;
9124 }
9125 }
9126
9127
9128 /* Should we apply an image transformation algorithm? */
9129 conversion = image_spec_value (spec, QCconversion, NULL);
9130 if (EQ (conversion, Qdisabled))
9131 x_disable_image (f, img);
9132 else if (EQ (conversion, Qlaplace))
9133 x_laplace (f, img);
9134 else if (EQ (conversion, Qemboss))
9135 x_emboss (f, img);
9136 else if (CONSP (conversion)
9137 && EQ (XCAR (conversion), Qedge_detection))
9138 {
9139 Lisp_Object tem;
9140 tem = XCDR (conversion);
9141 if (CONSP (tem))
9142 x_edge_detection (f, img,
9143 Fplist_get (tem, QCmatrix),
9144 Fplist_get (tem, QCcolor_adjustment));
9145 }
9146 }
9147#endif
9148}
9149
9150
6fc2811b
JR
9151/* Return the id of image with Lisp specification SPEC on frame F.
9152 SPEC must be a valid Lisp image specification (see valid_image_p). */
9153
9154int
9155lookup_image (f, spec)
9156 struct frame *f;
9157 Lisp_Object spec;
9158{
9159 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9160 struct image *img;
9161 int i;
9162 unsigned hash;
9163 struct gcpro gcpro1;
9164 EMACS_TIME now;
9165
9166 /* F must be a window-system frame, and SPEC must be a valid image
9167 specification. */
9168 xassert (FRAME_WINDOW_P (f));
9169 xassert (valid_image_p (spec));
9170
9171 GCPRO1 (spec);
9172
9173 /* Look up SPEC in the hash table of the image cache. */
9174 hash = sxhash (spec, 0);
9175 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9176
9177 for (img = c->buckets[i]; img; img = img->next)
9178 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9179 break;
9180
9181 /* If not found, create a new image and cache it. */
9182 if (img == NULL)
9183 {
3cf3436e
JR
9184 extern Lisp_Object Qpostscript;
9185
8edb0a6f 9186 BLOCK_INPUT;
6fc2811b
JR
9187 img = make_image (spec, hash);
9188 cache_image (f, img);
9189 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
9190
9191 /* If we can't load the image, and we don't have a width and
9192 height, use some arbitrary width and height so that we can
9193 draw a rectangle for it. */
9194 if (img->load_failed_p)
9195 {
9196 Lisp_Object value;
9197
9198 value = image_spec_value (spec, QCwidth, NULL);
9199 img->width = (INTEGERP (value)
9200 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9201 value = image_spec_value (spec, QCheight, NULL);
9202 img->height = (INTEGERP (value)
9203 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9204 }
9205 else
9206 {
9207 /* Handle image type independent image attributes
a05e2bae
JR
9208 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9209 `:background COLOR'. */
9210 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
9211
9212 ascent = image_spec_value (spec, QCascent, NULL);
9213 if (INTEGERP (ascent))
9214 img->ascent = XFASTINT (ascent);
dfff8a69
JR
9215 else if (EQ (ascent, Qcenter))
9216 img->ascent = CENTERED_IMAGE_ASCENT;
9217
6fc2811b
JR
9218 margin = image_spec_value (spec, QCmargin, NULL);
9219 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
9220 img->vmargin = img->hmargin = XFASTINT (margin);
9221 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9222 && INTEGERP (XCDR (margin)))
9223 {
9224 if (XINT (XCAR (margin)) > 0)
9225 img->hmargin = XFASTINT (XCAR (margin));
9226 if (XINT (XCDR (margin)) > 0)
9227 img->vmargin = XFASTINT (XCDR (margin));
9228 }
6fc2811b
JR
9229
9230 relief = image_spec_value (spec, QCrelief, NULL);
9231 if (INTEGERP (relief))
9232 {
9233 img->relief = XINT (relief);
8edb0a6f
JR
9234 img->hmargin += abs (img->relief);
9235 img->vmargin += abs (img->relief);
6fc2811b
JR
9236 }
9237
a05e2bae
JR
9238 if (! img->background_valid)
9239 {
9240 bg = image_spec_value (img->spec, QCbackground, NULL);
9241 if (!NILP (bg))
9242 {
9243 img->background
9244 = x_alloc_image_color (f, img, bg,
9245 FRAME_BACKGROUND_PIXEL (f));
9246 img->background_valid = 1;
9247 }
9248 }
9249
3cf3436e
JR
9250 /* Do image transformations and compute masks, unless we
9251 don't have the image yet. */
9252 if (!EQ (*img->type->type, Qpostscript))
9253 postprocess_image (f, img);
6fc2811b 9254 }
3cf3436e 9255
8edb0a6f
JR
9256 UNBLOCK_INPUT;
9257 xassert (!interrupt_input_blocked);
6fc2811b
JR
9258 }
9259
9260 /* We're using IMG, so set its timestamp to `now'. */
9261 EMACS_GET_TIME (now);
9262 img->timestamp = EMACS_SECS (now);
9263
9264 UNGCPRO;
9265
9266 /* Value is the image id. */
9267 return img->id;
9268}
9269
9270
9271/* Cache image IMG in the image cache of frame F. */
9272
9273static void
9274cache_image (f, img)
9275 struct frame *f;
9276 struct image *img;
9277{
9278 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9279 int i;
9280
9281 /* Find a free slot in c->images. */
9282 for (i = 0; i < c->used; ++i)
9283 if (c->images[i] == NULL)
9284 break;
9285
9286 /* If no free slot found, maybe enlarge c->images. */
9287 if (i == c->used && c->used == c->size)
9288 {
9289 c->size *= 2;
9290 c->images = (struct image **) xrealloc (c->images,
9291 c->size * sizeof *c->images);
9292 }
9293
9294 /* Add IMG to c->images, and assign IMG an id. */
9295 c->images[i] = img;
9296 img->id = i;
9297 if (i == c->used)
9298 ++c->used;
9299
9300 /* Add IMG to the cache's hash table. */
9301 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9302 img->next = c->buckets[i];
9303 if (img->next)
9304 img->next->prev = img;
9305 img->prev = NULL;
9306 c->buckets[i] = img;
9307}
9308
9309
9310/* Call FN on every image in the image cache of frame F. Used to mark
9311 Lisp Objects in the image cache. */
9312
9313void
9314forall_images_in_image_cache (f, fn)
9315 struct frame *f;
9316 void (*fn) P_ ((struct image *img));
9317{
9318 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9319 {
9320 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9321 if (c)
9322 {
9323 int i;
9324 for (i = 0; i < c->used; ++i)
9325 if (c->images[i])
9326 fn (c->images[i]);
9327 }
9328 }
9329}
9330
9331
9332\f
9333/***********************************************************************
9334 W32 support code
9335 ***********************************************************************/
9336
6fc2811b
JR
9337static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9338 XImage **, Pixmap *));
9339static void x_destroy_x_image P_ ((XImage *));
9340static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9341
9342
9343/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9344 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9345 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
ac849ba4
JR
9346 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9347 DEPTH should indicate the bit depth of the image. Print error
9348 messages via image_error if an error occurs. Value is non-zero if
9349 successful. */
6fc2811b
JR
9350
9351static int
9352x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9353 struct frame *f;
9354 int width, height, depth;
9355 XImage **ximg;
9356 Pixmap *pixmap;
9357{
ac849ba4
JR
9358 BITMAPINFOHEADER *header;
9359 HDC hdc;
9360 int scanline_width_bits;
9361 int remainder;
9362 int palette_colors = 0;
6fc2811b 9363
ac849ba4
JR
9364 if (depth == 0)
9365 depth = 24;
6fc2811b 9366
ac849ba4
JR
9367 if (depth != 1 && depth != 4 && depth != 8
9368 && depth != 16 && depth != 24 && depth != 32)
9369 {
9370 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9371 return 0;
9372 }
9373
9374 scanline_width_bits = width * depth;
9375 remainder = scanline_width_bits % 32;
9376
9377 if (remainder)
9378 scanline_width_bits += 32 - remainder;
9379
9380 /* Bitmaps with a depth less than 16 need a palette. */
9381 /* BITMAPINFO structure already contains the first RGBQUAD. */
9382 if (depth < 16)
9383 palette_colors = 1 << depth - 1;
9384
9385 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
6fc2811b
JR
9386 if (*ximg == NULL)
9387 {
ac849ba4 9388 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
6fc2811b
JR
9389 return 0;
9390 }
9391
ac849ba4
JR
9392 header = &((*ximg)->info.bmiHeader);
9393 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9394 header->biSize = sizeof (*header);
9395 header->biWidth = width;
9396 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9397 header->biPlanes = 1;
9398 header->biBitCount = depth;
9399 header->biCompression = BI_RGB;
9400 header->biClrUsed = palette_colors;
6fc2811b 9401
ac849ba4
JR
9402 hdc = get_frame_dc (f);
9403
9404 /* Create a DIBSection and raster array for the bitmap,
9405 and store its handle in *pixmap. */
9406 *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
9407 &((*ximg)->data), NULL, 0);
9408
9409 /* Realize display palette and garbage all frames. */
9410 release_frame_dc (f, hdc);
9411
9412 if (*pixmap == NULL)
6fc2811b 9413 {
ac849ba4
JR
9414 DWORD err = GetLastError();
9415 Lisp_Object errcode;
9416 /* All system errors are < 10000, so the following is safe. */
9417 XSETINT (errcode, (int) err);
9418 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
6fc2811b 9419 x_destroy_x_image (*ximg);
6fc2811b
JR
9420 return 0;
9421 }
ac849ba4 9422
6fc2811b
JR
9423 return 1;
9424}
9425
9426
9427/* Destroy XImage XIMG. Free XIMG->data. */
9428
9429static void
9430x_destroy_x_image (ximg)
9431 XImage *ximg;
9432{
9433 xassert (interrupt_input_blocked);
9434 if (ximg)
9435 {
ac849ba4 9436 /* Data will be freed by DestroyObject. */
6fc2811b 9437 ximg->data = NULL;
ac849ba4 9438 xfree (ximg);
6fc2811b
JR
9439 }
9440}
9441
9442
9443/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9444 are width and height of both the image and pixmap. */
9445
9446static void
9447x_put_x_image (f, ximg, pixmap, width, height)
9448 struct frame *f;
9449 XImage *ximg;
9450 Pixmap pixmap;
9451{
ac849ba4
JR
9452
9453#if TODO /* W32 specific image code. */
6fc2811b 9454 GC gc;
ac849ba4 9455
6fc2811b
JR
9456 xassert (interrupt_input_blocked);
9457 gc = XCreateGC (NULL, pixmap, 0, NULL);
9458 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9459 XFreeGC (NULL, gc);
6fc2811b 9460#endif
ac849ba4 9461}
6fc2811b
JR
9462
9463\f
9464/***********************************************************************
3cf3436e 9465 File Handling
6fc2811b
JR
9466 ***********************************************************************/
9467
9468static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9469static char *slurp_file P_ ((char *, int *));
9470
6fc2811b
JR
9471
9472/* Find image file FILE. Look in data-directory, then
9473 x-bitmap-file-path. Value is the full name of the file found, or
9474 nil if not found. */
9475
9476static Lisp_Object
9477x_find_image_file (file)
9478 Lisp_Object file;
9479{
9480 Lisp_Object file_found, search_path;
9481 struct gcpro gcpro1, gcpro2;
9482 int fd;
9483
9484 file_found = Qnil;
9485 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9486 GCPRO2 (file_found, search_path);
9487
9488 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 9489 fd = openp (search_path, file, Qnil, &file_found, Qnil);
6fc2811b 9490
939d6465 9491 if (fd == -1)
6fc2811b
JR
9492 file_found = Qnil;
9493 else
9494 close (fd);
9495
9496 UNGCPRO;
9497 return file_found;
9498}
9499
9500
3cf3436e
JR
9501/* Read FILE into memory. Value is a pointer to a buffer allocated
9502 with xmalloc holding FILE's contents. Value is null if an error
9503 occurred. *SIZE is set to the size of the file. */
9504
9505static char *
9506slurp_file (file, size)
9507 char *file;
9508 int *size;
9509{
9510 FILE *fp = NULL;
9511 char *buf = NULL;
9512 struct stat st;
9513
9514 if (stat (file, &st) == 0
9515 && (fp = fopen (file, "r")) != NULL
9516 && (buf = (char *) xmalloc (st.st_size),
9517 fread (buf, 1, st.st_size, fp) == st.st_size))
9518 {
9519 *size = st.st_size;
9520 fclose (fp);
9521 }
9522 else
9523 {
9524 if (fp)
9525 fclose (fp);
9526 if (buf)
9527 {
9528 xfree (buf);
9529 buf = NULL;
9530 }
9531 }
9532
9533 return buf;
9534}
9535
9536
6fc2811b
JR
9537\f
9538/***********************************************************************
9539 XBM images
9540 ***********************************************************************/
9541
217e5be0 9542static int xbm_scan P_ ((char **, char *, char *, int *));
6fc2811b 9543static int xbm_load P_ ((struct frame *f, struct image *img));
217e5be0
JR
9544static int xbm_load_image P_ ((struct frame *f, struct image *img,
9545 char *, char *));
6fc2811b 9546static int xbm_image_p P_ ((Lisp_Object object));
217e5be0
JR
9547static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
9548 unsigned char **));
9549static int xbm_file_p P_ ((Lisp_Object));
6fc2811b
JR
9550
9551
9552/* Indices of image specification fields in xbm_format, below. */
9553
9554enum xbm_keyword_index
9555{
9556 XBM_TYPE,
9557 XBM_FILE,
9558 XBM_WIDTH,
9559 XBM_HEIGHT,
9560 XBM_DATA,
9561 XBM_FOREGROUND,
9562 XBM_BACKGROUND,
9563 XBM_ASCENT,
9564 XBM_MARGIN,
9565 XBM_RELIEF,
9566 XBM_ALGORITHM,
9567 XBM_HEURISTIC_MASK,
a05e2bae 9568 XBM_MASK,
6fc2811b
JR
9569 XBM_LAST
9570};
9571
9572/* Vector of image_keyword structures describing the format
9573 of valid XBM image specifications. */
9574
9575static struct image_keyword xbm_format[XBM_LAST] =
9576{
9577 {":type", IMAGE_SYMBOL_VALUE, 1},
9578 {":file", IMAGE_STRING_VALUE, 0},
9579 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9580 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9581 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9582 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9583 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9584 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 9585 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9586 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9587 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9588 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9589 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6fc2811b
JR
9590};
9591
9592/* Structure describing the image type XBM. */
9593
9594static struct image_type xbm_type =
9595{
9596 &Qxbm,
9597 xbm_image_p,
9598 xbm_load,
9599 x_clear_image,
9600 NULL
9601};
9602
9603/* Tokens returned from xbm_scan. */
9604
9605enum xbm_token
9606{
9607 XBM_TK_IDENT = 256,
9608 XBM_TK_NUMBER
9609};
9610
9611
9612/* Return non-zero if OBJECT is a valid XBM-type image specification.
9613 A valid specification is a list starting with the symbol `image'
9614 The rest of the list is a property list which must contain an
9615 entry `:type xbm..
9616
9617 If the specification specifies a file to load, it must contain
9618 an entry `:file FILENAME' where FILENAME is a string.
9619
9620 If the specification is for a bitmap loaded from memory it must
9621 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9622 WIDTH and HEIGHT are integers > 0. DATA may be:
9623
9624 1. a string large enough to hold the bitmap data, i.e. it must
9625 have a size >= (WIDTH + 7) / 8 * HEIGHT
9626
9627 2. a bool-vector of size >= WIDTH * HEIGHT
9628
9629 3. a vector of strings or bool-vectors, one for each line of the
9630 bitmap.
9631
217e5be0
JR
9632 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
9633 may not be specified in this case because they are defined in the
9634 XBM file.
9635
6fc2811b
JR
9636 Both the file and data forms may contain the additional entries
9637 `:background COLOR' and `:foreground COLOR'. If not present,
9638 foreground and background of the frame on which the image is
217e5be0 9639 displayed is used. */
6fc2811b
JR
9640
9641static int
9642xbm_image_p (object)
9643 Lisp_Object object;
9644{
9645 struct image_keyword kw[XBM_LAST];
9646
9647 bcopy (xbm_format, kw, sizeof kw);
9648 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9649 return 0;
9650
9651 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9652
9653 if (kw[XBM_FILE].count)
9654 {
9655 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9656 return 0;
9657 }
217e5be0
JR
9658 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
9659 {
9660 /* In-memory XBM file. */
9661 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
9662 return 0;
9663 }
6fc2811b
JR
9664 else
9665 {
9666 Lisp_Object data;
9667 int width, height;
9668
9669 /* Entries for `:width', `:height' and `:data' must be present. */
9670 if (!kw[XBM_WIDTH].count
9671 || !kw[XBM_HEIGHT].count
9672 || !kw[XBM_DATA].count)
9673 return 0;
9674
9675 data = kw[XBM_DATA].value;
9676 width = XFASTINT (kw[XBM_WIDTH].value);
9677 height = XFASTINT (kw[XBM_HEIGHT].value);
9678
9679 /* Check type of data, and width and height against contents of
9680 data. */
9681 if (VECTORP (data))
9682 {
9683 int i;
9684
9685 /* Number of elements of the vector must be >= height. */
9686 if (XVECTOR (data)->size < height)
9687 return 0;
9688
9689 /* Each string or bool-vector in data must be large enough
9690 for one line of the image. */
9691 for (i = 0; i < height; ++i)
9692 {
9693 Lisp_Object elt = XVECTOR (data)->contents[i];
9694
9695 if (STRINGP (elt))
9696 {
9697 if (XSTRING (elt)->size
9698 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9699 return 0;
9700 }
9701 else if (BOOL_VECTOR_P (elt))
9702 {
9703 if (XBOOL_VECTOR (elt)->size < width)
9704 return 0;
9705 }
9706 else
9707 return 0;
9708 }
9709 }
9710 else if (STRINGP (data))
9711 {
9712 if (XSTRING (data)->size
9713 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9714 return 0;
9715 }
9716 else if (BOOL_VECTOR_P (data))
9717 {
9718 if (XBOOL_VECTOR (data)->size < width * height)
9719 return 0;
9720 }
9721 else
9722 return 0;
9723 }
9724
6fc2811b
JR
9725 return 1;
9726}
9727
9728
9729/* Scan a bitmap file. FP is the stream to read from. Value is
9730 either an enumerator from enum xbm_token, or a character for a
9731 single-character token, or 0 at end of file. If scanning an
9732 identifier, store the lexeme of the identifier in SVAL. If
9733 scanning a number, store its value in *IVAL. */
9734
9735static int
3cf3436e
JR
9736xbm_scan (s, end, sval, ival)
9737 char **s, *end;
6fc2811b
JR
9738 char *sval;
9739 int *ival;
9740{
9741 int c;
3cf3436e
JR
9742
9743 loop:
9744
6fc2811b 9745 /* Skip white space. */
af3f7be7 9746 while (*s < end && (c = *(*s)++, isspace (c)))
6fc2811b
JR
9747 ;
9748
3cf3436e 9749 if (*s >= end)
6fc2811b
JR
9750 c = 0;
9751 else if (isdigit (c))
9752 {
9753 int value = 0, digit;
9754
3cf3436e 9755 if (c == '0' && *s < end)
6fc2811b 9756 {
3cf3436e 9757 c = *(*s)++;
6fc2811b
JR
9758 if (c == 'x' || c == 'X')
9759 {
3cf3436e 9760 while (*s < end)
6fc2811b 9761 {
3cf3436e 9762 c = *(*s)++;
6fc2811b
JR
9763 if (isdigit (c))
9764 digit = c - '0';
9765 else if (c >= 'a' && c <= 'f')
9766 digit = c - 'a' + 10;
9767 else if (c >= 'A' && c <= 'F')
9768 digit = c - 'A' + 10;
9769 else
9770 break;
9771 value = 16 * value + digit;
9772 }
9773 }
9774 else if (isdigit (c))
9775 {
9776 value = c - '0';
3cf3436e
JR
9777 while (*s < end
9778 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9779 value = 8 * value + c - '0';
9780 }
9781 }
9782 else
9783 {
9784 value = c - '0';
3cf3436e
JR
9785 while (*s < end
9786 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9787 value = 10 * value + c - '0';
9788 }
9789
3cf3436e
JR
9790 if (*s < end)
9791 *s = *s - 1;
6fc2811b
JR
9792 *ival = value;
9793 c = XBM_TK_NUMBER;
9794 }
9795 else if (isalpha (c) || c == '_')
9796 {
9797 *sval++ = c;
3cf3436e
JR
9798 while (*s < end
9799 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9800 *sval++ = c;
9801 *sval = 0;
3cf3436e
JR
9802 if (*s < end)
9803 *s = *s - 1;
6fc2811b
JR
9804 c = XBM_TK_IDENT;
9805 }
3cf3436e
JR
9806 else if (c == '/' && **s == '*')
9807 {
9808 /* C-style comment. */
9809 ++*s;
9810 while (**s && (**s != '*' || *(*s + 1) != '/'))
9811 ++*s;
9812 if (**s)
9813 {
9814 *s += 2;
9815 goto loop;
9816 }
9817 }
6fc2811b
JR
9818
9819 return c;
9820}
9821
9822
217e5be0
JR
9823/* XBM bits seem to be backward within bytes compared with how
9824 Windows does things. */
9825static unsigned char reflect_byte (unsigned char orig)
9826{
9827 int i;
9828 unsigned char reflected = 0x00;
9829 for (i = 0; i < 8; i++)
9830 {
9831 if (orig & (0x01 << i))
9832 reflected |= 0x80 >> i;
9833 }
9834 return reflected;
9835}
9836
9837
af3f7be7
JR
9838/* Create a Windows bitmap from X bitmap data. */
9839static HBITMAP
9840w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
9841{
9842 int i, j, w1, w2;
9843 char *bits, *p;
9844 HBITMAP bmp;
9845
9846 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
9847 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
9848 bits = (char *) xmalloc (height * w2);
9849 bzero (bits, height * w2);
9850 for (i = 0; i < height; i++)
9851 {
9852 p = bits + i*w2;
9853 for (j = 0; j < w1; j++)
9854 *p++ = reflect_byte(*data++);
9855 }
9856 bmp = CreateBitmap (width, height, 1, 1, bits);
9857 xfree (bits);
9858
9859 return bmp;
9860}
9861
9862
6fc2811b 9863/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9864 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9865 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9866 the image. Return in *DATA the bitmap data allocated with xmalloc.
9867 Value is non-zero if successful. DATA null means just test if
9868 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9869
9870static int
3cf3436e
JR
9871xbm_read_bitmap_data (contents, end, width, height, data)
9872 char *contents, *end;
6fc2811b
JR
9873 int *width, *height;
9874 unsigned char **data;
9875{
3cf3436e 9876 char *s = contents;
6fc2811b
JR
9877 char buffer[BUFSIZ];
9878 int padding_p = 0;
9879 int v10 = 0;
af3f7be7 9880 int bytes_per_line, i, nbytes;
6fc2811b
JR
9881 unsigned char *p;
9882 int value;
9883 int LA1;
9884
9885#define match() \
217e5be0 9886 LA1 = xbm_scan (&s, end, buffer, &value)
6fc2811b
JR
9887
9888#define expect(TOKEN) \
9889 if (LA1 != (TOKEN)) \
9890 goto failure; \
9891 else \
9892 match ()
9893
9894#define expect_ident(IDENT) \
9895 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9896 match (); \
9897 else \
9898 goto failure
9899
6fc2811b 9900 *width = *height = -1;
3cf3436e
JR
9901 if (data)
9902 *data = NULL;
9903 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9904
9905 /* Parse defines for width, height and hot-spots. */
9906 while (LA1 == '#')
9907 {
9908 match ();
9909 expect_ident ("define");
9910 expect (XBM_TK_IDENT);
9911
9912 if (LA1 == XBM_TK_NUMBER);
9913 {
9914 char *p = strrchr (buffer, '_');
9915 p = p ? p + 1 : buffer;
9916 if (strcmp (p, "width") == 0)
9917 *width = value;
9918 else if (strcmp (p, "height") == 0)
9919 *height = value;
9920 }
9921 expect (XBM_TK_NUMBER);
9922 }
9923
9924 if (*width < 0 || *height < 0)
9925 goto failure;
3cf3436e
JR
9926 else if (data == NULL)
9927 goto success;
6fc2811b
JR
9928
9929 /* Parse bits. Must start with `static'. */
9930 expect_ident ("static");
9931 if (LA1 == XBM_TK_IDENT)
9932 {
9933 if (strcmp (buffer, "unsigned") == 0)
9934 {
9935 match ();
9936 expect_ident ("char");
9937 }
9938 else if (strcmp (buffer, "short") == 0)
9939 {
9940 match ();
9941 v10 = 1;
af3f7be7
JR
9942 if (*width % 16 && *width % 16 < 9)
9943 padding_p = 1;
6fc2811b
JR
9944 }
9945 else if (strcmp (buffer, "char") == 0)
9946 match ();
9947 else
9948 goto failure;
9949 }
9950 else
9951 goto failure;
9952
9953 expect (XBM_TK_IDENT);
9954 expect ('[');
9955 expect (']');
9956 expect ('=');
9957 expect ('{');
9958
af3f7be7
JR
9959 bytes_per_line = (*width + 7) / 8 + padding_p;
9960 nbytes = bytes_per_line * *height;
9961 p = *data = (char *) xmalloc (nbytes);
6fc2811b
JR
9962
9963 if (v10)
9964 {
6fc2811b
JR
9965 for (i = 0; i < nbytes; i += 2)
9966 {
9967 int val = value;
9968 expect (XBM_TK_NUMBER);
9969
af3f7be7
JR
9970 *p++ = val;
9971 if (!padding_p || ((i + 2) % bytes_per_line))
9972 *p++ = value >> 8;
6fc2811b
JR
9973
9974 if (LA1 == ',' || LA1 == '}')
9975 match ();
9976 else
9977 goto failure;
9978 }
9979 }
9980 else
9981 {
9982 for (i = 0; i < nbytes; ++i)
9983 {
9984 int val = value;
9985 expect (XBM_TK_NUMBER);
9986
af3f7be7 9987 *p++ = val;
217e5be0 9988
6fc2811b
JR
9989 if (LA1 == ',' || LA1 == '}')
9990 match ();
9991 else
9992 goto failure;
9993 }
9994 }
9995
3cf3436e 9996 success:
6fc2811b
JR
9997 return 1;
9998
9999 failure:
3cf3436e
JR
10000
10001 if (data && *data)
6fc2811b
JR
10002 {
10003 xfree (*data);
10004 *data = NULL;
10005 }
10006 return 0;
10007
10008#undef match
10009#undef expect
10010#undef expect_ident
10011}
10012
10013
3cf3436e
JR
10014/* Load XBM image IMG which will be displayed on frame F from buffer
10015 CONTENTS. END is the end of the buffer. Value is non-zero if
10016 successful. */
6fc2811b
JR
10017
10018static int
3cf3436e 10019xbm_load_image (f, img, contents, end)
6fc2811b
JR
10020 struct frame *f;
10021 struct image *img;
3cf3436e 10022 char *contents, *end;
6fc2811b
JR
10023{
10024 int rc;
10025 unsigned char *data;
10026 int success_p = 0;
6fc2811b 10027
3cf3436e 10028 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
10029 if (rc)
10030 {
6fc2811b
JR
10031 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10032 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10033 Lisp_Object value;
10034
10035 xassert (img->width > 0 && img->height > 0);
10036
10037 /* Get foreground and background colors, maybe allocate colors. */
10038 value = image_spec_value (img->spec, QCforeground, NULL);
10039 if (!NILP (value))
10040 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
10041 value = image_spec_value (img->spec, QCbackground, NULL);
10042 if (!NILP (value))
a05e2bae
JR
10043 {
10044 background = x_alloc_image_color (f, img, value, background);
10045 img->background = background;
10046 img->background_valid = 1;
10047 }
6fc2811b 10048 img->pixmap
af3f7be7 10049 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
ac849ba4 10050
6fc2811b
JR
10051 xfree (data);
10052
10053 if (img->pixmap == 0)
10054 {
10055 x_clear_image (f, img);
3cf3436e 10056 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
10057 }
10058 else
10059 success_p = 1;
6fc2811b
JR
10060 }
10061 else
10062 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10063
6fc2811b
JR
10064 return success_p;
10065}
10066
10067
3cf3436e
JR
10068/* Value is non-zero if DATA looks like an in-memory XBM file. */
10069
10070static int
10071xbm_file_p (data)
10072 Lisp_Object data;
10073{
10074 int w, h;
10075 return (STRINGP (data)
10076 && xbm_read_bitmap_data (XSTRING (data)->data,
10077 (XSTRING (data)->data
10078 + STRING_BYTES (XSTRING (data))),
10079 &w, &h, NULL));
10080}
10081
10082
6fc2811b
JR
10083/* Fill image IMG which is used on frame F with pixmap data. Value is
10084 non-zero if successful. */
10085
10086static int
10087xbm_load (f, img)
10088 struct frame *f;
10089 struct image *img;
10090{
10091 int success_p = 0;
10092 Lisp_Object file_name;
10093
10094 xassert (xbm_image_p (img->spec));
10095
10096 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10097 file_name = image_spec_value (img->spec, QCfile, NULL);
10098 if (STRINGP (file_name))
3cf3436e
JR
10099 {
10100 Lisp_Object file;
10101 char *contents;
10102 int size;
10103 struct gcpro gcpro1;
10104
10105 file = x_find_image_file (file_name);
10106 GCPRO1 (file);
10107 if (!STRINGP (file))
10108 {
10109 image_error ("Cannot find image file `%s'", file_name, Qnil);
10110 UNGCPRO;
10111 return 0;
10112 }
10113
10114 contents = slurp_file (XSTRING (file)->data, &size);
10115 if (contents == NULL)
10116 {
10117 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10118 UNGCPRO;
10119 return 0;
10120 }
10121
10122 success_p = xbm_load_image (f, img, contents, contents + size);
10123 UNGCPRO;
10124 }
6fc2811b
JR
10125 else
10126 {
10127 struct image_keyword fmt[XBM_LAST];
10128 Lisp_Object data;
10129 int depth;
10130 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10131 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10132 char *bits;
10133 int parsed_p;
3cf3436e
JR
10134 int in_memory_file_p = 0;
10135
10136 /* See if data looks like an in-memory XBM file. */
10137 data = image_spec_value (img->spec, QCdata, NULL);
10138 in_memory_file_p = xbm_file_p (data);
6fc2811b 10139
217e5be0 10140 /* Parse the image specification. */
6fc2811b
JR
10141 bcopy (xbm_format, fmt, sizeof fmt);
10142 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10143 xassert (parsed_p);
10144
10145 /* Get specified width, and height. */
3cf3436e
JR
10146 if (!in_memory_file_p)
10147 {
10148 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10149 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10150 xassert (img->width > 0 && img->height > 0);
10151 }
217e5be0 10152
6fc2811b 10153 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
10154 if (fmt[XBM_FOREGROUND].count
10155 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
10156 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10157 foreground);
3cf3436e
JR
10158 if (fmt[XBM_BACKGROUND].count
10159 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
10160 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10161 background);
10162
3cf3436e
JR
10163 if (in_memory_file_p)
10164 success_p = xbm_load_image (f, img, XSTRING (data)->data,
10165 (XSTRING (data)->data
10166 + STRING_BYTES (XSTRING (data))));
10167 else
6fc2811b 10168 {
3cf3436e
JR
10169 if (VECTORP (data))
10170 {
10171 int i;
10172 char *p;
10173 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 10174
3cf3436e
JR
10175 p = bits = (char *) alloca (nbytes * img->height);
10176 for (i = 0; i < img->height; ++i, p += nbytes)
10177 {
10178 Lisp_Object line = XVECTOR (data)->contents[i];
10179 if (STRINGP (line))
10180 bcopy (XSTRING (line)->data, p, nbytes);
10181 else
10182 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10183 }
10184 }
10185 else if (STRINGP (data))
10186 bits = XSTRING (data)->data;
10187 else
10188 bits = XBOOL_VECTOR (data)->data;
af3f7be7 10189
3cf3436e 10190 /* Create the pixmap. */
a05e2bae 10191 depth = one_w32_display_info.n_cbits;
3cf3436e 10192 img->pixmap
af3f7be7
JR
10193 = w32_create_pixmap_from_bitmap_data (img->width, img->height,
10194 bits);
10195
3cf3436e
JR
10196 if (img->pixmap)
10197 success_p = 1;
10198 else
6fc2811b 10199 {
3cf3436e
JR
10200 image_error ("Unable to create pixmap for XBM image `%s'",
10201 img->spec, Qnil);
10202 x_clear_image (f, img);
6fc2811b
JR
10203 }
10204 }
6fc2811b
JR
10205 }
10206
10207 return success_p;
10208}
10209
10210
10211\f
10212/***********************************************************************
10213 XPM images
10214 ***********************************************************************/
10215
10216#if HAVE_XPM
10217
10218static int xpm_image_p P_ ((Lisp_Object object));
10219static int xpm_load P_ ((struct frame *f, struct image *img));
10220static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10221
10222#include "X11/xpm.h"
10223
10224/* The symbol `xpm' identifying XPM-format images. */
10225
10226Lisp_Object Qxpm;
10227
10228/* Indices of image specification fields in xpm_format, below. */
10229
10230enum xpm_keyword_index
10231{
10232 XPM_TYPE,
10233 XPM_FILE,
10234 XPM_DATA,
10235 XPM_ASCENT,
10236 XPM_MARGIN,
10237 XPM_RELIEF,
10238 XPM_ALGORITHM,
10239 XPM_HEURISTIC_MASK,
a05e2bae 10240 XPM_MASK,
6fc2811b 10241 XPM_COLOR_SYMBOLS,
a05e2bae 10242 XPM_BACKGROUND,
6fc2811b
JR
10243 XPM_LAST
10244};
10245
10246/* Vector of image_keyword structures describing the format
10247 of valid XPM image specifications. */
10248
10249static struct image_keyword xpm_format[XPM_LAST] =
10250{
10251 {":type", IMAGE_SYMBOL_VALUE, 1},
10252 {":file", IMAGE_STRING_VALUE, 0},
10253 {":data", IMAGE_STRING_VALUE, 0},
10254 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10255 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10256 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10257 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 10258 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10259 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10260 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10261 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10262};
10263
10264/* Structure describing the image type XBM. */
10265
10266static struct image_type xpm_type =
10267{
10268 &Qxpm,
10269 xpm_image_p,
10270 xpm_load,
10271 x_clear_image,
10272 NULL
10273};
10274
10275
10276/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10277 for XPM images. Such a list must consist of conses whose car and
10278 cdr are strings. */
10279
10280static int
10281xpm_valid_color_symbols_p (color_symbols)
10282 Lisp_Object color_symbols;
10283{
10284 while (CONSP (color_symbols))
10285 {
10286 Lisp_Object sym = XCAR (color_symbols);
10287 if (!CONSP (sym)
10288 || !STRINGP (XCAR (sym))
10289 || !STRINGP (XCDR (sym)))
10290 break;
10291 color_symbols = XCDR (color_symbols);
10292 }
10293
10294 return NILP (color_symbols);
10295}
10296
10297
10298/* Value is non-zero if OBJECT is a valid XPM image specification. */
10299
10300static int
10301xpm_image_p (object)
10302 Lisp_Object object;
10303{
10304 struct image_keyword fmt[XPM_LAST];
10305 bcopy (xpm_format, fmt, sizeof fmt);
10306 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10307 /* Either `:file' or `:data' must be present. */
10308 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10309 /* Either no `:color-symbols' or it's a list of conses
10310 whose car and cdr are strings. */
10311 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10312 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10313 && (fmt[XPM_ASCENT].count == 0
10314 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10315}
10316
10317
10318/* Load image IMG which will be displayed on frame F. Value is
10319 non-zero if successful. */
10320
10321static int
10322xpm_load (f, img)
10323 struct frame *f;
10324 struct image *img;
10325{
10326 int rc, i;
10327 XpmAttributes attrs;
10328 Lisp_Object specified_file, color_symbols;
10329
10330 /* Configure the XPM lib. Use the visual of frame F. Allocate
10331 close colors. Return colors allocated. */
10332 bzero (&attrs, sizeof attrs);
dfff8a69
JR
10333 attrs.visual = FRAME_X_VISUAL (f);
10334 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 10335 attrs.valuemask |= XpmVisual;
dfff8a69 10336 attrs.valuemask |= XpmColormap;
6fc2811b 10337 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 10338#ifdef XpmAllocCloseColors
6fc2811b
JR
10339 attrs.alloc_close_colors = 1;
10340 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
10341#else
10342 attrs.closeness = 600;
10343 attrs.valuemask |= XpmCloseness;
10344#endif
6fc2811b
JR
10345
10346 /* If image specification contains symbolic color definitions, add
10347 these to `attrs'. */
10348 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10349 if (CONSP (color_symbols))
10350 {
10351 Lisp_Object tail;
10352 XpmColorSymbol *xpm_syms;
10353 int i, size;
10354
10355 attrs.valuemask |= XpmColorSymbols;
10356
10357 /* Count number of symbols. */
10358 attrs.numsymbols = 0;
10359 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10360 ++attrs.numsymbols;
10361
10362 /* Allocate an XpmColorSymbol array. */
10363 size = attrs.numsymbols * sizeof *xpm_syms;
10364 xpm_syms = (XpmColorSymbol *) alloca (size);
10365 bzero (xpm_syms, size);
10366 attrs.colorsymbols = xpm_syms;
10367
10368 /* Fill the color symbol array. */
10369 for (tail = color_symbols, i = 0;
10370 CONSP (tail);
10371 ++i, tail = XCDR (tail))
10372 {
10373 Lisp_Object name = XCAR (XCAR (tail));
10374 Lisp_Object color = XCDR (XCAR (tail));
10375 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10376 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10377 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10378 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10379 }
10380 }
10381
10382 /* Create a pixmap for the image, either from a file, or from a
10383 string buffer containing data in the same format as an XPM file. */
10384 BLOCK_INPUT;
10385 specified_file = image_spec_value (img->spec, QCfile, NULL);
10386 if (STRINGP (specified_file))
10387 {
10388 Lisp_Object file = x_find_image_file (specified_file);
10389 if (!STRINGP (file))
10390 {
10391 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10392 UNBLOCK_INPUT;
10393 return 0;
10394 }
10395
10396 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10397 XSTRING (file)->data, &img->pixmap, &img->mask,
10398 &attrs);
10399 }
10400 else
10401 {
10402 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10403 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10404 XSTRING (buffer)->data,
10405 &img->pixmap, &img->mask,
10406 &attrs);
10407 }
10408 UNBLOCK_INPUT;
10409
10410 if (rc == XpmSuccess)
10411 {
10412 /* Remember allocated colors. */
10413 img->ncolors = attrs.nalloc_pixels;
10414 img->colors = (unsigned long *) xmalloc (img->ncolors
10415 * sizeof *img->colors);
10416 for (i = 0; i < attrs.nalloc_pixels; ++i)
10417 img->colors[i] = attrs.alloc_pixels[i];
10418
10419 img->width = attrs.width;
10420 img->height = attrs.height;
10421 xassert (img->width > 0 && img->height > 0);
10422
10423 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10424 BLOCK_INPUT;
10425 XpmFreeAttributes (&attrs);
10426 UNBLOCK_INPUT;
10427 }
10428 else
10429 {
10430 switch (rc)
10431 {
10432 case XpmOpenFailed:
10433 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10434 break;
10435
10436 case XpmFileInvalid:
10437 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10438 break;
10439
10440 case XpmNoMemory:
10441 image_error ("Out of memory (%s)", img->spec, Qnil);
10442 break;
10443
10444 case XpmColorFailed:
10445 image_error ("Color allocation error (%s)", img->spec, Qnil);
10446 break;
10447
10448 default:
10449 image_error ("Unknown error (%s)", img->spec, Qnil);
10450 break;
10451 }
10452 }
10453
10454 return rc == XpmSuccess;
10455}
10456
10457#endif /* HAVE_XPM != 0 */
10458
10459\f
767b1ff0 10460#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
10461/***********************************************************************
10462 Color table
10463 ***********************************************************************/
10464
10465/* An entry in the color table mapping an RGB color to a pixel color. */
10466
10467struct ct_color
10468{
10469 int r, g, b;
10470 unsigned long pixel;
10471
10472 /* Next in color table collision list. */
10473 struct ct_color *next;
10474};
10475
10476/* The bucket vector size to use. Must be prime. */
10477
10478#define CT_SIZE 101
10479
10480/* Value is a hash of the RGB color given by R, G, and B. */
10481
10482#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10483
10484/* The color hash table. */
10485
10486struct ct_color **ct_table;
10487
10488/* Number of entries in the color table. */
10489
10490int ct_colors_allocated;
10491
10492/* Function prototypes. */
10493
10494static void init_color_table P_ ((void));
10495static void free_color_table P_ ((void));
10496static unsigned long *colors_in_color_table P_ ((int *n));
10497static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10498static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10499
10500
10501/* Initialize the color table. */
10502
10503static void
10504init_color_table ()
10505{
10506 int size = CT_SIZE * sizeof (*ct_table);
10507 ct_table = (struct ct_color **) xmalloc (size);
10508 bzero (ct_table, size);
10509 ct_colors_allocated = 0;
10510}
10511
10512
10513/* Free memory associated with the color table. */
10514
10515static void
10516free_color_table ()
10517{
10518 int i;
10519 struct ct_color *p, *next;
10520
10521 for (i = 0; i < CT_SIZE; ++i)
10522 for (p = ct_table[i]; p; p = next)
10523 {
10524 next = p->next;
10525 xfree (p);
10526 }
10527
10528 xfree (ct_table);
10529 ct_table = NULL;
10530}
10531
10532
10533/* Value is a pixel color for RGB color R, G, B on frame F. If an
10534 entry for that color already is in the color table, return the
10535 pixel color of that entry. Otherwise, allocate a new color for R,
10536 G, B, and make an entry in the color table. */
10537
10538static unsigned long
10539lookup_rgb_color (f, r, g, b)
10540 struct frame *f;
10541 int r, g, b;
10542{
10543 unsigned hash = CT_HASH_RGB (r, g, b);
10544 int i = hash % CT_SIZE;
10545 struct ct_color *p;
10546
10547 for (p = ct_table[i]; p; p = p->next)
10548 if (p->r == r && p->g == g && p->b == b)
10549 break;
10550
10551 if (p == NULL)
10552 {
10553 COLORREF color;
10554 Colormap cmap;
10555 int rc;
10556
10557 color = PALETTERGB (r, g, b);
10558
10559 ++ct_colors_allocated;
10560
10561 p = (struct ct_color *) xmalloc (sizeof *p);
10562 p->r = r;
10563 p->g = g;
10564 p->b = b;
10565 p->pixel = color;
10566 p->next = ct_table[i];
10567 ct_table[i] = p;
10568 }
10569
10570 return p->pixel;
10571}
10572
10573
10574/* Look up pixel color PIXEL which is used on frame F in the color
10575 table. If not already present, allocate it. Value is PIXEL. */
10576
10577static unsigned long
10578lookup_pixel_color (f, pixel)
10579 struct frame *f;
10580 unsigned long pixel;
10581{
10582 int i = pixel % CT_SIZE;
10583 struct ct_color *p;
10584
10585 for (p = ct_table[i]; p; p = p->next)
10586 if (p->pixel == pixel)
10587 break;
10588
10589 if (p == NULL)
10590 {
10591 XColor color;
10592 Colormap cmap;
10593 int rc;
10594
10595 BLOCK_INPUT;
10596
10597 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10598 color.pixel = pixel;
10599 XQueryColor (NULL, cmap, &color);
10600 rc = x_alloc_nearest_color (f, cmap, &color);
10601 UNBLOCK_INPUT;
10602
10603 if (rc)
10604 {
10605 ++ct_colors_allocated;
10606
10607 p = (struct ct_color *) xmalloc (sizeof *p);
10608 p->r = color.red;
10609 p->g = color.green;
10610 p->b = color.blue;
10611 p->pixel = pixel;
10612 p->next = ct_table[i];
10613 ct_table[i] = p;
10614 }
10615 else
10616 return FRAME_FOREGROUND_PIXEL (f);
10617 }
10618 return p->pixel;
10619}
10620
10621
10622/* Value is a vector of all pixel colors contained in the color table,
10623 allocated via xmalloc. Set *N to the number of colors. */
10624
10625static unsigned long *
10626colors_in_color_table (n)
10627 int *n;
10628{
10629 int i, j;
10630 struct ct_color *p;
10631 unsigned long *colors;
10632
10633 if (ct_colors_allocated == 0)
10634 {
10635 *n = 0;
10636 colors = NULL;
10637 }
10638 else
10639 {
10640 colors = (unsigned long *) xmalloc (ct_colors_allocated
10641 * sizeof *colors);
10642 *n = ct_colors_allocated;
10643
10644 for (i = j = 0; i < CT_SIZE; ++i)
10645 for (p = ct_table[i]; p; p = p->next)
10646 colors[j++] = p->pixel;
10647 }
10648
10649 return colors;
10650}
10651
767b1ff0 10652#endif /* TODO */
6fc2811b
JR
10653
10654\f
10655/***********************************************************************
10656 Algorithms
10657 ***********************************************************************/
3cf3436e
JR
10658static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10659static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10660static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
ac849ba4 10661static void XPutPixel (XImage *, int, int, COLORREF);
3cf3436e
JR
10662
10663/* Non-zero means draw a cross on images having `:conversion
10664 disabled'. */
6fc2811b 10665
3cf3436e 10666int cross_disabled_images;
6fc2811b 10667
3cf3436e
JR
10668/* Edge detection matrices for different edge-detection
10669 strategies. */
6fc2811b 10670
3cf3436e
JR
10671static int emboss_matrix[9] = {
10672 /* x - 1 x x + 1 */
10673 2, -1, 0, /* y - 1 */
10674 -1, 0, 1, /* y */
10675 0, 1, -2 /* y + 1 */
10676};
10677
10678static int laplace_matrix[9] = {
10679 /* x - 1 x x + 1 */
10680 1, 0, 0, /* y - 1 */
10681 0, 0, 0, /* y */
10682 0, 0, -1 /* y + 1 */
10683};
10684
10685/* Value is the intensity of the color whose red/green/blue values
10686 are R, G, and B. */
10687
10688#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10689
10690
10691/* On frame F, return an array of XColor structures describing image
10692 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10693 non-zero means also fill the red/green/blue members of the XColor
10694 structures. Value is a pointer to the array of XColors structures,
10695 allocated with xmalloc; it must be freed by the caller. */
10696
10697static XColor *
10698x_to_xcolors (f, img, rgb_p)
10699 struct frame *f;
10700 struct image *img;
10701 int rgb_p;
10702{
10703 int x, y;
10704 XColor *colors, *p;
10705 XImage *ximg;
10706
10707 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
ac849ba4 10708#if 0 /* TODO: implement image colors. */
3cf3436e
JR
10709 /* Get the X image IMG->pixmap. */
10710 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10711 0, 0, img->width, img->height, ~0, ZPixmap);
10712
10713 /* Fill the `pixel' members of the XColor array. I wished there
10714 were an easy and portable way to circumvent XGetPixel. */
10715 p = colors;
10716 for (y = 0; y < img->height; ++y)
10717 {
10718 XColor *row = p;
10719
10720 for (x = 0; x < img->width; ++x, ++p)
10721 p->pixel = XGetPixel (ximg, x, y);
10722
10723 if (rgb_p)
10724 x_query_colors (f, row, img->width);
10725 }
10726
10727 XDestroyImage (ximg);
ac849ba4 10728#endif
3cf3436e
JR
10729 return colors;
10730}
10731
ac849ba4
JR
10732/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10733 created with CreateDIBSection, with the pointer to the bit values
10734 stored in ximg->data. */
10735
10736static void XPutPixel (ximg, x, y, color)
10737 XImage * ximg;
10738 int x, y;
10739 COLORREF color;
10740{
10741 int width = ximg->info.bmiHeader.biWidth;
10742 int height = ximg->info.bmiHeader.biHeight;
10743 int rowbytes = width * 3;
10744 unsigned char * pixel;
10745
10746 /* Don't support putting pixels in images with palettes. */
10747 xassert (ximg->info.bmiHeader.biBitCount == 24);
10748
10749 /* Ensure scanlines are aligned on 4 byte boundaries. */
10750 if (rowbytes % 4)
10751 rowbytes += 4 - (rowbytes % 4);
10752
10753 pixel = ximg->data + y * rowbytes + x * 3;
10754 *pixel = 255 - GetRValue (color);
10755 *(pixel + 1) = 255 - GetGValue (color);
10756 *(pixel + 2) = 255 - GetBValue (color);
10757}
10758
3cf3436e
JR
10759
10760/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10761 RGB members are set. F is the frame on which this all happens.
10762 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10763
10764static void
3cf3436e 10765x_from_xcolors (f, img, colors)
6fc2811b 10766 struct frame *f;
3cf3436e 10767 struct image *img;
6fc2811b 10768 XColor *colors;
6fc2811b 10769{
3cf3436e
JR
10770 int x, y;
10771 XImage *oimg;
10772 Pixmap pixmap;
10773 XColor *p;
ac849ba4 10774#if 0 /* TODO: color tables. */
3cf3436e 10775 init_color_table ();
ac849ba4 10776#endif
3cf3436e
JR
10777 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10778 &oimg, &pixmap);
10779 p = colors;
10780 for (y = 0; y < img->height; ++y)
10781 for (x = 0; x < img->width; ++x, ++p)
10782 {
10783 unsigned long pixel;
ac849ba4 10784#if 0 /* TODO: color tables. */
3cf3436e 10785 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
ac849ba4
JR
10786#else
10787 pixel = PALETTERGB (p->red, p->green, p->blue);
10788#endif
3cf3436e
JR
10789 XPutPixel (oimg, x, y, pixel);
10790 }
6fc2811b 10791
3cf3436e
JR
10792 xfree (colors);
10793 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10794
3cf3436e
JR
10795 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10796 x_destroy_x_image (oimg);
10797 img->pixmap = pixmap;
ac849ba4 10798#if 0 /* TODO: color tables. */
3cf3436e
JR
10799 img->colors = colors_in_color_table (&img->ncolors);
10800 free_color_table ();
ac849ba4 10801#endif
6fc2811b
JR
10802}
10803
10804
3cf3436e
JR
10805/* On frame F, perform edge-detection on image IMG.
10806
10807 MATRIX is a nine-element array specifying the transformation
10808 matrix. See emboss_matrix for an example.
10809
10810 COLOR_ADJUST is a color adjustment added to each pixel of the
10811 outgoing image. */
6fc2811b
JR
10812
10813static void
3cf3436e 10814x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10815 struct frame *f;
3cf3436e
JR
10816 struct image *img;
10817 int matrix[9], color_adjust;
6fc2811b 10818{
3cf3436e
JR
10819 XColor *colors = x_to_xcolors (f, img, 1);
10820 XColor *new, *p;
10821 int x, y, i, sum;
10822
10823 for (i = sum = 0; i < 9; ++i)
10824 sum += abs (matrix[i]);
10825
10826#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10827
10828 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10829
10830 for (y = 0; y < img->height; ++y)
10831 {
10832 p = COLOR (new, 0, y);
10833 p->red = p->green = p->blue = 0xffff/2;
10834 p = COLOR (new, img->width - 1, y);
10835 p->red = p->green = p->blue = 0xffff/2;
10836 }
6fc2811b 10837
3cf3436e
JR
10838 for (x = 1; x < img->width - 1; ++x)
10839 {
10840 p = COLOR (new, x, 0);
10841 p->red = p->green = p->blue = 0xffff/2;
10842 p = COLOR (new, x, img->height - 1);
10843 p->red = p->green = p->blue = 0xffff/2;
10844 }
10845
10846 for (y = 1; y < img->height - 1; ++y)
10847 {
10848 p = COLOR (new, 1, y);
10849
10850 for (x = 1; x < img->width - 1; ++x, ++p)
10851 {
10852 int r, g, b, y1, x1;
10853
10854 r = g = b = i = 0;
10855 for (y1 = y - 1; y1 < y + 2; ++y1)
10856 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10857 if (matrix[i])
10858 {
10859 XColor *t = COLOR (colors, x1, y1);
10860 r += matrix[i] * t->red;
10861 g += matrix[i] * t->green;
10862 b += matrix[i] * t->blue;
10863 }
10864
10865 r = (r / sum + color_adjust) & 0xffff;
10866 g = (g / sum + color_adjust) & 0xffff;
10867 b = (b / sum + color_adjust) & 0xffff;
10868 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10869 }
10870 }
10871
10872 xfree (colors);
10873 x_from_xcolors (f, img, new);
10874
10875#undef COLOR
10876}
10877
10878
10879/* Perform the pre-defined `emboss' edge-detection on image IMG
10880 on frame F. */
10881
10882static void
10883x_emboss (f, img)
10884 struct frame *f;
10885 struct image *img;
10886{
10887 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10888}
3cf3436e 10889
6fc2811b
JR
10890
10891/* Transform image IMG which is used on frame F with a Laplace
10892 edge-detection algorithm. The result is an image that can be used
10893 to draw disabled buttons, for example. */
10894
10895static void
10896x_laplace (f, img)
10897 struct frame *f;
10898 struct image *img;
10899{
3cf3436e
JR
10900 x_detect_edges (f, img, laplace_matrix, 45000);
10901}
6fc2811b 10902
6fc2811b 10903
3cf3436e
JR
10904/* Perform edge-detection on image IMG on frame F, with specified
10905 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10906
3cf3436e 10907 MATRIX must be either
6fc2811b 10908
3cf3436e
JR
10909 - a list of at least 9 numbers in row-major form
10910 - a vector of at least 9 numbers
6fc2811b 10911
3cf3436e
JR
10912 COLOR_ADJUST nil means use a default; otherwise it must be a
10913 number. */
6fc2811b 10914
3cf3436e
JR
10915static void
10916x_edge_detection (f, img, matrix, color_adjust)
10917 struct frame *f;
10918 struct image *img;
10919 Lisp_Object matrix, color_adjust;
10920{
10921 int i = 0;
10922 int trans[9];
10923
10924 if (CONSP (matrix))
6fc2811b 10925 {
3cf3436e
JR
10926 for (i = 0;
10927 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10928 ++i, matrix = XCDR (matrix))
10929 trans[i] = XFLOATINT (XCAR (matrix));
10930 }
10931 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10932 {
10933 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10934 trans[i] = XFLOATINT (AREF (matrix, i));
10935 }
10936
10937 if (NILP (color_adjust))
10938 color_adjust = make_number (0xffff / 2);
10939
10940 if (i == 9 && NUMBERP (color_adjust))
10941 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10942}
10943
6fc2811b 10944
3cf3436e 10945/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10946
3cf3436e
JR
10947static void
10948x_disable_image (f, img)
10949 struct frame *f;
10950 struct image *img;
10951{
ac849ba4 10952 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3cf3436e 10953
ac849ba4 10954 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
3cf3436e
JR
10955 {
10956 /* Color (or grayscale). Convert to gray, and equalize. Just
10957 drawing such images with a stipple can look very odd, so
10958 we're using this method instead. */
10959 XColor *colors = x_to_xcolors (f, img, 1);
10960 XColor *p, *end;
10961 const int h = 15000;
10962 const int l = 30000;
10963
10964 for (p = colors, end = colors + img->width * img->height;
10965 p < end;
10966 ++p)
6fc2811b 10967 {
3cf3436e
JR
10968 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10969 int i2 = (0xffff - h - l) * i / 0xffff + l;
10970 p->red = p->green = p->blue = i2;
6fc2811b
JR
10971 }
10972
3cf3436e 10973 x_from_xcolors (f, img, colors);
6fc2811b
JR
10974 }
10975
3cf3436e
JR
10976 /* Draw a cross over the disabled image, if we must or if we
10977 should. */
ac849ba4 10978 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
3cf3436e 10979 {
ac849ba4 10980#if 0 /* TODO: full image support */
3cf3436e
JR
10981 Display *dpy = FRAME_X_DISPLAY (f);
10982 GC gc;
6fc2811b 10983
3cf3436e
JR
10984 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10985 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10986 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10987 img->width - 1, img->height - 1);
10988 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10989 img->width - 1, 0);
10990 XFreeGC (dpy, gc);
6fc2811b 10991
3cf3436e
JR
10992 if (img->mask)
10993 {
10994 gc = XCreateGC (dpy, img->mask, 0, NULL);
10995 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10996 XDrawLine (dpy, img->mask, gc, 0, 0,
10997 img->width - 1, img->height - 1);
10998 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10999 img->width - 1, 0);
11000 XFreeGC (dpy, gc);
11001 }
ac849ba4 11002#endif
3cf3436e 11003 }
6fc2811b
JR
11004}
11005
11006
11007/* Build a mask for image IMG which is used on frame F. FILE is the
11008 name of an image file, for error messages. HOW determines how to
11009 determine the background color of IMG. If it is a list '(R G B)',
11010 with R, G, and B being integers >= 0, take that as the color of the
11011 background. Otherwise, determine the background color of IMG
11012 heuristically. Value is non-zero if successful. */
11013
11014static int
11015x_build_heuristic_mask (f, img, how)
11016 struct frame *f;
11017 struct image *img;
11018 Lisp_Object how;
11019{
ac849ba4 11020#if 0 /* TODO: full image support. */
6fc2811b
JR
11021 Display *dpy = FRAME_W32_DISPLAY (f);
11022 XImage *ximg, *mask_img;
a05e2bae
JR
11023 int x, y, rc, use_img_background;
11024 unsigned long bg = 0;
11025
11026 if (img->mask)
11027 {
11028 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
11029 img->mask = None;
11030 img->background_transparent_valid = 0;
11031 }
6fc2811b 11032
6fc2811b
JR
11033 /* Create an image and pixmap serving as mask. */
11034 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
11035 &mask_img, &img->mask);
11036 if (!rc)
a05e2bae 11037 return 0;
6fc2811b
JR
11038
11039 /* Get the X image of IMG->pixmap. */
11040 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
11041 ~0, ZPixmap);
11042
11043 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
11044 take that as color. Otherwise, use the image's background color. */
11045 use_img_background = 1;
6fc2811b
JR
11046
11047 if (CONSP (how))
11048 {
a05e2bae 11049 int rgb[3], i;
6fc2811b 11050
a05e2bae 11051 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
11052 {
11053 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
11054 how = XCDR (how);
11055 }
11056
11057 if (i == 3 && NILP (how))
11058 {
11059 char color_name[30];
6fc2811b 11060 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
11061 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
11062 use_img_background = 0;
6fc2811b
JR
11063 }
11064 }
11065
a05e2bae
JR
11066 if (use_img_background)
11067 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
11068
11069 /* Set all bits in mask_img to 1 whose color in ximg is different
11070 from the background color bg. */
11071 for (y = 0; y < img->height; ++y)
11072 for (x = 0; x < img->width; ++x)
11073 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
11074
a05e2bae
JR
11075 /* Fill in the background_transparent field while we have the mask handy. */
11076 image_background_transparent (img, f, mask_img);
11077
6fc2811b
JR
11078 /* Put mask_img into img->mask. */
11079 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11080 x_destroy_x_image (mask_img);
11081 XDestroyImage (ximg);
6fc2811b
JR
11082
11083 return 1;
ac849ba4
JR
11084#else
11085 return 0;
11086#endif
6fc2811b 11087}
217e5be0 11088
6fc2811b
JR
11089\f
11090/***********************************************************************
11091 PBM (mono, gray, color)
11092 ***********************************************************************/
6fc2811b
JR
11093
11094static int pbm_image_p P_ ((Lisp_Object object));
11095static int pbm_load P_ ((struct frame *f, struct image *img));
11096static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11097
11098/* The symbol `pbm' identifying images of this type. */
11099
11100Lisp_Object Qpbm;
11101
11102/* Indices of image specification fields in gs_format, below. */
11103
11104enum pbm_keyword_index
11105{
11106 PBM_TYPE,
11107 PBM_FILE,
11108 PBM_DATA,
11109 PBM_ASCENT,
11110 PBM_MARGIN,
11111 PBM_RELIEF,
11112 PBM_ALGORITHM,
11113 PBM_HEURISTIC_MASK,
a05e2bae
JR
11114 PBM_MASK,
11115 PBM_FOREGROUND,
11116 PBM_BACKGROUND,
6fc2811b
JR
11117 PBM_LAST
11118};
11119
11120/* Vector of image_keyword structures describing the format
11121 of valid user-defined image specifications. */
11122
11123static struct image_keyword pbm_format[PBM_LAST] =
11124{
11125 {":type", IMAGE_SYMBOL_VALUE, 1},
11126 {":file", IMAGE_STRING_VALUE, 0},
11127 {":data", IMAGE_STRING_VALUE, 0},
11128 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11129 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11130 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11131 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
11132 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11133 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11134 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11135 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11136};
11137
11138/* Structure describing the image type `pbm'. */
11139
11140static struct image_type pbm_type =
11141{
11142 &Qpbm,
11143 pbm_image_p,
11144 pbm_load,
11145 x_clear_image,
11146 NULL
11147};
11148
11149
11150/* Return non-zero if OBJECT is a valid PBM image specification. */
11151
11152static int
11153pbm_image_p (object)
11154 Lisp_Object object;
11155{
11156 struct image_keyword fmt[PBM_LAST];
11157
11158 bcopy (pbm_format, fmt, sizeof fmt);
11159
11160 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
11161 || (fmt[PBM_ASCENT].count
11162 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11163 return 0;
11164
11165 /* Must specify either :data or :file. */
11166 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11167}
11168
11169
11170/* Scan a decimal number from *S and return it. Advance *S while
11171 reading the number. END is the end of the string. Value is -1 at
11172 end of input. */
11173
11174static int
11175pbm_scan_number (s, end)
11176 unsigned char **s, *end;
11177{
11178 int c, val = -1;
11179
11180 while (*s < end)
11181 {
11182 /* Skip white-space. */
11183 while (*s < end && (c = *(*s)++, isspace (c)))
11184 ;
11185
11186 if (c == '#')
11187 {
11188 /* Skip comment to end of line. */
11189 while (*s < end && (c = *(*s)++, c != '\n'))
11190 ;
11191 }
11192 else if (isdigit (c))
11193 {
11194 /* Read decimal number. */
11195 val = c - '0';
11196 while (*s < end && (c = *(*s)++, isdigit (c)))
11197 val = 10 * val + c - '0';
11198 break;
11199 }
11200 else
11201 break;
11202 }
11203
11204 return val;
11205}
11206
11207
11208/* Read FILE into memory. Value is a pointer to a buffer allocated
11209 with xmalloc holding FILE's contents. Value is null if an error
6f826971 11210 occurred. *SIZE is set to the size of the file. */
6fc2811b
JR
11211
11212static char *
11213pbm_read_file (file, size)
11214 Lisp_Object file;
11215 int *size;
11216{
11217 FILE *fp = NULL;
11218 char *buf = NULL;
11219 struct stat st;
11220
11221 if (stat (XSTRING (file)->data, &st) == 0
11222 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11223 && (buf = (char *) xmalloc (st.st_size),
11224 fread (buf, 1, st.st_size, fp) == st.st_size))
11225 {
11226 *size = st.st_size;
11227 fclose (fp);
11228 }
11229 else
11230 {
11231 if (fp)
11232 fclose (fp);
11233 if (buf)
11234 {
11235 xfree (buf);
11236 buf = NULL;
11237 }
11238 }
11239
11240 return buf;
11241}
11242
11243
11244/* Load PBM image IMG for use on frame F. */
11245
11246static int
11247pbm_load (f, img)
11248 struct frame *f;
11249 struct image *img;
11250{
11251 int raw_p, x, y;
11252 int width, height, max_color_idx = 0;
11253 XImage *ximg;
11254 Lisp_Object file, specified_file;
11255 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11256 struct gcpro gcpro1;
11257 unsigned char *contents = NULL;
11258 unsigned char *end, *p;
11259 int size;
11260
11261 specified_file = image_spec_value (img->spec, QCfile, NULL);
11262 file = Qnil;
11263 GCPRO1 (file);
11264
11265 if (STRINGP (specified_file))
11266 {
11267 file = x_find_image_file (specified_file);
11268 if (!STRINGP (file))
11269 {
11270 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11271 UNGCPRO;
11272 return 0;
11273 }
11274
3cf3436e 11275 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
11276 if (contents == NULL)
11277 {
11278 image_error ("Error reading `%s'", file, Qnil);
11279 UNGCPRO;
11280 return 0;
11281 }
11282
11283 p = contents;
11284 end = contents + size;
11285 }
11286 else
11287 {
11288 Lisp_Object data;
11289 data = image_spec_value (img->spec, QCdata, NULL);
11290 p = XSTRING (data)->data;
11291 end = p + STRING_BYTES (XSTRING (data));
11292 }
11293
11294 /* Check magic number. */
11295 if (end - p < 2 || *p++ != 'P')
11296 {
11297 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11298 error:
11299 xfree (contents);
11300 UNGCPRO;
11301 return 0;
11302 }
11303
6fc2811b
JR
11304 switch (*p++)
11305 {
11306 case '1':
11307 raw_p = 0, type = PBM_MONO;
11308 break;
11309
11310 case '2':
11311 raw_p = 0, type = PBM_GRAY;
11312 break;
11313
11314 case '3':
11315 raw_p = 0, type = PBM_COLOR;
11316 break;
11317
11318 case '4':
11319 raw_p = 1, type = PBM_MONO;
11320 break;
11321
11322 case '5':
11323 raw_p = 1, type = PBM_GRAY;
11324 break;
11325
11326 case '6':
11327 raw_p = 1, type = PBM_COLOR;
11328 break;
11329
11330 default:
11331 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11332 goto error;
11333 }
11334
11335 /* Read width, height, maximum color-component. Characters
11336 starting with `#' up to the end of a line are ignored. */
11337 width = pbm_scan_number (&p, end);
11338 height = pbm_scan_number (&p, end);
11339
11340 if (type != PBM_MONO)
11341 {
11342 max_color_idx = pbm_scan_number (&p, end);
11343 if (raw_p && max_color_idx > 255)
11344 max_color_idx = 255;
11345 }
11346
11347 if (width < 0
11348 || height < 0
11349 || (type != PBM_MONO && max_color_idx < 0))
11350 goto error;
11351
ac849ba4 11352 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
3cf3436e
JR
11353 goto error;
11354
ac849ba4 11355#if 0 /* TODO: color tables. */
6fc2811b
JR
11356 /* Initialize the color hash table. */
11357 init_color_table ();
ac849ba4 11358#endif
6fc2811b
JR
11359
11360 if (type == PBM_MONO)
11361 {
11362 int c = 0, g;
3cf3436e
JR
11363 struct image_keyword fmt[PBM_LAST];
11364 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11365 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11366
11367 /* Parse the image specification. */
11368 bcopy (pbm_format, fmt, sizeof fmt);
11369 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11370
11371 /* Get foreground and background colors, maybe allocate colors. */
11372 if (fmt[PBM_FOREGROUND].count
11373 && STRINGP (fmt[PBM_FOREGROUND].value))
11374 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11375 if (fmt[PBM_BACKGROUND].count
11376 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
11377 {
11378 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11379 img->background = bg;
11380 img->background_valid = 1;
11381 }
11382
6fc2811b
JR
11383 for (y = 0; y < height; ++y)
11384 for (x = 0; x < width; ++x)
11385 {
11386 if (raw_p)
11387 {
11388 if ((x & 7) == 0)
11389 c = *p++;
11390 g = c & 0x80;
11391 c <<= 1;
11392 }
11393 else
11394 g = pbm_scan_number (&p, end);
11395
3cf3436e 11396 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
11397 }
11398 }
11399 else
11400 {
11401 for (y = 0; y < height; ++y)
11402 for (x = 0; x < width; ++x)
11403 {
11404 int r, g, b;
11405
11406 if (type == PBM_GRAY)
11407 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11408 else if (raw_p)
11409 {
11410 r = *p++;
11411 g = *p++;
11412 b = *p++;
11413 }
11414 else
11415 {
11416 r = pbm_scan_number (&p, end);
11417 g = pbm_scan_number (&p, end);
11418 b = pbm_scan_number (&p, end);
11419 }
11420
11421 if (r < 0 || g < 0 || b < 0)
11422 {
ac849ba4 11423 x_destroy_x_image (ximg);
6fc2811b
JR
11424 image_error ("Invalid pixel value in image `%s'",
11425 img->spec, Qnil);
11426 goto error;
11427 }
11428
11429 /* RGB values are now in the range 0..max_color_idx.
ac849ba4
JR
11430 Scale this to the range 0..0xff supported by W32. */
11431 r = (int) ((double) r * 255 / max_color_idx);
11432 g = (int) ((double) g * 255 / max_color_idx);
11433 b = (int) ((double) b * 255 / max_color_idx);
11434 XPutPixel (ximg, x, y,
11435#if 0 /* TODO: color tables. */
11436 lookup_rgb_color (f, r, g, b));
11437#else
11438 PALETTERGB (r, g, b));
11439#endif
6fc2811b
JR
11440 }
11441 }
ac849ba4
JR
11442
11443#if 0 /* TODO: color tables. */
6fc2811b
JR
11444 /* Store in IMG->colors the colors allocated for the image, and
11445 free the color table. */
11446 img->colors = colors_in_color_table (&img->ncolors);
11447 free_color_table ();
ac849ba4 11448#endif
a05e2bae
JR
11449 /* Maybe fill in the background field while we have ximg handy. */
11450 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11451 IMAGE_BACKGROUND (img, f, ximg);
11452
6fc2811b
JR
11453 /* Put the image into a pixmap. */
11454 x_put_x_image (f, ximg, img->pixmap, width, height);
11455 x_destroy_x_image (ximg);
6fc2811b
JR
11456
11457 img->width = width;
11458 img->height = height;
11459
11460 UNGCPRO;
11461 xfree (contents);
11462 return 1;
11463}
6fc2811b
JR
11464
11465\f
11466/***********************************************************************
11467 PNG
11468 ***********************************************************************/
11469
11470#if HAVE_PNG
11471
11472#include <png.h>
11473
11474/* Function prototypes. */
11475
11476static int png_image_p P_ ((Lisp_Object object));
11477static int png_load P_ ((struct frame *f, struct image *img));
11478
11479/* The symbol `png' identifying images of this type. */
11480
11481Lisp_Object Qpng;
11482
11483/* Indices of image specification fields in png_format, below. */
11484
11485enum png_keyword_index
11486{
11487 PNG_TYPE,
11488 PNG_DATA,
11489 PNG_FILE,
11490 PNG_ASCENT,
11491 PNG_MARGIN,
11492 PNG_RELIEF,
11493 PNG_ALGORITHM,
11494 PNG_HEURISTIC_MASK,
a05e2bae
JR
11495 PNG_MASK,
11496 PNG_BACKGROUND,
6fc2811b
JR
11497 PNG_LAST
11498};
11499
11500/* Vector of image_keyword structures describing the format
11501 of valid user-defined image specifications. */
11502
11503static struct image_keyword png_format[PNG_LAST] =
11504{
11505 {":type", IMAGE_SYMBOL_VALUE, 1},
11506 {":data", IMAGE_STRING_VALUE, 0},
11507 {":file", IMAGE_STRING_VALUE, 0},
11508 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11509 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11510 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11511 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11512 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11513 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11514 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11515};
11516
11517/* Structure describing the image type `png'. */
11518
11519static struct image_type png_type =
11520{
11521 &Qpng,
11522 png_image_p,
11523 png_load,
11524 x_clear_image,
11525 NULL
11526};
11527
11528
11529/* Return non-zero if OBJECT is a valid PNG image specification. */
11530
11531static int
11532png_image_p (object)
11533 Lisp_Object object;
11534{
11535 struct image_keyword fmt[PNG_LAST];
11536 bcopy (png_format, fmt, sizeof fmt);
11537
11538 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11539 || (fmt[PNG_ASCENT].count
11540 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11541 return 0;
11542
11543 /* Must specify either the :data or :file keyword. */
11544 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11545}
11546
11547
11548/* Error and warning handlers installed when the PNG library
11549 is initialized. */
11550
11551static void
11552my_png_error (png_ptr, msg)
11553 png_struct *png_ptr;
11554 char *msg;
11555{
11556 xassert (png_ptr != NULL);
11557 image_error ("PNG error: %s", build_string (msg), Qnil);
11558 longjmp (png_ptr->jmpbuf, 1);
11559}
11560
11561
11562static void
11563my_png_warning (png_ptr, msg)
11564 png_struct *png_ptr;
11565 char *msg;
11566{
11567 xassert (png_ptr != NULL);
11568 image_error ("PNG warning: %s", build_string (msg), Qnil);
11569}
11570
6fc2811b
JR
11571/* Memory source for PNG decoding. */
11572
11573struct png_memory_storage
11574{
11575 unsigned char *bytes; /* The data */
11576 size_t len; /* How big is it? */
11577 int index; /* Where are we? */
11578};
11579
11580
11581/* Function set as reader function when reading PNG image from memory.
11582 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11583 bytes from the input to DATA. */
11584
11585static void
11586png_read_from_memory (png_ptr, data, length)
11587 png_structp png_ptr;
11588 png_bytep data;
11589 png_size_t length;
11590{
11591 struct png_memory_storage *tbr
11592 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11593
11594 if (length > tbr->len - tbr->index)
11595 png_error (png_ptr, "Read error");
11596
11597 bcopy (tbr->bytes + tbr->index, data, length);
11598 tbr->index = tbr->index + length;
11599}
11600
6fc2811b
JR
11601/* Load PNG image IMG for use on frame F. Value is non-zero if
11602 successful. */
11603
11604static int
11605png_load (f, img)
11606 struct frame *f;
11607 struct image *img;
11608{
11609 Lisp_Object file, specified_file;
11610 Lisp_Object specified_data;
11611 int x, y, i;
11612 XImage *ximg, *mask_img = NULL;
11613 struct gcpro gcpro1;
11614 png_struct *png_ptr = NULL;
11615 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11616 FILE *volatile fp = NULL;
6fc2811b 11617 png_byte sig[8];
a05e2bae
JR
11618 png_byte *volatile pixels = NULL;
11619 png_byte **volatile rows = NULL;
6fc2811b
JR
11620 png_uint_32 width, height;
11621 int bit_depth, color_type, interlace_type;
11622 png_byte channels;
11623 png_uint_32 row_bytes;
11624 int transparent_p;
11625 char *gamma_str;
11626 double screen_gamma, image_gamma;
11627 int intent;
11628 struct png_memory_storage tbr; /* Data to be read */
11629
11630 /* Find out what file to load. */
11631 specified_file = image_spec_value (img->spec, QCfile, NULL);
11632 specified_data = image_spec_value (img->spec, QCdata, NULL);
11633 file = Qnil;
11634 GCPRO1 (file);
11635
11636 if (NILP (specified_data))
11637 {
11638 file = x_find_image_file (specified_file);
11639 if (!STRINGP (file))
11640 {
11641 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11642 UNGCPRO;
11643 return 0;
11644 }
11645
11646 /* Open the image file. */
11647 fp = fopen (XSTRING (file)->data, "rb");
11648 if (!fp)
11649 {
11650 image_error ("Cannot open image file `%s'", file, Qnil);
11651 UNGCPRO;
11652 fclose (fp);
11653 return 0;
11654 }
11655
11656 /* Check PNG signature. */
11657 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11658 || !png_check_sig (sig, sizeof sig))
11659 {
11660 image_error ("Not a PNG file:` %s'", file, Qnil);
11661 UNGCPRO;
11662 fclose (fp);
11663 return 0;
11664 }
11665 }
11666 else
11667 {
11668 /* Read from memory. */
11669 tbr.bytes = XSTRING (specified_data)->data;
11670 tbr.len = STRING_BYTES (XSTRING (specified_data));
11671 tbr.index = 0;
11672
11673 /* Check PNG signature. */
11674 if (tbr.len < sizeof sig
11675 || !png_check_sig (tbr.bytes, sizeof sig))
11676 {
11677 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11678 UNGCPRO;
11679 return 0;
11680 }
11681
11682 /* Need to skip past the signature. */
11683 tbr.bytes += sizeof (sig);
11684 }
11685
6fc2811b
JR
11686 /* Initialize read and info structs for PNG lib. */
11687 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11688 my_png_error, my_png_warning);
11689 if (!png_ptr)
11690 {
11691 if (fp) fclose (fp);
11692 UNGCPRO;
11693 return 0;
11694 }
11695
11696 info_ptr = png_create_info_struct (png_ptr);
11697 if (!info_ptr)
11698 {
11699 png_destroy_read_struct (&png_ptr, NULL, NULL);
11700 if (fp) fclose (fp);
11701 UNGCPRO;
11702 return 0;
11703 }
11704
11705 end_info = png_create_info_struct (png_ptr);
11706 if (!end_info)
11707 {
11708 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11709 if (fp) fclose (fp);
11710 UNGCPRO;
11711 return 0;
11712 }
11713
11714 /* Set error jump-back. We come back here when the PNG library
11715 detects an error. */
11716 if (setjmp (png_ptr->jmpbuf))
11717 {
11718 error:
11719 if (png_ptr)
11720 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11721 xfree (pixels);
11722 xfree (rows);
11723 if (fp) fclose (fp);
11724 UNGCPRO;
11725 return 0;
11726 }
11727
11728 /* Read image info. */
11729 if (!NILP (specified_data))
11730 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11731 else
11732 png_init_io (png_ptr, fp);
11733
11734 png_set_sig_bytes (png_ptr, sizeof sig);
11735 png_read_info (png_ptr, info_ptr);
11736 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11737 &interlace_type, NULL, NULL);
11738
11739 /* If image contains simply transparency data, we prefer to
11740 construct a clipping mask. */
11741 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11742 transparent_p = 1;
11743 else
11744 transparent_p = 0;
11745
11746 /* This function is easier to write if we only have to handle
11747 one data format: RGB or RGBA with 8 bits per channel. Let's
11748 transform other formats into that format. */
11749
11750 /* Strip more than 8 bits per channel. */
11751 if (bit_depth == 16)
11752 png_set_strip_16 (png_ptr);
11753
11754 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11755 if available. */
11756 png_set_expand (png_ptr);
11757
11758 /* Convert grayscale images to RGB. */
11759 if (color_type == PNG_COLOR_TYPE_GRAY
11760 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11761 png_set_gray_to_rgb (png_ptr);
11762
11763 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11764 gamma_str = getenv ("SCREEN_GAMMA");
11765 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11766
11767 /* Tell the PNG lib to handle gamma correction for us. */
11768
11769#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11770 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11771 /* There is a special chunk in the image specifying the gamma. */
11772 png_set_sRGB (png_ptr, info_ptr, intent);
11773 else
11774#endif
11775 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11776 /* Image contains gamma information. */
11777 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11778 else
11779 /* Use a default of 0.5 for the image gamma. */
11780 png_set_gamma (png_ptr, screen_gamma, 0.5);
11781
11782 /* Handle alpha channel by combining the image with a background
11783 color. Do this only if a real alpha channel is supplied. For
11784 simple transparency, we prefer a clipping mask. */
11785 if (!transparent_p)
11786 {
11787 png_color_16 *image_background;
a05e2bae
JR
11788 Lisp_Object specified_bg
11789 = image_spec_value (img->spec, QCbackground, NULL);
11790
11791
11792 if (STRINGP (specified_bg))
11793 /* The user specified `:background', use that. */
11794 {
11795 COLORREF color;
11796 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11797 {
11798 png_color_16 user_bg;
11799
11800 bzero (&user_bg, sizeof user_bg);
11801 user_bg.red = color.red;
11802 user_bg.green = color.green;
11803 user_bg.blue = color.blue;
6fc2811b 11804
a05e2bae
JR
11805 png_set_background (png_ptr, &user_bg,
11806 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11807 }
11808 }
11809 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11810 /* Image contains a background color with which to
11811 combine the image. */
11812 png_set_background (png_ptr, image_background,
11813 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11814 else
11815 {
11816 /* Image does not contain a background color with which
11817 to combine the image data via an alpha channel. Use
11818 the frame's background instead. */
11819 XColor color;
11820 Colormap cmap;
11821 png_color_16 frame_background;
11822
a05e2bae 11823 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11824 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11825 x_query_color (f, &color);
6fc2811b
JR
11826
11827 bzero (&frame_background, sizeof frame_background);
11828 frame_background.red = color.red;
11829 frame_background.green = color.green;
11830 frame_background.blue = color.blue;
11831
11832 png_set_background (png_ptr, &frame_background,
11833 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11834 }
11835 }
11836
11837 /* Update info structure. */
11838 png_read_update_info (png_ptr, info_ptr);
11839
11840 /* Get number of channels. Valid values are 1 for grayscale images
11841 and images with a palette, 2 for grayscale images with transparency
11842 information (alpha channel), 3 for RGB images, and 4 for RGB
11843 images with alpha channel, i.e. RGBA. If conversions above were
11844 sufficient we should only have 3 or 4 channels here. */
11845 channels = png_get_channels (png_ptr, info_ptr);
11846 xassert (channels == 3 || channels == 4);
11847
11848 /* Number of bytes needed for one row of the image. */
11849 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11850
11851 /* Allocate memory for the image. */
11852 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11853 rows = (png_byte **) xmalloc (height * sizeof *rows);
11854 for (i = 0; i < height; ++i)
11855 rows[i] = pixels + i * row_bytes;
11856
11857 /* Read the entire image. */
11858 png_read_image (png_ptr, rows);
11859 png_read_end (png_ptr, info_ptr);
11860 if (fp)
11861 {
11862 fclose (fp);
11863 fp = NULL;
11864 }
11865
6fc2811b
JR
11866 /* Create the X image and pixmap. */
11867 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11868 &img->pixmap))
a05e2bae 11869 goto error;
6fc2811b
JR
11870
11871 /* Create an image and pixmap serving as mask if the PNG image
11872 contains an alpha channel. */
11873 if (channels == 4
11874 && !transparent_p
11875 && !x_create_x_image_and_pixmap (f, width, height, 1,
11876 &mask_img, &img->mask))
11877 {
11878 x_destroy_x_image (ximg);
11879 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11880 img->pixmap = 0;
6fc2811b
JR
11881 goto error;
11882 }
11883
11884 /* Fill the X image and mask from PNG data. */
11885 init_color_table ();
11886
11887 for (y = 0; y < height; ++y)
11888 {
11889 png_byte *p = rows[y];
11890
11891 for (x = 0; x < width; ++x)
11892 {
11893 unsigned r, g, b;
11894
11895 r = *p++ << 8;
11896 g = *p++ << 8;
11897 b = *p++ << 8;
11898 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11899
11900 /* An alpha channel, aka mask channel, associates variable
11901 transparency with an image. Where other image formats
11902 support binary transparency---fully transparent or fully
11903 opaque---PNG allows up to 254 levels of partial transparency.
11904 The PNG library implements partial transparency by combining
11905 the image with a specified background color.
11906
11907 I'm not sure how to handle this here nicely: because the
11908 background on which the image is displayed may change, for
11909 real alpha channel support, it would be necessary to create
11910 a new image for each possible background.
11911
11912 What I'm doing now is that a mask is created if we have
11913 boolean transparency information. Otherwise I'm using
11914 the frame's background color to combine the image with. */
11915
11916 if (channels == 4)
11917 {
11918 if (mask_img)
11919 XPutPixel (mask_img, x, y, *p > 0);
11920 ++p;
11921 }
11922 }
11923 }
11924
a05e2bae
JR
11925 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11926 /* Set IMG's background color from the PNG image, unless the user
11927 overrode it. */
11928 {
11929 png_color_16 *bg;
11930 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11931 {
11932 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11933 img->background_valid = 1;
11934 }
11935 }
11936
6fc2811b
JR
11937 /* Remember colors allocated for this image. */
11938 img->colors = colors_in_color_table (&img->ncolors);
11939 free_color_table ();
11940
11941 /* Clean up. */
11942 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11943 xfree (rows);
11944 xfree (pixels);
11945
11946 img->width = width;
11947 img->height = height;
11948
a05e2bae
JR
11949 /* Maybe fill in the background field while we have ximg handy. */
11950 IMAGE_BACKGROUND (img, f, ximg);
11951
6fc2811b
JR
11952 /* Put the image into the pixmap, then free the X image and its buffer. */
11953 x_put_x_image (f, ximg, img->pixmap, width, height);
11954 x_destroy_x_image (ximg);
11955
11956 /* Same for the mask. */
11957 if (mask_img)
11958 {
a05e2bae
JR
11959 /* Fill in the background_transparent field while we have the mask
11960 handy. */
11961 image_background_transparent (img, f, mask_img);
11962
6fc2811b
JR
11963 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11964 x_destroy_x_image (mask_img);
11965 }
11966
6fc2811b
JR
11967 UNGCPRO;
11968 return 1;
11969}
11970
11971#endif /* HAVE_PNG != 0 */
11972
11973
11974\f
11975/***********************************************************************
11976 JPEG
11977 ***********************************************************************/
11978
11979#if HAVE_JPEG
11980
11981/* Work around a warning about HAVE_STDLIB_H being redefined in
11982 jconfig.h. */
11983#ifdef HAVE_STDLIB_H
11984#define HAVE_STDLIB_H_1
11985#undef HAVE_STDLIB_H
11986#endif /* HAVE_STLIB_H */
11987
11988#include <jpeglib.h>
11989#include <jerror.h>
11990#include <setjmp.h>
11991
11992#ifdef HAVE_STLIB_H_1
11993#define HAVE_STDLIB_H 1
11994#endif
11995
11996static int jpeg_image_p P_ ((Lisp_Object object));
11997static int jpeg_load P_ ((struct frame *f, struct image *img));
11998
11999/* The symbol `jpeg' identifying images of this type. */
12000
12001Lisp_Object Qjpeg;
12002
12003/* Indices of image specification fields in gs_format, below. */
12004
12005enum jpeg_keyword_index
12006{
12007 JPEG_TYPE,
12008 JPEG_DATA,
12009 JPEG_FILE,
12010 JPEG_ASCENT,
12011 JPEG_MARGIN,
12012 JPEG_RELIEF,
12013 JPEG_ALGORITHM,
12014 JPEG_HEURISTIC_MASK,
a05e2bae
JR
12015 JPEG_MASK,
12016 JPEG_BACKGROUND,
6fc2811b
JR
12017 JPEG_LAST
12018};
12019
12020/* Vector of image_keyword structures describing the format
12021 of valid user-defined image specifications. */
12022
12023static struct image_keyword jpeg_format[JPEG_LAST] =
12024{
12025 {":type", IMAGE_SYMBOL_VALUE, 1},
12026 {":data", IMAGE_STRING_VALUE, 0},
12027 {":file", IMAGE_STRING_VALUE, 0},
12028 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12029 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12030 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12031 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12032 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12033 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12034 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12035};
12036
12037/* Structure describing the image type `jpeg'. */
12038
12039static struct image_type jpeg_type =
12040{
12041 &Qjpeg,
12042 jpeg_image_p,
12043 jpeg_load,
12044 x_clear_image,
12045 NULL
12046};
12047
12048
12049/* Return non-zero if OBJECT is a valid JPEG image specification. */
12050
12051static int
12052jpeg_image_p (object)
12053 Lisp_Object object;
12054{
12055 struct image_keyword fmt[JPEG_LAST];
12056
12057 bcopy (jpeg_format, fmt, sizeof fmt);
12058
12059 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
12060 || (fmt[JPEG_ASCENT].count
12061 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
12062 return 0;
12063
12064 /* Must specify either the :data or :file keyword. */
12065 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
12066}
12067
12068
12069struct my_jpeg_error_mgr
12070{
12071 struct jpeg_error_mgr pub;
12072 jmp_buf setjmp_buffer;
12073};
12074
12075static void
12076my_error_exit (cinfo)
12077 j_common_ptr cinfo;
12078{
12079 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12080 longjmp (mgr->setjmp_buffer, 1);
12081}
12082
6fc2811b
JR
12083/* Init source method for JPEG data source manager. Called by
12084 jpeg_read_header() before any data is actually read. See
12085 libjpeg.doc from the JPEG lib distribution. */
12086
12087static void
12088our_init_source (cinfo)
12089 j_decompress_ptr cinfo;
12090{
12091}
12092
12093
12094/* Fill input buffer method for JPEG data source manager. Called
12095 whenever more data is needed. We read the whole image in one step,
12096 so this only adds a fake end of input marker at the end. */
12097
12098static boolean
12099our_fill_input_buffer (cinfo)
12100 j_decompress_ptr cinfo;
12101{
12102 /* Insert a fake EOI marker. */
12103 struct jpeg_source_mgr *src = cinfo->src;
12104 static JOCTET buffer[2];
12105
12106 buffer[0] = (JOCTET) 0xFF;
12107 buffer[1] = (JOCTET) JPEG_EOI;
12108
12109 src->next_input_byte = buffer;
12110 src->bytes_in_buffer = 2;
12111 return TRUE;
12112}
12113
12114
12115/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12116 is the JPEG data source manager. */
12117
12118static void
12119our_skip_input_data (cinfo, num_bytes)
12120 j_decompress_ptr cinfo;
12121 long num_bytes;
12122{
12123 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12124
12125 if (src)
12126 {
12127 if (num_bytes > src->bytes_in_buffer)
12128 ERREXIT (cinfo, JERR_INPUT_EOF);
12129
12130 src->bytes_in_buffer -= num_bytes;
12131 src->next_input_byte += num_bytes;
12132 }
12133}
12134
12135
12136/* Method to terminate data source. Called by
12137 jpeg_finish_decompress() after all data has been processed. */
12138
12139static void
12140our_term_source (cinfo)
12141 j_decompress_ptr cinfo;
12142{
12143}
12144
12145
12146/* Set up the JPEG lib for reading an image from DATA which contains
12147 LEN bytes. CINFO is the decompression info structure created for
12148 reading the image. */
12149
12150static void
12151jpeg_memory_src (cinfo, data, len)
12152 j_decompress_ptr cinfo;
12153 JOCTET *data;
12154 unsigned int len;
12155{
12156 struct jpeg_source_mgr *src;
12157
12158 if (cinfo->src == NULL)
12159 {
12160 /* First time for this JPEG object? */
12161 cinfo->src = (struct jpeg_source_mgr *)
12162 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12163 sizeof (struct jpeg_source_mgr));
12164 src = (struct jpeg_source_mgr *) cinfo->src;
12165 src->next_input_byte = data;
12166 }
12167
12168 src = (struct jpeg_source_mgr *) cinfo->src;
12169 src->init_source = our_init_source;
12170 src->fill_input_buffer = our_fill_input_buffer;
12171 src->skip_input_data = our_skip_input_data;
12172 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12173 src->term_source = our_term_source;
12174 src->bytes_in_buffer = len;
12175 src->next_input_byte = data;
12176}
12177
12178
12179/* Load image IMG for use on frame F. Patterned after example.c
12180 from the JPEG lib. */
12181
12182static int
12183jpeg_load (f, img)
12184 struct frame *f;
12185 struct image *img;
12186{
12187 struct jpeg_decompress_struct cinfo;
12188 struct my_jpeg_error_mgr mgr;
12189 Lisp_Object file, specified_file;
12190 Lisp_Object specified_data;
a05e2bae 12191 FILE * volatile fp = NULL;
6fc2811b
JR
12192 JSAMPARRAY buffer;
12193 int row_stride, x, y;
12194 XImage *ximg = NULL;
12195 int rc;
12196 unsigned long *colors;
12197 int width, height;
12198 struct gcpro gcpro1;
12199
12200 /* Open the JPEG file. */
12201 specified_file = image_spec_value (img->spec, QCfile, NULL);
12202 specified_data = image_spec_value (img->spec, QCdata, NULL);
12203 file = Qnil;
12204 GCPRO1 (file);
12205
6fc2811b
JR
12206 if (NILP (specified_data))
12207 {
12208 file = x_find_image_file (specified_file);
12209 if (!STRINGP (file))
12210 {
12211 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12212 UNGCPRO;
12213 return 0;
12214 }
12215
12216 fp = fopen (XSTRING (file)->data, "r");
12217 if (fp == NULL)
12218 {
12219 image_error ("Cannot open `%s'", file, Qnil);
12220 UNGCPRO;
12221 return 0;
12222 }
12223 }
12224
12225 /* Customize libjpeg's error handling to call my_error_exit when an
12226 error is detected. This function will perform a longjmp. */
6fc2811b 12227 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 12228 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
12229
12230 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12231 {
12232 if (rc == 1)
12233 {
12234 /* Called from my_error_exit. Display a JPEG error. */
12235 char buffer[JMSG_LENGTH_MAX];
12236 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12237 image_error ("Error reading JPEG image `%s': %s", img->spec,
12238 build_string (buffer));
12239 }
12240
12241 /* Close the input file and destroy the JPEG object. */
12242 if (fp)
12243 fclose (fp);
12244 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
12245
12246 /* If we already have an XImage, free that. */
12247 x_destroy_x_image (ximg);
12248
12249 /* Free pixmap and colors. */
12250 x_clear_image (f, img);
12251
6fc2811b
JR
12252 UNGCPRO;
12253 return 0;
12254 }
12255
12256 /* Create the JPEG decompression object. Let it read from fp.
12257 Read the JPEG image header. */
12258 jpeg_create_decompress (&cinfo);
12259
12260 if (NILP (specified_data))
12261 jpeg_stdio_src (&cinfo, fp);
12262 else
12263 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12264 STRING_BYTES (XSTRING (specified_data)));
12265
12266 jpeg_read_header (&cinfo, TRUE);
12267
12268 /* Customize decompression so that color quantization will be used.
12269 Start decompression. */
12270 cinfo.quantize_colors = TRUE;
12271 jpeg_start_decompress (&cinfo);
12272 width = img->width = cinfo.output_width;
12273 height = img->height = cinfo.output_height;
12274
6fc2811b
JR
12275 /* Create X image and pixmap. */
12276 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12277 &img->pixmap))
a05e2bae 12278 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
12279
12280 /* Allocate colors. When color quantization is used,
12281 cinfo.actual_number_of_colors has been set with the number of
12282 colors generated, and cinfo.colormap is a two-dimensional array
12283 of color indices in the range 0..cinfo.actual_number_of_colors.
12284 No more than 255 colors will be generated. */
12285 {
12286 int i, ir, ig, ib;
12287
12288 if (cinfo.out_color_components > 2)
12289 ir = 0, ig = 1, ib = 2;
12290 else if (cinfo.out_color_components > 1)
12291 ir = 0, ig = 1, ib = 0;
12292 else
12293 ir = 0, ig = 0, ib = 0;
12294
12295 /* Use the color table mechanism because it handles colors that
12296 cannot be allocated nicely. Such colors will be replaced with
12297 a default color, and we don't have to care about which colors
12298 can be freed safely, and which can't. */
12299 init_color_table ();
12300 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12301 * sizeof *colors);
12302
12303 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12304 {
12305 /* Multiply RGB values with 255 because X expects RGB values
12306 in the range 0..0xffff. */
12307 int r = cinfo.colormap[ir][i] << 8;
12308 int g = cinfo.colormap[ig][i] << 8;
12309 int b = cinfo.colormap[ib][i] << 8;
12310 colors[i] = lookup_rgb_color (f, r, g, b);
12311 }
12312
12313 /* Remember those colors actually allocated. */
12314 img->colors = colors_in_color_table (&img->ncolors);
12315 free_color_table ();
12316 }
12317
12318 /* Read pixels. */
12319 row_stride = width * cinfo.output_components;
12320 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12321 row_stride, 1);
12322 for (y = 0; y < height; ++y)
12323 {
12324 jpeg_read_scanlines (&cinfo, buffer, 1);
12325 for (x = 0; x < cinfo.output_width; ++x)
12326 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12327 }
12328
12329 /* Clean up. */
12330 jpeg_finish_decompress (&cinfo);
12331 jpeg_destroy_decompress (&cinfo);
12332 if (fp)
12333 fclose (fp);
12334
a05e2bae
JR
12335 /* Maybe fill in the background field while we have ximg handy. */
12336 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12337 IMAGE_BACKGROUND (img, f, ximg);
12338
6fc2811b
JR
12339 /* Put the image into the pixmap. */
12340 x_put_x_image (f, ximg, img->pixmap, width, height);
12341 x_destroy_x_image (ximg);
12342 UNBLOCK_INPUT;
12343 UNGCPRO;
12344 return 1;
12345}
12346
12347#endif /* HAVE_JPEG */
12348
12349
12350\f
12351/***********************************************************************
12352 TIFF
12353 ***********************************************************************/
12354
12355#if HAVE_TIFF
12356
12357#include <tiffio.h>
12358
12359static int tiff_image_p P_ ((Lisp_Object object));
12360static int tiff_load P_ ((struct frame *f, struct image *img));
12361
12362/* The symbol `tiff' identifying images of this type. */
12363
12364Lisp_Object Qtiff;
12365
12366/* Indices of image specification fields in tiff_format, below. */
12367
12368enum tiff_keyword_index
12369{
12370 TIFF_TYPE,
12371 TIFF_DATA,
12372 TIFF_FILE,
12373 TIFF_ASCENT,
12374 TIFF_MARGIN,
12375 TIFF_RELIEF,
12376 TIFF_ALGORITHM,
12377 TIFF_HEURISTIC_MASK,
a05e2bae
JR
12378 TIFF_MASK,
12379 TIFF_BACKGROUND,
6fc2811b
JR
12380 TIFF_LAST
12381};
12382
12383/* Vector of image_keyword structures describing the format
12384 of valid user-defined image specifications. */
12385
12386static struct image_keyword tiff_format[TIFF_LAST] =
12387{
12388 {":type", IMAGE_SYMBOL_VALUE, 1},
12389 {":data", IMAGE_STRING_VALUE, 0},
12390 {":file", IMAGE_STRING_VALUE, 0},
12391 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12392 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12393 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12394 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12395 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12396 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12397 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12398};
12399
12400/* Structure describing the image type `tiff'. */
12401
12402static struct image_type tiff_type =
12403{
12404 &Qtiff,
12405 tiff_image_p,
12406 tiff_load,
12407 x_clear_image,
12408 NULL
12409};
12410
12411
12412/* Return non-zero if OBJECT is a valid TIFF image specification. */
12413
12414static int
12415tiff_image_p (object)
12416 Lisp_Object object;
12417{
12418 struct image_keyword fmt[TIFF_LAST];
12419 bcopy (tiff_format, fmt, sizeof fmt);
12420
12421 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12422 || (fmt[TIFF_ASCENT].count
12423 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12424 return 0;
12425
12426 /* Must specify either the :data or :file keyword. */
12427 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12428}
12429
12430
12431/* Reading from a memory buffer for TIFF images Based on the PNG
12432 memory source, but we have to provide a lot of extra functions.
12433 Blah.
12434
12435 We really only need to implement read and seek, but I am not
12436 convinced that the TIFF library is smart enough not to destroy
12437 itself if we only hand it the function pointers we need to
12438 override. */
12439
12440typedef struct
12441{
12442 unsigned char *bytes;
12443 size_t len;
12444 int index;
12445}
12446tiff_memory_source;
12447
12448static size_t
12449tiff_read_from_memory (data, buf, size)
12450 thandle_t data;
12451 tdata_t buf;
12452 tsize_t size;
12453{
12454 tiff_memory_source *src = (tiff_memory_source *) data;
12455
12456 if (size > src->len - src->index)
12457 return (size_t) -1;
12458 bcopy (src->bytes + src->index, buf, size);
12459 src->index += size;
12460 return size;
12461}
12462
12463static size_t
12464tiff_write_from_memory (data, buf, size)
12465 thandle_t data;
12466 tdata_t buf;
12467 tsize_t size;
12468{
12469 return (size_t) -1;
12470}
12471
12472static toff_t
12473tiff_seek_in_memory (data, off, whence)
12474 thandle_t data;
12475 toff_t off;
12476 int whence;
12477{
12478 tiff_memory_source *src = (tiff_memory_source *) data;
12479 int idx;
12480
12481 switch (whence)
12482 {
12483 case SEEK_SET: /* Go from beginning of source. */
12484 idx = off;
12485 break;
12486
12487 case SEEK_END: /* Go from end of source. */
12488 idx = src->len + off;
12489 break;
12490
12491 case SEEK_CUR: /* Go from current position. */
12492 idx = src->index + off;
12493 break;
12494
12495 default: /* Invalid `whence'. */
12496 return -1;
12497 }
12498
12499 if (idx > src->len || idx < 0)
12500 return -1;
12501
12502 src->index = idx;
12503 return src->index;
12504}
12505
12506static int
12507tiff_close_memory (data)
12508 thandle_t data;
12509{
12510 /* NOOP */
12511 return 0;
12512}
12513
12514static int
12515tiff_mmap_memory (data, pbase, psize)
12516 thandle_t data;
12517 tdata_t *pbase;
12518 toff_t *psize;
12519{
12520 /* It is already _IN_ memory. */
12521 return 0;
12522}
12523
12524static void
12525tiff_unmap_memory (data, base, size)
12526 thandle_t data;
12527 tdata_t base;
12528 toff_t size;
12529{
12530 /* We don't need to do this. */
12531}
12532
12533static toff_t
12534tiff_size_of_memory (data)
12535 thandle_t data;
12536{
12537 return ((tiff_memory_source *) data)->len;
12538}
12539
3cf3436e
JR
12540
12541static void
12542tiff_error_handler (title, format, ap)
12543 const char *title, *format;
12544 va_list ap;
12545{
12546 char buf[512];
12547 int len;
12548
12549 len = sprintf (buf, "TIFF error: %s ", title);
12550 vsprintf (buf + len, format, ap);
12551 add_to_log (buf, Qnil, Qnil);
12552}
12553
12554
12555static void
12556tiff_warning_handler (title, format, ap)
12557 const char *title, *format;
12558 va_list ap;
12559{
12560 char buf[512];
12561 int len;
12562
12563 len = sprintf (buf, "TIFF warning: %s ", title);
12564 vsprintf (buf + len, format, ap);
12565 add_to_log (buf, Qnil, Qnil);
12566}
12567
12568
6fc2811b
JR
12569/* Load TIFF image IMG for use on frame F. Value is non-zero if
12570 successful. */
12571
12572static int
12573tiff_load (f, img)
12574 struct frame *f;
12575 struct image *img;
12576{
12577 Lisp_Object file, specified_file;
12578 Lisp_Object specified_data;
12579 TIFF *tiff;
12580 int width, height, x, y;
12581 uint32 *buf;
12582 int rc;
12583 XImage *ximg;
12584 struct gcpro gcpro1;
12585 tiff_memory_source memsrc;
12586
12587 specified_file = image_spec_value (img->spec, QCfile, NULL);
12588 specified_data = image_spec_value (img->spec, QCdata, NULL);
12589 file = Qnil;
12590 GCPRO1 (file);
12591
3cf3436e
JR
12592 TIFFSetErrorHandler (tiff_error_handler);
12593 TIFFSetWarningHandler (tiff_warning_handler);
12594
6fc2811b
JR
12595 if (NILP (specified_data))
12596 {
12597 /* Read from a file */
12598 file = x_find_image_file (specified_file);
12599 if (!STRINGP (file))
3cf3436e
JR
12600 {
12601 image_error ("Cannot find image file `%s'", file, Qnil);
12602 UNGCPRO;
12603 return 0;
12604 }
12605
6fc2811b
JR
12606 /* Try to open the image file. */
12607 tiff = TIFFOpen (XSTRING (file)->data, "r");
12608 if (tiff == NULL)
3cf3436e
JR
12609 {
12610 image_error ("Cannot open `%s'", file, Qnil);
12611 UNGCPRO;
12612 return 0;
12613 }
6fc2811b
JR
12614 }
12615 else
12616 {
12617 /* Memory source! */
12618 memsrc.bytes = XSTRING (specified_data)->data;
12619 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12620 memsrc.index = 0;
12621
12622 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12623 (TIFFReadWriteProc) tiff_read_from_memory,
12624 (TIFFReadWriteProc) tiff_write_from_memory,
12625 tiff_seek_in_memory,
12626 tiff_close_memory,
12627 tiff_size_of_memory,
12628 tiff_mmap_memory,
12629 tiff_unmap_memory);
12630
12631 if (!tiff)
12632 {
12633 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12634 UNGCPRO;
12635 return 0;
12636 }
12637 }
12638
12639 /* Get width and height of the image, and allocate a raster buffer
12640 of width x height 32-bit values. */
12641 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12642 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12643 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12644
12645 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12646 TIFFClose (tiff);
12647 if (!rc)
12648 {
12649 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12650 xfree (buf);
12651 UNGCPRO;
12652 return 0;
12653 }
12654
6fc2811b
JR
12655 /* Create the X image and pixmap. */
12656 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12657 {
6fc2811b
JR
12658 xfree (buf);
12659 UNGCPRO;
12660 return 0;
12661 }
12662
12663 /* Initialize the color table. */
12664 init_color_table ();
12665
12666 /* Process the pixel raster. Origin is in the lower-left corner. */
12667 for (y = 0; y < height; ++y)
12668 {
12669 uint32 *row = buf + y * width;
12670
12671 for (x = 0; x < width; ++x)
12672 {
12673 uint32 abgr = row[x];
12674 int r = TIFFGetR (abgr) << 8;
12675 int g = TIFFGetG (abgr) << 8;
12676 int b = TIFFGetB (abgr) << 8;
12677 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12678 }
12679 }
12680
12681 /* Remember the colors allocated for the image. Free the color table. */
12682 img->colors = colors_in_color_table (&img->ncolors);
12683 free_color_table ();
12684
a05e2bae
JR
12685 img->width = width;
12686 img->height = height;
12687
12688 /* Maybe fill in the background field while we have ximg handy. */
12689 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12690 IMAGE_BACKGROUND (img, f, ximg);
12691
6fc2811b
JR
12692 /* Put the image into the pixmap, then free the X image and its buffer. */
12693 x_put_x_image (f, ximg, img->pixmap, width, height);
12694 x_destroy_x_image (ximg);
12695 xfree (buf);
6fc2811b
JR
12696
12697 UNGCPRO;
12698 return 1;
12699}
12700
12701#endif /* HAVE_TIFF != 0 */
12702
12703
12704\f
12705/***********************************************************************
12706 GIF
12707 ***********************************************************************/
12708
12709#if HAVE_GIF
12710
12711#include <gif_lib.h>
12712
12713static int gif_image_p P_ ((Lisp_Object object));
12714static int gif_load P_ ((struct frame *f, struct image *img));
12715
12716/* The symbol `gif' identifying images of this type. */
12717
12718Lisp_Object Qgif;
12719
12720/* Indices of image specification fields in gif_format, below. */
12721
12722enum gif_keyword_index
12723{
12724 GIF_TYPE,
12725 GIF_DATA,
12726 GIF_FILE,
12727 GIF_ASCENT,
12728 GIF_MARGIN,
12729 GIF_RELIEF,
12730 GIF_ALGORITHM,
12731 GIF_HEURISTIC_MASK,
a05e2bae 12732 GIF_MASK,
6fc2811b 12733 GIF_IMAGE,
a05e2bae 12734 GIF_BACKGROUND,
6fc2811b
JR
12735 GIF_LAST
12736};
12737
12738/* Vector of image_keyword structures describing the format
12739 of valid user-defined image specifications. */
12740
12741static struct image_keyword gif_format[GIF_LAST] =
12742{
12743 {":type", IMAGE_SYMBOL_VALUE, 1},
12744 {":data", IMAGE_STRING_VALUE, 0},
12745 {":file", IMAGE_STRING_VALUE, 0},
12746 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12747 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12748 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12749 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12750 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12751 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12752 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12753 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12754};
12755
12756/* Structure describing the image type `gif'. */
12757
12758static struct image_type gif_type =
12759{
12760 &Qgif,
12761 gif_image_p,
12762 gif_load,
12763 x_clear_image,
12764 NULL
12765};
12766
12767/* Return non-zero if OBJECT is a valid GIF image specification. */
12768
12769static int
12770gif_image_p (object)
12771 Lisp_Object object;
12772{
12773 struct image_keyword fmt[GIF_LAST];
12774 bcopy (gif_format, fmt, sizeof fmt);
12775
12776 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12777 || (fmt[GIF_ASCENT].count
12778 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12779 return 0;
12780
12781 /* Must specify either the :data or :file keyword. */
12782 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12783}
12784
12785/* Reading a GIF image from memory
12786 Based on the PNG memory stuff to a certain extent. */
12787
12788typedef struct
12789{
12790 unsigned char *bytes;
12791 size_t len;
12792 int index;
12793}
12794gif_memory_source;
12795
12796/* Make the current memory source available to gif_read_from_memory.
12797 It's done this way because not all versions of libungif support
12798 a UserData field in the GifFileType structure. */
12799static gif_memory_source *current_gif_memory_src;
12800
12801static int
12802gif_read_from_memory (file, buf, len)
12803 GifFileType *file;
12804 GifByteType *buf;
12805 int len;
12806{
12807 gif_memory_source *src = current_gif_memory_src;
12808
12809 if (len > src->len - src->index)
12810 return -1;
12811
12812 bcopy (src->bytes + src->index, buf, len);
12813 src->index += len;
12814 return len;
12815}
12816
12817
12818/* Load GIF image IMG for use on frame F. Value is non-zero if
12819 successful. */
12820
12821static int
12822gif_load (f, img)
12823 struct frame *f;
12824 struct image *img;
12825{
12826 Lisp_Object file, specified_file;
12827 Lisp_Object specified_data;
12828 int rc, width, height, x, y, i;
12829 XImage *ximg;
12830 ColorMapObject *gif_color_map;
12831 unsigned long pixel_colors[256];
12832 GifFileType *gif;
12833 struct gcpro gcpro1;
12834 Lisp_Object image;
12835 int ino, image_left, image_top, image_width, image_height;
12836 gif_memory_source memsrc;
12837 unsigned char *raster;
12838
12839 specified_file = image_spec_value (img->spec, QCfile, NULL);
12840 specified_data = image_spec_value (img->spec, QCdata, NULL);
12841 file = Qnil;
dfff8a69 12842 GCPRO1 (file);
6fc2811b
JR
12843
12844 if (NILP (specified_data))
12845 {
12846 file = x_find_image_file (specified_file);
6fc2811b
JR
12847 if (!STRINGP (file))
12848 {
12849 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12850 UNGCPRO;
12851 return 0;
12852 }
12853
12854 /* Open the GIF file. */
12855 gif = DGifOpenFileName (XSTRING (file)->data);
12856 if (gif == NULL)
12857 {
12858 image_error ("Cannot open `%s'", file, Qnil);
12859 UNGCPRO;
12860 return 0;
12861 }
12862 }
12863 else
12864 {
12865 /* Read from memory! */
12866 current_gif_memory_src = &memsrc;
12867 memsrc.bytes = XSTRING (specified_data)->data;
12868 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12869 memsrc.index = 0;
12870
12871 gif = DGifOpen(&memsrc, gif_read_from_memory);
12872 if (!gif)
12873 {
12874 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12875 UNGCPRO;
12876 return 0;
12877 }
12878 }
12879
12880 /* Read entire contents. */
12881 rc = DGifSlurp (gif);
12882 if (rc == GIF_ERROR)
12883 {
12884 image_error ("Error reading `%s'", img->spec, Qnil);
12885 DGifCloseFile (gif);
12886 UNGCPRO;
12887 return 0;
12888 }
12889
12890 image = image_spec_value (img->spec, QCindex, NULL);
12891 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12892 if (ino >= gif->ImageCount)
12893 {
12894 image_error ("Invalid image number `%s' in image `%s'",
12895 image, img->spec);
12896 DGifCloseFile (gif);
12897 UNGCPRO;
12898 return 0;
12899 }
12900
12901 width = img->width = gif->SWidth;
12902 height = img->height = gif->SHeight;
12903
6fc2811b
JR
12904 /* Create the X image and pixmap. */
12905 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12906 {
6fc2811b
JR
12907 DGifCloseFile (gif);
12908 UNGCPRO;
12909 return 0;
12910 }
12911
12912 /* Allocate colors. */
12913 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12914 if (!gif_color_map)
12915 gif_color_map = gif->SColorMap;
12916 init_color_table ();
12917 bzero (pixel_colors, sizeof pixel_colors);
12918
12919 for (i = 0; i < gif_color_map->ColorCount; ++i)
12920 {
12921 int r = gif_color_map->Colors[i].Red << 8;
12922 int g = gif_color_map->Colors[i].Green << 8;
12923 int b = gif_color_map->Colors[i].Blue << 8;
12924 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12925 }
12926
12927 img->colors = colors_in_color_table (&img->ncolors);
12928 free_color_table ();
12929
12930 /* Clear the part of the screen image that are not covered by
12931 the image from the GIF file. Full animated GIF support
12932 requires more than can be done here (see the gif89 spec,
12933 disposal methods). Let's simply assume that the part
12934 not covered by a sub-image is in the frame's background color. */
12935 image_top = gif->SavedImages[ino].ImageDesc.Top;
12936 image_left = gif->SavedImages[ino].ImageDesc.Left;
12937 image_width = gif->SavedImages[ino].ImageDesc.Width;
12938 image_height = gif->SavedImages[ino].ImageDesc.Height;
12939
12940 for (y = 0; y < image_top; ++y)
12941 for (x = 0; x < width; ++x)
12942 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12943
12944 for (y = image_top + image_height; y < height; ++y)
12945 for (x = 0; x < width; ++x)
12946 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12947
12948 for (y = image_top; y < image_top + image_height; ++y)
12949 {
12950 for (x = 0; x < image_left; ++x)
12951 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12952 for (x = image_left + image_width; x < width; ++x)
12953 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12954 }
12955
12956 /* Read the GIF image into the X image. We use a local variable
12957 `raster' here because RasterBits below is a char *, and invites
12958 problems with bytes >= 0x80. */
12959 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12960
12961 if (gif->SavedImages[ino].ImageDesc.Interlace)
12962 {
12963 static int interlace_start[] = {0, 4, 2, 1};
12964 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12965 int pass;
6fc2811b
JR
12966 int row = interlace_start[0];
12967
12968 pass = 0;
12969
12970 for (y = 0; y < image_height; y++)
12971 {
12972 if (row >= image_height)
12973 {
12974 row = interlace_start[++pass];
12975 while (row >= image_height)
12976 row = interlace_start[++pass];
12977 }
12978
12979 for (x = 0; x < image_width; x++)
12980 {
12981 int i = raster[(y * image_width) + x];
12982 XPutPixel (ximg, x + image_left, row + image_top,
12983 pixel_colors[i]);
12984 }
12985
12986 row += interlace_increment[pass];
12987 }
12988 }
12989 else
12990 {
12991 for (y = 0; y < image_height; ++y)
12992 for (x = 0; x < image_width; ++x)
12993 {
12994 int i = raster[y* image_width + x];
12995 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12996 }
12997 }
12998
12999 DGifCloseFile (gif);
a05e2bae
JR
13000
13001 /* Maybe fill in the background field while we have ximg handy. */
13002 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
13003 IMAGE_BACKGROUND (img, f, ximg);
13004
6fc2811b
JR
13005 /* Put the image into the pixmap, then free the X image and its buffer. */
13006 x_put_x_image (f, ximg, img->pixmap, width, height);
13007 x_destroy_x_image (ximg);
6fc2811b
JR
13008
13009 UNGCPRO;
13010 return 1;
13011}
13012
13013#endif /* HAVE_GIF != 0 */
13014
13015
13016\f
13017/***********************************************************************
13018 Ghostscript
13019 ***********************************************************************/
13020
3cf3436e
JR
13021Lisp_Object Qpostscript;
13022
6fc2811b
JR
13023#ifdef HAVE_GHOSTSCRIPT
13024static int gs_image_p P_ ((Lisp_Object object));
13025static int gs_load P_ ((struct frame *f, struct image *img));
13026static void gs_clear_image P_ ((struct frame *f, struct image *img));
13027
13028/* The symbol `postscript' identifying images of this type. */
13029
6fc2811b
JR
13030/* Keyword symbols. */
13031
13032Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
13033
13034/* Indices of image specification fields in gs_format, below. */
13035
13036enum gs_keyword_index
13037{
13038 GS_TYPE,
13039 GS_PT_WIDTH,
13040 GS_PT_HEIGHT,
13041 GS_FILE,
13042 GS_LOADER,
13043 GS_BOUNDING_BOX,
13044 GS_ASCENT,
13045 GS_MARGIN,
13046 GS_RELIEF,
13047 GS_ALGORITHM,
13048 GS_HEURISTIC_MASK,
a05e2bae
JR
13049 GS_MASK,
13050 GS_BACKGROUND,
6fc2811b
JR
13051 GS_LAST
13052};
13053
13054/* Vector of image_keyword structures describing the format
13055 of valid user-defined image specifications. */
13056
13057static struct image_keyword gs_format[GS_LAST] =
13058{
13059 {":type", IMAGE_SYMBOL_VALUE, 1},
13060 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13061 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13062 {":file", IMAGE_STRING_VALUE, 1},
13063 {":loader", IMAGE_FUNCTION_VALUE, 0},
13064 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
13065 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 13066 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 13067 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 13068 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
13069 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13070 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13071 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
13072};
13073
13074/* Structure describing the image type `ghostscript'. */
13075
13076static struct image_type gs_type =
13077{
13078 &Qpostscript,
13079 gs_image_p,
13080 gs_load,
13081 gs_clear_image,
13082 NULL
13083};
13084
13085
13086/* Free X resources of Ghostscript image IMG which is used on frame F. */
13087
13088static void
13089gs_clear_image (f, img)
13090 struct frame *f;
13091 struct image *img;
13092{
13093 /* IMG->data.ptr_val may contain a recorded colormap. */
13094 xfree (img->data.ptr_val);
13095 x_clear_image (f, img);
13096}
13097
13098
13099/* Return non-zero if OBJECT is a valid Ghostscript image
13100 specification. */
13101
13102static int
13103gs_image_p (object)
13104 Lisp_Object object;
13105{
13106 struct image_keyword fmt[GS_LAST];
13107 Lisp_Object tem;
13108 int i;
13109
13110 bcopy (gs_format, fmt, sizeof fmt);
13111
13112 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
13113 || (fmt[GS_ASCENT].count
13114 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13115 return 0;
13116
13117 /* Bounding box must be a list or vector containing 4 integers. */
13118 tem = fmt[GS_BOUNDING_BOX].value;
13119 if (CONSP (tem))
13120 {
13121 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13122 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13123 return 0;
13124 if (!NILP (tem))
13125 return 0;
13126 }
13127 else if (VECTORP (tem))
13128 {
13129 if (XVECTOR (tem)->size != 4)
13130 return 0;
13131 for (i = 0; i < 4; ++i)
13132 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13133 return 0;
13134 }
13135 else
13136 return 0;
13137
13138 return 1;
13139}
13140
13141
13142/* Load Ghostscript image IMG for use on frame F. Value is non-zero
13143 if successful. */
13144
13145static int
13146gs_load (f, img)
13147 struct frame *f;
13148 struct image *img;
13149{
13150 char buffer[100];
13151 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13152 struct gcpro gcpro1, gcpro2;
13153 Lisp_Object frame;
13154 double in_width, in_height;
13155 Lisp_Object pixel_colors = Qnil;
13156
13157 /* Compute pixel size of pixmap needed from the given size in the
13158 image specification. Sizes in the specification are in pt. 1 pt
13159 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13160 info. */
13161 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13162 in_width = XFASTINT (pt_width) / 72.0;
13163 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13164 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13165 in_height = XFASTINT (pt_height) / 72.0;
13166 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13167
13168 /* Create the pixmap. */
13169 BLOCK_INPUT;
13170 xassert (img->pixmap == 0);
13171 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13172 img->width, img->height,
a05e2bae 13173 one_w32_display_info.n_cbits);
6fc2811b
JR
13174 UNBLOCK_INPUT;
13175
13176 if (!img->pixmap)
13177 {
13178 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13179 return 0;
13180 }
13181
13182 /* Call the loader to fill the pixmap. It returns a process object
13183 if successful. We do not record_unwind_protect here because
13184 other places in redisplay like calling window scroll functions
13185 don't either. Let the Lisp loader use `unwind-protect' instead. */
13186 GCPRO2 (window_and_pixmap_id, pixel_colors);
13187
13188 sprintf (buffer, "%lu %lu",
13189 (unsigned long) FRAME_W32_WINDOW (f),
13190 (unsigned long) img->pixmap);
13191 window_and_pixmap_id = build_string (buffer);
13192
13193 sprintf (buffer, "%lu %lu",
13194 FRAME_FOREGROUND_PIXEL (f),
13195 FRAME_BACKGROUND_PIXEL (f));
13196 pixel_colors = build_string (buffer);
13197
13198 XSETFRAME (frame, f);
13199 loader = image_spec_value (img->spec, QCloader, NULL);
13200 if (NILP (loader))
13201 loader = intern ("gs-load-image");
13202
13203 img->data.lisp_val = call6 (loader, frame, img->spec,
13204 make_number (img->width),
13205 make_number (img->height),
13206 window_and_pixmap_id,
13207 pixel_colors);
13208 UNGCPRO;
13209 return PROCESSP (img->data.lisp_val);
13210}
13211
13212
13213/* Kill the Ghostscript process that was started to fill PIXMAP on
13214 frame F. Called from XTread_socket when receiving an event
13215 telling Emacs that Ghostscript has finished drawing. */
13216
13217void
13218x_kill_gs_process (pixmap, f)
13219 Pixmap pixmap;
13220 struct frame *f;
13221{
13222 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13223 int class, i;
13224 struct image *img;
13225
13226 /* Find the image containing PIXMAP. */
13227 for (i = 0; i < c->used; ++i)
13228 if (c->images[i]->pixmap == pixmap)
13229 break;
13230
3cf3436e
JR
13231 /* Should someone in between have cleared the image cache, for
13232 instance, give up. */
13233 if (i == c->used)
13234 return;
13235
6fc2811b
JR
13236 /* Kill the GS process. We should have found PIXMAP in the image
13237 cache and its image should contain a process object. */
6fc2811b
JR
13238 img = c->images[i];
13239 xassert (PROCESSP (img->data.lisp_val));
13240 Fkill_process (img->data.lisp_val, Qnil);
13241 img->data.lisp_val = Qnil;
13242
13243 /* On displays with a mutable colormap, figure out the colors
13244 allocated for the image by looking at the pixels of an XImage for
13245 img->pixmap. */
13246 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13247 if (class != StaticColor && class != StaticGray && class != TrueColor)
13248 {
13249 XImage *ximg;
13250
13251 BLOCK_INPUT;
13252
13253 /* Try to get an XImage for img->pixmep. */
13254 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13255 0, 0, img->width, img->height, ~0, ZPixmap);
13256 if (ximg)
13257 {
13258 int x, y;
13259
13260 /* Initialize the color table. */
13261 init_color_table ();
13262
13263 /* For each pixel of the image, look its color up in the
13264 color table. After having done so, the color table will
13265 contain an entry for each color used by the image. */
13266 for (y = 0; y < img->height; ++y)
13267 for (x = 0; x < img->width; ++x)
13268 {
13269 unsigned long pixel = XGetPixel (ximg, x, y);
13270 lookup_pixel_color (f, pixel);
13271 }
13272
13273 /* Record colors in the image. Free color table and XImage. */
13274 img->colors = colors_in_color_table (&img->ncolors);
13275 free_color_table ();
13276 XDestroyImage (ximg);
13277
13278#if 0 /* This doesn't seem to be the case. If we free the colors
13279 here, we get a BadAccess later in x_clear_image when
13280 freeing the colors. */
13281 /* We have allocated colors once, but Ghostscript has also
13282 allocated colors on behalf of us. So, to get the
13283 reference counts right, free them once. */
13284 if (img->ncolors)
3cf3436e 13285 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 13286 img->colors, img->ncolors, 0);
6fc2811b
JR
13287#endif
13288 }
13289 else
13290 image_error ("Cannot get X image of `%s'; colors will not be freed",
13291 img->spec, Qnil);
13292
13293 UNBLOCK_INPUT;
13294 }
3cf3436e
JR
13295
13296 /* Now that we have the pixmap, compute mask and transform the
13297 image if requested. */
13298 BLOCK_INPUT;
13299 postprocess_image (f, img);
13300 UNBLOCK_INPUT;
6fc2811b
JR
13301}
13302
13303#endif /* HAVE_GHOSTSCRIPT */
13304
13305\f
13306/***********************************************************************
13307 Window properties
13308 ***********************************************************************/
13309
13310DEFUN ("x-change-window-property", Fx_change_window_property,
13311 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
13312 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13313PROP and VALUE must be strings. FRAME nil or omitted means use the
13314selected frame. Value is VALUE. */)
6fc2811b
JR
13315 (prop, value, frame)
13316 Lisp_Object frame, prop, value;
13317{
767b1ff0 13318#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13319 struct frame *f = check_x_frame (frame);
13320 Atom prop_atom;
13321
b7826503
PJ
13322 CHECK_STRING (prop);
13323 CHECK_STRING (value);
6fc2811b
JR
13324
13325 BLOCK_INPUT;
13326 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13327 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13328 prop_atom, XA_STRING, 8, PropModeReplace,
13329 XSTRING (value)->data, XSTRING (value)->size);
13330
13331 /* Make sure the property is set when we return. */
13332 XFlush (FRAME_W32_DISPLAY (f));
13333 UNBLOCK_INPUT;
13334
767b1ff0 13335#endif /* TODO */
6fc2811b
JR
13336
13337 return value;
13338}
13339
13340
13341DEFUN ("x-delete-window-property", Fx_delete_window_property,
13342 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
13343 doc: /* Remove window property PROP from X window of FRAME.
13344FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
13345 (prop, frame)
13346 Lisp_Object prop, frame;
13347{
767b1ff0 13348#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13349
13350 struct frame *f = check_x_frame (frame);
13351 Atom prop_atom;
13352
b7826503 13353 CHECK_STRING (prop);
6fc2811b
JR
13354 BLOCK_INPUT;
13355 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13356 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13357
13358 /* Make sure the property is removed when we return. */
13359 XFlush (FRAME_W32_DISPLAY (f));
13360 UNBLOCK_INPUT;
767b1ff0 13361#endif /* TODO */
6fc2811b
JR
13362
13363 return prop;
13364}
13365
13366
13367DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13368 1, 2, 0,
74e1aeec
JR
13369 doc: /* Value is the value of window property PROP on FRAME.
13370If FRAME is nil or omitted, use the selected frame. Value is nil
13371if FRAME hasn't a property with name PROP or if PROP has no string
13372value. */)
6fc2811b
JR
13373 (prop, frame)
13374 Lisp_Object prop, frame;
13375{
767b1ff0 13376#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13377
13378 struct frame *f = check_x_frame (frame);
13379 Atom prop_atom;
13380 int rc;
13381 Lisp_Object prop_value = Qnil;
13382 char *tmp_data = NULL;
13383 Atom actual_type;
13384 int actual_format;
13385 unsigned long actual_size, bytes_remaining;
13386
b7826503 13387 CHECK_STRING (prop);
6fc2811b
JR
13388 BLOCK_INPUT;
13389 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13390 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13391 prop_atom, 0, 0, False, XA_STRING,
13392 &actual_type, &actual_format, &actual_size,
13393 &bytes_remaining, (unsigned char **) &tmp_data);
13394 if (rc == Success)
13395 {
13396 int size = bytes_remaining;
13397
13398 XFree (tmp_data);
13399 tmp_data = NULL;
13400
13401 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13402 prop_atom, 0, bytes_remaining,
13403 False, XA_STRING,
13404 &actual_type, &actual_format,
13405 &actual_size, &bytes_remaining,
13406 (unsigned char **) &tmp_data);
13407 if (rc == Success)
13408 prop_value = make_string (tmp_data, size);
13409
13410 XFree (tmp_data);
13411 }
13412
13413 UNBLOCK_INPUT;
13414
13415 return prop_value;
13416
767b1ff0 13417#endif /* TODO */
6fc2811b
JR
13418 return Qnil;
13419}
13420
13421
13422\f
13423/***********************************************************************
13424 Busy cursor
13425 ***********************************************************************/
13426
f79e6790 13427/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 13428 an hourglass cursor on all frames. */
6fc2811b 13429
0af913d7 13430static struct atimer *hourglass_atimer;
6fc2811b 13431
0af913d7 13432/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 13433
0af913d7 13434static int hourglass_shown_p;
6fc2811b 13435
0af913d7 13436/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 13437
0af913d7 13438static Lisp_Object Vhourglass_delay;
6fc2811b 13439
0af913d7 13440/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
13441 cursor. */
13442
0af913d7 13443#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
13444
13445/* Function prototypes. */
13446
0af913d7
GM
13447static void show_hourglass P_ ((struct atimer *));
13448static void hide_hourglass P_ ((void));
f79e6790
JR
13449
13450
0af913d7 13451/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
13452
13453void
0af913d7 13454start_hourglass ()
f79e6790 13455{
767b1ff0 13456#if 0 /* TODO: cursor shape changes. */
f79e6790 13457 EMACS_TIME delay;
dfff8a69 13458 int secs, usecs = 0;
f79e6790 13459
0af913d7 13460 cancel_hourglass ();
f79e6790 13461
0af913d7
GM
13462 if (INTEGERP (Vhourglass_delay)
13463 && XINT (Vhourglass_delay) > 0)
13464 secs = XFASTINT (Vhourglass_delay);
13465 else if (FLOATP (Vhourglass_delay)
13466 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
13467 {
13468 Lisp_Object tem;
0af913d7 13469 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 13470 secs = XFASTINT (tem);
0af913d7 13471 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 13472 }
f79e6790 13473 else
0af913d7 13474 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 13475
dfff8a69 13476 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
13477 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13478 show_hourglass, NULL);
f79e6790
JR
13479#endif
13480}
13481
13482
0af913d7
GM
13483/* Cancel the hourglass cursor timer if active, hide an hourglass
13484 cursor if shown. */
f79e6790
JR
13485
13486void
0af913d7 13487cancel_hourglass ()
f79e6790 13488{
0af913d7 13489 if (hourglass_atimer)
dfff8a69 13490 {
0af913d7
GM
13491 cancel_atimer (hourglass_atimer);
13492 hourglass_atimer = NULL;
dfff8a69
JR
13493 }
13494
0af913d7
GM
13495 if (hourglass_shown_p)
13496 hide_hourglass ();
f79e6790
JR
13497}
13498
13499
0af913d7
GM
13500/* Timer function of hourglass_atimer. TIMER is equal to
13501 hourglass_atimer.
f79e6790 13502
0af913d7
GM
13503 Display an hourglass cursor on all frames by mapping the frames'
13504 hourglass_window. Set the hourglass_p flag in the frames'
13505 output_data.x structure to indicate that an hourglass cursor is
13506 shown on the frames. */
f79e6790
JR
13507
13508static void
0af913d7 13509show_hourglass (timer)
f79e6790 13510 struct atimer *timer;
6fc2811b 13511{
767b1ff0 13512#if 0 /* TODO: cursor shape changes. */
f79e6790 13513 /* The timer implementation will cancel this timer automatically
0af913d7 13514 after this function has run. Set hourglass_atimer to null
f79e6790 13515 so that we know the timer doesn't have to be canceled. */
0af913d7 13516 hourglass_atimer = NULL;
f79e6790 13517
0af913d7 13518 if (!hourglass_shown_p)
6fc2811b
JR
13519 {
13520 Lisp_Object rest, frame;
f79e6790
JR
13521
13522 BLOCK_INPUT;
13523
6fc2811b 13524 FOR_EACH_FRAME (rest, frame)
dc220243 13525 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13526 {
13527 struct frame *f = XFRAME (frame);
f79e6790 13528
0af913d7 13529 f->output_data.w32->hourglass_p = 1;
f79e6790 13530
0af913d7 13531 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13532 {
13533 unsigned long mask = CWCursor;
13534 XSetWindowAttributes attrs;
f79e6790 13535
0af913d7 13536 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13537
0af913d7 13538 f->output_data.w32->hourglass_window
f79e6790 13539 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13540 FRAME_OUTER_WINDOW (f),
13541 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13542 InputOnly,
13543 CopyFromParent,
6fc2811b
JR
13544 mask, &attrs);
13545 }
f79e6790 13546
0af913d7
GM
13547 XMapRaised (FRAME_X_DISPLAY (f),
13548 f->output_data.w32->hourglass_window);
f79e6790 13549 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13550 }
6fc2811b 13551
0af913d7 13552 hourglass_shown_p = 1;
f79e6790
JR
13553 UNBLOCK_INPUT;
13554 }
13555#endif
6fc2811b
JR
13556}
13557
13558
0af913d7 13559/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13560
f79e6790 13561static void
0af913d7 13562hide_hourglass ()
f79e6790 13563{
767b1ff0 13564#if 0 /* TODO: cursor shape changes. */
0af913d7 13565 if (hourglass_shown_p)
6fc2811b 13566 {
f79e6790
JR
13567 Lisp_Object rest, frame;
13568
13569 BLOCK_INPUT;
13570 FOR_EACH_FRAME (rest, frame)
6fc2811b 13571 {
f79e6790
JR
13572 struct frame *f = XFRAME (frame);
13573
dc220243 13574 if (FRAME_W32_P (f)
f79e6790 13575 /* Watch out for newly created frames. */
0af913d7 13576 && f->output_data.x->hourglass_window)
f79e6790 13577 {
0af913d7
GM
13578 XUnmapWindow (FRAME_X_DISPLAY (f),
13579 f->output_data.x->hourglass_window);
13580 /* Sync here because XTread_socket looks at the
13581 hourglass_p flag that is reset to zero below. */
f79e6790 13582 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13583 f->output_data.x->hourglass_p = 0;
f79e6790 13584 }
6fc2811b 13585 }
6fc2811b 13586
0af913d7 13587 hourglass_shown_p = 0;
f79e6790
JR
13588 UNBLOCK_INPUT;
13589 }
13590#endif
6fc2811b
JR
13591}
13592
13593
13594\f
13595/***********************************************************************
13596 Tool tips
13597 ***********************************************************************/
13598
13599static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13600 Lisp_Object, Lisp_Object));
13601static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13602 Lisp_Object, int, int, int *, int *));
6fc2811b 13603
3cf3436e 13604/* The frame of a currently visible tooltip. */
6fc2811b 13605
937e601e 13606Lisp_Object tip_frame;
6fc2811b
JR
13607
13608/* If non-nil, a timer started that hides the last tooltip when it
13609 fires. */
13610
13611Lisp_Object tip_timer;
13612Window tip_window;
13613
3cf3436e
JR
13614/* If non-nil, a vector of 3 elements containing the last args
13615 with which x-show-tip was called. See there. */
13616
13617Lisp_Object last_show_tip_args;
13618
13619/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13620
13621Lisp_Object Vx_max_tooltip_size;
13622
13623
937e601e
AI
13624static Lisp_Object
13625unwind_create_tip_frame (frame)
13626 Lisp_Object frame;
13627{
c844a81a
GM
13628 Lisp_Object deleted;
13629
13630 deleted = unwind_create_frame (frame);
13631 if (EQ (deleted, Qt))
13632 {
13633 tip_window = NULL;
13634 tip_frame = Qnil;
13635 }
13636
13637 return deleted;
937e601e
AI
13638}
13639
13640
6fc2811b 13641/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13642 PARMS is a list of frame parameters. TEXT is the string to
13643 display in the tip frame. Value is the frame.
937e601e
AI
13644
13645 Note that functions called here, esp. x_default_parameter can
13646 signal errors, for instance when a specified color name is
13647 undefined. We have to make sure that we're in a consistent state
13648 when this happens. */
6fc2811b
JR
13649
13650static Lisp_Object
3cf3436e 13651x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13652 struct w32_display_info *dpyinfo;
3cf3436e 13653 Lisp_Object parms, text;
6fc2811b 13654{
6fc2811b
JR
13655 struct frame *f;
13656 Lisp_Object frame, tem;
13657 Lisp_Object name;
13658 long window_prompting = 0;
13659 int width, height;
331379bf 13660 int count = SPECPDL_INDEX ();
6fc2811b
JR
13661 struct gcpro gcpro1, gcpro2, gcpro3;
13662 struct kboard *kb;
3cf3436e
JR
13663 int face_change_count_before = face_change_count;
13664 Lisp_Object buffer;
13665 struct buffer *old_buffer;
6fc2811b 13666
ca56d953 13667 check_w32 ();
6fc2811b
JR
13668
13669 /* Use this general default value to start with until we know if
13670 this frame has a specified name. */
13671 Vx_resource_name = Vinvocation_name;
13672
13673#ifdef MULTI_KBOARD
13674 kb = dpyinfo->kboard;
13675#else
13676 kb = &the_only_kboard;
13677#endif
13678
13679 /* Get the name of the frame to use for resource lookup. */
13680 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13681 if (!STRINGP (name)
13682 && !EQ (name, Qunbound)
13683 && !NILP (name))
13684 error ("Invalid frame name--not a string or nil");
13685 Vx_resource_name = name;
13686
13687 frame = Qnil;
13688 GCPRO3 (parms, name, frame);
9eb16b62
JR
13689 /* Make a frame without minibuffer nor mode-line. */
13690 f = make_frame (0);
13691 f->wants_modeline = 0;
6fc2811b 13692 XSETFRAME (frame, f);
3cf3436e
JR
13693
13694 buffer = Fget_buffer_create (build_string (" *tip*"));
13695 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13696 old_buffer = current_buffer;
13697 set_buffer_internal_1 (XBUFFER (buffer));
13698 current_buffer->truncate_lines = Qnil;
13699 Ferase_buffer ();
13700 Finsert (1, &text);
13701 set_buffer_internal_1 (old_buffer);
13702
6fc2811b 13703 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13704 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13705
3cf3436e
JR
13706 /* By setting the output method, we're essentially saying that
13707 the frame is live, as per FRAME_LIVE_P. If we get a signal
13708 from this point on, x_destroy_window might screw up reference
13709 counts etc. */
d88c567c 13710 f->output_method = output_w32;
6fc2811b
JR
13711 f->output_data.w32 =
13712 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13713 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13714
13715 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13716 f->icon_name = Qnil;
13717
ca56d953 13718#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13719 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13720 dpyinfo_refcount = dpyinfo->reference_count;
13721#endif /* GLYPH_DEBUG */
6fc2811b
JR
13722#ifdef MULTI_KBOARD
13723 FRAME_KBOARD (f) = kb;
13724#endif
13725 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13726 f->output_data.w32->explicit_parent = 0;
13727
13728 /* Set the name; the functions to which we pass f expect the name to
13729 be set. */
13730 if (EQ (name, Qunbound) || NILP (name))
13731 {
ca56d953 13732 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13733 f->explicit_name = 0;
13734 }
13735 else
13736 {
13737 f->name = name;
13738 f->explicit_name = 1;
13739 /* use the frame's title when getting resources for this frame. */
13740 specbind (Qx_resource_name, name);
13741 }
13742
6fc2811b
JR
13743 /* Extract the window parameters from the supplied values
13744 that are needed to determine window geometry. */
13745 {
13746 Lisp_Object font;
13747
13748 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13749
13750 BLOCK_INPUT;
13751 /* First, try whatever font the caller has specified. */
13752 if (STRINGP (font))
13753 {
13754 tem = Fquery_fontset (font, Qnil);
13755 if (STRINGP (tem))
13756 font = x_new_fontset (f, XSTRING (tem)->data);
13757 else
13758 font = x_new_font (f, XSTRING (font)->data);
13759 }
13760
13761 /* Try out a font which we hope has bold and italic variations. */
13762 if (!STRINGP (font))
ca56d953 13763 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13764 if (! STRINGP (font))
ca56d953 13765 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13766 /* If those didn't work, look for something which will at least work. */
13767 if (! STRINGP (font))
ca56d953 13768 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13769 UNBLOCK_INPUT;
13770 if (! STRINGP (font))
ca56d953 13771 font = build_string ("Fixedsys");
6fc2811b
JR
13772
13773 x_default_parameter (f, parms, Qfont, font,
13774 "font", "Font", RES_TYPE_STRING);
13775 }
13776
13777 x_default_parameter (f, parms, Qborder_width, make_number (2),
13778 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13779 /* This defaults to 2 in order to match xterm. We recognize either
13780 internalBorderWidth or internalBorder (which is what xterm calls
13781 it). */
13782 if (NILP (Fassq (Qinternal_border_width, parms)))
13783 {
13784 Lisp_Object value;
13785
13786 value = w32_get_arg (parms, Qinternal_border_width,
13787 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13788 if (! EQ (value, Qunbound))
13789 parms = Fcons (Fcons (Qinternal_border_width, value),
13790 parms);
13791 }
bfd6edcc 13792 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13793 "internalBorderWidth", "internalBorderWidth",
13794 RES_TYPE_NUMBER);
13795
13796 /* Also do the stuff which must be set before the window exists. */
13797 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13798 "foreground", "Foreground", RES_TYPE_STRING);
13799 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13800 "background", "Background", RES_TYPE_STRING);
13801 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13802 "pointerColor", "Foreground", RES_TYPE_STRING);
13803 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13804 "cursorColor", "Foreground", RES_TYPE_STRING);
13805 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13806 "borderColor", "BorderColor", RES_TYPE_STRING);
13807
13808 /* Init faces before x_default_parameter is called for scroll-bar
13809 parameters because that function calls x_set_scroll_bar_width,
13810 which calls change_frame_size, which calls Fset_window_buffer,
13811 which runs hooks, which call Fvertical_motion. At the end, we
13812 end up in init_iterator with a null face cache, which should not
13813 happen. */
13814 init_frame_faces (f);
ca56d953
JR
13815
13816 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13817 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13818
6fc2811b
JR
13819 window_prompting = x_figure_window_size (f, parms);
13820
9eb16b62
JR
13821 /* No fringes on tip frame. */
13822 f->output_data.w32->fringes_extra = 0;
13823 f->output_data.w32->fringe_cols = 0;
13824 f->output_data.w32->left_fringe_width = 0;
13825 f->output_data.w32->right_fringe_width = 0;
13826
6fc2811b
JR
13827 if (window_prompting & XNegative)
13828 {
13829 if (window_prompting & YNegative)
13830 f->output_data.w32->win_gravity = SouthEastGravity;
13831 else
13832 f->output_data.w32->win_gravity = NorthEastGravity;
13833 }
13834 else
13835 {
13836 if (window_prompting & YNegative)
13837 f->output_data.w32->win_gravity = SouthWestGravity;
13838 else
13839 f->output_data.w32->win_gravity = NorthWestGravity;
13840 }
13841
13842 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13843
13844 BLOCK_INPUT;
13845 my_create_tip_window (f);
13846 UNBLOCK_INPUT;
6fc2811b
JR
13847
13848 x_make_gc (f);
13849
13850 x_default_parameter (f, parms, Qauto_raise, Qnil,
13851 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13852 x_default_parameter (f, parms, Qauto_lower, Qnil,
13853 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13854 x_default_parameter (f, parms, Qcursor_type, Qbox,
13855 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13856
13857 /* Dimensions, especially f->height, must be done via change_frame_size.
13858 Change will not be effected unless different from the current
13859 f->height. */
13860 width = f->width;
13861 height = f->height;
13862 f->height = 0;
13863 SET_FRAME_WIDTH (f, 0);
13864 change_frame_size (f, height, width, 1, 0, 0);
13865
3cf3436e
JR
13866 /* Set up faces after all frame parameters are known. This call
13867 also merges in face attributes specified for new frames.
13868
13869 Frame parameters may be changed if .Xdefaults contains
13870 specifications for the default font. For example, if there is an
13871 `Emacs.default.attributeBackground: pink', the `background-color'
13872 attribute of the frame get's set, which let's the internal border
13873 of the tooltip frame appear in pink. Prevent this. */
13874 {
13875 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13876
13877 /* Set tip_frame here, so that */
13878 tip_frame = frame;
13879 call1 (Qface_set_after_frame_default, frame);
13880
13881 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13882 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13883 Qnil));
13884 }
13885
6fc2811b
JR
13886 f->no_split = 1;
13887
13888 UNGCPRO;
13889
13890 /* It is now ok to make the frame official even if we get an error
13891 below. And the frame needs to be on Vframe_list or making it
13892 visible won't work. */
13893 Vframe_list = Fcons (frame, Vframe_list);
13894
13895 /* Now that the frame is official, it counts as a reference to
13896 its display. */
13897 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13898
3cf3436e
JR
13899 /* Setting attributes of faces of the tooltip frame from resources
13900 and similar will increment face_change_count, which leads to the
13901 clearing of all current matrices. Since this isn't necessary
13902 here, avoid it by resetting face_change_count to the value it
13903 had before we created the tip frame. */
13904 face_change_count = face_change_count_before;
13905
13906 /* Discard the unwind_protect. */
6fc2811b 13907 return unbind_to (count, frame);
ee78dc32
GV
13908}
13909
3cf3436e
JR
13910
13911/* Compute where to display tip frame F. PARMS is the list of frame
13912 parameters for F. DX and DY are specified offsets from the current
13913 location of the mouse. WIDTH and HEIGHT are the width and height
13914 of the tooltip. Return coordinates relative to the root window of
13915 the display in *ROOT_X, and *ROOT_Y. */
13916
13917static void
13918compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13919 struct frame *f;
13920 Lisp_Object parms, dx, dy;
13921 int width, height;
13922 int *root_x, *root_y;
13923{
3cf3436e 13924 Lisp_Object left, top;
3cf3436e
JR
13925
13926 /* User-specified position? */
13927 left = Fcdr (Fassq (Qleft, parms));
13928 top = Fcdr (Fassq (Qtop, parms));
13929
13930 /* Move the tooltip window where the mouse pointer is. Resize and
13931 show it. */
ca56d953 13932 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13933 {
ca56d953
JR
13934 POINT pt;
13935
3cf3436e 13936 BLOCK_INPUT;
ca56d953
JR
13937 GetCursorPos (&pt);
13938 *root_x = pt.x;
13939 *root_y = pt.y;
3cf3436e
JR
13940 UNBLOCK_INPUT;
13941 }
13942
13943 if (INTEGERP (top))
13944 *root_y = XINT (top);
13945 else if (*root_y + XINT (dy) - height < 0)
13946 *root_y -= XINT (dy);
13947 else
13948 {
13949 *root_y -= height;
13950 *root_y += XINT (dy);
13951 }
13952
13953 if (INTEGERP (left))
13954 *root_x = XINT (left);
72e4adef
JR
13955 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13956 /* It fits to the right of the pointer. */
13957 *root_x += XINT (dx);
13958 else if (width + XINT (dx) <= *root_x)
13959 /* It fits to the left of the pointer. */
3cf3436e
JR
13960 *root_x -= width + XINT (dx);
13961 else
72e4adef
JR
13962 /* Put it left justified on the screen -- it ought to fit that way. */
13963 *root_x = 0;
3cf3436e
JR
13964}
13965
13966
71eab8d1 13967DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13968 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13969A tooltip window is a small window displaying a string.
13970
13971FRAME nil or omitted means use the selected frame.
13972
13973PARMS is an optional list of frame parameters which can be
13974used to change the tooltip's appearance.
13975
ca56d953
JR
13976Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13977means use the default timeout of 5 seconds.
74e1aeec 13978
ca56d953 13979If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13980the tooltip is displayed at that x-position. Otherwise it is
13981displayed at the mouse position, with offset DX added (default is 5 if
13982DX isn't specified). Likewise for the y-position; if a `top' frame
13983parameter is specified, it determines the y-position of the tooltip
13984window, otherwise it is displayed at the mouse position, with offset
13985DY added (default is -10).
13986
13987A tooltip's maximum size is specified by `x-max-tooltip-size'.
13988Text larger than the specified size is clipped. */)
71eab8d1
AI
13989 (string, frame, parms, timeout, dx, dy)
13990 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13991{
6fc2811b
JR
13992 struct frame *f;
13993 struct window *w;
3cf3436e 13994 int root_x, root_y;
6fc2811b
JR
13995 struct buffer *old_buffer;
13996 struct text_pos pos;
13997 int i, width, height;
6fc2811b
JR
13998 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13999 int old_windows_or_buffers_changed = windows_or_buffers_changed;
331379bf 14000 int count = SPECPDL_INDEX ();
6fc2811b
JR
14001
14002 specbind (Qinhibit_redisplay, Qt);
ee78dc32 14003
dfff8a69 14004 GCPRO4 (string, parms, frame, timeout);
ee78dc32 14005
b7826503 14006 CHECK_STRING (string);
6fc2811b
JR
14007 f = check_x_frame (frame);
14008 if (NILP (timeout))
14009 timeout = make_number (5);
14010 else
b7826503 14011 CHECK_NATNUM (timeout);
ee78dc32 14012
71eab8d1
AI
14013 if (NILP (dx))
14014 dx = make_number (5);
14015 else
b7826503 14016 CHECK_NUMBER (dx);
71eab8d1
AI
14017
14018 if (NILP (dy))
dc220243 14019 dy = make_number (-10);
71eab8d1 14020 else
b7826503 14021 CHECK_NUMBER (dy);
71eab8d1 14022
dc220243
JR
14023 if (NILP (last_show_tip_args))
14024 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
14025
14026 if (!NILP (tip_frame))
14027 {
14028 Lisp_Object last_string = AREF (last_show_tip_args, 0);
14029 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
14030 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
14031
14032 if (EQ (frame, last_frame)
14033 && !NILP (Fequal (last_string, string))
14034 && !NILP (Fequal (last_parms, parms)))
14035 {
14036 struct frame *f = XFRAME (tip_frame);
14037
14038 /* Only DX and DY have changed. */
14039 if (!NILP (tip_timer))
14040 {
14041 Lisp_Object timer = tip_timer;
14042 tip_timer = Qnil;
14043 call1 (Qcancel_timer, timer);
14044 }
14045
14046 BLOCK_INPUT;
ca56d953
JR
14047 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
14048 PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
14049
14050 /* Put tooltip in topmost group and in position. */
ca56d953
JR
14051 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14052 root_x, root_y, 0, 0,
14053 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
14054
14055 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14056 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14057 0, 0, 0, 0,
14058 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14059
dc220243
JR
14060 UNBLOCK_INPUT;
14061 goto start_timer;
14062 }
14063 }
14064
6fc2811b
JR
14065 /* Hide a previous tip, if any. */
14066 Fx_hide_tip ();
ee78dc32 14067
dc220243
JR
14068 ASET (last_show_tip_args, 0, string);
14069 ASET (last_show_tip_args, 1, frame);
14070 ASET (last_show_tip_args, 2, parms);
14071
6fc2811b
JR
14072 /* Add default values to frame parameters. */
14073 if (NILP (Fassq (Qname, parms)))
14074 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14075 if (NILP (Fassq (Qinternal_border_width, parms)))
14076 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14077 if (NILP (Fassq (Qborder_width, parms)))
14078 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14079 if (NILP (Fassq (Qborder_color, parms)))
14080 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14081 if (NILP (Fassq (Qbackground_color, parms)))
14082 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14083 parms);
14084
0e3fcdef
JR
14085 /* Block input until the tip has been fully drawn, to avoid crashes
14086 when drawing tips in menus. */
14087 BLOCK_INPUT;
14088
6fc2811b
JR
14089 /* Create a frame for the tooltip, and record it in the global
14090 variable tip_frame. */
ca56d953 14091 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 14092 f = XFRAME (frame);
6fc2811b 14093
3cf3436e 14094 /* Set up the frame's root window. */
6fc2811b
JR
14095 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14096 w->left = w->top = make_number (0);
3cf3436e
JR
14097
14098 if (CONSP (Vx_max_tooltip_size)
14099 && INTEGERP (XCAR (Vx_max_tooltip_size))
14100 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14101 && INTEGERP (XCDR (Vx_max_tooltip_size))
14102 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14103 {
14104 w->width = XCAR (Vx_max_tooltip_size);
14105 w->height = XCDR (Vx_max_tooltip_size);
14106 }
14107 else
14108 {
14109 w->width = make_number (80);
14110 w->height = make_number (40);
14111 }
14112
14113 f->window_width = XINT (w->width);
6fc2811b
JR
14114 adjust_glyphs (f);
14115 w->pseudo_window_p = 1;
14116
14117 /* Display the tooltip text in a temporary buffer. */
6fc2811b 14118 old_buffer = current_buffer;
3cf3436e
JR
14119 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14120 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
14121 clear_glyph_matrix (w->desired_matrix);
14122 clear_glyph_matrix (w->current_matrix);
14123 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14124 try_window (FRAME_ROOT_WINDOW (f), pos);
14125
14126 /* Compute width and height of the tooltip. */
14127 width = height = 0;
14128 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 14129 {
6fc2811b
JR
14130 struct glyph_row *row = &w->desired_matrix->rows[i];
14131 struct glyph *last;
14132 int row_width;
14133
14134 /* Stop at the first empty row at the end. */
14135 if (!row->enabled_p || !row->displays_text_p)
14136 break;
14137
14138 /* Let the row go over the full width of the frame. */
14139 row->full_width_p = 1;
14140
4e3a1c61
JR
14141#ifdef TODO /* Investigate why some fonts need more width than is
14142 calculated for some tooltips. */
6fc2811b
JR
14143 /* There's a glyph at the end of rows that is use to place
14144 the cursor there. Don't include the width of this glyph. */
14145 if (row->used[TEXT_AREA])
14146 {
14147 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14148 row_width = row->pixel_width - last->pixel_width;
14149 }
14150 else
4e3a1c61 14151#endif
6fc2811b
JR
14152 row_width = row->pixel_width;
14153
ca56d953 14154 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 14155 height += row->height;
6fc2811b 14156 width = max (width, row_width);
ee78dc32
GV
14157 }
14158
6fc2811b
JR
14159 /* Add the frame's internal border to the width and height the X
14160 window should have. */
14161 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14162 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 14163
6fc2811b
JR
14164 /* Move the tooltip window where the mouse pointer is. Resize and
14165 show it. */
3cf3436e 14166 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 14167
bfd6edcc
JR
14168 {
14169 /* Adjust Window size to take border into account. */
14170 RECT rect;
14171 rect.left = rect.top = 0;
14172 rect.right = width;
14173 rect.bottom = height;
14174 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14175 FRAME_EXTERNAL_MENU_BAR (f));
14176
d65a9cdc 14177 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
14178 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14179 root_x, root_y, rect.right - rect.left,
14180 rect.bottom - rect.top, SWP_NOACTIVATE);
14181
d65a9cdc
JR
14182 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14183 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14184 0, 0, 0, 0,
14185 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14186
bfd6edcc
JR
14187 /* Let redisplay know that we have made the frame visible already. */
14188 f->async_visible = 1;
14189
14190 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14191 }
ee78dc32 14192
6fc2811b
JR
14193 /* Draw into the window. */
14194 w->must_be_updated_p = 1;
14195 update_single_window (w, 1);
ee78dc32 14196
0e3fcdef
JR
14197 UNBLOCK_INPUT;
14198
6fc2811b
JR
14199 /* Restore original current buffer. */
14200 set_buffer_internal_1 (old_buffer);
14201 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 14202
dc220243 14203 start_timer:
6fc2811b
JR
14204 /* Let the tip disappear after timeout seconds. */
14205 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14206 intern ("x-hide-tip"));
ee78dc32 14207
dfff8a69 14208 UNGCPRO;
6fc2811b 14209 return unbind_to (count, Qnil);
ee78dc32
GV
14210}
14211
ee78dc32 14212
6fc2811b 14213DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
14214 doc: /* Hide the current tooltip window, if there is any.
14215Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
14216 ()
14217{
937e601e
AI
14218 int count;
14219 Lisp_Object deleted, frame, timer;
14220 struct gcpro gcpro1, gcpro2;
14221
14222 /* Return quickly if nothing to do. */
14223 if (NILP (tip_timer) && NILP (tip_frame))
14224 return Qnil;
14225
14226 frame = tip_frame;
14227 timer = tip_timer;
14228 GCPRO2 (frame, timer);
14229 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 14230
331379bf 14231 count = SPECPDL_INDEX ();
6fc2811b 14232 specbind (Qinhibit_redisplay, Qt);
937e601e 14233 specbind (Qinhibit_quit, Qt);
6fc2811b 14234
937e601e 14235 if (!NILP (timer))
dc220243 14236 call1 (Qcancel_timer, timer);
ee78dc32 14237
937e601e 14238 if (FRAMEP (frame))
6fc2811b 14239 {
937e601e
AI
14240 Fdelete_frame (frame, Qnil);
14241 deleted = Qt;
6fc2811b 14242 }
1edf84e7 14243
937e601e
AI
14244 UNGCPRO;
14245 return unbind_to (count, deleted);
6fc2811b 14246}
5ac45f98 14247
5ac45f98 14248
6fc2811b
JR
14249\f
14250/***********************************************************************
14251 File selection dialog
14252 ***********************************************************************/
6fc2811b
JR
14253extern Lisp_Object Qfile_name_history;
14254
1030b26b
JR
14255/* Callback for altering the behaviour of the Open File dialog.
14256 Makes the Filename text field contain "Current Directory" and be
14257 read-only when "Directories" is selected in the filter. This
14258 allows us to work around the fact that the standard Open File
14259 dialog does not support directories. */
14260UINT CALLBACK
14261file_dialog_callback (hwnd, msg, wParam, lParam)
14262 HWND hwnd;
14263 UINT msg;
14264 WPARAM wParam;
14265 LPARAM lParam;
14266{
14267 if (msg == WM_NOTIFY)
14268 {
14269 OFNOTIFY * notify = (OFNOTIFY *)lParam;
14270 /* Detect when the Filter dropdown is changed. */
14271 if (notify->hdr.code == CDN_TYPECHANGE)
14272 {
14273 HWND dialog = GetParent (hwnd);
14274 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
14275
14276 /* Directories is in index 2. */
14277 if (notify->lpOFN->nFilterIndex == 2)
14278 {
14279 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14280 "Current Directory");
14281 EnableWindow (edit_control, FALSE);
14282 }
14283 else
14284 {
14285 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14286 "");
14287 EnableWindow (edit_control, TRUE);
14288 }
14289 }
14290 }
14291 return 0;
14292}
14293
6fc2811b 14294DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
14295 doc: /* Read file name, prompting with PROMPT in directory DIR.
14296Use a file selection dialog.
14297Select DEFAULT-FILENAME in the dialog's file selection box, if
14298specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
14299 (prompt, dir, default_filename, mustmatch)
14300 Lisp_Object prompt, dir, default_filename, mustmatch;
14301{
14302 struct frame *f = SELECTED_FRAME ();
14303 Lisp_Object file = Qnil;
14304 int count = specpdl_ptr - specpdl;
14305 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14306 char filename[MAX_PATH + 1];
14307 char init_dir[MAX_PATH + 1];
6fc2811b
JR
14308
14309 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
14310 CHECK_STRING (prompt);
14311 CHECK_STRING (dir);
6fc2811b
JR
14312
14313 /* Create the dialog with PROMPT as title, using DIR as initial
14314 directory and using "*" as pattern. */
14315 dir = Fexpand_file_name (dir, Qnil);
14316 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14317 init_dir[MAX_PATH] = '\0';
14318 unixtodos_filename (init_dir);
14319
14320 if (STRINGP (default_filename))
14321 {
14322 char *file_name_only;
14323 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 14324
6fc2811b 14325 unixtodos_filename (full_path_name);
5ac45f98 14326
6fc2811b
JR
14327 file_name_only = strrchr (full_path_name, '\\');
14328 if (!file_name_only)
14329 file_name_only = full_path_name;
14330 else
14331 {
14332 file_name_only++;
6fc2811b 14333 }
ee78dc32 14334
6fc2811b
JR
14335 strncpy (filename, file_name_only, MAX_PATH);
14336 filename[MAX_PATH] = '\0';
14337 }
ee78dc32 14338 else
6fc2811b 14339 filename[0] = '\0';
ee78dc32 14340
1030b26b
JR
14341 {
14342 OPENFILENAME file_details;
5ac45f98 14343
1030b26b
JR
14344 /* Prevent redisplay. */
14345 specbind (Qinhibit_redisplay, Qt);
14346 BLOCK_INPUT;
ee78dc32 14347
1030b26b
JR
14348 bzero (&file_details, sizeof (file_details));
14349 file_details.lStructSize = sizeof (file_details);
14350 file_details.hwndOwner = FRAME_W32_WINDOW (f);
14351 /* Undocumented Bug in Common File Dialog:
14352 If a filter is not specified, shell links are not resolved. */
14353 file_details.lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
14354 file_details.lpstrFile = filename;
14355 file_details.nMaxFile = sizeof (filename);
14356 file_details.lpstrInitialDir = init_dir;
14357 file_details.lpstrTitle = XSTRING (prompt)->data;
14358 file_details.Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
14359 | OFN_EXPLORER | OFN_ENABLEHOOK);
14360 if (!NILP (mustmatch))
14361 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
14362
14363 file_details.lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
14364
14365 if (GetOpenFileName (&file_details))
14366 {
14367 dostounix_filename (filename);
14368 if (file_details.nFilterIndex == 2)
14369 {
14370 /* "Folder Only" selected - strip dummy file name. */
14371 char * last = strrchr (filename, '/');
14372 *last = '\0';
14373 }
6fc2811b 14374
1030b26b
JR
14375 file = DECODE_FILE(build_string (filename));
14376 }
14377 /* User cancelled the dialog without making a selection. */
14378 else if (!CommDlgExtendedError ())
14379 file = Qnil;
14380 /* An error occurred, fallback on reading from the mini-buffer. */
14381 else
14382 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14383 dir, mustmatch, dir, Qfile_name_history,
14384 default_filename, Qnil);
14385
14386 UNBLOCK_INPUT;
14387 file = unbind_to (count, file);
14388 }
ee78dc32 14389
6fc2811b 14390 UNGCPRO;
1edf84e7 14391
6fc2811b
JR
14392 /* Make "Cancel" equivalent to C-g. */
14393 if (NILP (file))
14394 Fsignal (Qquit, Qnil);
ee78dc32 14395
dfff8a69 14396 return unbind_to (count, file);
6fc2811b 14397}
ee78dc32 14398
ee78dc32 14399
6fc2811b 14400\f
6fc2811b
JR
14401/***********************************************************************
14402 w32 specialized functions
14403 ***********************************************************************/
ee78dc32 14404
d84b082d 14405DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
14406 doc: /* Select a font using the W32 font dialog.
14407Returns an X font string corresponding to the selection. */)
d84b082d
JR
14408 (frame, include_proportional)
14409 Lisp_Object frame, include_proportional;
ee78dc32
GV
14410{
14411 FRAME_PTR f = check_x_frame (frame);
14412 CHOOSEFONT cf;
14413 LOGFONT lf;
f46e6225
GV
14414 TEXTMETRIC tm;
14415 HDC hdc;
14416 HANDLE oldobj;
ee78dc32
GV
14417 char buf[100];
14418
14419 bzero (&cf, sizeof (cf));
f46e6225 14420 bzero (&lf, sizeof (lf));
ee78dc32
GV
14421
14422 cf.lStructSize = sizeof (cf);
fbd6baed 14423 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
14424 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14425
14426 /* Unless include_proportional is non-nil, limit the selection to
14427 monospaced fonts. */
14428 if (NILP (include_proportional))
14429 cf.Flags |= CF_FIXEDPITCHONLY;
14430
ee78dc32
GV
14431 cf.lpLogFont = &lf;
14432
f46e6225
GV
14433 /* Initialize as much of the font details as we can from the current
14434 default font. */
14435 hdc = GetDC (FRAME_W32_WINDOW (f));
14436 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14437 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14438 if (GetTextMetrics (hdc, &tm))
14439 {
14440 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14441 lf.lfWeight = tm.tmWeight;
14442 lf.lfItalic = tm.tmItalic;
14443 lf.lfUnderline = tm.tmUnderlined;
14444 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
14445 lf.lfCharSet = tm.tmCharSet;
14446 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14447 }
14448 SelectObject (hdc, oldobj);
6fc2811b 14449 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 14450
767b1ff0 14451 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 14452 return Qnil;
ee78dc32
GV
14453
14454 return build_string (buf);
14455}
14456
74e1aeec
JR
14457DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14458 Sw32_send_sys_command, 1, 2, 0,
14459 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
14460Some useful values for command are #xf030 to maximise frame (#xf020
14461to minimize), #xf120 to restore frame to original size, and #xf100
14462to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
14463screen saver if defined.
14464
14465If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
14466 (command, frame)
14467 Lisp_Object command, frame;
14468{
1edf84e7
GV
14469 FRAME_PTR f = check_x_frame (frame);
14470
b7826503 14471 CHECK_NUMBER (command);
1edf84e7 14472
ce6059da 14473 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
14474
14475 return Qnil;
14476}
14477
55dcfc15 14478DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
14479 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14480This is a wrapper around the ShellExecute system function, which
14481invokes the application registered to handle OPERATION for DOCUMENT.
14482OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14483nil for the default action), and DOCUMENT is typically the name of a
14484document file or URL, but can also be a program executable to run or
14485a directory to open in the Windows Explorer.
14486
14487If DOCUMENT is a program executable, PARAMETERS can be a string
14488containing command line parameters, but otherwise should be nil.
14489
14490SHOW-FLAG can be used to control whether the invoked application is hidden
14491or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14492otherwise it is an integer representing a ShowWindow flag:
14493
14494 0 - start hidden
14495 1 - start normally
14496 3 - start maximized
14497 6 - start minimized */)
55dcfc15
AI
14498 (operation, document, parameters, show_flag)
14499 Lisp_Object operation, document, parameters, show_flag;
14500{
14501 Lisp_Object current_dir;
14502
b7826503 14503 CHECK_STRING (document);
55dcfc15
AI
14504
14505 /* Encode filename and current directory. */
14506 current_dir = ENCODE_FILE (current_buffer->directory);
14507 document = ENCODE_FILE (document);
14508 if ((int) ShellExecute (NULL,
6fc2811b
JR
14509 (STRINGP (operation) ?
14510 XSTRING (operation)->data : NULL),
55dcfc15
AI
14511 XSTRING (document)->data,
14512 (STRINGP (parameters) ?
14513 XSTRING (parameters)->data : NULL),
14514 XSTRING (current_dir)->data,
14515 (INTEGERP (show_flag) ?
14516 XINT (show_flag) : SW_SHOWDEFAULT))
14517 > 32)
14518 return Qt;
90d97e64 14519 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
14520}
14521
ccc2d29c
GV
14522/* Lookup virtual keycode from string representing the name of a
14523 non-ascii keystroke into the corresponding virtual key, using
14524 lispy_function_keys. */
14525static int
14526lookup_vk_code (char *key)
14527{
14528 int i;
14529
14530 for (i = 0; i < 256; i++)
14531 if (lispy_function_keys[i] != 0
14532 && strcmp (lispy_function_keys[i], key) == 0)
14533 return i;
14534
14535 return -1;
14536}
14537
14538/* Convert a one-element vector style key sequence to a hot key
14539 definition. */
14540static int
14541w32_parse_hot_key (key)
14542 Lisp_Object key;
14543{
14544 /* Copied from Fdefine_key and store_in_keymap. */
14545 register Lisp_Object c;
14546 int vk_code;
14547 int lisp_modifiers;
14548 int w32_modifiers;
14549 struct gcpro gcpro1;
14550
b7826503 14551 CHECK_VECTOR (key);
ccc2d29c
GV
14552
14553 if (XFASTINT (Flength (key)) != 1)
14554 return Qnil;
14555
14556 GCPRO1 (key);
14557
14558 c = Faref (key, make_number (0));
14559
14560 if (CONSP (c) && lucid_event_type_list_p (c))
14561 c = Fevent_convert_list (c);
14562
14563 UNGCPRO;
14564
14565 if (! INTEGERP (c) && ! SYMBOLP (c))
14566 error ("Key definition is invalid");
14567
14568 /* Work out the base key and the modifiers. */
14569 if (SYMBOLP (c))
14570 {
14571 c = parse_modifiers (c);
14572 lisp_modifiers = Fcar (Fcdr (c));
14573 c = Fcar (c);
14574 if (!SYMBOLP (c))
14575 abort ();
38b76195 14576 vk_code = lookup_vk_code (XSTRING (SYMBOL_NAME (c))->data);
ccc2d29c
GV
14577 }
14578 else if (INTEGERP (c))
14579 {
14580 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14581 /* Many ascii characters are their own virtual key code. */
14582 vk_code = XINT (c) & CHARACTERBITS;
14583 }
14584
14585 if (vk_code < 0 || vk_code > 255)
14586 return Qnil;
14587
14588 if ((lisp_modifiers & meta_modifier) != 0
14589 && !NILP (Vw32_alt_is_meta))
14590 lisp_modifiers |= alt_modifier;
14591
71eab8d1
AI
14592 /* Supply defs missing from mingw32. */
14593#ifndef MOD_ALT
14594#define MOD_ALT 0x0001
14595#define MOD_CONTROL 0x0002
14596#define MOD_SHIFT 0x0004
14597#define MOD_WIN 0x0008
14598#endif
14599
ccc2d29c
GV
14600 /* Convert lisp modifiers to Windows hot-key form. */
14601 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14602 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14603 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14604 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14605
14606 return HOTKEY (vk_code, w32_modifiers);
14607}
14608
74e1aeec
JR
14609DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14610 Sw32_register_hot_key, 1, 1, 0,
14611 doc: /* Register KEY as a hot-key combination.
14612Certain key combinations like Alt-Tab are reserved for system use on
14613Windows, and therefore are normally intercepted by the system. However,
14614most of these key combinations can be received by registering them as
14615hot-keys, overriding their special meaning.
14616
14617KEY must be a one element key definition in vector form that would be
14618acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14619modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14620is always interpreted as the Windows modifier keys.
14621
14622The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14623 (key)
14624 Lisp_Object key;
14625{
14626 key = w32_parse_hot_key (key);
14627
14628 if (NILP (Fmemq (key, w32_grabbed_keys)))
14629 {
14630 /* Reuse an empty slot if possible. */
14631 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14632
14633 /* Safe to add new key to list, even if we have focus. */
14634 if (NILP (item))
14635 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14636 else
f3fbd155 14637 XSETCAR (item, key);
ccc2d29c
GV
14638
14639 /* Notify input thread about new hot-key definition, so that it
14640 takes effect without needing to switch focus. */
14641 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14642 (WPARAM) key, 0);
14643 }
14644
14645 return key;
14646}
14647
74e1aeec
JR
14648DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14649 Sw32_unregister_hot_key, 1, 1, 0,
14650 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14651 (key)
14652 Lisp_Object key;
14653{
14654 Lisp_Object item;
14655
14656 if (!INTEGERP (key))
14657 key = w32_parse_hot_key (key);
14658
14659 item = Fmemq (key, w32_grabbed_keys);
14660
14661 if (!NILP (item))
14662 {
14663 /* Notify input thread about hot-key definition being removed, so
14664 that it takes effect without needing focus switch. */
14665 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14666 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14667 {
14668 MSG msg;
14669 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14670 }
14671 return Qt;
14672 }
14673 return Qnil;
14674}
14675
74e1aeec
JR
14676DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14677 Sw32_registered_hot_keys, 0, 0, 0,
14678 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14679 ()
14680{
14681 return Fcopy_sequence (w32_grabbed_keys);
14682}
14683
74e1aeec
JR
14684DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14685 Sw32_reconstruct_hot_key, 1, 1, 0,
14686 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14687 (hotkeyid)
14688 Lisp_Object hotkeyid;
14689{
14690 int vk_code, w32_modifiers;
14691 Lisp_Object key;
14692
b7826503 14693 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14694
14695 vk_code = HOTKEY_VK_CODE (hotkeyid);
14696 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14697
14698 if (lispy_function_keys[vk_code])
14699 key = intern (lispy_function_keys[vk_code]);
14700 else
14701 key = make_number (vk_code);
14702
14703 key = Fcons (key, Qnil);
14704 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14705 key = Fcons (Qshift, key);
ccc2d29c 14706 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14707 key = Fcons (Qctrl, key);
ccc2d29c 14708 if (w32_modifiers & MOD_ALT)
3ef68e6b 14709 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14710 if (w32_modifiers & MOD_WIN)
3ef68e6b 14711 key = Fcons (Qhyper, key);
ccc2d29c
GV
14712
14713 return key;
14714}
adcc3809 14715
74e1aeec
JR
14716DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14717 Sw32_toggle_lock_key, 1, 2, 0,
14718 doc: /* Toggle the state of the lock key KEY.
14719KEY can be `capslock', `kp-numlock', or `scroll'.
14720If the optional parameter NEW-STATE is a number, then the state of KEY
14721is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14722 (key, new_state)
14723 Lisp_Object key, new_state;
14724{
14725 int vk_code;
adcc3809
GV
14726
14727 if (EQ (key, intern ("capslock")))
14728 vk_code = VK_CAPITAL;
14729 else if (EQ (key, intern ("kp-numlock")))
14730 vk_code = VK_NUMLOCK;
14731 else if (EQ (key, intern ("scroll")))
14732 vk_code = VK_SCROLL;
14733 else
14734 return Qnil;
14735
14736 if (!dwWindowsThreadId)
14737 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14738
14739 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14740 (WPARAM) vk_code, (LPARAM) new_state))
14741 {
14742 MSG msg;
14743 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14744 return make_number (msg.wParam);
14745 }
14746 return Qnil;
14747}
ee78dc32 14748\f
2254bcde 14749DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14750 doc: /* Return storage information about the file system FILENAME is on.
14751Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14752storage of the file system, FREE is the free storage, and AVAIL is the
14753storage available to a non-superuser. All 3 numbers are in bytes.
14754If the underlying system call fails, value is nil. */)
2254bcde
AI
14755 (filename)
14756 Lisp_Object filename;
14757{
14758 Lisp_Object encoded, value;
14759
b7826503 14760 CHECK_STRING (filename);
2254bcde
AI
14761 filename = Fexpand_file_name (filename, Qnil);
14762 encoded = ENCODE_FILE (filename);
14763
14764 value = Qnil;
14765
14766 /* Determining the required information on Windows turns out, sadly,
14767 to be more involved than one would hope. The original Win32 api
14768 call for this will return bogus information on some systems, but we
14769 must dynamically probe for the replacement api, since that was
14770 added rather late on. */
14771 {
14772 HMODULE hKernel = GetModuleHandle ("kernel32");
14773 BOOL (*pfn_GetDiskFreeSpaceEx)
14774 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14775 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14776
14777 /* On Windows, we may need to specify the root directory of the
14778 volume holding FILENAME. */
14779 char rootname[MAX_PATH];
14780 char *name = XSTRING (encoded)->data;
14781
14782 /* find the root name of the volume if given */
14783 if (isalpha (name[0]) && name[1] == ':')
14784 {
14785 rootname[0] = name[0];
14786 rootname[1] = name[1];
14787 rootname[2] = '\\';
14788 rootname[3] = 0;
14789 }
14790 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14791 {
14792 char *str = rootname;
14793 int slashes = 4;
14794 do
14795 {
14796 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14797 break;
14798 *str++ = *name++;
14799 }
14800 while ( *name );
14801
14802 *str++ = '\\';
14803 *str = 0;
14804 }
14805
14806 if (pfn_GetDiskFreeSpaceEx)
14807 {
ac849ba4
JR
14808 /* Unsigned large integers cannot be cast to double, so
14809 use signed ones instead. */
2254bcde
AI
14810 LARGE_INTEGER availbytes;
14811 LARGE_INTEGER freebytes;
14812 LARGE_INTEGER totalbytes;
14813
14814 if (pfn_GetDiskFreeSpaceEx(rootname,
ac849ba4
JR
14815 (ULARGE_INTEGER *)&availbytes,
14816 (ULARGE_INTEGER *)&totalbytes,
14817 (ULARGE_INTEGER *)&freebytes))
2254bcde
AI
14818 value = list3 (make_float ((double) totalbytes.QuadPart),
14819 make_float ((double) freebytes.QuadPart),
14820 make_float ((double) availbytes.QuadPart));
14821 }
14822 else
14823 {
14824 DWORD sectors_per_cluster;
14825 DWORD bytes_per_sector;
14826 DWORD free_clusters;
14827 DWORD total_clusters;
14828
14829 if (GetDiskFreeSpace(rootname,
14830 &sectors_per_cluster,
14831 &bytes_per_sector,
14832 &free_clusters,
14833 &total_clusters))
14834 value = list3 (make_float ((double) total_clusters
14835 * sectors_per_cluster * bytes_per_sector),
14836 make_float ((double) free_clusters
14837 * sectors_per_cluster * bytes_per_sector),
14838 make_float ((double) free_clusters
14839 * sectors_per_cluster * bytes_per_sector));
14840 }
14841 }
14842
14843 return value;
14844}
14845\f
0e3fcdef
JR
14846/***********************************************************************
14847 Initialization
14848 ***********************************************************************/
14849
14850void
fbd6baed 14851syms_of_w32fns ()
ee78dc32 14852{
9eb16b62
JR
14853 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14854
1edf84e7
GV
14855 /* This is zero if not using MS-Windows. */
14856 w32_in_use = 0;
14857
9eb16b62
JR
14858 /* TrackMouseEvent not available in all versions of Windows, so must load
14859 it dynamically. Do it once, here, instead of every time it is used. */
14860 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14861 track_mouse_window = NULL;
14862
d285988b
JR
14863 w32_visible_system_caret_hwnd = NULL;
14864
ee78dc32
GV
14865 Qauto_raise = intern ("auto-raise");
14866 staticpro (&Qauto_raise);
14867 Qauto_lower = intern ("auto-lower");
14868 staticpro (&Qauto_lower);
ee78dc32
GV
14869 Qbar = intern ("bar");
14870 staticpro (&Qbar);
23afac8f
JR
14871 Qhbar = intern ("hbar");
14872 staticpro (&Qhbar);
ee78dc32
GV
14873 Qborder_color = intern ("border-color");
14874 staticpro (&Qborder_color);
14875 Qborder_width = intern ("border-width");
14876 staticpro (&Qborder_width);
14877 Qbox = intern ("box");
14878 staticpro (&Qbox);
14879 Qcursor_color = intern ("cursor-color");
14880 staticpro (&Qcursor_color);
14881 Qcursor_type = intern ("cursor-type");
14882 staticpro (&Qcursor_type);
ee78dc32
GV
14883 Qgeometry = intern ("geometry");
14884 staticpro (&Qgeometry);
14885 Qicon_left = intern ("icon-left");
14886 staticpro (&Qicon_left);
14887 Qicon_top = intern ("icon-top");
14888 staticpro (&Qicon_top);
14889 Qicon_type = intern ("icon-type");
14890 staticpro (&Qicon_type);
14891 Qicon_name = intern ("icon-name");
14892 staticpro (&Qicon_name);
14893 Qinternal_border_width = intern ("internal-border-width");
14894 staticpro (&Qinternal_border_width);
14895 Qleft = intern ("left");
14896 staticpro (&Qleft);
1026b400
RS
14897 Qright = intern ("right");
14898 staticpro (&Qright);
ee78dc32
GV
14899 Qmouse_color = intern ("mouse-color");
14900 staticpro (&Qmouse_color);
14901 Qnone = intern ("none");
14902 staticpro (&Qnone);
14903 Qparent_id = intern ("parent-id");
14904 staticpro (&Qparent_id);
14905 Qscroll_bar_width = intern ("scroll-bar-width");
14906 staticpro (&Qscroll_bar_width);
14907 Qsuppress_icon = intern ("suppress-icon");
14908 staticpro (&Qsuppress_icon);
ee78dc32
GV
14909 Qundefined_color = intern ("undefined-color");
14910 staticpro (&Qundefined_color);
14911 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14912 staticpro (&Qvertical_scroll_bars);
14913 Qvisibility = intern ("visibility");
14914 staticpro (&Qvisibility);
14915 Qwindow_id = intern ("window-id");
14916 staticpro (&Qwindow_id);
14917 Qx_frame_parameter = intern ("x-frame-parameter");
14918 staticpro (&Qx_frame_parameter);
14919 Qx_resource_name = intern ("x-resource-name");
14920 staticpro (&Qx_resource_name);
14921 Quser_position = intern ("user-position");
14922 staticpro (&Quser_position);
14923 Quser_size = intern ("user-size");
14924 staticpro (&Quser_size);
6fc2811b
JR
14925 Qscreen_gamma = intern ("screen-gamma");
14926 staticpro (&Qscreen_gamma);
dfff8a69
JR
14927 Qline_spacing = intern ("line-spacing");
14928 staticpro (&Qline_spacing);
14929 Qcenter = intern ("center");
14930 staticpro (&Qcenter);
dc220243
JR
14931 Qcancel_timer = intern ("cancel-timer");
14932 staticpro (&Qcancel_timer);
f7b9d4d1
JR
14933 Qfullscreen = intern ("fullscreen");
14934 staticpro (&Qfullscreen);
14935 Qfullwidth = intern ("fullwidth");
14936 staticpro (&Qfullwidth);
14937 Qfullheight = intern ("fullheight");
14938 staticpro (&Qfullheight);
14939 Qfullboth = intern ("fullboth");
14940 staticpro (&Qfullboth);
ee78dc32 14941
adcc3809
GV
14942 Qhyper = intern ("hyper");
14943 staticpro (&Qhyper);
14944 Qsuper = intern ("super");
14945 staticpro (&Qsuper);
14946 Qmeta = intern ("meta");
14947 staticpro (&Qmeta);
14948 Qalt = intern ("alt");
14949 staticpro (&Qalt);
14950 Qctrl = intern ("ctrl");
14951 staticpro (&Qctrl);
14952 Qcontrol = intern ("control");
14953 staticpro (&Qcontrol);
14954 Qshift = intern ("shift");
14955 staticpro (&Qshift);
f7b9d4d1 14956 /* This is the end of symbol initialization. */
adcc3809 14957
6fc2811b
JR
14958 /* Text property `display' should be nonsticky by default. */
14959 Vtext_property_default_nonsticky
14960 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14961
14962
14963 Qlaplace = intern ("laplace");
14964 staticpro (&Qlaplace);
3cf3436e
JR
14965 Qemboss = intern ("emboss");
14966 staticpro (&Qemboss);
14967 Qedge_detection = intern ("edge-detection");
14968 staticpro (&Qedge_detection);
14969 Qheuristic = intern ("heuristic");
14970 staticpro (&Qheuristic);
14971 QCmatrix = intern (":matrix");
14972 staticpro (&QCmatrix);
14973 QCcolor_adjustment = intern (":color-adjustment");
14974 staticpro (&QCcolor_adjustment);
14975 QCmask = intern (":mask");
14976 staticpro (&QCmask);
6fc2811b 14977
4b817373
RS
14978 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14979 staticpro (&Qface_set_after_frame_default);
14980
ee78dc32
GV
14981 Fput (Qundefined_color, Qerror_conditions,
14982 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14983 Fput (Qundefined_color, Qerror_message,
14984 build_string ("Undefined color"));
14985
ccc2d29c
GV
14986 staticpro (&w32_grabbed_keys);
14987 w32_grabbed_keys = Qnil;
14988
fbd6baed 14989 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14990 doc: /* An array of color name mappings for windows. */);
fbd6baed 14991 Vw32_color_map = Qnil;
ee78dc32 14992
fbd6baed 14993 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14994 doc: /* Non-nil if alt key presses are passed on to Windows.
14995When non-nil, for example, alt pressed and released and then space will
14996open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14997 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14998
fbd6baed 14999 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
15000 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
15001When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 15002 Vw32_alt_is_meta = Qt;
8c205c63 15003
7d081355 15004 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 15005 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
15006 XSETINT (Vw32_quit_key, 0);
15007
ccc2d29c
GV
15008 DEFVAR_LISP ("w32-pass-lwindow-to-system",
15009 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
15010 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
15011When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
15012 Vw32_pass_lwindow_to_system = Qt;
15013
15014 DEFVAR_LISP ("w32-pass-rwindow-to-system",
15015 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
15016 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
15017When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
15018 Vw32_pass_rwindow_to_system = Qt;
15019
adcc3809
GV
15020 DEFVAR_INT ("w32-phantom-key-code",
15021 &Vw32_phantom_key_code,
74e1aeec
JR
15022 doc: /* Virtual key code used to generate \"phantom\" key presses.
15023Value is a number between 0 and 255.
15024
15025Phantom key presses are generated in order to stop the system from
15026acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
15027`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
15028 /* Although 255 is technically not a valid key code, it works and
15029 means that this hack won't interfere with any real key code. */
15030 Vw32_phantom_key_code = 255;
adcc3809 15031
ccc2d29c
GV
15032 DEFVAR_LISP ("w32-enable-num-lock",
15033 &Vw32_enable_num_lock,
74e1aeec
JR
15034 doc: /* Non-nil if Num Lock should act normally.
15035Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
15036 Vw32_enable_num_lock = Qt;
15037
15038 DEFVAR_LISP ("w32-enable-caps-lock",
15039 &Vw32_enable_caps_lock,
74e1aeec
JR
15040 doc: /* Non-nil if Caps Lock should act normally.
15041Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
15042 Vw32_enable_caps_lock = Qt;
15043
15044 DEFVAR_LISP ("w32-scroll-lock-modifier",
15045 &Vw32_scroll_lock_modifier,
74e1aeec
JR
15046 doc: /* Modifier to use for the Scroll Lock on state.
15047The value can be hyper, super, meta, alt, control or shift for the
15048respective modifier, or nil to see Scroll Lock as the key `scroll'.
15049Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15050 Vw32_scroll_lock_modifier = Qt;
15051
15052 DEFVAR_LISP ("w32-lwindow-modifier",
15053 &Vw32_lwindow_modifier,
74e1aeec
JR
15054 doc: /* Modifier to use for the left \"Windows\" key.
15055The value can be hyper, super, meta, alt, control or shift for the
15056respective modifier, or nil to appear as the key `lwindow'.
15057Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15058 Vw32_lwindow_modifier = Qnil;
15059
15060 DEFVAR_LISP ("w32-rwindow-modifier",
15061 &Vw32_rwindow_modifier,
74e1aeec
JR
15062 doc: /* Modifier to use for the right \"Windows\" key.
15063The value can be hyper, super, meta, alt, control or shift for the
15064respective modifier, or nil to appear as the key `rwindow'.
15065Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15066 Vw32_rwindow_modifier = Qnil;
15067
15068 DEFVAR_LISP ("w32-apps-modifier",
15069 &Vw32_apps_modifier,
74e1aeec
JR
15070 doc: /* Modifier to use for the \"Apps\" key.
15071The value can be hyper, super, meta, alt, control or shift for the
15072respective modifier, or nil to appear as the key `apps'.
15073Any other value will cause the key to be ignored. */);
ccc2d29c 15074 Vw32_apps_modifier = Qnil;
da36a4d6 15075
d84b082d 15076 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 15077 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 15078 w32_enable_synthesized_fonts = 0;
5ac45f98 15079
fbd6baed 15080 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 15081 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 15082 Vw32_enable_palette = Qt;
5ac45f98 15083
fbd6baed
GV
15084 DEFVAR_INT ("w32-mouse-button-tolerance",
15085 &Vw32_mouse_button_tolerance,
74e1aeec
JR
15086 doc: /* Analogue of double click interval for faking middle mouse events.
15087The value is the minimum time in milliseconds that must elapse between
15088left/right button down events before they are considered distinct events.
15089If both mouse buttons are depressed within this interval, a middle mouse
15090button down event is generated instead. */);
fbd6baed 15091 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 15092
fbd6baed
GV
15093 DEFVAR_INT ("w32-mouse-move-interval",
15094 &Vw32_mouse_move_interval,
74e1aeec
JR
15095 doc: /* Minimum interval between mouse move events.
15096The value is the minimum time in milliseconds that must elapse between
15097successive mouse move (or scroll bar drag) events before they are
15098reported as lisp events. */);
247be837 15099 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 15100
74214547
JR
15101 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
15102 &w32_pass_extra_mouse_buttons_to_system,
15103 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
15104Recent versions of Windows support mice with up to five buttons.
15105Since most applications don't support these extra buttons, most mouse
15106drivers will allow you to map them to functions at the system level.
15107If this variable is non-nil, Emacs will pass them on, allowing the
15108system to handle them. */);
15109 w32_pass_extra_mouse_buttons_to_system = 0;
15110
ee78dc32
GV
15111 init_x_parm_symbols ();
15112
15113 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 15114 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
15115 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15116
15117 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
15118 doc: /* The shape of the pointer when over text.
15119Changing the value does not affect existing frames
15120unless you set the mouse color. */);
ee78dc32
GV
15121 Vx_pointer_shape = Qnil;
15122
15123 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
15124 doc: /* The name Emacs uses to look up resources; for internal use only.
15125`x-get-resource' uses this as the first component of the instance name
15126when requesting resource values.
15127Emacs initially sets `x-resource-name' to the name under which Emacs
15128was invoked, or to the value specified with the `-name' or `-rn'
15129switches, if present. */);
ee78dc32
GV
15130 Vx_resource_name = Qnil;
15131
15132 Vx_nontext_pointer_shape = Qnil;
15133
15134 Vx_mode_pointer_shape = Qnil;
15135
0af913d7 15136 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
15137 doc: /* The shape of the pointer when Emacs is busy.
15138This variable takes effect when you create a new frame
15139or when you set the mouse color. */);
0af913d7 15140 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 15141
0af913d7 15142 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 15143 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 15144 display_hourglass_p = 1;
6fc2811b 15145
0af913d7 15146 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
15147 doc: /* *Seconds to wait before displaying an hourglass pointer.
15148Value must be an integer or float. */);
0af913d7 15149 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 15150
6fc2811b 15151 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 15152 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
15153 doc: /* The shape of the pointer when over mouse-sensitive text.
15154This variable takes effect when you create a new frame
15155or when you set the mouse color. */);
ee78dc32
GV
15156 Vx_sensitive_text_pointer_shape = Qnil;
15157
4694d762
JR
15158 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15159 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
15160 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15161This variable takes effect when you create a new frame
15162or when you set the mouse color. */);
4694d762
JR
15163 Vx_window_horizontal_drag_shape = Qnil;
15164
ee78dc32 15165 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 15166 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
15167 Vx_cursor_fore_pixel = Qnil;
15168
3cf3436e 15169 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
15170 doc: /* Maximum size for tooltips.
15171Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
15172 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
15173
ee78dc32 15174 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
15175 doc: /* Non-nil if no window manager is in use.
15176Emacs doesn't try to figure this out; this is always nil
15177unless you set it to something else. */);
ee78dc32
GV
15178 /* We don't have any way to find this out, so set it to nil
15179 and maybe the user would like to set it to t. */
15180 Vx_no_window_manager = Qnil;
15181
4587b026
GV
15182 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15183 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
15184 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15185
15186Since Emacs gets width of a font matching with this regexp from
15187PIXEL_SIZE field of the name, font finding mechanism gets faster for
15188such a font. This is especially effective for such large fonts as
15189Chinese, Japanese, and Korean. */);
4587b026
GV
15190 Vx_pixel_size_width_font_regexp = Qnil;
15191
6fc2811b 15192 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
15193 doc: /* Time after which cached images are removed from the cache.
15194When an image has not been displayed this many seconds, remove it
15195from the image cache. Value must be an integer or nil with nil
15196meaning don't clear the cache. */);
6fc2811b
JR
15197 Vimage_cache_eviction_delay = make_number (30 * 60);
15198
33d52f9c
GV
15199 DEFVAR_LISP ("w32-bdf-filename-alist",
15200 &Vw32_bdf_filename_alist,
74e1aeec 15201 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
15202 Vw32_bdf_filename_alist = Qnil;
15203
1075afa9
GV
15204 DEFVAR_BOOL ("w32-strict-fontnames",
15205 &w32_strict_fontnames,
74e1aeec
JR
15206 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15207Default is nil, which allows old fontnames that are not XLFD compliant,
15208and allows third-party CJK display to work by specifying false charset
15209fields to trick Emacs into translating to Big5, SJIS etc.
15210Setting this to t will prevent wrong fonts being selected when
15211fontsets are automatically created. */);
1075afa9
GV
15212 w32_strict_fontnames = 0;
15213
c0611964
AI
15214 DEFVAR_BOOL ("w32-strict-painting",
15215 &w32_strict_painting,
74e1aeec
JR
15216 doc: /* Non-nil means use strict rules for repainting frames.
15217Set this to nil to get the old behaviour for repainting; this should
15218only be necessary if the default setting causes problems. */);
c0611964
AI
15219 w32_strict_painting = 1;
15220
dfff8a69
JR
15221 DEFVAR_LISP ("w32-charset-info-alist",
15222 &Vw32_charset_info_alist,
b3700ae7
JR
15223 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15224Each entry should be of the form:
74e1aeec
JR
15225
15226 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15227
15228where CHARSET_NAME is a string used in font names to identify the charset,
15229WINDOWS_CHARSET is a symbol that can be one of:
15230w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15231w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15232w32-charset-chinesebig5,
dfff8a69 15233#ifdef JOHAB_CHARSET
74e1aeec
JR
15234w32-charset-johab, w32-charset-hebrew,
15235w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15236w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15237w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
15238#endif
15239#ifdef UNICODE_CHARSET
74e1aeec 15240w32-charset-unicode,
dfff8a69 15241#endif
74e1aeec
JR
15242or w32-charset-oem.
15243CODEPAGE should be an integer specifying the codepage that should be used
15244to display the character set, t to do no translation and output as Unicode,
15245or nil to do no translation and output as 8 bit (or multibyte on far-east
15246versions of Windows) characters. */);
dfff8a69
JR
15247 Vw32_charset_info_alist = Qnil;
15248
15249 staticpro (&Qw32_charset_ansi);
15250 Qw32_charset_ansi = intern ("w32-charset-ansi");
15251 staticpro (&Qw32_charset_symbol);
15252 Qw32_charset_symbol = intern ("w32-charset-symbol");
15253 staticpro (&Qw32_charset_shiftjis);
15254 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
15255 staticpro (&Qw32_charset_hangeul);
15256 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
15257 staticpro (&Qw32_charset_chinesebig5);
15258 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15259 staticpro (&Qw32_charset_gb2312);
15260 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15261 staticpro (&Qw32_charset_oem);
15262 Qw32_charset_oem = intern ("w32-charset-oem");
15263
15264#ifdef JOHAB_CHARSET
15265 {
15266 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
15267 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15268 doc: /* Internal variable. */);
dfff8a69
JR
15269
15270 staticpro (&Qw32_charset_johab);
15271 Qw32_charset_johab = intern ("w32-charset-johab");
15272 staticpro (&Qw32_charset_easteurope);
15273 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15274 staticpro (&Qw32_charset_turkish);
15275 Qw32_charset_turkish = intern ("w32-charset-turkish");
15276 staticpro (&Qw32_charset_baltic);
15277 Qw32_charset_baltic = intern ("w32-charset-baltic");
15278 staticpro (&Qw32_charset_russian);
15279 Qw32_charset_russian = intern ("w32-charset-russian");
15280 staticpro (&Qw32_charset_arabic);
15281 Qw32_charset_arabic = intern ("w32-charset-arabic");
15282 staticpro (&Qw32_charset_greek);
15283 Qw32_charset_greek = intern ("w32-charset-greek");
15284 staticpro (&Qw32_charset_hebrew);
15285 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
15286 staticpro (&Qw32_charset_vietnamese);
15287 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
15288 staticpro (&Qw32_charset_thai);
15289 Qw32_charset_thai = intern ("w32-charset-thai");
15290 staticpro (&Qw32_charset_mac);
15291 Qw32_charset_mac = intern ("w32-charset-mac");
15292 }
15293#endif
15294
15295#ifdef UNICODE_CHARSET
15296 {
15297 static int w32_unicode_charset_defined = 1;
15298 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
15299 &w32_unicode_charset_defined,
15300 doc: /* Internal variable. */);
dfff8a69
JR
15301
15302 staticpro (&Qw32_charset_unicode);
15303 Qw32_charset_unicode = intern ("w32-charset-unicode");
15304#endif
15305
ee78dc32 15306 defsubr (&Sx_get_resource);
767b1ff0 15307#if 0 /* TODO: Port to W32 */
6fc2811b
JR
15308 defsubr (&Sx_change_window_property);
15309 defsubr (&Sx_delete_window_property);
15310 defsubr (&Sx_window_property);
15311#endif
2d764c78 15312 defsubr (&Sxw_display_color_p);
ee78dc32 15313 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
15314 defsubr (&Sxw_color_defined_p);
15315 defsubr (&Sxw_color_values);
ee78dc32
GV
15316 defsubr (&Sx_server_max_request_size);
15317 defsubr (&Sx_server_vendor);
15318 defsubr (&Sx_server_version);
15319 defsubr (&Sx_display_pixel_width);
15320 defsubr (&Sx_display_pixel_height);
15321 defsubr (&Sx_display_mm_width);
15322 defsubr (&Sx_display_mm_height);
15323 defsubr (&Sx_display_screens);
15324 defsubr (&Sx_display_planes);
15325 defsubr (&Sx_display_color_cells);
15326 defsubr (&Sx_display_visual_class);
15327 defsubr (&Sx_display_backing_store);
15328 defsubr (&Sx_display_save_under);
15329 defsubr (&Sx_parse_geometry);
15330 defsubr (&Sx_create_frame);
ee78dc32
GV
15331 defsubr (&Sx_open_connection);
15332 defsubr (&Sx_close_connection);
15333 defsubr (&Sx_display_list);
15334 defsubr (&Sx_synchronize);
15335
fbd6baed 15336 /* W32 specific functions */
ee78dc32 15337
1edf84e7 15338 defsubr (&Sw32_focus_frame);
fbd6baed
GV
15339 defsubr (&Sw32_select_font);
15340 defsubr (&Sw32_define_rgb_color);
15341 defsubr (&Sw32_default_color_map);
15342 defsubr (&Sw32_load_color_file);
1edf84e7 15343 defsubr (&Sw32_send_sys_command);
55dcfc15 15344 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
15345 defsubr (&Sw32_register_hot_key);
15346 defsubr (&Sw32_unregister_hot_key);
15347 defsubr (&Sw32_registered_hot_keys);
15348 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 15349 defsubr (&Sw32_toggle_lock_key);
33d52f9c 15350 defsubr (&Sw32_find_bdf_fonts);
4587b026 15351
2254bcde
AI
15352 defsubr (&Sfile_system_info);
15353
4587b026
GV
15354 /* Setting callback functions for fontset handler. */
15355 get_font_info_func = w32_get_font_info;
6fc2811b
JR
15356
15357#if 0 /* This function pointer doesn't seem to be used anywhere.
15358 And the pointer assigned has the wrong type, anyway. */
4587b026 15359 list_fonts_func = w32_list_fonts;
6fc2811b
JR
15360#endif
15361
4587b026
GV
15362 load_font_func = w32_load_font;
15363 find_ccl_program_func = w32_find_ccl_program;
15364 query_font_func = w32_query_font;
15365 set_frame_fontset_func = x_set_font;
15366 check_window_system_func = check_w32;
6fc2811b 15367
6fc2811b
JR
15368 /* Images. */
15369 Qxbm = intern ("xbm");
15370 staticpro (&Qxbm);
a93f4566
GM
15371 QCconversion = intern (":conversion");
15372 staticpro (&QCconversion);
6fc2811b
JR
15373 QCheuristic_mask = intern (":heuristic-mask");
15374 staticpro (&QCheuristic_mask);
15375 QCcolor_symbols = intern (":color-symbols");
15376 staticpro (&QCcolor_symbols);
6fc2811b
JR
15377 QCascent = intern (":ascent");
15378 staticpro (&QCascent);
15379 QCmargin = intern (":margin");
15380 staticpro (&QCmargin);
15381 QCrelief = intern (":relief");
15382 staticpro (&QCrelief);
15383 Qpostscript = intern ("postscript");
15384 staticpro (&Qpostscript);
ac849ba4 15385#if 0 /* TODO: These need entries at top of file. */
6fc2811b
JR
15386 QCloader = intern (":loader");
15387 staticpro (&QCloader);
15388 QCbounding_box = intern (":bounding-box");
15389 staticpro (&QCbounding_box);
15390 QCpt_width = intern (":pt-width");
15391 staticpro (&QCpt_width);
15392 QCpt_height = intern (":pt-height");
15393 staticpro (&QCpt_height);
ac849ba4 15394#endif
6fc2811b
JR
15395 QCindex = intern (":index");
15396 staticpro (&QCindex);
15397 Qpbm = intern ("pbm");
15398 staticpro (&Qpbm);
15399
15400#if HAVE_XPM
15401 Qxpm = intern ("xpm");
15402 staticpro (&Qxpm);
15403#endif
15404
15405#if HAVE_JPEG
15406 Qjpeg = intern ("jpeg");
15407 staticpro (&Qjpeg);
15408#endif
15409
15410#if HAVE_TIFF
15411 Qtiff = intern ("tiff");
15412 staticpro (&Qtiff);
15413#endif
15414
15415#if HAVE_GIF
15416 Qgif = intern ("gif");
15417 staticpro (&Qgif);
15418#endif
15419
15420#if HAVE_PNG
15421 Qpng = intern ("png");
15422 staticpro (&Qpng);
15423#endif
15424
15425 defsubr (&Sclear_image_cache);
ac849ba4
JR
15426 defsubr (&Simage_size);
15427 defsubr (&Simage_mask_p);
6fc2811b
JR
15428
15429#if GLYPH_DEBUG
15430 defsubr (&Simagep);
15431 defsubr (&Slookup_image);
15432#endif
6fc2811b 15433
0af913d7
GM
15434 hourglass_atimer = NULL;
15435 hourglass_shown_p = 0;
6fc2811b
JR
15436 defsubr (&Sx_show_tip);
15437 defsubr (&Sx_hide_tip);
6fc2811b 15438 tip_timer = Qnil;
57fa2774
JR
15439 staticpro (&tip_timer);
15440 tip_frame = Qnil;
15441 staticpro (&tip_frame);
6fc2811b 15442
ca56d953
JR
15443 last_show_tip_args = Qnil;
15444 staticpro (&last_show_tip_args);
15445
6fc2811b
JR
15446 defsubr (&Sx_file_dialog);
15447}
15448
15449
15450void
15451init_xfns ()
15452{
15453 image_types = NULL;
15454 Vimage_types = Qnil;
15455
ac849ba4 15456 define_image_type (&pbm_type);
6fc2811b 15457 define_image_type (&xbm_type);
217e5be0 15458#if 0 /* TODO : Image support for W32 */
6fc2811b 15459 define_image_type (&gs_type);
ac849ba4 15460#endif
6fc2811b
JR
15461
15462#if HAVE_XPM
15463 define_image_type (&xpm_type);
15464#endif
15465
15466#if HAVE_JPEG
15467 define_image_type (&jpeg_type);
15468#endif
15469
15470#if HAVE_TIFF
15471 define_image_type (&tiff_type);
15472#endif
919f1e88 15473
6fc2811b
JR
15474#if HAVE_GIF
15475 define_image_type (&gif_type);
15476#endif
15477
15478#if HAVE_PNG
15479 define_image_type (&png_type);
15480#endif
ee78dc32
GV
15481}
15482
15483#undef abort
15484
15485void
fbd6baed 15486w32_abort()
ee78dc32 15487{
5ac45f98
GV
15488 int button;
15489 button = MessageBox (NULL,
15490 "A fatal error has occurred!\n\n"
15491 "Select Abort to exit, Retry to debug, Ignore to continue",
15492 "Emacs Abort Dialog",
15493 MB_ICONEXCLAMATION | MB_TASKMODAL
15494 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15495 switch (button)
15496 {
15497 case IDRETRY:
15498 DebugBreak ();
15499 break;
15500 case IDIGNORE:
15501 break;
15502 case IDABORT:
15503 default:
15504 abort ();
15505 break;
15506 }
ee78dc32 15507}
d573caac 15508
83c75055
GV
15509/* For convenience when debugging. */
15510int
15511w32_last_error()
15512{
15513 return GetLastError ();
15514}