(x_set_cursor_color): Set cursor_gc as well.
[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;
6fc2811b 280
5ac45f98
GV
281/* State variables for emulating a three button mouse. */
282#define LMOUSE 1
283#define MMOUSE 2
284#define RMOUSE 4
285
286static int button_state = 0;
fbd6baed 287static W32Msg saved_mouse_button_msg;
48094ace 288static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
fbd6baed 289static W32Msg saved_mouse_move_msg;
48094ace 290static unsigned mouse_move_timer = 0;
84fb1139 291
9eb16b62
JR
292/* Window that is tracking the mouse. */
293static HWND track_mouse_window;
294FARPROC track_mouse_event_fn;
295
93fbe8b7
GV
296/* W95 mousewheel handler */
297unsigned int msh_mousewheel = 0;
298
48094ace 299/* Timers */
84fb1139
KH
300#define MOUSE_BUTTON_ID 1
301#define MOUSE_MOVE_ID 2
48094ace
JR
302#define MENU_FREE_ID 3
303/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
304 is received. */
305#define MENU_FREE_DELAY 1000
306static unsigned menu_free_timer = 0;
5ac45f98 307
ee78dc32 308/* The below are defined in frame.c. */
dfff8a69 309
ee78dc32 310extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 311extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 312extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
313
314extern Lisp_Object Vwindow_system_version;
315
4b817373
RS
316Lisp_Object Qface_set_after_frame_default;
317
937e601e
AI
318#ifdef GLYPH_DEBUG
319int image_cache_refcount, dpyinfo_refcount;
320#endif
321
322
fbd6baed
GV
323/* From w32term.c. */
324extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 325extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 326
65906840 327extern HWND w32_system_caret_hwnd;
93f2ca61 328
65906840
JR
329extern int w32_system_caret_height;
330extern int w32_system_caret_x;
331extern int w32_system_caret_y;
93f2ca61
JR
332extern int w32_use_visible_system_caret;
333
d285988b 334static HWND w32_visible_system_caret_hwnd;
65906840 335
ee78dc32 336\f
1edf84e7
GV
337/* Error if we are not connected to MS-Windows. */
338void
339check_w32 ()
340{
341 if (! w32_in_use)
342 error ("MS-Windows not in use or not initialized");
343}
344
345/* Nonzero if we can use mouse menus.
346 You should not call this unless HAVE_MENUS is defined. */
347
348int
349have_menus_p ()
350{
351 return w32_in_use;
352}
353
ee78dc32 354/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 355 and checking validity for W32. */
ee78dc32
GV
356
357FRAME_PTR
358check_x_frame (frame)
359 Lisp_Object frame;
360{
361 FRAME_PTR f;
362
363 if (NILP (frame))
6fc2811b 364 frame = selected_frame;
b7826503 365 CHECK_LIVE_FRAME (frame);
6fc2811b 366 f = XFRAME (frame);
fbd6baed
GV
367 if (! FRAME_W32_P (f))
368 error ("non-w32 frame used");
ee78dc32
GV
369 return f;
370}
371
372/* Let the user specify an display with a frame.
fbd6baed 373 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
374 the first display on the list. */
375
fbd6baed 376static struct w32_display_info *
ee78dc32
GV
377check_x_display_info (frame)
378 Lisp_Object frame;
379{
380 if (NILP (frame))
381 {
6fc2811b
JR
382 struct frame *sf = XFRAME (selected_frame);
383
384 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
385 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 386 else
fbd6baed 387 return &one_w32_display_info;
ee78dc32
GV
388 }
389 else if (STRINGP (frame))
390 return x_display_info_for_name (frame);
391 else
392 {
393 FRAME_PTR f;
394
b7826503 395 CHECK_LIVE_FRAME (frame);
ee78dc32 396 f = XFRAME (frame);
fbd6baed
GV
397 if (! FRAME_W32_P (f))
398 error ("non-w32 frame used");
399 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
400 }
401}
402\f
fbd6baed 403/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
404 It could be the frame's main window or an icon window. */
405
406/* This function can be called during GC, so use GC_xxx type test macros. */
407
408struct frame *
409x_window_to_frame (dpyinfo, wdesc)
fbd6baed 410 struct w32_display_info *dpyinfo;
ee78dc32
GV
411 HWND wdesc;
412{
413 Lisp_Object tail, frame;
414 struct frame *f;
415
8e713be6 416 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 417 {
8e713be6 418 frame = XCAR (tail);
ee78dc32
GV
419 if (!GC_FRAMEP (frame))
420 continue;
421 f = XFRAME (frame);
2d764c78 422 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 423 continue;
0af913d7 424 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
425 return f;
426
fbd6baed 427 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
428 return f;
429 }
430 return 0;
431}
432
433\f
434
435/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
436 id, which is just an int that this section returns. Bitmaps are
437 reference counted so they can be shared among frames.
438
439 Bitmap indices are guaranteed to be > 0, so a negative number can
440 be used to indicate no bitmap.
441
442 If you use x_create_bitmap_from_data, then you must keep track of
443 the bitmaps yourself. That is, creating a bitmap from the same
444 data more than once will not be caught. */
445
446
447/* Functions to access the contents of a bitmap, given an id. */
448
449int
450x_bitmap_height (f, id)
451 FRAME_PTR f;
452 int id;
453{
fbd6baed 454 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
455}
456
457int
458x_bitmap_width (f, id)
459 FRAME_PTR f;
460 int id;
461{
fbd6baed 462 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
463}
464
465int
466x_bitmap_pixmap (f, id)
467 FRAME_PTR f;
468 int id;
469{
fbd6baed 470 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
471}
472
473
474/* Allocate a new bitmap record. Returns index of new record. */
475
476static int
477x_allocate_bitmap_record (f)
478 FRAME_PTR f;
479{
fbd6baed 480 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
481 int i;
482
483 if (dpyinfo->bitmaps == NULL)
484 {
485 dpyinfo->bitmaps_size = 10;
486 dpyinfo->bitmaps
fbd6baed 487 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
488 dpyinfo->bitmaps_last = 1;
489 return 1;
490 }
491
492 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
493 return ++dpyinfo->bitmaps_last;
494
495 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
496 if (dpyinfo->bitmaps[i].refcount == 0)
497 return i + 1;
498
499 dpyinfo->bitmaps_size *= 2;
500 dpyinfo->bitmaps
fbd6baed
GV
501 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
502 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
503 return ++dpyinfo->bitmaps_last;
504}
505
506/* Add one reference to the reference count of the bitmap with id ID. */
507
508void
509x_reference_bitmap (f, id)
510 FRAME_PTR f;
511 int id;
512{
fbd6baed 513 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
514}
515
516/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
517
518int
519x_create_bitmap_from_data (f, bits, width, height)
520 struct frame *f;
521 char *bits;
522 unsigned int width, height;
523{
fbd6baed 524 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
525 Pixmap bitmap;
526 int id;
527
528 bitmap = CreateBitmap (width, height,
fbd6baed
GV
529 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
530 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
531 bits);
532
533 if (! bitmap)
534 return -1;
535
536 id = x_allocate_bitmap_record (f);
537 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
538 dpyinfo->bitmaps[id - 1].file = NULL;
539 dpyinfo->bitmaps[id - 1].hinst = NULL;
540 dpyinfo->bitmaps[id - 1].refcount = 1;
541 dpyinfo->bitmaps[id - 1].depth = 1;
542 dpyinfo->bitmaps[id - 1].height = height;
543 dpyinfo->bitmaps[id - 1].width = width;
544
545 return id;
546}
547
548/* Create bitmap from file FILE for frame F. */
549
550int
551x_create_bitmap_from_file (f, file)
552 struct frame *f;
553 Lisp_Object file;
554{
555 return -1;
767b1ff0 556#if 0 /* TODO : bitmap support */
fbd6baed 557 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 558 unsigned int width, height;
6fc2811b 559 HBITMAP bitmap;
ee78dc32
GV
560 int xhot, yhot, result, id;
561 Lisp_Object found;
562 int fd;
563 char *filename;
564 HINSTANCE hinst;
565
566 /* Look for an existing bitmap with the same name. */
567 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
568 {
569 if (dpyinfo->bitmaps[id].refcount
570 && dpyinfo->bitmaps[id].file
571 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
572 {
573 ++dpyinfo->bitmaps[id].refcount;
574 return id + 1;
575 }
576 }
577
578 /* Search bitmap-file-path for the file, if appropriate. */
c0ec53ad 579 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
ee78dc32
GV
580 if (fd < 0)
581 return -1;
6fc2811b 582 emacs_close (fd);
ee78dc32
GV
583
584 filename = (char *) XSTRING (found)->data;
585
586 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
587
588 if (hinst == NULL)
589 return -1;
590
591
fbd6baed 592 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
593 filename, &width, &height, &bitmap, &xhot, &yhot);
594 if (result != BitmapSuccess)
595 return -1;
596
597 id = x_allocate_bitmap_record (f);
598 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
599 dpyinfo->bitmaps[id - 1].refcount = 1;
600 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
601 dpyinfo->bitmaps[id - 1].depth = 1;
602 dpyinfo->bitmaps[id - 1].height = height;
603 dpyinfo->bitmaps[id - 1].width = width;
604 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
605
606 return id;
767b1ff0 607#endif /* TODO */
ee78dc32
GV
608}
609
610/* Remove reference to bitmap with id number ID. */
611
33d52f9c 612void
ee78dc32
GV
613x_destroy_bitmap (f, id)
614 FRAME_PTR f;
615 int id;
616{
fbd6baed 617 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
618
619 if (id > 0)
620 {
621 --dpyinfo->bitmaps[id - 1].refcount;
622 if (dpyinfo->bitmaps[id - 1].refcount == 0)
623 {
624 BLOCK_INPUT;
625 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
626 if (dpyinfo->bitmaps[id - 1].file)
627 {
6fc2811b 628 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
629 dpyinfo->bitmaps[id - 1].file = NULL;
630 }
631 UNBLOCK_INPUT;
632 }
633 }
634}
635
636/* Free all the bitmaps for the display specified by DPYINFO. */
637
638static void
639x_destroy_all_bitmaps (dpyinfo)
fbd6baed 640 struct w32_display_info *dpyinfo;
ee78dc32
GV
641{
642 int i;
643 for (i = 0; i < dpyinfo->bitmaps_last; i++)
644 if (dpyinfo->bitmaps[i].refcount > 0)
645 {
646 DeleteObject (dpyinfo->bitmaps[i].pixmap);
647 if (dpyinfo->bitmaps[i].file)
6fc2811b 648 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
649 }
650 dpyinfo->bitmaps_last = 0;
651}
652\f
fbd6baed 653/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
654 to the ways of passing the parameter values to the window system.
655
656 The name of a parameter, as a Lisp symbol,
657 has an `x-frame-parameter' property which is an integer in Lisp
658 but can be interpreted as an `enum x_frame_parm' in C. */
659
660enum x_frame_parm
661{
662 X_PARM_FOREGROUND_COLOR,
663 X_PARM_BACKGROUND_COLOR,
664 X_PARM_MOUSE_COLOR,
665 X_PARM_CURSOR_COLOR,
666 X_PARM_BORDER_COLOR,
667 X_PARM_ICON_TYPE,
668 X_PARM_FONT,
669 X_PARM_BORDER_WIDTH,
670 X_PARM_INTERNAL_BORDER_WIDTH,
671 X_PARM_NAME,
672 X_PARM_AUTORAISE,
673 X_PARM_AUTOLOWER,
674 X_PARM_VERT_SCROLL_BAR,
675 X_PARM_VISIBILITY,
676 X_PARM_MENU_BAR_LINES
677};
678
679
680struct x_frame_parm_table
681{
682 char *name;
6fc2811b 683 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
684};
685
ca56d953
JR
686BOOL my_show_window P_ ((struct frame *, HWND, int));
687void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
688static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
689static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
690static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 691/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 692void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 693static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
f7b9d4d1 694static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
695void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
698void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
701void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
702void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 703static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
704void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
706 Lisp_Object));
707void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
708void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
709void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
710void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
711 Lisp_Object));
712void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
713void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
714void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
715void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
716void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
717void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
718static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
719static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
720 Lisp_Object));
ee78dc32
GV
721
722static struct x_frame_parm_table x_frame_parms[] =
723{
72e4adef
JR
724 {"auto-raise", x_set_autoraise},
725 {"auto-lower", x_set_autolower},
726 {"background-color", x_set_background_color},
727 {"border-color", x_set_border_color},
728 {"border-width", x_set_border_width},
729 {"cursor-color", x_set_cursor_color},
730 {"cursor-type", x_set_cursor_type},
731 {"font", x_set_font},
732 {"foreground-color", x_set_foreground_color},
733 {"icon-name", x_set_icon_name},
734 {"icon-type", x_set_icon_type},
735 {"internal-border-width", x_set_internal_border_width},
736 {"menu-bar-lines", x_set_menu_bar_lines},
737 {"mouse-color", x_set_mouse_color},
738 {"name", x_explicitly_set_name},
739 {"scroll-bar-width", x_set_scroll_bar_width},
740 {"title", x_set_title},
741 {"unsplittable", x_set_unsplittable},
742 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
743 {"visibility", x_set_visibility},
744 {"tool-bar-lines", x_set_tool_bar_lines},
745 {"screen-gamma", x_set_screen_gamma},
746 {"line-spacing", x_set_line_spacing},
747 {"left-fringe", x_set_fringe_width},
f7b9d4d1
JR
748 {"right-fringe", x_set_fringe_width},
749 {"fullscreen", x_set_fullscreen},
ee78dc32
GV
750};
751
752/* Attach the `x-frame-parameter' properties to
fbd6baed 753 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 754
dfff8a69 755void
ee78dc32
GV
756init_x_parm_symbols ()
757{
758 int i;
759
760 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
761 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
762 make_number (i));
763}
764\f
f7b9d4d1
JR
765/* Really try to move where we want to be in case of fullscreen. Some WMs
766 moves the window where we tell them. Some (mwm, twm) moves the outer
767 window manager window there instead.
768 Try to compensate for those WM here. */
769static void
770x_fullscreen_move (f, new_top, new_left)
771 struct frame *f;
772 int new_top;
773 int new_left;
774{
775 if (new_top != f->output_data.w32->top_pos
776 || new_left != f->output_data.w32->left_pos)
777 {
778 int move_x = new_left;
779 int move_y = new_top;
780
781 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
782 x_set_offset (f, move_x, move_y, 1);
783 }
784}
785
dfff8a69 786/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
787 If a parameter is not specially recognized, do nothing;
788 otherwise call the `x_set_...' function for that parameter. */
789
790void
791x_set_frame_parameters (f, alist)
792 FRAME_PTR f;
793 Lisp_Object alist;
794{
795 Lisp_Object tail;
796
797 /* If both of these parameters are present, it's more efficient to
798 set them both at once. So we wait until we've looked at the
799 entire list before we set them. */
b839712d 800 int width, height;
ee78dc32
GV
801
802 /* Same here. */
803 Lisp_Object left, top;
804
805 /* Same with these. */
806 Lisp_Object icon_left, icon_top;
807
808 /* Record in these vectors all the parms specified. */
809 Lisp_Object *parms;
810 Lisp_Object *values;
a797a73d 811 int i, p;
ee78dc32
GV
812 int left_no_change = 0, top_no_change = 0;
813 int icon_left_no_change = 0, icon_top_no_change = 0;
f7b9d4d1 814 int fullscreen_is_being_set = 0;
ee78dc32 815
5878523b
RS
816 struct gcpro gcpro1, gcpro2;
817
ee78dc32
GV
818 i = 0;
819 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
820 i++;
821
822 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
823 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
824
825 /* Extract parm names and values into those vectors. */
826
827 i = 0;
828 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
829 {
6fc2811b 830 Lisp_Object elt;
ee78dc32
GV
831
832 elt = Fcar (tail);
833 parms[i] = Fcar (elt);
834 values[i] = Fcdr (elt);
835 i++;
836 }
5878523b
RS
837 /* TAIL and ALIST are not used again below here. */
838 alist = tail = Qnil;
839
840 GCPRO2 (*parms, *values);
841 gcpro1.nvars = i;
842 gcpro2.nvars = i;
843
844 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
845 because their values appear in VALUES and strings are not valid. */
b839712d 846 top = left = Qunbound;
ee78dc32
GV
847 icon_left = icon_top = Qunbound;
848
b839712d 849 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
850 if (FRAME_NEW_WIDTH (f))
851 width = FRAME_NEW_WIDTH (f);
852 else
853 width = FRAME_WIDTH (f);
854
855 if (FRAME_NEW_HEIGHT (f))
856 height = FRAME_NEW_HEIGHT (f);
857 else
858 height = FRAME_HEIGHT (f);
b839712d 859
a797a73d
GV
860 /* Process foreground_color and background_color before anything else.
861 They are independent of other properties, but other properties (e.g.,
862 cursor_color) are dependent upon them. */
41c1bdd9 863 /* Process default font as well, since fringe widths depends on it. */
a797a73d
GV
864 for (p = 0; p < i; p++)
865 {
866 Lisp_Object prop, val;
867
868 prop = parms[p];
869 val = values[p];
41c1bdd9
KS
870 if (EQ (prop, Qforeground_color)
871 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
872 || EQ (prop, Qfont)
873 || EQ (prop, Qfullscreen))
a797a73d
GV
874 {
875 register Lisp_Object param_index, old_value;
876
a797a73d 877 old_value = get_frame_param (f, prop);
f7b9d4d1 878 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
a05e2bae
JR
879
880 if (NILP (Fequal (val, old_value)))
881 {
882 store_frame_param (f, prop, val);
883
884 param_index = Fget (prop, Qx_frame_parameter);
885 if (NATNUMP (param_index)
886 && (XFASTINT (param_index)
887 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
888 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
889 }
a797a73d
GV
890 }
891 }
892
ee78dc32
GV
893 /* Now process them in reverse of specified order. */
894 for (i--; i >= 0; i--)
895 {
896 Lisp_Object prop, val;
897
898 prop = parms[i];
899 val = values[i];
900
b839712d
RS
901 if (EQ (prop, Qwidth) && NUMBERP (val))
902 width = XFASTINT (val);
903 else if (EQ (prop, Qheight) && NUMBERP (val))
904 height = XFASTINT (val);
ee78dc32
GV
905 else if (EQ (prop, Qtop))
906 top = val;
907 else if (EQ (prop, Qleft))
908 left = val;
909 else if (EQ (prop, Qicon_top))
910 icon_top = val;
911 else if (EQ (prop, Qicon_left))
912 icon_left = val;
41c1bdd9
KS
913 else if (EQ (prop, Qforeground_color)
914 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
915 || EQ (prop, Qfont)
916 || EQ (prop, Qfullscreen))
a797a73d
GV
917 /* Processed above. */
918 continue;
ee78dc32
GV
919 else
920 {
921 register Lisp_Object param_index, old_value;
922
ee78dc32 923 old_value = get_frame_param (f, prop);
a05e2bae 924
ee78dc32 925 store_frame_param (f, prop, val);
a05e2bae
JR
926
927 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
928 if (NATNUMP (param_index)
929 && (XFASTINT (param_index)
930 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 931 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
932 }
933 }
934
935 /* Don't die if just one of these was set. */
936 if (EQ (left, Qunbound))
937 {
938 left_no_change = 1;
fbd6baed
GV
939 if (f->output_data.w32->left_pos < 0)
940 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 941 else
fbd6baed 942 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
943 }
944 if (EQ (top, Qunbound))
945 {
946 top_no_change = 1;
fbd6baed
GV
947 if (f->output_data.w32->top_pos < 0)
948 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 949 else
fbd6baed 950 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
951 }
952
953 /* If one of the icon positions was not set, preserve or default it. */
954 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
955 {
956 icon_left_no_change = 1;
957 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
958 if (NILP (icon_left))
959 XSETINT (icon_left, 0);
960 }
961 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
962 {
963 icon_top_no_change = 1;
964 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
965 if (NILP (icon_top))
966 XSETINT (icon_top, 0);
967 }
968
f7b9d4d1
JR
969 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
970 {
971 /* If the frame is visible already and the fullscreen parameter is
972 being set, it is too late to set WM manager hints to specify
973 size and position.
974 Here we first get the width, height and position that applies to
975 fullscreen. We then move the frame to the appropriate
976 position. Resize of the frame is taken care of in the code after
977 this if-statement. */
978 int new_left, new_top;
979
980 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
981 x_fullscreen_move (f, new_top, new_left);
982 }
983
ee78dc32
GV
984 /* Don't set these parameters unless they've been explicitly
985 specified. The window might be mapped or resized while we're in
986 this function, and we don't want to override that unless the lisp
987 code has asked for it.
988
989 Don't set these parameters unless they actually differ from the
990 window's current parameters; the window may not actually exist
991 yet. */
992 {
993 Lisp_Object frame;
994
995 check_frame_size (f, &height, &width);
996
997 XSETFRAME (frame, f);
998
dfff8a69
JR
999 if (width != FRAME_WIDTH (f)
1000 || height != FRAME_HEIGHT (f)
1001 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 1002 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
1003
1004 if ((!NILP (left) || !NILP (top))
1005 && ! (left_no_change && top_no_change)
fbd6baed
GV
1006 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1007 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
1008 {
1009 int leftpos = 0;
1010 int toppos = 0;
1011
1012 /* Record the signs. */
fbd6baed 1013 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 1014 if (EQ (left, Qminus))
fbd6baed 1015 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
1016 else if (INTEGERP (left))
1017 {
1018 leftpos = XINT (left);
1019 if (leftpos < 0)
fbd6baed 1020 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1021 }
8e713be6
KR
1022 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1023 && CONSP (XCDR (left))
1024 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1025 {
8e713be6 1026 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 1027 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1028 }
8e713be6
KR
1029 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1030 && CONSP (XCDR (left))
1031 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1032 {
8e713be6 1033 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
1034 }
1035
1036 if (EQ (top, Qminus))
fbd6baed 1037 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
1038 else if (INTEGERP (top))
1039 {
1040 toppos = XINT (top);
1041 if (toppos < 0)
fbd6baed 1042 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1043 }
8e713be6
KR
1044 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1045 && CONSP (XCDR (top))
1046 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1047 {
8e713be6 1048 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 1049 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1050 }
8e713be6
KR
1051 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1052 && CONSP (XCDR (top))
1053 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1054 {
8e713be6 1055 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1056 }
1057
1058
1059 /* Store the numeric value of the position. */
fbd6baed
GV
1060 f->output_data.w32->top_pos = toppos;
1061 f->output_data.w32->left_pos = leftpos;
ee78dc32 1062
fbd6baed 1063 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1064
1065 /* Actually set that position, and convert to absolute. */
1066 x_set_offset (f, leftpos, toppos, -1);
1067 }
1068
1069 if ((!NILP (icon_left) || !NILP (icon_top))
1070 && ! (icon_left_no_change && icon_top_no_change))
1071 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1072 }
5878523b
RS
1073
1074 UNGCPRO;
ee78dc32
GV
1075}
1076
1077/* Store the screen positions of frame F into XPTR and YPTR.
1078 These are the positions of the containing window manager window,
1079 not Emacs's own window. */
1080
1081void
1082x_real_positions (f, xptr, yptr)
1083 FRAME_PTR f;
1084 int *xptr, *yptr;
1085{
1086 POINT pt;
f7b9d4d1 1087 RECT rect;
3c190163 1088
f7b9d4d1
JR
1089 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1090 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1091
1092 pt.x = rect.left;
1093 pt.y = rect.top;
ee78dc32 1094
fbd6baed 1095 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32 1096
f7b9d4d1
JR
1097 /* Remember x_pixels_diff and y_pixels_diff. */
1098 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1099 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1100
ee78dc32
GV
1101 *xptr = pt.x;
1102 *yptr = pt.y;
1103}
1104
1105/* Insert a description of internally-recorded parameters of frame X
1106 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1107 Only parameters that are specific to W32
ee78dc32
GV
1108 and whose values are not correctly recorded in the frame's
1109 param_alist need to be considered here. */
1110
dfff8a69 1111void
ee78dc32
GV
1112x_report_frame_params (f, alistptr)
1113 struct frame *f;
1114 Lisp_Object *alistptr;
1115{
1116 char buf[16];
1117 Lisp_Object tem;
1118
1119 /* Represent negative positions (off the top or left screen edge)
1120 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1121 XSETINT (tem, f->output_data.w32->left_pos);
1122 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1123 store_in_alist (alistptr, Qleft, tem);
1124 else
1125 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1126
fbd6baed
GV
1127 XSETINT (tem, f->output_data.w32->top_pos);
1128 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1129 store_in_alist (alistptr, Qtop, tem);
1130 else
1131 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1132
1133 store_in_alist (alistptr, Qborder_width,
fbd6baed 1134 make_number (f->output_data.w32->border_width));
ee78dc32 1135 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1136 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1137 store_in_alist (alistptr, Qleft_fringe,
1138 make_number (f->output_data.w32->left_fringe_width));
1139 store_in_alist (alistptr, Qright_fringe,
1140 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1141 store_in_alist (alistptr, Qscroll_bar_width,
1142 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1143 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1144 : 0));
fbd6baed 1145 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1146 store_in_alist (alistptr, Qwindow_id,
1147 build_string (buf));
1148 store_in_alist (alistptr, Qicon_name, f->icon_name);
1149 FRAME_SAMPLE_VISIBILITY (f);
1150 store_in_alist (alistptr, Qvisibility,
1151 (FRAME_VISIBLE_P (f) ? Qt
1152 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1153 store_in_alist (alistptr, Qdisplay,
8e713be6 1154 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1155}
1156\f
1157
74e1aeec
JR
1158DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1159 Sw32_define_rgb_color, 4, 4, 0,
1160 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1161This adds or updates a named color to w32-color-map, making it
1162available for use. The original entry's RGB ref is returned, or nil
1163if the entry is new. */)
5ac45f98
GV
1164 (red, green, blue, name)
1165 Lisp_Object red, green, blue, name;
ee78dc32 1166{
5ac45f98
GV
1167 Lisp_Object rgb;
1168 Lisp_Object oldrgb = Qnil;
1169 Lisp_Object entry;
1170
b7826503
PJ
1171 CHECK_NUMBER (red);
1172 CHECK_NUMBER (green);
1173 CHECK_NUMBER (blue);
1174 CHECK_STRING (name);
ee78dc32 1175
5ac45f98 1176 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1177
5ac45f98 1178 BLOCK_INPUT;
ee78dc32 1179
fbd6baed
GV
1180 /* replace existing entry in w32-color-map or add new entry. */
1181 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1182 if (NILP (entry))
1183 {
1184 entry = Fcons (name, rgb);
fbd6baed 1185 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1186 }
1187 else
1188 {
1189 oldrgb = Fcdr (entry);
1190 Fsetcdr (entry, rgb);
1191 }
1192
1193 UNBLOCK_INPUT;
1194
1195 return (oldrgb);
ee78dc32
GV
1196}
1197
74e1aeec
JR
1198DEFUN ("w32-load-color-file", Fw32_load_color_file,
1199 Sw32_load_color_file, 1, 1, 0,
1200 doc: /* Create an alist of color entries from an external file.
1201Assign this value to w32-color-map to replace the existing color map.
1202
1203The file should define one named RGB color per line like so:
1204 R G B name
1205where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1206 (filename)
1207 Lisp_Object filename;
1208{
1209 FILE *fp;
1210 Lisp_Object cmap = Qnil;
1211 Lisp_Object abspath;
1212
b7826503 1213 CHECK_STRING (filename);
5ac45f98
GV
1214 abspath = Fexpand_file_name (filename, Qnil);
1215
1216 fp = fopen (XSTRING (filename)->data, "rt");
1217 if (fp)
1218 {
1219 char buf[512];
1220 int red, green, blue;
1221 int num;
1222
1223 BLOCK_INPUT;
1224
1225 while (fgets (buf, sizeof (buf), fp) != NULL) {
1226 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1227 {
1228 char *name = buf + num;
1229 num = strlen (name) - 1;
1230 if (name[num] == '\n')
1231 name[num] = 0;
1232 cmap = Fcons (Fcons (build_string (name),
1233 make_number (RGB (red, green, blue))),
1234 cmap);
1235 }
1236 }
1237 fclose (fp);
1238
1239 UNBLOCK_INPUT;
1240 }
1241
1242 return cmap;
1243}
ee78dc32 1244
fbd6baed 1245/* The default colors for the w32 color map */
ee78dc32
GV
1246typedef struct colormap_t
1247{
1248 char *name;
1249 COLORREF colorref;
1250} colormap_t;
1251
fbd6baed 1252colormap_t w32_color_map[] =
ee78dc32 1253{
1da8a614
GV
1254 {"snow" , PALETTERGB (255,250,250)},
1255 {"ghost white" , PALETTERGB (248,248,255)},
1256 {"GhostWhite" , PALETTERGB (248,248,255)},
1257 {"white smoke" , PALETTERGB (245,245,245)},
1258 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1259 {"gainsboro" , PALETTERGB (220,220,220)},
1260 {"floral white" , PALETTERGB (255,250,240)},
1261 {"FloralWhite" , PALETTERGB (255,250,240)},
1262 {"old lace" , PALETTERGB (253,245,230)},
1263 {"OldLace" , PALETTERGB (253,245,230)},
1264 {"linen" , PALETTERGB (250,240,230)},
1265 {"antique white" , PALETTERGB (250,235,215)},
1266 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1267 {"papaya whip" , PALETTERGB (255,239,213)},
1268 {"PapayaWhip" , PALETTERGB (255,239,213)},
1269 {"blanched almond" , PALETTERGB (255,235,205)},
1270 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1271 {"bisque" , PALETTERGB (255,228,196)},
1272 {"peach puff" , PALETTERGB (255,218,185)},
1273 {"PeachPuff" , PALETTERGB (255,218,185)},
1274 {"navajo white" , PALETTERGB (255,222,173)},
1275 {"NavajoWhite" , PALETTERGB (255,222,173)},
1276 {"moccasin" , PALETTERGB (255,228,181)},
1277 {"cornsilk" , PALETTERGB (255,248,220)},
1278 {"ivory" , PALETTERGB (255,255,240)},
1279 {"lemon chiffon" , PALETTERGB (255,250,205)},
1280 {"LemonChiffon" , PALETTERGB (255,250,205)},
1281 {"seashell" , PALETTERGB (255,245,238)},
1282 {"honeydew" , PALETTERGB (240,255,240)},
1283 {"mint cream" , PALETTERGB (245,255,250)},
1284 {"MintCream" , PALETTERGB (245,255,250)},
1285 {"azure" , PALETTERGB (240,255,255)},
1286 {"alice blue" , PALETTERGB (240,248,255)},
1287 {"AliceBlue" , PALETTERGB (240,248,255)},
1288 {"lavender" , PALETTERGB (230,230,250)},
1289 {"lavender blush" , PALETTERGB (255,240,245)},
1290 {"LavenderBlush" , PALETTERGB (255,240,245)},
1291 {"misty rose" , PALETTERGB (255,228,225)},
1292 {"MistyRose" , PALETTERGB (255,228,225)},
1293 {"white" , PALETTERGB (255,255,255)},
1294 {"black" , PALETTERGB ( 0, 0, 0)},
1295 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1296 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1297 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1298 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1299 {"dim gray" , PALETTERGB (105,105,105)},
1300 {"DimGray" , PALETTERGB (105,105,105)},
1301 {"dim grey" , PALETTERGB (105,105,105)},
1302 {"DimGrey" , PALETTERGB (105,105,105)},
1303 {"slate gray" , PALETTERGB (112,128,144)},
1304 {"SlateGray" , PALETTERGB (112,128,144)},
1305 {"slate grey" , PALETTERGB (112,128,144)},
1306 {"SlateGrey" , PALETTERGB (112,128,144)},
1307 {"light slate gray" , PALETTERGB (119,136,153)},
1308 {"LightSlateGray" , PALETTERGB (119,136,153)},
1309 {"light slate grey" , PALETTERGB (119,136,153)},
1310 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1311 {"gray" , PALETTERGB (190,190,190)},
1312 {"grey" , PALETTERGB (190,190,190)},
1313 {"light grey" , PALETTERGB (211,211,211)},
1314 {"LightGrey" , PALETTERGB (211,211,211)},
1315 {"light gray" , PALETTERGB (211,211,211)},
1316 {"LightGray" , PALETTERGB (211,211,211)},
1317 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1318 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1319 {"navy" , PALETTERGB ( 0, 0,128)},
1320 {"navy blue" , PALETTERGB ( 0, 0,128)},
1321 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1322 {"cornflower blue" , PALETTERGB (100,149,237)},
1323 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1324 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1325 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1326 {"slate blue" , PALETTERGB (106, 90,205)},
1327 {"SlateBlue" , PALETTERGB (106, 90,205)},
1328 {"medium slate blue" , PALETTERGB (123,104,238)},
1329 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1330 {"light slate blue" , PALETTERGB (132,112,255)},
1331 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1332 {"medium blue" , PALETTERGB ( 0, 0,205)},
1333 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1334 {"royal blue" , PALETTERGB ( 65,105,225)},
1335 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1336 {"blue" , PALETTERGB ( 0, 0,255)},
1337 {"dodger blue" , PALETTERGB ( 30,144,255)},
1338 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1339 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1340 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1341 {"sky blue" , PALETTERGB (135,206,235)},
1342 {"SkyBlue" , PALETTERGB (135,206,235)},
1343 {"light sky blue" , PALETTERGB (135,206,250)},
1344 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1345 {"steel blue" , PALETTERGB ( 70,130,180)},
1346 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1347 {"light steel blue" , PALETTERGB (176,196,222)},
1348 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1349 {"light blue" , PALETTERGB (173,216,230)},
1350 {"LightBlue" , PALETTERGB (173,216,230)},
1351 {"powder blue" , PALETTERGB (176,224,230)},
1352 {"PowderBlue" , PALETTERGB (176,224,230)},
1353 {"pale turquoise" , PALETTERGB (175,238,238)},
1354 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1355 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1356 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1357 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1358 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1359 {"turquoise" , PALETTERGB ( 64,224,208)},
1360 {"cyan" , PALETTERGB ( 0,255,255)},
1361 {"light cyan" , PALETTERGB (224,255,255)},
1362 {"LightCyan" , PALETTERGB (224,255,255)},
1363 {"cadet blue" , PALETTERGB ( 95,158,160)},
1364 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1365 {"medium aquamarine" , PALETTERGB (102,205,170)},
1366 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1367 {"aquamarine" , PALETTERGB (127,255,212)},
1368 {"dark green" , PALETTERGB ( 0,100, 0)},
1369 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1370 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1371 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1372 {"dark sea green" , PALETTERGB (143,188,143)},
1373 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1374 {"sea green" , PALETTERGB ( 46,139, 87)},
1375 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1376 {"medium sea green" , PALETTERGB ( 60,179,113)},
1377 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1378 {"light sea green" , PALETTERGB ( 32,178,170)},
1379 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1380 {"pale green" , PALETTERGB (152,251,152)},
1381 {"PaleGreen" , PALETTERGB (152,251,152)},
1382 {"spring green" , PALETTERGB ( 0,255,127)},
1383 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1384 {"lawn green" , PALETTERGB (124,252, 0)},
1385 {"LawnGreen" , PALETTERGB (124,252, 0)},
1386 {"green" , PALETTERGB ( 0,255, 0)},
1387 {"chartreuse" , PALETTERGB (127,255, 0)},
1388 {"medium spring green" , PALETTERGB ( 0,250,154)},
1389 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1390 {"green yellow" , PALETTERGB (173,255, 47)},
1391 {"GreenYellow" , PALETTERGB (173,255, 47)},
1392 {"lime green" , PALETTERGB ( 50,205, 50)},
1393 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1394 {"yellow green" , PALETTERGB (154,205, 50)},
1395 {"YellowGreen" , PALETTERGB (154,205, 50)},
1396 {"forest green" , PALETTERGB ( 34,139, 34)},
1397 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1398 {"olive drab" , PALETTERGB (107,142, 35)},
1399 {"OliveDrab" , PALETTERGB (107,142, 35)},
1400 {"dark khaki" , PALETTERGB (189,183,107)},
1401 {"DarkKhaki" , PALETTERGB (189,183,107)},
1402 {"khaki" , PALETTERGB (240,230,140)},
1403 {"pale goldenrod" , PALETTERGB (238,232,170)},
1404 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1405 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1406 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1407 {"light yellow" , PALETTERGB (255,255,224)},
1408 {"LightYellow" , PALETTERGB (255,255,224)},
1409 {"yellow" , PALETTERGB (255,255, 0)},
1410 {"gold" , PALETTERGB (255,215, 0)},
1411 {"light goldenrod" , PALETTERGB (238,221,130)},
1412 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1413 {"goldenrod" , PALETTERGB (218,165, 32)},
1414 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1415 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1416 {"rosy brown" , PALETTERGB (188,143,143)},
1417 {"RosyBrown" , PALETTERGB (188,143,143)},
1418 {"indian red" , PALETTERGB (205, 92, 92)},
1419 {"IndianRed" , PALETTERGB (205, 92, 92)},
1420 {"saddle brown" , PALETTERGB (139, 69, 19)},
1421 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1422 {"sienna" , PALETTERGB (160, 82, 45)},
1423 {"peru" , PALETTERGB (205,133, 63)},
1424 {"burlywood" , PALETTERGB (222,184,135)},
1425 {"beige" , PALETTERGB (245,245,220)},
1426 {"wheat" , PALETTERGB (245,222,179)},
1427 {"sandy brown" , PALETTERGB (244,164, 96)},
1428 {"SandyBrown" , PALETTERGB (244,164, 96)},
1429 {"tan" , PALETTERGB (210,180,140)},
1430 {"chocolate" , PALETTERGB (210,105, 30)},
1431 {"firebrick" , PALETTERGB (178,34, 34)},
1432 {"brown" , PALETTERGB (165,42, 42)},
1433 {"dark salmon" , PALETTERGB (233,150,122)},
1434 {"DarkSalmon" , PALETTERGB (233,150,122)},
1435 {"salmon" , PALETTERGB (250,128,114)},
1436 {"light salmon" , PALETTERGB (255,160,122)},
1437 {"LightSalmon" , PALETTERGB (255,160,122)},
1438 {"orange" , PALETTERGB (255,165, 0)},
1439 {"dark orange" , PALETTERGB (255,140, 0)},
1440 {"DarkOrange" , PALETTERGB (255,140, 0)},
1441 {"coral" , PALETTERGB (255,127, 80)},
1442 {"light coral" , PALETTERGB (240,128,128)},
1443 {"LightCoral" , PALETTERGB (240,128,128)},
1444 {"tomato" , PALETTERGB (255, 99, 71)},
1445 {"orange red" , PALETTERGB (255, 69, 0)},
1446 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1447 {"red" , PALETTERGB (255, 0, 0)},
1448 {"hot pink" , PALETTERGB (255,105,180)},
1449 {"HotPink" , PALETTERGB (255,105,180)},
1450 {"deep pink" , PALETTERGB (255, 20,147)},
1451 {"DeepPink" , PALETTERGB (255, 20,147)},
1452 {"pink" , PALETTERGB (255,192,203)},
1453 {"light pink" , PALETTERGB (255,182,193)},
1454 {"LightPink" , PALETTERGB (255,182,193)},
1455 {"pale violet red" , PALETTERGB (219,112,147)},
1456 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1457 {"maroon" , PALETTERGB (176, 48, 96)},
1458 {"medium violet red" , PALETTERGB (199, 21,133)},
1459 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1460 {"violet red" , PALETTERGB (208, 32,144)},
1461 {"VioletRed" , PALETTERGB (208, 32,144)},
1462 {"magenta" , PALETTERGB (255, 0,255)},
1463 {"violet" , PALETTERGB (238,130,238)},
1464 {"plum" , PALETTERGB (221,160,221)},
1465 {"orchid" , PALETTERGB (218,112,214)},
1466 {"medium orchid" , PALETTERGB (186, 85,211)},
1467 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1468 {"dark orchid" , PALETTERGB (153, 50,204)},
1469 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1470 {"dark violet" , PALETTERGB (148, 0,211)},
1471 {"DarkViolet" , PALETTERGB (148, 0,211)},
1472 {"blue violet" , PALETTERGB (138, 43,226)},
1473 {"BlueViolet" , PALETTERGB (138, 43,226)},
1474 {"purple" , PALETTERGB (160, 32,240)},
1475 {"medium purple" , PALETTERGB (147,112,219)},
1476 {"MediumPurple" , PALETTERGB (147,112,219)},
1477 {"thistle" , PALETTERGB (216,191,216)},
1478 {"gray0" , PALETTERGB ( 0, 0, 0)},
1479 {"grey0" , PALETTERGB ( 0, 0, 0)},
1480 {"dark grey" , PALETTERGB (169,169,169)},
1481 {"DarkGrey" , PALETTERGB (169,169,169)},
1482 {"dark gray" , PALETTERGB (169,169,169)},
1483 {"DarkGray" , PALETTERGB (169,169,169)},
1484 {"dark blue" , PALETTERGB ( 0, 0,139)},
1485 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1486 {"dark cyan" , PALETTERGB ( 0,139,139)},
1487 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1488 {"dark magenta" , PALETTERGB (139, 0,139)},
1489 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1490 {"dark red" , PALETTERGB (139, 0, 0)},
1491 {"DarkRed" , PALETTERGB (139, 0, 0)},
1492 {"light green" , PALETTERGB (144,238,144)},
1493 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1494};
1495
fbd6baed 1496DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1497 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1498 ()
1499{
1500 int i;
fbd6baed 1501 colormap_t *pc = w32_color_map;
ee78dc32
GV
1502 Lisp_Object cmap;
1503
1504 BLOCK_INPUT;
1505
1506 cmap = Qnil;
1507
fbd6baed 1508 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1509 pc++, i++)
1510 cmap = Fcons (Fcons (build_string (pc->name),
1511 make_number (pc->colorref)),
1512 cmap);
1513
1514 UNBLOCK_INPUT;
1515
1516 return (cmap);
1517}
ee78dc32
GV
1518
1519Lisp_Object
fbd6baed 1520w32_to_x_color (rgb)
ee78dc32
GV
1521 Lisp_Object rgb;
1522{
1523 Lisp_Object color;
1524
b7826503 1525 CHECK_NUMBER (rgb);
ee78dc32
GV
1526
1527 BLOCK_INPUT;
1528
fbd6baed 1529 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1530
1531 UNBLOCK_INPUT;
1532
1533 if (!NILP (color))
1534 return (Fcar (color));
1535 else
1536 return Qnil;
1537}
1538
5d7fed93
GV
1539COLORREF
1540w32_color_map_lookup (colorname)
1541 char *colorname;
1542{
1543 Lisp_Object tail, ret = Qnil;
1544
1545 BLOCK_INPUT;
1546
1547 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1548 {
1549 register Lisp_Object elt, tem;
1550
1551 elt = Fcar (tail);
1552 if (!CONSP (elt)) continue;
1553
1554 tem = Fcar (elt);
1555
1556 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1557 {
1558 ret = XUINT (Fcdr (elt));
1559 break;
1560 }
1561
1562 QUIT;
1563 }
1564
1565
1566 UNBLOCK_INPUT;
1567
1568 return ret;
1569}
1570
ee78dc32 1571COLORREF
fbd6baed 1572x_to_w32_color (colorname)
ee78dc32
GV
1573 char * colorname;
1574{
8edb0a6f
JR
1575 register Lisp_Object ret = Qnil;
1576
ee78dc32 1577 BLOCK_INPUT;
1edf84e7
GV
1578
1579 if (colorname[0] == '#')
1580 {
1581 /* Could be an old-style RGB Device specification. */
1582 char *color;
1583 int size;
1584 color = colorname + 1;
1585
1586 size = strlen(color);
1587 if (size == 3 || size == 6 || size == 9 || size == 12)
1588 {
1589 UINT colorval;
1590 int i, pos;
1591 pos = 0;
1592 size /= 3;
1593 colorval = 0;
1594
1595 for (i = 0; i < 3; i++)
1596 {
1597 char *end;
1598 char t;
1599 unsigned long value;
1600
1601 /* The check for 'x' in the following conditional takes into
1602 account the fact that strtol allows a "0x" in front of
1603 our numbers, and we don't. */
1604 if (!isxdigit(color[0]) || color[1] == 'x')
1605 break;
1606 t = color[size];
1607 color[size] = '\0';
1608 value = strtoul(color, &end, 16);
1609 color[size] = t;
1610 if (errno == ERANGE || end - color != size)
1611 break;
1612 switch (size)
1613 {
1614 case 1:
1615 value = value * 0x10;
1616 break;
1617 case 2:
1618 break;
1619 case 3:
1620 value /= 0x10;
1621 break;
1622 case 4:
1623 value /= 0x100;
1624 break;
1625 }
1626 colorval |= (value << pos);
1627 pos += 0x8;
1628 if (i == 2)
1629 {
1630 UNBLOCK_INPUT;
1631 return (colorval);
1632 }
1633 color = end;
1634 }
1635 }
1636 }
1637 else if (strnicmp(colorname, "rgb:", 4) == 0)
1638 {
1639 char *color;
1640 UINT colorval;
1641 int i, pos;
1642 pos = 0;
1643
1644 colorval = 0;
1645 color = colorname + 4;
1646 for (i = 0; i < 3; i++)
1647 {
1648 char *end;
1649 unsigned long value;
1650
1651 /* The check for 'x' in the following conditional takes into
1652 account the fact that strtol allows a "0x" in front of
1653 our numbers, and we don't. */
1654 if (!isxdigit(color[0]) || color[1] == 'x')
1655 break;
1656 value = strtoul(color, &end, 16);
1657 if (errno == ERANGE)
1658 break;
1659 switch (end - color)
1660 {
1661 case 1:
1662 value = value * 0x10 + value;
1663 break;
1664 case 2:
1665 break;
1666 case 3:
1667 value /= 0x10;
1668 break;
1669 case 4:
1670 value /= 0x100;
1671 break;
1672 default:
1673 value = ULONG_MAX;
1674 }
1675 if (value == ULONG_MAX)
1676 break;
1677 colorval |= (value << pos);
1678 pos += 0x8;
1679 if (i == 2)
1680 {
1681 if (*end != '\0')
1682 break;
1683 UNBLOCK_INPUT;
1684 return (colorval);
1685 }
1686 if (*end != '/')
1687 break;
1688 color = end + 1;
1689 }
1690 }
1691 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1692 {
1693 /* This is an RGB Intensity specification. */
1694 char *color;
1695 UINT colorval;
1696 int i, pos;
1697 pos = 0;
1698
1699 colorval = 0;
1700 color = colorname + 5;
1701 for (i = 0; i < 3; i++)
1702 {
1703 char *end;
1704 double value;
1705 UINT val;
1706
1707 value = strtod(color, &end);
1708 if (errno == ERANGE)
1709 break;
1710 if (value < 0.0 || value > 1.0)
1711 break;
1712 val = (UINT)(0x100 * value);
1713 /* We used 0x100 instead of 0xFF to give an continuous
1714 range between 0.0 and 1.0 inclusive. The next statement
1715 fixes the 1.0 case. */
1716 if (val == 0x100)
1717 val = 0xFF;
1718 colorval |= (val << pos);
1719 pos += 0x8;
1720 if (i == 2)
1721 {
1722 if (*end != '\0')
1723 break;
1724 UNBLOCK_INPUT;
1725 return (colorval);
1726 }
1727 if (*end != '/')
1728 break;
1729 color = end + 1;
1730 }
1731 }
1732 /* I am not going to attempt to handle any of the CIE color schemes
1733 or TekHVC, since I don't know the algorithms for conversion to
1734 RGB. */
f695b4b1
GV
1735
1736 /* If we fail to lookup the color name in w32_color_map, then check the
1737 colorname to see if it can be crudely approximated: If the X color
1738 ends in a number (e.g., "darkseagreen2"), strip the number and
1739 return the result of looking up the base color name. */
1740 ret = w32_color_map_lookup (colorname);
1741 if (NILP (ret))
ee78dc32 1742 {
f695b4b1 1743 int len = strlen (colorname);
ee78dc32 1744
f695b4b1
GV
1745 if (isdigit (colorname[len - 1]))
1746 {
8b77111c 1747 char *ptr, *approx = alloca (len + 1);
ee78dc32 1748
f695b4b1
GV
1749 strcpy (approx, colorname);
1750 ptr = &approx[len - 1];
1751 while (ptr > approx && isdigit (*ptr))
1752 *ptr-- = '\0';
ee78dc32 1753
f695b4b1 1754 ret = w32_color_map_lookup (approx);
ee78dc32 1755 }
ee78dc32
GV
1756 }
1757
1758 UNBLOCK_INPUT;
ee78dc32
GV
1759 return ret;
1760}
1761
5ac45f98
GV
1762
1763void
fbd6baed 1764w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1765{
fbd6baed 1766 struct w32_palette_entry * list;
5ac45f98
GV
1767 LOGPALETTE * log_palette;
1768 HPALETTE new_palette;
1769 int i;
1770
1771 /* don't bother trying to create palette if not supported */
fbd6baed 1772 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1773 return;
1774
1775 log_palette = (LOGPALETTE *)
1776 alloca (sizeof (LOGPALETTE) +
fbd6baed 1777 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1778 log_palette->palVersion = 0x300;
fbd6baed 1779 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1780
fbd6baed 1781 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1782 for (i = 0;
fbd6baed 1783 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1784 i++, list = list->next)
1785 log_palette->palPalEntry[i] = list->entry;
1786
1787 new_palette = CreatePalette (log_palette);
1788
1789 enter_crit ();
1790
fbd6baed
GV
1791 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1792 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1793 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1794
1795 /* Realize display palette and garbage all frames. */
1796 release_frame_dc (f, get_frame_dc (f));
1797
1798 leave_crit ();
1799}
1800
fbd6baed
GV
1801#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1802#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1803 do \
1804 { \
1805 pe.peRed = GetRValue (color); \
1806 pe.peGreen = GetGValue (color); \
1807 pe.peBlue = GetBValue (color); \
1808 pe.peFlags = 0; \
1809 } while (0)
1810
1811#if 0
1812/* Keep these around in case we ever want to track color usage. */
1813void
fbd6baed 1814w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1815{
fbd6baed 1816 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1817
fbd6baed 1818 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1819 return;
1820
1821 /* check if color is already mapped */
1822 while (list)
1823 {
fbd6baed 1824 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1825 {
1826 ++list->refcount;
1827 return;
1828 }
1829 list = list->next;
1830 }
1831
1832 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1833 list = (struct w32_palette_entry *)
1834 xmalloc (sizeof (struct w32_palette_entry));
1835 SET_W32_COLOR (list->entry, color);
5ac45f98 1836 list->refcount = 1;
fbd6baed
GV
1837 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1838 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1839 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1840
1841 /* set flag that palette must be regenerated */
fbd6baed 1842 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1843}
1844
1845void
fbd6baed 1846w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1847{
fbd6baed
GV
1848 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1849 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1850
fbd6baed 1851 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1852 return;
1853
1854 /* check if color is already mapped */
1855 while (list)
1856 {
fbd6baed 1857 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1858 {
1859 if (--list->refcount == 0)
1860 {
1861 *prev = list->next;
1862 xfree (list);
fbd6baed 1863 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1864 break;
1865 }
1866 else
1867 return;
1868 }
1869 prev = &list->next;
1870 list = list->next;
1871 }
1872
1873 /* set flag that palette must be regenerated */
fbd6baed 1874 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1875}
1876#endif
1877
6fc2811b
JR
1878
1879/* Gamma-correct COLOR on frame F. */
1880
1881void
1882gamma_correct (f, color)
1883 struct frame *f;
1884 COLORREF *color;
1885{
1886 if (f->gamma)
1887 {
1888 *color = PALETTERGB (
1889 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1890 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1891 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1892 }
1893}
1894
1895
ee78dc32
GV
1896/* Decide if color named COLOR is valid for the display associated with
1897 the selected frame; if so, return the rgb values in COLOR_DEF.
1898 If ALLOC is nonzero, allocate a new colormap cell. */
1899
1900int
6fc2811b 1901w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1902 FRAME_PTR f;
1903 char *color;
6fc2811b 1904 XColor *color_def;
ee78dc32
GV
1905 int alloc;
1906{
1907 register Lisp_Object tem;
6fc2811b 1908 COLORREF w32_color_ref;
3c190163 1909
fbd6baed 1910 tem = x_to_w32_color (color);
3c190163 1911
ee78dc32
GV
1912 if (!NILP (tem))
1913 {
d88c567c
JR
1914 if (f)
1915 {
1916 /* Apply gamma correction. */
1917 w32_color_ref = XUINT (tem);
1918 gamma_correct (f, &w32_color_ref);
1919 XSETINT (tem, w32_color_ref);
1920 }
9badad41
JR
1921
1922 /* Map this color to the palette if it is enabled. */
fbd6baed 1923 if (!NILP (Vw32_enable_palette))
5ac45f98 1924 {
fbd6baed 1925 struct w32_palette_entry * entry =
d88c567c 1926 one_w32_display_info.color_list;
fbd6baed 1927 struct w32_palette_entry ** prev =
d88c567c 1928 &one_w32_display_info.color_list;
5ac45f98
GV
1929
1930 /* check if color is already mapped */
1931 while (entry)
1932 {
fbd6baed 1933 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1934 break;
1935 prev = &entry->next;
1936 entry = entry->next;
1937 }
1938
1939 if (entry == NULL && alloc)
1940 {
1941 /* not already mapped, so add to list */
fbd6baed
GV
1942 entry = (struct w32_palette_entry *)
1943 xmalloc (sizeof (struct w32_palette_entry));
1944 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1945 entry->next = NULL;
1946 *prev = entry;
d88c567c 1947 one_w32_display_info.num_colors++;
5ac45f98
GV
1948
1949 /* set flag that palette must be regenerated */
d88c567c 1950 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1951 }
1952 }
1953 /* Ensure COLORREF value is snapped to nearest color in (default)
1954 palette by simulating the PALETTERGB macro. This works whether
1955 or not the display device has a palette. */
6fc2811b
JR
1956 w32_color_ref = XUINT (tem) | 0x2000000;
1957
6fc2811b
JR
1958 color_def->pixel = w32_color_ref;
1959 color_def->red = GetRValue (w32_color_ref);
1960 color_def->green = GetGValue (w32_color_ref);
1961 color_def->blue = GetBValue (w32_color_ref);
1962
ee78dc32 1963 return 1;
5ac45f98 1964 }
7fb46567 1965 else
3c190163
GV
1966 {
1967 return 0;
1968 }
ee78dc32
GV
1969}
1970
1971/* Given a string ARG naming a color, compute a pixel value from it
1972 suitable for screen F.
1973 If F is not a color screen, return DEF (default) regardless of what
1974 ARG says. */
1975
1976int
1977x_decode_color (f, arg, def)
1978 FRAME_PTR f;
1979 Lisp_Object arg;
1980 int def;
1981{
6fc2811b 1982 XColor cdef;
ee78dc32 1983
b7826503 1984 CHECK_STRING (arg);
ee78dc32
GV
1985
1986 if (strcmp (XSTRING (arg)->data, "black") == 0)
1987 return BLACK_PIX_DEFAULT (f);
1988 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1989 return WHITE_PIX_DEFAULT (f);
1990
fbd6baed 1991 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1992 return def;
1993
6fc2811b 1994 /* w32_defined_color is responsible for coping with failures
ee78dc32 1995 by looking for a near-miss. */
6fc2811b
JR
1996 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1997 return cdef.pixel;
ee78dc32
GV
1998
1999 /* defined_color failed; return an ultimate default. */
2000 return def;
2001}
2002\f
dfff8a69
JR
2003/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2004 the previous value of that parameter, NEW_VALUE is the new value. */
2005
2006static void
2007x_set_line_spacing (f, new_value, old_value)
2008 struct frame *f;
2009 Lisp_Object new_value, old_value;
2010{
2011 if (NILP (new_value))
2012 f->extra_line_spacing = 0;
2013 else if (NATNUMP (new_value))
2014 f->extra_line_spacing = XFASTINT (new_value);
2015 else
1a948b17 2016 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
2017 Fcons (new_value, Qnil)));
2018 if (FRAME_VISIBLE_P (f))
2019 redraw_frame (f);
2020}
2021
2022
f7b9d4d1
JR
2023/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2024 the previous value of that parameter, NEW_VALUE is the new value. */
2025
2026static void
2027x_set_fullscreen (f, new_value, old_value)
2028 struct frame *f;
2029 Lisp_Object new_value, old_value;
2030{
2031 if (NILP (new_value))
2032 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2033 else if (EQ (new_value, Qfullboth))
2034 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2035 else if (EQ (new_value, Qfullwidth))
2036 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2037 else if (EQ (new_value, Qfullheight))
2038 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2039}
2040
2041
6fc2811b
JR
2042/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2043 the previous value of that parameter, NEW_VALUE is the new value. */
2044
2045static void
2046x_set_screen_gamma (f, new_value, old_value)
2047 struct frame *f;
2048 Lisp_Object new_value, old_value;
2049{
2050 if (NILP (new_value))
2051 f->gamma = 0;
2052 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2053 /* The value 0.4545 is the normal viewing gamma. */
2054 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2055 else
1a948b17 2056 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
2057 Fcons (new_value, Qnil)));
2058
2059 clear_face_cache (0);
2060}
2061
2062
ee78dc32
GV
2063/* Functions called only from `x_set_frame_param'
2064 to set individual parameters.
2065
fbd6baed 2066 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
2067 the frame is being created and its window does not exist yet.
2068 In that case, just record the parameter's new value
2069 in the standard place; do not attempt to change the window. */
2070
2071void
2072x_set_foreground_color (f, arg, oldval)
2073 struct frame *f;
2074 Lisp_Object arg, oldval;
2075{
3cf3436e
JR
2076 struct w32_output *x = f->output_data.w32;
2077 PIX_TYPE fg, old_fg;
2078
2079 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2080 old_fg = FRAME_FOREGROUND_PIXEL (f);
2081 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2082
fbd6baed 2083 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2084 {
3cf3436e
JR
2085 if (x->cursor_pixel == old_fg)
2086 x->cursor_pixel = fg;
2087
6fc2811b 2088 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2089 if (FRAME_VISIBLE_P (f))
2090 redraw_frame (f);
2091 }
2092}
2093
2094void
2095x_set_background_color (f, arg, oldval)
2096 struct frame *f;
2097 Lisp_Object arg, oldval;
2098{
6fc2811b 2099 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2100 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2101
fbd6baed 2102 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2103 {
6fc2811b
JR
2104 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2105 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2106
6fc2811b 2107 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2108
2109 if (FRAME_VISIBLE_P (f))
2110 redraw_frame (f);
2111 }
2112}
2113
2114void
2115x_set_mouse_color (f, arg, oldval)
2116 struct frame *f;
2117 Lisp_Object arg, oldval;
2118{
ee78dc32 2119 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2120 int count;
ee78dc32
GV
2121 int mask_color;
2122
2123 if (!EQ (Qnil, arg))
fbd6baed 2124 f->output_data.w32->mouse_pixel
ee78dc32 2125 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2126 mask_color = FRAME_BACKGROUND_PIXEL (f);
2127
2128 /* Don't let pointers be invisible. */
fbd6baed 2129 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2130 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2131 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2132
767b1ff0 2133#if 0 /* TODO : cursor changes */
ee78dc32
GV
2134 BLOCK_INPUT;
2135
2136 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2137 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2138
2139 if (!EQ (Qnil, Vx_pointer_shape))
2140 {
b7826503 2141 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2142 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2143 }
2144 else
fbd6baed
GV
2145 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2146 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2147
2148 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2149 {
b7826503 2150 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2151 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2152 XINT (Vx_nontext_pointer_shape));
2153 }
2154 else
fbd6baed
GV
2155 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2156 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2157
0af913d7 2158 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2159 {
b7826503 2160 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2161 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2162 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2163 }
2164 else
0af913d7 2165 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b
JR
2166 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2167
2168 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2169 if (!EQ (Qnil, Vx_mode_pointer_shape))
2170 {
b7826503 2171 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2172 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2173 XINT (Vx_mode_pointer_shape));
2174 }
2175 else
fbd6baed
GV
2176 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2177 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2178
2179 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2180 {
b7826503 2181 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2182 cross_cursor
fbd6baed 2183 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2184 XINT (Vx_sensitive_text_pointer_shape));
2185 }
2186 else
fbd6baed 2187 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2188
4694d762
JR
2189 if (!NILP (Vx_window_horizontal_drag_shape))
2190 {
b7826503 2191 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2192 horizontal_drag_cursor
2193 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2194 XINT (Vx_window_horizontal_drag_shape));
2195 }
2196 else
2197 horizontal_drag_cursor
2198 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2199
ee78dc32 2200 /* Check and report errors with the above calls. */
fbd6baed 2201 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2202 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2203
2204 {
2205 XColor fore_color, back_color;
2206
fbd6baed 2207 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2208 back_color.pixel = mask_color;
fbd6baed
GV
2209 XQueryColor (FRAME_W32_DISPLAY (f),
2210 DefaultColormap (FRAME_W32_DISPLAY (f),
2211 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2212 &fore_color);
fbd6baed
GV
2213 XQueryColor (FRAME_W32_DISPLAY (f),
2214 DefaultColormap (FRAME_W32_DISPLAY (f),
2215 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2216 &back_color);
fbd6baed 2217 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2218 &fore_color, &back_color);
fbd6baed 2219 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2220 &fore_color, &back_color);
fbd6baed 2221 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2222 &fore_color, &back_color);
fbd6baed 2223 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2224 &fore_color, &back_color);
0af913d7 2225 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2226 &fore_color, &back_color);
ee78dc32
GV
2227 }
2228
fbd6baed 2229 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2230 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2231
fbd6baed
GV
2232 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2233 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2234 f->output_data.w32->text_cursor = cursor;
2235
2236 if (nontext_cursor != f->output_data.w32->nontext_cursor
2237 && f->output_data.w32->nontext_cursor != 0)
2238 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2239 f->output_data.w32->nontext_cursor = nontext_cursor;
2240
0af913d7
GM
2241 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2242 && f->output_data.w32->hourglass_cursor != 0)
2243 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2244 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2245
fbd6baed
GV
2246 if (mode_cursor != f->output_data.w32->modeline_cursor
2247 && f->output_data.w32->modeline_cursor != 0)
2248 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2249 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2250
fbd6baed
GV
2251 if (cross_cursor != f->output_data.w32->cross_cursor
2252 && f->output_data.w32->cross_cursor != 0)
2253 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2254 f->output_data.w32->cross_cursor = cross_cursor;
2255
2256 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2257 UNBLOCK_INPUT;
6fc2811b
JR
2258
2259 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2260#endif /* TODO */
ee78dc32
GV
2261}
2262
70a0239a
JR
2263/* Defined in w32term.c. */
2264void x_update_cursor (struct frame *f, int on_p);
2265
ee78dc32
GV
2266void
2267x_set_cursor_color (f, arg, oldval)
2268 struct frame *f;
2269 Lisp_Object arg, oldval;
2270{
70a0239a 2271 unsigned long fore_pixel, pixel;
ee78dc32 2272
dfff8a69 2273 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2274 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2275 WHITE_PIX_DEFAULT (f));
ee78dc32 2276 else
6fc2811b 2277 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2278
6759f872 2279 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2280
2281 /* Make sure that the cursor color differs from the background color. */
70a0239a 2282 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2283 {
70a0239a
JR
2284 pixel = f->output_data.w32->mouse_pixel;
2285 if (pixel == fore_pixel)
6fc2811b 2286 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2287 }
70a0239a 2288
ac849ba4 2289 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
70a0239a 2290 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2291
fbd6baed 2292 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2293 {
0327b4cc
JR
2294 BLOCK_INPUT;
2295 /* Update frame's cursor_gc. */
2296 f->output_data.w32->cursor_gc->foreground = fore_pixel;
2297 f->output_data.w32->cursor_gc->background = pixel;
2298
2299 UNBLOCK_INPUT;
2300
ee78dc32
GV
2301 if (FRAME_VISIBLE_P (f))
2302 {
70a0239a
JR
2303 x_update_cursor (f, 0);
2304 x_update_cursor (f, 1);
ee78dc32
GV
2305 }
2306 }
6fc2811b
JR
2307
2308 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2309}
2310
33d52f9c
GV
2311/* Set the border-color of frame F to pixel value PIX.
2312 Note that this does not fully take effect if done before
2313 F has an window. */
2314void
2315x_set_border_pixel (f, pix)
2316 struct frame *f;
2317 int pix;
2318{
2319 f->output_data.w32->border_pixel = pix;
2320
2321 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2322 {
2323 if (FRAME_VISIBLE_P (f))
2324 redraw_frame (f);
2325 }
2326}
2327
ee78dc32
GV
2328/* Set the border-color of frame F to value described by ARG.
2329 ARG can be a string naming a color.
2330 The border-color is used for the border that is drawn by the server.
2331 Note that this does not fully take effect if done before
2332 F has a window; it must be redone when the window is created. */
2333
2334void
2335x_set_border_color (f, arg, oldval)
2336 struct frame *f;
2337 Lisp_Object arg, oldval;
2338{
ee78dc32
GV
2339 int pix;
2340
b7826503 2341 CHECK_STRING (arg);
ee78dc32 2342 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2343 x_set_border_pixel (f, pix);
6fc2811b 2344 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2345}
2346
dfff8a69
JR
2347/* Value is the internal representation of the specified cursor type
2348 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2349 of the bar cursor. */
2350
2351enum text_cursor_kinds
2352x_specified_cursor_type (arg, width)
2353 Lisp_Object arg;
2354 int *width;
ee78dc32 2355{
dfff8a69
JR
2356 enum text_cursor_kinds type;
2357
ee78dc32
GV
2358 if (EQ (arg, Qbar))
2359 {
dfff8a69
JR
2360 type = BAR_CURSOR;
2361 *width = 2;
ee78dc32 2362 }
dfff8a69
JR
2363 else if (CONSP (arg)
2364 && EQ (XCAR (arg), Qbar)
2365 && INTEGERP (XCDR (arg))
2366 && XINT (XCDR (arg)) >= 0)
ee78dc32 2367 {
dfff8a69
JR
2368 type = BAR_CURSOR;
2369 *width = XINT (XCDR (arg));
ee78dc32 2370 }
dfff8a69
JR
2371 else if (NILP (arg))
2372 type = NO_CURSOR;
ee78dc32
GV
2373 else
2374 /* Treat anything unknown as "box cursor".
2375 It was bad to signal an error; people have trouble fixing
2376 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2377 type = FILLED_BOX_CURSOR;
2378
2379 return type;
2380}
2381
2382void
2383x_set_cursor_type (f, arg, oldval)
2384 FRAME_PTR f;
2385 Lisp_Object arg, oldval;
2386{
2387 int width;
2388
2389 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2390 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2391
2392 /* Make sure the cursor gets redrawn. This is overkill, but how
2393 often do people change cursor types? */
2394 update_mode_lines++;
2395}
dfff8a69 2396\f
ee78dc32
GV
2397void
2398x_set_icon_type (f, arg, oldval)
2399 struct frame *f;
2400 Lisp_Object arg, oldval;
2401{
ee78dc32
GV
2402 int result;
2403
eb7576ce
GV
2404 if (NILP (arg) && NILP (oldval))
2405 return;
2406
2407 if (STRINGP (arg) && STRINGP (oldval)
2408 && EQ (Fstring_equal (oldval, arg), Qt))
2409 return;
2410
2411 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2412 return;
2413
2414 BLOCK_INPUT;
ee78dc32 2415
eb7576ce 2416 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2417 if (result)
2418 {
2419 UNBLOCK_INPUT;
2420 error ("No icon window available");
2421 }
2422
ee78dc32 2423 UNBLOCK_INPUT;
ee78dc32
GV
2424}
2425
2426/* Return non-nil if frame F wants a bitmap icon. */
2427
2428Lisp_Object
2429x_icon_type (f)
2430 FRAME_PTR f;
2431{
2432 Lisp_Object tem;
2433
2434 tem = assq_no_quit (Qicon_type, f->param_alist);
2435 if (CONSP (tem))
8e713be6 2436 return XCDR (tem);
ee78dc32
GV
2437 else
2438 return Qnil;
2439}
2440
2441void
2442x_set_icon_name (f, arg, oldval)
2443 struct frame *f;
2444 Lisp_Object arg, oldval;
2445{
ee78dc32
GV
2446 if (STRINGP (arg))
2447 {
2448 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2449 return;
2450 }
2451 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2452 return;
2453
2454 f->icon_name = arg;
2455
2456#if 0
fbd6baed 2457 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2458 return;
2459
2460 BLOCK_INPUT;
2461
2462 result = x_text_icon (f,
1edf84e7 2463 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2464 ? f->icon_name
1edf84e7
GV
2465 : !NILP (f->title)
2466 ? f->title
ee78dc32
GV
2467 : f->name))->data);
2468
2469 if (result)
2470 {
2471 UNBLOCK_INPUT;
2472 error ("No icon window available");
2473 }
2474
2475 /* If the window was unmapped (and its icon was mapped),
2476 the new icon is not mapped, so map the window in its stead. */
2477 if (FRAME_VISIBLE_P (f))
2478 {
2479#ifdef USE_X_TOOLKIT
fbd6baed 2480 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2481#endif
fbd6baed 2482 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2483 }
2484
fbd6baed 2485 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2486 UNBLOCK_INPUT;
2487#endif
2488}
2489
2490extern Lisp_Object x_new_font ();
4587b026 2491extern Lisp_Object x_new_fontset();
ee78dc32
GV
2492
2493void
2494x_set_font (f, arg, oldval)
2495 struct frame *f;
2496 Lisp_Object arg, oldval;
2497{
2498 Lisp_Object result;
4587b026 2499 Lisp_Object fontset_name;
4b817373 2500 Lisp_Object frame;
3cf3436e 2501 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2502
b7826503 2503 CHECK_STRING (arg);
ee78dc32 2504
4587b026
GV
2505 fontset_name = Fquery_fontset (arg, Qnil);
2506
ee78dc32 2507 BLOCK_INPUT;
4587b026
GV
2508 result = (STRINGP (fontset_name)
2509 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2510 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2511 UNBLOCK_INPUT;
2512
2513 if (EQ (result, Qnil))
dfff8a69 2514 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2515 else if (EQ (result, Qt))
dfff8a69 2516 error ("The characters of the given font have varying widths");
ee78dc32
GV
2517 else if (STRINGP (result))
2518 {
3cf3436e
JR
2519 if (STRINGP (fontset_name))
2520 {
2521 /* Fontset names are built from ASCII font names, so the
2522 names may be equal despite there was a change. */
2523 if (old_fontset == FRAME_FONTSET (f))
2524 return;
2525 }
2526 else if (!NILP (Fequal (result, oldval)))
dc220243 2527 return;
3cf3436e 2528
ee78dc32 2529 store_frame_param (f, Qfont, result);
6fc2811b 2530 recompute_basic_faces (f);
ee78dc32
GV
2531 }
2532 else
2533 abort ();
4b817373 2534
6fc2811b
JR
2535 do_pending_window_change (0);
2536
2537 /* Don't call `face-set-after-frame-default' when faces haven't been
2538 initialized yet. This is the case when called from
2539 Fx_create_frame. In that case, the X widget or window doesn't
2540 exist either, and we can end up in x_report_frame_params with a
2541 null widget which gives a segfault. */
2542 if (FRAME_FACE_CACHE (f))
2543 {
2544 XSETFRAME (frame, f);
2545 call1 (Qface_set_after_frame_default, frame);
2546 }
ee78dc32
GV
2547}
2548
41c1bdd9
KS
2549static void
2550x_set_fringe_width (f, new_value, old_value)
2551 struct frame *f;
2552 Lisp_Object new_value, old_value;
2553{
2554 x_compute_fringe_widths (f, 1);
2555}
2556
ee78dc32
GV
2557void
2558x_set_border_width (f, arg, oldval)
2559 struct frame *f;
2560 Lisp_Object arg, oldval;
2561{
b7826503 2562 CHECK_NUMBER (arg);
ee78dc32 2563
fbd6baed 2564 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2565 return;
2566
fbd6baed 2567 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2568 error ("Cannot change the border width of a window");
2569
fbd6baed 2570 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2571}
2572
2573void
2574x_set_internal_border_width (f, arg, oldval)
2575 struct frame *f;
2576 Lisp_Object arg, oldval;
2577{
fbd6baed 2578 int old = f->output_data.w32->internal_border_width;
ee78dc32 2579
b7826503 2580 CHECK_NUMBER (arg);
fbd6baed
GV
2581 f->output_data.w32->internal_border_width = XINT (arg);
2582 if (f->output_data.w32->internal_border_width < 0)
2583 f->output_data.w32->internal_border_width = 0;
ee78dc32 2584
fbd6baed 2585 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2586 return;
2587
fbd6baed 2588 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2589 {
ee78dc32 2590 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2591 SET_FRAME_GARBAGED (f);
6fc2811b 2592 do_pending_window_change (0);
ee78dc32 2593 }
a05e2bae
JR
2594 else
2595 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2596}
2597
2598void
2599x_set_visibility (f, value, oldval)
2600 struct frame *f;
2601 Lisp_Object value, oldval;
2602{
2603 Lisp_Object frame;
2604 XSETFRAME (frame, f);
2605
2606 if (NILP (value))
2607 Fmake_frame_invisible (frame, Qt);
2608 else if (EQ (value, Qicon))
2609 Ficonify_frame (frame);
2610 else
2611 Fmake_frame_visible (frame);
2612}
2613
a1258667
JR
2614\f
2615/* Change window heights in windows rooted in WINDOW by N lines. */
2616
2617static void
2618x_change_window_heights (window, n)
2619 Lisp_Object window;
2620 int n;
2621{
2622 struct window *w = XWINDOW (window);
2623
2624 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2625 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2626
2627 if (INTEGERP (w->orig_top))
2628 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2629 if (INTEGERP (w->orig_height))
2630 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2631
2632 /* Handle just the top child in a vertical split. */
2633 if (!NILP (w->vchild))
2634 x_change_window_heights (w->vchild, n);
2635
2636 /* Adjust all children in a horizontal split. */
2637 for (window = w->hchild; !NILP (window); window = w->next)
2638 {
2639 w = XWINDOW (window);
2640 x_change_window_heights (window, n);
2641 }
2642}
2643
ee78dc32
GV
2644void
2645x_set_menu_bar_lines (f, value, oldval)
2646 struct frame *f;
2647 Lisp_Object value, oldval;
2648{
2649 int nlines;
2650 int olines = FRAME_MENU_BAR_LINES (f);
2651
2652 /* Right now, menu bars don't work properly in minibuf-only frames;
2653 most of the commands try to apply themselves to the minibuffer
6fc2811b 2654 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2655 in or split the minibuffer window. */
2656 if (FRAME_MINIBUF_ONLY_P (f))
2657 return;
2658
2659 if (INTEGERP (value))
2660 nlines = XINT (value);
2661 else
2662 nlines = 0;
2663
2664 FRAME_MENU_BAR_LINES (f) = 0;
2665 if (nlines)
2666 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2667 else
2668 {
2669 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2670 free_frame_menubar (f);
2671 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2672
2673 /* Adjust the frame size so that the client (text) dimensions
2674 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2675 set correctly. */
2676 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2677 do_pending_window_change (0);
ee78dc32 2678 }
6fc2811b
JR
2679 adjust_glyphs (f);
2680}
2681
2682
2683/* Set the number of lines used for the tool bar of frame F to VALUE.
2684 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2685 is the old number of tool bar lines. This function changes the
2686 height of all windows on frame F to match the new tool bar height.
2687 The frame's height doesn't change. */
2688
2689void
2690x_set_tool_bar_lines (f, value, oldval)
2691 struct frame *f;
2692 Lisp_Object value, oldval;
2693{
36f8209a
JR
2694 int delta, nlines, root_height;
2695 Lisp_Object root_window;
6fc2811b 2696
dc220243
JR
2697 /* Treat tool bars like menu bars. */
2698 if (FRAME_MINIBUF_ONLY_P (f))
2699 return;
2700
6fc2811b
JR
2701 /* Use VALUE only if an integer >= 0. */
2702 if (INTEGERP (value) && XINT (value) >= 0)
2703 nlines = XFASTINT (value);
2704 else
2705 nlines = 0;
2706
2707 /* Make sure we redisplay all windows in this frame. */
2708 ++windows_or_buffers_changed;
2709
2710 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2711
2712 /* Don't resize the tool-bar to more than we have room for. */
2713 root_window = FRAME_ROOT_WINDOW (f);
2714 root_height = XINT (XWINDOW (root_window)->height);
2715 if (root_height - delta < 1)
2716 {
2717 delta = root_height - 1;
2718 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2719 }
2720
6fc2811b 2721 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2722 x_change_window_heights (root_window, delta);
6fc2811b 2723 adjust_glyphs (f);
36f8209a
JR
2724
2725 /* We also have to make sure that the internal border at the top of
2726 the frame, below the menu bar or tool bar, is redrawn when the
2727 tool bar disappears. This is so because the internal border is
2728 below the tool bar if one is displayed, but is below the menu bar
2729 if there isn't a tool bar. The tool bar draws into the area
2730 below the menu bar. */
2731 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2732 {
2733 updating_frame = f;
2734 clear_frame ();
2735 clear_current_matrices (f);
2736 updating_frame = NULL;
2737 }
2738
2739 /* If the tool bar gets smaller, the internal border below it
2740 has to be cleared. It was formerly part of the display
2741 of the larger tool bar, and updating windows won't clear it. */
2742 if (delta < 0)
2743 {
2744 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2745 int width = PIXEL_WIDTH (f);
2746 int y = nlines * CANON_Y_UNIT (f);
2747
2748 BLOCK_INPUT;
2749 {
2750 HDC hdc = get_frame_dc (f);
2751 w32_clear_area (f, hdc, 0, y, width, height);
2752 release_frame_dc (f, hdc);
2753 }
2754 UNBLOCK_INPUT;
3cf3436e
JR
2755
2756 if (WINDOWP (f->tool_bar_window))
2757 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2758 }
ee78dc32
GV
2759}
2760
6fc2811b 2761
ee78dc32 2762/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2763 w32_id_name.
ee78dc32
GV
2764
2765 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2766 name; if NAME is a string, set F's name to NAME and set
2767 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2768
2769 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2770 suggesting a new name, which lisp code should override; if
2771 F->explicit_name is set, ignore the new name; otherwise, set it. */
2772
2773void
2774x_set_name (f, name, explicit)
2775 struct frame *f;
2776 Lisp_Object name;
2777 int explicit;
2778{
2779 /* Make sure that requests from lisp code override requests from
2780 Emacs redisplay code. */
2781 if (explicit)
2782 {
2783 /* If we're switching from explicit to implicit, we had better
2784 update the mode lines and thereby update the title. */
2785 if (f->explicit_name && NILP (name))
2786 update_mode_lines = 1;
2787
2788 f->explicit_name = ! NILP (name);
2789 }
2790 else if (f->explicit_name)
2791 return;
2792
fbd6baed 2793 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2794 if (NILP (name))
2795 {
2796 /* Check for no change needed in this very common case
2797 before we do any consing. */
fbd6baed 2798 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2799 XSTRING (f->name)->data))
2800 return;
fbd6baed 2801 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2802 }
2803 else
b7826503 2804 CHECK_STRING (name);
ee78dc32
GV
2805
2806 /* Don't change the name if it's already NAME. */
2807 if (! NILP (Fstring_equal (name, f->name)))
2808 return;
2809
1edf84e7
GV
2810 f->name = name;
2811
2812 /* For setting the frame title, the title parameter should override
2813 the name parameter. */
2814 if (! NILP (f->title))
2815 name = f->title;
2816
fbd6baed 2817 if (FRAME_W32_WINDOW (f))
ee78dc32 2818 {
6fc2811b 2819 if (STRING_MULTIBYTE (name))
dfff8a69 2820 name = ENCODE_SYSTEM (name);
6fc2811b 2821
ee78dc32 2822 BLOCK_INPUT;
fbd6baed 2823 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2824 UNBLOCK_INPUT;
2825 }
ee78dc32
GV
2826}
2827
2828/* This function should be called when the user's lisp code has
2829 specified a name for the frame; the name will override any set by the
2830 redisplay code. */
2831void
2832x_explicitly_set_name (f, arg, oldval)
2833 FRAME_PTR f;
2834 Lisp_Object arg, oldval;
2835{
2836 x_set_name (f, arg, 1);
2837}
2838
2839/* This function should be called by Emacs redisplay code to set the
2840 name; names set this way will never override names set by the user's
2841 lisp code. */
2842void
2843x_implicitly_set_name (f, arg, oldval)
2844 FRAME_PTR f;
2845 Lisp_Object arg, oldval;
2846{
2847 x_set_name (f, arg, 0);
2848}
1edf84e7
GV
2849\f
2850/* Change the title of frame F to NAME.
2851 If NAME is nil, use the frame name as the title.
2852
2853 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2854 name; if NAME is a string, set F's name to NAME and set
2855 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2856
2857 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2858 suggesting a new name, which lisp code should override; if
2859 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2860
1edf84e7 2861void
6fc2811b 2862x_set_title (f, name, old_name)
1edf84e7 2863 struct frame *f;
6fc2811b 2864 Lisp_Object name, old_name;
1edf84e7
GV
2865{
2866 /* Don't change the title if it's already NAME. */
2867 if (EQ (name, f->title))
2868 return;
2869
2870 update_mode_lines = 1;
2871
2872 f->title = name;
2873
2874 if (NILP (name))
2875 name = f->name;
2876
2877 if (FRAME_W32_WINDOW (f))
2878 {
6fc2811b 2879 if (STRING_MULTIBYTE (name))
dfff8a69 2880 name = ENCODE_SYSTEM (name);
6fc2811b 2881
1edf84e7
GV
2882 BLOCK_INPUT;
2883 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2884 UNBLOCK_INPUT;
2885 }
2886}
2887\f
ee78dc32
GV
2888void
2889x_set_autoraise (f, arg, oldval)
2890 struct frame *f;
2891 Lisp_Object arg, oldval;
2892{
2893 f->auto_raise = !EQ (Qnil, arg);
2894}
2895
2896void
2897x_set_autolower (f, arg, oldval)
2898 struct frame *f;
2899 Lisp_Object arg, oldval;
2900{
2901 f->auto_lower = !EQ (Qnil, arg);
2902}
2903
2904void
2905x_set_unsplittable (f, arg, oldval)
2906 struct frame *f;
2907 Lisp_Object arg, oldval;
2908{
2909 f->no_split = !NILP (arg);
2910}
2911
2912void
2913x_set_vertical_scroll_bars (f, arg, oldval)
2914 struct frame *f;
2915 Lisp_Object arg, oldval;
2916{
1026b400
RS
2917 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2918 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2919 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2920 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2921 {
1026b400
RS
2922 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2923 vertical_scroll_bar_none :
87996783
GV
2924 /* Put scroll bars on the right by default, as is conventional
2925 on MS-Windows. */
2926 EQ (Qleft, arg)
2927 ? vertical_scroll_bar_left
2928 : vertical_scroll_bar_right;
ee78dc32
GV
2929
2930 /* We set this parameter before creating the window for the
2931 frame, so we can get the geometry right from the start.
2932 However, if the window hasn't been created yet, we shouldn't
2933 call x_set_window_size. */
fbd6baed 2934 if (FRAME_W32_WINDOW (f))
ee78dc32 2935 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2936 do_pending_window_change (0);
ee78dc32
GV
2937 }
2938}
2939
2940void
2941x_set_scroll_bar_width (f, arg, oldval)
2942 struct frame *f;
2943 Lisp_Object arg, oldval;
2944{
6fc2811b
JR
2945 int wid = FONT_WIDTH (f->output_data.w32->font);
2946
ee78dc32
GV
2947 if (NILP (arg))
2948 {
6fc2811b
JR
2949 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2950 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2951 wid - 1) / wid;
2952 if (FRAME_W32_WINDOW (f))
2953 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2954 do_pending_window_change (0);
ee78dc32
GV
2955 }
2956 else if (INTEGERP (arg) && XINT (arg) > 0
2957 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2958 {
ee78dc32 2959 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2960 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2961 + wid-1) / wid;
fbd6baed 2962 if (FRAME_W32_WINDOW (f))
ee78dc32 2963 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2964 do_pending_window_change (0);
ee78dc32 2965 }
6fc2811b
JR
2966 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2967 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2968 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2969}
2970\f
2971/* Subroutines of creating an frame. */
2972
2973/* Make sure that Vx_resource_name is set to a reasonable value.
2974 Fix it up, or set it to `emacs' if it is too hopeless. */
2975
2976static void
2977validate_x_resource_name ()
2978{
6fc2811b 2979 int len = 0;
ee78dc32
GV
2980 /* Number of valid characters in the resource name. */
2981 int good_count = 0;
2982 /* Number of invalid characters in the resource name. */
2983 int bad_count = 0;
2984 Lisp_Object new;
2985 int i;
2986
2987 if (STRINGP (Vx_resource_name))
2988 {
2989 unsigned char *p = XSTRING (Vx_resource_name)->data;
2990 int i;
2991
dfff8a69 2992 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2993
2994 /* Only letters, digits, - and _ are valid in resource names.
2995 Count the valid characters and count the invalid ones. */
2996 for (i = 0; i < len; i++)
2997 {
2998 int c = p[i];
2999 if (! ((c >= 'a' && c <= 'z')
3000 || (c >= 'A' && c <= 'Z')
3001 || (c >= '0' && c <= '9')
3002 || c == '-' || c == '_'))
3003 bad_count++;
3004 else
3005 good_count++;
3006 }
3007 }
3008 else
3009 /* Not a string => completely invalid. */
3010 bad_count = 5, good_count = 0;
3011
3012 /* If name is valid already, return. */
3013 if (bad_count == 0)
3014 return;
3015
3016 /* If name is entirely invalid, or nearly so, use `emacs'. */
3017 if (good_count == 0
3018 || (good_count == 1 && bad_count > 0))
3019 {
3020 Vx_resource_name = build_string ("emacs");
3021 return;
3022 }
3023
3024 /* Name is partly valid. Copy it and replace the invalid characters
3025 with underscores. */
3026
3027 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3028
3029 for (i = 0; i < len; i++)
3030 {
3031 int c = XSTRING (new)->data[i];
3032 if (! ((c >= 'a' && c <= 'z')
3033 || (c >= 'A' && c <= 'Z')
3034 || (c >= '0' && c <= '9')
3035 || c == '-' || c == '_'))
3036 XSTRING (new)->data[i] = '_';
3037 }
3038}
3039
3040
3041extern char *x_get_string_resource ();
3042
3043DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
3044 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3045This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3046class, where INSTANCE is the name under which Emacs was invoked, or
3047the name specified by the `-name' or `-rn' command-line arguments.
3048
3049The optional arguments COMPONENT and SUBCLASS add to the key and the
3050class, respectively. You must specify both of them or neither.
3051If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3052and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
3053 (attribute, class, component, subclass)
3054 Lisp_Object attribute, class, component, subclass;
3055{
3056 register char *value;
3057 char *name_key;
3058 char *class_key;
3059
b7826503
PJ
3060 CHECK_STRING (attribute);
3061 CHECK_STRING (class);
ee78dc32
GV
3062
3063 if (!NILP (component))
b7826503 3064 CHECK_STRING (component);
ee78dc32 3065 if (!NILP (subclass))
b7826503 3066 CHECK_STRING (subclass);
ee78dc32
GV
3067 if (NILP (component) != NILP (subclass))
3068 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3069
3070 validate_x_resource_name ();
3071
3072 /* Allocate space for the components, the dots which separate them,
3073 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 3074 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 3075 + (STRINGP (component)
dfff8a69
JR
3076 ? STRING_BYTES (XSTRING (component)) : 0)
3077 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
3078 + 3);
3079
3080 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 3081 + STRING_BYTES (XSTRING (class))
ee78dc32 3082 + (STRINGP (subclass)
dfff8a69 3083 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
3084 + 3);
3085
3086 /* Start with emacs.FRAMENAME for the name (the specific one)
3087 and with `Emacs' for the class key (the general one). */
3088 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3089 strcpy (class_key, EMACS_CLASS);
3090
3091 strcat (class_key, ".");
3092 strcat (class_key, XSTRING (class)->data);
3093
3094 if (!NILP (component))
3095 {
3096 strcat (class_key, ".");
3097 strcat (class_key, XSTRING (subclass)->data);
3098
3099 strcat (name_key, ".");
3100 strcat (name_key, XSTRING (component)->data);
3101 }
3102
3103 strcat (name_key, ".");
3104 strcat (name_key, XSTRING (attribute)->data);
3105
3106 value = x_get_string_resource (Qnil,
3107 name_key, class_key);
3108
3109 if (value != (char *) 0)
3110 return build_string (value);
3111 else
3112 return Qnil;
3113}
3114
3115/* Used when C code wants a resource value. */
3116
3117char *
3118x_get_resource_string (attribute, class)
3119 char *attribute, *class;
3120{
ee78dc32
GV
3121 char *name_key;
3122 char *class_key;
6fc2811b 3123 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3124
3125 /* Allocate space for the components, the dots which separate them,
3126 and the final '\0'. */
dfff8a69 3127 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3128 + strlen (attribute) + 2);
3129 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3130 + strlen (class) + 2);
3131
3132 sprintf (name_key, "%s.%s",
3133 XSTRING (Vinvocation_name)->data,
3134 attribute);
3135 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3136
6fc2811b 3137 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3138}
3139
3140/* Types we might convert a resource string into. */
3141enum resource_types
6fc2811b
JR
3142{
3143 RES_TYPE_NUMBER,
3144 RES_TYPE_FLOAT,
3145 RES_TYPE_BOOLEAN,
3146 RES_TYPE_STRING,
3147 RES_TYPE_SYMBOL
3148};
ee78dc32
GV
3149
3150/* Return the value of parameter PARAM.
3151
3152 First search ALIST, then Vdefault_frame_alist, then the X defaults
3153 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3154
3155 Convert the resource to the type specified by desired_type.
3156
3157 If no default is specified, return Qunbound. If you call
6fc2811b 3158 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3159 and don't let it get stored in any Lisp-visible variables! */
3160
3161static Lisp_Object
6fc2811b 3162w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3163 Lisp_Object alist, param;
3164 char *attribute;
3165 char *class;
3166 enum resource_types type;
3167{
3168 register Lisp_Object tem;
3169
3170 tem = Fassq (param, alist);
3171 if (EQ (tem, Qnil))
3172 tem = Fassq (param, Vdefault_frame_alist);
3173 if (EQ (tem, Qnil))
3174 {
3175
3176 if (attribute)
3177 {
3178 tem = Fx_get_resource (build_string (attribute),
3179 build_string (class),
3180 Qnil, Qnil);
3181
3182 if (NILP (tem))
3183 return Qunbound;
3184
3185 switch (type)
3186 {
6fc2811b 3187 case RES_TYPE_NUMBER:
ee78dc32
GV
3188 return make_number (atoi (XSTRING (tem)->data));
3189
6fc2811b
JR
3190 case RES_TYPE_FLOAT:
3191 return make_float (atof (XSTRING (tem)->data));
3192
3193 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3194 tem = Fdowncase (tem);
3195 if (!strcmp (XSTRING (tem)->data, "on")
3196 || !strcmp (XSTRING (tem)->data, "true"))
3197 return Qt;
3198 else
3199 return Qnil;
3200
6fc2811b 3201 case RES_TYPE_STRING:
ee78dc32
GV
3202 return tem;
3203
6fc2811b 3204 case RES_TYPE_SYMBOL:
ee78dc32
GV
3205 /* As a special case, we map the values `true' and `on'
3206 to Qt, and `false' and `off' to Qnil. */
3207 {
3208 Lisp_Object lower;
3209 lower = Fdowncase (tem);
3210 if (!strcmp (XSTRING (lower)->data, "on")
3211 || !strcmp (XSTRING (lower)->data, "true"))
3212 return Qt;
3213 else if (!strcmp (XSTRING (lower)->data, "off")
3214 || !strcmp (XSTRING (lower)->data, "false"))
3215 return Qnil;
3216 else
3217 return Fintern (tem, Qnil);
3218 }
3219
3220 default:
3221 abort ();
3222 }
3223 }
3224 else
3225 return Qunbound;
3226 }
3227 return Fcdr (tem);
3228}
3229
3230/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3231 of the parameter named PROP (a Lisp symbol).
3232 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3233 on the frame named NAME.
3234 If that is not found either, use the value DEFLT. */
3235
3236static Lisp_Object
3237x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3238 struct frame *f;
3239 Lisp_Object alist;
3240 Lisp_Object prop;
3241 Lisp_Object deflt;
3242 char *xprop;
3243 char *xclass;
3244 enum resource_types type;
3245{
3246 Lisp_Object tem;
3247
6fc2811b 3248 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3249 if (EQ (tem, Qunbound))
3250 tem = deflt;
3251 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3252 return tem;
3253}
3254\f
3255DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3256 doc: /* Parse an X-style geometry string STRING.
3257Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3258The properties returned may include `top', `left', `height', and `width'.
3259The value of `left' or `top' may be an integer,
3260or a list (+ N) meaning N pixels relative to top/left corner,
3261or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3262 (string)
3263 Lisp_Object string;
3264{
3265 int geometry, x, y;
3266 unsigned int width, height;
3267 Lisp_Object result;
3268
b7826503 3269 CHECK_STRING (string);
ee78dc32
GV
3270
3271 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3272 &x, &y, &width, &height);
3273
3274 result = Qnil;
3275 if (geometry & XValue)
3276 {
3277 Lisp_Object element;
3278
3279 if (x >= 0 && (geometry & XNegative))
3280 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3281 else if (x < 0 && ! (geometry & XNegative))
3282 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3283 else
3284 element = Fcons (Qleft, make_number (x));
3285 result = Fcons (element, result);
3286 }
3287
3288 if (geometry & YValue)
3289 {
3290 Lisp_Object element;
3291
3292 if (y >= 0 && (geometry & YNegative))
3293 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3294 else if (y < 0 && ! (geometry & YNegative))
3295 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3296 else
3297 element = Fcons (Qtop, make_number (y));
3298 result = Fcons (element, result);
3299 }
3300
3301 if (geometry & WidthValue)
3302 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3303 if (geometry & HeightValue)
3304 result = Fcons (Fcons (Qheight, make_number (height)), result);
3305
3306 return result;
3307}
3308
3309/* Calculate the desired size and position of this window,
3310 and return the flags saying which aspects were specified.
3311
3312 This function does not make the coordinates positive. */
3313
3314#define DEFAULT_ROWS 40
3315#define DEFAULT_COLS 80
3316
3317static int
3318x_figure_window_size (f, parms)
3319 struct frame *f;
3320 Lisp_Object parms;
3321{
3322 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3323 long window_prompting = 0;
3324
3325 /* Default values if we fall through.
3326 Actually, if that happens we should get
3327 window manager prompting. */
1026b400 3328 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3329 f->height = DEFAULT_ROWS;
3330 /* Window managers expect that if program-specified
3331 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3332 f->output_data.w32->top_pos = 0;
3333 f->output_data.w32->left_pos = 0;
ee78dc32 3334
35b41202
JR
3335 /* Ensure that old new_width and new_height will not override the
3336 values set here. */
3337 FRAME_NEW_WIDTH (f) = 0;
3338 FRAME_NEW_HEIGHT (f) = 0;
3339
6fc2811b
JR
3340 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3341 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3342 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3343 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3344 {
3345 if (!EQ (tem0, Qunbound))
3346 {
b7826503 3347 CHECK_NUMBER (tem0);
ee78dc32
GV
3348 f->height = XINT (tem0);
3349 }
3350 if (!EQ (tem1, Qunbound))
3351 {
b7826503 3352 CHECK_NUMBER (tem1);
1026b400 3353 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3354 }
3355 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3356 window_prompting |= USSize;
3357 else
3358 window_prompting |= PSize;
3359 }
3360
fbd6baed 3361 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3362 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3363 ? 0
3364 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3365 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3366 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
f7b9d4d1 3367
41c1bdd9 3368 x_compute_fringe_widths (f, 0);
f7b9d4d1 3369
fbd6baed
GV
3370 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3371 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3372
6fc2811b
JR
3373 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3374 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3375 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3376 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3377 {
3378 if (EQ (tem0, Qminus))
3379 {
fbd6baed 3380 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3381 window_prompting |= YNegative;
3382 }
8e713be6
KR
3383 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3384 && CONSP (XCDR (tem0))
3385 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3386 {
8e713be6 3387 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3388 window_prompting |= YNegative;
3389 }
8e713be6
KR
3390 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3391 && CONSP (XCDR (tem0))
3392 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3393 {
8e713be6 3394 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3395 }
3396 else if (EQ (tem0, Qunbound))
fbd6baed 3397 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3398 else
3399 {
b7826503 3400 CHECK_NUMBER (tem0);
fbd6baed
GV
3401 f->output_data.w32->top_pos = XINT (tem0);
3402 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3403 window_prompting |= YNegative;
3404 }
3405
3406 if (EQ (tem1, Qminus))
3407 {
fbd6baed 3408 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3409 window_prompting |= XNegative;
3410 }
8e713be6
KR
3411 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3412 && CONSP (XCDR (tem1))
3413 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3414 {
8e713be6 3415 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3416 window_prompting |= XNegative;
3417 }
8e713be6
KR
3418 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3419 && CONSP (XCDR (tem1))
3420 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3421 {
8e713be6 3422 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3423 }
3424 else if (EQ (tem1, Qunbound))
fbd6baed 3425 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3426 else
3427 {
b7826503 3428 CHECK_NUMBER (tem1);
fbd6baed
GV
3429 f->output_data.w32->left_pos = XINT (tem1);
3430 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3431 window_prompting |= XNegative;
3432 }
3433
3434 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3435 window_prompting |= USPosition;
3436 else
3437 window_prompting |= PPosition;
3438 }
3439
f7b9d4d1
JR
3440 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3441 {
3442 int left, top;
3443 int width, height;
3444
3445 /* It takes both for some WM:s to place it where we want */
3446 window_prompting = USPosition | PPosition;
3447 x_fullscreen_adjust (f, &width, &height, &top, &left);
3448 f->width = width;
3449 f->height = height;
3450 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3451 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3452 f->output_data.w32->left_pos = left;
3453 f->output_data.w32->top_pos = top;
3454 }
3455
ee78dc32
GV
3456 return window_prompting;
3457}
3458
3459\f
3460
fbd6baed 3461extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3462
3463BOOL
fbd6baed 3464w32_init_class (hinst)
ee78dc32
GV
3465 HINSTANCE hinst;
3466{
3467 WNDCLASS wc;
3468
5ac45f98 3469 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3470 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3471 wc.cbClsExtra = 0;
3472 wc.cbWndExtra = WND_EXTRA_BYTES;
3473 wc.hInstance = hinst;
3474 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3475 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3476 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3477 wc.lpszMenuName = NULL;
3478 wc.lpszClassName = EMACS_CLASS;
3479
3480 return (RegisterClass (&wc));
3481}
3482
3483HWND
fbd6baed 3484w32_createscrollbar (f, bar)
ee78dc32
GV
3485 struct frame *f;
3486 struct scroll_bar * bar;
3487{
3488 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3489 /* Position and size of scroll bar. */
6fc2811b
JR
3490 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3491 XINT(bar->top),
3492 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3493 XINT(bar->height),
fbd6baed 3494 FRAME_W32_WINDOW (f),
ee78dc32
GV
3495 NULL,
3496 hinst,
3497 NULL));
3498}
3499
3500void
fbd6baed 3501w32_createwindow (f)
ee78dc32
GV
3502 struct frame *f;
3503{
3504 HWND hwnd;
1edf84e7
GV
3505 RECT rect;
3506
3507 rect.left = rect.top = 0;
3508 rect.right = PIXEL_WIDTH (f);
3509 rect.bottom = PIXEL_HEIGHT (f);
3510
3511 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3512 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3513
3514 /* Do first time app init */
3515
3516 if (!hprevinst)
3517 {
fbd6baed 3518 w32_init_class (hinst);
ee78dc32
GV
3519 }
3520
1edf84e7
GV
3521 FRAME_W32_WINDOW (f) = hwnd
3522 = CreateWindow (EMACS_CLASS,
3523 f->namebuf,
9ead1b60 3524 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3525 f->output_data.w32->left_pos,
3526 f->output_data.w32->top_pos,
3527 rect.right - rect.left,
3528 rect.bottom - rect.top,
3529 NULL,
3530 NULL,
3531 hinst,
3532 NULL);
3533
ee78dc32
GV
3534 if (hwnd)
3535 {
1edf84e7
GV
3536 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3537 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3538 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3539 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3540 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3541
cb9e33d4
RS
3542 /* Enable drag-n-drop. */
3543 DragAcceptFiles (hwnd, TRUE);
3544
5ac45f98
GV
3545 /* Do this to discard the default setting specified by our parent. */
3546 ShowWindow (hwnd, SW_HIDE);
3c190163 3547 }
3c190163
GV
3548}
3549
ee78dc32
GV
3550void
3551my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3552 W32Msg * wmsg;
ee78dc32
GV
3553 HWND hwnd;
3554 UINT msg;
3555 WPARAM wParam;
3556 LPARAM lParam;
3557{
3558 wmsg->msg.hwnd = hwnd;
3559 wmsg->msg.message = msg;
3560 wmsg->msg.wParam = wParam;
3561 wmsg->msg.lParam = lParam;
3562 wmsg->msg.time = GetMessageTime ();
3563
3564 post_msg (wmsg);
3565}
3566
e9e23e23 3567/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3568 between left and right keys as advertised. We test for this
3569 support dynamically, and set a flag when the support is absent. If
3570 absent, we keep track of the left and right control and alt keys
3571 ourselves. This is particularly necessary on keyboards that rely
3572 upon the AltGr key, which is represented as having the left control
3573 and right alt keys pressed. For these keyboards, we need to know
3574 when the left alt key has been pressed in addition to the AltGr key
3575 so that we can properly support M-AltGr-key sequences (such as M-@
3576 on Swedish keyboards). */
3577
3578#define EMACS_LCONTROL 0
3579#define EMACS_RCONTROL 1
3580#define EMACS_LMENU 2
3581#define EMACS_RMENU 3
3582
3583static int modifiers[4];
3584static int modifiers_recorded;
3585static int modifier_key_support_tested;
3586
3587static void
3588test_modifier_support (unsigned int wparam)
3589{
3590 unsigned int l, r;
3591
3592 if (wparam != VK_CONTROL && wparam != VK_MENU)
3593 return;
3594 if (wparam == VK_CONTROL)
3595 {
3596 l = VK_LCONTROL;
3597 r = VK_RCONTROL;
3598 }
3599 else
3600 {
3601 l = VK_LMENU;
3602 r = VK_RMENU;
3603 }
3604 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3605 modifiers_recorded = 1;
3606 else
3607 modifiers_recorded = 0;
3608 modifier_key_support_tested = 1;
3609}
3610
3611static void
3612record_keydown (unsigned int wparam, unsigned int lparam)
3613{
3614 int i;
3615
3616 if (!modifier_key_support_tested)
3617 test_modifier_support (wparam);
3618
3619 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3620 return;
3621
3622 if (wparam == VK_CONTROL)
3623 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3624 else
3625 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3626
3627 modifiers[i] = 1;
3628}
3629
3630static void
3631record_keyup (unsigned int wparam, unsigned int lparam)
3632{
3633 int i;
3634
3635 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3636 return;
3637
3638 if (wparam == VK_CONTROL)
3639 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3640 else
3641 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3642
3643 modifiers[i] = 0;
3644}
3645
da36a4d6
GV
3646/* Emacs can lose focus while a modifier key has been pressed. When
3647 it regains focus, be conservative and clear all modifiers since
3648 we cannot reconstruct the left and right modifier state. */
3649static void
3650reset_modifiers ()
3651{
8681157a
RS
3652 SHORT ctrl, alt;
3653
adcc3809
GV
3654 if (GetFocus () == NULL)
3655 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3656 return;
8681157a
RS
3657
3658 ctrl = GetAsyncKeyState (VK_CONTROL);
3659 alt = GetAsyncKeyState (VK_MENU);
3660
8681157a
RS
3661 if (!(ctrl & 0x08000))
3662 /* Clear any recorded control modifier state. */
3663 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3664
3665 if (!(alt & 0x08000))
3666 /* Clear any recorded alt modifier state. */
3667 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3668
adcc3809
GV
3669 /* Update the state of all modifier keys, because modifiers used in
3670 hot-key combinations can get stuck on if Emacs loses focus as a
3671 result of a hot-key being pressed. */
3672 {
3673 BYTE keystate[256];
3674
3675#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3676
3677 GetKeyboardState (keystate);
3678 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3679 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3680 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3681 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3682 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3683 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3684 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3685 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3686 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3687 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3688 SetKeyboardState (keystate);
3689 }
da36a4d6
GV
3690}
3691
7830e24b
RS
3692/* Synchronize modifier state with what is reported with the current
3693 keystroke. Even if we cannot distinguish between left and right
3694 modifier keys, we know that, if no modifiers are set, then neither
3695 the left or right modifier should be set. */
3696static void
3697sync_modifiers ()
3698{
3699 if (!modifiers_recorded)
3700 return;
3701
3702 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3703 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3704
3705 if (!(GetKeyState (VK_MENU) & 0x8000))
3706 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3707}
3708
a1a80b40
GV
3709static int
3710modifier_set (int vkey)
3711{
ccc2d29c 3712 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3713 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3714 if (!modifiers_recorded)
3715 return (GetKeyState (vkey) & 0x8000);
3716
3717 switch (vkey)
3718 {
3719 case VK_LCONTROL:
3720 return modifiers[EMACS_LCONTROL];
3721 case VK_RCONTROL:
3722 return modifiers[EMACS_RCONTROL];
3723 case VK_LMENU:
3724 return modifiers[EMACS_LMENU];
3725 case VK_RMENU:
3726 return modifiers[EMACS_RMENU];
a1a80b40
GV
3727 }
3728 return (GetKeyState (vkey) & 0x8000);
3729}
3730
ccc2d29c
GV
3731/* Convert between the modifier bits W32 uses and the modifier bits
3732 Emacs uses. */
3733
3734unsigned int
3735w32_key_to_modifier (int key)
3736{
3737 Lisp_Object key_mapping;
3738
3739 switch (key)
3740 {
3741 case VK_LWIN:
3742 key_mapping = Vw32_lwindow_modifier;
3743 break;
3744 case VK_RWIN:
3745 key_mapping = Vw32_rwindow_modifier;
3746 break;
3747 case VK_APPS:
3748 key_mapping = Vw32_apps_modifier;
3749 break;
3750 case VK_SCROLL:
3751 key_mapping = Vw32_scroll_lock_modifier;
3752 break;
3753 default:
3754 key_mapping = Qnil;
3755 }
3756
adcc3809
GV
3757 /* NB. This code runs in the input thread, asychronously to the lisp
3758 thread, so we must be careful to ensure access to lisp data is
3759 thread-safe. The following code is safe because the modifier
3760 variable values are updated atomically from lisp and symbols are
3761 not relocated by GC. Also, we don't have to worry about seeing GC
3762 markbits here. */
3763 if (EQ (key_mapping, Qhyper))
ccc2d29c 3764 return hyper_modifier;
adcc3809 3765 if (EQ (key_mapping, Qsuper))
ccc2d29c 3766 return super_modifier;
adcc3809 3767 if (EQ (key_mapping, Qmeta))
ccc2d29c 3768 return meta_modifier;
adcc3809 3769 if (EQ (key_mapping, Qalt))
ccc2d29c 3770 return alt_modifier;
adcc3809 3771 if (EQ (key_mapping, Qctrl))
ccc2d29c 3772 return ctrl_modifier;
adcc3809 3773 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3774 return ctrl_modifier;
adcc3809 3775 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3776 return shift_modifier;
3777
3778 /* Don't generate any modifier if not explicitly requested. */
3779 return 0;
3780}
3781
3782unsigned int
3783w32_get_modifiers ()
3784{
3785 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3786 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3787 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3788 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3789 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3790 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3791 (modifier_set (VK_MENU) ?
3792 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3793}
3794
a1a80b40
GV
3795/* We map the VK_* modifiers into console modifier constants
3796 so that we can use the same routines to handle both console
3797 and window input. */
3798
3799static int
ccc2d29c 3800construct_console_modifiers ()
a1a80b40
GV
3801{
3802 int mods;
3803
a1a80b40
GV
3804 mods = 0;
3805 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3806 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3807 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3808 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3809 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3810 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3811 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3812 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3813 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3814 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3815 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3816
3817 return mods;
3818}
3819
ccc2d29c
GV
3820static int
3821w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3822{
ccc2d29c
GV
3823 int mods;
3824
3825 /* Convert to emacs modifiers. */
3826 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3827
3828 return mods;
3829}
da36a4d6 3830
ccc2d29c
GV
3831unsigned int
3832map_keypad_keys (unsigned int virt_key, unsigned int extended)
3833{
3834 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3835 return virt_key;
da36a4d6 3836
ccc2d29c 3837 if (virt_key == VK_RETURN)
da36a4d6
GV
3838 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3839
ccc2d29c
GV
3840 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3841 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3842
3843 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3844 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3845
3846 if (virt_key == VK_CLEAR)
3847 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3848
3849 return virt_key;
3850}
3851
3852/* List of special key combinations which w32 would normally capture,
3853 but emacs should grab instead. Not directly visible to lisp, to
3854 simplify synchronization. Each item is an integer encoding a virtual
3855 key code and modifier combination to capture. */
3856Lisp_Object w32_grabbed_keys;
3857
3858#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3859#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3860#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3861#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3862
3863/* Register hot-keys for reserved key combinations when Emacs has
3864 keyboard focus, since this is the only way Emacs can receive key
3865 combinations like Alt-Tab which are used by the system. */
3866
3867static void
3868register_hot_keys (hwnd)
3869 HWND hwnd;
3870{
3871 Lisp_Object keylist;
3872
3873 /* Use GC_CONSP, since we are called asynchronously. */
3874 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3875 {
3876 Lisp_Object key = XCAR (keylist);
3877
3878 /* Deleted entries get set to nil. */
3879 if (!INTEGERP (key))
3880 continue;
3881
3882 RegisterHotKey (hwnd, HOTKEY_ID (key),
3883 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3884 }
3885}
3886
3887static void
3888unregister_hot_keys (hwnd)
3889 HWND hwnd;
3890{
3891 Lisp_Object keylist;
3892
3893 /* Use GC_CONSP, since we are called asynchronously. */
3894 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3895 {
3896 Lisp_Object key = XCAR (keylist);
3897
3898 if (!INTEGERP (key))
3899 continue;
3900
3901 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3902 }
3903}
3904
5ac45f98
GV
3905/* Main message dispatch loop. */
3906
1edf84e7
GV
3907static void
3908w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3909{
3910 MSG msg;
ccc2d29c
GV
3911 int result;
3912 HWND focus_window;
93fbe8b7
GV
3913
3914 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3915
5ac45f98
GV
3916 while (GetMessage (&msg, NULL, 0, 0))
3917 {
3918 if (msg.hwnd == NULL)
3919 {
3920 switch (msg.message)
3921 {
3ef68e6b
AI
3922 case WM_NULL:
3923 /* Produced by complete_deferred_msg; just ignore. */
3924 break;
5ac45f98 3925 case WM_EMACS_CREATEWINDOW:
fbd6baed 3926 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3927 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3928 abort ();
5ac45f98 3929 break;
dfdb4047
GV
3930 case WM_EMACS_SETLOCALE:
3931 SetThreadLocale (msg.wParam);
3932 /* Reply is not expected. */
3933 break;
ccc2d29c
GV
3934 case WM_EMACS_SETKEYBOARDLAYOUT:
3935 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3936 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3937 result, 0))
3938 abort ();
3939 break;
3940 case WM_EMACS_REGISTER_HOT_KEY:
3941 focus_window = GetFocus ();
3942 if (focus_window != NULL)
3943 RegisterHotKey (focus_window,
3944 HOTKEY_ID (msg.wParam),
3945 HOTKEY_MODIFIERS (msg.wParam),
3946 HOTKEY_VK_CODE (msg.wParam));
3947 /* Reply is not expected. */
3948 break;
3949 case WM_EMACS_UNREGISTER_HOT_KEY:
3950 focus_window = GetFocus ();
3951 if (focus_window != NULL)
3952 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3953 /* Mark item as erased. NB: this code must be
3954 thread-safe. The next line is okay because the cons
3955 cell is never made into garbage and is not relocated by
3956 GC. */
f3fbd155 3957 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3958 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3959 abort ();
3960 break;
adcc3809
GV
3961 case WM_EMACS_TOGGLE_LOCK_KEY:
3962 {
3963 int vk_code = (int) msg.wParam;
3964 int cur_state = (GetKeyState (vk_code) & 1);
3965 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3966
3967 /* NB: This code must be thread-safe. It is safe to
3968 call NILP because symbols are not relocated by GC,
3969 and pointer here is not touched by GC (so the markbit
3970 can't be set). Numbers are safe because they are
3971 immediate values. */
3972 if (NILP (new_state)
3973 || (NUMBERP (new_state)
8edb0a6f 3974 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3975 {
3976 one_w32_display_info.faked_key = vk_code;
3977
3978 keybd_event ((BYTE) vk_code,
3979 (BYTE) MapVirtualKey (vk_code, 0),
3980 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3981 keybd_event ((BYTE) vk_code,
3982 (BYTE) MapVirtualKey (vk_code, 0),
3983 KEYEVENTF_EXTENDEDKEY | 0, 0);
3984 keybd_event ((BYTE) vk_code,
3985 (BYTE) MapVirtualKey (vk_code, 0),
3986 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3987 cur_state = !cur_state;
3988 }
3989 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3990 cur_state, 0))
3991 abort ();
3992 }
3993 break;
1edf84e7 3994 default:
1edf84e7 3995 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3996 }
3997 }
3998 else
3999 {
4000 DispatchMessage (&msg);
4001 }
1edf84e7
GV
4002
4003 /* Exit nested loop when our deferred message has completed. */
4004 if (msg_buf->completed)
4005 break;
5ac45f98 4006 }
1edf84e7
GV
4007}
4008
4009deferred_msg * deferred_msg_head;
4010
4011static deferred_msg *
4012find_deferred_msg (HWND hwnd, UINT msg)
4013{
4014 deferred_msg * item;
4015
4016 /* Don't actually need synchronization for read access, since
4017 modification of single pointer is always atomic. */
4018 /* enter_crit (); */
4019
4020 for (item = deferred_msg_head; item != NULL; item = item->next)
4021 if (item->w32msg.msg.hwnd == hwnd
4022 && item->w32msg.msg.message == msg)
4023 break;
4024
4025 /* leave_crit (); */
4026
4027 return item;
4028}
4029
4030static LRESULT
4031send_deferred_msg (deferred_msg * msg_buf,
4032 HWND hwnd,
4033 UINT msg,
4034 WPARAM wParam,
4035 LPARAM lParam)
4036{
4037 /* Only input thread can send deferred messages. */
4038 if (GetCurrentThreadId () != dwWindowsThreadId)
4039 abort ();
4040
4041 /* It is an error to send a message that is already deferred. */
4042 if (find_deferred_msg (hwnd, msg) != NULL)
4043 abort ();
4044
4045 /* Enforced synchronization is not needed because this is the only
4046 function that alters deferred_msg_head, and the following critical
4047 section is guaranteed to only be serially reentered (since only the
4048 input thread can call us). */
4049
4050 /* enter_crit (); */
4051
4052 msg_buf->completed = 0;
4053 msg_buf->next = deferred_msg_head;
4054 deferred_msg_head = msg_buf;
4055 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4056
4057 /* leave_crit (); */
4058
4059 /* Start a new nested message loop to process other messages until
4060 this one is completed. */
4061 w32_msg_pump (msg_buf);
4062
4063 deferred_msg_head = msg_buf->next;
4064
4065 return msg_buf->result;
4066}
4067
4068void
4069complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4070{
4071 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4072
4073 if (msg_buf == NULL)
3ef68e6b
AI
4074 /* Message may have been cancelled, so don't abort(). */
4075 return;
1edf84e7
GV
4076
4077 msg_buf->result = result;
4078 msg_buf->completed = 1;
4079
4080 /* Ensure input thread is woken so it notices the completion. */
4081 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4082}
4083
3ef68e6b
AI
4084void
4085cancel_all_deferred_msgs ()
4086{
4087 deferred_msg * item;
4088
4089 /* Don't actually need synchronization for read access, since
4090 modification of single pointer is always atomic. */
4091 /* enter_crit (); */
4092
4093 for (item = deferred_msg_head; item != NULL; item = item->next)
4094 {
4095 item->result = 0;
4096 item->completed = 1;
4097 }
4098
4099 /* leave_crit (); */
4100
4101 /* Ensure input thread is woken so it notices the completion. */
4102 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4103}
1edf84e7
GV
4104
4105DWORD
4106w32_msg_worker (dw)
4107 DWORD dw;
4108{
4109 MSG msg;
4110 deferred_msg dummy_buf;
4111
4112 /* Ensure our message queue is created */
4113
4114 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 4115
1edf84e7
GV
4116 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4117 abort ();
4118
4119 memset (&dummy_buf, 0, sizeof (dummy_buf));
4120 dummy_buf.w32msg.msg.hwnd = NULL;
4121 dummy_buf.w32msg.msg.message = WM_NULL;
4122
4123 /* This is the inital message loop which should only exit when the
4124 application quits. */
4125 w32_msg_pump (&dummy_buf);
4126
4127 return 0;
5ac45f98
GV
4128}
4129
3ef68e6b
AI
4130static void
4131post_character_message (hwnd, msg, wParam, lParam, modifiers)
4132 HWND hwnd;
4133 UINT msg;
4134 WPARAM wParam;
4135 LPARAM lParam;
4136 DWORD modifiers;
4137
4138{
4139 W32Msg wmsg;
4140
4141 wmsg.dwModifiers = modifiers;
4142
4143 /* Detect quit_char and set quit-flag directly. Note that we
4144 still need to post a message to ensure the main thread will be
4145 woken up if blocked in sys_select(), but we do NOT want to post
4146 the quit_char message itself (because it will usually be as if
4147 the user had typed quit_char twice). Instead, we post a dummy
4148 message that has no particular effect. */
4149 {
4150 int c = wParam;
4151 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4152 c = make_ctrl_char (c) & 0377;
7d081355
AI
4153 if (c == quit_char
4154 || (wmsg.dwModifiers == 0 &&
4155 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4156 {
4157 Vquit_flag = Qt;
4158
4159 /* The choice of message is somewhat arbitrary, as long as
4160 the main thread handler just ignores it. */
4161 msg = WM_NULL;
4162
4163 /* Interrupt any blocking system calls. */
4164 signal_quit ();
4165
4166 /* As a safety precaution, forcibly complete any deferred
4167 messages. This is a kludge, but I don't see any particularly
4168 clean way to handle the situation where a deferred message is
4169 "dropped" in the lisp thread, and will thus never be
4170 completed, eg. by the user trying to activate the menubar
4171 when the lisp thread is busy, and then typing C-g when the
4172 menubar doesn't open promptly (with the result that the
4173 menubar never responds at all because the deferred
4174 WM_INITMENU message is never completed). Another problem
4175 situation is when the lisp thread calls SendMessage (to send
4176 a window manager command) when a message has been deferred;
4177 the lisp thread gets blocked indefinitely waiting for the
4178 deferred message to be completed, which itself is waiting for
4179 the lisp thread to respond.
4180
4181 Note that we don't want to block the input thread waiting for
4182 a reponse from the lisp thread (although that would at least
4183 solve the deadlock problem above), because we want to be able
4184 to receive C-g to interrupt the lisp thread. */
4185 cancel_all_deferred_msgs ();
4186 }
4187 }
4188
4189 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4190}
4191
ee78dc32
GV
4192/* Main window procedure */
4193
ee78dc32 4194LRESULT CALLBACK
fbd6baed 4195w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4196 HWND hwnd;
4197 UINT msg;
4198 WPARAM wParam;
4199 LPARAM lParam;
4200{
4201 struct frame *f;
fbd6baed
GV
4202 struct w32_display_info *dpyinfo = &one_w32_display_info;
4203 W32Msg wmsg;
84fb1139 4204 int windows_translate;
576ba81c 4205 int key;
84fb1139 4206
a6085637
KH
4207 /* Note that it is okay to call x_window_to_frame, even though we are
4208 not running in the main lisp thread, because frame deletion
4209 requires the lisp thread to synchronize with this thread. Thus, if
4210 a frame struct is returned, it can be used without concern that the
4211 lisp thread might make it disappear while we are using it.
4212
4213 NB. Walking the frame list in this thread is safe (as long as
4214 writes of Lisp_Object slots are atomic, which they are on Windows).
4215 Although delete-frame can destructively modify the frame list while
4216 we are walking it, a garbage collection cannot occur until after
4217 delete-frame has synchronized with this thread.
4218
4219 It is also safe to use functions that make GDI calls, such as
fbd6baed 4220 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4221 from the frame struct using get_frame_dc which is thread-aware. */
4222
ee78dc32
GV
4223 switch (msg)
4224 {
4225 case WM_ERASEBKGND:
a6085637
KH
4226 f = x_window_to_frame (dpyinfo, hwnd);
4227 if (f)
4228 {
9badad41 4229 HDC hdc = get_frame_dc (f);
a6085637 4230 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4231 w32_clear_rect (f, hdc, &wmsg.rect);
4232 release_frame_dc (f, hdc);
ce6059da
AI
4233
4234#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4235 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4236 f,
4237 wmsg.rect.left, wmsg.rect.top,
4238 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4239#endif /* W32_DEBUG_DISPLAY */
a6085637 4240 }
5ac45f98
GV
4241 return 1;
4242 case WM_PALETTECHANGED:
4243 /* ignore our own changes */
4244 if ((HWND)wParam != hwnd)
4245 {
a6085637
KH
4246 f = x_window_to_frame (dpyinfo, hwnd);
4247 if (f)
4248 /* get_frame_dc will realize our palette and force all
4249 frames to be redrawn if needed. */
4250 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4251 }
4252 return 0;
ee78dc32 4253 case WM_PAINT:
ce6059da 4254 {
55dcfc15
AI
4255 PAINTSTRUCT paintStruct;
4256 RECT update_rect;
aa35b6ad 4257 bzero (&update_rect, sizeof (update_rect));
55dcfc15 4258
18f0b342
AI
4259 f = x_window_to_frame (dpyinfo, hwnd);
4260 if (f == 0)
4261 {
4262 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4263 return 0;
4264 }
4265
55dcfc15
AI
4266 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4267 fails. Apparently this can happen under some
4268 circumstances. */
aa35b6ad 4269 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
55dcfc15
AI
4270 {
4271 enter_crit ();
4272 BeginPaint (hwnd, &paintStruct);
4273
aa35b6ad
JR
4274 /* The rectangles returned by GetUpdateRect and BeginPaint
4275 do not always match. Play it safe by assuming both areas
4276 are invalid. */
4277 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
55dcfc15
AI
4278
4279#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4280 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4281 f,
4282 wmsg.rect.left, wmsg.rect.top,
4283 wmsg.rect.right, wmsg.rect.bottom));
4284 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4285 update_rect.left, update_rect.top,
4286 update_rect.right, update_rect.bottom));
4287#endif
4288 EndPaint (hwnd, &paintStruct);
4289 leave_crit ();
4290
4291 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4292
4293 return 0;
4294 }
c0611964
AI
4295
4296 /* If GetUpdateRect returns 0 (meaning there is no update
4297 region), assume the whole window needs to be repainted. */
4298 GetClientRect(hwnd, &wmsg.rect);
4299 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4300 return 0;
ee78dc32 4301 }
a1a80b40 4302
ccc2d29c
GV
4303 case WM_INPUTLANGCHANGE:
4304 /* Inform lisp thread of keyboard layout changes. */
4305 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4306
4307 /* Clear dead keys in the keyboard state; for simplicity only
4308 preserve modifier key states. */
4309 {
4310 int i;
4311 BYTE keystate[256];
4312
4313 GetKeyboardState (keystate);
4314 for (i = 0; i < 256; i++)
4315 if (1
4316 && i != VK_SHIFT
4317 && i != VK_LSHIFT
4318 && i != VK_RSHIFT
4319 && i != VK_CAPITAL
4320 && i != VK_NUMLOCK
4321 && i != VK_SCROLL
4322 && i != VK_CONTROL
4323 && i != VK_LCONTROL
4324 && i != VK_RCONTROL
4325 && i != VK_MENU
4326 && i != VK_LMENU
4327 && i != VK_RMENU
4328 && i != VK_LWIN
4329 && i != VK_RWIN)
4330 keystate[i] = 0;
4331 SetKeyboardState (keystate);
4332 }
4333 goto dflt;
4334
4335 case WM_HOTKEY:
4336 /* Synchronize hot keys with normal input. */
4337 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4338 return (0);
4339
a1a80b40
GV
4340 case WM_KEYUP:
4341 case WM_SYSKEYUP:
4342 record_keyup (wParam, lParam);
4343 goto dflt;
4344
ee78dc32
GV
4345 case WM_KEYDOWN:
4346 case WM_SYSKEYDOWN:
ccc2d29c
GV
4347 /* Ignore keystrokes we fake ourself; see below. */
4348 if (dpyinfo->faked_key == wParam)
4349 {
4350 dpyinfo->faked_key = 0;
576ba81c
AI
4351 /* Make sure TranslateMessage sees them though (as long as
4352 they don't produce WM_CHAR messages). This ensures that
4353 indicator lights are toggled promptly on Windows 9x, for
4354 example. */
4355 if (lispy_function_keys[wParam] != 0)
4356 {
4357 windows_translate = 1;
4358 goto translate;
4359 }
4360 return 0;
ccc2d29c
GV
4361 }
4362
7830e24b
RS
4363 /* Synchronize modifiers with current keystroke. */
4364 sync_modifiers ();
a1a80b40 4365 record_keydown (wParam, lParam);
ccc2d29c 4366 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4367
4368 windows_translate = 0;
ccc2d29c
GV
4369
4370 switch (wParam)
4371 {
4372 case VK_LWIN:
4373 if (NILP (Vw32_pass_lwindow_to_system))
4374 {
4375 /* Prevent system from acting on keyup (which opens the
4376 Start menu if no other key was pressed) by simulating a
4377 press of Space which we will ignore. */
4378 if (GetAsyncKeyState (wParam) & 1)
4379 {
adcc3809 4380 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4381 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4382 else
576ba81c
AI
4383 key = VK_SPACE;
4384 dpyinfo->faked_key = key;
4385 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4386 }
4387 }
4388 if (!NILP (Vw32_lwindow_modifier))
4389 return 0;
4390 break;
4391 case VK_RWIN:
4392 if (NILP (Vw32_pass_rwindow_to_system))
4393 {
4394 if (GetAsyncKeyState (wParam) & 1)
4395 {
adcc3809 4396 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4397 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4398 else
576ba81c
AI
4399 key = VK_SPACE;
4400 dpyinfo->faked_key = key;
4401 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4402 }
4403 }
4404 if (!NILP (Vw32_rwindow_modifier))
4405 return 0;
4406 break;
576ba81c 4407 case VK_APPS:
ccc2d29c
GV
4408 if (!NILP (Vw32_apps_modifier))
4409 return 0;
4410 break;
4411 case VK_MENU:
4412 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4413 /* Prevent DefWindowProc from activating the menu bar if an
4414 Alt key is pressed and released by itself. */
ccc2d29c 4415 return 0;
84fb1139 4416 windows_translate = 1;
ccc2d29c
GV
4417 break;
4418 case VK_CAPITAL:
4419 /* Decide whether to treat as modifier or function key. */
4420 if (NILP (Vw32_enable_caps_lock))
4421 goto disable_lock_key;
adcc3809
GV
4422 windows_translate = 1;
4423 break;
ccc2d29c
GV
4424 case VK_NUMLOCK:
4425 /* Decide whether to treat as modifier or function key. */
4426 if (NILP (Vw32_enable_num_lock))
4427 goto disable_lock_key;
adcc3809
GV
4428 windows_translate = 1;
4429 break;
ccc2d29c
GV
4430 case VK_SCROLL:
4431 /* Decide whether to treat as modifier or function key. */
4432 if (NILP (Vw32_scroll_lock_modifier))
4433 goto disable_lock_key;
adcc3809
GV
4434 windows_translate = 1;
4435 break;
ccc2d29c 4436 disable_lock_key:
adcc3809
GV
4437 /* Ensure the appropriate lock key state (and indicator light)
4438 remains in the same state. We do this by faking another
4439 press of the relevant key. Apparently, this really is the
4440 only way to toggle the state of the indicator lights. */
4441 dpyinfo->faked_key = wParam;
4442 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4443 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4444 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4445 KEYEVENTF_EXTENDEDKEY | 0, 0);
4446 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4447 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4448 /* Ensure indicator lights are updated promptly on Windows 9x
4449 (TranslateMessage apparently does this), after forwarding
4450 input event. */
4451 post_character_message (hwnd, msg, wParam, lParam,
4452 w32_get_key_modifiers (wParam, lParam));
4453 windows_translate = 1;
ccc2d29c
GV
4454 break;
4455 case VK_CONTROL:
4456 case VK_SHIFT:
4457 case VK_PROCESSKEY: /* Generated by IME. */
4458 windows_translate = 1;
4459 break;
adcc3809
GV
4460 case VK_CANCEL:
4461 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4462 which is confusing for purposes of key binding; convert
4463 VK_CANCEL events into VK_PAUSE events. */
4464 wParam = VK_PAUSE;
4465 break;
4466 case VK_PAUSE:
4467 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4468 for purposes of key binding; convert these back into
4469 VK_NUMLOCK events, at least when we want to see NumLock key
4470 presses. (Note that there is never any possibility that
4471 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4472 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4473 wParam = VK_NUMLOCK;
4474 break;
ccc2d29c
GV
4475 default:
4476 /* If not defined as a function key, change it to a WM_CHAR message. */
4477 if (lispy_function_keys[wParam] == 0)
4478 {
adcc3809
GV
4479 DWORD modifiers = construct_console_modifiers ();
4480
ccc2d29c
GV
4481 if (!NILP (Vw32_recognize_altgr)
4482 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4483 {
4484 /* Always let TranslateMessage handle AltGr key chords;
4485 for some reason, ToAscii doesn't always process AltGr
4486 chords correctly. */
4487 windows_translate = 1;
4488 }
adcc3809 4489 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4490 {
adcc3809
GV
4491 /* Handle key chords including any modifiers other
4492 than shift directly, in order to preserve as much
4493 modifier information as possible. */
ccc2d29c
GV
4494 if ('A' <= wParam && wParam <= 'Z')
4495 {
4496 /* Don't translate modified alphabetic keystrokes,
4497 so the user doesn't need to constantly switch
4498 layout to type control or meta keystrokes when
4499 the normal layout translates alphabetic
4500 characters to non-ascii characters. */
4501 if (!modifier_set (VK_SHIFT))
4502 wParam += ('a' - 'A');
4503 msg = WM_CHAR;
4504 }
4505 else
4506 {
4507 /* Try to handle other keystrokes by determining the
4508 base character (ie. translating the base key plus
4509 shift modifier). */
4510 int add;
4511 int isdead = 0;
4512 KEY_EVENT_RECORD key;
4513
4514 key.bKeyDown = TRUE;
4515 key.wRepeatCount = 1;
4516 key.wVirtualKeyCode = wParam;
4517 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4518 key.uChar.AsciiChar = 0;
adcc3809 4519 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4520
4521 add = w32_kbd_patch_key (&key);
4522 /* 0 means an unrecognised keycode, negative means
4523 dead key. Ignore both. */
4524 while (--add >= 0)
4525 {
4526 /* Forward asciified character sequence. */
4527 post_character_message
4528 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4529 w32_get_key_modifiers (wParam, lParam));
4530 w32_kbd_patch_key (&key);
4531 }
4532 return 0;
4533 }
4534 }
4535 else
4536 {
4537 /* Let TranslateMessage handle everything else. */
4538 windows_translate = 1;
4539 }
4540 }
4541 }
a1a80b40 4542
adcc3809 4543 translate:
84fb1139
KH
4544 if (windows_translate)
4545 {
e9e23e23 4546 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4547
e9e23e23
GV
4548 windows_msg.time = GetMessageTime ();
4549 TranslateMessage (&windows_msg);
84fb1139
KH
4550 goto dflt;
4551 }
4552
ee78dc32
GV
4553 /* Fall through */
4554
4555 case WM_SYSCHAR:
4556 case WM_CHAR:
ccc2d29c
GV
4557 post_character_message (hwnd, msg, wParam, lParam,
4558 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4559 break;
da36a4d6 4560
5ac45f98
GV
4561 /* Simulate middle mouse button events when left and right buttons
4562 are used together, but only if user has two button mouse. */
ee78dc32 4563 case WM_LBUTTONDOWN:
5ac45f98 4564 case WM_RBUTTONDOWN:
7ce9aaca 4565 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4566 goto handle_plain_button;
4567
4568 {
4569 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4570 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4571
3cb20f4a
RS
4572 if (button_state & this)
4573 return 0;
5ac45f98
GV
4574
4575 if (button_state == 0)
4576 SetCapture (hwnd);
4577
4578 button_state |= this;
4579
4580 if (button_state & other)
4581 {
84fb1139 4582 if (mouse_button_timer)
5ac45f98 4583 {
84fb1139
KH
4584 KillTimer (hwnd, mouse_button_timer);
4585 mouse_button_timer = 0;
5ac45f98
GV
4586
4587 /* Generate middle mouse event instead. */
4588 msg = WM_MBUTTONDOWN;
4589 button_state |= MMOUSE;
4590 }
4591 else if (button_state & MMOUSE)
4592 {
4593 /* Ignore button event if we've already generated a
4594 middle mouse down event. This happens if the
4595 user releases and press one of the two buttons
4596 after we've faked a middle mouse event. */
4597 return 0;
4598 }
4599 else
4600 {
4601 /* Flush out saved message. */
84fb1139 4602 post_msg (&saved_mouse_button_msg);
5ac45f98 4603 }
fbd6baed 4604 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4605 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4606
4607 /* Clear message buffer. */
84fb1139 4608 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4609 }
4610 else
4611 {
4612 /* Hold onto message for now. */
84fb1139 4613 mouse_button_timer =
adcc3809
GV
4614 SetTimer (hwnd, MOUSE_BUTTON_ID,
4615 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4616 saved_mouse_button_msg.msg.hwnd = hwnd;
4617 saved_mouse_button_msg.msg.message = msg;
4618 saved_mouse_button_msg.msg.wParam = wParam;
4619 saved_mouse_button_msg.msg.lParam = lParam;
4620 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4621 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4622 }
4623 }
4624 return 0;
4625
ee78dc32 4626 case WM_LBUTTONUP:
5ac45f98 4627 case WM_RBUTTONUP:
7ce9aaca 4628 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4629 goto handle_plain_button;
4630
4631 {
4632 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4633 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4634
3cb20f4a
RS
4635 if ((button_state & this) == 0)
4636 return 0;
5ac45f98
GV
4637
4638 button_state &= ~this;
4639
4640 if (button_state & MMOUSE)
4641 {
4642 /* Only generate event when second button is released. */
4643 if ((button_state & other) == 0)
4644 {
4645 msg = WM_MBUTTONUP;
4646 button_state &= ~MMOUSE;
4647
4648 if (button_state) abort ();
4649 }
4650 else
4651 return 0;
4652 }
4653 else
4654 {
4655 /* Flush out saved message if necessary. */
84fb1139 4656 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4657 {
84fb1139 4658 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4659 }
4660 }
fbd6baed 4661 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4662 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4663
4664 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4665 saved_mouse_button_msg.msg.hwnd = 0;
4666 KillTimer (hwnd, mouse_button_timer);
4667 mouse_button_timer = 0;
5ac45f98
GV
4668
4669 if (button_state == 0)
4670 ReleaseCapture ();
4671 }
4672 return 0;
4673
74214547
JR
4674 case WM_XBUTTONDOWN:
4675 case WM_XBUTTONUP:
4676 if (w32_pass_extra_mouse_buttons_to_system)
4677 goto dflt;
4678 /* else fall through and process them. */
ee78dc32
GV
4679 case WM_MBUTTONDOWN:
4680 case WM_MBUTTONUP:
5ac45f98 4681 handle_plain_button:
ee78dc32
GV
4682 {
4683 BOOL up;
1edf84e7 4684 int button;
ee78dc32 4685
74214547 4686 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
4687 {
4688 if (up) ReleaseCapture ();
4689 else SetCapture (hwnd);
1edf84e7
GV
4690 button = (button == 0) ? LMOUSE :
4691 ((button == 1) ? MMOUSE : RMOUSE);
4692 if (up)
4693 button_state &= ~button;
4694 else
4695 button_state |= button;
ee78dc32
GV
4696 }
4697 }
4698
fbd6baed 4699 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4700 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
4701
4702 /* Need to return true for XBUTTON messages, false for others,
4703 to indicate that we processed the message. */
4704 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 4705
5ac45f98 4706 case WM_MOUSEMOVE:
9eb16b62
JR
4707 /* If the mouse has just moved into the frame, start tracking
4708 it, so we will be notified when it leaves the frame. Mouse
4709 tracking only works under W98 and NT4 and later. On earlier
4710 versions, there is no way of telling when the mouse leaves the
4711 frame, so we just have to put up with help-echo and mouse
4712 highlighting remaining while the frame is not active. */
4713 if (track_mouse_event_fn && !track_mouse_window)
4714 {
4715 TRACKMOUSEEVENT tme;
4716 tme.cbSize = sizeof (tme);
4717 tme.dwFlags = TME_LEAVE;
4718 tme.hwndTrack = hwnd;
4719
4720 track_mouse_event_fn (&tme);
4721 track_mouse_window = hwnd;
4722 }
4723 case WM_VSCROLL:
fbd6baed 4724 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4725 || (msg == WM_MOUSEMOVE && button_state == 0))
4726 {
fbd6baed 4727 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4728 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4729 return 0;
4730 }
4731
4732 /* Hang onto mouse move and scroll messages for a bit, to avoid
4733 sending such events to Emacs faster than it can process them.
4734 If we get more events before the timer from the first message
4735 expires, we just replace the first message. */
4736
4737 if (saved_mouse_move_msg.msg.hwnd == 0)
4738 mouse_move_timer =
adcc3809
GV
4739 SetTimer (hwnd, MOUSE_MOVE_ID,
4740 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4741
4742 /* Hold onto message for now. */
4743 saved_mouse_move_msg.msg.hwnd = hwnd;
4744 saved_mouse_move_msg.msg.message = msg;
4745 saved_mouse_move_msg.msg.wParam = wParam;
4746 saved_mouse_move_msg.msg.lParam = lParam;
4747 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4748 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4749
4750 return 0;
4751
1edf84e7
GV
4752 case WM_MOUSEWHEEL:
4753 wmsg.dwModifiers = w32_get_modifiers ();
4754 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4755 return 0;
4756
cb9e33d4
RS
4757 case WM_DROPFILES:
4758 wmsg.dwModifiers = w32_get_modifiers ();
4759 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4760 return 0;
4761
84fb1139
KH
4762 case WM_TIMER:
4763 /* Flush out saved messages if necessary. */
4764 if (wParam == mouse_button_timer)
5ac45f98 4765 {
84fb1139
KH
4766 if (saved_mouse_button_msg.msg.hwnd)
4767 {
4768 post_msg (&saved_mouse_button_msg);
4769 saved_mouse_button_msg.msg.hwnd = 0;
4770 }
4771 KillTimer (hwnd, mouse_button_timer);
4772 mouse_button_timer = 0;
4773 }
4774 else if (wParam == mouse_move_timer)
4775 {
4776 if (saved_mouse_move_msg.msg.hwnd)
4777 {
4778 post_msg (&saved_mouse_move_msg);
4779 saved_mouse_move_msg.msg.hwnd = 0;
4780 }
4781 KillTimer (hwnd, mouse_move_timer);
4782 mouse_move_timer = 0;
5ac45f98 4783 }
48094ace
JR
4784 else if (wParam == menu_free_timer)
4785 {
4786 KillTimer (hwnd, menu_free_timer);
4787 menu_free_timer = 0;
27605fa7 4788 f = x_window_to_frame (dpyinfo, hwnd);
48094ace
JR
4789 if (!f->output_data.w32->menu_command_in_progress)
4790 {
4791 /* Free memory used by owner-drawn and help-echo strings. */
4792 w32_free_menu_strings (hwnd);
4793 f->output_data.w32->menubar_active = 0;
4794 }
4795 }
5ac45f98 4796 return 0;
84fb1139
KH
4797
4798 case WM_NCACTIVATE:
4799 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4800 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4801 The only indication we get that something happened is receiving
4802 this message afterwards. So this is a good time to reset our
4803 keyboard modifiers' state. */
4804 reset_modifiers ();
4805 goto dflt;
da36a4d6 4806
1edf84e7 4807 case WM_INITMENU:
487163ac
AI
4808 button_state = 0;
4809 ReleaseCapture ();
1edf84e7
GV
4810 /* We must ensure menu bar is fully constructed and up to date
4811 before allowing user interaction with it. To achieve this
4812 we send this message to the lisp thread and wait for a
4813 reply (whose value is not actually needed) to indicate that
4814 the menu bar is now ready for use, so we can now return.
4815
4816 To remain responsive in the meantime, we enter a nested message
4817 loop that can process all other messages.
4818
4819 However, we skip all this if the message results from calling
4820 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4821 thread a message because it is blocked on us at this point. We
4822 set menubar_active before calling TrackPopupMenu to indicate
4823 this (there is no possibility of confusion with real menubar
4824 being active). */
4825
4826 f = x_window_to_frame (dpyinfo, hwnd);
4827 if (f
4828 && (f->output_data.w32->menubar_active
4829 /* We can receive this message even in the absence of a
4830 menubar (ie. when the system menu is activated) - in this
4831 case we do NOT want to forward the message, otherwise it
4832 will cause the menubar to suddenly appear when the user
4833 had requested it to be turned off! */
4834 || f->output_data.w32->menubar_widget == NULL))
4835 return 0;
4836
4837 {
4838 deferred_msg msg_buf;
4839
4840 /* Detect if message has already been deferred; in this case
4841 we cannot return any sensible value to ignore this. */
4842 if (find_deferred_msg (hwnd, msg) != NULL)
4843 abort ();
4844
4845 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4846 }
4847
4848 case WM_EXITMENULOOP:
4849 f = x_window_to_frame (dpyinfo, hwnd);
4850
48094ace
JR
4851 /* If a menu command is not already in progress, check again
4852 after a short delay, since Windows often (always?) sends the
4853 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4854 if (f && !f->output_data.w32->menu_command_in_progress)
4855 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
1edf84e7
GV
4856 goto dflt;
4857
126f2e35 4858 case WM_MENUSELECT:
4e3a1c61
JR
4859 /* Direct handling of help_echo in menus. Should be safe now
4860 that we generate the help_echo by placing a help event in the
4861 keyboard buffer. */
ca56d953 4862 {
ca56d953
JR
4863 HMENU menu = (HMENU) lParam;
4864 UINT menu_item = (UINT) LOWORD (wParam);
4865 UINT flags = (UINT) HIWORD (wParam);
4866
4e3a1c61 4867 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4868 }
126f2e35
JR
4869 return 0;
4870
87996783
GV
4871 case WM_MEASUREITEM:
4872 f = x_window_to_frame (dpyinfo, hwnd);
4873 if (f)
4874 {
4875 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4876
4877 if (pMis->CtlType == ODT_MENU)
4878 {
4879 /* Work out dimensions for popup menu titles. */
4880 char * title = (char *) pMis->itemData;
4881 HDC hdc = GetDC (hwnd);
4882 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4883 LOGFONT menu_logfont;
4884 HFONT old_font;
4885 SIZE size;
4886
4887 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4888 menu_logfont.lfWeight = FW_BOLD;
4889 menu_font = CreateFontIndirect (&menu_logfont);
4890 old_font = SelectObject (hdc, menu_font);
4891
dfff8a69
JR
4892 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4893 if (title)
4894 {
4895 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4896 pMis->itemWidth = size.cx;
4897 if (pMis->itemHeight < size.cy)
4898 pMis->itemHeight = size.cy;
4899 }
4900 else
4901 pMis->itemWidth = 0;
87996783
GV
4902
4903 SelectObject (hdc, old_font);
4904 DeleteObject (menu_font);
4905 ReleaseDC (hwnd, hdc);
4906 return TRUE;
4907 }
4908 }
4909 return 0;
4910
4911 case WM_DRAWITEM:
4912 f = x_window_to_frame (dpyinfo, hwnd);
4913 if (f)
4914 {
4915 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4916
4917 if (pDis->CtlType == ODT_MENU)
4918 {
4919 /* Draw popup menu title. */
4920 char * title = (char *) pDis->itemData;
212da13b
JR
4921 if (title)
4922 {
4923 HDC hdc = pDis->hDC;
4924 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4925 LOGFONT menu_logfont;
4926 HFONT old_font;
4927
4928 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4929 menu_logfont.lfWeight = FW_BOLD;
4930 menu_font = CreateFontIndirect (&menu_logfont);
4931 old_font = SelectObject (hdc, menu_font);
4932
4933 /* Always draw title as if not selected. */
4934 ExtTextOut (hdc,
4935 pDis->rcItem.left
4936 + GetSystemMetrics (SM_CXMENUCHECK),
4937 pDis->rcItem.top,
4938 ETO_OPAQUE, &pDis->rcItem,
4939 title, strlen (title), NULL);
4940
4941 SelectObject (hdc, old_font);
4942 DeleteObject (menu_font);
4943 }
87996783
GV
4944 return TRUE;
4945 }
4946 }
4947 return 0;
4948
1edf84e7
GV
4949#if 0
4950 /* Still not right - can't distinguish between clicks in the
4951 client area of the frame from clicks forwarded from the scroll
4952 bars - may have to hook WM_NCHITTEST to remember the mouse
4953 position and then check if it is in the client area ourselves. */
4954 case WM_MOUSEACTIVATE:
4955 /* Discard the mouse click that activates a frame, allowing the
4956 user to click anywhere without changing point (or worse!).
4957 Don't eat mouse clicks on scrollbars though!! */
4958 if (LOWORD (lParam) == HTCLIENT )
4959 return MA_ACTIVATEANDEAT;
4960 goto dflt;
4961#endif
4962
9eb16b62
JR
4963 case WM_MOUSELEAVE:
4964 /* No longer tracking mouse. */
4965 track_mouse_window = NULL;
4966
1edf84e7 4967 case WM_ACTIVATEAPP:
ccc2d29c 4968 case WM_ACTIVATE:
1edf84e7
GV
4969 case WM_WINDOWPOSCHANGED:
4970 case WM_SHOWWINDOW:
4971 /* Inform lisp thread that a frame might have just been obscured
4972 or exposed, so should recheck visibility of all frames. */
4973 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4974 goto dflt;
4975
da36a4d6 4976 case WM_SETFOCUS:
adcc3809
GV
4977 dpyinfo->faked_key = 0;
4978 reset_modifiers ();
ccc2d29c
GV
4979 register_hot_keys (hwnd);
4980 goto command;
8681157a 4981 case WM_KILLFOCUS:
ccc2d29c 4982 unregister_hot_keys (hwnd);
487163ac
AI
4983 button_state = 0;
4984 ReleaseCapture ();
65906840
JR
4985 /* Relinquish the system caret. */
4986 if (w32_system_caret_hwnd)
4987 {
93f2ca61 4988 w32_visible_system_caret_hwnd = NULL;
d285988b
JR
4989 w32_system_caret_hwnd = NULL;
4990 DestroyCaret ();
65906840 4991 }
48094ace
JR
4992 goto command;
4993 case WM_COMMAND:
4994 f = x_window_to_frame (dpyinfo, hwnd);
4995 if (f && HIWORD (wParam) == 0)
4996 {
4997 f->output_data.w32->menu_command_in_progress = 1;
4998 if (menu_free_timer)
4999 {
5000 KillTimer (hwnd, menu_free_timer);
5001 menu_free_timer = 0;
5002 }
5003 }
ee78dc32
GV
5004 case WM_MOVE:
5005 case WM_SIZE:
ccc2d29c 5006 command:
fbd6baed 5007 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
5008 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5009 goto dflt;
8847d890
RS
5010
5011 case WM_CLOSE:
fbd6baed 5012 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
5013 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5014 return 0;
5015
ee78dc32 5016 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
5017 /* Don't restrict the sizing of tip frames. */
5018 if (hwnd == tip_window)
5019 return 0;
ee78dc32
GV
5020 {
5021 WINDOWPLACEMENT wp;
5022 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
5023
5024 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
5025 GetWindowPlacement (hwnd, &wp);
5026
1edf84e7 5027 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
5028 {
5029 RECT rect;
5030 int wdiff;
5031 int hdiff;
1edf84e7
GV
5032 DWORD font_width;
5033 DWORD line_height;
5034 DWORD internal_border;
5035 DWORD scrollbar_extra;
ee78dc32
GV
5036 RECT wr;
5037
5ac45f98 5038 wp.length = sizeof(wp);
ee78dc32
GV
5039 GetWindowRect (hwnd, &wr);
5040
3c190163 5041 enter_crit ();
ee78dc32 5042
1edf84e7
GV
5043 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5044 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5045 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5046 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 5047
3c190163 5048 leave_crit ();
ee78dc32
GV
5049
5050 memset (&rect, 0, sizeof (rect));
5051 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
5052 GetMenu (hwnd) != NULL);
5053
1edf84e7
GV
5054 /* Force width and height of client area to be exact
5055 multiples of the character cell dimensions. */
5056 wdiff = (lppos->cx - (rect.right - rect.left)
5057 - 2 * internal_border - scrollbar_extra)
5058 % font_width;
5059 hdiff = (lppos->cy - (rect.bottom - rect.top)
5060 - 2 * internal_border)
5061 % line_height;
ee78dc32
GV
5062
5063 if (wdiff || hdiff)
5064 {
5065 /* For right/bottom sizing we can just fix the sizes.
5066 However for top/left sizing we will need to fix the X
5067 and Y positions as well. */
5068
5069 lppos->cx -= wdiff;
5070 lppos->cy -= hdiff;
5071
5072 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 5073 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
5074 {
5075 if (lppos->x != wr.left || lppos->y != wr.top)
5076 {
5077 lppos->x += wdiff;
5078 lppos->y += hdiff;
5079 }
5080 else
5081 {
5082 lppos->flags |= SWP_NOMOVE;
5083 }
5084 }
5085
1edf84e7 5086 return 0;
ee78dc32
GV
5087 }
5088 }
5089 }
ee78dc32
GV
5090
5091 goto dflt;
1edf84e7 5092
b1f918f8
GV
5093 case WM_GETMINMAXINFO:
5094 /* Hack to correct bug that allows Emacs frames to be resized
5095 below the Minimum Tracking Size. */
5096 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
5097 /* Hack to allow resizing the Emacs frame above the screen size.
5098 Note that Windows 9x limits coordinates to 16-bits. */
5099 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5100 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
5101 return 0;
5102
1edf84e7
GV
5103 case WM_EMACS_CREATESCROLLBAR:
5104 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5105 (struct scroll_bar *) lParam);
5106
5ac45f98 5107 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
5108 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5109
dfdb4047 5110 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
5111 {
5112 HWND foreground_window;
5113 DWORD foreground_thread, retval;
5114
5115 /* On NT 5.0, and apparently Windows 98, it is necessary to
5116 attach to the thread that currently has focus in order to
5117 pull the focus away from it. */
5118 foreground_window = GetForegroundWindow ();
5119 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5120 if (!foreground_window
5121 || foreground_thread == GetCurrentThreadId ()
5122 || !AttachThreadInput (GetCurrentThreadId (),
5123 foreground_thread, TRUE))
5124 foreground_thread = 0;
5125
5126 retval = SetForegroundWindow ((HWND) wParam);
5127
5128 /* Detach from the previous foreground thread. */
5129 if (foreground_thread)
5130 AttachThreadInput (GetCurrentThreadId (),
5131 foreground_thread, FALSE);
5132
5133 return retval;
5134 }
dfdb4047 5135
5ac45f98
GV
5136 case WM_EMACS_SETWINDOWPOS:
5137 {
1edf84e7
GV
5138 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5139 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5140 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5141 }
1edf84e7 5142
ee78dc32 5143 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5144 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5145 return DestroyWindow ((HWND) wParam);
5146
93f2ca61
JR
5147 case WM_EMACS_HIDE_CARET:
5148 return HideCaret (hwnd);
5149
5150 case WM_EMACS_SHOW_CARET:
5151 return ShowCaret (hwnd);
5152
65906840
JR
5153 case WM_EMACS_DESTROY_CARET:
5154 w32_system_caret_hwnd = NULL;
93f2ca61 5155 w32_visible_system_caret_hwnd = NULL;
65906840
JR
5156 return DestroyCaret ();
5157
5158 case WM_EMACS_TRACK_CARET:
5159 /* If there is currently no system caret, create one. */
5160 if (w32_system_caret_hwnd == NULL)
5161 {
93f2ca61
JR
5162 /* Use the default caret width, and avoid changing it
5163 unneccesarily, as it confuses screen reader software. */
65906840 5164 w32_system_caret_hwnd = hwnd;
93f2ca61 5165 CreateCaret (hwnd, NULL, 0,
65906840
JR
5166 w32_system_caret_height);
5167 }
93f2ca61
JR
5168
5169 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5170 return 0;
5171 /* Ensure visible caret gets turned on when requested. */
5172 else if (w32_use_visible_system_caret
5173 && w32_visible_system_caret_hwnd != hwnd)
5174 {
5175 w32_visible_system_caret_hwnd = hwnd;
5176 return ShowCaret (hwnd);
5177 }
5178 /* Ensure visible caret gets turned off when requested. */
5179 else if (!w32_use_visible_system_caret
5180 && w32_visible_system_caret_hwnd)
5181 {
5182 w32_visible_system_caret_hwnd = NULL;
5183 return HideCaret (hwnd);
5184 }
5185 else
5186 return 1;
65906840 5187
1edf84e7
GV
5188 case WM_EMACS_TRACKPOPUPMENU:
5189 {
5190 UINT flags;
5191 POINT *pos;
5192 int retval;
5193 pos = (POINT *)lParam;
5194 flags = TPM_CENTERALIGN;
5195 if (button_state & LMOUSE)
5196 flags |= TPM_LEFTBUTTON;
5197 else if (button_state & RMOUSE)
5198 flags |= TPM_RIGHTBUTTON;
5199
87996783
GV
5200 /* Remember we did a SetCapture on the initial mouse down event,
5201 so for safety, we make sure the capture is cancelled now. */
5202 ReleaseCapture ();
490822ff 5203 button_state = 0;
87996783 5204
1edf84e7
GV
5205 /* Use menubar_active to indicate that WM_INITMENU is from
5206 TrackPopupMenu below, and should be ignored. */
5207 f = x_window_to_frame (dpyinfo, hwnd);
5208 if (f)
5209 f->output_data.w32->menubar_active = 1;
5210
5211 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5212 0, hwnd, NULL))
5213 {
5214 MSG amsg;
5215 /* Eat any mouse messages during popupmenu */
5216 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5217 PM_REMOVE));
5218 /* Get the menu selection, if any */
5219 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5220 {
5221 retval = LOWORD (amsg.wParam);
5222 }
5223 else
5224 {
5225 retval = 0;
5226 }
1edf84e7
GV
5227 }
5228 else
5229 {
5230 retval = -1;
5231 }
5232
5233 return retval;
5234 }
5235
ee78dc32 5236 default:
93fbe8b7
GV
5237 /* Check for messages registered at runtime. */
5238 if (msg == msh_mousewheel)
5239 {
5240 wmsg.dwModifiers = w32_get_modifiers ();
5241 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5242 return 0;
5243 }
5244
ee78dc32
GV
5245 dflt:
5246 return DefWindowProc (hwnd, msg, wParam, lParam);
5247 }
5248
1edf84e7
GV
5249
5250 /* The most common default return code for handled messages is 0. */
5251 return 0;
ee78dc32
GV
5252}
5253
5254void
5255my_create_window (f)
5256 struct frame * f;
5257{
5258 MSG msg;
5259
1edf84e7
GV
5260 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5261 abort ();
ee78dc32
GV
5262 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5263}
5264
ca56d953
JR
5265
5266/* Create a tooltip window. Unlike my_create_window, we do not do this
5267 indirectly via the Window thread, as we do not need to process Window
5268 messages for the tooltip. Creating tooltips indirectly also creates
5269 deadlocks when tooltips are created for menu items. */
5270void
5271my_create_tip_window (f)
5272 struct frame *f;
5273{
bfd6edcc 5274 RECT rect;
ca56d953 5275
bfd6edcc
JR
5276 rect.left = rect.top = 0;
5277 rect.right = PIXEL_WIDTH (f);
5278 rect.bottom = PIXEL_HEIGHT (f);
5279
5280 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5281 FRAME_EXTERNAL_MENU_BAR (f));
5282
5283 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5284 = CreateWindow (EMACS_CLASS,
5285 f->namebuf,
5286 f->output_data.w32->dwStyle,
5287 f->output_data.w32->left_pos,
5288 f->output_data.w32->top_pos,
bfd6edcc
JR
5289 rect.right - rect.left,
5290 rect.bottom - rect.top,
ca56d953
JR
5291 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5292 NULL,
5293 hinst,
5294 NULL);
5295
bfd6edcc 5296 if (tip_window)
ca56d953 5297 {
bfd6edcc
JR
5298 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5299 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5300 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5301 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5302
5303 /* Tip frames have no scrollbars. */
5304 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5305
5306 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5307 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5308 }
5309}
5310
5311
fbd6baed 5312/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5313
5314static void
fbd6baed 5315w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5316 struct frame *f;
5317 long window_prompting;
5318 int minibuffer_only;
5319{
5320 BLOCK_INPUT;
5321
5322 /* Use the resource name as the top-level window name
5323 for looking up resources. Make a non-Lisp copy
5324 for the window manager, so GC relocation won't bother it.
5325
5326 Elsewhere we specify the window name for the window manager. */
5327
5328 {
5329 char *str = (char *) XSTRING (Vx_resource_name)->data;
5330 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5331 strcpy (f->namebuf, str);
5332 }
5333
5334 my_create_window (f);
5335
5336 validate_x_resource_name ();
5337
5338 /* x_set_name normally ignores requests to set the name if the
5339 requested name is the same as the current name. This is the one
5340 place where that assumption isn't correct; f->name is set, but
5341 the server hasn't been told. */
5342 {
5343 Lisp_Object name;
5344 int explicit = f->explicit_name;
5345
5346 f->explicit_name = 0;
5347 name = f->name;
5348 f->name = Qnil;
5349 x_set_name (f, name, explicit);
5350 }
5351
5352 UNBLOCK_INPUT;
5353
5354 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5355 initialize_frame_menubar (f);
5356
fbd6baed 5357 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5358 error ("Unable to create window");
5359}
5360
5361/* Handle the icon stuff for this window. Perhaps later we might
5362 want an x_set_icon_position which can be called interactively as
5363 well. */
5364
5365static void
5366x_icon (f, parms)
5367 struct frame *f;
5368 Lisp_Object parms;
5369{
5370 Lisp_Object icon_x, icon_y;
5371
e9e23e23 5372 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5373 icons in the tray. */
6fc2811b
JR
5374 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5375 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5376 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5377 {
b7826503
PJ
5378 CHECK_NUMBER (icon_x);
5379 CHECK_NUMBER (icon_y);
ee78dc32
GV
5380 }
5381 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5382 error ("Both left and top icon corners of icon must be specified");
5383
5384 BLOCK_INPUT;
5385
5386 if (! EQ (icon_x, Qunbound))
5387 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5388
1edf84e7
GV
5389#if 0 /* TODO */
5390 /* Start up iconic or window? */
5391 x_wm_set_window_state
6fc2811b 5392 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5393 ? IconicState
5394 : NormalState));
5395
5396 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5397 ? f->icon_name
5398 : f->name))->data);
5399#endif
5400
ee78dc32
GV
5401 UNBLOCK_INPUT;
5402}
5403
6fc2811b
JR
5404
5405static void
5406x_make_gc (f)
5407 struct frame *f;
5408{
5409 XGCValues gc_values;
5410
5411 BLOCK_INPUT;
5412
5413 /* Create the GC's of this frame.
5414 Note that many default values are used. */
5415
5416 /* Normal video */
5417 gc_values.font = f->output_data.w32->font;
5418
5419 /* Cursor has cursor-color background, background-color foreground. */
5420 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5421 gc_values.background = f->output_data.w32->cursor_pixel;
5422 f->output_data.w32->cursor_gc
5423 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5424 (GCFont | GCForeground | GCBackground),
5425 &gc_values);
5426
5427 /* Reliefs. */
5428 f->output_data.w32->white_relief.gc = 0;
5429 f->output_data.w32->black_relief.gc = 0;
5430
5431 UNBLOCK_INPUT;
5432}
5433
5434
937e601e
AI
5435/* Handler for signals raised during x_create_frame and
5436 x_create_top_frame. FRAME is the frame which is partially
5437 constructed. */
5438
5439static Lisp_Object
5440unwind_create_frame (frame)
5441 Lisp_Object frame;
5442{
5443 struct frame *f = XFRAME (frame);
5444
5445 /* If frame is ``official'', nothing to do. */
5446 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5447 {
5448#ifdef GLYPH_DEBUG
5449 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5450#endif
5451
5452 x_free_frame_resources (f);
5453
5454 /* Check that reference counts are indeed correct. */
5455 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5456 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5457
5458 return Qt;
937e601e
AI
5459 }
5460
5461 return Qnil;
5462}
5463
5464
ee78dc32
GV
5465DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5466 1, 1, 0,
74e1aeec
JR
5467 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5468Returns an Emacs frame object.
5469ALIST is an alist of frame parameters.
5470If the parameters specify that the frame should not have a minibuffer,
5471and do not specify a specific minibuffer window to use,
5472then `default-minibuffer-frame' must be a frame whose minibuffer can
5473be shared by the new frame.
5474
5475This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5476 (parms)
5477 Lisp_Object parms;
5478{
5479 struct frame *f;
5480 Lisp_Object frame, tem;
5481 Lisp_Object name;
5482 int minibuffer_only = 0;
5483 long window_prompting = 0;
5484 int width, height;
dc220243 5485 int count = BINDING_STACK_SIZE ();
1edf84e7 5486 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5487 Lisp_Object display;
6fc2811b 5488 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5489 Lisp_Object parent;
5490 struct kboard *kb;
5491
4587b026
GV
5492 check_w32 ();
5493
ee78dc32
GV
5494 /* Use this general default value to start with
5495 until we know if this frame has a specified name. */
5496 Vx_resource_name = Vinvocation_name;
5497
6fc2811b 5498 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5499 if (EQ (display, Qunbound))
5500 display = Qnil;
5501 dpyinfo = check_x_display_info (display);
5502#ifdef MULTI_KBOARD
5503 kb = dpyinfo->kboard;
5504#else
5505 kb = &the_only_kboard;
5506#endif
5507
6fc2811b 5508 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5509 if (!STRINGP (name)
5510 && ! EQ (name, Qunbound)
5511 && ! NILP (name))
5512 error ("Invalid frame name--not a string or nil");
5513
5514 if (STRINGP (name))
5515 Vx_resource_name = name;
5516
5517 /* See if parent window is specified. */
6fc2811b 5518 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5519 if (EQ (parent, Qunbound))
5520 parent = Qnil;
5521 if (! NILP (parent))
b7826503 5522 CHECK_NUMBER (parent);
ee78dc32 5523
1edf84e7
GV
5524 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5525 /* No need to protect DISPLAY because that's not used after passing
5526 it to make_frame_without_minibuffer. */
5527 frame = Qnil;
5528 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5529 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5530 RES_TYPE_SYMBOL);
ee78dc32
GV
5531 if (EQ (tem, Qnone) || NILP (tem))
5532 f = make_frame_without_minibuffer (Qnil, kb, display);
5533 else if (EQ (tem, Qonly))
5534 {
5535 f = make_minibuffer_frame ();
5536 minibuffer_only = 1;
5537 }
5538 else if (WINDOWP (tem))
5539 f = make_frame_without_minibuffer (tem, kb, display);
5540 else
5541 f = make_frame (1);
5542
1edf84e7
GV
5543 XSETFRAME (frame, f);
5544
ee78dc32
GV
5545 /* Note that Windows does support scroll bars. */
5546 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5547 /* By default, make scrollbars the system standard width. */
5548 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5549
fbd6baed 5550 f->output_method = output_w32;
6fc2811b
JR
5551 f->output_data.w32 =
5552 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5553 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5554 FRAME_FONTSET (f) = -1;
937e601e 5555 record_unwind_protect (unwind_create_frame, frame);
4587b026 5556
1edf84e7 5557 f->icon_name
6fc2811b 5558 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5559 if (! STRINGP (f->icon_name))
5560 f->icon_name = Qnil;
5561
fbd6baed 5562/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5563#ifdef MULTI_KBOARD
5564 FRAME_KBOARD (f) = kb;
5565#endif
5566
5567 /* Specify the parent under which to make this window. */
5568
5569 if (!NILP (parent))
5570 {
1660f34a 5571 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5572 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5573 }
5574 else
5575 {
fbd6baed
GV
5576 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5577 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5578 }
5579
ee78dc32
GV
5580 /* Set the name; the functions to which we pass f expect the name to
5581 be set. */
5582 if (EQ (name, Qunbound) || NILP (name))
5583 {
fbd6baed 5584 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5585 f->explicit_name = 0;
5586 }
5587 else
5588 {
5589 f->name = name;
5590 f->explicit_name = 1;
5591 /* use the frame's title when getting resources for this frame. */
5592 specbind (Qx_resource_name, name);
5593 }
5594
5595 /* Extract the window parameters from the supplied values
5596 that are needed to determine window geometry. */
5597 {
5598 Lisp_Object font;
5599
6fc2811b
JR
5600 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5601
ee78dc32
GV
5602 BLOCK_INPUT;
5603 /* First, try whatever font the caller has specified. */
5604 if (STRINGP (font))
4587b026
GV
5605 {
5606 tem = Fquery_fontset (font, Qnil);
5607 if (STRINGP (tem))
5608 font = x_new_fontset (f, XSTRING (tem)->data);
5609 else
1075afa9 5610 font = x_new_font (f, XSTRING (font)->data);
4587b026 5611 }
ee78dc32
GV
5612 /* Try out a font which we hope has bold and italic variations. */
5613 if (!STRINGP (font))
e39649be 5614 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5615 if (! STRINGP (font))
6fc2811b 5616 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5617 /* If those didn't work, look for something which will at least work. */
5618 if (! STRINGP (font))
6fc2811b 5619 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5620 UNBLOCK_INPUT;
5621 if (! STRINGP (font))
1edf84e7 5622 font = build_string ("Fixedsys");
ee78dc32
GV
5623
5624 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5625 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5626 }
5627
5628 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5629 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5630 /* This defaults to 2 in order to match xterm. We recognize either
5631 internalBorderWidth or internalBorder (which is what xterm calls
5632 it). */
5633 if (NILP (Fassq (Qinternal_border_width, parms)))
5634 {
5635 Lisp_Object value;
5636
6fc2811b 5637 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5638 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5639 if (! EQ (value, Qunbound))
5640 parms = Fcons (Fcons (Qinternal_border_width, value),
5641 parms);
5642 }
1edf84e7 5643 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5644 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5645 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5646 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5647 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5648
5649 /* Also do the stuff which must be set before the window exists. */
5650 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5651 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5652 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5653 "background", "Background", RES_TYPE_STRING);
ee78dc32 5654 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5655 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5656 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5657 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5658 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5659 "borderColor", "BorderColor", RES_TYPE_STRING);
5660 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5661 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5662 x_default_parameter (f, parms, Qline_spacing, Qnil,
5663 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5664 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5665 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5666 x_default_parameter (f, parms, Qright_fringe, Qnil,
5667 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5668
ee78dc32 5669
6fc2811b
JR
5670 /* Init faces before x_default_parameter is called for scroll-bar
5671 parameters because that function calls x_set_scroll_bar_width,
5672 which calls change_frame_size, which calls Fset_window_buffer,
5673 which runs hooks, which call Fvertical_motion. At the end, we
5674 end up in init_iterator with a null face cache, which should not
5675 happen. */
5676 init_frame_faces (f);
5677
ee78dc32 5678 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b 5679 "menuBar", "MenuBar", RES_TYPE_NUMBER);
0327b4cc 5680 x_default_parameter (f, parms, Qtool_bar_lines, make_number (HAVE_IMAGES),
6fc2811b 5681 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5682 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5683 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5684 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5685 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
5686 x_default_parameter (f, parms, Qfullscreen, Qnil,
5687 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 5688
fbd6baed
GV
5689 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5690 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5691
5692 /* Add the tool-bar height to the initial frame height so that the
5693 user gets a text display area of the size he specified with -g or
5694 via .Xdefaults. Later changes of the tool-bar height don't
5695 change the frame size. This is done so that users can create
5696 tall Emacs frames without having to guess how tall the tool-bar
5697 will get. */
5698 if (FRAME_TOOL_BAR_LINES (f))
5699 {
5700 int margin, relief, bar_height;
5701
a05e2bae 5702 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5703 ? tool_bar_button_relief
5704 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5705
5706 if (INTEGERP (Vtool_bar_button_margin)
5707 && XINT (Vtool_bar_button_margin) > 0)
5708 margin = XFASTINT (Vtool_bar_button_margin);
5709 else if (CONSP (Vtool_bar_button_margin)
5710 && INTEGERP (XCDR (Vtool_bar_button_margin))
5711 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5712 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5713 else
5714 margin = 0;
5715
5716 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5717 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5718 }
5719
ee78dc32
GV
5720 window_prompting = x_figure_window_size (f, parms);
5721
5722 if (window_prompting & XNegative)
5723 {
5724 if (window_prompting & YNegative)
fbd6baed 5725 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5726 else
fbd6baed 5727 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5728 }
5729 else
5730 {
5731 if (window_prompting & YNegative)
fbd6baed 5732 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5733 else
fbd6baed 5734 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5735 }
5736
fbd6baed 5737 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5738
6fc2811b
JR
5739 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5740 f->no_split = minibuffer_only || EQ (tem, Qt);
5741
fbd6baed 5742 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5743 x_icon (f, parms);
6fc2811b
JR
5744
5745 x_make_gc (f);
5746
5747 /* Now consider the frame official. */
5748 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5749 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5750
5751 /* We need to do this after creating the window, so that the
5752 icon-creation functions can say whose icon they're describing. */
5753 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5754 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5755
5756 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5757 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5758 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5759 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5760 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5761 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5762 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5763 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5764
5765 /* Dimensions, especially f->height, must be done via change_frame_size.
5766 Change will not be effected unless different from the current
5767 f->height. */
5768 width = f->width;
5769 height = f->height;
dc220243 5770
1026b400
RS
5771 f->height = 0;
5772 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5773 change_frame_size (f, height, width, 1, 0, 0);
5774
6fc2811b
JR
5775 /* Tell the server what size and position, etc, we want, and how
5776 badly we want them. This should be done after we have the menu
5777 bar so that its size can be taken into account. */
ee78dc32
GV
5778 BLOCK_INPUT;
5779 x_wm_set_size_hint (f, window_prompting, 0);
5780 UNBLOCK_INPUT;
5781
815d969e
JR
5782 /* Avoid a bug that causes the new frame to never become visible if
5783 an echo area message is displayed during the following call1. */
5784 specbind(Qredisplay_dont_pause, Qt);
5785
4694d762
JR
5786 /* Set up faces after all frame parameters are known. This call
5787 also merges in face attributes specified for new frames. If we
5788 don't do this, the `menu' face for instance won't have the right
5789 colors, and the menu bar won't appear in the specified colors for
5790 new frames. */
5791 call1 (Qface_set_after_frame_default, frame);
5792
6fc2811b
JR
5793 /* Make the window appear on the frame and enable display, unless
5794 the caller says not to. However, with explicit parent, Emacs
5795 cannot control visibility, so don't try. */
fbd6baed 5796 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5797 {
5798 Lisp_Object visibility;
5799
6fc2811b 5800 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5801 if (EQ (visibility, Qunbound))
5802 visibility = Qt;
5803
5804 if (EQ (visibility, Qicon))
5805 x_iconify_frame (f);
5806 else if (! NILP (visibility))
5807 x_make_frame_visible (f);
5808 else
5809 /* Must have been Qnil. */
5810 ;
5811 }
6fc2811b 5812 UNGCPRO;
9e57df62
GM
5813
5814 /* Make sure windows on this frame appear in calls to next-window
5815 and similar functions. */
5816 Vwindow_list = Qnil;
5817
ee78dc32
GV
5818 return unbind_to (count, frame);
5819}
5820
5821/* FRAME is used only to get a handle on the X display. We don't pass the
5822 display info directly because we're called from frame.c, which doesn't
5823 know about that structure. */
5824Lisp_Object
5825x_get_focus_frame (frame)
5826 struct frame *frame;
5827{
fbd6baed 5828 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5829 Lisp_Object xfocus;
fbd6baed 5830 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5831 return Qnil;
5832
fbd6baed 5833 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5834 return xfocus;
5835}
1edf84e7
GV
5836
5837DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5838 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5839 (frame)
5840 Lisp_Object frame;
5841{
5842 x_focus_on_frame (check_x_frame (frame));
5843 return Qnil;
5844}
5845
ee78dc32 5846\f
767b1ff0
JR
5847/* Return the charset portion of a font name. */
5848char * xlfd_charset_of_font (char * fontname)
5849{
5850 char *charset, *encoding;
5851
5852 encoding = strrchr(fontname, '-');
ceb12877 5853 if (!encoding || encoding == fontname)
767b1ff0
JR
5854 return NULL;
5855
478ea067
AI
5856 for (charset = encoding - 1; charset >= fontname; charset--)
5857 if (*charset == '-')
5858 break;
767b1ff0 5859
478ea067 5860 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5861 return NULL;
5862
5863 return charset + 1;
5864}
5865
33d52f9c
GV
5866struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5867 int size, char* filename);
8edb0a6f 5868static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5869static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5870 char * charset);
5871static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5872
8edb0a6f 5873static struct font_info *
33d52f9c 5874w32_load_system_font (f,fontname,size)
55dcfc15
AI
5875 struct frame *f;
5876 char * fontname;
5877 int size;
ee78dc32 5878{
4587b026
GV
5879 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5880 Lisp_Object font_names;
5881
4587b026
GV
5882 /* Get a list of all the fonts that match this name. Once we
5883 have a list of matching fonts, we compare them against the fonts
5884 we already have loaded by comparing names. */
5885 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5886
5887 if (!NILP (font_names))
3c190163 5888 {
4587b026
GV
5889 Lisp_Object tail;
5890 int i;
4587b026
GV
5891
5892 /* First check if any are already loaded, as that is cheaper
5893 than loading another one. */
5894 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5895 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5896 if (dpyinfo->font_table[i].name
5897 && (!strcmp (dpyinfo->font_table[i].name,
5898 XSTRING (XCAR (tail))->data)
5899 || !strcmp (dpyinfo->font_table[i].full_name,
5900 XSTRING (XCAR (tail))->data)))
4587b026 5901 return (dpyinfo->font_table + i);
6fc2811b 5902
8e713be6 5903 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5904 }
1075afa9 5905 else if (w32_strict_fontnames)
5ca0cd71
GV
5906 {
5907 /* If EnumFontFamiliesEx was available, we got a full list of
5908 fonts back so stop now to avoid the possibility of loading a
5909 random font. If we had to fall back to EnumFontFamilies, the
5910 list is incomplete, so continue whether the font we want was
5911 listed or not. */
5912 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5913 FARPROC enum_font_families_ex
1075afa9 5914 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5915 if (enum_font_families_ex)
5916 return NULL;
5917 }
4587b026
GV
5918
5919 /* Load the font and add it to the table. */
5920 {
767b1ff0 5921 char *full_name, *encoding, *charset;
4587b026
GV
5922 XFontStruct *font;
5923 struct font_info *fontp;
3c190163 5924 LOGFONT lf;
4587b026 5925 BOOL ok;
19c291d3 5926 int codepage;
6fc2811b 5927 int i;
5ac45f98 5928
4587b026 5929 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5930 return (NULL);
5ac45f98 5931
4587b026
GV
5932 if (!*lf.lfFaceName)
5933 /* If no name was specified for the font, we get a random font
5934 from CreateFontIndirect - this is not particularly
5935 desirable, especially since CreateFontIndirect does not
5936 fill out the missing name in lf, so we never know what we
5937 ended up with. */
5938 return NULL;
5939
d65a9cdc
JR
5940 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5941 since those fonts leave garbage behind. */
5942 lf.lfQuality = ANTIALIASED_QUALITY;
5943
3c190163 5944 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5945 bzero (font, sizeof (*font));
5ac45f98 5946
33d52f9c
GV
5947 /* Set bdf to NULL to indicate that this is a Windows font. */
5948 font->bdf = NULL;
5ac45f98 5949
3c190163 5950 BLOCK_INPUT;
5ac45f98
GV
5951
5952 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5953
1a292d24
AI
5954 if (font->hfont == NULL)
5955 {
5956 ok = FALSE;
5957 }
5958 else
5959 {
5960 HDC hdc;
5961 HANDLE oldobj;
19c291d3
AI
5962
5963 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5964
5965 hdc = GetDC (dpyinfo->root_window);
5966 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5967
1a292d24 5968 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5969 if (codepage == CP_UNICODE)
5970 font->double_byte_p = 1;
5971 else
8b77111c
AI
5972 {
5973 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5974 don't report themselves as double byte fonts, when
5975 patently they are. So instead of trusting
5976 GetFontLanguageInfo, we check the properties of the
5977 codepage directly, since that is ultimately what we are
5978 working from anyway. */
5979 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5980 CPINFO cpi = {0};
5981 GetCPInfo (codepage, &cpi);
5982 font->double_byte_p = cpi.MaxCharSize > 1;
5983 }
5c6682be 5984
1a292d24
AI
5985 SelectObject (hdc, oldobj);
5986 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5987 /* Fill out details in lf according to the font that was
5988 actually loaded. */
5989 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5990 lf.lfWidth = font->tm.tmAveCharWidth;
5991 lf.lfWeight = font->tm.tmWeight;
5992 lf.lfItalic = font->tm.tmItalic;
5993 lf.lfCharSet = font->tm.tmCharSet;
5994 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5995 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5996 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5997 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5998
5999 w32_cache_char_metrics (font);
1a292d24 6000 }
5ac45f98 6001
1a292d24 6002 UNBLOCK_INPUT;
5ac45f98 6003
4587b026
GV
6004 if (!ok)
6005 {
1a292d24
AI
6006 w32_unload_font (dpyinfo, font);
6007 return (NULL);
6008 }
ee78dc32 6009
6fc2811b
JR
6010 /* Find a free slot in the font table. */
6011 for (i = 0; i < dpyinfo->n_fonts; ++i)
6012 if (dpyinfo->font_table[i].name == NULL)
6013 break;
6014
6015 /* If no free slot found, maybe enlarge the font table. */
6016 if (i == dpyinfo->n_fonts
6017 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 6018 {
6fc2811b
JR
6019 int sz;
6020 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6021 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 6022 dpyinfo->font_table
6fc2811b 6023 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
6024 }
6025
6fc2811b
JR
6026 fontp = dpyinfo->font_table + i;
6027 if (i == dpyinfo->n_fonts)
6028 ++dpyinfo->n_fonts;
4587b026
GV
6029
6030 /* Now fill in the slots of *FONTP. */
6031 BLOCK_INPUT;
6032 fontp->font = font;
6fc2811b 6033 fontp->font_idx = i;
4587b026
GV
6034 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6035 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6036
767b1ff0
JR
6037 charset = xlfd_charset_of_font (fontname);
6038
19c291d3
AI
6039 /* Cache the W32 codepage for a font. This makes w32_encode_char
6040 (called for every glyph during redisplay) much faster. */
6041 fontp->codepage = codepage;
6042
4587b026
GV
6043 /* Work out the font's full name. */
6044 full_name = (char *)xmalloc (100);
767b1ff0 6045 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
6046 fontp->full_name = full_name;
6047 else
6048 {
6049 /* If all else fails - just use the name we used to load it. */
6050 xfree (full_name);
6051 fontp->full_name = fontp->name;
6052 }
6053
6054 fontp->size = FONT_WIDTH (font);
6055 fontp->height = FONT_HEIGHT (font);
6056
6057 /* The slot `encoding' specifies how to map a character
6058 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
6059 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6060 (0:0x20..0x7F, 1:0xA0..0xFF,
6061 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 6062 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 6063 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
6064 which is never used by any charset. If mapping can't be
6065 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
6066
6067 /* SJIS fonts need to be set to type 4, all others seem to work as
6068 type FONT_ENCODING_NOT_DECIDED. */
6069 encoding = strrchr (fontp->name, '-');
d84b082d 6070 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 6071 fontp->encoding[1] = 4;
33d52f9c 6072 else
1c885fe1 6073 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
6074
6075 /* The following three values are set to 0 under W32, which is
6076 what they get set to if XGetFontProperty fails under X. */
6077 fontp->baseline_offset = 0;
6078 fontp->relative_compose = 0;
33d52f9c 6079 fontp->default_ascent = 0;
4587b026 6080
6fc2811b
JR
6081 /* Set global flag fonts_changed_p to non-zero if the font loaded
6082 has a character with a smaller width than any other character
f7b9d4d1 6083 before, or if the font loaded has a smaller height than any
6fc2811b
JR
6084 other font loaded before. If this happens, it will make a
6085 glyph matrix reallocation necessary. */
f7b9d4d1 6086 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 6087 UNBLOCK_INPUT;
4587b026
GV
6088 return fontp;
6089 }
6090}
6091
33d52f9c
GV
6092/* Load font named FONTNAME of size SIZE for frame F, and return a
6093 pointer to the structure font_info while allocating it dynamically.
6094 If loading fails, return NULL. */
6095struct font_info *
6096w32_load_font (f,fontname,size)
6097struct frame *f;
6098char * fontname;
6099int size;
6100{
6101 Lisp_Object bdf_fonts;
6102 struct font_info *retval = NULL;
6103
8edb0a6f 6104 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
6105
6106 while (!retval && CONSP (bdf_fonts))
6107 {
6108 char *bdf_name, *bdf_file;
6109 Lisp_Object bdf_pair;
6110
8e713be6
KR
6111 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6112 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6113 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
6114
6115 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6116
8e713be6 6117 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
6118 }
6119
6120 if (retval)
6121 return retval;
6122
6123 return w32_load_system_font(f, fontname, size);
6124}
6125
6126
ee78dc32 6127void
fbd6baed
GV
6128w32_unload_font (dpyinfo, font)
6129 struct w32_display_info *dpyinfo;
ee78dc32
GV
6130 XFontStruct * font;
6131{
6132 if (font)
6133 {
c6be3860 6134 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
6135 if (font->bdf) w32_free_bdf_font (font->bdf);
6136
3c190163 6137 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
6138 xfree (font);
6139 }
6140}
6141
fbd6baed 6142/* The font conversion stuff between x and w32 */
ee78dc32
GV
6143
6144/* X font string is as follows (from faces.el)
6145 * (let ((- "[-?]")
6146 * (foundry "[^-]+")
6147 * (family "[^-]+")
6148 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6149 * (weight\? "\\([^-]*\\)") ; 1
6150 * (slant "\\([ior]\\)") ; 2
6151 * (slant\? "\\([^-]?\\)") ; 2
6152 * (swidth "\\([^-]*\\)") ; 3
6153 * (adstyle "[^-]*") ; 4
6154 * (pixelsize "[0-9]+")
6155 * (pointsize "[0-9][0-9]+")
6156 * (resx "[0-9][0-9]+")
6157 * (resy "[0-9][0-9]+")
6158 * (spacing "[cmp?*]")
6159 * (avgwidth "[0-9]+")
6160 * (registry "[^-]+")
6161 * (encoding "[^-]+")
6162 * )
ee78dc32 6163 */
ee78dc32 6164
8edb0a6f 6165static LONG
fbd6baed 6166x_to_w32_weight (lpw)
ee78dc32
GV
6167 char * lpw;
6168{
6169 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6170
6171 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6172 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6173 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6174 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6175 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6176 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6177 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6178 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6179 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6180 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6181 else
5ac45f98 6182 return FW_DONTCARE;
ee78dc32
GV
6183}
6184
5ac45f98 6185
8edb0a6f 6186static char *
fbd6baed 6187w32_to_x_weight (fnweight)
ee78dc32
GV
6188 int fnweight;
6189{
5ac45f98
GV
6190 if (fnweight >= FW_HEAVY) return "heavy";
6191 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6192 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6193 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6194 if (fnweight >= FW_MEDIUM) return "medium";
6195 if (fnweight >= FW_NORMAL) return "normal";
6196 if (fnweight >= FW_LIGHT) return "light";
6197 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6198 if (fnweight >= FW_THIN) return "thin";
6199 else
6200 return "*";
6201}
6202
8edb0a6f 6203static LONG
fbd6baed 6204x_to_w32_charset (lpcs)
5ac45f98
GV
6205 char * lpcs;
6206{
767b1ff0 6207 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6208 char *charset;
6209 int len = strlen (lpcs);
6210
6211 /* Support "*-#nnn" format for unknown charsets. */
6212 if (strncmp (lpcs, "*-#", 3) == 0)
6213 return atoi (lpcs + 3);
6214
6215 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6216 charset = alloca (len + 1);
6217 strcpy (charset, lpcs);
6218 lpcs = strchr (charset, '*');
6219 if (lpcs)
6220 *lpcs = 0;
4587b026 6221
dfff8a69
JR
6222 /* Look through w32-charset-info-alist for the character set.
6223 Format of each entry is
6224 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6225 */
8b77111c 6226 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6227
767b1ff0
JR
6228 if (NILP(this_entry))
6229 {
6230 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6231 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6232 return ANSI_CHARSET;
6233 else
6234 return DEFAULT_CHARSET;
6235 }
6236
6237 w32_charset = Fcar (Fcdr (this_entry));
6238
d84b082d 6239 /* Translate Lisp symbol to number. */
767b1ff0
JR
6240 if (w32_charset == Qw32_charset_ansi)
6241 return ANSI_CHARSET;
6242 if (w32_charset == Qw32_charset_symbol)
6243 return SYMBOL_CHARSET;
6244 if (w32_charset == Qw32_charset_shiftjis)
6245 return SHIFTJIS_CHARSET;
6246 if (w32_charset == Qw32_charset_hangeul)
6247 return HANGEUL_CHARSET;
6248 if (w32_charset == Qw32_charset_chinesebig5)
6249 return CHINESEBIG5_CHARSET;
6250 if (w32_charset == Qw32_charset_gb2312)
6251 return GB2312_CHARSET;
6252 if (w32_charset == Qw32_charset_oem)
6253 return OEM_CHARSET;
dfff8a69 6254#ifdef JOHAB_CHARSET
767b1ff0
JR
6255 if (w32_charset == Qw32_charset_johab)
6256 return JOHAB_CHARSET;
6257 if (w32_charset == Qw32_charset_easteurope)
6258 return EASTEUROPE_CHARSET;
6259 if (w32_charset == Qw32_charset_turkish)
6260 return TURKISH_CHARSET;
6261 if (w32_charset == Qw32_charset_baltic)
6262 return BALTIC_CHARSET;
6263 if (w32_charset == Qw32_charset_russian)
6264 return RUSSIAN_CHARSET;
6265 if (w32_charset == Qw32_charset_arabic)
6266 return ARABIC_CHARSET;
6267 if (w32_charset == Qw32_charset_greek)
6268 return GREEK_CHARSET;
6269 if (w32_charset == Qw32_charset_hebrew)
6270 return HEBREW_CHARSET;
6271 if (w32_charset == Qw32_charset_vietnamese)
6272 return VIETNAMESE_CHARSET;
6273 if (w32_charset == Qw32_charset_thai)
6274 return THAI_CHARSET;
6275 if (w32_charset == Qw32_charset_mac)
6276 return MAC_CHARSET;
dfff8a69 6277#endif /* JOHAB_CHARSET */
5ac45f98 6278#ifdef UNICODE_CHARSET
767b1ff0
JR
6279 if (w32_charset == Qw32_charset_unicode)
6280 return UNICODE_CHARSET;
5ac45f98 6281#endif
dfff8a69
JR
6282
6283 return DEFAULT_CHARSET;
5ac45f98
GV
6284}
6285
dfff8a69 6286
8edb0a6f 6287static char *
fbd6baed 6288w32_to_x_charset (fncharset)
5ac45f98
GV
6289 int fncharset;
6290{
5e905a57 6291 static char buf[32];
767b1ff0 6292 Lisp_Object charset_type;
1edf84e7 6293
5ac45f98
GV
6294 switch (fncharset)
6295 {
767b1ff0
JR
6296 case ANSI_CHARSET:
6297 /* Handle startup case of w32-charset-info-alist not
6298 being set up yet. */
6299 if (NILP(Vw32_charset_info_alist))
6300 return "iso8859-1";
6301 charset_type = Qw32_charset_ansi;
6302 break;
6303 case DEFAULT_CHARSET:
6304 charset_type = Qw32_charset_default;
6305 break;
6306 case SYMBOL_CHARSET:
6307 charset_type = Qw32_charset_symbol;
6308 break;
6309 case SHIFTJIS_CHARSET:
6310 charset_type = Qw32_charset_shiftjis;
6311 break;
6312 case HANGEUL_CHARSET:
6313 charset_type = Qw32_charset_hangeul;
6314 break;
6315 case GB2312_CHARSET:
6316 charset_type = Qw32_charset_gb2312;
6317 break;
6318 case CHINESEBIG5_CHARSET:
6319 charset_type = Qw32_charset_chinesebig5;
6320 break;
6321 case OEM_CHARSET:
6322 charset_type = Qw32_charset_oem;
6323 break;
4587b026
GV
6324
6325 /* More recent versions of Windows (95 and NT4.0) define more
6326 character sets. */
6327#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6328 case EASTEUROPE_CHARSET:
6329 charset_type = Qw32_charset_easteurope;
6330 break;
6331 case TURKISH_CHARSET:
6332 charset_type = Qw32_charset_turkish;
6333 break;
6334 case BALTIC_CHARSET:
6335 charset_type = Qw32_charset_baltic;
6336 break;
33d52f9c 6337 case RUSSIAN_CHARSET:
767b1ff0
JR
6338 charset_type = Qw32_charset_russian;
6339 break;
6340 case ARABIC_CHARSET:
6341 charset_type = Qw32_charset_arabic;
6342 break;
6343 case GREEK_CHARSET:
6344 charset_type = Qw32_charset_greek;
6345 break;
6346 case HEBREW_CHARSET:
6347 charset_type = Qw32_charset_hebrew;
6348 break;
6349 case VIETNAMESE_CHARSET:
6350 charset_type = Qw32_charset_vietnamese;
6351 break;
6352 case THAI_CHARSET:
6353 charset_type = Qw32_charset_thai;
6354 break;
6355 case MAC_CHARSET:
6356 charset_type = Qw32_charset_mac;
6357 break;
6358 case JOHAB_CHARSET:
6359 charset_type = Qw32_charset_johab;
6360 break;
4587b026
GV
6361#endif
6362
5ac45f98 6363#ifdef UNICODE_CHARSET
767b1ff0
JR
6364 case UNICODE_CHARSET:
6365 charset_type = Qw32_charset_unicode;
6366 break;
5ac45f98 6367#endif
767b1ff0
JR
6368 default:
6369 /* Encode numerical value of unknown charset. */
6370 sprintf (buf, "*-#%u", fncharset);
6371 return buf;
5ac45f98 6372 }
767b1ff0
JR
6373
6374 {
6375 Lisp_Object rest;
6376 char * best_match = NULL;
6377
6378 /* Look through w32-charset-info-alist for the character set.
6379 Prefer ISO codepages, and prefer lower numbers in the ISO
6380 range. Only return charsets for codepages which are installed.
6381
6382 Format of each entry is
6383 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6384 */
6385 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6386 {
6387 char * x_charset;
6388 Lisp_Object w32_charset;
6389 Lisp_Object codepage;
6390
6391 Lisp_Object this_entry = XCAR (rest);
6392
6393 /* Skip invalid entries in alist. */
6394 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6395 || !CONSP (XCDR (this_entry))
6396 || !SYMBOLP (XCAR (XCDR (this_entry))))
6397 continue;
6398
6399 x_charset = XSTRING (XCAR (this_entry))->data;
6400 w32_charset = XCAR (XCDR (this_entry));
6401 codepage = XCDR (XCDR (this_entry));
6402
6403 /* Look for Same charset and a valid codepage (or non-int
6404 which means ignore). */
6405 if (w32_charset == charset_type
6406 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6407 || IsValidCodePage (XINT (codepage))))
6408 {
6409 /* If we don't have a match already, then this is the
6410 best. */
6411 if (!best_match)
6412 best_match = x_charset;
6413 /* If this is an ISO codepage, and the best so far isn't,
6414 then this is better. */
d84b082d
JR
6415 else if (strnicmp (best_match, "iso", 3) != 0
6416 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
6417 best_match = x_charset;
6418 /* If both are ISO8859 codepages, choose the one with the
6419 lowest number in the encoding field. */
d84b082d
JR
6420 else if (strnicmp (best_match, "iso8859-", 8) == 0
6421 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
6422 {
6423 int best_enc = atoi (best_match + 8);
6424 int this_enc = atoi (x_charset + 8);
6425 if (this_enc > 0 && this_enc < best_enc)
6426 best_match = x_charset;
6427 }
6428 }
6429 }
6430
6431 /* If no match, encode the numeric value. */
6432 if (!best_match)
6433 {
6434 sprintf (buf, "*-#%u", fncharset);
6435 return buf;
6436 }
6437
5e905a57
JR
6438 strncpy(buf, best_match, 31);
6439 buf[31] = '\0';
767b1ff0
JR
6440 return buf;
6441 }
ee78dc32
GV
6442}
6443
dfff8a69 6444
d84b082d
JR
6445/* Return all the X charsets that map to a font. */
6446static Lisp_Object
6447w32_to_all_x_charsets (fncharset)
6448 int fncharset;
6449{
6450 static char buf[32];
6451 Lisp_Object charset_type;
6452 Lisp_Object retval = Qnil;
6453
6454 switch (fncharset)
6455 {
6456 case ANSI_CHARSET:
6457 /* Handle startup case of w32-charset-info-alist not
6458 being set up yet. */
6459 if (NILP(Vw32_charset_info_alist))
d86c35ee
JR
6460 return Fcons (build_string ("iso8859-1"), Qnil);
6461
d84b082d
JR
6462 charset_type = Qw32_charset_ansi;
6463 break;
6464 case DEFAULT_CHARSET:
6465 charset_type = Qw32_charset_default;
6466 break;
6467 case SYMBOL_CHARSET:
6468 charset_type = Qw32_charset_symbol;
6469 break;
6470 case SHIFTJIS_CHARSET:
6471 charset_type = Qw32_charset_shiftjis;
6472 break;
6473 case HANGEUL_CHARSET:
6474 charset_type = Qw32_charset_hangeul;
6475 break;
6476 case GB2312_CHARSET:
6477 charset_type = Qw32_charset_gb2312;
6478 break;
6479 case CHINESEBIG5_CHARSET:
6480 charset_type = Qw32_charset_chinesebig5;
6481 break;
6482 case OEM_CHARSET:
6483 charset_type = Qw32_charset_oem;
6484 break;
6485
6486 /* More recent versions of Windows (95 and NT4.0) define more
6487 character sets. */
6488#ifdef EASTEUROPE_CHARSET
6489 case EASTEUROPE_CHARSET:
6490 charset_type = Qw32_charset_easteurope;
6491 break;
6492 case TURKISH_CHARSET:
6493 charset_type = Qw32_charset_turkish;
6494 break;
6495 case BALTIC_CHARSET:
6496 charset_type = Qw32_charset_baltic;
6497 break;
6498 case RUSSIAN_CHARSET:
6499 charset_type = Qw32_charset_russian;
6500 break;
6501 case ARABIC_CHARSET:
6502 charset_type = Qw32_charset_arabic;
6503 break;
6504 case GREEK_CHARSET:
6505 charset_type = Qw32_charset_greek;
6506 break;
6507 case HEBREW_CHARSET:
6508 charset_type = Qw32_charset_hebrew;
6509 break;
6510 case VIETNAMESE_CHARSET:
6511 charset_type = Qw32_charset_vietnamese;
6512 break;
6513 case THAI_CHARSET:
6514 charset_type = Qw32_charset_thai;
6515 break;
6516 case MAC_CHARSET:
6517 charset_type = Qw32_charset_mac;
6518 break;
6519 case JOHAB_CHARSET:
6520 charset_type = Qw32_charset_johab;
6521 break;
6522#endif
6523
6524#ifdef UNICODE_CHARSET
6525 case UNICODE_CHARSET:
6526 charset_type = Qw32_charset_unicode;
6527 break;
6528#endif
6529 default:
6530 /* Encode numerical value of unknown charset. */
6531 sprintf (buf, "*-#%u", fncharset);
6532 return Fcons (build_string (buf), Qnil);
6533 }
6534
6535 {
6536 Lisp_Object rest;
6537 /* Look through w32-charset-info-alist for the character set.
6538 Only return charsets for codepages which are installed.
6539
6540 Format of each entry in Vw32_charset_info_alist is
6541 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6542 */
6543 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6544 {
6545 Lisp_Object x_charset;
6546 Lisp_Object w32_charset;
6547 Lisp_Object codepage;
6548
6549 Lisp_Object this_entry = XCAR (rest);
6550
6551 /* Skip invalid entries in alist. */
6552 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6553 || !CONSP (XCDR (this_entry))
6554 || !SYMBOLP (XCAR (XCDR (this_entry))))
6555 continue;
6556
6557 x_charset = XCAR (this_entry);
6558 w32_charset = XCAR (XCDR (this_entry));
6559 codepage = XCDR (XCDR (this_entry));
6560
6561 /* Look for Same charset and a valid codepage (or non-int
6562 which means ignore). */
6563 if (w32_charset == charset_type
6564 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6565 || IsValidCodePage (XINT (codepage))))
6566 {
6567 retval = Fcons (x_charset, retval);
6568 }
6569 }
6570
6571 /* If no match, encode the numeric value. */
6572 if (NILP (retval))
6573 {
6574 sprintf (buf, "*-#%u", fncharset);
6575 return Fcons (build_string (buf), Qnil);
6576 }
6577
6578 return retval;
6579 }
6580}
6581
dfff8a69
JR
6582/* Get the Windows codepage corresponding to the specified font. The
6583 charset info in the font name is used to look up
6584 w32-charset-to-codepage-alist. */
6585int
6586w32_codepage_for_font (char *fontname)
6587{
767b1ff0
JR
6588 Lisp_Object codepage, entry;
6589 char *charset_str, *charset, *end;
dfff8a69 6590
767b1ff0 6591 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6592 return CP_DEFAULT;
6593
767b1ff0
JR
6594 /* Extract charset part of font string. */
6595 charset = xlfd_charset_of_font (fontname);
6596
6597 if (!charset)
ceb12877 6598 return CP_UNKNOWN;
767b1ff0 6599
8b77111c 6600 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6601 strcpy (charset_str, charset);
6602
8b77111c 6603#if 0
dfff8a69
JR
6604 /* Remove leading "*-". */
6605 if (strncmp ("*-", charset_str, 2) == 0)
6606 charset = charset_str + 2;
6607 else
8b77111c 6608#endif
dfff8a69
JR
6609 charset = charset_str;
6610
6611 /* Stop match at wildcard (including preceding '-'). */
6612 if (end = strchr (charset, '*'))
6613 {
6614 if (end > charset && *(end-1) == '-')
6615 end--;
6616 *end = '\0';
6617 }
6618
767b1ff0
JR
6619 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6620 if (NILP (entry))
ceb12877 6621 return CP_UNKNOWN;
767b1ff0
JR
6622
6623 codepage = Fcdr (Fcdr (entry));
6624
6625 if (NILP (codepage))
6626 return CP_8BIT;
6627 else if (XFASTINT (codepage) == XFASTINT (Qt))
6628 return CP_UNICODE;
6629 else if (INTEGERP (codepage))
dfff8a69
JR
6630 return XINT (codepage);
6631 else
ceb12877 6632 return CP_UNKNOWN;
dfff8a69
JR
6633}
6634
6635
8edb0a6f 6636static BOOL
767b1ff0 6637w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6638 LOGFONT * lplogfont;
6639 char * lpxstr;
6640 int len;
767b1ff0 6641 char * specific_charset;
ee78dc32 6642{
6fc2811b 6643 char* fonttype;
f46e6225 6644 char *fontname;
3cb20f4a
RS
6645 char height_pixels[8];
6646 char height_dpi[8];
6647 char width_pixels[8];
4587b026 6648 char *fontname_dash;
ac849ba4
JR
6649 int display_resy = (int) one_w32_display_info.resy;
6650 int display_resx = (int) one_w32_display_info.resx;
f46e6225
GV
6651 int bufsz;
6652 struct coding_system coding;
3cb20f4a
RS
6653
6654 if (!lpxstr) abort ();
ee78dc32 6655
3cb20f4a
RS
6656 if (!lplogfont)
6657 return FALSE;
6658
6fc2811b
JR
6659 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6660 fonttype = "raster";
6661 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6662 fonttype = "outline";
6663 else
6664 fonttype = "unknown";
6665
1fa3a200 6666 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6667 &coding);
aab5ac44
KH
6668 coding.src_multibyte = 0;
6669 coding.dst_multibyte = 1;
f46e6225
GV
6670 coding.mode |= CODING_MODE_LAST_BLOCK;
6671 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6672
6673 fontname = alloca(sizeof(*fontname) * bufsz);
6674 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6675 strlen(lplogfont->lfFaceName), bufsz - 1);
6676 *(fontname + coding.produced) = '\0';
4587b026
GV
6677
6678 /* Replace dashes with underscores so the dashes are not
f46e6225 6679 misinterpreted. */
4587b026
GV
6680 fontname_dash = fontname;
6681 while (fontname_dash = strchr (fontname_dash, '-'))
6682 *fontname_dash = '_';
6683
3cb20f4a 6684 if (lplogfont->lfHeight)
ee78dc32 6685 {
3cb20f4a
RS
6686 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6687 sprintf (height_dpi, "%u",
33d52f9c 6688 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6689 }
6690 else
ee78dc32 6691 {
3cb20f4a
RS
6692 strcpy (height_pixels, "*");
6693 strcpy (height_dpi, "*");
ee78dc32 6694 }
3cb20f4a
RS
6695 if (lplogfont->lfWidth)
6696 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6697 else
6698 strcpy (width_pixels, "*");
6699
6700 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6701 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6702 fonttype, /* foundry */
4587b026
GV
6703 fontname, /* family */
6704 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6705 lplogfont->lfItalic?'i':'r', /* slant */
6706 /* setwidth name */
6707 /* add style name */
6708 height_pixels, /* pixel size */
6709 height_dpi, /* point size */
33d52f9c
GV
6710 display_resx, /* resx */
6711 display_resy, /* resy */
4587b026
GV
6712 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6713 ? 'p' : 'c', /* spacing */
6714 width_pixels, /* avg width */
767b1ff0
JR
6715 specific_charset ? specific_charset
6716 : w32_to_x_charset (lplogfont->lfCharSet)
6717 /* charset registry and encoding */
3cb20f4a
RS
6718 );
6719
ee78dc32
GV
6720 lpxstr[len - 1] = 0; /* just to be sure */
6721 return (TRUE);
6722}
6723
8edb0a6f 6724static BOOL
fbd6baed 6725x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6726 char * lpxstr;
6727 LOGFONT * lplogfont;
6728{
f46e6225
GV
6729 struct coding_system coding;
6730
ee78dc32 6731 if (!lplogfont) return (FALSE);
f46e6225 6732
ee78dc32 6733 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6734
1a292d24 6735 /* Set default value for each field. */
771c47d5 6736#if 1
ee78dc32
GV
6737 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6738 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6739 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6740#else
6741 /* go for maximum quality */
6742 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6743 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6744 lplogfont->lfQuality = PROOF_QUALITY;
6745#endif
6746
1a292d24
AI
6747 lplogfont->lfCharSet = DEFAULT_CHARSET;
6748 lplogfont->lfWeight = FW_DONTCARE;
6749 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6750
5ac45f98
GV
6751 if (!lpxstr)
6752 return FALSE;
6753
6754 /* Provide a simple escape mechanism for specifying Windows font names
6755 * directly -- if font spec does not beginning with '-', assume this
6756 * format:
6757 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6758 */
ee78dc32 6759
5ac45f98
GV
6760 if (*lpxstr == '-')
6761 {
33d52f9c
GV
6762 int fields, tem;
6763 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6764 width[10], resy[10], remainder[50];
5ac45f98 6765 char * encoding;
ac849ba4 6766 int dpi = (int) one_w32_display_info.resy;
5ac45f98
GV
6767
6768 fields = sscanf (lpxstr,
8b77111c 6769 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6770 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6771 if (fields == EOF)
6772 return (FALSE);
6773
6774 /* In the general case when wildcards cover more than one field,
6775 we don't know which field is which, so don't fill any in.
6776 However, we need to cope with this particular form, which is
6777 generated by font_list_1 (invoked by try_font_list):
6778 "-raster-6x10-*-gb2312*-*"
6779 and make sure to correctly parse the charset field. */
6780 if (fields == 3)
6781 {
6782 fields = sscanf (lpxstr,
6783 "-%*[^-]-%49[^-]-*-%49s",
6784 name, remainder);
6785 }
6786 else if (fields < 9)
6787 {
6788 fields = 0;
6789 remainder[0] = 0;
6790 }
6fc2811b 6791
5ac45f98
GV
6792 if (fields > 0 && name[0] != '*')
6793 {
8ea3e054
RS
6794 int bufsize;
6795 unsigned char *buf;
6796
f46e6225 6797 setup_coding_system
1fa3a200 6798 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6799 coding.src_multibyte = 1;
6800 coding.dst_multibyte = 1;
8ea3e054
RS
6801 bufsize = encoding_buffer_size (&coding, strlen (name));
6802 buf = (unsigned char *) alloca (bufsize);
f46e6225 6803 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6804 encode_coding (&coding, name, buf, strlen (name), bufsize);
6805 if (coding.produced >= LF_FACESIZE)
6806 coding.produced = LF_FACESIZE - 1;
6807 buf[coding.produced] = 0;
6808 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6809 }
6810 else
6811 {
6fc2811b 6812 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6813 }
6814
6815 fields--;
6816
fbd6baed 6817 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6818
6819 fields--;
6820
c8874f14 6821 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6822
6823 fields--;
6824
6825 if (fields > 0 && pixels[0] != '*')
6826 lplogfont->lfHeight = atoi (pixels);
6827
6828 fields--;
5ac45f98 6829 fields--;
33d52f9c
GV
6830 if (fields > 0 && resy[0] != '*')
6831 {
6fc2811b 6832 tem = atoi (resy);
33d52f9c
GV
6833 if (tem > 0) dpi = tem;
6834 }
5ac45f98 6835
33d52f9c
GV
6836 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6837 lplogfont->lfHeight = atoi (height) * dpi / 720;
6838
6839 if (fields > 0)
5ac45f98
GV
6840 lplogfont->lfPitchAndFamily =
6841 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6842
6843 fields--;
6844
6845 if (fields > 0 && width[0] != '*')
6846 lplogfont->lfWidth = atoi (width) / 10;
6847
6848 fields--;
6849
4587b026 6850 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6851 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6852 {
5ac45f98
GV
6853 int len = strlen (remainder);
6854 if (len > 0 && remainder[len-1] == '-')
6855 remainder[len-1] = 0;
ee78dc32 6856 }
5ac45f98 6857 encoding = remainder;
8b77111c 6858#if 0
5ac45f98
GV
6859 if (strncmp (encoding, "*-", 2) == 0)
6860 encoding += 2;
8b77111c
AI
6861#endif
6862 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6863 }
6864 else
6865 {
6866 int fields;
6867 char name[100], height[10], width[10], weight[20];
a1a80b40 6868
5ac45f98
GV
6869 fields = sscanf (lpxstr,
6870 "%99[^:]:%9[^:]:%9[^:]:%19s",
6871 name, height, width, weight);
6872
6873 if (fields == EOF) return (FALSE);
6874
6875 if (fields > 0)
6876 {
6877 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6878 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6879 }
6880 else
6881 {
6882 lplogfont->lfFaceName[0] = 0;
6883 }
6884
6885 fields--;
6886
6887 if (fields > 0)
6888 lplogfont->lfHeight = atoi (height);
6889
6890 fields--;
6891
6892 if (fields > 0)
6893 lplogfont->lfWidth = atoi (width);
6894
6895 fields--;
6896
fbd6baed 6897 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6898 }
6899
6900 /* This makes TrueType fonts work better. */
6901 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6902
ee78dc32
GV
6903 return (TRUE);
6904}
6905
d88c567c
JR
6906/* Strip the pixel height and point height from the given xlfd, and
6907 return the pixel height. If no pixel height is specified, calculate
6908 one from the point height, or if that isn't defined either, return
6909 0 (which usually signifies a scalable font).
6910*/
8edb0a6f
JR
6911static int
6912xlfd_strip_height (char *fontname)
d88c567c 6913{
8edb0a6f 6914 int pixel_height, field_number;
d88c567c
JR
6915 char *read_from, *write_to;
6916
6917 xassert (fontname);
6918
6919 pixel_height = field_number = 0;
6920 write_to = NULL;
6921
6922 /* Look for height fields. */
6923 for (read_from = fontname; *read_from; read_from++)
6924 {
6925 if (*read_from == '-')
6926 {
6927 field_number++;
6928 if (field_number == 7) /* Pixel height. */
6929 {
6930 read_from++;
6931 write_to = read_from;
6932
6933 /* Find end of field. */
6934 for (;*read_from && *read_from != '-'; read_from++)
6935 ;
6936
6937 /* Split the fontname at end of field. */
6938 if (*read_from)
6939 {
6940 *read_from = '\0';
6941 read_from++;
6942 }
6943 pixel_height = atoi (write_to);
6944 /* Blank out field. */
6945 if (read_from > write_to)
6946 {
6947 *write_to = '-';
6948 write_to++;
6949 }
767b1ff0 6950 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6951 return now. */
6952 else
6953 return pixel_height;
6954
6955 /* If we got a pixel height, the point height can be
6956 ignored. Just blank it out and break now. */
6957 if (pixel_height)
6958 {
6959 /* Find end of point size field. */
6960 for (; *read_from && *read_from != '-'; read_from++)
6961 ;
6962
6963 if (*read_from)
6964 read_from++;
6965
6966 /* Blank out the point size field. */
6967 if (read_from > write_to)
6968 {
6969 *write_to = '-';
6970 write_to++;
6971 }
6972 else
6973 return pixel_height;
6974
6975 break;
6976 }
6977 /* If the point height is already blank, break now. */
6978 if (*read_from == '-')
6979 {
6980 read_from++;
6981 break;
6982 }
6983 }
6984 else if (field_number == 8)
6985 {
6986 /* If we didn't get a pixel height, try to get the point
6987 height and convert that. */
6988 int point_size;
6989 char *point_size_start = read_from++;
6990
6991 /* Find end of field. */
6992 for (; *read_from && *read_from != '-'; read_from++)
6993 ;
6994
6995 if (*read_from)
6996 {
6997 *read_from = '\0';
6998 read_from++;
6999 }
7000
7001 point_size = atoi (point_size_start);
7002
7003 /* Convert to pixel height. */
7004 pixel_height = point_size
7005 * one_w32_display_info.height_in / 720;
7006
7007 /* Blank out this field and break. */
7008 *write_to = '-';
7009 write_to++;
7010 break;
7011 }
7012 }
7013 }
7014
7015 /* Shift the rest of the font spec into place. */
7016 if (write_to && read_from > write_to)
7017 {
7018 for (; *read_from; read_from++, write_to++)
7019 *write_to = *read_from;
7020 *write_to = '\0';
7021 }
7022
7023 return pixel_height;
7024}
7025
6fc2811b 7026/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 7027static BOOL
6fc2811b
JR
7028w32_font_match (fontname, pattern)
7029 char * fontname;
7030 char * pattern;
ee78dc32 7031{
e7c72122 7032 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 7033 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 7034 char *ptr;
ee78dc32 7035
d88c567c
JR
7036 /* Copy fontname so we can modify it during comparison. */
7037 strcpy (font_name_copy, fontname);
7038
6fc2811b
JR
7039 ptr = regex;
7040 *ptr++ = '^';
ee78dc32 7041
6fc2811b
JR
7042 /* Turn pattern into a regexp and do a regexp match. */
7043 for (; *pattern; pattern++)
7044 {
7045 if (*pattern == '?')
7046 *ptr++ = '.';
7047 else if (*pattern == '*')
7048 {
7049 *ptr++ = '.';
7050 *ptr++ = '*';
7051 }
33d52f9c 7052 else
6fc2811b 7053 *ptr++ = *pattern;
ee78dc32 7054 }
6fc2811b
JR
7055 *ptr = '$';
7056 *(ptr + 1) = '\0';
7057
d88c567c
JR
7058 /* Strip out font heights and compare them seperately, since
7059 rounding error can cause mismatches. This also allows a
7060 comparison between a font that declares only a pixel height and a
7061 pattern that declares the point height.
7062 */
7063 {
7064 int font_height, pattern_height;
7065
7066 font_height = xlfd_strip_height (font_name_copy);
7067 pattern_height = xlfd_strip_height (regex);
7068
7069 /* Compare now, and don't bother doing expensive regexp matching
7070 if the heights differ. */
7071 if (font_height && pattern_height && (font_height != pattern_height))
7072 return FALSE;
7073 }
7074
6fc2811b 7075 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 7076 font_name_copy) >= 0);
ee78dc32
GV
7077}
7078
5ca0cd71
GV
7079/* Callback functions, and a structure holding info they need, for
7080 listing system fonts on W32. We need one set of functions to do the
7081 job properly, but these don't work on NT 3.51 and earlier, so we
7082 have a second set which don't handle character sets properly to
7083 fall back on.
7084
7085 In both cases, there are two passes made. The first pass gets one
7086 font from each family, the second pass lists all the fonts from
7087 each family. */
7088
ee78dc32
GV
7089typedef struct enumfont_t
7090{
7091 HDC hdc;
7092 int numFonts;
3cb20f4a 7093 LOGFONT logfont;
ee78dc32
GV
7094 XFontStruct *size_ref;
7095 Lisp_Object *pattern;
d84b082d 7096 Lisp_Object list;
ee78dc32
GV
7097 Lisp_Object *tail;
7098} enumfont_t;
7099
d84b082d
JR
7100
7101static void
7102enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7103
7104
8edb0a6f 7105static int CALLBACK
ee78dc32
GV
7106enum_font_cb2 (lplf, lptm, FontType, lpef)
7107 ENUMLOGFONT * lplf;
7108 NEWTEXTMETRIC * lptm;
7109 int FontType;
7110 enumfont_t * lpef;
7111{
66895301
JR
7112 /* Ignore struck out and underlined versions of fonts. */
7113 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7114 return 1;
7115
7116 /* Only return fonts with names starting with @ if they were
7117 explicitly specified, since Microsoft uses an initial @ to
7118 denote fonts for vertical writing, without providing a more
7119 convenient way of identifying them. */
7120 if (lplf->elfLogFont.lfFaceName[0] == '@'
7121 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
7122 return 1;
7123
4587b026
GV
7124 /* Check that the character set matches if it was specified */
7125 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7126 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 7127 return 1;
4587b026 7128
ee78dc32
GV
7129 {
7130 char buf[100];
4587b026 7131 Lisp_Object width = Qnil;
d84b082d 7132 Lisp_Object charset_list = Qnil;
767b1ff0 7133 char *charset = NULL;
ee78dc32 7134
6fc2811b
JR
7135 /* Truetype fonts do not report their true metrics until loaded */
7136 if (FontType != RASTER_FONTTYPE)
3cb20f4a 7137 {
6fc2811b
JR
7138 if (!NILP (*(lpef->pattern)))
7139 {
7140 /* Scalable fonts are as big as you want them to be. */
7141 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7142 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7143 width = make_number (lpef->logfont.lfWidth);
7144 }
7145 else
7146 {
7147 lplf->elfLogFont.lfHeight = 0;
7148 lplf->elfLogFont.lfWidth = 0;
7149 }
3cb20f4a 7150 }
6fc2811b 7151
f46e6225
GV
7152 /* Make sure the height used here is the same as everywhere
7153 else (ie character height, not cell height). */
6fc2811b
JR
7154 if (lplf->elfLogFont.lfHeight > 0)
7155 {
7156 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7157 if (FontType == RASTER_FONTTYPE)
7158 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7159 else
7160 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7161 }
4587b026 7162
767b1ff0
JR
7163 if (!NILP (*(lpef->pattern)))
7164 {
7165 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
7166
644cefdf
JR
7167 /* We already checked charsets above, but DEFAULT_CHARSET
7168 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7169 if (charset
7170 && strncmp (charset, "*-*", 3) != 0
7171 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7172 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7173 return 1;
767b1ff0
JR
7174 }
7175
d84b082d
JR
7176 if (charset)
7177 charset_list = Fcons (build_string (charset), Qnil);
7178 else
7179 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 7180
d84b082d
JR
7181 /* Loop through the charsets. */
7182 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 7183 {
d84b082d
JR
7184 Lisp_Object this_charset = Fcar (charset_list);
7185 charset = XSTRING (this_charset)->data;
7186
7187 /* List bold and italic variations if w32-enable-synthesized-fonts
7188 is non-nil and this is a plain font. */
7189 if (w32_enable_synthesized_fonts
7190 && lplf->elfLogFont.lfWeight == FW_NORMAL
7191 && lplf->elfLogFont.lfItalic == FALSE)
7192 {
7193 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7194 charset, width);
7195 /* bold. */
7196 lplf->elfLogFont.lfWeight = FW_BOLD;
7197 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7198 charset, width);
7199 /* bold italic. */
7200 lplf->elfLogFont.lfItalic = TRUE;
7201 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7202 charset, width);
7203 /* italic. */
7204 lplf->elfLogFont.lfWeight = FW_NORMAL;
7205 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7206 charset, width);
7207 }
7208 else
7209 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7210 charset, width);
ee78dc32
GV
7211 }
7212 }
6fc2811b 7213
5e905a57 7214 return 1;
ee78dc32
GV
7215}
7216
d84b082d
JR
7217static void
7218enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7219 enumfont_t * lpef;
7220 LOGFONT * logfont;
7221 char * match_charset;
7222 Lisp_Object width;
7223{
7224 char buf[100];
7225
7226 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7227 return;
7228
7229 if (NILP (*(lpef->pattern))
7230 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
7231 {
7232 /* Check if we already listed this font. This may happen if
7233 w32_enable_synthesized_fonts is non-nil, and there are real
7234 bold and italic versions of the font. */
7235 Lisp_Object font_name = build_string (buf);
7236 if (NILP (Fmember (font_name, lpef->list)))
7237 {
7238 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
7239 lpef->tail = &(XCDR (*lpef->tail));
7240 lpef->numFonts++;
7241 }
7242 }
7243}
7244
7245
8edb0a6f 7246static int CALLBACK
ee78dc32
GV
7247enum_font_cb1 (lplf, lptm, FontType, lpef)
7248 ENUMLOGFONT * lplf;
7249 NEWTEXTMETRIC * lptm;
7250 int FontType;
7251 enumfont_t * lpef;
7252{
7253 return EnumFontFamilies (lpef->hdc,
7254 lplf->elfLogFont.lfFaceName,
7255 (FONTENUMPROC) enum_font_cb2,
7256 (LPARAM) lpef);
7257}
7258
7259
8edb0a6f 7260static int CALLBACK
5ca0cd71
GV
7261enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7262 ENUMLOGFONTEX * lplf;
7263 NEWTEXTMETRICEX * lptm;
7264 int font_type;
7265 enumfont_t * lpef;
7266{
7267 /* We are not interested in the extra info we get back from the 'Ex
7268 version - only the fact that we get character set variations
7269 enumerated seperately. */
7270 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7271 font_type, lpef);
7272}
7273
8edb0a6f 7274static int CALLBACK
5ca0cd71
GV
7275enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7276 ENUMLOGFONTEX * lplf;
7277 NEWTEXTMETRICEX * lptm;
7278 int font_type;
7279 enumfont_t * lpef;
7280{
7281 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7282 FARPROC enum_font_families_ex
7283 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7284 /* We don't really expect EnumFontFamiliesEx to disappear once we
7285 get here, so don't bother handling it gracefully. */
7286 if (enum_font_families_ex == NULL)
7287 error ("gdi32.dll has disappeared!");
7288 return enum_font_families_ex (lpef->hdc,
7289 &lplf->elfLogFont,
7290 (FONTENUMPROC) enum_fontex_cb2,
7291 (LPARAM) lpef, 0);
7292}
7293
4587b026
GV
7294/* Interface to fontset handler. (adapted from mw32font.c in Meadow
7295 and xterm.c in Emacs 20.3) */
7296
8edb0a6f 7297static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
7298{
7299 char *fontname, *ptnstr;
7300 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 7301 int n_fonts = 0;
33d52f9c
GV
7302
7303 list = Vw32_bdf_filename_alist;
7304 ptnstr = XSTRING (pattern)->data;
7305
8e713be6 7306 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 7307 {
8e713be6 7308 tem = XCAR (list);
33d52f9c 7309 if (CONSP (tem))
8e713be6 7310 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
7311 else if (STRINGP (tem))
7312 fontname = XSTRING (tem)->data;
7313 else
7314 continue;
7315
7316 if (w32_font_match (fontname, ptnstr))
5ca0cd71 7317 {
8e713be6 7318 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7319 n_fonts++;
7320 if (n_fonts >= max_names)
7321 break;
7322 }
33d52f9c
GV
7323 }
7324
7325 return newlist;
7326}
7327
5ca0cd71 7328
4587b026
GV
7329/* Return a list of names of available fonts matching PATTERN on frame
7330 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7331 to be listed. Frame F NULL means we have not yet created any
7332 frame, which means we can't get proper size info, as we don't have
7333 a device context to use for GetTextMetrics.
7334 MAXNAMES sets a limit on how many fonts to match. */
7335
7336Lisp_Object
dc220243
JR
7337w32_list_fonts (f, pattern, size, maxnames)
7338 struct frame *f;
7339 Lisp_Object pattern;
7340 int size;
7341 int maxnames;
4587b026 7342{
6fc2811b 7343 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 7344 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 7345 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 7346 int n_fonts = 0;
396594fe 7347
4587b026
GV
7348 patterns = Fassoc (pattern, Valternate_fontname_alist);
7349 if (NILP (patterns))
7350 patterns = Fcons (pattern, Qnil);
7351
8e713be6 7352 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
7353 {
7354 enumfont_t ef;
767b1ff0 7355 int codepage;
4587b026 7356
8e713be6 7357 tpat = XCAR (patterns);
4587b026 7358
767b1ff0
JR
7359 if (!STRINGP (tpat))
7360 continue;
7361
7362 /* Avoid expensive EnumFontFamilies functions if we are not
7363 going to be able to output one of these anyway. */
7364 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7365 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7366 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7367 && !IsValidCodePage(codepage))
767b1ff0
JR
7368 continue;
7369
4587b026
GV
7370 /* See if we cached the result for this particular query.
7371 The cache is an alist of the form:
7372 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7373 */
8e713be6 7374 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7375 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7376 {
7377 list = Fcdr_safe (list);
7378 /* We have a cached list. Don't have to get the list again. */
7379 goto label_cached;
7380 }
7381
7382 BLOCK_INPUT;
7383 /* At first, put PATTERN in the cache. */
7384 list = Qnil;
33d52f9c 7385 ef.pattern = &tpat;
d84b082d 7386 ef.list = list;
33d52f9c 7387 ef.tail = &list;
4587b026 7388 ef.numFonts = 0;
33d52f9c 7389
5ca0cd71
GV
7390 /* Use EnumFontFamiliesEx where it is available, as it knows
7391 about character sets. Fall back to EnumFontFamilies for
7392 older versions of NT that don't support the 'Ex function. */
767b1ff0 7393 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7394 {
5ca0cd71
GV
7395 LOGFONT font_match_pattern;
7396 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7397 FARPROC enum_font_families_ex
7398 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7399
7400 /* We do our own pattern matching so we can handle wildcards. */
7401 font_match_pattern.lfFaceName[0] = 0;
7402 font_match_pattern.lfPitchAndFamily = 0;
7403 /* We can use the charset, because if it is a wildcard it will
7404 be DEFAULT_CHARSET anyway. */
7405 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7406
33d52f9c 7407 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7408
5ca0cd71
GV
7409 if (enum_font_families_ex)
7410 enum_font_families_ex (ef.hdc,
7411 &font_match_pattern,
7412 (FONTENUMPROC) enum_fontex_cb1,
7413 (LPARAM) &ef, 0);
7414 else
7415 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7416 (LPARAM)&ef);
4587b026 7417
33d52f9c 7418 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7419 }
7420
7421 UNBLOCK_INPUT;
7422
7423 /* Make a list of the fonts we got back.
7424 Store that in the font cache for the display. */
f3fbd155
KR
7425 XSETCDR (dpyinfo->name_list_element,
7426 Fcons (Fcons (tpat, list),
7427 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7428
7429 label_cached:
7430 if (NILP (list)) continue; /* Try the remaining alternatives. */
7431
7432 newlist = second_best = Qnil;
7433
7434 /* Make a list of the fonts that have the right width. */
8e713be6 7435 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7436 {
7437 int found_size;
8e713be6 7438 tem = XCAR (list);
4587b026
GV
7439
7440 if (!CONSP (tem))
7441 continue;
8e713be6 7442 if (NILP (XCAR (tem)))
4587b026
GV
7443 continue;
7444 if (!size)
7445 {
8e713be6 7446 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7447 n_fonts++;
7448 if (n_fonts >= maxnames)
7449 break;
7450 else
7451 continue;
4587b026 7452 }
8e713be6 7453 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7454 {
7455 /* Since we don't yet know the size of the font, we must
7456 load it and try GetTextMetrics. */
4587b026
GV
7457 W32FontStruct thisinfo;
7458 LOGFONT lf;
7459 HDC hdc;
7460 HANDLE oldobj;
7461
8e713be6 7462 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7463 continue;
7464
7465 BLOCK_INPUT;
33d52f9c 7466 thisinfo.bdf = NULL;
4587b026
GV
7467 thisinfo.hfont = CreateFontIndirect (&lf);
7468 if (thisinfo.hfont == NULL)
7469 continue;
7470
7471 hdc = GetDC (dpyinfo->root_window);
7472 oldobj = SelectObject (hdc, thisinfo.hfont);
7473 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7474 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7475 else
f3fbd155 7476 XSETCDR (tem, make_number (0));
4587b026
GV
7477 SelectObject (hdc, oldobj);
7478 ReleaseDC (dpyinfo->root_window, hdc);
7479 DeleteObject(thisinfo.hfont);
7480 UNBLOCK_INPUT;
7481 }
8e713be6 7482 found_size = XINT (XCDR (tem));
4587b026 7483 if (found_size == size)
5ca0cd71 7484 {
8e713be6 7485 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7486 n_fonts++;
7487 if (n_fonts >= maxnames)
7488 break;
7489 }
4587b026
GV
7490 /* keep track of the closest matching size in case
7491 no exact match is found. */
7492 else if (found_size > 0)
7493 {
7494 if (NILP (second_best))
7495 second_best = tem;
5ca0cd71 7496
4587b026
GV
7497 else if (found_size < size)
7498 {
8e713be6
KR
7499 if (XINT (XCDR (second_best)) > size
7500 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7501 second_best = tem;
7502 }
7503 else
7504 {
8e713be6
KR
7505 if (XINT (XCDR (second_best)) > size
7506 && XINT (XCDR (second_best)) >
4587b026
GV
7507 found_size)
7508 second_best = tem;
7509 }
7510 }
7511 }
7512
7513 if (!NILP (newlist))
7514 break;
7515 else if (!NILP (second_best))
7516 {
8e713be6 7517 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7518 break;
7519 }
7520 }
7521
33d52f9c 7522 /* Include any bdf fonts. */
5ca0cd71 7523 if (n_fonts < maxnames)
33d52f9c
GV
7524 {
7525 Lisp_Object combined[2];
5ca0cd71 7526 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7527 combined[1] = newlist;
7528 newlist = Fnconc(2, combined);
7529 }
7530
4587b026
GV
7531 return newlist;
7532}
7533
5ca0cd71 7534
4587b026
GV
7535/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7536struct font_info *
7537w32_get_font_info (f, font_idx)
7538 FRAME_PTR f;
7539 int font_idx;
7540{
7541 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7542}
7543
7544
7545struct font_info*
7546w32_query_font (struct frame *f, char *fontname)
7547{
7548 int i;
7549 struct font_info *pfi;
7550
7551 pfi = FRAME_W32_FONT_TABLE (f);
7552
7553 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7554 {
7555 if (strcmp(pfi->name, fontname) == 0) return pfi;
7556 }
7557
7558 return NULL;
7559}
7560
7561/* Find a CCL program for a font specified by FONTP, and set the member
7562 `encoder' of the structure. */
7563
7564void
7565w32_find_ccl_program (fontp)
7566 struct font_info *fontp;
7567{
3545439c 7568 Lisp_Object list, elt;
4587b026 7569
8e713be6 7570 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7571 {
8e713be6 7572 elt = XCAR (list);
4587b026 7573 if (CONSP (elt)
8e713be6
KR
7574 && STRINGP (XCAR (elt))
7575 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7576 >= 0))
3545439c
KH
7577 break;
7578 }
7579 if (! NILP (list))
7580 {
17eedd00
KH
7581 struct ccl_program *ccl
7582 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7583
8e713be6 7584 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7585 xfree (ccl);
7586 else
7587 fontp->font_encoder = ccl;
4587b026
GV
7588 }
7589}
7590
7591\f
8edb0a6f
JR
7592/* Find BDF files in a specified directory. (use GCPRO when calling,
7593 as this calls lisp to get a directory listing). */
7594static Lisp_Object
7595w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7596{
7597 Lisp_Object filelist, list = Qnil;
7598 char fontname[100];
7599
7600 if (!STRINGP(directory))
7601 return Qnil;
7602
7603 filelist = Fdirectory_files (directory, Qt,
7604 build_string (".*\\.[bB][dD][fF]"), Qt);
7605
7606 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7607 {
7608 Lisp_Object filename = XCAR (filelist);
7609 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7610 store_in_alist (&list, build_string (fontname), filename);
7611 }
7612 return list;
7613}
7614
6fc2811b
JR
7615DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7616 1, 1, 0,
b3700ae7
JR
7617 doc: /* Return a list of BDF fonts in DIR.
7618The list is suitable for appending to w32-bdf-filename-alist. Fonts
7619which do not contain an xlfd description will not be included in the
7620list. DIR may be a list of directories. */)
6fc2811b
JR
7621 (directory)
7622 Lisp_Object directory;
7623{
7624 Lisp_Object list = Qnil;
7625 struct gcpro gcpro1, gcpro2;
ee78dc32 7626
6fc2811b
JR
7627 if (!CONSP (directory))
7628 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7629
6fc2811b 7630 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7631 {
6fc2811b
JR
7632 Lisp_Object pair[2];
7633 pair[0] = list;
7634 pair[1] = Qnil;
7635 GCPRO2 (directory, list);
7636 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7637 list = Fnconc( 2, pair );
7638 UNGCPRO;
7639 }
7640 return list;
7641}
ee78dc32 7642
6fc2811b
JR
7643\f
7644DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7645 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7646 (color, frame)
7647 Lisp_Object color, frame;
7648{
7649 XColor foo;
7650 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7651
b7826503 7652 CHECK_STRING (color);
ee78dc32 7653
6fc2811b
JR
7654 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7655 return Qt;
7656 else
7657 return Qnil;
7658}
ee78dc32 7659
2d764c78 7660DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7661 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7662 (color, frame)
7663 Lisp_Object color, frame;
7664{
6fc2811b 7665 XColor foo;
ee78dc32
GV
7666 FRAME_PTR f = check_x_frame (frame);
7667
b7826503 7668 CHECK_STRING (color);
ee78dc32 7669
6fc2811b 7670 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7671 {
7672 Lisp_Object rgb[3];
7673
6fc2811b
JR
7674 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7675 | GetRValue (foo.pixel));
7676 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7677 | GetGValue (foo.pixel));
7678 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7679 | GetBValue (foo.pixel));
ee78dc32
GV
7680 return Flist (3, rgb);
7681 }
7682 else
7683 return Qnil;
7684}
7685
2d764c78 7686DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7687 doc: /* Internal function called by `display-color-p', which see. */)
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 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7694 return Qnil;
7695
7696 return Qt;
7697}
7698
74e1aeec
JR
7699DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7700 Sx_display_grayscale_p, 0, 1, 0,
7701 doc: /* Return t if the X display supports shades of gray.
7702Note that color displays do support shades of gray.
7703The optional argument DISPLAY specifies which display to ask about.
7704DISPLAY should be either a frame or a display name (a string).
7705If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7706 (display)
7707 Lisp_Object display;
7708{
fbd6baed 7709 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7710
7711 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7712 return Qnil;
7713
7714 return Qt;
7715}
7716
74e1aeec
JR
7717DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7718 Sx_display_pixel_width, 0, 1, 0,
7719 doc: /* Returns the width in pixels of DISPLAY.
7720The optional argument DISPLAY specifies which display to ask about.
7721DISPLAY should be either a frame or a display name (a string).
7722If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7723 (display)
7724 Lisp_Object display;
7725{
fbd6baed 7726 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7727
7728 return make_number (dpyinfo->width);
7729}
7730
7731DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7732 Sx_display_pixel_height, 0, 1, 0,
7733 doc: /* Returns the height in pixels of DISPLAY.
7734The optional argument DISPLAY specifies which display to ask about.
7735DISPLAY should be either a frame or a display name (a string).
7736If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7737 (display)
7738 Lisp_Object display;
7739{
fbd6baed 7740 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7741
7742 return make_number (dpyinfo->height);
7743}
7744
7745DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7746 0, 1, 0,
7747 doc: /* Returns the number of bitplanes of DISPLAY.
7748The optional argument DISPLAY specifies which display to ask about.
7749DISPLAY should be either a frame or a display name (a string).
7750If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7751 (display)
7752 Lisp_Object display;
7753{
fbd6baed 7754 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7755
7756 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7757}
7758
7759DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7760 0, 1, 0,
7761 doc: /* Returns the number of color cells of DISPLAY.
7762The optional argument DISPLAY specifies which display to ask about.
7763DISPLAY should be either a frame or a display name (a string).
7764If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7765 (display)
7766 Lisp_Object display;
7767{
fbd6baed 7768 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7769 HDC hdc;
7770 int cap;
7771
5ac45f98
GV
7772 hdc = GetDC (dpyinfo->root_window);
7773 if (dpyinfo->has_palette)
7774 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7775 else
7776 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b 7777
007776bc
JB
7778 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7779 and because probably is more meaningful on Windows anyway */
abf8c61b 7780 if (cap < 0)
007776bc 7781 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
ee78dc32
GV
7782
7783 ReleaseDC (dpyinfo->root_window, hdc);
7784
7785 return make_number (cap);
7786}
7787
7788DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7789 Sx_server_max_request_size,
74e1aeec
JR
7790 0, 1, 0,
7791 doc: /* Returns the maximum request size of the server of DISPLAY.
7792The optional argument DISPLAY specifies which display to ask about.
7793DISPLAY should be either a frame or a display name (a string).
7794If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7795 (display)
7796 Lisp_Object display;
7797{
fbd6baed 7798 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7799
7800 return make_number (1);
7801}
7802
7803DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7804 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7805The optional argument DISPLAY specifies which display to ask about.
7806DISPLAY should be either a frame or a display name (a string).
7807If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7808 (display)
7809 Lisp_Object display;
7810{
dfff8a69 7811 return build_string ("Microsoft Corp.");
ee78dc32
GV
7812}
7813
7814DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7815 doc: /* Returns the version numbers of the server of DISPLAY.
7816The value is a list of three integers: the major and minor
7817version numbers, and the vendor-specific release
7818number. See also the function `x-server-vendor'.
7819
7820The optional argument DISPLAY specifies which display to ask about.
7821DISPLAY should be either a frame or a display name (a string).
7822If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7823 (display)
7824 Lisp_Object display;
7825{
fbd6baed 7826 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7827 Fcons (make_number (w32_minor_version),
7828 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7829}
7830
7831DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7832 doc: /* Returns the number of screens on the server of DISPLAY.
7833The optional argument DISPLAY specifies which display to ask about.
7834DISPLAY should be either a frame or a display name (a string).
7835If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7836 (display)
7837 Lisp_Object display;
7838{
ee78dc32
GV
7839 return make_number (1);
7840}
7841
74e1aeec
JR
7842DEFUN ("x-display-mm-height", Fx_display_mm_height,
7843 Sx_display_mm_height, 0, 1, 0,
7844 doc: /* Returns the height in millimeters of DISPLAY.
7845The optional argument DISPLAY specifies which display to ask about.
7846DISPLAY should be either a frame or a display name (a string).
7847If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7848 (display)
7849 Lisp_Object display;
7850{
fbd6baed 7851 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7852 HDC hdc;
7853 int cap;
7854
5ac45f98 7855 hdc = GetDC (dpyinfo->root_window);
3c190163 7856
ee78dc32 7857 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7858
ee78dc32
GV
7859 ReleaseDC (dpyinfo->root_window, hdc);
7860
7861 return make_number (cap);
7862}
7863
7864DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7865 doc: /* Returns the width in millimeters of DISPLAY.
7866The optional argument DISPLAY specifies which display to ask about.
7867DISPLAY should be either a frame or a display name (a string).
7868If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7869 (display)
7870 Lisp_Object display;
7871{
fbd6baed 7872 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7873
7874 HDC hdc;
7875 int cap;
7876
5ac45f98 7877 hdc = GetDC (dpyinfo->root_window);
3c190163 7878
ee78dc32 7879 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7880
ee78dc32
GV
7881 ReleaseDC (dpyinfo->root_window, hdc);
7882
7883 return make_number (cap);
7884}
7885
7886DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7887 Sx_display_backing_store, 0, 1, 0,
7888 doc: /* Returns an indication of whether DISPLAY does backing store.
7889The value may be `always', `when-mapped', or `not-useful'.
7890The optional argument DISPLAY specifies which display to ask about.
7891DISPLAY should be either a frame or a display name (a string).
7892If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7893 (display)
7894 Lisp_Object display;
7895{
7896 return intern ("not-useful");
7897}
7898
7899DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7900 Sx_display_visual_class, 0, 1, 0,
7901 doc: /* Returns the visual class of DISPLAY.
7902The value is one of the symbols `static-gray', `gray-scale',
7903`static-color', `pseudo-color', `true-color', or `direct-color'.
7904
7905The optional argument DISPLAY specifies which display to ask about.
7906DISPLAY should be either a frame or a display name (a string).
7907If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7908 (display)
7909 Lisp_Object display;
7910{
fbd6baed 7911 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7912 Lisp_Object result = Qnil;
ee78dc32 7913
abf8c61b
AI
7914 if (dpyinfo->has_palette)
7915 result = intern ("pseudo-color");
7916 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7917 result = intern ("static-grey");
7918 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7919 result = intern ("static-color");
7920 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7921 result = intern ("true-color");
ee78dc32 7922
abf8c61b 7923 return result;
ee78dc32
GV
7924}
7925
7926DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7927 Sx_display_save_under, 0, 1, 0,
7928 doc: /* Returns t if DISPLAY supports the save-under feature.
7929The optional argument DISPLAY specifies which display to ask about.
7930DISPLAY should be either a frame or a display name (a string).
7931If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7932 (display)
7933 Lisp_Object display;
7934{
6fc2811b
JR
7935 return Qnil;
7936}
7937\f
7938int
7939x_pixel_width (f)
7940 register struct frame *f;
7941{
7942 return PIXEL_WIDTH (f);
7943}
7944
7945int
7946x_pixel_height (f)
7947 register struct frame *f;
7948{
7949 return PIXEL_HEIGHT (f);
7950}
7951
7952int
7953x_char_width (f)
7954 register struct frame *f;
7955{
7956 return FONT_WIDTH (f->output_data.w32->font);
7957}
7958
7959int
7960x_char_height (f)
7961 register struct frame *f;
7962{
7963 return f->output_data.w32->line_height;
7964}
7965
7966int
7967x_screen_planes (f)
7968 register struct frame *f;
7969{
7970 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7971}
7972\f
7973/* Return the display structure for the display named NAME.
7974 Open a new connection if necessary. */
7975
7976struct w32_display_info *
7977x_display_info_for_name (name)
7978 Lisp_Object name;
7979{
7980 Lisp_Object names;
7981 struct w32_display_info *dpyinfo;
7982
b7826503 7983 CHECK_STRING (name);
6fc2811b
JR
7984
7985 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7986 dpyinfo;
7987 dpyinfo = dpyinfo->next, names = XCDR (names))
7988 {
7989 Lisp_Object tem;
7990 tem = Fstring_equal (XCAR (XCAR (names)), name);
7991 if (!NILP (tem))
7992 return dpyinfo;
7993 }
7994
7995 /* Use this general default value to start with. */
7996 Vx_resource_name = Vinvocation_name;
7997
7998 validate_x_resource_name ();
7999
8000 dpyinfo = w32_term_init (name, (unsigned char *)0,
8001 (char *) XSTRING (Vx_resource_name)->data);
8002
8003 if (dpyinfo == 0)
8004 error ("Cannot connect to server %s", XSTRING (name)->data);
8005
8006 w32_in_use = 1;
8007 XSETFASTINT (Vwindow_system_version, 3);
8008
8009 return dpyinfo;
8010}
8011
8012DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
8013 1, 3, 0, doc: /* Open a connection to a server.
8014DISPLAY is the name of the display to connect to.
8015Optional second arg XRM-STRING is a string of resources in xrdb format.
8016If the optional third arg MUST-SUCCEED is non-nil,
8017terminate Emacs if we can't open the connection. */)
6fc2811b
JR
8018 (display, xrm_string, must_succeed)
8019 Lisp_Object display, xrm_string, must_succeed;
8020{
8021 unsigned char *xrm_option;
8022 struct w32_display_info *dpyinfo;
8023
74e1aeec
JR
8024 /* If initialization has already been done, return now to avoid
8025 overwriting critical parts of one_w32_display_info. */
8026 if (w32_in_use)
8027 return Qnil;
8028
b7826503 8029 CHECK_STRING (display);
6fc2811b 8030 if (! NILP (xrm_string))
b7826503 8031 CHECK_STRING (xrm_string);
6fc2811b
JR
8032
8033 if (! EQ (Vwindow_system, intern ("w32")))
8034 error ("Not using Microsoft Windows");
8035
8036 /* Allow color mapping to be defined externally; first look in user's
8037 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8038 {
8039 Lisp_Object color_file;
8040 struct gcpro gcpro1;
8041
8042 color_file = build_string("~/rgb.txt");
8043
8044 GCPRO1 (color_file);
8045
8046 if (NILP (Ffile_readable_p (color_file)))
8047 color_file =
8048 Fexpand_file_name (build_string ("rgb.txt"),
8049 Fsymbol_value (intern ("data-directory")));
8050
8051 Vw32_color_map = Fw32_load_color_file (color_file);
8052
8053 UNGCPRO;
8054 }
8055 if (NILP (Vw32_color_map))
8056 Vw32_color_map = Fw32_default_color_map ();
8057
8058 if (! NILP (xrm_string))
8059 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8060 else
8061 xrm_option = (unsigned char *) 0;
8062
8063 /* Use this general default value to start with. */
8064 /* First remove .exe suffix from invocation-name - it looks ugly. */
8065 {
8066 char basename[ MAX_PATH ], *str;
8067
8068 strcpy (basename, XSTRING (Vinvocation_name)->data);
8069 str = strrchr (basename, '.');
8070 if (str) *str = 0;
8071 Vinvocation_name = build_string (basename);
8072 }
8073 Vx_resource_name = Vinvocation_name;
8074
8075 validate_x_resource_name ();
8076
8077 /* This is what opens the connection and sets x_current_display.
8078 This also initializes many symbols, such as those used for input. */
8079 dpyinfo = w32_term_init (display, xrm_option,
8080 (char *) XSTRING (Vx_resource_name)->data);
8081
8082 if (dpyinfo == 0)
8083 {
8084 if (!NILP (must_succeed))
8085 fatal ("Cannot connect to server %s.\n",
8086 XSTRING (display)->data);
8087 else
8088 error ("Cannot connect to server %s", XSTRING (display)->data);
8089 }
8090
8091 w32_in_use = 1;
8092
8093 XSETFASTINT (Vwindow_system_version, 3);
8094 return Qnil;
8095}
8096
8097DEFUN ("x-close-connection", Fx_close_connection,
8098 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
8099 doc: /* Close the connection to DISPLAY's server.
8100For DISPLAY, specify either a frame or a display name (a string).
8101If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
8102 (display)
8103 Lisp_Object display;
8104{
8105 struct w32_display_info *dpyinfo = check_x_display_info (display);
8106 int i;
8107
8108 if (dpyinfo->reference_count > 0)
8109 error ("Display still has frames on it");
8110
8111 BLOCK_INPUT;
8112 /* Free the fonts in the font table. */
8113 for (i = 0; i < dpyinfo->n_fonts; i++)
8114 if (dpyinfo->font_table[i].name)
8115 {
126f2e35
JR
8116 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8117 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 8118 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
8119 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8120 }
8121 x_destroy_all_bitmaps (dpyinfo);
8122
8123 x_delete_display (dpyinfo);
8124 UNBLOCK_INPUT;
8125
8126 return Qnil;
8127}
8128
8129DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 8130 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
8131 ()
8132{
8133 Lisp_Object tail, result;
8134
8135 result = Qnil;
8136 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8137 result = Fcons (XCAR (XCAR (tail)), result);
8138
8139 return result;
8140}
8141
8142DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
8143 doc: /* This is a noop on W32 systems. */)
8144 (on, display)
8145 Lisp_Object display, on;
6fc2811b 8146{
6fc2811b
JR
8147 return Qnil;
8148}
8149
8150\f
6fc2811b
JR
8151/***********************************************************************
8152 Image types
8153 ***********************************************************************/
8154
8155/* Value is the number of elements of vector VECTOR. */
8156
8157#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8158
8159/* List of supported image types. Use define_image_type to add new
8160 types. Use lookup_image_type to find a type for a given symbol. */
8161
8162static struct image_type *image_types;
8163
6fc2811b
JR
8164/* The symbol `image' which is the car of the lists used to represent
8165 images in Lisp. */
8166
8167extern Lisp_Object Qimage;
8168
8169/* The symbol `xbm' which is used as the type symbol for XBM images. */
8170
8171Lisp_Object Qxbm;
8172
8173/* Keywords. */
8174
6fc2811b 8175extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
8176extern Lisp_Object QCdata, QCtype;
8177Lisp_Object QCascent, QCmargin, QCrelief;
a93f4566 8178Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 8179Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
8180
8181/* Other symbols. */
8182
3cf3436e 8183Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
8184
8185/* Time in seconds after which images should be removed from the cache
8186 if not displayed. */
8187
8188Lisp_Object Vimage_cache_eviction_delay;
8189
8190/* Function prototypes. */
8191
8192static void define_image_type P_ ((struct image_type *type));
8193static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8194static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8195static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 8196static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
8197static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8198 Lisp_Object));
8199
dfff8a69 8200
6fc2811b
JR
8201/* Define a new image type from TYPE. This adds a copy of TYPE to
8202 image_types and adds the symbol *TYPE->type to Vimage_types. */
8203
8204static void
8205define_image_type (type)
8206 struct image_type *type;
8207{
8208 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8209 The initialized data segment is read-only. */
8210 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8211 bcopy (type, p, sizeof *p);
8212 p->next = image_types;
8213 image_types = p;
8214 Vimage_types = Fcons (*p->type, Vimage_types);
8215}
8216
8217
8218/* Look up image type SYMBOL, and return a pointer to its image_type
8219 structure. Value is null if SYMBOL is not a known image type. */
8220
8221static INLINE struct image_type *
8222lookup_image_type (symbol)
8223 Lisp_Object symbol;
8224{
8225 struct image_type *type;
8226
8227 for (type = image_types; type; type = type->next)
8228 if (EQ (symbol, *type->type))
8229 break;
8230
8231 return type;
8232}
8233
8234
8235/* Value is non-zero if OBJECT is a valid Lisp image specification. A
8236 valid image specification is a list whose car is the symbol
8237 `image', and whose rest is a property list. The property list must
8238 contain a value for key `:type'. That value must be the name of a
8239 supported image type. The rest of the property list depends on the
8240 image type. */
8241
8242int
8243valid_image_p (object)
8244 Lisp_Object object;
8245{
8246 int valid_p = 0;
8247
8248 if (CONSP (object) && EQ (XCAR (object), Qimage))
8249 {
3cf3436e
JR
8250 Lisp_Object tem;
8251
8252 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8253 if (EQ (XCAR (tem), QCtype))
8254 {
8255 tem = XCDR (tem);
8256 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8257 {
8258 struct image_type *type;
8259 type = lookup_image_type (XCAR (tem));
8260 if (type)
8261 valid_p = type->valid_p (object);
8262 }
8263
8264 break;
8265 }
6fc2811b
JR
8266 }
8267
8268 return valid_p;
8269}
8270
8271
8272/* Log error message with format string FORMAT and argument ARG.
8273 Signaling an error, e.g. when an image cannot be loaded, is not a
8274 good idea because this would interrupt redisplay, and the error
8275 message display would lead to another redisplay. This function
8276 therefore simply displays a message. */
8277
8278static void
8279image_error (format, arg1, arg2)
8280 char *format;
8281 Lisp_Object arg1, arg2;
8282{
8283 add_to_log (format, arg1, arg2);
8284}
8285
8286
8287\f
8288/***********************************************************************
8289 Image specifications
8290 ***********************************************************************/
8291
8292enum image_value_type
8293{
8294 IMAGE_DONT_CHECK_VALUE_TYPE,
8295 IMAGE_STRING_VALUE,
3cf3436e 8296 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
8297 IMAGE_SYMBOL_VALUE,
8298 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8299 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8300 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8301 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8302 IMAGE_INTEGER_VALUE,
8303 IMAGE_FUNCTION_VALUE,
8304 IMAGE_NUMBER_VALUE,
8305 IMAGE_BOOL_VALUE
8306};
8307
8308/* Structure used when parsing image specifications. */
8309
8310struct image_keyword
8311{
8312 /* Name of keyword. */
8313 char *name;
8314
8315 /* The type of value allowed. */
8316 enum image_value_type type;
8317
8318 /* Non-zero means key must be present. */
8319 int mandatory_p;
8320
8321 /* Used to recognize duplicate keywords in a property list. */
8322 int count;
8323
8324 /* The value that was found. */
8325 Lisp_Object value;
8326};
8327
8328
8329static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8330 int, Lisp_Object));
8331static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8332
8333
8334/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8335 has the format (image KEYWORD VALUE ...). One of the keyword/
8336 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8337 image_keywords structures of size NKEYWORDS describing other
8338 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8339
8340static int
8341parse_image_spec (spec, keywords, nkeywords, type)
8342 Lisp_Object spec;
8343 struct image_keyword *keywords;
8344 int nkeywords;
8345 Lisp_Object type;
8346{
8347 int i;
8348 Lisp_Object plist;
8349
8350 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8351 return 0;
8352
8353 plist = XCDR (spec);
8354 while (CONSP (plist))
8355 {
8356 Lisp_Object key, value;
8357
8358 /* First element of a pair must be a symbol. */
8359 key = XCAR (plist);
8360 plist = XCDR (plist);
8361 if (!SYMBOLP (key))
8362 return 0;
8363
8364 /* There must follow a value. */
8365 if (!CONSP (plist))
8366 return 0;
8367 value = XCAR (plist);
8368 plist = XCDR (plist);
8369
8370 /* Find key in KEYWORDS. Error if not found. */
8371 for (i = 0; i < nkeywords; ++i)
8372 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8373 break;
8374
8375 if (i == nkeywords)
8376 continue;
8377
8378 /* Record that we recognized the keyword. If a keywords
8379 was found more than once, it's an error. */
8380 keywords[i].value = value;
8381 ++keywords[i].count;
8382
8383 if (keywords[i].count > 1)
8384 return 0;
8385
8386 /* Check type of value against allowed type. */
8387 switch (keywords[i].type)
8388 {
8389 case IMAGE_STRING_VALUE:
8390 if (!STRINGP (value))
8391 return 0;
8392 break;
8393
3cf3436e
JR
8394 case IMAGE_STRING_OR_NIL_VALUE:
8395 if (!STRINGP (value) && !NILP (value))
8396 return 0;
8397 break;
8398
6fc2811b
JR
8399 case IMAGE_SYMBOL_VALUE:
8400 if (!SYMBOLP (value))
8401 return 0;
8402 break;
8403
8404 case IMAGE_POSITIVE_INTEGER_VALUE:
8405 if (!INTEGERP (value) || XINT (value) <= 0)
8406 return 0;
8407 break;
8408
8edb0a6f
JR
8409 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8410 if (INTEGERP (value) && XINT (value) >= 0)
8411 break;
8412 if (CONSP (value)
8413 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8414 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8415 break;
8416 return 0;
8417
dfff8a69
JR
8418 case IMAGE_ASCENT_VALUE:
8419 if (SYMBOLP (value) && EQ (value, Qcenter))
8420 break;
8421 else if (INTEGERP (value)
8422 && XINT (value) >= 0
8423 && XINT (value) <= 100)
8424 break;
8425 return 0;
8426
6fc2811b
JR
8427 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8428 if (!INTEGERP (value) || XINT (value) < 0)
8429 return 0;
8430 break;
8431
8432 case IMAGE_DONT_CHECK_VALUE_TYPE:
8433 break;
8434
8435 case IMAGE_FUNCTION_VALUE:
8436 value = indirect_function (value);
8437 if (SUBRP (value)
8438 || COMPILEDP (value)
8439 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8440 break;
8441 return 0;
8442
8443 case IMAGE_NUMBER_VALUE:
8444 if (!INTEGERP (value) && !FLOATP (value))
8445 return 0;
8446 break;
8447
8448 case IMAGE_INTEGER_VALUE:
8449 if (!INTEGERP (value))
8450 return 0;
8451 break;
8452
8453 case IMAGE_BOOL_VALUE:
8454 if (!NILP (value) && !EQ (value, Qt))
8455 return 0;
8456 break;
8457
8458 default:
8459 abort ();
8460 break;
8461 }
8462
8463 if (EQ (key, QCtype) && !EQ (type, value))
8464 return 0;
8465 }
8466
8467 /* Check that all mandatory fields are present. */
8468 for (i = 0; i < nkeywords; ++i)
8469 if (keywords[i].mandatory_p && keywords[i].count == 0)
8470 return 0;
8471
8472 return NILP (plist);
8473}
8474
8475
8476/* Return the value of KEY in image specification SPEC. Value is nil
8477 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8478 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8479
8480static Lisp_Object
8481image_spec_value (spec, key, found)
8482 Lisp_Object spec, key;
8483 int *found;
8484{
8485 Lisp_Object tail;
8486
8487 xassert (valid_image_p (spec));
8488
8489 for (tail = XCDR (spec);
8490 CONSP (tail) && CONSP (XCDR (tail));
8491 tail = XCDR (XCDR (tail)))
8492 {
8493 if (EQ (XCAR (tail), key))
8494 {
8495 if (found)
8496 *found = 1;
8497 return XCAR (XCDR (tail));
8498 }
8499 }
8500
8501 if (found)
8502 *found = 0;
8503 return Qnil;
8504}
8505
8506
ac849ba4
JR
8507#ifdef HAVE_IMAGES
8508DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8509 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8510PIXELS non-nil means return the size in pixels, otherwise return the
8511size in canonical character units.
8512FRAME is the frame on which the image will be displayed. FRAME nil
8513or omitted means use the selected frame. */)
8514 (spec, pixels, frame)
8515 Lisp_Object spec, pixels, frame;
8516{
8517 Lisp_Object size;
8518
8519 size = Qnil;
8520 if (valid_image_p (spec))
8521 {
8522 struct frame *f = check_x_frame (frame);
8523 int id = lookup_image (f, spec);
8524 struct image *img = IMAGE_FROM_ID (f, id);
8525 int width = img->width + 2 * img->hmargin;
8526 int height = img->height + 2 * img->vmargin;
8527
8528 if (NILP (pixels))
8529 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8530 make_float ((double) height / CANON_Y_UNIT (f)));
8531 else
8532 size = Fcons (make_number (width), make_number (height));
8533 }
8534 else
8535 error ("Invalid image specification");
8536
8537 return size;
8538}
8539
8540
8541DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8542 doc: /* Return t if image SPEC has a mask bitmap.
8543FRAME is the frame on which the image will be displayed. FRAME nil
8544or omitted means use the selected frame. */)
8545 (spec, frame)
8546 Lisp_Object spec, frame;
8547{
8548 Lisp_Object mask;
8549
8550 mask = Qnil;
8551 if (valid_image_p (spec))
8552 {
8553 struct frame *f = check_x_frame (frame);
8554 int id = lookup_image (f, spec);
8555 struct image *img = IMAGE_FROM_ID (f, id);
8556 if (img->mask)
8557 mask = Qt;
8558 }
8559 else
8560 error ("Invalid image specification");
8561
8562 return mask;
8563}
8564#endif
6fc2811b
JR
8565
8566\f
8567/***********************************************************************
8568 Image type independent image structures
8569 ***********************************************************************/
8570
8571static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8572static void free_image P_ ((struct frame *f, struct image *img));
8573
8574
8575/* Allocate and return a new image structure for image specification
8576 SPEC. SPEC has a hash value of HASH. */
8577
8578static struct image *
8579make_image (spec, hash)
8580 Lisp_Object spec;
8581 unsigned hash;
8582{
8583 struct image *img = (struct image *) xmalloc (sizeof *img);
8584
8585 xassert (valid_image_p (spec));
8586 bzero (img, sizeof *img);
8587 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8588 xassert (img->type != NULL);
8589 img->spec = spec;
8590 img->data.lisp_val = Qnil;
8591 img->ascent = DEFAULT_IMAGE_ASCENT;
8592 img->hash = hash;
8593 return img;
8594}
8595
8596
8597/* Free image IMG which was used on frame F, including its resources. */
8598
8599static void
8600free_image (f, img)
8601 struct frame *f;
8602 struct image *img;
8603{
8604 if (img)
8605 {
8606 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8607
8608 /* Remove IMG from the hash table of its cache. */
8609 if (img->prev)
8610 img->prev->next = img->next;
8611 else
8612 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8613
8614 if (img->next)
8615 img->next->prev = img->prev;
8616
8617 c->images[img->id] = NULL;
8618
8619 /* Free resources, then free IMG. */
8620 img->type->free (f, img);
8621 xfree (img);
8622 }
8623}
8624
8625
8626/* Prepare image IMG for display on frame F. Must be called before
8627 drawing an image. */
8628
8629void
8630prepare_image_for_display (f, img)
8631 struct frame *f;
8632 struct image *img;
8633{
8634 EMACS_TIME t;
8635
8636 /* We're about to display IMG, so set its timestamp to `now'. */
8637 EMACS_GET_TIME (t);
8638 img->timestamp = EMACS_SECS (t);
8639
8640 /* If IMG doesn't have a pixmap yet, load it now, using the image
8641 type dependent loader function. */
8642 if (img->pixmap == 0 && !img->load_failed_p)
8643 img->load_failed_p = img->type->load (f, img) == 0;
8644}
8645
8646
dfff8a69
JR
8647/* Value is the number of pixels for the ascent of image IMG when
8648 drawn in face FACE. */
8649
8650int
8651image_ascent (img, face)
8652 struct image *img;
8653 struct face *face;
8654{
8edb0a6f 8655 int height = img->height + img->vmargin;
dfff8a69
JR
8656 int ascent;
8657
8658 if (img->ascent == CENTERED_IMAGE_ASCENT)
8659 {
8660 if (face->font)
8661 ascent = height / 2 - (FONT_DESCENT(face->font)
8662 - FONT_BASE(face->font)) / 2;
8663 else
8664 ascent = height / 2;
8665 }
8666 else
ac849ba4 8667 ascent = (int) (height * img->ascent / 100.0);
dfff8a69
JR
8668
8669 return ascent;
8670}
8671
8672
6fc2811b 8673\f
a05e2bae
JR
8674/* Image background colors. */
8675
ac849ba4
JR
8676/* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8677 context with the bitmap selected. */
8678static COLORREF
a05e2bae 8679four_corners_best (ximg, width, height)
ac849ba4 8680 HDC ximg;
a05e2bae
JR
8681 unsigned long width, height;
8682{
ac849ba4 8683 COLORREF corners[4], best;
a05e2bae
JR
8684 int i, best_count;
8685
8686 /* Get the colors at the corners of ximg. */
ac849ba4
JR
8687 corners[0] = GetPixel (ximg, 0, 0);
8688 corners[1] = GetPixel (ximg, width - 1, 0);
8689 corners[2] = GetPixel (ximg, width - 1, height - 1);
8690 corners[3] = GetPixel (ximg, 0, height - 1);
a05e2bae
JR
8691
8692 /* Choose the most frequently found color as background. */
8693 for (i = best_count = 0; i < 4; ++i)
8694 {
8695 int j, n;
8696
8697 for (j = n = 0; j < 4; ++j)
8698 if (corners[i] == corners[j])
8699 ++n;
8700
8701 if (n > best_count)
8702 best = corners[i], best_count = n;
8703 }
8704
8705 return best;
a05e2bae
JR
8706}
8707
8708/* Return the `background' field of IMG. If IMG doesn't have one yet,
8709 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8710 object to use for the heuristic. */
8711
8712unsigned long
8713image_background (img, f, ximg)
8714 struct image *img;
8715 struct frame *f;
8716 XImage *ximg;
8717{
8718 if (! img->background_valid)
8719 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8720 {
8721#if 0 /* TODO: Image support. */
8722 int free_ximg = !ximg;
8723
8724 if (! ximg)
8725 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8726 0, 0, img->width, img->height, ~0, ZPixmap);
8727
8728 img->background = four_corners_best (ximg, img->width, img->height);
8729
8730 if (free_ximg)
8731 XDestroyImage (ximg);
8732
8733 img->background_valid = 1;
8734#endif
8735 }
8736
8737 return img->background;
8738}
8739
8740/* Return the `background_transparent' field of IMG. If IMG doesn't
8741 have one yet, it is guessed heuristically. If non-zero, MASK is an
8742 existing XImage object to use for the heuristic. */
8743
8744int
8745image_background_transparent (img, f, mask)
8746 struct image *img;
8747 struct frame *f;
8748 XImage *mask;
8749{
8750 if (! img->background_transparent_valid)
8751 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8752 {
8753#if 0 /* TODO: Image support. */
8754 if (img->mask)
8755 {
8756 int free_mask = !mask;
8757
8758 if (! mask)
8759 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8760 0, 0, img->width, img->height, ~0, ZPixmap);
8761
8762 img->background_transparent
8763 = !four_corners_best (mask, img->width, img->height);
8764
8765 if (free_mask)
8766 XDestroyImage (mask);
8767 }
8768 else
8769#endif
8770 img->background_transparent = 0;
8771
8772 img->background_transparent_valid = 1;
8773 }
8774
8775 return img->background_transparent;
8776}
8777
8778\f
6fc2811b
JR
8779/***********************************************************************
8780 Helper functions for X image types
8781 ***********************************************************************/
8782
a05e2bae
JR
8783static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8784 int, int));
6fc2811b
JR
8785static void x_clear_image P_ ((struct frame *f, struct image *img));
8786static unsigned long x_alloc_image_color P_ ((struct frame *f,
8787 struct image *img,
8788 Lisp_Object color_name,
8789 unsigned long dflt));
8790
a05e2bae
JR
8791
8792/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8793 free the pixmap if any. MASK_P non-zero means clear the mask
8794 pixmap if any. COLORS_P non-zero means free colors allocated for
8795 the image, if any. */
8796
8797static void
8798x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8799 struct frame *f;
8800 struct image *img;
8801 int pixmap_p, mask_p, colors_p;
8802{
a05e2bae
JR
8803 if (pixmap_p && img->pixmap)
8804 {
ac849ba4
JR
8805 DeleteObject (img->pixmap);
8806 img->pixmap = NULL;
a05e2bae
JR
8807 img->background_valid = 0;
8808 }
8809
8810 if (mask_p && img->mask)
8811 {
ac849ba4
JR
8812 DeleteObject (img->mask);
8813 img->mask = NULL;
a05e2bae
JR
8814 img->background_transparent_valid = 0;
8815 }
8816
8817 if (colors_p && img->ncolors)
8818 {
bf76fe9c 8819#if 0 /* TODO: color table support. */
a05e2bae 8820 x_free_colors (f, img->colors, img->ncolors);
bf76fe9c 8821#endif
a05e2bae
JR
8822 xfree (img->colors);
8823 img->colors = NULL;
8824 img->ncolors = 0;
8825 }
a05e2bae
JR
8826}
8827
6fc2811b
JR
8828/* Free X resources of image IMG which is used on frame F. */
8829
8830static void
8831x_clear_image (f, img)
8832 struct frame *f;
8833 struct image *img;
8834{
6fc2811b
JR
8835 if (img->pixmap)
8836 {
8837 BLOCK_INPUT;
ac849ba4 8838 DeleteObject (img->pixmap);
6fc2811b
JR
8839 img->pixmap = 0;
8840 UNBLOCK_INPUT;
8841 }
8842
8843 if (img->ncolors)
8844 {
ac849ba4
JR
8845#if 0 /* TODO: color table support */
8846
6fc2811b
JR
8847 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8848
8849 /* If display has an immutable color map, freeing colors is not
8850 necessary and some servers don't allow it. So don't do it. */
8851 if (class != StaticColor
8852 && class != StaticGray
8853 && class != TrueColor)
8854 {
8855 Colormap cmap;
8856 BLOCK_INPUT;
8857 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8858 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8859 img->ncolors, 0);
8860 UNBLOCK_INPUT;
8861 }
ac849ba4 8862#endif
6fc2811b
JR
8863
8864 xfree (img->colors);
8865 img->colors = NULL;
8866 img->ncolors = 0;
8867 }
6fc2811b
JR
8868}
8869
8870
8871/* Allocate color COLOR_NAME for image IMG on frame F. If color
8872 cannot be allocated, use DFLT. Add a newly allocated color to
8873 IMG->colors, so that it can be freed again. Value is the pixel
8874 color. */
8875
8876static unsigned long
8877x_alloc_image_color (f, img, color_name, dflt)
8878 struct frame *f;
8879 struct image *img;
8880 Lisp_Object color_name;
8881 unsigned long dflt;
8882{
6fc2811b
JR
8883 XColor color;
8884 unsigned long result;
8885
8886 xassert (STRINGP (color_name));
8887
8888 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8889 {
8890 /* This isn't called frequently so we get away with simply
8891 reallocating the color vector to the needed size, here. */
8892 ++img->ncolors;
8893 img->colors =
8894 (unsigned long *) xrealloc (img->colors,
8895 img->ncolors * sizeof *img->colors);
8896 img->colors[img->ncolors - 1] = color.pixel;
8897 result = color.pixel;
8898 }
8899 else
8900 result = dflt;
8901 return result;
6fc2811b
JR
8902}
8903
8904
8905\f
8906/***********************************************************************
8907 Image Cache
8908 ***********************************************************************/
8909
8910static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8911static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8912
8913
8914/* Return a new, initialized image cache that is allocated from the
8915 heap. Call free_image_cache to free an image cache. */
8916
8917struct image_cache *
8918make_image_cache ()
8919{
8920 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8921 int size;
8922
8923 bzero (c, sizeof *c);
8924 c->size = 50;
8925 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8926 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8927 c->buckets = (struct image **) xmalloc (size);
8928 bzero (c->buckets, size);
8929 return c;
8930}
8931
8932
8933/* Free image cache of frame F. Be aware that X frames share images
8934 caches. */
8935
8936void
8937free_image_cache (f)
8938 struct frame *f;
8939{
8940 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8941 if (c)
8942 {
8943 int i;
8944
8945 /* Cache should not be referenced by any frame when freed. */
8946 xassert (c->refcount == 0);
8947
8948 for (i = 0; i < c->used; ++i)
8949 free_image (f, c->images[i]);
8950 xfree (c->images);
8951 xfree (c);
8952 xfree (c->buckets);
8953 FRAME_X_IMAGE_CACHE (f) = NULL;
8954 }
8955}
8956
8957
8958/* Clear image cache of frame F. FORCE_P non-zero means free all
8959 images. FORCE_P zero means clear only images that haven't been
8960 displayed for some time. Should be called from time to time to
dfff8a69
JR
8961 reduce the number of loaded images. If image-eviction-seconds is
8962 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8963 at least that many seconds. */
8964
8965void
8966clear_image_cache (f, force_p)
8967 struct frame *f;
8968 int force_p;
8969{
8970 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8971
8972 if (c && INTEGERP (Vimage_cache_eviction_delay))
8973 {
8974 EMACS_TIME t;
8975 unsigned long old;
0327b4cc 8976 int i, nfreed;
6fc2811b
JR
8977
8978 EMACS_GET_TIME (t);
8979 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8980
0327b4cc
JR
8981 /* Block input so that we won't be interrupted by a SIGIO
8982 while being in an inconsistent state. */
8983 BLOCK_INPUT;
8984
8985 for (i = nfreed = 0; i < c->used; ++i)
6fc2811b
JR
8986 {
8987 struct image *img = c->images[i];
8988 if (img != NULL
0327b4cc 8989 && (force_p || (img->timestamp < old)))
6fc2811b
JR
8990 {
8991 free_image (f, img);
0327b4cc 8992 ++nfreed;
6fc2811b
JR
8993 }
8994 }
8995
8996 /* We may be clearing the image cache because, for example,
8997 Emacs was iconified for a longer period of time. In that
8998 case, current matrices may still contain references to
8999 images freed above. So, clear these matrices. */
0327b4cc 9000 if (nfreed)
6fc2811b 9001 {
0327b4cc
JR
9002 Lisp_Object tail, frame;
9003
9004 FOR_EACH_FRAME (tail, frame)
9005 {
9006 struct frame *f = XFRAME (frame);
9007 if (FRAME_W32_P (f)
9008 && FRAME_X_IMAGE_CACHE (f) == c)
9009 clear_current_matrices (f);
9010 }
9011
6fc2811b
JR
9012 ++windows_or_buffers_changed;
9013 }
0327b4cc
JR
9014
9015 UNBLOCK_INPUT;
6fc2811b
JR
9016 }
9017}
9018
9019
9020DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9021 0, 1, 0,
74e1aeec
JR
9022 doc: /* Clear the image cache of FRAME.
9023FRAME nil or omitted means use the selected frame.
9024FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
9025 (frame)
9026 Lisp_Object frame;
9027{
9028 if (EQ (frame, Qt))
9029 {
9030 Lisp_Object tail;
9031
9032 FOR_EACH_FRAME (tail, frame)
9033 if (FRAME_W32_P (XFRAME (frame)))
9034 clear_image_cache (XFRAME (frame), 1);
9035 }
9036 else
9037 clear_image_cache (check_x_frame (frame), 1);
9038
9039 return Qnil;
9040}
9041
9042
3cf3436e
JR
9043/* Compute masks and transform image IMG on frame F, as specified
9044 by the image's specification, */
9045
9046static void
9047postprocess_image (f, img)
9048 struct frame *f;
9049 struct image *img;
9050{
9051#if 0 /* TODO: image support. */
9052 /* Manipulation of the image's mask. */
9053 if (img->pixmap)
9054 {
9055 Lisp_Object conversion, spec;
9056 Lisp_Object mask;
9057
9058 spec = img->spec;
9059
9060 /* `:heuristic-mask t'
9061 `:mask heuristic'
9062 means build a mask heuristically.
9063 `:heuristic-mask (R G B)'
9064 `:mask (heuristic (R G B))'
9065 means build a mask from color (R G B) in the
9066 image.
9067 `:mask nil'
9068 means remove a mask, if any. */
9069
9070 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9071 if (!NILP (mask))
9072 x_build_heuristic_mask (f, img, mask);
9073 else
9074 {
9075 int found_p;
9076
9077 mask = image_spec_value (spec, QCmask, &found_p);
9078
9079 if (EQ (mask, Qheuristic))
9080 x_build_heuristic_mask (f, img, Qt);
9081 else if (CONSP (mask)
9082 && EQ (XCAR (mask), Qheuristic))
9083 {
9084 if (CONSP (XCDR (mask)))
9085 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9086 else
9087 x_build_heuristic_mask (f, img, XCDR (mask));
9088 }
9089 else if (NILP (mask) && found_p && img->mask)
9090 {
ac849ba4 9091 DeleteObject (img->mask);
3cf3436e
JR
9092 img->mask = NULL;
9093 }
9094 }
9095
9096
9097 /* Should we apply an image transformation algorithm? */
9098 conversion = image_spec_value (spec, QCconversion, NULL);
9099 if (EQ (conversion, Qdisabled))
9100 x_disable_image (f, img);
9101 else if (EQ (conversion, Qlaplace))
9102 x_laplace (f, img);
9103 else if (EQ (conversion, Qemboss))
9104 x_emboss (f, img);
9105 else if (CONSP (conversion)
9106 && EQ (XCAR (conversion), Qedge_detection))
9107 {
9108 Lisp_Object tem;
9109 tem = XCDR (conversion);
9110 if (CONSP (tem))
9111 x_edge_detection (f, img,
9112 Fplist_get (tem, QCmatrix),
9113 Fplist_get (tem, QCcolor_adjustment));
9114 }
9115 }
9116#endif
9117}
9118
9119
6fc2811b
JR
9120/* Return the id of image with Lisp specification SPEC on frame F.
9121 SPEC must be a valid Lisp image specification (see valid_image_p). */
9122
9123int
9124lookup_image (f, spec)
9125 struct frame *f;
9126 Lisp_Object spec;
9127{
9128 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9129 struct image *img;
9130 int i;
9131 unsigned hash;
9132 struct gcpro gcpro1;
9133 EMACS_TIME now;
9134
9135 /* F must be a window-system frame, and SPEC must be a valid image
9136 specification. */
9137 xassert (FRAME_WINDOW_P (f));
9138 xassert (valid_image_p (spec));
9139
9140 GCPRO1 (spec);
9141
9142 /* Look up SPEC in the hash table of the image cache. */
9143 hash = sxhash (spec, 0);
9144 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9145
9146 for (img = c->buckets[i]; img; img = img->next)
9147 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9148 break;
9149
9150 /* If not found, create a new image and cache it. */
9151 if (img == NULL)
9152 {
3cf3436e
JR
9153 extern Lisp_Object Qpostscript;
9154
8edb0a6f 9155 BLOCK_INPUT;
6fc2811b
JR
9156 img = make_image (spec, hash);
9157 cache_image (f, img);
9158 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
9159
9160 /* If we can't load the image, and we don't have a width and
9161 height, use some arbitrary width and height so that we can
9162 draw a rectangle for it. */
9163 if (img->load_failed_p)
9164 {
9165 Lisp_Object value;
9166
9167 value = image_spec_value (spec, QCwidth, NULL);
9168 img->width = (INTEGERP (value)
9169 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9170 value = image_spec_value (spec, QCheight, NULL);
9171 img->height = (INTEGERP (value)
9172 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9173 }
9174 else
9175 {
9176 /* Handle image type independent image attributes
a05e2bae
JR
9177 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9178 `:background COLOR'. */
9179 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
9180
9181 ascent = image_spec_value (spec, QCascent, NULL);
9182 if (INTEGERP (ascent))
9183 img->ascent = XFASTINT (ascent);
dfff8a69
JR
9184 else if (EQ (ascent, Qcenter))
9185 img->ascent = CENTERED_IMAGE_ASCENT;
9186
6fc2811b
JR
9187 margin = image_spec_value (spec, QCmargin, NULL);
9188 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
9189 img->vmargin = img->hmargin = XFASTINT (margin);
9190 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9191 && INTEGERP (XCDR (margin)))
9192 {
9193 if (XINT (XCAR (margin)) > 0)
9194 img->hmargin = XFASTINT (XCAR (margin));
9195 if (XINT (XCDR (margin)) > 0)
9196 img->vmargin = XFASTINT (XCDR (margin));
9197 }
6fc2811b
JR
9198
9199 relief = image_spec_value (spec, QCrelief, NULL);
9200 if (INTEGERP (relief))
9201 {
9202 img->relief = XINT (relief);
8edb0a6f
JR
9203 img->hmargin += abs (img->relief);
9204 img->vmargin += abs (img->relief);
6fc2811b
JR
9205 }
9206
a05e2bae
JR
9207 if (! img->background_valid)
9208 {
9209 bg = image_spec_value (img->spec, QCbackground, NULL);
9210 if (!NILP (bg))
9211 {
9212 img->background
9213 = x_alloc_image_color (f, img, bg,
9214 FRAME_BACKGROUND_PIXEL (f));
9215 img->background_valid = 1;
9216 }
9217 }
9218
3cf3436e
JR
9219 /* Do image transformations and compute masks, unless we
9220 don't have the image yet. */
9221 if (!EQ (*img->type->type, Qpostscript))
9222 postprocess_image (f, img);
6fc2811b 9223 }
3cf3436e 9224
8edb0a6f
JR
9225 UNBLOCK_INPUT;
9226 xassert (!interrupt_input_blocked);
6fc2811b
JR
9227 }
9228
9229 /* We're using IMG, so set its timestamp to `now'. */
9230 EMACS_GET_TIME (now);
9231 img->timestamp = EMACS_SECS (now);
9232
9233 UNGCPRO;
9234
9235 /* Value is the image id. */
9236 return img->id;
9237}
9238
9239
9240/* Cache image IMG in the image cache of frame F. */
9241
9242static void
9243cache_image (f, img)
9244 struct frame *f;
9245 struct image *img;
9246{
9247 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9248 int i;
9249
9250 /* Find a free slot in c->images. */
9251 for (i = 0; i < c->used; ++i)
9252 if (c->images[i] == NULL)
9253 break;
9254
9255 /* If no free slot found, maybe enlarge c->images. */
9256 if (i == c->used && c->used == c->size)
9257 {
9258 c->size *= 2;
9259 c->images = (struct image **) xrealloc (c->images,
9260 c->size * sizeof *c->images);
9261 }
9262
9263 /* Add IMG to c->images, and assign IMG an id. */
9264 c->images[i] = img;
9265 img->id = i;
9266 if (i == c->used)
9267 ++c->used;
9268
9269 /* Add IMG to the cache's hash table. */
9270 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9271 img->next = c->buckets[i];
9272 if (img->next)
9273 img->next->prev = img;
9274 img->prev = NULL;
9275 c->buckets[i] = img;
9276}
9277
9278
9279/* Call FN on every image in the image cache of frame F. Used to mark
9280 Lisp Objects in the image cache. */
9281
9282void
9283forall_images_in_image_cache (f, fn)
9284 struct frame *f;
9285 void (*fn) P_ ((struct image *img));
9286{
9287 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9288 {
9289 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9290 if (c)
9291 {
9292 int i;
9293 for (i = 0; i < c->used; ++i)
9294 if (c->images[i])
9295 fn (c->images[i]);
9296 }
9297 }
9298}
9299
9300
9301\f
9302/***********************************************************************
9303 W32 support code
9304 ***********************************************************************/
9305
6fc2811b
JR
9306static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9307 XImage **, Pixmap *));
9308static void x_destroy_x_image P_ ((XImage *));
9309static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9310
9311
9312/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9313 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9314 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
ac849ba4
JR
9315 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9316 DEPTH should indicate the bit depth of the image. Print error
9317 messages via image_error if an error occurs. Value is non-zero if
9318 successful. */
6fc2811b
JR
9319
9320static int
9321x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9322 struct frame *f;
9323 int width, height, depth;
9324 XImage **ximg;
9325 Pixmap *pixmap;
9326{
ac849ba4
JR
9327 BITMAPINFOHEADER *header;
9328 HDC hdc;
9329 int scanline_width_bits;
9330 int remainder;
9331 int palette_colors = 0;
6fc2811b 9332
ac849ba4
JR
9333 if (depth == 0)
9334 depth = 24;
6fc2811b 9335
ac849ba4
JR
9336 if (depth != 1 && depth != 4 && depth != 8
9337 && depth != 16 && depth != 24 && depth != 32)
9338 {
9339 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9340 return 0;
9341 }
9342
9343 scanline_width_bits = width * depth;
9344 remainder = scanline_width_bits % 32;
9345
9346 if (remainder)
9347 scanline_width_bits += 32 - remainder;
9348
9349 /* Bitmaps with a depth less than 16 need a palette. */
9350 /* BITMAPINFO structure already contains the first RGBQUAD. */
9351 if (depth < 16)
9352 palette_colors = 1 << depth - 1;
9353
9354 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
6fc2811b
JR
9355 if (*ximg == NULL)
9356 {
ac849ba4 9357 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
6fc2811b
JR
9358 return 0;
9359 }
9360
ac849ba4
JR
9361 header = &((*ximg)->info.bmiHeader);
9362 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9363 header->biSize = sizeof (*header);
9364 header->biWidth = width;
9365 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9366 header->biPlanes = 1;
9367 header->biBitCount = depth;
9368 header->biCompression = BI_RGB;
9369 header->biClrUsed = palette_colors;
6fc2811b 9370
ac849ba4
JR
9371 hdc = get_frame_dc (f);
9372
9373 /* Create a DIBSection and raster array for the bitmap,
9374 and store its handle in *pixmap. */
9375 *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
9376 &((*ximg)->data), NULL, 0);
9377
9378 /* Realize display palette and garbage all frames. */
9379 release_frame_dc (f, hdc);
9380
9381 if (*pixmap == NULL)
6fc2811b 9382 {
ac849ba4
JR
9383 DWORD err = GetLastError();
9384 Lisp_Object errcode;
9385 /* All system errors are < 10000, so the following is safe. */
9386 XSETINT (errcode, (int) err);
9387 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
6fc2811b 9388 x_destroy_x_image (*ximg);
6fc2811b
JR
9389 return 0;
9390 }
ac849ba4 9391
6fc2811b
JR
9392 return 1;
9393}
9394
9395
9396/* Destroy XImage XIMG. Free XIMG->data. */
9397
9398static void
9399x_destroy_x_image (ximg)
9400 XImage *ximg;
9401{
9402 xassert (interrupt_input_blocked);
9403 if (ximg)
9404 {
ac849ba4 9405 /* Data will be freed by DestroyObject. */
6fc2811b 9406 ximg->data = NULL;
ac849ba4 9407 xfree (ximg);
6fc2811b
JR
9408 }
9409}
9410
9411
9412/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9413 are width and height of both the image and pixmap. */
9414
9415static void
9416x_put_x_image (f, ximg, pixmap, width, height)
9417 struct frame *f;
9418 XImage *ximg;
9419 Pixmap pixmap;
9420{
ac849ba4
JR
9421
9422#if TODO /* W32 specific image code. */
6fc2811b 9423 GC gc;
ac849ba4 9424
6fc2811b
JR
9425 xassert (interrupt_input_blocked);
9426 gc = XCreateGC (NULL, pixmap, 0, NULL);
9427 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9428 XFreeGC (NULL, gc);
6fc2811b 9429#endif
ac849ba4 9430}
6fc2811b
JR
9431
9432\f
9433/***********************************************************************
3cf3436e 9434 File Handling
6fc2811b
JR
9435 ***********************************************************************/
9436
9437static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9438static char *slurp_file P_ ((char *, int *));
9439
6fc2811b
JR
9440
9441/* Find image file FILE. Look in data-directory, then
9442 x-bitmap-file-path. Value is the full name of the file found, or
9443 nil if not found. */
9444
9445static Lisp_Object
9446x_find_image_file (file)
9447 Lisp_Object file;
9448{
9449 Lisp_Object file_found, search_path;
9450 struct gcpro gcpro1, gcpro2;
9451 int fd;
9452
9453 file_found = Qnil;
9454 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9455 GCPRO2 (file_found, search_path);
9456
9457 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 9458 fd = openp (search_path, file, Qnil, &file_found, 0);
6fc2811b 9459
939d6465 9460 if (fd == -1)
6fc2811b
JR
9461 file_found = Qnil;
9462 else
9463 close (fd);
9464
9465 UNGCPRO;
9466 return file_found;
9467}
9468
9469
3cf3436e
JR
9470/* Read FILE into memory. Value is a pointer to a buffer allocated
9471 with xmalloc holding FILE's contents. Value is null if an error
9472 occurred. *SIZE is set to the size of the file. */
9473
9474static char *
9475slurp_file (file, size)
9476 char *file;
9477 int *size;
9478{
9479 FILE *fp = NULL;
9480 char *buf = NULL;
9481 struct stat st;
9482
9483 if (stat (file, &st) == 0
9484 && (fp = fopen (file, "r")) != NULL
9485 && (buf = (char *) xmalloc (st.st_size),
9486 fread (buf, 1, st.st_size, fp) == st.st_size))
9487 {
9488 *size = st.st_size;
9489 fclose (fp);
9490 }
9491 else
9492 {
9493 if (fp)
9494 fclose (fp);
9495 if (buf)
9496 {
9497 xfree (buf);
9498 buf = NULL;
9499 }
9500 }
9501
9502 return buf;
9503}
9504
9505
6fc2811b
JR
9506\f
9507/***********************************************************************
9508 XBM images
9509 ***********************************************************************/
9510
9511static int xbm_load P_ ((struct frame *f, struct image *img));
9512static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9513 Lisp_Object file));
9514static int xbm_image_p P_ ((Lisp_Object object));
9515static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9516 unsigned char **));
9517
9518
9519/* Indices of image specification fields in xbm_format, below. */
9520
9521enum xbm_keyword_index
9522{
9523 XBM_TYPE,
9524 XBM_FILE,
9525 XBM_WIDTH,
9526 XBM_HEIGHT,
9527 XBM_DATA,
9528 XBM_FOREGROUND,
9529 XBM_BACKGROUND,
9530 XBM_ASCENT,
9531 XBM_MARGIN,
9532 XBM_RELIEF,
9533 XBM_ALGORITHM,
9534 XBM_HEURISTIC_MASK,
a05e2bae 9535 XBM_MASK,
6fc2811b
JR
9536 XBM_LAST
9537};
9538
9539/* Vector of image_keyword structures describing the format
9540 of valid XBM image specifications. */
9541
9542static struct image_keyword xbm_format[XBM_LAST] =
9543{
9544 {":type", IMAGE_SYMBOL_VALUE, 1},
9545 {":file", IMAGE_STRING_VALUE, 0},
9546 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9547 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9548 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
9549 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9550 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6fc2811b 9551 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9552 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9553 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9554 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
9555 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9556};
9557
9558/* Structure describing the image type XBM. */
9559
9560static struct image_type xbm_type =
9561{
9562 &Qxbm,
9563 xbm_image_p,
9564 xbm_load,
9565 x_clear_image,
9566 NULL
9567};
9568
9569/* Tokens returned from xbm_scan. */
9570
9571enum xbm_token
9572{
9573 XBM_TK_IDENT = 256,
9574 XBM_TK_NUMBER
9575};
9576
9577
9578/* Return non-zero if OBJECT is a valid XBM-type image specification.
9579 A valid specification is a list starting with the symbol `image'
9580 The rest of the list is a property list which must contain an
9581 entry `:type xbm..
9582
9583 If the specification specifies a file to load, it must contain
9584 an entry `:file FILENAME' where FILENAME is a string.
9585
9586 If the specification is for a bitmap loaded from memory it must
9587 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9588 WIDTH and HEIGHT are integers > 0. DATA may be:
9589
9590 1. a string large enough to hold the bitmap data, i.e. it must
9591 have a size >= (WIDTH + 7) / 8 * HEIGHT
9592
9593 2. a bool-vector of size >= WIDTH * HEIGHT
9594
9595 3. a vector of strings or bool-vectors, one for each line of the
9596 bitmap.
9597
9598 Both the file and data forms may contain the additional entries
9599 `:background COLOR' and `:foreground COLOR'. If not present,
9600 foreground and background of the frame on which the image is
9601 displayed, is used. */
9602
9603static int
9604xbm_image_p (object)
9605 Lisp_Object object;
9606{
9607 struct image_keyword kw[XBM_LAST];
9608
9609 bcopy (xbm_format, kw, sizeof kw);
9610 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9611 return 0;
9612
9613 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9614
9615 if (kw[XBM_FILE].count)
9616 {
9617 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9618 return 0;
9619 }
9620 else
9621 {
9622 Lisp_Object data;
9623 int width, height;
9624
9625 /* Entries for `:width', `:height' and `:data' must be present. */
9626 if (!kw[XBM_WIDTH].count
9627 || !kw[XBM_HEIGHT].count
9628 || !kw[XBM_DATA].count)
9629 return 0;
9630
9631 data = kw[XBM_DATA].value;
9632 width = XFASTINT (kw[XBM_WIDTH].value);
9633 height = XFASTINT (kw[XBM_HEIGHT].value);
9634
9635 /* Check type of data, and width and height against contents of
9636 data. */
9637 if (VECTORP (data))
9638 {
9639 int i;
9640
9641 /* Number of elements of the vector must be >= height. */
9642 if (XVECTOR (data)->size < height)
9643 return 0;
9644
9645 /* Each string or bool-vector in data must be large enough
9646 for one line of the image. */
9647 for (i = 0; i < height; ++i)
9648 {
9649 Lisp_Object elt = XVECTOR (data)->contents[i];
9650
9651 if (STRINGP (elt))
9652 {
9653 if (XSTRING (elt)->size
9654 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9655 return 0;
9656 }
9657 else if (BOOL_VECTOR_P (elt))
9658 {
9659 if (XBOOL_VECTOR (elt)->size < width)
9660 return 0;
9661 }
9662 else
9663 return 0;
9664 }
9665 }
9666 else if (STRINGP (data))
9667 {
9668 if (XSTRING (data)->size
9669 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9670 return 0;
9671 }
9672 else if (BOOL_VECTOR_P (data))
9673 {
9674 if (XBOOL_VECTOR (data)->size < width * height)
9675 return 0;
9676 }
9677 else
9678 return 0;
9679 }
9680
9681 /* Baseline must be a value between 0 and 100 (a percentage). */
9682 if (kw[XBM_ASCENT].count
9683 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9684 return 0;
9685
9686 return 1;
9687}
9688
9689
9690/* Scan a bitmap file. FP is the stream to read from. Value is
9691 either an enumerator from enum xbm_token, or a character for a
9692 single-character token, or 0 at end of file. If scanning an
9693 identifier, store the lexeme of the identifier in SVAL. If
9694 scanning a number, store its value in *IVAL. */
9695
9696static int
3cf3436e
JR
9697xbm_scan (s, end, sval, ival)
9698 char **s, *end;
6fc2811b
JR
9699 char *sval;
9700 int *ival;
9701{
9702 int c;
3cf3436e
JR
9703
9704 loop:
9705
6fc2811b 9706 /* Skip white space. */
3cf3436e 9707 while (*s < end &&(c = *(*s)++, isspace (c)))
6fc2811b
JR
9708 ;
9709
3cf3436e 9710 if (*s >= end)
6fc2811b
JR
9711 c = 0;
9712 else if (isdigit (c))
9713 {
9714 int value = 0, digit;
9715
3cf3436e 9716 if (c == '0' && *s < end)
6fc2811b 9717 {
3cf3436e 9718 c = *(*s)++;
6fc2811b
JR
9719 if (c == 'x' || c == 'X')
9720 {
3cf3436e 9721 while (*s < end)
6fc2811b 9722 {
3cf3436e 9723 c = *(*s)++;
6fc2811b
JR
9724 if (isdigit (c))
9725 digit = c - '0';
9726 else if (c >= 'a' && c <= 'f')
9727 digit = c - 'a' + 10;
9728 else if (c >= 'A' && c <= 'F')
9729 digit = c - 'A' + 10;
9730 else
9731 break;
9732 value = 16 * value + digit;
9733 }
9734 }
9735 else if (isdigit (c))
9736 {
9737 value = c - '0';
3cf3436e
JR
9738 while (*s < end
9739 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9740 value = 8 * value + c - '0';
9741 }
9742 }
9743 else
9744 {
9745 value = c - '0';
3cf3436e
JR
9746 while (*s < end
9747 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9748 value = 10 * value + c - '0';
9749 }
9750
3cf3436e
JR
9751 if (*s < end)
9752 *s = *s - 1;
6fc2811b
JR
9753 *ival = value;
9754 c = XBM_TK_NUMBER;
9755 }
9756 else if (isalpha (c) || c == '_')
9757 {
9758 *sval++ = c;
3cf3436e
JR
9759 while (*s < end
9760 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9761 *sval++ = c;
9762 *sval = 0;
3cf3436e
JR
9763 if (*s < end)
9764 *s = *s - 1;
6fc2811b
JR
9765 c = XBM_TK_IDENT;
9766 }
3cf3436e
JR
9767 else if (c == '/' && **s == '*')
9768 {
9769 /* C-style comment. */
9770 ++*s;
9771 while (**s && (**s != '*' || *(*s + 1) != '/'))
9772 ++*s;
9773 if (**s)
9774 {
9775 *s += 2;
9776 goto loop;
9777 }
9778 }
6fc2811b
JR
9779
9780 return c;
9781}
9782
9783
9784/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9785 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9786 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9787 the image. Return in *DATA the bitmap data allocated with xmalloc.
9788 Value is non-zero if successful. DATA null means just test if
9789 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9790
9791static int
3cf3436e
JR
9792xbm_read_bitmap_data (contents, end, width, height, data)
9793 char *contents, *end;
6fc2811b
JR
9794 int *width, *height;
9795 unsigned char **data;
9796{
3cf3436e 9797 char *s = contents;
6fc2811b
JR
9798 char buffer[BUFSIZ];
9799 int padding_p = 0;
9800 int v10 = 0;
9801 int bytes_per_line, i, nbytes;
9802 unsigned char *p;
9803 int value;
9804 int LA1;
9805
9806#define match() \
3cf3436e 9807 LA1 = xbm_scan (contents, end, buffer, &value)
6fc2811b
JR
9808
9809#define expect(TOKEN) \
9810 if (LA1 != (TOKEN)) \
9811 goto failure; \
9812 else \
9813 match ()
9814
9815#define expect_ident(IDENT) \
9816 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9817 match (); \
9818 else \
9819 goto failure
9820
6fc2811b 9821 *width = *height = -1;
3cf3436e
JR
9822 if (data)
9823 *data = NULL;
9824 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9825
9826 /* Parse defines for width, height and hot-spots. */
9827 while (LA1 == '#')
9828 {
9829 match ();
9830 expect_ident ("define");
9831 expect (XBM_TK_IDENT);
9832
9833 if (LA1 == XBM_TK_NUMBER);
9834 {
9835 char *p = strrchr (buffer, '_');
9836 p = p ? p + 1 : buffer;
9837 if (strcmp (p, "width") == 0)
9838 *width = value;
9839 else if (strcmp (p, "height") == 0)
9840 *height = value;
9841 }
9842 expect (XBM_TK_NUMBER);
9843 }
9844
9845 if (*width < 0 || *height < 0)
9846 goto failure;
3cf3436e
JR
9847 else if (data == NULL)
9848 goto success;
6fc2811b
JR
9849
9850 /* Parse bits. Must start with `static'. */
9851 expect_ident ("static");
9852 if (LA1 == XBM_TK_IDENT)
9853 {
9854 if (strcmp (buffer, "unsigned") == 0)
9855 {
9856 match ();
9857 expect_ident ("char");
9858 }
9859 else if (strcmp (buffer, "short") == 0)
9860 {
9861 match ();
9862 v10 = 1;
9863 if (*width % 16 && *width % 16 < 9)
9864 padding_p = 1;
9865 }
9866 else if (strcmp (buffer, "char") == 0)
9867 match ();
9868 else
9869 goto failure;
9870 }
9871 else
9872 goto failure;
9873
9874 expect (XBM_TK_IDENT);
9875 expect ('[');
9876 expect (']');
9877 expect ('=');
9878 expect ('{');
9879
9880 bytes_per_line = (*width + 7) / 8 + padding_p;
9881 nbytes = bytes_per_line * *height;
9882 p = *data = (char *) xmalloc (nbytes);
9883
9884 if (v10)
9885 {
9886
9887 for (i = 0; i < nbytes; i += 2)
9888 {
9889 int val = value;
9890 expect (XBM_TK_NUMBER);
9891
9892 *p++ = val;
9893 if (!padding_p || ((i + 2) % bytes_per_line))
9894 *p++ = value >> 8;
9895
9896 if (LA1 == ',' || LA1 == '}')
9897 match ();
9898 else
9899 goto failure;
9900 }
9901 }
9902 else
9903 {
9904 for (i = 0; i < nbytes; ++i)
9905 {
9906 int val = value;
9907 expect (XBM_TK_NUMBER);
9908
9909 *p++ = val;
9910
9911 if (LA1 == ',' || LA1 == '}')
9912 match ();
9913 else
9914 goto failure;
9915 }
9916 }
9917
3cf3436e 9918 success:
6fc2811b
JR
9919 return 1;
9920
9921 failure:
3cf3436e
JR
9922
9923 if (data && *data)
6fc2811b
JR
9924 {
9925 xfree (*data);
9926 *data = NULL;
9927 }
9928 return 0;
9929
9930#undef match
9931#undef expect
9932#undef expect_ident
9933}
9934
9935
3cf3436e
JR
9936/* Load XBM image IMG which will be displayed on frame F from buffer
9937 CONTENTS. END is the end of the buffer. Value is non-zero if
9938 successful. */
6fc2811b
JR
9939
9940static int
3cf3436e 9941xbm_load_image (f, img, contents, end)
6fc2811b
JR
9942 struct frame *f;
9943 struct image *img;
3cf3436e 9944 char *contents, *end;
6fc2811b
JR
9945{
9946 int rc;
9947 unsigned char *data;
9948 int success_p = 0;
6fc2811b 9949
3cf3436e 9950 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
9951 if (rc)
9952 {
9953 int depth = one_w32_display_info.n_cbits;
ac849ba4
JR
9954 int planes = one_w32_display_info.n_planes;
9955
6fc2811b
JR
9956 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9957 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9958 Lisp_Object value;
9959
9960 xassert (img->width > 0 && img->height > 0);
9961
9962 /* Get foreground and background colors, maybe allocate colors. */
9963 value = image_spec_value (img->spec, QCforeground, NULL);
9964 if (!NILP (value))
9965 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
9966 value = image_spec_value (img->spec, QCbackground, NULL);
9967 if (!NILP (value))
a05e2bae
JR
9968 {
9969 background = x_alloc_image_color (f, img, value, background);
9970 img->background = background;
9971 img->background_valid = 1;
9972 }
6fc2811b 9973 img->pixmap
ac849ba4
JR
9974 = CreateBitmap (img->width, img->height, planes, depth, data);
9975
6fc2811b
JR
9976 xfree (data);
9977
9978 if (img->pixmap == 0)
9979 {
9980 x_clear_image (f, img);
3cf3436e 9981 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
9982 }
9983 else
9984 success_p = 1;
6fc2811b
JR
9985 }
9986 else
9987 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9988
6fc2811b
JR
9989 return success_p;
9990}
9991
9992
3cf3436e
JR
9993/* Value is non-zero if DATA looks like an in-memory XBM file. */
9994
9995static int
9996xbm_file_p (data)
9997 Lisp_Object data;
9998{
9999 int w, h;
10000 return (STRINGP (data)
10001 && xbm_read_bitmap_data (XSTRING (data)->data,
10002 (XSTRING (data)->data
10003 + STRING_BYTES (XSTRING (data))),
10004 &w, &h, NULL));
10005}
10006
10007
6fc2811b
JR
10008/* Fill image IMG which is used on frame F with pixmap data. Value is
10009 non-zero if successful. */
10010
10011static int
10012xbm_load (f, img)
10013 struct frame *f;
10014 struct image *img;
10015{
10016 int success_p = 0;
10017 Lisp_Object file_name;
10018
10019 xassert (xbm_image_p (img->spec));
10020
10021 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10022 file_name = image_spec_value (img->spec, QCfile, NULL);
10023 if (STRINGP (file_name))
3cf3436e
JR
10024 {
10025 Lisp_Object file;
10026 char *contents;
10027 int size;
10028 struct gcpro gcpro1;
10029
10030 file = x_find_image_file (file_name);
10031 GCPRO1 (file);
10032 if (!STRINGP (file))
10033 {
10034 image_error ("Cannot find image file `%s'", file_name, Qnil);
10035 UNGCPRO;
10036 return 0;
10037 }
10038
10039 contents = slurp_file (XSTRING (file)->data, &size);
10040 if (contents == NULL)
10041 {
10042 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10043 UNGCPRO;
10044 return 0;
10045 }
10046
10047 success_p = xbm_load_image (f, img, contents, contents + size);
10048 UNGCPRO;
10049 }
6fc2811b
JR
10050 else
10051 {
10052 struct image_keyword fmt[XBM_LAST];
10053 Lisp_Object data;
10054 int depth;
10055 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10056 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10057 char *bits;
10058 int parsed_p;
3cf3436e
JR
10059 int in_memory_file_p = 0;
10060
10061 /* See if data looks like an in-memory XBM file. */
10062 data = image_spec_value (img->spec, QCdata, NULL);
10063 in_memory_file_p = xbm_file_p (data);
6fc2811b
JR
10064
10065 /* Parse the list specification. */
10066 bcopy (xbm_format, fmt, sizeof fmt);
10067 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10068 xassert (parsed_p);
10069
10070 /* Get specified width, and height. */
3cf3436e
JR
10071 if (!in_memory_file_p)
10072 {
10073 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10074 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10075 xassert (img->width > 0 && img->height > 0);
10076 }
6fc2811b 10077 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
10078 if (fmt[XBM_FOREGROUND].count
10079 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
10080 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10081 foreground);
3cf3436e
JR
10082 if (fmt[XBM_BACKGROUND].count
10083 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
10084 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10085 background);
10086
3cf3436e
JR
10087 if (in_memory_file_p)
10088 success_p = xbm_load_image (f, img, XSTRING (data)->data,
10089 (XSTRING (data)->data
10090 + STRING_BYTES (XSTRING (data))));
10091 else
6fc2811b 10092 {
3cf3436e
JR
10093 if (VECTORP (data))
10094 {
10095 int i;
10096 char *p;
10097 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 10098
3cf3436e
JR
10099 p = bits = (char *) alloca (nbytes * img->height);
10100 for (i = 0; i < img->height; ++i, p += nbytes)
10101 {
10102 Lisp_Object line = XVECTOR (data)->contents[i];
10103 if (STRINGP (line))
10104 bcopy (XSTRING (line)->data, p, nbytes);
10105 else
10106 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10107 }
10108 }
10109 else if (STRINGP (data))
10110 bits = XSTRING (data)->data;
10111 else
10112 bits = XBOOL_VECTOR (data)->data;
10113#ifdef TODO /* image support. */
10114 /* Create the pixmap. */
a05e2bae 10115 depth = one_w32_display_info.n_cbits;
3cf3436e
JR
10116 img->pixmap
10117 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
10118 FRAME_X_WINDOW (f),
10119 bits,
10120 img->width, img->height,
10121 foreground, background,
10122 depth);
10123#endif
10124 if (img->pixmap)
10125 success_p = 1;
10126 else
6fc2811b 10127 {
3cf3436e
JR
10128 image_error ("Unable to create pixmap for XBM image `%s'",
10129 img->spec, Qnil);
10130 x_clear_image (f, img);
6fc2811b
JR
10131 }
10132 }
6fc2811b
JR
10133 }
10134
10135 return success_p;
10136}
10137
10138
10139\f
10140/***********************************************************************
10141 XPM images
10142 ***********************************************************************/
10143
10144#if HAVE_XPM
10145
10146static int xpm_image_p P_ ((Lisp_Object object));
10147static int xpm_load P_ ((struct frame *f, struct image *img));
10148static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10149
10150#include "X11/xpm.h"
10151
10152/* The symbol `xpm' identifying XPM-format images. */
10153
10154Lisp_Object Qxpm;
10155
10156/* Indices of image specification fields in xpm_format, below. */
10157
10158enum xpm_keyword_index
10159{
10160 XPM_TYPE,
10161 XPM_FILE,
10162 XPM_DATA,
10163 XPM_ASCENT,
10164 XPM_MARGIN,
10165 XPM_RELIEF,
10166 XPM_ALGORITHM,
10167 XPM_HEURISTIC_MASK,
a05e2bae 10168 XPM_MASK,
6fc2811b 10169 XPM_COLOR_SYMBOLS,
a05e2bae 10170 XPM_BACKGROUND,
6fc2811b
JR
10171 XPM_LAST
10172};
10173
10174/* Vector of image_keyword structures describing the format
10175 of valid XPM image specifications. */
10176
10177static struct image_keyword xpm_format[XPM_LAST] =
10178{
10179 {":type", IMAGE_SYMBOL_VALUE, 1},
10180 {":file", IMAGE_STRING_VALUE, 0},
10181 {":data", IMAGE_STRING_VALUE, 0},
10182 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10183 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10184 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10185 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 10186 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10187 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10188 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10189 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10190};
10191
10192/* Structure describing the image type XBM. */
10193
10194static struct image_type xpm_type =
10195{
10196 &Qxpm,
10197 xpm_image_p,
10198 xpm_load,
10199 x_clear_image,
10200 NULL
10201};
10202
10203
10204/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10205 for XPM images. Such a list must consist of conses whose car and
10206 cdr are strings. */
10207
10208static int
10209xpm_valid_color_symbols_p (color_symbols)
10210 Lisp_Object color_symbols;
10211{
10212 while (CONSP (color_symbols))
10213 {
10214 Lisp_Object sym = XCAR (color_symbols);
10215 if (!CONSP (sym)
10216 || !STRINGP (XCAR (sym))
10217 || !STRINGP (XCDR (sym)))
10218 break;
10219 color_symbols = XCDR (color_symbols);
10220 }
10221
10222 return NILP (color_symbols);
10223}
10224
10225
10226/* Value is non-zero if OBJECT is a valid XPM image specification. */
10227
10228static int
10229xpm_image_p (object)
10230 Lisp_Object object;
10231{
10232 struct image_keyword fmt[XPM_LAST];
10233 bcopy (xpm_format, fmt, sizeof fmt);
10234 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10235 /* Either `:file' or `:data' must be present. */
10236 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10237 /* Either no `:color-symbols' or it's a list of conses
10238 whose car and cdr are strings. */
10239 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10240 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10241 && (fmt[XPM_ASCENT].count == 0
10242 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10243}
10244
10245
10246/* Load image IMG which will be displayed on frame F. Value is
10247 non-zero if successful. */
10248
10249static int
10250xpm_load (f, img)
10251 struct frame *f;
10252 struct image *img;
10253{
10254 int rc, i;
10255 XpmAttributes attrs;
10256 Lisp_Object specified_file, color_symbols;
10257
10258 /* Configure the XPM lib. Use the visual of frame F. Allocate
10259 close colors. Return colors allocated. */
10260 bzero (&attrs, sizeof attrs);
dfff8a69
JR
10261 attrs.visual = FRAME_X_VISUAL (f);
10262 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 10263 attrs.valuemask |= XpmVisual;
dfff8a69 10264 attrs.valuemask |= XpmColormap;
6fc2811b 10265 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 10266#ifdef XpmAllocCloseColors
6fc2811b
JR
10267 attrs.alloc_close_colors = 1;
10268 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
10269#else
10270 attrs.closeness = 600;
10271 attrs.valuemask |= XpmCloseness;
10272#endif
6fc2811b
JR
10273
10274 /* If image specification contains symbolic color definitions, add
10275 these to `attrs'. */
10276 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10277 if (CONSP (color_symbols))
10278 {
10279 Lisp_Object tail;
10280 XpmColorSymbol *xpm_syms;
10281 int i, size;
10282
10283 attrs.valuemask |= XpmColorSymbols;
10284
10285 /* Count number of symbols. */
10286 attrs.numsymbols = 0;
10287 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10288 ++attrs.numsymbols;
10289
10290 /* Allocate an XpmColorSymbol array. */
10291 size = attrs.numsymbols * sizeof *xpm_syms;
10292 xpm_syms = (XpmColorSymbol *) alloca (size);
10293 bzero (xpm_syms, size);
10294 attrs.colorsymbols = xpm_syms;
10295
10296 /* Fill the color symbol array. */
10297 for (tail = color_symbols, i = 0;
10298 CONSP (tail);
10299 ++i, tail = XCDR (tail))
10300 {
10301 Lisp_Object name = XCAR (XCAR (tail));
10302 Lisp_Object color = XCDR (XCAR (tail));
10303 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10304 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10305 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10306 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10307 }
10308 }
10309
10310 /* Create a pixmap for the image, either from a file, or from a
10311 string buffer containing data in the same format as an XPM file. */
10312 BLOCK_INPUT;
10313 specified_file = image_spec_value (img->spec, QCfile, NULL);
10314 if (STRINGP (specified_file))
10315 {
10316 Lisp_Object file = x_find_image_file (specified_file);
10317 if (!STRINGP (file))
10318 {
10319 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10320 UNBLOCK_INPUT;
10321 return 0;
10322 }
10323
10324 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10325 XSTRING (file)->data, &img->pixmap, &img->mask,
10326 &attrs);
10327 }
10328 else
10329 {
10330 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10331 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10332 XSTRING (buffer)->data,
10333 &img->pixmap, &img->mask,
10334 &attrs);
10335 }
10336 UNBLOCK_INPUT;
10337
10338 if (rc == XpmSuccess)
10339 {
10340 /* Remember allocated colors. */
10341 img->ncolors = attrs.nalloc_pixels;
10342 img->colors = (unsigned long *) xmalloc (img->ncolors
10343 * sizeof *img->colors);
10344 for (i = 0; i < attrs.nalloc_pixels; ++i)
10345 img->colors[i] = attrs.alloc_pixels[i];
10346
10347 img->width = attrs.width;
10348 img->height = attrs.height;
10349 xassert (img->width > 0 && img->height > 0);
10350
10351 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10352 BLOCK_INPUT;
10353 XpmFreeAttributes (&attrs);
10354 UNBLOCK_INPUT;
10355 }
10356 else
10357 {
10358 switch (rc)
10359 {
10360 case XpmOpenFailed:
10361 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10362 break;
10363
10364 case XpmFileInvalid:
10365 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10366 break;
10367
10368 case XpmNoMemory:
10369 image_error ("Out of memory (%s)", img->spec, Qnil);
10370 break;
10371
10372 case XpmColorFailed:
10373 image_error ("Color allocation error (%s)", img->spec, Qnil);
10374 break;
10375
10376 default:
10377 image_error ("Unknown error (%s)", img->spec, Qnil);
10378 break;
10379 }
10380 }
10381
10382 return rc == XpmSuccess;
10383}
10384
10385#endif /* HAVE_XPM != 0 */
10386
10387\f
767b1ff0 10388#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
10389/***********************************************************************
10390 Color table
10391 ***********************************************************************/
10392
10393/* An entry in the color table mapping an RGB color to a pixel color. */
10394
10395struct ct_color
10396{
10397 int r, g, b;
10398 unsigned long pixel;
10399
10400 /* Next in color table collision list. */
10401 struct ct_color *next;
10402};
10403
10404/* The bucket vector size to use. Must be prime. */
10405
10406#define CT_SIZE 101
10407
10408/* Value is a hash of the RGB color given by R, G, and B. */
10409
10410#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10411
10412/* The color hash table. */
10413
10414struct ct_color **ct_table;
10415
10416/* Number of entries in the color table. */
10417
10418int ct_colors_allocated;
10419
10420/* Function prototypes. */
10421
10422static void init_color_table P_ ((void));
10423static void free_color_table P_ ((void));
10424static unsigned long *colors_in_color_table P_ ((int *n));
10425static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10426static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10427
10428
10429/* Initialize the color table. */
10430
10431static void
10432init_color_table ()
10433{
10434 int size = CT_SIZE * sizeof (*ct_table);
10435 ct_table = (struct ct_color **) xmalloc (size);
10436 bzero (ct_table, size);
10437 ct_colors_allocated = 0;
10438}
10439
10440
10441/* Free memory associated with the color table. */
10442
10443static void
10444free_color_table ()
10445{
10446 int i;
10447 struct ct_color *p, *next;
10448
10449 for (i = 0; i < CT_SIZE; ++i)
10450 for (p = ct_table[i]; p; p = next)
10451 {
10452 next = p->next;
10453 xfree (p);
10454 }
10455
10456 xfree (ct_table);
10457 ct_table = NULL;
10458}
10459
10460
10461/* Value is a pixel color for RGB color R, G, B on frame F. If an
10462 entry for that color already is in the color table, return the
10463 pixel color of that entry. Otherwise, allocate a new color for R,
10464 G, B, and make an entry in the color table. */
10465
10466static unsigned long
10467lookup_rgb_color (f, r, g, b)
10468 struct frame *f;
10469 int r, g, b;
10470{
10471 unsigned hash = CT_HASH_RGB (r, g, b);
10472 int i = hash % CT_SIZE;
10473 struct ct_color *p;
10474
10475 for (p = ct_table[i]; p; p = p->next)
10476 if (p->r == r && p->g == g && p->b == b)
10477 break;
10478
10479 if (p == NULL)
10480 {
10481 COLORREF color;
10482 Colormap cmap;
10483 int rc;
10484
10485 color = PALETTERGB (r, g, b);
10486
10487 ++ct_colors_allocated;
10488
10489 p = (struct ct_color *) xmalloc (sizeof *p);
10490 p->r = r;
10491 p->g = g;
10492 p->b = b;
10493 p->pixel = color;
10494 p->next = ct_table[i];
10495 ct_table[i] = p;
10496 }
10497
10498 return p->pixel;
10499}
10500
10501
10502/* Look up pixel color PIXEL which is used on frame F in the color
10503 table. If not already present, allocate it. Value is PIXEL. */
10504
10505static unsigned long
10506lookup_pixel_color (f, pixel)
10507 struct frame *f;
10508 unsigned long pixel;
10509{
10510 int i = pixel % CT_SIZE;
10511 struct ct_color *p;
10512
10513 for (p = ct_table[i]; p; p = p->next)
10514 if (p->pixel == pixel)
10515 break;
10516
10517 if (p == NULL)
10518 {
10519 XColor color;
10520 Colormap cmap;
10521 int rc;
10522
10523 BLOCK_INPUT;
10524
10525 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10526 color.pixel = pixel;
10527 XQueryColor (NULL, cmap, &color);
10528 rc = x_alloc_nearest_color (f, cmap, &color);
10529 UNBLOCK_INPUT;
10530
10531 if (rc)
10532 {
10533 ++ct_colors_allocated;
10534
10535 p = (struct ct_color *) xmalloc (sizeof *p);
10536 p->r = color.red;
10537 p->g = color.green;
10538 p->b = color.blue;
10539 p->pixel = pixel;
10540 p->next = ct_table[i];
10541 ct_table[i] = p;
10542 }
10543 else
10544 return FRAME_FOREGROUND_PIXEL (f);
10545 }
10546 return p->pixel;
10547}
10548
10549
10550/* Value is a vector of all pixel colors contained in the color table,
10551 allocated via xmalloc. Set *N to the number of colors. */
10552
10553static unsigned long *
10554colors_in_color_table (n)
10555 int *n;
10556{
10557 int i, j;
10558 struct ct_color *p;
10559 unsigned long *colors;
10560
10561 if (ct_colors_allocated == 0)
10562 {
10563 *n = 0;
10564 colors = NULL;
10565 }
10566 else
10567 {
10568 colors = (unsigned long *) xmalloc (ct_colors_allocated
10569 * sizeof *colors);
10570 *n = ct_colors_allocated;
10571
10572 for (i = j = 0; i < CT_SIZE; ++i)
10573 for (p = ct_table[i]; p; p = p->next)
10574 colors[j++] = p->pixel;
10575 }
10576
10577 return colors;
10578}
10579
767b1ff0 10580#endif /* TODO */
6fc2811b
JR
10581
10582\f
ac849ba4 10583#ifdef HAVE_IMAGES /* TODO */
6fc2811b
JR
10584/***********************************************************************
10585 Algorithms
10586 ***********************************************************************/
3cf3436e
JR
10587static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10588static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10589static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
ac849ba4 10590static void XPutPixel (XImage *, int, int, COLORREF);
3cf3436e
JR
10591
10592/* Non-zero means draw a cross on images having `:conversion
10593 disabled'. */
6fc2811b 10594
3cf3436e 10595int cross_disabled_images;
6fc2811b 10596
3cf3436e
JR
10597/* Edge detection matrices for different edge-detection
10598 strategies. */
6fc2811b 10599
3cf3436e
JR
10600static int emboss_matrix[9] = {
10601 /* x - 1 x x + 1 */
10602 2, -1, 0, /* y - 1 */
10603 -1, 0, 1, /* y */
10604 0, 1, -2 /* y + 1 */
10605};
10606
10607static int laplace_matrix[9] = {
10608 /* x - 1 x x + 1 */
10609 1, 0, 0, /* y - 1 */
10610 0, 0, 0, /* y */
10611 0, 0, -1 /* y + 1 */
10612};
10613
10614/* Value is the intensity of the color whose red/green/blue values
10615 are R, G, and B. */
10616
10617#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10618
10619
10620/* On frame F, return an array of XColor structures describing image
10621 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10622 non-zero means also fill the red/green/blue members of the XColor
10623 structures. Value is a pointer to the array of XColors structures,
10624 allocated with xmalloc; it must be freed by the caller. */
10625
10626static XColor *
10627x_to_xcolors (f, img, rgb_p)
10628 struct frame *f;
10629 struct image *img;
10630 int rgb_p;
10631{
10632 int x, y;
10633 XColor *colors, *p;
10634 XImage *ximg;
10635
10636 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
ac849ba4 10637#if 0 /* TODO: implement image colors. */
3cf3436e
JR
10638 /* Get the X image IMG->pixmap. */
10639 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10640 0, 0, img->width, img->height, ~0, ZPixmap);
10641
10642 /* Fill the `pixel' members of the XColor array. I wished there
10643 were an easy and portable way to circumvent XGetPixel. */
10644 p = colors;
10645 for (y = 0; y < img->height; ++y)
10646 {
10647 XColor *row = p;
10648
10649 for (x = 0; x < img->width; ++x, ++p)
10650 p->pixel = XGetPixel (ximg, x, y);
10651
10652 if (rgb_p)
10653 x_query_colors (f, row, img->width);
10654 }
10655
10656 XDestroyImage (ximg);
ac849ba4 10657#endif
3cf3436e
JR
10658 return colors;
10659}
10660
ac849ba4
JR
10661/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10662 created with CreateDIBSection, with the pointer to the bit values
10663 stored in ximg->data. */
10664
10665static void XPutPixel (ximg, x, y, color)
10666 XImage * ximg;
10667 int x, y;
10668 COLORREF color;
10669{
10670 int width = ximg->info.bmiHeader.biWidth;
10671 int height = ximg->info.bmiHeader.biHeight;
10672 int rowbytes = width * 3;
10673 unsigned char * pixel;
10674
10675 /* Don't support putting pixels in images with palettes. */
10676 xassert (ximg->info.bmiHeader.biBitCount == 24);
10677
10678 /* Ensure scanlines are aligned on 4 byte boundaries. */
10679 if (rowbytes % 4)
10680 rowbytes += 4 - (rowbytes % 4);
10681
10682 pixel = ximg->data + y * rowbytes + x * 3;
10683 *pixel = 255 - GetRValue (color);
10684 *(pixel + 1) = 255 - GetGValue (color);
10685 *(pixel + 2) = 255 - GetBValue (color);
10686}
10687
3cf3436e
JR
10688
10689/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10690 RGB members are set. F is the frame on which this all happens.
10691 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10692
10693static void
3cf3436e 10694x_from_xcolors (f, img, colors)
6fc2811b 10695 struct frame *f;
3cf3436e 10696 struct image *img;
6fc2811b 10697 XColor *colors;
6fc2811b 10698{
3cf3436e
JR
10699 int x, y;
10700 XImage *oimg;
10701 Pixmap pixmap;
10702 XColor *p;
ac849ba4 10703#if 0 /* TODO: color tables. */
3cf3436e 10704 init_color_table ();
ac849ba4 10705#endif
3cf3436e
JR
10706 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10707 &oimg, &pixmap);
10708 p = colors;
10709 for (y = 0; y < img->height; ++y)
10710 for (x = 0; x < img->width; ++x, ++p)
10711 {
10712 unsigned long pixel;
ac849ba4 10713#if 0 /* TODO: color tables. */
3cf3436e 10714 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
ac849ba4
JR
10715#else
10716 pixel = PALETTERGB (p->red, p->green, p->blue);
10717#endif
3cf3436e
JR
10718 XPutPixel (oimg, x, y, pixel);
10719 }
6fc2811b 10720
3cf3436e
JR
10721 xfree (colors);
10722 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10723
3cf3436e
JR
10724 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10725 x_destroy_x_image (oimg);
10726 img->pixmap = pixmap;
ac849ba4 10727#if 0 /* TODO: color tables. */
3cf3436e
JR
10728 img->colors = colors_in_color_table (&img->ncolors);
10729 free_color_table ();
ac849ba4 10730#endif
6fc2811b
JR
10731}
10732
10733
3cf3436e
JR
10734/* On frame F, perform edge-detection on image IMG.
10735
10736 MATRIX is a nine-element array specifying the transformation
10737 matrix. See emboss_matrix for an example.
10738
10739 COLOR_ADJUST is a color adjustment added to each pixel of the
10740 outgoing image. */
6fc2811b
JR
10741
10742static void
3cf3436e 10743x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10744 struct frame *f;
3cf3436e
JR
10745 struct image *img;
10746 int matrix[9], color_adjust;
6fc2811b 10747{
3cf3436e
JR
10748 XColor *colors = x_to_xcolors (f, img, 1);
10749 XColor *new, *p;
10750 int x, y, i, sum;
10751
10752 for (i = sum = 0; i < 9; ++i)
10753 sum += abs (matrix[i]);
10754
10755#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10756
10757 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10758
10759 for (y = 0; y < img->height; ++y)
10760 {
10761 p = COLOR (new, 0, y);
10762 p->red = p->green = p->blue = 0xffff/2;
10763 p = COLOR (new, img->width - 1, y);
10764 p->red = p->green = p->blue = 0xffff/2;
10765 }
6fc2811b 10766
3cf3436e
JR
10767 for (x = 1; x < img->width - 1; ++x)
10768 {
10769 p = COLOR (new, x, 0);
10770 p->red = p->green = p->blue = 0xffff/2;
10771 p = COLOR (new, x, img->height - 1);
10772 p->red = p->green = p->blue = 0xffff/2;
10773 }
10774
10775 for (y = 1; y < img->height - 1; ++y)
10776 {
10777 p = COLOR (new, 1, y);
10778
10779 for (x = 1; x < img->width - 1; ++x, ++p)
10780 {
10781 int r, g, b, y1, x1;
10782
10783 r = g = b = i = 0;
10784 for (y1 = y - 1; y1 < y + 2; ++y1)
10785 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10786 if (matrix[i])
10787 {
10788 XColor *t = COLOR (colors, x1, y1);
10789 r += matrix[i] * t->red;
10790 g += matrix[i] * t->green;
10791 b += matrix[i] * t->blue;
10792 }
10793
10794 r = (r / sum + color_adjust) & 0xffff;
10795 g = (g / sum + color_adjust) & 0xffff;
10796 b = (b / sum + color_adjust) & 0xffff;
10797 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10798 }
10799 }
10800
10801 xfree (colors);
10802 x_from_xcolors (f, img, new);
10803
10804#undef COLOR
10805}
10806
10807
10808/* Perform the pre-defined `emboss' edge-detection on image IMG
10809 on frame F. */
10810
10811static void
10812x_emboss (f, img)
10813 struct frame *f;
10814 struct image *img;
10815{
10816 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10817}
3cf3436e 10818
6fc2811b
JR
10819
10820/* Transform image IMG which is used on frame F with a Laplace
10821 edge-detection algorithm. The result is an image that can be used
10822 to draw disabled buttons, for example. */
10823
10824static void
10825x_laplace (f, img)
10826 struct frame *f;
10827 struct image *img;
10828{
3cf3436e
JR
10829 x_detect_edges (f, img, laplace_matrix, 45000);
10830}
6fc2811b 10831
6fc2811b 10832
3cf3436e
JR
10833/* Perform edge-detection on image IMG on frame F, with specified
10834 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10835
3cf3436e 10836 MATRIX must be either
6fc2811b 10837
3cf3436e
JR
10838 - a list of at least 9 numbers in row-major form
10839 - a vector of at least 9 numbers
6fc2811b 10840
3cf3436e
JR
10841 COLOR_ADJUST nil means use a default; otherwise it must be a
10842 number. */
6fc2811b 10843
3cf3436e
JR
10844static void
10845x_edge_detection (f, img, matrix, color_adjust)
10846 struct frame *f;
10847 struct image *img;
10848 Lisp_Object matrix, color_adjust;
10849{
10850 int i = 0;
10851 int trans[9];
10852
10853 if (CONSP (matrix))
6fc2811b 10854 {
3cf3436e
JR
10855 for (i = 0;
10856 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10857 ++i, matrix = XCDR (matrix))
10858 trans[i] = XFLOATINT (XCAR (matrix));
10859 }
10860 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10861 {
10862 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10863 trans[i] = XFLOATINT (AREF (matrix, i));
10864 }
10865
10866 if (NILP (color_adjust))
10867 color_adjust = make_number (0xffff / 2);
10868
10869 if (i == 9 && NUMBERP (color_adjust))
10870 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10871}
10872
6fc2811b 10873
3cf3436e 10874/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10875
3cf3436e
JR
10876static void
10877x_disable_image (f, img)
10878 struct frame *f;
10879 struct image *img;
10880{
ac849ba4 10881 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3cf3436e 10882
ac849ba4 10883 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
3cf3436e
JR
10884 {
10885 /* Color (or grayscale). Convert to gray, and equalize. Just
10886 drawing such images with a stipple can look very odd, so
10887 we're using this method instead. */
10888 XColor *colors = x_to_xcolors (f, img, 1);
10889 XColor *p, *end;
10890 const int h = 15000;
10891 const int l = 30000;
10892
10893 for (p = colors, end = colors + img->width * img->height;
10894 p < end;
10895 ++p)
6fc2811b 10896 {
3cf3436e
JR
10897 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10898 int i2 = (0xffff - h - l) * i / 0xffff + l;
10899 p->red = p->green = p->blue = i2;
6fc2811b
JR
10900 }
10901
3cf3436e 10902 x_from_xcolors (f, img, colors);
6fc2811b
JR
10903 }
10904
3cf3436e
JR
10905 /* Draw a cross over the disabled image, if we must or if we
10906 should. */
ac849ba4 10907 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
3cf3436e 10908 {
ac849ba4 10909#if 0 /* TODO: full image support */
3cf3436e
JR
10910 Display *dpy = FRAME_X_DISPLAY (f);
10911 GC gc;
6fc2811b 10912
3cf3436e
JR
10913 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10914 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10915 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10916 img->width - 1, img->height - 1);
10917 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10918 img->width - 1, 0);
10919 XFreeGC (dpy, gc);
6fc2811b 10920
3cf3436e
JR
10921 if (img->mask)
10922 {
10923 gc = XCreateGC (dpy, img->mask, 0, NULL);
10924 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10925 XDrawLine (dpy, img->mask, gc, 0, 0,
10926 img->width - 1, img->height - 1);
10927 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10928 img->width - 1, 0);
10929 XFreeGC (dpy, gc);
10930 }
ac849ba4 10931#endif
3cf3436e 10932 }
6fc2811b
JR
10933}
10934
10935
10936/* Build a mask for image IMG which is used on frame F. FILE is the
10937 name of an image file, for error messages. HOW determines how to
10938 determine the background color of IMG. If it is a list '(R G B)',
10939 with R, G, and B being integers >= 0, take that as the color of the
10940 background. Otherwise, determine the background color of IMG
10941 heuristically. Value is non-zero if successful. */
10942
10943static int
10944x_build_heuristic_mask (f, img, how)
10945 struct frame *f;
10946 struct image *img;
10947 Lisp_Object how;
10948{
ac849ba4 10949#if 0 /* TODO: full image support. */
6fc2811b
JR
10950 Display *dpy = FRAME_W32_DISPLAY (f);
10951 XImage *ximg, *mask_img;
a05e2bae
JR
10952 int x, y, rc, use_img_background;
10953 unsigned long bg = 0;
10954
10955 if (img->mask)
10956 {
10957 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10958 img->mask = None;
10959 img->background_transparent_valid = 0;
10960 }
6fc2811b 10961
6fc2811b
JR
10962 /* Create an image and pixmap serving as mask. */
10963 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10964 &mask_img, &img->mask);
10965 if (!rc)
a05e2bae 10966 return 0;
6fc2811b
JR
10967
10968 /* Get the X image of IMG->pixmap. */
10969 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10970 ~0, ZPixmap);
10971
10972 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
10973 take that as color. Otherwise, use the image's background color. */
10974 use_img_background = 1;
6fc2811b
JR
10975
10976 if (CONSP (how))
10977 {
a05e2bae 10978 int rgb[3], i;
6fc2811b 10979
a05e2bae 10980 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
10981 {
10982 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10983 how = XCDR (how);
10984 }
10985
10986 if (i == 3 && NILP (how))
10987 {
10988 char color_name[30];
6fc2811b 10989 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
10990 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10991 use_img_background = 0;
6fc2811b
JR
10992 }
10993 }
10994
a05e2bae
JR
10995 if (use_img_background)
10996 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
10997
10998 /* Set all bits in mask_img to 1 whose color in ximg is different
10999 from the background color bg. */
11000 for (y = 0; y < img->height; ++y)
11001 for (x = 0; x < img->width; ++x)
11002 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
11003
a05e2bae
JR
11004 /* Fill in the background_transparent field while we have the mask handy. */
11005 image_background_transparent (img, f, mask_img);
11006
6fc2811b
JR
11007 /* Put mask_img into img->mask. */
11008 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11009 x_destroy_x_image (mask_img);
11010 XDestroyImage (ximg);
6fc2811b
JR
11011
11012 return 1;
ac849ba4
JR
11013#else
11014 return 0;
11015#endif
6fc2811b 11016}
ac849ba4 11017#endif
6fc2811b
JR
11018\f
11019/***********************************************************************
11020 PBM (mono, gray, color)
11021 ***********************************************************************/
11022#ifdef HAVE_PBM
11023
11024static int pbm_image_p P_ ((Lisp_Object object));
11025static int pbm_load P_ ((struct frame *f, struct image *img));
11026static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11027
11028/* The symbol `pbm' identifying images of this type. */
11029
11030Lisp_Object Qpbm;
11031
11032/* Indices of image specification fields in gs_format, below. */
11033
11034enum pbm_keyword_index
11035{
11036 PBM_TYPE,
11037 PBM_FILE,
11038 PBM_DATA,
11039 PBM_ASCENT,
11040 PBM_MARGIN,
11041 PBM_RELIEF,
11042 PBM_ALGORITHM,
11043 PBM_HEURISTIC_MASK,
a05e2bae
JR
11044 PBM_MASK,
11045 PBM_FOREGROUND,
11046 PBM_BACKGROUND,
6fc2811b
JR
11047 PBM_LAST
11048};
11049
11050/* Vector of image_keyword structures describing the format
11051 of valid user-defined image specifications. */
11052
11053static struct image_keyword pbm_format[PBM_LAST] =
11054{
11055 {":type", IMAGE_SYMBOL_VALUE, 1},
11056 {":file", IMAGE_STRING_VALUE, 0},
11057 {":data", IMAGE_STRING_VALUE, 0},
11058 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11059 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11060 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11061 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
11062 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11063 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11064 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11065 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11066};
11067
11068/* Structure describing the image type `pbm'. */
11069
11070static struct image_type pbm_type =
11071{
11072 &Qpbm,
11073 pbm_image_p,
11074 pbm_load,
11075 x_clear_image,
11076 NULL
11077};
11078
11079
11080/* Return non-zero if OBJECT is a valid PBM image specification. */
11081
11082static int
11083pbm_image_p (object)
11084 Lisp_Object object;
11085{
11086 struct image_keyword fmt[PBM_LAST];
11087
11088 bcopy (pbm_format, fmt, sizeof fmt);
11089
11090 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
11091 || (fmt[PBM_ASCENT].count
11092 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11093 return 0;
11094
11095 /* Must specify either :data or :file. */
11096 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11097}
11098
11099
11100/* Scan a decimal number from *S and return it. Advance *S while
11101 reading the number. END is the end of the string. Value is -1 at
11102 end of input. */
11103
11104static int
11105pbm_scan_number (s, end)
11106 unsigned char **s, *end;
11107{
11108 int c, val = -1;
11109
11110 while (*s < end)
11111 {
11112 /* Skip white-space. */
11113 while (*s < end && (c = *(*s)++, isspace (c)))
11114 ;
11115
11116 if (c == '#')
11117 {
11118 /* Skip comment to end of line. */
11119 while (*s < end && (c = *(*s)++, c != '\n'))
11120 ;
11121 }
11122 else if (isdigit (c))
11123 {
11124 /* Read decimal number. */
11125 val = c - '0';
11126 while (*s < end && (c = *(*s)++, isdigit (c)))
11127 val = 10 * val + c - '0';
11128 break;
11129 }
11130 else
11131 break;
11132 }
11133
11134 return val;
11135}
11136
11137
11138/* Read FILE into memory. Value is a pointer to a buffer allocated
11139 with xmalloc holding FILE's contents. Value is null if an error
11140 occured. *SIZE is set to the size of the file. */
11141
11142static char *
11143pbm_read_file (file, size)
11144 Lisp_Object file;
11145 int *size;
11146{
11147 FILE *fp = NULL;
11148 char *buf = NULL;
11149 struct stat st;
11150
11151 if (stat (XSTRING (file)->data, &st) == 0
11152 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11153 && (buf = (char *) xmalloc (st.st_size),
11154 fread (buf, 1, st.st_size, fp) == st.st_size))
11155 {
11156 *size = st.st_size;
11157 fclose (fp);
11158 }
11159 else
11160 {
11161 if (fp)
11162 fclose (fp);
11163 if (buf)
11164 {
11165 xfree (buf);
11166 buf = NULL;
11167 }
11168 }
11169
11170 return buf;
11171}
11172
11173
11174/* Load PBM image IMG for use on frame F. */
11175
11176static int
11177pbm_load (f, img)
11178 struct frame *f;
11179 struct image *img;
11180{
11181 int raw_p, x, y;
11182 int width, height, max_color_idx = 0;
11183 XImage *ximg;
11184 Lisp_Object file, specified_file;
11185 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11186 struct gcpro gcpro1;
11187 unsigned char *contents = NULL;
11188 unsigned char *end, *p;
11189 int size;
11190
11191 specified_file = image_spec_value (img->spec, QCfile, NULL);
11192 file = Qnil;
11193 GCPRO1 (file);
11194
11195 if (STRINGP (specified_file))
11196 {
11197 file = x_find_image_file (specified_file);
11198 if (!STRINGP (file))
11199 {
11200 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11201 UNGCPRO;
11202 return 0;
11203 }
11204
3cf3436e 11205 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
11206 if (contents == NULL)
11207 {
11208 image_error ("Error reading `%s'", file, Qnil);
11209 UNGCPRO;
11210 return 0;
11211 }
11212
11213 p = contents;
11214 end = contents + size;
11215 }
11216 else
11217 {
11218 Lisp_Object data;
11219 data = image_spec_value (img->spec, QCdata, NULL);
11220 p = XSTRING (data)->data;
11221 end = p + STRING_BYTES (XSTRING (data));
11222 }
11223
11224 /* Check magic number. */
11225 if (end - p < 2 || *p++ != 'P')
11226 {
11227 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11228 error:
11229 xfree (contents);
11230 UNGCPRO;
11231 return 0;
11232 }
11233
6fc2811b
JR
11234 switch (*p++)
11235 {
11236 case '1':
11237 raw_p = 0, type = PBM_MONO;
11238 break;
11239
11240 case '2':
11241 raw_p = 0, type = PBM_GRAY;
11242 break;
11243
11244 case '3':
11245 raw_p = 0, type = PBM_COLOR;
11246 break;
11247
11248 case '4':
11249 raw_p = 1, type = PBM_MONO;
11250 break;
11251
11252 case '5':
11253 raw_p = 1, type = PBM_GRAY;
11254 break;
11255
11256 case '6':
11257 raw_p = 1, type = PBM_COLOR;
11258 break;
11259
11260 default:
11261 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11262 goto error;
11263 }
11264
11265 /* Read width, height, maximum color-component. Characters
11266 starting with `#' up to the end of a line are ignored. */
11267 width = pbm_scan_number (&p, end);
11268 height = pbm_scan_number (&p, end);
11269
11270 if (type != PBM_MONO)
11271 {
11272 max_color_idx = pbm_scan_number (&p, end);
11273 if (raw_p && max_color_idx > 255)
11274 max_color_idx = 255;
11275 }
11276
11277 if (width < 0
11278 || height < 0
11279 || (type != PBM_MONO && max_color_idx < 0))
11280 goto error;
11281
ac849ba4 11282 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
3cf3436e
JR
11283 goto error;
11284
ac849ba4 11285#if 0 /* TODO: color tables. */
6fc2811b
JR
11286 /* Initialize the color hash table. */
11287 init_color_table ();
ac849ba4 11288#endif
6fc2811b
JR
11289
11290 if (type == PBM_MONO)
11291 {
11292 int c = 0, g;
3cf3436e
JR
11293 struct image_keyword fmt[PBM_LAST];
11294 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11295 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11296
11297 /* Parse the image specification. */
11298 bcopy (pbm_format, fmt, sizeof fmt);
11299 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11300
11301 /* Get foreground and background colors, maybe allocate colors. */
11302 if (fmt[PBM_FOREGROUND].count
11303 && STRINGP (fmt[PBM_FOREGROUND].value))
11304 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11305 if (fmt[PBM_BACKGROUND].count
11306 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
11307 {
11308 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11309 img->background = bg;
11310 img->background_valid = 1;
11311 }
11312
6fc2811b
JR
11313 for (y = 0; y < height; ++y)
11314 for (x = 0; x < width; ++x)
11315 {
11316 if (raw_p)
11317 {
11318 if ((x & 7) == 0)
11319 c = *p++;
11320 g = c & 0x80;
11321 c <<= 1;
11322 }
11323 else
11324 g = pbm_scan_number (&p, end);
11325
3cf3436e 11326 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
11327 }
11328 }
11329 else
11330 {
11331 for (y = 0; y < height; ++y)
11332 for (x = 0; x < width; ++x)
11333 {
11334 int r, g, b;
11335
11336 if (type == PBM_GRAY)
11337 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11338 else if (raw_p)
11339 {
11340 r = *p++;
11341 g = *p++;
11342 b = *p++;
11343 }
11344 else
11345 {
11346 r = pbm_scan_number (&p, end);
11347 g = pbm_scan_number (&p, end);
11348 b = pbm_scan_number (&p, end);
11349 }
11350
11351 if (r < 0 || g < 0 || b < 0)
11352 {
ac849ba4 11353 x_destroy_x_image (ximg);
6fc2811b
JR
11354 image_error ("Invalid pixel value in image `%s'",
11355 img->spec, Qnil);
11356 goto error;
11357 }
11358
11359 /* RGB values are now in the range 0..max_color_idx.
ac849ba4
JR
11360 Scale this to the range 0..0xff supported by W32. */
11361 r = (int) ((double) r * 255 / max_color_idx);
11362 g = (int) ((double) g * 255 / max_color_idx);
11363 b = (int) ((double) b * 255 / max_color_idx);
11364 XPutPixel (ximg, x, y,
11365#if 0 /* TODO: color tables. */
11366 lookup_rgb_color (f, r, g, b));
11367#else
11368 PALETTERGB (r, g, b));
11369#endif
6fc2811b
JR
11370 }
11371 }
ac849ba4
JR
11372
11373#if 0 /* TODO: color tables. */
6fc2811b
JR
11374 /* Store in IMG->colors the colors allocated for the image, and
11375 free the color table. */
11376 img->colors = colors_in_color_table (&img->ncolors);
11377 free_color_table ();
ac849ba4 11378#endif
a05e2bae
JR
11379 /* Maybe fill in the background field while we have ximg handy. */
11380 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11381 IMAGE_BACKGROUND (img, f, ximg);
11382
6fc2811b
JR
11383 /* Put the image into a pixmap. */
11384 x_put_x_image (f, ximg, img->pixmap, width, height);
11385 x_destroy_x_image (ximg);
6fc2811b
JR
11386
11387 img->width = width;
11388 img->height = height;
11389
11390 UNGCPRO;
11391 xfree (contents);
11392 return 1;
11393}
11394#endif /* HAVE_PBM */
11395
11396\f
11397/***********************************************************************
11398 PNG
11399 ***********************************************************************/
11400
11401#if HAVE_PNG
11402
11403#include <png.h>
11404
11405/* Function prototypes. */
11406
11407static int png_image_p P_ ((Lisp_Object object));
11408static int png_load P_ ((struct frame *f, struct image *img));
11409
11410/* The symbol `png' identifying images of this type. */
11411
11412Lisp_Object Qpng;
11413
11414/* Indices of image specification fields in png_format, below. */
11415
11416enum png_keyword_index
11417{
11418 PNG_TYPE,
11419 PNG_DATA,
11420 PNG_FILE,
11421 PNG_ASCENT,
11422 PNG_MARGIN,
11423 PNG_RELIEF,
11424 PNG_ALGORITHM,
11425 PNG_HEURISTIC_MASK,
a05e2bae
JR
11426 PNG_MASK,
11427 PNG_BACKGROUND,
6fc2811b
JR
11428 PNG_LAST
11429};
11430
11431/* Vector of image_keyword structures describing the format
11432 of valid user-defined image specifications. */
11433
11434static struct image_keyword png_format[PNG_LAST] =
11435{
11436 {":type", IMAGE_SYMBOL_VALUE, 1},
11437 {":data", IMAGE_STRING_VALUE, 0},
11438 {":file", IMAGE_STRING_VALUE, 0},
11439 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11440 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11441 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11442 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11443 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11444 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11445 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11446};
11447
11448/* Structure describing the image type `png'. */
11449
11450static struct image_type png_type =
11451{
11452 &Qpng,
11453 png_image_p,
11454 png_load,
11455 x_clear_image,
11456 NULL
11457};
11458
11459
11460/* Return non-zero if OBJECT is a valid PNG image specification. */
11461
11462static int
11463png_image_p (object)
11464 Lisp_Object object;
11465{
11466 struct image_keyword fmt[PNG_LAST];
11467 bcopy (png_format, fmt, sizeof fmt);
11468
11469 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11470 || (fmt[PNG_ASCENT].count
11471 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11472 return 0;
11473
11474 /* Must specify either the :data or :file keyword. */
11475 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11476}
11477
11478
11479/* Error and warning handlers installed when the PNG library
11480 is initialized. */
11481
11482static void
11483my_png_error (png_ptr, msg)
11484 png_struct *png_ptr;
11485 char *msg;
11486{
11487 xassert (png_ptr != NULL);
11488 image_error ("PNG error: %s", build_string (msg), Qnil);
11489 longjmp (png_ptr->jmpbuf, 1);
11490}
11491
11492
11493static void
11494my_png_warning (png_ptr, msg)
11495 png_struct *png_ptr;
11496 char *msg;
11497{
11498 xassert (png_ptr != NULL);
11499 image_error ("PNG warning: %s", build_string (msg), Qnil);
11500}
11501
6fc2811b
JR
11502/* Memory source for PNG decoding. */
11503
11504struct png_memory_storage
11505{
11506 unsigned char *bytes; /* The data */
11507 size_t len; /* How big is it? */
11508 int index; /* Where are we? */
11509};
11510
11511
11512/* Function set as reader function when reading PNG image from memory.
11513 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11514 bytes from the input to DATA. */
11515
11516static void
11517png_read_from_memory (png_ptr, data, length)
11518 png_structp png_ptr;
11519 png_bytep data;
11520 png_size_t length;
11521{
11522 struct png_memory_storage *tbr
11523 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11524
11525 if (length > tbr->len - tbr->index)
11526 png_error (png_ptr, "Read error");
11527
11528 bcopy (tbr->bytes + tbr->index, data, length);
11529 tbr->index = tbr->index + length;
11530}
11531
6fc2811b
JR
11532/* Load PNG image IMG for use on frame F. Value is non-zero if
11533 successful. */
11534
11535static int
11536png_load (f, img)
11537 struct frame *f;
11538 struct image *img;
11539{
11540 Lisp_Object file, specified_file;
11541 Lisp_Object specified_data;
11542 int x, y, i;
11543 XImage *ximg, *mask_img = NULL;
11544 struct gcpro gcpro1;
11545 png_struct *png_ptr = NULL;
11546 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11547 FILE *volatile fp = NULL;
6fc2811b 11548 png_byte sig[8];
a05e2bae
JR
11549 png_byte *volatile pixels = NULL;
11550 png_byte **volatile rows = NULL;
6fc2811b
JR
11551 png_uint_32 width, height;
11552 int bit_depth, color_type, interlace_type;
11553 png_byte channels;
11554 png_uint_32 row_bytes;
11555 int transparent_p;
11556 char *gamma_str;
11557 double screen_gamma, image_gamma;
11558 int intent;
11559 struct png_memory_storage tbr; /* Data to be read */
11560
11561 /* Find out what file to load. */
11562 specified_file = image_spec_value (img->spec, QCfile, NULL);
11563 specified_data = image_spec_value (img->spec, QCdata, NULL);
11564 file = Qnil;
11565 GCPRO1 (file);
11566
11567 if (NILP (specified_data))
11568 {
11569 file = x_find_image_file (specified_file);
11570 if (!STRINGP (file))
11571 {
11572 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11573 UNGCPRO;
11574 return 0;
11575 }
11576
11577 /* Open the image file. */
11578 fp = fopen (XSTRING (file)->data, "rb");
11579 if (!fp)
11580 {
11581 image_error ("Cannot open image file `%s'", file, Qnil);
11582 UNGCPRO;
11583 fclose (fp);
11584 return 0;
11585 }
11586
11587 /* Check PNG signature. */
11588 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11589 || !png_check_sig (sig, sizeof sig))
11590 {
11591 image_error ("Not a PNG file:` %s'", file, Qnil);
11592 UNGCPRO;
11593 fclose (fp);
11594 return 0;
11595 }
11596 }
11597 else
11598 {
11599 /* Read from memory. */
11600 tbr.bytes = XSTRING (specified_data)->data;
11601 tbr.len = STRING_BYTES (XSTRING (specified_data));
11602 tbr.index = 0;
11603
11604 /* Check PNG signature. */
11605 if (tbr.len < sizeof sig
11606 || !png_check_sig (tbr.bytes, sizeof sig))
11607 {
11608 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11609 UNGCPRO;
11610 return 0;
11611 }
11612
11613 /* Need to skip past the signature. */
11614 tbr.bytes += sizeof (sig);
11615 }
11616
6fc2811b
JR
11617 /* Initialize read and info structs for PNG lib. */
11618 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11619 my_png_error, my_png_warning);
11620 if (!png_ptr)
11621 {
11622 if (fp) fclose (fp);
11623 UNGCPRO;
11624 return 0;
11625 }
11626
11627 info_ptr = png_create_info_struct (png_ptr);
11628 if (!info_ptr)
11629 {
11630 png_destroy_read_struct (&png_ptr, NULL, NULL);
11631 if (fp) fclose (fp);
11632 UNGCPRO;
11633 return 0;
11634 }
11635
11636 end_info = png_create_info_struct (png_ptr);
11637 if (!end_info)
11638 {
11639 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11640 if (fp) fclose (fp);
11641 UNGCPRO;
11642 return 0;
11643 }
11644
11645 /* Set error jump-back. We come back here when the PNG library
11646 detects an error. */
11647 if (setjmp (png_ptr->jmpbuf))
11648 {
11649 error:
11650 if (png_ptr)
11651 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11652 xfree (pixels);
11653 xfree (rows);
11654 if (fp) fclose (fp);
11655 UNGCPRO;
11656 return 0;
11657 }
11658
11659 /* Read image info. */
11660 if (!NILP (specified_data))
11661 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11662 else
11663 png_init_io (png_ptr, fp);
11664
11665 png_set_sig_bytes (png_ptr, sizeof sig);
11666 png_read_info (png_ptr, info_ptr);
11667 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11668 &interlace_type, NULL, NULL);
11669
11670 /* If image contains simply transparency data, we prefer to
11671 construct a clipping mask. */
11672 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11673 transparent_p = 1;
11674 else
11675 transparent_p = 0;
11676
11677 /* This function is easier to write if we only have to handle
11678 one data format: RGB or RGBA with 8 bits per channel. Let's
11679 transform other formats into that format. */
11680
11681 /* Strip more than 8 bits per channel. */
11682 if (bit_depth == 16)
11683 png_set_strip_16 (png_ptr);
11684
11685 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11686 if available. */
11687 png_set_expand (png_ptr);
11688
11689 /* Convert grayscale images to RGB. */
11690 if (color_type == PNG_COLOR_TYPE_GRAY
11691 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11692 png_set_gray_to_rgb (png_ptr);
11693
11694 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11695 gamma_str = getenv ("SCREEN_GAMMA");
11696 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11697
11698 /* Tell the PNG lib to handle gamma correction for us. */
11699
11700#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11701 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11702 /* There is a special chunk in the image specifying the gamma. */
11703 png_set_sRGB (png_ptr, info_ptr, intent);
11704 else
11705#endif
11706 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11707 /* Image contains gamma information. */
11708 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11709 else
11710 /* Use a default of 0.5 for the image gamma. */
11711 png_set_gamma (png_ptr, screen_gamma, 0.5);
11712
11713 /* Handle alpha channel by combining the image with a background
11714 color. Do this only if a real alpha channel is supplied. For
11715 simple transparency, we prefer a clipping mask. */
11716 if (!transparent_p)
11717 {
11718 png_color_16 *image_background;
a05e2bae
JR
11719 Lisp_Object specified_bg
11720 = image_spec_value (img->spec, QCbackground, NULL);
11721
11722
11723 if (STRINGP (specified_bg))
11724 /* The user specified `:background', use that. */
11725 {
11726 COLORREF color;
11727 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11728 {
11729 png_color_16 user_bg;
11730
11731 bzero (&user_bg, sizeof user_bg);
11732 user_bg.red = color.red;
11733 user_bg.green = color.green;
11734 user_bg.blue = color.blue;
6fc2811b 11735
a05e2bae
JR
11736 png_set_background (png_ptr, &user_bg,
11737 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11738 }
11739 }
11740 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11741 /* Image contains a background color with which to
11742 combine the image. */
11743 png_set_background (png_ptr, image_background,
11744 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11745 else
11746 {
11747 /* Image does not contain a background color with which
11748 to combine the image data via an alpha channel. Use
11749 the frame's background instead. */
11750 XColor color;
11751 Colormap cmap;
11752 png_color_16 frame_background;
11753
a05e2bae 11754 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11755 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11756 x_query_color (f, &color);
6fc2811b
JR
11757
11758 bzero (&frame_background, sizeof frame_background);
11759 frame_background.red = color.red;
11760 frame_background.green = color.green;
11761 frame_background.blue = color.blue;
11762
11763 png_set_background (png_ptr, &frame_background,
11764 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11765 }
11766 }
11767
11768 /* Update info structure. */
11769 png_read_update_info (png_ptr, info_ptr);
11770
11771 /* Get number of channels. Valid values are 1 for grayscale images
11772 and images with a palette, 2 for grayscale images with transparency
11773 information (alpha channel), 3 for RGB images, and 4 for RGB
11774 images with alpha channel, i.e. RGBA. If conversions above were
11775 sufficient we should only have 3 or 4 channels here. */
11776 channels = png_get_channels (png_ptr, info_ptr);
11777 xassert (channels == 3 || channels == 4);
11778
11779 /* Number of bytes needed for one row of the image. */
11780 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11781
11782 /* Allocate memory for the image. */
11783 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11784 rows = (png_byte **) xmalloc (height * sizeof *rows);
11785 for (i = 0; i < height; ++i)
11786 rows[i] = pixels + i * row_bytes;
11787
11788 /* Read the entire image. */
11789 png_read_image (png_ptr, rows);
11790 png_read_end (png_ptr, info_ptr);
11791 if (fp)
11792 {
11793 fclose (fp);
11794 fp = NULL;
11795 }
11796
6fc2811b
JR
11797 /* Create the X image and pixmap. */
11798 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11799 &img->pixmap))
a05e2bae 11800 goto error;
6fc2811b
JR
11801
11802 /* Create an image and pixmap serving as mask if the PNG image
11803 contains an alpha channel. */
11804 if (channels == 4
11805 && !transparent_p
11806 && !x_create_x_image_and_pixmap (f, width, height, 1,
11807 &mask_img, &img->mask))
11808 {
11809 x_destroy_x_image (ximg);
11810 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11811 img->pixmap = 0;
6fc2811b
JR
11812 goto error;
11813 }
11814
11815 /* Fill the X image and mask from PNG data. */
11816 init_color_table ();
11817
11818 for (y = 0; y < height; ++y)
11819 {
11820 png_byte *p = rows[y];
11821
11822 for (x = 0; x < width; ++x)
11823 {
11824 unsigned r, g, b;
11825
11826 r = *p++ << 8;
11827 g = *p++ << 8;
11828 b = *p++ << 8;
11829 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11830
11831 /* An alpha channel, aka mask channel, associates variable
11832 transparency with an image. Where other image formats
11833 support binary transparency---fully transparent or fully
11834 opaque---PNG allows up to 254 levels of partial transparency.
11835 The PNG library implements partial transparency by combining
11836 the image with a specified background color.
11837
11838 I'm not sure how to handle this here nicely: because the
11839 background on which the image is displayed may change, for
11840 real alpha channel support, it would be necessary to create
11841 a new image for each possible background.
11842
11843 What I'm doing now is that a mask is created if we have
11844 boolean transparency information. Otherwise I'm using
11845 the frame's background color to combine the image with. */
11846
11847 if (channels == 4)
11848 {
11849 if (mask_img)
11850 XPutPixel (mask_img, x, y, *p > 0);
11851 ++p;
11852 }
11853 }
11854 }
11855
a05e2bae
JR
11856 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11857 /* Set IMG's background color from the PNG image, unless the user
11858 overrode it. */
11859 {
11860 png_color_16 *bg;
11861 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11862 {
11863 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11864 img->background_valid = 1;
11865 }
11866 }
11867
6fc2811b
JR
11868 /* Remember colors allocated for this image. */
11869 img->colors = colors_in_color_table (&img->ncolors);
11870 free_color_table ();
11871
11872 /* Clean up. */
11873 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11874 xfree (rows);
11875 xfree (pixels);
11876
11877 img->width = width;
11878 img->height = height;
11879
a05e2bae
JR
11880 /* Maybe fill in the background field while we have ximg handy. */
11881 IMAGE_BACKGROUND (img, f, ximg);
11882
6fc2811b
JR
11883 /* Put the image into the pixmap, then free the X image and its buffer. */
11884 x_put_x_image (f, ximg, img->pixmap, width, height);
11885 x_destroy_x_image (ximg);
11886
11887 /* Same for the mask. */
11888 if (mask_img)
11889 {
a05e2bae
JR
11890 /* Fill in the background_transparent field while we have the mask
11891 handy. */
11892 image_background_transparent (img, f, mask_img);
11893
6fc2811b
JR
11894 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11895 x_destroy_x_image (mask_img);
11896 }
11897
6fc2811b
JR
11898 UNGCPRO;
11899 return 1;
11900}
11901
11902#endif /* HAVE_PNG != 0 */
11903
11904
11905\f
11906/***********************************************************************
11907 JPEG
11908 ***********************************************************************/
11909
11910#if HAVE_JPEG
11911
11912/* Work around a warning about HAVE_STDLIB_H being redefined in
11913 jconfig.h. */
11914#ifdef HAVE_STDLIB_H
11915#define HAVE_STDLIB_H_1
11916#undef HAVE_STDLIB_H
11917#endif /* HAVE_STLIB_H */
11918
11919#include <jpeglib.h>
11920#include <jerror.h>
11921#include <setjmp.h>
11922
11923#ifdef HAVE_STLIB_H_1
11924#define HAVE_STDLIB_H 1
11925#endif
11926
11927static int jpeg_image_p P_ ((Lisp_Object object));
11928static int jpeg_load P_ ((struct frame *f, struct image *img));
11929
11930/* The symbol `jpeg' identifying images of this type. */
11931
11932Lisp_Object Qjpeg;
11933
11934/* Indices of image specification fields in gs_format, below. */
11935
11936enum jpeg_keyword_index
11937{
11938 JPEG_TYPE,
11939 JPEG_DATA,
11940 JPEG_FILE,
11941 JPEG_ASCENT,
11942 JPEG_MARGIN,
11943 JPEG_RELIEF,
11944 JPEG_ALGORITHM,
11945 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11946 JPEG_MASK,
11947 JPEG_BACKGROUND,
6fc2811b
JR
11948 JPEG_LAST
11949};
11950
11951/* Vector of image_keyword structures describing the format
11952 of valid user-defined image specifications. */
11953
11954static struct image_keyword jpeg_format[JPEG_LAST] =
11955{
11956 {":type", IMAGE_SYMBOL_VALUE, 1},
11957 {":data", IMAGE_STRING_VALUE, 0},
11958 {":file", IMAGE_STRING_VALUE, 0},
11959 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11960 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11961 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11962 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11963 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11964 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11965 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11966};
11967
11968/* Structure describing the image type `jpeg'. */
11969
11970static struct image_type jpeg_type =
11971{
11972 &Qjpeg,
11973 jpeg_image_p,
11974 jpeg_load,
11975 x_clear_image,
11976 NULL
11977};
11978
11979
11980/* Return non-zero if OBJECT is a valid JPEG image specification. */
11981
11982static int
11983jpeg_image_p (object)
11984 Lisp_Object object;
11985{
11986 struct image_keyword fmt[JPEG_LAST];
11987
11988 bcopy (jpeg_format, fmt, sizeof fmt);
11989
11990 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11991 || (fmt[JPEG_ASCENT].count
11992 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11993 return 0;
11994
11995 /* Must specify either the :data or :file keyword. */
11996 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11997}
11998
11999
12000struct my_jpeg_error_mgr
12001{
12002 struct jpeg_error_mgr pub;
12003 jmp_buf setjmp_buffer;
12004};
12005
12006static void
12007my_error_exit (cinfo)
12008 j_common_ptr cinfo;
12009{
12010 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12011 longjmp (mgr->setjmp_buffer, 1);
12012}
12013
6fc2811b
JR
12014/* Init source method for JPEG data source manager. Called by
12015 jpeg_read_header() before any data is actually read. See
12016 libjpeg.doc from the JPEG lib distribution. */
12017
12018static void
12019our_init_source (cinfo)
12020 j_decompress_ptr cinfo;
12021{
12022}
12023
12024
12025/* Fill input buffer method for JPEG data source manager. Called
12026 whenever more data is needed. We read the whole image in one step,
12027 so this only adds a fake end of input marker at the end. */
12028
12029static boolean
12030our_fill_input_buffer (cinfo)
12031 j_decompress_ptr cinfo;
12032{
12033 /* Insert a fake EOI marker. */
12034 struct jpeg_source_mgr *src = cinfo->src;
12035 static JOCTET buffer[2];
12036
12037 buffer[0] = (JOCTET) 0xFF;
12038 buffer[1] = (JOCTET) JPEG_EOI;
12039
12040 src->next_input_byte = buffer;
12041 src->bytes_in_buffer = 2;
12042 return TRUE;
12043}
12044
12045
12046/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12047 is the JPEG data source manager. */
12048
12049static void
12050our_skip_input_data (cinfo, num_bytes)
12051 j_decompress_ptr cinfo;
12052 long num_bytes;
12053{
12054 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12055
12056 if (src)
12057 {
12058 if (num_bytes > src->bytes_in_buffer)
12059 ERREXIT (cinfo, JERR_INPUT_EOF);
12060
12061 src->bytes_in_buffer -= num_bytes;
12062 src->next_input_byte += num_bytes;
12063 }
12064}
12065
12066
12067/* Method to terminate data source. Called by
12068 jpeg_finish_decompress() after all data has been processed. */
12069
12070static void
12071our_term_source (cinfo)
12072 j_decompress_ptr cinfo;
12073{
12074}
12075
12076
12077/* Set up the JPEG lib for reading an image from DATA which contains
12078 LEN bytes. CINFO is the decompression info structure created for
12079 reading the image. */
12080
12081static void
12082jpeg_memory_src (cinfo, data, len)
12083 j_decompress_ptr cinfo;
12084 JOCTET *data;
12085 unsigned int len;
12086{
12087 struct jpeg_source_mgr *src;
12088
12089 if (cinfo->src == NULL)
12090 {
12091 /* First time for this JPEG object? */
12092 cinfo->src = (struct jpeg_source_mgr *)
12093 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12094 sizeof (struct jpeg_source_mgr));
12095 src = (struct jpeg_source_mgr *) cinfo->src;
12096 src->next_input_byte = data;
12097 }
12098
12099 src = (struct jpeg_source_mgr *) cinfo->src;
12100 src->init_source = our_init_source;
12101 src->fill_input_buffer = our_fill_input_buffer;
12102 src->skip_input_data = our_skip_input_data;
12103 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12104 src->term_source = our_term_source;
12105 src->bytes_in_buffer = len;
12106 src->next_input_byte = data;
12107}
12108
12109
12110/* Load image IMG for use on frame F. Patterned after example.c
12111 from the JPEG lib. */
12112
12113static int
12114jpeg_load (f, img)
12115 struct frame *f;
12116 struct image *img;
12117{
12118 struct jpeg_decompress_struct cinfo;
12119 struct my_jpeg_error_mgr mgr;
12120 Lisp_Object file, specified_file;
12121 Lisp_Object specified_data;
a05e2bae 12122 FILE * volatile fp = NULL;
6fc2811b
JR
12123 JSAMPARRAY buffer;
12124 int row_stride, x, y;
12125 XImage *ximg = NULL;
12126 int rc;
12127 unsigned long *colors;
12128 int width, height;
12129 struct gcpro gcpro1;
12130
12131 /* Open the JPEG file. */
12132 specified_file = image_spec_value (img->spec, QCfile, NULL);
12133 specified_data = image_spec_value (img->spec, QCdata, NULL);
12134 file = Qnil;
12135 GCPRO1 (file);
12136
6fc2811b
JR
12137 if (NILP (specified_data))
12138 {
12139 file = x_find_image_file (specified_file);
12140 if (!STRINGP (file))
12141 {
12142 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12143 UNGCPRO;
12144 return 0;
12145 }
12146
12147 fp = fopen (XSTRING (file)->data, "r");
12148 if (fp == NULL)
12149 {
12150 image_error ("Cannot open `%s'", file, Qnil);
12151 UNGCPRO;
12152 return 0;
12153 }
12154 }
12155
12156 /* Customize libjpeg's error handling to call my_error_exit when an
12157 error is detected. This function will perform a longjmp. */
6fc2811b 12158 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 12159 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
12160
12161 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12162 {
12163 if (rc == 1)
12164 {
12165 /* Called from my_error_exit. Display a JPEG error. */
12166 char buffer[JMSG_LENGTH_MAX];
12167 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12168 image_error ("Error reading JPEG image `%s': %s", img->spec,
12169 build_string (buffer));
12170 }
12171
12172 /* Close the input file and destroy the JPEG object. */
12173 if (fp)
12174 fclose (fp);
12175 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
12176
12177 /* If we already have an XImage, free that. */
12178 x_destroy_x_image (ximg);
12179
12180 /* Free pixmap and colors. */
12181 x_clear_image (f, img);
12182
6fc2811b
JR
12183 UNGCPRO;
12184 return 0;
12185 }
12186
12187 /* Create the JPEG decompression object. Let it read from fp.
12188 Read the JPEG image header. */
12189 jpeg_create_decompress (&cinfo);
12190
12191 if (NILP (specified_data))
12192 jpeg_stdio_src (&cinfo, fp);
12193 else
12194 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12195 STRING_BYTES (XSTRING (specified_data)));
12196
12197 jpeg_read_header (&cinfo, TRUE);
12198
12199 /* Customize decompression so that color quantization will be used.
12200 Start decompression. */
12201 cinfo.quantize_colors = TRUE;
12202 jpeg_start_decompress (&cinfo);
12203 width = img->width = cinfo.output_width;
12204 height = img->height = cinfo.output_height;
12205
6fc2811b
JR
12206 /* Create X image and pixmap. */
12207 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12208 &img->pixmap))
a05e2bae 12209 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
12210
12211 /* Allocate colors. When color quantization is used,
12212 cinfo.actual_number_of_colors has been set with the number of
12213 colors generated, and cinfo.colormap is a two-dimensional array
12214 of color indices in the range 0..cinfo.actual_number_of_colors.
12215 No more than 255 colors will be generated. */
12216 {
12217 int i, ir, ig, ib;
12218
12219 if (cinfo.out_color_components > 2)
12220 ir = 0, ig = 1, ib = 2;
12221 else if (cinfo.out_color_components > 1)
12222 ir = 0, ig = 1, ib = 0;
12223 else
12224 ir = 0, ig = 0, ib = 0;
12225
12226 /* Use the color table mechanism because it handles colors that
12227 cannot be allocated nicely. Such colors will be replaced with
12228 a default color, and we don't have to care about which colors
12229 can be freed safely, and which can't. */
12230 init_color_table ();
12231 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12232 * sizeof *colors);
12233
12234 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12235 {
12236 /* Multiply RGB values with 255 because X expects RGB values
12237 in the range 0..0xffff. */
12238 int r = cinfo.colormap[ir][i] << 8;
12239 int g = cinfo.colormap[ig][i] << 8;
12240 int b = cinfo.colormap[ib][i] << 8;
12241 colors[i] = lookup_rgb_color (f, r, g, b);
12242 }
12243
12244 /* Remember those colors actually allocated. */
12245 img->colors = colors_in_color_table (&img->ncolors);
12246 free_color_table ();
12247 }
12248
12249 /* Read pixels. */
12250 row_stride = width * cinfo.output_components;
12251 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12252 row_stride, 1);
12253 for (y = 0; y < height; ++y)
12254 {
12255 jpeg_read_scanlines (&cinfo, buffer, 1);
12256 for (x = 0; x < cinfo.output_width; ++x)
12257 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12258 }
12259
12260 /* Clean up. */
12261 jpeg_finish_decompress (&cinfo);
12262 jpeg_destroy_decompress (&cinfo);
12263 if (fp)
12264 fclose (fp);
12265
a05e2bae
JR
12266 /* Maybe fill in the background field while we have ximg handy. */
12267 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12268 IMAGE_BACKGROUND (img, f, ximg);
12269
6fc2811b
JR
12270 /* Put the image into the pixmap. */
12271 x_put_x_image (f, ximg, img->pixmap, width, height);
12272 x_destroy_x_image (ximg);
12273 UNBLOCK_INPUT;
12274 UNGCPRO;
12275 return 1;
12276}
12277
12278#endif /* HAVE_JPEG */
12279
12280
12281\f
12282/***********************************************************************
12283 TIFF
12284 ***********************************************************************/
12285
12286#if HAVE_TIFF
12287
12288#include <tiffio.h>
12289
12290static int tiff_image_p P_ ((Lisp_Object object));
12291static int tiff_load P_ ((struct frame *f, struct image *img));
12292
12293/* The symbol `tiff' identifying images of this type. */
12294
12295Lisp_Object Qtiff;
12296
12297/* Indices of image specification fields in tiff_format, below. */
12298
12299enum tiff_keyword_index
12300{
12301 TIFF_TYPE,
12302 TIFF_DATA,
12303 TIFF_FILE,
12304 TIFF_ASCENT,
12305 TIFF_MARGIN,
12306 TIFF_RELIEF,
12307 TIFF_ALGORITHM,
12308 TIFF_HEURISTIC_MASK,
a05e2bae
JR
12309 TIFF_MASK,
12310 TIFF_BACKGROUND,
6fc2811b
JR
12311 TIFF_LAST
12312};
12313
12314/* Vector of image_keyword structures describing the format
12315 of valid user-defined image specifications. */
12316
12317static struct image_keyword tiff_format[TIFF_LAST] =
12318{
12319 {":type", IMAGE_SYMBOL_VALUE, 1},
12320 {":data", IMAGE_STRING_VALUE, 0},
12321 {":file", IMAGE_STRING_VALUE, 0},
12322 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12323 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12324 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12325 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12326 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12327 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12328 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12329};
12330
12331/* Structure describing the image type `tiff'. */
12332
12333static struct image_type tiff_type =
12334{
12335 &Qtiff,
12336 tiff_image_p,
12337 tiff_load,
12338 x_clear_image,
12339 NULL
12340};
12341
12342
12343/* Return non-zero if OBJECT is a valid TIFF image specification. */
12344
12345static int
12346tiff_image_p (object)
12347 Lisp_Object object;
12348{
12349 struct image_keyword fmt[TIFF_LAST];
12350 bcopy (tiff_format, fmt, sizeof fmt);
12351
12352 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12353 || (fmt[TIFF_ASCENT].count
12354 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12355 return 0;
12356
12357 /* Must specify either the :data or :file keyword. */
12358 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12359}
12360
12361
12362/* Reading from a memory buffer for TIFF images Based on the PNG
12363 memory source, but we have to provide a lot of extra functions.
12364 Blah.
12365
12366 We really only need to implement read and seek, but I am not
12367 convinced that the TIFF library is smart enough not to destroy
12368 itself if we only hand it the function pointers we need to
12369 override. */
12370
12371typedef struct
12372{
12373 unsigned char *bytes;
12374 size_t len;
12375 int index;
12376}
12377tiff_memory_source;
12378
12379static size_t
12380tiff_read_from_memory (data, buf, size)
12381 thandle_t data;
12382 tdata_t buf;
12383 tsize_t size;
12384{
12385 tiff_memory_source *src = (tiff_memory_source *) data;
12386
12387 if (size > src->len - src->index)
12388 return (size_t) -1;
12389 bcopy (src->bytes + src->index, buf, size);
12390 src->index += size;
12391 return size;
12392}
12393
12394static size_t
12395tiff_write_from_memory (data, buf, size)
12396 thandle_t data;
12397 tdata_t buf;
12398 tsize_t size;
12399{
12400 return (size_t) -1;
12401}
12402
12403static toff_t
12404tiff_seek_in_memory (data, off, whence)
12405 thandle_t data;
12406 toff_t off;
12407 int whence;
12408{
12409 tiff_memory_source *src = (tiff_memory_source *) data;
12410 int idx;
12411
12412 switch (whence)
12413 {
12414 case SEEK_SET: /* Go from beginning of source. */
12415 idx = off;
12416 break;
12417
12418 case SEEK_END: /* Go from end of source. */
12419 idx = src->len + off;
12420 break;
12421
12422 case SEEK_CUR: /* Go from current position. */
12423 idx = src->index + off;
12424 break;
12425
12426 default: /* Invalid `whence'. */
12427 return -1;
12428 }
12429
12430 if (idx > src->len || idx < 0)
12431 return -1;
12432
12433 src->index = idx;
12434 return src->index;
12435}
12436
12437static int
12438tiff_close_memory (data)
12439 thandle_t data;
12440{
12441 /* NOOP */
12442 return 0;
12443}
12444
12445static int
12446tiff_mmap_memory (data, pbase, psize)
12447 thandle_t data;
12448 tdata_t *pbase;
12449 toff_t *psize;
12450{
12451 /* It is already _IN_ memory. */
12452 return 0;
12453}
12454
12455static void
12456tiff_unmap_memory (data, base, size)
12457 thandle_t data;
12458 tdata_t base;
12459 toff_t size;
12460{
12461 /* We don't need to do this. */
12462}
12463
12464static toff_t
12465tiff_size_of_memory (data)
12466 thandle_t data;
12467{
12468 return ((tiff_memory_source *) data)->len;
12469}
12470
3cf3436e
JR
12471
12472static void
12473tiff_error_handler (title, format, ap)
12474 const char *title, *format;
12475 va_list ap;
12476{
12477 char buf[512];
12478 int len;
12479
12480 len = sprintf (buf, "TIFF error: %s ", title);
12481 vsprintf (buf + len, format, ap);
12482 add_to_log (buf, Qnil, Qnil);
12483}
12484
12485
12486static void
12487tiff_warning_handler (title, format, ap)
12488 const char *title, *format;
12489 va_list ap;
12490{
12491 char buf[512];
12492 int len;
12493
12494 len = sprintf (buf, "TIFF warning: %s ", title);
12495 vsprintf (buf + len, format, ap);
12496 add_to_log (buf, Qnil, Qnil);
12497}
12498
12499
6fc2811b
JR
12500/* Load TIFF image IMG for use on frame F. Value is non-zero if
12501 successful. */
12502
12503static int
12504tiff_load (f, img)
12505 struct frame *f;
12506 struct image *img;
12507{
12508 Lisp_Object file, specified_file;
12509 Lisp_Object specified_data;
12510 TIFF *tiff;
12511 int width, height, x, y;
12512 uint32 *buf;
12513 int rc;
12514 XImage *ximg;
12515 struct gcpro gcpro1;
12516 tiff_memory_source memsrc;
12517
12518 specified_file = image_spec_value (img->spec, QCfile, NULL);
12519 specified_data = image_spec_value (img->spec, QCdata, NULL);
12520 file = Qnil;
12521 GCPRO1 (file);
12522
3cf3436e
JR
12523 TIFFSetErrorHandler (tiff_error_handler);
12524 TIFFSetWarningHandler (tiff_warning_handler);
12525
6fc2811b
JR
12526 if (NILP (specified_data))
12527 {
12528 /* Read from a file */
12529 file = x_find_image_file (specified_file);
12530 if (!STRINGP (file))
3cf3436e
JR
12531 {
12532 image_error ("Cannot find image file `%s'", file, Qnil);
12533 UNGCPRO;
12534 return 0;
12535 }
12536
6fc2811b
JR
12537 /* Try to open the image file. */
12538 tiff = TIFFOpen (XSTRING (file)->data, "r");
12539 if (tiff == NULL)
3cf3436e
JR
12540 {
12541 image_error ("Cannot open `%s'", file, Qnil);
12542 UNGCPRO;
12543 return 0;
12544 }
6fc2811b
JR
12545 }
12546 else
12547 {
12548 /* Memory source! */
12549 memsrc.bytes = XSTRING (specified_data)->data;
12550 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12551 memsrc.index = 0;
12552
12553 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12554 (TIFFReadWriteProc) tiff_read_from_memory,
12555 (TIFFReadWriteProc) tiff_write_from_memory,
12556 tiff_seek_in_memory,
12557 tiff_close_memory,
12558 tiff_size_of_memory,
12559 tiff_mmap_memory,
12560 tiff_unmap_memory);
12561
12562 if (!tiff)
12563 {
12564 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12565 UNGCPRO;
12566 return 0;
12567 }
12568 }
12569
12570 /* Get width and height of the image, and allocate a raster buffer
12571 of width x height 32-bit values. */
12572 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12573 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12574 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12575
12576 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12577 TIFFClose (tiff);
12578 if (!rc)
12579 {
12580 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12581 xfree (buf);
12582 UNGCPRO;
12583 return 0;
12584 }
12585
6fc2811b
JR
12586 /* Create the X image and pixmap. */
12587 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12588 {
6fc2811b
JR
12589 xfree (buf);
12590 UNGCPRO;
12591 return 0;
12592 }
12593
12594 /* Initialize the color table. */
12595 init_color_table ();
12596
12597 /* Process the pixel raster. Origin is in the lower-left corner. */
12598 for (y = 0; y < height; ++y)
12599 {
12600 uint32 *row = buf + y * width;
12601
12602 for (x = 0; x < width; ++x)
12603 {
12604 uint32 abgr = row[x];
12605 int r = TIFFGetR (abgr) << 8;
12606 int g = TIFFGetG (abgr) << 8;
12607 int b = TIFFGetB (abgr) << 8;
12608 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12609 }
12610 }
12611
12612 /* Remember the colors allocated for the image. Free the color table. */
12613 img->colors = colors_in_color_table (&img->ncolors);
12614 free_color_table ();
12615
a05e2bae
JR
12616 img->width = width;
12617 img->height = height;
12618
12619 /* Maybe fill in the background field while we have ximg handy. */
12620 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12621 IMAGE_BACKGROUND (img, f, ximg);
12622
6fc2811b
JR
12623 /* Put the image into the pixmap, then free the X image and its buffer. */
12624 x_put_x_image (f, ximg, img->pixmap, width, height);
12625 x_destroy_x_image (ximg);
12626 xfree (buf);
6fc2811b
JR
12627
12628 UNGCPRO;
12629 return 1;
12630}
12631
12632#endif /* HAVE_TIFF != 0 */
12633
12634
12635\f
12636/***********************************************************************
12637 GIF
12638 ***********************************************************************/
12639
12640#if HAVE_GIF
12641
12642#include <gif_lib.h>
12643
12644static int gif_image_p P_ ((Lisp_Object object));
12645static int gif_load P_ ((struct frame *f, struct image *img));
12646
12647/* The symbol `gif' identifying images of this type. */
12648
12649Lisp_Object Qgif;
12650
12651/* Indices of image specification fields in gif_format, below. */
12652
12653enum gif_keyword_index
12654{
12655 GIF_TYPE,
12656 GIF_DATA,
12657 GIF_FILE,
12658 GIF_ASCENT,
12659 GIF_MARGIN,
12660 GIF_RELIEF,
12661 GIF_ALGORITHM,
12662 GIF_HEURISTIC_MASK,
a05e2bae 12663 GIF_MASK,
6fc2811b 12664 GIF_IMAGE,
a05e2bae 12665 GIF_BACKGROUND,
6fc2811b
JR
12666 GIF_LAST
12667};
12668
12669/* Vector of image_keyword structures describing the format
12670 of valid user-defined image specifications. */
12671
12672static struct image_keyword gif_format[GIF_LAST] =
12673{
12674 {":type", IMAGE_SYMBOL_VALUE, 1},
12675 {":data", IMAGE_STRING_VALUE, 0},
12676 {":file", IMAGE_STRING_VALUE, 0},
12677 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12678 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12679 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12680 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12681 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12682 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12683 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12684 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12685};
12686
12687/* Structure describing the image type `gif'. */
12688
12689static struct image_type gif_type =
12690{
12691 &Qgif,
12692 gif_image_p,
12693 gif_load,
12694 x_clear_image,
12695 NULL
12696};
12697
12698/* Return non-zero if OBJECT is a valid GIF image specification. */
12699
12700static int
12701gif_image_p (object)
12702 Lisp_Object object;
12703{
12704 struct image_keyword fmt[GIF_LAST];
12705 bcopy (gif_format, fmt, sizeof fmt);
12706
12707 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12708 || (fmt[GIF_ASCENT].count
12709 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12710 return 0;
12711
12712 /* Must specify either the :data or :file keyword. */
12713 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12714}
12715
12716/* Reading a GIF image from memory
12717 Based on the PNG memory stuff to a certain extent. */
12718
12719typedef struct
12720{
12721 unsigned char *bytes;
12722 size_t len;
12723 int index;
12724}
12725gif_memory_source;
12726
12727/* Make the current memory source available to gif_read_from_memory.
12728 It's done this way because not all versions of libungif support
12729 a UserData field in the GifFileType structure. */
12730static gif_memory_source *current_gif_memory_src;
12731
12732static int
12733gif_read_from_memory (file, buf, len)
12734 GifFileType *file;
12735 GifByteType *buf;
12736 int len;
12737{
12738 gif_memory_source *src = current_gif_memory_src;
12739
12740 if (len > src->len - src->index)
12741 return -1;
12742
12743 bcopy (src->bytes + src->index, buf, len);
12744 src->index += len;
12745 return len;
12746}
12747
12748
12749/* Load GIF image IMG for use on frame F. Value is non-zero if
12750 successful. */
12751
12752static int
12753gif_load (f, img)
12754 struct frame *f;
12755 struct image *img;
12756{
12757 Lisp_Object file, specified_file;
12758 Lisp_Object specified_data;
12759 int rc, width, height, x, y, i;
12760 XImage *ximg;
12761 ColorMapObject *gif_color_map;
12762 unsigned long pixel_colors[256];
12763 GifFileType *gif;
12764 struct gcpro gcpro1;
12765 Lisp_Object image;
12766 int ino, image_left, image_top, image_width, image_height;
12767 gif_memory_source memsrc;
12768 unsigned char *raster;
12769
12770 specified_file = image_spec_value (img->spec, QCfile, NULL);
12771 specified_data = image_spec_value (img->spec, QCdata, NULL);
12772 file = Qnil;
dfff8a69 12773 GCPRO1 (file);
6fc2811b
JR
12774
12775 if (NILP (specified_data))
12776 {
12777 file = x_find_image_file (specified_file);
6fc2811b
JR
12778 if (!STRINGP (file))
12779 {
12780 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12781 UNGCPRO;
12782 return 0;
12783 }
12784
12785 /* Open the GIF file. */
12786 gif = DGifOpenFileName (XSTRING (file)->data);
12787 if (gif == NULL)
12788 {
12789 image_error ("Cannot open `%s'", file, Qnil);
12790 UNGCPRO;
12791 return 0;
12792 }
12793 }
12794 else
12795 {
12796 /* Read from memory! */
12797 current_gif_memory_src = &memsrc;
12798 memsrc.bytes = XSTRING (specified_data)->data;
12799 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12800 memsrc.index = 0;
12801
12802 gif = DGifOpen(&memsrc, gif_read_from_memory);
12803 if (!gif)
12804 {
12805 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12806 UNGCPRO;
12807 return 0;
12808 }
12809 }
12810
12811 /* Read entire contents. */
12812 rc = DGifSlurp (gif);
12813 if (rc == GIF_ERROR)
12814 {
12815 image_error ("Error reading `%s'", img->spec, Qnil);
12816 DGifCloseFile (gif);
12817 UNGCPRO;
12818 return 0;
12819 }
12820
12821 image = image_spec_value (img->spec, QCindex, NULL);
12822 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12823 if (ino >= gif->ImageCount)
12824 {
12825 image_error ("Invalid image number `%s' in image `%s'",
12826 image, img->spec);
12827 DGifCloseFile (gif);
12828 UNGCPRO;
12829 return 0;
12830 }
12831
12832 width = img->width = gif->SWidth;
12833 height = img->height = gif->SHeight;
12834
6fc2811b
JR
12835 /* Create the X image and pixmap. */
12836 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12837 {
6fc2811b
JR
12838 DGifCloseFile (gif);
12839 UNGCPRO;
12840 return 0;
12841 }
12842
12843 /* Allocate colors. */
12844 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12845 if (!gif_color_map)
12846 gif_color_map = gif->SColorMap;
12847 init_color_table ();
12848 bzero (pixel_colors, sizeof pixel_colors);
12849
12850 for (i = 0; i < gif_color_map->ColorCount; ++i)
12851 {
12852 int r = gif_color_map->Colors[i].Red << 8;
12853 int g = gif_color_map->Colors[i].Green << 8;
12854 int b = gif_color_map->Colors[i].Blue << 8;
12855 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12856 }
12857
12858 img->colors = colors_in_color_table (&img->ncolors);
12859 free_color_table ();
12860
12861 /* Clear the part of the screen image that are not covered by
12862 the image from the GIF file. Full animated GIF support
12863 requires more than can be done here (see the gif89 spec,
12864 disposal methods). Let's simply assume that the part
12865 not covered by a sub-image is in the frame's background color. */
12866 image_top = gif->SavedImages[ino].ImageDesc.Top;
12867 image_left = gif->SavedImages[ino].ImageDesc.Left;
12868 image_width = gif->SavedImages[ino].ImageDesc.Width;
12869 image_height = gif->SavedImages[ino].ImageDesc.Height;
12870
12871 for (y = 0; y < image_top; ++y)
12872 for (x = 0; x < width; ++x)
12873 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12874
12875 for (y = image_top + image_height; y < height; ++y)
12876 for (x = 0; x < width; ++x)
12877 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12878
12879 for (y = image_top; y < image_top + image_height; ++y)
12880 {
12881 for (x = 0; x < image_left; ++x)
12882 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12883 for (x = image_left + image_width; x < width; ++x)
12884 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12885 }
12886
12887 /* Read the GIF image into the X image. We use a local variable
12888 `raster' here because RasterBits below is a char *, and invites
12889 problems with bytes >= 0x80. */
12890 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12891
12892 if (gif->SavedImages[ino].ImageDesc.Interlace)
12893 {
12894 static int interlace_start[] = {0, 4, 2, 1};
12895 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12896 int pass;
6fc2811b
JR
12897 int row = interlace_start[0];
12898
12899 pass = 0;
12900
12901 for (y = 0; y < image_height; y++)
12902 {
12903 if (row >= image_height)
12904 {
12905 row = interlace_start[++pass];
12906 while (row >= image_height)
12907 row = interlace_start[++pass];
12908 }
12909
12910 for (x = 0; x < image_width; x++)
12911 {
12912 int i = raster[(y * image_width) + x];
12913 XPutPixel (ximg, x + image_left, row + image_top,
12914 pixel_colors[i]);
12915 }
12916
12917 row += interlace_increment[pass];
12918 }
12919 }
12920 else
12921 {
12922 for (y = 0; y < image_height; ++y)
12923 for (x = 0; x < image_width; ++x)
12924 {
12925 int i = raster[y* image_width + x];
12926 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12927 }
12928 }
12929
12930 DGifCloseFile (gif);
a05e2bae
JR
12931
12932 /* Maybe fill in the background field while we have ximg handy. */
12933 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12934 IMAGE_BACKGROUND (img, f, ximg);
12935
6fc2811b
JR
12936 /* Put the image into the pixmap, then free the X image and its buffer. */
12937 x_put_x_image (f, ximg, img->pixmap, width, height);
12938 x_destroy_x_image (ximg);
6fc2811b
JR
12939
12940 UNGCPRO;
12941 return 1;
12942}
12943
12944#endif /* HAVE_GIF != 0 */
12945
12946
12947\f
12948/***********************************************************************
12949 Ghostscript
12950 ***********************************************************************/
12951
3cf3436e
JR
12952Lisp_Object Qpostscript;
12953
6fc2811b
JR
12954#ifdef HAVE_GHOSTSCRIPT
12955static int gs_image_p P_ ((Lisp_Object object));
12956static int gs_load P_ ((struct frame *f, struct image *img));
12957static void gs_clear_image P_ ((struct frame *f, struct image *img));
12958
12959/* The symbol `postscript' identifying images of this type. */
12960
6fc2811b
JR
12961/* Keyword symbols. */
12962
12963Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12964
12965/* Indices of image specification fields in gs_format, below. */
12966
12967enum gs_keyword_index
12968{
12969 GS_TYPE,
12970 GS_PT_WIDTH,
12971 GS_PT_HEIGHT,
12972 GS_FILE,
12973 GS_LOADER,
12974 GS_BOUNDING_BOX,
12975 GS_ASCENT,
12976 GS_MARGIN,
12977 GS_RELIEF,
12978 GS_ALGORITHM,
12979 GS_HEURISTIC_MASK,
a05e2bae
JR
12980 GS_MASK,
12981 GS_BACKGROUND,
6fc2811b
JR
12982 GS_LAST
12983};
12984
12985/* Vector of image_keyword structures describing the format
12986 of valid user-defined image specifications. */
12987
12988static struct image_keyword gs_format[GS_LAST] =
12989{
12990 {":type", IMAGE_SYMBOL_VALUE, 1},
12991 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12992 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12993 {":file", IMAGE_STRING_VALUE, 1},
12994 {":loader", IMAGE_FUNCTION_VALUE, 0},
12995 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12996 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12997 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12998 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12999 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
13000 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13001 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13002 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
13003};
13004
13005/* Structure describing the image type `ghostscript'. */
13006
13007static struct image_type gs_type =
13008{
13009 &Qpostscript,
13010 gs_image_p,
13011 gs_load,
13012 gs_clear_image,
13013 NULL
13014};
13015
13016
13017/* Free X resources of Ghostscript image IMG which is used on frame F. */
13018
13019static void
13020gs_clear_image (f, img)
13021 struct frame *f;
13022 struct image *img;
13023{
13024 /* IMG->data.ptr_val may contain a recorded colormap. */
13025 xfree (img->data.ptr_val);
13026 x_clear_image (f, img);
13027}
13028
13029
13030/* Return non-zero if OBJECT is a valid Ghostscript image
13031 specification. */
13032
13033static int
13034gs_image_p (object)
13035 Lisp_Object object;
13036{
13037 struct image_keyword fmt[GS_LAST];
13038 Lisp_Object tem;
13039 int i;
13040
13041 bcopy (gs_format, fmt, sizeof fmt);
13042
13043 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
13044 || (fmt[GS_ASCENT].count
13045 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13046 return 0;
13047
13048 /* Bounding box must be a list or vector containing 4 integers. */
13049 tem = fmt[GS_BOUNDING_BOX].value;
13050 if (CONSP (tem))
13051 {
13052 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13053 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13054 return 0;
13055 if (!NILP (tem))
13056 return 0;
13057 }
13058 else if (VECTORP (tem))
13059 {
13060 if (XVECTOR (tem)->size != 4)
13061 return 0;
13062 for (i = 0; i < 4; ++i)
13063 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13064 return 0;
13065 }
13066 else
13067 return 0;
13068
13069 return 1;
13070}
13071
13072
13073/* Load Ghostscript image IMG for use on frame F. Value is non-zero
13074 if successful. */
13075
13076static int
13077gs_load (f, img)
13078 struct frame *f;
13079 struct image *img;
13080{
13081 char buffer[100];
13082 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13083 struct gcpro gcpro1, gcpro2;
13084 Lisp_Object frame;
13085 double in_width, in_height;
13086 Lisp_Object pixel_colors = Qnil;
13087
13088 /* Compute pixel size of pixmap needed from the given size in the
13089 image specification. Sizes in the specification are in pt. 1 pt
13090 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13091 info. */
13092 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13093 in_width = XFASTINT (pt_width) / 72.0;
13094 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13095 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13096 in_height = XFASTINT (pt_height) / 72.0;
13097 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13098
13099 /* Create the pixmap. */
13100 BLOCK_INPUT;
13101 xassert (img->pixmap == 0);
13102 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13103 img->width, img->height,
a05e2bae 13104 one_w32_display_info.n_cbits);
6fc2811b
JR
13105 UNBLOCK_INPUT;
13106
13107 if (!img->pixmap)
13108 {
13109 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13110 return 0;
13111 }
13112
13113 /* Call the loader to fill the pixmap. It returns a process object
13114 if successful. We do not record_unwind_protect here because
13115 other places in redisplay like calling window scroll functions
13116 don't either. Let the Lisp loader use `unwind-protect' instead. */
13117 GCPRO2 (window_and_pixmap_id, pixel_colors);
13118
13119 sprintf (buffer, "%lu %lu",
13120 (unsigned long) FRAME_W32_WINDOW (f),
13121 (unsigned long) img->pixmap);
13122 window_and_pixmap_id = build_string (buffer);
13123
13124 sprintf (buffer, "%lu %lu",
13125 FRAME_FOREGROUND_PIXEL (f),
13126 FRAME_BACKGROUND_PIXEL (f));
13127 pixel_colors = build_string (buffer);
13128
13129 XSETFRAME (frame, f);
13130 loader = image_spec_value (img->spec, QCloader, NULL);
13131 if (NILP (loader))
13132 loader = intern ("gs-load-image");
13133
13134 img->data.lisp_val = call6 (loader, frame, img->spec,
13135 make_number (img->width),
13136 make_number (img->height),
13137 window_and_pixmap_id,
13138 pixel_colors);
13139 UNGCPRO;
13140 return PROCESSP (img->data.lisp_val);
13141}
13142
13143
13144/* Kill the Ghostscript process that was started to fill PIXMAP on
13145 frame F. Called from XTread_socket when receiving an event
13146 telling Emacs that Ghostscript has finished drawing. */
13147
13148void
13149x_kill_gs_process (pixmap, f)
13150 Pixmap pixmap;
13151 struct frame *f;
13152{
13153 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13154 int class, i;
13155 struct image *img;
13156
13157 /* Find the image containing PIXMAP. */
13158 for (i = 0; i < c->used; ++i)
13159 if (c->images[i]->pixmap == pixmap)
13160 break;
13161
3cf3436e
JR
13162 /* Should someone in between have cleared the image cache, for
13163 instance, give up. */
13164 if (i == c->used)
13165 return;
13166
6fc2811b
JR
13167 /* Kill the GS process. We should have found PIXMAP in the image
13168 cache and its image should contain a process object. */
6fc2811b
JR
13169 img = c->images[i];
13170 xassert (PROCESSP (img->data.lisp_val));
13171 Fkill_process (img->data.lisp_val, Qnil);
13172 img->data.lisp_val = Qnil;
13173
13174 /* On displays with a mutable colormap, figure out the colors
13175 allocated for the image by looking at the pixels of an XImage for
13176 img->pixmap. */
13177 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13178 if (class != StaticColor && class != StaticGray && class != TrueColor)
13179 {
13180 XImage *ximg;
13181
13182 BLOCK_INPUT;
13183
13184 /* Try to get an XImage for img->pixmep. */
13185 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13186 0, 0, img->width, img->height, ~0, ZPixmap);
13187 if (ximg)
13188 {
13189 int x, y;
13190
13191 /* Initialize the color table. */
13192 init_color_table ();
13193
13194 /* For each pixel of the image, look its color up in the
13195 color table. After having done so, the color table will
13196 contain an entry for each color used by the image. */
13197 for (y = 0; y < img->height; ++y)
13198 for (x = 0; x < img->width; ++x)
13199 {
13200 unsigned long pixel = XGetPixel (ximg, x, y);
13201 lookup_pixel_color (f, pixel);
13202 }
13203
13204 /* Record colors in the image. Free color table and XImage. */
13205 img->colors = colors_in_color_table (&img->ncolors);
13206 free_color_table ();
13207 XDestroyImage (ximg);
13208
13209#if 0 /* This doesn't seem to be the case. If we free the colors
13210 here, we get a BadAccess later in x_clear_image when
13211 freeing the colors. */
13212 /* We have allocated colors once, but Ghostscript has also
13213 allocated colors on behalf of us. So, to get the
13214 reference counts right, free them once. */
13215 if (img->ncolors)
3cf3436e 13216 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 13217 img->colors, img->ncolors, 0);
6fc2811b
JR
13218#endif
13219 }
13220 else
13221 image_error ("Cannot get X image of `%s'; colors will not be freed",
13222 img->spec, Qnil);
13223
13224 UNBLOCK_INPUT;
13225 }
3cf3436e
JR
13226
13227 /* Now that we have the pixmap, compute mask and transform the
13228 image if requested. */
13229 BLOCK_INPUT;
13230 postprocess_image (f, img);
13231 UNBLOCK_INPUT;
6fc2811b
JR
13232}
13233
13234#endif /* HAVE_GHOSTSCRIPT */
13235
13236\f
13237/***********************************************************************
13238 Window properties
13239 ***********************************************************************/
13240
13241DEFUN ("x-change-window-property", Fx_change_window_property,
13242 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
13243 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13244PROP and VALUE must be strings. FRAME nil or omitted means use the
13245selected frame. Value is VALUE. */)
6fc2811b
JR
13246 (prop, value, frame)
13247 Lisp_Object frame, prop, value;
13248{
767b1ff0 13249#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13250 struct frame *f = check_x_frame (frame);
13251 Atom prop_atom;
13252
b7826503
PJ
13253 CHECK_STRING (prop);
13254 CHECK_STRING (value);
6fc2811b
JR
13255
13256 BLOCK_INPUT;
13257 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13258 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13259 prop_atom, XA_STRING, 8, PropModeReplace,
13260 XSTRING (value)->data, XSTRING (value)->size);
13261
13262 /* Make sure the property is set when we return. */
13263 XFlush (FRAME_W32_DISPLAY (f));
13264 UNBLOCK_INPUT;
13265
767b1ff0 13266#endif /* TODO */
6fc2811b
JR
13267
13268 return value;
13269}
13270
13271
13272DEFUN ("x-delete-window-property", Fx_delete_window_property,
13273 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
13274 doc: /* Remove window property PROP from X window of FRAME.
13275FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
13276 (prop, frame)
13277 Lisp_Object prop, frame;
13278{
767b1ff0 13279#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13280
13281 struct frame *f = check_x_frame (frame);
13282 Atom prop_atom;
13283
b7826503 13284 CHECK_STRING (prop);
6fc2811b
JR
13285 BLOCK_INPUT;
13286 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13287 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13288
13289 /* Make sure the property is removed when we return. */
13290 XFlush (FRAME_W32_DISPLAY (f));
13291 UNBLOCK_INPUT;
767b1ff0 13292#endif /* TODO */
6fc2811b
JR
13293
13294 return prop;
13295}
13296
13297
13298DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13299 1, 2, 0,
74e1aeec
JR
13300 doc: /* Value is the value of window property PROP on FRAME.
13301If FRAME is nil or omitted, use the selected frame. Value is nil
13302if FRAME hasn't a property with name PROP or if PROP has no string
13303value. */)
6fc2811b
JR
13304 (prop, frame)
13305 Lisp_Object prop, frame;
13306{
767b1ff0 13307#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13308
13309 struct frame *f = check_x_frame (frame);
13310 Atom prop_atom;
13311 int rc;
13312 Lisp_Object prop_value = Qnil;
13313 char *tmp_data = NULL;
13314 Atom actual_type;
13315 int actual_format;
13316 unsigned long actual_size, bytes_remaining;
13317
b7826503 13318 CHECK_STRING (prop);
6fc2811b
JR
13319 BLOCK_INPUT;
13320 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13321 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13322 prop_atom, 0, 0, False, XA_STRING,
13323 &actual_type, &actual_format, &actual_size,
13324 &bytes_remaining, (unsigned char **) &tmp_data);
13325 if (rc == Success)
13326 {
13327 int size = bytes_remaining;
13328
13329 XFree (tmp_data);
13330 tmp_data = NULL;
13331
13332 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13333 prop_atom, 0, bytes_remaining,
13334 False, XA_STRING,
13335 &actual_type, &actual_format,
13336 &actual_size, &bytes_remaining,
13337 (unsigned char **) &tmp_data);
13338 if (rc == Success)
13339 prop_value = make_string (tmp_data, size);
13340
13341 XFree (tmp_data);
13342 }
13343
13344 UNBLOCK_INPUT;
13345
13346 return prop_value;
13347
767b1ff0 13348#endif /* TODO */
6fc2811b
JR
13349 return Qnil;
13350}
13351
13352
13353\f
13354/***********************************************************************
13355 Busy cursor
13356 ***********************************************************************/
13357
f79e6790 13358/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 13359 an hourglass cursor on all frames. */
6fc2811b 13360
0af913d7 13361static struct atimer *hourglass_atimer;
6fc2811b 13362
0af913d7 13363/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 13364
0af913d7 13365static int hourglass_shown_p;
6fc2811b 13366
0af913d7 13367/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 13368
0af913d7 13369static Lisp_Object Vhourglass_delay;
6fc2811b 13370
0af913d7 13371/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
13372 cursor. */
13373
0af913d7 13374#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
13375
13376/* Function prototypes. */
13377
0af913d7
GM
13378static void show_hourglass P_ ((struct atimer *));
13379static void hide_hourglass P_ ((void));
f79e6790
JR
13380
13381
0af913d7 13382/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
13383
13384void
0af913d7 13385start_hourglass ()
f79e6790 13386{
767b1ff0 13387#if 0 /* TODO: cursor shape changes. */
f79e6790 13388 EMACS_TIME delay;
dfff8a69 13389 int secs, usecs = 0;
f79e6790 13390
0af913d7 13391 cancel_hourglass ();
f79e6790 13392
0af913d7
GM
13393 if (INTEGERP (Vhourglass_delay)
13394 && XINT (Vhourglass_delay) > 0)
13395 secs = XFASTINT (Vhourglass_delay);
13396 else if (FLOATP (Vhourglass_delay)
13397 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
13398 {
13399 Lisp_Object tem;
0af913d7 13400 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 13401 secs = XFASTINT (tem);
0af913d7 13402 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 13403 }
f79e6790 13404 else
0af913d7 13405 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 13406
dfff8a69 13407 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
13408 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13409 show_hourglass, NULL);
f79e6790
JR
13410#endif
13411}
13412
13413
0af913d7
GM
13414/* Cancel the hourglass cursor timer if active, hide an hourglass
13415 cursor if shown. */
f79e6790
JR
13416
13417void
0af913d7 13418cancel_hourglass ()
f79e6790 13419{
0af913d7 13420 if (hourglass_atimer)
dfff8a69 13421 {
0af913d7
GM
13422 cancel_atimer (hourglass_atimer);
13423 hourglass_atimer = NULL;
dfff8a69
JR
13424 }
13425
0af913d7
GM
13426 if (hourglass_shown_p)
13427 hide_hourglass ();
f79e6790
JR
13428}
13429
13430
0af913d7
GM
13431/* Timer function of hourglass_atimer. TIMER is equal to
13432 hourglass_atimer.
f79e6790 13433
0af913d7
GM
13434 Display an hourglass cursor on all frames by mapping the frames'
13435 hourglass_window. Set the hourglass_p flag in the frames'
13436 output_data.x structure to indicate that an hourglass cursor is
13437 shown on the frames. */
f79e6790
JR
13438
13439static void
0af913d7 13440show_hourglass (timer)
f79e6790 13441 struct atimer *timer;
6fc2811b 13442{
767b1ff0 13443#if 0 /* TODO: cursor shape changes. */
f79e6790 13444 /* The timer implementation will cancel this timer automatically
0af913d7 13445 after this function has run. Set hourglass_atimer to null
f79e6790 13446 so that we know the timer doesn't have to be canceled. */
0af913d7 13447 hourglass_atimer = NULL;
f79e6790 13448
0af913d7 13449 if (!hourglass_shown_p)
6fc2811b
JR
13450 {
13451 Lisp_Object rest, frame;
f79e6790
JR
13452
13453 BLOCK_INPUT;
13454
6fc2811b 13455 FOR_EACH_FRAME (rest, frame)
dc220243 13456 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13457 {
13458 struct frame *f = XFRAME (frame);
f79e6790 13459
0af913d7 13460 f->output_data.w32->hourglass_p = 1;
f79e6790 13461
0af913d7 13462 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13463 {
13464 unsigned long mask = CWCursor;
13465 XSetWindowAttributes attrs;
f79e6790 13466
0af913d7 13467 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13468
0af913d7 13469 f->output_data.w32->hourglass_window
f79e6790 13470 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13471 FRAME_OUTER_WINDOW (f),
13472 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13473 InputOnly,
13474 CopyFromParent,
6fc2811b
JR
13475 mask, &attrs);
13476 }
f79e6790 13477
0af913d7
GM
13478 XMapRaised (FRAME_X_DISPLAY (f),
13479 f->output_data.w32->hourglass_window);
f79e6790 13480 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13481 }
6fc2811b 13482
0af913d7 13483 hourglass_shown_p = 1;
f79e6790
JR
13484 UNBLOCK_INPUT;
13485 }
13486#endif
6fc2811b
JR
13487}
13488
13489
0af913d7 13490/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13491
f79e6790 13492static void
0af913d7 13493hide_hourglass ()
f79e6790 13494{
767b1ff0 13495#if 0 /* TODO: cursor shape changes. */
0af913d7 13496 if (hourglass_shown_p)
6fc2811b 13497 {
f79e6790
JR
13498 Lisp_Object rest, frame;
13499
13500 BLOCK_INPUT;
13501 FOR_EACH_FRAME (rest, frame)
6fc2811b 13502 {
f79e6790
JR
13503 struct frame *f = XFRAME (frame);
13504
dc220243 13505 if (FRAME_W32_P (f)
f79e6790 13506 /* Watch out for newly created frames. */
0af913d7 13507 && f->output_data.x->hourglass_window)
f79e6790 13508 {
0af913d7
GM
13509 XUnmapWindow (FRAME_X_DISPLAY (f),
13510 f->output_data.x->hourglass_window);
13511 /* Sync here because XTread_socket looks at the
13512 hourglass_p flag that is reset to zero below. */
f79e6790 13513 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13514 f->output_data.x->hourglass_p = 0;
f79e6790 13515 }
6fc2811b 13516 }
6fc2811b 13517
0af913d7 13518 hourglass_shown_p = 0;
f79e6790
JR
13519 UNBLOCK_INPUT;
13520 }
13521#endif
6fc2811b
JR
13522}
13523
13524
13525\f
13526/***********************************************************************
13527 Tool tips
13528 ***********************************************************************/
13529
13530static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13531 Lisp_Object, Lisp_Object));
13532static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13533 Lisp_Object, int, int, int *, int *));
6fc2811b 13534
3cf3436e 13535/* The frame of a currently visible tooltip. */
6fc2811b 13536
937e601e 13537Lisp_Object tip_frame;
6fc2811b
JR
13538
13539/* If non-nil, a timer started that hides the last tooltip when it
13540 fires. */
13541
13542Lisp_Object tip_timer;
13543Window tip_window;
13544
3cf3436e
JR
13545/* If non-nil, a vector of 3 elements containing the last args
13546 with which x-show-tip was called. See there. */
13547
13548Lisp_Object last_show_tip_args;
13549
13550/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13551
13552Lisp_Object Vx_max_tooltip_size;
13553
13554
937e601e
AI
13555static Lisp_Object
13556unwind_create_tip_frame (frame)
13557 Lisp_Object frame;
13558{
c844a81a
GM
13559 Lisp_Object deleted;
13560
13561 deleted = unwind_create_frame (frame);
13562 if (EQ (deleted, Qt))
13563 {
13564 tip_window = NULL;
13565 tip_frame = Qnil;
13566 }
13567
13568 return deleted;
937e601e
AI
13569}
13570
13571
6fc2811b 13572/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13573 PARMS is a list of frame parameters. TEXT is the string to
13574 display in the tip frame. Value is the frame.
937e601e
AI
13575
13576 Note that functions called here, esp. x_default_parameter can
13577 signal errors, for instance when a specified color name is
13578 undefined. We have to make sure that we're in a consistent state
13579 when this happens. */
6fc2811b
JR
13580
13581static Lisp_Object
3cf3436e 13582x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13583 struct w32_display_info *dpyinfo;
3cf3436e 13584 Lisp_Object parms, text;
6fc2811b 13585{
6fc2811b
JR
13586 struct frame *f;
13587 Lisp_Object frame, tem;
13588 Lisp_Object name;
13589 long window_prompting = 0;
13590 int width, height;
dc220243 13591 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13592 struct gcpro gcpro1, gcpro2, gcpro3;
13593 struct kboard *kb;
3cf3436e
JR
13594 int face_change_count_before = face_change_count;
13595 Lisp_Object buffer;
13596 struct buffer *old_buffer;
6fc2811b 13597
ca56d953 13598 check_w32 ();
6fc2811b
JR
13599
13600 /* Use this general default value to start with until we know if
13601 this frame has a specified name. */
13602 Vx_resource_name = Vinvocation_name;
13603
13604#ifdef MULTI_KBOARD
13605 kb = dpyinfo->kboard;
13606#else
13607 kb = &the_only_kboard;
13608#endif
13609
13610 /* Get the name of the frame to use for resource lookup. */
13611 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13612 if (!STRINGP (name)
13613 && !EQ (name, Qunbound)
13614 && !NILP (name))
13615 error ("Invalid frame name--not a string or nil");
13616 Vx_resource_name = name;
13617
13618 frame = Qnil;
13619 GCPRO3 (parms, name, frame);
9eb16b62
JR
13620 /* Make a frame without minibuffer nor mode-line. */
13621 f = make_frame (0);
13622 f->wants_modeline = 0;
6fc2811b 13623 XSETFRAME (frame, f);
3cf3436e
JR
13624
13625 buffer = Fget_buffer_create (build_string (" *tip*"));
13626 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13627 old_buffer = current_buffer;
13628 set_buffer_internal_1 (XBUFFER (buffer));
13629 current_buffer->truncate_lines = Qnil;
13630 Ferase_buffer ();
13631 Finsert (1, &text);
13632 set_buffer_internal_1 (old_buffer);
13633
6fc2811b 13634 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13635 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13636
3cf3436e
JR
13637 /* By setting the output method, we're essentially saying that
13638 the frame is live, as per FRAME_LIVE_P. If we get a signal
13639 from this point on, x_destroy_window might screw up reference
13640 counts etc. */
d88c567c 13641 f->output_method = output_w32;
6fc2811b
JR
13642 f->output_data.w32 =
13643 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13644 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13645
13646 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13647 f->icon_name = Qnil;
13648
ca56d953 13649#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13650 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13651 dpyinfo_refcount = dpyinfo->reference_count;
13652#endif /* GLYPH_DEBUG */
6fc2811b
JR
13653#ifdef MULTI_KBOARD
13654 FRAME_KBOARD (f) = kb;
13655#endif
13656 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13657 f->output_data.w32->explicit_parent = 0;
13658
13659 /* Set the name; the functions to which we pass f expect the name to
13660 be set. */
13661 if (EQ (name, Qunbound) || NILP (name))
13662 {
ca56d953 13663 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13664 f->explicit_name = 0;
13665 }
13666 else
13667 {
13668 f->name = name;
13669 f->explicit_name = 1;
13670 /* use the frame's title when getting resources for this frame. */
13671 specbind (Qx_resource_name, name);
13672 }
13673
6fc2811b
JR
13674 /* Extract the window parameters from the supplied values
13675 that are needed to determine window geometry. */
13676 {
13677 Lisp_Object font;
13678
13679 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13680
13681 BLOCK_INPUT;
13682 /* First, try whatever font the caller has specified. */
13683 if (STRINGP (font))
13684 {
13685 tem = Fquery_fontset (font, Qnil);
13686 if (STRINGP (tem))
13687 font = x_new_fontset (f, XSTRING (tem)->data);
13688 else
13689 font = x_new_font (f, XSTRING (font)->data);
13690 }
13691
13692 /* Try out a font which we hope has bold and italic variations. */
13693 if (!STRINGP (font))
ca56d953 13694 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13695 if (! STRINGP (font))
ca56d953 13696 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13697 /* If those didn't work, look for something which will at least work. */
13698 if (! STRINGP (font))
ca56d953 13699 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13700 UNBLOCK_INPUT;
13701 if (! STRINGP (font))
ca56d953 13702 font = build_string ("Fixedsys");
6fc2811b
JR
13703
13704 x_default_parameter (f, parms, Qfont, font,
13705 "font", "Font", RES_TYPE_STRING);
13706 }
13707
13708 x_default_parameter (f, parms, Qborder_width, make_number (2),
13709 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13710 /* This defaults to 2 in order to match xterm. We recognize either
13711 internalBorderWidth or internalBorder (which is what xterm calls
13712 it). */
13713 if (NILP (Fassq (Qinternal_border_width, parms)))
13714 {
13715 Lisp_Object value;
13716
13717 value = w32_get_arg (parms, Qinternal_border_width,
13718 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13719 if (! EQ (value, Qunbound))
13720 parms = Fcons (Fcons (Qinternal_border_width, value),
13721 parms);
13722 }
bfd6edcc 13723 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13724 "internalBorderWidth", "internalBorderWidth",
13725 RES_TYPE_NUMBER);
13726
13727 /* Also do the stuff which must be set before the window exists. */
13728 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13729 "foreground", "Foreground", RES_TYPE_STRING);
13730 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13731 "background", "Background", RES_TYPE_STRING);
13732 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13733 "pointerColor", "Foreground", RES_TYPE_STRING);
13734 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13735 "cursorColor", "Foreground", RES_TYPE_STRING);
13736 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13737 "borderColor", "BorderColor", RES_TYPE_STRING);
13738
13739 /* Init faces before x_default_parameter is called for scroll-bar
13740 parameters because that function calls x_set_scroll_bar_width,
13741 which calls change_frame_size, which calls Fset_window_buffer,
13742 which runs hooks, which call Fvertical_motion. At the end, we
13743 end up in init_iterator with a null face cache, which should not
13744 happen. */
13745 init_frame_faces (f);
ca56d953
JR
13746
13747 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13748 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13749
6fc2811b
JR
13750 window_prompting = x_figure_window_size (f, parms);
13751
9eb16b62
JR
13752 /* No fringes on tip frame. */
13753 f->output_data.w32->fringes_extra = 0;
13754 f->output_data.w32->fringe_cols = 0;
13755 f->output_data.w32->left_fringe_width = 0;
13756 f->output_data.w32->right_fringe_width = 0;
13757
6fc2811b
JR
13758 if (window_prompting & XNegative)
13759 {
13760 if (window_prompting & YNegative)
13761 f->output_data.w32->win_gravity = SouthEastGravity;
13762 else
13763 f->output_data.w32->win_gravity = NorthEastGravity;
13764 }
13765 else
13766 {
13767 if (window_prompting & YNegative)
13768 f->output_data.w32->win_gravity = SouthWestGravity;
13769 else
13770 f->output_data.w32->win_gravity = NorthWestGravity;
13771 }
13772
13773 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13774
13775 BLOCK_INPUT;
13776 my_create_tip_window (f);
13777 UNBLOCK_INPUT;
6fc2811b
JR
13778
13779 x_make_gc (f);
13780
13781 x_default_parameter (f, parms, Qauto_raise, Qnil,
13782 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13783 x_default_parameter (f, parms, Qauto_lower, Qnil,
13784 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13785 x_default_parameter (f, parms, Qcursor_type, Qbox,
13786 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13787
13788 /* Dimensions, especially f->height, must be done via change_frame_size.
13789 Change will not be effected unless different from the current
13790 f->height. */
13791 width = f->width;
13792 height = f->height;
13793 f->height = 0;
13794 SET_FRAME_WIDTH (f, 0);
13795 change_frame_size (f, height, width, 1, 0, 0);
13796
3cf3436e
JR
13797 /* Set up faces after all frame parameters are known. This call
13798 also merges in face attributes specified for new frames.
13799
13800 Frame parameters may be changed if .Xdefaults contains
13801 specifications for the default font. For example, if there is an
13802 `Emacs.default.attributeBackground: pink', the `background-color'
13803 attribute of the frame get's set, which let's the internal border
13804 of the tooltip frame appear in pink. Prevent this. */
13805 {
13806 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13807
13808 /* Set tip_frame here, so that */
13809 tip_frame = frame;
13810 call1 (Qface_set_after_frame_default, frame);
13811
13812 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13813 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13814 Qnil));
13815 }
13816
6fc2811b
JR
13817 f->no_split = 1;
13818
13819 UNGCPRO;
13820
13821 /* It is now ok to make the frame official even if we get an error
13822 below. And the frame needs to be on Vframe_list or making it
13823 visible won't work. */
13824 Vframe_list = Fcons (frame, Vframe_list);
13825
13826 /* Now that the frame is official, it counts as a reference to
13827 its display. */
13828 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13829
3cf3436e
JR
13830 /* Setting attributes of faces of the tooltip frame from resources
13831 and similar will increment face_change_count, which leads to the
13832 clearing of all current matrices. Since this isn't necessary
13833 here, avoid it by resetting face_change_count to the value it
13834 had before we created the tip frame. */
13835 face_change_count = face_change_count_before;
13836
13837 /* Discard the unwind_protect. */
6fc2811b 13838 return unbind_to (count, frame);
ee78dc32
GV
13839}
13840
3cf3436e
JR
13841
13842/* Compute where to display tip frame F. PARMS is the list of frame
13843 parameters for F. DX and DY are specified offsets from the current
13844 location of the mouse. WIDTH and HEIGHT are the width and height
13845 of the tooltip. Return coordinates relative to the root window of
13846 the display in *ROOT_X, and *ROOT_Y. */
13847
13848static void
13849compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13850 struct frame *f;
13851 Lisp_Object parms, dx, dy;
13852 int width, height;
13853 int *root_x, *root_y;
13854{
3cf3436e 13855 Lisp_Object left, top;
3cf3436e
JR
13856
13857 /* User-specified position? */
13858 left = Fcdr (Fassq (Qleft, parms));
13859 top = Fcdr (Fassq (Qtop, parms));
13860
13861 /* Move the tooltip window where the mouse pointer is. Resize and
13862 show it. */
ca56d953 13863 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13864 {
ca56d953
JR
13865 POINT pt;
13866
3cf3436e 13867 BLOCK_INPUT;
ca56d953
JR
13868 GetCursorPos (&pt);
13869 *root_x = pt.x;
13870 *root_y = pt.y;
3cf3436e
JR
13871 UNBLOCK_INPUT;
13872 }
13873
13874 if (INTEGERP (top))
13875 *root_y = XINT (top);
13876 else if (*root_y + XINT (dy) - height < 0)
13877 *root_y -= XINT (dy);
13878 else
13879 {
13880 *root_y -= height;
13881 *root_y += XINT (dy);
13882 }
13883
13884 if (INTEGERP (left))
13885 *root_x = XINT (left);
72e4adef
JR
13886 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13887 /* It fits to the right of the pointer. */
13888 *root_x += XINT (dx);
13889 else if (width + XINT (dx) <= *root_x)
13890 /* It fits to the left of the pointer. */
3cf3436e
JR
13891 *root_x -= width + XINT (dx);
13892 else
72e4adef
JR
13893 /* Put it left justified on the screen -- it ought to fit that way. */
13894 *root_x = 0;
3cf3436e
JR
13895}
13896
13897
71eab8d1 13898DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13899 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13900A tooltip window is a small window displaying a string.
13901
13902FRAME nil or omitted means use the selected frame.
13903
13904PARMS is an optional list of frame parameters which can be
13905used to change the tooltip's appearance.
13906
ca56d953
JR
13907Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13908means use the default timeout of 5 seconds.
74e1aeec 13909
ca56d953 13910If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13911the tooltip is displayed at that x-position. Otherwise it is
13912displayed at the mouse position, with offset DX added (default is 5 if
13913DX isn't specified). Likewise for the y-position; if a `top' frame
13914parameter is specified, it determines the y-position of the tooltip
13915window, otherwise it is displayed at the mouse position, with offset
13916DY added (default is -10).
13917
13918A tooltip's maximum size is specified by `x-max-tooltip-size'.
13919Text larger than the specified size is clipped. */)
71eab8d1
AI
13920 (string, frame, parms, timeout, dx, dy)
13921 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13922{
6fc2811b
JR
13923 struct frame *f;
13924 struct window *w;
3cf3436e 13925 int root_x, root_y;
6fc2811b
JR
13926 struct buffer *old_buffer;
13927 struct text_pos pos;
13928 int i, width, height;
6fc2811b
JR
13929 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13930 int old_windows_or_buffers_changed = windows_or_buffers_changed;
ca56d953 13931 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13932
13933 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13934
dfff8a69 13935 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13936
b7826503 13937 CHECK_STRING (string);
6fc2811b
JR
13938 f = check_x_frame (frame);
13939 if (NILP (timeout))
13940 timeout = make_number (5);
13941 else
b7826503 13942 CHECK_NATNUM (timeout);
ee78dc32 13943
71eab8d1
AI
13944 if (NILP (dx))
13945 dx = make_number (5);
13946 else
b7826503 13947 CHECK_NUMBER (dx);
71eab8d1
AI
13948
13949 if (NILP (dy))
dc220243 13950 dy = make_number (-10);
71eab8d1 13951 else
b7826503 13952 CHECK_NUMBER (dy);
71eab8d1 13953
dc220243
JR
13954 if (NILP (last_show_tip_args))
13955 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13956
13957 if (!NILP (tip_frame))
13958 {
13959 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13960 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13961 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13962
13963 if (EQ (frame, last_frame)
13964 && !NILP (Fequal (last_string, string))
13965 && !NILP (Fequal (last_parms, parms)))
13966 {
13967 struct frame *f = XFRAME (tip_frame);
13968
13969 /* Only DX and DY have changed. */
13970 if (!NILP (tip_timer))
13971 {
13972 Lisp_Object timer = tip_timer;
13973 tip_timer = Qnil;
13974 call1 (Qcancel_timer, timer);
13975 }
13976
13977 BLOCK_INPUT;
ca56d953
JR
13978 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13979 PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
13980
13981 /* Put tooltip in topmost group and in position. */
ca56d953
JR
13982 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13983 root_x, root_y, 0, 0,
13984 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
13985
13986 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13987 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13988 0, 0, 0, 0,
13989 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13990
dc220243
JR
13991 UNBLOCK_INPUT;
13992 goto start_timer;
13993 }
13994 }
13995
6fc2811b
JR
13996 /* Hide a previous tip, if any. */
13997 Fx_hide_tip ();
ee78dc32 13998
dc220243
JR
13999 ASET (last_show_tip_args, 0, string);
14000 ASET (last_show_tip_args, 1, frame);
14001 ASET (last_show_tip_args, 2, parms);
14002
6fc2811b
JR
14003 /* Add default values to frame parameters. */
14004 if (NILP (Fassq (Qname, parms)))
14005 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14006 if (NILP (Fassq (Qinternal_border_width, parms)))
14007 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14008 if (NILP (Fassq (Qborder_width, parms)))
14009 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14010 if (NILP (Fassq (Qborder_color, parms)))
14011 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14012 if (NILP (Fassq (Qbackground_color, parms)))
14013 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14014 parms);
14015
0e3fcdef
JR
14016 /* Block input until the tip has been fully drawn, to avoid crashes
14017 when drawing tips in menus. */
14018 BLOCK_INPUT;
14019
6fc2811b
JR
14020 /* Create a frame for the tooltip, and record it in the global
14021 variable tip_frame. */
ca56d953 14022 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 14023 f = XFRAME (frame);
6fc2811b 14024
3cf3436e 14025 /* Set up the frame's root window. */
6fc2811b
JR
14026 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14027 w->left = w->top = make_number (0);
3cf3436e
JR
14028
14029 if (CONSP (Vx_max_tooltip_size)
14030 && INTEGERP (XCAR (Vx_max_tooltip_size))
14031 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14032 && INTEGERP (XCDR (Vx_max_tooltip_size))
14033 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14034 {
14035 w->width = XCAR (Vx_max_tooltip_size);
14036 w->height = XCDR (Vx_max_tooltip_size);
14037 }
14038 else
14039 {
14040 w->width = make_number (80);
14041 w->height = make_number (40);
14042 }
14043
14044 f->window_width = XINT (w->width);
6fc2811b
JR
14045 adjust_glyphs (f);
14046 w->pseudo_window_p = 1;
14047
14048 /* Display the tooltip text in a temporary buffer. */
6fc2811b 14049 old_buffer = current_buffer;
3cf3436e
JR
14050 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14051 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
14052 clear_glyph_matrix (w->desired_matrix);
14053 clear_glyph_matrix (w->current_matrix);
14054 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14055 try_window (FRAME_ROOT_WINDOW (f), pos);
14056
14057 /* Compute width and height of the tooltip. */
14058 width = height = 0;
14059 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 14060 {
6fc2811b
JR
14061 struct glyph_row *row = &w->desired_matrix->rows[i];
14062 struct glyph *last;
14063 int row_width;
14064
14065 /* Stop at the first empty row at the end. */
14066 if (!row->enabled_p || !row->displays_text_p)
14067 break;
14068
14069 /* Let the row go over the full width of the frame. */
14070 row->full_width_p = 1;
14071
4e3a1c61
JR
14072#ifdef TODO /* Investigate why some fonts need more width than is
14073 calculated for some tooltips. */
6fc2811b
JR
14074 /* There's a glyph at the end of rows that is use to place
14075 the cursor there. Don't include the width of this glyph. */
14076 if (row->used[TEXT_AREA])
14077 {
14078 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14079 row_width = row->pixel_width - last->pixel_width;
14080 }
14081 else
4e3a1c61 14082#endif
6fc2811b
JR
14083 row_width = row->pixel_width;
14084
ca56d953 14085 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 14086 height += row->height;
6fc2811b 14087 width = max (width, row_width);
ee78dc32
GV
14088 }
14089
6fc2811b
JR
14090 /* Add the frame's internal border to the width and height the X
14091 window should have. */
14092 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14093 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 14094
6fc2811b
JR
14095 /* Move the tooltip window where the mouse pointer is. Resize and
14096 show it. */
3cf3436e 14097 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 14098
bfd6edcc
JR
14099 {
14100 /* Adjust Window size to take border into account. */
14101 RECT rect;
14102 rect.left = rect.top = 0;
14103 rect.right = width;
14104 rect.bottom = height;
14105 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14106 FRAME_EXTERNAL_MENU_BAR (f));
14107
d65a9cdc 14108 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
14109 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14110 root_x, root_y, rect.right - rect.left,
14111 rect.bottom - rect.top, SWP_NOACTIVATE);
14112
d65a9cdc
JR
14113 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14114 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14115 0, 0, 0, 0,
14116 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14117
bfd6edcc
JR
14118 /* Let redisplay know that we have made the frame visible already. */
14119 f->async_visible = 1;
14120
14121 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14122 }
ee78dc32 14123
6fc2811b
JR
14124 /* Draw into the window. */
14125 w->must_be_updated_p = 1;
14126 update_single_window (w, 1);
ee78dc32 14127
0e3fcdef
JR
14128 UNBLOCK_INPUT;
14129
6fc2811b
JR
14130 /* Restore original current buffer. */
14131 set_buffer_internal_1 (old_buffer);
14132 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 14133
dc220243 14134 start_timer:
6fc2811b
JR
14135 /* Let the tip disappear after timeout seconds. */
14136 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14137 intern ("x-hide-tip"));
ee78dc32 14138
dfff8a69 14139 UNGCPRO;
6fc2811b 14140 return unbind_to (count, Qnil);
ee78dc32
GV
14141}
14142
ee78dc32 14143
6fc2811b 14144DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
14145 doc: /* Hide the current tooltip window, if there is any.
14146Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
14147 ()
14148{
937e601e
AI
14149 int count;
14150 Lisp_Object deleted, frame, timer;
14151 struct gcpro gcpro1, gcpro2;
14152
14153 /* Return quickly if nothing to do. */
14154 if (NILP (tip_timer) && NILP (tip_frame))
14155 return Qnil;
14156
14157 frame = tip_frame;
14158 timer = tip_timer;
14159 GCPRO2 (frame, timer);
14160 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 14161
937e601e 14162 count = BINDING_STACK_SIZE ();
6fc2811b 14163 specbind (Qinhibit_redisplay, Qt);
937e601e 14164 specbind (Qinhibit_quit, Qt);
6fc2811b 14165
937e601e 14166 if (!NILP (timer))
dc220243 14167 call1 (Qcancel_timer, timer);
ee78dc32 14168
937e601e 14169 if (FRAMEP (frame))
6fc2811b 14170 {
937e601e
AI
14171 Fdelete_frame (frame, Qnil);
14172 deleted = Qt;
6fc2811b 14173 }
1edf84e7 14174
937e601e
AI
14175 UNGCPRO;
14176 return unbind_to (count, deleted);
6fc2811b 14177}
5ac45f98 14178
5ac45f98 14179
6fc2811b
JR
14180\f
14181/***********************************************************************
14182 File selection dialog
14183 ***********************************************************************/
14184
14185extern Lisp_Object Qfile_name_history;
14186
14187DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
14188 doc: /* Read file name, prompting with PROMPT in directory DIR.
14189Use a file selection dialog.
14190Select DEFAULT-FILENAME in the dialog's file selection box, if
14191specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
14192 (prompt, dir, default_filename, mustmatch)
14193 Lisp_Object prompt, dir, default_filename, mustmatch;
14194{
14195 struct frame *f = SELECTED_FRAME ();
14196 Lisp_Object file = Qnil;
14197 int count = specpdl_ptr - specpdl;
14198 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14199 char filename[MAX_PATH + 1];
14200 char init_dir[MAX_PATH + 1];
14201 int use_dialog_p = 1;
14202
14203 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
14204 CHECK_STRING (prompt);
14205 CHECK_STRING (dir);
6fc2811b
JR
14206
14207 /* Create the dialog with PROMPT as title, using DIR as initial
14208 directory and using "*" as pattern. */
14209 dir = Fexpand_file_name (dir, Qnil);
14210 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14211 init_dir[MAX_PATH] = '\0';
14212 unixtodos_filename (init_dir);
14213
14214 if (STRINGP (default_filename))
14215 {
14216 char *file_name_only;
14217 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 14218
6fc2811b 14219 unixtodos_filename (full_path_name);
5ac45f98 14220
6fc2811b
JR
14221 file_name_only = strrchr (full_path_name, '\\');
14222 if (!file_name_only)
14223 file_name_only = full_path_name;
14224 else
14225 {
14226 file_name_only++;
5ac45f98 14227
6fc2811b
JR
14228 /* If default_file_name is a directory, don't use the open
14229 file dialog, as it does not support selecting
14230 directories. */
14231 if (!(*file_name_only))
14232 use_dialog_p = 0;
14233 }
ee78dc32 14234
6fc2811b
JR
14235 strncpy (filename, file_name_only, MAX_PATH);
14236 filename[MAX_PATH] = '\0';
14237 }
ee78dc32 14238 else
6fc2811b 14239 filename[0] = '\0';
ee78dc32 14240
6fc2811b
JR
14241 if (use_dialog_p)
14242 {
14243 OPENFILENAME file_details;
5ac45f98 14244
6fc2811b
JR
14245 /* Prevent redisplay. */
14246 specbind (Qinhibit_redisplay, Qt);
14247 BLOCK_INPUT;
ee78dc32 14248
6fc2811b
JR
14249 bzero (&file_details, sizeof (file_details));
14250 file_details.lStructSize = sizeof (file_details);
14251 file_details.hwndOwner = FRAME_W32_WINDOW (f);
3cf3436e
JR
14252 /* Undocumented Bug in Common File Dialog:
14253 If a filter is not specified, shell links are not resolved. */
14254 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
6fc2811b
JR
14255 file_details.lpstrFile = filename;
14256 file_details.nMaxFile = sizeof (filename);
14257 file_details.lpstrInitialDir = init_dir;
14258 file_details.lpstrTitle = XSTRING (prompt)->data;
14259 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 14260
6fc2811b
JR
14261 if (!NILP (mustmatch))
14262 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 14263
6fc2811b
JR
14264 if (GetOpenFileName (&file_details))
14265 {
14266 dostounix_filename (filename);
14267 file = build_string (filename);
14268 }
ee78dc32 14269 else
6fc2811b
JR
14270 file = Qnil;
14271
14272 UNBLOCK_INPUT;
14273 file = unbind_to (count, file);
ee78dc32 14274 }
6fc2811b
JR
14275 /* Open File dialog will not allow folders to be selected, so resort
14276 to minibuffer completing reads for directories. */
14277 else
14278 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14279 dir, mustmatch, dir, Qfile_name_history,
14280 default_filename, Qnil);
ee78dc32 14281
6fc2811b 14282 UNGCPRO;
1edf84e7 14283
6fc2811b
JR
14284 /* Make "Cancel" equivalent to C-g. */
14285 if (NILP (file))
14286 Fsignal (Qquit, Qnil);
ee78dc32 14287
dfff8a69 14288 return unbind_to (count, file);
6fc2811b 14289}
ee78dc32 14290
ee78dc32 14291
6fc2811b 14292\f
6fc2811b
JR
14293/***********************************************************************
14294 w32 specialized functions
14295 ***********************************************************************/
ee78dc32 14296
d84b082d 14297DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
14298 doc: /* Select a font using the W32 font dialog.
14299Returns an X font string corresponding to the selection. */)
d84b082d
JR
14300 (frame, include_proportional)
14301 Lisp_Object frame, include_proportional;
ee78dc32
GV
14302{
14303 FRAME_PTR f = check_x_frame (frame);
14304 CHOOSEFONT cf;
14305 LOGFONT lf;
f46e6225
GV
14306 TEXTMETRIC tm;
14307 HDC hdc;
14308 HANDLE oldobj;
ee78dc32
GV
14309 char buf[100];
14310
14311 bzero (&cf, sizeof (cf));
f46e6225 14312 bzero (&lf, sizeof (lf));
ee78dc32
GV
14313
14314 cf.lStructSize = sizeof (cf);
fbd6baed 14315 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
14316 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14317
14318 /* Unless include_proportional is non-nil, limit the selection to
14319 monospaced fonts. */
14320 if (NILP (include_proportional))
14321 cf.Flags |= CF_FIXEDPITCHONLY;
14322
ee78dc32
GV
14323 cf.lpLogFont = &lf;
14324
f46e6225
GV
14325 /* Initialize as much of the font details as we can from the current
14326 default font. */
14327 hdc = GetDC (FRAME_W32_WINDOW (f));
14328 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14329 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14330 if (GetTextMetrics (hdc, &tm))
14331 {
14332 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14333 lf.lfWeight = tm.tmWeight;
14334 lf.lfItalic = tm.tmItalic;
14335 lf.lfUnderline = tm.tmUnderlined;
14336 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
14337 lf.lfCharSet = tm.tmCharSet;
14338 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14339 }
14340 SelectObject (hdc, oldobj);
6fc2811b 14341 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 14342
767b1ff0 14343 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 14344 return Qnil;
ee78dc32
GV
14345
14346 return build_string (buf);
14347}
14348
74e1aeec
JR
14349DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14350 Sw32_send_sys_command, 1, 2, 0,
14351 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
14352Some useful values for command are #xf030 to maximise frame (#xf020
14353to minimize), #xf120 to restore frame to original size, and #xf100
14354to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
14355screen saver if defined.
14356
14357If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
14358 (command, frame)
14359 Lisp_Object command, frame;
14360{
1edf84e7
GV
14361 FRAME_PTR f = check_x_frame (frame);
14362
b7826503 14363 CHECK_NUMBER (command);
1edf84e7 14364
ce6059da 14365 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
14366
14367 return Qnil;
14368}
14369
55dcfc15 14370DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
14371 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14372This is a wrapper around the ShellExecute system function, which
14373invokes the application registered to handle OPERATION for DOCUMENT.
14374OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14375nil for the default action), and DOCUMENT is typically the name of a
14376document file or URL, but can also be a program executable to run or
14377a directory to open in the Windows Explorer.
14378
14379If DOCUMENT is a program executable, PARAMETERS can be a string
14380containing command line parameters, but otherwise should be nil.
14381
14382SHOW-FLAG can be used to control whether the invoked application is hidden
14383or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14384otherwise it is an integer representing a ShowWindow flag:
14385
14386 0 - start hidden
14387 1 - start normally
14388 3 - start maximized
14389 6 - start minimized */)
55dcfc15
AI
14390 (operation, document, parameters, show_flag)
14391 Lisp_Object operation, document, parameters, show_flag;
14392{
14393 Lisp_Object current_dir;
14394
b7826503 14395 CHECK_STRING (document);
55dcfc15
AI
14396
14397 /* Encode filename and current directory. */
14398 current_dir = ENCODE_FILE (current_buffer->directory);
14399 document = ENCODE_FILE (document);
14400 if ((int) ShellExecute (NULL,
6fc2811b
JR
14401 (STRINGP (operation) ?
14402 XSTRING (operation)->data : NULL),
55dcfc15
AI
14403 XSTRING (document)->data,
14404 (STRINGP (parameters) ?
14405 XSTRING (parameters)->data : NULL),
14406 XSTRING (current_dir)->data,
14407 (INTEGERP (show_flag) ?
14408 XINT (show_flag) : SW_SHOWDEFAULT))
14409 > 32)
14410 return Qt;
90d97e64 14411 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
14412}
14413
ccc2d29c
GV
14414/* Lookup virtual keycode from string representing the name of a
14415 non-ascii keystroke into the corresponding virtual key, using
14416 lispy_function_keys. */
14417static int
14418lookup_vk_code (char *key)
14419{
14420 int i;
14421
14422 for (i = 0; i < 256; i++)
14423 if (lispy_function_keys[i] != 0
14424 && strcmp (lispy_function_keys[i], key) == 0)
14425 return i;
14426
14427 return -1;
14428}
14429
14430/* Convert a one-element vector style key sequence to a hot key
14431 definition. */
14432static int
14433w32_parse_hot_key (key)
14434 Lisp_Object key;
14435{
14436 /* Copied from Fdefine_key and store_in_keymap. */
14437 register Lisp_Object c;
14438 int vk_code;
14439 int lisp_modifiers;
14440 int w32_modifiers;
14441 struct gcpro gcpro1;
14442
b7826503 14443 CHECK_VECTOR (key);
ccc2d29c
GV
14444
14445 if (XFASTINT (Flength (key)) != 1)
14446 return Qnil;
14447
14448 GCPRO1 (key);
14449
14450 c = Faref (key, make_number (0));
14451
14452 if (CONSP (c) && lucid_event_type_list_p (c))
14453 c = Fevent_convert_list (c);
14454
14455 UNGCPRO;
14456
14457 if (! INTEGERP (c) && ! SYMBOLP (c))
14458 error ("Key definition is invalid");
14459
14460 /* Work out the base key and the modifiers. */
14461 if (SYMBOLP (c))
14462 {
14463 c = parse_modifiers (c);
14464 lisp_modifiers = Fcar (Fcdr (c));
14465 c = Fcar (c);
14466 if (!SYMBOLP (c))
14467 abort ();
14468 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
14469 }
14470 else if (INTEGERP (c))
14471 {
14472 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14473 /* Many ascii characters are their own virtual key code. */
14474 vk_code = XINT (c) & CHARACTERBITS;
14475 }
14476
14477 if (vk_code < 0 || vk_code > 255)
14478 return Qnil;
14479
14480 if ((lisp_modifiers & meta_modifier) != 0
14481 && !NILP (Vw32_alt_is_meta))
14482 lisp_modifiers |= alt_modifier;
14483
71eab8d1
AI
14484 /* Supply defs missing from mingw32. */
14485#ifndef MOD_ALT
14486#define MOD_ALT 0x0001
14487#define MOD_CONTROL 0x0002
14488#define MOD_SHIFT 0x0004
14489#define MOD_WIN 0x0008
14490#endif
14491
ccc2d29c
GV
14492 /* Convert lisp modifiers to Windows hot-key form. */
14493 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14494 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14495 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14496 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14497
14498 return HOTKEY (vk_code, w32_modifiers);
14499}
14500
74e1aeec
JR
14501DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14502 Sw32_register_hot_key, 1, 1, 0,
14503 doc: /* Register KEY as a hot-key combination.
14504Certain key combinations like Alt-Tab are reserved for system use on
14505Windows, and therefore are normally intercepted by the system. However,
14506most of these key combinations can be received by registering them as
14507hot-keys, overriding their special meaning.
14508
14509KEY must be a one element key definition in vector form that would be
14510acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14511modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14512is always interpreted as the Windows modifier keys.
14513
14514The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14515 (key)
14516 Lisp_Object key;
14517{
14518 key = w32_parse_hot_key (key);
14519
14520 if (NILP (Fmemq (key, w32_grabbed_keys)))
14521 {
14522 /* Reuse an empty slot if possible. */
14523 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14524
14525 /* Safe to add new key to list, even if we have focus. */
14526 if (NILP (item))
14527 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14528 else
f3fbd155 14529 XSETCAR (item, key);
ccc2d29c
GV
14530
14531 /* Notify input thread about new hot-key definition, so that it
14532 takes effect without needing to switch focus. */
14533 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14534 (WPARAM) key, 0);
14535 }
14536
14537 return key;
14538}
14539
74e1aeec
JR
14540DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14541 Sw32_unregister_hot_key, 1, 1, 0,
14542 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14543 (key)
14544 Lisp_Object key;
14545{
14546 Lisp_Object item;
14547
14548 if (!INTEGERP (key))
14549 key = w32_parse_hot_key (key);
14550
14551 item = Fmemq (key, w32_grabbed_keys);
14552
14553 if (!NILP (item))
14554 {
14555 /* Notify input thread about hot-key definition being removed, so
14556 that it takes effect without needing focus switch. */
14557 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14558 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14559 {
14560 MSG msg;
14561 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14562 }
14563 return Qt;
14564 }
14565 return Qnil;
14566}
14567
74e1aeec
JR
14568DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14569 Sw32_registered_hot_keys, 0, 0, 0,
14570 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14571 ()
14572{
14573 return Fcopy_sequence (w32_grabbed_keys);
14574}
14575
74e1aeec
JR
14576DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14577 Sw32_reconstruct_hot_key, 1, 1, 0,
14578 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14579 (hotkeyid)
14580 Lisp_Object hotkeyid;
14581{
14582 int vk_code, w32_modifiers;
14583 Lisp_Object key;
14584
b7826503 14585 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14586
14587 vk_code = HOTKEY_VK_CODE (hotkeyid);
14588 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14589
14590 if (lispy_function_keys[vk_code])
14591 key = intern (lispy_function_keys[vk_code]);
14592 else
14593 key = make_number (vk_code);
14594
14595 key = Fcons (key, Qnil);
14596 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14597 key = Fcons (Qshift, key);
ccc2d29c 14598 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14599 key = Fcons (Qctrl, key);
ccc2d29c 14600 if (w32_modifiers & MOD_ALT)
3ef68e6b 14601 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14602 if (w32_modifiers & MOD_WIN)
3ef68e6b 14603 key = Fcons (Qhyper, key);
ccc2d29c
GV
14604
14605 return key;
14606}
adcc3809 14607
74e1aeec
JR
14608DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14609 Sw32_toggle_lock_key, 1, 2, 0,
14610 doc: /* Toggle the state of the lock key KEY.
14611KEY can be `capslock', `kp-numlock', or `scroll'.
14612If the optional parameter NEW-STATE is a number, then the state of KEY
14613is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14614 (key, new_state)
14615 Lisp_Object key, new_state;
14616{
14617 int vk_code;
adcc3809
GV
14618
14619 if (EQ (key, intern ("capslock")))
14620 vk_code = VK_CAPITAL;
14621 else if (EQ (key, intern ("kp-numlock")))
14622 vk_code = VK_NUMLOCK;
14623 else if (EQ (key, intern ("scroll")))
14624 vk_code = VK_SCROLL;
14625 else
14626 return Qnil;
14627
14628 if (!dwWindowsThreadId)
14629 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14630
14631 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14632 (WPARAM) vk_code, (LPARAM) new_state))
14633 {
14634 MSG msg;
14635 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14636 return make_number (msg.wParam);
14637 }
14638 return Qnil;
14639}
ee78dc32 14640\f
2254bcde 14641DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14642 doc: /* Return storage information about the file system FILENAME is on.
14643Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14644storage of the file system, FREE is the free storage, and AVAIL is the
14645storage available to a non-superuser. All 3 numbers are in bytes.
14646If the underlying system call fails, value is nil. */)
2254bcde
AI
14647 (filename)
14648 Lisp_Object filename;
14649{
14650 Lisp_Object encoded, value;
14651
b7826503 14652 CHECK_STRING (filename);
2254bcde
AI
14653 filename = Fexpand_file_name (filename, Qnil);
14654 encoded = ENCODE_FILE (filename);
14655
14656 value = Qnil;
14657
14658 /* Determining the required information on Windows turns out, sadly,
14659 to be more involved than one would hope. The original Win32 api
14660 call for this will return bogus information on some systems, but we
14661 must dynamically probe for the replacement api, since that was
14662 added rather late on. */
14663 {
14664 HMODULE hKernel = GetModuleHandle ("kernel32");
14665 BOOL (*pfn_GetDiskFreeSpaceEx)
14666 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14667 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14668
14669 /* On Windows, we may need to specify the root directory of the
14670 volume holding FILENAME. */
14671 char rootname[MAX_PATH];
14672 char *name = XSTRING (encoded)->data;
14673
14674 /* find the root name of the volume if given */
14675 if (isalpha (name[0]) && name[1] == ':')
14676 {
14677 rootname[0] = name[0];
14678 rootname[1] = name[1];
14679 rootname[2] = '\\';
14680 rootname[3] = 0;
14681 }
14682 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14683 {
14684 char *str = rootname;
14685 int slashes = 4;
14686 do
14687 {
14688 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14689 break;
14690 *str++ = *name++;
14691 }
14692 while ( *name );
14693
14694 *str++ = '\\';
14695 *str = 0;
14696 }
14697
14698 if (pfn_GetDiskFreeSpaceEx)
14699 {
ac849ba4
JR
14700 /* Unsigned large integers cannot be cast to double, so
14701 use signed ones instead. */
2254bcde
AI
14702 LARGE_INTEGER availbytes;
14703 LARGE_INTEGER freebytes;
14704 LARGE_INTEGER totalbytes;
14705
14706 if (pfn_GetDiskFreeSpaceEx(rootname,
ac849ba4
JR
14707 (ULARGE_INTEGER *)&availbytes,
14708 (ULARGE_INTEGER *)&totalbytes,
14709 (ULARGE_INTEGER *)&freebytes))
2254bcde
AI
14710 value = list3 (make_float ((double) totalbytes.QuadPart),
14711 make_float ((double) freebytes.QuadPart),
14712 make_float ((double) availbytes.QuadPart));
14713 }
14714 else
14715 {
14716 DWORD sectors_per_cluster;
14717 DWORD bytes_per_sector;
14718 DWORD free_clusters;
14719 DWORD total_clusters;
14720
14721 if (GetDiskFreeSpace(rootname,
14722 &sectors_per_cluster,
14723 &bytes_per_sector,
14724 &free_clusters,
14725 &total_clusters))
14726 value = list3 (make_float ((double) total_clusters
14727 * sectors_per_cluster * bytes_per_sector),
14728 make_float ((double) free_clusters
14729 * sectors_per_cluster * bytes_per_sector),
14730 make_float ((double) free_clusters
14731 * sectors_per_cluster * bytes_per_sector));
14732 }
14733 }
14734
14735 return value;
14736}
14737\f
0e3fcdef
JR
14738/***********************************************************************
14739 Initialization
14740 ***********************************************************************/
14741
14742void
fbd6baed 14743syms_of_w32fns ()
ee78dc32 14744{
9eb16b62
JR
14745 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14746
1edf84e7
GV
14747 /* This is zero if not using MS-Windows. */
14748 w32_in_use = 0;
14749
9eb16b62
JR
14750 /* TrackMouseEvent not available in all versions of Windows, so must load
14751 it dynamically. Do it once, here, instead of every time it is used. */
14752 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14753 track_mouse_window = NULL;
14754
d285988b
JR
14755 w32_visible_system_caret_hwnd = NULL;
14756
ee78dc32
GV
14757 Qauto_raise = intern ("auto-raise");
14758 staticpro (&Qauto_raise);
14759 Qauto_lower = intern ("auto-lower");
14760 staticpro (&Qauto_lower);
ee78dc32
GV
14761 Qbar = intern ("bar");
14762 staticpro (&Qbar);
14763 Qborder_color = intern ("border-color");
14764 staticpro (&Qborder_color);
14765 Qborder_width = intern ("border-width");
14766 staticpro (&Qborder_width);
14767 Qbox = intern ("box");
14768 staticpro (&Qbox);
14769 Qcursor_color = intern ("cursor-color");
14770 staticpro (&Qcursor_color);
14771 Qcursor_type = intern ("cursor-type");
14772 staticpro (&Qcursor_type);
ee78dc32
GV
14773 Qgeometry = intern ("geometry");
14774 staticpro (&Qgeometry);
14775 Qicon_left = intern ("icon-left");
14776 staticpro (&Qicon_left);
14777 Qicon_top = intern ("icon-top");
14778 staticpro (&Qicon_top);
14779 Qicon_type = intern ("icon-type");
14780 staticpro (&Qicon_type);
14781 Qicon_name = intern ("icon-name");
14782 staticpro (&Qicon_name);
14783 Qinternal_border_width = intern ("internal-border-width");
14784 staticpro (&Qinternal_border_width);
14785 Qleft = intern ("left");
14786 staticpro (&Qleft);
1026b400
RS
14787 Qright = intern ("right");
14788 staticpro (&Qright);
ee78dc32
GV
14789 Qmouse_color = intern ("mouse-color");
14790 staticpro (&Qmouse_color);
14791 Qnone = intern ("none");
14792 staticpro (&Qnone);
14793 Qparent_id = intern ("parent-id");
14794 staticpro (&Qparent_id);
14795 Qscroll_bar_width = intern ("scroll-bar-width");
14796 staticpro (&Qscroll_bar_width);
14797 Qsuppress_icon = intern ("suppress-icon");
14798 staticpro (&Qsuppress_icon);
ee78dc32
GV
14799 Qundefined_color = intern ("undefined-color");
14800 staticpro (&Qundefined_color);
14801 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14802 staticpro (&Qvertical_scroll_bars);
14803 Qvisibility = intern ("visibility");
14804 staticpro (&Qvisibility);
14805 Qwindow_id = intern ("window-id");
14806 staticpro (&Qwindow_id);
14807 Qx_frame_parameter = intern ("x-frame-parameter");
14808 staticpro (&Qx_frame_parameter);
14809 Qx_resource_name = intern ("x-resource-name");
14810 staticpro (&Qx_resource_name);
14811 Quser_position = intern ("user-position");
14812 staticpro (&Quser_position);
14813 Quser_size = intern ("user-size");
14814 staticpro (&Quser_size);
6fc2811b
JR
14815 Qscreen_gamma = intern ("screen-gamma");
14816 staticpro (&Qscreen_gamma);
dfff8a69
JR
14817 Qline_spacing = intern ("line-spacing");
14818 staticpro (&Qline_spacing);
14819 Qcenter = intern ("center");
14820 staticpro (&Qcenter);
dc220243
JR
14821 Qcancel_timer = intern ("cancel-timer");
14822 staticpro (&Qcancel_timer);
f7b9d4d1
JR
14823 Qfullscreen = intern ("fullscreen");
14824 staticpro (&Qfullscreen);
14825 Qfullwidth = intern ("fullwidth");
14826 staticpro (&Qfullwidth);
14827 Qfullheight = intern ("fullheight");
14828 staticpro (&Qfullheight);
14829 Qfullboth = intern ("fullboth");
14830 staticpro (&Qfullboth);
ee78dc32 14831
adcc3809
GV
14832 Qhyper = intern ("hyper");
14833 staticpro (&Qhyper);
14834 Qsuper = intern ("super");
14835 staticpro (&Qsuper);
14836 Qmeta = intern ("meta");
14837 staticpro (&Qmeta);
14838 Qalt = intern ("alt");
14839 staticpro (&Qalt);
14840 Qctrl = intern ("ctrl");
14841 staticpro (&Qctrl);
14842 Qcontrol = intern ("control");
14843 staticpro (&Qcontrol);
14844 Qshift = intern ("shift");
14845 staticpro (&Qshift);
f7b9d4d1 14846 /* This is the end of symbol initialization. */
adcc3809 14847
6fc2811b
JR
14848 /* Text property `display' should be nonsticky by default. */
14849 Vtext_property_default_nonsticky
14850 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14851
14852
14853 Qlaplace = intern ("laplace");
14854 staticpro (&Qlaplace);
3cf3436e
JR
14855 Qemboss = intern ("emboss");
14856 staticpro (&Qemboss);
14857 Qedge_detection = intern ("edge-detection");
14858 staticpro (&Qedge_detection);
14859 Qheuristic = intern ("heuristic");
14860 staticpro (&Qheuristic);
14861 QCmatrix = intern (":matrix");
14862 staticpro (&QCmatrix);
14863 QCcolor_adjustment = intern (":color-adjustment");
14864 staticpro (&QCcolor_adjustment);
14865 QCmask = intern (":mask");
14866 staticpro (&QCmask);
6fc2811b 14867
4b817373
RS
14868 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14869 staticpro (&Qface_set_after_frame_default);
14870
ee78dc32
GV
14871 Fput (Qundefined_color, Qerror_conditions,
14872 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14873 Fput (Qundefined_color, Qerror_message,
14874 build_string ("Undefined color"));
14875
ccc2d29c
GV
14876 staticpro (&w32_grabbed_keys);
14877 w32_grabbed_keys = Qnil;
14878
fbd6baed 14879 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14880 doc: /* An array of color name mappings for windows. */);
fbd6baed 14881 Vw32_color_map = Qnil;
ee78dc32 14882
fbd6baed 14883 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14884 doc: /* Non-nil if alt key presses are passed on to Windows.
14885When non-nil, for example, alt pressed and released and then space will
14886open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14887 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14888
fbd6baed 14889 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14890 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14891When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14892 Vw32_alt_is_meta = Qt;
8c205c63 14893
7d081355 14894 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14895 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14896 XSETINT (Vw32_quit_key, 0);
14897
ccc2d29c
GV
14898 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14899 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14900 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14901When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14902 Vw32_pass_lwindow_to_system = Qt;
14903
14904 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14905 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14906 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14907When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14908 Vw32_pass_rwindow_to_system = Qt;
14909
adcc3809
GV
14910 DEFVAR_INT ("w32-phantom-key-code",
14911 &Vw32_phantom_key_code,
74e1aeec
JR
14912 doc: /* Virtual key code used to generate \"phantom\" key presses.
14913Value is a number between 0 and 255.
14914
14915Phantom key presses are generated in order to stop the system from
14916acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14917`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14918 /* Although 255 is technically not a valid key code, it works and
14919 means that this hack won't interfere with any real key code. */
14920 Vw32_phantom_key_code = 255;
adcc3809 14921
ccc2d29c
GV
14922 DEFVAR_LISP ("w32-enable-num-lock",
14923 &Vw32_enable_num_lock,
74e1aeec
JR
14924 doc: /* Non-nil if Num Lock should act normally.
14925Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14926 Vw32_enable_num_lock = Qt;
14927
14928 DEFVAR_LISP ("w32-enable-caps-lock",
14929 &Vw32_enable_caps_lock,
74e1aeec
JR
14930 doc: /* Non-nil if Caps Lock should act normally.
14931Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14932 Vw32_enable_caps_lock = Qt;
14933
14934 DEFVAR_LISP ("w32-scroll-lock-modifier",
14935 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14936 doc: /* Modifier to use for the Scroll Lock on state.
14937The value can be hyper, super, meta, alt, control or shift for the
14938respective modifier, or nil to see Scroll Lock as the key `scroll'.
14939Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14940 Vw32_scroll_lock_modifier = Qt;
14941
14942 DEFVAR_LISP ("w32-lwindow-modifier",
14943 &Vw32_lwindow_modifier,
74e1aeec
JR
14944 doc: /* Modifier to use for the left \"Windows\" key.
14945The value can be hyper, super, meta, alt, control or shift for the
14946respective modifier, or nil to appear as the key `lwindow'.
14947Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14948 Vw32_lwindow_modifier = Qnil;
14949
14950 DEFVAR_LISP ("w32-rwindow-modifier",
14951 &Vw32_rwindow_modifier,
74e1aeec
JR
14952 doc: /* Modifier to use for the right \"Windows\" key.
14953The value can be hyper, super, meta, alt, control or shift for the
14954respective modifier, or nil to appear as the key `rwindow'.
14955Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14956 Vw32_rwindow_modifier = Qnil;
14957
14958 DEFVAR_LISP ("w32-apps-modifier",
14959 &Vw32_apps_modifier,
74e1aeec
JR
14960 doc: /* Modifier to use for the \"Apps\" key.
14961The value can be hyper, super, meta, alt, control or shift for the
14962respective modifier, or nil to appear as the key `apps'.
14963Any other value will cause the key to be ignored. */);
ccc2d29c 14964 Vw32_apps_modifier = Qnil;
da36a4d6 14965
d84b082d 14966 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 14967 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 14968 w32_enable_synthesized_fonts = 0;
5ac45f98 14969
fbd6baed 14970 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 14971 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 14972 Vw32_enable_palette = Qt;
5ac45f98 14973
fbd6baed
GV
14974 DEFVAR_INT ("w32-mouse-button-tolerance",
14975 &Vw32_mouse_button_tolerance,
74e1aeec
JR
14976 doc: /* Analogue of double click interval for faking middle mouse events.
14977The value is the minimum time in milliseconds that must elapse between
14978left/right button down events before they are considered distinct events.
14979If both mouse buttons are depressed within this interval, a middle mouse
14980button down event is generated instead. */);
fbd6baed 14981 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 14982
fbd6baed
GV
14983 DEFVAR_INT ("w32-mouse-move-interval",
14984 &Vw32_mouse_move_interval,
74e1aeec
JR
14985 doc: /* Minimum interval between mouse move events.
14986The value is the minimum time in milliseconds that must elapse between
14987successive mouse move (or scroll bar drag) events before they are
14988reported as lisp events. */);
247be837 14989 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 14990
74214547
JR
14991 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
14992 &w32_pass_extra_mouse_buttons_to_system,
14993 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
14994Recent versions of Windows support mice with up to five buttons.
14995Since most applications don't support these extra buttons, most mouse
14996drivers will allow you to map them to functions at the system level.
14997If this variable is non-nil, Emacs will pass them on, allowing the
14998system to handle them. */);
14999 w32_pass_extra_mouse_buttons_to_system = 0;
15000
ee78dc32
GV
15001 init_x_parm_symbols ();
15002
15003 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 15004 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
15005 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15006
15007 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
15008 doc: /* The shape of the pointer when over text.
15009Changing the value does not affect existing frames
15010unless you set the mouse color. */);
ee78dc32
GV
15011 Vx_pointer_shape = Qnil;
15012
15013 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
15014 doc: /* The name Emacs uses to look up resources; for internal use only.
15015`x-get-resource' uses this as the first component of the instance name
15016when requesting resource values.
15017Emacs initially sets `x-resource-name' to the name under which Emacs
15018was invoked, or to the value specified with the `-name' or `-rn'
15019switches, if present. */);
ee78dc32
GV
15020 Vx_resource_name = Qnil;
15021
15022 Vx_nontext_pointer_shape = Qnil;
15023
15024 Vx_mode_pointer_shape = Qnil;
15025
0af913d7 15026 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
15027 doc: /* The shape of the pointer when Emacs is busy.
15028This variable takes effect when you create a new frame
15029or when you set the mouse color. */);
0af913d7 15030 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 15031
0af913d7 15032 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 15033 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 15034 display_hourglass_p = 1;
6fc2811b 15035
0af913d7 15036 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
15037 doc: /* *Seconds to wait before displaying an hourglass pointer.
15038Value must be an integer or float. */);
0af913d7 15039 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 15040
6fc2811b 15041 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 15042 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
15043 doc: /* The shape of the pointer when over mouse-sensitive text.
15044This variable takes effect when you create a new frame
15045or when you set the mouse color. */);
ee78dc32
GV
15046 Vx_sensitive_text_pointer_shape = Qnil;
15047
4694d762
JR
15048 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15049 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
15050 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15051This variable takes effect when you create a new frame
15052or when you set the mouse color. */);
4694d762
JR
15053 Vx_window_horizontal_drag_shape = Qnil;
15054
ee78dc32 15055 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 15056 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
15057 Vx_cursor_fore_pixel = Qnil;
15058
3cf3436e 15059 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
15060 doc: /* Maximum size for tooltips.
15061Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
15062 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
15063
ee78dc32 15064 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
15065 doc: /* Non-nil if no window manager is in use.
15066Emacs doesn't try to figure this out; this is always nil
15067unless you set it to something else. */);
ee78dc32
GV
15068 /* We don't have any way to find this out, so set it to nil
15069 and maybe the user would like to set it to t. */
15070 Vx_no_window_manager = Qnil;
15071
4587b026
GV
15072 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15073 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
15074 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15075
15076Since Emacs gets width of a font matching with this regexp from
15077PIXEL_SIZE field of the name, font finding mechanism gets faster for
15078such a font. This is especially effective for such large fonts as
15079Chinese, Japanese, and Korean. */);
4587b026
GV
15080 Vx_pixel_size_width_font_regexp = Qnil;
15081
6fc2811b 15082 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
15083 doc: /* Time after which cached images are removed from the cache.
15084When an image has not been displayed this many seconds, remove it
15085from the image cache. Value must be an integer or nil with nil
15086meaning don't clear the cache. */);
6fc2811b
JR
15087 Vimage_cache_eviction_delay = make_number (30 * 60);
15088
33d52f9c
GV
15089 DEFVAR_LISP ("w32-bdf-filename-alist",
15090 &Vw32_bdf_filename_alist,
74e1aeec 15091 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
15092 Vw32_bdf_filename_alist = Qnil;
15093
1075afa9
GV
15094 DEFVAR_BOOL ("w32-strict-fontnames",
15095 &w32_strict_fontnames,
74e1aeec
JR
15096 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15097Default is nil, which allows old fontnames that are not XLFD compliant,
15098and allows third-party CJK display to work by specifying false charset
15099fields to trick Emacs into translating to Big5, SJIS etc.
15100Setting this to t will prevent wrong fonts being selected when
15101fontsets are automatically created. */);
1075afa9
GV
15102 w32_strict_fontnames = 0;
15103
c0611964
AI
15104 DEFVAR_BOOL ("w32-strict-painting",
15105 &w32_strict_painting,
74e1aeec
JR
15106 doc: /* Non-nil means use strict rules for repainting frames.
15107Set this to nil to get the old behaviour for repainting; this should
15108only be necessary if the default setting causes problems. */);
c0611964
AI
15109 w32_strict_painting = 1;
15110
dfff8a69
JR
15111 DEFVAR_LISP ("w32-charset-info-alist",
15112 &Vw32_charset_info_alist,
b3700ae7
JR
15113 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15114Each entry should be of the form:
74e1aeec
JR
15115
15116 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15117
15118where CHARSET_NAME is a string used in font names to identify the charset,
15119WINDOWS_CHARSET is a symbol that can be one of:
15120w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15121w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15122w32-charset-chinesebig5,
dfff8a69 15123#ifdef JOHAB_CHARSET
74e1aeec
JR
15124w32-charset-johab, w32-charset-hebrew,
15125w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15126w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15127w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
15128#endif
15129#ifdef UNICODE_CHARSET
74e1aeec 15130w32-charset-unicode,
dfff8a69 15131#endif
74e1aeec
JR
15132or w32-charset-oem.
15133CODEPAGE should be an integer specifying the codepage that should be used
15134to display the character set, t to do no translation and output as Unicode,
15135or nil to do no translation and output as 8 bit (or multibyte on far-east
15136versions of Windows) characters. */);
dfff8a69
JR
15137 Vw32_charset_info_alist = Qnil;
15138
15139 staticpro (&Qw32_charset_ansi);
15140 Qw32_charset_ansi = intern ("w32-charset-ansi");
15141 staticpro (&Qw32_charset_symbol);
15142 Qw32_charset_symbol = intern ("w32-charset-symbol");
15143 staticpro (&Qw32_charset_shiftjis);
15144 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
15145 staticpro (&Qw32_charset_hangeul);
15146 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
15147 staticpro (&Qw32_charset_chinesebig5);
15148 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15149 staticpro (&Qw32_charset_gb2312);
15150 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15151 staticpro (&Qw32_charset_oem);
15152 Qw32_charset_oem = intern ("w32-charset-oem");
15153
15154#ifdef JOHAB_CHARSET
15155 {
15156 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
15157 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15158 doc: /* Internal variable. */);
dfff8a69
JR
15159
15160 staticpro (&Qw32_charset_johab);
15161 Qw32_charset_johab = intern ("w32-charset-johab");
15162 staticpro (&Qw32_charset_easteurope);
15163 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15164 staticpro (&Qw32_charset_turkish);
15165 Qw32_charset_turkish = intern ("w32-charset-turkish");
15166 staticpro (&Qw32_charset_baltic);
15167 Qw32_charset_baltic = intern ("w32-charset-baltic");
15168 staticpro (&Qw32_charset_russian);
15169 Qw32_charset_russian = intern ("w32-charset-russian");
15170 staticpro (&Qw32_charset_arabic);
15171 Qw32_charset_arabic = intern ("w32-charset-arabic");
15172 staticpro (&Qw32_charset_greek);
15173 Qw32_charset_greek = intern ("w32-charset-greek");
15174 staticpro (&Qw32_charset_hebrew);
15175 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
15176 staticpro (&Qw32_charset_vietnamese);
15177 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
15178 staticpro (&Qw32_charset_thai);
15179 Qw32_charset_thai = intern ("w32-charset-thai");
15180 staticpro (&Qw32_charset_mac);
15181 Qw32_charset_mac = intern ("w32-charset-mac");
15182 }
15183#endif
15184
15185#ifdef UNICODE_CHARSET
15186 {
15187 static int w32_unicode_charset_defined = 1;
15188 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
15189 &w32_unicode_charset_defined,
15190 doc: /* Internal variable. */);
dfff8a69
JR
15191
15192 staticpro (&Qw32_charset_unicode);
15193 Qw32_charset_unicode = intern ("w32-charset-unicode");
15194#endif
15195
ee78dc32 15196 defsubr (&Sx_get_resource);
767b1ff0 15197#if 0 /* TODO: Port to W32 */
6fc2811b
JR
15198 defsubr (&Sx_change_window_property);
15199 defsubr (&Sx_delete_window_property);
15200 defsubr (&Sx_window_property);
15201#endif
2d764c78 15202 defsubr (&Sxw_display_color_p);
ee78dc32 15203 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
15204 defsubr (&Sxw_color_defined_p);
15205 defsubr (&Sxw_color_values);
ee78dc32
GV
15206 defsubr (&Sx_server_max_request_size);
15207 defsubr (&Sx_server_vendor);
15208 defsubr (&Sx_server_version);
15209 defsubr (&Sx_display_pixel_width);
15210 defsubr (&Sx_display_pixel_height);
15211 defsubr (&Sx_display_mm_width);
15212 defsubr (&Sx_display_mm_height);
15213 defsubr (&Sx_display_screens);
15214 defsubr (&Sx_display_planes);
15215 defsubr (&Sx_display_color_cells);
15216 defsubr (&Sx_display_visual_class);
15217 defsubr (&Sx_display_backing_store);
15218 defsubr (&Sx_display_save_under);
15219 defsubr (&Sx_parse_geometry);
15220 defsubr (&Sx_create_frame);
ee78dc32
GV
15221 defsubr (&Sx_open_connection);
15222 defsubr (&Sx_close_connection);
15223 defsubr (&Sx_display_list);
15224 defsubr (&Sx_synchronize);
15225
fbd6baed 15226 /* W32 specific functions */
ee78dc32 15227
1edf84e7 15228 defsubr (&Sw32_focus_frame);
fbd6baed
GV
15229 defsubr (&Sw32_select_font);
15230 defsubr (&Sw32_define_rgb_color);
15231 defsubr (&Sw32_default_color_map);
15232 defsubr (&Sw32_load_color_file);
1edf84e7 15233 defsubr (&Sw32_send_sys_command);
55dcfc15 15234 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
15235 defsubr (&Sw32_register_hot_key);
15236 defsubr (&Sw32_unregister_hot_key);
15237 defsubr (&Sw32_registered_hot_keys);
15238 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 15239 defsubr (&Sw32_toggle_lock_key);
33d52f9c 15240 defsubr (&Sw32_find_bdf_fonts);
4587b026 15241
2254bcde
AI
15242 defsubr (&Sfile_system_info);
15243
4587b026
GV
15244 /* Setting callback functions for fontset handler. */
15245 get_font_info_func = w32_get_font_info;
6fc2811b
JR
15246
15247#if 0 /* This function pointer doesn't seem to be used anywhere.
15248 And the pointer assigned has the wrong type, anyway. */
4587b026 15249 list_fonts_func = w32_list_fonts;
6fc2811b
JR
15250#endif
15251
4587b026
GV
15252 load_font_func = w32_load_font;
15253 find_ccl_program_func = w32_find_ccl_program;
15254 query_font_func = w32_query_font;
15255 set_frame_fontset_func = x_set_font;
15256 check_window_system_func = check_w32;
6fc2811b 15257
ac849ba4 15258#ifdef IMAGES
6fc2811b
JR
15259 /* Images. */
15260 Qxbm = intern ("xbm");
15261 staticpro (&Qxbm);
a93f4566
GM
15262 QCconversion = intern (":conversion");
15263 staticpro (&QCconversion);
6fc2811b
JR
15264 QCheuristic_mask = intern (":heuristic-mask");
15265 staticpro (&QCheuristic_mask);
15266 QCcolor_symbols = intern (":color-symbols");
15267 staticpro (&QCcolor_symbols);
6fc2811b
JR
15268 QCascent = intern (":ascent");
15269 staticpro (&QCascent);
15270 QCmargin = intern (":margin");
15271 staticpro (&QCmargin);
15272 QCrelief = intern (":relief");
15273 staticpro (&QCrelief);
15274 Qpostscript = intern ("postscript");
15275 staticpro (&Qpostscript);
ac849ba4 15276#if 0 /* TODO: These need entries at top of file. */
6fc2811b
JR
15277 QCloader = intern (":loader");
15278 staticpro (&QCloader);
15279 QCbounding_box = intern (":bounding-box");
15280 staticpro (&QCbounding_box);
15281 QCpt_width = intern (":pt-width");
15282 staticpro (&QCpt_width);
15283 QCpt_height = intern (":pt-height");
15284 staticpro (&QCpt_height);
ac849ba4 15285#endif
6fc2811b
JR
15286 QCindex = intern (":index");
15287 staticpro (&QCindex);
15288 Qpbm = intern ("pbm");
15289 staticpro (&Qpbm);
ac849ba4 15290#endif
6fc2811b
JR
15291
15292#if HAVE_XPM
15293 Qxpm = intern ("xpm");
15294 staticpro (&Qxpm);
15295#endif
15296
15297#if HAVE_JPEG
15298 Qjpeg = intern ("jpeg");
15299 staticpro (&Qjpeg);
15300#endif
15301
15302#if HAVE_TIFF
15303 Qtiff = intern ("tiff");
15304 staticpro (&Qtiff);
15305#endif
15306
15307#if HAVE_GIF
15308 Qgif = intern ("gif");
15309 staticpro (&Qgif);
15310#endif
15311
15312#if HAVE_PNG
15313 Qpng = intern ("png");
15314 staticpro (&Qpng);
15315#endif
15316
ac849ba4 15317#ifdef HAVE_IMAGES
6fc2811b 15318 defsubr (&Sclear_image_cache);
ac849ba4
JR
15319 defsubr (&Simage_size);
15320 defsubr (&Simage_mask_p);
15321#endif
6fc2811b
JR
15322
15323#if GLYPH_DEBUG
15324 defsubr (&Simagep);
15325 defsubr (&Slookup_image);
15326#endif
6fc2811b 15327
0af913d7
GM
15328 hourglass_atimer = NULL;
15329 hourglass_shown_p = 0;
6fc2811b
JR
15330 defsubr (&Sx_show_tip);
15331 defsubr (&Sx_hide_tip);
6fc2811b 15332 tip_timer = Qnil;
57fa2774
JR
15333 staticpro (&tip_timer);
15334 tip_frame = Qnil;
15335 staticpro (&tip_frame);
6fc2811b 15336
ca56d953
JR
15337 last_show_tip_args = Qnil;
15338 staticpro (&last_show_tip_args);
15339
6fc2811b
JR
15340 defsubr (&Sx_file_dialog);
15341}
15342
15343
15344void
15345init_xfns ()
15346{
15347 image_types = NULL;
15348 Vimage_types = Qnil;
15349
ac849ba4
JR
15350#if HAVE_PBM
15351 define_image_type (&pbm_type);
15352#endif
15353
767b1ff0 15354#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
15355 define_image_type (&xbm_type);
15356 define_image_type (&gs_type);
ac849ba4 15357#endif
6fc2811b
JR
15358
15359#if HAVE_XPM
15360 define_image_type (&xpm_type);
15361#endif
15362
15363#if HAVE_JPEG
15364 define_image_type (&jpeg_type);
15365#endif
15366
15367#if HAVE_TIFF
15368 define_image_type (&tiff_type);
15369#endif
15370
15371#if HAVE_GIF
15372 define_image_type (&gif_type);
15373#endif
15374
15375#if HAVE_PNG
15376 define_image_type (&png_type);
15377#endif
ee78dc32
GV
15378}
15379
15380#undef abort
15381
15382void
fbd6baed 15383w32_abort()
ee78dc32 15384{
5ac45f98
GV
15385 int button;
15386 button = MessageBox (NULL,
15387 "A fatal error has occurred!\n\n"
15388 "Select Abort to exit, Retry to debug, Ignore to continue",
15389 "Emacs Abort Dialog",
15390 MB_ICONEXCLAMATION | MB_TASKMODAL
15391 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15392 switch (button)
15393 {
15394 case IDRETRY:
15395 DebugBreak ();
15396 break;
15397 case IDIGNORE:
15398 break;
15399 case IDABORT:
15400 default:
15401 abort ();
15402 break;
15403 }
ee78dc32 15404}
d573caac 15405
83c75055
GV
15406/* For convenience when debugging. */
15407int
15408w32_last_error()
15409{
15410 return GetLastError ();
15411}