*** empty log message ***
[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
ee78dc32 55extern void free_frame_menubar ();
9eb16b62 56extern void x_compute_fringe_widths P_ ((struct frame *, int));
6fc2811b 57extern double atof ();
9eb16b62
JR
58extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
59extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
60extern void w32_free_menu_strings P_ ((HWND));
61
5ac45f98 62extern int quit_char;
ee78dc32 63
6fc2811b
JR
64/* A definition of XColor for non-X frames. */
65#ifndef HAVE_X_WINDOWS
66typedef struct {
67 unsigned long pixel;
68 unsigned short red, green, blue;
69 char flags;
70 char pad;
71} XColor;
72#endif
73
ccc2d29c
GV
74extern char *lispy_function_keys[];
75
6fc2811b
JR
76/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
77 it, and including `bitmaps/gray' more than once is a problem when
78 config.h defines `static' as an empty replacement string. */
79
80int gray_bitmap_width = gray_width;
81int gray_bitmap_height = gray_height;
82unsigned char *gray_bitmap_bits = gray_bits;
83
ee78dc32 84/* The colormap for converting color names to RGB values */
fbd6baed 85Lisp_Object Vw32_color_map;
ee78dc32 86
da36a4d6 87/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 88Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 89
8c205c63
RS
90/* Non nil if alt key is translated to meta_modifier, nil if it is translated
91 to alt_modifier. */
fbd6baed 92Lisp_Object Vw32_alt_is_meta;
8c205c63 93
7d081355
AI
94/* If non-zero, the windows virtual key code for an alternative quit key. */
95Lisp_Object Vw32_quit_key;
96
ccc2d29c
GV
97/* Non nil if left window key events are passed on to Windows (this only
98 affects whether "tapping" the key opens the Start menu). */
99Lisp_Object Vw32_pass_lwindow_to_system;
100
101/* Non nil if right window key events are passed on to Windows (this
102 only affects whether "tapping" the key opens the Start menu). */
103Lisp_Object Vw32_pass_rwindow_to_system;
104
adcc3809
GV
105/* Virtual key code used to generate "phantom" key presses in order
106 to stop system from acting on Windows key events. */
107Lisp_Object Vw32_phantom_key_code;
108
ccc2d29c
GV
109/* Modifier associated with the left "Windows" key, or nil to act as a
110 normal key. */
111Lisp_Object Vw32_lwindow_modifier;
112
113/* Modifier associated with the right "Windows" key, or nil to act as a
114 normal key. */
115Lisp_Object Vw32_rwindow_modifier;
116
117/* Modifier associated with the "Apps" key, or nil to act as a normal
118 key. */
119Lisp_Object Vw32_apps_modifier;
120
121/* Value is nil if Num Lock acts as a function key. */
122Lisp_Object Vw32_enable_num_lock;
123
124/* Value is nil if Caps Lock acts as a function key. */
125Lisp_Object Vw32_enable_caps_lock;
126
127/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
128Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 129
7ce9aaca 130/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b 131 and italic versions of fonts. */
d84b082d 132int w32_enable_synthesized_fonts;
5ac45f98
GV
133
134/* Enable palette management. */
fbd6baed 135Lisp_Object Vw32_enable_palette;
5ac45f98
GV
136
137/* Control how close left/right button down events must be to
138 be converted to a middle button down event. */
fbd6baed 139Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 140
84fb1139
KH
141/* Minimum interval between mouse movement (and scroll bar drag)
142 events that are passed on to the event loop. */
fbd6baed 143Lisp_Object Vw32_mouse_move_interval;
84fb1139 144
74214547
JR
145/* Flag to indicate if XBUTTON events should be passed on to Windows. */
146int w32_pass_extra_mouse_buttons_to_system;
147
ee78dc32
GV
148/* The name we're using in resource queries. */
149Lisp_Object Vx_resource_name;
150
151/* Non nil if no window manager is in use. */
152Lisp_Object Vx_no_window_manager;
153
0af913d7 154/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 155
0af913d7 156int display_hourglass_p;
6fc2811b 157
ee78dc32
GV
158/* The background and shape of the mouse pointer, and shape when not
159 over text or in the modeline. */
dfff8a69 160
ee78dc32 161Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 162Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 163
ee78dc32 164/* The shape when over mouse-sensitive text. */
dfff8a69 165
ee78dc32
GV
166Lisp_Object Vx_sensitive_text_pointer_shape;
167
168/* Color of chars displayed in cursor box. */
dfff8a69 169
ee78dc32
GV
170Lisp_Object Vx_cursor_fore_pixel;
171
1edf84e7 172/* Nonzero if using Windows. */
dfff8a69 173
1edf84e7
GV
174static int w32_in_use;
175
ee78dc32 176/* Search path for bitmap files. */
dfff8a69 177
ee78dc32
GV
178Lisp_Object Vx_bitmap_file_path;
179
4587b026 180/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 181
4587b026
GV
182Lisp_Object Vx_pixel_size_width_font_regexp;
183
33d52f9c
GV
184/* Alist of bdf fonts and the files that define them. */
185Lisp_Object Vw32_bdf_filename_alist;
186
f46e6225 187/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
188int w32_strict_fontnames;
189
c0611964
AI
190/* A flag to control whether we should only repaint if GetUpdateRect
191 indicates there is an update region. */
192int w32_strict_painting;
193
dfff8a69
JR
194/* Associative list linking character set strings to Windows codepages. */
195Lisp_Object Vw32_charset_info_alist;
196
197/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
198#ifndef VIETNAMESE_CHARSET
199#define VIETNAMESE_CHARSET 163
200#endif
201
ee78dc32
GV
202Lisp_Object Qauto_raise;
203Lisp_Object Qauto_lower;
ee78dc32
GV
204Lisp_Object Qbar;
205Lisp_Object Qborder_color;
206Lisp_Object Qborder_width;
207Lisp_Object Qbox;
208Lisp_Object Qcursor_color;
209Lisp_Object Qcursor_type;
ee78dc32
GV
210Lisp_Object Qgeometry;
211Lisp_Object Qicon_left;
212Lisp_Object Qicon_top;
213Lisp_Object Qicon_type;
214Lisp_Object Qicon_name;
215Lisp_Object Qinternal_border_width;
216Lisp_Object Qleft;
1026b400 217Lisp_Object Qright;
ee78dc32
GV
218Lisp_Object Qmouse_color;
219Lisp_Object Qnone;
220Lisp_Object Qparent_id;
221Lisp_Object Qscroll_bar_width;
222Lisp_Object Qsuppress_icon;
ee78dc32
GV
223Lisp_Object Qundefined_color;
224Lisp_Object Qvertical_scroll_bars;
225Lisp_Object Qvisibility;
226Lisp_Object Qwindow_id;
227Lisp_Object Qx_frame_parameter;
228Lisp_Object Qx_resource_name;
229Lisp_Object Quser_position;
230Lisp_Object Quser_size;
6fc2811b 231Lisp_Object Qscreen_gamma;
dfff8a69
JR
232Lisp_Object Qline_spacing;
233Lisp_Object Qcenter;
dc220243 234Lisp_Object Qcancel_timer;
adcc3809
GV
235Lisp_Object Qhyper;
236Lisp_Object Qsuper;
237Lisp_Object Qmeta;
238Lisp_Object Qalt;
239Lisp_Object Qctrl;
240Lisp_Object Qcontrol;
241Lisp_Object Qshift;
242
dfff8a69
JR
243Lisp_Object Qw32_charset_ansi;
244Lisp_Object Qw32_charset_default;
245Lisp_Object Qw32_charset_symbol;
246Lisp_Object Qw32_charset_shiftjis;
767b1ff0 247Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
248Lisp_Object Qw32_charset_gb2312;
249Lisp_Object Qw32_charset_chinesebig5;
250Lisp_Object Qw32_charset_oem;
251
71eab8d1
AI
252#ifndef JOHAB_CHARSET
253#define JOHAB_CHARSET 130
254#endif
dfff8a69
JR
255#ifdef JOHAB_CHARSET
256Lisp_Object Qw32_charset_easteurope;
257Lisp_Object Qw32_charset_turkish;
258Lisp_Object Qw32_charset_baltic;
259Lisp_Object Qw32_charset_russian;
260Lisp_Object Qw32_charset_arabic;
261Lisp_Object Qw32_charset_greek;
262Lisp_Object Qw32_charset_hebrew;
767b1ff0 263Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
264Lisp_Object Qw32_charset_thai;
265Lisp_Object Qw32_charset_johab;
266Lisp_Object Qw32_charset_mac;
267#endif
268
269#ifdef UNICODE_CHARSET
270Lisp_Object Qw32_charset_unicode;
271#endif
272
f7b9d4d1
JR
273Lisp_Object Qfullscreen;
274Lisp_Object Qfullwidth;
275Lisp_Object Qfullheight;
276Lisp_Object Qfullboth;
277
6fc2811b
JR
278extern Lisp_Object Qtop;
279extern Lisp_Object Qdisplay;
280extern Lisp_Object Qtool_bar_lines;
281
5ac45f98
GV
282/* State variables for emulating a three button mouse. */
283#define LMOUSE 1
284#define MMOUSE 2
285#define RMOUSE 4
286
287static int button_state = 0;
fbd6baed 288static W32Msg saved_mouse_button_msg;
84fb1139 289static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 290static W32Msg saved_mouse_move_msg;
84fb1139
KH
291static unsigned mouse_move_timer;
292
9eb16b62
JR
293/* Window that is tracking the mouse. */
294static HWND track_mouse_window;
295FARPROC track_mouse_event_fn;
296
93fbe8b7
GV
297/* W95 mousewheel handler */
298unsigned int msh_mousewheel = 0;
299
84fb1139
KH
300#define MOUSE_BUTTON_ID 1
301#define MOUSE_MOVE_ID 2
5ac45f98 302
ee78dc32 303/* The below are defined in frame.c. */
dfff8a69 304
ee78dc32 305extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 306extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 307extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
308
309extern Lisp_Object Vwindow_system_version;
310
4b817373
RS
311Lisp_Object Qface_set_after_frame_default;
312
937e601e
AI
313#ifdef GLYPH_DEBUG
314int image_cache_refcount, dpyinfo_refcount;
315#endif
316
317
fbd6baed
GV
318/* From w32term.c. */
319extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 320extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 321
65906840 322extern HWND w32_system_caret_hwnd;
93f2ca61 323
65906840
JR
324extern int w32_system_caret_height;
325extern int w32_system_caret_x;
326extern int w32_system_caret_y;
93f2ca61
JR
327extern int w32_use_visible_system_caret;
328
d285988b 329static HWND w32_visible_system_caret_hwnd;
65906840 330
ee78dc32 331\f
1edf84e7
GV
332/* Error if we are not connected to MS-Windows. */
333void
334check_w32 ()
335{
336 if (! w32_in_use)
337 error ("MS-Windows not in use or not initialized");
338}
339
340/* Nonzero if we can use mouse menus.
341 You should not call this unless HAVE_MENUS is defined. */
342
343int
344have_menus_p ()
345{
346 return w32_in_use;
347}
348
ee78dc32 349/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 350 and checking validity for W32. */
ee78dc32
GV
351
352FRAME_PTR
353check_x_frame (frame)
354 Lisp_Object frame;
355{
356 FRAME_PTR f;
357
358 if (NILP (frame))
6fc2811b 359 frame = selected_frame;
b7826503 360 CHECK_LIVE_FRAME (frame);
6fc2811b 361 f = XFRAME (frame);
fbd6baed
GV
362 if (! FRAME_W32_P (f))
363 error ("non-w32 frame used");
ee78dc32
GV
364 return f;
365}
366
367/* Let the user specify an display with a frame.
fbd6baed 368 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
369 the first display on the list. */
370
fbd6baed 371static struct w32_display_info *
ee78dc32
GV
372check_x_display_info (frame)
373 Lisp_Object frame;
374{
375 if (NILP (frame))
376 {
6fc2811b
JR
377 struct frame *sf = XFRAME (selected_frame);
378
379 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
380 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 381 else
fbd6baed 382 return &one_w32_display_info;
ee78dc32
GV
383 }
384 else if (STRINGP (frame))
385 return x_display_info_for_name (frame);
386 else
387 {
388 FRAME_PTR f;
389
b7826503 390 CHECK_LIVE_FRAME (frame);
ee78dc32 391 f = XFRAME (frame);
fbd6baed
GV
392 if (! FRAME_W32_P (f))
393 error ("non-w32 frame used");
394 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
395 }
396}
397\f
fbd6baed 398/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
399 It could be the frame's main window or an icon window. */
400
401/* This function can be called during GC, so use GC_xxx type test macros. */
402
403struct frame *
404x_window_to_frame (dpyinfo, wdesc)
fbd6baed 405 struct w32_display_info *dpyinfo;
ee78dc32
GV
406 HWND wdesc;
407{
408 Lisp_Object tail, frame;
409 struct frame *f;
410
8e713be6 411 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 412 {
8e713be6 413 frame = XCAR (tail);
ee78dc32
GV
414 if (!GC_FRAMEP (frame))
415 continue;
416 f = XFRAME (frame);
2d764c78 417 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 418 continue;
0af913d7 419 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
420 return f;
421
fbd6baed 422 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
423 return f;
424 }
425 return 0;
426}
427
428\f
429
430/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
431 id, which is just an int that this section returns. Bitmaps are
432 reference counted so they can be shared among frames.
433
434 Bitmap indices are guaranteed to be > 0, so a negative number can
435 be used to indicate no bitmap.
436
437 If you use x_create_bitmap_from_data, then you must keep track of
438 the bitmaps yourself. That is, creating a bitmap from the same
439 data more than once will not be caught. */
440
441
442/* Functions to access the contents of a bitmap, given an id. */
443
444int
445x_bitmap_height (f, id)
446 FRAME_PTR f;
447 int id;
448{
fbd6baed 449 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
450}
451
452int
453x_bitmap_width (f, id)
454 FRAME_PTR f;
455 int id;
456{
fbd6baed 457 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
458}
459
460int
461x_bitmap_pixmap (f, id)
462 FRAME_PTR f;
463 int id;
464{
fbd6baed 465 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
466}
467
468
469/* Allocate a new bitmap record. Returns index of new record. */
470
471static int
472x_allocate_bitmap_record (f)
473 FRAME_PTR f;
474{
fbd6baed 475 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
476 int i;
477
478 if (dpyinfo->bitmaps == NULL)
479 {
480 dpyinfo->bitmaps_size = 10;
481 dpyinfo->bitmaps
fbd6baed 482 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
483 dpyinfo->bitmaps_last = 1;
484 return 1;
485 }
486
487 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
488 return ++dpyinfo->bitmaps_last;
489
490 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
491 if (dpyinfo->bitmaps[i].refcount == 0)
492 return i + 1;
493
494 dpyinfo->bitmaps_size *= 2;
495 dpyinfo->bitmaps
fbd6baed
GV
496 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
497 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
498 return ++dpyinfo->bitmaps_last;
499}
500
501/* Add one reference to the reference count of the bitmap with id ID. */
502
503void
504x_reference_bitmap (f, id)
505 FRAME_PTR f;
506 int id;
507{
fbd6baed 508 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
509}
510
511/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
512
513int
514x_create_bitmap_from_data (f, bits, width, height)
515 struct frame *f;
516 char *bits;
517 unsigned int width, height;
518{
fbd6baed 519 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
520 Pixmap bitmap;
521 int id;
522
523 bitmap = CreateBitmap (width, height,
fbd6baed
GV
524 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
525 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
526 bits);
527
528 if (! bitmap)
529 return -1;
530
531 id = x_allocate_bitmap_record (f);
532 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
533 dpyinfo->bitmaps[id - 1].file = NULL;
534 dpyinfo->bitmaps[id - 1].hinst = NULL;
535 dpyinfo->bitmaps[id - 1].refcount = 1;
536 dpyinfo->bitmaps[id - 1].depth = 1;
537 dpyinfo->bitmaps[id - 1].height = height;
538 dpyinfo->bitmaps[id - 1].width = width;
539
540 return id;
541}
542
543/* Create bitmap from file FILE for frame F. */
544
545int
546x_create_bitmap_from_file (f, file)
547 struct frame *f;
548 Lisp_Object file;
549{
550 return -1;
767b1ff0 551#if 0 /* TODO : bitmap support */
fbd6baed 552 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 553 unsigned int width, height;
6fc2811b 554 HBITMAP bitmap;
ee78dc32
GV
555 int xhot, yhot, result, id;
556 Lisp_Object found;
557 int fd;
558 char *filename;
559 HINSTANCE hinst;
560
561 /* Look for an existing bitmap with the same name. */
562 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
563 {
564 if (dpyinfo->bitmaps[id].refcount
565 && dpyinfo->bitmaps[id].file
566 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
567 {
568 ++dpyinfo->bitmaps[id].refcount;
569 return id + 1;
570 }
571 }
572
573 /* Search bitmap-file-path for the file, if appropriate. */
c0ec53ad 574 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
ee78dc32
GV
575 if (fd < 0)
576 return -1;
6fc2811b 577 emacs_close (fd);
ee78dc32
GV
578
579 filename = (char *) XSTRING (found)->data;
580
581 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
582
583 if (hinst == NULL)
584 return -1;
585
586
fbd6baed 587 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
588 filename, &width, &height, &bitmap, &xhot, &yhot);
589 if (result != BitmapSuccess)
590 return -1;
591
592 id = x_allocate_bitmap_record (f);
593 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
594 dpyinfo->bitmaps[id - 1].refcount = 1;
595 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
596 dpyinfo->bitmaps[id - 1].depth = 1;
597 dpyinfo->bitmaps[id - 1].height = height;
598 dpyinfo->bitmaps[id - 1].width = width;
599 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
600
601 return id;
767b1ff0 602#endif /* TODO */
ee78dc32
GV
603}
604
605/* Remove reference to bitmap with id number ID. */
606
33d52f9c 607void
ee78dc32
GV
608x_destroy_bitmap (f, id)
609 FRAME_PTR f;
610 int id;
611{
fbd6baed 612 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
613
614 if (id > 0)
615 {
616 --dpyinfo->bitmaps[id - 1].refcount;
617 if (dpyinfo->bitmaps[id - 1].refcount == 0)
618 {
619 BLOCK_INPUT;
620 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
621 if (dpyinfo->bitmaps[id - 1].file)
622 {
6fc2811b 623 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
624 dpyinfo->bitmaps[id - 1].file = NULL;
625 }
626 UNBLOCK_INPUT;
627 }
628 }
629}
630
631/* Free all the bitmaps for the display specified by DPYINFO. */
632
633static void
634x_destroy_all_bitmaps (dpyinfo)
fbd6baed 635 struct w32_display_info *dpyinfo;
ee78dc32
GV
636{
637 int i;
638 for (i = 0; i < dpyinfo->bitmaps_last; i++)
639 if (dpyinfo->bitmaps[i].refcount > 0)
640 {
641 DeleteObject (dpyinfo->bitmaps[i].pixmap);
642 if (dpyinfo->bitmaps[i].file)
6fc2811b 643 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
644 }
645 dpyinfo->bitmaps_last = 0;
646}
647\f
fbd6baed 648/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
649 to the ways of passing the parameter values to the window system.
650
651 The name of a parameter, as a Lisp symbol,
652 has an `x-frame-parameter' property which is an integer in Lisp
653 but can be interpreted as an `enum x_frame_parm' in C. */
654
655enum x_frame_parm
656{
657 X_PARM_FOREGROUND_COLOR,
658 X_PARM_BACKGROUND_COLOR,
659 X_PARM_MOUSE_COLOR,
660 X_PARM_CURSOR_COLOR,
661 X_PARM_BORDER_COLOR,
662 X_PARM_ICON_TYPE,
663 X_PARM_FONT,
664 X_PARM_BORDER_WIDTH,
665 X_PARM_INTERNAL_BORDER_WIDTH,
666 X_PARM_NAME,
667 X_PARM_AUTORAISE,
668 X_PARM_AUTOLOWER,
669 X_PARM_VERT_SCROLL_BAR,
670 X_PARM_VISIBILITY,
671 X_PARM_MENU_BAR_LINES
672};
673
674
675struct x_frame_parm_table
676{
677 char *name;
6fc2811b 678 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
679};
680
ca56d953
JR
681BOOL my_show_window P_ ((struct frame *, HWND, int));
682void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
683static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
684static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
685static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 686/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 687void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 688static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
f7b9d4d1 689static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
690void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
691void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
692void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
693void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
694void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
695void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 698static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
699void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
701 Lisp_Object));
702void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
703void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
704void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
706 Lisp_Object));
707void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
708void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
709void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
710void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
711void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
712void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
713static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
714static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
715 Lisp_Object));
ee78dc32
GV
716
717static struct x_frame_parm_table x_frame_parms[] =
718{
72e4adef
JR
719 {"auto-raise", x_set_autoraise},
720 {"auto-lower", x_set_autolower},
721 {"background-color", x_set_background_color},
722 {"border-color", x_set_border_color},
723 {"border-width", x_set_border_width},
724 {"cursor-color", x_set_cursor_color},
725 {"cursor-type", x_set_cursor_type},
726 {"font", x_set_font},
727 {"foreground-color", x_set_foreground_color},
728 {"icon-name", x_set_icon_name},
729 {"icon-type", x_set_icon_type},
730 {"internal-border-width", x_set_internal_border_width},
731 {"menu-bar-lines", x_set_menu_bar_lines},
732 {"mouse-color", x_set_mouse_color},
733 {"name", x_explicitly_set_name},
734 {"scroll-bar-width", x_set_scroll_bar_width},
735 {"title", x_set_title},
736 {"unsplittable", x_set_unsplittable},
737 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
738 {"visibility", x_set_visibility},
739 {"tool-bar-lines", x_set_tool_bar_lines},
740 {"screen-gamma", x_set_screen_gamma},
741 {"line-spacing", x_set_line_spacing},
742 {"left-fringe", x_set_fringe_width},
f7b9d4d1
JR
743 {"right-fringe", x_set_fringe_width},
744 {"fullscreen", x_set_fullscreen},
ee78dc32
GV
745};
746
747/* Attach the `x-frame-parameter' properties to
fbd6baed 748 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 749
dfff8a69 750void
ee78dc32
GV
751init_x_parm_symbols ()
752{
753 int i;
754
755 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
756 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
757 make_number (i));
758}
759\f
f7b9d4d1
JR
760/* Really try to move where we want to be in case of fullscreen. Some WMs
761 moves the window where we tell them. Some (mwm, twm) moves the outer
762 window manager window there instead.
763 Try to compensate for those WM here. */
764static void
765x_fullscreen_move (f, new_top, new_left)
766 struct frame *f;
767 int new_top;
768 int new_left;
769{
770 if (new_top != f->output_data.w32->top_pos
771 || new_left != f->output_data.w32->left_pos)
772 {
773 int move_x = new_left;
774 int move_y = new_top;
775
776 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
777 x_set_offset (f, move_x, move_y, 1);
778 }
779}
780
dfff8a69 781/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
782 If a parameter is not specially recognized, do nothing;
783 otherwise call the `x_set_...' function for that parameter. */
784
785void
786x_set_frame_parameters (f, alist)
787 FRAME_PTR f;
788 Lisp_Object alist;
789{
790 Lisp_Object tail;
791
792 /* If both of these parameters are present, it's more efficient to
793 set them both at once. So we wait until we've looked at the
794 entire list before we set them. */
b839712d 795 int width, height;
ee78dc32
GV
796
797 /* Same here. */
798 Lisp_Object left, top;
799
800 /* Same with these. */
801 Lisp_Object icon_left, icon_top;
802
803 /* Record in these vectors all the parms specified. */
804 Lisp_Object *parms;
805 Lisp_Object *values;
a797a73d 806 int i, p;
ee78dc32
GV
807 int left_no_change = 0, top_no_change = 0;
808 int icon_left_no_change = 0, icon_top_no_change = 0;
f7b9d4d1 809 int fullscreen_is_being_set = 0;
ee78dc32 810
5878523b
RS
811 struct gcpro gcpro1, gcpro2;
812
ee78dc32
GV
813 i = 0;
814 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
815 i++;
816
817 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
818 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
819
820 /* Extract parm names and values into those vectors. */
821
822 i = 0;
823 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
824 {
6fc2811b 825 Lisp_Object elt;
ee78dc32
GV
826
827 elt = Fcar (tail);
828 parms[i] = Fcar (elt);
829 values[i] = Fcdr (elt);
830 i++;
831 }
5878523b
RS
832 /* TAIL and ALIST are not used again below here. */
833 alist = tail = Qnil;
834
835 GCPRO2 (*parms, *values);
836 gcpro1.nvars = i;
837 gcpro2.nvars = i;
838
839 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
840 because their values appear in VALUES and strings are not valid. */
b839712d 841 top = left = Qunbound;
ee78dc32
GV
842 icon_left = icon_top = Qunbound;
843
b839712d 844 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
845 if (FRAME_NEW_WIDTH (f))
846 width = FRAME_NEW_WIDTH (f);
847 else
848 width = FRAME_WIDTH (f);
849
850 if (FRAME_NEW_HEIGHT (f))
851 height = FRAME_NEW_HEIGHT (f);
852 else
853 height = FRAME_HEIGHT (f);
b839712d 854
a797a73d
GV
855 /* Process foreground_color and background_color before anything else.
856 They are independent of other properties, but other properties (e.g.,
857 cursor_color) are dependent upon them. */
41c1bdd9 858 /* Process default font as well, since fringe widths depends on it. */
a797a73d
GV
859 for (p = 0; p < i; p++)
860 {
861 Lisp_Object prop, val;
862
863 prop = parms[p];
864 val = values[p];
41c1bdd9
KS
865 if (EQ (prop, Qforeground_color)
866 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
867 || EQ (prop, Qfont)
868 || EQ (prop, Qfullscreen))
a797a73d
GV
869 {
870 register Lisp_Object param_index, old_value;
871
a797a73d 872 old_value = get_frame_param (f, prop);
f7b9d4d1 873 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
a05e2bae
JR
874
875 if (NILP (Fequal (val, old_value)))
876 {
877 store_frame_param (f, prop, val);
878
879 param_index = Fget (prop, Qx_frame_parameter);
880 if (NATNUMP (param_index)
881 && (XFASTINT (param_index)
882 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
883 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
884 }
a797a73d
GV
885 }
886 }
887
ee78dc32
GV
888 /* Now process them in reverse of specified order. */
889 for (i--; i >= 0; i--)
890 {
891 Lisp_Object prop, val;
892
893 prop = parms[i];
894 val = values[i];
895
b839712d
RS
896 if (EQ (prop, Qwidth) && NUMBERP (val))
897 width = XFASTINT (val);
898 else if (EQ (prop, Qheight) && NUMBERP (val))
899 height = XFASTINT (val);
ee78dc32
GV
900 else if (EQ (prop, Qtop))
901 top = val;
902 else if (EQ (prop, Qleft))
903 left = val;
904 else if (EQ (prop, Qicon_top))
905 icon_top = val;
906 else if (EQ (prop, Qicon_left))
907 icon_left = val;
41c1bdd9
KS
908 else if (EQ (prop, Qforeground_color)
909 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
910 || EQ (prop, Qfont)
911 || EQ (prop, Qfullscreen))
a797a73d
GV
912 /* Processed above. */
913 continue;
ee78dc32
GV
914 else
915 {
916 register Lisp_Object param_index, old_value;
917
ee78dc32 918 old_value = get_frame_param (f, prop);
a05e2bae 919
ee78dc32 920 store_frame_param (f, prop, val);
a05e2bae
JR
921
922 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
923 if (NATNUMP (param_index)
924 && (XFASTINT (param_index)
925 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 926 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
927 }
928 }
929
930 /* Don't die if just one of these was set. */
931 if (EQ (left, Qunbound))
932 {
933 left_no_change = 1;
fbd6baed
GV
934 if (f->output_data.w32->left_pos < 0)
935 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 936 else
fbd6baed 937 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
938 }
939 if (EQ (top, Qunbound))
940 {
941 top_no_change = 1;
fbd6baed
GV
942 if (f->output_data.w32->top_pos < 0)
943 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 944 else
fbd6baed 945 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
946 }
947
948 /* If one of the icon positions was not set, preserve or default it. */
949 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
950 {
951 icon_left_no_change = 1;
952 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
953 if (NILP (icon_left))
954 XSETINT (icon_left, 0);
955 }
956 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
957 {
958 icon_top_no_change = 1;
959 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
960 if (NILP (icon_top))
961 XSETINT (icon_top, 0);
962 }
963
f7b9d4d1
JR
964 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
965 {
966 /* If the frame is visible already and the fullscreen parameter is
967 being set, it is too late to set WM manager hints to specify
968 size and position.
969 Here we first get the width, height and position that applies to
970 fullscreen. We then move the frame to the appropriate
971 position. Resize of the frame is taken care of in the code after
972 this if-statement. */
973 int new_left, new_top;
974
975 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
976 x_fullscreen_move (f, new_top, new_left);
977 }
978
ee78dc32
GV
979 /* Don't set these parameters unless they've been explicitly
980 specified. The window might be mapped or resized while we're in
981 this function, and we don't want to override that unless the lisp
982 code has asked for it.
983
984 Don't set these parameters unless they actually differ from the
985 window's current parameters; the window may not actually exist
986 yet. */
987 {
988 Lisp_Object frame;
989
990 check_frame_size (f, &height, &width);
991
992 XSETFRAME (frame, f);
993
dfff8a69
JR
994 if (width != FRAME_WIDTH (f)
995 || height != FRAME_HEIGHT (f)
996 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 997 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
998
999 if ((!NILP (left) || !NILP (top))
1000 && ! (left_no_change && top_no_change)
fbd6baed
GV
1001 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1002 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
1003 {
1004 int leftpos = 0;
1005 int toppos = 0;
1006
1007 /* Record the signs. */
fbd6baed 1008 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 1009 if (EQ (left, Qminus))
fbd6baed 1010 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
1011 else if (INTEGERP (left))
1012 {
1013 leftpos = XINT (left);
1014 if (leftpos < 0)
fbd6baed 1015 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1016 }
8e713be6
KR
1017 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1018 && CONSP (XCDR (left))
1019 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1020 {
8e713be6 1021 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 1022 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1023 }
8e713be6
KR
1024 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1025 && CONSP (XCDR (left))
1026 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1027 {
8e713be6 1028 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
1029 }
1030
1031 if (EQ (top, Qminus))
fbd6baed 1032 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
1033 else if (INTEGERP (top))
1034 {
1035 toppos = XINT (top);
1036 if (toppos < 0)
fbd6baed 1037 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1038 }
8e713be6
KR
1039 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1040 && CONSP (XCDR (top))
1041 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1042 {
8e713be6 1043 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 1044 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1045 }
8e713be6
KR
1046 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1047 && CONSP (XCDR (top))
1048 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1049 {
8e713be6 1050 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1051 }
1052
1053
1054 /* Store the numeric value of the position. */
fbd6baed
GV
1055 f->output_data.w32->top_pos = toppos;
1056 f->output_data.w32->left_pos = leftpos;
ee78dc32 1057
fbd6baed 1058 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1059
1060 /* Actually set that position, and convert to absolute. */
1061 x_set_offset (f, leftpos, toppos, -1);
1062 }
1063
1064 if ((!NILP (icon_left) || !NILP (icon_top))
1065 && ! (icon_left_no_change && icon_top_no_change))
1066 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1067 }
5878523b
RS
1068
1069 UNGCPRO;
ee78dc32
GV
1070}
1071
1072/* Store the screen positions of frame F into XPTR and YPTR.
1073 These are the positions of the containing window manager window,
1074 not Emacs's own window. */
1075
1076void
1077x_real_positions (f, xptr, yptr)
1078 FRAME_PTR f;
1079 int *xptr, *yptr;
1080{
1081 POINT pt;
f7b9d4d1 1082 RECT rect;
3c190163 1083
f7b9d4d1
JR
1084 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1085 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1086
1087 pt.x = rect.left;
1088 pt.y = rect.top;
ee78dc32 1089
fbd6baed 1090 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32 1091
f7b9d4d1
JR
1092 /* Remember x_pixels_diff and y_pixels_diff. */
1093 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1094 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1095
ee78dc32
GV
1096 *xptr = pt.x;
1097 *yptr = pt.y;
1098}
1099
1100/* Insert a description of internally-recorded parameters of frame X
1101 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1102 Only parameters that are specific to W32
ee78dc32
GV
1103 and whose values are not correctly recorded in the frame's
1104 param_alist need to be considered here. */
1105
dfff8a69 1106void
ee78dc32
GV
1107x_report_frame_params (f, alistptr)
1108 struct frame *f;
1109 Lisp_Object *alistptr;
1110{
1111 char buf[16];
1112 Lisp_Object tem;
1113
1114 /* Represent negative positions (off the top or left screen edge)
1115 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1116 XSETINT (tem, f->output_data.w32->left_pos);
1117 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1118 store_in_alist (alistptr, Qleft, tem);
1119 else
1120 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1121
fbd6baed
GV
1122 XSETINT (tem, f->output_data.w32->top_pos);
1123 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1124 store_in_alist (alistptr, Qtop, tem);
1125 else
1126 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1127
1128 store_in_alist (alistptr, Qborder_width,
fbd6baed 1129 make_number (f->output_data.w32->border_width));
ee78dc32 1130 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1131 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1132 store_in_alist (alistptr, Qleft_fringe,
1133 make_number (f->output_data.w32->left_fringe_width));
1134 store_in_alist (alistptr, Qright_fringe,
1135 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1136 store_in_alist (alistptr, Qscroll_bar_width,
1137 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1138 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1139 : 0));
fbd6baed 1140 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1141 store_in_alist (alistptr, Qwindow_id,
1142 build_string (buf));
1143 store_in_alist (alistptr, Qicon_name, f->icon_name);
1144 FRAME_SAMPLE_VISIBILITY (f);
1145 store_in_alist (alistptr, Qvisibility,
1146 (FRAME_VISIBLE_P (f) ? Qt
1147 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1148 store_in_alist (alistptr, Qdisplay,
8e713be6 1149 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1150}
1151\f
1152
74e1aeec
JR
1153DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1154 Sw32_define_rgb_color, 4, 4, 0,
1155 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1156This adds or updates a named color to w32-color-map, making it
1157available for use. The original entry's RGB ref is returned, or nil
1158if the entry is new. */)
5ac45f98
GV
1159 (red, green, blue, name)
1160 Lisp_Object red, green, blue, name;
ee78dc32 1161{
5ac45f98
GV
1162 Lisp_Object rgb;
1163 Lisp_Object oldrgb = Qnil;
1164 Lisp_Object entry;
1165
b7826503
PJ
1166 CHECK_NUMBER (red);
1167 CHECK_NUMBER (green);
1168 CHECK_NUMBER (blue);
1169 CHECK_STRING (name);
ee78dc32 1170
5ac45f98 1171 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1172
5ac45f98 1173 BLOCK_INPUT;
ee78dc32 1174
fbd6baed
GV
1175 /* replace existing entry in w32-color-map or add new entry. */
1176 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1177 if (NILP (entry))
1178 {
1179 entry = Fcons (name, rgb);
fbd6baed 1180 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1181 }
1182 else
1183 {
1184 oldrgb = Fcdr (entry);
1185 Fsetcdr (entry, rgb);
1186 }
1187
1188 UNBLOCK_INPUT;
1189
1190 return (oldrgb);
ee78dc32
GV
1191}
1192
74e1aeec
JR
1193DEFUN ("w32-load-color-file", Fw32_load_color_file,
1194 Sw32_load_color_file, 1, 1, 0,
1195 doc: /* Create an alist of color entries from an external file.
1196Assign this value to w32-color-map to replace the existing color map.
1197
1198The file should define one named RGB color per line like so:
1199 R G B name
1200where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1201 (filename)
1202 Lisp_Object filename;
1203{
1204 FILE *fp;
1205 Lisp_Object cmap = Qnil;
1206 Lisp_Object abspath;
1207
b7826503 1208 CHECK_STRING (filename);
5ac45f98
GV
1209 abspath = Fexpand_file_name (filename, Qnil);
1210
1211 fp = fopen (XSTRING (filename)->data, "rt");
1212 if (fp)
1213 {
1214 char buf[512];
1215 int red, green, blue;
1216 int num;
1217
1218 BLOCK_INPUT;
1219
1220 while (fgets (buf, sizeof (buf), fp) != NULL) {
1221 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1222 {
1223 char *name = buf + num;
1224 num = strlen (name) - 1;
1225 if (name[num] == '\n')
1226 name[num] = 0;
1227 cmap = Fcons (Fcons (build_string (name),
1228 make_number (RGB (red, green, blue))),
1229 cmap);
1230 }
1231 }
1232 fclose (fp);
1233
1234 UNBLOCK_INPUT;
1235 }
1236
1237 return cmap;
1238}
ee78dc32 1239
fbd6baed 1240/* The default colors for the w32 color map */
ee78dc32
GV
1241typedef struct colormap_t
1242{
1243 char *name;
1244 COLORREF colorref;
1245} colormap_t;
1246
fbd6baed 1247colormap_t w32_color_map[] =
ee78dc32 1248{
1da8a614
GV
1249 {"snow" , PALETTERGB (255,250,250)},
1250 {"ghost white" , PALETTERGB (248,248,255)},
1251 {"GhostWhite" , PALETTERGB (248,248,255)},
1252 {"white smoke" , PALETTERGB (245,245,245)},
1253 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1254 {"gainsboro" , PALETTERGB (220,220,220)},
1255 {"floral white" , PALETTERGB (255,250,240)},
1256 {"FloralWhite" , PALETTERGB (255,250,240)},
1257 {"old lace" , PALETTERGB (253,245,230)},
1258 {"OldLace" , PALETTERGB (253,245,230)},
1259 {"linen" , PALETTERGB (250,240,230)},
1260 {"antique white" , PALETTERGB (250,235,215)},
1261 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1262 {"papaya whip" , PALETTERGB (255,239,213)},
1263 {"PapayaWhip" , PALETTERGB (255,239,213)},
1264 {"blanched almond" , PALETTERGB (255,235,205)},
1265 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1266 {"bisque" , PALETTERGB (255,228,196)},
1267 {"peach puff" , PALETTERGB (255,218,185)},
1268 {"PeachPuff" , PALETTERGB (255,218,185)},
1269 {"navajo white" , PALETTERGB (255,222,173)},
1270 {"NavajoWhite" , PALETTERGB (255,222,173)},
1271 {"moccasin" , PALETTERGB (255,228,181)},
1272 {"cornsilk" , PALETTERGB (255,248,220)},
1273 {"ivory" , PALETTERGB (255,255,240)},
1274 {"lemon chiffon" , PALETTERGB (255,250,205)},
1275 {"LemonChiffon" , PALETTERGB (255,250,205)},
1276 {"seashell" , PALETTERGB (255,245,238)},
1277 {"honeydew" , PALETTERGB (240,255,240)},
1278 {"mint cream" , PALETTERGB (245,255,250)},
1279 {"MintCream" , PALETTERGB (245,255,250)},
1280 {"azure" , PALETTERGB (240,255,255)},
1281 {"alice blue" , PALETTERGB (240,248,255)},
1282 {"AliceBlue" , PALETTERGB (240,248,255)},
1283 {"lavender" , PALETTERGB (230,230,250)},
1284 {"lavender blush" , PALETTERGB (255,240,245)},
1285 {"LavenderBlush" , PALETTERGB (255,240,245)},
1286 {"misty rose" , PALETTERGB (255,228,225)},
1287 {"MistyRose" , PALETTERGB (255,228,225)},
1288 {"white" , PALETTERGB (255,255,255)},
1289 {"black" , PALETTERGB ( 0, 0, 0)},
1290 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1291 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1292 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1293 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1294 {"dim gray" , PALETTERGB (105,105,105)},
1295 {"DimGray" , PALETTERGB (105,105,105)},
1296 {"dim grey" , PALETTERGB (105,105,105)},
1297 {"DimGrey" , PALETTERGB (105,105,105)},
1298 {"slate gray" , PALETTERGB (112,128,144)},
1299 {"SlateGray" , PALETTERGB (112,128,144)},
1300 {"slate grey" , PALETTERGB (112,128,144)},
1301 {"SlateGrey" , PALETTERGB (112,128,144)},
1302 {"light slate gray" , PALETTERGB (119,136,153)},
1303 {"LightSlateGray" , PALETTERGB (119,136,153)},
1304 {"light slate grey" , PALETTERGB (119,136,153)},
1305 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1306 {"gray" , PALETTERGB (190,190,190)},
1307 {"grey" , PALETTERGB (190,190,190)},
1308 {"light grey" , PALETTERGB (211,211,211)},
1309 {"LightGrey" , PALETTERGB (211,211,211)},
1310 {"light gray" , PALETTERGB (211,211,211)},
1311 {"LightGray" , PALETTERGB (211,211,211)},
1312 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1313 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1314 {"navy" , PALETTERGB ( 0, 0,128)},
1315 {"navy blue" , PALETTERGB ( 0, 0,128)},
1316 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1317 {"cornflower blue" , PALETTERGB (100,149,237)},
1318 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1319 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1320 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1321 {"slate blue" , PALETTERGB (106, 90,205)},
1322 {"SlateBlue" , PALETTERGB (106, 90,205)},
1323 {"medium slate blue" , PALETTERGB (123,104,238)},
1324 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1325 {"light slate blue" , PALETTERGB (132,112,255)},
1326 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1327 {"medium blue" , PALETTERGB ( 0, 0,205)},
1328 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1329 {"royal blue" , PALETTERGB ( 65,105,225)},
1330 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1331 {"blue" , PALETTERGB ( 0, 0,255)},
1332 {"dodger blue" , PALETTERGB ( 30,144,255)},
1333 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1334 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1335 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1336 {"sky blue" , PALETTERGB (135,206,235)},
1337 {"SkyBlue" , PALETTERGB (135,206,235)},
1338 {"light sky blue" , PALETTERGB (135,206,250)},
1339 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1340 {"steel blue" , PALETTERGB ( 70,130,180)},
1341 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1342 {"light steel blue" , PALETTERGB (176,196,222)},
1343 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1344 {"light blue" , PALETTERGB (173,216,230)},
1345 {"LightBlue" , PALETTERGB (173,216,230)},
1346 {"powder blue" , PALETTERGB (176,224,230)},
1347 {"PowderBlue" , PALETTERGB (176,224,230)},
1348 {"pale turquoise" , PALETTERGB (175,238,238)},
1349 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1350 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1351 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1352 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1353 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1354 {"turquoise" , PALETTERGB ( 64,224,208)},
1355 {"cyan" , PALETTERGB ( 0,255,255)},
1356 {"light cyan" , PALETTERGB (224,255,255)},
1357 {"LightCyan" , PALETTERGB (224,255,255)},
1358 {"cadet blue" , PALETTERGB ( 95,158,160)},
1359 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1360 {"medium aquamarine" , PALETTERGB (102,205,170)},
1361 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1362 {"aquamarine" , PALETTERGB (127,255,212)},
1363 {"dark green" , PALETTERGB ( 0,100, 0)},
1364 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1365 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1366 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1367 {"dark sea green" , PALETTERGB (143,188,143)},
1368 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1369 {"sea green" , PALETTERGB ( 46,139, 87)},
1370 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1371 {"medium sea green" , PALETTERGB ( 60,179,113)},
1372 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1373 {"light sea green" , PALETTERGB ( 32,178,170)},
1374 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1375 {"pale green" , PALETTERGB (152,251,152)},
1376 {"PaleGreen" , PALETTERGB (152,251,152)},
1377 {"spring green" , PALETTERGB ( 0,255,127)},
1378 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1379 {"lawn green" , PALETTERGB (124,252, 0)},
1380 {"LawnGreen" , PALETTERGB (124,252, 0)},
1381 {"green" , PALETTERGB ( 0,255, 0)},
1382 {"chartreuse" , PALETTERGB (127,255, 0)},
1383 {"medium spring green" , PALETTERGB ( 0,250,154)},
1384 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1385 {"green yellow" , PALETTERGB (173,255, 47)},
1386 {"GreenYellow" , PALETTERGB (173,255, 47)},
1387 {"lime green" , PALETTERGB ( 50,205, 50)},
1388 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1389 {"yellow green" , PALETTERGB (154,205, 50)},
1390 {"YellowGreen" , PALETTERGB (154,205, 50)},
1391 {"forest green" , PALETTERGB ( 34,139, 34)},
1392 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1393 {"olive drab" , PALETTERGB (107,142, 35)},
1394 {"OliveDrab" , PALETTERGB (107,142, 35)},
1395 {"dark khaki" , PALETTERGB (189,183,107)},
1396 {"DarkKhaki" , PALETTERGB (189,183,107)},
1397 {"khaki" , PALETTERGB (240,230,140)},
1398 {"pale goldenrod" , PALETTERGB (238,232,170)},
1399 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1400 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1401 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1402 {"light yellow" , PALETTERGB (255,255,224)},
1403 {"LightYellow" , PALETTERGB (255,255,224)},
1404 {"yellow" , PALETTERGB (255,255, 0)},
1405 {"gold" , PALETTERGB (255,215, 0)},
1406 {"light goldenrod" , PALETTERGB (238,221,130)},
1407 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1408 {"goldenrod" , PALETTERGB (218,165, 32)},
1409 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1410 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1411 {"rosy brown" , PALETTERGB (188,143,143)},
1412 {"RosyBrown" , PALETTERGB (188,143,143)},
1413 {"indian red" , PALETTERGB (205, 92, 92)},
1414 {"IndianRed" , PALETTERGB (205, 92, 92)},
1415 {"saddle brown" , PALETTERGB (139, 69, 19)},
1416 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1417 {"sienna" , PALETTERGB (160, 82, 45)},
1418 {"peru" , PALETTERGB (205,133, 63)},
1419 {"burlywood" , PALETTERGB (222,184,135)},
1420 {"beige" , PALETTERGB (245,245,220)},
1421 {"wheat" , PALETTERGB (245,222,179)},
1422 {"sandy brown" , PALETTERGB (244,164, 96)},
1423 {"SandyBrown" , PALETTERGB (244,164, 96)},
1424 {"tan" , PALETTERGB (210,180,140)},
1425 {"chocolate" , PALETTERGB (210,105, 30)},
1426 {"firebrick" , PALETTERGB (178,34, 34)},
1427 {"brown" , PALETTERGB (165,42, 42)},
1428 {"dark salmon" , PALETTERGB (233,150,122)},
1429 {"DarkSalmon" , PALETTERGB (233,150,122)},
1430 {"salmon" , PALETTERGB (250,128,114)},
1431 {"light salmon" , PALETTERGB (255,160,122)},
1432 {"LightSalmon" , PALETTERGB (255,160,122)},
1433 {"orange" , PALETTERGB (255,165, 0)},
1434 {"dark orange" , PALETTERGB (255,140, 0)},
1435 {"DarkOrange" , PALETTERGB (255,140, 0)},
1436 {"coral" , PALETTERGB (255,127, 80)},
1437 {"light coral" , PALETTERGB (240,128,128)},
1438 {"LightCoral" , PALETTERGB (240,128,128)},
1439 {"tomato" , PALETTERGB (255, 99, 71)},
1440 {"orange red" , PALETTERGB (255, 69, 0)},
1441 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1442 {"red" , PALETTERGB (255, 0, 0)},
1443 {"hot pink" , PALETTERGB (255,105,180)},
1444 {"HotPink" , PALETTERGB (255,105,180)},
1445 {"deep pink" , PALETTERGB (255, 20,147)},
1446 {"DeepPink" , PALETTERGB (255, 20,147)},
1447 {"pink" , PALETTERGB (255,192,203)},
1448 {"light pink" , PALETTERGB (255,182,193)},
1449 {"LightPink" , PALETTERGB (255,182,193)},
1450 {"pale violet red" , PALETTERGB (219,112,147)},
1451 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1452 {"maroon" , PALETTERGB (176, 48, 96)},
1453 {"medium violet red" , PALETTERGB (199, 21,133)},
1454 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1455 {"violet red" , PALETTERGB (208, 32,144)},
1456 {"VioletRed" , PALETTERGB (208, 32,144)},
1457 {"magenta" , PALETTERGB (255, 0,255)},
1458 {"violet" , PALETTERGB (238,130,238)},
1459 {"plum" , PALETTERGB (221,160,221)},
1460 {"orchid" , PALETTERGB (218,112,214)},
1461 {"medium orchid" , PALETTERGB (186, 85,211)},
1462 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1463 {"dark orchid" , PALETTERGB (153, 50,204)},
1464 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1465 {"dark violet" , PALETTERGB (148, 0,211)},
1466 {"DarkViolet" , PALETTERGB (148, 0,211)},
1467 {"blue violet" , PALETTERGB (138, 43,226)},
1468 {"BlueViolet" , PALETTERGB (138, 43,226)},
1469 {"purple" , PALETTERGB (160, 32,240)},
1470 {"medium purple" , PALETTERGB (147,112,219)},
1471 {"MediumPurple" , PALETTERGB (147,112,219)},
1472 {"thistle" , PALETTERGB (216,191,216)},
1473 {"gray0" , PALETTERGB ( 0, 0, 0)},
1474 {"grey0" , PALETTERGB ( 0, 0, 0)},
1475 {"dark grey" , PALETTERGB (169,169,169)},
1476 {"DarkGrey" , PALETTERGB (169,169,169)},
1477 {"dark gray" , PALETTERGB (169,169,169)},
1478 {"DarkGray" , PALETTERGB (169,169,169)},
1479 {"dark blue" , PALETTERGB ( 0, 0,139)},
1480 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1481 {"dark cyan" , PALETTERGB ( 0,139,139)},
1482 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1483 {"dark magenta" , PALETTERGB (139, 0,139)},
1484 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1485 {"dark red" , PALETTERGB (139, 0, 0)},
1486 {"DarkRed" , PALETTERGB (139, 0, 0)},
1487 {"light green" , PALETTERGB (144,238,144)},
1488 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1489};
1490
fbd6baed 1491DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1492 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1493 ()
1494{
1495 int i;
fbd6baed 1496 colormap_t *pc = w32_color_map;
ee78dc32
GV
1497 Lisp_Object cmap;
1498
1499 BLOCK_INPUT;
1500
1501 cmap = Qnil;
1502
fbd6baed 1503 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1504 pc++, i++)
1505 cmap = Fcons (Fcons (build_string (pc->name),
1506 make_number (pc->colorref)),
1507 cmap);
1508
1509 UNBLOCK_INPUT;
1510
1511 return (cmap);
1512}
ee78dc32
GV
1513
1514Lisp_Object
fbd6baed 1515w32_to_x_color (rgb)
ee78dc32
GV
1516 Lisp_Object rgb;
1517{
1518 Lisp_Object color;
1519
b7826503 1520 CHECK_NUMBER (rgb);
ee78dc32
GV
1521
1522 BLOCK_INPUT;
1523
fbd6baed 1524 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1525
1526 UNBLOCK_INPUT;
1527
1528 if (!NILP (color))
1529 return (Fcar (color));
1530 else
1531 return Qnil;
1532}
1533
5d7fed93
GV
1534COLORREF
1535w32_color_map_lookup (colorname)
1536 char *colorname;
1537{
1538 Lisp_Object tail, ret = Qnil;
1539
1540 BLOCK_INPUT;
1541
1542 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1543 {
1544 register Lisp_Object elt, tem;
1545
1546 elt = Fcar (tail);
1547 if (!CONSP (elt)) continue;
1548
1549 tem = Fcar (elt);
1550
1551 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1552 {
1553 ret = XUINT (Fcdr (elt));
1554 break;
1555 }
1556
1557 QUIT;
1558 }
1559
1560
1561 UNBLOCK_INPUT;
1562
1563 return ret;
1564}
1565
ee78dc32 1566COLORREF
fbd6baed 1567x_to_w32_color (colorname)
ee78dc32
GV
1568 char * colorname;
1569{
8edb0a6f
JR
1570 register Lisp_Object ret = Qnil;
1571
ee78dc32 1572 BLOCK_INPUT;
1edf84e7
GV
1573
1574 if (colorname[0] == '#')
1575 {
1576 /* Could be an old-style RGB Device specification. */
1577 char *color;
1578 int size;
1579 color = colorname + 1;
1580
1581 size = strlen(color);
1582 if (size == 3 || size == 6 || size == 9 || size == 12)
1583 {
1584 UINT colorval;
1585 int i, pos;
1586 pos = 0;
1587 size /= 3;
1588 colorval = 0;
1589
1590 for (i = 0; i < 3; i++)
1591 {
1592 char *end;
1593 char t;
1594 unsigned long value;
1595
1596 /* The check for 'x' in the following conditional takes into
1597 account the fact that strtol allows a "0x" in front of
1598 our numbers, and we don't. */
1599 if (!isxdigit(color[0]) || color[1] == 'x')
1600 break;
1601 t = color[size];
1602 color[size] = '\0';
1603 value = strtoul(color, &end, 16);
1604 color[size] = t;
1605 if (errno == ERANGE || end - color != size)
1606 break;
1607 switch (size)
1608 {
1609 case 1:
1610 value = value * 0x10;
1611 break;
1612 case 2:
1613 break;
1614 case 3:
1615 value /= 0x10;
1616 break;
1617 case 4:
1618 value /= 0x100;
1619 break;
1620 }
1621 colorval |= (value << pos);
1622 pos += 0x8;
1623 if (i == 2)
1624 {
1625 UNBLOCK_INPUT;
1626 return (colorval);
1627 }
1628 color = end;
1629 }
1630 }
1631 }
1632 else if (strnicmp(colorname, "rgb:", 4) == 0)
1633 {
1634 char *color;
1635 UINT colorval;
1636 int i, pos;
1637 pos = 0;
1638
1639 colorval = 0;
1640 color = colorname + 4;
1641 for (i = 0; i < 3; i++)
1642 {
1643 char *end;
1644 unsigned long value;
1645
1646 /* The check for 'x' in the following conditional takes into
1647 account the fact that strtol allows a "0x" in front of
1648 our numbers, and we don't. */
1649 if (!isxdigit(color[0]) || color[1] == 'x')
1650 break;
1651 value = strtoul(color, &end, 16);
1652 if (errno == ERANGE)
1653 break;
1654 switch (end - color)
1655 {
1656 case 1:
1657 value = value * 0x10 + value;
1658 break;
1659 case 2:
1660 break;
1661 case 3:
1662 value /= 0x10;
1663 break;
1664 case 4:
1665 value /= 0x100;
1666 break;
1667 default:
1668 value = ULONG_MAX;
1669 }
1670 if (value == ULONG_MAX)
1671 break;
1672 colorval |= (value << pos);
1673 pos += 0x8;
1674 if (i == 2)
1675 {
1676 if (*end != '\0')
1677 break;
1678 UNBLOCK_INPUT;
1679 return (colorval);
1680 }
1681 if (*end != '/')
1682 break;
1683 color = end + 1;
1684 }
1685 }
1686 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1687 {
1688 /* This is an RGB Intensity specification. */
1689 char *color;
1690 UINT colorval;
1691 int i, pos;
1692 pos = 0;
1693
1694 colorval = 0;
1695 color = colorname + 5;
1696 for (i = 0; i < 3; i++)
1697 {
1698 char *end;
1699 double value;
1700 UINT val;
1701
1702 value = strtod(color, &end);
1703 if (errno == ERANGE)
1704 break;
1705 if (value < 0.0 || value > 1.0)
1706 break;
1707 val = (UINT)(0x100 * value);
1708 /* We used 0x100 instead of 0xFF to give an continuous
1709 range between 0.0 and 1.0 inclusive. The next statement
1710 fixes the 1.0 case. */
1711 if (val == 0x100)
1712 val = 0xFF;
1713 colorval |= (val << pos);
1714 pos += 0x8;
1715 if (i == 2)
1716 {
1717 if (*end != '\0')
1718 break;
1719 UNBLOCK_INPUT;
1720 return (colorval);
1721 }
1722 if (*end != '/')
1723 break;
1724 color = end + 1;
1725 }
1726 }
1727 /* I am not going to attempt to handle any of the CIE color schemes
1728 or TekHVC, since I don't know the algorithms for conversion to
1729 RGB. */
f695b4b1
GV
1730
1731 /* If we fail to lookup the color name in w32_color_map, then check the
1732 colorname to see if it can be crudely approximated: If the X color
1733 ends in a number (e.g., "darkseagreen2"), strip the number and
1734 return the result of looking up the base color name. */
1735 ret = w32_color_map_lookup (colorname);
1736 if (NILP (ret))
ee78dc32 1737 {
f695b4b1 1738 int len = strlen (colorname);
ee78dc32 1739
f695b4b1
GV
1740 if (isdigit (colorname[len - 1]))
1741 {
8b77111c 1742 char *ptr, *approx = alloca (len + 1);
ee78dc32 1743
f695b4b1
GV
1744 strcpy (approx, colorname);
1745 ptr = &approx[len - 1];
1746 while (ptr > approx && isdigit (*ptr))
1747 *ptr-- = '\0';
ee78dc32 1748
f695b4b1 1749 ret = w32_color_map_lookup (approx);
ee78dc32 1750 }
ee78dc32
GV
1751 }
1752
1753 UNBLOCK_INPUT;
ee78dc32
GV
1754 return ret;
1755}
1756
5ac45f98
GV
1757
1758void
fbd6baed 1759w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1760{
fbd6baed 1761 struct w32_palette_entry * list;
5ac45f98
GV
1762 LOGPALETTE * log_palette;
1763 HPALETTE new_palette;
1764 int i;
1765
1766 /* don't bother trying to create palette if not supported */
fbd6baed 1767 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1768 return;
1769
1770 log_palette = (LOGPALETTE *)
1771 alloca (sizeof (LOGPALETTE) +
fbd6baed 1772 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1773 log_palette->palVersion = 0x300;
fbd6baed 1774 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1775
fbd6baed 1776 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1777 for (i = 0;
fbd6baed 1778 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1779 i++, list = list->next)
1780 log_palette->palPalEntry[i] = list->entry;
1781
1782 new_palette = CreatePalette (log_palette);
1783
1784 enter_crit ();
1785
fbd6baed
GV
1786 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1787 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1788 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1789
1790 /* Realize display palette and garbage all frames. */
1791 release_frame_dc (f, get_frame_dc (f));
1792
1793 leave_crit ();
1794}
1795
fbd6baed
GV
1796#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1797#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1798 do \
1799 { \
1800 pe.peRed = GetRValue (color); \
1801 pe.peGreen = GetGValue (color); \
1802 pe.peBlue = GetBValue (color); \
1803 pe.peFlags = 0; \
1804 } while (0)
1805
1806#if 0
1807/* Keep these around in case we ever want to track color usage. */
1808void
fbd6baed 1809w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1810{
fbd6baed 1811 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1812
fbd6baed 1813 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1814 return;
1815
1816 /* check if color is already mapped */
1817 while (list)
1818 {
fbd6baed 1819 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1820 {
1821 ++list->refcount;
1822 return;
1823 }
1824 list = list->next;
1825 }
1826
1827 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1828 list = (struct w32_palette_entry *)
1829 xmalloc (sizeof (struct w32_palette_entry));
1830 SET_W32_COLOR (list->entry, color);
5ac45f98 1831 list->refcount = 1;
fbd6baed
GV
1832 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1833 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1834 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1835
1836 /* set flag that palette must be regenerated */
fbd6baed 1837 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1838}
1839
1840void
fbd6baed 1841w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1842{
fbd6baed
GV
1843 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1844 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1845
fbd6baed 1846 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1847 return;
1848
1849 /* check if color is already mapped */
1850 while (list)
1851 {
fbd6baed 1852 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1853 {
1854 if (--list->refcount == 0)
1855 {
1856 *prev = list->next;
1857 xfree (list);
fbd6baed 1858 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1859 break;
1860 }
1861 else
1862 return;
1863 }
1864 prev = &list->next;
1865 list = list->next;
1866 }
1867
1868 /* set flag that palette must be regenerated */
fbd6baed 1869 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1870}
1871#endif
1872
6fc2811b
JR
1873
1874/* Gamma-correct COLOR on frame F. */
1875
1876void
1877gamma_correct (f, color)
1878 struct frame *f;
1879 COLORREF *color;
1880{
1881 if (f->gamma)
1882 {
1883 *color = PALETTERGB (
1884 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1885 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1886 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1887 }
1888}
1889
1890
ee78dc32
GV
1891/* Decide if color named COLOR is valid for the display associated with
1892 the selected frame; if so, return the rgb values in COLOR_DEF.
1893 If ALLOC is nonzero, allocate a new colormap cell. */
1894
1895int
6fc2811b 1896w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1897 FRAME_PTR f;
1898 char *color;
6fc2811b 1899 XColor *color_def;
ee78dc32
GV
1900 int alloc;
1901{
1902 register Lisp_Object tem;
6fc2811b 1903 COLORREF w32_color_ref;
3c190163 1904
fbd6baed 1905 tem = x_to_w32_color (color);
3c190163 1906
ee78dc32
GV
1907 if (!NILP (tem))
1908 {
d88c567c
JR
1909 if (f)
1910 {
1911 /* Apply gamma correction. */
1912 w32_color_ref = XUINT (tem);
1913 gamma_correct (f, &w32_color_ref);
1914 XSETINT (tem, w32_color_ref);
1915 }
9badad41
JR
1916
1917 /* Map this color to the palette if it is enabled. */
fbd6baed 1918 if (!NILP (Vw32_enable_palette))
5ac45f98 1919 {
fbd6baed 1920 struct w32_palette_entry * entry =
d88c567c 1921 one_w32_display_info.color_list;
fbd6baed 1922 struct w32_palette_entry ** prev =
d88c567c 1923 &one_w32_display_info.color_list;
5ac45f98
GV
1924
1925 /* check if color is already mapped */
1926 while (entry)
1927 {
fbd6baed 1928 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1929 break;
1930 prev = &entry->next;
1931 entry = entry->next;
1932 }
1933
1934 if (entry == NULL && alloc)
1935 {
1936 /* not already mapped, so add to list */
fbd6baed
GV
1937 entry = (struct w32_palette_entry *)
1938 xmalloc (sizeof (struct w32_palette_entry));
1939 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1940 entry->next = NULL;
1941 *prev = entry;
d88c567c 1942 one_w32_display_info.num_colors++;
5ac45f98
GV
1943
1944 /* set flag that palette must be regenerated */
d88c567c 1945 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1946 }
1947 }
1948 /* Ensure COLORREF value is snapped to nearest color in (default)
1949 palette by simulating the PALETTERGB macro. This works whether
1950 or not the display device has a palette. */
6fc2811b
JR
1951 w32_color_ref = XUINT (tem) | 0x2000000;
1952
6fc2811b
JR
1953 color_def->pixel = w32_color_ref;
1954 color_def->red = GetRValue (w32_color_ref);
1955 color_def->green = GetGValue (w32_color_ref);
1956 color_def->blue = GetBValue (w32_color_ref);
1957
ee78dc32 1958 return 1;
5ac45f98 1959 }
7fb46567 1960 else
3c190163
GV
1961 {
1962 return 0;
1963 }
ee78dc32
GV
1964}
1965
1966/* Given a string ARG naming a color, compute a pixel value from it
1967 suitable for screen F.
1968 If F is not a color screen, return DEF (default) regardless of what
1969 ARG says. */
1970
1971int
1972x_decode_color (f, arg, def)
1973 FRAME_PTR f;
1974 Lisp_Object arg;
1975 int def;
1976{
6fc2811b 1977 XColor cdef;
ee78dc32 1978
b7826503 1979 CHECK_STRING (arg);
ee78dc32
GV
1980
1981 if (strcmp (XSTRING (arg)->data, "black") == 0)
1982 return BLACK_PIX_DEFAULT (f);
1983 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1984 return WHITE_PIX_DEFAULT (f);
1985
fbd6baed 1986 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1987 return def;
1988
6fc2811b 1989 /* w32_defined_color is responsible for coping with failures
ee78dc32 1990 by looking for a near-miss. */
6fc2811b
JR
1991 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1992 return cdef.pixel;
ee78dc32
GV
1993
1994 /* defined_color failed; return an ultimate default. */
1995 return def;
1996}
1997\f
dfff8a69
JR
1998/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1999 the previous value of that parameter, NEW_VALUE is the new value. */
2000
2001static void
2002x_set_line_spacing (f, new_value, old_value)
2003 struct frame *f;
2004 Lisp_Object new_value, old_value;
2005{
2006 if (NILP (new_value))
2007 f->extra_line_spacing = 0;
2008 else if (NATNUMP (new_value))
2009 f->extra_line_spacing = XFASTINT (new_value);
2010 else
1a948b17 2011 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
2012 Fcons (new_value, Qnil)));
2013 if (FRAME_VISIBLE_P (f))
2014 redraw_frame (f);
2015}
2016
2017
f7b9d4d1
JR
2018/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2019 the previous value of that parameter, NEW_VALUE is the new value. */
2020
2021static void
2022x_set_fullscreen (f, new_value, old_value)
2023 struct frame *f;
2024 Lisp_Object new_value, old_value;
2025{
2026 if (NILP (new_value))
2027 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2028 else if (EQ (new_value, Qfullboth))
2029 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2030 else if (EQ (new_value, Qfullwidth))
2031 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2032 else if (EQ (new_value, Qfullheight))
2033 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2034}
2035
2036
6fc2811b
JR
2037/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2038 the previous value of that parameter, NEW_VALUE is the new value. */
2039
2040static void
2041x_set_screen_gamma (f, new_value, old_value)
2042 struct frame *f;
2043 Lisp_Object new_value, old_value;
2044{
2045 if (NILP (new_value))
2046 f->gamma = 0;
2047 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2048 /* The value 0.4545 is the normal viewing gamma. */
2049 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2050 else
1a948b17 2051 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
2052 Fcons (new_value, Qnil)));
2053
2054 clear_face_cache (0);
2055}
2056
2057
ee78dc32
GV
2058/* Functions called only from `x_set_frame_param'
2059 to set individual parameters.
2060
fbd6baed 2061 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
2062 the frame is being created and its window does not exist yet.
2063 In that case, just record the parameter's new value
2064 in the standard place; do not attempt to change the window. */
2065
2066void
2067x_set_foreground_color (f, arg, oldval)
2068 struct frame *f;
2069 Lisp_Object arg, oldval;
2070{
3cf3436e
JR
2071 struct w32_output *x = f->output_data.w32;
2072 PIX_TYPE fg, old_fg;
2073
2074 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2075 old_fg = FRAME_FOREGROUND_PIXEL (f);
2076 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2077
fbd6baed 2078 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2079 {
3cf3436e
JR
2080 if (x->cursor_pixel == old_fg)
2081 x->cursor_pixel = fg;
2082
6fc2811b 2083 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2084 if (FRAME_VISIBLE_P (f))
2085 redraw_frame (f);
2086 }
2087}
2088
2089void
2090x_set_background_color (f, arg, oldval)
2091 struct frame *f;
2092 Lisp_Object arg, oldval;
2093{
6fc2811b 2094 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2095 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2096
fbd6baed 2097 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2098 {
6fc2811b
JR
2099 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2100 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2101
6fc2811b 2102 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2103
2104 if (FRAME_VISIBLE_P (f))
2105 redraw_frame (f);
2106 }
2107}
2108
2109void
2110x_set_mouse_color (f, arg, oldval)
2111 struct frame *f;
2112 Lisp_Object arg, oldval;
2113{
ee78dc32 2114 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2115 int count;
ee78dc32
GV
2116 int mask_color;
2117
2118 if (!EQ (Qnil, arg))
fbd6baed 2119 f->output_data.w32->mouse_pixel
ee78dc32 2120 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2121 mask_color = FRAME_BACKGROUND_PIXEL (f);
2122
2123 /* Don't let pointers be invisible. */
fbd6baed 2124 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2125 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2126 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2127
767b1ff0 2128#if 0 /* TODO : cursor changes */
ee78dc32
GV
2129 BLOCK_INPUT;
2130
2131 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2132 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2133
2134 if (!EQ (Qnil, Vx_pointer_shape))
2135 {
b7826503 2136 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2137 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2138 }
2139 else
fbd6baed
GV
2140 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2141 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2142
2143 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2144 {
b7826503 2145 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2146 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2147 XINT (Vx_nontext_pointer_shape));
2148 }
2149 else
fbd6baed
GV
2150 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2151 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2152
0af913d7 2153 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2154 {
b7826503 2155 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2156 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2157 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2158 }
2159 else
0af913d7 2160 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b
JR
2161 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2162
2163 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2164 if (!EQ (Qnil, Vx_mode_pointer_shape))
2165 {
b7826503 2166 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2167 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2168 XINT (Vx_mode_pointer_shape));
2169 }
2170 else
fbd6baed
GV
2171 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2172 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2173
2174 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2175 {
b7826503 2176 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2177 cross_cursor
fbd6baed 2178 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2179 XINT (Vx_sensitive_text_pointer_shape));
2180 }
2181 else
fbd6baed 2182 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2183
4694d762
JR
2184 if (!NILP (Vx_window_horizontal_drag_shape))
2185 {
b7826503 2186 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2187 horizontal_drag_cursor
2188 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2189 XINT (Vx_window_horizontal_drag_shape));
2190 }
2191 else
2192 horizontal_drag_cursor
2193 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2194
ee78dc32 2195 /* Check and report errors with the above calls. */
fbd6baed 2196 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2197 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2198
2199 {
2200 XColor fore_color, back_color;
2201
fbd6baed 2202 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2203 back_color.pixel = mask_color;
fbd6baed
GV
2204 XQueryColor (FRAME_W32_DISPLAY (f),
2205 DefaultColormap (FRAME_W32_DISPLAY (f),
2206 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2207 &fore_color);
fbd6baed
GV
2208 XQueryColor (FRAME_W32_DISPLAY (f),
2209 DefaultColormap (FRAME_W32_DISPLAY (f),
2210 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2211 &back_color);
fbd6baed 2212 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2213 &fore_color, &back_color);
fbd6baed 2214 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2215 &fore_color, &back_color);
fbd6baed 2216 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2217 &fore_color, &back_color);
fbd6baed 2218 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2219 &fore_color, &back_color);
0af913d7 2220 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2221 &fore_color, &back_color);
ee78dc32
GV
2222 }
2223
fbd6baed 2224 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2225 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2226
fbd6baed
GV
2227 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2228 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2229 f->output_data.w32->text_cursor = cursor;
2230
2231 if (nontext_cursor != f->output_data.w32->nontext_cursor
2232 && f->output_data.w32->nontext_cursor != 0)
2233 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2234 f->output_data.w32->nontext_cursor = nontext_cursor;
2235
0af913d7
GM
2236 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2237 && f->output_data.w32->hourglass_cursor != 0)
2238 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2239 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2240
fbd6baed
GV
2241 if (mode_cursor != f->output_data.w32->modeline_cursor
2242 && f->output_data.w32->modeline_cursor != 0)
2243 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2244 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2245
fbd6baed
GV
2246 if (cross_cursor != f->output_data.w32->cross_cursor
2247 && f->output_data.w32->cross_cursor != 0)
2248 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2249 f->output_data.w32->cross_cursor = cross_cursor;
2250
2251 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2252 UNBLOCK_INPUT;
6fc2811b
JR
2253
2254 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2255#endif /* TODO */
ee78dc32
GV
2256}
2257
70a0239a
JR
2258/* Defined in w32term.c. */
2259void x_update_cursor (struct frame *f, int on_p);
2260
ee78dc32
GV
2261void
2262x_set_cursor_color (f, arg, oldval)
2263 struct frame *f;
2264 Lisp_Object arg, oldval;
2265{
70a0239a 2266 unsigned long fore_pixel, pixel;
ee78dc32 2267
dfff8a69 2268 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2269 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2270 WHITE_PIX_DEFAULT (f));
ee78dc32 2271 else
6fc2811b 2272 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2273
6759f872 2274 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2275
2276 /* Make sure that the cursor color differs from the background color. */
70a0239a 2277 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2278 {
70a0239a
JR
2279 pixel = f->output_data.w32->mouse_pixel;
2280 if (pixel == fore_pixel)
6fc2811b 2281 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2282 }
70a0239a 2283
6fc2811b 2284 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
70a0239a 2285 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2286
fbd6baed 2287 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2288 {
2289 if (FRAME_VISIBLE_P (f))
2290 {
70a0239a
JR
2291 x_update_cursor (f, 0);
2292 x_update_cursor (f, 1);
ee78dc32
GV
2293 }
2294 }
6fc2811b
JR
2295
2296 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2297}
2298
33d52f9c
GV
2299/* Set the border-color of frame F to pixel value PIX.
2300 Note that this does not fully take effect if done before
2301 F has an window. */
2302void
2303x_set_border_pixel (f, pix)
2304 struct frame *f;
2305 int pix;
2306{
2307 f->output_data.w32->border_pixel = pix;
2308
2309 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2310 {
2311 if (FRAME_VISIBLE_P (f))
2312 redraw_frame (f);
2313 }
2314}
2315
ee78dc32
GV
2316/* Set the border-color of frame F to value described by ARG.
2317 ARG can be a string naming a color.
2318 The border-color is used for the border that is drawn by the server.
2319 Note that this does not fully take effect if done before
2320 F has a window; it must be redone when the window is created. */
2321
2322void
2323x_set_border_color (f, arg, oldval)
2324 struct frame *f;
2325 Lisp_Object arg, oldval;
2326{
ee78dc32
GV
2327 int pix;
2328
b7826503 2329 CHECK_STRING (arg);
ee78dc32 2330 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2331 x_set_border_pixel (f, pix);
6fc2811b 2332 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2333}
2334
dfff8a69
JR
2335/* Value is the internal representation of the specified cursor type
2336 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2337 of the bar cursor. */
2338
2339enum text_cursor_kinds
2340x_specified_cursor_type (arg, width)
2341 Lisp_Object arg;
2342 int *width;
ee78dc32 2343{
dfff8a69
JR
2344 enum text_cursor_kinds type;
2345
ee78dc32
GV
2346 if (EQ (arg, Qbar))
2347 {
dfff8a69
JR
2348 type = BAR_CURSOR;
2349 *width = 2;
ee78dc32 2350 }
dfff8a69
JR
2351 else if (CONSP (arg)
2352 && EQ (XCAR (arg), Qbar)
2353 && INTEGERP (XCDR (arg))
2354 && XINT (XCDR (arg)) >= 0)
ee78dc32 2355 {
dfff8a69
JR
2356 type = BAR_CURSOR;
2357 *width = XINT (XCDR (arg));
ee78dc32 2358 }
dfff8a69
JR
2359 else if (NILP (arg))
2360 type = NO_CURSOR;
ee78dc32
GV
2361 else
2362 /* Treat anything unknown as "box cursor".
2363 It was bad to signal an error; people have trouble fixing
2364 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2365 type = FILLED_BOX_CURSOR;
2366
2367 return type;
2368}
2369
2370void
2371x_set_cursor_type (f, arg, oldval)
2372 FRAME_PTR f;
2373 Lisp_Object arg, oldval;
2374{
2375 int width;
2376
2377 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2378 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2379
2380 /* Make sure the cursor gets redrawn. This is overkill, but how
2381 often do people change cursor types? */
2382 update_mode_lines++;
2383}
dfff8a69 2384\f
ee78dc32
GV
2385void
2386x_set_icon_type (f, arg, oldval)
2387 struct frame *f;
2388 Lisp_Object arg, oldval;
2389{
ee78dc32
GV
2390 int result;
2391
eb7576ce
GV
2392 if (NILP (arg) && NILP (oldval))
2393 return;
2394
2395 if (STRINGP (arg) && STRINGP (oldval)
2396 && EQ (Fstring_equal (oldval, arg), Qt))
2397 return;
2398
2399 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2400 return;
2401
2402 BLOCK_INPUT;
ee78dc32 2403
eb7576ce 2404 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2405 if (result)
2406 {
2407 UNBLOCK_INPUT;
2408 error ("No icon window available");
2409 }
2410
ee78dc32 2411 UNBLOCK_INPUT;
ee78dc32
GV
2412}
2413
2414/* Return non-nil if frame F wants a bitmap icon. */
2415
2416Lisp_Object
2417x_icon_type (f)
2418 FRAME_PTR f;
2419{
2420 Lisp_Object tem;
2421
2422 tem = assq_no_quit (Qicon_type, f->param_alist);
2423 if (CONSP (tem))
8e713be6 2424 return XCDR (tem);
ee78dc32
GV
2425 else
2426 return Qnil;
2427}
2428
2429void
2430x_set_icon_name (f, arg, oldval)
2431 struct frame *f;
2432 Lisp_Object arg, oldval;
2433{
ee78dc32
GV
2434 if (STRINGP (arg))
2435 {
2436 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2437 return;
2438 }
2439 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2440 return;
2441
2442 f->icon_name = arg;
2443
2444#if 0
fbd6baed 2445 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2446 return;
2447
2448 BLOCK_INPUT;
2449
2450 result = x_text_icon (f,
1edf84e7 2451 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2452 ? f->icon_name
1edf84e7
GV
2453 : !NILP (f->title)
2454 ? f->title
ee78dc32
GV
2455 : f->name))->data);
2456
2457 if (result)
2458 {
2459 UNBLOCK_INPUT;
2460 error ("No icon window available");
2461 }
2462
2463 /* If the window was unmapped (and its icon was mapped),
2464 the new icon is not mapped, so map the window in its stead. */
2465 if (FRAME_VISIBLE_P (f))
2466 {
2467#ifdef USE_X_TOOLKIT
fbd6baed 2468 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2469#endif
fbd6baed 2470 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2471 }
2472
fbd6baed 2473 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2474 UNBLOCK_INPUT;
2475#endif
2476}
2477
2478extern Lisp_Object x_new_font ();
4587b026 2479extern Lisp_Object x_new_fontset();
ee78dc32
GV
2480
2481void
2482x_set_font (f, arg, oldval)
2483 struct frame *f;
2484 Lisp_Object arg, oldval;
2485{
2486 Lisp_Object result;
4587b026 2487 Lisp_Object fontset_name;
4b817373 2488 Lisp_Object frame;
3cf3436e 2489 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2490
b7826503 2491 CHECK_STRING (arg);
ee78dc32 2492
4587b026
GV
2493 fontset_name = Fquery_fontset (arg, Qnil);
2494
ee78dc32 2495 BLOCK_INPUT;
4587b026
GV
2496 result = (STRINGP (fontset_name)
2497 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2498 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2499 UNBLOCK_INPUT;
2500
2501 if (EQ (result, Qnil))
dfff8a69 2502 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2503 else if (EQ (result, Qt))
dfff8a69 2504 error ("The characters of the given font have varying widths");
ee78dc32
GV
2505 else if (STRINGP (result))
2506 {
3cf3436e
JR
2507 if (STRINGP (fontset_name))
2508 {
2509 /* Fontset names are built from ASCII font names, so the
2510 names may be equal despite there was a change. */
2511 if (old_fontset == FRAME_FONTSET (f))
2512 return;
2513 }
2514 else if (!NILP (Fequal (result, oldval)))
dc220243 2515 return;
3cf3436e 2516
ee78dc32 2517 store_frame_param (f, Qfont, result);
6fc2811b 2518 recompute_basic_faces (f);
ee78dc32
GV
2519 }
2520 else
2521 abort ();
4b817373 2522
6fc2811b
JR
2523 do_pending_window_change (0);
2524
2525 /* Don't call `face-set-after-frame-default' when faces haven't been
2526 initialized yet. This is the case when called from
2527 Fx_create_frame. In that case, the X widget or window doesn't
2528 exist either, and we can end up in x_report_frame_params with a
2529 null widget which gives a segfault. */
2530 if (FRAME_FACE_CACHE (f))
2531 {
2532 XSETFRAME (frame, f);
2533 call1 (Qface_set_after_frame_default, frame);
2534 }
ee78dc32
GV
2535}
2536
41c1bdd9
KS
2537static void
2538x_set_fringe_width (f, new_value, old_value)
2539 struct frame *f;
2540 Lisp_Object new_value, old_value;
2541{
2542 x_compute_fringe_widths (f, 1);
2543}
2544
ee78dc32
GV
2545void
2546x_set_border_width (f, arg, oldval)
2547 struct frame *f;
2548 Lisp_Object arg, oldval;
2549{
b7826503 2550 CHECK_NUMBER (arg);
ee78dc32 2551
fbd6baed 2552 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2553 return;
2554
fbd6baed 2555 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2556 error ("Cannot change the border width of a window");
2557
fbd6baed 2558 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2559}
2560
2561void
2562x_set_internal_border_width (f, arg, oldval)
2563 struct frame *f;
2564 Lisp_Object arg, oldval;
2565{
fbd6baed 2566 int old = f->output_data.w32->internal_border_width;
ee78dc32 2567
b7826503 2568 CHECK_NUMBER (arg);
fbd6baed
GV
2569 f->output_data.w32->internal_border_width = XINT (arg);
2570 if (f->output_data.w32->internal_border_width < 0)
2571 f->output_data.w32->internal_border_width = 0;
ee78dc32 2572
fbd6baed 2573 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2574 return;
2575
fbd6baed 2576 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2577 {
ee78dc32 2578 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2579 SET_FRAME_GARBAGED (f);
6fc2811b 2580 do_pending_window_change (0);
ee78dc32 2581 }
a05e2bae
JR
2582 else
2583 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2584}
2585
2586void
2587x_set_visibility (f, value, oldval)
2588 struct frame *f;
2589 Lisp_Object value, oldval;
2590{
2591 Lisp_Object frame;
2592 XSETFRAME (frame, f);
2593
2594 if (NILP (value))
2595 Fmake_frame_invisible (frame, Qt);
2596 else if (EQ (value, Qicon))
2597 Ficonify_frame (frame);
2598 else
2599 Fmake_frame_visible (frame);
2600}
2601
a1258667
JR
2602\f
2603/* Change window heights in windows rooted in WINDOW by N lines. */
2604
2605static void
2606x_change_window_heights (window, n)
2607 Lisp_Object window;
2608 int n;
2609{
2610 struct window *w = XWINDOW (window);
2611
2612 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2613 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2614
2615 if (INTEGERP (w->orig_top))
2616 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2617 if (INTEGERP (w->orig_height))
2618 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2619
2620 /* Handle just the top child in a vertical split. */
2621 if (!NILP (w->vchild))
2622 x_change_window_heights (w->vchild, n);
2623
2624 /* Adjust all children in a horizontal split. */
2625 for (window = w->hchild; !NILP (window); window = w->next)
2626 {
2627 w = XWINDOW (window);
2628 x_change_window_heights (window, n);
2629 }
2630}
2631
ee78dc32
GV
2632void
2633x_set_menu_bar_lines (f, value, oldval)
2634 struct frame *f;
2635 Lisp_Object value, oldval;
2636{
2637 int nlines;
2638 int olines = FRAME_MENU_BAR_LINES (f);
2639
2640 /* Right now, menu bars don't work properly in minibuf-only frames;
2641 most of the commands try to apply themselves to the minibuffer
6fc2811b 2642 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2643 in or split the minibuffer window. */
2644 if (FRAME_MINIBUF_ONLY_P (f))
2645 return;
2646
2647 if (INTEGERP (value))
2648 nlines = XINT (value);
2649 else
2650 nlines = 0;
2651
2652 FRAME_MENU_BAR_LINES (f) = 0;
2653 if (nlines)
2654 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2655 else
2656 {
2657 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2658 free_frame_menubar (f);
2659 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2660
2661 /* Adjust the frame size so that the client (text) dimensions
2662 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2663 set correctly. */
2664 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2665 do_pending_window_change (0);
ee78dc32 2666 }
6fc2811b
JR
2667 adjust_glyphs (f);
2668}
2669
2670
2671/* Set the number of lines used for the tool bar of frame F to VALUE.
2672 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2673 is the old number of tool bar lines. This function changes the
2674 height of all windows on frame F to match the new tool bar height.
2675 The frame's height doesn't change. */
2676
2677void
2678x_set_tool_bar_lines (f, value, oldval)
2679 struct frame *f;
2680 Lisp_Object value, oldval;
2681{
36f8209a
JR
2682 int delta, nlines, root_height;
2683 Lisp_Object root_window;
6fc2811b 2684
dc220243
JR
2685 /* Treat tool bars like menu bars. */
2686 if (FRAME_MINIBUF_ONLY_P (f))
2687 return;
2688
6fc2811b
JR
2689 /* Use VALUE only if an integer >= 0. */
2690 if (INTEGERP (value) && XINT (value) >= 0)
2691 nlines = XFASTINT (value);
2692 else
2693 nlines = 0;
2694
2695 /* Make sure we redisplay all windows in this frame. */
2696 ++windows_or_buffers_changed;
2697
2698 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2699
2700 /* Don't resize the tool-bar to more than we have room for. */
2701 root_window = FRAME_ROOT_WINDOW (f);
2702 root_height = XINT (XWINDOW (root_window)->height);
2703 if (root_height - delta < 1)
2704 {
2705 delta = root_height - 1;
2706 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2707 }
2708
6fc2811b 2709 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2710 x_change_window_heights (root_window, delta);
6fc2811b 2711 adjust_glyphs (f);
36f8209a
JR
2712
2713 /* We also have to make sure that the internal border at the top of
2714 the frame, below the menu bar or tool bar, is redrawn when the
2715 tool bar disappears. This is so because the internal border is
2716 below the tool bar if one is displayed, but is below the menu bar
2717 if there isn't a tool bar. The tool bar draws into the area
2718 below the menu bar. */
2719 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2720 {
2721 updating_frame = f;
2722 clear_frame ();
2723 clear_current_matrices (f);
2724 updating_frame = NULL;
2725 }
2726
2727 /* If the tool bar gets smaller, the internal border below it
2728 has to be cleared. It was formerly part of the display
2729 of the larger tool bar, and updating windows won't clear it. */
2730 if (delta < 0)
2731 {
2732 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2733 int width = PIXEL_WIDTH (f);
2734 int y = nlines * CANON_Y_UNIT (f);
2735
2736 BLOCK_INPUT;
2737 {
2738 HDC hdc = get_frame_dc (f);
2739 w32_clear_area (f, hdc, 0, y, width, height);
2740 release_frame_dc (f, hdc);
2741 }
2742 UNBLOCK_INPUT;
3cf3436e
JR
2743
2744 if (WINDOWP (f->tool_bar_window))
2745 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2746 }
ee78dc32
GV
2747}
2748
6fc2811b 2749
ee78dc32 2750/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2751 w32_id_name.
ee78dc32
GV
2752
2753 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2754 name; if NAME is a string, set F's name to NAME and set
2755 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2756
2757 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2758 suggesting a new name, which lisp code should override; if
2759 F->explicit_name is set, ignore the new name; otherwise, set it. */
2760
2761void
2762x_set_name (f, name, explicit)
2763 struct frame *f;
2764 Lisp_Object name;
2765 int explicit;
2766{
2767 /* Make sure that requests from lisp code override requests from
2768 Emacs redisplay code. */
2769 if (explicit)
2770 {
2771 /* If we're switching from explicit to implicit, we had better
2772 update the mode lines and thereby update the title. */
2773 if (f->explicit_name && NILP (name))
2774 update_mode_lines = 1;
2775
2776 f->explicit_name = ! NILP (name);
2777 }
2778 else if (f->explicit_name)
2779 return;
2780
fbd6baed 2781 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2782 if (NILP (name))
2783 {
2784 /* Check for no change needed in this very common case
2785 before we do any consing. */
fbd6baed 2786 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2787 XSTRING (f->name)->data))
2788 return;
fbd6baed 2789 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2790 }
2791 else
b7826503 2792 CHECK_STRING (name);
ee78dc32
GV
2793
2794 /* Don't change the name if it's already NAME. */
2795 if (! NILP (Fstring_equal (name, f->name)))
2796 return;
2797
1edf84e7
GV
2798 f->name = name;
2799
2800 /* For setting the frame title, the title parameter should override
2801 the name parameter. */
2802 if (! NILP (f->title))
2803 name = f->title;
2804
fbd6baed 2805 if (FRAME_W32_WINDOW (f))
ee78dc32 2806 {
6fc2811b 2807 if (STRING_MULTIBYTE (name))
dfff8a69 2808 name = ENCODE_SYSTEM (name);
6fc2811b 2809
ee78dc32 2810 BLOCK_INPUT;
fbd6baed 2811 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2812 UNBLOCK_INPUT;
2813 }
ee78dc32
GV
2814}
2815
2816/* This function should be called when the user's lisp code has
2817 specified a name for the frame; the name will override any set by the
2818 redisplay code. */
2819void
2820x_explicitly_set_name (f, arg, oldval)
2821 FRAME_PTR f;
2822 Lisp_Object arg, oldval;
2823{
2824 x_set_name (f, arg, 1);
2825}
2826
2827/* This function should be called by Emacs redisplay code to set the
2828 name; names set this way will never override names set by the user's
2829 lisp code. */
2830void
2831x_implicitly_set_name (f, arg, oldval)
2832 FRAME_PTR f;
2833 Lisp_Object arg, oldval;
2834{
2835 x_set_name (f, arg, 0);
2836}
1edf84e7
GV
2837\f
2838/* Change the title of frame F to NAME.
2839 If NAME is nil, use the frame name as the title.
2840
2841 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2842 name; if NAME is a string, set F's name to NAME and set
2843 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2844
2845 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2846 suggesting a new name, which lisp code should override; if
2847 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2848
1edf84e7 2849void
6fc2811b 2850x_set_title (f, name, old_name)
1edf84e7 2851 struct frame *f;
6fc2811b 2852 Lisp_Object name, old_name;
1edf84e7
GV
2853{
2854 /* Don't change the title if it's already NAME. */
2855 if (EQ (name, f->title))
2856 return;
2857
2858 update_mode_lines = 1;
2859
2860 f->title = name;
2861
2862 if (NILP (name))
2863 name = f->name;
2864
2865 if (FRAME_W32_WINDOW (f))
2866 {
6fc2811b 2867 if (STRING_MULTIBYTE (name))
dfff8a69 2868 name = ENCODE_SYSTEM (name);
6fc2811b 2869
1edf84e7
GV
2870 BLOCK_INPUT;
2871 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2872 UNBLOCK_INPUT;
2873 }
2874}
2875\f
ee78dc32
GV
2876void
2877x_set_autoraise (f, arg, oldval)
2878 struct frame *f;
2879 Lisp_Object arg, oldval;
2880{
2881 f->auto_raise = !EQ (Qnil, arg);
2882}
2883
2884void
2885x_set_autolower (f, arg, oldval)
2886 struct frame *f;
2887 Lisp_Object arg, oldval;
2888{
2889 f->auto_lower = !EQ (Qnil, arg);
2890}
2891
2892void
2893x_set_unsplittable (f, arg, oldval)
2894 struct frame *f;
2895 Lisp_Object arg, oldval;
2896{
2897 f->no_split = !NILP (arg);
2898}
2899
2900void
2901x_set_vertical_scroll_bars (f, arg, oldval)
2902 struct frame *f;
2903 Lisp_Object arg, oldval;
2904{
1026b400
RS
2905 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2906 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2907 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2908 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2909 {
1026b400
RS
2910 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2911 vertical_scroll_bar_none :
87996783
GV
2912 /* Put scroll bars on the right by default, as is conventional
2913 on MS-Windows. */
2914 EQ (Qleft, arg)
2915 ? vertical_scroll_bar_left
2916 : vertical_scroll_bar_right;
ee78dc32
GV
2917
2918 /* We set this parameter before creating the window for the
2919 frame, so we can get the geometry right from the start.
2920 However, if the window hasn't been created yet, we shouldn't
2921 call x_set_window_size. */
fbd6baed 2922 if (FRAME_W32_WINDOW (f))
ee78dc32 2923 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2924 do_pending_window_change (0);
ee78dc32
GV
2925 }
2926}
2927
2928void
2929x_set_scroll_bar_width (f, arg, oldval)
2930 struct frame *f;
2931 Lisp_Object arg, oldval;
2932{
6fc2811b
JR
2933 int wid = FONT_WIDTH (f->output_data.w32->font);
2934
ee78dc32
GV
2935 if (NILP (arg))
2936 {
6fc2811b
JR
2937 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2938 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2939 wid - 1) / wid;
2940 if (FRAME_W32_WINDOW (f))
2941 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2942 do_pending_window_change (0);
ee78dc32
GV
2943 }
2944 else if (INTEGERP (arg) && XINT (arg) > 0
2945 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2946 {
ee78dc32 2947 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2948 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2949 + wid-1) / wid;
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 2953 }
6fc2811b
JR
2954 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2955 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2956 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2957}
2958\f
2959/* Subroutines of creating an frame. */
2960
2961/* Make sure that Vx_resource_name is set to a reasonable value.
2962 Fix it up, or set it to `emacs' if it is too hopeless. */
2963
2964static void
2965validate_x_resource_name ()
2966{
6fc2811b 2967 int len = 0;
ee78dc32
GV
2968 /* Number of valid characters in the resource name. */
2969 int good_count = 0;
2970 /* Number of invalid characters in the resource name. */
2971 int bad_count = 0;
2972 Lisp_Object new;
2973 int i;
2974
2975 if (STRINGP (Vx_resource_name))
2976 {
2977 unsigned char *p = XSTRING (Vx_resource_name)->data;
2978 int i;
2979
dfff8a69 2980 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2981
2982 /* Only letters, digits, - and _ are valid in resource names.
2983 Count the valid characters and count the invalid ones. */
2984 for (i = 0; i < len; i++)
2985 {
2986 int c = p[i];
2987 if (! ((c >= 'a' && c <= 'z')
2988 || (c >= 'A' && c <= 'Z')
2989 || (c >= '0' && c <= '9')
2990 || c == '-' || c == '_'))
2991 bad_count++;
2992 else
2993 good_count++;
2994 }
2995 }
2996 else
2997 /* Not a string => completely invalid. */
2998 bad_count = 5, good_count = 0;
2999
3000 /* If name is valid already, return. */
3001 if (bad_count == 0)
3002 return;
3003
3004 /* If name is entirely invalid, or nearly so, use `emacs'. */
3005 if (good_count == 0
3006 || (good_count == 1 && bad_count > 0))
3007 {
3008 Vx_resource_name = build_string ("emacs");
3009 return;
3010 }
3011
3012 /* Name is partly valid. Copy it and replace the invalid characters
3013 with underscores. */
3014
3015 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3016
3017 for (i = 0; i < len; i++)
3018 {
3019 int c = XSTRING (new)->data[i];
3020 if (! ((c >= 'a' && c <= 'z')
3021 || (c >= 'A' && c <= 'Z')
3022 || (c >= '0' && c <= '9')
3023 || c == '-' || c == '_'))
3024 XSTRING (new)->data[i] = '_';
3025 }
3026}
3027
3028
3029extern char *x_get_string_resource ();
3030
3031DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
3032 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3033This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3034class, where INSTANCE is the name under which Emacs was invoked, or
3035the name specified by the `-name' or `-rn' command-line arguments.
3036
3037The optional arguments COMPONENT and SUBCLASS add to the key and the
3038class, respectively. You must specify both of them or neither.
3039If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3040and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
3041 (attribute, class, component, subclass)
3042 Lisp_Object attribute, class, component, subclass;
3043{
3044 register char *value;
3045 char *name_key;
3046 char *class_key;
3047
b7826503
PJ
3048 CHECK_STRING (attribute);
3049 CHECK_STRING (class);
ee78dc32
GV
3050
3051 if (!NILP (component))
b7826503 3052 CHECK_STRING (component);
ee78dc32 3053 if (!NILP (subclass))
b7826503 3054 CHECK_STRING (subclass);
ee78dc32
GV
3055 if (NILP (component) != NILP (subclass))
3056 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3057
3058 validate_x_resource_name ();
3059
3060 /* Allocate space for the components, the dots which separate them,
3061 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 3062 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 3063 + (STRINGP (component)
dfff8a69
JR
3064 ? STRING_BYTES (XSTRING (component)) : 0)
3065 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
3066 + 3);
3067
3068 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 3069 + STRING_BYTES (XSTRING (class))
ee78dc32 3070 + (STRINGP (subclass)
dfff8a69 3071 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
3072 + 3);
3073
3074 /* Start with emacs.FRAMENAME for the name (the specific one)
3075 and with `Emacs' for the class key (the general one). */
3076 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3077 strcpy (class_key, EMACS_CLASS);
3078
3079 strcat (class_key, ".");
3080 strcat (class_key, XSTRING (class)->data);
3081
3082 if (!NILP (component))
3083 {
3084 strcat (class_key, ".");
3085 strcat (class_key, XSTRING (subclass)->data);
3086
3087 strcat (name_key, ".");
3088 strcat (name_key, XSTRING (component)->data);
3089 }
3090
3091 strcat (name_key, ".");
3092 strcat (name_key, XSTRING (attribute)->data);
3093
3094 value = x_get_string_resource (Qnil,
3095 name_key, class_key);
3096
3097 if (value != (char *) 0)
3098 return build_string (value);
3099 else
3100 return Qnil;
3101}
3102
3103/* Used when C code wants a resource value. */
3104
3105char *
3106x_get_resource_string (attribute, class)
3107 char *attribute, *class;
3108{
ee78dc32
GV
3109 char *name_key;
3110 char *class_key;
6fc2811b 3111 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3112
3113 /* Allocate space for the components, the dots which separate them,
3114 and the final '\0'. */
dfff8a69 3115 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3116 + strlen (attribute) + 2);
3117 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3118 + strlen (class) + 2);
3119
3120 sprintf (name_key, "%s.%s",
3121 XSTRING (Vinvocation_name)->data,
3122 attribute);
3123 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3124
6fc2811b 3125 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3126}
3127
3128/* Types we might convert a resource string into. */
3129enum resource_types
6fc2811b
JR
3130{
3131 RES_TYPE_NUMBER,
3132 RES_TYPE_FLOAT,
3133 RES_TYPE_BOOLEAN,
3134 RES_TYPE_STRING,
3135 RES_TYPE_SYMBOL
3136};
ee78dc32
GV
3137
3138/* Return the value of parameter PARAM.
3139
3140 First search ALIST, then Vdefault_frame_alist, then the X defaults
3141 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3142
3143 Convert the resource to the type specified by desired_type.
3144
3145 If no default is specified, return Qunbound. If you call
6fc2811b 3146 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3147 and don't let it get stored in any Lisp-visible variables! */
3148
3149static Lisp_Object
6fc2811b 3150w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3151 Lisp_Object alist, param;
3152 char *attribute;
3153 char *class;
3154 enum resource_types type;
3155{
3156 register Lisp_Object tem;
3157
3158 tem = Fassq (param, alist);
3159 if (EQ (tem, Qnil))
3160 tem = Fassq (param, Vdefault_frame_alist);
3161 if (EQ (tem, Qnil))
3162 {
3163
3164 if (attribute)
3165 {
3166 tem = Fx_get_resource (build_string (attribute),
3167 build_string (class),
3168 Qnil, Qnil);
3169
3170 if (NILP (tem))
3171 return Qunbound;
3172
3173 switch (type)
3174 {
6fc2811b 3175 case RES_TYPE_NUMBER:
ee78dc32
GV
3176 return make_number (atoi (XSTRING (tem)->data));
3177
6fc2811b
JR
3178 case RES_TYPE_FLOAT:
3179 return make_float (atof (XSTRING (tem)->data));
3180
3181 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3182 tem = Fdowncase (tem);
3183 if (!strcmp (XSTRING (tem)->data, "on")
3184 || !strcmp (XSTRING (tem)->data, "true"))
3185 return Qt;
3186 else
3187 return Qnil;
3188
6fc2811b 3189 case RES_TYPE_STRING:
ee78dc32
GV
3190 return tem;
3191
6fc2811b 3192 case RES_TYPE_SYMBOL:
ee78dc32
GV
3193 /* As a special case, we map the values `true' and `on'
3194 to Qt, and `false' and `off' to Qnil. */
3195 {
3196 Lisp_Object lower;
3197 lower = Fdowncase (tem);
3198 if (!strcmp (XSTRING (lower)->data, "on")
3199 || !strcmp (XSTRING (lower)->data, "true"))
3200 return Qt;
3201 else if (!strcmp (XSTRING (lower)->data, "off")
3202 || !strcmp (XSTRING (lower)->data, "false"))
3203 return Qnil;
3204 else
3205 return Fintern (tem, Qnil);
3206 }
3207
3208 default:
3209 abort ();
3210 }
3211 }
3212 else
3213 return Qunbound;
3214 }
3215 return Fcdr (tem);
3216}
3217
3218/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3219 of the parameter named PROP (a Lisp symbol).
3220 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3221 on the frame named NAME.
3222 If that is not found either, use the value DEFLT. */
3223
3224static Lisp_Object
3225x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3226 struct frame *f;
3227 Lisp_Object alist;
3228 Lisp_Object prop;
3229 Lisp_Object deflt;
3230 char *xprop;
3231 char *xclass;
3232 enum resource_types type;
3233{
3234 Lisp_Object tem;
3235
6fc2811b 3236 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3237 if (EQ (tem, Qunbound))
3238 tem = deflt;
3239 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3240 return tem;
3241}
3242\f
3243DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3244 doc: /* Parse an X-style geometry string STRING.
3245Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3246The properties returned may include `top', `left', `height', and `width'.
3247The value of `left' or `top' may be an integer,
3248or a list (+ N) meaning N pixels relative to top/left corner,
3249or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3250 (string)
3251 Lisp_Object string;
3252{
3253 int geometry, x, y;
3254 unsigned int width, height;
3255 Lisp_Object result;
3256
b7826503 3257 CHECK_STRING (string);
ee78dc32
GV
3258
3259 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3260 &x, &y, &width, &height);
3261
3262 result = Qnil;
3263 if (geometry & XValue)
3264 {
3265 Lisp_Object element;
3266
3267 if (x >= 0 && (geometry & XNegative))
3268 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3269 else if (x < 0 && ! (geometry & XNegative))
3270 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3271 else
3272 element = Fcons (Qleft, make_number (x));
3273 result = Fcons (element, result);
3274 }
3275
3276 if (geometry & YValue)
3277 {
3278 Lisp_Object element;
3279
3280 if (y >= 0 && (geometry & YNegative))
3281 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3282 else if (y < 0 && ! (geometry & YNegative))
3283 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3284 else
3285 element = Fcons (Qtop, make_number (y));
3286 result = Fcons (element, result);
3287 }
3288
3289 if (geometry & WidthValue)
3290 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3291 if (geometry & HeightValue)
3292 result = Fcons (Fcons (Qheight, make_number (height)), result);
3293
3294 return result;
3295}
3296
3297/* Calculate the desired size and position of this window,
3298 and return the flags saying which aspects were specified.
3299
3300 This function does not make the coordinates positive. */
3301
3302#define DEFAULT_ROWS 40
3303#define DEFAULT_COLS 80
3304
3305static int
3306x_figure_window_size (f, parms)
3307 struct frame *f;
3308 Lisp_Object parms;
3309{
3310 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3311 long window_prompting = 0;
3312
3313 /* Default values if we fall through.
3314 Actually, if that happens we should get
3315 window manager prompting. */
1026b400 3316 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3317 f->height = DEFAULT_ROWS;
3318 /* Window managers expect that if program-specified
3319 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3320 f->output_data.w32->top_pos = 0;
3321 f->output_data.w32->left_pos = 0;
ee78dc32 3322
35b41202
JR
3323 /* Ensure that old new_width and new_height will not override the
3324 values set here. */
3325 FRAME_NEW_WIDTH (f) = 0;
3326 FRAME_NEW_HEIGHT (f) = 0;
3327
6fc2811b
JR
3328 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3329 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3330 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3331 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3332 {
3333 if (!EQ (tem0, Qunbound))
3334 {
b7826503 3335 CHECK_NUMBER (tem0);
ee78dc32
GV
3336 f->height = XINT (tem0);
3337 }
3338 if (!EQ (tem1, Qunbound))
3339 {
b7826503 3340 CHECK_NUMBER (tem1);
1026b400 3341 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3342 }
3343 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3344 window_prompting |= USSize;
3345 else
3346 window_prompting |= PSize;
3347 }
3348
fbd6baed 3349 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3350 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3351 ? 0
3352 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3353 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3354 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
f7b9d4d1 3355
41c1bdd9 3356 x_compute_fringe_widths (f, 0);
f7b9d4d1 3357
fbd6baed
GV
3358 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3359 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3360
6fc2811b
JR
3361 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3362 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3363 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3364 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3365 {
3366 if (EQ (tem0, Qminus))
3367 {
fbd6baed 3368 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3369 window_prompting |= YNegative;
3370 }
8e713be6
KR
3371 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3372 && CONSP (XCDR (tem0))
3373 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3374 {
8e713be6 3375 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3376 window_prompting |= YNegative;
3377 }
8e713be6
KR
3378 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3379 && CONSP (XCDR (tem0))
3380 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3381 {
8e713be6 3382 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3383 }
3384 else if (EQ (tem0, Qunbound))
fbd6baed 3385 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3386 else
3387 {
b7826503 3388 CHECK_NUMBER (tem0);
fbd6baed
GV
3389 f->output_data.w32->top_pos = XINT (tem0);
3390 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3391 window_prompting |= YNegative;
3392 }
3393
3394 if (EQ (tem1, Qminus))
3395 {
fbd6baed 3396 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3397 window_prompting |= XNegative;
3398 }
8e713be6
KR
3399 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3400 && CONSP (XCDR (tem1))
3401 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3402 {
8e713be6 3403 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3404 window_prompting |= XNegative;
3405 }
8e713be6
KR
3406 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3407 && CONSP (XCDR (tem1))
3408 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3409 {
8e713be6 3410 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3411 }
3412 else if (EQ (tem1, Qunbound))
fbd6baed 3413 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3414 else
3415 {
b7826503 3416 CHECK_NUMBER (tem1);
fbd6baed
GV
3417 f->output_data.w32->left_pos = XINT (tem1);
3418 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3419 window_prompting |= XNegative;
3420 }
3421
3422 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3423 window_prompting |= USPosition;
3424 else
3425 window_prompting |= PPosition;
3426 }
3427
f7b9d4d1
JR
3428 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3429 {
3430 int left, top;
3431 int width, height;
3432
3433 /* It takes both for some WM:s to place it where we want */
3434 window_prompting = USPosition | PPosition;
3435 x_fullscreen_adjust (f, &width, &height, &top, &left);
3436 f->width = width;
3437 f->height = height;
3438 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3439 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3440 f->output_data.w32->left_pos = left;
3441 f->output_data.w32->top_pos = top;
3442 }
3443
ee78dc32
GV
3444 return window_prompting;
3445}
3446
3447\f
3448
fbd6baed 3449extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3450
3451BOOL
fbd6baed 3452w32_init_class (hinst)
ee78dc32
GV
3453 HINSTANCE hinst;
3454{
3455 WNDCLASS wc;
3456
5ac45f98 3457 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3458 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3459 wc.cbClsExtra = 0;
3460 wc.cbWndExtra = WND_EXTRA_BYTES;
3461 wc.hInstance = hinst;
3462 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3463 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3464 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3465 wc.lpszMenuName = NULL;
3466 wc.lpszClassName = EMACS_CLASS;
3467
3468 return (RegisterClass (&wc));
3469}
3470
3471HWND
fbd6baed 3472w32_createscrollbar (f, bar)
ee78dc32
GV
3473 struct frame *f;
3474 struct scroll_bar * bar;
3475{
3476 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3477 /* Position and size of scroll bar. */
6fc2811b
JR
3478 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3479 XINT(bar->top),
3480 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3481 XINT(bar->height),
fbd6baed 3482 FRAME_W32_WINDOW (f),
ee78dc32
GV
3483 NULL,
3484 hinst,
3485 NULL));
3486}
3487
3488void
fbd6baed 3489w32_createwindow (f)
ee78dc32
GV
3490 struct frame *f;
3491{
3492 HWND hwnd;
1edf84e7
GV
3493 RECT rect;
3494
3495 rect.left = rect.top = 0;
3496 rect.right = PIXEL_WIDTH (f);
3497 rect.bottom = PIXEL_HEIGHT (f);
3498
3499 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3500 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3501
3502 /* Do first time app init */
3503
3504 if (!hprevinst)
3505 {
fbd6baed 3506 w32_init_class (hinst);
ee78dc32
GV
3507 }
3508
1edf84e7
GV
3509 FRAME_W32_WINDOW (f) = hwnd
3510 = CreateWindow (EMACS_CLASS,
3511 f->namebuf,
9ead1b60 3512 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3513 f->output_data.w32->left_pos,
3514 f->output_data.w32->top_pos,
3515 rect.right - rect.left,
3516 rect.bottom - rect.top,
3517 NULL,
3518 NULL,
3519 hinst,
3520 NULL);
3521
ee78dc32
GV
3522 if (hwnd)
3523 {
1edf84e7
GV
3524 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3525 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3526 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3527 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3528 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3529
cb9e33d4
RS
3530 /* Enable drag-n-drop. */
3531 DragAcceptFiles (hwnd, TRUE);
3532
5ac45f98
GV
3533 /* Do this to discard the default setting specified by our parent. */
3534 ShowWindow (hwnd, SW_HIDE);
3c190163 3535 }
3c190163
GV
3536}
3537
ee78dc32
GV
3538void
3539my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3540 W32Msg * wmsg;
ee78dc32
GV
3541 HWND hwnd;
3542 UINT msg;
3543 WPARAM wParam;
3544 LPARAM lParam;
3545{
3546 wmsg->msg.hwnd = hwnd;
3547 wmsg->msg.message = msg;
3548 wmsg->msg.wParam = wParam;
3549 wmsg->msg.lParam = lParam;
3550 wmsg->msg.time = GetMessageTime ();
3551
3552 post_msg (wmsg);
3553}
3554
e9e23e23 3555/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3556 between left and right keys as advertised. We test for this
3557 support dynamically, and set a flag when the support is absent. If
3558 absent, we keep track of the left and right control and alt keys
3559 ourselves. This is particularly necessary on keyboards that rely
3560 upon the AltGr key, which is represented as having the left control
3561 and right alt keys pressed. For these keyboards, we need to know
3562 when the left alt key has been pressed in addition to the AltGr key
3563 so that we can properly support M-AltGr-key sequences (such as M-@
3564 on Swedish keyboards). */
3565
3566#define EMACS_LCONTROL 0
3567#define EMACS_RCONTROL 1
3568#define EMACS_LMENU 2
3569#define EMACS_RMENU 3
3570
3571static int modifiers[4];
3572static int modifiers_recorded;
3573static int modifier_key_support_tested;
3574
3575static void
3576test_modifier_support (unsigned int wparam)
3577{
3578 unsigned int l, r;
3579
3580 if (wparam != VK_CONTROL && wparam != VK_MENU)
3581 return;
3582 if (wparam == VK_CONTROL)
3583 {
3584 l = VK_LCONTROL;
3585 r = VK_RCONTROL;
3586 }
3587 else
3588 {
3589 l = VK_LMENU;
3590 r = VK_RMENU;
3591 }
3592 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3593 modifiers_recorded = 1;
3594 else
3595 modifiers_recorded = 0;
3596 modifier_key_support_tested = 1;
3597}
3598
3599static void
3600record_keydown (unsigned int wparam, unsigned int lparam)
3601{
3602 int i;
3603
3604 if (!modifier_key_support_tested)
3605 test_modifier_support (wparam);
3606
3607 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3608 return;
3609
3610 if (wparam == VK_CONTROL)
3611 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3612 else
3613 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3614
3615 modifiers[i] = 1;
3616}
3617
3618static void
3619record_keyup (unsigned int wparam, unsigned int lparam)
3620{
3621 int i;
3622
3623 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3624 return;
3625
3626 if (wparam == VK_CONTROL)
3627 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3628 else
3629 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3630
3631 modifiers[i] = 0;
3632}
3633
da36a4d6
GV
3634/* Emacs can lose focus while a modifier key has been pressed. When
3635 it regains focus, be conservative and clear all modifiers since
3636 we cannot reconstruct the left and right modifier state. */
3637static void
3638reset_modifiers ()
3639{
8681157a
RS
3640 SHORT ctrl, alt;
3641
adcc3809
GV
3642 if (GetFocus () == NULL)
3643 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3644 return;
8681157a
RS
3645
3646 ctrl = GetAsyncKeyState (VK_CONTROL);
3647 alt = GetAsyncKeyState (VK_MENU);
3648
8681157a
RS
3649 if (!(ctrl & 0x08000))
3650 /* Clear any recorded control modifier state. */
3651 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3652
3653 if (!(alt & 0x08000))
3654 /* Clear any recorded alt modifier state. */
3655 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3656
adcc3809
GV
3657 /* Update the state of all modifier keys, because modifiers used in
3658 hot-key combinations can get stuck on if Emacs loses focus as a
3659 result of a hot-key being pressed. */
3660 {
3661 BYTE keystate[256];
3662
3663#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3664
3665 GetKeyboardState (keystate);
3666 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3667 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3668 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3669 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3670 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3671 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3672 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3673 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3674 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3675 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3676 SetKeyboardState (keystate);
3677 }
da36a4d6
GV
3678}
3679
7830e24b
RS
3680/* Synchronize modifier state with what is reported with the current
3681 keystroke. Even if we cannot distinguish between left and right
3682 modifier keys, we know that, if no modifiers are set, then neither
3683 the left or right modifier should be set. */
3684static void
3685sync_modifiers ()
3686{
3687 if (!modifiers_recorded)
3688 return;
3689
3690 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3691 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3692
3693 if (!(GetKeyState (VK_MENU) & 0x8000))
3694 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3695}
3696
a1a80b40
GV
3697static int
3698modifier_set (int vkey)
3699{
ccc2d29c 3700 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3701 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3702 if (!modifiers_recorded)
3703 return (GetKeyState (vkey) & 0x8000);
3704
3705 switch (vkey)
3706 {
3707 case VK_LCONTROL:
3708 return modifiers[EMACS_LCONTROL];
3709 case VK_RCONTROL:
3710 return modifiers[EMACS_RCONTROL];
3711 case VK_LMENU:
3712 return modifiers[EMACS_LMENU];
3713 case VK_RMENU:
3714 return modifiers[EMACS_RMENU];
a1a80b40
GV
3715 }
3716 return (GetKeyState (vkey) & 0x8000);
3717}
3718
ccc2d29c
GV
3719/* Convert between the modifier bits W32 uses and the modifier bits
3720 Emacs uses. */
3721
3722unsigned int
3723w32_key_to_modifier (int key)
3724{
3725 Lisp_Object key_mapping;
3726
3727 switch (key)
3728 {
3729 case VK_LWIN:
3730 key_mapping = Vw32_lwindow_modifier;
3731 break;
3732 case VK_RWIN:
3733 key_mapping = Vw32_rwindow_modifier;
3734 break;
3735 case VK_APPS:
3736 key_mapping = Vw32_apps_modifier;
3737 break;
3738 case VK_SCROLL:
3739 key_mapping = Vw32_scroll_lock_modifier;
3740 break;
3741 default:
3742 key_mapping = Qnil;
3743 }
3744
adcc3809
GV
3745 /* NB. This code runs in the input thread, asychronously to the lisp
3746 thread, so we must be careful to ensure access to lisp data is
3747 thread-safe. The following code is safe because the modifier
3748 variable values are updated atomically from lisp and symbols are
3749 not relocated by GC. Also, we don't have to worry about seeing GC
3750 markbits here. */
3751 if (EQ (key_mapping, Qhyper))
ccc2d29c 3752 return hyper_modifier;
adcc3809 3753 if (EQ (key_mapping, Qsuper))
ccc2d29c 3754 return super_modifier;
adcc3809 3755 if (EQ (key_mapping, Qmeta))
ccc2d29c 3756 return meta_modifier;
adcc3809 3757 if (EQ (key_mapping, Qalt))
ccc2d29c 3758 return alt_modifier;
adcc3809 3759 if (EQ (key_mapping, Qctrl))
ccc2d29c 3760 return ctrl_modifier;
adcc3809 3761 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3762 return ctrl_modifier;
adcc3809 3763 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3764 return shift_modifier;
3765
3766 /* Don't generate any modifier if not explicitly requested. */
3767 return 0;
3768}
3769
3770unsigned int
3771w32_get_modifiers ()
3772{
3773 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3774 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3775 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3776 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3777 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3778 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3779 (modifier_set (VK_MENU) ?
3780 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3781}
3782
a1a80b40
GV
3783/* We map the VK_* modifiers into console modifier constants
3784 so that we can use the same routines to handle both console
3785 and window input. */
3786
3787static int
ccc2d29c 3788construct_console_modifiers ()
a1a80b40
GV
3789{
3790 int mods;
3791
a1a80b40
GV
3792 mods = 0;
3793 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3794 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3795 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3796 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3797 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3798 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3799 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3800 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3801 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3802 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3803 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3804
3805 return mods;
3806}
3807
ccc2d29c
GV
3808static int
3809w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3810{
ccc2d29c
GV
3811 int mods;
3812
3813 /* Convert to emacs modifiers. */
3814 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3815
3816 return mods;
3817}
da36a4d6 3818
ccc2d29c
GV
3819unsigned int
3820map_keypad_keys (unsigned int virt_key, unsigned int extended)
3821{
3822 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3823 return virt_key;
da36a4d6 3824
ccc2d29c 3825 if (virt_key == VK_RETURN)
da36a4d6
GV
3826 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3827
ccc2d29c
GV
3828 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3829 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3830
3831 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3832 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3833
3834 if (virt_key == VK_CLEAR)
3835 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3836
3837 return virt_key;
3838}
3839
3840/* List of special key combinations which w32 would normally capture,
3841 but emacs should grab instead. Not directly visible to lisp, to
3842 simplify synchronization. Each item is an integer encoding a virtual
3843 key code and modifier combination to capture. */
3844Lisp_Object w32_grabbed_keys;
3845
3846#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3847#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3848#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3849#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3850
3851/* Register hot-keys for reserved key combinations when Emacs has
3852 keyboard focus, since this is the only way Emacs can receive key
3853 combinations like Alt-Tab which are used by the system. */
3854
3855static void
3856register_hot_keys (hwnd)
3857 HWND hwnd;
3858{
3859 Lisp_Object keylist;
3860
3861 /* Use GC_CONSP, since we are called asynchronously. */
3862 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3863 {
3864 Lisp_Object key = XCAR (keylist);
3865
3866 /* Deleted entries get set to nil. */
3867 if (!INTEGERP (key))
3868 continue;
3869
3870 RegisterHotKey (hwnd, HOTKEY_ID (key),
3871 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3872 }
3873}
3874
3875static void
3876unregister_hot_keys (hwnd)
3877 HWND hwnd;
3878{
3879 Lisp_Object keylist;
3880
3881 /* Use GC_CONSP, since we are called asynchronously. */
3882 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3883 {
3884 Lisp_Object key = XCAR (keylist);
3885
3886 if (!INTEGERP (key))
3887 continue;
3888
3889 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3890 }
3891}
3892
5ac45f98
GV
3893/* Main message dispatch loop. */
3894
1edf84e7
GV
3895static void
3896w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3897{
3898 MSG msg;
ccc2d29c
GV
3899 int result;
3900 HWND focus_window;
93fbe8b7
GV
3901
3902 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3903
5ac45f98
GV
3904 while (GetMessage (&msg, NULL, 0, 0))
3905 {
3906 if (msg.hwnd == NULL)
3907 {
3908 switch (msg.message)
3909 {
3ef68e6b
AI
3910 case WM_NULL:
3911 /* Produced by complete_deferred_msg; just ignore. */
3912 break;
5ac45f98 3913 case WM_EMACS_CREATEWINDOW:
fbd6baed 3914 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3915 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3916 abort ();
5ac45f98 3917 break;
dfdb4047
GV
3918 case WM_EMACS_SETLOCALE:
3919 SetThreadLocale (msg.wParam);
3920 /* Reply is not expected. */
3921 break;
ccc2d29c
GV
3922 case WM_EMACS_SETKEYBOARDLAYOUT:
3923 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3924 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3925 result, 0))
3926 abort ();
3927 break;
3928 case WM_EMACS_REGISTER_HOT_KEY:
3929 focus_window = GetFocus ();
3930 if (focus_window != NULL)
3931 RegisterHotKey (focus_window,
3932 HOTKEY_ID (msg.wParam),
3933 HOTKEY_MODIFIERS (msg.wParam),
3934 HOTKEY_VK_CODE (msg.wParam));
3935 /* Reply is not expected. */
3936 break;
3937 case WM_EMACS_UNREGISTER_HOT_KEY:
3938 focus_window = GetFocus ();
3939 if (focus_window != NULL)
3940 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3941 /* Mark item as erased. NB: this code must be
3942 thread-safe. The next line is okay because the cons
3943 cell is never made into garbage and is not relocated by
3944 GC. */
f3fbd155 3945 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3946 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3947 abort ();
3948 break;
adcc3809
GV
3949 case WM_EMACS_TOGGLE_LOCK_KEY:
3950 {
3951 int vk_code = (int) msg.wParam;
3952 int cur_state = (GetKeyState (vk_code) & 1);
3953 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3954
3955 /* NB: This code must be thread-safe. It is safe to
3956 call NILP because symbols are not relocated by GC,
3957 and pointer here is not touched by GC (so the markbit
3958 can't be set). Numbers are safe because they are
3959 immediate values. */
3960 if (NILP (new_state)
3961 || (NUMBERP (new_state)
8edb0a6f 3962 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3963 {
3964 one_w32_display_info.faked_key = vk_code;
3965
3966 keybd_event ((BYTE) vk_code,
3967 (BYTE) MapVirtualKey (vk_code, 0),
3968 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3969 keybd_event ((BYTE) vk_code,
3970 (BYTE) MapVirtualKey (vk_code, 0),
3971 KEYEVENTF_EXTENDEDKEY | 0, 0);
3972 keybd_event ((BYTE) vk_code,
3973 (BYTE) MapVirtualKey (vk_code, 0),
3974 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3975 cur_state = !cur_state;
3976 }
3977 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3978 cur_state, 0))
3979 abort ();
3980 }
3981 break;
1edf84e7 3982 default:
1edf84e7 3983 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3984 }
3985 }
3986 else
3987 {
3988 DispatchMessage (&msg);
3989 }
1edf84e7
GV
3990
3991 /* Exit nested loop when our deferred message has completed. */
3992 if (msg_buf->completed)
3993 break;
5ac45f98 3994 }
1edf84e7
GV
3995}
3996
3997deferred_msg * deferred_msg_head;
3998
3999static deferred_msg *
4000find_deferred_msg (HWND hwnd, UINT msg)
4001{
4002 deferred_msg * item;
4003
4004 /* Don't actually need synchronization for read access, since
4005 modification of single pointer is always atomic. */
4006 /* enter_crit (); */
4007
4008 for (item = deferred_msg_head; item != NULL; item = item->next)
4009 if (item->w32msg.msg.hwnd == hwnd
4010 && item->w32msg.msg.message == msg)
4011 break;
4012
4013 /* leave_crit (); */
4014
4015 return item;
4016}
4017
4018static LRESULT
4019send_deferred_msg (deferred_msg * msg_buf,
4020 HWND hwnd,
4021 UINT msg,
4022 WPARAM wParam,
4023 LPARAM lParam)
4024{
4025 /* Only input thread can send deferred messages. */
4026 if (GetCurrentThreadId () != dwWindowsThreadId)
4027 abort ();
4028
4029 /* It is an error to send a message that is already deferred. */
4030 if (find_deferred_msg (hwnd, msg) != NULL)
4031 abort ();
4032
4033 /* Enforced synchronization is not needed because this is the only
4034 function that alters deferred_msg_head, and the following critical
4035 section is guaranteed to only be serially reentered (since only the
4036 input thread can call us). */
4037
4038 /* enter_crit (); */
4039
4040 msg_buf->completed = 0;
4041 msg_buf->next = deferred_msg_head;
4042 deferred_msg_head = msg_buf;
4043 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4044
4045 /* leave_crit (); */
4046
4047 /* Start a new nested message loop to process other messages until
4048 this one is completed. */
4049 w32_msg_pump (msg_buf);
4050
4051 deferred_msg_head = msg_buf->next;
4052
4053 return msg_buf->result;
4054}
4055
4056void
4057complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4058{
4059 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4060
4061 if (msg_buf == NULL)
3ef68e6b
AI
4062 /* Message may have been cancelled, so don't abort(). */
4063 return;
1edf84e7
GV
4064
4065 msg_buf->result = result;
4066 msg_buf->completed = 1;
4067
4068 /* Ensure input thread is woken so it notices the completion. */
4069 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4070}
4071
3ef68e6b
AI
4072void
4073cancel_all_deferred_msgs ()
4074{
4075 deferred_msg * item;
4076
4077 /* Don't actually need synchronization for read access, since
4078 modification of single pointer is always atomic. */
4079 /* enter_crit (); */
4080
4081 for (item = deferred_msg_head; item != NULL; item = item->next)
4082 {
4083 item->result = 0;
4084 item->completed = 1;
4085 }
4086
4087 /* leave_crit (); */
4088
4089 /* Ensure input thread is woken so it notices the completion. */
4090 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4091}
1edf84e7
GV
4092
4093DWORD
4094w32_msg_worker (dw)
4095 DWORD dw;
4096{
4097 MSG msg;
4098 deferred_msg dummy_buf;
4099
4100 /* Ensure our message queue is created */
4101
4102 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 4103
1edf84e7
GV
4104 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4105 abort ();
4106
4107 memset (&dummy_buf, 0, sizeof (dummy_buf));
4108 dummy_buf.w32msg.msg.hwnd = NULL;
4109 dummy_buf.w32msg.msg.message = WM_NULL;
4110
4111 /* This is the inital message loop which should only exit when the
4112 application quits. */
4113 w32_msg_pump (&dummy_buf);
4114
4115 return 0;
5ac45f98
GV
4116}
4117
3ef68e6b
AI
4118static void
4119post_character_message (hwnd, msg, wParam, lParam, modifiers)
4120 HWND hwnd;
4121 UINT msg;
4122 WPARAM wParam;
4123 LPARAM lParam;
4124 DWORD modifiers;
4125
4126{
4127 W32Msg wmsg;
4128
4129 wmsg.dwModifiers = modifiers;
4130
4131 /* Detect quit_char and set quit-flag directly. Note that we
4132 still need to post a message to ensure the main thread will be
4133 woken up if blocked in sys_select(), but we do NOT want to post
4134 the quit_char message itself (because it will usually be as if
4135 the user had typed quit_char twice). Instead, we post a dummy
4136 message that has no particular effect. */
4137 {
4138 int c = wParam;
4139 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4140 c = make_ctrl_char (c) & 0377;
7d081355
AI
4141 if (c == quit_char
4142 || (wmsg.dwModifiers == 0 &&
4143 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4144 {
4145 Vquit_flag = Qt;
4146
4147 /* The choice of message is somewhat arbitrary, as long as
4148 the main thread handler just ignores it. */
4149 msg = WM_NULL;
4150
4151 /* Interrupt any blocking system calls. */
4152 signal_quit ();
4153
4154 /* As a safety precaution, forcibly complete any deferred
4155 messages. This is a kludge, but I don't see any particularly
4156 clean way to handle the situation where a deferred message is
4157 "dropped" in the lisp thread, and will thus never be
4158 completed, eg. by the user trying to activate the menubar
4159 when the lisp thread is busy, and then typing C-g when the
4160 menubar doesn't open promptly (with the result that the
4161 menubar never responds at all because the deferred
4162 WM_INITMENU message is never completed). Another problem
4163 situation is when the lisp thread calls SendMessage (to send
4164 a window manager command) when a message has been deferred;
4165 the lisp thread gets blocked indefinitely waiting for the
4166 deferred message to be completed, which itself is waiting for
4167 the lisp thread to respond.
4168
4169 Note that we don't want to block the input thread waiting for
4170 a reponse from the lisp thread (although that would at least
4171 solve the deadlock problem above), because we want to be able
4172 to receive C-g to interrupt the lisp thread. */
4173 cancel_all_deferred_msgs ();
4174 }
4175 }
4176
4177 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4178}
4179
ee78dc32
GV
4180/* Main window procedure */
4181
ee78dc32 4182LRESULT CALLBACK
fbd6baed 4183w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4184 HWND hwnd;
4185 UINT msg;
4186 WPARAM wParam;
4187 LPARAM lParam;
4188{
4189 struct frame *f;
fbd6baed
GV
4190 struct w32_display_info *dpyinfo = &one_w32_display_info;
4191 W32Msg wmsg;
84fb1139 4192 int windows_translate;
576ba81c 4193 int key;
84fb1139 4194
a6085637
KH
4195 /* Note that it is okay to call x_window_to_frame, even though we are
4196 not running in the main lisp thread, because frame deletion
4197 requires the lisp thread to synchronize with this thread. Thus, if
4198 a frame struct is returned, it can be used without concern that the
4199 lisp thread might make it disappear while we are using it.
4200
4201 NB. Walking the frame list in this thread is safe (as long as
4202 writes of Lisp_Object slots are atomic, which they are on Windows).
4203 Although delete-frame can destructively modify the frame list while
4204 we are walking it, a garbage collection cannot occur until after
4205 delete-frame has synchronized with this thread.
4206
4207 It is also safe to use functions that make GDI calls, such as
fbd6baed 4208 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4209 from the frame struct using get_frame_dc which is thread-aware. */
4210
ee78dc32
GV
4211 switch (msg)
4212 {
4213 case WM_ERASEBKGND:
a6085637
KH
4214 f = x_window_to_frame (dpyinfo, hwnd);
4215 if (f)
4216 {
9badad41 4217 HDC hdc = get_frame_dc (f);
a6085637 4218 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4219 w32_clear_rect (f, hdc, &wmsg.rect);
4220 release_frame_dc (f, hdc);
ce6059da
AI
4221
4222#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4223 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4224 f,
4225 wmsg.rect.left, wmsg.rect.top,
4226 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4227#endif /* W32_DEBUG_DISPLAY */
a6085637 4228 }
5ac45f98
GV
4229 return 1;
4230 case WM_PALETTECHANGED:
4231 /* ignore our own changes */
4232 if ((HWND)wParam != hwnd)
4233 {
a6085637
KH
4234 f = x_window_to_frame (dpyinfo, hwnd);
4235 if (f)
4236 /* get_frame_dc will realize our palette and force all
4237 frames to be redrawn if needed. */
4238 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4239 }
4240 return 0;
ee78dc32 4241 case WM_PAINT:
ce6059da 4242 {
55dcfc15
AI
4243 PAINTSTRUCT paintStruct;
4244 RECT update_rect;
aa35b6ad 4245 bzero (&update_rect, sizeof (update_rect));
55dcfc15 4246
18f0b342
AI
4247 f = x_window_to_frame (dpyinfo, hwnd);
4248 if (f == 0)
4249 {
4250 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4251 return 0;
4252 }
4253
55dcfc15
AI
4254 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4255 fails. Apparently this can happen under some
4256 circumstances. */
aa35b6ad 4257 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
55dcfc15
AI
4258 {
4259 enter_crit ();
4260 BeginPaint (hwnd, &paintStruct);
4261
aa35b6ad
JR
4262 /* The rectangles returned by GetUpdateRect and BeginPaint
4263 do not always match. Play it safe by assuming both areas
4264 are invalid. */
4265 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
55dcfc15
AI
4266
4267#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4268 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4269 f,
4270 wmsg.rect.left, wmsg.rect.top,
4271 wmsg.rect.right, wmsg.rect.bottom));
4272 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4273 update_rect.left, update_rect.top,
4274 update_rect.right, update_rect.bottom));
4275#endif
4276 EndPaint (hwnd, &paintStruct);
4277 leave_crit ();
4278
4279 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4280
4281 return 0;
4282 }
c0611964
AI
4283
4284 /* If GetUpdateRect returns 0 (meaning there is no update
4285 region), assume the whole window needs to be repainted. */
4286 GetClientRect(hwnd, &wmsg.rect);
4287 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4288 return 0;
ee78dc32 4289 }
a1a80b40 4290
ccc2d29c
GV
4291 case WM_INPUTLANGCHANGE:
4292 /* Inform lisp thread of keyboard layout changes. */
4293 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4294
4295 /* Clear dead keys in the keyboard state; for simplicity only
4296 preserve modifier key states. */
4297 {
4298 int i;
4299 BYTE keystate[256];
4300
4301 GetKeyboardState (keystate);
4302 for (i = 0; i < 256; i++)
4303 if (1
4304 && i != VK_SHIFT
4305 && i != VK_LSHIFT
4306 && i != VK_RSHIFT
4307 && i != VK_CAPITAL
4308 && i != VK_NUMLOCK
4309 && i != VK_SCROLL
4310 && i != VK_CONTROL
4311 && i != VK_LCONTROL
4312 && i != VK_RCONTROL
4313 && i != VK_MENU
4314 && i != VK_LMENU
4315 && i != VK_RMENU
4316 && i != VK_LWIN
4317 && i != VK_RWIN)
4318 keystate[i] = 0;
4319 SetKeyboardState (keystate);
4320 }
4321 goto dflt;
4322
4323 case WM_HOTKEY:
4324 /* Synchronize hot keys with normal input. */
4325 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4326 return (0);
4327
a1a80b40
GV
4328 case WM_KEYUP:
4329 case WM_SYSKEYUP:
4330 record_keyup (wParam, lParam);
4331 goto dflt;
4332
ee78dc32
GV
4333 case WM_KEYDOWN:
4334 case WM_SYSKEYDOWN:
ccc2d29c
GV
4335 /* Ignore keystrokes we fake ourself; see below. */
4336 if (dpyinfo->faked_key == wParam)
4337 {
4338 dpyinfo->faked_key = 0;
576ba81c
AI
4339 /* Make sure TranslateMessage sees them though (as long as
4340 they don't produce WM_CHAR messages). This ensures that
4341 indicator lights are toggled promptly on Windows 9x, for
4342 example. */
4343 if (lispy_function_keys[wParam] != 0)
4344 {
4345 windows_translate = 1;
4346 goto translate;
4347 }
4348 return 0;
ccc2d29c
GV
4349 }
4350
7830e24b
RS
4351 /* Synchronize modifiers with current keystroke. */
4352 sync_modifiers ();
a1a80b40 4353 record_keydown (wParam, lParam);
ccc2d29c 4354 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4355
4356 windows_translate = 0;
ccc2d29c
GV
4357
4358 switch (wParam)
4359 {
4360 case VK_LWIN:
4361 if (NILP (Vw32_pass_lwindow_to_system))
4362 {
4363 /* Prevent system from acting on keyup (which opens the
4364 Start menu if no other key was pressed) by simulating a
4365 press of Space which we will ignore. */
4366 if (GetAsyncKeyState (wParam) & 1)
4367 {
adcc3809 4368 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4369 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4370 else
576ba81c
AI
4371 key = VK_SPACE;
4372 dpyinfo->faked_key = key;
4373 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4374 }
4375 }
4376 if (!NILP (Vw32_lwindow_modifier))
4377 return 0;
4378 break;
4379 case VK_RWIN:
4380 if (NILP (Vw32_pass_rwindow_to_system))
4381 {
4382 if (GetAsyncKeyState (wParam) & 1)
4383 {
adcc3809 4384 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4385 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4386 else
576ba81c
AI
4387 key = VK_SPACE;
4388 dpyinfo->faked_key = key;
4389 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4390 }
4391 }
4392 if (!NILP (Vw32_rwindow_modifier))
4393 return 0;
4394 break;
576ba81c 4395 case VK_APPS:
ccc2d29c
GV
4396 if (!NILP (Vw32_apps_modifier))
4397 return 0;
4398 break;
4399 case VK_MENU:
4400 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4401 /* Prevent DefWindowProc from activating the menu bar if an
4402 Alt key is pressed and released by itself. */
ccc2d29c 4403 return 0;
84fb1139 4404 windows_translate = 1;
ccc2d29c
GV
4405 break;
4406 case VK_CAPITAL:
4407 /* Decide whether to treat as modifier or function key. */
4408 if (NILP (Vw32_enable_caps_lock))
4409 goto disable_lock_key;
adcc3809
GV
4410 windows_translate = 1;
4411 break;
ccc2d29c
GV
4412 case VK_NUMLOCK:
4413 /* Decide whether to treat as modifier or function key. */
4414 if (NILP (Vw32_enable_num_lock))
4415 goto disable_lock_key;
adcc3809
GV
4416 windows_translate = 1;
4417 break;
ccc2d29c
GV
4418 case VK_SCROLL:
4419 /* Decide whether to treat as modifier or function key. */
4420 if (NILP (Vw32_scroll_lock_modifier))
4421 goto disable_lock_key;
adcc3809
GV
4422 windows_translate = 1;
4423 break;
ccc2d29c 4424 disable_lock_key:
adcc3809
GV
4425 /* Ensure the appropriate lock key state (and indicator light)
4426 remains in the same state. We do this by faking another
4427 press of the relevant key. Apparently, this really is the
4428 only way to toggle the state of the indicator lights. */
4429 dpyinfo->faked_key = wParam;
4430 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4431 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4432 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4433 KEYEVENTF_EXTENDEDKEY | 0, 0);
4434 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4435 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4436 /* Ensure indicator lights are updated promptly on Windows 9x
4437 (TranslateMessage apparently does this), after forwarding
4438 input event. */
4439 post_character_message (hwnd, msg, wParam, lParam,
4440 w32_get_key_modifiers (wParam, lParam));
4441 windows_translate = 1;
ccc2d29c
GV
4442 break;
4443 case VK_CONTROL:
4444 case VK_SHIFT:
4445 case VK_PROCESSKEY: /* Generated by IME. */
4446 windows_translate = 1;
4447 break;
adcc3809
GV
4448 case VK_CANCEL:
4449 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4450 which is confusing for purposes of key binding; convert
4451 VK_CANCEL events into VK_PAUSE events. */
4452 wParam = VK_PAUSE;
4453 break;
4454 case VK_PAUSE:
4455 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4456 for purposes of key binding; convert these back into
4457 VK_NUMLOCK events, at least when we want to see NumLock key
4458 presses. (Note that there is never any possibility that
4459 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4460 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4461 wParam = VK_NUMLOCK;
4462 break;
ccc2d29c
GV
4463 default:
4464 /* If not defined as a function key, change it to a WM_CHAR message. */
4465 if (lispy_function_keys[wParam] == 0)
4466 {
adcc3809
GV
4467 DWORD modifiers = construct_console_modifiers ();
4468
ccc2d29c
GV
4469 if (!NILP (Vw32_recognize_altgr)
4470 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4471 {
4472 /* Always let TranslateMessage handle AltGr key chords;
4473 for some reason, ToAscii doesn't always process AltGr
4474 chords correctly. */
4475 windows_translate = 1;
4476 }
adcc3809 4477 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4478 {
adcc3809
GV
4479 /* Handle key chords including any modifiers other
4480 than shift directly, in order to preserve as much
4481 modifier information as possible. */
ccc2d29c
GV
4482 if ('A' <= wParam && wParam <= 'Z')
4483 {
4484 /* Don't translate modified alphabetic keystrokes,
4485 so the user doesn't need to constantly switch
4486 layout to type control or meta keystrokes when
4487 the normal layout translates alphabetic
4488 characters to non-ascii characters. */
4489 if (!modifier_set (VK_SHIFT))
4490 wParam += ('a' - 'A');
4491 msg = WM_CHAR;
4492 }
4493 else
4494 {
4495 /* Try to handle other keystrokes by determining the
4496 base character (ie. translating the base key plus
4497 shift modifier). */
4498 int add;
4499 int isdead = 0;
4500 KEY_EVENT_RECORD key;
4501
4502 key.bKeyDown = TRUE;
4503 key.wRepeatCount = 1;
4504 key.wVirtualKeyCode = wParam;
4505 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4506 key.uChar.AsciiChar = 0;
adcc3809 4507 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4508
4509 add = w32_kbd_patch_key (&key);
4510 /* 0 means an unrecognised keycode, negative means
4511 dead key. Ignore both. */
4512 while (--add >= 0)
4513 {
4514 /* Forward asciified character sequence. */
4515 post_character_message
4516 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4517 w32_get_key_modifiers (wParam, lParam));
4518 w32_kbd_patch_key (&key);
4519 }
4520 return 0;
4521 }
4522 }
4523 else
4524 {
4525 /* Let TranslateMessage handle everything else. */
4526 windows_translate = 1;
4527 }
4528 }
4529 }
a1a80b40 4530
adcc3809 4531 translate:
84fb1139
KH
4532 if (windows_translate)
4533 {
e9e23e23 4534 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4535
e9e23e23
GV
4536 windows_msg.time = GetMessageTime ();
4537 TranslateMessage (&windows_msg);
84fb1139
KH
4538 goto dflt;
4539 }
4540
ee78dc32
GV
4541 /* Fall through */
4542
4543 case WM_SYSCHAR:
4544 case WM_CHAR:
ccc2d29c
GV
4545 post_character_message (hwnd, msg, wParam, lParam,
4546 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4547 break;
da36a4d6 4548
5ac45f98
GV
4549 /* Simulate middle mouse button events when left and right buttons
4550 are used together, but only if user has two button mouse. */
ee78dc32 4551 case WM_LBUTTONDOWN:
5ac45f98 4552 case WM_RBUTTONDOWN:
7ce9aaca 4553 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4554 goto handle_plain_button;
4555
4556 {
4557 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4558 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4559
3cb20f4a
RS
4560 if (button_state & this)
4561 return 0;
5ac45f98
GV
4562
4563 if (button_state == 0)
4564 SetCapture (hwnd);
4565
4566 button_state |= this;
4567
4568 if (button_state & other)
4569 {
84fb1139 4570 if (mouse_button_timer)
5ac45f98 4571 {
84fb1139
KH
4572 KillTimer (hwnd, mouse_button_timer);
4573 mouse_button_timer = 0;
5ac45f98
GV
4574
4575 /* Generate middle mouse event instead. */
4576 msg = WM_MBUTTONDOWN;
4577 button_state |= MMOUSE;
4578 }
4579 else if (button_state & MMOUSE)
4580 {
4581 /* Ignore button event if we've already generated a
4582 middle mouse down event. This happens if the
4583 user releases and press one of the two buttons
4584 after we've faked a middle mouse event. */
4585 return 0;
4586 }
4587 else
4588 {
4589 /* Flush out saved message. */
84fb1139 4590 post_msg (&saved_mouse_button_msg);
5ac45f98 4591 }
fbd6baed 4592 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4593 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4594
4595 /* Clear message buffer. */
84fb1139 4596 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4597 }
4598 else
4599 {
4600 /* Hold onto message for now. */
84fb1139 4601 mouse_button_timer =
adcc3809
GV
4602 SetTimer (hwnd, MOUSE_BUTTON_ID,
4603 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4604 saved_mouse_button_msg.msg.hwnd = hwnd;
4605 saved_mouse_button_msg.msg.message = msg;
4606 saved_mouse_button_msg.msg.wParam = wParam;
4607 saved_mouse_button_msg.msg.lParam = lParam;
4608 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4609 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4610 }
4611 }
4612 return 0;
4613
ee78dc32 4614 case WM_LBUTTONUP:
5ac45f98 4615 case WM_RBUTTONUP:
7ce9aaca 4616 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4617 goto handle_plain_button;
4618
4619 {
4620 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4621 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4622
3cb20f4a
RS
4623 if ((button_state & this) == 0)
4624 return 0;
5ac45f98
GV
4625
4626 button_state &= ~this;
4627
4628 if (button_state & MMOUSE)
4629 {
4630 /* Only generate event when second button is released. */
4631 if ((button_state & other) == 0)
4632 {
4633 msg = WM_MBUTTONUP;
4634 button_state &= ~MMOUSE;
4635
4636 if (button_state) abort ();
4637 }
4638 else
4639 return 0;
4640 }
4641 else
4642 {
4643 /* Flush out saved message if necessary. */
84fb1139 4644 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4645 {
84fb1139 4646 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4647 }
4648 }
fbd6baed 4649 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4650 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4651
4652 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4653 saved_mouse_button_msg.msg.hwnd = 0;
4654 KillTimer (hwnd, mouse_button_timer);
4655 mouse_button_timer = 0;
5ac45f98
GV
4656
4657 if (button_state == 0)
4658 ReleaseCapture ();
4659 }
4660 return 0;
4661
74214547
JR
4662 case WM_XBUTTONDOWN:
4663 case WM_XBUTTONUP:
4664 if (w32_pass_extra_mouse_buttons_to_system)
4665 goto dflt;
4666 /* else fall through and process them. */
ee78dc32
GV
4667 case WM_MBUTTONDOWN:
4668 case WM_MBUTTONUP:
5ac45f98 4669 handle_plain_button:
ee78dc32
GV
4670 {
4671 BOOL up;
1edf84e7 4672 int button;
ee78dc32 4673
74214547 4674 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
4675 {
4676 if (up) ReleaseCapture ();
4677 else SetCapture (hwnd);
1edf84e7
GV
4678 button = (button == 0) ? LMOUSE :
4679 ((button == 1) ? MMOUSE : RMOUSE);
4680 if (up)
4681 button_state &= ~button;
4682 else
4683 button_state |= button;
ee78dc32
GV
4684 }
4685 }
4686
fbd6baed 4687 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4688 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
4689
4690 /* Need to return true for XBUTTON messages, false for others,
4691 to indicate that we processed the message. */
4692 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 4693
5ac45f98 4694 case WM_MOUSEMOVE:
9eb16b62
JR
4695 /* If the mouse has just moved into the frame, start tracking
4696 it, so we will be notified when it leaves the frame. Mouse
4697 tracking only works under W98 and NT4 and later. On earlier
4698 versions, there is no way of telling when the mouse leaves the
4699 frame, so we just have to put up with help-echo and mouse
4700 highlighting remaining while the frame is not active. */
4701 if (track_mouse_event_fn && !track_mouse_window)
4702 {
4703 TRACKMOUSEEVENT tme;
4704 tme.cbSize = sizeof (tme);
4705 tme.dwFlags = TME_LEAVE;
4706 tme.hwndTrack = hwnd;
4707
4708 track_mouse_event_fn (&tme);
4709 track_mouse_window = hwnd;
4710 }
4711 case WM_VSCROLL:
fbd6baed 4712 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4713 || (msg == WM_MOUSEMOVE && button_state == 0))
4714 {
fbd6baed 4715 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4716 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4717 return 0;
4718 }
4719
4720 /* Hang onto mouse move and scroll messages for a bit, to avoid
4721 sending such events to Emacs faster than it can process them.
4722 If we get more events before the timer from the first message
4723 expires, we just replace the first message. */
4724
4725 if (saved_mouse_move_msg.msg.hwnd == 0)
4726 mouse_move_timer =
adcc3809
GV
4727 SetTimer (hwnd, MOUSE_MOVE_ID,
4728 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4729
4730 /* Hold onto message for now. */
4731 saved_mouse_move_msg.msg.hwnd = hwnd;
4732 saved_mouse_move_msg.msg.message = msg;
4733 saved_mouse_move_msg.msg.wParam = wParam;
4734 saved_mouse_move_msg.msg.lParam = lParam;
4735 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4736 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4737
4738 return 0;
4739
1edf84e7
GV
4740 case WM_MOUSEWHEEL:
4741 wmsg.dwModifiers = w32_get_modifiers ();
4742 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4743 return 0;
4744
cb9e33d4
RS
4745 case WM_DROPFILES:
4746 wmsg.dwModifiers = w32_get_modifiers ();
4747 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4748 return 0;
4749
84fb1139
KH
4750 case WM_TIMER:
4751 /* Flush out saved messages if necessary. */
4752 if (wParam == mouse_button_timer)
5ac45f98 4753 {
84fb1139
KH
4754 if (saved_mouse_button_msg.msg.hwnd)
4755 {
4756 post_msg (&saved_mouse_button_msg);
4757 saved_mouse_button_msg.msg.hwnd = 0;
4758 }
4759 KillTimer (hwnd, mouse_button_timer);
4760 mouse_button_timer = 0;
4761 }
4762 else if (wParam == mouse_move_timer)
4763 {
4764 if (saved_mouse_move_msg.msg.hwnd)
4765 {
4766 post_msg (&saved_mouse_move_msg);
4767 saved_mouse_move_msg.msg.hwnd = 0;
4768 }
4769 KillTimer (hwnd, mouse_move_timer);
4770 mouse_move_timer = 0;
5ac45f98 4771 }
5ac45f98 4772 return 0;
84fb1139
KH
4773
4774 case WM_NCACTIVATE:
4775 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4776 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4777 The only indication we get that something happened is receiving
4778 this message afterwards. So this is a good time to reset our
4779 keyboard modifiers' state. */
4780 reset_modifiers ();
4781 goto dflt;
da36a4d6 4782
1edf84e7 4783 case WM_INITMENU:
487163ac
AI
4784 button_state = 0;
4785 ReleaseCapture ();
1edf84e7
GV
4786 /* We must ensure menu bar is fully constructed and up to date
4787 before allowing user interaction with it. To achieve this
4788 we send this message to the lisp thread and wait for a
4789 reply (whose value is not actually needed) to indicate that
4790 the menu bar is now ready for use, so we can now return.
4791
4792 To remain responsive in the meantime, we enter a nested message
4793 loop that can process all other messages.
4794
4795 However, we skip all this if the message results from calling
4796 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4797 thread a message because it is blocked on us at this point. We
4798 set menubar_active before calling TrackPopupMenu to indicate
4799 this (there is no possibility of confusion with real menubar
4800 being active). */
4801
4802 f = x_window_to_frame (dpyinfo, hwnd);
4803 if (f
4804 && (f->output_data.w32->menubar_active
4805 /* We can receive this message even in the absence of a
4806 menubar (ie. when the system menu is activated) - in this
4807 case we do NOT want to forward the message, otherwise it
4808 will cause the menubar to suddenly appear when the user
4809 had requested it to be turned off! */
4810 || f->output_data.w32->menubar_widget == NULL))
4811 return 0;
4812
4813 {
4814 deferred_msg msg_buf;
4815
4816 /* Detect if message has already been deferred; in this case
4817 we cannot return any sensible value to ignore this. */
4818 if (find_deferred_msg (hwnd, msg) != NULL)
4819 abort ();
4820
4821 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4822 }
4823
4824 case WM_EXITMENULOOP:
4825 f = x_window_to_frame (dpyinfo, hwnd);
4826
9eb16b62
JR
4827 /* Free memory used by owner-drawn and help-echo strings. */
4828 w32_free_menu_strings (hwnd);
4829
1edf84e7
GV
4830 /* Indicate that menubar can be modified again. */
4831 if (f)
4832 f->output_data.w32->menubar_active = 0;
4833 goto dflt;
4834
126f2e35 4835 case WM_MENUSELECT:
4e3a1c61
JR
4836 /* Direct handling of help_echo in menus. Should be safe now
4837 that we generate the help_echo by placing a help event in the
4838 keyboard buffer. */
ca56d953 4839 {
ca56d953
JR
4840 HMENU menu = (HMENU) lParam;
4841 UINT menu_item = (UINT) LOWORD (wParam);
4842 UINT flags = (UINT) HIWORD (wParam);
4843
4e3a1c61 4844 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4845 }
126f2e35
JR
4846 return 0;
4847
87996783
GV
4848 case WM_MEASUREITEM:
4849 f = x_window_to_frame (dpyinfo, hwnd);
4850 if (f)
4851 {
4852 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4853
4854 if (pMis->CtlType == ODT_MENU)
4855 {
4856 /* Work out dimensions for popup menu titles. */
4857 char * title = (char *) pMis->itemData;
4858 HDC hdc = GetDC (hwnd);
4859 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4860 LOGFONT menu_logfont;
4861 HFONT old_font;
4862 SIZE size;
4863
4864 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4865 menu_logfont.lfWeight = FW_BOLD;
4866 menu_font = CreateFontIndirect (&menu_logfont);
4867 old_font = SelectObject (hdc, menu_font);
4868
dfff8a69
JR
4869 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4870 if (title)
4871 {
4872 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4873 pMis->itemWidth = size.cx;
4874 if (pMis->itemHeight < size.cy)
4875 pMis->itemHeight = size.cy;
4876 }
4877 else
4878 pMis->itemWidth = 0;
87996783
GV
4879
4880 SelectObject (hdc, old_font);
4881 DeleteObject (menu_font);
4882 ReleaseDC (hwnd, hdc);
4883 return TRUE;
4884 }
4885 }
4886 return 0;
4887
4888 case WM_DRAWITEM:
4889 f = x_window_to_frame (dpyinfo, hwnd);
4890 if (f)
4891 {
4892 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4893
4894 if (pDis->CtlType == ODT_MENU)
4895 {
4896 /* Draw popup menu title. */
4897 char * title = (char *) pDis->itemData;
212da13b
JR
4898 if (title)
4899 {
4900 HDC hdc = pDis->hDC;
4901 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4902 LOGFONT menu_logfont;
4903 HFONT old_font;
4904
4905 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4906 menu_logfont.lfWeight = FW_BOLD;
4907 menu_font = CreateFontIndirect (&menu_logfont);
4908 old_font = SelectObject (hdc, menu_font);
4909
4910 /* Always draw title as if not selected. */
4911 ExtTextOut (hdc,
4912 pDis->rcItem.left
4913 + GetSystemMetrics (SM_CXMENUCHECK),
4914 pDis->rcItem.top,
4915 ETO_OPAQUE, &pDis->rcItem,
4916 title, strlen (title), NULL);
4917
4918 SelectObject (hdc, old_font);
4919 DeleteObject (menu_font);
4920 }
87996783
GV
4921 return TRUE;
4922 }
4923 }
4924 return 0;
4925
1edf84e7
GV
4926#if 0
4927 /* Still not right - can't distinguish between clicks in the
4928 client area of the frame from clicks forwarded from the scroll
4929 bars - may have to hook WM_NCHITTEST to remember the mouse
4930 position and then check if it is in the client area ourselves. */
4931 case WM_MOUSEACTIVATE:
4932 /* Discard the mouse click that activates a frame, allowing the
4933 user to click anywhere without changing point (or worse!).
4934 Don't eat mouse clicks on scrollbars though!! */
4935 if (LOWORD (lParam) == HTCLIENT )
4936 return MA_ACTIVATEANDEAT;
4937 goto dflt;
4938#endif
4939
9eb16b62
JR
4940 case WM_MOUSELEAVE:
4941 /* No longer tracking mouse. */
4942 track_mouse_window = NULL;
4943
1edf84e7 4944 case WM_ACTIVATEAPP:
ccc2d29c 4945 case WM_ACTIVATE:
1edf84e7
GV
4946 case WM_WINDOWPOSCHANGED:
4947 case WM_SHOWWINDOW:
4948 /* Inform lisp thread that a frame might have just been obscured
4949 or exposed, so should recheck visibility of all frames. */
4950 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4951 goto dflt;
4952
da36a4d6 4953 case WM_SETFOCUS:
adcc3809
GV
4954 dpyinfo->faked_key = 0;
4955 reset_modifiers ();
ccc2d29c
GV
4956 register_hot_keys (hwnd);
4957 goto command;
8681157a 4958 case WM_KILLFOCUS:
ccc2d29c 4959 unregister_hot_keys (hwnd);
487163ac
AI
4960 button_state = 0;
4961 ReleaseCapture ();
65906840
JR
4962 /* Relinquish the system caret. */
4963 if (w32_system_caret_hwnd)
4964 {
93f2ca61 4965 w32_visible_system_caret_hwnd = NULL;
d285988b
JR
4966 w32_system_caret_hwnd = NULL;
4967 DestroyCaret ();
65906840 4968 }
ee78dc32
GV
4969 case WM_MOVE:
4970 case WM_SIZE:
ee78dc32 4971 case WM_COMMAND:
ccc2d29c 4972 command:
fbd6baed 4973 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4974 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4975 goto dflt;
8847d890
RS
4976
4977 case WM_CLOSE:
fbd6baed 4978 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4979 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4980 return 0;
4981
ee78dc32 4982 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
4983 /* Don't restrict the sizing of tip frames. */
4984 if (hwnd == tip_window)
4985 return 0;
ee78dc32
GV
4986 {
4987 WINDOWPLACEMENT wp;
4988 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4989
4990 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4991 GetWindowPlacement (hwnd, &wp);
4992
1edf84e7 4993 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4994 {
4995 RECT rect;
4996 int wdiff;
4997 int hdiff;
1edf84e7
GV
4998 DWORD font_width;
4999 DWORD line_height;
5000 DWORD internal_border;
5001 DWORD scrollbar_extra;
ee78dc32
GV
5002 RECT wr;
5003
5ac45f98 5004 wp.length = sizeof(wp);
ee78dc32
GV
5005 GetWindowRect (hwnd, &wr);
5006
3c190163 5007 enter_crit ();
ee78dc32 5008
1edf84e7
GV
5009 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5010 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5011 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5012 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 5013
3c190163 5014 leave_crit ();
ee78dc32
GV
5015
5016 memset (&rect, 0, sizeof (rect));
5017 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
5018 GetMenu (hwnd) != NULL);
5019
1edf84e7
GV
5020 /* Force width and height of client area to be exact
5021 multiples of the character cell dimensions. */
5022 wdiff = (lppos->cx - (rect.right - rect.left)
5023 - 2 * internal_border - scrollbar_extra)
5024 % font_width;
5025 hdiff = (lppos->cy - (rect.bottom - rect.top)
5026 - 2 * internal_border)
5027 % line_height;
ee78dc32
GV
5028
5029 if (wdiff || hdiff)
5030 {
5031 /* For right/bottom sizing we can just fix the sizes.
5032 However for top/left sizing we will need to fix the X
5033 and Y positions as well. */
5034
5035 lppos->cx -= wdiff;
5036 lppos->cy -= hdiff;
5037
5038 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 5039 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
5040 {
5041 if (lppos->x != wr.left || lppos->y != wr.top)
5042 {
5043 lppos->x += wdiff;
5044 lppos->y += hdiff;
5045 }
5046 else
5047 {
5048 lppos->flags |= SWP_NOMOVE;
5049 }
5050 }
5051
1edf84e7 5052 return 0;
ee78dc32
GV
5053 }
5054 }
5055 }
ee78dc32
GV
5056
5057 goto dflt;
1edf84e7 5058
b1f918f8
GV
5059 case WM_GETMINMAXINFO:
5060 /* Hack to correct bug that allows Emacs frames to be resized
5061 below the Minimum Tracking Size. */
5062 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
5063 /* Hack to allow resizing the Emacs frame above the screen size.
5064 Note that Windows 9x limits coordinates to 16-bits. */
5065 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5066 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
5067 return 0;
5068
1edf84e7
GV
5069 case WM_EMACS_CREATESCROLLBAR:
5070 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5071 (struct scroll_bar *) lParam);
5072
5ac45f98 5073 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
5074 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5075
dfdb4047 5076 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
5077 {
5078 HWND foreground_window;
5079 DWORD foreground_thread, retval;
5080
5081 /* On NT 5.0, and apparently Windows 98, it is necessary to
5082 attach to the thread that currently has focus in order to
5083 pull the focus away from it. */
5084 foreground_window = GetForegroundWindow ();
5085 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5086 if (!foreground_window
5087 || foreground_thread == GetCurrentThreadId ()
5088 || !AttachThreadInput (GetCurrentThreadId (),
5089 foreground_thread, TRUE))
5090 foreground_thread = 0;
5091
5092 retval = SetForegroundWindow ((HWND) wParam);
5093
5094 /* Detach from the previous foreground thread. */
5095 if (foreground_thread)
5096 AttachThreadInput (GetCurrentThreadId (),
5097 foreground_thread, FALSE);
5098
5099 return retval;
5100 }
dfdb4047 5101
5ac45f98
GV
5102 case WM_EMACS_SETWINDOWPOS:
5103 {
1edf84e7
GV
5104 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5105 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5106 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5107 }
1edf84e7 5108
ee78dc32 5109 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5110 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5111 return DestroyWindow ((HWND) wParam);
5112
93f2ca61
JR
5113 case WM_EMACS_HIDE_CARET:
5114 return HideCaret (hwnd);
5115
5116 case WM_EMACS_SHOW_CARET:
5117 return ShowCaret (hwnd);
5118
65906840
JR
5119 case WM_EMACS_DESTROY_CARET:
5120 w32_system_caret_hwnd = NULL;
93f2ca61 5121 w32_visible_system_caret_hwnd = NULL;
65906840
JR
5122 return DestroyCaret ();
5123
5124 case WM_EMACS_TRACK_CARET:
5125 /* If there is currently no system caret, create one. */
5126 if (w32_system_caret_hwnd == NULL)
5127 {
93f2ca61
JR
5128 /* Use the default caret width, and avoid changing it
5129 unneccesarily, as it confuses screen reader software. */
65906840 5130 w32_system_caret_hwnd = hwnd;
93f2ca61 5131 CreateCaret (hwnd, NULL, 0,
65906840
JR
5132 w32_system_caret_height);
5133 }
93f2ca61
JR
5134
5135 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5136 return 0;
5137 /* Ensure visible caret gets turned on when requested. */
5138 else if (w32_use_visible_system_caret
5139 && w32_visible_system_caret_hwnd != hwnd)
5140 {
5141 w32_visible_system_caret_hwnd = hwnd;
5142 return ShowCaret (hwnd);
5143 }
5144 /* Ensure visible caret gets turned off when requested. */
5145 else if (!w32_use_visible_system_caret
5146 && w32_visible_system_caret_hwnd)
5147 {
5148 w32_visible_system_caret_hwnd = NULL;
5149 return HideCaret (hwnd);
5150 }
5151 else
5152 return 1;
65906840 5153
1edf84e7
GV
5154 case WM_EMACS_TRACKPOPUPMENU:
5155 {
5156 UINT flags;
5157 POINT *pos;
5158 int retval;
5159 pos = (POINT *)lParam;
5160 flags = TPM_CENTERALIGN;
5161 if (button_state & LMOUSE)
5162 flags |= TPM_LEFTBUTTON;
5163 else if (button_state & RMOUSE)
5164 flags |= TPM_RIGHTBUTTON;
5165
87996783
GV
5166 /* Remember we did a SetCapture on the initial mouse down event,
5167 so for safety, we make sure the capture is cancelled now. */
5168 ReleaseCapture ();
490822ff 5169 button_state = 0;
87996783 5170
1edf84e7
GV
5171 /* Use menubar_active to indicate that WM_INITMENU is from
5172 TrackPopupMenu below, and should be ignored. */
5173 f = x_window_to_frame (dpyinfo, hwnd);
5174 if (f)
5175 f->output_data.w32->menubar_active = 1;
5176
5177 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5178 0, hwnd, NULL))
5179 {
5180 MSG amsg;
5181 /* Eat any mouse messages during popupmenu */
5182 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5183 PM_REMOVE));
5184 /* Get the menu selection, if any */
5185 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5186 {
5187 retval = LOWORD (amsg.wParam);
5188 }
5189 else
5190 {
5191 retval = 0;
5192 }
1edf84e7
GV
5193 }
5194 else
5195 {
5196 retval = -1;
5197 }
5198
5199 return retval;
5200 }
5201
ee78dc32 5202 default:
93fbe8b7
GV
5203 /* Check for messages registered at runtime. */
5204 if (msg == msh_mousewheel)
5205 {
5206 wmsg.dwModifiers = w32_get_modifiers ();
5207 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5208 return 0;
5209 }
5210
ee78dc32
GV
5211 dflt:
5212 return DefWindowProc (hwnd, msg, wParam, lParam);
5213 }
5214
1edf84e7
GV
5215
5216 /* The most common default return code for handled messages is 0. */
5217 return 0;
ee78dc32
GV
5218}
5219
5220void
5221my_create_window (f)
5222 struct frame * f;
5223{
5224 MSG msg;
5225
1edf84e7
GV
5226 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5227 abort ();
ee78dc32
GV
5228 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5229}
5230
ca56d953
JR
5231
5232/* Create a tooltip window. Unlike my_create_window, we do not do this
5233 indirectly via the Window thread, as we do not need to process Window
5234 messages for the tooltip. Creating tooltips indirectly also creates
5235 deadlocks when tooltips are created for menu items. */
5236void
5237my_create_tip_window (f)
5238 struct frame *f;
5239{
bfd6edcc 5240 RECT rect;
ca56d953 5241
bfd6edcc
JR
5242 rect.left = rect.top = 0;
5243 rect.right = PIXEL_WIDTH (f);
5244 rect.bottom = PIXEL_HEIGHT (f);
5245
5246 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5247 FRAME_EXTERNAL_MENU_BAR (f));
5248
5249 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5250 = CreateWindow (EMACS_CLASS,
5251 f->namebuf,
5252 f->output_data.w32->dwStyle,
5253 f->output_data.w32->left_pos,
5254 f->output_data.w32->top_pos,
bfd6edcc
JR
5255 rect.right - rect.left,
5256 rect.bottom - rect.top,
ca56d953
JR
5257 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5258 NULL,
5259 hinst,
5260 NULL);
5261
bfd6edcc 5262 if (tip_window)
ca56d953 5263 {
bfd6edcc
JR
5264 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5265 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5266 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5267 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5268
5269 /* Tip frames have no scrollbars. */
5270 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5271
5272 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5273 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5274 }
5275}
5276
5277
fbd6baed 5278/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5279
5280static void
fbd6baed 5281w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5282 struct frame *f;
5283 long window_prompting;
5284 int minibuffer_only;
5285{
5286 BLOCK_INPUT;
5287
5288 /* Use the resource name as the top-level window name
5289 for looking up resources. Make a non-Lisp copy
5290 for the window manager, so GC relocation won't bother it.
5291
5292 Elsewhere we specify the window name for the window manager. */
5293
5294 {
5295 char *str = (char *) XSTRING (Vx_resource_name)->data;
5296 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5297 strcpy (f->namebuf, str);
5298 }
5299
5300 my_create_window (f);
5301
5302 validate_x_resource_name ();
5303
5304 /* x_set_name normally ignores requests to set the name if the
5305 requested name is the same as the current name. This is the one
5306 place where that assumption isn't correct; f->name is set, but
5307 the server hasn't been told. */
5308 {
5309 Lisp_Object name;
5310 int explicit = f->explicit_name;
5311
5312 f->explicit_name = 0;
5313 name = f->name;
5314 f->name = Qnil;
5315 x_set_name (f, name, explicit);
5316 }
5317
5318 UNBLOCK_INPUT;
5319
5320 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5321 initialize_frame_menubar (f);
5322
fbd6baed 5323 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5324 error ("Unable to create window");
5325}
5326
5327/* Handle the icon stuff for this window. Perhaps later we might
5328 want an x_set_icon_position which can be called interactively as
5329 well. */
5330
5331static void
5332x_icon (f, parms)
5333 struct frame *f;
5334 Lisp_Object parms;
5335{
5336 Lisp_Object icon_x, icon_y;
5337
e9e23e23 5338 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5339 icons in the tray. */
6fc2811b
JR
5340 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5341 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5342 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5343 {
b7826503
PJ
5344 CHECK_NUMBER (icon_x);
5345 CHECK_NUMBER (icon_y);
ee78dc32
GV
5346 }
5347 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5348 error ("Both left and top icon corners of icon must be specified");
5349
5350 BLOCK_INPUT;
5351
5352 if (! EQ (icon_x, Qunbound))
5353 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5354
1edf84e7
GV
5355#if 0 /* TODO */
5356 /* Start up iconic or window? */
5357 x_wm_set_window_state
6fc2811b 5358 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5359 ? IconicState
5360 : NormalState));
5361
5362 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5363 ? f->icon_name
5364 : f->name))->data);
5365#endif
5366
ee78dc32
GV
5367 UNBLOCK_INPUT;
5368}
5369
6fc2811b
JR
5370
5371static void
5372x_make_gc (f)
5373 struct frame *f;
5374{
5375 XGCValues gc_values;
5376
5377 BLOCK_INPUT;
5378
5379 /* Create the GC's of this frame.
5380 Note that many default values are used. */
5381
5382 /* Normal video */
5383 gc_values.font = f->output_data.w32->font;
5384
5385 /* Cursor has cursor-color background, background-color foreground. */
5386 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5387 gc_values.background = f->output_data.w32->cursor_pixel;
5388 f->output_data.w32->cursor_gc
5389 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5390 (GCFont | GCForeground | GCBackground),
5391 &gc_values);
5392
5393 /* Reliefs. */
5394 f->output_data.w32->white_relief.gc = 0;
5395 f->output_data.w32->black_relief.gc = 0;
5396
5397 UNBLOCK_INPUT;
5398}
5399
5400
937e601e
AI
5401/* Handler for signals raised during x_create_frame and
5402 x_create_top_frame. FRAME is the frame which is partially
5403 constructed. */
5404
5405static Lisp_Object
5406unwind_create_frame (frame)
5407 Lisp_Object frame;
5408{
5409 struct frame *f = XFRAME (frame);
5410
5411 /* If frame is ``official'', nothing to do. */
5412 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5413 {
5414#ifdef GLYPH_DEBUG
5415 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5416#endif
5417
5418 x_free_frame_resources (f);
5419
5420 /* Check that reference counts are indeed correct. */
5421 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5422 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5423
5424 return Qt;
937e601e
AI
5425 }
5426
5427 return Qnil;
5428}
5429
5430
ee78dc32
GV
5431DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5432 1, 1, 0,
74e1aeec
JR
5433 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5434Returns an Emacs frame object.
5435ALIST is an alist of frame parameters.
5436If the parameters specify that the frame should not have a minibuffer,
5437and do not specify a specific minibuffer window to use,
5438then `default-minibuffer-frame' must be a frame whose minibuffer can
5439be shared by the new frame.
5440
5441This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5442 (parms)
5443 Lisp_Object parms;
5444{
5445 struct frame *f;
5446 Lisp_Object frame, tem;
5447 Lisp_Object name;
5448 int minibuffer_only = 0;
5449 long window_prompting = 0;
5450 int width, height;
dc220243 5451 int count = BINDING_STACK_SIZE ();
1edf84e7 5452 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5453 Lisp_Object display;
6fc2811b 5454 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5455 Lisp_Object parent;
5456 struct kboard *kb;
5457
4587b026
GV
5458 check_w32 ();
5459
ee78dc32
GV
5460 /* Use this general default value to start with
5461 until we know if this frame has a specified name. */
5462 Vx_resource_name = Vinvocation_name;
5463
6fc2811b 5464 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5465 if (EQ (display, Qunbound))
5466 display = Qnil;
5467 dpyinfo = check_x_display_info (display);
5468#ifdef MULTI_KBOARD
5469 kb = dpyinfo->kboard;
5470#else
5471 kb = &the_only_kboard;
5472#endif
5473
6fc2811b 5474 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5475 if (!STRINGP (name)
5476 && ! EQ (name, Qunbound)
5477 && ! NILP (name))
5478 error ("Invalid frame name--not a string or nil");
5479
5480 if (STRINGP (name))
5481 Vx_resource_name = name;
5482
5483 /* See if parent window is specified. */
6fc2811b 5484 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5485 if (EQ (parent, Qunbound))
5486 parent = Qnil;
5487 if (! NILP (parent))
b7826503 5488 CHECK_NUMBER (parent);
ee78dc32 5489
1edf84e7
GV
5490 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5491 /* No need to protect DISPLAY because that's not used after passing
5492 it to make_frame_without_minibuffer. */
5493 frame = Qnil;
5494 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5495 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5496 RES_TYPE_SYMBOL);
ee78dc32
GV
5497 if (EQ (tem, Qnone) || NILP (tem))
5498 f = make_frame_without_minibuffer (Qnil, kb, display);
5499 else if (EQ (tem, Qonly))
5500 {
5501 f = make_minibuffer_frame ();
5502 minibuffer_only = 1;
5503 }
5504 else if (WINDOWP (tem))
5505 f = make_frame_without_minibuffer (tem, kb, display);
5506 else
5507 f = make_frame (1);
5508
1edf84e7
GV
5509 XSETFRAME (frame, f);
5510
ee78dc32
GV
5511 /* Note that Windows does support scroll bars. */
5512 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5513 /* By default, make scrollbars the system standard width. */
5514 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5515
fbd6baed 5516 f->output_method = output_w32;
6fc2811b
JR
5517 f->output_data.w32 =
5518 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5519 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5520 FRAME_FONTSET (f) = -1;
937e601e 5521 record_unwind_protect (unwind_create_frame, frame);
4587b026 5522
1edf84e7 5523 f->icon_name
6fc2811b 5524 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5525 if (! STRINGP (f->icon_name))
5526 f->icon_name = Qnil;
5527
fbd6baed 5528/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5529#ifdef MULTI_KBOARD
5530 FRAME_KBOARD (f) = kb;
5531#endif
5532
5533 /* Specify the parent under which to make this window. */
5534
5535 if (!NILP (parent))
5536 {
1660f34a 5537 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5538 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5539 }
5540 else
5541 {
fbd6baed
GV
5542 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5543 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5544 }
5545
ee78dc32
GV
5546 /* Set the name; the functions to which we pass f expect the name to
5547 be set. */
5548 if (EQ (name, Qunbound) || NILP (name))
5549 {
fbd6baed 5550 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5551 f->explicit_name = 0;
5552 }
5553 else
5554 {
5555 f->name = name;
5556 f->explicit_name = 1;
5557 /* use the frame's title when getting resources for this frame. */
5558 specbind (Qx_resource_name, name);
5559 }
5560
5561 /* Extract the window parameters from the supplied values
5562 that are needed to determine window geometry. */
5563 {
5564 Lisp_Object font;
5565
6fc2811b
JR
5566 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5567
ee78dc32
GV
5568 BLOCK_INPUT;
5569 /* First, try whatever font the caller has specified. */
5570 if (STRINGP (font))
4587b026
GV
5571 {
5572 tem = Fquery_fontset (font, Qnil);
5573 if (STRINGP (tem))
5574 font = x_new_fontset (f, XSTRING (tem)->data);
5575 else
1075afa9 5576 font = x_new_font (f, XSTRING (font)->data);
4587b026 5577 }
ee78dc32
GV
5578 /* Try out a font which we hope has bold and italic variations. */
5579 if (!STRINGP (font))
e39649be 5580 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5581 if (! STRINGP (font))
6fc2811b 5582 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5583 /* If those didn't work, look for something which will at least work. */
5584 if (! STRINGP (font))
6fc2811b 5585 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5586 UNBLOCK_INPUT;
5587 if (! STRINGP (font))
1edf84e7 5588 font = build_string ("Fixedsys");
ee78dc32
GV
5589
5590 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5591 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5592 }
5593
5594 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5595 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5596 /* This defaults to 2 in order to match xterm. We recognize either
5597 internalBorderWidth or internalBorder (which is what xterm calls
5598 it). */
5599 if (NILP (Fassq (Qinternal_border_width, parms)))
5600 {
5601 Lisp_Object value;
5602
6fc2811b 5603 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5604 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5605 if (! EQ (value, Qunbound))
5606 parms = Fcons (Fcons (Qinternal_border_width, value),
5607 parms);
5608 }
1edf84e7 5609 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5610 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5611 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5612 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5613 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5614
5615 /* Also do the stuff which must be set before the window exists. */
5616 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5617 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5618 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5619 "background", "Background", RES_TYPE_STRING);
ee78dc32 5620 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5621 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5622 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5623 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5624 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5625 "borderColor", "BorderColor", RES_TYPE_STRING);
5626 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5627 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5628 x_default_parameter (f, parms, Qline_spacing, Qnil,
5629 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5630 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5631 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5632 x_default_parameter (f, parms, Qright_fringe, Qnil,
5633 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5634
ee78dc32 5635
6fc2811b
JR
5636 /* Init faces before x_default_parameter is called for scroll-bar
5637 parameters because that function calls x_set_scroll_bar_width,
5638 which calls change_frame_size, which calls Fset_window_buffer,
5639 which runs hooks, which call Fvertical_motion. At the end, we
5640 end up in init_iterator with a null face cache, which should not
5641 happen. */
5642 init_frame_faces (f);
5643
ee78dc32 5644 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5645 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5646 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5647 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5648 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5649 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5650 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5651 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
5652 x_default_parameter (f, parms, Qfullscreen, Qnil,
5653 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 5654
fbd6baed
GV
5655 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5656 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5657
5658 /* Add the tool-bar height to the initial frame height so that the
5659 user gets a text display area of the size he specified with -g or
5660 via .Xdefaults. Later changes of the tool-bar height don't
5661 change the frame size. This is done so that users can create
5662 tall Emacs frames without having to guess how tall the tool-bar
5663 will get. */
5664 if (FRAME_TOOL_BAR_LINES (f))
5665 {
5666 int margin, relief, bar_height;
5667
a05e2bae 5668 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5669 ? tool_bar_button_relief
5670 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5671
5672 if (INTEGERP (Vtool_bar_button_margin)
5673 && XINT (Vtool_bar_button_margin) > 0)
5674 margin = XFASTINT (Vtool_bar_button_margin);
5675 else if (CONSP (Vtool_bar_button_margin)
5676 && INTEGERP (XCDR (Vtool_bar_button_margin))
5677 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5678 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5679 else
5680 margin = 0;
5681
5682 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5683 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5684 }
5685
ee78dc32
GV
5686 window_prompting = x_figure_window_size (f, parms);
5687
5688 if (window_prompting & XNegative)
5689 {
5690 if (window_prompting & YNegative)
fbd6baed 5691 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5692 else
fbd6baed 5693 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5694 }
5695 else
5696 {
5697 if (window_prompting & YNegative)
fbd6baed 5698 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5699 else
fbd6baed 5700 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5701 }
5702
fbd6baed 5703 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5704
6fc2811b
JR
5705 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5706 f->no_split = minibuffer_only || EQ (tem, Qt);
5707
fbd6baed 5708 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5709 x_icon (f, parms);
6fc2811b
JR
5710
5711 x_make_gc (f);
5712
5713 /* Now consider the frame official. */
5714 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5715 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5716
5717 /* We need to do this after creating the window, so that the
5718 icon-creation functions can say whose icon they're describing. */
5719 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5720 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5721
5722 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5723 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5724 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5725 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5726 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5727 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5728 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5729 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5730
5731 /* Dimensions, especially f->height, must be done via change_frame_size.
5732 Change will not be effected unless different from the current
5733 f->height. */
5734 width = f->width;
5735 height = f->height;
dc220243 5736
1026b400
RS
5737 f->height = 0;
5738 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5739 change_frame_size (f, height, width, 1, 0, 0);
5740
6fc2811b
JR
5741 /* Tell the server what size and position, etc, we want, and how
5742 badly we want them. This should be done after we have the menu
5743 bar so that its size can be taken into account. */
ee78dc32
GV
5744 BLOCK_INPUT;
5745 x_wm_set_size_hint (f, window_prompting, 0);
5746 UNBLOCK_INPUT;
5747
815d969e
JR
5748 /* Avoid a bug that causes the new frame to never become visible if
5749 an echo area message is displayed during the following call1. */
5750 specbind(Qredisplay_dont_pause, Qt);
5751
4694d762
JR
5752 /* Set up faces after all frame parameters are known. This call
5753 also merges in face attributes specified for new frames. If we
5754 don't do this, the `menu' face for instance won't have the right
5755 colors, and the menu bar won't appear in the specified colors for
5756 new frames. */
5757 call1 (Qface_set_after_frame_default, frame);
5758
6fc2811b
JR
5759 /* Make the window appear on the frame and enable display, unless
5760 the caller says not to. However, with explicit parent, Emacs
5761 cannot control visibility, so don't try. */
fbd6baed 5762 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5763 {
5764 Lisp_Object visibility;
5765
6fc2811b 5766 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5767 if (EQ (visibility, Qunbound))
5768 visibility = Qt;
5769
5770 if (EQ (visibility, Qicon))
5771 x_iconify_frame (f);
5772 else if (! NILP (visibility))
5773 x_make_frame_visible (f);
5774 else
5775 /* Must have been Qnil. */
5776 ;
5777 }
6fc2811b 5778 UNGCPRO;
9e57df62
GM
5779
5780 /* Make sure windows on this frame appear in calls to next-window
5781 and similar functions. */
5782 Vwindow_list = Qnil;
5783
ee78dc32
GV
5784 return unbind_to (count, frame);
5785}
5786
5787/* FRAME is used only to get a handle on the X display. We don't pass the
5788 display info directly because we're called from frame.c, which doesn't
5789 know about that structure. */
5790Lisp_Object
5791x_get_focus_frame (frame)
5792 struct frame *frame;
5793{
fbd6baed 5794 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5795 Lisp_Object xfocus;
fbd6baed 5796 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5797 return Qnil;
5798
fbd6baed 5799 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5800 return xfocus;
5801}
1edf84e7
GV
5802
5803DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5804 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5805 (frame)
5806 Lisp_Object frame;
5807{
5808 x_focus_on_frame (check_x_frame (frame));
5809 return Qnil;
5810}
5811
ee78dc32 5812\f
767b1ff0
JR
5813/* Return the charset portion of a font name. */
5814char * xlfd_charset_of_font (char * fontname)
5815{
5816 char *charset, *encoding;
5817
5818 encoding = strrchr(fontname, '-');
ceb12877 5819 if (!encoding || encoding == fontname)
767b1ff0
JR
5820 return NULL;
5821
478ea067
AI
5822 for (charset = encoding - 1; charset >= fontname; charset--)
5823 if (*charset == '-')
5824 break;
767b1ff0 5825
478ea067 5826 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5827 return NULL;
5828
5829 return charset + 1;
5830}
5831
33d52f9c
GV
5832struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5833 int size, char* filename);
8edb0a6f 5834static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5835static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5836 char * charset);
5837static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5838
8edb0a6f 5839static struct font_info *
33d52f9c 5840w32_load_system_font (f,fontname,size)
55dcfc15
AI
5841 struct frame *f;
5842 char * fontname;
5843 int size;
ee78dc32 5844{
4587b026
GV
5845 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5846 Lisp_Object font_names;
5847
4587b026
GV
5848 /* Get a list of all the fonts that match this name. Once we
5849 have a list of matching fonts, we compare them against the fonts
5850 we already have loaded by comparing names. */
5851 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5852
5853 if (!NILP (font_names))
3c190163 5854 {
4587b026
GV
5855 Lisp_Object tail;
5856 int i;
4587b026
GV
5857
5858 /* First check if any are already loaded, as that is cheaper
5859 than loading another one. */
5860 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5861 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5862 if (dpyinfo->font_table[i].name
5863 && (!strcmp (dpyinfo->font_table[i].name,
5864 XSTRING (XCAR (tail))->data)
5865 || !strcmp (dpyinfo->font_table[i].full_name,
5866 XSTRING (XCAR (tail))->data)))
4587b026 5867 return (dpyinfo->font_table + i);
6fc2811b 5868
8e713be6 5869 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5870 }
1075afa9 5871 else if (w32_strict_fontnames)
5ca0cd71
GV
5872 {
5873 /* If EnumFontFamiliesEx was available, we got a full list of
5874 fonts back so stop now to avoid the possibility of loading a
5875 random font. If we had to fall back to EnumFontFamilies, the
5876 list is incomplete, so continue whether the font we want was
5877 listed or not. */
5878 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5879 FARPROC enum_font_families_ex
1075afa9 5880 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5881 if (enum_font_families_ex)
5882 return NULL;
5883 }
4587b026
GV
5884
5885 /* Load the font and add it to the table. */
5886 {
767b1ff0 5887 char *full_name, *encoding, *charset;
4587b026
GV
5888 XFontStruct *font;
5889 struct font_info *fontp;
3c190163 5890 LOGFONT lf;
4587b026 5891 BOOL ok;
19c291d3 5892 int codepage;
6fc2811b 5893 int i;
5ac45f98 5894
4587b026 5895 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5896 return (NULL);
5ac45f98 5897
4587b026
GV
5898 if (!*lf.lfFaceName)
5899 /* If no name was specified for the font, we get a random font
5900 from CreateFontIndirect - this is not particularly
5901 desirable, especially since CreateFontIndirect does not
5902 fill out the missing name in lf, so we never know what we
5903 ended up with. */
5904 return NULL;
5905
d65a9cdc
JR
5906 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5907 since those fonts leave garbage behind. */
5908 lf.lfQuality = ANTIALIASED_QUALITY;
5909
3c190163 5910 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5911 bzero (font, sizeof (*font));
5ac45f98 5912
33d52f9c
GV
5913 /* Set bdf to NULL to indicate that this is a Windows font. */
5914 font->bdf = NULL;
5ac45f98 5915
3c190163 5916 BLOCK_INPUT;
5ac45f98
GV
5917
5918 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5919
1a292d24
AI
5920 if (font->hfont == NULL)
5921 {
5922 ok = FALSE;
5923 }
5924 else
5925 {
5926 HDC hdc;
5927 HANDLE oldobj;
19c291d3
AI
5928
5929 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5930
5931 hdc = GetDC (dpyinfo->root_window);
5932 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5933
1a292d24 5934 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5935 if (codepage == CP_UNICODE)
5936 font->double_byte_p = 1;
5937 else
8b77111c
AI
5938 {
5939 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5940 don't report themselves as double byte fonts, when
5941 patently they are. So instead of trusting
5942 GetFontLanguageInfo, we check the properties of the
5943 codepage directly, since that is ultimately what we are
5944 working from anyway. */
5945 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5946 CPINFO cpi = {0};
5947 GetCPInfo (codepage, &cpi);
5948 font->double_byte_p = cpi.MaxCharSize > 1;
5949 }
5c6682be 5950
1a292d24
AI
5951 SelectObject (hdc, oldobj);
5952 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5953 /* Fill out details in lf according to the font that was
5954 actually loaded. */
5955 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5956 lf.lfWidth = font->tm.tmAveCharWidth;
5957 lf.lfWeight = font->tm.tmWeight;
5958 lf.lfItalic = font->tm.tmItalic;
5959 lf.lfCharSet = font->tm.tmCharSet;
5960 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5961 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5962 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5963 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5964
5965 w32_cache_char_metrics (font);
1a292d24 5966 }
5ac45f98 5967
1a292d24 5968 UNBLOCK_INPUT;
5ac45f98 5969
4587b026
GV
5970 if (!ok)
5971 {
1a292d24
AI
5972 w32_unload_font (dpyinfo, font);
5973 return (NULL);
5974 }
ee78dc32 5975
6fc2811b
JR
5976 /* Find a free slot in the font table. */
5977 for (i = 0; i < dpyinfo->n_fonts; ++i)
5978 if (dpyinfo->font_table[i].name == NULL)
5979 break;
5980
5981 /* If no free slot found, maybe enlarge the font table. */
5982 if (i == dpyinfo->n_fonts
5983 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5984 {
6fc2811b
JR
5985 int sz;
5986 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5987 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5988 dpyinfo->font_table
6fc2811b 5989 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5990 }
5991
6fc2811b
JR
5992 fontp = dpyinfo->font_table + i;
5993 if (i == dpyinfo->n_fonts)
5994 ++dpyinfo->n_fonts;
4587b026
GV
5995
5996 /* Now fill in the slots of *FONTP. */
5997 BLOCK_INPUT;
5998 fontp->font = font;
6fc2811b 5999 fontp->font_idx = i;
4587b026
GV
6000 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6001 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6002
767b1ff0
JR
6003 charset = xlfd_charset_of_font (fontname);
6004
19c291d3
AI
6005 /* Cache the W32 codepage for a font. This makes w32_encode_char
6006 (called for every glyph during redisplay) much faster. */
6007 fontp->codepage = codepage;
6008
4587b026
GV
6009 /* Work out the font's full name. */
6010 full_name = (char *)xmalloc (100);
767b1ff0 6011 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
6012 fontp->full_name = full_name;
6013 else
6014 {
6015 /* If all else fails - just use the name we used to load it. */
6016 xfree (full_name);
6017 fontp->full_name = fontp->name;
6018 }
6019
6020 fontp->size = FONT_WIDTH (font);
6021 fontp->height = FONT_HEIGHT (font);
6022
6023 /* The slot `encoding' specifies how to map a character
6024 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
6025 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6026 (0:0x20..0x7F, 1:0xA0..0xFF,
6027 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 6028 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 6029 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
6030 which is never used by any charset. If mapping can't be
6031 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
6032
6033 /* SJIS fonts need to be set to type 4, all others seem to work as
6034 type FONT_ENCODING_NOT_DECIDED. */
6035 encoding = strrchr (fontp->name, '-');
d84b082d 6036 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 6037 fontp->encoding[1] = 4;
33d52f9c 6038 else
1c885fe1 6039 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
6040
6041 /* The following three values are set to 0 under W32, which is
6042 what they get set to if XGetFontProperty fails under X. */
6043 fontp->baseline_offset = 0;
6044 fontp->relative_compose = 0;
33d52f9c 6045 fontp->default_ascent = 0;
4587b026 6046
6fc2811b
JR
6047 /* Set global flag fonts_changed_p to non-zero if the font loaded
6048 has a character with a smaller width than any other character
f7b9d4d1 6049 before, or if the font loaded has a smaller height than any
6fc2811b
JR
6050 other font loaded before. If this happens, it will make a
6051 glyph matrix reallocation necessary. */
f7b9d4d1 6052 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 6053 UNBLOCK_INPUT;
4587b026
GV
6054 return fontp;
6055 }
6056}
6057
33d52f9c
GV
6058/* Load font named FONTNAME of size SIZE for frame F, and return a
6059 pointer to the structure font_info while allocating it dynamically.
6060 If loading fails, return NULL. */
6061struct font_info *
6062w32_load_font (f,fontname,size)
6063struct frame *f;
6064char * fontname;
6065int size;
6066{
6067 Lisp_Object bdf_fonts;
6068 struct font_info *retval = NULL;
6069
8edb0a6f 6070 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
6071
6072 while (!retval && CONSP (bdf_fonts))
6073 {
6074 char *bdf_name, *bdf_file;
6075 Lisp_Object bdf_pair;
6076
8e713be6
KR
6077 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6078 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6079 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
6080
6081 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6082
8e713be6 6083 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
6084 }
6085
6086 if (retval)
6087 return retval;
6088
6089 return w32_load_system_font(f, fontname, size);
6090}
6091
6092
ee78dc32 6093void
fbd6baed
GV
6094w32_unload_font (dpyinfo, font)
6095 struct w32_display_info *dpyinfo;
ee78dc32
GV
6096 XFontStruct * font;
6097{
6098 if (font)
6099 {
c6be3860 6100 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
6101 if (font->bdf) w32_free_bdf_font (font->bdf);
6102
3c190163 6103 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
6104 xfree (font);
6105 }
6106}
6107
fbd6baed 6108/* The font conversion stuff between x and w32 */
ee78dc32
GV
6109
6110/* X font string is as follows (from faces.el)
6111 * (let ((- "[-?]")
6112 * (foundry "[^-]+")
6113 * (family "[^-]+")
6114 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6115 * (weight\? "\\([^-]*\\)") ; 1
6116 * (slant "\\([ior]\\)") ; 2
6117 * (slant\? "\\([^-]?\\)") ; 2
6118 * (swidth "\\([^-]*\\)") ; 3
6119 * (adstyle "[^-]*") ; 4
6120 * (pixelsize "[0-9]+")
6121 * (pointsize "[0-9][0-9]+")
6122 * (resx "[0-9][0-9]+")
6123 * (resy "[0-9][0-9]+")
6124 * (spacing "[cmp?*]")
6125 * (avgwidth "[0-9]+")
6126 * (registry "[^-]+")
6127 * (encoding "[^-]+")
6128 * )
ee78dc32 6129 */
ee78dc32 6130
8edb0a6f 6131static LONG
fbd6baed 6132x_to_w32_weight (lpw)
ee78dc32
GV
6133 char * lpw;
6134{
6135 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6136
6137 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6138 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6139 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6140 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6141 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6142 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6143 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6144 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6145 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6146 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6147 else
5ac45f98 6148 return FW_DONTCARE;
ee78dc32
GV
6149}
6150
5ac45f98 6151
8edb0a6f 6152static char *
fbd6baed 6153w32_to_x_weight (fnweight)
ee78dc32
GV
6154 int fnweight;
6155{
5ac45f98
GV
6156 if (fnweight >= FW_HEAVY) return "heavy";
6157 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6158 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6159 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6160 if (fnweight >= FW_MEDIUM) return "medium";
6161 if (fnweight >= FW_NORMAL) return "normal";
6162 if (fnweight >= FW_LIGHT) return "light";
6163 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6164 if (fnweight >= FW_THIN) return "thin";
6165 else
6166 return "*";
6167}
6168
8edb0a6f 6169static LONG
fbd6baed 6170x_to_w32_charset (lpcs)
5ac45f98
GV
6171 char * lpcs;
6172{
767b1ff0 6173 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6174 char *charset;
6175 int len = strlen (lpcs);
6176
6177 /* Support "*-#nnn" format for unknown charsets. */
6178 if (strncmp (lpcs, "*-#", 3) == 0)
6179 return atoi (lpcs + 3);
6180
6181 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6182 charset = alloca (len + 1);
6183 strcpy (charset, lpcs);
6184 lpcs = strchr (charset, '*');
6185 if (lpcs)
6186 *lpcs = 0;
4587b026 6187
dfff8a69
JR
6188 /* Look through w32-charset-info-alist for the character set.
6189 Format of each entry is
6190 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6191 */
8b77111c 6192 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6193
767b1ff0
JR
6194 if (NILP(this_entry))
6195 {
6196 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6197 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6198 return ANSI_CHARSET;
6199 else
6200 return DEFAULT_CHARSET;
6201 }
6202
6203 w32_charset = Fcar (Fcdr (this_entry));
6204
d84b082d 6205 /* Translate Lisp symbol to number. */
767b1ff0
JR
6206 if (w32_charset == Qw32_charset_ansi)
6207 return ANSI_CHARSET;
6208 if (w32_charset == Qw32_charset_symbol)
6209 return SYMBOL_CHARSET;
6210 if (w32_charset == Qw32_charset_shiftjis)
6211 return SHIFTJIS_CHARSET;
6212 if (w32_charset == Qw32_charset_hangeul)
6213 return HANGEUL_CHARSET;
6214 if (w32_charset == Qw32_charset_chinesebig5)
6215 return CHINESEBIG5_CHARSET;
6216 if (w32_charset == Qw32_charset_gb2312)
6217 return GB2312_CHARSET;
6218 if (w32_charset == Qw32_charset_oem)
6219 return OEM_CHARSET;
dfff8a69 6220#ifdef JOHAB_CHARSET
767b1ff0
JR
6221 if (w32_charset == Qw32_charset_johab)
6222 return JOHAB_CHARSET;
6223 if (w32_charset == Qw32_charset_easteurope)
6224 return EASTEUROPE_CHARSET;
6225 if (w32_charset == Qw32_charset_turkish)
6226 return TURKISH_CHARSET;
6227 if (w32_charset == Qw32_charset_baltic)
6228 return BALTIC_CHARSET;
6229 if (w32_charset == Qw32_charset_russian)
6230 return RUSSIAN_CHARSET;
6231 if (w32_charset == Qw32_charset_arabic)
6232 return ARABIC_CHARSET;
6233 if (w32_charset == Qw32_charset_greek)
6234 return GREEK_CHARSET;
6235 if (w32_charset == Qw32_charset_hebrew)
6236 return HEBREW_CHARSET;
6237 if (w32_charset == Qw32_charset_vietnamese)
6238 return VIETNAMESE_CHARSET;
6239 if (w32_charset == Qw32_charset_thai)
6240 return THAI_CHARSET;
6241 if (w32_charset == Qw32_charset_mac)
6242 return MAC_CHARSET;
dfff8a69 6243#endif /* JOHAB_CHARSET */
5ac45f98 6244#ifdef UNICODE_CHARSET
767b1ff0
JR
6245 if (w32_charset == Qw32_charset_unicode)
6246 return UNICODE_CHARSET;
5ac45f98 6247#endif
dfff8a69
JR
6248
6249 return DEFAULT_CHARSET;
5ac45f98
GV
6250}
6251
dfff8a69 6252
8edb0a6f 6253static char *
fbd6baed 6254w32_to_x_charset (fncharset)
5ac45f98
GV
6255 int fncharset;
6256{
5e905a57 6257 static char buf[32];
767b1ff0 6258 Lisp_Object charset_type;
1edf84e7 6259
5ac45f98
GV
6260 switch (fncharset)
6261 {
767b1ff0
JR
6262 case ANSI_CHARSET:
6263 /* Handle startup case of w32-charset-info-alist not
6264 being set up yet. */
6265 if (NILP(Vw32_charset_info_alist))
6266 return "iso8859-1";
6267 charset_type = Qw32_charset_ansi;
6268 break;
6269 case DEFAULT_CHARSET:
6270 charset_type = Qw32_charset_default;
6271 break;
6272 case SYMBOL_CHARSET:
6273 charset_type = Qw32_charset_symbol;
6274 break;
6275 case SHIFTJIS_CHARSET:
6276 charset_type = Qw32_charset_shiftjis;
6277 break;
6278 case HANGEUL_CHARSET:
6279 charset_type = Qw32_charset_hangeul;
6280 break;
6281 case GB2312_CHARSET:
6282 charset_type = Qw32_charset_gb2312;
6283 break;
6284 case CHINESEBIG5_CHARSET:
6285 charset_type = Qw32_charset_chinesebig5;
6286 break;
6287 case OEM_CHARSET:
6288 charset_type = Qw32_charset_oem;
6289 break;
4587b026
GV
6290
6291 /* More recent versions of Windows (95 and NT4.0) define more
6292 character sets. */
6293#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6294 case EASTEUROPE_CHARSET:
6295 charset_type = Qw32_charset_easteurope;
6296 break;
6297 case TURKISH_CHARSET:
6298 charset_type = Qw32_charset_turkish;
6299 break;
6300 case BALTIC_CHARSET:
6301 charset_type = Qw32_charset_baltic;
6302 break;
33d52f9c 6303 case RUSSIAN_CHARSET:
767b1ff0
JR
6304 charset_type = Qw32_charset_russian;
6305 break;
6306 case ARABIC_CHARSET:
6307 charset_type = Qw32_charset_arabic;
6308 break;
6309 case GREEK_CHARSET:
6310 charset_type = Qw32_charset_greek;
6311 break;
6312 case HEBREW_CHARSET:
6313 charset_type = Qw32_charset_hebrew;
6314 break;
6315 case VIETNAMESE_CHARSET:
6316 charset_type = Qw32_charset_vietnamese;
6317 break;
6318 case THAI_CHARSET:
6319 charset_type = Qw32_charset_thai;
6320 break;
6321 case MAC_CHARSET:
6322 charset_type = Qw32_charset_mac;
6323 break;
6324 case JOHAB_CHARSET:
6325 charset_type = Qw32_charset_johab;
6326 break;
4587b026
GV
6327#endif
6328
5ac45f98 6329#ifdef UNICODE_CHARSET
767b1ff0
JR
6330 case UNICODE_CHARSET:
6331 charset_type = Qw32_charset_unicode;
6332 break;
5ac45f98 6333#endif
767b1ff0
JR
6334 default:
6335 /* Encode numerical value of unknown charset. */
6336 sprintf (buf, "*-#%u", fncharset);
6337 return buf;
5ac45f98 6338 }
767b1ff0
JR
6339
6340 {
6341 Lisp_Object rest;
6342 char * best_match = NULL;
6343
6344 /* Look through w32-charset-info-alist for the character set.
6345 Prefer ISO codepages, and prefer lower numbers in the ISO
6346 range. Only return charsets for codepages which are installed.
6347
6348 Format of each entry is
6349 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6350 */
6351 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6352 {
6353 char * x_charset;
6354 Lisp_Object w32_charset;
6355 Lisp_Object codepage;
6356
6357 Lisp_Object this_entry = XCAR (rest);
6358
6359 /* Skip invalid entries in alist. */
6360 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6361 || !CONSP (XCDR (this_entry))
6362 || !SYMBOLP (XCAR (XCDR (this_entry))))
6363 continue;
6364
6365 x_charset = XSTRING (XCAR (this_entry))->data;
6366 w32_charset = XCAR (XCDR (this_entry));
6367 codepage = XCDR (XCDR (this_entry));
6368
6369 /* Look for Same charset and a valid codepage (or non-int
6370 which means ignore). */
6371 if (w32_charset == charset_type
6372 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6373 || IsValidCodePage (XINT (codepage))))
6374 {
6375 /* If we don't have a match already, then this is the
6376 best. */
6377 if (!best_match)
6378 best_match = x_charset;
6379 /* If this is an ISO codepage, and the best so far isn't,
6380 then this is better. */
d84b082d
JR
6381 else if (strnicmp (best_match, "iso", 3) != 0
6382 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
6383 best_match = x_charset;
6384 /* If both are ISO8859 codepages, choose the one with the
6385 lowest number in the encoding field. */
d84b082d
JR
6386 else if (strnicmp (best_match, "iso8859-", 8) == 0
6387 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
6388 {
6389 int best_enc = atoi (best_match + 8);
6390 int this_enc = atoi (x_charset + 8);
6391 if (this_enc > 0 && this_enc < best_enc)
6392 best_match = x_charset;
6393 }
6394 }
6395 }
6396
6397 /* If no match, encode the numeric value. */
6398 if (!best_match)
6399 {
6400 sprintf (buf, "*-#%u", fncharset);
6401 return buf;
6402 }
6403
5e905a57
JR
6404 strncpy(buf, best_match, 31);
6405 buf[31] = '\0';
767b1ff0
JR
6406 return buf;
6407 }
ee78dc32
GV
6408}
6409
dfff8a69 6410
d84b082d
JR
6411/* Return all the X charsets that map to a font. */
6412static Lisp_Object
6413w32_to_all_x_charsets (fncharset)
6414 int fncharset;
6415{
6416 static char buf[32];
6417 Lisp_Object charset_type;
6418 Lisp_Object retval = Qnil;
6419
6420 switch (fncharset)
6421 {
6422 case ANSI_CHARSET:
6423 /* Handle startup case of w32-charset-info-alist not
6424 being set up yet. */
6425 if (NILP(Vw32_charset_info_alist))
6426 return "iso8859-1";
6427 charset_type = Qw32_charset_ansi;
6428 break;
6429 case DEFAULT_CHARSET:
6430 charset_type = Qw32_charset_default;
6431 break;
6432 case SYMBOL_CHARSET:
6433 charset_type = Qw32_charset_symbol;
6434 break;
6435 case SHIFTJIS_CHARSET:
6436 charset_type = Qw32_charset_shiftjis;
6437 break;
6438 case HANGEUL_CHARSET:
6439 charset_type = Qw32_charset_hangeul;
6440 break;
6441 case GB2312_CHARSET:
6442 charset_type = Qw32_charset_gb2312;
6443 break;
6444 case CHINESEBIG5_CHARSET:
6445 charset_type = Qw32_charset_chinesebig5;
6446 break;
6447 case OEM_CHARSET:
6448 charset_type = Qw32_charset_oem;
6449 break;
6450
6451 /* More recent versions of Windows (95 and NT4.0) define more
6452 character sets. */
6453#ifdef EASTEUROPE_CHARSET
6454 case EASTEUROPE_CHARSET:
6455 charset_type = Qw32_charset_easteurope;
6456 break;
6457 case TURKISH_CHARSET:
6458 charset_type = Qw32_charset_turkish;
6459 break;
6460 case BALTIC_CHARSET:
6461 charset_type = Qw32_charset_baltic;
6462 break;
6463 case RUSSIAN_CHARSET:
6464 charset_type = Qw32_charset_russian;
6465 break;
6466 case ARABIC_CHARSET:
6467 charset_type = Qw32_charset_arabic;
6468 break;
6469 case GREEK_CHARSET:
6470 charset_type = Qw32_charset_greek;
6471 break;
6472 case HEBREW_CHARSET:
6473 charset_type = Qw32_charset_hebrew;
6474 break;
6475 case VIETNAMESE_CHARSET:
6476 charset_type = Qw32_charset_vietnamese;
6477 break;
6478 case THAI_CHARSET:
6479 charset_type = Qw32_charset_thai;
6480 break;
6481 case MAC_CHARSET:
6482 charset_type = Qw32_charset_mac;
6483 break;
6484 case JOHAB_CHARSET:
6485 charset_type = Qw32_charset_johab;
6486 break;
6487#endif
6488
6489#ifdef UNICODE_CHARSET
6490 case UNICODE_CHARSET:
6491 charset_type = Qw32_charset_unicode;
6492 break;
6493#endif
6494 default:
6495 /* Encode numerical value of unknown charset. */
6496 sprintf (buf, "*-#%u", fncharset);
6497 return Fcons (build_string (buf), Qnil);
6498 }
6499
6500 {
6501 Lisp_Object rest;
6502 /* Look through w32-charset-info-alist for the character set.
6503 Only return charsets for codepages which are installed.
6504
6505 Format of each entry in Vw32_charset_info_alist is
6506 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6507 */
6508 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6509 {
6510 Lisp_Object x_charset;
6511 Lisp_Object w32_charset;
6512 Lisp_Object codepage;
6513
6514 Lisp_Object this_entry = XCAR (rest);
6515
6516 /* Skip invalid entries in alist. */
6517 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6518 || !CONSP (XCDR (this_entry))
6519 || !SYMBOLP (XCAR (XCDR (this_entry))))
6520 continue;
6521
6522 x_charset = XCAR (this_entry);
6523 w32_charset = XCAR (XCDR (this_entry));
6524 codepage = XCDR (XCDR (this_entry));
6525
6526 /* Look for Same charset and a valid codepage (or non-int
6527 which means ignore). */
6528 if (w32_charset == charset_type
6529 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6530 || IsValidCodePage (XINT (codepage))))
6531 {
6532 retval = Fcons (x_charset, retval);
6533 }
6534 }
6535
6536 /* If no match, encode the numeric value. */
6537 if (NILP (retval))
6538 {
6539 sprintf (buf, "*-#%u", fncharset);
6540 return Fcons (build_string (buf), Qnil);
6541 }
6542
6543 return retval;
6544 }
6545}
6546
dfff8a69
JR
6547/* Get the Windows codepage corresponding to the specified font. The
6548 charset info in the font name is used to look up
6549 w32-charset-to-codepage-alist. */
6550int
6551w32_codepage_for_font (char *fontname)
6552{
767b1ff0
JR
6553 Lisp_Object codepage, entry;
6554 char *charset_str, *charset, *end;
dfff8a69 6555
767b1ff0 6556 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6557 return CP_DEFAULT;
6558
767b1ff0
JR
6559 /* Extract charset part of font string. */
6560 charset = xlfd_charset_of_font (fontname);
6561
6562 if (!charset)
ceb12877 6563 return CP_UNKNOWN;
767b1ff0 6564
8b77111c 6565 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6566 strcpy (charset_str, charset);
6567
8b77111c 6568#if 0
dfff8a69
JR
6569 /* Remove leading "*-". */
6570 if (strncmp ("*-", charset_str, 2) == 0)
6571 charset = charset_str + 2;
6572 else
8b77111c 6573#endif
dfff8a69
JR
6574 charset = charset_str;
6575
6576 /* Stop match at wildcard (including preceding '-'). */
6577 if (end = strchr (charset, '*'))
6578 {
6579 if (end > charset && *(end-1) == '-')
6580 end--;
6581 *end = '\0';
6582 }
6583
767b1ff0
JR
6584 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6585 if (NILP (entry))
ceb12877 6586 return CP_UNKNOWN;
767b1ff0
JR
6587
6588 codepage = Fcdr (Fcdr (entry));
6589
6590 if (NILP (codepage))
6591 return CP_8BIT;
6592 else if (XFASTINT (codepage) == XFASTINT (Qt))
6593 return CP_UNICODE;
6594 else if (INTEGERP (codepage))
dfff8a69
JR
6595 return XINT (codepage);
6596 else
ceb12877 6597 return CP_UNKNOWN;
dfff8a69
JR
6598}
6599
6600
8edb0a6f 6601static BOOL
767b1ff0 6602w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6603 LOGFONT * lplogfont;
6604 char * lpxstr;
6605 int len;
767b1ff0 6606 char * specific_charset;
ee78dc32 6607{
6fc2811b 6608 char* fonttype;
f46e6225 6609 char *fontname;
3cb20f4a
RS
6610 char height_pixels[8];
6611 char height_dpi[8];
6612 char width_pixels[8];
4587b026 6613 char *fontname_dash;
d88c567c
JR
6614 int display_resy = one_w32_display_info.resy;
6615 int display_resx = one_w32_display_info.resx;
f46e6225
GV
6616 int bufsz;
6617 struct coding_system coding;
3cb20f4a
RS
6618
6619 if (!lpxstr) abort ();
ee78dc32 6620
3cb20f4a
RS
6621 if (!lplogfont)
6622 return FALSE;
6623
6fc2811b
JR
6624 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6625 fonttype = "raster";
6626 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6627 fonttype = "outline";
6628 else
6629 fonttype = "unknown";
6630
1fa3a200 6631 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6632 &coding);
aab5ac44
KH
6633 coding.src_multibyte = 0;
6634 coding.dst_multibyte = 1;
f46e6225
GV
6635 coding.mode |= CODING_MODE_LAST_BLOCK;
6636 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6637
6638 fontname = alloca(sizeof(*fontname) * bufsz);
6639 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6640 strlen(lplogfont->lfFaceName), bufsz - 1);
6641 *(fontname + coding.produced) = '\0';
4587b026
GV
6642
6643 /* Replace dashes with underscores so the dashes are not
f46e6225 6644 misinterpreted. */
4587b026
GV
6645 fontname_dash = fontname;
6646 while (fontname_dash = strchr (fontname_dash, '-'))
6647 *fontname_dash = '_';
6648
3cb20f4a 6649 if (lplogfont->lfHeight)
ee78dc32 6650 {
3cb20f4a
RS
6651 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6652 sprintf (height_dpi, "%u",
33d52f9c 6653 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6654 }
6655 else
ee78dc32 6656 {
3cb20f4a
RS
6657 strcpy (height_pixels, "*");
6658 strcpy (height_dpi, "*");
ee78dc32 6659 }
3cb20f4a
RS
6660 if (lplogfont->lfWidth)
6661 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6662 else
6663 strcpy (width_pixels, "*");
6664
6665 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6666 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6667 fonttype, /* foundry */
4587b026
GV
6668 fontname, /* family */
6669 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6670 lplogfont->lfItalic?'i':'r', /* slant */
6671 /* setwidth name */
6672 /* add style name */
6673 height_pixels, /* pixel size */
6674 height_dpi, /* point size */
33d52f9c
GV
6675 display_resx, /* resx */
6676 display_resy, /* resy */
4587b026
GV
6677 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6678 ? 'p' : 'c', /* spacing */
6679 width_pixels, /* avg width */
767b1ff0
JR
6680 specific_charset ? specific_charset
6681 : w32_to_x_charset (lplogfont->lfCharSet)
6682 /* charset registry and encoding */
3cb20f4a
RS
6683 );
6684
ee78dc32
GV
6685 lpxstr[len - 1] = 0; /* just to be sure */
6686 return (TRUE);
6687}
6688
8edb0a6f 6689static BOOL
fbd6baed 6690x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6691 char * lpxstr;
6692 LOGFONT * lplogfont;
6693{
f46e6225
GV
6694 struct coding_system coding;
6695
ee78dc32 6696 if (!lplogfont) return (FALSE);
f46e6225 6697
ee78dc32 6698 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6699
1a292d24 6700 /* Set default value for each field. */
771c47d5 6701#if 1
ee78dc32
GV
6702 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6703 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6704 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6705#else
6706 /* go for maximum quality */
6707 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6708 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6709 lplogfont->lfQuality = PROOF_QUALITY;
6710#endif
6711
1a292d24
AI
6712 lplogfont->lfCharSet = DEFAULT_CHARSET;
6713 lplogfont->lfWeight = FW_DONTCARE;
6714 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6715
5ac45f98
GV
6716 if (!lpxstr)
6717 return FALSE;
6718
6719 /* Provide a simple escape mechanism for specifying Windows font names
6720 * directly -- if font spec does not beginning with '-', assume this
6721 * format:
6722 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6723 */
ee78dc32 6724
5ac45f98
GV
6725 if (*lpxstr == '-')
6726 {
33d52f9c
GV
6727 int fields, tem;
6728 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6729 width[10], resy[10], remainder[50];
5ac45f98 6730 char * encoding;
d98c0337 6731 int dpi = one_w32_display_info.resy;
5ac45f98
GV
6732
6733 fields = sscanf (lpxstr,
8b77111c 6734 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6735 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6736 if (fields == EOF)
6737 return (FALSE);
6738
6739 /* In the general case when wildcards cover more than one field,
6740 we don't know which field is which, so don't fill any in.
6741 However, we need to cope with this particular form, which is
6742 generated by font_list_1 (invoked by try_font_list):
6743 "-raster-6x10-*-gb2312*-*"
6744 and make sure to correctly parse the charset field. */
6745 if (fields == 3)
6746 {
6747 fields = sscanf (lpxstr,
6748 "-%*[^-]-%49[^-]-*-%49s",
6749 name, remainder);
6750 }
6751 else if (fields < 9)
6752 {
6753 fields = 0;
6754 remainder[0] = 0;
6755 }
6fc2811b 6756
5ac45f98
GV
6757 if (fields > 0 && name[0] != '*')
6758 {
8ea3e054
RS
6759 int bufsize;
6760 unsigned char *buf;
6761
f46e6225 6762 setup_coding_system
1fa3a200 6763 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6764 coding.src_multibyte = 1;
6765 coding.dst_multibyte = 1;
8ea3e054
RS
6766 bufsize = encoding_buffer_size (&coding, strlen (name));
6767 buf = (unsigned char *) alloca (bufsize);
f46e6225 6768 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6769 encode_coding (&coding, name, buf, strlen (name), bufsize);
6770 if (coding.produced >= LF_FACESIZE)
6771 coding.produced = LF_FACESIZE - 1;
6772 buf[coding.produced] = 0;
6773 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6774 }
6775 else
6776 {
6fc2811b 6777 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6778 }
6779
6780 fields--;
6781
fbd6baed 6782 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6783
6784 fields--;
6785
c8874f14 6786 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6787
6788 fields--;
6789
6790 if (fields > 0 && pixels[0] != '*')
6791 lplogfont->lfHeight = atoi (pixels);
6792
6793 fields--;
5ac45f98 6794 fields--;
33d52f9c
GV
6795 if (fields > 0 && resy[0] != '*')
6796 {
6fc2811b 6797 tem = atoi (resy);
33d52f9c
GV
6798 if (tem > 0) dpi = tem;
6799 }
5ac45f98 6800
33d52f9c
GV
6801 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6802 lplogfont->lfHeight = atoi (height) * dpi / 720;
6803
6804 if (fields > 0)
5ac45f98
GV
6805 lplogfont->lfPitchAndFamily =
6806 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6807
6808 fields--;
6809
6810 if (fields > 0 && width[0] != '*')
6811 lplogfont->lfWidth = atoi (width) / 10;
6812
6813 fields--;
6814
4587b026 6815 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6816 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6817 {
5ac45f98
GV
6818 int len = strlen (remainder);
6819 if (len > 0 && remainder[len-1] == '-')
6820 remainder[len-1] = 0;
ee78dc32 6821 }
5ac45f98 6822 encoding = remainder;
8b77111c 6823#if 0
5ac45f98
GV
6824 if (strncmp (encoding, "*-", 2) == 0)
6825 encoding += 2;
8b77111c
AI
6826#endif
6827 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6828 }
6829 else
6830 {
6831 int fields;
6832 char name[100], height[10], width[10], weight[20];
a1a80b40 6833
5ac45f98
GV
6834 fields = sscanf (lpxstr,
6835 "%99[^:]:%9[^:]:%9[^:]:%19s",
6836 name, height, width, weight);
6837
6838 if (fields == EOF) return (FALSE);
6839
6840 if (fields > 0)
6841 {
6842 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6843 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6844 }
6845 else
6846 {
6847 lplogfont->lfFaceName[0] = 0;
6848 }
6849
6850 fields--;
6851
6852 if (fields > 0)
6853 lplogfont->lfHeight = atoi (height);
6854
6855 fields--;
6856
6857 if (fields > 0)
6858 lplogfont->lfWidth = atoi (width);
6859
6860 fields--;
6861
fbd6baed 6862 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6863 }
6864
6865 /* This makes TrueType fonts work better. */
6866 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6867
ee78dc32
GV
6868 return (TRUE);
6869}
6870
d88c567c
JR
6871/* Strip the pixel height and point height from the given xlfd, and
6872 return the pixel height. If no pixel height is specified, calculate
6873 one from the point height, or if that isn't defined either, return
6874 0 (which usually signifies a scalable font).
6875*/
8edb0a6f
JR
6876static int
6877xlfd_strip_height (char *fontname)
d88c567c 6878{
8edb0a6f 6879 int pixel_height, field_number;
d88c567c
JR
6880 char *read_from, *write_to;
6881
6882 xassert (fontname);
6883
6884 pixel_height = field_number = 0;
6885 write_to = NULL;
6886
6887 /* Look for height fields. */
6888 for (read_from = fontname; *read_from; read_from++)
6889 {
6890 if (*read_from == '-')
6891 {
6892 field_number++;
6893 if (field_number == 7) /* Pixel height. */
6894 {
6895 read_from++;
6896 write_to = read_from;
6897
6898 /* Find end of field. */
6899 for (;*read_from && *read_from != '-'; read_from++)
6900 ;
6901
6902 /* Split the fontname at end of field. */
6903 if (*read_from)
6904 {
6905 *read_from = '\0';
6906 read_from++;
6907 }
6908 pixel_height = atoi (write_to);
6909 /* Blank out field. */
6910 if (read_from > write_to)
6911 {
6912 *write_to = '-';
6913 write_to++;
6914 }
767b1ff0 6915 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6916 return now. */
6917 else
6918 return pixel_height;
6919
6920 /* If we got a pixel height, the point height can be
6921 ignored. Just blank it out and break now. */
6922 if (pixel_height)
6923 {
6924 /* Find end of point size field. */
6925 for (; *read_from && *read_from != '-'; read_from++)
6926 ;
6927
6928 if (*read_from)
6929 read_from++;
6930
6931 /* Blank out the point size field. */
6932 if (read_from > write_to)
6933 {
6934 *write_to = '-';
6935 write_to++;
6936 }
6937 else
6938 return pixel_height;
6939
6940 break;
6941 }
6942 /* If the point height is already blank, break now. */
6943 if (*read_from == '-')
6944 {
6945 read_from++;
6946 break;
6947 }
6948 }
6949 else if (field_number == 8)
6950 {
6951 /* If we didn't get a pixel height, try to get the point
6952 height and convert that. */
6953 int point_size;
6954 char *point_size_start = read_from++;
6955
6956 /* Find end of field. */
6957 for (; *read_from && *read_from != '-'; read_from++)
6958 ;
6959
6960 if (*read_from)
6961 {
6962 *read_from = '\0';
6963 read_from++;
6964 }
6965
6966 point_size = atoi (point_size_start);
6967
6968 /* Convert to pixel height. */
6969 pixel_height = point_size
6970 * one_w32_display_info.height_in / 720;
6971
6972 /* Blank out this field and break. */
6973 *write_to = '-';
6974 write_to++;
6975 break;
6976 }
6977 }
6978 }
6979
6980 /* Shift the rest of the font spec into place. */
6981 if (write_to && read_from > write_to)
6982 {
6983 for (; *read_from; read_from++, write_to++)
6984 *write_to = *read_from;
6985 *write_to = '\0';
6986 }
6987
6988 return pixel_height;
6989}
6990
6fc2811b 6991/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 6992static BOOL
6fc2811b
JR
6993w32_font_match (fontname, pattern)
6994 char * fontname;
6995 char * pattern;
ee78dc32 6996{
e7c72122 6997 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 6998 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6999 char *ptr;
ee78dc32 7000
d88c567c
JR
7001 /* Copy fontname so we can modify it during comparison. */
7002 strcpy (font_name_copy, fontname);
7003
6fc2811b
JR
7004 ptr = regex;
7005 *ptr++ = '^';
ee78dc32 7006
6fc2811b
JR
7007 /* Turn pattern into a regexp and do a regexp match. */
7008 for (; *pattern; pattern++)
7009 {
7010 if (*pattern == '?')
7011 *ptr++ = '.';
7012 else if (*pattern == '*')
7013 {
7014 *ptr++ = '.';
7015 *ptr++ = '*';
7016 }
33d52f9c 7017 else
6fc2811b 7018 *ptr++ = *pattern;
ee78dc32 7019 }
6fc2811b
JR
7020 *ptr = '$';
7021 *(ptr + 1) = '\0';
7022
d88c567c
JR
7023 /* Strip out font heights and compare them seperately, since
7024 rounding error can cause mismatches. This also allows a
7025 comparison between a font that declares only a pixel height and a
7026 pattern that declares the point height.
7027 */
7028 {
7029 int font_height, pattern_height;
7030
7031 font_height = xlfd_strip_height (font_name_copy);
7032 pattern_height = xlfd_strip_height (regex);
7033
7034 /* Compare now, and don't bother doing expensive regexp matching
7035 if the heights differ. */
7036 if (font_height && pattern_height && (font_height != pattern_height))
7037 return FALSE;
7038 }
7039
6fc2811b 7040 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 7041 font_name_copy) >= 0);
ee78dc32
GV
7042}
7043
5ca0cd71
GV
7044/* Callback functions, and a structure holding info they need, for
7045 listing system fonts on W32. We need one set of functions to do the
7046 job properly, but these don't work on NT 3.51 and earlier, so we
7047 have a second set which don't handle character sets properly to
7048 fall back on.
7049
7050 In both cases, there are two passes made. The first pass gets one
7051 font from each family, the second pass lists all the fonts from
7052 each family. */
7053
ee78dc32
GV
7054typedef struct enumfont_t
7055{
7056 HDC hdc;
7057 int numFonts;
3cb20f4a 7058 LOGFONT logfont;
ee78dc32
GV
7059 XFontStruct *size_ref;
7060 Lisp_Object *pattern;
d84b082d 7061 Lisp_Object list;
ee78dc32
GV
7062 Lisp_Object *tail;
7063} enumfont_t;
7064
d84b082d
JR
7065
7066static void
7067enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7068
7069
8edb0a6f 7070static int CALLBACK
ee78dc32
GV
7071enum_font_cb2 (lplf, lptm, FontType, lpef)
7072 ENUMLOGFONT * lplf;
7073 NEWTEXTMETRIC * lptm;
7074 int FontType;
7075 enumfont_t * lpef;
7076{
66895301
JR
7077 /* Ignore struck out and underlined versions of fonts. */
7078 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7079 return 1;
7080
7081 /* Only return fonts with names starting with @ if they were
7082 explicitly specified, since Microsoft uses an initial @ to
7083 denote fonts for vertical writing, without providing a more
7084 convenient way of identifying them. */
7085 if (lplf->elfLogFont.lfFaceName[0] == '@'
7086 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
7087 return 1;
7088
4587b026
GV
7089 /* Check that the character set matches if it was specified */
7090 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7091 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 7092 return 1;
4587b026 7093
ee78dc32
GV
7094 {
7095 char buf[100];
4587b026 7096 Lisp_Object width = Qnil;
d84b082d 7097 Lisp_Object charset_list = Qnil;
767b1ff0 7098 char *charset = NULL;
ee78dc32 7099
6fc2811b
JR
7100 /* Truetype fonts do not report their true metrics until loaded */
7101 if (FontType != RASTER_FONTTYPE)
3cb20f4a 7102 {
6fc2811b
JR
7103 if (!NILP (*(lpef->pattern)))
7104 {
7105 /* Scalable fonts are as big as you want them to be. */
7106 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7107 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7108 width = make_number (lpef->logfont.lfWidth);
7109 }
7110 else
7111 {
7112 lplf->elfLogFont.lfHeight = 0;
7113 lplf->elfLogFont.lfWidth = 0;
7114 }
3cb20f4a 7115 }
6fc2811b 7116
f46e6225
GV
7117 /* Make sure the height used here is the same as everywhere
7118 else (ie character height, not cell height). */
6fc2811b
JR
7119 if (lplf->elfLogFont.lfHeight > 0)
7120 {
7121 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7122 if (FontType == RASTER_FONTTYPE)
7123 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7124 else
7125 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7126 }
4587b026 7127
767b1ff0
JR
7128 if (!NILP (*(lpef->pattern)))
7129 {
7130 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
7131
644cefdf
JR
7132 /* We already checked charsets above, but DEFAULT_CHARSET
7133 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7134 if (charset
7135 && strncmp (charset, "*-*", 3) != 0
7136 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7137 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7138 return 1;
767b1ff0
JR
7139 }
7140
d84b082d
JR
7141 if (charset)
7142 charset_list = Fcons (build_string (charset), Qnil);
7143 else
7144 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 7145
d84b082d
JR
7146 /* Loop through the charsets. */
7147 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 7148 {
d84b082d
JR
7149 Lisp_Object this_charset = Fcar (charset_list);
7150 charset = XSTRING (this_charset)->data;
7151
7152 /* List bold and italic variations if w32-enable-synthesized-fonts
7153 is non-nil and this is a plain font. */
7154 if (w32_enable_synthesized_fonts
7155 && lplf->elfLogFont.lfWeight == FW_NORMAL
7156 && lplf->elfLogFont.lfItalic == FALSE)
7157 {
7158 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7159 charset, width);
7160 /* bold. */
7161 lplf->elfLogFont.lfWeight = FW_BOLD;
7162 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7163 charset, width);
7164 /* bold italic. */
7165 lplf->elfLogFont.lfItalic = TRUE;
7166 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7167 charset, width);
7168 /* italic. */
7169 lplf->elfLogFont.lfWeight = FW_NORMAL;
7170 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7171 charset, width);
7172 }
7173 else
7174 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7175 charset, width);
ee78dc32
GV
7176 }
7177 }
6fc2811b 7178
5e905a57 7179 return 1;
ee78dc32
GV
7180}
7181
d84b082d
JR
7182static void
7183enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7184 enumfont_t * lpef;
7185 LOGFONT * logfont;
7186 char * match_charset;
7187 Lisp_Object width;
7188{
7189 char buf[100];
7190
7191 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7192 return;
7193
7194 if (NILP (*(lpef->pattern))
7195 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
7196 {
7197 /* Check if we already listed this font. This may happen if
7198 w32_enable_synthesized_fonts is non-nil, and there are real
7199 bold and italic versions of the font. */
7200 Lisp_Object font_name = build_string (buf);
7201 if (NILP (Fmember (font_name, lpef->list)))
7202 {
7203 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
7204 lpef->tail = &(XCDR (*lpef->tail));
7205 lpef->numFonts++;
7206 }
7207 }
7208}
7209
7210
8edb0a6f 7211static int CALLBACK
ee78dc32
GV
7212enum_font_cb1 (lplf, lptm, FontType, lpef)
7213 ENUMLOGFONT * lplf;
7214 NEWTEXTMETRIC * lptm;
7215 int FontType;
7216 enumfont_t * lpef;
7217{
7218 return EnumFontFamilies (lpef->hdc,
7219 lplf->elfLogFont.lfFaceName,
7220 (FONTENUMPROC) enum_font_cb2,
7221 (LPARAM) lpef);
7222}
7223
7224
8edb0a6f 7225static int CALLBACK
5ca0cd71
GV
7226enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7227 ENUMLOGFONTEX * lplf;
7228 NEWTEXTMETRICEX * lptm;
7229 int font_type;
7230 enumfont_t * lpef;
7231{
7232 /* We are not interested in the extra info we get back from the 'Ex
7233 version - only the fact that we get character set variations
7234 enumerated seperately. */
7235 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7236 font_type, lpef);
7237}
7238
8edb0a6f 7239static int CALLBACK
5ca0cd71
GV
7240enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7241 ENUMLOGFONTEX * lplf;
7242 NEWTEXTMETRICEX * lptm;
7243 int font_type;
7244 enumfont_t * lpef;
7245{
7246 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7247 FARPROC enum_font_families_ex
7248 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7249 /* We don't really expect EnumFontFamiliesEx to disappear once we
7250 get here, so don't bother handling it gracefully. */
7251 if (enum_font_families_ex == NULL)
7252 error ("gdi32.dll has disappeared!");
7253 return enum_font_families_ex (lpef->hdc,
7254 &lplf->elfLogFont,
7255 (FONTENUMPROC) enum_fontex_cb2,
7256 (LPARAM) lpef, 0);
7257}
7258
4587b026
GV
7259/* Interface to fontset handler. (adapted from mw32font.c in Meadow
7260 and xterm.c in Emacs 20.3) */
7261
8edb0a6f 7262static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
7263{
7264 char *fontname, *ptnstr;
7265 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 7266 int n_fonts = 0;
33d52f9c
GV
7267
7268 list = Vw32_bdf_filename_alist;
7269 ptnstr = XSTRING (pattern)->data;
7270
8e713be6 7271 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 7272 {
8e713be6 7273 tem = XCAR (list);
33d52f9c 7274 if (CONSP (tem))
8e713be6 7275 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
7276 else if (STRINGP (tem))
7277 fontname = XSTRING (tem)->data;
7278 else
7279 continue;
7280
7281 if (w32_font_match (fontname, ptnstr))
5ca0cd71 7282 {
8e713be6 7283 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7284 n_fonts++;
7285 if (n_fonts >= max_names)
7286 break;
7287 }
33d52f9c
GV
7288 }
7289
7290 return newlist;
7291}
7292
5ca0cd71 7293
4587b026
GV
7294/* Return a list of names of available fonts matching PATTERN on frame
7295 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7296 to be listed. Frame F NULL means we have not yet created any
7297 frame, which means we can't get proper size info, as we don't have
7298 a device context to use for GetTextMetrics.
7299 MAXNAMES sets a limit on how many fonts to match. */
7300
7301Lisp_Object
dc220243
JR
7302w32_list_fonts (f, pattern, size, maxnames)
7303 struct frame *f;
7304 Lisp_Object pattern;
7305 int size;
7306 int maxnames;
4587b026 7307{
6fc2811b 7308 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 7309 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 7310 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 7311 int n_fonts = 0;
396594fe 7312
4587b026
GV
7313 patterns = Fassoc (pattern, Valternate_fontname_alist);
7314 if (NILP (patterns))
7315 patterns = Fcons (pattern, Qnil);
7316
8e713be6 7317 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
7318 {
7319 enumfont_t ef;
767b1ff0 7320 int codepage;
4587b026 7321
8e713be6 7322 tpat = XCAR (patterns);
4587b026 7323
767b1ff0
JR
7324 if (!STRINGP (tpat))
7325 continue;
7326
7327 /* Avoid expensive EnumFontFamilies functions if we are not
7328 going to be able to output one of these anyway. */
7329 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7330 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7331 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7332 && !IsValidCodePage(codepage))
767b1ff0
JR
7333 continue;
7334
4587b026
GV
7335 /* See if we cached the result for this particular query.
7336 The cache is an alist of the form:
7337 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7338 */
8e713be6 7339 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7340 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7341 {
7342 list = Fcdr_safe (list);
7343 /* We have a cached list. Don't have to get the list again. */
7344 goto label_cached;
7345 }
7346
7347 BLOCK_INPUT;
7348 /* At first, put PATTERN in the cache. */
7349 list = Qnil;
33d52f9c 7350 ef.pattern = &tpat;
d84b082d 7351 ef.list = list;
33d52f9c 7352 ef.tail = &list;
4587b026 7353 ef.numFonts = 0;
33d52f9c 7354
5ca0cd71
GV
7355 /* Use EnumFontFamiliesEx where it is available, as it knows
7356 about character sets. Fall back to EnumFontFamilies for
7357 older versions of NT that don't support the 'Ex function. */
767b1ff0 7358 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7359 {
5ca0cd71
GV
7360 LOGFONT font_match_pattern;
7361 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7362 FARPROC enum_font_families_ex
7363 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7364
7365 /* We do our own pattern matching so we can handle wildcards. */
7366 font_match_pattern.lfFaceName[0] = 0;
7367 font_match_pattern.lfPitchAndFamily = 0;
7368 /* We can use the charset, because if it is a wildcard it will
7369 be DEFAULT_CHARSET anyway. */
7370 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7371
33d52f9c 7372 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7373
5ca0cd71
GV
7374 if (enum_font_families_ex)
7375 enum_font_families_ex (ef.hdc,
7376 &font_match_pattern,
7377 (FONTENUMPROC) enum_fontex_cb1,
7378 (LPARAM) &ef, 0);
7379 else
7380 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7381 (LPARAM)&ef);
4587b026 7382
33d52f9c 7383 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7384 }
7385
7386 UNBLOCK_INPUT;
7387
7388 /* Make a list of the fonts we got back.
7389 Store that in the font cache for the display. */
f3fbd155
KR
7390 XSETCDR (dpyinfo->name_list_element,
7391 Fcons (Fcons (tpat, list),
7392 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7393
7394 label_cached:
7395 if (NILP (list)) continue; /* Try the remaining alternatives. */
7396
7397 newlist = second_best = Qnil;
7398
7399 /* Make a list of the fonts that have the right width. */
8e713be6 7400 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7401 {
7402 int found_size;
8e713be6 7403 tem = XCAR (list);
4587b026
GV
7404
7405 if (!CONSP (tem))
7406 continue;
8e713be6 7407 if (NILP (XCAR (tem)))
4587b026
GV
7408 continue;
7409 if (!size)
7410 {
8e713be6 7411 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7412 n_fonts++;
7413 if (n_fonts >= maxnames)
7414 break;
7415 else
7416 continue;
4587b026 7417 }
8e713be6 7418 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7419 {
7420 /* Since we don't yet know the size of the font, we must
7421 load it and try GetTextMetrics. */
4587b026
GV
7422 W32FontStruct thisinfo;
7423 LOGFONT lf;
7424 HDC hdc;
7425 HANDLE oldobj;
7426
8e713be6 7427 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7428 continue;
7429
7430 BLOCK_INPUT;
33d52f9c 7431 thisinfo.bdf = NULL;
4587b026
GV
7432 thisinfo.hfont = CreateFontIndirect (&lf);
7433 if (thisinfo.hfont == NULL)
7434 continue;
7435
7436 hdc = GetDC (dpyinfo->root_window);
7437 oldobj = SelectObject (hdc, thisinfo.hfont);
7438 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7439 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7440 else
f3fbd155 7441 XSETCDR (tem, make_number (0));
4587b026
GV
7442 SelectObject (hdc, oldobj);
7443 ReleaseDC (dpyinfo->root_window, hdc);
7444 DeleteObject(thisinfo.hfont);
7445 UNBLOCK_INPUT;
7446 }
8e713be6 7447 found_size = XINT (XCDR (tem));
4587b026 7448 if (found_size == size)
5ca0cd71 7449 {
8e713be6 7450 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7451 n_fonts++;
7452 if (n_fonts >= maxnames)
7453 break;
7454 }
4587b026
GV
7455 /* keep track of the closest matching size in case
7456 no exact match is found. */
7457 else if (found_size > 0)
7458 {
7459 if (NILP (second_best))
7460 second_best = tem;
5ca0cd71 7461
4587b026
GV
7462 else if (found_size < size)
7463 {
8e713be6
KR
7464 if (XINT (XCDR (second_best)) > size
7465 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7466 second_best = tem;
7467 }
7468 else
7469 {
8e713be6
KR
7470 if (XINT (XCDR (second_best)) > size
7471 && XINT (XCDR (second_best)) >
4587b026
GV
7472 found_size)
7473 second_best = tem;
7474 }
7475 }
7476 }
7477
7478 if (!NILP (newlist))
7479 break;
7480 else if (!NILP (second_best))
7481 {
8e713be6 7482 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7483 break;
7484 }
7485 }
7486
33d52f9c 7487 /* Include any bdf fonts. */
5ca0cd71 7488 if (n_fonts < maxnames)
33d52f9c
GV
7489 {
7490 Lisp_Object combined[2];
5ca0cd71 7491 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7492 combined[1] = newlist;
7493 newlist = Fnconc(2, combined);
7494 }
7495
4587b026
GV
7496 return newlist;
7497}
7498
5ca0cd71 7499
4587b026
GV
7500/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7501struct font_info *
7502w32_get_font_info (f, font_idx)
7503 FRAME_PTR f;
7504 int font_idx;
7505{
7506 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7507}
7508
7509
7510struct font_info*
7511w32_query_font (struct frame *f, char *fontname)
7512{
7513 int i;
7514 struct font_info *pfi;
7515
7516 pfi = FRAME_W32_FONT_TABLE (f);
7517
7518 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7519 {
7520 if (strcmp(pfi->name, fontname) == 0) return pfi;
7521 }
7522
7523 return NULL;
7524}
7525
7526/* Find a CCL program for a font specified by FONTP, and set the member
7527 `encoder' of the structure. */
7528
7529void
7530w32_find_ccl_program (fontp)
7531 struct font_info *fontp;
7532{
3545439c 7533 Lisp_Object list, elt;
4587b026 7534
8e713be6 7535 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7536 {
8e713be6 7537 elt = XCAR (list);
4587b026 7538 if (CONSP (elt)
8e713be6
KR
7539 && STRINGP (XCAR (elt))
7540 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7541 >= 0))
3545439c
KH
7542 break;
7543 }
7544 if (! NILP (list))
7545 {
17eedd00
KH
7546 struct ccl_program *ccl
7547 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7548
8e713be6 7549 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7550 xfree (ccl);
7551 else
7552 fontp->font_encoder = ccl;
4587b026
GV
7553 }
7554}
7555
7556\f
8edb0a6f
JR
7557/* Find BDF files in a specified directory. (use GCPRO when calling,
7558 as this calls lisp to get a directory listing). */
7559static Lisp_Object
7560w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7561{
7562 Lisp_Object filelist, list = Qnil;
7563 char fontname[100];
7564
7565 if (!STRINGP(directory))
7566 return Qnil;
7567
7568 filelist = Fdirectory_files (directory, Qt,
7569 build_string (".*\\.[bB][dD][fF]"), Qt);
7570
7571 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7572 {
7573 Lisp_Object filename = XCAR (filelist);
7574 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7575 store_in_alist (&list, build_string (fontname), filename);
7576 }
7577 return list;
7578}
7579
6fc2811b
JR
7580DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7581 1, 1, 0,
b3700ae7
JR
7582 doc: /* Return a list of BDF fonts in DIR.
7583The list is suitable for appending to w32-bdf-filename-alist. Fonts
7584which do not contain an xlfd description will not be included in the
7585list. DIR may be a list of directories. */)
6fc2811b
JR
7586 (directory)
7587 Lisp_Object directory;
7588{
7589 Lisp_Object list = Qnil;
7590 struct gcpro gcpro1, gcpro2;
ee78dc32 7591
6fc2811b
JR
7592 if (!CONSP (directory))
7593 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7594
6fc2811b 7595 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7596 {
6fc2811b
JR
7597 Lisp_Object pair[2];
7598 pair[0] = list;
7599 pair[1] = Qnil;
7600 GCPRO2 (directory, list);
7601 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7602 list = Fnconc( 2, pair );
7603 UNGCPRO;
7604 }
7605 return list;
7606}
ee78dc32 7607
6fc2811b
JR
7608\f
7609DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7610 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7611 (color, frame)
7612 Lisp_Object color, frame;
7613{
7614 XColor foo;
7615 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7616
b7826503 7617 CHECK_STRING (color);
ee78dc32 7618
6fc2811b
JR
7619 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7620 return Qt;
7621 else
7622 return Qnil;
7623}
ee78dc32 7624
2d764c78 7625DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7626 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7627 (color, frame)
7628 Lisp_Object color, frame;
7629{
6fc2811b 7630 XColor foo;
ee78dc32
GV
7631 FRAME_PTR f = check_x_frame (frame);
7632
b7826503 7633 CHECK_STRING (color);
ee78dc32 7634
6fc2811b 7635 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7636 {
7637 Lisp_Object rgb[3];
7638
6fc2811b
JR
7639 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7640 | GetRValue (foo.pixel));
7641 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7642 | GetGValue (foo.pixel));
7643 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7644 | GetBValue (foo.pixel));
ee78dc32
GV
7645 return Flist (3, rgb);
7646 }
7647 else
7648 return Qnil;
7649}
7650
2d764c78 7651DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7652 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7653 (display)
7654 Lisp_Object display;
7655{
fbd6baed 7656 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7657
7658 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7659 return Qnil;
7660
7661 return Qt;
7662}
7663
74e1aeec
JR
7664DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7665 Sx_display_grayscale_p, 0, 1, 0,
7666 doc: /* Return t if the X display supports shades of gray.
7667Note that color displays do support shades of gray.
7668The optional argument DISPLAY specifies which display to ask about.
7669DISPLAY should be either a frame or a display name (a string).
7670If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7671 (display)
7672 Lisp_Object display;
7673{
fbd6baed 7674 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7675
7676 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7677 return Qnil;
7678
7679 return Qt;
7680}
7681
74e1aeec
JR
7682DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7683 Sx_display_pixel_width, 0, 1, 0,
7684 doc: /* Returns the width in pixels of DISPLAY.
7685The optional argument DISPLAY specifies which display to ask about.
7686DISPLAY should be either a frame or a display name (a string).
7687If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7688 (display)
7689 Lisp_Object display;
7690{
fbd6baed 7691 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7692
7693 return make_number (dpyinfo->width);
7694}
7695
7696DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7697 Sx_display_pixel_height, 0, 1, 0,
7698 doc: /* Returns the height in pixels of DISPLAY.
7699The optional argument DISPLAY specifies which display to ask about.
7700DISPLAY should be either a frame or a display name (a string).
7701If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7702 (display)
7703 Lisp_Object display;
7704{
fbd6baed 7705 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7706
7707 return make_number (dpyinfo->height);
7708}
7709
7710DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7711 0, 1, 0,
7712 doc: /* Returns the number of bitplanes of DISPLAY.
7713The optional argument DISPLAY specifies which display to ask about.
7714DISPLAY should be either a frame or a display name (a string).
7715If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7716 (display)
7717 Lisp_Object display;
7718{
fbd6baed 7719 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7720
7721 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7722}
7723
7724DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7725 0, 1, 0,
7726 doc: /* Returns the number of color cells of DISPLAY.
7727The optional argument DISPLAY specifies which display to ask about.
7728DISPLAY should be either a frame or a display name (a string).
7729If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7730 (display)
7731 Lisp_Object display;
7732{
fbd6baed 7733 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7734 HDC hdc;
7735 int cap;
7736
5ac45f98
GV
7737 hdc = GetDC (dpyinfo->root_window);
7738 if (dpyinfo->has_palette)
7739 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7740 else
7741 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b
AI
7742
7743 if (cap < 0)
7744 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
ee78dc32
GV
7745
7746 ReleaseDC (dpyinfo->root_window, hdc);
7747
7748 return make_number (cap);
7749}
7750
7751DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7752 Sx_server_max_request_size,
74e1aeec
JR
7753 0, 1, 0,
7754 doc: /* Returns the maximum request size of the server of DISPLAY.
7755The optional argument DISPLAY specifies which display to ask about.
7756DISPLAY should be either a frame or a display name (a string).
7757If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7758 (display)
7759 Lisp_Object display;
7760{
fbd6baed 7761 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7762
7763 return make_number (1);
7764}
7765
7766DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7767 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7768The optional argument DISPLAY specifies which display to ask about.
7769DISPLAY should be either a frame or a display name (a string).
7770If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7771 (display)
7772 Lisp_Object display;
7773{
dfff8a69 7774 return build_string ("Microsoft Corp.");
ee78dc32
GV
7775}
7776
7777DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7778 doc: /* Returns the version numbers of the server of DISPLAY.
7779The value is a list of three integers: the major and minor
7780version numbers, and the vendor-specific release
7781number. See also the function `x-server-vendor'.
7782
7783The optional argument DISPLAY specifies which display to ask about.
7784DISPLAY should be either a frame or a display name (a string).
7785If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7786 (display)
7787 Lisp_Object display;
7788{
fbd6baed 7789 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7790 Fcons (make_number (w32_minor_version),
7791 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7792}
7793
7794DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7795 doc: /* Returns the number of screens on the server of DISPLAY.
7796The optional argument DISPLAY specifies which display to ask about.
7797DISPLAY should be either a frame or a display name (a string).
7798If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7799 (display)
7800 Lisp_Object display;
7801{
ee78dc32
GV
7802 return make_number (1);
7803}
7804
74e1aeec
JR
7805DEFUN ("x-display-mm-height", Fx_display_mm_height,
7806 Sx_display_mm_height, 0, 1, 0,
7807 doc: /* Returns the height in millimeters of DISPLAY.
7808The optional argument DISPLAY specifies which display to ask about.
7809DISPLAY should be either a frame or a display name (a string).
7810If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7811 (display)
7812 Lisp_Object display;
7813{
fbd6baed 7814 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7815 HDC hdc;
7816 int cap;
7817
5ac45f98 7818 hdc = GetDC (dpyinfo->root_window);
3c190163 7819
ee78dc32 7820 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7821
ee78dc32
GV
7822 ReleaseDC (dpyinfo->root_window, hdc);
7823
7824 return make_number (cap);
7825}
7826
7827DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7828 doc: /* Returns the width in millimeters of DISPLAY.
7829The optional argument DISPLAY specifies which display to ask about.
7830DISPLAY should be either a frame or a display name (a string).
7831If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7832 (display)
7833 Lisp_Object display;
7834{
fbd6baed 7835 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7836
7837 HDC hdc;
7838 int cap;
7839
5ac45f98 7840 hdc = GetDC (dpyinfo->root_window);
3c190163 7841
ee78dc32 7842 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7843
ee78dc32
GV
7844 ReleaseDC (dpyinfo->root_window, hdc);
7845
7846 return make_number (cap);
7847}
7848
7849DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7850 Sx_display_backing_store, 0, 1, 0,
7851 doc: /* Returns an indication of whether DISPLAY does backing store.
7852The value may be `always', `when-mapped', or `not-useful'.
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{
7859 return intern ("not-useful");
7860}
7861
7862DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7863 Sx_display_visual_class, 0, 1, 0,
7864 doc: /* Returns the visual class of DISPLAY.
7865The value is one of the symbols `static-gray', `gray-scale',
7866`static-color', `pseudo-color', `true-color', or `direct-color'.
7867
7868The optional argument DISPLAY specifies which display to ask about.
7869DISPLAY should be either a frame or a display name (a string).
7870If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7871 (display)
7872 Lisp_Object display;
7873{
fbd6baed 7874 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7875 Lisp_Object result = Qnil;
ee78dc32 7876
abf8c61b
AI
7877 if (dpyinfo->has_palette)
7878 result = intern ("pseudo-color");
7879 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7880 result = intern ("static-grey");
7881 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7882 result = intern ("static-color");
7883 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7884 result = intern ("true-color");
ee78dc32 7885
abf8c61b 7886 return result;
ee78dc32
GV
7887}
7888
7889DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7890 Sx_display_save_under, 0, 1, 0,
7891 doc: /* Returns t if DISPLAY supports the save-under feature.
7892The optional argument DISPLAY specifies which display to ask about.
7893DISPLAY should be either a frame or a display name (a string).
7894If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7895 (display)
7896 Lisp_Object display;
7897{
6fc2811b
JR
7898 return Qnil;
7899}
7900\f
7901int
7902x_pixel_width (f)
7903 register struct frame *f;
7904{
7905 return PIXEL_WIDTH (f);
7906}
7907
7908int
7909x_pixel_height (f)
7910 register struct frame *f;
7911{
7912 return PIXEL_HEIGHT (f);
7913}
7914
7915int
7916x_char_width (f)
7917 register struct frame *f;
7918{
7919 return FONT_WIDTH (f->output_data.w32->font);
7920}
7921
7922int
7923x_char_height (f)
7924 register struct frame *f;
7925{
7926 return f->output_data.w32->line_height;
7927}
7928
7929int
7930x_screen_planes (f)
7931 register struct frame *f;
7932{
7933 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7934}
7935\f
7936/* Return the display structure for the display named NAME.
7937 Open a new connection if necessary. */
7938
7939struct w32_display_info *
7940x_display_info_for_name (name)
7941 Lisp_Object name;
7942{
7943 Lisp_Object names;
7944 struct w32_display_info *dpyinfo;
7945
b7826503 7946 CHECK_STRING (name);
6fc2811b
JR
7947
7948 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7949 dpyinfo;
7950 dpyinfo = dpyinfo->next, names = XCDR (names))
7951 {
7952 Lisp_Object tem;
7953 tem = Fstring_equal (XCAR (XCAR (names)), name);
7954 if (!NILP (tem))
7955 return dpyinfo;
7956 }
7957
7958 /* Use this general default value to start with. */
7959 Vx_resource_name = Vinvocation_name;
7960
7961 validate_x_resource_name ();
7962
7963 dpyinfo = w32_term_init (name, (unsigned char *)0,
7964 (char *) XSTRING (Vx_resource_name)->data);
7965
7966 if (dpyinfo == 0)
7967 error ("Cannot connect to server %s", XSTRING (name)->data);
7968
7969 w32_in_use = 1;
7970 XSETFASTINT (Vwindow_system_version, 3);
7971
7972 return dpyinfo;
7973}
7974
7975DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
7976 1, 3, 0, doc: /* Open a connection to a server.
7977DISPLAY is the name of the display to connect to.
7978Optional second arg XRM-STRING is a string of resources in xrdb format.
7979If the optional third arg MUST-SUCCEED is non-nil,
7980terminate Emacs if we can't open the connection. */)
6fc2811b
JR
7981 (display, xrm_string, must_succeed)
7982 Lisp_Object display, xrm_string, must_succeed;
7983{
7984 unsigned char *xrm_option;
7985 struct w32_display_info *dpyinfo;
7986
74e1aeec
JR
7987 /* If initialization has already been done, return now to avoid
7988 overwriting critical parts of one_w32_display_info. */
7989 if (w32_in_use)
7990 return Qnil;
7991
b7826503 7992 CHECK_STRING (display);
6fc2811b 7993 if (! NILP (xrm_string))
b7826503 7994 CHECK_STRING (xrm_string);
6fc2811b
JR
7995
7996 if (! EQ (Vwindow_system, intern ("w32")))
7997 error ("Not using Microsoft Windows");
7998
7999 /* Allow color mapping to be defined externally; first look in user's
8000 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8001 {
8002 Lisp_Object color_file;
8003 struct gcpro gcpro1;
8004
8005 color_file = build_string("~/rgb.txt");
8006
8007 GCPRO1 (color_file);
8008
8009 if (NILP (Ffile_readable_p (color_file)))
8010 color_file =
8011 Fexpand_file_name (build_string ("rgb.txt"),
8012 Fsymbol_value (intern ("data-directory")));
8013
8014 Vw32_color_map = Fw32_load_color_file (color_file);
8015
8016 UNGCPRO;
8017 }
8018 if (NILP (Vw32_color_map))
8019 Vw32_color_map = Fw32_default_color_map ();
8020
8021 if (! NILP (xrm_string))
8022 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8023 else
8024 xrm_option = (unsigned char *) 0;
8025
8026 /* Use this general default value to start with. */
8027 /* First remove .exe suffix from invocation-name - it looks ugly. */
8028 {
8029 char basename[ MAX_PATH ], *str;
8030
8031 strcpy (basename, XSTRING (Vinvocation_name)->data);
8032 str = strrchr (basename, '.');
8033 if (str) *str = 0;
8034 Vinvocation_name = build_string (basename);
8035 }
8036 Vx_resource_name = Vinvocation_name;
8037
8038 validate_x_resource_name ();
8039
8040 /* This is what opens the connection and sets x_current_display.
8041 This also initializes many symbols, such as those used for input. */
8042 dpyinfo = w32_term_init (display, xrm_option,
8043 (char *) XSTRING (Vx_resource_name)->data);
8044
8045 if (dpyinfo == 0)
8046 {
8047 if (!NILP (must_succeed))
8048 fatal ("Cannot connect to server %s.\n",
8049 XSTRING (display)->data);
8050 else
8051 error ("Cannot connect to server %s", XSTRING (display)->data);
8052 }
8053
8054 w32_in_use = 1;
8055
8056 XSETFASTINT (Vwindow_system_version, 3);
8057 return Qnil;
8058}
8059
8060DEFUN ("x-close-connection", Fx_close_connection,
8061 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
8062 doc: /* Close the connection to DISPLAY's server.
8063For DISPLAY, specify either a frame or a display name (a string).
8064If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
8065 (display)
8066 Lisp_Object display;
8067{
8068 struct w32_display_info *dpyinfo = check_x_display_info (display);
8069 int i;
8070
8071 if (dpyinfo->reference_count > 0)
8072 error ("Display still has frames on it");
8073
8074 BLOCK_INPUT;
8075 /* Free the fonts in the font table. */
8076 for (i = 0; i < dpyinfo->n_fonts; i++)
8077 if (dpyinfo->font_table[i].name)
8078 {
126f2e35
JR
8079 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8080 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 8081 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
8082 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8083 }
8084 x_destroy_all_bitmaps (dpyinfo);
8085
8086 x_delete_display (dpyinfo);
8087 UNBLOCK_INPUT;
8088
8089 return Qnil;
8090}
8091
8092DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 8093 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
8094 ()
8095{
8096 Lisp_Object tail, result;
8097
8098 result = Qnil;
8099 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8100 result = Fcons (XCAR (XCAR (tail)), result);
8101
8102 return result;
8103}
8104
8105DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
8106 doc: /* This is a noop on W32 systems. */)
8107 (on, display)
8108 Lisp_Object display, on;
6fc2811b 8109{
6fc2811b
JR
8110 return Qnil;
8111}
8112
8113\f
8114\f
8115/***********************************************************************
8116 Image types
8117 ***********************************************************************/
8118
8119/* Value is the number of elements of vector VECTOR. */
8120
8121#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8122
8123/* List of supported image types. Use define_image_type to add new
8124 types. Use lookup_image_type to find a type for a given symbol. */
8125
8126static struct image_type *image_types;
8127
6fc2811b
JR
8128/* The symbol `image' which is the car of the lists used to represent
8129 images in Lisp. */
8130
8131extern Lisp_Object Qimage;
8132
8133/* The symbol `xbm' which is used as the type symbol for XBM images. */
8134
8135Lisp_Object Qxbm;
8136
8137/* Keywords. */
8138
6fc2811b 8139extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
8140extern Lisp_Object QCdata;
8141Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
a93f4566 8142Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 8143Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
8144
8145/* Other symbols. */
8146
3cf3436e 8147Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
8148
8149/* Time in seconds after which images should be removed from the cache
8150 if not displayed. */
8151
8152Lisp_Object Vimage_cache_eviction_delay;
8153
8154/* Function prototypes. */
8155
8156static void define_image_type P_ ((struct image_type *type));
8157static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8158static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8159static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 8160static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
8161static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8162 Lisp_Object));
8163
dfff8a69 8164
6fc2811b
JR
8165/* Define a new image type from TYPE. This adds a copy of TYPE to
8166 image_types and adds the symbol *TYPE->type to Vimage_types. */
8167
8168static void
8169define_image_type (type)
8170 struct image_type *type;
8171{
8172 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8173 The initialized data segment is read-only. */
8174 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8175 bcopy (type, p, sizeof *p);
8176 p->next = image_types;
8177 image_types = p;
8178 Vimage_types = Fcons (*p->type, Vimage_types);
8179}
8180
8181
8182/* Look up image type SYMBOL, and return a pointer to its image_type
8183 structure. Value is null if SYMBOL is not a known image type. */
8184
8185static INLINE struct image_type *
8186lookup_image_type (symbol)
8187 Lisp_Object symbol;
8188{
8189 struct image_type *type;
8190
8191 for (type = image_types; type; type = type->next)
8192 if (EQ (symbol, *type->type))
8193 break;
8194
8195 return type;
8196}
8197
8198
8199/* Value is non-zero if OBJECT is a valid Lisp image specification. A
8200 valid image specification is a list whose car is the symbol
8201 `image', and whose rest is a property list. The property list must
8202 contain a value for key `:type'. That value must be the name of a
8203 supported image type. The rest of the property list depends on the
8204 image type. */
8205
8206int
8207valid_image_p (object)
8208 Lisp_Object object;
8209{
8210 int valid_p = 0;
8211
8212 if (CONSP (object) && EQ (XCAR (object), Qimage))
8213 {
3cf3436e
JR
8214 Lisp_Object tem;
8215
8216 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8217 if (EQ (XCAR (tem), QCtype))
8218 {
8219 tem = XCDR (tem);
8220 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8221 {
8222 struct image_type *type;
8223 type = lookup_image_type (XCAR (tem));
8224 if (type)
8225 valid_p = type->valid_p (object);
8226 }
8227
8228 break;
8229 }
6fc2811b
JR
8230 }
8231
8232 return valid_p;
8233}
8234
8235
8236/* Log error message with format string FORMAT and argument ARG.
8237 Signaling an error, e.g. when an image cannot be loaded, is not a
8238 good idea because this would interrupt redisplay, and the error
8239 message display would lead to another redisplay. This function
8240 therefore simply displays a message. */
8241
8242static void
8243image_error (format, arg1, arg2)
8244 char *format;
8245 Lisp_Object arg1, arg2;
8246{
8247 add_to_log (format, arg1, arg2);
8248}
8249
8250
8251\f
8252/***********************************************************************
8253 Image specifications
8254 ***********************************************************************/
8255
8256enum image_value_type
8257{
8258 IMAGE_DONT_CHECK_VALUE_TYPE,
8259 IMAGE_STRING_VALUE,
3cf3436e 8260 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
8261 IMAGE_SYMBOL_VALUE,
8262 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8263 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8264 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8265 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8266 IMAGE_INTEGER_VALUE,
8267 IMAGE_FUNCTION_VALUE,
8268 IMAGE_NUMBER_VALUE,
8269 IMAGE_BOOL_VALUE
8270};
8271
8272/* Structure used when parsing image specifications. */
8273
8274struct image_keyword
8275{
8276 /* Name of keyword. */
8277 char *name;
8278
8279 /* The type of value allowed. */
8280 enum image_value_type type;
8281
8282 /* Non-zero means key must be present. */
8283 int mandatory_p;
8284
8285 /* Used to recognize duplicate keywords in a property list. */
8286 int count;
8287
8288 /* The value that was found. */
8289 Lisp_Object value;
8290};
8291
8292
8293static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8294 int, Lisp_Object));
8295static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8296
8297
8298/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8299 has the format (image KEYWORD VALUE ...). One of the keyword/
8300 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8301 image_keywords structures of size NKEYWORDS describing other
8302 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8303
8304static int
8305parse_image_spec (spec, keywords, nkeywords, type)
8306 Lisp_Object spec;
8307 struct image_keyword *keywords;
8308 int nkeywords;
8309 Lisp_Object type;
8310{
8311 int i;
8312 Lisp_Object plist;
8313
8314 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8315 return 0;
8316
8317 plist = XCDR (spec);
8318 while (CONSP (plist))
8319 {
8320 Lisp_Object key, value;
8321
8322 /* First element of a pair must be a symbol. */
8323 key = XCAR (plist);
8324 plist = XCDR (plist);
8325 if (!SYMBOLP (key))
8326 return 0;
8327
8328 /* There must follow a value. */
8329 if (!CONSP (plist))
8330 return 0;
8331 value = XCAR (plist);
8332 plist = XCDR (plist);
8333
8334 /* Find key in KEYWORDS. Error if not found. */
8335 for (i = 0; i < nkeywords; ++i)
8336 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8337 break;
8338
8339 if (i == nkeywords)
8340 continue;
8341
8342 /* Record that we recognized the keyword. If a keywords
8343 was found more than once, it's an error. */
8344 keywords[i].value = value;
8345 ++keywords[i].count;
8346
8347 if (keywords[i].count > 1)
8348 return 0;
8349
8350 /* Check type of value against allowed type. */
8351 switch (keywords[i].type)
8352 {
8353 case IMAGE_STRING_VALUE:
8354 if (!STRINGP (value))
8355 return 0;
8356 break;
8357
3cf3436e
JR
8358 case IMAGE_STRING_OR_NIL_VALUE:
8359 if (!STRINGP (value) && !NILP (value))
8360 return 0;
8361 break;
8362
6fc2811b
JR
8363 case IMAGE_SYMBOL_VALUE:
8364 if (!SYMBOLP (value))
8365 return 0;
8366 break;
8367
8368 case IMAGE_POSITIVE_INTEGER_VALUE:
8369 if (!INTEGERP (value) || XINT (value) <= 0)
8370 return 0;
8371 break;
8372
8edb0a6f
JR
8373 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8374 if (INTEGERP (value) && XINT (value) >= 0)
8375 break;
8376 if (CONSP (value)
8377 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8378 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8379 break;
8380 return 0;
8381
dfff8a69
JR
8382 case IMAGE_ASCENT_VALUE:
8383 if (SYMBOLP (value) && EQ (value, Qcenter))
8384 break;
8385 else if (INTEGERP (value)
8386 && XINT (value) >= 0
8387 && XINT (value) <= 100)
8388 break;
8389 return 0;
8390
6fc2811b
JR
8391 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8392 if (!INTEGERP (value) || XINT (value) < 0)
8393 return 0;
8394 break;
8395
8396 case IMAGE_DONT_CHECK_VALUE_TYPE:
8397 break;
8398
8399 case IMAGE_FUNCTION_VALUE:
8400 value = indirect_function (value);
8401 if (SUBRP (value)
8402 || COMPILEDP (value)
8403 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8404 break;
8405 return 0;
8406
8407 case IMAGE_NUMBER_VALUE:
8408 if (!INTEGERP (value) && !FLOATP (value))
8409 return 0;
8410 break;
8411
8412 case IMAGE_INTEGER_VALUE:
8413 if (!INTEGERP (value))
8414 return 0;
8415 break;
8416
8417 case IMAGE_BOOL_VALUE:
8418 if (!NILP (value) && !EQ (value, Qt))
8419 return 0;
8420 break;
8421
8422 default:
8423 abort ();
8424 break;
8425 }
8426
8427 if (EQ (key, QCtype) && !EQ (type, value))
8428 return 0;
8429 }
8430
8431 /* Check that all mandatory fields are present. */
8432 for (i = 0; i < nkeywords; ++i)
8433 if (keywords[i].mandatory_p && keywords[i].count == 0)
8434 return 0;
8435
8436 return NILP (plist);
8437}
8438
8439
8440/* Return the value of KEY in image specification SPEC. Value is nil
8441 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8442 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8443
8444static Lisp_Object
8445image_spec_value (spec, key, found)
8446 Lisp_Object spec, key;
8447 int *found;
8448{
8449 Lisp_Object tail;
8450
8451 xassert (valid_image_p (spec));
8452
8453 for (tail = XCDR (spec);
8454 CONSP (tail) && CONSP (XCDR (tail));
8455 tail = XCDR (XCDR (tail)))
8456 {
8457 if (EQ (XCAR (tail), key))
8458 {
8459 if (found)
8460 *found = 1;
8461 return XCAR (XCDR (tail));
8462 }
8463 }
8464
8465 if (found)
8466 *found = 0;
8467 return Qnil;
8468}
8469
8470
8471
8472\f
8473/***********************************************************************
8474 Image type independent image structures
8475 ***********************************************************************/
8476
8477static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8478static void free_image P_ ((struct frame *f, struct image *img));
8479
8480
8481/* Allocate and return a new image structure for image specification
8482 SPEC. SPEC has a hash value of HASH. */
8483
8484static struct image *
8485make_image (spec, hash)
8486 Lisp_Object spec;
8487 unsigned hash;
8488{
8489 struct image *img = (struct image *) xmalloc (sizeof *img);
8490
8491 xassert (valid_image_p (spec));
8492 bzero (img, sizeof *img);
8493 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8494 xassert (img->type != NULL);
8495 img->spec = spec;
8496 img->data.lisp_val = Qnil;
8497 img->ascent = DEFAULT_IMAGE_ASCENT;
8498 img->hash = hash;
8499 return img;
8500}
8501
8502
8503/* Free image IMG which was used on frame F, including its resources. */
8504
8505static void
8506free_image (f, img)
8507 struct frame *f;
8508 struct image *img;
8509{
8510 if (img)
8511 {
8512 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8513
8514 /* Remove IMG from the hash table of its cache. */
8515 if (img->prev)
8516 img->prev->next = img->next;
8517 else
8518 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8519
8520 if (img->next)
8521 img->next->prev = img->prev;
8522
8523 c->images[img->id] = NULL;
8524
8525 /* Free resources, then free IMG. */
8526 img->type->free (f, img);
8527 xfree (img);
8528 }
8529}
8530
8531
8532/* Prepare image IMG for display on frame F. Must be called before
8533 drawing an image. */
8534
8535void
8536prepare_image_for_display (f, img)
8537 struct frame *f;
8538 struct image *img;
8539{
8540 EMACS_TIME t;
8541
8542 /* We're about to display IMG, so set its timestamp to `now'. */
8543 EMACS_GET_TIME (t);
8544 img->timestamp = EMACS_SECS (t);
8545
8546 /* If IMG doesn't have a pixmap yet, load it now, using the image
8547 type dependent loader function. */
8548 if (img->pixmap == 0 && !img->load_failed_p)
8549 img->load_failed_p = img->type->load (f, img) == 0;
8550}
8551
8552
dfff8a69
JR
8553/* Value is the number of pixels for the ascent of image IMG when
8554 drawn in face FACE. */
8555
8556int
8557image_ascent (img, face)
8558 struct image *img;
8559 struct face *face;
8560{
8edb0a6f 8561 int height = img->height + img->vmargin;
dfff8a69
JR
8562 int ascent;
8563
8564 if (img->ascent == CENTERED_IMAGE_ASCENT)
8565 {
8566 if (face->font)
8567 ascent = height / 2 - (FONT_DESCENT(face->font)
8568 - FONT_BASE(face->font)) / 2;
8569 else
8570 ascent = height / 2;
8571 }
8572 else
8573 ascent = height * img->ascent / 100.0;
8574
8575 return ascent;
8576}
8577
8578
6fc2811b 8579\f
a05e2bae
JR
8580/* Image background colors. */
8581
8582static unsigned long
8583four_corners_best (ximg, width, height)
8584 XImage *ximg;
8585 unsigned long width, height;
8586{
8587#if 0 /* TODO: Image support. */
8588 unsigned long corners[4], best;
8589 int i, best_count;
8590
8591 /* Get the colors at the corners of ximg. */
8592 corners[0] = XGetPixel (ximg, 0, 0);
8593 corners[1] = XGetPixel (ximg, width - 1, 0);
8594 corners[2] = XGetPixel (ximg, width - 1, height - 1);
8595 corners[3] = XGetPixel (ximg, 0, height - 1);
8596
8597 /* Choose the most frequently found color as background. */
8598 for (i = best_count = 0; i < 4; ++i)
8599 {
8600 int j, n;
8601
8602 for (j = n = 0; j < 4; ++j)
8603 if (corners[i] == corners[j])
8604 ++n;
8605
8606 if (n > best_count)
8607 best = corners[i], best_count = n;
8608 }
8609
8610 return best;
8611#else
8612 return 0;
8613#endif
8614}
8615
8616/* Return the `background' field of IMG. If IMG doesn't have one yet,
8617 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8618 object to use for the heuristic. */
8619
8620unsigned long
8621image_background (img, f, ximg)
8622 struct image *img;
8623 struct frame *f;
8624 XImage *ximg;
8625{
8626 if (! img->background_valid)
8627 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8628 {
8629#if 0 /* TODO: Image support. */
8630 int free_ximg = !ximg;
8631
8632 if (! ximg)
8633 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8634 0, 0, img->width, img->height, ~0, ZPixmap);
8635
8636 img->background = four_corners_best (ximg, img->width, img->height);
8637
8638 if (free_ximg)
8639 XDestroyImage (ximg);
8640
8641 img->background_valid = 1;
8642#endif
8643 }
8644
8645 return img->background;
8646}
8647
8648/* Return the `background_transparent' field of IMG. If IMG doesn't
8649 have one yet, it is guessed heuristically. If non-zero, MASK is an
8650 existing XImage object to use for the heuristic. */
8651
8652int
8653image_background_transparent (img, f, mask)
8654 struct image *img;
8655 struct frame *f;
8656 XImage *mask;
8657{
8658 if (! img->background_transparent_valid)
8659 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8660 {
8661#if 0 /* TODO: Image support. */
8662 if (img->mask)
8663 {
8664 int free_mask = !mask;
8665
8666 if (! mask)
8667 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8668 0, 0, img->width, img->height, ~0, ZPixmap);
8669
8670 img->background_transparent
8671 = !four_corners_best (mask, img->width, img->height);
8672
8673 if (free_mask)
8674 XDestroyImage (mask);
8675 }
8676 else
8677#endif
8678 img->background_transparent = 0;
8679
8680 img->background_transparent_valid = 1;
8681 }
8682
8683 return img->background_transparent;
8684}
8685
8686\f
6fc2811b
JR
8687/***********************************************************************
8688 Helper functions for X image types
8689 ***********************************************************************/
8690
a05e2bae
JR
8691static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8692 int, int));
6fc2811b
JR
8693static void x_clear_image P_ ((struct frame *f, struct image *img));
8694static unsigned long x_alloc_image_color P_ ((struct frame *f,
8695 struct image *img,
8696 Lisp_Object color_name,
8697 unsigned long dflt));
8698
a05e2bae
JR
8699
8700/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8701 free the pixmap if any. MASK_P non-zero means clear the mask
8702 pixmap if any. COLORS_P non-zero means free colors allocated for
8703 the image, if any. */
8704
8705static void
8706x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8707 struct frame *f;
8708 struct image *img;
8709 int pixmap_p, mask_p, colors_p;
8710{
9eb16b62 8711#if 0 /* TODO: W32 image support */
a05e2bae
JR
8712 if (pixmap_p && img->pixmap)
8713 {
8714 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8715 img->pixmap = None;
8716 img->background_valid = 0;
8717 }
8718
8719 if (mask_p && img->mask)
8720 {
8721 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8722 img->mask = None;
8723 img->background_transparent_valid = 0;
8724 }
8725
8726 if (colors_p && img->ncolors)
8727 {
8728 x_free_colors (f, img->colors, img->ncolors);
8729 xfree (img->colors);
8730 img->colors = NULL;
8731 img->ncolors = 0;
8732 }
8733#endif
8734}
8735
6fc2811b
JR
8736/* Free X resources of image IMG which is used on frame F. */
8737
8738static void
8739x_clear_image (f, img)
8740 struct frame *f;
8741 struct image *img;
8742{
767b1ff0 8743#if 0 /* TODO: W32 image support */
6fc2811b
JR
8744
8745 if (img->pixmap)
8746 {
8747 BLOCK_INPUT;
8748 XFreePixmap (NULL, img->pixmap);
8749 img->pixmap = 0;
8750 UNBLOCK_INPUT;
8751 }
8752
8753 if (img->ncolors)
8754 {
8755 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8756
8757 /* If display has an immutable color map, freeing colors is not
8758 necessary and some servers don't allow it. So don't do it. */
8759 if (class != StaticColor
8760 && class != StaticGray
8761 && class != TrueColor)
8762 {
8763 Colormap cmap;
8764 BLOCK_INPUT;
8765 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8766 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8767 img->ncolors, 0);
8768 UNBLOCK_INPUT;
8769 }
8770
8771 xfree (img->colors);
8772 img->colors = NULL;
8773 img->ncolors = 0;
8774 }
8775#endif
8776}
8777
8778
8779/* Allocate color COLOR_NAME for image IMG on frame F. If color
8780 cannot be allocated, use DFLT. Add a newly allocated color to
8781 IMG->colors, so that it can be freed again. Value is the pixel
8782 color. */
8783
8784static unsigned long
8785x_alloc_image_color (f, img, color_name, dflt)
8786 struct frame *f;
8787 struct image *img;
8788 Lisp_Object color_name;
8789 unsigned long dflt;
8790{
767b1ff0 8791#if 0 /* TODO: allocing colors. */
6fc2811b
JR
8792 XColor color;
8793 unsigned long result;
8794
8795 xassert (STRINGP (color_name));
8796
8797 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8798 {
8799 /* This isn't called frequently so we get away with simply
8800 reallocating the color vector to the needed size, here. */
8801 ++img->ncolors;
8802 img->colors =
8803 (unsigned long *) xrealloc (img->colors,
8804 img->ncolors * sizeof *img->colors);
8805 img->colors[img->ncolors - 1] = color.pixel;
8806 result = color.pixel;
8807 }
8808 else
8809 result = dflt;
8810 return result;
8811#endif
8812 return 0;
8813}
8814
8815
8816\f
8817/***********************************************************************
8818 Image Cache
8819 ***********************************************************************/
8820
8821static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8822static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8823
8824
8825/* Return a new, initialized image cache that is allocated from the
8826 heap. Call free_image_cache to free an image cache. */
8827
8828struct image_cache *
8829make_image_cache ()
8830{
8831 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8832 int size;
8833
8834 bzero (c, sizeof *c);
8835 c->size = 50;
8836 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8837 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8838 c->buckets = (struct image **) xmalloc (size);
8839 bzero (c->buckets, size);
8840 return c;
8841}
8842
8843
8844/* Free image cache of frame F. Be aware that X frames share images
8845 caches. */
8846
8847void
8848free_image_cache (f)
8849 struct frame *f;
8850{
8851 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8852 if (c)
8853 {
8854 int i;
8855
8856 /* Cache should not be referenced by any frame when freed. */
8857 xassert (c->refcount == 0);
8858
8859 for (i = 0; i < c->used; ++i)
8860 free_image (f, c->images[i]);
8861 xfree (c->images);
8862 xfree (c);
8863 xfree (c->buckets);
8864 FRAME_X_IMAGE_CACHE (f) = NULL;
8865 }
8866}
8867
8868
8869/* Clear image cache of frame F. FORCE_P non-zero means free all
8870 images. FORCE_P zero means clear only images that haven't been
8871 displayed for some time. Should be called from time to time to
dfff8a69
JR
8872 reduce the number of loaded images. If image-eviction-seconds is
8873 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8874 at least that many seconds. */
8875
8876void
8877clear_image_cache (f, force_p)
8878 struct frame *f;
8879 int force_p;
8880{
8881 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8882
8883 if (c && INTEGERP (Vimage_cache_eviction_delay))
8884 {
8885 EMACS_TIME t;
8886 unsigned long old;
8887 int i, any_freed_p = 0;
8888
8889 EMACS_GET_TIME (t);
8890 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8891
8892 for (i = 0; i < c->used; ++i)
8893 {
8894 struct image *img = c->images[i];
8895 if (img != NULL
8896 && (force_p
8897 || (img->timestamp > old)))
8898 {
8899 free_image (f, img);
8900 any_freed_p = 1;
8901 }
8902 }
8903
8904 /* We may be clearing the image cache because, for example,
8905 Emacs was iconified for a longer period of time. In that
8906 case, current matrices may still contain references to
8907 images freed above. So, clear these matrices. */
8908 if (any_freed_p)
8909 {
8910 clear_current_matrices (f);
8911 ++windows_or_buffers_changed;
8912 }
8913 }
8914}
8915
8916
8917DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8918 0, 1, 0,
74e1aeec
JR
8919 doc: /* Clear the image cache of FRAME.
8920FRAME nil or omitted means use the selected frame.
8921FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
8922 (frame)
8923 Lisp_Object frame;
8924{
8925 if (EQ (frame, Qt))
8926 {
8927 Lisp_Object tail;
8928
8929 FOR_EACH_FRAME (tail, frame)
8930 if (FRAME_W32_P (XFRAME (frame)))
8931 clear_image_cache (XFRAME (frame), 1);
8932 }
8933 else
8934 clear_image_cache (check_x_frame (frame), 1);
8935
8936 return Qnil;
8937}
8938
8939
3cf3436e
JR
8940/* Compute masks and transform image IMG on frame F, as specified
8941 by the image's specification, */
8942
8943static void
8944postprocess_image (f, img)
8945 struct frame *f;
8946 struct image *img;
8947{
8948#if 0 /* TODO: image support. */
8949 /* Manipulation of the image's mask. */
8950 if (img->pixmap)
8951 {
8952 Lisp_Object conversion, spec;
8953 Lisp_Object mask;
8954
8955 spec = img->spec;
8956
8957 /* `:heuristic-mask t'
8958 `:mask heuristic'
8959 means build a mask heuristically.
8960 `:heuristic-mask (R G B)'
8961 `:mask (heuristic (R G B))'
8962 means build a mask from color (R G B) in the
8963 image.
8964 `:mask nil'
8965 means remove a mask, if any. */
8966
8967 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8968 if (!NILP (mask))
8969 x_build_heuristic_mask (f, img, mask);
8970 else
8971 {
8972 int found_p;
8973
8974 mask = image_spec_value (spec, QCmask, &found_p);
8975
8976 if (EQ (mask, Qheuristic))
8977 x_build_heuristic_mask (f, img, Qt);
8978 else if (CONSP (mask)
8979 && EQ (XCAR (mask), Qheuristic))
8980 {
8981 if (CONSP (XCDR (mask)))
8982 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8983 else
8984 x_build_heuristic_mask (f, img, XCDR (mask));
8985 }
8986 else if (NILP (mask) && found_p && img->mask)
8987 {
8988 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8989 img->mask = NULL;
8990 }
8991 }
8992
8993
8994 /* Should we apply an image transformation algorithm? */
8995 conversion = image_spec_value (spec, QCconversion, NULL);
8996 if (EQ (conversion, Qdisabled))
8997 x_disable_image (f, img);
8998 else if (EQ (conversion, Qlaplace))
8999 x_laplace (f, img);
9000 else if (EQ (conversion, Qemboss))
9001 x_emboss (f, img);
9002 else if (CONSP (conversion)
9003 && EQ (XCAR (conversion), Qedge_detection))
9004 {
9005 Lisp_Object tem;
9006 tem = XCDR (conversion);
9007 if (CONSP (tem))
9008 x_edge_detection (f, img,
9009 Fplist_get (tem, QCmatrix),
9010 Fplist_get (tem, QCcolor_adjustment));
9011 }
9012 }
9013#endif
9014}
9015
9016
6fc2811b
JR
9017/* Return the id of image with Lisp specification SPEC on frame F.
9018 SPEC must be a valid Lisp image specification (see valid_image_p). */
9019
9020int
9021lookup_image (f, spec)
9022 struct frame *f;
9023 Lisp_Object spec;
9024{
9025 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9026 struct image *img;
9027 int i;
9028 unsigned hash;
9029 struct gcpro gcpro1;
9030 EMACS_TIME now;
9031
9032 /* F must be a window-system frame, and SPEC must be a valid image
9033 specification. */
9034 xassert (FRAME_WINDOW_P (f));
9035 xassert (valid_image_p (spec));
9036
9037 GCPRO1 (spec);
9038
9039 /* Look up SPEC in the hash table of the image cache. */
9040 hash = sxhash (spec, 0);
9041 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9042
9043 for (img = c->buckets[i]; img; img = img->next)
9044 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9045 break;
9046
9047 /* If not found, create a new image and cache it. */
9048 if (img == NULL)
9049 {
3cf3436e
JR
9050 extern Lisp_Object Qpostscript;
9051
8edb0a6f 9052 BLOCK_INPUT;
6fc2811b
JR
9053 img = make_image (spec, hash);
9054 cache_image (f, img);
9055 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
9056
9057 /* If we can't load the image, and we don't have a width and
9058 height, use some arbitrary width and height so that we can
9059 draw a rectangle for it. */
9060 if (img->load_failed_p)
9061 {
9062 Lisp_Object value;
9063
9064 value = image_spec_value (spec, QCwidth, NULL);
9065 img->width = (INTEGERP (value)
9066 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9067 value = image_spec_value (spec, QCheight, NULL);
9068 img->height = (INTEGERP (value)
9069 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9070 }
9071 else
9072 {
9073 /* Handle image type independent image attributes
a05e2bae
JR
9074 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9075 `:background COLOR'. */
9076 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
9077
9078 ascent = image_spec_value (spec, QCascent, NULL);
9079 if (INTEGERP (ascent))
9080 img->ascent = XFASTINT (ascent);
dfff8a69
JR
9081 else if (EQ (ascent, Qcenter))
9082 img->ascent = CENTERED_IMAGE_ASCENT;
9083
6fc2811b
JR
9084 margin = image_spec_value (spec, QCmargin, NULL);
9085 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
9086 img->vmargin = img->hmargin = XFASTINT (margin);
9087 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9088 && INTEGERP (XCDR (margin)))
9089 {
9090 if (XINT (XCAR (margin)) > 0)
9091 img->hmargin = XFASTINT (XCAR (margin));
9092 if (XINT (XCDR (margin)) > 0)
9093 img->vmargin = XFASTINT (XCDR (margin));
9094 }
6fc2811b
JR
9095
9096 relief = image_spec_value (spec, QCrelief, NULL);
9097 if (INTEGERP (relief))
9098 {
9099 img->relief = XINT (relief);
8edb0a6f
JR
9100 img->hmargin += abs (img->relief);
9101 img->vmargin += abs (img->relief);
6fc2811b
JR
9102 }
9103
a05e2bae
JR
9104 if (! img->background_valid)
9105 {
9106 bg = image_spec_value (img->spec, QCbackground, NULL);
9107 if (!NILP (bg))
9108 {
9109 img->background
9110 = x_alloc_image_color (f, img, bg,
9111 FRAME_BACKGROUND_PIXEL (f));
9112 img->background_valid = 1;
9113 }
9114 }
9115
3cf3436e
JR
9116 /* Do image transformations and compute masks, unless we
9117 don't have the image yet. */
9118 if (!EQ (*img->type->type, Qpostscript))
9119 postprocess_image (f, img);
6fc2811b 9120 }
3cf3436e 9121
8edb0a6f
JR
9122 UNBLOCK_INPUT;
9123 xassert (!interrupt_input_blocked);
6fc2811b
JR
9124 }
9125
9126 /* We're using IMG, so set its timestamp to `now'. */
9127 EMACS_GET_TIME (now);
9128 img->timestamp = EMACS_SECS (now);
9129
9130 UNGCPRO;
9131
9132 /* Value is the image id. */
9133 return img->id;
9134}
9135
9136
9137/* Cache image IMG in the image cache of frame F. */
9138
9139static void
9140cache_image (f, img)
9141 struct frame *f;
9142 struct image *img;
9143{
9144 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9145 int i;
9146
9147 /* Find a free slot in c->images. */
9148 for (i = 0; i < c->used; ++i)
9149 if (c->images[i] == NULL)
9150 break;
9151
9152 /* If no free slot found, maybe enlarge c->images. */
9153 if (i == c->used && c->used == c->size)
9154 {
9155 c->size *= 2;
9156 c->images = (struct image **) xrealloc (c->images,
9157 c->size * sizeof *c->images);
9158 }
9159
9160 /* Add IMG to c->images, and assign IMG an id. */
9161 c->images[i] = img;
9162 img->id = i;
9163 if (i == c->used)
9164 ++c->used;
9165
9166 /* Add IMG to the cache's hash table. */
9167 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9168 img->next = c->buckets[i];
9169 if (img->next)
9170 img->next->prev = img;
9171 img->prev = NULL;
9172 c->buckets[i] = img;
9173}
9174
9175
9176/* Call FN on every image in the image cache of frame F. Used to mark
9177 Lisp Objects in the image cache. */
9178
9179void
9180forall_images_in_image_cache (f, fn)
9181 struct frame *f;
9182 void (*fn) P_ ((struct image *img));
9183{
9184 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9185 {
9186 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9187 if (c)
9188 {
9189 int i;
9190 for (i = 0; i < c->used; ++i)
9191 if (c->images[i])
9192 fn (c->images[i]);
9193 }
9194 }
9195}
9196
9197
9198\f
9199/***********************************************************************
9200 W32 support code
9201 ***********************************************************************/
9202
767b1ff0 9203#if 0 /* TODO: W32 specific image code. */
6fc2811b
JR
9204
9205static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9206 XImage **, Pixmap *));
9207static void x_destroy_x_image P_ ((XImage *));
9208static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9209
9210
9211/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9212 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9213 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
9214 via xmalloc. Print error messages via image_error if an error
9215 occurs. Value is non-zero if successful. */
9216
9217static int
9218x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9219 struct frame *f;
9220 int width, height, depth;
9221 XImage **ximg;
9222 Pixmap *pixmap;
9223{
767b1ff0 9224#if 0 /* TODO: Image support for W32 */
6fc2811b
JR
9225 Display *display = FRAME_W32_DISPLAY (f);
9226 Screen *screen = FRAME_X_SCREEN (f);
9227 Window window = FRAME_W32_WINDOW (f);
9228
9229 xassert (interrupt_input_blocked);
9230
9231 if (depth <= 0)
a05e2bae 9232 depth = one_w32_display_info.n_cbits;
6fc2811b
JR
9233 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
9234 depth, ZPixmap, 0, NULL, width, height,
9235 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
9236 if (*ximg == NULL)
9237 {
9238 image_error ("Unable to allocate X image", Qnil, Qnil);
9239 return 0;
9240 }
9241
9242 /* Allocate image raster. */
9243 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
9244
9245 /* Allocate a pixmap of the same size. */
9246 *pixmap = XCreatePixmap (display, window, width, height, depth);
9247 if (*pixmap == 0)
9248 {
9249 x_destroy_x_image (*ximg);
9250 *ximg = NULL;
9251 image_error ("Unable to create X pixmap", Qnil, Qnil);
9252 return 0;
9253 }
9254#endif
9255 return 1;
9256}
9257
9258
9259/* Destroy XImage XIMG. Free XIMG->data. */
9260
9261static void
9262x_destroy_x_image (ximg)
9263 XImage *ximg;
9264{
9265 xassert (interrupt_input_blocked);
9266 if (ximg)
9267 {
9268 xfree (ximg->data);
9269 ximg->data = NULL;
9270 XDestroyImage (ximg);
9271 }
9272}
9273
9274
9275/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9276 are width and height of both the image and pixmap. */
9277
9278static void
9279x_put_x_image (f, ximg, pixmap, width, height)
9280 struct frame *f;
9281 XImage *ximg;
9282 Pixmap pixmap;
9283{
9284 GC gc;
9285
9286 xassert (interrupt_input_blocked);
9287 gc = XCreateGC (NULL, pixmap, 0, NULL);
9288 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9289 XFreeGC (NULL, gc);
9290}
9291
9292#endif
9293
9294\f
9295/***********************************************************************
3cf3436e 9296 File Handling
6fc2811b
JR
9297 ***********************************************************************/
9298
9299static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9300static char *slurp_file P_ ((char *, int *));
9301
6fc2811b
JR
9302
9303/* Find image file FILE. Look in data-directory, then
9304 x-bitmap-file-path. Value is the full name of the file found, or
9305 nil if not found. */
9306
9307static Lisp_Object
9308x_find_image_file (file)
9309 Lisp_Object file;
9310{
9311 Lisp_Object file_found, search_path;
9312 struct gcpro gcpro1, gcpro2;
9313 int fd;
9314
9315 file_found = Qnil;
9316 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9317 GCPRO2 (file_found, search_path);
9318
9319 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 9320 fd = openp (search_path, file, Qnil, &file_found, 0);
6fc2811b 9321
939d6465 9322 if (fd == -1)
6fc2811b
JR
9323 file_found = Qnil;
9324 else
9325 close (fd);
9326
9327 UNGCPRO;
9328 return file_found;
9329}
9330
9331
3cf3436e
JR
9332/* Read FILE into memory. Value is a pointer to a buffer allocated
9333 with xmalloc holding FILE's contents. Value is null if an error
9334 occurred. *SIZE is set to the size of the file. */
9335
9336static char *
9337slurp_file (file, size)
9338 char *file;
9339 int *size;
9340{
9341 FILE *fp = NULL;
9342 char *buf = NULL;
9343 struct stat st;
9344
9345 if (stat (file, &st) == 0
9346 && (fp = fopen (file, "r")) != NULL
9347 && (buf = (char *) xmalloc (st.st_size),
9348 fread (buf, 1, st.st_size, fp) == st.st_size))
9349 {
9350 *size = st.st_size;
9351 fclose (fp);
9352 }
9353 else
9354 {
9355 if (fp)
9356 fclose (fp);
9357 if (buf)
9358 {
9359 xfree (buf);
9360 buf = NULL;
9361 }
9362 }
9363
9364 return buf;
9365}
9366
9367
6fc2811b
JR
9368\f
9369/***********************************************************************
9370 XBM images
9371 ***********************************************************************/
9372
9373static int xbm_load P_ ((struct frame *f, struct image *img));
9374static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9375 Lisp_Object file));
9376static int xbm_image_p P_ ((Lisp_Object object));
9377static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9378 unsigned char **));
9379
9380
9381/* Indices of image specification fields in xbm_format, below. */
9382
9383enum xbm_keyword_index
9384{
9385 XBM_TYPE,
9386 XBM_FILE,
9387 XBM_WIDTH,
9388 XBM_HEIGHT,
9389 XBM_DATA,
9390 XBM_FOREGROUND,
9391 XBM_BACKGROUND,
9392 XBM_ASCENT,
9393 XBM_MARGIN,
9394 XBM_RELIEF,
9395 XBM_ALGORITHM,
9396 XBM_HEURISTIC_MASK,
a05e2bae 9397 XBM_MASK,
6fc2811b
JR
9398 XBM_LAST
9399};
9400
9401/* Vector of image_keyword structures describing the format
9402 of valid XBM image specifications. */
9403
9404static struct image_keyword xbm_format[XBM_LAST] =
9405{
9406 {":type", IMAGE_SYMBOL_VALUE, 1},
9407 {":file", IMAGE_STRING_VALUE, 0},
9408 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9409 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9410 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
9411 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9412 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6fc2811b 9413 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9414 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9415 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9416 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
9417 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9418};
9419
9420/* Structure describing the image type XBM. */
9421
9422static struct image_type xbm_type =
9423{
9424 &Qxbm,
9425 xbm_image_p,
9426 xbm_load,
9427 x_clear_image,
9428 NULL
9429};
9430
9431/* Tokens returned from xbm_scan. */
9432
9433enum xbm_token
9434{
9435 XBM_TK_IDENT = 256,
9436 XBM_TK_NUMBER
9437};
9438
9439
9440/* Return non-zero if OBJECT is a valid XBM-type image specification.
9441 A valid specification is a list starting with the symbol `image'
9442 The rest of the list is a property list which must contain an
9443 entry `:type xbm..
9444
9445 If the specification specifies a file to load, it must contain
9446 an entry `:file FILENAME' where FILENAME is a string.
9447
9448 If the specification is for a bitmap loaded from memory it must
9449 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9450 WIDTH and HEIGHT are integers > 0. DATA may be:
9451
9452 1. a string large enough to hold the bitmap data, i.e. it must
9453 have a size >= (WIDTH + 7) / 8 * HEIGHT
9454
9455 2. a bool-vector of size >= WIDTH * HEIGHT
9456
9457 3. a vector of strings or bool-vectors, one for each line of the
9458 bitmap.
9459
9460 Both the file and data forms may contain the additional entries
9461 `:background COLOR' and `:foreground COLOR'. If not present,
9462 foreground and background of the frame on which the image is
9463 displayed, is used. */
9464
9465static int
9466xbm_image_p (object)
9467 Lisp_Object object;
9468{
9469 struct image_keyword kw[XBM_LAST];
9470
9471 bcopy (xbm_format, kw, sizeof kw);
9472 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9473 return 0;
9474
9475 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9476
9477 if (kw[XBM_FILE].count)
9478 {
9479 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9480 return 0;
9481 }
9482 else
9483 {
9484 Lisp_Object data;
9485 int width, height;
9486
9487 /* Entries for `:width', `:height' and `:data' must be present. */
9488 if (!kw[XBM_WIDTH].count
9489 || !kw[XBM_HEIGHT].count
9490 || !kw[XBM_DATA].count)
9491 return 0;
9492
9493 data = kw[XBM_DATA].value;
9494 width = XFASTINT (kw[XBM_WIDTH].value);
9495 height = XFASTINT (kw[XBM_HEIGHT].value);
9496
9497 /* Check type of data, and width and height against contents of
9498 data. */
9499 if (VECTORP (data))
9500 {
9501 int i;
9502
9503 /* Number of elements of the vector must be >= height. */
9504 if (XVECTOR (data)->size < height)
9505 return 0;
9506
9507 /* Each string or bool-vector in data must be large enough
9508 for one line of the image. */
9509 for (i = 0; i < height; ++i)
9510 {
9511 Lisp_Object elt = XVECTOR (data)->contents[i];
9512
9513 if (STRINGP (elt))
9514 {
9515 if (XSTRING (elt)->size
9516 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9517 return 0;
9518 }
9519 else if (BOOL_VECTOR_P (elt))
9520 {
9521 if (XBOOL_VECTOR (elt)->size < width)
9522 return 0;
9523 }
9524 else
9525 return 0;
9526 }
9527 }
9528 else if (STRINGP (data))
9529 {
9530 if (XSTRING (data)->size
9531 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9532 return 0;
9533 }
9534 else if (BOOL_VECTOR_P (data))
9535 {
9536 if (XBOOL_VECTOR (data)->size < width * height)
9537 return 0;
9538 }
9539 else
9540 return 0;
9541 }
9542
9543 /* Baseline must be a value between 0 and 100 (a percentage). */
9544 if (kw[XBM_ASCENT].count
9545 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9546 return 0;
9547
9548 return 1;
9549}
9550
9551
9552/* Scan a bitmap file. FP is the stream to read from. Value is
9553 either an enumerator from enum xbm_token, or a character for a
9554 single-character token, or 0 at end of file. If scanning an
9555 identifier, store the lexeme of the identifier in SVAL. If
9556 scanning a number, store its value in *IVAL. */
9557
9558static int
3cf3436e
JR
9559xbm_scan (s, end, sval, ival)
9560 char **s, *end;
6fc2811b
JR
9561 char *sval;
9562 int *ival;
9563{
9564 int c;
3cf3436e
JR
9565
9566 loop:
9567
6fc2811b 9568 /* Skip white space. */
3cf3436e 9569 while (*s < end &&(c = *(*s)++, isspace (c)))
6fc2811b
JR
9570 ;
9571
3cf3436e 9572 if (*s >= end)
6fc2811b
JR
9573 c = 0;
9574 else if (isdigit (c))
9575 {
9576 int value = 0, digit;
9577
3cf3436e 9578 if (c == '0' && *s < end)
6fc2811b 9579 {
3cf3436e 9580 c = *(*s)++;
6fc2811b
JR
9581 if (c == 'x' || c == 'X')
9582 {
3cf3436e 9583 while (*s < end)
6fc2811b 9584 {
3cf3436e 9585 c = *(*s)++;
6fc2811b
JR
9586 if (isdigit (c))
9587 digit = c - '0';
9588 else if (c >= 'a' && c <= 'f')
9589 digit = c - 'a' + 10;
9590 else if (c >= 'A' && c <= 'F')
9591 digit = c - 'A' + 10;
9592 else
9593 break;
9594 value = 16 * value + digit;
9595 }
9596 }
9597 else if (isdigit (c))
9598 {
9599 value = c - '0';
3cf3436e
JR
9600 while (*s < end
9601 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9602 value = 8 * value + c - '0';
9603 }
9604 }
9605 else
9606 {
9607 value = c - '0';
3cf3436e
JR
9608 while (*s < end
9609 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9610 value = 10 * value + c - '0';
9611 }
9612
3cf3436e
JR
9613 if (*s < end)
9614 *s = *s - 1;
6fc2811b
JR
9615 *ival = value;
9616 c = XBM_TK_NUMBER;
9617 }
9618 else if (isalpha (c) || c == '_')
9619 {
9620 *sval++ = c;
3cf3436e
JR
9621 while (*s < end
9622 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9623 *sval++ = c;
9624 *sval = 0;
3cf3436e
JR
9625 if (*s < end)
9626 *s = *s - 1;
6fc2811b
JR
9627 c = XBM_TK_IDENT;
9628 }
3cf3436e
JR
9629 else if (c == '/' && **s == '*')
9630 {
9631 /* C-style comment. */
9632 ++*s;
9633 while (**s && (**s != '*' || *(*s + 1) != '/'))
9634 ++*s;
9635 if (**s)
9636 {
9637 *s += 2;
9638 goto loop;
9639 }
9640 }
6fc2811b
JR
9641
9642 return c;
9643}
9644
9645
9646/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9647 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9648 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9649 the image. Return in *DATA the bitmap data allocated with xmalloc.
9650 Value is non-zero if successful. DATA null means just test if
9651 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9652
9653static int
3cf3436e
JR
9654xbm_read_bitmap_data (contents, end, width, height, data)
9655 char *contents, *end;
6fc2811b
JR
9656 int *width, *height;
9657 unsigned char **data;
9658{
3cf3436e 9659 char *s = contents;
6fc2811b
JR
9660 char buffer[BUFSIZ];
9661 int padding_p = 0;
9662 int v10 = 0;
9663 int bytes_per_line, i, nbytes;
9664 unsigned char *p;
9665 int value;
9666 int LA1;
9667
9668#define match() \
3cf3436e 9669 LA1 = xbm_scan (contents, end, buffer, &value)
6fc2811b
JR
9670
9671#define expect(TOKEN) \
9672 if (LA1 != (TOKEN)) \
9673 goto failure; \
9674 else \
9675 match ()
9676
9677#define expect_ident(IDENT) \
9678 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9679 match (); \
9680 else \
9681 goto failure
9682
6fc2811b 9683 *width = *height = -1;
3cf3436e
JR
9684 if (data)
9685 *data = NULL;
9686 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9687
9688 /* Parse defines for width, height and hot-spots. */
9689 while (LA1 == '#')
9690 {
9691 match ();
9692 expect_ident ("define");
9693 expect (XBM_TK_IDENT);
9694
9695 if (LA1 == XBM_TK_NUMBER);
9696 {
9697 char *p = strrchr (buffer, '_');
9698 p = p ? p + 1 : buffer;
9699 if (strcmp (p, "width") == 0)
9700 *width = value;
9701 else if (strcmp (p, "height") == 0)
9702 *height = value;
9703 }
9704 expect (XBM_TK_NUMBER);
9705 }
9706
9707 if (*width < 0 || *height < 0)
9708 goto failure;
3cf3436e
JR
9709 else if (data == NULL)
9710 goto success;
6fc2811b
JR
9711
9712 /* Parse bits. Must start with `static'. */
9713 expect_ident ("static");
9714 if (LA1 == XBM_TK_IDENT)
9715 {
9716 if (strcmp (buffer, "unsigned") == 0)
9717 {
9718 match ();
9719 expect_ident ("char");
9720 }
9721 else if (strcmp (buffer, "short") == 0)
9722 {
9723 match ();
9724 v10 = 1;
9725 if (*width % 16 && *width % 16 < 9)
9726 padding_p = 1;
9727 }
9728 else if (strcmp (buffer, "char") == 0)
9729 match ();
9730 else
9731 goto failure;
9732 }
9733 else
9734 goto failure;
9735
9736 expect (XBM_TK_IDENT);
9737 expect ('[');
9738 expect (']');
9739 expect ('=');
9740 expect ('{');
9741
9742 bytes_per_line = (*width + 7) / 8 + padding_p;
9743 nbytes = bytes_per_line * *height;
9744 p = *data = (char *) xmalloc (nbytes);
9745
9746 if (v10)
9747 {
9748
9749 for (i = 0; i < nbytes; i += 2)
9750 {
9751 int val = value;
9752 expect (XBM_TK_NUMBER);
9753
9754 *p++ = val;
9755 if (!padding_p || ((i + 2) % bytes_per_line))
9756 *p++ = value >> 8;
9757
9758 if (LA1 == ',' || LA1 == '}')
9759 match ();
9760 else
9761 goto failure;
9762 }
9763 }
9764 else
9765 {
9766 for (i = 0; i < nbytes; ++i)
9767 {
9768 int val = value;
9769 expect (XBM_TK_NUMBER);
9770
9771 *p++ = val;
9772
9773 if (LA1 == ',' || LA1 == '}')
9774 match ();
9775 else
9776 goto failure;
9777 }
9778 }
9779
3cf3436e 9780 success:
6fc2811b
JR
9781 return 1;
9782
9783 failure:
3cf3436e
JR
9784
9785 if (data && *data)
6fc2811b
JR
9786 {
9787 xfree (*data);
9788 *data = NULL;
9789 }
9790 return 0;
9791
9792#undef match
9793#undef expect
9794#undef expect_ident
9795}
9796
9797
3cf3436e
JR
9798/* Load XBM image IMG which will be displayed on frame F from buffer
9799 CONTENTS. END is the end of the buffer. Value is non-zero if
9800 successful. */
6fc2811b
JR
9801
9802static int
3cf3436e 9803xbm_load_image (f, img, contents, end)
6fc2811b
JR
9804 struct frame *f;
9805 struct image *img;
3cf3436e 9806 char *contents, *end;
6fc2811b
JR
9807{
9808 int rc;
9809 unsigned char *data;
9810 int success_p = 0;
6fc2811b 9811
3cf3436e 9812 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
9813 if (rc)
9814 {
9815 int depth = one_w32_display_info.n_cbits;
9816 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9817 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9818 Lisp_Object value;
9819
9820 xassert (img->width > 0 && img->height > 0);
9821
9822 /* Get foreground and background colors, maybe allocate colors. */
9823 value = image_spec_value (img->spec, QCforeground, NULL);
9824 if (!NILP (value))
9825 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
9826 value = image_spec_value (img->spec, QCbackground, NULL);
9827 if (!NILP (value))
a05e2bae
JR
9828 {
9829 background = x_alloc_image_color (f, img, value, background);
9830 img->background = background;
9831 img->background_valid = 1;
9832 }
9833
767b1ff0 9834#if 0 /* TODO : Port image display to W32 */
6fc2811b
JR
9835 img->pixmap
9836 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9837 FRAME_W32_WINDOW (f),
9838 data,
9839 img->width, img->height,
9840 foreground, background,
9841 depth);
a05e2bae 9842#endif
6fc2811b
JR
9843 xfree (data);
9844
9845 if (img->pixmap == 0)
9846 {
9847 x_clear_image (f, img);
3cf3436e 9848 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
9849 }
9850 else
9851 success_p = 1;
6fc2811b
JR
9852 }
9853 else
9854 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9855
6fc2811b
JR
9856 return success_p;
9857}
9858
9859
3cf3436e
JR
9860/* Value is non-zero if DATA looks like an in-memory XBM file. */
9861
9862static int
9863xbm_file_p (data)
9864 Lisp_Object data;
9865{
9866 int w, h;
9867 return (STRINGP (data)
9868 && xbm_read_bitmap_data (XSTRING (data)->data,
9869 (XSTRING (data)->data
9870 + STRING_BYTES (XSTRING (data))),
9871 &w, &h, NULL));
9872}
9873
9874
6fc2811b
JR
9875/* Fill image IMG which is used on frame F with pixmap data. Value is
9876 non-zero if successful. */
9877
9878static int
9879xbm_load (f, img)
9880 struct frame *f;
9881 struct image *img;
9882{
9883 int success_p = 0;
9884 Lisp_Object file_name;
9885
9886 xassert (xbm_image_p (img->spec));
9887
9888 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9889 file_name = image_spec_value (img->spec, QCfile, NULL);
9890 if (STRINGP (file_name))
3cf3436e
JR
9891 {
9892 Lisp_Object file;
9893 char *contents;
9894 int size;
9895 struct gcpro gcpro1;
9896
9897 file = x_find_image_file (file_name);
9898 GCPRO1 (file);
9899 if (!STRINGP (file))
9900 {
9901 image_error ("Cannot find image file `%s'", file_name, Qnil);
9902 UNGCPRO;
9903 return 0;
9904 }
9905
9906 contents = slurp_file (XSTRING (file)->data, &size);
9907 if (contents == NULL)
9908 {
9909 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9910 UNGCPRO;
9911 return 0;
9912 }
9913
9914 success_p = xbm_load_image (f, img, contents, contents + size);
9915 UNGCPRO;
9916 }
6fc2811b
JR
9917 else
9918 {
9919 struct image_keyword fmt[XBM_LAST];
9920 Lisp_Object data;
9921 int depth;
9922 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9923 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9924 char *bits;
9925 int parsed_p;
3cf3436e
JR
9926 int in_memory_file_p = 0;
9927
9928 /* See if data looks like an in-memory XBM file. */
9929 data = image_spec_value (img->spec, QCdata, NULL);
9930 in_memory_file_p = xbm_file_p (data);
6fc2811b
JR
9931
9932 /* Parse the list specification. */
9933 bcopy (xbm_format, fmt, sizeof fmt);
9934 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9935 xassert (parsed_p);
9936
9937 /* Get specified width, and height. */
3cf3436e
JR
9938 if (!in_memory_file_p)
9939 {
9940 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9941 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9942 xassert (img->width > 0 && img->height > 0);
9943 }
6fc2811b 9944 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
9945 if (fmt[XBM_FOREGROUND].count
9946 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
9947 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9948 foreground);
3cf3436e
JR
9949 if (fmt[XBM_BACKGROUND].count
9950 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
9951 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9952 background);
9953
3cf3436e
JR
9954 if (in_memory_file_p)
9955 success_p = xbm_load_image (f, img, XSTRING (data)->data,
9956 (XSTRING (data)->data
9957 + STRING_BYTES (XSTRING (data))));
9958 else
6fc2811b 9959 {
3cf3436e
JR
9960 if (VECTORP (data))
9961 {
9962 int i;
9963 char *p;
9964 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 9965
3cf3436e
JR
9966 p = bits = (char *) alloca (nbytes * img->height);
9967 for (i = 0; i < img->height; ++i, p += nbytes)
9968 {
9969 Lisp_Object line = XVECTOR (data)->contents[i];
9970 if (STRINGP (line))
9971 bcopy (XSTRING (line)->data, p, nbytes);
9972 else
9973 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9974 }
9975 }
9976 else if (STRINGP (data))
9977 bits = XSTRING (data)->data;
9978 else
9979 bits = XBOOL_VECTOR (data)->data;
9980#ifdef TODO /* image support. */
9981 /* Create the pixmap. */
a05e2bae 9982 depth = one_w32_display_info.n_cbits;
3cf3436e
JR
9983 img->pixmap
9984 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
9985 FRAME_X_WINDOW (f),
9986 bits,
9987 img->width, img->height,
9988 foreground, background,
9989 depth);
9990#endif
9991 if (img->pixmap)
9992 success_p = 1;
9993 else
6fc2811b 9994 {
3cf3436e
JR
9995 image_error ("Unable to create pixmap for XBM image `%s'",
9996 img->spec, Qnil);
9997 x_clear_image (f, img);
6fc2811b
JR
9998 }
9999 }
6fc2811b
JR
10000 }
10001
10002 return success_p;
10003}
10004
10005
10006\f
10007/***********************************************************************
10008 XPM images
10009 ***********************************************************************/
10010
10011#if HAVE_XPM
10012
10013static int xpm_image_p P_ ((Lisp_Object object));
10014static int xpm_load P_ ((struct frame *f, struct image *img));
10015static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10016
10017#include "X11/xpm.h"
10018
10019/* The symbol `xpm' identifying XPM-format images. */
10020
10021Lisp_Object Qxpm;
10022
10023/* Indices of image specification fields in xpm_format, below. */
10024
10025enum xpm_keyword_index
10026{
10027 XPM_TYPE,
10028 XPM_FILE,
10029 XPM_DATA,
10030 XPM_ASCENT,
10031 XPM_MARGIN,
10032 XPM_RELIEF,
10033 XPM_ALGORITHM,
10034 XPM_HEURISTIC_MASK,
a05e2bae 10035 XPM_MASK,
6fc2811b 10036 XPM_COLOR_SYMBOLS,
a05e2bae 10037 XPM_BACKGROUND,
6fc2811b
JR
10038 XPM_LAST
10039};
10040
10041/* Vector of image_keyword structures describing the format
10042 of valid XPM image specifications. */
10043
10044static struct image_keyword xpm_format[XPM_LAST] =
10045{
10046 {":type", IMAGE_SYMBOL_VALUE, 1},
10047 {":file", IMAGE_STRING_VALUE, 0},
10048 {":data", IMAGE_STRING_VALUE, 0},
10049 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10050 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10051 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10052 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 10053 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10054 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10055 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10056 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10057};
10058
10059/* Structure describing the image type XBM. */
10060
10061static struct image_type xpm_type =
10062{
10063 &Qxpm,
10064 xpm_image_p,
10065 xpm_load,
10066 x_clear_image,
10067 NULL
10068};
10069
10070
10071/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10072 for XPM images. Such a list must consist of conses whose car and
10073 cdr are strings. */
10074
10075static int
10076xpm_valid_color_symbols_p (color_symbols)
10077 Lisp_Object color_symbols;
10078{
10079 while (CONSP (color_symbols))
10080 {
10081 Lisp_Object sym = XCAR (color_symbols);
10082 if (!CONSP (sym)
10083 || !STRINGP (XCAR (sym))
10084 || !STRINGP (XCDR (sym)))
10085 break;
10086 color_symbols = XCDR (color_symbols);
10087 }
10088
10089 return NILP (color_symbols);
10090}
10091
10092
10093/* Value is non-zero if OBJECT is a valid XPM image specification. */
10094
10095static int
10096xpm_image_p (object)
10097 Lisp_Object object;
10098{
10099 struct image_keyword fmt[XPM_LAST];
10100 bcopy (xpm_format, fmt, sizeof fmt);
10101 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10102 /* Either `:file' or `:data' must be present. */
10103 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10104 /* Either no `:color-symbols' or it's a list of conses
10105 whose car and cdr are strings. */
10106 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10107 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10108 && (fmt[XPM_ASCENT].count == 0
10109 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10110}
10111
10112
10113/* Load image IMG which will be displayed on frame F. Value is
10114 non-zero if successful. */
10115
10116static int
10117xpm_load (f, img)
10118 struct frame *f;
10119 struct image *img;
10120{
10121 int rc, i;
10122 XpmAttributes attrs;
10123 Lisp_Object specified_file, color_symbols;
10124
10125 /* Configure the XPM lib. Use the visual of frame F. Allocate
10126 close colors. Return colors allocated. */
10127 bzero (&attrs, sizeof attrs);
dfff8a69
JR
10128 attrs.visual = FRAME_X_VISUAL (f);
10129 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 10130 attrs.valuemask |= XpmVisual;
dfff8a69 10131 attrs.valuemask |= XpmColormap;
6fc2811b 10132 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 10133#ifdef XpmAllocCloseColors
6fc2811b
JR
10134 attrs.alloc_close_colors = 1;
10135 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
10136#else
10137 attrs.closeness = 600;
10138 attrs.valuemask |= XpmCloseness;
10139#endif
6fc2811b
JR
10140
10141 /* If image specification contains symbolic color definitions, add
10142 these to `attrs'. */
10143 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10144 if (CONSP (color_symbols))
10145 {
10146 Lisp_Object tail;
10147 XpmColorSymbol *xpm_syms;
10148 int i, size;
10149
10150 attrs.valuemask |= XpmColorSymbols;
10151
10152 /* Count number of symbols. */
10153 attrs.numsymbols = 0;
10154 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10155 ++attrs.numsymbols;
10156
10157 /* Allocate an XpmColorSymbol array. */
10158 size = attrs.numsymbols * sizeof *xpm_syms;
10159 xpm_syms = (XpmColorSymbol *) alloca (size);
10160 bzero (xpm_syms, size);
10161 attrs.colorsymbols = xpm_syms;
10162
10163 /* Fill the color symbol array. */
10164 for (tail = color_symbols, i = 0;
10165 CONSP (tail);
10166 ++i, tail = XCDR (tail))
10167 {
10168 Lisp_Object name = XCAR (XCAR (tail));
10169 Lisp_Object color = XCDR (XCAR (tail));
10170 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10171 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10172 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10173 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10174 }
10175 }
10176
10177 /* Create a pixmap for the image, either from a file, or from a
10178 string buffer containing data in the same format as an XPM file. */
10179 BLOCK_INPUT;
10180 specified_file = image_spec_value (img->spec, QCfile, NULL);
10181 if (STRINGP (specified_file))
10182 {
10183 Lisp_Object file = x_find_image_file (specified_file);
10184 if (!STRINGP (file))
10185 {
10186 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10187 UNBLOCK_INPUT;
10188 return 0;
10189 }
10190
10191 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10192 XSTRING (file)->data, &img->pixmap, &img->mask,
10193 &attrs);
10194 }
10195 else
10196 {
10197 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10198 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10199 XSTRING (buffer)->data,
10200 &img->pixmap, &img->mask,
10201 &attrs);
10202 }
10203 UNBLOCK_INPUT;
10204
10205 if (rc == XpmSuccess)
10206 {
10207 /* Remember allocated colors. */
10208 img->ncolors = attrs.nalloc_pixels;
10209 img->colors = (unsigned long *) xmalloc (img->ncolors
10210 * sizeof *img->colors);
10211 for (i = 0; i < attrs.nalloc_pixels; ++i)
10212 img->colors[i] = attrs.alloc_pixels[i];
10213
10214 img->width = attrs.width;
10215 img->height = attrs.height;
10216 xassert (img->width > 0 && img->height > 0);
10217
10218 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10219 BLOCK_INPUT;
10220 XpmFreeAttributes (&attrs);
10221 UNBLOCK_INPUT;
10222 }
10223 else
10224 {
10225 switch (rc)
10226 {
10227 case XpmOpenFailed:
10228 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10229 break;
10230
10231 case XpmFileInvalid:
10232 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10233 break;
10234
10235 case XpmNoMemory:
10236 image_error ("Out of memory (%s)", img->spec, Qnil);
10237 break;
10238
10239 case XpmColorFailed:
10240 image_error ("Color allocation error (%s)", img->spec, Qnil);
10241 break;
10242
10243 default:
10244 image_error ("Unknown error (%s)", img->spec, Qnil);
10245 break;
10246 }
10247 }
10248
10249 return rc == XpmSuccess;
10250}
10251
10252#endif /* HAVE_XPM != 0 */
10253
10254\f
767b1ff0 10255#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
10256/***********************************************************************
10257 Color table
10258 ***********************************************************************/
10259
10260/* An entry in the color table mapping an RGB color to a pixel color. */
10261
10262struct ct_color
10263{
10264 int r, g, b;
10265 unsigned long pixel;
10266
10267 /* Next in color table collision list. */
10268 struct ct_color *next;
10269};
10270
10271/* The bucket vector size to use. Must be prime. */
10272
10273#define CT_SIZE 101
10274
10275/* Value is a hash of the RGB color given by R, G, and B. */
10276
10277#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10278
10279/* The color hash table. */
10280
10281struct ct_color **ct_table;
10282
10283/* Number of entries in the color table. */
10284
10285int ct_colors_allocated;
10286
10287/* Function prototypes. */
10288
10289static void init_color_table P_ ((void));
10290static void free_color_table P_ ((void));
10291static unsigned long *colors_in_color_table P_ ((int *n));
10292static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10293static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10294
10295
10296/* Initialize the color table. */
10297
10298static void
10299init_color_table ()
10300{
10301 int size = CT_SIZE * sizeof (*ct_table);
10302 ct_table = (struct ct_color **) xmalloc (size);
10303 bzero (ct_table, size);
10304 ct_colors_allocated = 0;
10305}
10306
10307
10308/* Free memory associated with the color table. */
10309
10310static void
10311free_color_table ()
10312{
10313 int i;
10314 struct ct_color *p, *next;
10315
10316 for (i = 0; i < CT_SIZE; ++i)
10317 for (p = ct_table[i]; p; p = next)
10318 {
10319 next = p->next;
10320 xfree (p);
10321 }
10322
10323 xfree (ct_table);
10324 ct_table = NULL;
10325}
10326
10327
10328/* Value is a pixel color for RGB color R, G, B on frame F. If an
10329 entry for that color already is in the color table, return the
10330 pixel color of that entry. Otherwise, allocate a new color for R,
10331 G, B, and make an entry in the color table. */
10332
10333static unsigned long
10334lookup_rgb_color (f, r, g, b)
10335 struct frame *f;
10336 int r, g, b;
10337{
10338 unsigned hash = CT_HASH_RGB (r, g, b);
10339 int i = hash % CT_SIZE;
10340 struct ct_color *p;
10341
10342 for (p = ct_table[i]; p; p = p->next)
10343 if (p->r == r && p->g == g && p->b == b)
10344 break;
10345
10346 if (p == NULL)
10347 {
10348 COLORREF color;
10349 Colormap cmap;
10350 int rc;
10351
10352 color = PALETTERGB (r, g, b);
10353
10354 ++ct_colors_allocated;
10355
10356 p = (struct ct_color *) xmalloc (sizeof *p);
10357 p->r = r;
10358 p->g = g;
10359 p->b = b;
10360 p->pixel = color;
10361 p->next = ct_table[i];
10362 ct_table[i] = p;
10363 }
10364
10365 return p->pixel;
10366}
10367
10368
10369/* Look up pixel color PIXEL which is used on frame F in the color
10370 table. If not already present, allocate it. Value is PIXEL. */
10371
10372static unsigned long
10373lookup_pixel_color (f, pixel)
10374 struct frame *f;
10375 unsigned long pixel;
10376{
10377 int i = pixel % CT_SIZE;
10378 struct ct_color *p;
10379
10380 for (p = ct_table[i]; p; p = p->next)
10381 if (p->pixel == pixel)
10382 break;
10383
10384 if (p == NULL)
10385 {
10386 XColor color;
10387 Colormap cmap;
10388 int rc;
10389
10390 BLOCK_INPUT;
10391
10392 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10393 color.pixel = pixel;
10394 XQueryColor (NULL, cmap, &color);
10395 rc = x_alloc_nearest_color (f, cmap, &color);
10396 UNBLOCK_INPUT;
10397
10398 if (rc)
10399 {
10400 ++ct_colors_allocated;
10401
10402 p = (struct ct_color *) xmalloc (sizeof *p);
10403 p->r = color.red;
10404 p->g = color.green;
10405 p->b = color.blue;
10406 p->pixel = pixel;
10407 p->next = ct_table[i];
10408 ct_table[i] = p;
10409 }
10410 else
10411 return FRAME_FOREGROUND_PIXEL (f);
10412 }
10413 return p->pixel;
10414}
10415
10416
10417/* Value is a vector of all pixel colors contained in the color table,
10418 allocated via xmalloc. Set *N to the number of colors. */
10419
10420static unsigned long *
10421colors_in_color_table (n)
10422 int *n;
10423{
10424 int i, j;
10425 struct ct_color *p;
10426 unsigned long *colors;
10427
10428 if (ct_colors_allocated == 0)
10429 {
10430 *n = 0;
10431 colors = NULL;
10432 }
10433 else
10434 {
10435 colors = (unsigned long *) xmalloc (ct_colors_allocated
10436 * sizeof *colors);
10437 *n = ct_colors_allocated;
10438
10439 for (i = j = 0; i < CT_SIZE; ++i)
10440 for (p = ct_table[i]; p; p = p->next)
10441 colors[j++] = p->pixel;
10442 }
10443
10444 return colors;
10445}
10446
767b1ff0 10447#endif /* TODO */
6fc2811b
JR
10448
10449\f
10450/***********************************************************************
10451 Algorithms
10452 ***********************************************************************/
3cf3436e
JR
10453#if 0 /* TODO: image support. */
10454static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10455static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10456static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10457
10458/* Non-zero means draw a cross on images having `:conversion
10459 disabled'. */
6fc2811b 10460
3cf3436e 10461int cross_disabled_images;
6fc2811b 10462
3cf3436e
JR
10463/* Edge detection matrices for different edge-detection
10464 strategies. */
6fc2811b 10465
3cf3436e
JR
10466static int emboss_matrix[9] = {
10467 /* x - 1 x x + 1 */
10468 2, -1, 0, /* y - 1 */
10469 -1, 0, 1, /* y */
10470 0, 1, -2 /* y + 1 */
10471};
10472
10473static int laplace_matrix[9] = {
10474 /* x - 1 x x + 1 */
10475 1, 0, 0, /* y - 1 */
10476 0, 0, 0, /* y */
10477 0, 0, -1 /* y + 1 */
10478};
10479
10480/* Value is the intensity of the color whose red/green/blue values
10481 are R, G, and B. */
10482
10483#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10484
10485
10486/* On frame F, return an array of XColor structures describing image
10487 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10488 non-zero means also fill the red/green/blue members of the XColor
10489 structures. Value is a pointer to the array of XColors structures,
10490 allocated with xmalloc; it must be freed by the caller. */
10491
10492static XColor *
10493x_to_xcolors (f, img, rgb_p)
10494 struct frame *f;
10495 struct image *img;
10496 int rgb_p;
10497{
10498 int x, y;
10499 XColor *colors, *p;
10500 XImage *ximg;
10501
10502 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10503
10504 /* Get the X image IMG->pixmap. */
10505 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10506 0, 0, img->width, img->height, ~0, ZPixmap);
10507
10508 /* Fill the `pixel' members of the XColor array. I wished there
10509 were an easy and portable way to circumvent XGetPixel. */
10510 p = colors;
10511 for (y = 0; y < img->height; ++y)
10512 {
10513 XColor *row = p;
10514
10515 for (x = 0; x < img->width; ++x, ++p)
10516 p->pixel = XGetPixel (ximg, x, y);
10517
10518 if (rgb_p)
10519 x_query_colors (f, row, img->width);
10520 }
10521
10522 XDestroyImage (ximg);
10523 return colors;
10524}
10525
10526
10527/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10528 RGB members are set. F is the frame on which this all happens.
10529 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10530
10531static void
3cf3436e 10532x_from_xcolors (f, img, colors)
6fc2811b 10533 struct frame *f;
3cf3436e 10534 struct image *img;
6fc2811b 10535 XColor *colors;
6fc2811b 10536{
3cf3436e
JR
10537 int x, y;
10538 XImage *oimg;
10539 Pixmap pixmap;
10540 XColor *p;
10541
10542 init_color_table ();
10543
10544 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10545 &oimg, &pixmap);
10546 p = colors;
10547 for (y = 0; y < img->height; ++y)
10548 for (x = 0; x < img->width; ++x, ++p)
10549 {
10550 unsigned long pixel;
10551 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10552 XPutPixel (oimg, x, y, pixel);
10553 }
6fc2811b 10554
3cf3436e
JR
10555 xfree (colors);
10556 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10557
3cf3436e
JR
10558 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10559 x_destroy_x_image (oimg);
10560 img->pixmap = pixmap;
10561 img->colors = colors_in_color_table (&img->ncolors);
10562 free_color_table ();
6fc2811b
JR
10563}
10564
10565
3cf3436e
JR
10566/* On frame F, perform edge-detection on image IMG.
10567
10568 MATRIX is a nine-element array specifying the transformation
10569 matrix. See emboss_matrix for an example.
10570
10571 COLOR_ADJUST is a color adjustment added to each pixel of the
10572 outgoing image. */
6fc2811b
JR
10573
10574static void
3cf3436e 10575x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10576 struct frame *f;
3cf3436e
JR
10577 struct image *img;
10578 int matrix[9], color_adjust;
6fc2811b 10579{
3cf3436e
JR
10580 XColor *colors = x_to_xcolors (f, img, 1);
10581 XColor *new, *p;
10582 int x, y, i, sum;
10583
10584 for (i = sum = 0; i < 9; ++i)
10585 sum += abs (matrix[i]);
10586
10587#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10588
10589 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10590
10591 for (y = 0; y < img->height; ++y)
10592 {
10593 p = COLOR (new, 0, y);
10594 p->red = p->green = p->blue = 0xffff/2;
10595 p = COLOR (new, img->width - 1, y);
10596 p->red = p->green = p->blue = 0xffff/2;
10597 }
6fc2811b 10598
3cf3436e
JR
10599 for (x = 1; x < img->width - 1; ++x)
10600 {
10601 p = COLOR (new, x, 0);
10602 p->red = p->green = p->blue = 0xffff/2;
10603 p = COLOR (new, x, img->height - 1);
10604 p->red = p->green = p->blue = 0xffff/2;
10605 }
10606
10607 for (y = 1; y < img->height - 1; ++y)
10608 {
10609 p = COLOR (new, 1, y);
10610
10611 for (x = 1; x < img->width - 1; ++x, ++p)
10612 {
10613 int r, g, b, y1, x1;
10614
10615 r = g = b = i = 0;
10616 for (y1 = y - 1; y1 < y + 2; ++y1)
10617 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10618 if (matrix[i])
10619 {
10620 XColor *t = COLOR (colors, x1, y1);
10621 r += matrix[i] * t->red;
10622 g += matrix[i] * t->green;
10623 b += matrix[i] * t->blue;
10624 }
10625
10626 r = (r / sum + color_adjust) & 0xffff;
10627 g = (g / sum + color_adjust) & 0xffff;
10628 b = (b / sum + color_adjust) & 0xffff;
10629 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10630 }
10631 }
10632
10633 xfree (colors);
10634 x_from_xcolors (f, img, new);
10635
10636#undef COLOR
10637}
10638
10639
10640/* Perform the pre-defined `emboss' edge-detection on image IMG
10641 on frame F. */
10642
10643static void
10644x_emboss (f, img)
10645 struct frame *f;
10646 struct image *img;
10647{
10648 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10649}
3cf3436e 10650
6fc2811b
JR
10651
10652/* Transform image IMG which is used on frame F with a Laplace
10653 edge-detection algorithm. The result is an image that can be used
10654 to draw disabled buttons, for example. */
10655
10656static void
10657x_laplace (f, img)
10658 struct frame *f;
10659 struct image *img;
10660{
3cf3436e
JR
10661 x_detect_edges (f, img, laplace_matrix, 45000);
10662}
6fc2811b 10663
6fc2811b 10664
3cf3436e
JR
10665/* Perform edge-detection on image IMG on frame F, with specified
10666 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10667
3cf3436e 10668 MATRIX must be either
6fc2811b 10669
3cf3436e
JR
10670 - a list of at least 9 numbers in row-major form
10671 - a vector of at least 9 numbers
6fc2811b 10672
3cf3436e
JR
10673 COLOR_ADJUST nil means use a default; otherwise it must be a
10674 number. */
6fc2811b 10675
3cf3436e
JR
10676static void
10677x_edge_detection (f, img, matrix, color_adjust)
10678 struct frame *f;
10679 struct image *img;
10680 Lisp_Object matrix, color_adjust;
10681{
10682 int i = 0;
10683 int trans[9];
10684
10685 if (CONSP (matrix))
6fc2811b 10686 {
3cf3436e
JR
10687 for (i = 0;
10688 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10689 ++i, matrix = XCDR (matrix))
10690 trans[i] = XFLOATINT (XCAR (matrix));
10691 }
10692 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10693 {
10694 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10695 trans[i] = XFLOATINT (AREF (matrix, i));
10696 }
10697
10698 if (NILP (color_adjust))
10699 color_adjust = make_number (0xffff / 2);
10700
10701 if (i == 9 && NUMBERP (color_adjust))
10702 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10703}
10704
6fc2811b 10705
3cf3436e 10706/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10707
3cf3436e
JR
10708static void
10709x_disable_image (f, img)
10710 struct frame *f;
10711 struct image *img;
10712{
10713 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10714
10715 if (dpyinfo->n_planes >= 2)
10716 {
10717 /* Color (or grayscale). Convert to gray, and equalize. Just
10718 drawing such images with a stipple can look very odd, so
10719 we're using this method instead. */
10720 XColor *colors = x_to_xcolors (f, img, 1);
10721 XColor *p, *end;
10722 const int h = 15000;
10723 const int l = 30000;
10724
10725 for (p = colors, end = colors + img->width * img->height;
10726 p < end;
10727 ++p)
6fc2811b 10728 {
3cf3436e
JR
10729 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10730 int i2 = (0xffff - h - l) * i / 0xffff + l;
10731 p->red = p->green = p->blue = i2;
6fc2811b
JR
10732 }
10733
3cf3436e 10734 x_from_xcolors (f, img, colors);
6fc2811b
JR
10735 }
10736
3cf3436e
JR
10737 /* Draw a cross over the disabled image, if we must or if we
10738 should. */
10739 if (dpyinfo->n_planes < 2 || cross_disabled_images)
10740 {
10741 Display *dpy = FRAME_X_DISPLAY (f);
10742 GC gc;
6fc2811b 10743
3cf3436e
JR
10744 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10745 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10746 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10747 img->width - 1, img->height - 1);
10748 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10749 img->width - 1, 0);
10750 XFreeGC (dpy, gc);
6fc2811b 10751
3cf3436e
JR
10752 if (img->mask)
10753 {
10754 gc = XCreateGC (dpy, img->mask, 0, NULL);
10755 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10756 XDrawLine (dpy, img->mask, gc, 0, 0,
10757 img->width - 1, img->height - 1);
10758 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10759 img->width - 1, 0);
10760 XFreeGC (dpy, gc);
10761 }
10762 }
6fc2811b
JR
10763}
10764
10765
10766/* Build a mask for image IMG which is used on frame F. FILE is the
10767 name of an image file, for error messages. HOW determines how to
10768 determine the background color of IMG. If it is a list '(R G B)',
10769 with R, G, and B being integers >= 0, take that as the color of the
10770 background. Otherwise, determine the background color of IMG
10771 heuristically. Value is non-zero if successful. */
10772
10773static int
10774x_build_heuristic_mask (f, img, how)
10775 struct frame *f;
10776 struct image *img;
10777 Lisp_Object how;
10778{
6fc2811b
JR
10779 Display *dpy = FRAME_W32_DISPLAY (f);
10780 XImage *ximg, *mask_img;
a05e2bae
JR
10781 int x, y, rc, use_img_background;
10782 unsigned long bg = 0;
10783
10784 if (img->mask)
10785 {
10786 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10787 img->mask = None;
10788 img->background_transparent_valid = 0;
10789 }
6fc2811b 10790
6fc2811b
JR
10791 /* Create an image and pixmap serving as mask. */
10792 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10793 &mask_img, &img->mask);
10794 if (!rc)
a05e2bae 10795 return 0;
6fc2811b
JR
10796
10797 /* Get the X image of IMG->pixmap. */
10798 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10799 ~0, ZPixmap);
10800
10801 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
10802 take that as color. Otherwise, use the image's background color. */
10803 use_img_background = 1;
6fc2811b
JR
10804
10805 if (CONSP (how))
10806 {
a05e2bae 10807 int rgb[3], i;
6fc2811b 10808
a05e2bae 10809 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
10810 {
10811 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10812 how = XCDR (how);
10813 }
10814
10815 if (i == 3 && NILP (how))
10816 {
10817 char color_name[30];
6fc2811b 10818 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
10819 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10820 use_img_background = 0;
6fc2811b
JR
10821 }
10822 }
10823
a05e2bae
JR
10824 if (use_img_background)
10825 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
10826
10827 /* Set all bits in mask_img to 1 whose color in ximg is different
10828 from the background color bg. */
10829 for (y = 0; y < img->height; ++y)
10830 for (x = 0; x < img->width; ++x)
10831 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
10832
a05e2bae
JR
10833 /* Fill in the background_transparent field while we have the mask handy. */
10834 image_background_transparent (img, f, mask_img);
10835
6fc2811b
JR
10836 /* Put mask_img into img->mask. */
10837 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10838 x_destroy_x_image (mask_img);
10839 XDestroyImage (ximg);
6fc2811b
JR
10840
10841 return 1;
10842}
3cf3436e 10843#endif /* TODO */
6fc2811b
JR
10844
10845\f
10846/***********************************************************************
10847 PBM (mono, gray, color)
10848 ***********************************************************************/
10849#ifdef HAVE_PBM
10850
10851static int pbm_image_p P_ ((Lisp_Object object));
10852static int pbm_load P_ ((struct frame *f, struct image *img));
10853static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10854
10855/* The symbol `pbm' identifying images of this type. */
10856
10857Lisp_Object Qpbm;
10858
10859/* Indices of image specification fields in gs_format, below. */
10860
10861enum pbm_keyword_index
10862{
10863 PBM_TYPE,
10864 PBM_FILE,
10865 PBM_DATA,
10866 PBM_ASCENT,
10867 PBM_MARGIN,
10868 PBM_RELIEF,
10869 PBM_ALGORITHM,
10870 PBM_HEURISTIC_MASK,
a05e2bae
JR
10871 PBM_MASK,
10872 PBM_FOREGROUND,
10873 PBM_BACKGROUND,
6fc2811b
JR
10874 PBM_LAST
10875};
10876
10877/* Vector of image_keyword structures describing the format
10878 of valid user-defined image specifications. */
10879
10880static struct image_keyword pbm_format[PBM_LAST] =
10881{
10882 {":type", IMAGE_SYMBOL_VALUE, 1},
10883 {":file", IMAGE_STRING_VALUE, 0},
10884 {":data", IMAGE_STRING_VALUE, 0},
10885 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10886 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10887 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10888 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
10889 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10890 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10891 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10892 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10893};
10894
10895/* Structure describing the image type `pbm'. */
10896
10897static struct image_type pbm_type =
10898{
10899 &Qpbm,
10900 pbm_image_p,
10901 pbm_load,
10902 x_clear_image,
10903 NULL
10904};
10905
10906
10907/* Return non-zero if OBJECT is a valid PBM image specification. */
10908
10909static int
10910pbm_image_p (object)
10911 Lisp_Object object;
10912{
10913 struct image_keyword fmt[PBM_LAST];
10914
10915 bcopy (pbm_format, fmt, sizeof fmt);
10916
10917 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
10918 || (fmt[PBM_ASCENT].count
10919 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
10920 return 0;
10921
10922 /* Must specify either :data or :file. */
10923 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10924}
10925
10926
10927/* Scan a decimal number from *S and return it. Advance *S while
10928 reading the number. END is the end of the string. Value is -1 at
10929 end of input. */
10930
10931static int
10932pbm_scan_number (s, end)
10933 unsigned char **s, *end;
10934{
10935 int c, val = -1;
10936
10937 while (*s < end)
10938 {
10939 /* Skip white-space. */
10940 while (*s < end && (c = *(*s)++, isspace (c)))
10941 ;
10942
10943 if (c == '#')
10944 {
10945 /* Skip comment to end of line. */
10946 while (*s < end && (c = *(*s)++, c != '\n'))
10947 ;
10948 }
10949 else if (isdigit (c))
10950 {
10951 /* Read decimal number. */
10952 val = c - '0';
10953 while (*s < end && (c = *(*s)++, isdigit (c)))
10954 val = 10 * val + c - '0';
10955 break;
10956 }
10957 else
10958 break;
10959 }
10960
10961 return val;
10962}
10963
10964
10965/* Read FILE into memory. Value is a pointer to a buffer allocated
10966 with xmalloc holding FILE's contents. Value is null if an error
10967 occured. *SIZE is set to the size of the file. */
10968
10969static char *
10970pbm_read_file (file, size)
10971 Lisp_Object file;
10972 int *size;
10973{
10974 FILE *fp = NULL;
10975 char *buf = NULL;
10976 struct stat st;
10977
10978 if (stat (XSTRING (file)->data, &st) == 0
10979 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10980 && (buf = (char *) xmalloc (st.st_size),
10981 fread (buf, 1, st.st_size, fp) == st.st_size))
10982 {
10983 *size = st.st_size;
10984 fclose (fp);
10985 }
10986 else
10987 {
10988 if (fp)
10989 fclose (fp);
10990 if (buf)
10991 {
10992 xfree (buf);
10993 buf = NULL;
10994 }
10995 }
10996
10997 return buf;
10998}
10999
11000
11001/* Load PBM image IMG for use on frame F. */
11002
11003static int
11004pbm_load (f, img)
11005 struct frame *f;
11006 struct image *img;
11007{
11008 int raw_p, x, y;
11009 int width, height, max_color_idx = 0;
11010 XImage *ximg;
11011 Lisp_Object file, specified_file;
11012 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11013 struct gcpro gcpro1;
11014 unsigned char *contents = NULL;
11015 unsigned char *end, *p;
11016 int size;
11017
11018 specified_file = image_spec_value (img->spec, QCfile, NULL);
11019 file = Qnil;
11020 GCPRO1 (file);
11021
11022 if (STRINGP (specified_file))
11023 {
11024 file = x_find_image_file (specified_file);
11025 if (!STRINGP (file))
11026 {
11027 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11028 UNGCPRO;
11029 return 0;
11030 }
11031
3cf3436e 11032 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
11033 if (contents == NULL)
11034 {
11035 image_error ("Error reading `%s'", file, Qnil);
11036 UNGCPRO;
11037 return 0;
11038 }
11039
11040 p = contents;
11041 end = contents + size;
11042 }
11043 else
11044 {
11045 Lisp_Object data;
11046 data = image_spec_value (img->spec, QCdata, NULL);
11047 p = XSTRING (data)->data;
11048 end = p + STRING_BYTES (XSTRING (data));
11049 }
11050
11051 /* Check magic number. */
11052 if (end - p < 2 || *p++ != 'P')
11053 {
11054 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11055 error:
11056 xfree (contents);
11057 UNGCPRO;
11058 return 0;
11059 }
11060
6fc2811b
JR
11061 switch (*p++)
11062 {
11063 case '1':
11064 raw_p = 0, type = PBM_MONO;
11065 break;
11066
11067 case '2':
11068 raw_p = 0, type = PBM_GRAY;
11069 break;
11070
11071 case '3':
11072 raw_p = 0, type = PBM_COLOR;
11073 break;
11074
11075 case '4':
11076 raw_p = 1, type = PBM_MONO;
11077 break;
11078
11079 case '5':
11080 raw_p = 1, type = PBM_GRAY;
11081 break;
11082
11083 case '6':
11084 raw_p = 1, type = PBM_COLOR;
11085 break;
11086
11087 default:
11088 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11089 goto error;
11090 }
11091
11092 /* Read width, height, maximum color-component. Characters
11093 starting with `#' up to the end of a line are ignored. */
11094 width = pbm_scan_number (&p, end);
11095 height = pbm_scan_number (&p, end);
11096
11097 if (type != PBM_MONO)
11098 {
11099 max_color_idx = pbm_scan_number (&p, end);
11100 if (raw_p && max_color_idx > 255)
11101 max_color_idx = 255;
11102 }
11103
11104 if (width < 0
11105 || height < 0
11106 || (type != PBM_MONO && max_color_idx < 0))
11107 goto error;
11108
6fc2811b
JR
11109 if (!x_create_x_image_and_pixmap (f, width, height, 0,
11110 &ximg, &img->pixmap))
3cf3436e
JR
11111 goto error;
11112
6fc2811b
JR
11113 /* Initialize the color hash table. */
11114 init_color_table ();
11115
11116 if (type == PBM_MONO)
11117 {
11118 int c = 0, g;
3cf3436e
JR
11119 struct image_keyword fmt[PBM_LAST];
11120 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11121 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11122
11123 /* Parse the image specification. */
11124 bcopy (pbm_format, fmt, sizeof fmt);
11125 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11126
11127 /* Get foreground and background colors, maybe allocate colors. */
11128 if (fmt[PBM_FOREGROUND].count
11129 && STRINGP (fmt[PBM_FOREGROUND].value))
11130 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11131 if (fmt[PBM_BACKGROUND].count
11132 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
11133 {
11134 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11135 img->background = bg;
11136 img->background_valid = 1;
11137 }
11138
6fc2811b
JR
11139 for (y = 0; y < height; ++y)
11140 for (x = 0; x < width; ++x)
11141 {
11142 if (raw_p)
11143 {
11144 if ((x & 7) == 0)
11145 c = *p++;
11146 g = c & 0x80;
11147 c <<= 1;
11148 }
11149 else
11150 g = pbm_scan_number (&p, end);
11151
3cf3436e 11152 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
11153 }
11154 }
11155 else
11156 {
11157 for (y = 0; y < height; ++y)
11158 for (x = 0; x < width; ++x)
11159 {
11160 int r, g, b;
11161
11162 if (type == PBM_GRAY)
11163 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11164 else if (raw_p)
11165 {
11166 r = *p++;
11167 g = *p++;
11168 b = *p++;
11169 }
11170 else
11171 {
11172 r = pbm_scan_number (&p, end);
11173 g = pbm_scan_number (&p, end);
11174 b = pbm_scan_number (&p, end);
11175 }
11176
11177 if (r < 0 || g < 0 || b < 0)
11178 {
dfff8a69 11179 xfree (ximg->data);
6fc2811b
JR
11180 ximg->data = NULL;
11181 XDestroyImage (ximg);
6fc2811b
JR
11182 image_error ("Invalid pixel value in image `%s'",
11183 img->spec, Qnil);
11184 goto error;
11185 }
11186
11187 /* RGB values are now in the range 0..max_color_idx.
11188 Scale this to the range 0..0xffff supported by X. */
11189 r = (double) r * 65535 / max_color_idx;
11190 g = (double) g * 65535 / max_color_idx;
11191 b = (double) b * 65535 / max_color_idx;
11192 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11193 }
11194 }
11195
11196 /* Store in IMG->colors the colors allocated for the image, and
11197 free the color table. */
11198 img->colors = colors_in_color_table (&img->ncolors);
11199 free_color_table ();
11200
a05e2bae
JR
11201 /* Maybe fill in the background field while we have ximg handy. */
11202 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11203 IMAGE_BACKGROUND (img, f, ximg);
11204
6fc2811b
JR
11205 /* Put the image into a pixmap. */
11206 x_put_x_image (f, ximg, img->pixmap, width, height);
11207 x_destroy_x_image (ximg);
6fc2811b
JR
11208
11209 img->width = width;
11210 img->height = height;
11211
11212 UNGCPRO;
11213 xfree (contents);
11214 return 1;
11215}
11216#endif /* HAVE_PBM */
11217
11218\f
11219/***********************************************************************
11220 PNG
11221 ***********************************************************************/
11222
11223#if HAVE_PNG
11224
11225#include <png.h>
11226
11227/* Function prototypes. */
11228
11229static int png_image_p P_ ((Lisp_Object object));
11230static int png_load P_ ((struct frame *f, struct image *img));
11231
11232/* The symbol `png' identifying images of this type. */
11233
11234Lisp_Object Qpng;
11235
11236/* Indices of image specification fields in png_format, below. */
11237
11238enum png_keyword_index
11239{
11240 PNG_TYPE,
11241 PNG_DATA,
11242 PNG_FILE,
11243 PNG_ASCENT,
11244 PNG_MARGIN,
11245 PNG_RELIEF,
11246 PNG_ALGORITHM,
11247 PNG_HEURISTIC_MASK,
a05e2bae
JR
11248 PNG_MASK,
11249 PNG_BACKGROUND,
6fc2811b
JR
11250 PNG_LAST
11251};
11252
11253/* Vector of image_keyword structures describing the format
11254 of valid user-defined image specifications. */
11255
11256static struct image_keyword png_format[PNG_LAST] =
11257{
11258 {":type", IMAGE_SYMBOL_VALUE, 1},
11259 {":data", IMAGE_STRING_VALUE, 0},
11260 {":file", IMAGE_STRING_VALUE, 0},
11261 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11262 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11263 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11264 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11265 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11266 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11267 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11268};
11269
11270/* Structure describing the image type `png'. */
11271
11272static struct image_type png_type =
11273{
11274 &Qpng,
11275 png_image_p,
11276 png_load,
11277 x_clear_image,
11278 NULL
11279};
11280
11281
11282/* Return non-zero if OBJECT is a valid PNG image specification. */
11283
11284static int
11285png_image_p (object)
11286 Lisp_Object object;
11287{
11288 struct image_keyword fmt[PNG_LAST];
11289 bcopy (png_format, fmt, sizeof fmt);
11290
11291 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11292 || (fmt[PNG_ASCENT].count
11293 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11294 return 0;
11295
11296 /* Must specify either the :data or :file keyword. */
11297 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11298}
11299
11300
11301/* Error and warning handlers installed when the PNG library
11302 is initialized. */
11303
11304static void
11305my_png_error (png_ptr, msg)
11306 png_struct *png_ptr;
11307 char *msg;
11308{
11309 xassert (png_ptr != NULL);
11310 image_error ("PNG error: %s", build_string (msg), Qnil);
11311 longjmp (png_ptr->jmpbuf, 1);
11312}
11313
11314
11315static void
11316my_png_warning (png_ptr, msg)
11317 png_struct *png_ptr;
11318 char *msg;
11319{
11320 xassert (png_ptr != NULL);
11321 image_error ("PNG warning: %s", build_string (msg), Qnil);
11322}
11323
6fc2811b
JR
11324/* Memory source for PNG decoding. */
11325
11326struct png_memory_storage
11327{
11328 unsigned char *bytes; /* The data */
11329 size_t len; /* How big is it? */
11330 int index; /* Where are we? */
11331};
11332
11333
11334/* Function set as reader function when reading PNG image from memory.
11335 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11336 bytes from the input to DATA. */
11337
11338static void
11339png_read_from_memory (png_ptr, data, length)
11340 png_structp png_ptr;
11341 png_bytep data;
11342 png_size_t length;
11343{
11344 struct png_memory_storage *tbr
11345 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11346
11347 if (length > tbr->len - tbr->index)
11348 png_error (png_ptr, "Read error");
11349
11350 bcopy (tbr->bytes + tbr->index, data, length);
11351 tbr->index = tbr->index + length;
11352}
11353
6fc2811b
JR
11354/* Load PNG image IMG for use on frame F. Value is non-zero if
11355 successful. */
11356
11357static int
11358png_load (f, img)
11359 struct frame *f;
11360 struct image *img;
11361{
11362 Lisp_Object file, specified_file;
11363 Lisp_Object specified_data;
11364 int x, y, i;
11365 XImage *ximg, *mask_img = NULL;
11366 struct gcpro gcpro1;
11367 png_struct *png_ptr = NULL;
11368 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11369 FILE *volatile fp = NULL;
6fc2811b 11370 png_byte sig[8];
a05e2bae
JR
11371 png_byte *volatile pixels = NULL;
11372 png_byte **volatile rows = NULL;
6fc2811b
JR
11373 png_uint_32 width, height;
11374 int bit_depth, color_type, interlace_type;
11375 png_byte channels;
11376 png_uint_32 row_bytes;
11377 int transparent_p;
11378 char *gamma_str;
11379 double screen_gamma, image_gamma;
11380 int intent;
11381 struct png_memory_storage tbr; /* Data to be read */
11382
11383 /* Find out what file to load. */
11384 specified_file = image_spec_value (img->spec, QCfile, NULL);
11385 specified_data = image_spec_value (img->spec, QCdata, NULL);
11386 file = Qnil;
11387 GCPRO1 (file);
11388
11389 if (NILP (specified_data))
11390 {
11391 file = x_find_image_file (specified_file);
11392 if (!STRINGP (file))
11393 {
11394 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11395 UNGCPRO;
11396 return 0;
11397 }
11398
11399 /* Open the image file. */
11400 fp = fopen (XSTRING (file)->data, "rb");
11401 if (!fp)
11402 {
11403 image_error ("Cannot open image file `%s'", file, Qnil);
11404 UNGCPRO;
11405 fclose (fp);
11406 return 0;
11407 }
11408
11409 /* Check PNG signature. */
11410 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11411 || !png_check_sig (sig, sizeof sig))
11412 {
11413 image_error ("Not a PNG file:` %s'", file, Qnil);
11414 UNGCPRO;
11415 fclose (fp);
11416 return 0;
11417 }
11418 }
11419 else
11420 {
11421 /* Read from memory. */
11422 tbr.bytes = XSTRING (specified_data)->data;
11423 tbr.len = STRING_BYTES (XSTRING (specified_data));
11424 tbr.index = 0;
11425
11426 /* Check PNG signature. */
11427 if (tbr.len < sizeof sig
11428 || !png_check_sig (tbr.bytes, sizeof sig))
11429 {
11430 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11431 UNGCPRO;
11432 return 0;
11433 }
11434
11435 /* Need to skip past the signature. */
11436 tbr.bytes += sizeof (sig);
11437 }
11438
6fc2811b
JR
11439 /* Initialize read and info structs for PNG lib. */
11440 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11441 my_png_error, my_png_warning);
11442 if (!png_ptr)
11443 {
11444 if (fp) fclose (fp);
11445 UNGCPRO;
11446 return 0;
11447 }
11448
11449 info_ptr = png_create_info_struct (png_ptr);
11450 if (!info_ptr)
11451 {
11452 png_destroy_read_struct (&png_ptr, NULL, NULL);
11453 if (fp) fclose (fp);
11454 UNGCPRO;
11455 return 0;
11456 }
11457
11458 end_info = png_create_info_struct (png_ptr);
11459 if (!end_info)
11460 {
11461 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11462 if (fp) fclose (fp);
11463 UNGCPRO;
11464 return 0;
11465 }
11466
11467 /* Set error jump-back. We come back here when the PNG library
11468 detects an error. */
11469 if (setjmp (png_ptr->jmpbuf))
11470 {
11471 error:
11472 if (png_ptr)
11473 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11474 xfree (pixels);
11475 xfree (rows);
11476 if (fp) fclose (fp);
11477 UNGCPRO;
11478 return 0;
11479 }
11480
11481 /* Read image info. */
11482 if (!NILP (specified_data))
11483 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11484 else
11485 png_init_io (png_ptr, fp);
11486
11487 png_set_sig_bytes (png_ptr, sizeof sig);
11488 png_read_info (png_ptr, info_ptr);
11489 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11490 &interlace_type, NULL, NULL);
11491
11492 /* If image contains simply transparency data, we prefer to
11493 construct a clipping mask. */
11494 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11495 transparent_p = 1;
11496 else
11497 transparent_p = 0;
11498
11499 /* This function is easier to write if we only have to handle
11500 one data format: RGB or RGBA with 8 bits per channel. Let's
11501 transform other formats into that format. */
11502
11503 /* Strip more than 8 bits per channel. */
11504 if (bit_depth == 16)
11505 png_set_strip_16 (png_ptr);
11506
11507 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11508 if available. */
11509 png_set_expand (png_ptr);
11510
11511 /* Convert grayscale images to RGB. */
11512 if (color_type == PNG_COLOR_TYPE_GRAY
11513 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11514 png_set_gray_to_rgb (png_ptr);
11515
11516 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11517 gamma_str = getenv ("SCREEN_GAMMA");
11518 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11519
11520 /* Tell the PNG lib to handle gamma correction for us. */
11521
11522#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11523 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11524 /* There is a special chunk in the image specifying the gamma. */
11525 png_set_sRGB (png_ptr, info_ptr, intent);
11526 else
11527#endif
11528 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11529 /* Image contains gamma information. */
11530 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11531 else
11532 /* Use a default of 0.5 for the image gamma. */
11533 png_set_gamma (png_ptr, screen_gamma, 0.5);
11534
11535 /* Handle alpha channel by combining the image with a background
11536 color. Do this only if a real alpha channel is supplied. For
11537 simple transparency, we prefer a clipping mask. */
11538 if (!transparent_p)
11539 {
11540 png_color_16 *image_background;
a05e2bae
JR
11541 Lisp_Object specified_bg
11542 = image_spec_value (img->spec, QCbackground, NULL);
11543
11544
11545 if (STRINGP (specified_bg))
11546 /* The user specified `:background', use that. */
11547 {
11548 COLORREF color;
11549 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11550 {
11551 png_color_16 user_bg;
11552
11553 bzero (&user_bg, sizeof user_bg);
11554 user_bg.red = color.red;
11555 user_bg.green = color.green;
11556 user_bg.blue = color.blue;
6fc2811b 11557
a05e2bae
JR
11558 png_set_background (png_ptr, &user_bg,
11559 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11560 }
11561 }
11562 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11563 /* Image contains a background color with which to
11564 combine the image. */
11565 png_set_background (png_ptr, image_background,
11566 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11567 else
11568 {
11569 /* Image does not contain a background color with which
11570 to combine the image data via an alpha channel. Use
11571 the frame's background instead. */
11572 XColor color;
11573 Colormap cmap;
11574 png_color_16 frame_background;
11575
a05e2bae 11576 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11577 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11578 x_query_color (f, &color);
6fc2811b
JR
11579
11580 bzero (&frame_background, sizeof frame_background);
11581 frame_background.red = color.red;
11582 frame_background.green = color.green;
11583 frame_background.blue = color.blue;
11584
11585 png_set_background (png_ptr, &frame_background,
11586 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11587 }
11588 }
11589
11590 /* Update info structure. */
11591 png_read_update_info (png_ptr, info_ptr);
11592
11593 /* Get number of channels. Valid values are 1 for grayscale images
11594 and images with a palette, 2 for grayscale images with transparency
11595 information (alpha channel), 3 for RGB images, and 4 for RGB
11596 images with alpha channel, i.e. RGBA. If conversions above were
11597 sufficient we should only have 3 or 4 channels here. */
11598 channels = png_get_channels (png_ptr, info_ptr);
11599 xassert (channels == 3 || channels == 4);
11600
11601 /* Number of bytes needed for one row of the image. */
11602 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11603
11604 /* Allocate memory for the image. */
11605 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11606 rows = (png_byte **) xmalloc (height * sizeof *rows);
11607 for (i = 0; i < height; ++i)
11608 rows[i] = pixels + i * row_bytes;
11609
11610 /* Read the entire image. */
11611 png_read_image (png_ptr, rows);
11612 png_read_end (png_ptr, info_ptr);
11613 if (fp)
11614 {
11615 fclose (fp);
11616 fp = NULL;
11617 }
11618
6fc2811b
JR
11619 /* Create the X image and pixmap. */
11620 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11621 &img->pixmap))
a05e2bae 11622 goto error;
6fc2811b
JR
11623
11624 /* Create an image and pixmap serving as mask if the PNG image
11625 contains an alpha channel. */
11626 if (channels == 4
11627 && !transparent_p
11628 && !x_create_x_image_and_pixmap (f, width, height, 1,
11629 &mask_img, &img->mask))
11630 {
11631 x_destroy_x_image (ximg);
11632 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11633 img->pixmap = 0;
6fc2811b
JR
11634 goto error;
11635 }
11636
11637 /* Fill the X image and mask from PNG data. */
11638 init_color_table ();
11639
11640 for (y = 0; y < height; ++y)
11641 {
11642 png_byte *p = rows[y];
11643
11644 for (x = 0; x < width; ++x)
11645 {
11646 unsigned r, g, b;
11647
11648 r = *p++ << 8;
11649 g = *p++ << 8;
11650 b = *p++ << 8;
11651 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11652
11653 /* An alpha channel, aka mask channel, associates variable
11654 transparency with an image. Where other image formats
11655 support binary transparency---fully transparent or fully
11656 opaque---PNG allows up to 254 levels of partial transparency.
11657 The PNG library implements partial transparency by combining
11658 the image with a specified background color.
11659
11660 I'm not sure how to handle this here nicely: because the
11661 background on which the image is displayed may change, for
11662 real alpha channel support, it would be necessary to create
11663 a new image for each possible background.
11664
11665 What I'm doing now is that a mask is created if we have
11666 boolean transparency information. Otherwise I'm using
11667 the frame's background color to combine the image with. */
11668
11669 if (channels == 4)
11670 {
11671 if (mask_img)
11672 XPutPixel (mask_img, x, y, *p > 0);
11673 ++p;
11674 }
11675 }
11676 }
11677
a05e2bae
JR
11678 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11679 /* Set IMG's background color from the PNG image, unless the user
11680 overrode it. */
11681 {
11682 png_color_16 *bg;
11683 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11684 {
11685 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11686 img->background_valid = 1;
11687 }
11688 }
11689
6fc2811b
JR
11690 /* Remember colors allocated for this image. */
11691 img->colors = colors_in_color_table (&img->ncolors);
11692 free_color_table ();
11693
11694 /* Clean up. */
11695 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11696 xfree (rows);
11697 xfree (pixels);
11698
11699 img->width = width;
11700 img->height = height;
11701
a05e2bae
JR
11702 /* Maybe fill in the background field while we have ximg handy. */
11703 IMAGE_BACKGROUND (img, f, ximg);
11704
6fc2811b
JR
11705 /* Put the image into the pixmap, then free the X image and its buffer. */
11706 x_put_x_image (f, ximg, img->pixmap, width, height);
11707 x_destroy_x_image (ximg);
11708
11709 /* Same for the mask. */
11710 if (mask_img)
11711 {
a05e2bae
JR
11712 /* Fill in the background_transparent field while we have the mask
11713 handy. */
11714 image_background_transparent (img, f, mask_img);
11715
6fc2811b
JR
11716 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11717 x_destroy_x_image (mask_img);
11718 }
11719
6fc2811b
JR
11720 UNGCPRO;
11721 return 1;
11722}
11723
11724#endif /* HAVE_PNG != 0 */
11725
11726
11727\f
11728/***********************************************************************
11729 JPEG
11730 ***********************************************************************/
11731
11732#if HAVE_JPEG
11733
11734/* Work around a warning about HAVE_STDLIB_H being redefined in
11735 jconfig.h. */
11736#ifdef HAVE_STDLIB_H
11737#define HAVE_STDLIB_H_1
11738#undef HAVE_STDLIB_H
11739#endif /* HAVE_STLIB_H */
11740
11741#include <jpeglib.h>
11742#include <jerror.h>
11743#include <setjmp.h>
11744
11745#ifdef HAVE_STLIB_H_1
11746#define HAVE_STDLIB_H 1
11747#endif
11748
11749static int jpeg_image_p P_ ((Lisp_Object object));
11750static int jpeg_load P_ ((struct frame *f, struct image *img));
11751
11752/* The symbol `jpeg' identifying images of this type. */
11753
11754Lisp_Object Qjpeg;
11755
11756/* Indices of image specification fields in gs_format, below. */
11757
11758enum jpeg_keyword_index
11759{
11760 JPEG_TYPE,
11761 JPEG_DATA,
11762 JPEG_FILE,
11763 JPEG_ASCENT,
11764 JPEG_MARGIN,
11765 JPEG_RELIEF,
11766 JPEG_ALGORITHM,
11767 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11768 JPEG_MASK,
11769 JPEG_BACKGROUND,
6fc2811b
JR
11770 JPEG_LAST
11771};
11772
11773/* Vector of image_keyword structures describing the format
11774 of valid user-defined image specifications. */
11775
11776static struct image_keyword jpeg_format[JPEG_LAST] =
11777{
11778 {":type", IMAGE_SYMBOL_VALUE, 1},
11779 {":data", IMAGE_STRING_VALUE, 0},
11780 {":file", IMAGE_STRING_VALUE, 0},
11781 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11782 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11783 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11784 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11785 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11786 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11787 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11788};
11789
11790/* Structure describing the image type `jpeg'. */
11791
11792static struct image_type jpeg_type =
11793{
11794 &Qjpeg,
11795 jpeg_image_p,
11796 jpeg_load,
11797 x_clear_image,
11798 NULL
11799};
11800
11801
11802/* Return non-zero if OBJECT is a valid JPEG image specification. */
11803
11804static int
11805jpeg_image_p (object)
11806 Lisp_Object object;
11807{
11808 struct image_keyword fmt[JPEG_LAST];
11809
11810 bcopy (jpeg_format, fmt, sizeof fmt);
11811
11812 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11813 || (fmt[JPEG_ASCENT].count
11814 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11815 return 0;
11816
11817 /* Must specify either the :data or :file keyword. */
11818 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11819}
11820
11821
11822struct my_jpeg_error_mgr
11823{
11824 struct jpeg_error_mgr pub;
11825 jmp_buf setjmp_buffer;
11826};
11827
11828static void
11829my_error_exit (cinfo)
11830 j_common_ptr cinfo;
11831{
11832 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11833 longjmp (mgr->setjmp_buffer, 1);
11834}
11835
6fc2811b
JR
11836/* Init source method for JPEG data source manager. Called by
11837 jpeg_read_header() before any data is actually read. See
11838 libjpeg.doc from the JPEG lib distribution. */
11839
11840static void
11841our_init_source (cinfo)
11842 j_decompress_ptr cinfo;
11843{
11844}
11845
11846
11847/* Fill input buffer method for JPEG data source manager. Called
11848 whenever more data is needed. We read the whole image in one step,
11849 so this only adds a fake end of input marker at the end. */
11850
11851static boolean
11852our_fill_input_buffer (cinfo)
11853 j_decompress_ptr cinfo;
11854{
11855 /* Insert a fake EOI marker. */
11856 struct jpeg_source_mgr *src = cinfo->src;
11857 static JOCTET buffer[2];
11858
11859 buffer[0] = (JOCTET) 0xFF;
11860 buffer[1] = (JOCTET) JPEG_EOI;
11861
11862 src->next_input_byte = buffer;
11863 src->bytes_in_buffer = 2;
11864 return TRUE;
11865}
11866
11867
11868/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11869 is the JPEG data source manager. */
11870
11871static void
11872our_skip_input_data (cinfo, num_bytes)
11873 j_decompress_ptr cinfo;
11874 long num_bytes;
11875{
11876 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11877
11878 if (src)
11879 {
11880 if (num_bytes > src->bytes_in_buffer)
11881 ERREXIT (cinfo, JERR_INPUT_EOF);
11882
11883 src->bytes_in_buffer -= num_bytes;
11884 src->next_input_byte += num_bytes;
11885 }
11886}
11887
11888
11889/* Method to terminate data source. Called by
11890 jpeg_finish_decompress() after all data has been processed. */
11891
11892static void
11893our_term_source (cinfo)
11894 j_decompress_ptr cinfo;
11895{
11896}
11897
11898
11899/* Set up the JPEG lib for reading an image from DATA which contains
11900 LEN bytes. CINFO is the decompression info structure created for
11901 reading the image. */
11902
11903static void
11904jpeg_memory_src (cinfo, data, len)
11905 j_decompress_ptr cinfo;
11906 JOCTET *data;
11907 unsigned int len;
11908{
11909 struct jpeg_source_mgr *src;
11910
11911 if (cinfo->src == NULL)
11912 {
11913 /* First time for this JPEG object? */
11914 cinfo->src = (struct jpeg_source_mgr *)
11915 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11916 sizeof (struct jpeg_source_mgr));
11917 src = (struct jpeg_source_mgr *) cinfo->src;
11918 src->next_input_byte = data;
11919 }
11920
11921 src = (struct jpeg_source_mgr *) cinfo->src;
11922 src->init_source = our_init_source;
11923 src->fill_input_buffer = our_fill_input_buffer;
11924 src->skip_input_data = our_skip_input_data;
11925 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
11926 src->term_source = our_term_source;
11927 src->bytes_in_buffer = len;
11928 src->next_input_byte = data;
11929}
11930
11931
11932/* Load image IMG for use on frame F. Patterned after example.c
11933 from the JPEG lib. */
11934
11935static int
11936jpeg_load (f, img)
11937 struct frame *f;
11938 struct image *img;
11939{
11940 struct jpeg_decompress_struct cinfo;
11941 struct my_jpeg_error_mgr mgr;
11942 Lisp_Object file, specified_file;
11943 Lisp_Object specified_data;
a05e2bae 11944 FILE * volatile fp = NULL;
6fc2811b
JR
11945 JSAMPARRAY buffer;
11946 int row_stride, x, y;
11947 XImage *ximg = NULL;
11948 int rc;
11949 unsigned long *colors;
11950 int width, height;
11951 struct gcpro gcpro1;
11952
11953 /* Open the JPEG file. */
11954 specified_file = image_spec_value (img->spec, QCfile, NULL);
11955 specified_data = image_spec_value (img->spec, QCdata, NULL);
11956 file = Qnil;
11957 GCPRO1 (file);
11958
6fc2811b
JR
11959 if (NILP (specified_data))
11960 {
11961 file = x_find_image_file (specified_file);
11962 if (!STRINGP (file))
11963 {
11964 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11965 UNGCPRO;
11966 return 0;
11967 }
11968
11969 fp = fopen (XSTRING (file)->data, "r");
11970 if (fp == NULL)
11971 {
11972 image_error ("Cannot open `%s'", file, Qnil);
11973 UNGCPRO;
11974 return 0;
11975 }
11976 }
11977
11978 /* Customize libjpeg's error handling to call my_error_exit when an
11979 error is detected. This function will perform a longjmp. */
6fc2811b 11980 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 11981 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
11982
11983 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
11984 {
11985 if (rc == 1)
11986 {
11987 /* Called from my_error_exit. Display a JPEG error. */
11988 char buffer[JMSG_LENGTH_MAX];
11989 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11990 image_error ("Error reading JPEG image `%s': %s", img->spec,
11991 build_string (buffer));
11992 }
11993
11994 /* Close the input file and destroy the JPEG object. */
11995 if (fp)
11996 fclose (fp);
11997 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
11998
11999 /* If we already have an XImage, free that. */
12000 x_destroy_x_image (ximg);
12001
12002 /* Free pixmap and colors. */
12003 x_clear_image (f, img);
12004
6fc2811b
JR
12005 UNGCPRO;
12006 return 0;
12007 }
12008
12009 /* Create the JPEG decompression object. Let it read from fp.
12010 Read the JPEG image header. */
12011 jpeg_create_decompress (&cinfo);
12012
12013 if (NILP (specified_data))
12014 jpeg_stdio_src (&cinfo, fp);
12015 else
12016 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12017 STRING_BYTES (XSTRING (specified_data)));
12018
12019 jpeg_read_header (&cinfo, TRUE);
12020
12021 /* Customize decompression so that color quantization will be used.
12022 Start decompression. */
12023 cinfo.quantize_colors = TRUE;
12024 jpeg_start_decompress (&cinfo);
12025 width = img->width = cinfo.output_width;
12026 height = img->height = cinfo.output_height;
12027
6fc2811b
JR
12028 /* Create X image and pixmap. */
12029 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12030 &img->pixmap))
a05e2bae 12031 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
12032
12033 /* Allocate colors. When color quantization is used,
12034 cinfo.actual_number_of_colors has been set with the number of
12035 colors generated, and cinfo.colormap is a two-dimensional array
12036 of color indices in the range 0..cinfo.actual_number_of_colors.
12037 No more than 255 colors will be generated. */
12038 {
12039 int i, ir, ig, ib;
12040
12041 if (cinfo.out_color_components > 2)
12042 ir = 0, ig = 1, ib = 2;
12043 else if (cinfo.out_color_components > 1)
12044 ir = 0, ig = 1, ib = 0;
12045 else
12046 ir = 0, ig = 0, ib = 0;
12047
12048 /* Use the color table mechanism because it handles colors that
12049 cannot be allocated nicely. Such colors will be replaced with
12050 a default color, and we don't have to care about which colors
12051 can be freed safely, and which can't. */
12052 init_color_table ();
12053 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12054 * sizeof *colors);
12055
12056 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12057 {
12058 /* Multiply RGB values with 255 because X expects RGB values
12059 in the range 0..0xffff. */
12060 int r = cinfo.colormap[ir][i] << 8;
12061 int g = cinfo.colormap[ig][i] << 8;
12062 int b = cinfo.colormap[ib][i] << 8;
12063 colors[i] = lookup_rgb_color (f, r, g, b);
12064 }
12065
12066 /* Remember those colors actually allocated. */
12067 img->colors = colors_in_color_table (&img->ncolors);
12068 free_color_table ();
12069 }
12070
12071 /* Read pixels. */
12072 row_stride = width * cinfo.output_components;
12073 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12074 row_stride, 1);
12075 for (y = 0; y < height; ++y)
12076 {
12077 jpeg_read_scanlines (&cinfo, buffer, 1);
12078 for (x = 0; x < cinfo.output_width; ++x)
12079 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12080 }
12081
12082 /* Clean up. */
12083 jpeg_finish_decompress (&cinfo);
12084 jpeg_destroy_decompress (&cinfo);
12085 if (fp)
12086 fclose (fp);
12087
a05e2bae
JR
12088 /* Maybe fill in the background field while we have ximg handy. */
12089 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12090 IMAGE_BACKGROUND (img, f, ximg);
12091
6fc2811b
JR
12092 /* Put the image into the pixmap. */
12093 x_put_x_image (f, ximg, img->pixmap, width, height);
12094 x_destroy_x_image (ximg);
12095 UNBLOCK_INPUT;
12096 UNGCPRO;
12097 return 1;
12098}
12099
12100#endif /* HAVE_JPEG */
12101
12102
12103\f
12104/***********************************************************************
12105 TIFF
12106 ***********************************************************************/
12107
12108#if HAVE_TIFF
12109
12110#include <tiffio.h>
12111
12112static int tiff_image_p P_ ((Lisp_Object object));
12113static int tiff_load P_ ((struct frame *f, struct image *img));
12114
12115/* The symbol `tiff' identifying images of this type. */
12116
12117Lisp_Object Qtiff;
12118
12119/* Indices of image specification fields in tiff_format, below. */
12120
12121enum tiff_keyword_index
12122{
12123 TIFF_TYPE,
12124 TIFF_DATA,
12125 TIFF_FILE,
12126 TIFF_ASCENT,
12127 TIFF_MARGIN,
12128 TIFF_RELIEF,
12129 TIFF_ALGORITHM,
12130 TIFF_HEURISTIC_MASK,
a05e2bae
JR
12131 TIFF_MASK,
12132 TIFF_BACKGROUND,
6fc2811b
JR
12133 TIFF_LAST
12134};
12135
12136/* Vector of image_keyword structures describing the format
12137 of valid user-defined image specifications. */
12138
12139static struct image_keyword tiff_format[TIFF_LAST] =
12140{
12141 {":type", IMAGE_SYMBOL_VALUE, 1},
12142 {":data", IMAGE_STRING_VALUE, 0},
12143 {":file", IMAGE_STRING_VALUE, 0},
12144 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12145 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12146 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12147 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12148 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12149 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12150 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12151};
12152
12153/* Structure describing the image type `tiff'. */
12154
12155static struct image_type tiff_type =
12156{
12157 &Qtiff,
12158 tiff_image_p,
12159 tiff_load,
12160 x_clear_image,
12161 NULL
12162};
12163
12164
12165/* Return non-zero if OBJECT is a valid TIFF image specification. */
12166
12167static int
12168tiff_image_p (object)
12169 Lisp_Object object;
12170{
12171 struct image_keyword fmt[TIFF_LAST];
12172 bcopy (tiff_format, fmt, sizeof fmt);
12173
12174 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12175 || (fmt[TIFF_ASCENT].count
12176 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12177 return 0;
12178
12179 /* Must specify either the :data or :file keyword. */
12180 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12181}
12182
12183
12184/* Reading from a memory buffer for TIFF images Based on the PNG
12185 memory source, but we have to provide a lot of extra functions.
12186 Blah.
12187
12188 We really only need to implement read and seek, but I am not
12189 convinced that the TIFF library is smart enough not to destroy
12190 itself if we only hand it the function pointers we need to
12191 override. */
12192
12193typedef struct
12194{
12195 unsigned char *bytes;
12196 size_t len;
12197 int index;
12198}
12199tiff_memory_source;
12200
12201static size_t
12202tiff_read_from_memory (data, buf, size)
12203 thandle_t data;
12204 tdata_t buf;
12205 tsize_t size;
12206{
12207 tiff_memory_source *src = (tiff_memory_source *) data;
12208
12209 if (size > src->len - src->index)
12210 return (size_t) -1;
12211 bcopy (src->bytes + src->index, buf, size);
12212 src->index += size;
12213 return size;
12214}
12215
12216static size_t
12217tiff_write_from_memory (data, buf, size)
12218 thandle_t data;
12219 tdata_t buf;
12220 tsize_t size;
12221{
12222 return (size_t) -1;
12223}
12224
12225static toff_t
12226tiff_seek_in_memory (data, off, whence)
12227 thandle_t data;
12228 toff_t off;
12229 int whence;
12230{
12231 tiff_memory_source *src = (tiff_memory_source *) data;
12232 int idx;
12233
12234 switch (whence)
12235 {
12236 case SEEK_SET: /* Go from beginning of source. */
12237 idx = off;
12238 break;
12239
12240 case SEEK_END: /* Go from end of source. */
12241 idx = src->len + off;
12242 break;
12243
12244 case SEEK_CUR: /* Go from current position. */
12245 idx = src->index + off;
12246 break;
12247
12248 default: /* Invalid `whence'. */
12249 return -1;
12250 }
12251
12252 if (idx > src->len || idx < 0)
12253 return -1;
12254
12255 src->index = idx;
12256 return src->index;
12257}
12258
12259static int
12260tiff_close_memory (data)
12261 thandle_t data;
12262{
12263 /* NOOP */
12264 return 0;
12265}
12266
12267static int
12268tiff_mmap_memory (data, pbase, psize)
12269 thandle_t data;
12270 tdata_t *pbase;
12271 toff_t *psize;
12272{
12273 /* It is already _IN_ memory. */
12274 return 0;
12275}
12276
12277static void
12278tiff_unmap_memory (data, base, size)
12279 thandle_t data;
12280 tdata_t base;
12281 toff_t size;
12282{
12283 /* We don't need to do this. */
12284}
12285
12286static toff_t
12287tiff_size_of_memory (data)
12288 thandle_t data;
12289{
12290 return ((tiff_memory_source *) data)->len;
12291}
12292
3cf3436e
JR
12293
12294static void
12295tiff_error_handler (title, format, ap)
12296 const char *title, *format;
12297 va_list ap;
12298{
12299 char buf[512];
12300 int len;
12301
12302 len = sprintf (buf, "TIFF error: %s ", title);
12303 vsprintf (buf + len, format, ap);
12304 add_to_log (buf, Qnil, Qnil);
12305}
12306
12307
12308static void
12309tiff_warning_handler (title, format, ap)
12310 const char *title, *format;
12311 va_list ap;
12312{
12313 char buf[512];
12314 int len;
12315
12316 len = sprintf (buf, "TIFF warning: %s ", title);
12317 vsprintf (buf + len, format, ap);
12318 add_to_log (buf, Qnil, Qnil);
12319}
12320
12321
6fc2811b
JR
12322/* Load TIFF image IMG for use on frame F. Value is non-zero if
12323 successful. */
12324
12325static int
12326tiff_load (f, img)
12327 struct frame *f;
12328 struct image *img;
12329{
12330 Lisp_Object file, specified_file;
12331 Lisp_Object specified_data;
12332 TIFF *tiff;
12333 int width, height, x, y;
12334 uint32 *buf;
12335 int rc;
12336 XImage *ximg;
12337 struct gcpro gcpro1;
12338 tiff_memory_source memsrc;
12339
12340 specified_file = image_spec_value (img->spec, QCfile, NULL);
12341 specified_data = image_spec_value (img->spec, QCdata, NULL);
12342 file = Qnil;
12343 GCPRO1 (file);
12344
3cf3436e
JR
12345 TIFFSetErrorHandler (tiff_error_handler);
12346 TIFFSetWarningHandler (tiff_warning_handler);
12347
6fc2811b
JR
12348 if (NILP (specified_data))
12349 {
12350 /* Read from a file */
12351 file = x_find_image_file (specified_file);
12352 if (!STRINGP (file))
3cf3436e
JR
12353 {
12354 image_error ("Cannot find image file `%s'", file, Qnil);
12355 UNGCPRO;
12356 return 0;
12357 }
12358
6fc2811b
JR
12359 /* Try to open the image file. */
12360 tiff = TIFFOpen (XSTRING (file)->data, "r");
12361 if (tiff == NULL)
3cf3436e
JR
12362 {
12363 image_error ("Cannot open `%s'", file, Qnil);
12364 UNGCPRO;
12365 return 0;
12366 }
6fc2811b
JR
12367 }
12368 else
12369 {
12370 /* Memory source! */
12371 memsrc.bytes = XSTRING (specified_data)->data;
12372 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12373 memsrc.index = 0;
12374
12375 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12376 (TIFFReadWriteProc) tiff_read_from_memory,
12377 (TIFFReadWriteProc) tiff_write_from_memory,
12378 tiff_seek_in_memory,
12379 tiff_close_memory,
12380 tiff_size_of_memory,
12381 tiff_mmap_memory,
12382 tiff_unmap_memory);
12383
12384 if (!tiff)
12385 {
12386 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12387 UNGCPRO;
12388 return 0;
12389 }
12390 }
12391
12392 /* Get width and height of the image, and allocate a raster buffer
12393 of width x height 32-bit values. */
12394 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12395 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12396 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12397
12398 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12399 TIFFClose (tiff);
12400 if (!rc)
12401 {
12402 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12403 xfree (buf);
12404 UNGCPRO;
12405 return 0;
12406 }
12407
6fc2811b
JR
12408 /* Create the X image and pixmap. */
12409 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12410 {
6fc2811b
JR
12411 xfree (buf);
12412 UNGCPRO;
12413 return 0;
12414 }
12415
12416 /* Initialize the color table. */
12417 init_color_table ();
12418
12419 /* Process the pixel raster. Origin is in the lower-left corner. */
12420 for (y = 0; y < height; ++y)
12421 {
12422 uint32 *row = buf + y * width;
12423
12424 for (x = 0; x < width; ++x)
12425 {
12426 uint32 abgr = row[x];
12427 int r = TIFFGetR (abgr) << 8;
12428 int g = TIFFGetG (abgr) << 8;
12429 int b = TIFFGetB (abgr) << 8;
12430 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12431 }
12432 }
12433
12434 /* Remember the colors allocated for the image. Free the color table. */
12435 img->colors = colors_in_color_table (&img->ncolors);
12436 free_color_table ();
12437
a05e2bae
JR
12438 img->width = width;
12439 img->height = height;
12440
12441 /* Maybe fill in the background field while we have ximg handy. */
12442 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12443 IMAGE_BACKGROUND (img, f, ximg);
12444
6fc2811b
JR
12445 /* Put the image into the pixmap, then free the X image and its buffer. */
12446 x_put_x_image (f, ximg, img->pixmap, width, height);
12447 x_destroy_x_image (ximg);
12448 xfree (buf);
6fc2811b
JR
12449
12450 UNGCPRO;
12451 return 1;
12452}
12453
12454#endif /* HAVE_TIFF != 0 */
12455
12456
12457\f
12458/***********************************************************************
12459 GIF
12460 ***********************************************************************/
12461
12462#if HAVE_GIF
12463
12464#include <gif_lib.h>
12465
12466static int gif_image_p P_ ((Lisp_Object object));
12467static int gif_load P_ ((struct frame *f, struct image *img));
12468
12469/* The symbol `gif' identifying images of this type. */
12470
12471Lisp_Object Qgif;
12472
12473/* Indices of image specification fields in gif_format, below. */
12474
12475enum gif_keyword_index
12476{
12477 GIF_TYPE,
12478 GIF_DATA,
12479 GIF_FILE,
12480 GIF_ASCENT,
12481 GIF_MARGIN,
12482 GIF_RELIEF,
12483 GIF_ALGORITHM,
12484 GIF_HEURISTIC_MASK,
a05e2bae 12485 GIF_MASK,
6fc2811b 12486 GIF_IMAGE,
a05e2bae 12487 GIF_BACKGROUND,
6fc2811b
JR
12488 GIF_LAST
12489};
12490
12491/* Vector of image_keyword structures describing the format
12492 of valid user-defined image specifications. */
12493
12494static struct image_keyword gif_format[GIF_LAST] =
12495{
12496 {":type", IMAGE_SYMBOL_VALUE, 1},
12497 {":data", IMAGE_STRING_VALUE, 0},
12498 {":file", IMAGE_STRING_VALUE, 0},
12499 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12500 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12501 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12502 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12503 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12504 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12505 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12506 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12507};
12508
12509/* Structure describing the image type `gif'. */
12510
12511static struct image_type gif_type =
12512{
12513 &Qgif,
12514 gif_image_p,
12515 gif_load,
12516 x_clear_image,
12517 NULL
12518};
12519
12520/* Return non-zero if OBJECT is a valid GIF image specification. */
12521
12522static int
12523gif_image_p (object)
12524 Lisp_Object object;
12525{
12526 struct image_keyword fmt[GIF_LAST];
12527 bcopy (gif_format, fmt, sizeof fmt);
12528
12529 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12530 || (fmt[GIF_ASCENT].count
12531 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12532 return 0;
12533
12534 /* Must specify either the :data or :file keyword. */
12535 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12536}
12537
12538/* Reading a GIF image from memory
12539 Based on the PNG memory stuff to a certain extent. */
12540
12541typedef struct
12542{
12543 unsigned char *bytes;
12544 size_t len;
12545 int index;
12546}
12547gif_memory_source;
12548
12549/* Make the current memory source available to gif_read_from_memory.
12550 It's done this way because not all versions of libungif support
12551 a UserData field in the GifFileType structure. */
12552static gif_memory_source *current_gif_memory_src;
12553
12554static int
12555gif_read_from_memory (file, buf, len)
12556 GifFileType *file;
12557 GifByteType *buf;
12558 int len;
12559{
12560 gif_memory_source *src = current_gif_memory_src;
12561
12562 if (len > src->len - src->index)
12563 return -1;
12564
12565 bcopy (src->bytes + src->index, buf, len);
12566 src->index += len;
12567 return len;
12568}
12569
12570
12571/* Load GIF image IMG for use on frame F. Value is non-zero if
12572 successful. */
12573
12574static int
12575gif_load (f, img)
12576 struct frame *f;
12577 struct image *img;
12578{
12579 Lisp_Object file, specified_file;
12580 Lisp_Object specified_data;
12581 int rc, width, height, x, y, i;
12582 XImage *ximg;
12583 ColorMapObject *gif_color_map;
12584 unsigned long pixel_colors[256];
12585 GifFileType *gif;
12586 struct gcpro gcpro1;
12587 Lisp_Object image;
12588 int ino, image_left, image_top, image_width, image_height;
12589 gif_memory_source memsrc;
12590 unsigned char *raster;
12591
12592 specified_file = image_spec_value (img->spec, QCfile, NULL);
12593 specified_data = image_spec_value (img->spec, QCdata, NULL);
12594 file = Qnil;
dfff8a69 12595 GCPRO1 (file);
6fc2811b
JR
12596
12597 if (NILP (specified_data))
12598 {
12599 file = x_find_image_file (specified_file);
6fc2811b
JR
12600 if (!STRINGP (file))
12601 {
12602 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12603 UNGCPRO;
12604 return 0;
12605 }
12606
12607 /* Open the GIF file. */
12608 gif = DGifOpenFileName (XSTRING (file)->data);
12609 if (gif == NULL)
12610 {
12611 image_error ("Cannot open `%s'", file, Qnil);
12612 UNGCPRO;
12613 return 0;
12614 }
12615 }
12616 else
12617 {
12618 /* Read from memory! */
12619 current_gif_memory_src = &memsrc;
12620 memsrc.bytes = XSTRING (specified_data)->data;
12621 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12622 memsrc.index = 0;
12623
12624 gif = DGifOpen(&memsrc, gif_read_from_memory);
12625 if (!gif)
12626 {
12627 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12628 UNGCPRO;
12629 return 0;
12630 }
12631 }
12632
12633 /* Read entire contents. */
12634 rc = DGifSlurp (gif);
12635 if (rc == GIF_ERROR)
12636 {
12637 image_error ("Error reading `%s'", img->spec, Qnil);
12638 DGifCloseFile (gif);
12639 UNGCPRO;
12640 return 0;
12641 }
12642
12643 image = image_spec_value (img->spec, QCindex, NULL);
12644 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12645 if (ino >= gif->ImageCount)
12646 {
12647 image_error ("Invalid image number `%s' in image `%s'",
12648 image, img->spec);
12649 DGifCloseFile (gif);
12650 UNGCPRO;
12651 return 0;
12652 }
12653
12654 width = img->width = gif->SWidth;
12655 height = img->height = gif->SHeight;
12656
6fc2811b
JR
12657 /* Create the X image and pixmap. */
12658 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12659 {
6fc2811b
JR
12660 DGifCloseFile (gif);
12661 UNGCPRO;
12662 return 0;
12663 }
12664
12665 /* Allocate colors. */
12666 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12667 if (!gif_color_map)
12668 gif_color_map = gif->SColorMap;
12669 init_color_table ();
12670 bzero (pixel_colors, sizeof pixel_colors);
12671
12672 for (i = 0; i < gif_color_map->ColorCount; ++i)
12673 {
12674 int r = gif_color_map->Colors[i].Red << 8;
12675 int g = gif_color_map->Colors[i].Green << 8;
12676 int b = gif_color_map->Colors[i].Blue << 8;
12677 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12678 }
12679
12680 img->colors = colors_in_color_table (&img->ncolors);
12681 free_color_table ();
12682
12683 /* Clear the part of the screen image that are not covered by
12684 the image from the GIF file. Full animated GIF support
12685 requires more than can be done here (see the gif89 spec,
12686 disposal methods). Let's simply assume that the part
12687 not covered by a sub-image is in the frame's background color. */
12688 image_top = gif->SavedImages[ino].ImageDesc.Top;
12689 image_left = gif->SavedImages[ino].ImageDesc.Left;
12690 image_width = gif->SavedImages[ino].ImageDesc.Width;
12691 image_height = gif->SavedImages[ino].ImageDesc.Height;
12692
12693 for (y = 0; y < image_top; ++y)
12694 for (x = 0; x < width; ++x)
12695 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12696
12697 for (y = image_top + image_height; y < height; ++y)
12698 for (x = 0; x < width; ++x)
12699 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12700
12701 for (y = image_top; y < image_top + image_height; ++y)
12702 {
12703 for (x = 0; x < image_left; ++x)
12704 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12705 for (x = image_left + image_width; x < width; ++x)
12706 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12707 }
12708
12709 /* Read the GIF image into the X image. We use a local variable
12710 `raster' here because RasterBits below is a char *, and invites
12711 problems with bytes >= 0x80. */
12712 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12713
12714 if (gif->SavedImages[ino].ImageDesc.Interlace)
12715 {
12716 static int interlace_start[] = {0, 4, 2, 1};
12717 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12718 int pass;
6fc2811b
JR
12719 int row = interlace_start[0];
12720
12721 pass = 0;
12722
12723 for (y = 0; y < image_height; y++)
12724 {
12725 if (row >= image_height)
12726 {
12727 row = interlace_start[++pass];
12728 while (row >= image_height)
12729 row = interlace_start[++pass];
12730 }
12731
12732 for (x = 0; x < image_width; x++)
12733 {
12734 int i = raster[(y * image_width) + x];
12735 XPutPixel (ximg, x + image_left, row + image_top,
12736 pixel_colors[i]);
12737 }
12738
12739 row += interlace_increment[pass];
12740 }
12741 }
12742 else
12743 {
12744 for (y = 0; y < image_height; ++y)
12745 for (x = 0; x < image_width; ++x)
12746 {
12747 int i = raster[y* image_width + x];
12748 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12749 }
12750 }
12751
12752 DGifCloseFile (gif);
a05e2bae
JR
12753
12754 /* Maybe fill in the background field while we have ximg handy. */
12755 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12756 IMAGE_BACKGROUND (img, f, ximg);
12757
6fc2811b
JR
12758 /* Put the image into the pixmap, then free the X image and its buffer. */
12759 x_put_x_image (f, ximg, img->pixmap, width, height);
12760 x_destroy_x_image (ximg);
6fc2811b
JR
12761
12762 UNGCPRO;
12763 return 1;
12764}
12765
12766#endif /* HAVE_GIF != 0 */
12767
12768
12769\f
12770/***********************************************************************
12771 Ghostscript
12772 ***********************************************************************/
12773
3cf3436e
JR
12774Lisp_Object Qpostscript;
12775
6fc2811b
JR
12776#ifdef HAVE_GHOSTSCRIPT
12777static int gs_image_p P_ ((Lisp_Object object));
12778static int gs_load P_ ((struct frame *f, struct image *img));
12779static void gs_clear_image P_ ((struct frame *f, struct image *img));
12780
12781/* The symbol `postscript' identifying images of this type. */
12782
6fc2811b
JR
12783/* Keyword symbols. */
12784
12785Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12786
12787/* Indices of image specification fields in gs_format, below. */
12788
12789enum gs_keyword_index
12790{
12791 GS_TYPE,
12792 GS_PT_WIDTH,
12793 GS_PT_HEIGHT,
12794 GS_FILE,
12795 GS_LOADER,
12796 GS_BOUNDING_BOX,
12797 GS_ASCENT,
12798 GS_MARGIN,
12799 GS_RELIEF,
12800 GS_ALGORITHM,
12801 GS_HEURISTIC_MASK,
a05e2bae
JR
12802 GS_MASK,
12803 GS_BACKGROUND,
6fc2811b
JR
12804 GS_LAST
12805};
12806
12807/* Vector of image_keyword structures describing the format
12808 of valid user-defined image specifications. */
12809
12810static struct image_keyword gs_format[GS_LAST] =
12811{
12812 {":type", IMAGE_SYMBOL_VALUE, 1},
12813 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12814 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12815 {":file", IMAGE_STRING_VALUE, 1},
12816 {":loader", IMAGE_FUNCTION_VALUE, 0},
12817 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12818 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12819 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12820 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12821 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12822 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12823 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12824 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12825};
12826
12827/* Structure describing the image type `ghostscript'. */
12828
12829static struct image_type gs_type =
12830{
12831 &Qpostscript,
12832 gs_image_p,
12833 gs_load,
12834 gs_clear_image,
12835 NULL
12836};
12837
12838
12839/* Free X resources of Ghostscript image IMG which is used on frame F. */
12840
12841static void
12842gs_clear_image (f, img)
12843 struct frame *f;
12844 struct image *img;
12845{
12846 /* IMG->data.ptr_val may contain a recorded colormap. */
12847 xfree (img->data.ptr_val);
12848 x_clear_image (f, img);
12849}
12850
12851
12852/* Return non-zero if OBJECT is a valid Ghostscript image
12853 specification. */
12854
12855static int
12856gs_image_p (object)
12857 Lisp_Object object;
12858{
12859 struct image_keyword fmt[GS_LAST];
12860 Lisp_Object tem;
12861 int i;
12862
12863 bcopy (gs_format, fmt, sizeof fmt);
12864
12865 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
12866 || (fmt[GS_ASCENT].count
12867 && XFASTINT (fmt[GS_ASCENT].value) > 100))
12868 return 0;
12869
12870 /* Bounding box must be a list or vector containing 4 integers. */
12871 tem = fmt[GS_BOUNDING_BOX].value;
12872 if (CONSP (tem))
12873 {
12874 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12875 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12876 return 0;
12877 if (!NILP (tem))
12878 return 0;
12879 }
12880 else if (VECTORP (tem))
12881 {
12882 if (XVECTOR (tem)->size != 4)
12883 return 0;
12884 for (i = 0; i < 4; ++i)
12885 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12886 return 0;
12887 }
12888 else
12889 return 0;
12890
12891 return 1;
12892}
12893
12894
12895/* Load Ghostscript image IMG for use on frame F. Value is non-zero
12896 if successful. */
12897
12898static int
12899gs_load (f, img)
12900 struct frame *f;
12901 struct image *img;
12902{
12903 char buffer[100];
12904 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12905 struct gcpro gcpro1, gcpro2;
12906 Lisp_Object frame;
12907 double in_width, in_height;
12908 Lisp_Object pixel_colors = Qnil;
12909
12910 /* Compute pixel size of pixmap needed from the given size in the
12911 image specification. Sizes in the specification are in pt. 1 pt
12912 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12913 info. */
12914 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12915 in_width = XFASTINT (pt_width) / 72.0;
12916 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12917 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12918 in_height = XFASTINT (pt_height) / 72.0;
12919 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12920
12921 /* Create the pixmap. */
12922 BLOCK_INPUT;
12923 xassert (img->pixmap == 0);
12924 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12925 img->width, img->height,
a05e2bae 12926 one_w32_display_info.n_cbits);
6fc2811b
JR
12927 UNBLOCK_INPUT;
12928
12929 if (!img->pixmap)
12930 {
12931 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12932 return 0;
12933 }
12934
12935 /* Call the loader to fill the pixmap. It returns a process object
12936 if successful. We do not record_unwind_protect here because
12937 other places in redisplay like calling window scroll functions
12938 don't either. Let the Lisp loader use `unwind-protect' instead. */
12939 GCPRO2 (window_and_pixmap_id, pixel_colors);
12940
12941 sprintf (buffer, "%lu %lu",
12942 (unsigned long) FRAME_W32_WINDOW (f),
12943 (unsigned long) img->pixmap);
12944 window_and_pixmap_id = build_string (buffer);
12945
12946 sprintf (buffer, "%lu %lu",
12947 FRAME_FOREGROUND_PIXEL (f),
12948 FRAME_BACKGROUND_PIXEL (f));
12949 pixel_colors = build_string (buffer);
12950
12951 XSETFRAME (frame, f);
12952 loader = image_spec_value (img->spec, QCloader, NULL);
12953 if (NILP (loader))
12954 loader = intern ("gs-load-image");
12955
12956 img->data.lisp_val = call6 (loader, frame, img->spec,
12957 make_number (img->width),
12958 make_number (img->height),
12959 window_and_pixmap_id,
12960 pixel_colors);
12961 UNGCPRO;
12962 return PROCESSP (img->data.lisp_val);
12963}
12964
12965
12966/* Kill the Ghostscript process that was started to fill PIXMAP on
12967 frame F. Called from XTread_socket when receiving an event
12968 telling Emacs that Ghostscript has finished drawing. */
12969
12970void
12971x_kill_gs_process (pixmap, f)
12972 Pixmap pixmap;
12973 struct frame *f;
12974{
12975 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
12976 int class, i;
12977 struct image *img;
12978
12979 /* Find the image containing PIXMAP. */
12980 for (i = 0; i < c->used; ++i)
12981 if (c->images[i]->pixmap == pixmap)
12982 break;
12983
3cf3436e
JR
12984 /* Should someone in between have cleared the image cache, for
12985 instance, give up. */
12986 if (i == c->used)
12987 return;
12988
6fc2811b
JR
12989 /* Kill the GS process. We should have found PIXMAP in the image
12990 cache and its image should contain a process object. */
6fc2811b
JR
12991 img = c->images[i];
12992 xassert (PROCESSP (img->data.lisp_val));
12993 Fkill_process (img->data.lisp_val, Qnil);
12994 img->data.lisp_val = Qnil;
12995
12996 /* On displays with a mutable colormap, figure out the colors
12997 allocated for the image by looking at the pixels of an XImage for
12998 img->pixmap. */
12999 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13000 if (class != StaticColor && class != StaticGray && class != TrueColor)
13001 {
13002 XImage *ximg;
13003
13004 BLOCK_INPUT;
13005
13006 /* Try to get an XImage for img->pixmep. */
13007 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13008 0, 0, img->width, img->height, ~0, ZPixmap);
13009 if (ximg)
13010 {
13011 int x, y;
13012
13013 /* Initialize the color table. */
13014 init_color_table ();
13015
13016 /* For each pixel of the image, look its color up in the
13017 color table. After having done so, the color table will
13018 contain an entry for each color used by the image. */
13019 for (y = 0; y < img->height; ++y)
13020 for (x = 0; x < img->width; ++x)
13021 {
13022 unsigned long pixel = XGetPixel (ximg, x, y);
13023 lookup_pixel_color (f, pixel);
13024 }
13025
13026 /* Record colors in the image. Free color table and XImage. */
13027 img->colors = colors_in_color_table (&img->ncolors);
13028 free_color_table ();
13029 XDestroyImage (ximg);
13030
13031#if 0 /* This doesn't seem to be the case. If we free the colors
13032 here, we get a BadAccess later in x_clear_image when
13033 freeing the colors. */
13034 /* We have allocated colors once, but Ghostscript has also
13035 allocated colors on behalf of us. So, to get the
13036 reference counts right, free them once. */
13037 if (img->ncolors)
3cf3436e 13038 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 13039 img->colors, img->ncolors, 0);
6fc2811b
JR
13040#endif
13041 }
13042 else
13043 image_error ("Cannot get X image of `%s'; colors will not be freed",
13044 img->spec, Qnil);
13045
13046 UNBLOCK_INPUT;
13047 }
3cf3436e
JR
13048
13049 /* Now that we have the pixmap, compute mask and transform the
13050 image if requested. */
13051 BLOCK_INPUT;
13052 postprocess_image (f, img);
13053 UNBLOCK_INPUT;
6fc2811b
JR
13054}
13055
13056#endif /* HAVE_GHOSTSCRIPT */
13057
13058\f
13059/***********************************************************************
13060 Window properties
13061 ***********************************************************************/
13062
13063DEFUN ("x-change-window-property", Fx_change_window_property,
13064 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
13065 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13066PROP and VALUE must be strings. FRAME nil or omitted means use the
13067selected frame. Value is VALUE. */)
6fc2811b
JR
13068 (prop, value, frame)
13069 Lisp_Object frame, prop, value;
13070{
767b1ff0 13071#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13072 struct frame *f = check_x_frame (frame);
13073 Atom prop_atom;
13074
b7826503
PJ
13075 CHECK_STRING (prop);
13076 CHECK_STRING (value);
6fc2811b
JR
13077
13078 BLOCK_INPUT;
13079 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13080 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13081 prop_atom, XA_STRING, 8, PropModeReplace,
13082 XSTRING (value)->data, XSTRING (value)->size);
13083
13084 /* Make sure the property is set when we return. */
13085 XFlush (FRAME_W32_DISPLAY (f));
13086 UNBLOCK_INPUT;
13087
767b1ff0 13088#endif /* TODO */
6fc2811b
JR
13089
13090 return value;
13091}
13092
13093
13094DEFUN ("x-delete-window-property", Fx_delete_window_property,
13095 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
13096 doc: /* Remove window property PROP from X window of FRAME.
13097FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
13098 (prop, frame)
13099 Lisp_Object prop, frame;
13100{
767b1ff0 13101#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13102
13103 struct frame *f = check_x_frame (frame);
13104 Atom prop_atom;
13105
b7826503 13106 CHECK_STRING (prop);
6fc2811b
JR
13107 BLOCK_INPUT;
13108 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13109 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13110
13111 /* Make sure the property is removed when we return. */
13112 XFlush (FRAME_W32_DISPLAY (f));
13113 UNBLOCK_INPUT;
767b1ff0 13114#endif /* TODO */
6fc2811b
JR
13115
13116 return prop;
13117}
13118
13119
13120DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13121 1, 2, 0,
74e1aeec
JR
13122 doc: /* Value is the value of window property PROP on FRAME.
13123If FRAME is nil or omitted, use the selected frame. Value is nil
13124if FRAME hasn't a property with name PROP or if PROP has no string
13125value. */)
6fc2811b
JR
13126 (prop, frame)
13127 Lisp_Object prop, frame;
13128{
767b1ff0 13129#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13130
13131 struct frame *f = check_x_frame (frame);
13132 Atom prop_atom;
13133 int rc;
13134 Lisp_Object prop_value = Qnil;
13135 char *tmp_data = NULL;
13136 Atom actual_type;
13137 int actual_format;
13138 unsigned long actual_size, bytes_remaining;
13139
b7826503 13140 CHECK_STRING (prop);
6fc2811b
JR
13141 BLOCK_INPUT;
13142 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13143 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13144 prop_atom, 0, 0, False, XA_STRING,
13145 &actual_type, &actual_format, &actual_size,
13146 &bytes_remaining, (unsigned char **) &tmp_data);
13147 if (rc == Success)
13148 {
13149 int size = bytes_remaining;
13150
13151 XFree (tmp_data);
13152 tmp_data = NULL;
13153
13154 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13155 prop_atom, 0, bytes_remaining,
13156 False, XA_STRING,
13157 &actual_type, &actual_format,
13158 &actual_size, &bytes_remaining,
13159 (unsigned char **) &tmp_data);
13160 if (rc == Success)
13161 prop_value = make_string (tmp_data, size);
13162
13163 XFree (tmp_data);
13164 }
13165
13166 UNBLOCK_INPUT;
13167
13168 return prop_value;
13169
767b1ff0 13170#endif /* TODO */
6fc2811b
JR
13171 return Qnil;
13172}
13173
13174
13175\f
13176/***********************************************************************
13177 Busy cursor
13178 ***********************************************************************/
13179
f79e6790 13180/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 13181 an hourglass cursor on all frames. */
6fc2811b 13182
0af913d7 13183static struct atimer *hourglass_atimer;
6fc2811b 13184
0af913d7 13185/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 13186
0af913d7 13187static int hourglass_shown_p;
6fc2811b 13188
0af913d7 13189/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 13190
0af913d7 13191static Lisp_Object Vhourglass_delay;
6fc2811b 13192
0af913d7 13193/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
13194 cursor. */
13195
0af913d7 13196#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
13197
13198/* Function prototypes. */
13199
0af913d7
GM
13200static void show_hourglass P_ ((struct atimer *));
13201static void hide_hourglass P_ ((void));
f79e6790
JR
13202
13203
0af913d7 13204/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
13205
13206void
0af913d7 13207start_hourglass ()
f79e6790 13208{
767b1ff0 13209#if 0 /* TODO: cursor shape changes. */
f79e6790 13210 EMACS_TIME delay;
dfff8a69 13211 int secs, usecs = 0;
f79e6790 13212
0af913d7 13213 cancel_hourglass ();
f79e6790 13214
0af913d7
GM
13215 if (INTEGERP (Vhourglass_delay)
13216 && XINT (Vhourglass_delay) > 0)
13217 secs = XFASTINT (Vhourglass_delay);
13218 else if (FLOATP (Vhourglass_delay)
13219 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
13220 {
13221 Lisp_Object tem;
0af913d7 13222 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 13223 secs = XFASTINT (tem);
0af913d7 13224 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 13225 }
f79e6790 13226 else
0af913d7 13227 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 13228
dfff8a69 13229 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
13230 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13231 show_hourglass, NULL);
f79e6790
JR
13232#endif
13233}
13234
13235
0af913d7
GM
13236/* Cancel the hourglass cursor timer if active, hide an hourglass
13237 cursor if shown. */
f79e6790
JR
13238
13239void
0af913d7 13240cancel_hourglass ()
f79e6790 13241{
0af913d7 13242 if (hourglass_atimer)
dfff8a69 13243 {
0af913d7
GM
13244 cancel_atimer (hourglass_atimer);
13245 hourglass_atimer = NULL;
dfff8a69
JR
13246 }
13247
0af913d7
GM
13248 if (hourglass_shown_p)
13249 hide_hourglass ();
f79e6790
JR
13250}
13251
13252
0af913d7
GM
13253/* Timer function of hourglass_atimer. TIMER is equal to
13254 hourglass_atimer.
f79e6790 13255
0af913d7
GM
13256 Display an hourglass cursor on all frames by mapping the frames'
13257 hourglass_window. Set the hourglass_p flag in the frames'
13258 output_data.x structure to indicate that an hourglass cursor is
13259 shown on the frames. */
f79e6790
JR
13260
13261static void
0af913d7 13262show_hourglass (timer)
f79e6790 13263 struct atimer *timer;
6fc2811b 13264{
767b1ff0 13265#if 0 /* TODO: cursor shape changes. */
f79e6790 13266 /* The timer implementation will cancel this timer automatically
0af913d7 13267 after this function has run. Set hourglass_atimer to null
f79e6790 13268 so that we know the timer doesn't have to be canceled. */
0af913d7 13269 hourglass_atimer = NULL;
f79e6790 13270
0af913d7 13271 if (!hourglass_shown_p)
6fc2811b
JR
13272 {
13273 Lisp_Object rest, frame;
f79e6790
JR
13274
13275 BLOCK_INPUT;
13276
6fc2811b 13277 FOR_EACH_FRAME (rest, frame)
dc220243 13278 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13279 {
13280 struct frame *f = XFRAME (frame);
f79e6790 13281
0af913d7 13282 f->output_data.w32->hourglass_p = 1;
f79e6790 13283
0af913d7 13284 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13285 {
13286 unsigned long mask = CWCursor;
13287 XSetWindowAttributes attrs;
f79e6790 13288
0af913d7 13289 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13290
0af913d7 13291 f->output_data.w32->hourglass_window
f79e6790 13292 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13293 FRAME_OUTER_WINDOW (f),
13294 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13295 InputOnly,
13296 CopyFromParent,
6fc2811b
JR
13297 mask, &attrs);
13298 }
f79e6790 13299
0af913d7
GM
13300 XMapRaised (FRAME_X_DISPLAY (f),
13301 f->output_data.w32->hourglass_window);
f79e6790 13302 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13303 }
6fc2811b 13304
0af913d7 13305 hourglass_shown_p = 1;
f79e6790
JR
13306 UNBLOCK_INPUT;
13307 }
13308#endif
6fc2811b
JR
13309}
13310
13311
0af913d7 13312/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13313
f79e6790 13314static void
0af913d7 13315hide_hourglass ()
f79e6790 13316{
767b1ff0 13317#if 0 /* TODO: cursor shape changes. */
0af913d7 13318 if (hourglass_shown_p)
6fc2811b 13319 {
f79e6790
JR
13320 Lisp_Object rest, frame;
13321
13322 BLOCK_INPUT;
13323 FOR_EACH_FRAME (rest, frame)
6fc2811b 13324 {
f79e6790
JR
13325 struct frame *f = XFRAME (frame);
13326
dc220243 13327 if (FRAME_W32_P (f)
f79e6790 13328 /* Watch out for newly created frames. */
0af913d7 13329 && f->output_data.x->hourglass_window)
f79e6790 13330 {
0af913d7
GM
13331 XUnmapWindow (FRAME_X_DISPLAY (f),
13332 f->output_data.x->hourglass_window);
13333 /* Sync here because XTread_socket looks at the
13334 hourglass_p flag that is reset to zero below. */
f79e6790 13335 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13336 f->output_data.x->hourglass_p = 0;
f79e6790 13337 }
6fc2811b 13338 }
6fc2811b 13339
0af913d7 13340 hourglass_shown_p = 0;
f79e6790
JR
13341 UNBLOCK_INPUT;
13342 }
13343#endif
6fc2811b
JR
13344}
13345
13346
13347\f
13348/***********************************************************************
13349 Tool tips
13350 ***********************************************************************/
13351
13352static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13353 Lisp_Object, Lisp_Object));
13354static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13355 Lisp_Object, int, int, int *, int *));
6fc2811b 13356
3cf3436e 13357/* The frame of a currently visible tooltip. */
6fc2811b 13358
937e601e 13359Lisp_Object tip_frame;
6fc2811b
JR
13360
13361/* If non-nil, a timer started that hides the last tooltip when it
13362 fires. */
13363
13364Lisp_Object tip_timer;
13365Window tip_window;
13366
3cf3436e
JR
13367/* If non-nil, a vector of 3 elements containing the last args
13368 with which x-show-tip was called. See there. */
13369
13370Lisp_Object last_show_tip_args;
13371
13372/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13373
13374Lisp_Object Vx_max_tooltip_size;
13375
13376
937e601e
AI
13377static Lisp_Object
13378unwind_create_tip_frame (frame)
13379 Lisp_Object frame;
13380{
c844a81a
GM
13381 Lisp_Object deleted;
13382
13383 deleted = unwind_create_frame (frame);
13384 if (EQ (deleted, Qt))
13385 {
13386 tip_window = NULL;
13387 tip_frame = Qnil;
13388 }
13389
13390 return deleted;
937e601e
AI
13391}
13392
13393
6fc2811b 13394/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13395 PARMS is a list of frame parameters. TEXT is the string to
13396 display in the tip frame. Value is the frame.
937e601e
AI
13397
13398 Note that functions called here, esp. x_default_parameter can
13399 signal errors, for instance when a specified color name is
13400 undefined. We have to make sure that we're in a consistent state
13401 when this happens. */
6fc2811b
JR
13402
13403static Lisp_Object
3cf3436e 13404x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13405 struct w32_display_info *dpyinfo;
3cf3436e 13406 Lisp_Object parms, text;
6fc2811b 13407{
6fc2811b
JR
13408 struct frame *f;
13409 Lisp_Object frame, tem;
13410 Lisp_Object name;
13411 long window_prompting = 0;
13412 int width, height;
dc220243 13413 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13414 struct gcpro gcpro1, gcpro2, gcpro3;
13415 struct kboard *kb;
3cf3436e
JR
13416 int face_change_count_before = face_change_count;
13417 Lisp_Object buffer;
13418 struct buffer *old_buffer;
6fc2811b 13419
ca56d953 13420 check_w32 ();
6fc2811b
JR
13421
13422 /* Use this general default value to start with until we know if
13423 this frame has a specified name. */
13424 Vx_resource_name = Vinvocation_name;
13425
13426#ifdef MULTI_KBOARD
13427 kb = dpyinfo->kboard;
13428#else
13429 kb = &the_only_kboard;
13430#endif
13431
13432 /* Get the name of the frame to use for resource lookup. */
13433 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13434 if (!STRINGP (name)
13435 && !EQ (name, Qunbound)
13436 && !NILP (name))
13437 error ("Invalid frame name--not a string or nil");
13438 Vx_resource_name = name;
13439
13440 frame = Qnil;
13441 GCPRO3 (parms, name, frame);
9eb16b62
JR
13442 /* Make a frame without minibuffer nor mode-line. */
13443 f = make_frame (0);
13444 f->wants_modeline = 0;
6fc2811b 13445 XSETFRAME (frame, f);
3cf3436e
JR
13446
13447 buffer = Fget_buffer_create (build_string (" *tip*"));
13448 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13449 old_buffer = current_buffer;
13450 set_buffer_internal_1 (XBUFFER (buffer));
13451 current_buffer->truncate_lines = Qnil;
13452 Ferase_buffer ();
13453 Finsert (1, &text);
13454 set_buffer_internal_1 (old_buffer);
13455
6fc2811b 13456 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13457 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13458
3cf3436e
JR
13459 /* By setting the output method, we're essentially saying that
13460 the frame is live, as per FRAME_LIVE_P. If we get a signal
13461 from this point on, x_destroy_window might screw up reference
13462 counts etc. */
d88c567c 13463 f->output_method = output_w32;
6fc2811b
JR
13464 f->output_data.w32 =
13465 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13466 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13467
13468 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13469 f->icon_name = Qnil;
13470
ca56d953 13471#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13472 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13473 dpyinfo_refcount = dpyinfo->reference_count;
13474#endif /* GLYPH_DEBUG */
6fc2811b
JR
13475#ifdef MULTI_KBOARD
13476 FRAME_KBOARD (f) = kb;
13477#endif
13478 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13479 f->output_data.w32->explicit_parent = 0;
13480
13481 /* Set the name; the functions to which we pass f expect the name to
13482 be set. */
13483 if (EQ (name, Qunbound) || NILP (name))
13484 {
ca56d953 13485 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13486 f->explicit_name = 0;
13487 }
13488 else
13489 {
13490 f->name = name;
13491 f->explicit_name = 1;
13492 /* use the frame's title when getting resources for this frame. */
13493 specbind (Qx_resource_name, name);
13494 }
13495
6fc2811b
JR
13496 /* Extract the window parameters from the supplied values
13497 that are needed to determine window geometry. */
13498 {
13499 Lisp_Object font;
13500
13501 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13502
13503 BLOCK_INPUT;
13504 /* First, try whatever font the caller has specified. */
13505 if (STRINGP (font))
13506 {
13507 tem = Fquery_fontset (font, Qnil);
13508 if (STRINGP (tem))
13509 font = x_new_fontset (f, XSTRING (tem)->data);
13510 else
13511 font = x_new_font (f, XSTRING (font)->data);
13512 }
13513
13514 /* Try out a font which we hope has bold and italic variations. */
13515 if (!STRINGP (font))
ca56d953 13516 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13517 if (! STRINGP (font))
ca56d953 13518 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13519 /* If those didn't work, look for something which will at least work. */
13520 if (! STRINGP (font))
ca56d953 13521 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13522 UNBLOCK_INPUT;
13523 if (! STRINGP (font))
ca56d953 13524 font = build_string ("Fixedsys");
6fc2811b
JR
13525
13526 x_default_parameter (f, parms, Qfont, font,
13527 "font", "Font", RES_TYPE_STRING);
13528 }
13529
13530 x_default_parameter (f, parms, Qborder_width, make_number (2),
13531 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13532 /* This defaults to 2 in order to match xterm. We recognize either
13533 internalBorderWidth or internalBorder (which is what xterm calls
13534 it). */
13535 if (NILP (Fassq (Qinternal_border_width, parms)))
13536 {
13537 Lisp_Object value;
13538
13539 value = w32_get_arg (parms, Qinternal_border_width,
13540 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13541 if (! EQ (value, Qunbound))
13542 parms = Fcons (Fcons (Qinternal_border_width, value),
13543 parms);
13544 }
bfd6edcc 13545 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13546 "internalBorderWidth", "internalBorderWidth",
13547 RES_TYPE_NUMBER);
13548
13549 /* Also do the stuff which must be set before the window exists. */
13550 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13551 "foreground", "Foreground", RES_TYPE_STRING);
13552 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13553 "background", "Background", RES_TYPE_STRING);
13554 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13555 "pointerColor", "Foreground", RES_TYPE_STRING);
13556 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13557 "cursorColor", "Foreground", RES_TYPE_STRING);
13558 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13559 "borderColor", "BorderColor", RES_TYPE_STRING);
13560
13561 /* Init faces before x_default_parameter is called for scroll-bar
13562 parameters because that function calls x_set_scroll_bar_width,
13563 which calls change_frame_size, which calls Fset_window_buffer,
13564 which runs hooks, which call Fvertical_motion. At the end, we
13565 end up in init_iterator with a null face cache, which should not
13566 happen. */
13567 init_frame_faces (f);
ca56d953
JR
13568
13569 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13570 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13571
6fc2811b
JR
13572 window_prompting = x_figure_window_size (f, parms);
13573
9eb16b62
JR
13574 /* No fringes on tip frame. */
13575 f->output_data.w32->fringes_extra = 0;
13576 f->output_data.w32->fringe_cols = 0;
13577 f->output_data.w32->left_fringe_width = 0;
13578 f->output_data.w32->right_fringe_width = 0;
13579
6fc2811b
JR
13580 if (window_prompting & XNegative)
13581 {
13582 if (window_prompting & YNegative)
13583 f->output_data.w32->win_gravity = SouthEastGravity;
13584 else
13585 f->output_data.w32->win_gravity = NorthEastGravity;
13586 }
13587 else
13588 {
13589 if (window_prompting & YNegative)
13590 f->output_data.w32->win_gravity = SouthWestGravity;
13591 else
13592 f->output_data.w32->win_gravity = NorthWestGravity;
13593 }
13594
13595 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13596
13597 BLOCK_INPUT;
13598 my_create_tip_window (f);
13599 UNBLOCK_INPUT;
6fc2811b
JR
13600
13601 x_make_gc (f);
13602
13603 x_default_parameter (f, parms, Qauto_raise, Qnil,
13604 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13605 x_default_parameter (f, parms, Qauto_lower, Qnil,
13606 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13607 x_default_parameter (f, parms, Qcursor_type, Qbox,
13608 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13609
13610 /* Dimensions, especially f->height, must be done via change_frame_size.
13611 Change will not be effected unless different from the current
13612 f->height. */
13613 width = f->width;
13614 height = f->height;
13615 f->height = 0;
13616 SET_FRAME_WIDTH (f, 0);
13617 change_frame_size (f, height, width, 1, 0, 0);
13618
3cf3436e
JR
13619 /* Set up faces after all frame parameters are known. This call
13620 also merges in face attributes specified for new frames.
13621
13622 Frame parameters may be changed if .Xdefaults contains
13623 specifications for the default font. For example, if there is an
13624 `Emacs.default.attributeBackground: pink', the `background-color'
13625 attribute of the frame get's set, which let's the internal border
13626 of the tooltip frame appear in pink. Prevent this. */
13627 {
13628 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13629
13630 /* Set tip_frame here, so that */
13631 tip_frame = frame;
13632 call1 (Qface_set_after_frame_default, frame);
13633
13634 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13635 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13636 Qnil));
13637 }
13638
6fc2811b
JR
13639 f->no_split = 1;
13640
13641 UNGCPRO;
13642
13643 /* It is now ok to make the frame official even if we get an error
13644 below. And the frame needs to be on Vframe_list or making it
13645 visible won't work. */
13646 Vframe_list = Fcons (frame, Vframe_list);
13647
13648 /* Now that the frame is official, it counts as a reference to
13649 its display. */
13650 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13651
3cf3436e
JR
13652 /* Setting attributes of faces of the tooltip frame from resources
13653 and similar will increment face_change_count, which leads to the
13654 clearing of all current matrices. Since this isn't necessary
13655 here, avoid it by resetting face_change_count to the value it
13656 had before we created the tip frame. */
13657 face_change_count = face_change_count_before;
13658
13659 /* Discard the unwind_protect. */
6fc2811b 13660 return unbind_to (count, frame);
ee78dc32
GV
13661}
13662
3cf3436e
JR
13663
13664/* Compute where to display tip frame F. PARMS is the list of frame
13665 parameters for F. DX and DY are specified offsets from the current
13666 location of the mouse. WIDTH and HEIGHT are the width and height
13667 of the tooltip. Return coordinates relative to the root window of
13668 the display in *ROOT_X, and *ROOT_Y. */
13669
13670static void
13671compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13672 struct frame *f;
13673 Lisp_Object parms, dx, dy;
13674 int width, height;
13675 int *root_x, *root_y;
13676{
3cf3436e 13677 Lisp_Object left, top;
3cf3436e
JR
13678
13679 /* User-specified position? */
13680 left = Fcdr (Fassq (Qleft, parms));
13681 top = Fcdr (Fassq (Qtop, parms));
13682
13683 /* Move the tooltip window where the mouse pointer is. Resize and
13684 show it. */
ca56d953 13685 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13686 {
ca56d953
JR
13687 POINT pt;
13688
3cf3436e 13689 BLOCK_INPUT;
ca56d953
JR
13690 GetCursorPos (&pt);
13691 *root_x = pt.x;
13692 *root_y = pt.y;
3cf3436e
JR
13693 UNBLOCK_INPUT;
13694 }
13695
13696 if (INTEGERP (top))
13697 *root_y = XINT (top);
13698 else if (*root_y + XINT (dy) - height < 0)
13699 *root_y -= XINT (dy);
13700 else
13701 {
13702 *root_y -= height;
13703 *root_y += XINT (dy);
13704 }
13705
13706 if (INTEGERP (left))
13707 *root_x = XINT (left);
72e4adef
JR
13708 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13709 /* It fits to the right of the pointer. */
13710 *root_x += XINT (dx);
13711 else if (width + XINT (dx) <= *root_x)
13712 /* It fits to the left of the pointer. */
3cf3436e
JR
13713 *root_x -= width + XINT (dx);
13714 else
72e4adef
JR
13715 /* Put it left justified on the screen -- it ought to fit that way. */
13716 *root_x = 0;
3cf3436e
JR
13717}
13718
13719
71eab8d1 13720DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13721 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13722A tooltip window is a small window displaying a string.
13723
13724FRAME nil or omitted means use the selected frame.
13725
13726PARMS is an optional list of frame parameters which can be
13727used to change the tooltip's appearance.
13728
ca56d953
JR
13729Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13730means use the default timeout of 5 seconds.
74e1aeec 13731
ca56d953 13732If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13733the tooltip is displayed at that x-position. Otherwise it is
13734displayed at the mouse position, with offset DX added (default is 5 if
13735DX isn't specified). Likewise for the y-position; if a `top' frame
13736parameter is specified, it determines the y-position of the tooltip
13737window, otherwise it is displayed at the mouse position, with offset
13738DY added (default is -10).
13739
13740A tooltip's maximum size is specified by `x-max-tooltip-size'.
13741Text larger than the specified size is clipped. */)
71eab8d1
AI
13742 (string, frame, parms, timeout, dx, dy)
13743 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13744{
6fc2811b
JR
13745 struct frame *f;
13746 struct window *w;
3cf3436e 13747 int root_x, root_y;
6fc2811b
JR
13748 struct buffer *old_buffer;
13749 struct text_pos pos;
13750 int i, width, height;
6fc2811b
JR
13751 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13752 int old_windows_or_buffers_changed = windows_or_buffers_changed;
ca56d953 13753 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13754
13755 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13756
dfff8a69 13757 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13758
b7826503 13759 CHECK_STRING (string);
6fc2811b
JR
13760 f = check_x_frame (frame);
13761 if (NILP (timeout))
13762 timeout = make_number (5);
13763 else
b7826503 13764 CHECK_NATNUM (timeout);
ee78dc32 13765
71eab8d1
AI
13766 if (NILP (dx))
13767 dx = make_number (5);
13768 else
b7826503 13769 CHECK_NUMBER (dx);
71eab8d1
AI
13770
13771 if (NILP (dy))
dc220243 13772 dy = make_number (-10);
71eab8d1 13773 else
b7826503 13774 CHECK_NUMBER (dy);
71eab8d1 13775
dc220243
JR
13776 if (NILP (last_show_tip_args))
13777 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13778
13779 if (!NILP (tip_frame))
13780 {
13781 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13782 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13783 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13784
13785 if (EQ (frame, last_frame)
13786 && !NILP (Fequal (last_string, string))
13787 && !NILP (Fequal (last_parms, parms)))
13788 {
13789 struct frame *f = XFRAME (tip_frame);
13790
13791 /* Only DX and DY have changed. */
13792 if (!NILP (tip_timer))
13793 {
13794 Lisp_Object timer = tip_timer;
13795 tip_timer = Qnil;
13796 call1 (Qcancel_timer, timer);
13797 }
13798
13799 BLOCK_INPUT;
ca56d953
JR
13800 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13801 PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
13802
13803 /* Put tooltip in topmost group and in position. */
ca56d953
JR
13804 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13805 root_x, root_y, 0, 0,
13806 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
13807
13808 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13809 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13810 0, 0, 0, 0,
13811 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13812
dc220243
JR
13813 UNBLOCK_INPUT;
13814 goto start_timer;
13815 }
13816 }
13817
6fc2811b
JR
13818 /* Hide a previous tip, if any. */
13819 Fx_hide_tip ();
ee78dc32 13820
dc220243
JR
13821 ASET (last_show_tip_args, 0, string);
13822 ASET (last_show_tip_args, 1, frame);
13823 ASET (last_show_tip_args, 2, parms);
13824
6fc2811b
JR
13825 /* Add default values to frame parameters. */
13826 if (NILP (Fassq (Qname, parms)))
13827 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13828 if (NILP (Fassq (Qinternal_border_width, parms)))
13829 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13830 if (NILP (Fassq (Qborder_width, parms)))
13831 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13832 if (NILP (Fassq (Qborder_color, parms)))
13833 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13834 if (NILP (Fassq (Qbackground_color, parms)))
13835 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13836 parms);
13837
0e3fcdef
JR
13838 /* Block input until the tip has been fully drawn, to avoid crashes
13839 when drawing tips in menus. */
13840 BLOCK_INPUT;
13841
6fc2811b
JR
13842 /* Create a frame for the tooltip, and record it in the global
13843 variable tip_frame. */
ca56d953 13844 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 13845 f = XFRAME (frame);
6fc2811b 13846
3cf3436e 13847 /* Set up the frame's root window. */
6fc2811b
JR
13848 w = XWINDOW (FRAME_ROOT_WINDOW (f));
13849 w->left = w->top = make_number (0);
3cf3436e
JR
13850
13851 if (CONSP (Vx_max_tooltip_size)
13852 && INTEGERP (XCAR (Vx_max_tooltip_size))
13853 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13854 && INTEGERP (XCDR (Vx_max_tooltip_size))
13855 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13856 {
13857 w->width = XCAR (Vx_max_tooltip_size);
13858 w->height = XCDR (Vx_max_tooltip_size);
13859 }
13860 else
13861 {
13862 w->width = make_number (80);
13863 w->height = make_number (40);
13864 }
13865
13866 f->window_width = XINT (w->width);
6fc2811b
JR
13867 adjust_glyphs (f);
13868 w->pseudo_window_p = 1;
13869
13870 /* Display the tooltip text in a temporary buffer. */
6fc2811b 13871 old_buffer = current_buffer;
3cf3436e
JR
13872 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13873 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
13874 clear_glyph_matrix (w->desired_matrix);
13875 clear_glyph_matrix (w->current_matrix);
13876 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13877 try_window (FRAME_ROOT_WINDOW (f), pos);
13878
13879 /* Compute width and height of the tooltip. */
13880 width = height = 0;
13881 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 13882 {
6fc2811b
JR
13883 struct glyph_row *row = &w->desired_matrix->rows[i];
13884 struct glyph *last;
13885 int row_width;
13886
13887 /* Stop at the first empty row at the end. */
13888 if (!row->enabled_p || !row->displays_text_p)
13889 break;
13890
13891 /* Let the row go over the full width of the frame. */
13892 row->full_width_p = 1;
13893
4e3a1c61
JR
13894#ifdef TODO /* Investigate why some fonts need more width than is
13895 calculated for some tooltips. */
6fc2811b
JR
13896 /* There's a glyph at the end of rows that is use to place
13897 the cursor there. Don't include the width of this glyph. */
13898 if (row->used[TEXT_AREA])
13899 {
13900 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13901 row_width = row->pixel_width - last->pixel_width;
13902 }
13903 else
4e3a1c61 13904#endif
6fc2811b
JR
13905 row_width = row->pixel_width;
13906
ca56d953 13907 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 13908 height += row->height;
6fc2811b 13909 width = max (width, row_width);
ee78dc32
GV
13910 }
13911
6fc2811b
JR
13912 /* Add the frame's internal border to the width and height the X
13913 window should have. */
13914 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13915 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 13916
6fc2811b
JR
13917 /* Move the tooltip window where the mouse pointer is. Resize and
13918 show it. */
3cf3436e 13919 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 13920
bfd6edcc
JR
13921 {
13922 /* Adjust Window size to take border into account. */
13923 RECT rect;
13924 rect.left = rect.top = 0;
13925 rect.right = width;
13926 rect.bottom = height;
13927 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
13928 FRAME_EXTERNAL_MENU_BAR (f));
13929
d65a9cdc 13930 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
13931 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13932 root_x, root_y, rect.right - rect.left,
13933 rect.bottom - rect.top, SWP_NOACTIVATE);
13934
d65a9cdc
JR
13935 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13936 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13937 0, 0, 0, 0,
13938 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13939
bfd6edcc
JR
13940 /* Let redisplay know that we have made the frame visible already. */
13941 f->async_visible = 1;
13942
13943 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
13944 }
ee78dc32 13945
6fc2811b
JR
13946 /* Draw into the window. */
13947 w->must_be_updated_p = 1;
13948 update_single_window (w, 1);
ee78dc32 13949
0e3fcdef
JR
13950 UNBLOCK_INPUT;
13951
6fc2811b
JR
13952 /* Restore original current buffer. */
13953 set_buffer_internal_1 (old_buffer);
13954 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 13955
dc220243 13956 start_timer:
6fc2811b
JR
13957 /* Let the tip disappear after timeout seconds. */
13958 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13959 intern ("x-hide-tip"));
ee78dc32 13960
dfff8a69 13961 UNGCPRO;
6fc2811b 13962 return unbind_to (count, Qnil);
ee78dc32
GV
13963}
13964
ee78dc32 13965
6fc2811b 13966DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
13967 doc: /* Hide the current tooltip window, if there is any.
13968Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
13969 ()
13970{
937e601e
AI
13971 int count;
13972 Lisp_Object deleted, frame, timer;
13973 struct gcpro gcpro1, gcpro2;
13974
13975 /* Return quickly if nothing to do. */
13976 if (NILP (tip_timer) && NILP (tip_frame))
13977 return Qnil;
13978
13979 frame = tip_frame;
13980 timer = tip_timer;
13981 GCPRO2 (frame, timer);
13982 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 13983
937e601e 13984 count = BINDING_STACK_SIZE ();
6fc2811b 13985 specbind (Qinhibit_redisplay, Qt);
937e601e 13986 specbind (Qinhibit_quit, Qt);
6fc2811b 13987
937e601e 13988 if (!NILP (timer))
dc220243 13989 call1 (Qcancel_timer, timer);
ee78dc32 13990
937e601e 13991 if (FRAMEP (frame))
6fc2811b 13992 {
937e601e
AI
13993 Fdelete_frame (frame, Qnil);
13994 deleted = Qt;
6fc2811b 13995 }
1edf84e7 13996
937e601e
AI
13997 UNGCPRO;
13998 return unbind_to (count, deleted);
6fc2811b 13999}
5ac45f98 14000
5ac45f98 14001
6fc2811b
JR
14002\f
14003/***********************************************************************
14004 File selection dialog
14005 ***********************************************************************/
14006
14007extern Lisp_Object Qfile_name_history;
14008
14009DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
14010 doc: /* Read file name, prompting with PROMPT in directory DIR.
14011Use a file selection dialog.
14012Select DEFAULT-FILENAME in the dialog's file selection box, if
14013specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
14014 (prompt, dir, default_filename, mustmatch)
14015 Lisp_Object prompt, dir, default_filename, mustmatch;
14016{
14017 struct frame *f = SELECTED_FRAME ();
14018 Lisp_Object file = Qnil;
14019 int count = specpdl_ptr - specpdl;
14020 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14021 char filename[MAX_PATH + 1];
14022 char init_dir[MAX_PATH + 1];
14023 int use_dialog_p = 1;
14024
14025 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
14026 CHECK_STRING (prompt);
14027 CHECK_STRING (dir);
6fc2811b
JR
14028
14029 /* Create the dialog with PROMPT as title, using DIR as initial
14030 directory and using "*" as pattern. */
14031 dir = Fexpand_file_name (dir, Qnil);
14032 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14033 init_dir[MAX_PATH] = '\0';
14034 unixtodos_filename (init_dir);
14035
14036 if (STRINGP (default_filename))
14037 {
14038 char *file_name_only;
14039 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 14040
6fc2811b 14041 unixtodos_filename (full_path_name);
5ac45f98 14042
6fc2811b
JR
14043 file_name_only = strrchr (full_path_name, '\\');
14044 if (!file_name_only)
14045 file_name_only = full_path_name;
14046 else
14047 {
14048 file_name_only++;
5ac45f98 14049
6fc2811b
JR
14050 /* If default_file_name is a directory, don't use the open
14051 file dialog, as it does not support selecting
14052 directories. */
14053 if (!(*file_name_only))
14054 use_dialog_p = 0;
14055 }
ee78dc32 14056
6fc2811b
JR
14057 strncpy (filename, file_name_only, MAX_PATH);
14058 filename[MAX_PATH] = '\0';
14059 }
ee78dc32 14060 else
6fc2811b 14061 filename[0] = '\0';
ee78dc32 14062
6fc2811b
JR
14063 if (use_dialog_p)
14064 {
14065 OPENFILENAME file_details;
5ac45f98 14066
6fc2811b
JR
14067 /* Prevent redisplay. */
14068 specbind (Qinhibit_redisplay, Qt);
14069 BLOCK_INPUT;
ee78dc32 14070
6fc2811b
JR
14071 bzero (&file_details, sizeof (file_details));
14072 file_details.lStructSize = sizeof (file_details);
14073 file_details.hwndOwner = FRAME_W32_WINDOW (f);
3cf3436e
JR
14074 /* Undocumented Bug in Common File Dialog:
14075 If a filter is not specified, shell links are not resolved. */
14076 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
6fc2811b
JR
14077 file_details.lpstrFile = filename;
14078 file_details.nMaxFile = sizeof (filename);
14079 file_details.lpstrInitialDir = init_dir;
14080 file_details.lpstrTitle = XSTRING (prompt)->data;
14081 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 14082
6fc2811b
JR
14083 if (!NILP (mustmatch))
14084 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 14085
6fc2811b
JR
14086 if (GetOpenFileName (&file_details))
14087 {
14088 dostounix_filename (filename);
14089 file = build_string (filename);
14090 }
ee78dc32 14091 else
6fc2811b
JR
14092 file = Qnil;
14093
14094 UNBLOCK_INPUT;
14095 file = unbind_to (count, file);
ee78dc32 14096 }
6fc2811b
JR
14097 /* Open File dialog will not allow folders to be selected, so resort
14098 to minibuffer completing reads for directories. */
14099 else
14100 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14101 dir, mustmatch, dir, Qfile_name_history,
14102 default_filename, Qnil);
ee78dc32 14103
6fc2811b 14104 UNGCPRO;
1edf84e7 14105
6fc2811b
JR
14106 /* Make "Cancel" equivalent to C-g. */
14107 if (NILP (file))
14108 Fsignal (Qquit, Qnil);
ee78dc32 14109
dfff8a69 14110 return unbind_to (count, file);
6fc2811b 14111}
ee78dc32 14112
ee78dc32 14113
6fc2811b 14114\f
6fc2811b
JR
14115/***********************************************************************
14116 w32 specialized functions
14117 ***********************************************************************/
ee78dc32 14118
d84b082d 14119DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
14120 doc: /* Select a font using the W32 font dialog.
14121Returns an X font string corresponding to the selection. */)
d84b082d
JR
14122 (frame, include_proportional)
14123 Lisp_Object frame, include_proportional;
ee78dc32
GV
14124{
14125 FRAME_PTR f = check_x_frame (frame);
14126 CHOOSEFONT cf;
14127 LOGFONT lf;
f46e6225
GV
14128 TEXTMETRIC tm;
14129 HDC hdc;
14130 HANDLE oldobj;
ee78dc32
GV
14131 char buf[100];
14132
14133 bzero (&cf, sizeof (cf));
f46e6225 14134 bzero (&lf, sizeof (lf));
ee78dc32
GV
14135
14136 cf.lStructSize = sizeof (cf);
fbd6baed 14137 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
14138 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14139
14140 /* Unless include_proportional is non-nil, limit the selection to
14141 monospaced fonts. */
14142 if (NILP (include_proportional))
14143 cf.Flags |= CF_FIXEDPITCHONLY;
14144
ee78dc32
GV
14145 cf.lpLogFont = &lf;
14146
f46e6225
GV
14147 /* Initialize as much of the font details as we can from the current
14148 default font. */
14149 hdc = GetDC (FRAME_W32_WINDOW (f));
14150 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14151 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14152 if (GetTextMetrics (hdc, &tm))
14153 {
14154 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14155 lf.lfWeight = tm.tmWeight;
14156 lf.lfItalic = tm.tmItalic;
14157 lf.lfUnderline = tm.tmUnderlined;
14158 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
14159 lf.lfCharSet = tm.tmCharSet;
14160 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14161 }
14162 SelectObject (hdc, oldobj);
6fc2811b 14163 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 14164
767b1ff0 14165 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 14166 return Qnil;
ee78dc32
GV
14167
14168 return build_string (buf);
14169}
14170
74e1aeec
JR
14171DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14172 Sw32_send_sys_command, 1, 2, 0,
14173 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
14174Some useful values for command are #xf030 to maximise frame (#xf020
14175to minimize), #xf120 to restore frame to original size, and #xf100
14176to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
14177screen saver if defined.
14178
14179If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
14180 (command, frame)
14181 Lisp_Object command, frame;
14182{
1edf84e7
GV
14183 FRAME_PTR f = check_x_frame (frame);
14184
b7826503 14185 CHECK_NUMBER (command);
1edf84e7 14186
ce6059da 14187 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
14188
14189 return Qnil;
14190}
14191
55dcfc15 14192DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
14193 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14194This is a wrapper around the ShellExecute system function, which
14195invokes the application registered to handle OPERATION for DOCUMENT.
14196OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14197nil for the default action), and DOCUMENT is typically the name of a
14198document file or URL, but can also be a program executable to run or
14199a directory to open in the Windows Explorer.
14200
14201If DOCUMENT is a program executable, PARAMETERS can be a string
14202containing command line parameters, but otherwise should be nil.
14203
14204SHOW-FLAG can be used to control whether the invoked application is hidden
14205or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14206otherwise it is an integer representing a ShowWindow flag:
14207
14208 0 - start hidden
14209 1 - start normally
14210 3 - start maximized
14211 6 - start minimized */)
55dcfc15
AI
14212 (operation, document, parameters, show_flag)
14213 Lisp_Object operation, document, parameters, show_flag;
14214{
14215 Lisp_Object current_dir;
14216
b7826503 14217 CHECK_STRING (document);
55dcfc15
AI
14218
14219 /* Encode filename and current directory. */
14220 current_dir = ENCODE_FILE (current_buffer->directory);
14221 document = ENCODE_FILE (document);
14222 if ((int) ShellExecute (NULL,
6fc2811b
JR
14223 (STRINGP (operation) ?
14224 XSTRING (operation)->data : NULL),
55dcfc15
AI
14225 XSTRING (document)->data,
14226 (STRINGP (parameters) ?
14227 XSTRING (parameters)->data : NULL),
14228 XSTRING (current_dir)->data,
14229 (INTEGERP (show_flag) ?
14230 XINT (show_flag) : SW_SHOWDEFAULT))
14231 > 32)
14232 return Qt;
90d97e64 14233 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
14234}
14235
ccc2d29c
GV
14236/* Lookup virtual keycode from string representing the name of a
14237 non-ascii keystroke into the corresponding virtual key, using
14238 lispy_function_keys. */
14239static int
14240lookup_vk_code (char *key)
14241{
14242 int i;
14243
14244 for (i = 0; i < 256; i++)
14245 if (lispy_function_keys[i] != 0
14246 && strcmp (lispy_function_keys[i], key) == 0)
14247 return i;
14248
14249 return -1;
14250}
14251
14252/* Convert a one-element vector style key sequence to a hot key
14253 definition. */
14254static int
14255w32_parse_hot_key (key)
14256 Lisp_Object key;
14257{
14258 /* Copied from Fdefine_key and store_in_keymap. */
14259 register Lisp_Object c;
14260 int vk_code;
14261 int lisp_modifiers;
14262 int w32_modifiers;
14263 struct gcpro gcpro1;
14264
b7826503 14265 CHECK_VECTOR (key);
ccc2d29c
GV
14266
14267 if (XFASTINT (Flength (key)) != 1)
14268 return Qnil;
14269
14270 GCPRO1 (key);
14271
14272 c = Faref (key, make_number (0));
14273
14274 if (CONSP (c) && lucid_event_type_list_p (c))
14275 c = Fevent_convert_list (c);
14276
14277 UNGCPRO;
14278
14279 if (! INTEGERP (c) && ! SYMBOLP (c))
14280 error ("Key definition is invalid");
14281
14282 /* Work out the base key and the modifiers. */
14283 if (SYMBOLP (c))
14284 {
14285 c = parse_modifiers (c);
14286 lisp_modifiers = Fcar (Fcdr (c));
14287 c = Fcar (c);
14288 if (!SYMBOLP (c))
14289 abort ();
14290 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
14291 }
14292 else if (INTEGERP (c))
14293 {
14294 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14295 /* Many ascii characters are their own virtual key code. */
14296 vk_code = XINT (c) & CHARACTERBITS;
14297 }
14298
14299 if (vk_code < 0 || vk_code > 255)
14300 return Qnil;
14301
14302 if ((lisp_modifiers & meta_modifier) != 0
14303 && !NILP (Vw32_alt_is_meta))
14304 lisp_modifiers |= alt_modifier;
14305
71eab8d1
AI
14306 /* Supply defs missing from mingw32. */
14307#ifndef MOD_ALT
14308#define MOD_ALT 0x0001
14309#define MOD_CONTROL 0x0002
14310#define MOD_SHIFT 0x0004
14311#define MOD_WIN 0x0008
14312#endif
14313
ccc2d29c
GV
14314 /* Convert lisp modifiers to Windows hot-key form. */
14315 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14316 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14317 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14318 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14319
14320 return HOTKEY (vk_code, w32_modifiers);
14321}
14322
74e1aeec
JR
14323DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14324 Sw32_register_hot_key, 1, 1, 0,
14325 doc: /* Register KEY as a hot-key combination.
14326Certain key combinations like Alt-Tab are reserved for system use on
14327Windows, and therefore are normally intercepted by the system. However,
14328most of these key combinations can be received by registering them as
14329hot-keys, overriding their special meaning.
14330
14331KEY must be a one element key definition in vector form that would be
14332acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14333modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14334is always interpreted as the Windows modifier keys.
14335
14336The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14337 (key)
14338 Lisp_Object key;
14339{
14340 key = w32_parse_hot_key (key);
14341
14342 if (NILP (Fmemq (key, w32_grabbed_keys)))
14343 {
14344 /* Reuse an empty slot if possible. */
14345 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14346
14347 /* Safe to add new key to list, even if we have focus. */
14348 if (NILP (item))
14349 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14350 else
f3fbd155 14351 XSETCAR (item, key);
ccc2d29c
GV
14352
14353 /* Notify input thread about new hot-key definition, so that it
14354 takes effect without needing to switch focus. */
14355 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14356 (WPARAM) key, 0);
14357 }
14358
14359 return key;
14360}
14361
74e1aeec
JR
14362DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14363 Sw32_unregister_hot_key, 1, 1, 0,
14364 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14365 (key)
14366 Lisp_Object key;
14367{
14368 Lisp_Object item;
14369
14370 if (!INTEGERP (key))
14371 key = w32_parse_hot_key (key);
14372
14373 item = Fmemq (key, w32_grabbed_keys);
14374
14375 if (!NILP (item))
14376 {
14377 /* Notify input thread about hot-key definition being removed, so
14378 that it takes effect without needing focus switch. */
14379 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14380 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14381 {
14382 MSG msg;
14383 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14384 }
14385 return Qt;
14386 }
14387 return Qnil;
14388}
14389
74e1aeec
JR
14390DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14391 Sw32_registered_hot_keys, 0, 0, 0,
14392 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14393 ()
14394{
14395 return Fcopy_sequence (w32_grabbed_keys);
14396}
14397
74e1aeec
JR
14398DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14399 Sw32_reconstruct_hot_key, 1, 1, 0,
14400 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14401 (hotkeyid)
14402 Lisp_Object hotkeyid;
14403{
14404 int vk_code, w32_modifiers;
14405 Lisp_Object key;
14406
b7826503 14407 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14408
14409 vk_code = HOTKEY_VK_CODE (hotkeyid);
14410 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14411
14412 if (lispy_function_keys[vk_code])
14413 key = intern (lispy_function_keys[vk_code]);
14414 else
14415 key = make_number (vk_code);
14416
14417 key = Fcons (key, Qnil);
14418 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14419 key = Fcons (Qshift, key);
ccc2d29c 14420 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14421 key = Fcons (Qctrl, key);
ccc2d29c 14422 if (w32_modifiers & MOD_ALT)
3ef68e6b 14423 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14424 if (w32_modifiers & MOD_WIN)
3ef68e6b 14425 key = Fcons (Qhyper, key);
ccc2d29c
GV
14426
14427 return key;
14428}
adcc3809 14429
74e1aeec
JR
14430DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14431 Sw32_toggle_lock_key, 1, 2, 0,
14432 doc: /* Toggle the state of the lock key KEY.
14433KEY can be `capslock', `kp-numlock', or `scroll'.
14434If the optional parameter NEW-STATE is a number, then the state of KEY
14435is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14436 (key, new_state)
14437 Lisp_Object key, new_state;
14438{
14439 int vk_code;
adcc3809
GV
14440
14441 if (EQ (key, intern ("capslock")))
14442 vk_code = VK_CAPITAL;
14443 else if (EQ (key, intern ("kp-numlock")))
14444 vk_code = VK_NUMLOCK;
14445 else if (EQ (key, intern ("scroll")))
14446 vk_code = VK_SCROLL;
14447 else
14448 return Qnil;
14449
14450 if (!dwWindowsThreadId)
14451 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14452
14453 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14454 (WPARAM) vk_code, (LPARAM) new_state))
14455 {
14456 MSG msg;
14457 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14458 return make_number (msg.wParam);
14459 }
14460 return Qnil;
14461}
ee78dc32 14462\f
2254bcde 14463DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14464 doc: /* Return storage information about the file system FILENAME is on.
14465Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14466storage of the file system, FREE is the free storage, and AVAIL is the
14467storage available to a non-superuser. All 3 numbers are in bytes.
14468If the underlying system call fails, value is nil. */)
2254bcde
AI
14469 (filename)
14470 Lisp_Object filename;
14471{
14472 Lisp_Object encoded, value;
14473
b7826503 14474 CHECK_STRING (filename);
2254bcde
AI
14475 filename = Fexpand_file_name (filename, Qnil);
14476 encoded = ENCODE_FILE (filename);
14477
14478 value = Qnil;
14479
14480 /* Determining the required information on Windows turns out, sadly,
14481 to be more involved than one would hope. The original Win32 api
14482 call for this will return bogus information on some systems, but we
14483 must dynamically probe for the replacement api, since that was
14484 added rather late on. */
14485 {
14486 HMODULE hKernel = GetModuleHandle ("kernel32");
14487 BOOL (*pfn_GetDiskFreeSpaceEx)
14488 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14489 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14490
14491 /* On Windows, we may need to specify the root directory of the
14492 volume holding FILENAME. */
14493 char rootname[MAX_PATH];
14494 char *name = XSTRING (encoded)->data;
14495
14496 /* find the root name of the volume if given */
14497 if (isalpha (name[0]) && name[1] == ':')
14498 {
14499 rootname[0] = name[0];
14500 rootname[1] = name[1];
14501 rootname[2] = '\\';
14502 rootname[3] = 0;
14503 }
14504 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14505 {
14506 char *str = rootname;
14507 int slashes = 4;
14508 do
14509 {
14510 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14511 break;
14512 *str++ = *name++;
14513 }
14514 while ( *name );
14515
14516 *str++ = '\\';
14517 *str = 0;
14518 }
14519
14520 if (pfn_GetDiskFreeSpaceEx)
14521 {
14522 LARGE_INTEGER availbytes;
14523 LARGE_INTEGER freebytes;
14524 LARGE_INTEGER totalbytes;
14525
14526 if (pfn_GetDiskFreeSpaceEx(rootname,
14527 &availbytes,
14528 &totalbytes,
14529 &freebytes))
14530 value = list3 (make_float ((double) totalbytes.QuadPart),
14531 make_float ((double) freebytes.QuadPart),
14532 make_float ((double) availbytes.QuadPart));
14533 }
14534 else
14535 {
14536 DWORD sectors_per_cluster;
14537 DWORD bytes_per_sector;
14538 DWORD free_clusters;
14539 DWORD total_clusters;
14540
14541 if (GetDiskFreeSpace(rootname,
14542 &sectors_per_cluster,
14543 &bytes_per_sector,
14544 &free_clusters,
14545 &total_clusters))
14546 value = list3 (make_float ((double) total_clusters
14547 * sectors_per_cluster * bytes_per_sector),
14548 make_float ((double) free_clusters
14549 * sectors_per_cluster * bytes_per_sector),
14550 make_float ((double) free_clusters
14551 * sectors_per_cluster * bytes_per_sector));
14552 }
14553 }
14554
14555 return value;
14556}
14557\f
0e3fcdef
JR
14558/***********************************************************************
14559 Initialization
14560 ***********************************************************************/
14561
14562void
fbd6baed 14563syms_of_w32fns ()
ee78dc32 14564{
9eb16b62
JR
14565 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14566
1edf84e7
GV
14567 /* This is zero if not using MS-Windows. */
14568 w32_in_use = 0;
14569
9eb16b62
JR
14570 /* TrackMouseEvent not available in all versions of Windows, so must load
14571 it dynamically. Do it once, here, instead of every time it is used. */
14572 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14573 track_mouse_window = NULL;
14574
d285988b
JR
14575 w32_visible_system_caret_hwnd = NULL;
14576
ee78dc32
GV
14577 Qauto_raise = intern ("auto-raise");
14578 staticpro (&Qauto_raise);
14579 Qauto_lower = intern ("auto-lower");
14580 staticpro (&Qauto_lower);
ee78dc32
GV
14581 Qbar = intern ("bar");
14582 staticpro (&Qbar);
14583 Qborder_color = intern ("border-color");
14584 staticpro (&Qborder_color);
14585 Qborder_width = intern ("border-width");
14586 staticpro (&Qborder_width);
14587 Qbox = intern ("box");
14588 staticpro (&Qbox);
14589 Qcursor_color = intern ("cursor-color");
14590 staticpro (&Qcursor_color);
14591 Qcursor_type = intern ("cursor-type");
14592 staticpro (&Qcursor_type);
ee78dc32
GV
14593 Qgeometry = intern ("geometry");
14594 staticpro (&Qgeometry);
14595 Qicon_left = intern ("icon-left");
14596 staticpro (&Qicon_left);
14597 Qicon_top = intern ("icon-top");
14598 staticpro (&Qicon_top);
14599 Qicon_type = intern ("icon-type");
14600 staticpro (&Qicon_type);
14601 Qicon_name = intern ("icon-name");
14602 staticpro (&Qicon_name);
14603 Qinternal_border_width = intern ("internal-border-width");
14604 staticpro (&Qinternal_border_width);
14605 Qleft = intern ("left");
14606 staticpro (&Qleft);
1026b400
RS
14607 Qright = intern ("right");
14608 staticpro (&Qright);
ee78dc32
GV
14609 Qmouse_color = intern ("mouse-color");
14610 staticpro (&Qmouse_color);
14611 Qnone = intern ("none");
14612 staticpro (&Qnone);
14613 Qparent_id = intern ("parent-id");
14614 staticpro (&Qparent_id);
14615 Qscroll_bar_width = intern ("scroll-bar-width");
14616 staticpro (&Qscroll_bar_width);
14617 Qsuppress_icon = intern ("suppress-icon");
14618 staticpro (&Qsuppress_icon);
ee78dc32
GV
14619 Qundefined_color = intern ("undefined-color");
14620 staticpro (&Qundefined_color);
14621 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14622 staticpro (&Qvertical_scroll_bars);
14623 Qvisibility = intern ("visibility");
14624 staticpro (&Qvisibility);
14625 Qwindow_id = intern ("window-id");
14626 staticpro (&Qwindow_id);
14627 Qx_frame_parameter = intern ("x-frame-parameter");
14628 staticpro (&Qx_frame_parameter);
14629 Qx_resource_name = intern ("x-resource-name");
14630 staticpro (&Qx_resource_name);
14631 Quser_position = intern ("user-position");
14632 staticpro (&Quser_position);
14633 Quser_size = intern ("user-size");
14634 staticpro (&Quser_size);
6fc2811b
JR
14635 Qscreen_gamma = intern ("screen-gamma");
14636 staticpro (&Qscreen_gamma);
dfff8a69
JR
14637 Qline_spacing = intern ("line-spacing");
14638 staticpro (&Qline_spacing);
14639 Qcenter = intern ("center");
14640 staticpro (&Qcenter);
dc220243
JR
14641 Qcancel_timer = intern ("cancel-timer");
14642 staticpro (&Qcancel_timer);
f7b9d4d1
JR
14643 Qfullscreen = intern ("fullscreen");
14644 staticpro (&Qfullscreen);
14645 Qfullwidth = intern ("fullwidth");
14646 staticpro (&Qfullwidth);
14647 Qfullheight = intern ("fullheight");
14648 staticpro (&Qfullheight);
14649 Qfullboth = intern ("fullboth");
14650 staticpro (&Qfullboth);
ee78dc32 14651
adcc3809
GV
14652 Qhyper = intern ("hyper");
14653 staticpro (&Qhyper);
14654 Qsuper = intern ("super");
14655 staticpro (&Qsuper);
14656 Qmeta = intern ("meta");
14657 staticpro (&Qmeta);
14658 Qalt = intern ("alt");
14659 staticpro (&Qalt);
14660 Qctrl = intern ("ctrl");
14661 staticpro (&Qctrl);
14662 Qcontrol = intern ("control");
14663 staticpro (&Qcontrol);
14664 Qshift = intern ("shift");
14665 staticpro (&Qshift);
f7b9d4d1 14666 /* This is the end of symbol initialization. */
adcc3809 14667
6fc2811b
JR
14668 /* Text property `display' should be nonsticky by default. */
14669 Vtext_property_default_nonsticky
14670 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14671
14672
14673 Qlaplace = intern ("laplace");
14674 staticpro (&Qlaplace);
3cf3436e
JR
14675 Qemboss = intern ("emboss");
14676 staticpro (&Qemboss);
14677 Qedge_detection = intern ("edge-detection");
14678 staticpro (&Qedge_detection);
14679 Qheuristic = intern ("heuristic");
14680 staticpro (&Qheuristic);
14681 QCmatrix = intern (":matrix");
14682 staticpro (&QCmatrix);
14683 QCcolor_adjustment = intern (":color-adjustment");
14684 staticpro (&QCcolor_adjustment);
14685 QCmask = intern (":mask");
14686 staticpro (&QCmask);
6fc2811b 14687
4b817373
RS
14688 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14689 staticpro (&Qface_set_after_frame_default);
14690
ee78dc32
GV
14691 Fput (Qundefined_color, Qerror_conditions,
14692 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14693 Fput (Qundefined_color, Qerror_message,
14694 build_string ("Undefined color"));
14695
ccc2d29c
GV
14696 staticpro (&w32_grabbed_keys);
14697 w32_grabbed_keys = Qnil;
14698
fbd6baed 14699 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14700 doc: /* An array of color name mappings for windows. */);
fbd6baed 14701 Vw32_color_map = Qnil;
ee78dc32 14702
fbd6baed 14703 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14704 doc: /* Non-nil if alt key presses are passed on to Windows.
14705When non-nil, for example, alt pressed and released and then space will
14706open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14707 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14708
fbd6baed 14709 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14710 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14711When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14712 Vw32_alt_is_meta = Qt;
8c205c63 14713
7d081355 14714 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14715 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14716 XSETINT (Vw32_quit_key, 0);
14717
ccc2d29c
GV
14718 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14719 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14720 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14721When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14722 Vw32_pass_lwindow_to_system = Qt;
14723
14724 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14725 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14726 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14727When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14728 Vw32_pass_rwindow_to_system = Qt;
14729
adcc3809
GV
14730 DEFVAR_INT ("w32-phantom-key-code",
14731 &Vw32_phantom_key_code,
74e1aeec
JR
14732 doc: /* Virtual key code used to generate \"phantom\" key presses.
14733Value is a number between 0 and 255.
14734
14735Phantom key presses are generated in order to stop the system from
14736acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14737`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14738 /* Although 255 is technically not a valid key code, it works and
14739 means that this hack won't interfere with any real key code. */
14740 Vw32_phantom_key_code = 255;
adcc3809 14741
ccc2d29c
GV
14742 DEFVAR_LISP ("w32-enable-num-lock",
14743 &Vw32_enable_num_lock,
74e1aeec
JR
14744 doc: /* Non-nil if Num Lock should act normally.
14745Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14746 Vw32_enable_num_lock = Qt;
14747
14748 DEFVAR_LISP ("w32-enable-caps-lock",
14749 &Vw32_enable_caps_lock,
74e1aeec
JR
14750 doc: /* Non-nil if Caps Lock should act normally.
14751Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14752 Vw32_enable_caps_lock = Qt;
14753
14754 DEFVAR_LISP ("w32-scroll-lock-modifier",
14755 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14756 doc: /* Modifier to use for the Scroll Lock on state.
14757The value can be hyper, super, meta, alt, control or shift for the
14758respective modifier, or nil to see Scroll Lock as the key `scroll'.
14759Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14760 Vw32_scroll_lock_modifier = Qt;
14761
14762 DEFVAR_LISP ("w32-lwindow-modifier",
14763 &Vw32_lwindow_modifier,
74e1aeec
JR
14764 doc: /* Modifier to use for the left \"Windows\" key.
14765The value can be hyper, super, meta, alt, control or shift for the
14766respective modifier, or nil to appear as the key `lwindow'.
14767Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14768 Vw32_lwindow_modifier = Qnil;
14769
14770 DEFVAR_LISP ("w32-rwindow-modifier",
14771 &Vw32_rwindow_modifier,
74e1aeec
JR
14772 doc: /* Modifier to use for the right \"Windows\" key.
14773The value can be hyper, super, meta, alt, control or shift for the
14774respective modifier, or nil to appear as the key `rwindow'.
14775Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14776 Vw32_rwindow_modifier = Qnil;
14777
14778 DEFVAR_LISP ("w32-apps-modifier",
14779 &Vw32_apps_modifier,
74e1aeec
JR
14780 doc: /* Modifier to use for the \"Apps\" key.
14781The value can be hyper, super, meta, alt, control or shift for the
14782respective modifier, or nil to appear as the key `apps'.
14783Any other value will cause the key to be ignored. */);
ccc2d29c 14784 Vw32_apps_modifier = Qnil;
da36a4d6 14785
d84b082d 14786 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 14787 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 14788 w32_enable_synthesized_fonts = 0;
5ac45f98 14789
fbd6baed 14790 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 14791 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 14792 Vw32_enable_palette = Qt;
5ac45f98 14793
fbd6baed
GV
14794 DEFVAR_INT ("w32-mouse-button-tolerance",
14795 &Vw32_mouse_button_tolerance,
74e1aeec
JR
14796 doc: /* Analogue of double click interval for faking middle mouse events.
14797The value is the minimum time in milliseconds that must elapse between
14798left/right button down events before they are considered distinct events.
14799If both mouse buttons are depressed within this interval, a middle mouse
14800button down event is generated instead. */);
fbd6baed 14801 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 14802
fbd6baed
GV
14803 DEFVAR_INT ("w32-mouse-move-interval",
14804 &Vw32_mouse_move_interval,
74e1aeec
JR
14805 doc: /* Minimum interval between mouse move events.
14806The value is the minimum time in milliseconds that must elapse between
14807successive mouse move (or scroll bar drag) events before they are
14808reported as lisp events. */);
247be837 14809 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 14810
74214547
JR
14811 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
14812 &w32_pass_extra_mouse_buttons_to_system,
14813 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
14814Recent versions of Windows support mice with up to five buttons.
14815Since most applications don't support these extra buttons, most mouse
14816drivers will allow you to map them to functions at the system level.
14817If this variable is non-nil, Emacs will pass them on, allowing the
14818system to handle them. */);
14819 w32_pass_extra_mouse_buttons_to_system = 0;
14820
ee78dc32
GV
14821 init_x_parm_symbols ();
14822
14823 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 14824 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
14825 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14826
14827 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
14828 doc: /* The shape of the pointer when over text.
14829Changing the value does not affect existing frames
14830unless you set the mouse color. */);
ee78dc32
GV
14831 Vx_pointer_shape = Qnil;
14832
14833 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
14834 doc: /* The name Emacs uses to look up resources; for internal use only.
14835`x-get-resource' uses this as the first component of the instance name
14836when requesting resource values.
14837Emacs initially sets `x-resource-name' to the name under which Emacs
14838was invoked, or to the value specified with the `-name' or `-rn'
14839switches, if present. */);
ee78dc32
GV
14840 Vx_resource_name = Qnil;
14841
14842 Vx_nontext_pointer_shape = Qnil;
14843
14844 Vx_mode_pointer_shape = Qnil;
14845
0af913d7 14846 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
14847 doc: /* The shape of the pointer when Emacs is busy.
14848This variable takes effect when you create a new frame
14849or when you set the mouse color. */);
0af913d7 14850 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 14851
0af913d7 14852 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 14853 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 14854 display_hourglass_p = 1;
6fc2811b 14855
0af913d7 14856 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
14857 doc: /* *Seconds to wait before displaying an hourglass pointer.
14858Value must be an integer or float. */);
0af913d7 14859 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 14860
6fc2811b 14861 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 14862 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
14863 doc: /* The shape of the pointer when over mouse-sensitive text.
14864This variable takes effect when you create a new frame
14865or when you set the mouse color. */);
ee78dc32
GV
14866 Vx_sensitive_text_pointer_shape = Qnil;
14867
4694d762
JR
14868 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14869 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
14870 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14871This variable takes effect when you create a new frame
14872or when you set the mouse color. */);
4694d762
JR
14873 Vx_window_horizontal_drag_shape = Qnil;
14874
ee78dc32 14875 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 14876 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
14877 Vx_cursor_fore_pixel = Qnil;
14878
3cf3436e 14879 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
14880 doc: /* Maximum size for tooltips.
14881Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
14882 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
14883
ee78dc32 14884 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
14885 doc: /* Non-nil if no window manager is in use.
14886Emacs doesn't try to figure this out; this is always nil
14887unless you set it to something else. */);
ee78dc32
GV
14888 /* We don't have any way to find this out, so set it to nil
14889 and maybe the user would like to set it to t. */
14890 Vx_no_window_manager = Qnil;
14891
4587b026
GV
14892 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14893 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
14894 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14895
14896Since Emacs gets width of a font matching with this regexp from
14897PIXEL_SIZE field of the name, font finding mechanism gets faster for
14898such a font. This is especially effective for such large fonts as
14899Chinese, Japanese, and Korean. */);
4587b026
GV
14900 Vx_pixel_size_width_font_regexp = Qnil;
14901
6fc2811b 14902 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
14903 doc: /* Time after which cached images are removed from the cache.
14904When an image has not been displayed this many seconds, remove it
14905from the image cache. Value must be an integer or nil with nil
14906meaning don't clear the cache. */);
6fc2811b
JR
14907 Vimage_cache_eviction_delay = make_number (30 * 60);
14908
33d52f9c
GV
14909 DEFVAR_LISP ("w32-bdf-filename-alist",
14910 &Vw32_bdf_filename_alist,
74e1aeec 14911 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
14912 Vw32_bdf_filename_alist = Qnil;
14913
1075afa9
GV
14914 DEFVAR_BOOL ("w32-strict-fontnames",
14915 &w32_strict_fontnames,
74e1aeec
JR
14916 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14917Default is nil, which allows old fontnames that are not XLFD compliant,
14918and allows third-party CJK display to work by specifying false charset
14919fields to trick Emacs into translating to Big5, SJIS etc.
14920Setting this to t will prevent wrong fonts being selected when
14921fontsets are automatically created. */);
1075afa9
GV
14922 w32_strict_fontnames = 0;
14923
c0611964
AI
14924 DEFVAR_BOOL ("w32-strict-painting",
14925 &w32_strict_painting,
74e1aeec
JR
14926 doc: /* Non-nil means use strict rules for repainting frames.
14927Set this to nil to get the old behaviour for repainting; this should
14928only be necessary if the default setting causes problems. */);
c0611964
AI
14929 w32_strict_painting = 1;
14930
dfff8a69
JR
14931 DEFVAR_LISP ("w32-charset-info-alist",
14932 &Vw32_charset_info_alist,
b3700ae7
JR
14933 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14934Each entry should be of the form:
74e1aeec
JR
14935
14936 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14937
14938where CHARSET_NAME is a string used in font names to identify the charset,
14939WINDOWS_CHARSET is a symbol that can be one of:
14940w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14941w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14942w32-charset-chinesebig5,
dfff8a69 14943#ifdef JOHAB_CHARSET
74e1aeec
JR
14944w32-charset-johab, w32-charset-hebrew,
14945w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14946w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14947w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
14948#endif
14949#ifdef UNICODE_CHARSET
74e1aeec 14950w32-charset-unicode,
dfff8a69 14951#endif
74e1aeec
JR
14952or w32-charset-oem.
14953CODEPAGE should be an integer specifying the codepage that should be used
14954to display the character set, t to do no translation and output as Unicode,
14955or nil to do no translation and output as 8 bit (or multibyte on far-east
14956versions of Windows) characters. */);
dfff8a69
JR
14957 Vw32_charset_info_alist = Qnil;
14958
14959 staticpro (&Qw32_charset_ansi);
14960 Qw32_charset_ansi = intern ("w32-charset-ansi");
14961 staticpro (&Qw32_charset_symbol);
14962 Qw32_charset_symbol = intern ("w32-charset-symbol");
14963 staticpro (&Qw32_charset_shiftjis);
14964 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
14965 staticpro (&Qw32_charset_hangeul);
14966 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
14967 staticpro (&Qw32_charset_chinesebig5);
14968 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
14969 staticpro (&Qw32_charset_gb2312);
14970 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
14971 staticpro (&Qw32_charset_oem);
14972 Qw32_charset_oem = intern ("w32-charset-oem");
14973
14974#ifdef JOHAB_CHARSET
14975 {
14976 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
14977 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
14978 doc: /* Internal variable. */);
dfff8a69
JR
14979
14980 staticpro (&Qw32_charset_johab);
14981 Qw32_charset_johab = intern ("w32-charset-johab");
14982 staticpro (&Qw32_charset_easteurope);
14983 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
14984 staticpro (&Qw32_charset_turkish);
14985 Qw32_charset_turkish = intern ("w32-charset-turkish");
14986 staticpro (&Qw32_charset_baltic);
14987 Qw32_charset_baltic = intern ("w32-charset-baltic");
14988 staticpro (&Qw32_charset_russian);
14989 Qw32_charset_russian = intern ("w32-charset-russian");
14990 staticpro (&Qw32_charset_arabic);
14991 Qw32_charset_arabic = intern ("w32-charset-arabic");
14992 staticpro (&Qw32_charset_greek);
14993 Qw32_charset_greek = intern ("w32-charset-greek");
14994 staticpro (&Qw32_charset_hebrew);
14995 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
14996 staticpro (&Qw32_charset_vietnamese);
14997 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
14998 staticpro (&Qw32_charset_thai);
14999 Qw32_charset_thai = intern ("w32-charset-thai");
15000 staticpro (&Qw32_charset_mac);
15001 Qw32_charset_mac = intern ("w32-charset-mac");
15002 }
15003#endif
15004
15005#ifdef UNICODE_CHARSET
15006 {
15007 static int w32_unicode_charset_defined = 1;
15008 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
15009 &w32_unicode_charset_defined,
15010 doc: /* Internal variable. */);
dfff8a69
JR
15011
15012 staticpro (&Qw32_charset_unicode);
15013 Qw32_charset_unicode = intern ("w32-charset-unicode");
15014#endif
15015
ee78dc32 15016 defsubr (&Sx_get_resource);
767b1ff0 15017#if 0 /* TODO: Port to W32 */
6fc2811b
JR
15018 defsubr (&Sx_change_window_property);
15019 defsubr (&Sx_delete_window_property);
15020 defsubr (&Sx_window_property);
15021#endif
2d764c78 15022 defsubr (&Sxw_display_color_p);
ee78dc32 15023 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
15024 defsubr (&Sxw_color_defined_p);
15025 defsubr (&Sxw_color_values);
ee78dc32
GV
15026 defsubr (&Sx_server_max_request_size);
15027 defsubr (&Sx_server_vendor);
15028 defsubr (&Sx_server_version);
15029 defsubr (&Sx_display_pixel_width);
15030 defsubr (&Sx_display_pixel_height);
15031 defsubr (&Sx_display_mm_width);
15032 defsubr (&Sx_display_mm_height);
15033 defsubr (&Sx_display_screens);
15034 defsubr (&Sx_display_planes);
15035 defsubr (&Sx_display_color_cells);
15036 defsubr (&Sx_display_visual_class);
15037 defsubr (&Sx_display_backing_store);
15038 defsubr (&Sx_display_save_under);
15039 defsubr (&Sx_parse_geometry);
15040 defsubr (&Sx_create_frame);
ee78dc32
GV
15041 defsubr (&Sx_open_connection);
15042 defsubr (&Sx_close_connection);
15043 defsubr (&Sx_display_list);
15044 defsubr (&Sx_synchronize);
15045
fbd6baed 15046 /* W32 specific functions */
ee78dc32 15047
1edf84e7 15048 defsubr (&Sw32_focus_frame);
fbd6baed
GV
15049 defsubr (&Sw32_select_font);
15050 defsubr (&Sw32_define_rgb_color);
15051 defsubr (&Sw32_default_color_map);
15052 defsubr (&Sw32_load_color_file);
1edf84e7 15053 defsubr (&Sw32_send_sys_command);
55dcfc15 15054 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
15055 defsubr (&Sw32_register_hot_key);
15056 defsubr (&Sw32_unregister_hot_key);
15057 defsubr (&Sw32_registered_hot_keys);
15058 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 15059 defsubr (&Sw32_toggle_lock_key);
33d52f9c 15060 defsubr (&Sw32_find_bdf_fonts);
4587b026 15061
2254bcde
AI
15062 defsubr (&Sfile_system_info);
15063
4587b026
GV
15064 /* Setting callback functions for fontset handler. */
15065 get_font_info_func = w32_get_font_info;
6fc2811b
JR
15066
15067#if 0 /* This function pointer doesn't seem to be used anywhere.
15068 And the pointer assigned has the wrong type, anyway. */
4587b026 15069 list_fonts_func = w32_list_fonts;
6fc2811b
JR
15070#endif
15071
4587b026
GV
15072 load_font_func = w32_load_font;
15073 find_ccl_program_func = w32_find_ccl_program;
15074 query_font_func = w32_query_font;
15075 set_frame_fontset_func = x_set_font;
15076 check_window_system_func = check_w32;
6fc2811b 15077
767b1ff0 15078#if 0 /* TODO Image support for W32 */
6fc2811b
JR
15079 /* Images. */
15080 Qxbm = intern ("xbm");
15081 staticpro (&Qxbm);
15082 QCtype = intern (":type");
15083 staticpro (&QCtype);
a93f4566
GM
15084 QCconversion = intern (":conversion");
15085 staticpro (&QCconversion);
6fc2811b
JR
15086 QCheuristic_mask = intern (":heuristic-mask");
15087 staticpro (&QCheuristic_mask);
15088 QCcolor_symbols = intern (":color-symbols");
15089 staticpro (&QCcolor_symbols);
6fc2811b
JR
15090 QCascent = intern (":ascent");
15091 staticpro (&QCascent);
15092 QCmargin = intern (":margin");
15093 staticpro (&QCmargin);
15094 QCrelief = intern (":relief");
15095 staticpro (&QCrelief);
15096 Qpostscript = intern ("postscript");
15097 staticpro (&Qpostscript);
15098 QCloader = intern (":loader");
15099 staticpro (&QCloader);
15100 QCbounding_box = intern (":bounding-box");
15101 staticpro (&QCbounding_box);
15102 QCpt_width = intern (":pt-width");
15103 staticpro (&QCpt_width);
15104 QCpt_height = intern (":pt-height");
15105 staticpro (&QCpt_height);
15106 QCindex = intern (":index");
15107 staticpro (&QCindex);
15108 Qpbm = intern ("pbm");
15109 staticpro (&Qpbm);
15110
15111#if HAVE_XPM
15112 Qxpm = intern ("xpm");
15113 staticpro (&Qxpm);
15114#endif
15115
15116#if HAVE_JPEG
15117 Qjpeg = intern ("jpeg");
15118 staticpro (&Qjpeg);
15119#endif
15120
15121#if HAVE_TIFF
15122 Qtiff = intern ("tiff");
15123 staticpro (&Qtiff);
15124#endif
15125
15126#if HAVE_GIF
15127 Qgif = intern ("gif");
15128 staticpro (&Qgif);
15129#endif
15130
15131#if HAVE_PNG
15132 Qpng = intern ("png");
15133 staticpro (&Qpng);
15134#endif
15135
15136 defsubr (&Sclear_image_cache);
15137
15138#if GLYPH_DEBUG
15139 defsubr (&Simagep);
15140 defsubr (&Slookup_image);
15141#endif
767b1ff0 15142#endif /* TODO */
6fc2811b 15143
0af913d7
GM
15144 hourglass_atimer = NULL;
15145 hourglass_shown_p = 0;
6fc2811b
JR
15146 defsubr (&Sx_show_tip);
15147 defsubr (&Sx_hide_tip);
6fc2811b 15148 tip_timer = Qnil;
57fa2774
JR
15149 staticpro (&tip_timer);
15150 tip_frame = Qnil;
15151 staticpro (&tip_frame);
6fc2811b 15152
ca56d953
JR
15153 last_show_tip_args = Qnil;
15154 staticpro (&last_show_tip_args);
15155
6fc2811b
JR
15156 defsubr (&Sx_file_dialog);
15157}
15158
15159
15160void
15161init_xfns ()
15162{
15163 image_types = NULL;
15164 Vimage_types = Qnil;
15165
767b1ff0 15166#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
15167 define_image_type (&xbm_type);
15168 define_image_type (&gs_type);
15169 define_image_type (&pbm_type);
15170
15171#if HAVE_XPM
15172 define_image_type (&xpm_type);
15173#endif
15174
15175#if HAVE_JPEG
15176 define_image_type (&jpeg_type);
15177#endif
15178
15179#if HAVE_TIFF
15180 define_image_type (&tiff_type);
15181#endif
15182
15183#if HAVE_GIF
15184 define_image_type (&gif_type);
15185#endif
15186
15187#if HAVE_PNG
15188 define_image_type (&png_type);
15189#endif
767b1ff0 15190#endif /* TODO */
ee78dc32
GV
15191}
15192
15193#undef abort
15194
15195void
fbd6baed 15196w32_abort()
ee78dc32 15197{
5ac45f98
GV
15198 int button;
15199 button = MessageBox (NULL,
15200 "A fatal error has occurred!\n\n"
15201 "Select Abort to exit, Retry to debug, Ignore to continue",
15202 "Emacs Abort Dialog",
15203 MB_ICONEXCLAMATION | MB_TASKMODAL
15204 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15205 switch (button)
15206 {
15207 case IDRETRY:
15208 DebugBreak ();
15209 break;
15210 case IDIGNORE:
15211 break;
15212 case IDABORT:
15213 default:
15214 abort ();
15215 break;
15216 }
ee78dc32 15217}
d573caac 15218
83c75055
GV
15219/* For convenience when debugging. */
15220int
15221w32_last_error()
15222{
15223 return GetLastError ();
15224}