* data.c (Fkeywordp, Fsymbol_name, store_symval_forwarding)
[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. */
de2413e9 579 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
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);
d3109773 5680 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
6fc2811b 5681 "toolBar", "ToolBar", RES_TYPE_NUMBER);
919f1e88 5682
1edf84e7 5683 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5684 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5685 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5686 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
5687 x_default_parameter (f, parms, Qfullscreen, Qnil,
5688 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 5689
fbd6baed
GV
5690 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5691 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5692
5693 /* Add the tool-bar height to the initial frame height so that the
5694 user gets a text display area of the size he specified with -g or
5695 via .Xdefaults. Later changes of the tool-bar height don't
5696 change the frame size. This is done so that users can create
5697 tall Emacs frames without having to guess how tall the tool-bar
5698 will get. */
5699 if (FRAME_TOOL_BAR_LINES (f))
5700 {
5701 int margin, relief, bar_height;
5702
a05e2bae 5703 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5704 ? tool_bar_button_relief
5705 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5706
5707 if (INTEGERP (Vtool_bar_button_margin)
5708 && XINT (Vtool_bar_button_margin) > 0)
5709 margin = XFASTINT (Vtool_bar_button_margin);
5710 else if (CONSP (Vtool_bar_button_margin)
5711 && INTEGERP (XCDR (Vtool_bar_button_margin))
5712 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5713 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5714 else
5715 margin = 0;
5716
5717 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5718 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5719 }
5720
ee78dc32
GV
5721 window_prompting = x_figure_window_size (f, parms);
5722
5723 if (window_prompting & XNegative)
5724 {
5725 if (window_prompting & YNegative)
fbd6baed 5726 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5727 else
fbd6baed 5728 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5729 }
5730 else
5731 {
5732 if (window_prompting & YNegative)
fbd6baed 5733 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5734 else
fbd6baed 5735 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5736 }
5737
fbd6baed 5738 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5739
6fc2811b
JR
5740 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5741 f->no_split = minibuffer_only || EQ (tem, Qt);
5742
fbd6baed 5743 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5744 x_icon (f, parms);
6fc2811b
JR
5745
5746 x_make_gc (f);
5747
5748 /* Now consider the frame official. */
5749 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5750 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5751
5752 /* We need to do this after creating the window, so that the
5753 icon-creation functions can say whose icon they're describing. */
5754 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5755 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5756
5757 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5758 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5759 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5760 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5761 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5762 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5763 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5764 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5765
5766 /* Dimensions, especially f->height, must be done via change_frame_size.
5767 Change will not be effected unless different from the current
5768 f->height. */
5769 width = f->width;
5770 height = f->height;
dc220243 5771
1026b400
RS
5772 f->height = 0;
5773 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5774 change_frame_size (f, height, width, 1, 0, 0);
5775
6fc2811b
JR
5776 /* Tell the server what size and position, etc, we want, and how
5777 badly we want them. This should be done after we have the menu
5778 bar so that its size can be taken into account. */
ee78dc32
GV
5779 BLOCK_INPUT;
5780 x_wm_set_size_hint (f, window_prompting, 0);
5781 UNBLOCK_INPUT;
5782
815d969e
JR
5783 /* Avoid a bug that causes the new frame to never become visible if
5784 an echo area message is displayed during the following call1. */
5785 specbind(Qredisplay_dont_pause, Qt);
5786
4694d762
JR
5787 /* Set up faces after all frame parameters are known. This call
5788 also merges in face attributes specified for new frames. If we
5789 don't do this, the `menu' face for instance won't have the right
5790 colors, and the menu bar won't appear in the specified colors for
5791 new frames. */
5792 call1 (Qface_set_after_frame_default, frame);
5793
6fc2811b
JR
5794 /* Make the window appear on the frame and enable display, unless
5795 the caller says not to. However, with explicit parent, Emacs
5796 cannot control visibility, so don't try. */
fbd6baed 5797 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5798 {
5799 Lisp_Object visibility;
5800
6fc2811b 5801 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5802 if (EQ (visibility, Qunbound))
5803 visibility = Qt;
5804
5805 if (EQ (visibility, Qicon))
5806 x_iconify_frame (f);
5807 else if (! NILP (visibility))
5808 x_make_frame_visible (f);
5809 else
5810 /* Must have been Qnil. */
5811 ;
5812 }
6fc2811b 5813 UNGCPRO;
9e57df62
GM
5814
5815 /* Make sure windows on this frame appear in calls to next-window
5816 and similar functions. */
5817 Vwindow_list = Qnil;
5818
ee78dc32
GV
5819 return unbind_to (count, frame);
5820}
5821
5822/* FRAME is used only to get a handle on the X display. We don't pass the
5823 display info directly because we're called from frame.c, which doesn't
5824 know about that structure. */
5825Lisp_Object
5826x_get_focus_frame (frame)
5827 struct frame *frame;
5828{
fbd6baed 5829 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5830 Lisp_Object xfocus;
fbd6baed 5831 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5832 return Qnil;
5833
fbd6baed 5834 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5835 return xfocus;
5836}
1edf84e7
GV
5837
5838DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5839 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5840 (frame)
5841 Lisp_Object frame;
5842{
5843 x_focus_on_frame (check_x_frame (frame));
5844 return Qnil;
5845}
5846
ee78dc32 5847\f
767b1ff0
JR
5848/* Return the charset portion of a font name. */
5849char * xlfd_charset_of_font (char * fontname)
5850{
5851 char *charset, *encoding;
5852
5853 encoding = strrchr(fontname, '-');
ceb12877 5854 if (!encoding || encoding == fontname)
767b1ff0
JR
5855 return NULL;
5856
478ea067
AI
5857 for (charset = encoding - 1; charset >= fontname; charset--)
5858 if (*charset == '-')
5859 break;
767b1ff0 5860
478ea067 5861 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5862 return NULL;
5863
5864 return charset + 1;
5865}
5866
33d52f9c
GV
5867struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5868 int size, char* filename);
8edb0a6f 5869static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5870static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5871 char * charset);
5872static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5873
8edb0a6f 5874static struct font_info *
33d52f9c 5875w32_load_system_font (f,fontname,size)
55dcfc15
AI
5876 struct frame *f;
5877 char * fontname;
5878 int size;
ee78dc32 5879{
4587b026
GV
5880 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5881 Lisp_Object font_names;
5882
4587b026
GV
5883 /* Get a list of all the fonts that match this name. Once we
5884 have a list of matching fonts, we compare them against the fonts
5885 we already have loaded by comparing names. */
5886 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5887
5888 if (!NILP (font_names))
3c190163 5889 {
4587b026
GV
5890 Lisp_Object tail;
5891 int i;
4587b026
GV
5892
5893 /* First check if any are already loaded, as that is cheaper
5894 than loading another one. */
5895 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5896 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5897 if (dpyinfo->font_table[i].name
5898 && (!strcmp (dpyinfo->font_table[i].name,
5899 XSTRING (XCAR (tail))->data)
5900 || !strcmp (dpyinfo->font_table[i].full_name,
5901 XSTRING (XCAR (tail))->data)))
4587b026 5902 return (dpyinfo->font_table + i);
6fc2811b 5903
8e713be6 5904 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5905 }
1075afa9 5906 else if (w32_strict_fontnames)
5ca0cd71
GV
5907 {
5908 /* If EnumFontFamiliesEx was available, we got a full list of
5909 fonts back so stop now to avoid the possibility of loading a
5910 random font. If we had to fall back to EnumFontFamilies, the
5911 list is incomplete, so continue whether the font we want was
5912 listed or not. */
5913 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5914 FARPROC enum_font_families_ex
1075afa9 5915 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5916 if (enum_font_families_ex)
5917 return NULL;
5918 }
4587b026
GV
5919
5920 /* Load the font and add it to the table. */
5921 {
767b1ff0 5922 char *full_name, *encoding, *charset;
4587b026
GV
5923 XFontStruct *font;
5924 struct font_info *fontp;
3c190163 5925 LOGFONT lf;
4587b026 5926 BOOL ok;
19c291d3 5927 int codepage;
6fc2811b 5928 int i;
5ac45f98 5929
4587b026 5930 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5931 return (NULL);
5ac45f98 5932
4587b026
GV
5933 if (!*lf.lfFaceName)
5934 /* If no name was specified for the font, we get a random font
5935 from CreateFontIndirect - this is not particularly
5936 desirable, especially since CreateFontIndirect does not
5937 fill out the missing name in lf, so we never know what we
5938 ended up with. */
5939 return NULL;
5940
d65a9cdc
JR
5941 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5942 since those fonts leave garbage behind. */
5943 lf.lfQuality = ANTIALIASED_QUALITY;
5944
3c190163 5945 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5946 bzero (font, sizeof (*font));
5ac45f98 5947
33d52f9c
GV
5948 /* Set bdf to NULL to indicate that this is a Windows font. */
5949 font->bdf = NULL;
5ac45f98 5950
3c190163 5951 BLOCK_INPUT;
5ac45f98
GV
5952
5953 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5954
1a292d24
AI
5955 if (font->hfont == NULL)
5956 {
5957 ok = FALSE;
5958 }
5959 else
5960 {
5961 HDC hdc;
5962 HANDLE oldobj;
19c291d3
AI
5963
5964 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5965
5966 hdc = GetDC (dpyinfo->root_window);
5967 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5968
1a292d24 5969 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5970 if (codepage == CP_UNICODE)
5971 font->double_byte_p = 1;
5972 else
8b77111c
AI
5973 {
5974 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5975 don't report themselves as double byte fonts, when
5976 patently they are. So instead of trusting
5977 GetFontLanguageInfo, we check the properties of the
5978 codepage directly, since that is ultimately what we are
5979 working from anyway. */
5980 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5981 CPINFO cpi = {0};
5982 GetCPInfo (codepage, &cpi);
5983 font->double_byte_p = cpi.MaxCharSize > 1;
5984 }
5c6682be 5985
1a292d24
AI
5986 SelectObject (hdc, oldobj);
5987 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5988 /* Fill out details in lf according to the font that was
5989 actually loaded. */
5990 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5991 lf.lfWidth = font->tm.tmAveCharWidth;
5992 lf.lfWeight = font->tm.tmWeight;
5993 lf.lfItalic = font->tm.tmItalic;
5994 lf.lfCharSet = font->tm.tmCharSet;
5995 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5996 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5997 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5998 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5999
6000 w32_cache_char_metrics (font);
1a292d24 6001 }
5ac45f98 6002
1a292d24 6003 UNBLOCK_INPUT;
5ac45f98 6004
4587b026
GV
6005 if (!ok)
6006 {
1a292d24
AI
6007 w32_unload_font (dpyinfo, font);
6008 return (NULL);
6009 }
ee78dc32 6010
6fc2811b
JR
6011 /* Find a free slot in the font table. */
6012 for (i = 0; i < dpyinfo->n_fonts; ++i)
6013 if (dpyinfo->font_table[i].name == NULL)
6014 break;
6015
6016 /* If no free slot found, maybe enlarge the font table. */
6017 if (i == dpyinfo->n_fonts
6018 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 6019 {
6fc2811b
JR
6020 int sz;
6021 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6022 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 6023 dpyinfo->font_table
6fc2811b 6024 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
6025 }
6026
6fc2811b
JR
6027 fontp = dpyinfo->font_table + i;
6028 if (i == dpyinfo->n_fonts)
6029 ++dpyinfo->n_fonts;
4587b026
GV
6030
6031 /* Now fill in the slots of *FONTP. */
6032 BLOCK_INPUT;
6033 fontp->font = font;
6fc2811b 6034 fontp->font_idx = i;
4587b026
GV
6035 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6036 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6037
767b1ff0
JR
6038 charset = xlfd_charset_of_font (fontname);
6039
19c291d3
AI
6040 /* Cache the W32 codepage for a font. This makes w32_encode_char
6041 (called for every glyph during redisplay) much faster. */
6042 fontp->codepage = codepage;
6043
4587b026
GV
6044 /* Work out the font's full name. */
6045 full_name = (char *)xmalloc (100);
767b1ff0 6046 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
6047 fontp->full_name = full_name;
6048 else
6049 {
6050 /* If all else fails - just use the name we used to load it. */
6051 xfree (full_name);
6052 fontp->full_name = fontp->name;
6053 }
6054
6055 fontp->size = FONT_WIDTH (font);
6056 fontp->height = FONT_HEIGHT (font);
6057
6058 /* The slot `encoding' specifies how to map a character
6059 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
6060 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6061 (0:0x20..0x7F, 1:0xA0..0xFF,
6062 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 6063 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 6064 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
6065 which is never used by any charset. If mapping can't be
6066 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
6067
6068 /* SJIS fonts need to be set to type 4, all others seem to work as
6069 type FONT_ENCODING_NOT_DECIDED. */
6070 encoding = strrchr (fontp->name, '-');
d84b082d 6071 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 6072 fontp->encoding[1] = 4;
33d52f9c 6073 else
1c885fe1 6074 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
6075
6076 /* The following three values are set to 0 under W32, which is
6077 what they get set to if XGetFontProperty fails under X. */
6078 fontp->baseline_offset = 0;
6079 fontp->relative_compose = 0;
33d52f9c 6080 fontp->default_ascent = 0;
4587b026 6081
6fc2811b
JR
6082 /* Set global flag fonts_changed_p to non-zero if the font loaded
6083 has a character with a smaller width than any other character
f7b9d4d1 6084 before, or if the font loaded has a smaller height than any
6fc2811b
JR
6085 other font loaded before. If this happens, it will make a
6086 glyph matrix reallocation necessary. */
f7b9d4d1 6087 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 6088 UNBLOCK_INPUT;
4587b026
GV
6089 return fontp;
6090 }
6091}
6092
33d52f9c
GV
6093/* Load font named FONTNAME of size SIZE for frame F, and return a
6094 pointer to the structure font_info while allocating it dynamically.
6095 If loading fails, return NULL. */
6096struct font_info *
6097w32_load_font (f,fontname,size)
6098struct frame *f;
6099char * fontname;
6100int size;
6101{
6102 Lisp_Object bdf_fonts;
6103 struct font_info *retval = NULL;
6104
8edb0a6f 6105 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
6106
6107 while (!retval && CONSP (bdf_fonts))
6108 {
6109 char *bdf_name, *bdf_file;
6110 Lisp_Object bdf_pair;
6111
8e713be6
KR
6112 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6113 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6114 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
6115
6116 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6117
8e713be6 6118 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
6119 }
6120
6121 if (retval)
6122 return retval;
6123
6124 return w32_load_system_font(f, fontname, size);
6125}
6126
6127
ee78dc32 6128void
fbd6baed
GV
6129w32_unload_font (dpyinfo, font)
6130 struct w32_display_info *dpyinfo;
ee78dc32
GV
6131 XFontStruct * font;
6132{
6133 if (font)
6134 {
c6be3860 6135 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
6136 if (font->bdf) w32_free_bdf_font (font->bdf);
6137
3c190163 6138 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
6139 xfree (font);
6140 }
6141}
6142
fbd6baed 6143/* The font conversion stuff between x and w32 */
ee78dc32
GV
6144
6145/* X font string is as follows (from faces.el)
6146 * (let ((- "[-?]")
6147 * (foundry "[^-]+")
6148 * (family "[^-]+")
6149 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6150 * (weight\? "\\([^-]*\\)") ; 1
6151 * (slant "\\([ior]\\)") ; 2
6152 * (slant\? "\\([^-]?\\)") ; 2
6153 * (swidth "\\([^-]*\\)") ; 3
6154 * (adstyle "[^-]*") ; 4
6155 * (pixelsize "[0-9]+")
6156 * (pointsize "[0-9][0-9]+")
6157 * (resx "[0-9][0-9]+")
6158 * (resy "[0-9][0-9]+")
6159 * (spacing "[cmp?*]")
6160 * (avgwidth "[0-9]+")
6161 * (registry "[^-]+")
6162 * (encoding "[^-]+")
6163 * )
ee78dc32 6164 */
ee78dc32 6165
8edb0a6f 6166static LONG
fbd6baed 6167x_to_w32_weight (lpw)
ee78dc32
GV
6168 char * lpw;
6169{
6170 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6171
6172 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6173 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6174 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6175 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6176 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6177 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6178 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6179 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6180 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6181 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6182 else
5ac45f98 6183 return FW_DONTCARE;
ee78dc32
GV
6184}
6185
5ac45f98 6186
8edb0a6f 6187static char *
fbd6baed 6188w32_to_x_weight (fnweight)
ee78dc32
GV
6189 int fnweight;
6190{
5ac45f98
GV
6191 if (fnweight >= FW_HEAVY) return "heavy";
6192 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6193 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6194 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6195 if (fnweight >= FW_MEDIUM) return "medium";
6196 if (fnweight >= FW_NORMAL) return "normal";
6197 if (fnweight >= FW_LIGHT) return "light";
6198 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6199 if (fnweight >= FW_THIN) return "thin";
6200 else
6201 return "*";
6202}
6203
8edb0a6f 6204static LONG
fbd6baed 6205x_to_w32_charset (lpcs)
5ac45f98
GV
6206 char * lpcs;
6207{
767b1ff0 6208 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6209 char *charset;
6210 int len = strlen (lpcs);
6211
6212 /* Support "*-#nnn" format for unknown charsets. */
6213 if (strncmp (lpcs, "*-#", 3) == 0)
6214 return atoi (lpcs + 3);
6215
6216 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6217 charset = alloca (len + 1);
6218 strcpy (charset, lpcs);
6219 lpcs = strchr (charset, '*');
6220 if (lpcs)
6221 *lpcs = 0;
4587b026 6222
dfff8a69
JR
6223 /* Look through w32-charset-info-alist for the character set.
6224 Format of each entry is
6225 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6226 */
8b77111c 6227 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6228
767b1ff0
JR
6229 if (NILP(this_entry))
6230 {
6231 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6232 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6233 return ANSI_CHARSET;
6234 else
6235 return DEFAULT_CHARSET;
6236 }
6237
6238 w32_charset = Fcar (Fcdr (this_entry));
6239
d84b082d 6240 /* Translate Lisp symbol to number. */
767b1ff0
JR
6241 if (w32_charset == Qw32_charset_ansi)
6242 return ANSI_CHARSET;
6243 if (w32_charset == Qw32_charset_symbol)
6244 return SYMBOL_CHARSET;
6245 if (w32_charset == Qw32_charset_shiftjis)
6246 return SHIFTJIS_CHARSET;
6247 if (w32_charset == Qw32_charset_hangeul)
6248 return HANGEUL_CHARSET;
6249 if (w32_charset == Qw32_charset_chinesebig5)
6250 return CHINESEBIG5_CHARSET;
6251 if (w32_charset == Qw32_charset_gb2312)
6252 return GB2312_CHARSET;
6253 if (w32_charset == Qw32_charset_oem)
6254 return OEM_CHARSET;
dfff8a69 6255#ifdef JOHAB_CHARSET
767b1ff0
JR
6256 if (w32_charset == Qw32_charset_johab)
6257 return JOHAB_CHARSET;
6258 if (w32_charset == Qw32_charset_easteurope)
6259 return EASTEUROPE_CHARSET;
6260 if (w32_charset == Qw32_charset_turkish)
6261 return TURKISH_CHARSET;
6262 if (w32_charset == Qw32_charset_baltic)
6263 return BALTIC_CHARSET;
6264 if (w32_charset == Qw32_charset_russian)
6265 return RUSSIAN_CHARSET;
6266 if (w32_charset == Qw32_charset_arabic)
6267 return ARABIC_CHARSET;
6268 if (w32_charset == Qw32_charset_greek)
6269 return GREEK_CHARSET;
6270 if (w32_charset == Qw32_charset_hebrew)
6271 return HEBREW_CHARSET;
6272 if (w32_charset == Qw32_charset_vietnamese)
6273 return VIETNAMESE_CHARSET;
6274 if (w32_charset == Qw32_charset_thai)
6275 return THAI_CHARSET;
6276 if (w32_charset == Qw32_charset_mac)
6277 return MAC_CHARSET;
dfff8a69 6278#endif /* JOHAB_CHARSET */
5ac45f98 6279#ifdef UNICODE_CHARSET
767b1ff0
JR
6280 if (w32_charset == Qw32_charset_unicode)
6281 return UNICODE_CHARSET;
5ac45f98 6282#endif
dfff8a69
JR
6283
6284 return DEFAULT_CHARSET;
5ac45f98
GV
6285}
6286
dfff8a69 6287
8edb0a6f 6288static char *
fbd6baed 6289w32_to_x_charset (fncharset)
5ac45f98
GV
6290 int fncharset;
6291{
5e905a57 6292 static char buf[32];
767b1ff0 6293 Lisp_Object charset_type;
1edf84e7 6294
5ac45f98
GV
6295 switch (fncharset)
6296 {
767b1ff0
JR
6297 case ANSI_CHARSET:
6298 /* Handle startup case of w32-charset-info-alist not
6299 being set up yet. */
6300 if (NILP(Vw32_charset_info_alist))
6301 return "iso8859-1";
6302 charset_type = Qw32_charset_ansi;
6303 break;
6304 case DEFAULT_CHARSET:
6305 charset_type = Qw32_charset_default;
6306 break;
6307 case SYMBOL_CHARSET:
6308 charset_type = Qw32_charset_symbol;
6309 break;
6310 case SHIFTJIS_CHARSET:
6311 charset_type = Qw32_charset_shiftjis;
6312 break;
6313 case HANGEUL_CHARSET:
6314 charset_type = Qw32_charset_hangeul;
6315 break;
6316 case GB2312_CHARSET:
6317 charset_type = Qw32_charset_gb2312;
6318 break;
6319 case CHINESEBIG5_CHARSET:
6320 charset_type = Qw32_charset_chinesebig5;
6321 break;
6322 case OEM_CHARSET:
6323 charset_type = Qw32_charset_oem;
6324 break;
4587b026
GV
6325
6326 /* More recent versions of Windows (95 and NT4.0) define more
6327 character sets. */
6328#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6329 case EASTEUROPE_CHARSET:
6330 charset_type = Qw32_charset_easteurope;
6331 break;
6332 case TURKISH_CHARSET:
6333 charset_type = Qw32_charset_turkish;
6334 break;
6335 case BALTIC_CHARSET:
6336 charset_type = Qw32_charset_baltic;
6337 break;
33d52f9c 6338 case RUSSIAN_CHARSET:
767b1ff0
JR
6339 charset_type = Qw32_charset_russian;
6340 break;
6341 case ARABIC_CHARSET:
6342 charset_type = Qw32_charset_arabic;
6343 break;
6344 case GREEK_CHARSET:
6345 charset_type = Qw32_charset_greek;
6346 break;
6347 case HEBREW_CHARSET:
6348 charset_type = Qw32_charset_hebrew;
6349 break;
6350 case VIETNAMESE_CHARSET:
6351 charset_type = Qw32_charset_vietnamese;
6352 break;
6353 case THAI_CHARSET:
6354 charset_type = Qw32_charset_thai;
6355 break;
6356 case MAC_CHARSET:
6357 charset_type = Qw32_charset_mac;
6358 break;
6359 case JOHAB_CHARSET:
6360 charset_type = Qw32_charset_johab;
6361 break;
4587b026
GV
6362#endif
6363
5ac45f98 6364#ifdef UNICODE_CHARSET
767b1ff0
JR
6365 case UNICODE_CHARSET:
6366 charset_type = Qw32_charset_unicode;
6367 break;
5ac45f98 6368#endif
767b1ff0
JR
6369 default:
6370 /* Encode numerical value of unknown charset. */
6371 sprintf (buf, "*-#%u", fncharset);
6372 return buf;
5ac45f98 6373 }
767b1ff0
JR
6374
6375 {
6376 Lisp_Object rest;
6377 char * best_match = NULL;
6378
6379 /* Look through w32-charset-info-alist for the character set.
6380 Prefer ISO codepages, and prefer lower numbers in the ISO
6381 range. Only return charsets for codepages which are installed.
6382
6383 Format of each entry is
6384 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6385 */
6386 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6387 {
6388 char * x_charset;
6389 Lisp_Object w32_charset;
6390 Lisp_Object codepage;
6391
6392 Lisp_Object this_entry = XCAR (rest);
6393
6394 /* Skip invalid entries in alist. */
6395 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6396 || !CONSP (XCDR (this_entry))
6397 || !SYMBOLP (XCAR (XCDR (this_entry))))
6398 continue;
6399
6400 x_charset = XSTRING (XCAR (this_entry))->data;
6401 w32_charset = XCAR (XCDR (this_entry));
6402 codepage = XCDR (XCDR (this_entry));
6403
6404 /* Look for Same charset and a valid codepage (or non-int
6405 which means ignore). */
6406 if (w32_charset == charset_type
6407 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6408 || IsValidCodePage (XINT (codepage))))
6409 {
6410 /* If we don't have a match already, then this is the
6411 best. */
6412 if (!best_match)
6413 best_match = x_charset;
6414 /* If this is an ISO codepage, and the best so far isn't,
6415 then this is better. */
d84b082d
JR
6416 else if (strnicmp (best_match, "iso", 3) != 0
6417 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
6418 best_match = x_charset;
6419 /* If both are ISO8859 codepages, choose the one with the
6420 lowest number in the encoding field. */
d84b082d
JR
6421 else if (strnicmp (best_match, "iso8859-", 8) == 0
6422 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
6423 {
6424 int best_enc = atoi (best_match + 8);
6425 int this_enc = atoi (x_charset + 8);
6426 if (this_enc > 0 && this_enc < best_enc)
6427 best_match = x_charset;
6428 }
6429 }
6430 }
6431
6432 /* If no match, encode the numeric value. */
6433 if (!best_match)
6434 {
6435 sprintf (buf, "*-#%u", fncharset);
6436 return buf;
6437 }
6438
5e905a57
JR
6439 strncpy(buf, best_match, 31);
6440 buf[31] = '\0';
767b1ff0
JR
6441 return buf;
6442 }
ee78dc32
GV
6443}
6444
dfff8a69 6445
d84b082d
JR
6446/* Return all the X charsets that map to a font. */
6447static Lisp_Object
6448w32_to_all_x_charsets (fncharset)
6449 int fncharset;
6450{
6451 static char buf[32];
6452 Lisp_Object charset_type;
6453 Lisp_Object retval = Qnil;
6454
6455 switch (fncharset)
6456 {
6457 case ANSI_CHARSET:
6458 /* Handle startup case of w32-charset-info-alist not
6459 being set up yet. */
6460 if (NILP(Vw32_charset_info_alist))
d86c35ee
JR
6461 return Fcons (build_string ("iso8859-1"), Qnil);
6462
d84b082d
JR
6463 charset_type = Qw32_charset_ansi;
6464 break;
6465 case DEFAULT_CHARSET:
6466 charset_type = Qw32_charset_default;
6467 break;
6468 case SYMBOL_CHARSET:
6469 charset_type = Qw32_charset_symbol;
6470 break;
6471 case SHIFTJIS_CHARSET:
6472 charset_type = Qw32_charset_shiftjis;
6473 break;
6474 case HANGEUL_CHARSET:
6475 charset_type = Qw32_charset_hangeul;
6476 break;
6477 case GB2312_CHARSET:
6478 charset_type = Qw32_charset_gb2312;
6479 break;
6480 case CHINESEBIG5_CHARSET:
6481 charset_type = Qw32_charset_chinesebig5;
6482 break;
6483 case OEM_CHARSET:
6484 charset_type = Qw32_charset_oem;
6485 break;
6486
6487 /* More recent versions of Windows (95 and NT4.0) define more
6488 character sets. */
6489#ifdef EASTEUROPE_CHARSET
6490 case EASTEUROPE_CHARSET:
6491 charset_type = Qw32_charset_easteurope;
6492 break;
6493 case TURKISH_CHARSET:
6494 charset_type = Qw32_charset_turkish;
6495 break;
6496 case BALTIC_CHARSET:
6497 charset_type = Qw32_charset_baltic;
6498 break;
6499 case RUSSIAN_CHARSET:
6500 charset_type = Qw32_charset_russian;
6501 break;
6502 case ARABIC_CHARSET:
6503 charset_type = Qw32_charset_arabic;
6504 break;
6505 case GREEK_CHARSET:
6506 charset_type = Qw32_charset_greek;
6507 break;
6508 case HEBREW_CHARSET:
6509 charset_type = Qw32_charset_hebrew;
6510 break;
6511 case VIETNAMESE_CHARSET:
6512 charset_type = Qw32_charset_vietnamese;
6513 break;
6514 case THAI_CHARSET:
6515 charset_type = Qw32_charset_thai;
6516 break;
6517 case MAC_CHARSET:
6518 charset_type = Qw32_charset_mac;
6519 break;
6520 case JOHAB_CHARSET:
6521 charset_type = Qw32_charset_johab;
6522 break;
6523#endif
6524
6525#ifdef UNICODE_CHARSET
6526 case UNICODE_CHARSET:
6527 charset_type = Qw32_charset_unicode;
6528 break;
6529#endif
6530 default:
6531 /* Encode numerical value of unknown charset. */
6532 sprintf (buf, "*-#%u", fncharset);
6533 return Fcons (build_string (buf), Qnil);
6534 }
6535
6536 {
6537 Lisp_Object rest;
6538 /* Look through w32-charset-info-alist for the character set.
6539 Only return charsets for codepages which are installed.
6540
6541 Format of each entry in Vw32_charset_info_alist is
6542 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6543 */
6544 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6545 {
6546 Lisp_Object x_charset;
6547 Lisp_Object w32_charset;
6548 Lisp_Object codepage;
6549
6550 Lisp_Object this_entry = XCAR (rest);
6551
6552 /* Skip invalid entries in alist. */
6553 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6554 || !CONSP (XCDR (this_entry))
6555 || !SYMBOLP (XCAR (XCDR (this_entry))))
6556 continue;
6557
6558 x_charset = XCAR (this_entry);
6559 w32_charset = XCAR (XCDR (this_entry));
6560 codepage = XCDR (XCDR (this_entry));
6561
6562 /* Look for Same charset and a valid codepage (or non-int
6563 which means ignore). */
6564 if (w32_charset == charset_type
6565 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6566 || IsValidCodePage (XINT (codepage))))
6567 {
6568 retval = Fcons (x_charset, retval);
6569 }
6570 }
6571
6572 /* If no match, encode the numeric value. */
6573 if (NILP (retval))
6574 {
6575 sprintf (buf, "*-#%u", fncharset);
6576 return Fcons (build_string (buf), Qnil);
6577 }
6578
6579 return retval;
6580 }
6581}
6582
dfff8a69
JR
6583/* Get the Windows codepage corresponding to the specified font. The
6584 charset info in the font name is used to look up
6585 w32-charset-to-codepage-alist. */
6586int
6587w32_codepage_for_font (char *fontname)
6588{
767b1ff0
JR
6589 Lisp_Object codepage, entry;
6590 char *charset_str, *charset, *end;
dfff8a69 6591
767b1ff0 6592 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6593 return CP_DEFAULT;
6594
767b1ff0
JR
6595 /* Extract charset part of font string. */
6596 charset = xlfd_charset_of_font (fontname);
6597
6598 if (!charset)
ceb12877 6599 return CP_UNKNOWN;
767b1ff0 6600
8b77111c 6601 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6602 strcpy (charset_str, charset);
6603
8b77111c 6604#if 0
dfff8a69
JR
6605 /* Remove leading "*-". */
6606 if (strncmp ("*-", charset_str, 2) == 0)
6607 charset = charset_str + 2;
6608 else
8b77111c 6609#endif
dfff8a69
JR
6610 charset = charset_str;
6611
6612 /* Stop match at wildcard (including preceding '-'). */
6613 if (end = strchr (charset, '*'))
6614 {
6615 if (end > charset && *(end-1) == '-')
6616 end--;
6617 *end = '\0';
6618 }
6619
767b1ff0
JR
6620 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6621 if (NILP (entry))
ceb12877 6622 return CP_UNKNOWN;
767b1ff0
JR
6623
6624 codepage = Fcdr (Fcdr (entry));
6625
6626 if (NILP (codepage))
6627 return CP_8BIT;
6628 else if (XFASTINT (codepage) == XFASTINT (Qt))
6629 return CP_UNICODE;
6630 else if (INTEGERP (codepage))
dfff8a69
JR
6631 return XINT (codepage);
6632 else
ceb12877 6633 return CP_UNKNOWN;
dfff8a69
JR
6634}
6635
6636
8edb0a6f 6637static BOOL
767b1ff0 6638w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6639 LOGFONT * lplogfont;
6640 char * lpxstr;
6641 int len;
767b1ff0 6642 char * specific_charset;
ee78dc32 6643{
6fc2811b 6644 char* fonttype;
f46e6225 6645 char *fontname;
3cb20f4a
RS
6646 char height_pixels[8];
6647 char height_dpi[8];
6648 char width_pixels[8];
4587b026 6649 char *fontname_dash;
ac849ba4
JR
6650 int display_resy = (int) one_w32_display_info.resy;
6651 int display_resx = (int) one_w32_display_info.resx;
f46e6225
GV
6652 int bufsz;
6653 struct coding_system coding;
3cb20f4a
RS
6654
6655 if (!lpxstr) abort ();
ee78dc32 6656
3cb20f4a
RS
6657 if (!lplogfont)
6658 return FALSE;
6659
6fc2811b
JR
6660 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6661 fonttype = "raster";
6662 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6663 fonttype = "outline";
6664 else
6665 fonttype = "unknown";
6666
1fa3a200 6667 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6668 &coding);
aab5ac44
KH
6669 coding.src_multibyte = 0;
6670 coding.dst_multibyte = 1;
f46e6225
GV
6671 coding.mode |= CODING_MODE_LAST_BLOCK;
6672 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6673
6674 fontname = alloca(sizeof(*fontname) * bufsz);
6675 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6676 strlen(lplogfont->lfFaceName), bufsz - 1);
6677 *(fontname + coding.produced) = '\0';
4587b026
GV
6678
6679 /* Replace dashes with underscores so the dashes are not
f46e6225 6680 misinterpreted. */
4587b026
GV
6681 fontname_dash = fontname;
6682 while (fontname_dash = strchr (fontname_dash, '-'))
6683 *fontname_dash = '_';
6684
3cb20f4a 6685 if (lplogfont->lfHeight)
ee78dc32 6686 {
3cb20f4a
RS
6687 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6688 sprintf (height_dpi, "%u",
33d52f9c 6689 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6690 }
6691 else
ee78dc32 6692 {
3cb20f4a
RS
6693 strcpy (height_pixels, "*");
6694 strcpy (height_dpi, "*");
ee78dc32 6695 }
3cb20f4a
RS
6696 if (lplogfont->lfWidth)
6697 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6698 else
6699 strcpy (width_pixels, "*");
6700
6701 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6702 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6703 fonttype, /* foundry */
4587b026
GV
6704 fontname, /* family */
6705 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6706 lplogfont->lfItalic?'i':'r', /* slant */
6707 /* setwidth name */
6708 /* add style name */
6709 height_pixels, /* pixel size */
6710 height_dpi, /* point size */
33d52f9c
GV
6711 display_resx, /* resx */
6712 display_resy, /* resy */
4587b026
GV
6713 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6714 ? 'p' : 'c', /* spacing */
6715 width_pixels, /* avg width */
767b1ff0
JR
6716 specific_charset ? specific_charset
6717 : w32_to_x_charset (lplogfont->lfCharSet)
6718 /* charset registry and encoding */
3cb20f4a
RS
6719 );
6720
ee78dc32
GV
6721 lpxstr[len - 1] = 0; /* just to be sure */
6722 return (TRUE);
6723}
6724
8edb0a6f 6725static BOOL
fbd6baed 6726x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6727 char * lpxstr;
6728 LOGFONT * lplogfont;
6729{
f46e6225
GV
6730 struct coding_system coding;
6731
ee78dc32 6732 if (!lplogfont) return (FALSE);
f46e6225 6733
ee78dc32 6734 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6735
1a292d24 6736 /* Set default value for each field. */
771c47d5 6737#if 1
ee78dc32
GV
6738 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6739 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6740 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6741#else
6742 /* go for maximum quality */
6743 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6744 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6745 lplogfont->lfQuality = PROOF_QUALITY;
6746#endif
6747
1a292d24
AI
6748 lplogfont->lfCharSet = DEFAULT_CHARSET;
6749 lplogfont->lfWeight = FW_DONTCARE;
6750 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6751
5ac45f98
GV
6752 if (!lpxstr)
6753 return FALSE;
6754
6755 /* Provide a simple escape mechanism for specifying Windows font names
6756 * directly -- if font spec does not beginning with '-', assume this
6757 * format:
6758 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6759 */
ee78dc32 6760
5ac45f98
GV
6761 if (*lpxstr == '-')
6762 {
33d52f9c
GV
6763 int fields, tem;
6764 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6765 width[10], resy[10], remainder[50];
5ac45f98 6766 char * encoding;
ac849ba4 6767 int dpi = (int) one_w32_display_info.resy;
5ac45f98
GV
6768
6769 fields = sscanf (lpxstr,
8b77111c 6770 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6771 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6772 if (fields == EOF)
6773 return (FALSE);
6774
6775 /* In the general case when wildcards cover more than one field,
6776 we don't know which field is which, so don't fill any in.
6777 However, we need to cope with this particular form, which is
6778 generated by font_list_1 (invoked by try_font_list):
6779 "-raster-6x10-*-gb2312*-*"
6780 and make sure to correctly parse the charset field. */
6781 if (fields == 3)
6782 {
6783 fields = sscanf (lpxstr,
6784 "-%*[^-]-%49[^-]-*-%49s",
6785 name, remainder);
6786 }
6787 else if (fields < 9)
6788 {
6789 fields = 0;
6790 remainder[0] = 0;
6791 }
6fc2811b 6792
5ac45f98
GV
6793 if (fields > 0 && name[0] != '*')
6794 {
8ea3e054
RS
6795 int bufsize;
6796 unsigned char *buf;
6797
f46e6225 6798 setup_coding_system
1fa3a200 6799 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6800 coding.src_multibyte = 1;
6801 coding.dst_multibyte = 1;
8ea3e054
RS
6802 bufsize = encoding_buffer_size (&coding, strlen (name));
6803 buf = (unsigned char *) alloca (bufsize);
f46e6225 6804 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6805 encode_coding (&coding, name, buf, strlen (name), bufsize);
6806 if (coding.produced >= LF_FACESIZE)
6807 coding.produced = LF_FACESIZE - 1;
6808 buf[coding.produced] = 0;
6809 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6810 }
6811 else
6812 {
6fc2811b 6813 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6814 }
6815
6816 fields--;
6817
fbd6baed 6818 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6819
6820 fields--;
6821
c8874f14 6822 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6823
6824 fields--;
6825
6826 if (fields > 0 && pixels[0] != '*')
6827 lplogfont->lfHeight = atoi (pixels);
6828
6829 fields--;
5ac45f98 6830 fields--;
33d52f9c
GV
6831 if (fields > 0 && resy[0] != '*')
6832 {
6fc2811b 6833 tem = atoi (resy);
33d52f9c
GV
6834 if (tem > 0) dpi = tem;
6835 }
5ac45f98 6836
33d52f9c
GV
6837 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6838 lplogfont->lfHeight = atoi (height) * dpi / 720;
6839
6840 if (fields > 0)
5ac45f98
GV
6841 lplogfont->lfPitchAndFamily =
6842 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6843
6844 fields--;
6845
6846 if (fields > 0 && width[0] != '*')
6847 lplogfont->lfWidth = atoi (width) / 10;
6848
6849 fields--;
6850
4587b026 6851 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6852 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6853 {
5ac45f98
GV
6854 int len = strlen (remainder);
6855 if (len > 0 && remainder[len-1] == '-')
6856 remainder[len-1] = 0;
ee78dc32 6857 }
5ac45f98 6858 encoding = remainder;
8b77111c 6859#if 0
5ac45f98
GV
6860 if (strncmp (encoding, "*-", 2) == 0)
6861 encoding += 2;
8b77111c
AI
6862#endif
6863 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6864 }
6865 else
6866 {
6867 int fields;
6868 char name[100], height[10], width[10], weight[20];
a1a80b40 6869
5ac45f98
GV
6870 fields = sscanf (lpxstr,
6871 "%99[^:]:%9[^:]:%9[^:]:%19s",
6872 name, height, width, weight);
6873
6874 if (fields == EOF) return (FALSE);
6875
6876 if (fields > 0)
6877 {
6878 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6879 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6880 }
6881 else
6882 {
6883 lplogfont->lfFaceName[0] = 0;
6884 }
6885
6886 fields--;
6887
6888 if (fields > 0)
6889 lplogfont->lfHeight = atoi (height);
6890
6891 fields--;
6892
6893 if (fields > 0)
6894 lplogfont->lfWidth = atoi (width);
6895
6896 fields--;
6897
fbd6baed 6898 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6899 }
6900
6901 /* This makes TrueType fonts work better. */
6902 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6903
ee78dc32
GV
6904 return (TRUE);
6905}
6906
d88c567c
JR
6907/* Strip the pixel height and point height from the given xlfd, and
6908 return the pixel height. If no pixel height is specified, calculate
6909 one from the point height, or if that isn't defined either, return
6910 0 (which usually signifies a scalable font).
6911*/
8edb0a6f
JR
6912static int
6913xlfd_strip_height (char *fontname)
d88c567c 6914{
8edb0a6f 6915 int pixel_height, field_number;
d88c567c
JR
6916 char *read_from, *write_to;
6917
6918 xassert (fontname);
6919
6920 pixel_height = field_number = 0;
6921 write_to = NULL;
6922
6923 /* Look for height fields. */
6924 for (read_from = fontname; *read_from; read_from++)
6925 {
6926 if (*read_from == '-')
6927 {
6928 field_number++;
6929 if (field_number == 7) /* Pixel height. */
6930 {
6931 read_from++;
6932 write_to = read_from;
6933
6934 /* Find end of field. */
6935 for (;*read_from && *read_from != '-'; read_from++)
6936 ;
6937
6938 /* Split the fontname at end of field. */
6939 if (*read_from)
6940 {
6941 *read_from = '\0';
6942 read_from++;
6943 }
6944 pixel_height = atoi (write_to);
6945 /* Blank out field. */
6946 if (read_from > write_to)
6947 {
6948 *write_to = '-';
6949 write_to++;
6950 }
767b1ff0 6951 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6952 return now. */
6953 else
6954 return pixel_height;
6955
6956 /* If we got a pixel height, the point height can be
6957 ignored. Just blank it out and break now. */
6958 if (pixel_height)
6959 {
6960 /* Find end of point size field. */
6961 for (; *read_from && *read_from != '-'; read_from++)
6962 ;
6963
6964 if (*read_from)
6965 read_from++;
6966
6967 /* Blank out the point size field. */
6968 if (read_from > write_to)
6969 {
6970 *write_to = '-';
6971 write_to++;
6972 }
6973 else
6974 return pixel_height;
6975
6976 break;
6977 }
6978 /* If the point height is already blank, break now. */
6979 if (*read_from == '-')
6980 {
6981 read_from++;
6982 break;
6983 }
6984 }
6985 else if (field_number == 8)
6986 {
6987 /* If we didn't get a pixel height, try to get the point
6988 height and convert that. */
6989 int point_size;
6990 char *point_size_start = read_from++;
6991
6992 /* Find end of field. */
6993 for (; *read_from && *read_from != '-'; read_from++)
6994 ;
6995
6996 if (*read_from)
6997 {
6998 *read_from = '\0';
6999 read_from++;
7000 }
7001
7002 point_size = atoi (point_size_start);
7003
7004 /* Convert to pixel height. */
7005 pixel_height = point_size
7006 * one_w32_display_info.height_in / 720;
7007
7008 /* Blank out this field and break. */
7009 *write_to = '-';
7010 write_to++;
7011 break;
7012 }
7013 }
7014 }
7015
7016 /* Shift the rest of the font spec into place. */
7017 if (write_to && read_from > write_to)
7018 {
7019 for (; *read_from; read_from++, write_to++)
7020 *write_to = *read_from;
7021 *write_to = '\0';
7022 }
7023
7024 return pixel_height;
7025}
7026
6fc2811b 7027/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 7028static BOOL
6fc2811b
JR
7029w32_font_match (fontname, pattern)
7030 char * fontname;
7031 char * pattern;
ee78dc32 7032{
e7c72122 7033 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 7034 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 7035 char *ptr;
ee78dc32 7036
d88c567c
JR
7037 /* Copy fontname so we can modify it during comparison. */
7038 strcpy (font_name_copy, fontname);
7039
6fc2811b
JR
7040 ptr = regex;
7041 *ptr++ = '^';
ee78dc32 7042
6fc2811b
JR
7043 /* Turn pattern into a regexp and do a regexp match. */
7044 for (; *pattern; pattern++)
7045 {
7046 if (*pattern == '?')
7047 *ptr++ = '.';
7048 else if (*pattern == '*')
7049 {
7050 *ptr++ = '.';
7051 *ptr++ = '*';
7052 }
33d52f9c 7053 else
6fc2811b 7054 *ptr++ = *pattern;
ee78dc32 7055 }
6fc2811b
JR
7056 *ptr = '$';
7057 *(ptr + 1) = '\0';
7058
d88c567c
JR
7059 /* Strip out font heights and compare them seperately, since
7060 rounding error can cause mismatches. This also allows a
7061 comparison between a font that declares only a pixel height and a
7062 pattern that declares the point height.
7063 */
7064 {
7065 int font_height, pattern_height;
7066
7067 font_height = xlfd_strip_height (font_name_copy);
7068 pattern_height = xlfd_strip_height (regex);
7069
7070 /* Compare now, and don't bother doing expensive regexp matching
7071 if the heights differ. */
7072 if (font_height && pattern_height && (font_height != pattern_height))
7073 return FALSE;
7074 }
7075
6fc2811b 7076 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 7077 font_name_copy) >= 0);
ee78dc32
GV
7078}
7079
5ca0cd71
GV
7080/* Callback functions, and a structure holding info they need, for
7081 listing system fonts on W32. We need one set of functions to do the
7082 job properly, but these don't work on NT 3.51 and earlier, so we
7083 have a second set which don't handle character sets properly to
7084 fall back on.
7085
7086 In both cases, there are two passes made. The first pass gets one
7087 font from each family, the second pass lists all the fonts from
7088 each family. */
7089
ee78dc32
GV
7090typedef struct enumfont_t
7091{
7092 HDC hdc;
7093 int numFonts;
3cb20f4a 7094 LOGFONT logfont;
ee78dc32
GV
7095 XFontStruct *size_ref;
7096 Lisp_Object *pattern;
d84b082d 7097 Lisp_Object list;
ee78dc32
GV
7098 Lisp_Object *tail;
7099} enumfont_t;
7100
d84b082d
JR
7101
7102static void
7103enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7104
7105
8edb0a6f 7106static int CALLBACK
ee78dc32
GV
7107enum_font_cb2 (lplf, lptm, FontType, lpef)
7108 ENUMLOGFONT * lplf;
7109 NEWTEXTMETRIC * lptm;
7110 int FontType;
7111 enumfont_t * lpef;
7112{
66895301
JR
7113 /* Ignore struck out and underlined versions of fonts. */
7114 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7115 return 1;
7116
7117 /* Only return fonts with names starting with @ if they were
7118 explicitly specified, since Microsoft uses an initial @ to
7119 denote fonts for vertical writing, without providing a more
7120 convenient way of identifying them. */
7121 if (lplf->elfLogFont.lfFaceName[0] == '@'
7122 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
7123 return 1;
7124
4587b026
GV
7125 /* Check that the character set matches if it was specified */
7126 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7127 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 7128 return 1;
4587b026 7129
6358474d
JR
7130 if (FontType == RASTER_FONTTYPE)
7131 {
7132 /* DBCS raster fonts have problems displaying, so skip them. */
7133 int charset = lplf->elfLogFont.lfCharSet;
7134 if (charset == SHIFTJIS_CHARSET
7135 || charset == HANGEUL_CHARSET
7136 || charset == CHINESEBIG5_CHARSET
7137 || charset == GB2312_CHARSET
7138#ifdef JOHAB_CHARSET
7139 || charset == JOHAB_CHARSET
7140#endif
7141 )
7142 return 1;
7143 }
7144
ee78dc32
GV
7145 {
7146 char buf[100];
4587b026 7147 Lisp_Object width = Qnil;
d84b082d 7148 Lisp_Object charset_list = Qnil;
767b1ff0 7149 char *charset = NULL;
ee78dc32 7150
6fc2811b
JR
7151 /* Truetype fonts do not report their true metrics until loaded */
7152 if (FontType != RASTER_FONTTYPE)
3cb20f4a 7153 {
6fc2811b
JR
7154 if (!NILP (*(lpef->pattern)))
7155 {
7156 /* Scalable fonts are as big as you want them to be. */
7157 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7158 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7159 width = make_number (lpef->logfont.lfWidth);
7160 }
7161 else
7162 {
7163 lplf->elfLogFont.lfHeight = 0;
7164 lplf->elfLogFont.lfWidth = 0;
7165 }
3cb20f4a 7166 }
6fc2811b 7167
f46e6225
GV
7168 /* Make sure the height used here is the same as everywhere
7169 else (ie character height, not cell height). */
6fc2811b
JR
7170 if (lplf->elfLogFont.lfHeight > 0)
7171 {
7172 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7173 if (FontType == RASTER_FONTTYPE)
7174 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7175 else
7176 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7177 }
4587b026 7178
767b1ff0
JR
7179 if (!NILP (*(lpef->pattern)))
7180 {
7181 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
7182
644cefdf
JR
7183 /* We already checked charsets above, but DEFAULT_CHARSET
7184 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7185 if (charset
7186 && strncmp (charset, "*-*", 3) != 0
7187 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7188 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7189 return 1;
767b1ff0
JR
7190 }
7191
d84b082d
JR
7192 if (charset)
7193 charset_list = Fcons (build_string (charset), Qnil);
7194 else
7195 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 7196
d84b082d
JR
7197 /* Loop through the charsets. */
7198 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 7199 {
d84b082d
JR
7200 Lisp_Object this_charset = Fcar (charset_list);
7201 charset = XSTRING (this_charset)->data;
7202
7203 /* List bold and italic variations if w32-enable-synthesized-fonts
7204 is non-nil and this is a plain font. */
7205 if (w32_enable_synthesized_fonts
7206 && lplf->elfLogFont.lfWeight == FW_NORMAL
7207 && lplf->elfLogFont.lfItalic == FALSE)
7208 {
7209 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7210 charset, width);
7211 /* bold. */
7212 lplf->elfLogFont.lfWeight = FW_BOLD;
7213 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7214 charset, width);
7215 /* bold italic. */
7216 lplf->elfLogFont.lfItalic = TRUE;
7217 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7218 charset, width);
7219 /* italic. */
7220 lplf->elfLogFont.lfWeight = FW_NORMAL;
7221 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7222 charset, width);
7223 }
7224 else
7225 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7226 charset, width);
ee78dc32
GV
7227 }
7228 }
6fc2811b 7229
5e905a57 7230 return 1;
ee78dc32
GV
7231}
7232
d84b082d
JR
7233static void
7234enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7235 enumfont_t * lpef;
7236 LOGFONT * logfont;
7237 char * match_charset;
7238 Lisp_Object width;
7239{
7240 char buf[100];
7241
7242 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7243 return;
7244
7245 if (NILP (*(lpef->pattern))
7246 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
7247 {
7248 /* Check if we already listed this font. This may happen if
7249 w32_enable_synthesized_fonts is non-nil, and there are real
7250 bold and italic versions of the font. */
7251 Lisp_Object font_name = build_string (buf);
7252 if (NILP (Fmember (font_name, lpef->list)))
7253 {
7254 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
7255 lpef->tail = &(XCDR (*lpef->tail));
7256 lpef->numFonts++;
7257 }
7258 }
7259}
7260
7261
8edb0a6f 7262static int CALLBACK
ee78dc32
GV
7263enum_font_cb1 (lplf, lptm, FontType, lpef)
7264 ENUMLOGFONT * lplf;
7265 NEWTEXTMETRIC * lptm;
7266 int FontType;
7267 enumfont_t * lpef;
7268{
7269 return EnumFontFamilies (lpef->hdc,
7270 lplf->elfLogFont.lfFaceName,
7271 (FONTENUMPROC) enum_font_cb2,
7272 (LPARAM) lpef);
7273}
7274
7275
8edb0a6f 7276static int CALLBACK
5ca0cd71
GV
7277enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7278 ENUMLOGFONTEX * lplf;
7279 NEWTEXTMETRICEX * lptm;
7280 int font_type;
7281 enumfont_t * lpef;
7282{
7283 /* We are not interested in the extra info we get back from the 'Ex
7284 version - only the fact that we get character set variations
7285 enumerated seperately. */
7286 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7287 font_type, lpef);
7288}
7289
8edb0a6f 7290static int CALLBACK
5ca0cd71
GV
7291enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7292 ENUMLOGFONTEX * lplf;
7293 NEWTEXTMETRICEX * lptm;
7294 int font_type;
7295 enumfont_t * lpef;
7296{
7297 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7298 FARPROC enum_font_families_ex
7299 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7300 /* We don't really expect EnumFontFamiliesEx to disappear once we
7301 get here, so don't bother handling it gracefully. */
7302 if (enum_font_families_ex == NULL)
7303 error ("gdi32.dll has disappeared!");
7304 return enum_font_families_ex (lpef->hdc,
7305 &lplf->elfLogFont,
7306 (FONTENUMPROC) enum_fontex_cb2,
7307 (LPARAM) lpef, 0);
7308}
7309
4587b026
GV
7310/* Interface to fontset handler. (adapted from mw32font.c in Meadow
7311 and xterm.c in Emacs 20.3) */
7312
8edb0a6f 7313static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
7314{
7315 char *fontname, *ptnstr;
7316 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 7317 int n_fonts = 0;
33d52f9c
GV
7318
7319 list = Vw32_bdf_filename_alist;
7320 ptnstr = XSTRING (pattern)->data;
7321
8e713be6 7322 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 7323 {
8e713be6 7324 tem = XCAR (list);
33d52f9c 7325 if (CONSP (tem))
8e713be6 7326 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
7327 else if (STRINGP (tem))
7328 fontname = XSTRING (tem)->data;
7329 else
7330 continue;
7331
7332 if (w32_font_match (fontname, ptnstr))
5ca0cd71 7333 {
8e713be6 7334 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7335 n_fonts++;
7336 if (n_fonts >= max_names)
7337 break;
7338 }
33d52f9c
GV
7339 }
7340
7341 return newlist;
7342}
7343
5ca0cd71 7344
4587b026
GV
7345/* Return a list of names of available fonts matching PATTERN on frame
7346 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7347 to be listed. Frame F NULL means we have not yet created any
7348 frame, which means we can't get proper size info, as we don't have
7349 a device context to use for GetTextMetrics.
7350 MAXNAMES sets a limit on how many fonts to match. */
7351
7352Lisp_Object
dc220243
JR
7353w32_list_fonts (f, pattern, size, maxnames)
7354 struct frame *f;
7355 Lisp_Object pattern;
7356 int size;
7357 int maxnames;
4587b026 7358{
6fc2811b 7359 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 7360 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 7361 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 7362 int n_fonts = 0;
396594fe 7363
4587b026
GV
7364 patterns = Fassoc (pattern, Valternate_fontname_alist);
7365 if (NILP (patterns))
7366 patterns = Fcons (pattern, Qnil);
7367
8e713be6 7368 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
7369 {
7370 enumfont_t ef;
767b1ff0 7371 int codepage;
4587b026 7372
8e713be6 7373 tpat = XCAR (patterns);
4587b026 7374
767b1ff0
JR
7375 if (!STRINGP (tpat))
7376 continue;
7377
7378 /* Avoid expensive EnumFontFamilies functions if we are not
7379 going to be able to output one of these anyway. */
7380 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7381 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7382 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7383 && !IsValidCodePage(codepage))
767b1ff0
JR
7384 continue;
7385
4587b026
GV
7386 /* See if we cached the result for this particular query.
7387 The cache is an alist of the form:
7388 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7389 */
8e713be6 7390 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7391 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7392 {
7393 list = Fcdr_safe (list);
7394 /* We have a cached list. Don't have to get the list again. */
7395 goto label_cached;
7396 }
7397
7398 BLOCK_INPUT;
7399 /* At first, put PATTERN in the cache. */
7400 list = Qnil;
33d52f9c 7401 ef.pattern = &tpat;
d84b082d 7402 ef.list = list;
33d52f9c 7403 ef.tail = &list;
4587b026 7404 ef.numFonts = 0;
33d52f9c 7405
5ca0cd71
GV
7406 /* Use EnumFontFamiliesEx where it is available, as it knows
7407 about character sets. Fall back to EnumFontFamilies for
7408 older versions of NT that don't support the 'Ex function. */
767b1ff0 7409 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7410 {
5ca0cd71
GV
7411 LOGFONT font_match_pattern;
7412 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7413 FARPROC enum_font_families_ex
7414 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7415
7416 /* We do our own pattern matching so we can handle wildcards. */
7417 font_match_pattern.lfFaceName[0] = 0;
7418 font_match_pattern.lfPitchAndFamily = 0;
7419 /* We can use the charset, because if it is a wildcard it will
7420 be DEFAULT_CHARSET anyway. */
7421 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7422
33d52f9c 7423 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7424
5ca0cd71
GV
7425 if (enum_font_families_ex)
7426 enum_font_families_ex (ef.hdc,
7427 &font_match_pattern,
7428 (FONTENUMPROC) enum_fontex_cb1,
7429 (LPARAM) &ef, 0);
7430 else
7431 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7432 (LPARAM)&ef);
4587b026 7433
33d52f9c 7434 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7435 }
7436
7437 UNBLOCK_INPUT;
7438
7439 /* Make a list of the fonts we got back.
7440 Store that in the font cache for the display. */
f3fbd155
KR
7441 XSETCDR (dpyinfo->name_list_element,
7442 Fcons (Fcons (tpat, list),
7443 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7444
7445 label_cached:
7446 if (NILP (list)) continue; /* Try the remaining alternatives. */
7447
7448 newlist = second_best = Qnil;
7449
7450 /* Make a list of the fonts that have the right width. */
8e713be6 7451 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7452 {
7453 int found_size;
8e713be6 7454 tem = XCAR (list);
4587b026
GV
7455
7456 if (!CONSP (tem))
7457 continue;
8e713be6 7458 if (NILP (XCAR (tem)))
4587b026
GV
7459 continue;
7460 if (!size)
7461 {
8e713be6 7462 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7463 n_fonts++;
7464 if (n_fonts >= maxnames)
7465 break;
7466 else
7467 continue;
4587b026 7468 }
8e713be6 7469 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7470 {
7471 /* Since we don't yet know the size of the font, we must
7472 load it and try GetTextMetrics. */
4587b026
GV
7473 W32FontStruct thisinfo;
7474 LOGFONT lf;
7475 HDC hdc;
7476 HANDLE oldobj;
7477
8e713be6 7478 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7479 continue;
7480
7481 BLOCK_INPUT;
33d52f9c 7482 thisinfo.bdf = NULL;
4587b026
GV
7483 thisinfo.hfont = CreateFontIndirect (&lf);
7484 if (thisinfo.hfont == NULL)
7485 continue;
7486
7487 hdc = GetDC (dpyinfo->root_window);
7488 oldobj = SelectObject (hdc, thisinfo.hfont);
7489 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7490 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7491 else
f3fbd155 7492 XSETCDR (tem, make_number (0));
4587b026
GV
7493 SelectObject (hdc, oldobj);
7494 ReleaseDC (dpyinfo->root_window, hdc);
7495 DeleteObject(thisinfo.hfont);
7496 UNBLOCK_INPUT;
7497 }
8e713be6 7498 found_size = XINT (XCDR (tem));
4587b026 7499 if (found_size == size)
5ca0cd71 7500 {
8e713be6 7501 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7502 n_fonts++;
7503 if (n_fonts >= maxnames)
7504 break;
7505 }
4587b026
GV
7506 /* keep track of the closest matching size in case
7507 no exact match is found. */
7508 else if (found_size > 0)
7509 {
7510 if (NILP (second_best))
7511 second_best = tem;
5ca0cd71 7512
4587b026
GV
7513 else if (found_size < size)
7514 {
8e713be6
KR
7515 if (XINT (XCDR (second_best)) > size
7516 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7517 second_best = tem;
7518 }
7519 else
7520 {
8e713be6
KR
7521 if (XINT (XCDR (second_best)) > size
7522 && XINT (XCDR (second_best)) >
4587b026
GV
7523 found_size)
7524 second_best = tem;
7525 }
7526 }
7527 }
7528
7529 if (!NILP (newlist))
7530 break;
7531 else if (!NILP (second_best))
7532 {
8e713be6 7533 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7534 break;
7535 }
7536 }
7537
33d52f9c 7538 /* Include any bdf fonts. */
5ca0cd71 7539 if (n_fonts < maxnames)
33d52f9c
GV
7540 {
7541 Lisp_Object combined[2];
5ca0cd71 7542 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7543 combined[1] = newlist;
7544 newlist = Fnconc(2, combined);
7545 }
7546
4587b026
GV
7547 return newlist;
7548}
7549
5ca0cd71 7550
4587b026
GV
7551/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7552struct font_info *
7553w32_get_font_info (f, font_idx)
7554 FRAME_PTR f;
7555 int font_idx;
7556{
7557 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7558}
7559
7560
7561struct font_info*
7562w32_query_font (struct frame *f, char *fontname)
7563{
7564 int i;
7565 struct font_info *pfi;
7566
7567 pfi = FRAME_W32_FONT_TABLE (f);
7568
7569 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7570 {
7571 if (strcmp(pfi->name, fontname) == 0) return pfi;
7572 }
7573
7574 return NULL;
7575}
7576
7577/* Find a CCL program for a font specified by FONTP, and set the member
7578 `encoder' of the structure. */
7579
7580void
7581w32_find_ccl_program (fontp)
7582 struct font_info *fontp;
7583{
3545439c 7584 Lisp_Object list, elt;
4587b026 7585
8e713be6 7586 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7587 {
8e713be6 7588 elt = XCAR (list);
4587b026 7589 if (CONSP (elt)
8e713be6
KR
7590 && STRINGP (XCAR (elt))
7591 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7592 >= 0))
3545439c
KH
7593 break;
7594 }
7595 if (! NILP (list))
7596 {
17eedd00
KH
7597 struct ccl_program *ccl
7598 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7599
8e713be6 7600 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7601 xfree (ccl);
7602 else
7603 fontp->font_encoder = ccl;
4587b026
GV
7604 }
7605}
7606
7607\f
8edb0a6f
JR
7608/* Find BDF files in a specified directory. (use GCPRO when calling,
7609 as this calls lisp to get a directory listing). */
7610static Lisp_Object
7611w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7612{
7613 Lisp_Object filelist, list = Qnil;
7614 char fontname[100];
7615
7616 if (!STRINGP(directory))
7617 return Qnil;
7618
7619 filelist = Fdirectory_files (directory, Qt,
7620 build_string (".*\\.[bB][dD][fF]"), Qt);
7621
7622 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7623 {
7624 Lisp_Object filename = XCAR (filelist);
7625 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7626 store_in_alist (&list, build_string (fontname), filename);
7627 }
7628 return list;
7629}
7630
6fc2811b
JR
7631DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7632 1, 1, 0,
b3700ae7
JR
7633 doc: /* Return a list of BDF fonts in DIR.
7634The list is suitable for appending to w32-bdf-filename-alist. Fonts
7635which do not contain an xlfd description will not be included in the
7636list. DIR may be a list of directories. */)
6fc2811b
JR
7637 (directory)
7638 Lisp_Object directory;
7639{
7640 Lisp_Object list = Qnil;
7641 struct gcpro gcpro1, gcpro2;
ee78dc32 7642
6fc2811b
JR
7643 if (!CONSP (directory))
7644 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7645
6fc2811b 7646 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7647 {
6fc2811b
JR
7648 Lisp_Object pair[2];
7649 pair[0] = list;
7650 pair[1] = Qnil;
7651 GCPRO2 (directory, list);
7652 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7653 list = Fnconc( 2, pair );
7654 UNGCPRO;
7655 }
7656 return list;
7657}
ee78dc32 7658
6fc2811b
JR
7659\f
7660DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7661 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7662 (color, frame)
7663 Lisp_Object color, frame;
7664{
7665 XColor foo;
7666 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7667
b7826503 7668 CHECK_STRING (color);
ee78dc32 7669
6fc2811b
JR
7670 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7671 return Qt;
7672 else
7673 return Qnil;
7674}
ee78dc32 7675
2d764c78 7676DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7677 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7678 (color, frame)
7679 Lisp_Object color, frame;
7680{
6fc2811b 7681 XColor foo;
ee78dc32
GV
7682 FRAME_PTR f = check_x_frame (frame);
7683
b7826503 7684 CHECK_STRING (color);
ee78dc32 7685
6fc2811b 7686 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7687 {
7688 Lisp_Object rgb[3];
7689
6fc2811b
JR
7690 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7691 | GetRValue (foo.pixel));
7692 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7693 | GetGValue (foo.pixel));
7694 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7695 | GetBValue (foo.pixel));
ee78dc32
GV
7696 return Flist (3, rgb);
7697 }
7698 else
7699 return Qnil;
7700}
7701
2d764c78 7702DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7703 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7704 (display)
7705 Lisp_Object display;
7706{
fbd6baed 7707 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7708
7709 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7710 return Qnil;
7711
7712 return Qt;
7713}
7714
74e1aeec
JR
7715DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7716 Sx_display_grayscale_p, 0, 1, 0,
7717 doc: /* Return t if the X display supports shades of gray.
7718Note that color displays do support shades of gray.
7719The optional argument DISPLAY specifies which display to ask about.
7720DISPLAY should be either a frame or a display name (a string).
7721If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7722 (display)
7723 Lisp_Object display;
7724{
fbd6baed 7725 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7726
7727 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7728 return Qnil;
7729
7730 return Qt;
7731}
7732
74e1aeec
JR
7733DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7734 Sx_display_pixel_width, 0, 1, 0,
7735 doc: /* Returns the width in pixels of DISPLAY.
7736The optional argument DISPLAY specifies which display to ask about.
7737DISPLAY should be either a frame or a display name (a string).
7738If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7739 (display)
7740 Lisp_Object display;
7741{
fbd6baed 7742 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7743
7744 return make_number (dpyinfo->width);
7745}
7746
7747DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7748 Sx_display_pixel_height, 0, 1, 0,
7749 doc: /* Returns the height in pixels of DISPLAY.
7750The optional argument DISPLAY specifies which display to ask about.
7751DISPLAY should be either a frame or a display name (a string).
7752If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7753 (display)
7754 Lisp_Object display;
7755{
fbd6baed 7756 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7757
7758 return make_number (dpyinfo->height);
7759}
7760
7761DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7762 0, 1, 0,
7763 doc: /* Returns the number of bitplanes of DISPLAY.
7764The optional argument DISPLAY specifies which display to ask about.
7765DISPLAY should be either a frame or a display name (a string).
7766If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7767 (display)
7768 Lisp_Object display;
7769{
fbd6baed 7770 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7771
7772 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7773}
7774
7775DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7776 0, 1, 0,
7777 doc: /* Returns the number of color cells of DISPLAY.
7778The optional argument DISPLAY specifies which display to ask about.
7779DISPLAY should be either a frame or a display name (a string).
7780If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7781 (display)
7782 Lisp_Object display;
7783{
fbd6baed 7784 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7785 HDC hdc;
7786 int cap;
7787
5ac45f98
GV
7788 hdc = GetDC (dpyinfo->root_window);
7789 if (dpyinfo->has_palette)
7790 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7791 else
7792 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b 7793
007776bc
JB
7794 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7795 and because probably is more meaningful on Windows anyway */
abf8c61b 7796 if (cap < 0)
007776bc 7797 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
ee78dc32
GV
7798
7799 ReleaseDC (dpyinfo->root_window, hdc);
7800
7801 return make_number (cap);
7802}
7803
7804DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7805 Sx_server_max_request_size,
74e1aeec
JR
7806 0, 1, 0,
7807 doc: /* Returns the maximum request size of the server of DISPLAY.
7808The optional argument DISPLAY specifies which display to ask about.
7809DISPLAY should be either a frame or a display name (a string).
7810If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7811 (display)
7812 Lisp_Object display;
7813{
fbd6baed 7814 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7815
7816 return make_number (1);
7817}
7818
7819DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7820 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7821The optional argument DISPLAY specifies which display to ask about.
7822DISPLAY should be either a frame or a display name (a string).
7823If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7824 (display)
7825 Lisp_Object display;
7826{
dfff8a69 7827 return build_string ("Microsoft Corp.");
ee78dc32
GV
7828}
7829
7830DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7831 doc: /* Returns the version numbers of the server of DISPLAY.
7832The value is a list of three integers: the major and minor
7833version numbers, and the vendor-specific release
7834number. See also the function `x-server-vendor'.
7835
7836The optional argument DISPLAY specifies which display to ask about.
7837DISPLAY should be either a frame or a display name (a string).
7838If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7839 (display)
7840 Lisp_Object display;
7841{
fbd6baed 7842 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7843 Fcons (make_number (w32_minor_version),
7844 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7845}
7846
7847DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7848 doc: /* Returns the number of screens on the server of DISPLAY.
7849The optional argument DISPLAY specifies which display to ask about.
7850DISPLAY should be either a frame or a display name (a string).
7851If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7852 (display)
7853 Lisp_Object display;
7854{
ee78dc32
GV
7855 return make_number (1);
7856}
7857
74e1aeec
JR
7858DEFUN ("x-display-mm-height", Fx_display_mm_height,
7859 Sx_display_mm_height, 0, 1, 0,
7860 doc: /* Returns the height in millimeters of DISPLAY.
7861The optional argument DISPLAY specifies which display to ask about.
7862DISPLAY should be either a frame or a display name (a string).
7863If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7864 (display)
7865 Lisp_Object display;
7866{
fbd6baed 7867 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7868 HDC hdc;
7869 int cap;
7870
5ac45f98 7871 hdc = GetDC (dpyinfo->root_window);
3c190163 7872
ee78dc32 7873 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7874
ee78dc32
GV
7875 ReleaseDC (dpyinfo->root_window, hdc);
7876
7877 return make_number (cap);
7878}
7879
7880DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7881 doc: /* Returns the width in millimeters of DISPLAY.
7882The optional argument DISPLAY specifies which display to ask about.
7883DISPLAY should be either a frame or a display name (a string).
7884If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7885 (display)
7886 Lisp_Object display;
7887{
fbd6baed 7888 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7889
7890 HDC hdc;
7891 int cap;
7892
5ac45f98 7893 hdc = GetDC (dpyinfo->root_window);
3c190163 7894
ee78dc32 7895 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7896
ee78dc32
GV
7897 ReleaseDC (dpyinfo->root_window, hdc);
7898
7899 return make_number (cap);
7900}
7901
7902DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7903 Sx_display_backing_store, 0, 1, 0,
7904 doc: /* Returns an indication of whether DISPLAY does backing store.
7905The value may be `always', `when-mapped', or `not-useful'.
7906The optional argument DISPLAY specifies which display to ask about.
7907DISPLAY should be either a frame or a display name (a string).
7908If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7909 (display)
7910 Lisp_Object display;
7911{
7912 return intern ("not-useful");
7913}
7914
7915DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7916 Sx_display_visual_class, 0, 1, 0,
7917 doc: /* Returns the visual class of DISPLAY.
7918The value is one of the symbols `static-gray', `gray-scale',
7919`static-color', `pseudo-color', `true-color', or `direct-color'.
7920
7921The optional argument DISPLAY specifies which display to ask about.
7922DISPLAY should be either a frame or a display name (a string).
7923If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7924 (display)
7925 Lisp_Object display;
7926{
fbd6baed 7927 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7928 Lisp_Object result = Qnil;
ee78dc32 7929
abf8c61b
AI
7930 if (dpyinfo->has_palette)
7931 result = intern ("pseudo-color");
7932 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7933 result = intern ("static-grey");
7934 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7935 result = intern ("static-color");
7936 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7937 result = intern ("true-color");
ee78dc32 7938
abf8c61b 7939 return result;
ee78dc32
GV
7940}
7941
7942DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7943 Sx_display_save_under, 0, 1, 0,
7944 doc: /* Returns t if DISPLAY supports the save-under feature.
7945The optional argument DISPLAY specifies which display to ask about.
7946DISPLAY should be either a frame or a display name (a string).
7947If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7948 (display)
7949 Lisp_Object display;
7950{
6fc2811b
JR
7951 return Qnil;
7952}
7953\f
7954int
7955x_pixel_width (f)
7956 register struct frame *f;
7957{
7958 return PIXEL_WIDTH (f);
7959}
7960
7961int
7962x_pixel_height (f)
7963 register struct frame *f;
7964{
7965 return PIXEL_HEIGHT (f);
7966}
7967
7968int
7969x_char_width (f)
7970 register struct frame *f;
7971{
7972 return FONT_WIDTH (f->output_data.w32->font);
7973}
7974
7975int
7976x_char_height (f)
7977 register struct frame *f;
7978{
7979 return f->output_data.w32->line_height;
7980}
7981
7982int
7983x_screen_planes (f)
7984 register struct frame *f;
7985{
7986 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7987}
7988\f
7989/* Return the display structure for the display named NAME.
7990 Open a new connection if necessary. */
7991
7992struct w32_display_info *
7993x_display_info_for_name (name)
7994 Lisp_Object name;
7995{
7996 Lisp_Object names;
7997 struct w32_display_info *dpyinfo;
7998
b7826503 7999 CHECK_STRING (name);
6fc2811b
JR
8000
8001 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
8002 dpyinfo;
8003 dpyinfo = dpyinfo->next, names = XCDR (names))
8004 {
8005 Lisp_Object tem;
8006 tem = Fstring_equal (XCAR (XCAR (names)), name);
8007 if (!NILP (tem))
8008 return dpyinfo;
8009 }
8010
8011 /* Use this general default value to start with. */
8012 Vx_resource_name = Vinvocation_name;
8013
8014 validate_x_resource_name ();
8015
8016 dpyinfo = w32_term_init (name, (unsigned char *)0,
8017 (char *) XSTRING (Vx_resource_name)->data);
8018
8019 if (dpyinfo == 0)
8020 error ("Cannot connect to server %s", XSTRING (name)->data);
8021
8022 w32_in_use = 1;
8023 XSETFASTINT (Vwindow_system_version, 3);
8024
8025 return dpyinfo;
8026}
8027
8028DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
8029 1, 3, 0, doc: /* Open a connection to a server.
8030DISPLAY is the name of the display to connect to.
8031Optional second arg XRM-STRING is a string of resources in xrdb format.
8032If the optional third arg MUST-SUCCEED is non-nil,
8033terminate Emacs if we can't open the connection. */)
6fc2811b
JR
8034 (display, xrm_string, must_succeed)
8035 Lisp_Object display, xrm_string, must_succeed;
8036{
8037 unsigned char *xrm_option;
8038 struct w32_display_info *dpyinfo;
8039
74e1aeec
JR
8040 /* If initialization has already been done, return now to avoid
8041 overwriting critical parts of one_w32_display_info. */
8042 if (w32_in_use)
8043 return Qnil;
8044
b7826503 8045 CHECK_STRING (display);
6fc2811b 8046 if (! NILP (xrm_string))
b7826503 8047 CHECK_STRING (xrm_string);
6fc2811b
JR
8048
8049 if (! EQ (Vwindow_system, intern ("w32")))
8050 error ("Not using Microsoft Windows");
8051
8052 /* Allow color mapping to be defined externally; first look in user's
8053 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8054 {
8055 Lisp_Object color_file;
8056 struct gcpro gcpro1;
8057
8058 color_file = build_string("~/rgb.txt");
8059
8060 GCPRO1 (color_file);
8061
8062 if (NILP (Ffile_readable_p (color_file)))
8063 color_file =
8064 Fexpand_file_name (build_string ("rgb.txt"),
8065 Fsymbol_value (intern ("data-directory")));
8066
8067 Vw32_color_map = Fw32_load_color_file (color_file);
8068
8069 UNGCPRO;
8070 }
8071 if (NILP (Vw32_color_map))
8072 Vw32_color_map = Fw32_default_color_map ();
8073
8074 if (! NILP (xrm_string))
8075 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8076 else
8077 xrm_option = (unsigned char *) 0;
8078
8079 /* Use this general default value to start with. */
8080 /* First remove .exe suffix from invocation-name - it looks ugly. */
8081 {
8082 char basename[ MAX_PATH ], *str;
8083
8084 strcpy (basename, XSTRING (Vinvocation_name)->data);
8085 str = strrchr (basename, '.');
8086 if (str) *str = 0;
8087 Vinvocation_name = build_string (basename);
8088 }
8089 Vx_resource_name = Vinvocation_name;
8090
8091 validate_x_resource_name ();
8092
8093 /* This is what opens the connection and sets x_current_display.
8094 This also initializes many symbols, such as those used for input. */
8095 dpyinfo = w32_term_init (display, xrm_option,
8096 (char *) XSTRING (Vx_resource_name)->data);
8097
8098 if (dpyinfo == 0)
8099 {
8100 if (!NILP (must_succeed))
8101 fatal ("Cannot connect to server %s.\n",
8102 XSTRING (display)->data);
8103 else
8104 error ("Cannot connect to server %s", XSTRING (display)->data);
8105 }
8106
8107 w32_in_use = 1;
8108
8109 XSETFASTINT (Vwindow_system_version, 3);
8110 return Qnil;
8111}
8112
8113DEFUN ("x-close-connection", Fx_close_connection,
8114 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
8115 doc: /* Close the connection to DISPLAY's server.
8116For DISPLAY, specify either a frame or a display name (a string).
8117If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
8118 (display)
8119 Lisp_Object display;
8120{
8121 struct w32_display_info *dpyinfo = check_x_display_info (display);
8122 int i;
8123
8124 if (dpyinfo->reference_count > 0)
8125 error ("Display still has frames on it");
8126
8127 BLOCK_INPUT;
8128 /* Free the fonts in the font table. */
8129 for (i = 0; i < dpyinfo->n_fonts; i++)
8130 if (dpyinfo->font_table[i].name)
8131 {
126f2e35
JR
8132 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8133 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 8134 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
8135 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8136 }
8137 x_destroy_all_bitmaps (dpyinfo);
8138
8139 x_delete_display (dpyinfo);
8140 UNBLOCK_INPUT;
8141
8142 return Qnil;
8143}
8144
8145DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 8146 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
8147 ()
8148{
8149 Lisp_Object tail, result;
8150
8151 result = Qnil;
8152 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8153 result = Fcons (XCAR (XCAR (tail)), result);
8154
8155 return result;
8156}
8157
8158DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
8159 doc: /* This is a noop on W32 systems. */)
8160 (on, display)
8161 Lisp_Object display, on;
6fc2811b 8162{
6fc2811b
JR
8163 return Qnil;
8164}
8165
8166\f
6fc2811b
JR
8167/***********************************************************************
8168 Image types
8169 ***********************************************************************/
8170
8171/* Value is the number of elements of vector VECTOR. */
8172
8173#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8174
8175/* List of supported image types. Use define_image_type to add new
8176 types. Use lookup_image_type to find a type for a given symbol. */
8177
8178static struct image_type *image_types;
8179
6fc2811b
JR
8180/* The symbol `image' which is the car of the lists used to represent
8181 images in Lisp. */
8182
8183extern Lisp_Object Qimage;
8184
8185/* The symbol `xbm' which is used as the type symbol for XBM images. */
8186
8187Lisp_Object Qxbm;
8188
8189/* Keywords. */
8190
6fc2811b 8191extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
8192extern Lisp_Object QCdata, QCtype;
8193Lisp_Object QCascent, QCmargin, QCrelief;
a93f4566 8194Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 8195Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
8196
8197/* Other symbols. */
8198
3cf3436e 8199Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
8200
8201/* Time in seconds after which images should be removed from the cache
8202 if not displayed. */
8203
8204Lisp_Object Vimage_cache_eviction_delay;
8205
8206/* Function prototypes. */
8207
8208static void define_image_type P_ ((struct image_type *type));
8209static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8210static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8211static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 8212static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
8213static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8214 Lisp_Object));
8215
dfff8a69 8216
6fc2811b
JR
8217/* Define a new image type from TYPE. This adds a copy of TYPE to
8218 image_types and adds the symbol *TYPE->type to Vimage_types. */
8219
8220static void
8221define_image_type (type)
8222 struct image_type *type;
8223{
8224 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8225 The initialized data segment is read-only. */
8226 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8227 bcopy (type, p, sizeof *p);
8228 p->next = image_types;
8229 image_types = p;
8230 Vimage_types = Fcons (*p->type, Vimage_types);
8231}
8232
8233
8234/* Look up image type SYMBOL, and return a pointer to its image_type
8235 structure. Value is null if SYMBOL is not a known image type. */
8236
8237static INLINE struct image_type *
8238lookup_image_type (symbol)
8239 Lisp_Object symbol;
8240{
8241 struct image_type *type;
8242
8243 for (type = image_types; type; type = type->next)
8244 if (EQ (symbol, *type->type))
8245 break;
8246
8247 return type;
8248}
8249
8250
8251/* Value is non-zero if OBJECT is a valid Lisp image specification. A
8252 valid image specification is a list whose car is the symbol
8253 `image', and whose rest is a property list. The property list must
8254 contain a value for key `:type'. That value must be the name of a
8255 supported image type. The rest of the property list depends on the
8256 image type. */
8257
8258int
8259valid_image_p (object)
8260 Lisp_Object object;
8261{
8262 int valid_p = 0;
8263
8264 if (CONSP (object) && EQ (XCAR (object), Qimage))
8265 {
3cf3436e
JR
8266 Lisp_Object tem;
8267
8268 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8269 if (EQ (XCAR (tem), QCtype))
8270 {
8271 tem = XCDR (tem);
8272 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8273 {
8274 struct image_type *type;
8275 type = lookup_image_type (XCAR (tem));
8276 if (type)
8277 valid_p = type->valid_p (object);
8278 }
8279
8280 break;
8281 }
6fc2811b
JR
8282 }
8283
8284 return valid_p;
8285}
8286
8287
8288/* Log error message with format string FORMAT and argument ARG.
8289 Signaling an error, e.g. when an image cannot be loaded, is not a
8290 good idea because this would interrupt redisplay, and the error
8291 message display would lead to another redisplay. This function
8292 therefore simply displays a message. */
8293
8294static void
8295image_error (format, arg1, arg2)
8296 char *format;
8297 Lisp_Object arg1, arg2;
8298{
8299 add_to_log (format, arg1, arg2);
8300}
8301
8302
8303\f
8304/***********************************************************************
8305 Image specifications
8306 ***********************************************************************/
8307
8308enum image_value_type
8309{
8310 IMAGE_DONT_CHECK_VALUE_TYPE,
8311 IMAGE_STRING_VALUE,
3cf3436e 8312 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
8313 IMAGE_SYMBOL_VALUE,
8314 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8315 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8316 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8317 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8318 IMAGE_INTEGER_VALUE,
8319 IMAGE_FUNCTION_VALUE,
8320 IMAGE_NUMBER_VALUE,
8321 IMAGE_BOOL_VALUE
8322};
8323
8324/* Structure used when parsing image specifications. */
8325
8326struct image_keyword
8327{
8328 /* Name of keyword. */
8329 char *name;
8330
8331 /* The type of value allowed. */
8332 enum image_value_type type;
8333
8334 /* Non-zero means key must be present. */
8335 int mandatory_p;
8336
8337 /* Used to recognize duplicate keywords in a property list. */
8338 int count;
8339
8340 /* The value that was found. */
8341 Lisp_Object value;
8342};
8343
8344
8345static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8346 int, Lisp_Object));
8347static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8348
8349
8350/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8351 has the format (image KEYWORD VALUE ...). One of the keyword/
8352 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8353 image_keywords structures of size NKEYWORDS describing other
8354 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8355
8356static int
8357parse_image_spec (spec, keywords, nkeywords, type)
8358 Lisp_Object spec;
8359 struct image_keyword *keywords;
8360 int nkeywords;
8361 Lisp_Object type;
8362{
8363 int i;
8364 Lisp_Object plist;
8365
8366 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8367 return 0;
8368
8369 plist = XCDR (spec);
8370 while (CONSP (plist))
8371 {
8372 Lisp_Object key, value;
8373
8374 /* First element of a pair must be a symbol. */
8375 key = XCAR (plist);
8376 plist = XCDR (plist);
8377 if (!SYMBOLP (key))
8378 return 0;
8379
8380 /* There must follow a value. */
8381 if (!CONSP (plist))
8382 return 0;
8383 value = XCAR (plist);
8384 plist = XCDR (plist);
8385
8386 /* Find key in KEYWORDS. Error if not found. */
8387 for (i = 0; i < nkeywords; ++i)
8388 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8389 break;
8390
8391 if (i == nkeywords)
8392 continue;
8393
8394 /* Record that we recognized the keyword. If a keywords
8395 was found more than once, it's an error. */
8396 keywords[i].value = value;
8397 ++keywords[i].count;
8398
8399 if (keywords[i].count > 1)
8400 return 0;
8401
8402 /* Check type of value against allowed type. */
8403 switch (keywords[i].type)
8404 {
8405 case IMAGE_STRING_VALUE:
8406 if (!STRINGP (value))
8407 return 0;
8408 break;
8409
3cf3436e
JR
8410 case IMAGE_STRING_OR_NIL_VALUE:
8411 if (!STRINGP (value) && !NILP (value))
8412 return 0;
8413 break;
8414
6fc2811b
JR
8415 case IMAGE_SYMBOL_VALUE:
8416 if (!SYMBOLP (value))
8417 return 0;
8418 break;
8419
8420 case IMAGE_POSITIVE_INTEGER_VALUE:
8421 if (!INTEGERP (value) || XINT (value) <= 0)
8422 return 0;
8423 break;
8424
8edb0a6f
JR
8425 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8426 if (INTEGERP (value) && XINT (value) >= 0)
8427 break;
8428 if (CONSP (value)
8429 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8430 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8431 break;
8432 return 0;
8433
dfff8a69
JR
8434 case IMAGE_ASCENT_VALUE:
8435 if (SYMBOLP (value) && EQ (value, Qcenter))
8436 break;
8437 else if (INTEGERP (value)
8438 && XINT (value) >= 0
8439 && XINT (value) <= 100)
8440 break;
8441 return 0;
8442
6fc2811b
JR
8443 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8444 if (!INTEGERP (value) || XINT (value) < 0)
8445 return 0;
8446 break;
8447
8448 case IMAGE_DONT_CHECK_VALUE_TYPE:
8449 break;
8450
8451 case IMAGE_FUNCTION_VALUE:
8452 value = indirect_function (value);
8453 if (SUBRP (value)
8454 || COMPILEDP (value)
8455 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8456 break;
8457 return 0;
8458
8459 case IMAGE_NUMBER_VALUE:
8460 if (!INTEGERP (value) && !FLOATP (value))
8461 return 0;
8462 break;
8463
8464 case IMAGE_INTEGER_VALUE:
8465 if (!INTEGERP (value))
8466 return 0;
8467 break;
8468
8469 case IMAGE_BOOL_VALUE:
8470 if (!NILP (value) && !EQ (value, Qt))
8471 return 0;
8472 break;
8473
8474 default:
8475 abort ();
8476 break;
8477 }
8478
8479 if (EQ (key, QCtype) && !EQ (type, value))
8480 return 0;
8481 }
8482
8483 /* Check that all mandatory fields are present. */
8484 for (i = 0; i < nkeywords; ++i)
8485 if (keywords[i].mandatory_p && keywords[i].count == 0)
8486 return 0;
8487
8488 return NILP (plist);
8489}
8490
8491
8492/* Return the value of KEY in image specification SPEC. Value is nil
8493 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8494 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8495
8496static Lisp_Object
8497image_spec_value (spec, key, found)
8498 Lisp_Object spec, key;
8499 int *found;
8500{
8501 Lisp_Object tail;
8502
8503 xassert (valid_image_p (spec));
8504
8505 for (tail = XCDR (spec);
8506 CONSP (tail) && CONSP (XCDR (tail));
8507 tail = XCDR (XCDR (tail)))
8508 {
8509 if (EQ (XCAR (tail), key))
8510 {
8511 if (found)
8512 *found = 1;
8513 return XCAR (XCDR (tail));
8514 }
8515 }
8516
8517 if (found)
8518 *found = 0;
8519 return Qnil;
8520}
8521
8522
ac849ba4
JR
8523DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8524 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8525PIXELS non-nil means return the size in pixels, otherwise return the
8526size in canonical character units.
8527FRAME is the frame on which the image will be displayed. FRAME nil
8528or omitted means use the selected frame. */)
8529 (spec, pixels, frame)
8530 Lisp_Object spec, pixels, frame;
8531{
8532 Lisp_Object size;
8533
8534 size = Qnil;
8535 if (valid_image_p (spec))
8536 {
8537 struct frame *f = check_x_frame (frame);
8538 int id = lookup_image (f, spec);
8539 struct image *img = IMAGE_FROM_ID (f, id);
8540 int width = img->width + 2 * img->hmargin;
8541 int height = img->height + 2 * img->vmargin;
8542
8543 if (NILP (pixels))
8544 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8545 make_float ((double) height / CANON_Y_UNIT (f)));
8546 else
8547 size = Fcons (make_number (width), make_number (height));
8548 }
8549 else
8550 error ("Invalid image specification");
8551
8552 return size;
8553}
8554
8555
8556DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8557 doc: /* Return t if image SPEC has a mask bitmap.
8558FRAME is the frame on which the image will be displayed. FRAME nil
8559or omitted means use the selected frame. */)
8560 (spec, frame)
8561 Lisp_Object spec, frame;
8562{
8563 Lisp_Object mask;
8564
8565 mask = Qnil;
8566 if (valid_image_p (spec))
8567 {
8568 struct frame *f = check_x_frame (frame);
8569 int id = lookup_image (f, spec);
8570 struct image *img = IMAGE_FROM_ID (f, id);
8571 if (img->mask)
8572 mask = Qt;
8573 }
8574 else
8575 error ("Invalid image specification");
8576
8577 return mask;
8578}
6fc2811b
JR
8579
8580\f
8581/***********************************************************************
8582 Image type independent image structures
8583 ***********************************************************************/
8584
8585static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8586static void free_image P_ ((struct frame *f, struct image *img));
8587
8588
8589/* Allocate and return a new image structure for image specification
8590 SPEC. SPEC has a hash value of HASH. */
8591
8592static struct image *
8593make_image (spec, hash)
8594 Lisp_Object spec;
8595 unsigned hash;
8596{
8597 struct image *img = (struct image *) xmalloc (sizeof *img);
8598
8599 xassert (valid_image_p (spec));
8600 bzero (img, sizeof *img);
8601 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8602 xassert (img->type != NULL);
8603 img->spec = spec;
8604 img->data.lisp_val = Qnil;
8605 img->ascent = DEFAULT_IMAGE_ASCENT;
8606 img->hash = hash;
8607 return img;
8608}
8609
8610
8611/* Free image IMG which was used on frame F, including its resources. */
8612
8613static void
8614free_image (f, img)
8615 struct frame *f;
8616 struct image *img;
8617{
8618 if (img)
8619 {
8620 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8621
8622 /* Remove IMG from the hash table of its cache. */
8623 if (img->prev)
8624 img->prev->next = img->next;
8625 else
8626 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8627
8628 if (img->next)
8629 img->next->prev = img->prev;
8630
8631 c->images[img->id] = NULL;
8632
8633 /* Free resources, then free IMG. */
8634 img->type->free (f, img);
8635 xfree (img);
8636 }
8637}
8638
8639
8640/* Prepare image IMG for display on frame F. Must be called before
8641 drawing an image. */
8642
8643void
8644prepare_image_for_display (f, img)
8645 struct frame *f;
8646 struct image *img;
8647{
8648 EMACS_TIME t;
8649
8650 /* We're about to display IMG, so set its timestamp to `now'. */
8651 EMACS_GET_TIME (t);
8652 img->timestamp = EMACS_SECS (t);
8653
8654 /* If IMG doesn't have a pixmap yet, load it now, using the image
8655 type dependent loader function. */
8656 if (img->pixmap == 0 && !img->load_failed_p)
8657 img->load_failed_p = img->type->load (f, img) == 0;
8658}
8659
8660
dfff8a69
JR
8661/* Value is the number of pixels for the ascent of image IMG when
8662 drawn in face FACE. */
8663
8664int
8665image_ascent (img, face)
8666 struct image *img;
8667 struct face *face;
8668{
8edb0a6f 8669 int height = img->height + img->vmargin;
dfff8a69
JR
8670 int ascent;
8671
8672 if (img->ascent == CENTERED_IMAGE_ASCENT)
8673 {
8674 if (face->font)
8675 ascent = height / 2 - (FONT_DESCENT(face->font)
8676 - FONT_BASE(face->font)) / 2;
8677 else
8678 ascent = height / 2;
8679 }
8680 else
ac849ba4 8681 ascent = (int) (height * img->ascent / 100.0);
dfff8a69
JR
8682
8683 return ascent;
8684}
8685
8686
6fc2811b 8687\f
a05e2bae
JR
8688/* Image background colors. */
8689
ac849ba4
JR
8690/* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8691 context with the bitmap selected. */
8692static COLORREF
a05e2bae 8693four_corners_best (ximg, width, height)
ac849ba4 8694 HDC ximg;
a05e2bae
JR
8695 unsigned long width, height;
8696{
ac849ba4 8697 COLORREF corners[4], best;
a05e2bae
JR
8698 int i, best_count;
8699
8700 /* Get the colors at the corners of ximg. */
ac849ba4
JR
8701 corners[0] = GetPixel (ximg, 0, 0);
8702 corners[1] = GetPixel (ximg, width - 1, 0);
8703 corners[2] = GetPixel (ximg, width - 1, height - 1);
8704 corners[3] = GetPixel (ximg, 0, height - 1);
a05e2bae
JR
8705
8706 /* Choose the most frequently found color as background. */
8707 for (i = best_count = 0; i < 4; ++i)
8708 {
8709 int j, n;
8710
8711 for (j = n = 0; j < 4; ++j)
8712 if (corners[i] == corners[j])
8713 ++n;
8714
8715 if (n > best_count)
8716 best = corners[i], best_count = n;
8717 }
8718
8719 return best;
a05e2bae
JR
8720}
8721
8722/* Return the `background' field of IMG. If IMG doesn't have one yet,
8723 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8724 object to use for the heuristic. */
8725
8726unsigned long
8727image_background (img, f, ximg)
8728 struct image *img;
8729 struct frame *f;
8730 XImage *ximg;
8731{
8732 if (! img->background_valid)
8733 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8734 {
8735#if 0 /* TODO: Image support. */
8736 int free_ximg = !ximg;
8737
8738 if (! ximg)
8739 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8740 0, 0, img->width, img->height, ~0, ZPixmap);
8741
8742 img->background = four_corners_best (ximg, img->width, img->height);
8743
8744 if (free_ximg)
8745 XDestroyImage (ximg);
8746
8747 img->background_valid = 1;
8748#endif
8749 }
8750
8751 return img->background;
8752}
8753
8754/* Return the `background_transparent' field of IMG. If IMG doesn't
8755 have one yet, it is guessed heuristically. If non-zero, MASK is an
8756 existing XImage object to use for the heuristic. */
8757
8758int
8759image_background_transparent (img, f, mask)
8760 struct image *img;
8761 struct frame *f;
8762 XImage *mask;
8763{
8764 if (! img->background_transparent_valid)
8765 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8766 {
8767#if 0 /* TODO: Image support. */
8768 if (img->mask)
8769 {
8770 int free_mask = !mask;
8771
8772 if (! mask)
8773 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8774 0, 0, img->width, img->height, ~0, ZPixmap);
8775
8776 img->background_transparent
8777 = !four_corners_best (mask, img->width, img->height);
8778
8779 if (free_mask)
8780 XDestroyImage (mask);
8781 }
8782 else
8783#endif
8784 img->background_transparent = 0;
8785
8786 img->background_transparent_valid = 1;
8787 }
8788
8789 return img->background_transparent;
8790}
8791
8792\f
6fc2811b
JR
8793/***********************************************************************
8794 Helper functions for X image types
8795 ***********************************************************************/
8796
a05e2bae
JR
8797static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8798 int, int));
6fc2811b
JR
8799static void x_clear_image P_ ((struct frame *f, struct image *img));
8800static unsigned long x_alloc_image_color P_ ((struct frame *f,
8801 struct image *img,
8802 Lisp_Object color_name,
8803 unsigned long dflt));
8804
a05e2bae
JR
8805
8806/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8807 free the pixmap if any. MASK_P non-zero means clear the mask
8808 pixmap if any. COLORS_P non-zero means free colors allocated for
8809 the image, if any. */
8810
8811static void
8812x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8813 struct frame *f;
8814 struct image *img;
8815 int pixmap_p, mask_p, colors_p;
8816{
a05e2bae
JR
8817 if (pixmap_p && img->pixmap)
8818 {
ac849ba4
JR
8819 DeleteObject (img->pixmap);
8820 img->pixmap = NULL;
a05e2bae
JR
8821 img->background_valid = 0;
8822 }
8823
8824 if (mask_p && img->mask)
8825 {
ac849ba4
JR
8826 DeleteObject (img->mask);
8827 img->mask = NULL;
a05e2bae
JR
8828 img->background_transparent_valid = 0;
8829 }
8830
8831 if (colors_p && img->ncolors)
8832 {
bf76fe9c 8833#if 0 /* TODO: color table support. */
a05e2bae 8834 x_free_colors (f, img->colors, img->ncolors);
bf76fe9c 8835#endif
a05e2bae
JR
8836 xfree (img->colors);
8837 img->colors = NULL;
8838 img->ncolors = 0;
8839 }
a05e2bae
JR
8840}
8841
6fc2811b
JR
8842/* Free X resources of image IMG which is used on frame F. */
8843
8844static void
8845x_clear_image (f, img)
8846 struct frame *f;
8847 struct image *img;
8848{
6fc2811b
JR
8849 if (img->pixmap)
8850 {
8851 BLOCK_INPUT;
ac849ba4 8852 DeleteObject (img->pixmap);
6fc2811b
JR
8853 img->pixmap = 0;
8854 UNBLOCK_INPUT;
8855 }
8856
8857 if (img->ncolors)
8858 {
ac849ba4
JR
8859#if 0 /* TODO: color table support */
8860
6fc2811b
JR
8861 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8862
8863 /* If display has an immutable color map, freeing colors is not
8864 necessary and some servers don't allow it. So don't do it. */
8865 if (class != StaticColor
8866 && class != StaticGray
8867 && class != TrueColor)
8868 {
8869 Colormap cmap;
8870 BLOCK_INPUT;
8871 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8872 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8873 img->ncolors, 0);
8874 UNBLOCK_INPUT;
8875 }
ac849ba4 8876#endif
6fc2811b
JR
8877
8878 xfree (img->colors);
8879 img->colors = NULL;
8880 img->ncolors = 0;
8881 }
6fc2811b
JR
8882}
8883
8884
8885/* Allocate color COLOR_NAME for image IMG on frame F. If color
8886 cannot be allocated, use DFLT. Add a newly allocated color to
8887 IMG->colors, so that it can be freed again. Value is the pixel
8888 color. */
8889
8890static unsigned long
8891x_alloc_image_color (f, img, color_name, dflt)
8892 struct frame *f;
8893 struct image *img;
8894 Lisp_Object color_name;
8895 unsigned long dflt;
8896{
6fc2811b
JR
8897 XColor color;
8898 unsigned long result;
8899
8900 xassert (STRINGP (color_name));
8901
8902 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8903 {
8904 /* This isn't called frequently so we get away with simply
8905 reallocating the color vector to the needed size, here. */
8906 ++img->ncolors;
8907 img->colors =
8908 (unsigned long *) xrealloc (img->colors,
8909 img->ncolors * sizeof *img->colors);
8910 img->colors[img->ncolors - 1] = color.pixel;
8911 result = color.pixel;
8912 }
8913 else
8914 result = dflt;
8915 return result;
6fc2811b
JR
8916}
8917
8918
8919\f
8920/***********************************************************************
8921 Image Cache
8922 ***********************************************************************/
8923
8924static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8925static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8926
8927
8928/* Return a new, initialized image cache that is allocated from the
8929 heap. Call free_image_cache to free an image cache. */
8930
8931struct image_cache *
8932make_image_cache ()
8933{
8934 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8935 int size;
8936
8937 bzero (c, sizeof *c);
8938 c->size = 50;
8939 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8940 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8941 c->buckets = (struct image **) xmalloc (size);
8942 bzero (c->buckets, size);
8943 return c;
8944}
8945
8946
8947/* Free image cache of frame F. Be aware that X frames share images
8948 caches. */
8949
8950void
8951free_image_cache (f)
8952 struct frame *f;
8953{
8954 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8955 if (c)
8956 {
8957 int i;
8958
8959 /* Cache should not be referenced by any frame when freed. */
8960 xassert (c->refcount == 0);
8961
8962 for (i = 0; i < c->used; ++i)
8963 free_image (f, c->images[i]);
8964 xfree (c->images);
8965 xfree (c);
8966 xfree (c->buckets);
8967 FRAME_X_IMAGE_CACHE (f) = NULL;
8968 }
8969}
8970
8971
8972/* Clear image cache of frame F. FORCE_P non-zero means free all
8973 images. FORCE_P zero means clear only images that haven't been
8974 displayed for some time. Should be called from time to time to
dfff8a69
JR
8975 reduce the number of loaded images. If image-eviction-seconds is
8976 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8977 at least that many seconds. */
8978
8979void
8980clear_image_cache (f, force_p)
8981 struct frame *f;
8982 int force_p;
8983{
8984 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8985
8986 if (c && INTEGERP (Vimage_cache_eviction_delay))
8987 {
8988 EMACS_TIME t;
8989 unsigned long old;
0327b4cc 8990 int i, nfreed;
6fc2811b
JR
8991
8992 EMACS_GET_TIME (t);
8993 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8994
0327b4cc
JR
8995 /* Block input so that we won't be interrupted by a SIGIO
8996 while being in an inconsistent state. */
8997 BLOCK_INPUT;
8998
8999 for (i = nfreed = 0; i < c->used; ++i)
6fc2811b
JR
9000 {
9001 struct image *img = c->images[i];
9002 if (img != NULL
0327b4cc 9003 && (force_p || (img->timestamp < old)))
6fc2811b
JR
9004 {
9005 free_image (f, img);
0327b4cc 9006 ++nfreed;
6fc2811b
JR
9007 }
9008 }
9009
9010 /* We may be clearing the image cache because, for example,
9011 Emacs was iconified for a longer period of time. In that
9012 case, current matrices may still contain references to
9013 images freed above. So, clear these matrices. */
0327b4cc 9014 if (nfreed)
6fc2811b 9015 {
0327b4cc
JR
9016 Lisp_Object tail, frame;
9017
9018 FOR_EACH_FRAME (tail, frame)
9019 {
9020 struct frame *f = XFRAME (frame);
9021 if (FRAME_W32_P (f)
9022 && FRAME_X_IMAGE_CACHE (f) == c)
9023 clear_current_matrices (f);
9024 }
9025
6fc2811b
JR
9026 ++windows_or_buffers_changed;
9027 }
0327b4cc
JR
9028
9029 UNBLOCK_INPUT;
6fc2811b
JR
9030 }
9031}
9032
9033
9034DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9035 0, 1, 0,
74e1aeec
JR
9036 doc: /* Clear the image cache of FRAME.
9037FRAME nil or omitted means use the selected frame.
9038FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
9039 (frame)
9040 Lisp_Object frame;
9041{
9042 if (EQ (frame, Qt))
9043 {
9044 Lisp_Object tail;
9045
9046 FOR_EACH_FRAME (tail, frame)
9047 if (FRAME_W32_P (XFRAME (frame)))
9048 clear_image_cache (XFRAME (frame), 1);
9049 }
9050 else
9051 clear_image_cache (check_x_frame (frame), 1);
9052
9053 return Qnil;
9054}
9055
9056
3cf3436e
JR
9057/* Compute masks and transform image IMG on frame F, as specified
9058 by the image's specification, */
9059
9060static void
9061postprocess_image (f, img)
9062 struct frame *f;
9063 struct image *img;
9064{
9065#if 0 /* TODO: image support. */
9066 /* Manipulation of the image's mask. */
9067 if (img->pixmap)
9068 {
9069 Lisp_Object conversion, spec;
9070 Lisp_Object mask;
9071
9072 spec = img->spec;
9073
9074 /* `:heuristic-mask t'
9075 `:mask heuristic'
9076 means build a mask heuristically.
9077 `:heuristic-mask (R G B)'
9078 `:mask (heuristic (R G B))'
9079 means build a mask from color (R G B) in the
9080 image.
9081 `:mask nil'
9082 means remove a mask, if any. */
9083
9084 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9085 if (!NILP (mask))
9086 x_build_heuristic_mask (f, img, mask);
9087 else
9088 {
9089 int found_p;
9090
9091 mask = image_spec_value (spec, QCmask, &found_p);
9092
9093 if (EQ (mask, Qheuristic))
9094 x_build_heuristic_mask (f, img, Qt);
9095 else if (CONSP (mask)
9096 && EQ (XCAR (mask), Qheuristic))
9097 {
9098 if (CONSP (XCDR (mask)))
9099 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9100 else
9101 x_build_heuristic_mask (f, img, XCDR (mask));
9102 }
9103 else if (NILP (mask) && found_p && img->mask)
9104 {
ac849ba4 9105 DeleteObject (img->mask);
3cf3436e
JR
9106 img->mask = NULL;
9107 }
9108 }
9109
9110
9111 /* Should we apply an image transformation algorithm? */
9112 conversion = image_spec_value (spec, QCconversion, NULL);
9113 if (EQ (conversion, Qdisabled))
9114 x_disable_image (f, img);
9115 else if (EQ (conversion, Qlaplace))
9116 x_laplace (f, img);
9117 else if (EQ (conversion, Qemboss))
9118 x_emboss (f, img);
9119 else if (CONSP (conversion)
9120 && EQ (XCAR (conversion), Qedge_detection))
9121 {
9122 Lisp_Object tem;
9123 tem = XCDR (conversion);
9124 if (CONSP (tem))
9125 x_edge_detection (f, img,
9126 Fplist_get (tem, QCmatrix),
9127 Fplist_get (tem, QCcolor_adjustment));
9128 }
9129 }
9130#endif
9131}
9132
9133
6fc2811b
JR
9134/* Return the id of image with Lisp specification SPEC on frame F.
9135 SPEC must be a valid Lisp image specification (see valid_image_p). */
9136
9137int
9138lookup_image (f, spec)
9139 struct frame *f;
9140 Lisp_Object spec;
9141{
9142 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9143 struct image *img;
9144 int i;
9145 unsigned hash;
9146 struct gcpro gcpro1;
9147 EMACS_TIME now;
9148
9149 /* F must be a window-system frame, and SPEC must be a valid image
9150 specification. */
9151 xassert (FRAME_WINDOW_P (f));
9152 xassert (valid_image_p (spec));
9153
9154 GCPRO1 (spec);
9155
9156 /* Look up SPEC in the hash table of the image cache. */
9157 hash = sxhash (spec, 0);
9158 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9159
9160 for (img = c->buckets[i]; img; img = img->next)
9161 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9162 break;
9163
9164 /* If not found, create a new image and cache it. */
9165 if (img == NULL)
9166 {
3cf3436e
JR
9167 extern Lisp_Object Qpostscript;
9168
8edb0a6f 9169 BLOCK_INPUT;
6fc2811b
JR
9170 img = make_image (spec, hash);
9171 cache_image (f, img);
9172 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
9173
9174 /* If we can't load the image, and we don't have a width and
9175 height, use some arbitrary width and height so that we can
9176 draw a rectangle for it. */
9177 if (img->load_failed_p)
9178 {
9179 Lisp_Object value;
9180
9181 value = image_spec_value (spec, QCwidth, NULL);
9182 img->width = (INTEGERP (value)
9183 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9184 value = image_spec_value (spec, QCheight, NULL);
9185 img->height = (INTEGERP (value)
9186 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9187 }
9188 else
9189 {
9190 /* Handle image type independent image attributes
a05e2bae
JR
9191 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9192 `:background COLOR'. */
9193 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
9194
9195 ascent = image_spec_value (spec, QCascent, NULL);
9196 if (INTEGERP (ascent))
9197 img->ascent = XFASTINT (ascent);
dfff8a69
JR
9198 else if (EQ (ascent, Qcenter))
9199 img->ascent = CENTERED_IMAGE_ASCENT;
9200
6fc2811b
JR
9201 margin = image_spec_value (spec, QCmargin, NULL);
9202 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
9203 img->vmargin = img->hmargin = XFASTINT (margin);
9204 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9205 && INTEGERP (XCDR (margin)))
9206 {
9207 if (XINT (XCAR (margin)) > 0)
9208 img->hmargin = XFASTINT (XCAR (margin));
9209 if (XINT (XCDR (margin)) > 0)
9210 img->vmargin = XFASTINT (XCDR (margin));
9211 }
6fc2811b
JR
9212
9213 relief = image_spec_value (spec, QCrelief, NULL);
9214 if (INTEGERP (relief))
9215 {
9216 img->relief = XINT (relief);
8edb0a6f
JR
9217 img->hmargin += abs (img->relief);
9218 img->vmargin += abs (img->relief);
6fc2811b
JR
9219 }
9220
a05e2bae
JR
9221 if (! img->background_valid)
9222 {
9223 bg = image_spec_value (img->spec, QCbackground, NULL);
9224 if (!NILP (bg))
9225 {
9226 img->background
9227 = x_alloc_image_color (f, img, bg,
9228 FRAME_BACKGROUND_PIXEL (f));
9229 img->background_valid = 1;
9230 }
9231 }
9232
3cf3436e
JR
9233 /* Do image transformations and compute masks, unless we
9234 don't have the image yet. */
9235 if (!EQ (*img->type->type, Qpostscript))
9236 postprocess_image (f, img);
6fc2811b 9237 }
3cf3436e 9238
8edb0a6f
JR
9239 UNBLOCK_INPUT;
9240 xassert (!interrupt_input_blocked);
6fc2811b
JR
9241 }
9242
9243 /* We're using IMG, so set its timestamp to `now'. */
9244 EMACS_GET_TIME (now);
9245 img->timestamp = EMACS_SECS (now);
9246
9247 UNGCPRO;
9248
9249 /* Value is the image id. */
9250 return img->id;
9251}
9252
9253
9254/* Cache image IMG in the image cache of frame F. */
9255
9256static void
9257cache_image (f, img)
9258 struct frame *f;
9259 struct image *img;
9260{
9261 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9262 int i;
9263
9264 /* Find a free slot in c->images. */
9265 for (i = 0; i < c->used; ++i)
9266 if (c->images[i] == NULL)
9267 break;
9268
9269 /* If no free slot found, maybe enlarge c->images. */
9270 if (i == c->used && c->used == c->size)
9271 {
9272 c->size *= 2;
9273 c->images = (struct image **) xrealloc (c->images,
9274 c->size * sizeof *c->images);
9275 }
9276
9277 /* Add IMG to c->images, and assign IMG an id. */
9278 c->images[i] = img;
9279 img->id = i;
9280 if (i == c->used)
9281 ++c->used;
9282
9283 /* Add IMG to the cache's hash table. */
9284 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9285 img->next = c->buckets[i];
9286 if (img->next)
9287 img->next->prev = img;
9288 img->prev = NULL;
9289 c->buckets[i] = img;
9290}
9291
9292
9293/* Call FN on every image in the image cache of frame F. Used to mark
9294 Lisp Objects in the image cache. */
9295
9296void
9297forall_images_in_image_cache (f, fn)
9298 struct frame *f;
9299 void (*fn) P_ ((struct image *img));
9300{
9301 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9302 {
9303 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9304 if (c)
9305 {
9306 int i;
9307 for (i = 0; i < c->used; ++i)
9308 if (c->images[i])
9309 fn (c->images[i]);
9310 }
9311 }
9312}
9313
9314
9315\f
9316/***********************************************************************
9317 W32 support code
9318 ***********************************************************************/
9319
6fc2811b
JR
9320static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9321 XImage **, Pixmap *));
9322static void x_destroy_x_image P_ ((XImage *));
9323static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9324
9325
9326/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9327 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9328 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
ac849ba4
JR
9329 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9330 DEPTH should indicate the bit depth of the image. Print error
9331 messages via image_error if an error occurs. Value is non-zero if
9332 successful. */
6fc2811b
JR
9333
9334static int
9335x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9336 struct frame *f;
9337 int width, height, depth;
9338 XImage **ximg;
9339 Pixmap *pixmap;
9340{
ac849ba4
JR
9341 BITMAPINFOHEADER *header;
9342 HDC hdc;
9343 int scanline_width_bits;
9344 int remainder;
9345 int palette_colors = 0;
6fc2811b 9346
ac849ba4
JR
9347 if (depth == 0)
9348 depth = 24;
6fc2811b 9349
ac849ba4
JR
9350 if (depth != 1 && depth != 4 && depth != 8
9351 && depth != 16 && depth != 24 && depth != 32)
9352 {
9353 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9354 return 0;
9355 }
9356
9357 scanline_width_bits = width * depth;
9358 remainder = scanline_width_bits % 32;
9359
9360 if (remainder)
9361 scanline_width_bits += 32 - remainder;
9362
9363 /* Bitmaps with a depth less than 16 need a palette. */
9364 /* BITMAPINFO structure already contains the first RGBQUAD. */
9365 if (depth < 16)
9366 palette_colors = 1 << depth - 1;
9367
9368 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
6fc2811b
JR
9369 if (*ximg == NULL)
9370 {
ac849ba4 9371 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
6fc2811b
JR
9372 return 0;
9373 }
9374
ac849ba4
JR
9375 header = &((*ximg)->info.bmiHeader);
9376 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9377 header->biSize = sizeof (*header);
9378 header->biWidth = width;
9379 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9380 header->biPlanes = 1;
9381 header->biBitCount = depth;
9382 header->biCompression = BI_RGB;
9383 header->biClrUsed = palette_colors;
6fc2811b 9384
ac849ba4
JR
9385 hdc = get_frame_dc (f);
9386
9387 /* Create a DIBSection and raster array for the bitmap,
9388 and store its handle in *pixmap. */
9389 *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
9390 &((*ximg)->data), NULL, 0);
9391
9392 /* Realize display palette and garbage all frames. */
9393 release_frame_dc (f, hdc);
9394
9395 if (*pixmap == NULL)
6fc2811b 9396 {
ac849ba4
JR
9397 DWORD err = GetLastError();
9398 Lisp_Object errcode;
9399 /* All system errors are < 10000, so the following is safe. */
9400 XSETINT (errcode, (int) err);
9401 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
6fc2811b 9402 x_destroy_x_image (*ximg);
6fc2811b
JR
9403 return 0;
9404 }
ac849ba4 9405
6fc2811b
JR
9406 return 1;
9407}
9408
9409
9410/* Destroy XImage XIMG. Free XIMG->data. */
9411
9412static void
9413x_destroy_x_image (ximg)
9414 XImage *ximg;
9415{
9416 xassert (interrupt_input_blocked);
9417 if (ximg)
9418 {
ac849ba4 9419 /* Data will be freed by DestroyObject. */
6fc2811b 9420 ximg->data = NULL;
ac849ba4 9421 xfree (ximg);
6fc2811b
JR
9422 }
9423}
9424
9425
9426/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9427 are width and height of both the image and pixmap. */
9428
9429static void
9430x_put_x_image (f, ximg, pixmap, width, height)
9431 struct frame *f;
9432 XImage *ximg;
9433 Pixmap pixmap;
9434{
ac849ba4
JR
9435
9436#if TODO /* W32 specific image code. */
6fc2811b 9437 GC gc;
ac849ba4 9438
6fc2811b
JR
9439 xassert (interrupt_input_blocked);
9440 gc = XCreateGC (NULL, pixmap, 0, NULL);
9441 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9442 XFreeGC (NULL, gc);
6fc2811b 9443#endif
ac849ba4 9444}
6fc2811b
JR
9445
9446\f
9447/***********************************************************************
3cf3436e 9448 File Handling
6fc2811b
JR
9449 ***********************************************************************/
9450
9451static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9452static char *slurp_file P_ ((char *, int *));
9453
6fc2811b
JR
9454
9455/* Find image file FILE. Look in data-directory, then
9456 x-bitmap-file-path. Value is the full name of the file found, or
9457 nil if not found. */
9458
9459static Lisp_Object
9460x_find_image_file (file)
9461 Lisp_Object file;
9462{
9463 Lisp_Object file_found, search_path;
9464 struct gcpro gcpro1, gcpro2;
9465 int fd;
9466
9467 file_found = Qnil;
9468 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9469 GCPRO2 (file_found, search_path);
9470
9471 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 9472 fd = openp (search_path, file, Qnil, &file_found, Qnil);
6fc2811b 9473
939d6465 9474 if (fd == -1)
6fc2811b
JR
9475 file_found = Qnil;
9476 else
9477 close (fd);
9478
9479 UNGCPRO;
9480 return file_found;
9481}
9482
9483
3cf3436e
JR
9484/* Read FILE into memory. Value is a pointer to a buffer allocated
9485 with xmalloc holding FILE's contents. Value is null if an error
9486 occurred. *SIZE is set to the size of the file. */
9487
9488static char *
9489slurp_file (file, size)
9490 char *file;
9491 int *size;
9492{
9493 FILE *fp = NULL;
9494 char *buf = NULL;
9495 struct stat st;
9496
9497 if (stat (file, &st) == 0
9498 && (fp = fopen (file, "r")) != NULL
9499 && (buf = (char *) xmalloc (st.st_size),
9500 fread (buf, 1, st.st_size, fp) == st.st_size))
9501 {
9502 *size = st.st_size;
9503 fclose (fp);
9504 }
9505 else
9506 {
9507 if (fp)
9508 fclose (fp);
9509 if (buf)
9510 {
9511 xfree (buf);
9512 buf = NULL;
9513 }
9514 }
9515
9516 return buf;
9517}
9518
9519
6fc2811b
JR
9520\f
9521/***********************************************************************
9522 XBM images
9523 ***********************************************************************/
9524
217e5be0 9525static int xbm_scan P_ ((char **, char *, char *, int *));
6fc2811b 9526static int xbm_load P_ ((struct frame *f, struct image *img));
217e5be0
JR
9527static int xbm_load_image P_ ((struct frame *f, struct image *img,
9528 char *, char *));
6fc2811b 9529static int xbm_image_p P_ ((Lisp_Object object));
217e5be0
JR
9530static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
9531 unsigned char **));
9532static int xbm_file_p P_ ((Lisp_Object));
6fc2811b
JR
9533
9534
9535/* Indices of image specification fields in xbm_format, below. */
9536
9537enum xbm_keyword_index
9538{
9539 XBM_TYPE,
9540 XBM_FILE,
9541 XBM_WIDTH,
9542 XBM_HEIGHT,
9543 XBM_DATA,
9544 XBM_FOREGROUND,
9545 XBM_BACKGROUND,
9546 XBM_ASCENT,
9547 XBM_MARGIN,
9548 XBM_RELIEF,
9549 XBM_ALGORITHM,
9550 XBM_HEURISTIC_MASK,
a05e2bae 9551 XBM_MASK,
6fc2811b
JR
9552 XBM_LAST
9553};
9554
9555/* Vector of image_keyword structures describing the format
9556 of valid XBM image specifications. */
9557
9558static struct image_keyword xbm_format[XBM_LAST] =
9559{
9560 {":type", IMAGE_SYMBOL_VALUE, 1},
9561 {":file", IMAGE_STRING_VALUE, 0},
9562 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9563 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9564 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9565 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9566 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9567 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 9568 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9569 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9570 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9571 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9572 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6fc2811b
JR
9573};
9574
9575/* Structure describing the image type XBM. */
9576
9577static struct image_type xbm_type =
9578{
9579 &Qxbm,
9580 xbm_image_p,
9581 xbm_load,
9582 x_clear_image,
9583 NULL
9584};
9585
9586/* Tokens returned from xbm_scan. */
9587
9588enum xbm_token
9589{
9590 XBM_TK_IDENT = 256,
9591 XBM_TK_NUMBER
9592};
9593
9594
9595/* Return non-zero if OBJECT is a valid XBM-type image specification.
9596 A valid specification is a list starting with the symbol `image'
9597 The rest of the list is a property list which must contain an
9598 entry `:type xbm..
9599
9600 If the specification specifies a file to load, it must contain
9601 an entry `:file FILENAME' where FILENAME is a string.
9602
9603 If the specification is for a bitmap loaded from memory it must
9604 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9605 WIDTH and HEIGHT are integers > 0. DATA may be:
9606
9607 1. a string large enough to hold the bitmap data, i.e. it must
9608 have a size >= (WIDTH + 7) / 8 * HEIGHT
9609
9610 2. a bool-vector of size >= WIDTH * HEIGHT
9611
9612 3. a vector of strings or bool-vectors, one for each line of the
9613 bitmap.
9614
217e5be0
JR
9615 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
9616 may not be specified in this case because they are defined in the
9617 XBM file.
9618
6fc2811b
JR
9619 Both the file and data forms may contain the additional entries
9620 `:background COLOR' and `:foreground COLOR'. If not present,
9621 foreground and background of the frame on which the image is
217e5be0 9622 displayed is used. */
6fc2811b
JR
9623
9624static int
9625xbm_image_p (object)
9626 Lisp_Object object;
9627{
9628 struct image_keyword kw[XBM_LAST];
9629
9630 bcopy (xbm_format, kw, sizeof kw);
9631 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9632 return 0;
9633
9634 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9635
9636 if (kw[XBM_FILE].count)
9637 {
9638 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9639 return 0;
9640 }
217e5be0
JR
9641 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
9642 {
9643 /* In-memory XBM file. */
9644 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
9645 return 0;
9646 }
6fc2811b
JR
9647 else
9648 {
9649 Lisp_Object data;
9650 int width, height;
9651
9652 /* Entries for `:width', `:height' and `:data' must be present. */
9653 if (!kw[XBM_WIDTH].count
9654 || !kw[XBM_HEIGHT].count
9655 || !kw[XBM_DATA].count)
9656 return 0;
9657
9658 data = kw[XBM_DATA].value;
9659 width = XFASTINT (kw[XBM_WIDTH].value);
9660 height = XFASTINT (kw[XBM_HEIGHT].value);
9661
9662 /* Check type of data, and width and height against contents of
9663 data. */
9664 if (VECTORP (data))
9665 {
9666 int i;
9667
9668 /* Number of elements of the vector must be >= height. */
9669 if (XVECTOR (data)->size < height)
9670 return 0;
9671
9672 /* Each string or bool-vector in data must be large enough
9673 for one line of the image. */
9674 for (i = 0; i < height; ++i)
9675 {
9676 Lisp_Object elt = XVECTOR (data)->contents[i];
9677
9678 if (STRINGP (elt))
9679 {
9680 if (XSTRING (elt)->size
9681 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9682 return 0;
9683 }
9684 else if (BOOL_VECTOR_P (elt))
9685 {
9686 if (XBOOL_VECTOR (elt)->size < width)
9687 return 0;
9688 }
9689 else
9690 return 0;
9691 }
9692 }
9693 else if (STRINGP (data))
9694 {
9695 if (XSTRING (data)->size
9696 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9697 return 0;
9698 }
9699 else if (BOOL_VECTOR_P (data))
9700 {
9701 if (XBOOL_VECTOR (data)->size < width * height)
9702 return 0;
9703 }
9704 else
9705 return 0;
9706 }
9707
6fc2811b
JR
9708 return 1;
9709}
9710
9711
9712/* Scan a bitmap file. FP is the stream to read from. Value is
9713 either an enumerator from enum xbm_token, or a character for a
9714 single-character token, or 0 at end of file. If scanning an
9715 identifier, store the lexeme of the identifier in SVAL. If
9716 scanning a number, store its value in *IVAL. */
9717
9718static int
3cf3436e
JR
9719xbm_scan (s, end, sval, ival)
9720 char **s, *end;
6fc2811b
JR
9721 char *sval;
9722 int *ival;
9723{
9724 int c;
3cf3436e
JR
9725
9726 loop:
9727
6fc2811b 9728 /* Skip white space. */
af3f7be7 9729 while (*s < end && (c = *(*s)++, isspace (c)))
6fc2811b
JR
9730 ;
9731
3cf3436e 9732 if (*s >= end)
6fc2811b
JR
9733 c = 0;
9734 else if (isdigit (c))
9735 {
9736 int value = 0, digit;
9737
3cf3436e 9738 if (c == '0' && *s < end)
6fc2811b 9739 {
3cf3436e 9740 c = *(*s)++;
6fc2811b
JR
9741 if (c == 'x' || c == 'X')
9742 {
3cf3436e 9743 while (*s < end)
6fc2811b 9744 {
3cf3436e 9745 c = *(*s)++;
6fc2811b
JR
9746 if (isdigit (c))
9747 digit = c - '0';
9748 else if (c >= 'a' && c <= 'f')
9749 digit = c - 'a' + 10;
9750 else if (c >= 'A' && c <= 'F')
9751 digit = c - 'A' + 10;
9752 else
9753 break;
9754 value = 16 * value + digit;
9755 }
9756 }
9757 else if (isdigit (c))
9758 {
9759 value = c - '0';
3cf3436e
JR
9760 while (*s < end
9761 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9762 value = 8 * value + c - '0';
9763 }
9764 }
9765 else
9766 {
9767 value = c - '0';
3cf3436e
JR
9768 while (*s < end
9769 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9770 value = 10 * value + c - '0';
9771 }
9772
3cf3436e
JR
9773 if (*s < end)
9774 *s = *s - 1;
6fc2811b
JR
9775 *ival = value;
9776 c = XBM_TK_NUMBER;
9777 }
9778 else if (isalpha (c) || c == '_')
9779 {
9780 *sval++ = c;
3cf3436e
JR
9781 while (*s < end
9782 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9783 *sval++ = c;
9784 *sval = 0;
3cf3436e
JR
9785 if (*s < end)
9786 *s = *s - 1;
6fc2811b
JR
9787 c = XBM_TK_IDENT;
9788 }
3cf3436e
JR
9789 else if (c == '/' && **s == '*')
9790 {
9791 /* C-style comment. */
9792 ++*s;
9793 while (**s && (**s != '*' || *(*s + 1) != '/'))
9794 ++*s;
9795 if (**s)
9796 {
9797 *s += 2;
9798 goto loop;
9799 }
9800 }
6fc2811b
JR
9801
9802 return c;
9803}
9804
9805
217e5be0
JR
9806/* XBM bits seem to be backward within bytes compared with how
9807 Windows does things. */
9808static unsigned char reflect_byte (unsigned char orig)
9809{
9810 int i;
9811 unsigned char reflected = 0x00;
9812 for (i = 0; i < 8; i++)
9813 {
9814 if (orig & (0x01 << i))
9815 reflected |= 0x80 >> i;
9816 }
9817 return reflected;
9818}
9819
9820
af3f7be7
JR
9821/* Create a Windows bitmap from X bitmap data. */
9822static HBITMAP
9823w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
9824{
9825 int i, j, w1, w2;
9826 char *bits, *p;
9827 HBITMAP bmp;
9828
9829 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
9830 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
9831 bits = (char *) xmalloc (height * w2);
9832 bzero (bits, height * w2);
9833 for (i = 0; i < height; i++)
9834 {
9835 p = bits + i*w2;
9836 for (j = 0; j < w1; j++)
9837 *p++ = reflect_byte(*data++);
9838 }
9839 bmp = CreateBitmap (width, height, 1, 1, bits);
9840 xfree (bits);
9841
9842 return bmp;
9843}
9844
9845
6fc2811b 9846/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9847 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9848 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9849 the image. Return in *DATA the bitmap data allocated with xmalloc.
9850 Value is non-zero if successful. DATA null means just test if
9851 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9852
9853static int
3cf3436e
JR
9854xbm_read_bitmap_data (contents, end, width, height, data)
9855 char *contents, *end;
6fc2811b
JR
9856 int *width, *height;
9857 unsigned char **data;
9858{
3cf3436e 9859 char *s = contents;
6fc2811b
JR
9860 char buffer[BUFSIZ];
9861 int padding_p = 0;
9862 int v10 = 0;
af3f7be7 9863 int bytes_per_line, i, nbytes;
6fc2811b
JR
9864 unsigned char *p;
9865 int value;
9866 int LA1;
9867
9868#define match() \
217e5be0 9869 LA1 = xbm_scan (&s, end, buffer, &value)
6fc2811b
JR
9870
9871#define expect(TOKEN) \
9872 if (LA1 != (TOKEN)) \
9873 goto failure; \
9874 else \
9875 match ()
9876
9877#define expect_ident(IDENT) \
9878 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9879 match (); \
9880 else \
9881 goto failure
9882
6fc2811b 9883 *width = *height = -1;
3cf3436e
JR
9884 if (data)
9885 *data = NULL;
9886 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9887
9888 /* Parse defines for width, height and hot-spots. */
9889 while (LA1 == '#')
9890 {
9891 match ();
9892 expect_ident ("define");
9893 expect (XBM_TK_IDENT);
9894
9895 if (LA1 == XBM_TK_NUMBER);
9896 {
9897 char *p = strrchr (buffer, '_');
9898 p = p ? p + 1 : buffer;
9899 if (strcmp (p, "width") == 0)
9900 *width = value;
9901 else if (strcmp (p, "height") == 0)
9902 *height = value;
9903 }
9904 expect (XBM_TK_NUMBER);
9905 }
9906
9907 if (*width < 0 || *height < 0)
9908 goto failure;
3cf3436e
JR
9909 else if (data == NULL)
9910 goto success;
6fc2811b
JR
9911
9912 /* Parse bits. Must start with `static'. */
9913 expect_ident ("static");
9914 if (LA1 == XBM_TK_IDENT)
9915 {
9916 if (strcmp (buffer, "unsigned") == 0)
9917 {
9918 match ();
9919 expect_ident ("char");
9920 }
9921 else if (strcmp (buffer, "short") == 0)
9922 {
9923 match ();
9924 v10 = 1;
af3f7be7
JR
9925 if (*width % 16 && *width % 16 < 9)
9926 padding_p = 1;
6fc2811b
JR
9927 }
9928 else if (strcmp (buffer, "char") == 0)
9929 match ();
9930 else
9931 goto failure;
9932 }
9933 else
9934 goto failure;
9935
9936 expect (XBM_TK_IDENT);
9937 expect ('[');
9938 expect (']');
9939 expect ('=');
9940 expect ('{');
9941
af3f7be7
JR
9942 bytes_per_line = (*width + 7) / 8 + padding_p;
9943 nbytes = bytes_per_line * *height;
9944 p = *data = (char *) xmalloc (nbytes);
6fc2811b
JR
9945
9946 if (v10)
9947 {
6fc2811b
JR
9948 for (i = 0; i < nbytes; i += 2)
9949 {
9950 int val = value;
9951 expect (XBM_TK_NUMBER);
9952
af3f7be7
JR
9953 *p++ = val;
9954 if (!padding_p || ((i + 2) % bytes_per_line))
9955 *p++ = value >> 8;
6fc2811b
JR
9956
9957 if (LA1 == ',' || LA1 == '}')
9958 match ();
9959 else
9960 goto failure;
9961 }
9962 }
9963 else
9964 {
9965 for (i = 0; i < nbytes; ++i)
9966 {
9967 int val = value;
9968 expect (XBM_TK_NUMBER);
9969
af3f7be7 9970 *p++ = val;
217e5be0 9971
6fc2811b
JR
9972 if (LA1 == ',' || LA1 == '}')
9973 match ();
9974 else
9975 goto failure;
9976 }
9977 }
9978
3cf3436e 9979 success:
6fc2811b
JR
9980 return 1;
9981
9982 failure:
3cf3436e
JR
9983
9984 if (data && *data)
6fc2811b
JR
9985 {
9986 xfree (*data);
9987 *data = NULL;
9988 }
9989 return 0;
9990
9991#undef match
9992#undef expect
9993#undef expect_ident
9994}
9995
9996
3cf3436e
JR
9997/* Load XBM image IMG which will be displayed on frame F from buffer
9998 CONTENTS. END is the end of the buffer. Value is non-zero if
9999 successful. */
6fc2811b
JR
10000
10001static int
3cf3436e 10002xbm_load_image (f, img, contents, end)
6fc2811b
JR
10003 struct frame *f;
10004 struct image *img;
3cf3436e 10005 char *contents, *end;
6fc2811b
JR
10006{
10007 int rc;
10008 unsigned char *data;
10009 int success_p = 0;
6fc2811b 10010
3cf3436e 10011 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
10012 if (rc)
10013 {
6fc2811b
JR
10014 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10015 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10016 Lisp_Object value;
10017
10018 xassert (img->width > 0 && img->height > 0);
10019
10020 /* Get foreground and background colors, maybe allocate colors. */
10021 value = image_spec_value (img->spec, QCforeground, NULL);
10022 if (!NILP (value))
10023 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
10024 value = image_spec_value (img->spec, QCbackground, NULL);
10025 if (!NILP (value))
a05e2bae
JR
10026 {
10027 background = x_alloc_image_color (f, img, value, background);
10028 img->background = background;
10029 img->background_valid = 1;
10030 }
6fc2811b 10031 img->pixmap
af3f7be7 10032 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
ac849ba4 10033
6fc2811b
JR
10034 xfree (data);
10035
10036 if (img->pixmap == 0)
10037 {
10038 x_clear_image (f, img);
3cf3436e 10039 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
10040 }
10041 else
10042 success_p = 1;
6fc2811b
JR
10043 }
10044 else
10045 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10046
6fc2811b
JR
10047 return success_p;
10048}
10049
10050
3cf3436e
JR
10051/* Value is non-zero if DATA looks like an in-memory XBM file. */
10052
10053static int
10054xbm_file_p (data)
10055 Lisp_Object data;
10056{
10057 int w, h;
10058 return (STRINGP (data)
10059 && xbm_read_bitmap_data (XSTRING (data)->data,
10060 (XSTRING (data)->data
10061 + STRING_BYTES (XSTRING (data))),
10062 &w, &h, NULL));
10063}
10064
10065
6fc2811b
JR
10066/* Fill image IMG which is used on frame F with pixmap data. Value is
10067 non-zero if successful. */
10068
10069static int
10070xbm_load (f, img)
10071 struct frame *f;
10072 struct image *img;
10073{
10074 int success_p = 0;
10075 Lisp_Object file_name;
10076
10077 xassert (xbm_image_p (img->spec));
10078
10079 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10080 file_name = image_spec_value (img->spec, QCfile, NULL);
10081 if (STRINGP (file_name))
3cf3436e
JR
10082 {
10083 Lisp_Object file;
10084 char *contents;
10085 int size;
10086 struct gcpro gcpro1;
10087
10088 file = x_find_image_file (file_name);
10089 GCPRO1 (file);
10090 if (!STRINGP (file))
10091 {
10092 image_error ("Cannot find image file `%s'", file_name, Qnil);
10093 UNGCPRO;
10094 return 0;
10095 }
10096
10097 contents = slurp_file (XSTRING (file)->data, &size);
10098 if (contents == NULL)
10099 {
10100 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10101 UNGCPRO;
10102 return 0;
10103 }
10104
10105 success_p = xbm_load_image (f, img, contents, contents + size);
10106 UNGCPRO;
10107 }
6fc2811b
JR
10108 else
10109 {
10110 struct image_keyword fmt[XBM_LAST];
10111 Lisp_Object data;
10112 int depth;
10113 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10114 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10115 char *bits;
10116 int parsed_p;
3cf3436e
JR
10117 int in_memory_file_p = 0;
10118
10119 /* See if data looks like an in-memory XBM file. */
10120 data = image_spec_value (img->spec, QCdata, NULL);
10121 in_memory_file_p = xbm_file_p (data);
6fc2811b 10122
217e5be0 10123 /* Parse the image specification. */
6fc2811b
JR
10124 bcopy (xbm_format, fmt, sizeof fmt);
10125 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10126 xassert (parsed_p);
10127
10128 /* Get specified width, and height. */
3cf3436e
JR
10129 if (!in_memory_file_p)
10130 {
10131 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10132 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10133 xassert (img->width > 0 && img->height > 0);
10134 }
217e5be0 10135
6fc2811b 10136 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
10137 if (fmt[XBM_FOREGROUND].count
10138 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
10139 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10140 foreground);
3cf3436e
JR
10141 if (fmt[XBM_BACKGROUND].count
10142 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
10143 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10144 background);
10145
3cf3436e
JR
10146 if (in_memory_file_p)
10147 success_p = xbm_load_image (f, img, XSTRING (data)->data,
10148 (XSTRING (data)->data
10149 + STRING_BYTES (XSTRING (data))));
10150 else
6fc2811b 10151 {
3cf3436e
JR
10152 if (VECTORP (data))
10153 {
10154 int i;
10155 char *p;
10156 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 10157
3cf3436e
JR
10158 p = bits = (char *) alloca (nbytes * img->height);
10159 for (i = 0; i < img->height; ++i, p += nbytes)
10160 {
10161 Lisp_Object line = XVECTOR (data)->contents[i];
10162 if (STRINGP (line))
10163 bcopy (XSTRING (line)->data, p, nbytes);
10164 else
10165 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10166 }
10167 }
10168 else if (STRINGP (data))
10169 bits = XSTRING (data)->data;
10170 else
10171 bits = XBOOL_VECTOR (data)->data;
af3f7be7 10172
3cf3436e 10173 /* Create the pixmap. */
a05e2bae 10174 depth = one_w32_display_info.n_cbits;
3cf3436e 10175 img->pixmap
af3f7be7
JR
10176 = w32_create_pixmap_from_bitmap_data (img->width, img->height,
10177 bits);
10178
3cf3436e
JR
10179 if (img->pixmap)
10180 success_p = 1;
10181 else
6fc2811b 10182 {
3cf3436e
JR
10183 image_error ("Unable to create pixmap for XBM image `%s'",
10184 img->spec, Qnil);
10185 x_clear_image (f, img);
6fc2811b
JR
10186 }
10187 }
6fc2811b
JR
10188 }
10189
10190 return success_p;
10191}
10192
10193
10194\f
10195/***********************************************************************
10196 XPM images
10197 ***********************************************************************/
10198
10199#if HAVE_XPM
10200
10201static int xpm_image_p P_ ((Lisp_Object object));
10202static int xpm_load P_ ((struct frame *f, struct image *img));
10203static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10204
10205#include "X11/xpm.h"
10206
10207/* The symbol `xpm' identifying XPM-format images. */
10208
10209Lisp_Object Qxpm;
10210
10211/* Indices of image specification fields in xpm_format, below. */
10212
10213enum xpm_keyword_index
10214{
10215 XPM_TYPE,
10216 XPM_FILE,
10217 XPM_DATA,
10218 XPM_ASCENT,
10219 XPM_MARGIN,
10220 XPM_RELIEF,
10221 XPM_ALGORITHM,
10222 XPM_HEURISTIC_MASK,
a05e2bae 10223 XPM_MASK,
6fc2811b 10224 XPM_COLOR_SYMBOLS,
a05e2bae 10225 XPM_BACKGROUND,
6fc2811b
JR
10226 XPM_LAST
10227};
10228
10229/* Vector of image_keyword structures describing the format
10230 of valid XPM image specifications. */
10231
10232static struct image_keyword xpm_format[XPM_LAST] =
10233{
10234 {":type", IMAGE_SYMBOL_VALUE, 1},
10235 {":file", IMAGE_STRING_VALUE, 0},
10236 {":data", IMAGE_STRING_VALUE, 0},
10237 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10238 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10239 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10240 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 10241 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10242 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10243 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10244 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10245};
10246
10247/* Structure describing the image type XBM. */
10248
10249static struct image_type xpm_type =
10250{
10251 &Qxpm,
10252 xpm_image_p,
10253 xpm_load,
10254 x_clear_image,
10255 NULL
10256};
10257
10258
10259/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10260 for XPM images. Such a list must consist of conses whose car and
10261 cdr are strings. */
10262
10263static int
10264xpm_valid_color_symbols_p (color_symbols)
10265 Lisp_Object color_symbols;
10266{
10267 while (CONSP (color_symbols))
10268 {
10269 Lisp_Object sym = XCAR (color_symbols);
10270 if (!CONSP (sym)
10271 || !STRINGP (XCAR (sym))
10272 || !STRINGP (XCDR (sym)))
10273 break;
10274 color_symbols = XCDR (color_symbols);
10275 }
10276
10277 return NILP (color_symbols);
10278}
10279
10280
10281/* Value is non-zero if OBJECT is a valid XPM image specification. */
10282
10283static int
10284xpm_image_p (object)
10285 Lisp_Object object;
10286{
10287 struct image_keyword fmt[XPM_LAST];
10288 bcopy (xpm_format, fmt, sizeof fmt);
10289 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10290 /* Either `:file' or `:data' must be present. */
10291 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10292 /* Either no `:color-symbols' or it's a list of conses
10293 whose car and cdr are strings. */
10294 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10295 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10296 && (fmt[XPM_ASCENT].count == 0
10297 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10298}
10299
10300
10301/* Load image IMG which will be displayed on frame F. Value is
10302 non-zero if successful. */
10303
10304static int
10305xpm_load (f, img)
10306 struct frame *f;
10307 struct image *img;
10308{
10309 int rc, i;
10310 XpmAttributes attrs;
10311 Lisp_Object specified_file, color_symbols;
10312
10313 /* Configure the XPM lib. Use the visual of frame F. Allocate
10314 close colors. Return colors allocated. */
10315 bzero (&attrs, sizeof attrs);
dfff8a69
JR
10316 attrs.visual = FRAME_X_VISUAL (f);
10317 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 10318 attrs.valuemask |= XpmVisual;
dfff8a69 10319 attrs.valuemask |= XpmColormap;
6fc2811b 10320 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 10321#ifdef XpmAllocCloseColors
6fc2811b
JR
10322 attrs.alloc_close_colors = 1;
10323 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
10324#else
10325 attrs.closeness = 600;
10326 attrs.valuemask |= XpmCloseness;
10327#endif
6fc2811b
JR
10328
10329 /* If image specification contains symbolic color definitions, add
10330 these to `attrs'. */
10331 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10332 if (CONSP (color_symbols))
10333 {
10334 Lisp_Object tail;
10335 XpmColorSymbol *xpm_syms;
10336 int i, size;
10337
10338 attrs.valuemask |= XpmColorSymbols;
10339
10340 /* Count number of symbols. */
10341 attrs.numsymbols = 0;
10342 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10343 ++attrs.numsymbols;
10344
10345 /* Allocate an XpmColorSymbol array. */
10346 size = attrs.numsymbols * sizeof *xpm_syms;
10347 xpm_syms = (XpmColorSymbol *) alloca (size);
10348 bzero (xpm_syms, size);
10349 attrs.colorsymbols = xpm_syms;
10350
10351 /* Fill the color symbol array. */
10352 for (tail = color_symbols, i = 0;
10353 CONSP (tail);
10354 ++i, tail = XCDR (tail))
10355 {
10356 Lisp_Object name = XCAR (XCAR (tail));
10357 Lisp_Object color = XCDR (XCAR (tail));
10358 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10359 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10360 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10361 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10362 }
10363 }
10364
10365 /* Create a pixmap for the image, either from a file, or from a
10366 string buffer containing data in the same format as an XPM file. */
10367 BLOCK_INPUT;
10368 specified_file = image_spec_value (img->spec, QCfile, NULL);
10369 if (STRINGP (specified_file))
10370 {
10371 Lisp_Object file = x_find_image_file (specified_file);
10372 if (!STRINGP (file))
10373 {
10374 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10375 UNBLOCK_INPUT;
10376 return 0;
10377 }
10378
10379 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10380 XSTRING (file)->data, &img->pixmap, &img->mask,
10381 &attrs);
10382 }
10383 else
10384 {
10385 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10386 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10387 XSTRING (buffer)->data,
10388 &img->pixmap, &img->mask,
10389 &attrs);
10390 }
10391 UNBLOCK_INPUT;
10392
10393 if (rc == XpmSuccess)
10394 {
10395 /* Remember allocated colors. */
10396 img->ncolors = attrs.nalloc_pixels;
10397 img->colors = (unsigned long *) xmalloc (img->ncolors
10398 * sizeof *img->colors);
10399 for (i = 0; i < attrs.nalloc_pixels; ++i)
10400 img->colors[i] = attrs.alloc_pixels[i];
10401
10402 img->width = attrs.width;
10403 img->height = attrs.height;
10404 xassert (img->width > 0 && img->height > 0);
10405
10406 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10407 BLOCK_INPUT;
10408 XpmFreeAttributes (&attrs);
10409 UNBLOCK_INPUT;
10410 }
10411 else
10412 {
10413 switch (rc)
10414 {
10415 case XpmOpenFailed:
10416 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10417 break;
10418
10419 case XpmFileInvalid:
10420 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10421 break;
10422
10423 case XpmNoMemory:
10424 image_error ("Out of memory (%s)", img->spec, Qnil);
10425 break;
10426
10427 case XpmColorFailed:
10428 image_error ("Color allocation error (%s)", img->spec, Qnil);
10429 break;
10430
10431 default:
10432 image_error ("Unknown error (%s)", img->spec, Qnil);
10433 break;
10434 }
10435 }
10436
10437 return rc == XpmSuccess;
10438}
10439
10440#endif /* HAVE_XPM != 0 */
10441
10442\f
767b1ff0 10443#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
10444/***********************************************************************
10445 Color table
10446 ***********************************************************************/
10447
10448/* An entry in the color table mapping an RGB color to a pixel color. */
10449
10450struct ct_color
10451{
10452 int r, g, b;
10453 unsigned long pixel;
10454
10455 /* Next in color table collision list. */
10456 struct ct_color *next;
10457};
10458
10459/* The bucket vector size to use. Must be prime. */
10460
10461#define CT_SIZE 101
10462
10463/* Value is a hash of the RGB color given by R, G, and B. */
10464
10465#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10466
10467/* The color hash table. */
10468
10469struct ct_color **ct_table;
10470
10471/* Number of entries in the color table. */
10472
10473int ct_colors_allocated;
10474
10475/* Function prototypes. */
10476
10477static void init_color_table P_ ((void));
10478static void free_color_table P_ ((void));
10479static unsigned long *colors_in_color_table P_ ((int *n));
10480static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10481static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10482
10483
10484/* Initialize the color table. */
10485
10486static void
10487init_color_table ()
10488{
10489 int size = CT_SIZE * sizeof (*ct_table);
10490 ct_table = (struct ct_color **) xmalloc (size);
10491 bzero (ct_table, size);
10492 ct_colors_allocated = 0;
10493}
10494
10495
10496/* Free memory associated with the color table. */
10497
10498static void
10499free_color_table ()
10500{
10501 int i;
10502 struct ct_color *p, *next;
10503
10504 for (i = 0; i < CT_SIZE; ++i)
10505 for (p = ct_table[i]; p; p = next)
10506 {
10507 next = p->next;
10508 xfree (p);
10509 }
10510
10511 xfree (ct_table);
10512 ct_table = NULL;
10513}
10514
10515
10516/* Value is a pixel color for RGB color R, G, B on frame F. If an
10517 entry for that color already is in the color table, return the
10518 pixel color of that entry. Otherwise, allocate a new color for R,
10519 G, B, and make an entry in the color table. */
10520
10521static unsigned long
10522lookup_rgb_color (f, r, g, b)
10523 struct frame *f;
10524 int r, g, b;
10525{
10526 unsigned hash = CT_HASH_RGB (r, g, b);
10527 int i = hash % CT_SIZE;
10528 struct ct_color *p;
10529
10530 for (p = ct_table[i]; p; p = p->next)
10531 if (p->r == r && p->g == g && p->b == b)
10532 break;
10533
10534 if (p == NULL)
10535 {
10536 COLORREF color;
10537 Colormap cmap;
10538 int rc;
10539
10540 color = PALETTERGB (r, g, b);
10541
10542 ++ct_colors_allocated;
10543
10544 p = (struct ct_color *) xmalloc (sizeof *p);
10545 p->r = r;
10546 p->g = g;
10547 p->b = b;
10548 p->pixel = color;
10549 p->next = ct_table[i];
10550 ct_table[i] = p;
10551 }
10552
10553 return p->pixel;
10554}
10555
10556
10557/* Look up pixel color PIXEL which is used on frame F in the color
10558 table. If not already present, allocate it. Value is PIXEL. */
10559
10560static unsigned long
10561lookup_pixel_color (f, pixel)
10562 struct frame *f;
10563 unsigned long pixel;
10564{
10565 int i = pixel % CT_SIZE;
10566 struct ct_color *p;
10567
10568 for (p = ct_table[i]; p; p = p->next)
10569 if (p->pixel == pixel)
10570 break;
10571
10572 if (p == NULL)
10573 {
10574 XColor color;
10575 Colormap cmap;
10576 int rc;
10577
10578 BLOCK_INPUT;
10579
10580 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10581 color.pixel = pixel;
10582 XQueryColor (NULL, cmap, &color);
10583 rc = x_alloc_nearest_color (f, cmap, &color);
10584 UNBLOCK_INPUT;
10585
10586 if (rc)
10587 {
10588 ++ct_colors_allocated;
10589
10590 p = (struct ct_color *) xmalloc (sizeof *p);
10591 p->r = color.red;
10592 p->g = color.green;
10593 p->b = color.blue;
10594 p->pixel = pixel;
10595 p->next = ct_table[i];
10596 ct_table[i] = p;
10597 }
10598 else
10599 return FRAME_FOREGROUND_PIXEL (f);
10600 }
10601 return p->pixel;
10602}
10603
10604
10605/* Value is a vector of all pixel colors contained in the color table,
10606 allocated via xmalloc. Set *N to the number of colors. */
10607
10608static unsigned long *
10609colors_in_color_table (n)
10610 int *n;
10611{
10612 int i, j;
10613 struct ct_color *p;
10614 unsigned long *colors;
10615
10616 if (ct_colors_allocated == 0)
10617 {
10618 *n = 0;
10619 colors = NULL;
10620 }
10621 else
10622 {
10623 colors = (unsigned long *) xmalloc (ct_colors_allocated
10624 * sizeof *colors);
10625 *n = ct_colors_allocated;
10626
10627 for (i = j = 0; i < CT_SIZE; ++i)
10628 for (p = ct_table[i]; p; p = p->next)
10629 colors[j++] = p->pixel;
10630 }
10631
10632 return colors;
10633}
10634
767b1ff0 10635#endif /* TODO */
6fc2811b
JR
10636
10637\f
10638/***********************************************************************
10639 Algorithms
10640 ***********************************************************************/
3cf3436e
JR
10641static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10642static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10643static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
ac849ba4 10644static void XPutPixel (XImage *, int, int, COLORREF);
3cf3436e
JR
10645
10646/* Non-zero means draw a cross on images having `:conversion
10647 disabled'. */
6fc2811b 10648
3cf3436e 10649int cross_disabled_images;
6fc2811b 10650
3cf3436e
JR
10651/* Edge detection matrices for different edge-detection
10652 strategies. */
6fc2811b 10653
3cf3436e
JR
10654static int emboss_matrix[9] = {
10655 /* x - 1 x x + 1 */
10656 2, -1, 0, /* y - 1 */
10657 -1, 0, 1, /* y */
10658 0, 1, -2 /* y + 1 */
10659};
10660
10661static int laplace_matrix[9] = {
10662 /* x - 1 x x + 1 */
10663 1, 0, 0, /* y - 1 */
10664 0, 0, 0, /* y */
10665 0, 0, -1 /* y + 1 */
10666};
10667
10668/* Value is the intensity of the color whose red/green/blue values
10669 are R, G, and B. */
10670
10671#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10672
10673
10674/* On frame F, return an array of XColor structures describing image
10675 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10676 non-zero means also fill the red/green/blue members of the XColor
10677 structures. Value is a pointer to the array of XColors structures,
10678 allocated with xmalloc; it must be freed by the caller. */
10679
10680static XColor *
10681x_to_xcolors (f, img, rgb_p)
10682 struct frame *f;
10683 struct image *img;
10684 int rgb_p;
10685{
10686 int x, y;
10687 XColor *colors, *p;
10688 XImage *ximg;
10689
10690 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
ac849ba4 10691#if 0 /* TODO: implement image colors. */
3cf3436e
JR
10692 /* Get the X image IMG->pixmap. */
10693 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10694 0, 0, img->width, img->height, ~0, ZPixmap);
10695
10696 /* Fill the `pixel' members of the XColor array. I wished there
10697 were an easy and portable way to circumvent XGetPixel. */
10698 p = colors;
10699 for (y = 0; y < img->height; ++y)
10700 {
10701 XColor *row = p;
10702
10703 for (x = 0; x < img->width; ++x, ++p)
10704 p->pixel = XGetPixel (ximg, x, y);
10705
10706 if (rgb_p)
10707 x_query_colors (f, row, img->width);
10708 }
10709
10710 XDestroyImage (ximg);
ac849ba4 10711#endif
3cf3436e
JR
10712 return colors;
10713}
10714
ac849ba4
JR
10715/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10716 created with CreateDIBSection, with the pointer to the bit values
10717 stored in ximg->data. */
10718
10719static void XPutPixel (ximg, x, y, color)
10720 XImage * ximg;
10721 int x, y;
10722 COLORREF color;
10723{
10724 int width = ximg->info.bmiHeader.biWidth;
10725 int height = ximg->info.bmiHeader.biHeight;
10726 int rowbytes = width * 3;
10727 unsigned char * pixel;
10728
10729 /* Don't support putting pixels in images with palettes. */
10730 xassert (ximg->info.bmiHeader.biBitCount == 24);
10731
10732 /* Ensure scanlines are aligned on 4 byte boundaries. */
10733 if (rowbytes % 4)
10734 rowbytes += 4 - (rowbytes % 4);
10735
10736 pixel = ximg->data + y * rowbytes + x * 3;
10737 *pixel = 255 - GetRValue (color);
10738 *(pixel + 1) = 255 - GetGValue (color);
10739 *(pixel + 2) = 255 - GetBValue (color);
10740}
10741
3cf3436e
JR
10742
10743/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10744 RGB members are set. F is the frame on which this all happens.
10745 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10746
10747static void
3cf3436e 10748x_from_xcolors (f, img, colors)
6fc2811b 10749 struct frame *f;
3cf3436e 10750 struct image *img;
6fc2811b 10751 XColor *colors;
6fc2811b 10752{
3cf3436e
JR
10753 int x, y;
10754 XImage *oimg;
10755 Pixmap pixmap;
10756 XColor *p;
ac849ba4 10757#if 0 /* TODO: color tables. */
3cf3436e 10758 init_color_table ();
ac849ba4 10759#endif
3cf3436e
JR
10760 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10761 &oimg, &pixmap);
10762 p = colors;
10763 for (y = 0; y < img->height; ++y)
10764 for (x = 0; x < img->width; ++x, ++p)
10765 {
10766 unsigned long pixel;
ac849ba4 10767#if 0 /* TODO: color tables. */
3cf3436e 10768 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
ac849ba4
JR
10769#else
10770 pixel = PALETTERGB (p->red, p->green, p->blue);
10771#endif
3cf3436e
JR
10772 XPutPixel (oimg, x, y, pixel);
10773 }
6fc2811b 10774
3cf3436e
JR
10775 xfree (colors);
10776 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10777
3cf3436e
JR
10778 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10779 x_destroy_x_image (oimg);
10780 img->pixmap = pixmap;
ac849ba4 10781#if 0 /* TODO: color tables. */
3cf3436e
JR
10782 img->colors = colors_in_color_table (&img->ncolors);
10783 free_color_table ();
ac849ba4 10784#endif
6fc2811b
JR
10785}
10786
10787
3cf3436e
JR
10788/* On frame F, perform edge-detection on image IMG.
10789
10790 MATRIX is a nine-element array specifying the transformation
10791 matrix. See emboss_matrix for an example.
10792
10793 COLOR_ADJUST is a color adjustment added to each pixel of the
10794 outgoing image. */
6fc2811b
JR
10795
10796static void
3cf3436e 10797x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10798 struct frame *f;
3cf3436e
JR
10799 struct image *img;
10800 int matrix[9], color_adjust;
6fc2811b 10801{
3cf3436e
JR
10802 XColor *colors = x_to_xcolors (f, img, 1);
10803 XColor *new, *p;
10804 int x, y, i, sum;
10805
10806 for (i = sum = 0; i < 9; ++i)
10807 sum += abs (matrix[i]);
10808
10809#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10810
10811 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10812
10813 for (y = 0; y < img->height; ++y)
10814 {
10815 p = COLOR (new, 0, y);
10816 p->red = p->green = p->blue = 0xffff/2;
10817 p = COLOR (new, img->width - 1, y);
10818 p->red = p->green = p->blue = 0xffff/2;
10819 }
6fc2811b 10820
3cf3436e
JR
10821 for (x = 1; x < img->width - 1; ++x)
10822 {
10823 p = COLOR (new, x, 0);
10824 p->red = p->green = p->blue = 0xffff/2;
10825 p = COLOR (new, x, img->height - 1);
10826 p->red = p->green = p->blue = 0xffff/2;
10827 }
10828
10829 for (y = 1; y < img->height - 1; ++y)
10830 {
10831 p = COLOR (new, 1, y);
10832
10833 for (x = 1; x < img->width - 1; ++x, ++p)
10834 {
10835 int r, g, b, y1, x1;
10836
10837 r = g = b = i = 0;
10838 for (y1 = y - 1; y1 < y + 2; ++y1)
10839 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10840 if (matrix[i])
10841 {
10842 XColor *t = COLOR (colors, x1, y1);
10843 r += matrix[i] * t->red;
10844 g += matrix[i] * t->green;
10845 b += matrix[i] * t->blue;
10846 }
10847
10848 r = (r / sum + color_adjust) & 0xffff;
10849 g = (g / sum + color_adjust) & 0xffff;
10850 b = (b / sum + color_adjust) & 0xffff;
10851 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10852 }
10853 }
10854
10855 xfree (colors);
10856 x_from_xcolors (f, img, new);
10857
10858#undef COLOR
10859}
10860
10861
10862/* Perform the pre-defined `emboss' edge-detection on image IMG
10863 on frame F. */
10864
10865static void
10866x_emboss (f, img)
10867 struct frame *f;
10868 struct image *img;
10869{
10870 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10871}
3cf3436e 10872
6fc2811b
JR
10873
10874/* Transform image IMG which is used on frame F with a Laplace
10875 edge-detection algorithm. The result is an image that can be used
10876 to draw disabled buttons, for example. */
10877
10878static void
10879x_laplace (f, img)
10880 struct frame *f;
10881 struct image *img;
10882{
3cf3436e
JR
10883 x_detect_edges (f, img, laplace_matrix, 45000);
10884}
6fc2811b 10885
6fc2811b 10886
3cf3436e
JR
10887/* Perform edge-detection on image IMG on frame F, with specified
10888 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10889
3cf3436e 10890 MATRIX must be either
6fc2811b 10891
3cf3436e
JR
10892 - a list of at least 9 numbers in row-major form
10893 - a vector of at least 9 numbers
6fc2811b 10894
3cf3436e
JR
10895 COLOR_ADJUST nil means use a default; otherwise it must be a
10896 number. */
6fc2811b 10897
3cf3436e
JR
10898static void
10899x_edge_detection (f, img, matrix, color_adjust)
10900 struct frame *f;
10901 struct image *img;
10902 Lisp_Object matrix, color_adjust;
10903{
10904 int i = 0;
10905 int trans[9];
10906
10907 if (CONSP (matrix))
6fc2811b 10908 {
3cf3436e
JR
10909 for (i = 0;
10910 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10911 ++i, matrix = XCDR (matrix))
10912 trans[i] = XFLOATINT (XCAR (matrix));
10913 }
10914 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10915 {
10916 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10917 trans[i] = XFLOATINT (AREF (matrix, i));
10918 }
10919
10920 if (NILP (color_adjust))
10921 color_adjust = make_number (0xffff / 2);
10922
10923 if (i == 9 && NUMBERP (color_adjust))
10924 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10925}
10926
6fc2811b 10927
3cf3436e 10928/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10929
3cf3436e
JR
10930static void
10931x_disable_image (f, img)
10932 struct frame *f;
10933 struct image *img;
10934{
ac849ba4 10935 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3cf3436e 10936
ac849ba4 10937 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
3cf3436e
JR
10938 {
10939 /* Color (or grayscale). Convert to gray, and equalize. Just
10940 drawing such images with a stipple can look very odd, so
10941 we're using this method instead. */
10942 XColor *colors = x_to_xcolors (f, img, 1);
10943 XColor *p, *end;
10944 const int h = 15000;
10945 const int l = 30000;
10946
10947 for (p = colors, end = colors + img->width * img->height;
10948 p < end;
10949 ++p)
6fc2811b 10950 {
3cf3436e
JR
10951 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10952 int i2 = (0xffff - h - l) * i / 0xffff + l;
10953 p->red = p->green = p->blue = i2;
6fc2811b
JR
10954 }
10955
3cf3436e 10956 x_from_xcolors (f, img, colors);
6fc2811b
JR
10957 }
10958
3cf3436e
JR
10959 /* Draw a cross over the disabled image, if we must or if we
10960 should. */
ac849ba4 10961 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
3cf3436e 10962 {
ac849ba4 10963#if 0 /* TODO: full image support */
3cf3436e
JR
10964 Display *dpy = FRAME_X_DISPLAY (f);
10965 GC gc;
6fc2811b 10966
3cf3436e
JR
10967 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10968 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10969 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10970 img->width - 1, img->height - 1);
10971 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10972 img->width - 1, 0);
10973 XFreeGC (dpy, gc);
6fc2811b 10974
3cf3436e
JR
10975 if (img->mask)
10976 {
10977 gc = XCreateGC (dpy, img->mask, 0, NULL);
10978 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10979 XDrawLine (dpy, img->mask, gc, 0, 0,
10980 img->width - 1, img->height - 1);
10981 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10982 img->width - 1, 0);
10983 XFreeGC (dpy, gc);
10984 }
ac849ba4 10985#endif
3cf3436e 10986 }
6fc2811b
JR
10987}
10988
10989
10990/* Build a mask for image IMG which is used on frame F. FILE is the
10991 name of an image file, for error messages. HOW determines how to
10992 determine the background color of IMG. If it is a list '(R G B)',
10993 with R, G, and B being integers >= 0, take that as the color of the
10994 background. Otherwise, determine the background color of IMG
10995 heuristically. Value is non-zero if successful. */
10996
10997static int
10998x_build_heuristic_mask (f, img, how)
10999 struct frame *f;
11000 struct image *img;
11001 Lisp_Object how;
11002{
ac849ba4 11003#if 0 /* TODO: full image support. */
6fc2811b
JR
11004 Display *dpy = FRAME_W32_DISPLAY (f);
11005 XImage *ximg, *mask_img;
a05e2bae
JR
11006 int x, y, rc, use_img_background;
11007 unsigned long bg = 0;
11008
11009 if (img->mask)
11010 {
11011 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
11012 img->mask = None;
11013 img->background_transparent_valid = 0;
11014 }
6fc2811b 11015
6fc2811b
JR
11016 /* Create an image and pixmap serving as mask. */
11017 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
11018 &mask_img, &img->mask);
11019 if (!rc)
a05e2bae 11020 return 0;
6fc2811b
JR
11021
11022 /* Get the X image of IMG->pixmap. */
11023 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
11024 ~0, ZPixmap);
11025
11026 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
11027 take that as color. Otherwise, use the image's background color. */
11028 use_img_background = 1;
6fc2811b
JR
11029
11030 if (CONSP (how))
11031 {
a05e2bae 11032 int rgb[3], i;
6fc2811b 11033
a05e2bae 11034 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
11035 {
11036 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
11037 how = XCDR (how);
11038 }
11039
11040 if (i == 3 && NILP (how))
11041 {
11042 char color_name[30];
6fc2811b 11043 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
11044 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
11045 use_img_background = 0;
6fc2811b
JR
11046 }
11047 }
11048
a05e2bae
JR
11049 if (use_img_background)
11050 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
11051
11052 /* Set all bits in mask_img to 1 whose color in ximg is different
11053 from the background color bg. */
11054 for (y = 0; y < img->height; ++y)
11055 for (x = 0; x < img->width; ++x)
11056 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
11057
a05e2bae
JR
11058 /* Fill in the background_transparent field while we have the mask handy. */
11059 image_background_transparent (img, f, mask_img);
11060
6fc2811b
JR
11061 /* Put mask_img into img->mask. */
11062 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11063 x_destroy_x_image (mask_img);
11064 XDestroyImage (ximg);
6fc2811b
JR
11065
11066 return 1;
ac849ba4
JR
11067#else
11068 return 0;
11069#endif
6fc2811b 11070}
217e5be0 11071
6fc2811b
JR
11072\f
11073/***********************************************************************
11074 PBM (mono, gray, color)
11075 ***********************************************************************/
6fc2811b
JR
11076
11077static int pbm_image_p P_ ((Lisp_Object object));
11078static int pbm_load P_ ((struct frame *f, struct image *img));
11079static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11080
11081/* The symbol `pbm' identifying images of this type. */
11082
11083Lisp_Object Qpbm;
11084
11085/* Indices of image specification fields in gs_format, below. */
11086
11087enum pbm_keyword_index
11088{
11089 PBM_TYPE,
11090 PBM_FILE,
11091 PBM_DATA,
11092 PBM_ASCENT,
11093 PBM_MARGIN,
11094 PBM_RELIEF,
11095 PBM_ALGORITHM,
11096 PBM_HEURISTIC_MASK,
a05e2bae
JR
11097 PBM_MASK,
11098 PBM_FOREGROUND,
11099 PBM_BACKGROUND,
6fc2811b
JR
11100 PBM_LAST
11101};
11102
11103/* Vector of image_keyword structures describing the format
11104 of valid user-defined image specifications. */
11105
11106static struct image_keyword pbm_format[PBM_LAST] =
11107{
11108 {":type", IMAGE_SYMBOL_VALUE, 1},
11109 {":file", IMAGE_STRING_VALUE, 0},
11110 {":data", IMAGE_STRING_VALUE, 0},
11111 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11112 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11113 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11114 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
11115 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11116 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11117 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11118 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11119};
11120
11121/* Structure describing the image type `pbm'. */
11122
11123static struct image_type pbm_type =
11124{
11125 &Qpbm,
11126 pbm_image_p,
11127 pbm_load,
11128 x_clear_image,
11129 NULL
11130};
11131
11132
11133/* Return non-zero if OBJECT is a valid PBM image specification. */
11134
11135static int
11136pbm_image_p (object)
11137 Lisp_Object object;
11138{
11139 struct image_keyword fmt[PBM_LAST];
11140
11141 bcopy (pbm_format, fmt, sizeof fmt);
11142
11143 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
11144 || (fmt[PBM_ASCENT].count
11145 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11146 return 0;
11147
11148 /* Must specify either :data or :file. */
11149 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11150}
11151
11152
11153/* Scan a decimal number from *S and return it. Advance *S while
11154 reading the number. END is the end of the string. Value is -1 at
11155 end of input. */
11156
11157static int
11158pbm_scan_number (s, end)
11159 unsigned char **s, *end;
11160{
11161 int c, val = -1;
11162
11163 while (*s < end)
11164 {
11165 /* Skip white-space. */
11166 while (*s < end && (c = *(*s)++, isspace (c)))
11167 ;
11168
11169 if (c == '#')
11170 {
11171 /* Skip comment to end of line. */
11172 while (*s < end && (c = *(*s)++, c != '\n'))
11173 ;
11174 }
11175 else if (isdigit (c))
11176 {
11177 /* Read decimal number. */
11178 val = c - '0';
11179 while (*s < end && (c = *(*s)++, isdigit (c)))
11180 val = 10 * val + c - '0';
11181 break;
11182 }
11183 else
11184 break;
11185 }
11186
11187 return val;
11188}
11189
11190
11191/* Read FILE into memory. Value is a pointer to a buffer allocated
11192 with xmalloc holding FILE's contents. Value is null if an error
11193 occured. *SIZE is set to the size of the file. */
11194
11195static char *
11196pbm_read_file (file, size)
11197 Lisp_Object file;
11198 int *size;
11199{
11200 FILE *fp = NULL;
11201 char *buf = NULL;
11202 struct stat st;
11203
11204 if (stat (XSTRING (file)->data, &st) == 0
11205 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11206 && (buf = (char *) xmalloc (st.st_size),
11207 fread (buf, 1, st.st_size, fp) == st.st_size))
11208 {
11209 *size = st.st_size;
11210 fclose (fp);
11211 }
11212 else
11213 {
11214 if (fp)
11215 fclose (fp);
11216 if (buf)
11217 {
11218 xfree (buf);
11219 buf = NULL;
11220 }
11221 }
11222
11223 return buf;
11224}
11225
11226
11227/* Load PBM image IMG for use on frame F. */
11228
11229static int
11230pbm_load (f, img)
11231 struct frame *f;
11232 struct image *img;
11233{
11234 int raw_p, x, y;
11235 int width, height, max_color_idx = 0;
11236 XImage *ximg;
11237 Lisp_Object file, specified_file;
11238 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11239 struct gcpro gcpro1;
11240 unsigned char *contents = NULL;
11241 unsigned char *end, *p;
11242 int size;
11243
11244 specified_file = image_spec_value (img->spec, QCfile, NULL);
11245 file = Qnil;
11246 GCPRO1 (file);
11247
11248 if (STRINGP (specified_file))
11249 {
11250 file = x_find_image_file (specified_file);
11251 if (!STRINGP (file))
11252 {
11253 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11254 UNGCPRO;
11255 return 0;
11256 }
11257
3cf3436e 11258 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
11259 if (contents == NULL)
11260 {
11261 image_error ("Error reading `%s'", file, Qnil);
11262 UNGCPRO;
11263 return 0;
11264 }
11265
11266 p = contents;
11267 end = contents + size;
11268 }
11269 else
11270 {
11271 Lisp_Object data;
11272 data = image_spec_value (img->spec, QCdata, NULL);
11273 p = XSTRING (data)->data;
11274 end = p + STRING_BYTES (XSTRING (data));
11275 }
11276
11277 /* Check magic number. */
11278 if (end - p < 2 || *p++ != 'P')
11279 {
11280 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11281 error:
11282 xfree (contents);
11283 UNGCPRO;
11284 return 0;
11285 }
11286
6fc2811b
JR
11287 switch (*p++)
11288 {
11289 case '1':
11290 raw_p = 0, type = PBM_MONO;
11291 break;
11292
11293 case '2':
11294 raw_p = 0, type = PBM_GRAY;
11295 break;
11296
11297 case '3':
11298 raw_p = 0, type = PBM_COLOR;
11299 break;
11300
11301 case '4':
11302 raw_p = 1, type = PBM_MONO;
11303 break;
11304
11305 case '5':
11306 raw_p = 1, type = PBM_GRAY;
11307 break;
11308
11309 case '6':
11310 raw_p = 1, type = PBM_COLOR;
11311 break;
11312
11313 default:
11314 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11315 goto error;
11316 }
11317
11318 /* Read width, height, maximum color-component. Characters
11319 starting with `#' up to the end of a line are ignored. */
11320 width = pbm_scan_number (&p, end);
11321 height = pbm_scan_number (&p, end);
11322
11323 if (type != PBM_MONO)
11324 {
11325 max_color_idx = pbm_scan_number (&p, end);
11326 if (raw_p && max_color_idx > 255)
11327 max_color_idx = 255;
11328 }
11329
11330 if (width < 0
11331 || height < 0
11332 || (type != PBM_MONO && max_color_idx < 0))
11333 goto error;
11334
ac849ba4 11335 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
3cf3436e
JR
11336 goto error;
11337
ac849ba4 11338#if 0 /* TODO: color tables. */
6fc2811b
JR
11339 /* Initialize the color hash table. */
11340 init_color_table ();
ac849ba4 11341#endif
6fc2811b
JR
11342
11343 if (type == PBM_MONO)
11344 {
11345 int c = 0, g;
3cf3436e
JR
11346 struct image_keyword fmt[PBM_LAST];
11347 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11348 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11349
11350 /* Parse the image specification. */
11351 bcopy (pbm_format, fmt, sizeof fmt);
11352 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11353
11354 /* Get foreground and background colors, maybe allocate colors. */
11355 if (fmt[PBM_FOREGROUND].count
11356 && STRINGP (fmt[PBM_FOREGROUND].value))
11357 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11358 if (fmt[PBM_BACKGROUND].count
11359 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
11360 {
11361 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11362 img->background = bg;
11363 img->background_valid = 1;
11364 }
11365
6fc2811b
JR
11366 for (y = 0; y < height; ++y)
11367 for (x = 0; x < width; ++x)
11368 {
11369 if (raw_p)
11370 {
11371 if ((x & 7) == 0)
11372 c = *p++;
11373 g = c & 0x80;
11374 c <<= 1;
11375 }
11376 else
11377 g = pbm_scan_number (&p, end);
11378
3cf3436e 11379 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
11380 }
11381 }
11382 else
11383 {
11384 for (y = 0; y < height; ++y)
11385 for (x = 0; x < width; ++x)
11386 {
11387 int r, g, b;
11388
11389 if (type == PBM_GRAY)
11390 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11391 else if (raw_p)
11392 {
11393 r = *p++;
11394 g = *p++;
11395 b = *p++;
11396 }
11397 else
11398 {
11399 r = pbm_scan_number (&p, end);
11400 g = pbm_scan_number (&p, end);
11401 b = pbm_scan_number (&p, end);
11402 }
11403
11404 if (r < 0 || g < 0 || b < 0)
11405 {
ac849ba4 11406 x_destroy_x_image (ximg);
6fc2811b
JR
11407 image_error ("Invalid pixel value in image `%s'",
11408 img->spec, Qnil);
11409 goto error;
11410 }
11411
11412 /* RGB values are now in the range 0..max_color_idx.
ac849ba4
JR
11413 Scale this to the range 0..0xff supported by W32. */
11414 r = (int) ((double) r * 255 / max_color_idx);
11415 g = (int) ((double) g * 255 / max_color_idx);
11416 b = (int) ((double) b * 255 / max_color_idx);
11417 XPutPixel (ximg, x, y,
11418#if 0 /* TODO: color tables. */
11419 lookup_rgb_color (f, r, g, b));
11420#else
11421 PALETTERGB (r, g, b));
11422#endif
6fc2811b
JR
11423 }
11424 }
ac849ba4
JR
11425
11426#if 0 /* TODO: color tables. */
6fc2811b
JR
11427 /* Store in IMG->colors the colors allocated for the image, and
11428 free the color table. */
11429 img->colors = colors_in_color_table (&img->ncolors);
11430 free_color_table ();
ac849ba4 11431#endif
a05e2bae
JR
11432 /* Maybe fill in the background field while we have ximg handy. */
11433 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11434 IMAGE_BACKGROUND (img, f, ximg);
11435
6fc2811b
JR
11436 /* Put the image into a pixmap. */
11437 x_put_x_image (f, ximg, img->pixmap, width, height);
11438 x_destroy_x_image (ximg);
6fc2811b
JR
11439
11440 img->width = width;
11441 img->height = height;
11442
11443 UNGCPRO;
11444 xfree (contents);
11445 return 1;
11446}
6fc2811b
JR
11447
11448\f
11449/***********************************************************************
11450 PNG
11451 ***********************************************************************/
11452
11453#if HAVE_PNG
11454
11455#include <png.h>
11456
11457/* Function prototypes. */
11458
11459static int png_image_p P_ ((Lisp_Object object));
11460static int png_load P_ ((struct frame *f, struct image *img));
11461
11462/* The symbol `png' identifying images of this type. */
11463
11464Lisp_Object Qpng;
11465
11466/* Indices of image specification fields in png_format, below. */
11467
11468enum png_keyword_index
11469{
11470 PNG_TYPE,
11471 PNG_DATA,
11472 PNG_FILE,
11473 PNG_ASCENT,
11474 PNG_MARGIN,
11475 PNG_RELIEF,
11476 PNG_ALGORITHM,
11477 PNG_HEURISTIC_MASK,
a05e2bae
JR
11478 PNG_MASK,
11479 PNG_BACKGROUND,
6fc2811b
JR
11480 PNG_LAST
11481};
11482
11483/* Vector of image_keyword structures describing the format
11484 of valid user-defined image specifications. */
11485
11486static struct image_keyword png_format[PNG_LAST] =
11487{
11488 {":type", IMAGE_SYMBOL_VALUE, 1},
11489 {":data", IMAGE_STRING_VALUE, 0},
11490 {":file", IMAGE_STRING_VALUE, 0},
11491 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11492 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11493 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11494 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11495 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11496 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11497 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11498};
11499
11500/* Structure describing the image type `png'. */
11501
11502static struct image_type png_type =
11503{
11504 &Qpng,
11505 png_image_p,
11506 png_load,
11507 x_clear_image,
11508 NULL
11509};
11510
11511
11512/* Return non-zero if OBJECT is a valid PNG image specification. */
11513
11514static int
11515png_image_p (object)
11516 Lisp_Object object;
11517{
11518 struct image_keyword fmt[PNG_LAST];
11519 bcopy (png_format, fmt, sizeof fmt);
11520
11521 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11522 || (fmt[PNG_ASCENT].count
11523 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11524 return 0;
11525
11526 /* Must specify either the :data or :file keyword. */
11527 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11528}
11529
11530
11531/* Error and warning handlers installed when the PNG library
11532 is initialized. */
11533
11534static void
11535my_png_error (png_ptr, msg)
11536 png_struct *png_ptr;
11537 char *msg;
11538{
11539 xassert (png_ptr != NULL);
11540 image_error ("PNG error: %s", build_string (msg), Qnil);
11541 longjmp (png_ptr->jmpbuf, 1);
11542}
11543
11544
11545static void
11546my_png_warning (png_ptr, msg)
11547 png_struct *png_ptr;
11548 char *msg;
11549{
11550 xassert (png_ptr != NULL);
11551 image_error ("PNG warning: %s", build_string (msg), Qnil);
11552}
11553
6fc2811b
JR
11554/* Memory source for PNG decoding. */
11555
11556struct png_memory_storage
11557{
11558 unsigned char *bytes; /* The data */
11559 size_t len; /* How big is it? */
11560 int index; /* Where are we? */
11561};
11562
11563
11564/* Function set as reader function when reading PNG image from memory.
11565 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11566 bytes from the input to DATA. */
11567
11568static void
11569png_read_from_memory (png_ptr, data, length)
11570 png_structp png_ptr;
11571 png_bytep data;
11572 png_size_t length;
11573{
11574 struct png_memory_storage *tbr
11575 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11576
11577 if (length > tbr->len - tbr->index)
11578 png_error (png_ptr, "Read error");
11579
11580 bcopy (tbr->bytes + tbr->index, data, length);
11581 tbr->index = tbr->index + length;
11582}
11583
6fc2811b
JR
11584/* Load PNG image IMG for use on frame F. Value is non-zero if
11585 successful. */
11586
11587static int
11588png_load (f, img)
11589 struct frame *f;
11590 struct image *img;
11591{
11592 Lisp_Object file, specified_file;
11593 Lisp_Object specified_data;
11594 int x, y, i;
11595 XImage *ximg, *mask_img = NULL;
11596 struct gcpro gcpro1;
11597 png_struct *png_ptr = NULL;
11598 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11599 FILE *volatile fp = NULL;
6fc2811b 11600 png_byte sig[8];
a05e2bae
JR
11601 png_byte *volatile pixels = NULL;
11602 png_byte **volatile rows = NULL;
6fc2811b
JR
11603 png_uint_32 width, height;
11604 int bit_depth, color_type, interlace_type;
11605 png_byte channels;
11606 png_uint_32 row_bytes;
11607 int transparent_p;
11608 char *gamma_str;
11609 double screen_gamma, image_gamma;
11610 int intent;
11611 struct png_memory_storage tbr; /* Data to be read */
11612
11613 /* Find out what file to load. */
11614 specified_file = image_spec_value (img->spec, QCfile, NULL);
11615 specified_data = image_spec_value (img->spec, QCdata, NULL);
11616 file = Qnil;
11617 GCPRO1 (file);
11618
11619 if (NILP (specified_data))
11620 {
11621 file = x_find_image_file (specified_file);
11622 if (!STRINGP (file))
11623 {
11624 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11625 UNGCPRO;
11626 return 0;
11627 }
11628
11629 /* Open the image file. */
11630 fp = fopen (XSTRING (file)->data, "rb");
11631 if (!fp)
11632 {
11633 image_error ("Cannot open image file `%s'", file, Qnil);
11634 UNGCPRO;
11635 fclose (fp);
11636 return 0;
11637 }
11638
11639 /* Check PNG signature. */
11640 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11641 || !png_check_sig (sig, sizeof sig))
11642 {
11643 image_error ("Not a PNG file:` %s'", file, Qnil);
11644 UNGCPRO;
11645 fclose (fp);
11646 return 0;
11647 }
11648 }
11649 else
11650 {
11651 /* Read from memory. */
11652 tbr.bytes = XSTRING (specified_data)->data;
11653 tbr.len = STRING_BYTES (XSTRING (specified_data));
11654 tbr.index = 0;
11655
11656 /* Check PNG signature. */
11657 if (tbr.len < sizeof sig
11658 || !png_check_sig (tbr.bytes, sizeof sig))
11659 {
11660 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11661 UNGCPRO;
11662 return 0;
11663 }
11664
11665 /* Need to skip past the signature. */
11666 tbr.bytes += sizeof (sig);
11667 }
11668
6fc2811b
JR
11669 /* Initialize read and info structs for PNG lib. */
11670 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11671 my_png_error, my_png_warning);
11672 if (!png_ptr)
11673 {
11674 if (fp) fclose (fp);
11675 UNGCPRO;
11676 return 0;
11677 }
11678
11679 info_ptr = png_create_info_struct (png_ptr);
11680 if (!info_ptr)
11681 {
11682 png_destroy_read_struct (&png_ptr, NULL, NULL);
11683 if (fp) fclose (fp);
11684 UNGCPRO;
11685 return 0;
11686 }
11687
11688 end_info = png_create_info_struct (png_ptr);
11689 if (!end_info)
11690 {
11691 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11692 if (fp) fclose (fp);
11693 UNGCPRO;
11694 return 0;
11695 }
11696
11697 /* Set error jump-back. We come back here when the PNG library
11698 detects an error. */
11699 if (setjmp (png_ptr->jmpbuf))
11700 {
11701 error:
11702 if (png_ptr)
11703 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11704 xfree (pixels);
11705 xfree (rows);
11706 if (fp) fclose (fp);
11707 UNGCPRO;
11708 return 0;
11709 }
11710
11711 /* Read image info. */
11712 if (!NILP (specified_data))
11713 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11714 else
11715 png_init_io (png_ptr, fp);
11716
11717 png_set_sig_bytes (png_ptr, sizeof sig);
11718 png_read_info (png_ptr, info_ptr);
11719 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11720 &interlace_type, NULL, NULL);
11721
11722 /* If image contains simply transparency data, we prefer to
11723 construct a clipping mask. */
11724 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11725 transparent_p = 1;
11726 else
11727 transparent_p = 0;
11728
11729 /* This function is easier to write if we only have to handle
11730 one data format: RGB or RGBA with 8 bits per channel. Let's
11731 transform other formats into that format. */
11732
11733 /* Strip more than 8 bits per channel. */
11734 if (bit_depth == 16)
11735 png_set_strip_16 (png_ptr);
11736
11737 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11738 if available. */
11739 png_set_expand (png_ptr);
11740
11741 /* Convert grayscale images to RGB. */
11742 if (color_type == PNG_COLOR_TYPE_GRAY
11743 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11744 png_set_gray_to_rgb (png_ptr);
11745
11746 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11747 gamma_str = getenv ("SCREEN_GAMMA");
11748 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11749
11750 /* Tell the PNG lib to handle gamma correction for us. */
11751
11752#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11753 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11754 /* There is a special chunk in the image specifying the gamma. */
11755 png_set_sRGB (png_ptr, info_ptr, intent);
11756 else
11757#endif
11758 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11759 /* Image contains gamma information. */
11760 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11761 else
11762 /* Use a default of 0.5 for the image gamma. */
11763 png_set_gamma (png_ptr, screen_gamma, 0.5);
11764
11765 /* Handle alpha channel by combining the image with a background
11766 color. Do this only if a real alpha channel is supplied. For
11767 simple transparency, we prefer a clipping mask. */
11768 if (!transparent_p)
11769 {
11770 png_color_16 *image_background;
a05e2bae
JR
11771 Lisp_Object specified_bg
11772 = image_spec_value (img->spec, QCbackground, NULL);
11773
11774
11775 if (STRINGP (specified_bg))
11776 /* The user specified `:background', use that. */
11777 {
11778 COLORREF color;
11779 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11780 {
11781 png_color_16 user_bg;
11782
11783 bzero (&user_bg, sizeof user_bg);
11784 user_bg.red = color.red;
11785 user_bg.green = color.green;
11786 user_bg.blue = color.blue;
6fc2811b 11787
a05e2bae
JR
11788 png_set_background (png_ptr, &user_bg,
11789 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11790 }
11791 }
11792 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11793 /* Image contains a background color with which to
11794 combine the image. */
11795 png_set_background (png_ptr, image_background,
11796 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11797 else
11798 {
11799 /* Image does not contain a background color with which
11800 to combine the image data via an alpha channel. Use
11801 the frame's background instead. */
11802 XColor color;
11803 Colormap cmap;
11804 png_color_16 frame_background;
11805
a05e2bae 11806 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11807 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11808 x_query_color (f, &color);
6fc2811b
JR
11809
11810 bzero (&frame_background, sizeof frame_background);
11811 frame_background.red = color.red;
11812 frame_background.green = color.green;
11813 frame_background.blue = color.blue;
11814
11815 png_set_background (png_ptr, &frame_background,
11816 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11817 }
11818 }
11819
11820 /* Update info structure. */
11821 png_read_update_info (png_ptr, info_ptr);
11822
11823 /* Get number of channels. Valid values are 1 for grayscale images
11824 and images with a palette, 2 for grayscale images with transparency
11825 information (alpha channel), 3 for RGB images, and 4 for RGB
11826 images with alpha channel, i.e. RGBA. If conversions above were
11827 sufficient we should only have 3 or 4 channels here. */
11828 channels = png_get_channels (png_ptr, info_ptr);
11829 xassert (channels == 3 || channels == 4);
11830
11831 /* Number of bytes needed for one row of the image. */
11832 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11833
11834 /* Allocate memory for the image. */
11835 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11836 rows = (png_byte **) xmalloc (height * sizeof *rows);
11837 for (i = 0; i < height; ++i)
11838 rows[i] = pixels + i * row_bytes;
11839
11840 /* Read the entire image. */
11841 png_read_image (png_ptr, rows);
11842 png_read_end (png_ptr, info_ptr);
11843 if (fp)
11844 {
11845 fclose (fp);
11846 fp = NULL;
11847 }
11848
6fc2811b
JR
11849 /* Create the X image and pixmap. */
11850 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11851 &img->pixmap))
a05e2bae 11852 goto error;
6fc2811b
JR
11853
11854 /* Create an image and pixmap serving as mask if the PNG image
11855 contains an alpha channel. */
11856 if (channels == 4
11857 && !transparent_p
11858 && !x_create_x_image_and_pixmap (f, width, height, 1,
11859 &mask_img, &img->mask))
11860 {
11861 x_destroy_x_image (ximg);
11862 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11863 img->pixmap = 0;
6fc2811b
JR
11864 goto error;
11865 }
11866
11867 /* Fill the X image and mask from PNG data. */
11868 init_color_table ();
11869
11870 for (y = 0; y < height; ++y)
11871 {
11872 png_byte *p = rows[y];
11873
11874 for (x = 0; x < width; ++x)
11875 {
11876 unsigned r, g, b;
11877
11878 r = *p++ << 8;
11879 g = *p++ << 8;
11880 b = *p++ << 8;
11881 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11882
11883 /* An alpha channel, aka mask channel, associates variable
11884 transparency with an image. Where other image formats
11885 support binary transparency---fully transparent or fully
11886 opaque---PNG allows up to 254 levels of partial transparency.
11887 The PNG library implements partial transparency by combining
11888 the image with a specified background color.
11889
11890 I'm not sure how to handle this here nicely: because the
11891 background on which the image is displayed may change, for
11892 real alpha channel support, it would be necessary to create
11893 a new image for each possible background.
11894
11895 What I'm doing now is that a mask is created if we have
11896 boolean transparency information. Otherwise I'm using
11897 the frame's background color to combine the image with. */
11898
11899 if (channels == 4)
11900 {
11901 if (mask_img)
11902 XPutPixel (mask_img, x, y, *p > 0);
11903 ++p;
11904 }
11905 }
11906 }
11907
a05e2bae
JR
11908 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11909 /* Set IMG's background color from the PNG image, unless the user
11910 overrode it. */
11911 {
11912 png_color_16 *bg;
11913 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11914 {
11915 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11916 img->background_valid = 1;
11917 }
11918 }
11919
6fc2811b
JR
11920 /* Remember colors allocated for this image. */
11921 img->colors = colors_in_color_table (&img->ncolors);
11922 free_color_table ();
11923
11924 /* Clean up. */
11925 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11926 xfree (rows);
11927 xfree (pixels);
11928
11929 img->width = width;
11930 img->height = height;
11931
a05e2bae
JR
11932 /* Maybe fill in the background field while we have ximg handy. */
11933 IMAGE_BACKGROUND (img, f, ximg);
11934
6fc2811b
JR
11935 /* Put the image into the pixmap, then free the X image and its buffer. */
11936 x_put_x_image (f, ximg, img->pixmap, width, height);
11937 x_destroy_x_image (ximg);
11938
11939 /* Same for the mask. */
11940 if (mask_img)
11941 {
a05e2bae
JR
11942 /* Fill in the background_transparent field while we have the mask
11943 handy. */
11944 image_background_transparent (img, f, mask_img);
11945
6fc2811b
JR
11946 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11947 x_destroy_x_image (mask_img);
11948 }
11949
6fc2811b
JR
11950 UNGCPRO;
11951 return 1;
11952}
11953
11954#endif /* HAVE_PNG != 0 */
11955
11956
11957\f
11958/***********************************************************************
11959 JPEG
11960 ***********************************************************************/
11961
11962#if HAVE_JPEG
11963
11964/* Work around a warning about HAVE_STDLIB_H being redefined in
11965 jconfig.h. */
11966#ifdef HAVE_STDLIB_H
11967#define HAVE_STDLIB_H_1
11968#undef HAVE_STDLIB_H
11969#endif /* HAVE_STLIB_H */
11970
11971#include <jpeglib.h>
11972#include <jerror.h>
11973#include <setjmp.h>
11974
11975#ifdef HAVE_STLIB_H_1
11976#define HAVE_STDLIB_H 1
11977#endif
11978
11979static int jpeg_image_p P_ ((Lisp_Object object));
11980static int jpeg_load P_ ((struct frame *f, struct image *img));
11981
11982/* The symbol `jpeg' identifying images of this type. */
11983
11984Lisp_Object Qjpeg;
11985
11986/* Indices of image specification fields in gs_format, below. */
11987
11988enum jpeg_keyword_index
11989{
11990 JPEG_TYPE,
11991 JPEG_DATA,
11992 JPEG_FILE,
11993 JPEG_ASCENT,
11994 JPEG_MARGIN,
11995 JPEG_RELIEF,
11996 JPEG_ALGORITHM,
11997 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11998 JPEG_MASK,
11999 JPEG_BACKGROUND,
6fc2811b
JR
12000 JPEG_LAST
12001};
12002
12003/* Vector of image_keyword structures describing the format
12004 of valid user-defined image specifications. */
12005
12006static struct image_keyword jpeg_format[JPEG_LAST] =
12007{
12008 {":type", IMAGE_SYMBOL_VALUE, 1},
12009 {":data", IMAGE_STRING_VALUE, 0},
12010 {":file", IMAGE_STRING_VALUE, 0},
12011 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12012 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12013 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12014 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12015 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12016 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12017 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12018};
12019
12020/* Structure describing the image type `jpeg'. */
12021
12022static struct image_type jpeg_type =
12023{
12024 &Qjpeg,
12025 jpeg_image_p,
12026 jpeg_load,
12027 x_clear_image,
12028 NULL
12029};
12030
12031
12032/* Return non-zero if OBJECT is a valid JPEG image specification. */
12033
12034static int
12035jpeg_image_p (object)
12036 Lisp_Object object;
12037{
12038 struct image_keyword fmt[JPEG_LAST];
12039
12040 bcopy (jpeg_format, fmt, sizeof fmt);
12041
12042 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
12043 || (fmt[JPEG_ASCENT].count
12044 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
12045 return 0;
12046
12047 /* Must specify either the :data or :file keyword. */
12048 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
12049}
12050
12051
12052struct my_jpeg_error_mgr
12053{
12054 struct jpeg_error_mgr pub;
12055 jmp_buf setjmp_buffer;
12056};
12057
12058static void
12059my_error_exit (cinfo)
12060 j_common_ptr cinfo;
12061{
12062 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12063 longjmp (mgr->setjmp_buffer, 1);
12064}
12065
6fc2811b
JR
12066/* Init source method for JPEG data source manager. Called by
12067 jpeg_read_header() before any data is actually read. See
12068 libjpeg.doc from the JPEG lib distribution. */
12069
12070static void
12071our_init_source (cinfo)
12072 j_decompress_ptr cinfo;
12073{
12074}
12075
12076
12077/* Fill input buffer method for JPEG data source manager. Called
12078 whenever more data is needed. We read the whole image in one step,
12079 so this only adds a fake end of input marker at the end. */
12080
12081static boolean
12082our_fill_input_buffer (cinfo)
12083 j_decompress_ptr cinfo;
12084{
12085 /* Insert a fake EOI marker. */
12086 struct jpeg_source_mgr *src = cinfo->src;
12087 static JOCTET buffer[2];
12088
12089 buffer[0] = (JOCTET) 0xFF;
12090 buffer[1] = (JOCTET) JPEG_EOI;
12091
12092 src->next_input_byte = buffer;
12093 src->bytes_in_buffer = 2;
12094 return TRUE;
12095}
12096
12097
12098/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12099 is the JPEG data source manager. */
12100
12101static void
12102our_skip_input_data (cinfo, num_bytes)
12103 j_decompress_ptr cinfo;
12104 long num_bytes;
12105{
12106 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12107
12108 if (src)
12109 {
12110 if (num_bytes > src->bytes_in_buffer)
12111 ERREXIT (cinfo, JERR_INPUT_EOF);
12112
12113 src->bytes_in_buffer -= num_bytes;
12114 src->next_input_byte += num_bytes;
12115 }
12116}
12117
12118
12119/* Method to terminate data source. Called by
12120 jpeg_finish_decompress() after all data has been processed. */
12121
12122static void
12123our_term_source (cinfo)
12124 j_decompress_ptr cinfo;
12125{
12126}
12127
12128
12129/* Set up the JPEG lib for reading an image from DATA which contains
12130 LEN bytes. CINFO is the decompression info structure created for
12131 reading the image. */
12132
12133static void
12134jpeg_memory_src (cinfo, data, len)
12135 j_decompress_ptr cinfo;
12136 JOCTET *data;
12137 unsigned int len;
12138{
12139 struct jpeg_source_mgr *src;
12140
12141 if (cinfo->src == NULL)
12142 {
12143 /* First time for this JPEG object? */
12144 cinfo->src = (struct jpeg_source_mgr *)
12145 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12146 sizeof (struct jpeg_source_mgr));
12147 src = (struct jpeg_source_mgr *) cinfo->src;
12148 src->next_input_byte = data;
12149 }
12150
12151 src = (struct jpeg_source_mgr *) cinfo->src;
12152 src->init_source = our_init_source;
12153 src->fill_input_buffer = our_fill_input_buffer;
12154 src->skip_input_data = our_skip_input_data;
12155 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12156 src->term_source = our_term_source;
12157 src->bytes_in_buffer = len;
12158 src->next_input_byte = data;
12159}
12160
12161
12162/* Load image IMG for use on frame F. Patterned after example.c
12163 from the JPEG lib. */
12164
12165static int
12166jpeg_load (f, img)
12167 struct frame *f;
12168 struct image *img;
12169{
12170 struct jpeg_decompress_struct cinfo;
12171 struct my_jpeg_error_mgr mgr;
12172 Lisp_Object file, specified_file;
12173 Lisp_Object specified_data;
a05e2bae 12174 FILE * volatile fp = NULL;
6fc2811b
JR
12175 JSAMPARRAY buffer;
12176 int row_stride, x, y;
12177 XImage *ximg = NULL;
12178 int rc;
12179 unsigned long *colors;
12180 int width, height;
12181 struct gcpro gcpro1;
12182
12183 /* Open the JPEG file. */
12184 specified_file = image_spec_value (img->spec, QCfile, NULL);
12185 specified_data = image_spec_value (img->spec, QCdata, NULL);
12186 file = Qnil;
12187 GCPRO1 (file);
12188
6fc2811b
JR
12189 if (NILP (specified_data))
12190 {
12191 file = x_find_image_file (specified_file);
12192 if (!STRINGP (file))
12193 {
12194 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12195 UNGCPRO;
12196 return 0;
12197 }
12198
12199 fp = fopen (XSTRING (file)->data, "r");
12200 if (fp == NULL)
12201 {
12202 image_error ("Cannot open `%s'", file, Qnil);
12203 UNGCPRO;
12204 return 0;
12205 }
12206 }
12207
12208 /* Customize libjpeg's error handling to call my_error_exit when an
12209 error is detected. This function will perform a longjmp. */
6fc2811b 12210 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 12211 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
12212
12213 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12214 {
12215 if (rc == 1)
12216 {
12217 /* Called from my_error_exit. Display a JPEG error. */
12218 char buffer[JMSG_LENGTH_MAX];
12219 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12220 image_error ("Error reading JPEG image `%s': %s", img->spec,
12221 build_string (buffer));
12222 }
12223
12224 /* Close the input file and destroy the JPEG object. */
12225 if (fp)
12226 fclose (fp);
12227 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
12228
12229 /* If we already have an XImage, free that. */
12230 x_destroy_x_image (ximg);
12231
12232 /* Free pixmap and colors. */
12233 x_clear_image (f, img);
12234
6fc2811b
JR
12235 UNGCPRO;
12236 return 0;
12237 }
12238
12239 /* Create the JPEG decompression object. Let it read from fp.
12240 Read the JPEG image header. */
12241 jpeg_create_decompress (&cinfo);
12242
12243 if (NILP (specified_data))
12244 jpeg_stdio_src (&cinfo, fp);
12245 else
12246 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12247 STRING_BYTES (XSTRING (specified_data)));
12248
12249 jpeg_read_header (&cinfo, TRUE);
12250
12251 /* Customize decompression so that color quantization will be used.
12252 Start decompression. */
12253 cinfo.quantize_colors = TRUE;
12254 jpeg_start_decompress (&cinfo);
12255 width = img->width = cinfo.output_width;
12256 height = img->height = cinfo.output_height;
12257
6fc2811b
JR
12258 /* Create X image and pixmap. */
12259 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12260 &img->pixmap))
a05e2bae 12261 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
12262
12263 /* Allocate colors. When color quantization is used,
12264 cinfo.actual_number_of_colors has been set with the number of
12265 colors generated, and cinfo.colormap is a two-dimensional array
12266 of color indices in the range 0..cinfo.actual_number_of_colors.
12267 No more than 255 colors will be generated. */
12268 {
12269 int i, ir, ig, ib;
12270
12271 if (cinfo.out_color_components > 2)
12272 ir = 0, ig = 1, ib = 2;
12273 else if (cinfo.out_color_components > 1)
12274 ir = 0, ig = 1, ib = 0;
12275 else
12276 ir = 0, ig = 0, ib = 0;
12277
12278 /* Use the color table mechanism because it handles colors that
12279 cannot be allocated nicely. Such colors will be replaced with
12280 a default color, and we don't have to care about which colors
12281 can be freed safely, and which can't. */
12282 init_color_table ();
12283 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12284 * sizeof *colors);
12285
12286 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12287 {
12288 /* Multiply RGB values with 255 because X expects RGB values
12289 in the range 0..0xffff. */
12290 int r = cinfo.colormap[ir][i] << 8;
12291 int g = cinfo.colormap[ig][i] << 8;
12292 int b = cinfo.colormap[ib][i] << 8;
12293 colors[i] = lookup_rgb_color (f, r, g, b);
12294 }
12295
12296 /* Remember those colors actually allocated. */
12297 img->colors = colors_in_color_table (&img->ncolors);
12298 free_color_table ();
12299 }
12300
12301 /* Read pixels. */
12302 row_stride = width * cinfo.output_components;
12303 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12304 row_stride, 1);
12305 for (y = 0; y < height; ++y)
12306 {
12307 jpeg_read_scanlines (&cinfo, buffer, 1);
12308 for (x = 0; x < cinfo.output_width; ++x)
12309 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12310 }
12311
12312 /* Clean up. */
12313 jpeg_finish_decompress (&cinfo);
12314 jpeg_destroy_decompress (&cinfo);
12315 if (fp)
12316 fclose (fp);
12317
a05e2bae
JR
12318 /* Maybe fill in the background field while we have ximg handy. */
12319 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12320 IMAGE_BACKGROUND (img, f, ximg);
12321
6fc2811b
JR
12322 /* Put the image into the pixmap. */
12323 x_put_x_image (f, ximg, img->pixmap, width, height);
12324 x_destroy_x_image (ximg);
12325 UNBLOCK_INPUT;
12326 UNGCPRO;
12327 return 1;
12328}
12329
12330#endif /* HAVE_JPEG */
12331
12332
12333\f
12334/***********************************************************************
12335 TIFF
12336 ***********************************************************************/
12337
12338#if HAVE_TIFF
12339
12340#include <tiffio.h>
12341
12342static int tiff_image_p P_ ((Lisp_Object object));
12343static int tiff_load P_ ((struct frame *f, struct image *img));
12344
12345/* The symbol `tiff' identifying images of this type. */
12346
12347Lisp_Object Qtiff;
12348
12349/* Indices of image specification fields in tiff_format, below. */
12350
12351enum tiff_keyword_index
12352{
12353 TIFF_TYPE,
12354 TIFF_DATA,
12355 TIFF_FILE,
12356 TIFF_ASCENT,
12357 TIFF_MARGIN,
12358 TIFF_RELIEF,
12359 TIFF_ALGORITHM,
12360 TIFF_HEURISTIC_MASK,
a05e2bae
JR
12361 TIFF_MASK,
12362 TIFF_BACKGROUND,
6fc2811b
JR
12363 TIFF_LAST
12364};
12365
12366/* Vector of image_keyword structures describing the format
12367 of valid user-defined image specifications. */
12368
12369static struct image_keyword tiff_format[TIFF_LAST] =
12370{
12371 {":type", IMAGE_SYMBOL_VALUE, 1},
12372 {":data", IMAGE_STRING_VALUE, 0},
12373 {":file", IMAGE_STRING_VALUE, 0},
12374 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12375 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12376 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12377 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12378 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12379 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12380 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12381};
12382
12383/* Structure describing the image type `tiff'. */
12384
12385static struct image_type tiff_type =
12386{
12387 &Qtiff,
12388 tiff_image_p,
12389 tiff_load,
12390 x_clear_image,
12391 NULL
12392};
12393
12394
12395/* Return non-zero if OBJECT is a valid TIFF image specification. */
12396
12397static int
12398tiff_image_p (object)
12399 Lisp_Object object;
12400{
12401 struct image_keyword fmt[TIFF_LAST];
12402 bcopy (tiff_format, fmt, sizeof fmt);
12403
12404 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12405 || (fmt[TIFF_ASCENT].count
12406 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12407 return 0;
12408
12409 /* Must specify either the :data or :file keyword. */
12410 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12411}
12412
12413
12414/* Reading from a memory buffer for TIFF images Based on the PNG
12415 memory source, but we have to provide a lot of extra functions.
12416 Blah.
12417
12418 We really only need to implement read and seek, but I am not
12419 convinced that the TIFF library is smart enough not to destroy
12420 itself if we only hand it the function pointers we need to
12421 override. */
12422
12423typedef struct
12424{
12425 unsigned char *bytes;
12426 size_t len;
12427 int index;
12428}
12429tiff_memory_source;
12430
12431static size_t
12432tiff_read_from_memory (data, buf, size)
12433 thandle_t data;
12434 tdata_t buf;
12435 tsize_t size;
12436{
12437 tiff_memory_source *src = (tiff_memory_source *) data;
12438
12439 if (size > src->len - src->index)
12440 return (size_t) -1;
12441 bcopy (src->bytes + src->index, buf, size);
12442 src->index += size;
12443 return size;
12444}
12445
12446static size_t
12447tiff_write_from_memory (data, buf, size)
12448 thandle_t data;
12449 tdata_t buf;
12450 tsize_t size;
12451{
12452 return (size_t) -1;
12453}
12454
12455static toff_t
12456tiff_seek_in_memory (data, off, whence)
12457 thandle_t data;
12458 toff_t off;
12459 int whence;
12460{
12461 tiff_memory_source *src = (tiff_memory_source *) data;
12462 int idx;
12463
12464 switch (whence)
12465 {
12466 case SEEK_SET: /* Go from beginning of source. */
12467 idx = off;
12468 break;
12469
12470 case SEEK_END: /* Go from end of source. */
12471 idx = src->len + off;
12472 break;
12473
12474 case SEEK_CUR: /* Go from current position. */
12475 idx = src->index + off;
12476 break;
12477
12478 default: /* Invalid `whence'. */
12479 return -1;
12480 }
12481
12482 if (idx > src->len || idx < 0)
12483 return -1;
12484
12485 src->index = idx;
12486 return src->index;
12487}
12488
12489static int
12490tiff_close_memory (data)
12491 thandle_t data;
12492{
12493 /* NOOP */
12494 return 0;
12495}
12496
12497static int
12498tiff_mmap_memory (data, pbase, psize)
12499 thandle_t data;
12500 tdata_t *pbase;
12501 toff_t *psize;
12502{
12503 /* It is already _IN_ memory. */
12504 return 0;
12505}
12506
12507static void
12508tiff_unmap_memory (data, base, size)
12509 thandle_t data;
12510 tdata_t base;
12511 toff_t size;
12512{
12513 /* We don't need to do this. */
12514}
12515
12516static toff_t
12517tiff_size_of_memory (data)
12518 thandle_t data;
12519{
12520 return ((tiff_memory_source *) data)->len;
12521}
12522
3cf3436e
JR
12523
12524static void
12525tiff_error_handler (title, format, ap)
12526 const char *title, *format;
12527 va_list ap;
12528{
12529 char buf[512];
12530 int len;
12531
12532 len = sprintf (buf, "TIFF error: %s ", title);
12533 vsprintf (buf + len, format, ap);
12534 add_to_log (buf, Qnil, Qnil);
12535}
12536
12537
12538static void
12539tiff_warning_handler (title, format, ap)
12540 const char *title, *format;
12541 va_list ap;
12542{
12543 char buf[512];
12544 int len;
12545
12546 len = sprintf (buf, "TIFF warning: %s ", title);
12547 vsprintf (buf + len, format, ap);
12548 add_to_log (buf, Qnil, Qnil);
12549}
12550
12551
6fc2811b
JR
12552/* Load TIFF image IMG for use on frame F. Value is non-zero if
12553 successful. */
12554
12555static int
12556tiff_load (f, img)
12557 struct frame *f;
12558 struct image *img;
12559{
12560 Lisp_Object file, specified_file;
12561 Lisp_Object specified_data;
12562 TIFF *tiff;
12563 int width, height, x, y;
12564 uint32 *buf;
12565 int rc;
12566 XImage *ximg;
12567 struct gcpro gcpro1;
12568 tiff_memory_source memsrc;
12569
12570 specified_file = image_spec_value (img->spec, QCfile, NULL);
12571 specified_data = image_spec_value (img->spec, QCdata, NULL);
12572 file = Qnil;
12573 GCPRO1 (file);
12574
3cf3436e
JR
12575 TIFFSetErrorHandler (tiff_error_handler);
12576 TIFFSetWarningHandler (tiff_warning_handler);
12577
6fc2811b
JR
12578 if (NILP (specified_data))
12579 {
12580 /* Read from a file */
12581 file = x_find_image_file (specified_file);
12582 if (!STRINGP (file))
3cf3436e
JR
12583 {
12584 image_error ("Cannot find image file `%s'", file, Qnil);
12585 UNGCPRO;
12586 return 0;
12587 }
12588
6fc2811b
JR
12589 /* Try to open the image file. */
12590 tiff = TIFFOpen (XSTRING (file)->data, "r");
12591 if (tiff == NULL)
3cf3436e
JR
12592 {
12593 image_error ("Cannot open `%s'", file, Qnil);
12594 UNGCPRO;
12595 return 0;
12596 }
6fc2811b
JR
12597 }
12598 else
12599 {
12600 /* Memory source! */
12601 memsrc.bytes = XSTRING (specified_data)->data;
12602 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12603 memsrc.index = 0;
12604
12605 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12606 (TIFFReadWriteProc) tiff_read_from_memory,
12607 (TIFFReadWriteProc) tiff_write_from_memory,
12608 tiff_seek_in_memory,
12609 tiff_close_memory,
12610 tiff_size_of_memory,
12611 tiff_mmap_memory,
12612 tiff_unmap_memory);
12613
12614 if (!tiff)
12615 {
12616 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12617 UNGCPRO;
12618 return 0;
12619 }
12620 }
12621
12622 /* Get width and height of the image, and allocate a raster buffer
12623 of width x height 32-bit values. */
12624 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12625 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12626 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12627
12628 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12629 TIFFClose (tiff);
12630 if (!rc)
12631 {
12632 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12633 xfree (buf);
12634 UNGCPRO;
12635 return 0;
12636 }
12637
6fc2811b
JR
12638 /* Create the X image and pixmap. */
12639 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12640 {
6fc2811b
JR
12641 xfree (buf);
12642 UNGCPRO;
12643 return 0;
12644 }
12645
12646 /* Initialize the color table. */
12647 init_color_table ();
12648
12649 /* Process the pixel raster. Origin is in the lower-left corner. */
12650 for (y = 0; y < height; ++y)
12651 {
12652 uint32 *row = buf + y * width;
12653
12654 for (x = 0; x < width; ++x)
12655 {
12656 uint32 abgr = row[x];
12657 int r = TIFFGetR (abgr) << 8;
12658 int g = TIFFGetG (abgr) << 8;
12659 int b = TIFFGetB (abgr) << 8;
12660 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12661 }
12662 }
12663
12664 /* Remember the colors allocated for the image. Free the color table. */
12665 img->colors = colors_in_color_table (&img->ncolors);
12666 free_color_table ();
12667
a05e2bae
JR
12668 img->width = width;
12669 img->height = height;
12670
12671 /* Maybe fill in the background field while we have ximg handy. */
12672 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12673 IMAGE_BACKGROUND (img, f, ximg);
12674
6fc2811b
JR
12675 /* Put the image into the pixmap, then free the X image and its buffer. */
12676 x_put_x_image (f, ximg, img->pixmap, width, height);
12677 x_destroy_x_image (ximg);
12678 xfree (buf);
6fc2811b
JR
12679
12680 UNGCPRO;
12681 return 1;
12682}
12683
12684#endif /* HAVE_TIFF != 0 */
12685
12686
12687\f
12688/***********************************************************************
12689 GIF
12690 ***********************************************************************/
12691
12692#if HAVE_GIF
12693
12694#include <gif_lib.h>
12695
12696static int gif_image_p P_ ((Lisp_Object object));
12697static int gif_load P_ ((struct frame *f, struct image *img));
12698
12699/* The symbol `gif' identifying images of this type. */
12700
12701Lisp_Object Qgif;
12702
12703/* Indices of image specification fields in gif_format, below. */
12704
12705enum gif_keyword_index
12706{
12707 GIF_TYPE,
12708 GIF_DATA,
12709 GIF_FILE,
12710 GIF_ASCENT,
12711 GIF_MARGIN,
12712 GIF_RELIEF,
12713 GIF_ALGORITHM,
12714 GIF_HEURISTIC_MASK,
a05e2bae 12715 GIF_MASK,
6fc2811b 12716 GIF_IMAGE,
a05e2bae 12717 GIF_BACKGROUND,
6fc2811b
JR
12718 GIF_LAST
12719};
12720
12721/* Vector of image_keyword structures describing the format
12722 of valid user-defined image specifications. */
12723
12724static struct image_keyword gif_format[GIF_LAST] =
12725{
12726 {":type", IMAGE_SYMBOL_VALUE, 1},
12727 {":data", IMAGE_STRING_VALUE, 0},
12728 {":file", IMAGE_STRING_VALUE, 0},
12729 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12730 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12731 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12732 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12733 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12734 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12735 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12736 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12737};
12738
12739/* Structure describing the image type `gif'. */
12740
12741static struct image_type gif_type =
12742{
12743 &Qgif,
12744 gif_image_p,
12745 gif_load,
12746 x_clear_image,
12747 NULL
12748};
12749
12750/* Return non-zero if OBJECT is a valid GIF image specification. */
12751
12752static int
12753gif_image_p (object)
12754 Lisp_Object object;
12755{
12756 struct image_keyword fmt[GIF_LAST];
12757 bcopy (gif_format, fmt, sizeof fmt);
12758
12759 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12760 || (fmt[GIF_ASCENT].count
12761 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12762 return 0;
12763
12764 /* Must specify either the :data or :file keyword. */
12765 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12766}
12767
12768/* Reading a GIF image from memory
12769 Based on the PNG memory stuff to a certain extent. */
12770
12771typedef struct
12772{
12773 unsigned char *bytes;
12774 size_t len;
12775 int index;
12776}
12777gif_memory_source;
12778
12779/* Make the current memory source available to gif_read_from_memory.
12780 It's done this way because not all versions of libungif support
12781 a UserData field in the GifFileType structure. */
12782static gif_memory_source *current_gif_memory_src;
12783
12784static int
12785gif_read_from_memory (file, buf, len)
12786 GifFileType *file;
12787 GifByteType *buf;
12788 int len;
12789{
12790 gif_memory_source *src = current_gif_memory_src;
12791
12792 if (len > src->len - src->index)
12793 return -1;
12794
12795 bcopy (src->bytes + src->index, buf, len);
12796 src->index += len;
12797 return len;
12798}
12799
12800
12801/* Load GIF image IMG for use on frame F. Value is non-zero if
12802 successful. */
12803
12804static int
12805gif_load (f, img)
12806 struct frame *f;
12807 struct image *img;
12808{
12809 Lisp_Object file, specified_file;
12810 Lisp_Object specified_data;
12811 int rc, width, height, x, y, i;
12812 XImage *ximg;
12813 ColorMapObject *gif_color_map;
12814 unsigned long pixel_colors[256];
12815 GifFileType *gif;
12816 struct gcpro gcpro1;
12817 Lisp_Object image;
12818 int ino, image_left, image_top, image_width, image_height;
12819 gif_memory_source memsrc;
12820 unsigned char *raster;
12821
12822 specified_file = image_spec_value (img->spec, QCfile, NULL);
12823 specified_data = image_spec_value (img->spec, QCdata, NULL);
12824 file = Qnil;
dfff8a69 12825 GCPRO1 (file);
6fc2811b
JR
12826
12827 if (NILP (specified_data))
12828 {
12829 file = x_find_image_file (specified_file);
6fc2811b
JR
12830 if (!STRINGP (file))
12831 {
12832 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12833 UNGCPRO;
12834 return 0;
12835 }
12836
12837 /* Open the GIF file. */
12838 gif = DGifOpenFileName (XSTRING (file)->data);
12839 if (gif == NULL)
12840 {
12841 image_error ("Cannot open `%s'", file, Qnil);
12842 UNGCPRO;
12843 return 0;
12844 }
12845 }
12846 else
12847 {
12848 /* Read from memory! */
12849 current_gif_memory_src = &memsrc;
12850 memsrc.bytes = XSTRING (specified_data)->data;
12851 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12852 memsrc.index = 0;
12853
12854 gif = DGifOpen(&memsrc, gif_read_from_memory);
12855 if (!gif)
12856 {
12857 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12858 UNGCPRO;
12859 return 0;
12860 }
12861 }
12862
12863 /* Read entire contents. */
12864 rc = DGifSlurp (gif);
12865 if (rc == GIF_ERROR)
12866 {
12867 image_error ("Error reading `%s'", img->spec, Qnil);
12868 DGifCloseFile (gif);
12869 UNGCPRO;
12870 return 0;
12871 }
12872
12873 image = image_spec_value (img->spec, QCindex, NULL);
12874 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12875 if (ino >= gif->ImageCount)
12876 {
12877 image_error ("Invalid image number `%s' in image `%s'",
12878 image, img->spec);
12879 DGifCloseFile (gif);
12880 UNGCPRO;
12881 return 0;
12882 }
12883
12884 width = img->width = gif->SWidth;
12885 height = img->height = gif->SHeight;
12886
6fc2811b
JR
12887 /* Create the X image and pixmap. */
12888 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12889 {
6fc2811b
JR
12890 DGifCloseFile (gif);
12891 UNGCPRO;
12892 return 0;
12893 }
12894
12895 /* Allocate colors. */
12896 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12897 if (!gif_color_map)
12898 gif_color_map = gif->SColorMap;
12899 init_color_table ();
12900 bzero (pixel_colors, sizeof pixel_colors);
12901
12902 for (i = 0; i < gif_color_map->ColorCount; ++i)
12903 {
12904 int r = gif_color_map->Colors[i].Red << 8;
12905 int g = gif_color_map->Colors[i].Green << 8;
12906 int b = gif_color_map->Colors[i].Blue << 8;
12907 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12908 }
12909
12910 img->colors = colors_in_color_table (&img->ncolors);
12911 free_color_table ();
12912
12913 /* Clear the part of the screen image that are not covered by
12914 the image from the GIF file. Full animated GIF support
12915 requires more than can be done here (see the gif89 spec,
12916 disposal methods). Let's simply assume that the part
12917 not covered by a sub-image is in the frame's background color. */
12918 image_top = gif->SavedImages[ino].ImageDesc.Top;
12919 image_left = gif->SavedImages[ino].ImageDesc.Left;
12920 image_width = gif->SavedImages[ino].ImageDesc.Width;
12921 image_height = gif->SavedImages[ino].ImageDesc.Height;
12922
12923 for (y = 0; y < image_top; ++y)
12924 for (x = 0; x < width; ++x)
12925 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12926
12927 for (y = image_top + image_height; y < height; ++y)
12928 for (x = 0; x < width; ++x)
12929 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12930
12931 for (y = image_top; y < image_top + image_height; ++y)
12932 {
12933 for (x = 0; x < image_left; ++x)
12934 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12935 for (x = image_left + image_width; x < width; ++x)
12936 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12937 }
12938
12939 /* Read the GIF image into the X image. We use a local variable
12940 `raster' here because RasterBits below is a char *, and invites
12941 problems with bytes >= 0x80. */
12942 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12943
12944 if (gif->SavedImages[ino].ImageDesc.Interlace)
12945 {
12946 static int interlace_start[] = {0, 4, 2, 1};
12947 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12948 int pass;
6fc2811b
JR
12949 int row = interlace_start[0];
12950
12951 pass = 0;
12952
12953 for (y = 0; y < image_height; y++)
12954 {
12955 if (row >= image_height)
12956 {
12957 row = interlace_start[++pass];
12958 while (row >= image_height)
12959 row = interlace_start[++pass];
12960 }
12961
12962 for (x = 0; x < image_width; x++)
12963 {
12964 int i = raster[(y * image_width) + x];
12965 XPutPixel (ximg, x + image_left, row + image_top,
12966 pixel_colors[i]);
12967 }
12968
12969 row += interlace_increment[pass];
12970 }
12971 }
12972 else
12973 {
12974 for (y = 0; y < image_height; ++y)
12975 for (x = 0; x < image_width; ++x)
12976 {
12977 int i = raster[y* image_width + x];
12978 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12979 }
12980 }
12981
12982 DGifCloseFile (gif);
a05e2bae
JR
12983
12984 /* Maybe fill in the background field while we have ximg handy. */
12985 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12986 IMAGE_BACKGROUND (img, f, ximg);
12987
6fc2811b
JR
12988 /* Put the image into the pixmap, then free the X image and its buffer. */
12989 x_put_x_image (f, ximg, img->pixmap, width, height);
12990 x_destroy_x_image (ximg);
6fc2811b
JR
12991
12992 UNGCPRO;
12993 return 1;
12994}
12995
12996#endif /* HAVE_GIF != 0 */
12997
12998
12999\f
13000/***********************************************************************
13001 Ghostscript
13002 ***********************************************************************/
13003
3cf3436e
JR
13004Lisp_Object Qpostscript;
13005
6fc2811b
JR
13006#ifdef HAVE_GHOSTSCRIPT
13007static int gs_image_p P_ ((Lisp_Object object));
13008static int gs_load P_ ((struct frame *f, struct image *img));
13009static void gs_clear_image P_ ((struct frame *f, struct image *img));
13010
13011/* The symbol `postscript' identifying images of this type. */
13012
6fc2811b
JR
13013/* Keyword symbols. */
13014
13015Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
13016
13017/* Indices of image specification fields in gs_format, below. */
13018
13019enum gs_keyword_index
13020{
13021 GS_TYPE,
13022 GS_PT_WIDTH,
13023 GS_PT_HEIGHT,
13024 GS_FILE,
13025 GS_LOADER,
13026 GS_BOUNDING_BOX,
13027 GS_ASCENT,
13028 GS_MARGIN,
13029 GS_RELIEF,
13030 GS_ALGORITHM,
13031 GS_HEURISTIC_MASK,
a05e2bae
JR
13032 GS_MASK,
13033 GS_BACKGROUND,
6fc2811b
JR
13034 GS_LAST
13035};
13036
13037/* Vector of image_keyword structures describing the format
13038 of valid user-defined image specifications. */
13039
13040static struct image_keyword gs_format[GS_LAST] =
13041{
13042 {":type", IMAGE_SYMBOL_VALUE, 1},
13043 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13044 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13045 {":file", IMAGE_STRING_VALUE, 1},
13046 {":loader", IMAGE_FUNCTION_VALUE, 0},
13047 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
13048 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 13049 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 13050 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 13051 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
13052 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13053 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13054 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
13055};
13056
13057/* Structure describing the image type `ghostscript'. */
13058
13059static struct image_type gs_type =
13060{
13061 &Qpostscript,
13062 gs_image_p,
13063 gs_load,
13064 gs_clear_image,
13065 NULL
13066};
13067
13068
13069/* Free X resources of Ghostscript image IMG which is used on frame F. */
13070
13071static void
13072gs_clear_image (f, img)
13073 struct frame *f;
13074 struct image *img;
13075{
13076 /* IMG->data.ptr_val may contain a recorded colormap. */
13077 xfree (img->data.ptr_val);
13078 x_clear_image (f, img);
13079}
13080
13081
13082/* Return non-zero if OBJECT is a valid Ghostscript image
13083 specification. */
13084
13085static int
13086gs_image_p (object)
13087 Lisp_Object object;
13088{
13089 struct image_keyword fmt[GS_LAST];
13090 Lisp_Object tem;
13091 int i;
13092
13093 bcopy (gs_format, fmt, sizeof fmt);
13094
13095 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
13096 || (fmt[GS_ASCENT].count
13097 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13098 return 0;
13099
13100 /* Bounding box must be a list or vector containing 4 integers. */
13101 tem = fmt[GS_BOUNDING_BOX].value;
13102 if (CONSP (tem))
13103 {
13104 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13105 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13106 return 0;
13107 if (!NILP (tem))
13108 return 0;
13109 }
13110 else if (VECTORP (tem))
13111 {
13112 if (XVECTOR (tem)->size != 4)
13113 return 0;
13114 for (i = 0; i < 4; ++i)
13115 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13116 return 0;
13117 }
13118 else
13119 return 0;
13120
13121 return 1;
13122}
13123
13124
13125/* Load Ghostscript image IMG for use on frame F. Value is non-zero
13126 if successful. */
13127
13128static int
13129gs_load (f, img)
13130 struct frame *f;
13131 struct image *img;
13132{
13133 char buffer[100];
13134 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13135 struct gcpro gcpro1, gcpro2;
13136 Lisp_Object frame;
13137 double in_width, in_height;
13138 Lisp_Object pixel_colors = Qnil;
13139
13140 /* Compute pixel size of pixmap needed from the given size in the
13141 image specification. Sizes in the specification are in pt. 1 pt
13142 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13143 info. */
13144 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13145 in_width = XFASTINT (pt_width) / 72.0;
13146 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13147 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13148 in_height = XFASTINT (pt_height) / 72.0;
13149 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13150
13151 /* Create the pixmap. */
13152 BLOCK_INPUT;
13153 xassert (img->pixmap == 0);
13154 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13155 img->width, img->height,
a05e2bae 13156 one_w32_display_info.n_cbits);
6fc2811b
JR
13157 UNBLOCK_INPUT;
13158
13159 if (!img->pixmap)
13160 {
13161 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13162 return 0;
13163 }
13164
13165 /* Call the loader to fill the pixmap. It returns a process object
13166 if successful. We do not record_unwind_protect here because
13167 other places in redisplay like calling window scroll functions
13168 don't either. Let the Lisp loader use `unwind-protect' instead. */
13169 GCPRO2 (window_and_pixmap_id, pixel_colors);
13170
13171 sprintf (buffer, "%lu %lu",
13172 (unsigned long) FRAME_W32_WINDOW (f),
13173 (unsigned long) img->pixmap);
13174 window_and_pixmap_id = build_string (buffer);
13175
13176 sprintf (buffer, "%lu %lu",
13177 FRAME_FOREGROUND_PIXEL (f),
13178 FRAME_BACKGROUND_PIXEL (f));
13179 pixel_colors = build_string (buffer);
13180
13181 XSETFRAME (frame, f);
13182 loader = image_spec_value (img->spec, QCloader, NULL);
13183 if (NILP (loader))
13184 loader = intern ("gs-load-image");
13185
13186 img->data.lisp_val = call6 (loader, frame, img->spec,
13187 make_number (img->width),
13188 make_number (img->height),
13189 window_and_pixmap_id,
13190 pixel_colors);
13191 UNGCPRO;
13192 return PROCESSP (img->data.lisp_val);
13193}
13194
13195
13196/* Kill the Ghostscript process that was started to fill PIXMAP on
13197 frame F. Called from XTread_socket when receiving an event
13198 telling Emacs that Ghostscript has finished drawing. */
13199
13200void
13201x_kill_gs_process (pixmap, f)
13202 Pixmap pixmap;
13203 struct frame *f;
13204{
13205 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13206 int class, i;
13207 struct image *img;
13208
13209 /* Find the image containing PIXMAP. */
13210 for (i = 0; i < c->used; ++i)
13211 if (c->images[i]->pixmap == pixmap)
13212 break;
13213
3cf3436e
JR
13214 /* Should someone in between have cleared the image cache, for
13215 instance, give up. */
13216 if (i == c->used)
13217 return;
13218
6fc2811b
JR
13219 /* Kill the GS process. We should have found PIXMAP in the image
13220 cache and its image should contain a process object. */
6fc2811b
JR
13221 img = c->images[i];
13222 xassert (PROCESSP (img->data.lisp_val));
13223 Fkill_process (img->data.lisp_val, Qnil);
13224 img->data.lisp_val = Qnil;
13225
13226 /* On displays with a mutable colormap, figure out the colors
13227 allocated for the image by looking at the pixels of an XImage for
13228 img->pixmap. */
13229 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13230 if (class != StaticColor && class != StaticGray && class != TrueColor)
13231 {
13232 XImage *ximg;
13233
13234 BLOCK_INPUT;
13235
13236 /* Try to get an XImage for img->pixmep. */
13237 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13238 0, 0, img->width, img->height, ~0, ZPixmap);
13239 if (ximg)
13240 {
13241 int x, y;
13242
13243 /* Initialize the color table. */
13244 init_color_table ();
13245
13246 /* For each pixel of the image, look its color up in the
13247 color table. After having done so, the color table will
13248 contain an entry for each color used by the image. */
13249 for (y = 0; y < img->height; ++y)
13250 for (x = 0; x < img->width; ++x)
13251 {
13252 unsigned long pixel = XGetPixel (ximg, x, y);
13253 lookup_pixel_color (f, pixel);
13254 }
13255
13256 /* Record colors in the image. Free color table and XImage. */
13257 img->colors = colors_in_color_table (&img->ncolors);
13258 free_color_table ();
13259 XDestroyImage (ximg);
13260
13261#if 0 /* This doesn't seem to be the case. If we free the colors
13262 here, we get a BadAccess later in x_clear_image when
13263 freeing the colors. */
13264 /* We have allocated colors once, but Ghostscript has also
13265 allocated colors on behalf of us. So, to get the
13266 reference counts right, free them once. */
13267 if (img->ncolors)
3cf3436e 13268 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 13269 img->colors, img->ncolors, 0);
6fc2811b
JR
13270#endif
13271 }
13272 else
13273 image_error ("Cannot get X image of `%s'; colors will not be freed",
13274 img->spec, Qnil);
13275
13276 UNBLOCK_INPUT;
13277 }
3cf3436e
JR
13278
13279 /* Now that we have the pixmap, compute mask and transform the
13280 image if requested. */
13281 BLOCK_INPUT;
13282 postprocess_image (f, img);
13283 UNBLOCK_INPUT;
6fc2811b
JR
13284}
13285
13286#endif /* HAVE_GHOSTSCRIPT */
13287
13288\f
13289/***********************************************************************
13290 Window properties
13291 ***********************************************************************/
13292
13293DEFUN ("x-change-window-property", Fx_change_window_property,
13294 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
13295 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13296PROP and VALUE must be strings. FRAME nil or omitted means use the
13297selected frame. Value is VALUE. */)
6fc2811b
JR
13298 (prop, value, frame)
13299 Lisp_Object frame, prop, value;
13300{
767b1ff0 13301#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13302 struct frame *f = check_x_frame (frame);
13303 Atom prop_atom;
13304
b7826503
PJ
13305 CHECK_STRING (prop);
13306 CHECK_STRING (value);
6fc2811b
JR
13307
13308 BLOCK_INPUT;
13309 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13310 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13311 prop_atom, XA_STRING, 8, PropModeReplace,
13312 XSTRING (value)->data, XSTRING (value)->size);
13313
13314 /* Make sure the property is set when we return. */
13315 XFlush (FRAME_W32_DISPLAY (f));
13316 UNBLOCK_INPUT;
13317
767b1ff0 13318#endif /* TODO */
6fc2811b
JR
13319
13320 return value;
13321}
13322
13323
13324DEFUN ("x-delete-window-property", Fx_delete_window_property,
13325 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
13326 doc: /* Remove window property PROP from X window of FRAME.
13327FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
13328 (prop, frame)
13329 Lisp_Object prop, frame;
13330{
767b1ff0 13331#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13332
13333 struct frame *f = check_x_frame (frame);
13334 Atom prop_atom;
13335
b7826503 13336 CHECK_STRING (prop);
6fc2811b
JR
13337 BLOCK_INPUT;
13338 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13339 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13340
13341 /* Make sure the property is removed when we return. */
13342 XFlush (FRAME_W32_DISPLAY (f));
13343 UNBLOCK_INPUT;
767b1ff0 13344#endif /* TODO */
6fc2811b
JR
13345
13346 return prop;
13347}
13348
13349
13350DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13351 1, 2, 0,
74e1aeec
JR
13352 doc: /* Value is the value of window property PROP on FRAME.
13353If FRAME is nil or omitted, use the selected frame. Value is nil
13354if FRAME hasn't a property with name PROP or if PROP has no string
13355value. */)
6fc2811b
JR
13356 (prop, frame)
13357 Lisp_Object prop, frame;
13358{
767b1ff0 13359#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13360
13361 struct frame *f = check_x_frame (frame);
13362 Atom prop_atom;
13363 int rc;
13364 Lisp_Object prop_value = Qnil;
13365 char *tmp_data = NULL;
13366 Atom actual_type;
13367 int actual_format;
13368 unsigned long actual_size, bytes_remaining;
13369
b7826503 13370 CHECK_STRING (prop);
6fc2811b
JR
13371 BLOCK_INPUT;
13372 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13373 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13374 prop_atom, 0, 0, False, XA_STRING,
13375 &actual_type, &actual_format, &actual_size,
13376 &bytes_remaining, (unsigned char **) &tmp_data);
13377 if (rc == Success)
13378 {
13379 int size = bytes_remaining;
13380
13381 XFree (tmp_data);
13382 tmp_data = NULL;
13383
13384 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13385 prop_atom, 0, bytes_remaining,
13386 False, XA_STRING,
13387 &actual_type, &actual_format,
13388 &actual_size, &bytes_remaining,
13389 (unsigned char **) &tmp_data);
13390 if (rc == Success)
13391 prop_value = make_string (tmp_data, size);
13392
13393 XFree (tmp_data);
13394 }
13395
13396 UNBLOCK_INPUT;
13397
13398 return prop_value;
13399
767b1ff0 13400#endif /* TODO */
6fc2811b
JR
13401 return Qnil;
13402}
13403
13404
13405\f
13406/***********************************************************************
13407 Busy cursor
13408 ***********************************************************************/
13409
f79e6790 13410/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 13411 an hourglass cursor on all frames. */
6fc2811b 13412
0af913d7 13413static struct atimer *hourglass_atimer;
6fc2811b 13414
0af913d7 13415/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 13416
0af913d7 13417static int hourglass_shown_p;
6fc2811b 13418
0af913d7 13419/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 13420
0af913d7 13421static Lisp_Object Vhourglass_delay;
6fc2811b 13422
0af913d7 13423/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
13424 cursor. */
13425
0af913d7 13426#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
13427
13428/* Function prototypes. */
13429
0af913d7
GM
13430static void show_hourglass P_ ((struct atimer *));
13431static void hide_hourglass P_ ((void));
f79e6790
JR
13432
13433
0af913d7 13434/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
13435
13436void
0af913d7 13437start_hourglass ()
f79e6790 13438{
767b1ff0 13439#if 0 /* TODO: cursor shape changes. */
f79e6790 13440 EMACS_TIME delay;
dfff8a69 13441 int secs, usecs = 0;
f79e6790 13442
0af913d7 13443 cancel_hourglass ();
f79e6790 13444
0af913d7
GM
13445 if (INTEGERP (Vhourglass_delay)
13446 && XINT (Vhourglass_delay) > 0)
13447 secs = XFASTINT (Vhourglass_delay);
13448 else if (FLOATP (Vhourglass_delay)
13449 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
13450 {
13451 Lisp_Object tem;
0af913d7 13452 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 13453 secs = XFASTINT (tem);
0af913d7 13454 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 13455 }
f79e6790 13456 else
0af913d7 13457 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 13458
dfff8a69 13459 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
13460 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13461 show_hourglass, NULL);
f79e6790
JR
13462#endif
13463}
13464
13465
0af913d7
GM
13466/* Cancel the hourglass cursor timer if active, hide an hourglass
13467 cursor if shown. */
f79e6790
JR
13468
13469void
0af913d7 13470cancel_hourglass ()
f79e6790 13471{
0af913d7 13472 if (hourglass_atimer)
dfff8a69 13473 {
0af913d7
GM
13474 cancel_atimer (hourglass_atimer);
13475 hourglass_atimer = NULL;
dfff8a69
JR
13476 }
13477
0af913d7
GM
13478 if (hourglass_shown_p)
13479 hide_hourglass ();
f79e6790
JR
13480}
13481
13482
0af913d7
GM
13483/* Timer function of hourglass_atimer. TIMER is equal to
13484 hourglass_atimer.
f79e6790 13485
0af913d7
GM
13486 Display an hourglass cursor on all frames by mapping the frames'
13487 hourglass_window. Set the hourglass_p flag in the frames'
13488 output_data.x structure to indicate that an hourglass cursor is
13489 shown on the frames. */
f79e6790
JR
13490
13491static void
0af913d7 13492show_hourglass (timer)
f79e6790 13493 struct atimer *timer;
6fc2811b 13494{
767b1ff0 13495#if 0 /* TODO: cursor shape changes. */
f79e6790 13496 /* The timer implementation will cancel this timer automatically
0af913d7 13497 after this function has run. Set hourglass_atimer to null
f79e6790 13498 so that we know the timer doesn't have to be canceled. */
0af913d7 13499 hourglass_atimer = NULL;
f79e6790 13500
0af913d7 13501 if (!hourglass_shown_p)
6fc2811b
JR
13502 {
13503 Lisp_Object rest, frame;
f79e6790
JR
13504
13505 BLOCK_INPUT;
13506
6fc2811b 13507 FOR_EACH_FRAME (rest, frame)
dc220243 13508 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13509 {
13510 struct frame *f = XFRAME (frame);
f79e6790 13511
0af913d7 13512 f->output_data.w32->hourglass_p = 1;
f79e6790 13513
0af913d7 13514 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13515 {
13516 unsigned long mask = CWCursor;
13517 XSetWindowAttributes attrs;
f79e6790 13518
0af913d7 13519 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13520
0af913d7 13521 f->output_data.w32->hourglass_window
f79e6790 13522 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13523 FRAME_OUTER_WINDOW (f),
13524 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13525 InputOnly,
13526 CopyFromParent,
6fc2811b
JR
13527 mask, &attrs);
13528 }
f79e6790 13529
0af913d7
GM
13530 XMapRaised (FRAME_X_DISPLAY (f),
13531 f->output_data.w32->hourglass_window);
f79e6790 13532 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13533 }
6fc2811b 13534
0af913d7 13535 hourglass_shown_p = 1;
f79e6790
JR
13536 UNBLOCK_INPUT;
13537 }
13538#endif
6fc2811b
JR
13539}
13540
13541
0af913d7 13542/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13543
f79e6790 13544static void
0af913d7 13545hide_hourglass ()
f79e6790 13546{
767b1ff0 13547#if 0 /* TODO: cursor shape changes. */
0af913d7 13548 if (hourglass_shown_p)
6fc2811b 13549 {
f79e6790
JR
13550 Lisp_Object rest, frame;
13551
13552 BLOCK_INPUT;
13553 FOR_EACH_FRAME (rest, frame)
6fc2811b 13554 {
f79e6790
JR
13555 struct frame *f = XFRAME (frame);
13556
dc220243 13557 if (FRAME_W32_P (f)
f79e6790 13558 /* Watch out for newly created frames. */
0af913d7 13559 && f->output_data.x->hourglass_window)
f79e6790 13560 {
0af913d7
GM
13561 XUnmapWindow (FRAME_X_DISPLAY (f),
13562 f->output_data.x->hourglass_window);
13563 /* Sync here because XTread_socket looks at the
13564 hourglass_p flag that is reset to zero below. */
f79e6790 13565 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13566 f->output_data.x->hourglass_p = 0;
f79e6790 13567 }
6fc2811b 13568 }
6fc2811b 13569
0af913d7 13570 hourglass_shown_p = 0;
f79e6790
JR
13571 UNBLOCK_INPUT;
13572 }
13573#endif
6fc2811b
JR
13574}
13575
13576
13577\f
13578/***********************************************************************
13579 Tool tips
13580 ***********************************************************************/
13581
13582static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13583 Lisp_Object, Lisp_Object));
13584static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13585 Lisp_Object, int, int, int *, int *));
6fc2811b 13586
3cf3436e 13587/* The frame of a currently visible tooltip. */
6fc2811b 13588
937e601e 13589Lisp_Object tip_frame;
6fc2811b
JR
13590
13591/* If non-nil, a timer started that hides the last tooltip when it
13592 fires. */
13593
13594Lisp_Object tip_timer;
13595Window tip_window;
13596
3cf3436e
JR
13597/* If non-nil, a vector of 3 elements containing the last args
13598 with which x-show-tip was called. See there. */
13599
13600Lisp_Object last_show_tip_args;
13601
13602/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13603
13604Lisp_Object Vx_max_tooltip_size;
13605
13606
937e601e
AI
13607static Lisp_Object
13608unwind_create_tip_frame (frame)
13609 Lisp_Object frame;
13610{
c844a81a
GM
13611 Lisp_Object deleted;
13612
13613 deleted = unwind_create_frame (frame);
13614 if (EQ (deleted, Qt))
13615 {
13616 tip_window = NULL;
13617 tip_frame = Qnil;
13618 }
13619
13620 return deleted;
937e601e
AI
13621}
13622
13623
6fc2811b 13624/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13625 PARMS is a list of frame parameters. TEXT is the string to
13626 display in the tip frame. Value is the frame.
937e601e
AI
13627
13628 Note that functions called here, esp. x_default_parameter can
13629 signal errors, for instance when a specified color name is
13630 undefined. We have to make sure that we're in a consistent state
13631 when this happens. */
6fc2811b
JR
13632
13633static Lisp_Object
3cf3436e 13634x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13635 struct w32_display_info *dpyinfo;
3cf3436e 13636 Lisp_Object parms, text;
6fc2811b 13637{
6fc2811b
JR
13638 struct frame *f;
13639 Lisp_Object frame, tem;
13640 Lisp_Object name;
13641 long window_prompting = 0;
13642 int width, height;
dc220243 13643 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13644 struct gcpro gcpro1, gcpro2, gcpro3;
13645 struct kboard *kb;
3cf3436e
JR
13646 int face_change_count_before = face_change_count;
13647 Lisp_Object buffer;
13648 struct buffer *old_buffer;
6fc2811b 13649
ca56d953 13650 check_w32 ();
6fc2811b
JR
13651
13652 /* Use this general default value to start with until we know if
13653 this frame has a specified name. */
13654 Vx_resource_name = Vinvocation_name;
13655
13656#ifdef MULTI_KBOARD
13657 kb = dpyinfo->kboard;
13658#else
13659 kb = &the_only_kboard;
13660#endif
13661
13662 /* Get the name of the frame to use for resource lookup. */
13663 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13664 if (!STRINGP (name)
13665 && !EQ (name, Qunbound)
13666 && !NILP (name))
13667 error ("Invalid frame name--not a string or nil");
13668 Vx_resource_name = name;
13669
13670 frame = Qnil;
13671 GCPRO3 (parms, name, frame);
9eb16b62
JR
13672 /* Make a frame without minibuffer nor mode-line. */
13673 f = make_frame (0);
13674 f->wants_modeline = 0;
6fc2811b 13675 XSETFRAME (frame, f);
3cf3436e
JR
13676
13677 buffer = Fget_buffer_create (build_string (" *tip*"));
13678 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13679 old_buffer = current_buffer;
13680 set_buffer_internal_1 (XBUFFER (buffer));
13681 current_buffer->truncate_lines = Qnil;
13682 Ferase_buffer ();
13683 Finsert (1, &text);
13684 set_buffer_internal_1 (old_buffer);
13685
6fc2811b 13686 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13687 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13688
3cf3436e
JR
13689 /* By setting the output method, we're essentially saying that
13690 the frame is live, as per FRAME_LIVE_P. If we get a signal
13691 from this point on, x_destroy_window might screw up reference
13692 counts etc. */
d88c567c 13693 f->output_method = output_w32;
6fc2811b
JR
13694 f->output_data.w32 =
13695 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13696 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13697
13698 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13699 f->icon_name = Qnil;
13700
ca56d953 13701#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13702 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13703 dpyinfo_refcount = dpyinfo->reference_count;
13704#endif /* GLYPH_DEBUG */
6fc2811b
JR
13705#ifdef MULTI_KBOARD
13706 FRAME_KBOARD (f) = kb;
13707#endif
13708 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13709 f->output_data.w32->explicit_parent = 0;
13710
13711 /* Set the name; the functions to which we pass f expect the name to
13712 be set. */
13713 if (EQ (name, Qunbound) || NILP (name))
13714 {
ca56d953 13715 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13716 f->explicit_name = 0;
13717 }
13718 else
13719 {
13720 f->name = name;
13721 f->explicit_name = 1;
13722 /* use the frame's title when getting resources for this frame. */
13723 specbind (Qx_resource_name, name);
13724 }
13725
6fc2811b
JR
13726 /* Extract the window parameters from the supplied values
13727 that are needed to determine window geometry. */
13728 {
13729 Lisp_Object font;
13730
13731 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13732
13733 BLOCK_INPUT;
13734 /* First, try whatever font the caller has specified. */
13735 if (STRINGP (font))
13736 {
13737 tem = Fquery_fontset (font, Qnil);
13738 if (STRINGP (tem))
13739 font = x_new_fontset (f, XSTRING (tem)->data);
13740 else
13741 font = x_new_font (f, XSTRING (font)->data);
13742 }
13743
13744 /* Try out a font which we hope has bold and italic variations. */
13745 if (!STRINGP (font))
ca56d953 13746 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13747 if (! STRINGP (font))
ca56d953 13748 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13749 /* If those didn't work, look for something which will at least work. */
13750 if (! STRINGP (font))
ca56d953 13751 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13752 UNBLOCK_INPUT;
13753 if (! STRINGP (font))
ca56d953 13754 font = build_string ("Fixedsys");
6fc2811b
JR
13755
13756 x_default_parameter (f, parms, Qfont, font,
13757 "font", "Font", RES_TYPE_STRING);
13758 }
13759
13760 x_default_parameter (f, parms, Qborder_width, make_number (2),
13761 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13762 /* This defaults to 2 in order to match xterm. We recognize either
13763 internalBorderWidth or internalBorder (which is what xterm calls
13764 it). */
13765 if (NILP (Fassq (Qinternal_border_width, parms)))
13766 {
13767 Lisp_Object value;
13768
13769 value = w32_get_arg (parms, Qinternal_border_width,
13770 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13771 if (! EQ (value, Qunbound))
13772 parms = Fcons (Fcons (Qinternal_border_width, value),
13773 parms);
13774 }
bfd6edcc 13775 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13776 "internalBorderWidth", "internalBorderWidth",
13777 RES_TYPE_NUMBER);
13778
13779 /* Also do the stuff which must be set before the window exists. */
13780 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13781 "foreground", "Foreground", RES_TYPE_STRING);
13782 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13783 "background", "Background", RES_TYPE_STRING);
13784 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13785 "pointerColor", "Foreground", RES_TYPE_STRING);
13786 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13787 "cursorColor", "Foreground", RES_TYPE_STRING);
13788 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13789 "borderColor", "BorderColor", RES_TYPE_STRING);
13790
13791 /* Init faces before x_default_parameter is called for scroll-bar
13792 parameters because that function calls x_set_scroll_bar_width,
13793 which calls change_frame_size, which calls Fset_window_buffer,
13794 which runs hooks, which call Fvertical_motion. At the end, we
13795 end up in init_iterator with a null face cache, which should not
13796 happen. */
13797 init_frame_faces (f);
ca56d953
JR
13798
13799 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13800 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13801
6fc2811b
JR
13802 window_prompting = x_figure_window_size (f, parms);
13803
9eb16b62
JR
13804 /* No fringes on tip frame. */
13805 f->output_data.w32->fringes_extra = 0;
13806 f->output_data.w32->fringe_cols = 0;
13807 f->output_data.w32->left_fringe_width = 0;
13808 f->output_data.w32->right_fringe_width = 0;
13809
6fc2811b
JR
13810 if (window_prompting & XNegative)
13811 {
13812 if (window_prompting & YNegative)
13813 f->output_data.w32->win_gravity = SouthEastGravity;
13814 else
13815 f->output_data.w32->win_gravity = NorthEastGravity;
13816 }
13817 else
13818 {
13819 if (window_prompting & YNegative)
13820 f->output_data.w32->win_gravity = SouthWestGravity;
13821 else
13822 f->output_data.w32->win_gravity = NorthWestGravity;
13823 }
13824
13825 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13826
13827 BLOCK_INPUT;
13828 my_create_tip_window (f);
13829 UNBLOCK_INPUT;
6fc2811b
JR
13830
13831 x_make_gc (f);
13832
13833 x_default_parameter (f, parms, Qauto_raise, Qnil,
13834 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13835 x_default_parameter (f, parms, Qauto_lower, Qnil,
13836 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13837 x_default_parameter (f, parms, Qcursor_type, Qbox,
13838 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13839
13840 /* Dimensions, especially f->height, must be done via change_frame_size.
13841 Change will not be effected unless different from the current
13842 f->height. */
13843 width = f->width;
13844 height = f->height;
13845 f->height = 0;
13846 SET_FRAME_WIDTH (f, 0);
13847 change_frame_size (f, height, width, 1, 0, 0);
13848
3cf3436e
JR
13849 /* Set up faces after all frame parameters are known. This call
13850 also merges in face attributes specified for new frames.
13851
13852 Frame parameters may be changed if .Xdefaults contains
13853 specifications for the default font. For example, if there is an
13854 `Emacs.default.attributeBackground: pink', the `background-color'
13855 attribute of the frame get's set, which let's the internal border
13856 of the tooltip frame appear in pink. Prevent this. */
13857 {
13858 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13859
13860 /* Set tip_frame here, so that */
13861 tip_frame = frame;
13862 call1 (Qface_set_after_frame_default, frame);
13863
13864 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13865 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13866 Qnil));
13867 }
13868
6fc2811b
JR
13869 f->no_split = 1;
13870
13871 UNGCPRO;
13872
13873 /* It is now ok to make the frame official even if we get an error
13874 below. And the frame needs to be on Vframe_list or making it
13875 visible won't work. */
13876 Vframe_list = Fcons (frame, Vframe_list);
13877
13878 /* Now that the frame is official, it counts as a reference to
13879 its display. */
13880 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13881
3cf3436e
JR
13882 /* Setting attributes of faces of the tooltip frame from resources
13883 and similar will increment face_change_count, which leads to the
13884 clearing of all current matrices. Since this isn't necessary
13885 here, avoid it by resetting face_change_count to the value it
13886 had before we created the tip frame. */
13887 face_change_count = face_change_count_before;
13888
13889 /* Discard the unwind_protect. */
6fc2811b 13890 return unbind_to (count, frame);
ee78dc32
GV
13891}
13892
3cf3436e
JR
13893
13894/* Compute where to display tip frame F. PARMS is the list of frame
13895 parameters for F. DX and DY are specified offsets from the current
13896 location of the mouse. WIDTH and HEIGHT are the width and height
13897 of the tooltip. Return coordinates relative to the root window of
13898 the display in *ROOT_X, and *ROOT_Y. */
13899
13900static void
13901compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13902 struct frame *f;
13903 Lisp_Object parms, dx, dy;
13904 int width, height;
13905 int *root_x, *root_y;
13906{
3cf3436e 13907 Lisp_Object left, top;
3cf3436e
JR
13908
13909 /* User-specified position? */
13910 left = Fcdr (Fassq (Qleft, parms));
13911 top = Fcdr (Fassq (Qtop, parms));
13912
13913 /* Move the tooltip window where the mouse pointer is. Resize and
13914 show it. */
ca56d953 13915 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13916 {
ca56d953
JR
13917 POINT pt;
13918
3cf3436e 13919 BLOCK_INPUT;
ca56d953
JR
13920 GetCursorPos (&pt);
13921 *root_x = pt.x;
13922 *root_y = pt.y;
3cf3436e
JR
13923 UNBLOCK_INPUT;
13924 }
13925
13926 if (INTEGERP (top))
13927 *root_y = XINT (top);
13928 else if (*root_y + XINT (dy) - height < 0)
13929 *root_y -= XINT (dy);
13930 else
13931 {
13932 *root_y -= height;
13933 *root_y += XINT (dy);
13934 }
13935
13936 if (INTEGERP (left))
13937 *root_x = XINT (left);
72e4adef
JR
13938 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13939 /* It fits to the right of the pointer. */
13940 *root_x += XINT (dx);
13941 else if (width + XINT (dx) <= *root_x)
13942 /* It fits to the left of the pointer. */
3cf3436e
JR
13943 *root_x -= width + XINT (dx);
13944 else
72e4adef
JR
13945 /* Put it left justified on the screen -- it ought to fit that way. */
13946 *root_x = 0;
3cf3436e
JR
13947}
13948
13949
71eab8d1 13950DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13951 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13952A tooltip window is a small window displaying a string.
13953
13954FRAME nil or omitted means use the selected frame.
13955
13956PARMS is an optional list of frame parameters which can be
13957used to change the tooltip's appearance.
13958
ca56d953
JR
13959Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13960means use the default timeout of 5 seconds.
74e1aeec 13961
ca56d953 13962If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13963the tooltip is displayed at that x-position. Otherwise it is
13964displayed at the mouse position, with offset DX added (default is 5 if
13965DX isn't specified). Likewise for the y-position; if a `top' frame
13966parameter is specified, it determines the y-position of the tooltip
13967window, otherwise it is displayed at the mouse position, with offset
13968DY added (default is -10).
13969
13970A tooltip's maximum size is specified by `x-max-tooltip-size'.
13971Text larger than the specified size is clipped. */)
71eab8d1
AI
13972 (string, frame, parms, timeout, dx, dy)
13973 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13974{
6fc2811b
JR
13975 struct frame *f;
13976 struct window *w;
3cf3436e 13977 int root_x, root_y;
6fc2811b
JR
13978 struct buffer *old_buffer;
13979 struct text_pos pos;
13980 int i, width, height;
6fc2811b
JR
13981 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13982 int old_windows_or_buffers_changed = windows_or_buffers_changed;
ca56d953 13983 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13984
13985 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13986
dfff8a69 13987 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13988
b7826503 13989 CHECK_STRING (string);
6fc2811b
JR
13990 f = check_x_frame (frame);
13991 if (NILP (timeout))
13992 timeout = make_number (5);
13993 else
b7826503 13994 CHECK_NATNUM (timeout);
ee78dc32 13995
71eab8d1
AI
13996 if (NILP (dx))
13997 dx = make_number (5);
13998 else
b7826503 13999 CHECK_NUMBER (dx);
71eab8d1
AI
14000
14001 if (NILP (dy))
dc220243 14002 dy = make_number (-10);
71eab8d1 14003 else
b7826503 14004 CHECK_NUMBER (dy);
71eab8d1 14005
dc220243
JR
14006 if (NILP (last_show_tip_args))
14007 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
14008
14009 if (!NILP (tip_frame))
14010 {
14011 Lisp_Object last_string = AREF (last_show_tip_args, 0);
14012 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
14013 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
14014
14015 if (EQ (frame, last_frame)
14016 && !NILP (Fequal (last_string, string))
14017 && !NILP (Fequal (last_parms, parms)))
14018 {
14019 struct frame *f = XFRAME (tip_frame);
14020
14021 /* Only DX and DY have changed. */
14022 if (!NILP (tip_timer))
14023 {
14024 Lisp_Object timer = tip_timer;
14025 tip_timer = Qnil;
14026 call1 (Qcancel_timer, timer);
14027 }
14028
14029 BLOCK_INPUT;
ca56d953
JR
14030 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
14031 PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
14032
14033 /* Put tooltip in topmost group and in position. */
ca56d953
JR
14034 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14035 root_x, root_y, 0, 0,
14036 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
14037
14038 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14039 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14040 0, 0, 0, 0,
14041 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14042
dc220243
JR
14043 UNBLOCK_INPUT;
14044 goto start_timer;
14045 }
14046 }
14047
6fc2811b
JR
14048 /* Hide a previous tip, if any. */
14049 Fx_hide_tip ();
ee78dc32 14050
dc220243
JR
14051 ASET (last_show_tip_args, 0, string);
14052 ASET (last_show_tip_args, 1, frame);
14053 ASET (last_show_tip_args, 2, parms);
14054
6fc2811b
JR
14055 /* Add default values to frame parameters. */
14056 if (NILP (Fassq (Qname, parms)))
14057 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14058 if (NILP (Fassq (Qinternal_border_width, parms)))
14059 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14060 if (NILP (Fassq (Qborder_width, parms)))
14061 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14062 if (NILP (Fassq (Qborder_color, parms)))
14063 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14064 if (NILP (Fassq (Qbackground_color, parms)))
14065 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14066 parms);
14067
0e3fcdef
JR
14068 /* Block input until the tip has been fully drawn, to avoid crashes
14069 when drawing tips in menus. */
14070 BLOCK_INPUT;
14071
6fc2811b
JR
14072 /* Create a frame for the tooltip, and record it in the global
14073 variable tip_frame. */
ca56d953 14074 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 14075 f = XFRAME (frame);
6fc2811b 14076
3cf3436e 14077 /* Set up the frame's root window. */
6fc2811b
JR
14078 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14079 w->left = w->top = make_number (0);
3cf3436e
JR
14080
14081 if (CONSP (Vx_max_tooltip_size)
14082 && INTEGERP (XCAR (Vx_max_tooltip_size))
14083 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14084 && INTEGERP (XCDR (Vx_max_tooltip_size))
14085 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14086 {
14087 w->width = XCAR (Vx_max_tooltip_size);
14088 w->height = XCDR (Vx_max_tooltip_size);
14089 }
14090 else
14091 {
14092 w->width = make_number (80);
14093 w->height = make_number (40);
14094 }
14095
14096 f->window_width = XINT (w->width);
6fc2811b
JR
14097 adjust_glyphs (f);
14098 w->pseudo_window_p = 1;
14099
14100 /* Display the tooltip text in a temporary buffer. */
6fc2811b 14101 old_buffer = current_buffer;
3cf3436e
JR
14102 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14103 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
14104 clear_glyph_matrix (w->desired_matrix);
14105 clear_glyph_matrix (w->current_matrix);
14106 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14107 try_window (FRAME_ROOT_WINDOW (f), pos);
14108
14109 /* Compute width and height of the tooltip. */
14110 width = height = 0;
14111 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 14112 {
6fc2811b
JR
14113 struct glyph_row *row = &w->desired_matrix->rows[i];
14114 struct glyph *last;
14115 int row_width;
14116
14117 /* Stop at the first empty row at the end. */
14118 if (!row->enabled_p || !row->displays_text_p)
14119 break;
14120
14121 /* Let the row go over the full width of the frame. */
14122 row->full_width_p = 1;
14123
4e3a1c61
JR
14124#ifdef TODO /* Investigate why some fonts need more width than is
14125 calculated for some tooltips. */
6fc2811b
JR
14126 /* There's a glyph at the end of rows that is use to place
14127 the cursor there. Don't include the width of this glyph. */
14128 if (row->used[TEXT_AREA])
14129 {
14130 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14131 row_width = row->pixel_width - last->pixel_width;
14132 }
14133 else
4e3a1c61 14134#endif
6fc2811b
JR
14135 row_width = row->pixel_width;
14136
ca56d953 14137 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 14138 height += row->height;
6fc2811b 14139 width = max (width, row_width);
ee78dc32
GV
14140 }
14141
6fc2811b
JR
14142 /* Add the frame's internal border to the width and height the X
14143 window should have. */
14144 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14145 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 14146
6fc2811b
JR
14147 /* Move the tooltip window where the mouse pointer is. Resize and
14148 show it. */
3cf3436e 14149 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 14150
bfd6edcc
JR
14151 {
14152 /* Adjust Window size to take border into account. */
14153 RECT rect;
14154 rect.left = rect.top = 0;
14155 rect.right = width;
14156 rect.bottom = height;
14157 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14158 FRAME_EXTERNAL_MENU_BAR (f));
14159
d65a9cdc 14160 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
14161 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14162 root_x, root_y, rect.right - rect.left,
14163 rect.bottom - rect.top, SWP_NOACTIVATE);
14164
d65a9cdc
JR
14165 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14166 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14167 0, 0, 0, 0,
14168 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14169
bfd6edcc
JR
14170 /* Let redisplay know that we have made the frame visible already. */
14171 f->async_visible = 1;
14172
14173 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14174 }
ee78dc32 14175
6fc2811b
JR
14176 /* Draw into the window. */
14177 w->must_be_updated_p = 1;
14178 update_single_window (w, 1);
ee78dc32 14179
0e3fcdef
JR
14180 UNBLOCK_INPUT;
14181
6fc2811b
JR
14182 /* Restore original current buffer. */
14183 set_buffer_internal_1 (old_buffer);
14184 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 14185
dc220243 14186 start_timer:
6fc2811b
JR
14187 /* Let the tip disappear after timeout seconds. */
14188 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14189 intern ("x-hide-tip"));
ee78dc32 14190
dfff8a69 14191 UNGCPRO;
6fc2811b 14192 return unbind_to (count, Qnil);
ee78dc32
GV
14193}
14194
ee78dc32 14195
6fc2811b 14196DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
14197 doc: /* Hide the current tooltip window, if there is any.
14198Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
14199 ()
14200{
937e601e
AI
14201 int count;
14202 Lisp_Object deleted, frame, timer;
14203 struct gcpro gcpro1, gcpro2;
14204
14205 /* Return quickly if nothing to do. */
14206 if (NILP (tip_timer) && NILP (tip_frame))
14207 return Qnil;
14208
14209 frame = tip_frame;
14210 timer = tip_timer;
14211 GCPRO2 (frame, timer);
14212 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 14213
937e601e 14214 count = BINDING_STACK_SIZE ();
6fc2811b 14215 specbind (Qinhibit_redisplay, Qt);
937e601e 14216 specbind (Qinhibit_quit, Qt);
6fc2811b 14217
937e601e 14218 if (!NILP (timer))
dc220243 14219 call1 (Qcancel_timer, timer);
ee78dc32 14220
937e601e 14221 if (FRAMEP (frame))
6fc2811b 14222 {
937e601e
AI
14223 Fdelete_frame (frame, Qnil);
14224 deleted = Qt;
6fc2811b 14225 }
1edf84e7 14226
937e601e
AI
14227 UNGCPRO;
14228 return unbind_to (count, deleted);
6fc2811b 14229}
5ac45f98 14230
5ac45f98 14231
6fc2811b
JR
14232\f
14233/***********************************************************************
14234 File selection dialog
14235 ***********************************************************************/
14236
14237extern Lisp_Object Qfile_name_history;
14238
14239DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
14240 doc: /* Read file name, prompting with PROMPT in directory DIR.
14241Use a file selection dialog.
14242Select DEFAULT-FILENAME in the dialog's file selection box, if
14243specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
14244 (prompt, dir, default_filename, mustmatch)
14245 Lisp_Object prompt, dir, default_filename, mustmatch;
14246{
14247 struct frame *f = SELECTED_FRAME ();
14248 Lisp_Object file = Qnil;
14249 int count = specpdl_ptr - specpdl;
14250 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14251 char filename[MAX_PATH + 1];
14252 char init_dir[MAX_PATH + 1];
14253 int use_dialog_p = 1;
14254
14255 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
14256 CHECK_STRING (prompt);
14257 CHECK_STRING (dir);
6fc2811b
JR
14258
14259 /* Create the dialog with PROMPT as title, using DIR as initial
14260 directory and using "*" as pattern. */
14261 dir = Fexpand_file_name (dir, Qnil);
14262 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14263 init_dir[MAX_PATH] = '\0';
14264 unixtodos_filename (init_dir);
14265
14266 if (STRINGP (default_filename))
14267 {
14268 char *file_name_only;
14269 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 14270
6fc2811b 14271 unixtodos_filename (full_path_name);
5ac45f98 14272
6fc2811b
JR
14273 file_name_only = strrchr (full_path_name, '\\');
14274 if (!file_name_only)
14275 file_name_only = full_path_name;
14276 else
14277 {
14278 file_name_only++;
5ac45f98 14279
6fc2811b
JR
14280 /* If default_file_name is a directory, don't use the open
14281 file dialog, as it does not support selecting
14282 directories. */
14283 if (!(*file_name_only))
14284 use_dialog_p = 0;
14285 }
ee78dc32 14286
6fc2811b
JR
14287 strncpy (filename, file_name_only, MAX_PATH);
14288 filename[MAX_PATH] = '\0';
14289 }
ee78dc32 14290 else
6fc2811b 14291 filename[0] = '\0';
ee78dc32 14292
6fc2811b
JR
14293 if (use_dialog_p)
14294 {
14295 OPENFILENAME file_details;
5ac45f98 14296
6fc2811b
JR
14297 /* Prevent redisplay. */
14298 specbind (Qinhibit_redisplay, Qt);
14299 BLOCK_INPUT;
ee78dc32 14300
6fc2811b
JR
14301 bzero (&file_details, sizeof (file_details));
14302 file_details.lStructSize = sizeof (file_details);
14303 file_details.hwndOwner = FRAME_W32_WINDOW (f);
3cf3436e
JR
14304 /* Undocumented Bug in Common File Dialog:
14305 If a filter is not specified, shell links are not resolved. */
14306 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
6fc2811b
JR
14307 file_details.lpstrFile = filename;
14308 file_details.nMaxFile = sizeof (filename);
14309 file_details.lpstrInitialDir = init_dir;
14310 file_details.lpstrTitle = XSTRING (prompt)->data;
14311 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 14312
6fc2811b
JR
14313 if (!NILP (mustmatch))
14314 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 14315
6fc2811b
JR
14316 if (GetOpenFileName (&file_details))
14317 {
14318 dostounix_filename (filename);
f8a58bac 14319 file = DECODE_FILE(build_string (filename));
6fc2811b 14320 }
ee78dc32 14321 else
6fc2811b
JR
14322 file = Qnil;
14323
14324 UNBLOCK_INPUT;
14325 file = unbind_to (count, file);
ee78dc32 14326 }
6fc2811b
JR
14327 /* Open File dialog will not allow folders to be selected, so resort
14328 to minibuffer completing reads for directories. */
14329 else
14330 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14331 dir, mustmatch, dir, Qfile_name_history,
14332 default_filename, Qnil);
ee78dc32 14333
6fc2811b 14334 UNGCPRO;
1edf84e7 14335
6fc2811b
JR
14336 /* Make "Cancel" equivalent to C-g. */
14337 if (NILP (file))
14338 Fsignal (Qquit, Qnil);
ee78dc32 14339
dfff8a69 14340 return unbind_to (count, file);
6fc2811b 14341}
ee78dc32 14342
ee78dc32 14343
6fc2811b 14344\f
6fc2811b
JR
14345/***********************************************************************
14346 w32 specialized functions
14347 ***********************************************************************/
ee78dc32 14348
d84b082d 14349DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
14350 doc: /* Select a font using the W32 font dialog.
14351Returns an X font string corresponding to the selection. */)
d84b082d
JR
14352 (frame, include_proportional)
14353 Lisp_Object frame, include_proportional;
ee78dc32
GV
14354{
14355 FRAME_PTR f = check_x_frame (frame);
14356 CHOOSEFONT cf;
14357 LOGFONT lf;
f46e6225
GV
14358 TEXTMETRIC tm;
14359 HDC hdc;
14360 HANDLE oldobj;
ee78dc32
GV
14361 char buf[100];
14362
14363 bzero (&cf, sizeof (cf));
f46e6225 14364 bzero (&lf, sizeof (lf));
ee78dc32
GV
14365
14366 cf.lStructSize = sizeof (cf);
fbd6baed 14367 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
14368 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14369
14370 /* Unless include_proportional is non-nil, limit the selection to
14371 monospaced fonts. */
14372 if (NILP (include_proportional))
14373 cf.Flags |= CF_FIXEDPITCHONLY;
14374
ee78dc32
GV
14375 cf.lpLogFont = &lf;
14376
f46e6225
GV
14377 /* Initialize as much of the font details as we can from the current
14378 default font. */
14379 hdc = GetDC (FRAME_W32_WINDOW (f));
14380 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14381 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14382 if (GetTextMetrics (hdc, &tm))
14383 {
14384 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14385 lf.lfWeight = tm.tmWeight;
14386 lf.lfItalic = tm.tmItalic;
14387 lf.lfUnderline = tm.tmUnderlined;
14388 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
14389 lf.lfCharSet = tm.tmCharSet;
14390 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14391 }
14392 SelectObject (hdc, oldobj);
6fc2811b 14393 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 14394
767b1ff0 14395 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 14396 return Qnil;
ee78dc32
GV
14397
14398 return build_string (buf);
14399}
14400
74e1aeec
JR
14401DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14402 Sw32_send_sys_command, 1, 2, 0,
14403 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
14404Some useful values for command are #xf030 to maximise frame (#xf020
14405to minimize), #xf120 to restore frame to original size, and #xf100
14406to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
14407screen saver if defined.
14408
14409If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
14410 (command, frame)
14411 Lisp_Object command, frame;
14412{
1edf84e7
GV
14413 FRAME_PTR f = check_x_frame (frame);
14414
b7826503 14415 CHECK_NUMBER (command);
1edf84e7 14416
ce6059da 14417 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
14418
14419 return Qnil;
14420}
14421
55dcfc15 14422DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
14423 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14424This is a wrapper around the ShellExecute system function, which
14425invokes the application registered to handle OPERATION for DOCUMENT.
14426OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14427nil for the default action), and DOCUMENT is typically the name of a
14428document file or URL, but can also be a program executable to run or
14429a directory to open in the Windows Explorer.
14430
14431If DOCUMENT is a program executable, PARAMETERS can be a string
14432containing command line parameters, but otherwise should be nil.
14433
14434SHOW-FLAG can be used to control whether the invoked application is hidden
14435or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14436otherwise it is an integer representing a ShowWindow flag:
14437
14438 0 - start hidden
14439 1 - start normally
14440 3 - start maximized
14441 6 - start minimized */)
55dcfc15
AI
14442 (operation, document, parameters, show_flag)
14443 Lisp_Object operation, document, parameters, show_flag;
14444{
14445 Lisp_Object current_dir;
14446
b7826503 14447 CHECK_STRING (document);
55dcfc15
AI
14448
14449 /* Encode filename and current directory. */
14450 current_dir = ENCODE_FILE (current_buffer->directory);
14451 document = ENCODE_FILE (document);
14452 if ((int) ShellExecute (NULL,
6fc2811b
JR
14453 (STRINGP (operation) ?
14454 XSTRING (operation)->data : NULL),
55dcfc15
AI
14455 XSTRING (document)->data,
14456 (STRINGP (parameters) ?
14457 XSTRING (parameters)->data : NULL),
14458 XSTRING (current_dir)->data,
14459 (INTEGERP (show_flag) ?
14460 XINT (show_flag) : SW_SHOWDEFAULT))
14461 > 32)
14462 return Qt;
90d97e64 14463 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
14464}
14465
ccc2d29c
GV
14466/* Lookup virtual keycode from string representing the name of a
14467 non-ascii keystroke into the corresponding virtual key, using
14468 lispy_function_keys. */
14469static int
14470lookup_vk_code (char *key)
14471{
14472 int i;
14473
14474 for (i = 0; i < 256; i++)
14475 if (lispy_function_keys[i] != 0
14476 && strcmp (lispy_function_keys[i], key) == 0)
14477 return i;
14478
14479 return -1;
14480}
14481
14482/* Convert a one-element vector style key sequence to a hot key
14483 definition. */
14484static int
14485w32_parse_hot_key (key)
14486 Lisp_Object key;
14487{
14488 /* Copied from Fdefine_key and store_in_keymap. */
14489 register Lisp_Object c;
14490 int vk_code;
14491 int lisp_modifiers;
14492 int w32_modifiers;
14493 struct gcpro gcpro1;
14494
b7826503 14495 CHECK_VECTOR (key);
ccc2d29c
GV
14496
14497 if (XFASTINT (Flength (key)) != 1)
14498 return Qnil;
14499
14500 GCPRO1 (key);
14501
14502 c = Faref (key, make_number (0));
14503
14504 if (CONSP (c) && lucid_event_type_list_p (c))
14505 c = Fevent_convert_list (c);
14506
14507 UNGCPRO;
14508
14509 if (! INTEGERP (c) && ! SYMBOLP (c))
14510 error ("Key definition is invalid");
14511
14512 /* Work out the base key and the modifiers. */
14513 if (SYMBOLP (c))
14514 {
14515 c = parse_modifiers (c);
14516 lisp_modifiers = Fcar (Fcdr (c));
14517 c = Fcar (c);
14518 if (!SYMBOLP (c))
14519 abort ();
14520 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
14521 }
14522 else if (INTEGERP (c))
14523 {
14524 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14525 /* Many ascii characters are their own virtual key code. */
14526 vk_code = XINT (c) & CHARACTERBITS;
14527 }
14528
14529 if (vk_code < 0 || vk_code > 255)
14530 return Qnil;
14531
14532 if ((lisp_modifiers & meta_modifier) != 0
14533 && !NILP (Vw32_alt_is_meta))
14534 lisp_modifiers |= alt_modifier;
14535
71eab8d1
AI
14536 /* Supply defs missing from mingw32. */
14537#ifndef MOD_ALT
14538#define MOD_ALT 0x0001
14539#define MOD_CONTROL 0x0002
14540#define MOD_SHIFT 0x0004
14541#define MOD_WIN 0x0008
14542#endif
14543
ccc2d29c
GV
14544 /* Convert lisp modifiers to Windows hot-key form. */
14545 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14546 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14547 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14548 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14549
14550 return HOTKEY (vk_code, w32_modifiers);
14551}
14552
74e1aeec
JR
14553DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14554 Sw32_register_hot_key, 1, 1, 0,
14555 doc: /* Register KEY as a hot-key combination.
14556Certain key combinations like Alt-Tab are reserved for system use on
14557Windows, and therefore are normally intercepted by the system. However,
14558most of these key combinations can be received by registering them as
14559hot-keys, overriding their special meaning.
14560
14561KEY must be a one element key definition in vector form that would be
14562acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14563modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14564is always interpreted as the Windows modifier keys.
14565
14566The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14567 (key)
14568 Lisp_Object key;
14569{
14570 key = w32_parse_hot_key (key);
14571
14572 if (NILP (Fmemq (key, w32_grabbed_keys)))
14573 {
14574 /* Reuse an empty slot if possible. */
14575 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14576
14577 /* Safe to add new key to list, even if we have focus. */
14578 if (NILP (item))
14579 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14580 else
f3fbd155 14581 XSETCAR (item, key);
ccc2d29c
GV
14582
14583 /* Notify input thread about new hot-key definition, so that it
14584 takes effect without needing to switch focus. */
14585 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14586 (WPARAM) key, 0);
14587 }
14588
14589 return key;
14590}
14591
74e1aeec
JR
14592DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14593 Sw32_unregister_hot_key, 1, 1, 0,
14594 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14595 (key)
14596 Lisp_Object key;
14597{
14598 Lisp_Object item;
14599
14600 if (!INTEGERP (key))
14601 key = w32_parse_hot_key (key);
14602
14603 item = Fmemq (key, w32_grabbed_keys);
14604
14605 if (!NILP (item))
14606 {
14607 /* Notify input thread about hot-key definition being removed, so
14608 that it takes effect without needing focus switch. */
14609 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14610 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14611 {
14612 MSG msg;
14613 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14614 }
14615 return Qt;
14616 }
14617 return Qnil;
14618}
14619
74e1aeec
JR
14620DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14621 Sw32_registered_hot_keys, 0, 0, 0,
14622 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14623 ()
14624{
14625 return Fcopy_sequence (w32_grabbed_keys);
14626}
14627
74e1aeec
JR
14628DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14629 Sw32_reconstruct_hot_key, 1, 1, 0,
14630 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14631 (hotkeyid)
14632 Lisp_Object hotkeyid;
14633{
14634 int vk_code, w32_modifiers;
14635 Lisp_Object key;
14636
b7826503 14637 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14638
14639 vk_code = HOTKEY_VK_CODE (hotkeyid);
14640 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14641
14642 if (lispy_function_keys[vk_code])
14643 key = intern (lispy_function_keys[vk_code]);
14644 else
14645 key = make_number (vk_code);
14646
14647 key = Fcons (key, Qnil);
14648 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14649 key = Fcons (Qshift, key);
ccc2d29c 14650 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14651 key = Fcons (Qctrl, key);
ccc2d29c 14652 if (w32_modifiers & MOD_ALT)
3ef68e6b 14653 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14654 if (w32_modifiers & MOD_WIN)
3ef68e6b 14655 key = Fcons (Qhyper, key);
ccc2d29c
GV
14656
14657 return key;
14658}
adcc3809 14659
74e1aeec
JR
14660DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14661 Sw32_toggle_lock_key, 1, 2, 0,
14662 doc: /* Toggle the state of the lock key KEY.
14663KEY can be `capslock', `kp-numlock', or `scroll'.
14664If the optional parameter NEW-STATE is a number, then the state of KEY
14665is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14666 (key, new_state)
14667 Lisp_Object key, new_state;
14668{
14669 int vk_code;
adcc3809
GV
14670
14671 if (EQ (key, intern ("capslock")))
14672 vk_code = VK_CAPITAL;
14673 else if (EQ (key, intern ("kp-numlock")))
14674 vk_code = VK_NUMLOCK;
14675 else if (EQ (key, intern ("scroll")))
14676 vk_code = VK_SCROLL;
14677 else
14678 return Qnil;
14679
14680 if (!dwWindowsThreadId)
14681 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14682
14683 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14684 (WPARAM) vk_code, (LPARAM) new_state))
14685 {
14686 MSG msg;
14687 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14688 return make_number (msg.wParam);
14689 }
14690 return Qnil;
14691}
ee78dc32 14692\f
2254bcde 14693DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14694 doc: /* Return storage information about the file system FILENAME is on.
14695Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14696storage of the file system, FREE is the free storage, and AVAIL is the
14697storage available to a non-superuser. All 3 numbers are in bytes.
14698If the underlying system call fails, value is nil. */)
2254bcde
AI
14699 (filename)
14700 Lisp_Object filename;
14701{
14702 Lisp_Object encoded, value;
14703
b7826503 14704 CHECK_STRING (filename);
2254bcde
AI
14705 filename = Fexpand_file_name (filename, Qnil);
14706 encoded = ENCODE_FILE (filename);
14707
14708 value = Qnil;
14709
14710 /* Determining the required information on Windows turns out, sadly,
14711 to be more involved than one would hope. The original Win32 api
14712 call for this will return bogus information on some systems, but we
14713 must dynamically probe for the replacement api, since that was
14714 added rather late on. */
14715 {
14716 HMODULE hKernel = GetModuleHandle ("kernel32");
14717 BOOL (*pfn_GetDiskFreeSpaceEx)
14718 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14719 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14720
14721 /* On Windows, we may need to specify the root directory of the
14722 volume holding FILENAME. */
14723 char rootname[MAX_PATH];
14724 char *name = XSTRING (encoded)->data;
14725
14726 /* find the root name of the volume if given */
14727 if (isalpha (name[0]) && name[1] == ':')
14728 {
14729 rootname[0] = name[0];
14730 rootname[1] = name[1];
14731 rootname[2] = '\\';
14732 rootname[3] = 0;
14733 }
14734 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14735 {
14736 char *str = rootname;
14737 int slashes = 4;
14738 do
14739 {
14740 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14741 break;
14742 *str++ = *name++;
14743 }
14744 while ( *name );
14745
14746 *str++ = '\\';
14747 *str = 0;
14748 }
14749
14750 if (pfn_GetDiskFreeSpaceEx)
14751 {
ac849ba4
JR
14752 /* Unsigned large integers cannot be cast to double, so
14753 use signed ones instead. */
2254bcde
AI
14754 LARGE_INTEGER availbytes;
14755 LARGE_INTEGER freebytes;
14756 LARGE_INTEGER totalbytes;
14757
14758 if (pfn_GetDiskFreeSpaceEx(rootname,
ac849ba4
JR
14759 (ULARGE_INTEGER *)&availbytes,
14760 (ULARGE_INTEGER *)&totalbytes,
14761 (ULARGE_INTEGER *)&freebytes))
2254bcde
AI
14762 value = list3 (make_float ((double) totalbytes.QuadPart),
14763 make_float ((double) freebytes.QuadPart),
14764 make_float ((double) availbytes.QuadPart));
14765 }
14766 else
14767 {
14768 DWORD sectors_per_cluster;
14769 DWORD bytes_per_sector;
14770 DWORD free_clusters;
14771 DWORD total_clusters;
14772
14773 if (GetDiskFreeSpace(rootname,
14774 &sectors_per_cluster,
14775 &bytes_per_sector,
14776 &free_clusters,
14777 &total_clusters))
14778 value = list3 (make_float ((double) total_clusters
14779 * sectors_per_cluster * bytes_per_sector),
14780 make_float ((double) free_clusters
14781 * sectors_per_cluster * bytes_per_sector),
14782 make_float ((double) free_clusters
14783 * sectors_per_cluster * bytes_per_sector));
14784 }
14785 }
14786
14787 return value;
14788}
14789\f
0e3fcdef
JR
14790/***********************************************************************
14791 Initialization
14792 ***********************************************************************/
14793
14794void
fbd6baed 14795syms_of_w32fns ()
ee78dc32 14796{
9eb16b62
JR
14797 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14798
1edf84e7
GV
14799 /* This is zero if not using MS-Windows. */
14800 w32_in_use = 0;
14801
9eb16b62
JR
14802 /* TrackMouseEvent not available in all versions of Windows, so must load
14803 it dynamically. Do it once, here, instead of every time it is used. */
14804 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14805 track_mouse_window = NULL;
14806
d285988b
JR
14807 w32_visible_system_caret_hwnd = NULL;
14808
ee78dc32
GV
14809 Qauto_raise = intern ("auto-raise");
14810 staticpro (&Qauto_raise);
14811 Qauto_lower = intern ("auto-lower");
14812 staticpro (&Qauto_lower);
ee78dc32
GV
14813 Qbar = intern ("bar");
14814 staticpro (&Qbar);
14815 Qborder_color = intern ("border-color");
14816 staticpro (&Qborder_color);
14817 Qborder_width = intern ("border-width");
14818 staticpro (&Qborder_width);
14819 Qbox = intern ("box");
14820 staticpro (&Qbox);
14821 Qcursor_color = intern ("cursor-color");
14822 staticpro (&Qcursor_color);
14823 Qcursor_type = intern ("cursor-type");
14824 staticpro (&Qcursor_type);
ee78dc32
GV
14825 Qgeometry = intern ("geometry");
14826 staticpro (&Qgeometry);
14827 Qicon_left = intern ("icon-left");
14828 staticpro (&Qicon_left);
14829 Qicon_top = intern ("icon-top");
14830 staticpro (&Qicon_top);
14831 Qicon_type = intern ("icon-type");
14832 staticpro (&Qicon_type);
14833 Qicon_name = intern ("icon-name");
14834 staticpro (&Qicon_name);
14835 Qinternal_border_width = intern ("internal-border-width");
14836 staticpro (&Qinternal_border_width);
14837 Qleft = intern ("left");
14838 staticpro (&Qleft);
1026b400
RS
14839 Qright = intern ("right");
14840 staticpro (&Qright);
ee78dc32
GV
14841 Qmouse_color = intern ("mouse-color");
14842 staticpro (&Qmouse_color);
14843 Qnone = intern ("none");
14844 staticpro (&Qnone);
14845 Qparent_id = intern ("parent-id");
14846 staticpro (&Qparent_id);
14847 Qscroll_bar_width = intern ("scroll-bar-width");
14848 staticpro (&Qscroll_bar_width);
14849 Qsuppress_icon = intern ("suppress-icon");
14850 staticpro (&Qsuppress_icon);
ee78dc32
GV
14851 Qundefined_color = intern ("undefined-color");
14852 staticpro (&Qundefined_color);
14853 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14854 staticpro (&Qvertical_scroll_bars);
14855 Qvisibility = intern ("visibility");
14856 staticpro (&Qvisibility);
14857 Qwindow_id = intern ("window-id");
14858 staticpro (&Qwindow_id);
14859 Qx_frame_parameter = intern ("x-frame-parameter");
14860 staticpro (&Qx_frame_parameter);
14861 Qx_resource_name = intern ("x-resource-name");
14862 staticpro (&Qx_resource_name);
14863 Quser_position = intern ("user-position");
14864 staticpro (&Quser_position);
14865 Quser_size = intern ("user-size");
14866 staticpro (&Quser_size);
6fc2811b
JR
14867 Qscreen_gamma = intern ("screen-gamma");
14868 staticpro (&Qscreen_gamma);
dfff8a69
JR
14869 Qline_spacing = intern ("line-spacing");
14870 staticpro (&Qline_spacing);
14871 Qcenter = intern ("center");
14872 staticpro (&Qcenter);
dc220243
JR
14873 Qcancel_timer = intern ("cancel-timer");
14874 staticpro (&Qcancel_timer);
f7b9d4d1
JR
14875 Qfullscreen = intern ("fullscreen");
14876 staticpro (&Qfullscreen);
14877 Qfullwidth = intern ("fullwidth");
14878 staticpro (&Qfullwidth);
14879 Qfullheight = intern ("fullheight");
14880 staticpro (&Qfullheight);
14881 Qfullboth = intern ("fullboth");
14882 staticpro (&Qfullboth);
ee78dc32 14883
adcc3809
GV
14884 Qhyper = intern ("hyper");
14885 staticpro (&Qhyper);
14886 Qsuper = intern ("super");
14887 staticpro (&Qsuper);
14888 Qmeta = intern ("meta");
14889 staticpro (&Qmeta);
14890 Qalt = intern ("alt");
14891 staticpro (&Qalt);
14892 Qctrl = intern ("ctrl");
14893 staticpro (&Qctrl);
14894 Qcontrol = intern ("control");
14895 staticpro (&Qcontrol);
14896 Qshift = intern ("shift");
14897 staticpro (&Qshift);
f7b9d4d1 14898 /* This is the end of symbol initialization. */
adcc3809 14899
6fc2811b
JR
14900 /* Text property `display' should be nonsticky by default. */
14901 Vtext_property_default_nonsticky
14902 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14903
14904
14905 Qlaplace = intern ("laplace");
14906 staticpro (&Qlaplace);
3cf3436e
JR
14907 Qemboss = intern ("emboss");
14908 staticpro (&Qemboss);
14909 Qedge_detection = intern ("edge-detection");
14910 staticpro (&Qedge_detection);
14911 Qheuristic = intern ("heuristic");
14912 staticpro (&Qheuristic);
14913 QCmatrix = intern (":matrix");
14914 staticpro (&QCmatrix);
14915 QCcolor_adjustment = intern (":color-adjustment");
14916 staticpro (&QCcolor_adjustment);
14917 QCmask = intern (":mask");
14918 staticpro (&QCmask);
6fc2811b 14919
4b817373
RS
14920 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14921 staticpro (&Qface_set_after_frame_default);
14922
ee78dc32
GV
14923 Fput (Qundefined_color, Qerror_conditions,
14924 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14925 Fput (Qundefined_color, Qerror_message,
14926 build_string ("Undefined color"));
14927
ccc2d29c
GV
14928 staticpro (&w32_grabbed_keys);
14929 w32_grabbed_keys = Qnil;
14930
fbd6baed 14931 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14932 doc: /* An array of color name mappings for windows. */);
fbd6baed 14933 Vw32_color_map = Qnil;
ee78dc32 14934
fbd6baed 14935 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14936 doc: /* Non-nil if alt key presses are passed on to Windows.
14937When non-nil, for example, alt pressed and released and then space will
14938open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14939 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14940
fbd6baed 14941 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14942 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14943When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14944 Vw32_alt_is_meta = Qt;
8c205c63 14945
7d081355 14946 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14947 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14948 XSETINT (Vw32_quit_key, 0);
14949
ccc2d29c
GV
14950 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14951 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14952 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14953When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14954 Vw32_pass_lwindow_to_system = Qt;
14955
14956 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14957 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14958 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14959When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14960 Vw32_pass_rwindow_to_system = Qt;
14961
adcc3809
GV
14962 DEFVAR_INT ("w32-phantom-key-code",
14963 &Vw32_phantom_key_code,
74e1aeec
JR
14964 doc: /* Virtual key code used to generate \"phantom\" key presses.
14965Value is a number between 0 and 255.
14966
14967Phantom key presses are generated in order to stop the system from
14968acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14969`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14970 /* Although 255 is technically not a valid key code, it works and
14971 means that this hack won't interfere with any real key code. */
14972 Vw32_phantom_key_code = 255;
adcc3809 14973
ccc2d29c
GV
14974 DEFVAR_LISP ("w32-enable-num-lock",
14975 &Vw32_enable_num_lock,
74e1aeec
JR
14976 doc: /* Non-nil if Num Lock should act normally.
14977Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14978 Vw32_enable_num_lock = Qt;
14979
14980 DEFVAR_LISP ("w32-enable-caps-lock",
14981 &Vw32_enable_caps_lock,
74e1aeec
JR
14982 doc: /* Non-nil if Caps Lock should act normally.
14983Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14984 Vw32_enable_caps_lock = Qt;
14985
14986 DEFVAR_LISP ("w32-scroll-lock-modifier",
14987 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14988 doc: /* Modifier to use for the Scroll Lock on state.
14989The value can be hyper, super, meta, alt, control or shift for the
14990respective modifier, or nil to see Scroll Lock as the key `scroll'.
14991Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14992 Vw32_scroll_lock_modifier = Qt;
14993
14994 DEFVAR_LISP ("w32-lwindow-modifier",
14995 &Vw32_lwindow_modifier,
74e1aeec
JR
14996 doc: /* Modifier to use for the left \"Windows\" key.
14997The value can be hyper, super, meta, alt, control or shift for the
14998respective modifier, or nil to appear as the key `lwindow'.
14999Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15000 Vw32_lwindow_modifier = Qnil;
15001
15002 DEFVAR_LISP ("w32-rwindow-modifier",
15003 &Vw32_rwindow_modifier,
74e1aeec
JR
15004 doc: /* Modifier to use for the right \"Windows\" key.
15005The value can be hyper, super, meta, alt, control or shift for the
15006respective modifier, or nil to appear as the key `rwindow'.
15007Any other value will cause the key to be ignored. */);
ccc2d29c
GV
15008 Vw32_rwindow_modifier = Qnil;
15009
15010 DEFVAR_LISP ("w32-apps-modifier",
15011 &Vw32_apps_modifier,
74e1aeec
JR
15012 doc: /* Modifier to use for the \"Apps\" key.
15013The value can be hyper, super, meta, alt, control or shift for the
15014respective modifier, or nil to appear as the key `apps'.
15015Any other value will cause the key to be ignored. */);
ccc2d29c 15016 Vw32_apps_modifier = Qnil;
da36a4d6 15017
d84b082d 15018 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 15019 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 15020 w32_enable_synthesized_fonts = 0;
5ac45f98 15021
fbd6baed 15022 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 15023 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 15024 Vw32_enable_palette = Qt;
5ac45f98 15025
fbd6baed
GV
15026 DEFVAR_INT ("w32-mouse-button-tolerance",
15027 &Vw32_mouse_button_tolerance,
74e1aeec
JR
15028 doc: /* Analogue of double click interval for faking middle mouse events.
15029The value is the minimum time in milliseconds that must elapse between
15030left/right button down events before they are considered distinct events.
15031If both mouse buttons are depressed within this interval, a middle mouse
15032button down event is generated instead. */);
fbd6baed 15033 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 15034
fbd6baed
GV
15035 DEFVAR_INT ("w32-mouse-move-interval",
15036 &Vw32_mouse_move_interval,
74e1aeec
JR
15037 doc: /* Minimum interval between mouse move events.
15038The value is the minimum time in milliseconds that must elapse between
15039successive mouse move (or scroll bar drag) events before they are
15040reported as lisp events. */);
247be837 15041 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 15042
74214547
JR
15043 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
15044 &w32_pass_extra_mouse_buttons_to_system,
15045 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
15046Recent versions of Windows support mice with up to five buttons.
15047Since most applications don't support these extra buttons, most mouse
15048drivers will allow you to map them to functions at the system level.
15049If this variable is non-nil, Emacs will pass them on, allowing the
15050system to handle them. */);
15051 w32_pass_extra_mouse_buttons_to_system = 0;
15052
ee78dc32
GV
15053 init_x_parm_symbols ();
15054
15055 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 15056 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
15057 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15058
15059 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
15060 doc: /* The shape of the pointer when over text.
15061Changing the value does not affect existing frames
15062unless you set the mouse color. */);
ee78dc32
GV
15063 Vx_pointer_shape = Qnil;
15064
15065 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
15066 doc: /* The name Emacs uses to look up resources; for internal use only.
15067`x-get-resource' uses this as the first component of the instance name
15068when requesting resource values.
15069Emacs initially sets `x-resource-name' to the name under which Emacs
15070was invoked, or to the value specified with the `-name' or `-rn'
15071switches, if present. */);
ee78dc32
GV
15072 Vx_resource_name = Qnil;
15073
15074 Vx_nontext_pointer_shape = Qnil;
15075
15076 Vx_mode_pointer_shape = Qnil;
15077
0af913d7 15078 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
15079 doc: /* The shape of the pointer when Emacs is busy.
15080This variable takes effect when you create a new frame
15081or when you set the mouse color. */);
0af913d7 15082 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 15083
0af913d7 15084 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 15085 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 15086 display_hourglass_p = 1;
6fc2811b 15087
0af913d7 15088 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
15089 doc: /* *Seconds to wait before displaying an hourglass pointer.
15090Value must be an integer or float. */);
0af913d7 15091 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 15092
6fc2811b 15093 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 15094 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
15095 doc: /* The shape of the pointer when over mouse-sensitive text.
15096This variable takes effect when you create a new frame
15097or when you set the mouse color. */);
ee78dc32
GV
15098 Vx_sensitive_text_pointer_shape = Qnil;
15099
4694d762
JR
15100 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15101 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
15102 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15103This variable takes effect when you create a new frame
15104or when you set the mouse color. */);
4694d762
JR
15105 Vx_window_horizontal_drag_shape = Qnil;
15106
ee78dc32 15107 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 15108 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
15109 Vx_cursor_fore_pixel = Qnil;
15110
3cf3436e 15111 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
15112 doc: /* Maximum size for tooltips.
15113Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
15114 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
15115
ee78dc32 15116 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
15117 doc: /* Non-nil if no window manager is in use.
15118Emacs doesn't try to figure this out; this is always nil
15119unless you set it to something else. */);
ee78dc32
GV
15120 /* We don't have any way to find this out, so set it to nil
15121 and maybe the user would like to set it to t. */
15122 Vx_no_window_manager = Qnil;
15123
4587b026
GV
15124 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15125 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
15126 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15127
15128Since Emacs gets width of a font matching with this regexp from
15129PIXEL_SIZE field of the name, font finding mechanism gets faster for
15130such a font. This is especially effective for such large fonts as
15131Chinese, Japanese, and Korean. */);
4587b026
GV
15132 Vx_pixel_size_width_font_regexp = Qnil;
15133
6fc2811b 15134 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
15135 doc: /* Time after which cached images are removed from the cache.
15136When an image has not been displayed this many seconds, remove it
15137from the image cache. Value must be an integer or nil with nil
15138meaning don't clear the cache. */);
6fc2811b
JR
15139 Vimage_cache_eviction_delay = make_number (30 * 60);
15140
33d52f9c
GV
15141 DEFVAR_LISP ("w32-bdf-filename-alist",
15142 &Vw32_bdf_filename_alist,
74e1aeec 15143 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
15144 Vw32_bdf_filename_alist = Qnil;
15145
1075afa9
GV
15146 DEFVAR_BOOL ("w32-strict-fontnames",
15147 &w32_strict_fontnames,
74e1aeec
JR
15148 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15149Default is nil, which allows old fontnames that are not XLFD compliant,
15150and allows third-party CJK display to work by specifying false charset
15151fields to trick Emacs into translating to Big5, SJIS etc.
15152Setting this to t will prevent wrong fonts being selected when
15153fontsets are automatically created. */);
1075afa9
GV
15154 w32_strict_fontnames = 0;
15155
c0611964
AI
15156 DEFVAR_BOOL ("w32-strict-painting",
15157 &w32_strict_painting,
74e1aeec
JR
15158 doc: /* Non-nil means use strict rules for repainting frames.
15159Set this to nil to get the old behaviour for repainting; this should
15160only be necessary if the default setting causes problems. */);
c0611964
AI
15161 w32_strict_painting = 1;
15162
dfff8a69
JR
15163 DEFVAR_LISP ("w32-charset-info-alist",
15164 &Vw32_charset_info_alist,
b3700ae7
JR
15165 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15166Each entry should be of the form:
74e1aeec
JR
15167
15168 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15169
15170where CHARSET_NAME is a string used in font names to identify the charset,
15171WINDOWS_CHARSET is a symbol that can be one of:
15172w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15173w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15174w32-charset-chinesebig5,
dfff8a69 15175#ifdef JOHAB_CHARSET
74e1aeec
JR
15176w32-charset-johab, w32-charset-hebrew,
15177w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15178w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15179w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
15180#endif
15181#ifdef UNICODE_CHARSET
74e1aeec 15182w32-charset-unicode,
dfff8a69 15183#endif
74e1aeec
JR
15184or w32-charset-oem.
15185CODEPAGE should be an integer specifying the codepage that should be used
15186to display the character set, t to do no translation and output as Unicode,
15187or nil to do no translation and output as 8 bit (or multibyte on far-east
15188versions of Windows) characters. */);
dfff8a69
JR
15189 Vw32_charset_info_alist = Qnil;
15190
15191 staticpro (&Qw32_charset_ansi);
15192 Qw32_charset_ansi = intern ("w32-charset-ansi");
15193 staticpro (&Qw32_charset_symbol);
15194 Qw32_charset_symbol = intern ("w32-charset-symbol");
15195 staticpro (&Qw32_charset_shiftjis);
15196 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
15197 staticpro (&Qw32_charset_hangeul);
15198 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
15199 staticpro (&Qw32_charset_chinesebig5);
15200 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15201 staticpro (&Qw32_charset_gb2312);
15202 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15203 staticpro (&Qw32_charset_oem);
15204 Qw32_charset_oem = intern ("w32-charset-oem");
15205
15206#ifdef JOHAB_CHARSET
15207 {
15208 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
15209 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15210 doc: /* Internal variable. */);
dfff8a69
JR
15211
15212 staticpro (&Qw32_charset_johab);
15213 Qw32_charset_johab = intern ("w32-charset-johab");
15214 staticpro (&Qw32_charset_easteurope);
15215 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15216 staticpro (&Qw32_charset_turkish);
15217 Qw32_charset_turkish = intern ("w32-charset-turkish");
15218 staticpro (&Qw32_charset_baltic);
15219 Qw32_charset_baltic = intern ("w32-charset-baltic");
15220 staticpro (&Qw32_charset_russian);
15221 Qw32_charset_russian = intern ("w32-charset-russian");
15222 staticpro (&Qw32_charset_arabic);
15223 Qw32_charset_arabic = intern ("w32-charset-arabic");
15224 staticpro (&Qw32_charset_greek);
15225 Qw32_charset_greek = intern ("w32-charset-greek");
15226 staticpro (&Qw32_charset_hebrew);
15227 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
15228 staticpro (&Qw32_charset_vietnamese);
15229 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
15230 staticpro (&Qw32_charset_thai);
15231 Qw32_charset_thai = intern ("w32-charset-thai");
15232 staticpro (&Qw32_charset_mac);
15233 Qw32_charset_mac = intern ("w32-charset-mac");
15234 }
15235#endif
15236
15237#ifdef UNICODE_CHARSET
15238 {
15239 static int w32_unicode_charset_defined = 1;
15240 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
15241 &w32_unicode_charset_defined,
15242 doc: /* Internal variable. */);
dfff8a69
JR
15243
15244 staticpro (&Qw32_charset_unicode);
15245 Qw32_charset_unicode = intern ("w32-charset-unicode");
15246#endif
15247
ee78dc32 15248 defsubr (&Sx_get_resource);
767b1ff0 15249#if 0 /* TODO: Port to W32 */
6fc2811b
JR
15250 defsubr (&Sx_change_window_property);
15251 defsubr (&Sx_delete_window_property);
15252 defsubr (&Sx_window_property);
15253#endif
2d764c78 15254 defsubr (&Sxw_display_color_p);
ee78dc32 15255 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
15256 defsubr (&Sxw_color_defined_p);
15257 defsubr (&Sxw_color_values);
ee78dc32
GV
15258 defsubr (&Sx_server_max_request_size);
15259 defsubr (&Sx_server_vendor);
15260 defsubr (&Sx_server_version);
15261 defsubr (&Sx_display_pixel_width);
15262 defsubr (&Sx_display_pixel_height);
15263 defsubr (&Sx_display_mm_width);
15264 defsubr (&Sx_display_mm_height);
15265 defsubr (&Sx_display_screens);
15266 defsubr (&Sx_display_planes);
15267 defsubr (&Sx_display_color_cells);
15268 defsubr (&Sx_display_visual_class);
15269 defsubr (&Sx_display_backing_store);
15270 defsubr (&Sx_display_save_under);
15271 defsubr (&Sx_parse_geometry);
15272 defsubr (&Sx_create_frame);
ee78dc32
GV
15273 defsubr (&Sx_open_connection);
15274 defsubr (&Sx_close_connection);
15275 defsubr (&Sx_display_list);
15276 defsubr (&Sx_synchronize);
15277
fbd6baed 15278 /* W32 specific functions */
ee78dc32 15279
1edf84e7 15280 defsubr (&Sw32_focus_frame);
fbd6baed
GV
15281 defsubr (&Sw32_select_font);
15282 defsubr (&Sw32_define_rgb_color);
15283 defsubr (&Sw32_default_color_map);
15284 defsubr (&Sw32_load_color_file);
1edf84e7 15285 defsubr (&Sw32_send_sys_command);
55dcfc15 15286 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
15287 defsubr (&Sw32_register_hot_key);
15288 defsubr (&Sw32_unregister_hot_key);
15289 defsubr (&Sw32_registered_hot_keys);
15290 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 15291 defsubr (&Sw32_toggle_lock_key);
33d52f9c 15292 defsubr (&Sw32_find_bdf_fonts);
4587b026 15293
2254bcde
AI
15294 defsubr (&Sfile_system_info);
15295
4587b026
GV
15296 /* Setting callback functions for fontset handler. */
15297 get_font_info_func = w32_get_font_info;
6fc2811b
JR
15298
15299#if 0 /* This function pointer doesn't seem to be used anywhere.
15300 And the pointer assigned has the wrong type, anyway. */
4587b026 15301 list_fonts_func = w32_list_fonts;
6fc2811b
JR
15302#endif
15303
4587b026
GV
15304 load_font_func = w32_load_font;
15305 find_ccl_program_func = w32_find_ccl_program;
15306 query_font_func = w32_query_font;
15307 set_frame_fontset_func = x_set_font;
15308 check_window_system_func = check_w32;
6fc2811b 15309
6fc2811b
JR
15310 /* Images. */
15311 Qxbm = intern ("xbm");
15312 staticpro (&Qxbm);
a93f4566
GM
15313 QCconversion = intern (":conversion");
15314 staticpro (&QCconversion);
6fc2811b
JR
15315 QCheuristic_mask = intern (":heuristic-mask");
15316 staticpro (&QCheuristic_mask);
15317 QCcolor_symbols = intern (":color-symbols");
15318 staticpro (&QCcolor_symbols);
6fc2811b
JR
15319 QCascent = intern (":ascent");
15320 staticpro (&QCascent);
15321 QCmargin = intern (":margin");
15322 staticpro (&QCmargin);
15323 QCrelief = intern (":relief");
15324 staticpro (&QCrelief);
15325 Qpostscript = intern ("postscript");
15326 staticpro (&Qpostscript);
ac849ba4 15327#if 0 /* TODO: These need entries at top of file. */
6fc2811b
JR
15328 QCloader = intern (":loader");
15329 staticpro (&QCloader);
15330 QCbounding_box = intern (":bounding-box");
15331 staticpro (&QCbounding_box);
15332 QCpt_width = intern (":pt-width");
15333 staticpro (&QCpt_width);
15334 QCpt_height = intern (":pt-height");
15335 staticpro (&QCpt_height);
ac849ba4 15336#endif
6fc2811b
JR
15337 QCindex = intern (":index");
15338 staticpro (&QCindex);
15339 Qpbm = intern ("pbm");
15340 staticpro (&Qpbm);
15341
15342#if HAVE_XPM
15343 Qxpm = intern ("xpm");
15344 staticpro (&Qxpm);
15345#endif
15346
15347#if HAVE_JPEG
15348 Qjpeg = intern ("jpeg");
15349 staticpro (&Qjpeg);
15350#endif
15351
15352#if HAVE_TIFF
15353 Qtiff = intern ("tiff");
15354 staticpro (&Qtiff);
15355#endif
15356
15357#if HAVE_GIF
15358 Qgif = intern ("gif");
15359 staticpro (&Qgif);
15360#endif
15361
15362#if HAVE_PNG
15363 Qpng = intern ("png");
15364 staticpro (&Qpng);
15365#endif
15366
15367 defsubr (&Sclear_image_cache);
ac849ba4
JR
15368 defsubr (&Simage_size);
15369 defsubr (&Simage_mask_p);
6fc2811b
JR
15370
15371#if GLYPH_DEBUG
15372 defsubr (&Simagep);
15373 defsubr (&Slookup_image);
15374#endif
6fc2811b 15375
0af913d7
GM
15376 hourglass_atimer = NULL;
15377 hourglass_shown_p = 0;
6fc2811b
JR
15378 defsubr (&Sx_show_tip);
15379 defsubr (&Sx_hide_tip);
6fc2811b 15380 tip_timer = Qnil;
57fa2774
JR
15381 staticpro (&tip_timer);
15382 tip_frame = Qnil;
15383 staticpro (&tip_frame);
6fc2811b 15384
ca56d953
JR
15385 last_show_tip_args = Qnil;
15386 staticpro (&last_show_tip_args);
15387
6fc2811b
JR
15388 defsubr (&Sx_file_dialog);
15389}
15390
15391
15392void
15393init_xfns ()
15394{
15395 image_types = NULL;
15396 Vimage_types = Qnil;
15397
ac849ba4 15398 define_image_type (&pbm_type);
6fc2811b 15399 define_image_type (&xbm_type);
217e5be0 15400#if 0 /* TODO : Image support for W32 */
6fc2811b 15401 define_image_type (&gs_type);
ac849ba4 15402#endif
6fc2811b
JR
15403
15404#if HAVE_XPM
15405 define_image_type (&xpm_type);
15406#endif
15407
15408#if HAVE_JPEG
15409 define_image_type (&jpeg_type);
15410#endif
15411
15412#if HAVE_TIFF
15413 define_image_type (&tiff_type);
15414#endif
919f1e88 15415
6fc2811b
JR
15416#if HAVE_GIF
15417 define_image_type (&gif_type);
15418#endif
15419
15420#if HAVE_PNG
15421 define_image_type (&png_type);
15422#endif
ee78dc32
GV
15423}
15424
15425#undef abort
15426
15427void
fbd6baed 15428w32_abort()
ee78dc32 15429{
5ac45f98
GV
15430 int button;
15431 button = MessageBox (NULL,
15432 "A fatal error has occurred!\n\n"
15433 "Select Abort to exit, Retry to debug, Ignore to continue",
15434 "Emacs Abort Dialog",
15435 MB_ICONEXCLAMATION | MB_TASKMODAL
15436 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15437 switch (button)
15438 {
15439 case IDRETRY:
15440 DebugBreak ();
15441 break;
15442 case IDIGNORE:
15443 break;
15444 case IDABORT:
15445 default:
15446 abort ();
15447 break;
15448 }
ee78dc32 15449}
d573caac 15450
83c75055
GV
15451/* For convenience when debugging. */
15452int
15453w32_last_error()
15454{
15455 return GetLastError ();
15456}