(x_report_frame_params): Makes the scroll-bar-width frame parameter have
[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
JR
131 and italic versions of fonts. */
132Lisp_Object Vw32_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
ee78dc32
GV
145/* The name we're using in resource queries. */
146Lisp_Object Vx_resource_name;
147
148/* Non nil if no window manager is in use. */
149Lisp_Object Vx_no_window_manager;
150
0af913d7 151/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 152
0af913d7 153int display_hourglass_p;
6fc2811b 154
ee78dc32
GV
155/* The background and shape of the mouse pointer, and shape when not
156 over text or in the modeline. */
dfff8a69 157
ee78dc32 158Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 159Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 160
ee78dc32 161/* The shape when over mouse-sensitive text. */
dfff8a69 162
ee78dc32
GV
163Lisp_Object Vx_sensitive_text_pointer_shape;
164
165/* Color of chars displayed in cursor box. */
dfff8a69 166
ee78dc32
GV
167Lisp_Object Vx_cursor_fore_pixel;
168
1edf84e7 169/* Nonzero if using Windows. */
dfff8a69 170
1edf84e7
GV
171static int w32_in_use;
172
ee78dc32 173/* Search path for bitmap files. */
dfff8a69 174
ee78dc32
GV
175Lisp_Object Vx_bitmap_file_path;
176
4587b026 177/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 178
4587b026
GV
179Lisp_Object Vx_pixel_size_width_font_regexp;
180
33d52f9c
GV
181/* Alist of bdf fonts and the files that define them. */
182Lisp_Object Vw32_bdf_filename_alist;
183
f46e6225 184/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
185int w32_strict_fontnames;
186
c0611964
AI
187/* A flag to control whether we should only repaint if GetUpdateRect
188 indicates there is an update region. */
189int w32_strict_painting;
190
dfff8a69
JR
191/* Associative list linking character set strings to Windows codepages. */
192Lisp_Object Vw32_charset_info_alist;
193
194/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
195#ifndef VIETNAMESE_CHARSET
196#define VIETNAMESE_CHARSET 163
197#endif
198
ee78dc32
GV
199Lisp_Object Qauto_raise;
200Lisp_Object Qauto_lower;
ee78dc32
GV
201Lisp_Object Qbar;
202Lisp_Object Qborder_color;
203Lisp_Object Qborder_width;
204Lisp_Object Qbox;
205Lisp_Object Qcursor_color;
206Lisp_Object Qcursor_type;
ee78dc32
GV
207Lisp_Object Qgeometry;
208Lisp_Object Qicon_left;
209Lisp_Object Qicon_top;
210Lisp_Object Qicon_type;
211Lisp_Object Qicon_name;
212Lisp_Object Qinternal_border_width;
213Lisp_Object Qleft;
1026b400 214Lisp_Object Qright;
ee78dc32
GV
215Lisp_Object Qmouse_color;
216Lisp_Object Qnone;
217Lisp_Object Qparent_id;
218Lisp_Object Qscroll_bar_width;
219Lisp_Object Qsuppress_icon;
ee78dc32
GV
220Lisp_Object Qundefined_color;
221Lisp_Object Qvertical_scroll_bars;
222Lisp_Object Qvisibility;
223Lisp_Object Qwindow_id;
224Lisp_Object Qx_frame_parameter;
225Lisp_Object Qx_resource_name;
226Lisp_Object Quser_position;
227Lisp_Object Quser_size;
6fc2811b 228Lisp_Object Qscreen_gamma;
dfff8a69
JR
229Lisp_Object Qline_spacing;
230Lisp_Object Qcenter;
dc220243 231Lisp_Object Qcancel_timer;
adcc3809
GV
232Lisp_Object Qhyper;
233Lisp_Object Qsuper;
234Lisp_Object Qmeta;
235Lisp_Object Qalt;
236Lisp_Object Qctrl;
237Lisp_Object Qcontrol;
238Lisp_Object Qshift;
239
dfff8a69
JR
240Lisp_Object Qw32_charset_ansi;
241Lisp_Object Qw32_charset_default;
242Lisp_Object Qw32_charset_symbol;
243Lisp_Object Qw32_charset_shiftjis;
767b1ff0 244Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
245Lisp_Object Qw32_charset_gb2312;
246Lisp_Object Qw32_charset_chinesebig5;
247Lisp_Object Qw32_charset_oem;
248
71eab8d1
AI
249#ifndef JOHAB_CHARSET
250#define JOHAB_CHARSET 130
251#endif
dfff8a69
JR
252#ifdef JOHAB_CHARSET
253Lisp_Object Qw32_charset_easteurope;
254Lisp_Object Qw32_charset_turkish;
255Lisp_Object Qw32_charset_baltic;
256Lisp_Object Qw32_charset_russian;
257Lisp_Object Qw32_charset_arabic;
258Lisp_Object Qw32_charset_greek;
259Lisp_Object Qw32_charset_hebrew;
767b1ff0 260Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
261Lisp_Object Qw32_charset_thai;
262Lisp_Object Qw32_charset_johab;
263Lisp_Object Qw32_charset_mac;
264#endif
265
266#ifdef UNICODE_CHARSET
267Lisp_Object Qw32_charset_unicode;
268#endif
269
6fc2811b
JR
270extern Lisp_Object Qtop;
271extern Lisp_Object Qdisplay;
272extern Lisp_Object Qtool_bar_lines;
273
5ac45f98
GV
274/* State variables for emulating a three button mouse. */
275#define LMOUSE 1
276#define MMOUSE 2
277#define RMOUSE 4
278
279static int button_state = 0;
fbd6baed 280static W32Msg saved_mouse_button_msg;
84fb1139 281static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 282static W32Msg saved_mouse_move_msg;
84fb1139
KH
283static unsigned mouse_move_timer;
284
9eb16b62
JR
285/* Window that is tracking the mouse. */
286static HWND track_mouse_window;
287FARPROC track_mouse_event_fn;
288
93fbe8b7
GV
289/* W95 mousewheel handler */
290unsigned int msh_mousewheel = 0;
291
84fb1139
KH
292#define MOUSE_BUTTON_ID 1
293#define MOUSE_MOVE_ID 2
5ac45f98 294
ee78dc32 295/* The below are defined in frame.c. */
dfff8a69 296
ee78dc32 297extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 298extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 299extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
300
301extern Lisp_Object Vwindow_system_version;
302
4b817373
RS
303Lisp_Object Qface_set_after_frame_default;
304
937e601e
AI
305#ifdef GLYPH_DEBUG
306int image_cache_refcount, dpyinfo_refcount;
307#endif
308
309
fbd6baed
GV
310/* From w32term.c. */
311extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 312extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 313
65906840
JR
314extern HWND w32_system_caret_hwnd;
315extern int w32_system_caret_width;
316extern int w32_system_caret_height;
317extern int w32_system_caret_x;
318extern int w32_system_caret_y;
319
ee78dc32 320\f
1edf84e7
GV
321/* Error if we are not connected to MS-Windows. */
322void
323check_w32 ()
324{
325 if (! w32_in_use)
326 error ("MS-Windows not in use or not initialized");
327}
328
329/* Nonzero if we can use mouse menus.
330 You should not call this unless HAVE_MENUS is defined. */
331
332int
333have_menus_p ()
334{
335 return w32_in_use;
336}
337
ee78dc32 338/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 339 and checking validity for W32. */
ee78dc32
GV
340
341FRAME_PTR
342check_x_frame (frame)
343 Lisp_Object frame;
344{
345 FRAME_PTR f;
346
347 if (NILP (frame))
6fc2811b 348 frame = selected_frame;
b7826503 349 CHECK_LIVE_FRAME (frame);
6fc2811b 350 f = XFRAME (frame);
fbd6baed
GV
351 if (! FRAME_W32_P (f))
352 error ("non-w32 frame used");
ee78dc32
GV
353 return f;
354}
355
356/* Let the user specify an display with a frame.
fbd6baed 357 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
358 the first display on the list. */
359
fbd6baed 360static struct w32_display_info *
ee78dc32
GV
361check_x_display_info (frame)
362 Lisp_Object frame;
363{
364 if (NILP (frame))
365 {
6fc2811b
JR
366 struct frame *sf = XFRAME (selected_frame);
367
368 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
369 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 370 else
fbd6baed 371 return &one_w32_display_info;
ee78dc32
GV
372 }
373 else if (STRINGP (frame))
374 return x_display_info_for_name (frame);
375 else
376 {
377 FRAME_PTR f;
378
b7826503 379 CHECK_LIVE_FRAME (frame);
ee78dc32 380 f = XFRAME (frame);
fbd6baed
GV
381 if (! FRAME_W32_P (f))
382 error ("non-w32 frame used");
383 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
384 }
385}
386\f
fbd6baed 387/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
388 It could be the frame's main window or an icon window. */
389
390/* This function can be called during GC, so use GC_xxx type test macros. */
391
392struct frame *
393x_window_to_frame (dpyinfo, wdesc)
fbd6baed 394 struct w32_display_info *dpyinfo;
ee78dc32
GV
395 HWND wdesc;
396{
397 Lisp_Object tail, frame;
398 struct frame *f;
399
8e713be6 400 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 401 {
8e713be6 402 frame = XCAR (tail);
ee78dc32
GV
403 if (!GC_FRAMEP (frame))
404 continue;
405 f = XFRAME (frame);
2d764c78 406 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 407 continue;
0af913d7 408 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
409 return f;
410
fbd6baed 411 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
412 return f;
413 }
414 return 0;
415}
416
417\f
418
419/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
420 id, which is just an int that this section returns. Bitmaps are
421 reference counted so they can be shared among frames.
422
423 Bitmap indices are guaranteed to be > 0, so a negative number can
424 be used to indicate no bitmap.
425
426 If you use x_create_bitmap_from_data, then you must keep track of
427 the bitmaps yourself. That is, creating a bitmap from the same
428 data more than once will not be caught. */
429
430
431/* Functions to access the contents of a bitmap, given an id. */
432
433int
434x_bitmap_height (f, id)
435 FRAME_PTR f;
436 int id;
437{
fbd6baed 438 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
439}
440
441int
442x_bitmap_width (f, id)
443 FRAME_PTR f;
444 int id;
445{
fbd6baed 446 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
447}
448
449int
450x_bitmap_pixmap (f, id)
451 FRAME_PTR f;
452 int id;
453{
fbd6baed 454 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
455}
456
457
458/* Allocate a new bitmap record. Returns index of new record. */
459
460static int
461x_allocate_bitmap_record (f)
462 FRAME_PTR f;
463{
fbd6baed 464 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
465 int i;
466
467 if (dpyinfo->bitmaps == NULL)
468 {
469 dpyinfo->bitmaps_size = 10;
470 dpyinfo->bitmaps
fbd6baed 471 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
472 dpyinfo->bitmaps_last = 1;
473 return 1;
474 }
475
476 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
477 return ++dpyinfo->bitmaps_last;
478
479 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
480 if (dpyinfo->bitmaps[i].refcount == 0)
481 return i + 1;
482
483 dpyinfo->bitmaps_size *= 2;
484 dpyinfo->bitmaps
fbd6baed
GV
485 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
486 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
487 return ++dpyinfo->bitmaps_last;
488}
489
490/* Add one reference to the reference count of the bitmap with id ID. */
491
492void
493x_reference_bitmap (f, id)
494 FRAME_PTR f;
495 int id;
496{
fbd6baed 497 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
498}
499
500/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
501
502int
503x_create_bitmap_from_data (f, bits, width, height)
504 struct frame *f;
505 char *bits;
506 unsigned int width, height;
507{
fbd6baed 508 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
509 Pixmap bitmap;
510 int id;
511
512 bitmap = CreateBitmap (width, height,
fbd6baed
GV
513 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
514 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
515 bits);
516
517 if (! bitmap)
518 return -1;
519
520 id = x_allocate_bitmap_record (f);
521 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
522 dpyinfo->bitmaps[id - 1].file = NULL;
523 dpyinfo->bitmaps[id - 1].hinst = NULL;
524 dpyinfo->bitmaps[id - 1].refcount = 1;
525 dpyinfo->bitmaps[id - 1].depth = 1;
526 dpyinfo->bitmaps[id - 1].height = height;
527 dpyinfo->bitmaps[id - 1].width = width;
528
529 return id;
530}
531
532/* Create bitmap from file FILE for frame F. */
533
534int
535x_create_bitmap_from_file (f, file)
536 struct frame *f;
537 Lisp_Object file;
538{
539 return -1;
767b1ff0 540#if 0 /* TODO : bitmap support */
fbd6baed 541 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 542 unsigned int width, height;
6fc2811b 543 HBITMAP bitmap;
ee78dc32
GV
544 int xhot, yhot, result, id;
545 Lisp_Object found;
546 int fd;
547 char *filename;
548 HINSTANCE hinst;
549
550 /* Look for an existing bitmap with the same name. */
551 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
552 {
553 if (dpyinfo->bitmaps[id].refcount
554 && dpyinfo->bitmaps[id].file
555 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
556 {
557 ++dpyinfo->bitmaps[id].refcount;
558 return id + 1;
559 }
560 }
561
562 /* Search bitmap-file-path for the file, if appropriate. */
c0ec53ad 563 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
ee78dc32
GV
564 if (fd < 0)
565 return -1;
6fc2811b 566 emacs_close (fd);
ee78dc32
GV
567
568 filename = (char *) XSTRING (found)->data;
569
570 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
571
572 if (hinst == NULL)
573 return -1;
574
575
fbd6baed 576 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
577 filename, &width, &height, &bitmap, &xhot, &yhot);
578 if (result != BitmapSuccess)
579 return -1;
580
581 id = x_allocate_bitmap_record (f);
582 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
583 dpyinfo->bitmaps[id - 1].refcount = 1;
584 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
585 dpyinfo->bitmaps[id - 1].depth = 1;
586 dpyinfo->bitmaps[id - 1].height = height;
587 dpyinfo->bitmaps[id - 1].width = width;
588 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
589
590 return id;
767b1ff0 591#endif /* TODO */
ee78dc32
GV
592}
593
594/* Remove reference to bitmap with id number ID. */
595
33d52f9c 596void
ee78dc32
GV
597x_destroy_bitmap (f, id)
598 FRAME_PTR f;
599 int id;
600{
fbd6baed 601 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
602
603 if (id > 0)
604 {
605 --dpyinfo->bitmaps[id - 1].refcount;
606 if (dpyinfo->bitmaps[id - 1].refcount == 0)
607 {
608 BLOCK_INPUT;
609 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
610 if (dpyinfo->bitmaps[id - 1].file)
611 {
6fc2811b 612 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
613 dpyinfo->bitmaps[id - 1].file = NULL;
614 }
615 UNBLOCK_INPUT;
616 }
617 }
618}
619
620/* Free all the bitmaps for the display specified by DPYINFO. */
621
622static void
623x_destroy_all_bitmaps (dpyinfo)
fbd6baed 624 struct w32_display_info *dpyinfo;
ee78dc32
GV
625{
626 int i;
627 for (i = 0; i < dpyinfo->bitmaps_last; i++)
628 if (dpyinfo->bitmaps[i].refcount > 0)
629 {
630 DeleteObject (dpyinfo->bitmaps[i].pixmap);
631 if (dpyinfo->bitmaps[i].file)
6fc2811b 632 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
633 }
634 dpyinfo->bitmaps_last = 0;
635}
636\f
fbd6baed 637/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
638 to the ways of passing the parameter values to the window system.
639
640 The name of a parameter, as a Lisp symbol,
641 has an `x-frame-parameter' property which is an integer in Lisp
642 but can be interpreted as an `enum x_frame_parm' in C. */
643
644enum x_frame_parm
645{
646 X_PARM_FOREGROUND_COLOR,
647 X_PARM_BACKGROUND_COLOR,
648 X_PARM_MOUSE_COLOR,
649 X_PARM_CURSOR_COLOR,
650 X_PARM_BORDER_COLOR,
651 X_PARM_ICON_TYPE,
652 X_PARM_FONT,
653 X_PARM_BORDER_WIDTH,
654 X_PARM_INTERNAL_BORDER_WIDTH,
655 X_PARM_NAME,
656 X_PARM_AUTORAISE,
657 X_PARM_AUTOLOWER,
658 X_PARM_VERT_SCROLL_BAR,
659 X_PARM_VISIBILITY,
660 X_PARM_MENU_BAR_LINES
661};
662
663
664struct x_frame_parm_table
665{
666 char *name;
6fc2811b 667 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
668};
669
ca56d953
JR
670BOOL my_show_window P_ ((struct frame *, HWND, int));
671void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
672static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
673static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
674static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 675/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 676void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 677static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
678void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
679void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
680void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
681void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
682void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
683void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
684void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
685void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 686static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
687void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
688void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
689 Lisp_Object));
690void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
691void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
692void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
693void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
694 Lisp_Object));
695void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
698void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
701static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
702static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
703 Lisp_Object));
ee78dc32
GV
704
705static struct x_frame_parm_table x_frame_parms[] =
706{
1edf84e7
GV
707 "auto-raise", x_set_autoraise,
708 "auto-lower", x_set_autolower,
ee78dc32 709 "background-color", x_set_background_color,
ee78dc32 710 "border-color", x_set_border_color,
1edf84e7
GV
711 "border-width", x_set_border_width,
712 "cursor-color", x_set_cursor_color,
ee78dc32 713 "cursor-type", x_set_cursor_type,
ee78dc32 714 "font", x_set_font,
1edf84e7
GV
715 "foreground-color", x_set_foreground_color,
716 "icon-name", x_set_icon_name,
717 "icon-type", x_set_icon_type,
ee78dc32 718 "internal-border-width", x_set_internal_border_width,
ee78dc32 719 "menu-bar-lines", x_set_menu_bar_lines,
1edf84e7
GV
720 "mouse-color", x_set_mouse_color,
721 "name", x_explicitly_set_name,
ee78dc32 722 "scroll-bar-width", x_set_scroll_bar_width,
1edf84e7 723 "title", x_set_title,
ee78dc32 724 "unsplittable", x_set_unsplittable,
1edf84e7
GV
725 "vertical-scroll-bars", x_set_vertical_scroll_bars,
726 "visibility", x_set_visibility,
6fc2811b 727 "tool-bar-lines", x_set_tool_bar_lines,
dfff8a69 728 "screen-gamma", x_set_screen_gamma,
41c1bdd9
KS
729 "line-spacing", x_set_line_spacing,
730 "left-fringe", x_set_fringe_width,
731 "right-fringe", x_set_fringe_width
732
ee78dc32
GV
733};
734
735/* Attach the `x-frame-parameter' properties to
fbd6baed 736 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 737
dfff8a69 738void
ee78dc32
GV
739init_x_parm_symbols ()
740{
741 int i;
742
743 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
744 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
745 make_number (i));
746}
747\f
dfff8a69 748/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
749 If a parameter is not specially recognized, do nothing;
750 otherwise call the `x_set_...' function for that parameter. */
751
752void
753x_set_frame_parameters (f, alist)
754 FRAME_PTR f;
755 Lisp_Object alist;
756{
757 Lisp_Object tail;
758
759 /* If both of these parameters are present, it's more efficient to
760 set them both at once. So we wait until we've looked at the
761 entire list before we set them. */
b839712d 762 int width, height;
ee78dc32
GV
763
764 /* Same here. */
765 Lisp_Object left, top;
766
767 /* Same with these. */
768 Lisp_Object icon_left, icon_top;
769
770 /* Record in these vectors all the parms specified. */
771 Lisp_Object *parms;
772 Lisp_Object *values;
a797a73d 773 int i, p;
ee78dc32
GV
774 int left_no_change = 0, top_no_change = 0;
775 int icon_left_no_change = 0, icon_top_no_change = 0;
776
5878523b
RS
777 struct gcpro gcpro1, gcpro2;
778
ee78dc32
GV
779 i = 0;
780 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
781 i++;
782
783 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
784 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
785
786 /* Extract parm names and values into those vectors. */
787
788 i = 0;
789 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
790 {
6fc2811b 791 Lisp_Object elt;
ee78dc32
GV
792
793 elt = Fcar (tail);
794 parms[i] = Fcar (elt);
795 values[i] = Fcdr (elt);
796 i++;
797 }
5878523b
RS
798 /* TAIL and ALIST are not used again below here. */
799 alist = tail = Qnil;
800
801 GCPRO2 (*parms, *values);
802 gcpro1.nvars = i;
803 gcpro2.nvars = i;
804
805 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
806 because their values appear in VALUES and strings are not valid. */
b839712d 807 top = left = Qunbound;
ee78dc32
GV
808 icon_left = icon_top = Qunbound;
809
b839712d 810 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
811 if (FRAME_NEW_WIDTH (f))
812 width = FRAME_NEW_WIDTH (f);
813 else
814 width = FRAME_WIDTH (f);
815
816 if (FRAME_NEW_HEIGHT (f))
817 height = FRAME_NEW_HEIGHT (f);
818 else
819 height = FRAME_HEIGHT (f);
b839712d 820
a797a73d
GV
821 /* Process foreground_color and background_color before anything else.
822 They are independent of other properties, but other properties (e.g.,
823 cursor_color) are dependent upon them. */
41c1bdd9 824 /* Process default font as well, since fringe widths depends on it. */
a797a73d
GV
825 for (p = 0; p < i; p++)
826 {
827 Lisp_Object prop, val;
828
829 prop = parms[p];
830 val = values[p];
41c1bdd9
KS
831 if (EQ (prop, Qforeground_color)
832 || EQ (prop, Qbackground_color)
833 || EQ (prop, Qfont))
a797a73d
GV
834 {
835 register Lisp_Object param_index, old_value;
836
a797a73d 837 old_value = get_frame_param (f, prop);
a05e2bae
JR
838
839 if (NILP (Fequal (val, old_value)))
840 {
841 store_frame_param (f, prop, val);
842
843 param_index = Fget (prop, Qx_frame_parameter);
844 if (NATNUMP (param_index)
845 && (XFASTINT (param_index)
846 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
847 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
848 }
a797a73d
GV
849 }
850 }
851
ee78dc32
GV
852 /* Now process them in reverse of specified order. */
853 for (i--; i >= 0; i--)
854 {
855 Lisp_Object prop, val;
856
857 prop = parms[i];
858 val = values[i];
859
b839712d
RS
860 if (EQ (prop, Qwidth) && NUMBERP (val))
861 width = XFASTINT (val);
862 else if (EQ (prop, Qheight) && NUMBERP (val))
863 height = XFASTINT (val);
ee78dc32
GV
864 else if (EQ (prop, Qtop))
865 top = val;
866 else if (EQ (prop, Qleft))
867 left = val;
868 else if (EQ (prop, Qicon_top))
869 icon_top = val;
870 else if (EQ (prop, Qicon_left))
871 icon_left = val;
41c1bdd9
KS
872 else if (EQ (prop, Qforeground_color)
873 || EQ (prop, Qbackground_color)
874 || EQ (prop, Qfont))
a797a73d
GV
875 /* Processed above. */
876 continue;
ee78dc32
GV
877 else
878 {
879 register Lisp_Object param_index, old_value;
880
ee78dc32 881 old_value = get_frame_param (f, prop);
a05e2bae 882
ee78dc32 883 store_frame_param (f, prop, val);
a05e2bae
JR
884
885 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
886 if (NATNUMP (param_index)
887 && (XFASTINT (param_index)
888 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 889 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
890 }
891 }
892
893 /* Don't die if just one of these was set. */
894 if (EQ (left, Qunbound))
895 {
896 left_no_change = 1;
fbd6baed
GV
897 if (f->output_data.w32->left_pos < 0)
898 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 899 else
fbd6baed 900 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
901 }
902 if (EQ (top, Qunbound))
903 {
904 top_no_change = 1;
fbd6baed
GV
905 if (f->output_data.w32->top_pos < 0)
906 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 907 else
fbd6baed 908 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
909 }
910
911 /* If one of the icon positions was not set, preserve or default it. */
912 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
913 {
914 icon_left_no_change = 1;
915 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
916 if (NILP (icon_left))
917 XSETINT (icon_left, 0);
918 }
919 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
920 {
921 icon_top_no_change = 1;
922 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
923 if (NILP (icon_top))
924 XSETINT (icon_top, 0);
925 }
926
ee78dc32
GV
927 /* Don't set these parameters unless they've been explicitly
928 specified. The window might be mapped or resized while we're in
929 this function, and we don't want to override that unless the lisp
930 code has asked for it.
931
932 Don't set these parameters unless they actually differ from the
933 window's current parameters; the window may not actually exist
934 yet. */
935 {
936 Lisp_Object frame;
937
938 check_frame_size (f, &height, &width);
939
940 XSETFRAME (frame, f);
941
dfff8a69
JR
942 if (width != FRAME_WIDTH (f)
943 || height != FRAME_HEIGHT (f)
944 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 945 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
946
947 if ((!NILP (left) || !NILP (top))
948 && ! (left_no_change && top_no_change)
fbd6baed
GV
949 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
950 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
951 {
952 int leftpos = 0;
953 int toppos = 0;
954
955 /* Record the signs. */
fbd6baed 956 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 957 if (EQ (left, Qminus))
fbd6baed 958 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
959 else if (INTEGERP (left))
960 {
961 leftpos = XINT (left);
962 if (leftpos < 0)
fbd6baed 963 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 964 }
8e713be6
KR
965 else if (CONSP (left) && EQ (XCAR (left), Qminus)
966 && CONSP (XCDR (left))
967 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 968 {
8e713be6 969 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 970 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 971 }
8e713be6
KR
972 else if (CONSP (left) && EQ (XCAR (left), Qplus)
973 && CONSP (XCDR (left))
974 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 975 {
8e713be6 976 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
977 }
978
979 if (EQ (top, Qminus))
fbd6baed 980 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
981 else if (INTEGERP (top))
982 {
983 toppos = XINT (top);
984 if (toppos < 0)
fbd6baed 985 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 986 }
8e713be6
KR
987 else if (CONSP (top) && EQ (XCAR (top), Qminus)
988 && CONSP (XCDR (top))
989 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 990 {
8e713be6 991 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 992 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 993 }
8e713be6
KR
994 else if (CONSP (top) && EQ (XCAR (top), Qplus)
995 && CONSP (XCDR (top))
996 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 997 {
8e713be6 998 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
999 }
1000
1001
1002 /* Store the numeric value of the position. */
fbd6baed
GV
1003 f->output_data.w32->top_pos = toppos;
1004 f->output_data.w32->left_pos = leftpos;
ee78dc32 1005
fbd6baed 1006 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1007
1008 /* Actually set that position, and convert to absolute. */
1009 x_set_offset (f, leftpos, toppos, -1);
1010 }
1011
1012 if ((!NILP (icon_left) || !NILP (icon_top))
1013 && ! (icon_left_no_change && icon_top_no_change))
1014 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1015 }
5878523b
RS
1016
1017 UNGCPRO;
ee78dc32
GV
1018}
1019
1020/* Store the screen positions of frame F into XPTR and YPTR.
1021 These are the positions of the containing window manager window,
1022 not Emacs's own window. */
1023
1024void
1025x_real_positions (f, xptr, yptr)
1026 FRAME_PTR f;
1027 int *xptr, *yptr;
1028{
1029 POINT pt;
3c190163
GV
1030
1031 {
1032 RECT rect;
ee78dc32 1033
fbd6baed
GV
1034 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1035 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 1036
3c190163
GV
1037 pt.x = rect.left;
1038 pt.y = rect.top;
1039 }
ee78dc32 1040
fbd6baed 1041 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
1042
1043 *xptr = pt.x;
1044 *yptr = pt.y;
1045}
1046
1047/* Insert a description of internally-recorded parameters of frame X
1048 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1049 Only parameters that are specific to W32
ee78dc32
GV
1050 and whose values are not correctly recorded in the frame's
1051 param_alist need to be considered here. */
1052
dfff8a69 1053void
ee78dc32
GV
1054x_report_frame_params (f, alistptr)
1055 struct frame *f;
1056 Lisp_Object *alistptr;
1057{
1058 char buf[16];
1059 Lisp_Object tem;
1060
1061 /* Represent negative positions (off the top or left screen edge)
1062 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1063 XSETINT (tem, f->output_data.w32->left_pos);
1064 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1065 store_in_alist (alistptr, Qleft, tem);
1066 else
1067 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1068
fbd6baed
GV
1069 XSETINT (tem, f->output_data.w32->top_pos);
1070 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1071 store_in_alist (alistptr, Qtop, tem);
1072 else
1073 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1074
1075 store_in_alist (alistptr, Qborder_width,
fbd6baed 1076 make_number (f->output_data.w32->border_width));
ee78dc32 1077 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1078 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1079 store_in_alist (alistptr, Qleft_fringe,
1080 make_number (f->output_data.w32->left_fringe_width));
1081 store_in_alist (alistptr, Qright_fringe,
1082 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1083 store_in_alist (alistptr, Qscroll_bar_width,
1084 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1085 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1086 : 0));
fbd6baed 1087 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1088 store_in_alist (alistptr, Qwindow_id,
1089 build_string (buf));
1090 store_in_alist (alistptr, Qicon_name, f->icon_name);
1091 FRAME_SAMPLE_VISIBILITY (f);
1092 store_in_alist (alistptr, Qvisibility,
1093 (FRAME_VISIBLE_P (f) ? Qt
1094 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1095 store_in_alist (alistptr, Qdisplay,
8e713be6 1096 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1097}
1098\f
1099
74e1aeec
JR
1100DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1101 Sw32_define_rgb_color, 4, 4, 0,
1102 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1103This adds or updates a named color to w32-color-map, making it
1104available for use. The original entry's RGB ref is returned, or nil
1105if the entry is new. */)
5ac45f98
GV
1106 (red, green, blue, name)
1107 Lisp_Object red, green, blue, name;
ee78dc32 1108{
5ac45f98
GV
1109 Lisp_Object rgb;
1110 Lisp_Object oldrgb = Qnil;
1111 Lisp_Object entry;
1112
b7826503
PJ
1113 CHECK_NUMBER (red);
1114 CHECK_NUMBER (green);
1115 CHECK_NUMBER (blue);
1116 CHECK_STRING (name);
ee78dc32 1117
5ac45f98 1118 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1119
5ac45f98 1120 BLOCK_INPUT;
ee78dc32 1121
fbd6baed
GV
1122 /* replace existing entry in w32-color-map or add new entry. */
1123 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1124 if (NILP (entry))
1125 {
1126 entry = Fcons (name, rgb);
fbd6baed 1127 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1128 }
1129 else
1130 {
1131 oldrgb = Fcdr (entry);
1132 Fsetcdr (entry, rgb);
1133 }
1134
1135 UNBLOCK_INPUT;
1136
1137 return (oldrgb);
ee78dc32
GV
1138}
1139
74e1aeec
JR
1140DEFUN ("w32-load-color-file", Fw32_load_color_file,
1141 Sw32_load_color_file, 1, 1, 0,
1142 doc: /* Create an alist of color entries from an external file.
1143Assign this value to w32-color-map to replace the existing color map.
1144
1145The file should define one named RGB color per line like so:
1146 R G B name
1147where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1148 (filename)
1149 Lisp_Object filename;
1150{
1151 FILE *fp;
1152 Lisp_Object cmap = Qnil;
1153 Lisp_Object abspath;
1154
b7826503 1155 CHECK_STRING (filename);
5ac45f98
GV
1156 abspath = Fexpand_file_name (filename, Qnil);
1157
1158 fp = fopen (XSTRING (filename)->data, "rt");
1159 if (fp)
1160 {
1161 char buf[512];
1162 int red, green, blue;
1163 int num;
1164
1165 BLOCK_INPUT;
1166
1167 while (fgets (buf, sizeof (buf), fp) != NULL) {
1168 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1169 {
1170 char *name = buf + num;
1171 num = strlen (name) - 1;
1172 if (name[num] == '\n')
1173 name[num] = 0;
1174 cmap = Fcons (Fcons (build_string (name),
1175 make_number (RGB (red, green, blue))),
1176 cmap);
1177 }
1178 }
1179 fclose (fp);
1180
1181 UNBLOCK_INPUT;
1182 }
1183
1184 return cmap;
1185}
ee78dc32 1186
fbd6baed 1187/* The default colors for the w32 color map */
ee78dc32
GV
1188typedef struct colormap_t
1189{
1190 char *name;
1191 COLORREF colorref;
1192} colormap_t;
1193
fbd6baed 1194colormap_t w32_color_map[] =
ee78dc32 1195{
1da8a614
GV
1196 {"snow" , PALETTERGB (255,250,250)},
1197 {"ghost white" , PALETTERGB (248,248,255)},
1198 {"GhostWhite" , PALETTERGB (248,248,255)},
1199 {"white smoke" , PALETTERGB (245,245,245)},
1200 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1201 {"gainsboro" , PALETTERGB (220,220,220)},
1202 {"floral white" , PALETTERGB (255,250,240)},
1203 {"FloralWhite" , PALETTERGB (255,250,240)},
1204 {"old lace" , PALETTERGB (253,245,230)},
1205 {"OldLace" , PALETTERGB (253,245,230)},
1206 {"linen" , PALETTERGB (250,240,230)},
1207 {"antique white" , PALETTERGB (250,235,215)},
1208 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1209 {"papaya whip" , PALETTERGB (255,239,213)},
1210 {"PapayaWhip" , PALETTERGB (255,239,213)},
1211 {"blanched almond" , PALETTERGB (255,235,205)},
1212 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1213 {"bisque" , PALETTERGB (255,228,196)},
1214 {"peach puff" , PALETTERGB (255,218,185)},
1215 {"PeachPuff" , PALETTERGB (255,218,185)},
1216 {"navajo white" , PALETTERGB (255,222,173)},
1217 {"NavajoWhite" , PALETTERGB (255,222,173)},
1218 {"moccasin" , PALETTERGB (255,228,181)},
1219 {"cornsilk" , PALETTERGB (255,248,220)},
1220 {"ivory" , PALETTERGB (255,255,240)},
1221 {"lemon chiffon" , PALETTERGB (255,250,205)},
1222 {"LemonChiffon" , PALETTERGB (255,250,205)},
1223 {"seashell" , PALETTERGB (255,245,238)},
1224 {"honeydew" , PALETTERGB (240,255,240)},
1225 {"mint cream" , PALETTERGB (245,255,250)},
1226 {"MintCream" , PALETTERGB (245,255,250)},
1227 {"azure" , PALETTERGB (240,255,255)},
1228 {"alice blue" , PALETTERGB (240,248,255)},
1229 {"AliceBlue" , PALETTERGB (240,248,255)},
1230 {"lavender" , PALETTERGB (230,230,250)},
1231 {"lavender blush" , PALETTERGB (255,240,245)},
1232 {"LavenderBlush" , PALETTERGB (255,240,245)},
1233 {"misty rose" , PALETTERGB (255,228,225)},
1234 {"MistyRose" , PALETTERGB (255,228,225)},
1235 {"white" , PALETTERGB (255,255,255)},
1236 {"black" , PALETTERGB ( 0, 0, 0)},
1237 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1238 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1239 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1240 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1241 {"dim gray" , PALETTERGB (105,105,105)},
1242 {"DimGray" , PALETTERGB (105,105,105)},
1243 {"dim grey" , PALETTERGB (105,105,105)},
1244 {"DimGrey" , PALETTERGB (105,105,105)},
1245 {"slate gray" , PALETTERGB (112,128,144)},
1246 {"SlateGray" , PALETTERGB (112,128,144)},
1247 {"slate grey" , PALETTERGB (112,128,144)},
1248 {"SlateGrey" , PALETTERGB (112,128,144)},
1249 {"light slate gray" , PALETTERGB (119,136,153)},
1250 {"LightSlateGray" , PALETTERGB (119,136,153)},
1251 {"light slate grey" , PALETTERGB (119,136,153)},
1252 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1253 {"gray" , PALETTERGB (190,190,190)},
1254 {"grey" , PALETTERGB (190,190,190)},
1255 {"light grey" , PALETTERGB (211,211,211)},
1256 {"LightGrey" , PALETTERGB (211,211,211)},
1257 {"light gray" , PALETTERGB (211,211,211)},
1258 {"LightGray" , PALETTERGB (211,211,211)},
1259 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1260 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1261 {"navy" , PALETTERGB ( 0, 0,128)},
1262 {"navy blue" , PALETTERGB ( 0, 0,128)},
1263 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1264 {"cornflower blue" , PALETTERGB (100,149,237)},
1265 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1266 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1267 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1268 {"slate blue" , PALETTERGB (106, 90,205)},
1269 {"SlateBlue" , PALETTERGB (106, 90,205)},
1270 {"medium slate blue" , PALETTERGB (123,104,238)},
1271 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1272 {"light slate blue" , PALETTERGB (132,112,255)},
1273 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1274 {"medium blue" , PALETTERGB ( 0, 0,205)},
1275 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1276 {"royal blue" , PALETTERGB ( 65,105,225)},
1277 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1278 {"blue" , PALETTERGB ( 0, 0,255)},
1279 {"dodger blue" , PALETTERGB ( 30,144,255)},
1280 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1281 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1282 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1283 {"sky blue" , PALETTERGB (135,206,235)},
1284 {"SkyBlue" , PALETTERGB (135,206,235)},
1285 {"light sky blue" , PALETTERGB (135,206,250)},
1286 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1287 {"steel blue" , PALETTERGB ( 70,130,180)},
1288 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1289 {"light steel blue" , PALETTERGB (176,196,222)},
1290 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1291 {"light blue" , PALETTERGB (173,216,230)},
1292 {"LightBlue" , PALETTERGB (173,216,230)},
1293 {"powder blue" , PALETTERGB (176,224,230)},
1294 {"PowderBlue" , PALETTERGB (176,224,230)},
1295 {"pale turquoise" , PALETTERGB (175,238,238)},
1296 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1297 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1298 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1299 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1300 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1301 {"turquoise" , PALETTERGB ( 64,224,208)},
1302 {"cyan" , PALETTERGB ( 0,255,255)},
1303 {"light cyan" , PALETTERGB (224,255,255)},
1304 {"LightCyan" , PALETTERGB (224,255,255)},
1305 {"cadet blue" , PALETTERGB ( 95,158,160)},
1306 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1307 {"medium aquamarine" , PALETTERGB (102,205,170)},
1308 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1309 {"aquamarine" , PALETTERGB (127,255,212)},
1310 {"dark green" , PALETTERGB ( 0,100, 0)},
1311 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1312 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1313 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1314 {"dark sea green" , PALETTERGB (143,188,143)},
1315 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1316 {"sea green" , PALETTERGB ( 46,139, 87)},
1317 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1318 {"medium sea green" , PALETTERGB ( 60,179,113)},
1319 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1320 {"light sea green" , PALETTERGB ( 32,178,170)},
1321 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1322 {"pale green" , PALETTERGB (152,251,152)},
1323 {"PaleGreen" , PALETTERGB (152,251,152)},
1324 {"spring green" , PALETTERGB ( 0,255,127)},
1325 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1326 {"lawn green" , PALETTERGB (124,252, 0)},
1327 {"LawnGreen" , PALETTERGB (124,252, 0)},
1328 {"green" , PALETTERGB ( 0,255, 0)},
1329 {"chartreuse" , PALETTERGB (127,255, 0)},
1330 {"medium spring green" , PALETTERGB ( 0,250,154)},
1331 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1332 {"green yellow" , PALETTERGB (173,255, 47)},
1333 {"GreenYellow" , PALETTERGB (173,255, 47)},
1334 {"lime green" , PALETTERGB ( 50,205, 50)},
1335 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1336 {"yellow green" , PALETTERGB (154,205, 50)},
1337 {"YellowGreen" , PALETTERGB (154,205, 50)},
1338 {"forest green" , PALETTERGB ( 34,139, 34)},
1339 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1340 {"olive drab" , PALETTERGB (107,142, 35)},
1341 {"OliveDrab" , PALETTERGB (107,142, 35)},
1342 {"dark khaki" , PALETTERGB (189,183,107)},
1343 {"DarkKhaki" , PALETTERGB (189,183,107)},
1344 {"khaki" , PALETTERGB (240,230,140)},
1345 {"pale goldenrod" , PALETTERGB (238,232,170)},
1346 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1347 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1348 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1349 {"light yellow" , PALETTERGB (255,255,224)},
1350 {"LightYellow" , PALETTERGB (255,255,224)},
1351 {"yellow" , PALETTERGB (255,255, 0)},
1352 {"gold" , PALETTERGB (255,215, 0)},
1353 {"light goldenrod" , PALETTERGB (238,221,130)},
1354 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1355 {"goldenrod" , PALETTERGB (218,165, 32)},
1356 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1357 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1358 {"rosy brown" , PALETTERGB (188,143,143)},
1359 {"RosyBrown" , PALETTERGB (188,143,143)},
1360 {"indian red" , PALETTERGB (205, 92, 92)},
1361 {"IndianRed" , PALETTERGB (205, 92, 92)},
1362 {"saddle brown" , PALETTERGB (139, 69, 19)},
1363 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1364 {"sienna" , PALETTERGB (160, 82, 45)},
1365 {"peru" , PALETTERGB (205,133, 63)},
1366 {"burlywood" , PALETTERGB (222,184,135)},
1367 {"beige" , PALETTERGB (245,245,220)},
1368 {"wheat" , PALETTERGB (245,222,179)},
1369 {"sandy brown" , PALETTERGB (244,164, 96)},
1370 {"SandyBrown" , PALETTERGB (244,164, 96)},
1371 {"tan" , PALETTERGB (210,180,140)},
1372 {"chocolate" , PALETTERGB (210,105, 30)},
1373 {"firebrick" , PALETTERGB (178,34, 34)},
1374 {"brown" , PALETTERGB (165,42, 42)},
1375 {"dark salmon" , PALETTERGB (233,150,122)},
1376 {"DarkSalmon" , PALETTERGB (233,150,122)},
1377 {"salmon" , PALETTERGB (250,128,114)},
1378 {"light salmon" , PALETTERGB (255,160,122)},
1379 {"LightSalmon" , PALETTERGB (255,160,122)},
1380 {"orange" , PALETTERGB (255,165, 0)},
1381 {"dark orange" , PALETTERGB (255,140, 0)},
1382 {"DarkOrange" , PALETTERGB (255,140, 0)},
1383 {"coral" , PALETTERGB (255,127, 80)},
1384 {"light coral" , PALETTERGB (240,128,128)},
1385 {"LightCoral" , PALETTERGB (240,128,128)},
1386 {"tomato" , PALETTERGB (255, 99, 71)},
1387 {"orange red" , PALETTERGB (255, 69, 0)},
1388 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1389 {"red" , PALETTERGB (255, 0, 0)},
1390 {"hot pink" , PALETTERGB (255,105,180)},
1391 {"HotPink" , PALETTERGB (255,105,180)},
1392 {"deep pink" , PALETTERGB (255, 20,147)},
1393 {"DeepPink" , PALETTERGB (255, 20,147)},
1394 {"pink" , PALETTERGB (255,192,203)},
1395 {"light pink" , PALETTERGB (255,182,193)},
1396 {"LightPink" , PALETTERGB (255,182,193)},
1397 {"pale violet red" , PALETTERGB (219,112,147)},
1398 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1399 {"maroon" , PALETTERGB (176, 48, 96)},
1400 {"medium violet red" , PALETTERGB (199, 21,133)},
1401 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1402 {"violet red" , PALETTERGB (208, 32,144)},
1403 {"VioletRed" , PALETTERGB (208, 32,144)},
1404 {"magenta" , PALETTERGB (255, 0,255)},
1405 {"violet" , PALETTERGB (238,130,238)},
1406 {"plum" , PALETTERGB (221,160,221)},
1407 {"orchid" , PALETTERGB (218,112,214)},
1408 {"medium orchid" , PALETTERGB (186, 85,211)},
1409 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1410 {"dark orchid" , PALETTERGB (153, 50,204)},
1411 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1412 {"dark violet" , PALETTERGB (148, 0,211)},
1413 {"DarkViolet" , PALETTERGB (148, 0,211)},
1414 {"blue violet" , PALETTERGB (138, 43,226)},
1415 {"BlueViolet" , PALETTERGB (138, 43,226)},
1416 {"purple" , PALETTERGB (160, 32,240)},
1417 {"medium purple" , PALETTERGB (147,112,219)},
1418 {"MediumPurple" , PALETTERGB (147,112,219)},
1419 {"thistle" , PALETTERGB (216,191,216)},
1420 {"gray0" , PALETTERGB ( 0, 0, 0)},
1421 {"grey0" , PALETTERGB ( 0, 0, 0)},
1422 {"dark grey" , PALETTERGB (169,169,169)},
1423 {"DarkGrey" , PALETTERGB (169,169,169)},
1424 {"dark gray" , PALETTERGB (169,169,169)},
1425 {"DarkGray" , PALETTERGB (169,169,169)},
1426 {"dark blue" , PALETTERGB ( 0, 0,139)},
1427 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1428 {"dark cyan" , PALETTERGB ( 0,139,139)},
1429 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1430 {"dark magenta" , PALETTERGB (139, 0,139)},
1431 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1432 {"dark red" , PALETTERGB (139, 0, 0)},
1433 {"DarkRed" , PALETTERGB (139, 0, 0)},
1434 {"light green" , PALETTERGB (144,238,144)},
1435 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1436};
1437
fbd6baed 1438DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1439 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1440 ()
1441{
1442 int i;
fbd6baed 1443 colormap_t *pc = w32_color_map;
ee78dc32
GV
1444 Lisp_Object cmap;
1445
1446 BLOCK_INPUT;
1447
1448 cmap = Qnil;
1449
fbd6baed 1450 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1451 pc++, i++)
1452 cmap = Fcons (Fcons (build_string (pc->name),
1453 make_number (pc->colorref)),
1454 cmap);
1455
1456 UNBLOCK_INPUT;
1457
1458 return (cmap);
1459}
ee78dc32
GV
1460
1461Lisp_Object
fbd6baed 1462w32_to_x_color (rgb)
ee78dc32
GV
1463 Lisp_Object rgb;
1464{
1465 Lisp_Object color;
1466
b7826503 1467 CHECK_NUMBER (rgb);
ee78dc32
GV
1468
1469 BLOCK_INPUT;
1470
fbd6baed 1471 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1472
1473 UNBLOCK_INPUT;
1474
1475 if (!NILP (color))
1476 return (Fcar (color));
1477 else
1478 return Qnil;
1479}
1480
5d7fed93
GV
1481COLORREF
1482w32_color_map_lookup (colorname)
1483 char *colorname;
1484{
1485 Lisp_Object tail, ret = Qnil;
1486
1487 BLOCK_INPUT;
1488
1489 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1490 {
1491 register Lisp_Object elt, tem;
1492
1493 elt = Fcar (tail);
1494 if (!CONSP (elt)) continue;
1495
1496 tem = Fcar (elt);
1497
1498 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1499 {
1500 ret = XUINT (Fcdr (elt));
1501 break;
1502 }
1503
1504 QUIT;
1505 }
1506
1507
1508 UNBLOCK_INPUT;
1509
1510 return ret;
1511}
1512
ee78dc32 1513COLORREF
fbd6baed 1514x_to_w32_color (colorname)
ee78dc32
GV
1515 char * colorname;
1516{
8edb0a6f
JR
1517 register Lisp_Object ret = Qnil;
1518
ee78dc32 1519 BLOCK_INPUT;
1edf84e7
GV
1520
1521 if (colorname[0] == '#')
1522 {
1523 /* Could be an old-style RGB Device specification. */
1524 char *color;
1525 int size;
1526 color = colorname + 1;
1527
1528 size = strlen(color);
1529 if (size == 3 || size == 6 || size == 9 || size == 12)
1530 {
1531 UINT colorval;
1532 int i, pos;
1533 pos = 0;
1534 size /= 3;
1535 colorval = 0;
1536
1537 for (i = 0; i < 3; i++)
1538 {
1539 char *end;
1540 char t;
1541 unsigned long value;
1542
1543 /* The check for 'x' in the following conditional takes into
1544 account the fact that strtol allows a "0x" in front of
1545 our numbers, and we don't. */
1546 if (!isxdigit(color[0]) || color[1] == 'x')
1547 break;
1548 t = color[size];
1549 color[size] = '\0';
1550 value = strtoul(color, &end, 16);
1551 color[size] = t;
1552 if (errno == ERANGE || end - color != size)
1553 break;
1554 switch (size)
1555 {
1556 case 1:
1557 value = value * 0x10;
1558 break;
1559 case 2:
1560 break;
1561 case 3:
1562 value /= 0x10;
1563 break;
1564 case 4:
1565 value /= 0x100;
1566 break;
1567 }
1568 colorval |= (value << pos);
1569 pos += 0x8;
1570 if (i == 2)
1571 {
1572 UNBLOCK_INPUT;
1573 return (colorval);
1574 }
1575 color = end;
1576 }
1577 }
1578 }
1579 else if (strnicmp(colorname, "rgb:", 4) == 0)
1580 {
1581 char *color;
1582 UINT colorval;
1583 int i, pos;
1584 pos = 0;
1585
1586 colorval = 0;
1587 color = colorname + 4;
1588 for (i = 0; i < 3; i++)
1589 {
1590 char *end;
1591 unsigned long value;
1592
1593 /* The check for 'x' in the following conditional takes into
1594 account the fact that strtol allows a "0x" in front of
1595 our numbers, and we don't. */
1596 if (!isxdigit(color[0]) || color[1] == 'x')
1597 break;
1598 value = strtoul(color, &end, 16);
1599 if (errno == ERANGE)
1600 break;
1601 switch (end - color)
1602 {
1603 case 1:
1604 value = value * 0x10 + value;
1605 break;
1606 case 2:
1607 break;
1608 case 3:
1609 value /= 0x10;
1610 break;
1611 case 4:
1612 value /= 0x100;
1613 break;
1614 default:
1615 value = ULONG_MAX;
1616 }
1617 if (value == ULONG_MAX)
1618 break;
1619 colorval |= (value << pos);
1620 pos += 0x8;
1621 if (i == 2)
1622 {
1623 if (*end != '\0')
1624 break;
1625 UNBLOCK_INPUT;
1626 return (colorval);
1627 }
1628 if (*end != '/')
1629 break;
1630 color = end + 1;
1631 }
1632 }
1633 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1634 {
1635 /* This is an RGB Intensity specification. */
1636 char *color;
1637 UINT colorval;
1638 int i, pos;
1639 pos = 0;
1640
1641 colorval = 0;
1642 color = colorname + 5;
1643 for (i = 0; i < 3; i++)
1644 {
1645 char *end;
1646 double value;
1647 UINT val;
1648
1649 value = strtod(color, &end);
1650 if (errno == ERANGE)
1651 break;
1652 if (value < 0.0 || value > 1.0)
1653 break;
1654 val = (UINT)(0x100 * value);
1655 /* We used 0x100 instead of 0xFF to give an continuous
1656 range between 0.0 and 1.0 inclusive. The next statement
1657 fixes the 1.0 case. */
1658 if (val == 0x100)
1659 val = 0xFF;
1660 colorval |= (val << pos);
1661 pos += 0x8;
1662 if (i == 2)
1663 {
1664 if (*end != '\0')
1665 break;
1666 UNBLOCK_INPUT;
1667 return (colorval);
1668 }
1669 if (*end != '/')
1670 break;
1671 color = end + 1;
1672 }
1673 }
1674 /* I am not going to attempt to handle any of the CIE color schemes
1675 or TekHVC, since I don't know the algorithms for conversion to
1676 RGB. */
f695b4b1
GV
1677
1678 /* If we fail to lookup the color name in w32_color_map, then check the
1679 colorname to see if it can be crudely approximated: If the X color
1680 ends in a number (e.g., "darkseagreen2"), strip the number and
1681 return the result of looking up the base color name. */
1682 ret = w32_color_map_lookup (colorname);
1683 if (NILP (ret))
ee78dc32 1684 {
f695b4b1 1685 int len = strlen (colorname);
ee78dc32 1686
f695b4b1
GV
1687 if (isdigit (colorname[len - 1]))
1688 {
8b77111c 1689 char *ptr, *approx = alloca (len + 1);
ee78dc32 1690
f695b4b1
GV
1691 strcpy (approx, colorname);
1692 ptr = &approx[len - 1];
1693 while (ptr > approx && isdigit (*ptr))
1694 *ptr-- = '\0';
ee78dc32 1695
f695b4b1 1696 ret = w32_color_map_lookup (approx);
ee78dc32 1697 }
ee78dc32
GV
1698 }
1699
1700 UNBLOCK_INPUT;
ee78dc32
GV
1701 return ret;
1702}
1703
5ac45f98
GV
1704
1705void
fbd6baed 1706w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1707{
fbd6baed 1708 struct w32_palette_entry * list;
5ac45f98
GV
1709 LOGPALETTE * log_palette;
1710 HPALETTE new_palette;
1711 int i;
1712
1713 /* don't bother trying to create palette if not supported */
fbd6baed 1714 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1715 return;
1716
1717 log_palette = (LOGPALETTE *)
1718 alloca (sizeof (LOGPALETTE) +
fbd6baed 1719 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1720 log_palette->palVersion = 0x300;
fbd6baed 1721 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1722
fbd6baed 1723 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1724 for (i = 0;
fbd6baed 1725 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1726 i++, list = list->next)
1727 log_palette->palPalEntry[i] = list->entry;
1728
1729 new_palette = CreatePalette (log_palette);
1730
1731 enter_crit ();
1732
fbd6baed
GV
1733 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1734 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1735 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1736
1737 /* Realize display palette and garbage all frames. */
1738 release_frame_dc (f, get_frame_dc (f));
1739
1740 leave_crit ();
1741}
1742
fbd6baed
GV
1743#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1744#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1745 do \
1746 { \
1747 pe.peRed = GetRValue (color); \
1748 pe.peGreen = GetGValue (color); \
1749 pe.peBlue = GetBValue (color); \
1750 pe.peFlags = 0; \
1751 } while (0)
1752
1753#if 0
1754/* Keep these around in case we ever want to track color usage. */
1755void
fbd6baed 1756w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1757{
fbd6baed 1758 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1759
fbd6baed 1760 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1761 return;
1762
1763 /* check if color is already mapped */
1764 while (list)
1765 {
fbd6baed 1766 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1767 {
1768 ++list->refcount;
1769 return;
1770 }
1771 list = list->next;
1772 }
1773
1774 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1775 list = (struct w32_palette_entry *)
1776 xmalloc (sizeof (struct w32_palette_entry));
1777 SET_W32_COLOR (list->entry, color);
5ac45f98 1778 list->refcount = 1;
fbd6baed
GV
1779 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1780 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1781 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1782
1783 /* set flag that palette must be regenerated */
fbd6baed 1784 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1785}
1786
1787void
fbd6baed 1788w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1789{
fbd6baed
GV
1790 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1791 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1792
fbd6baed 1793 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1794 return;
1795
1796 /* check if color is already mapped */
1797 while (list)
1798 {
fbd6baed 1799 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1800 {
1801 if (--list->refcount == 0)
1802 {
1803 *prev = list->next;
1804 xfree (list);
fbd6baed 1805 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1806 break;
1807 }
1808 else
1809 return;
1810 }
1811 prev = &list->next;
1812 list = list->next;
1813 }
1814
1815 /* set flag that palette must be regenerated */
fbd6baed 1816 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1817}
1818#endif
1819
6fc2811b
JR
1820
1821/* Gamma-correct COLOR on frame F. */
1822
1823void
1824gamma_correct (f, color)
1825 struct frame *f;
1826 COLORREF *color;
1827{
1828 if (f->gamma)
1829 {
1830 *color = PALETTERGB (
1831 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1832 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1833 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1834 }
1835}
1836
1837
ee78dc32
GV
1838/* Decide if color named COLOR is valid for the display associated with
1839 the selected frame; if so, return the rgb values in COLOR_DEF.
1840 If ALLOC is nonzero, allocate a new colormap cell. */
1841
1842int
6fc2811b 1843w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1844 FRAME_PTR f;
1845 char *color;
6fc2811b 1846 XColor *color_def;
ee78dc32
GV
1847 int alloc;
1848{
1849 register Lisp_Object tem;
6fc2811b 1850 COLORREF w32_color_ref;
3c190163 1851
fbd6baed 1852 tem = x_to_w32_color (color);
3c190163 1853
ee78dc32
GV
1854 if (!NILP (tem))
1855 {
d88c567c
JR
1856 if (f)
1857 {
1858 /* Apply gamma correction. */
1859 w32_color_ref = XUINT (tem);
1860 gamma_correct (f, &w32_color_ref);
1861 XSETINT (tem, w32_color_ref);
1862 }
9badad41
JR
1863
1864 /* Map this color to the palette if it is enabled. */
fbd6baed 1865 if (!NILP (Vw32_enable_palette))
5ac45f98 1866 {
fbd6baed 1867 struct w32_palette_entry * entry =
d88c567c 1868 one_w32_display_info.color_list;
fbd6baed 1869 struct w32_palette_entry ** prev =
d88c567c 1870 &one_w32_display_info.color_list;
5ac45f98
GV
1871
1872 /* check if color is already mapped */
1873 while (entry)
1874 {
fbd6baed 1875 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1876 break;
1877 prev = &entry->next;
1878 entry = entry->next;
1879 }
1880
1881 if (entry == NULL && alloc)
1882 {
1883 /* not already mapped, so add to list */
fbd6baed
GV
1884 entry = (struct w32_palette_entry *)
1885 xmalloc (sizeof (struct w32_palette_entry));
1886 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1887 entry->next = NULL;
1888 *prev = entry;
d88c567c 1889 one_w32_display_info.num_colors++;
5ac45f98
GV
1890
1891 /* set flag that palette must be regenerated */
d88c567c 1892 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1893 }
1894 }
1895 /* Ensure COLORREF value is snapped to nearest color in (default)
1896 palette by simulating the PALETTERGB macro. This works whether
1897 or not the display device has a palette. */
6fc2811b
JR
1898 w32_color_ref = XUINT (tem) | 0x2000000;
1899
6fc2811b
JR
1900 color_def->pixel = w32_color_ref;
1901 color_def->red = GetRValue (w32_color_ref);
1902 color_def->green = GetGValue (w32_color_ref);
1903 color_def->blue = GetBValue (w32_color_ref);
1904
ee78dc32 1905 return 1;
5ac45f98 1906 }
7fb46567 1907 else
3c190163
GV
1908 {
1909 return 0;
1910 }
ee78dc32
GV
1911}
1912
1913/* Given a string ARG naming a color, compute a pixel value from it
1914 suitable for screen F.
1915 If F is not a color screen, return DEF (default) regardless of what
1916 ARG says. */
1917
1918int
1919x_decode_color (f, arg, def)
1920 FRAME_PTR f;
1921 Lisp_Object arg;
1922 int def;
1923{
6fc2811b 1924 XColor cdef;
ee78dc32 1925
b7826503 1926 CHECK_STRING (arg);
ee78dc32
GV
1927
1928 if (strcmp (XSTRING (arg)->data, "black") == 0)
1929 return BLACK_PIX_DEFAULT (f);
1930 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1931 return WHITE_PIX_DEFAULT (f);
1932
fbd6baed 1933 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1934 return def;
1935
6fc2811b 1936 /* w32_defined_color is responsible for coping with failures
ee78dc32 1937 by looking for a near-miss. */
6fc2811b
JR
1938 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1939 return cdef.pixel;
ee78dc32
GV
1940
1941 /* defined_color failed; return an ultimate default. */
1942 return def;
1943}
1944\f
dfff8a69
JR
1945/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1946 the previous value of that parameter, NEW_VALUE is the new value. */
1947
1948static void
1949x_set_line_spacing (f, new_value, old_value)
1950 struct frame *f;
1951 Lisp_Object new_value, old_value;
1952{
1953 if (NILP (new_value))
1954 f->extra_line_spacing = 0;
1955 else if (NATNUMP (new_value))
1956 f->extra_line_spacing = XFASTINT (new_value);
1957 else
1a948b17 1958 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
1959 Fcons (new_value, Qnil)));
1960 if (FRAME_VISIBLE_P (f))
1961 redraw_frame (f);
1962}
1963
1964
6fc2811b
JR
1965/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1966 the previous value of that parameter, NEW_VALUE is the new value. */
1967
1968static void
1969x_set_screen_gamma (f, new_value, old_value)
1970 struct frame *f;
1971 Lisp_Object new_value, old_value;
1972{
1973 if (NILP (new_value))
1974 f->gamma = 0;
1975 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1976 /* The value 0.4545 is the normal viewing gamma. */
1977 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1978 else
1a948b17 1979 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
1980 Fcons (new_value, Qnil)));
1981
1982 clear_face_cache (0);
1983}
1984
1985
ee78dc32
GV
1986/* Functions called only from `x_set_frame_param'
1987 to set individual parameters.
1988
fbd6baed 1989 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1990 the frame is being created and its window does not exist yet.
1991 In that case, just record the parameter's new value
1992 in the standard place; do not attempt to change the window. */
1993
1994void
1995x_set_foreground_color (f, arg, oldval)
1996 struct frame *f;
1997 Lisp_Object arg, oldval;
1998{
3cf3436e
JR
1999 struct w32_output *x = f->output_data.w32;
2000 PIX_TYPE fg, old_fg;
2001
2002 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2003 old_fg = FRAME_FOREGROUND_PIXEL (f);
2004 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2005
fbd6baed 2006 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2007 {
3cf3436e
JR
2008 if (x->cursor_pixel == old_fg)
2009 x->cursor_pixel = fg;
2010
6fc2811b 2011 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2012 if (FRAME_VISIBLE_P (f))
2013 redraw_frame (f);
2014 }
2015}
2016
2017void
2018x_set_background_color (f, arg, oldval)
2019 struct frame *f;
2020 Lisp_Object arg, oldval;
2021{
6fc2811b 2022 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2023 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2024
fbd6baed 2025 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2026 {
6fc2811b
JR
2027 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2028 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2029
6fc2811b 2030 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2031
2032 if (FRAME_VISIBLE_P (f))
2033 redraw_frame (f);
2034 }
2035}
2036
2037void
2038x_set_mouse_color (f, arg, oldval)
2039 struct frame *f;
2040 Lisp_Object arg, oldval;
2041{
ee78dc32 2042 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2043 int count;
ee78dc32
GV
2044 int mask_color;
2045
2046 if (!EQ (Qnil, arg))
fbd6baed 2047 f->output_data.w32->mouse_pixel
ee78dc32 2048 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2049 mask_color = FRAME_BACKGROUND_PIXEL (f);
2050
2051 /* Don't let pointers be invisible. */
fbd6baed 2052 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2053 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2054 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2055
767b1ff0 2056#if 0 /* TODO : cursor changes */
ee78dc32
GV
2057 BLOCK_INPUT;
2058
2059 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2060 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2061
2062 if (!EQ (Qnil, Vx_pointer_shape))
2063 {
b7826503 2064 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2065 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2066 }
2067 else
fbd6baed
GV
2068 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2069 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2070
2071 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2072 {
b7826503 2073 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2074 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2075 XINT (Vx_nontext_pointer_shape));
2076 }
2077 else
fbd6baed
GV
2078 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2079 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2080
0af913d7 2081 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2082 {
b7826503 2083 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2084 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2085 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2086 }
2087 else
0af913d7 2088 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b
JR
2089 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2090
2091 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2092 if (!EQ (Qnil, Vx_mode_pointer_shape))
2093 {
b7826503 2094 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2095 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2096 XINT (Vx_mode_pointer_shape));
2097 }
2098 else
fbd6baed
GV
2099 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2100 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2101
2102 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2103 {
b7826503 2104 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2105 cross_cursor
fbd6baed 2106 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2107 XINT (Vx_sensitive_text_pointer_shape));
2108 }
2109 else
fbd6baed 2110 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2111
4694d762
JR
2112 if (!NILP (Vx_window_horizontal_drag_shape))
2113 {
b7826503 2114 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2115 horizontal_drag_cursor
2116 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2117 XINT (Vx_window_horizontal_drag_shape));
2118 }
2119 else
2120 horizontal_drag_cursor
2121 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2122
ee78dc32 2123 /* Check and report errors with the above calls. */
fbd6baed 2124 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2125 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2126
2127 {
2128 XColor fore_color, back_color;
2129
fbd6baed 2130 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2131 back_color.pixel = mask_color;
fbd6baed
GV
2132 XQueryColor (FRAME_W32_DISPLAY (f),
2133 DefaultColormap (FRAME_W32_DISPLAY (f),
2134 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2135 &fore_color);
fbd6baed
GV
2136 XQueryColor (FRAME_W32_DISPLAY (f),
2137 DefaultColormap (FRAME_W32_DISPLAY (f),
2138 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2139 &back_color);
fbd6baed 2140 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2141 &fore_color, &back_color);
fbd6baed 2142 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2143 &fore_color, &back_color);
fbd6baed 2144 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2145 &fore_color, &back_color);
fbd6baed 2146 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2147 &fore_color, &back_color);
0af913d7 2148 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2149 &fore_color, &back_color);
ee78dc32
GV
2150 }
2151
fbd6baed 2152 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2153 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2154
fbd6baed
GV
2155 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2156 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2157 f->output_data.w32->text_cursor = cursor;
2158
2159 if (nontext_cursor != f->output_data.w32->nontext_cursor
2160 && f->output_data.w32->nontext_cursor != 0)
2161 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2162 f->output_data.w32->nontext_cursor = nontext_cursor;
2163
0af913d7
GM
2164 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2165 && f->output_data.w32->hourglass_cursor != 0)
2166 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2167 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2168
fbd6baed
GV
2169 if (mode_cursor != f->output_data.w32->modeline_cursor
2170 && f->output_data.w32->modeline_cursor != 0)
2171 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2172 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2173
fbd6baed
GV
2174 if (cross_cursor != f->output_data.w32->cross_cursor
2175 && f->output_data.w32->cross_cursor != 0)
2176 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2177 f->output_data.w32->cross_cursor = cross_cursor;
2178
2179 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2180 UNBLOCK_INPUT;
6fc2811b
JR
2181
2182 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2183#endif /* TODO */
ee78dc32
GV
2184}
2185
70a0239a
JR
2186/* Defined in w32term.c. */
2187void x_update_cursor (struct frame *f, int on_p);
2188
ee78dc32
GV
2189void
2190x_set_cursor_color (f, arg, oldval)
2191 struct frame *f;
2192 Lisp_Object arg, oldval;
2193{
70a0239a 2194 unsigned long fore_pixel, pixel;
ee78dc32 2195
dfff8a69 2196 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2197 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2198 WHITE_PIX_DEFAULT (f));
ee78dc32 2199 else
6fc2811b 2200 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2201
6759f872 2202 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2203
2204 /* Make sure that the cursor color differs from the background color. */
70a0239a 2205 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2206 {
70a0239a
JR
2207 pixel = f->output_data.w32->mouse_pixel;
2208 if (pixel == fore_pixel)
6fc2811b 2209 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2210 }
70a0239a 2211
6fc2811b 2212 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
70a0239a 2213 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2214
fbd6baed 2215 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2216 {
2217 if (FRAME_VISIBLE_P (f))
2218 {
70a0239a
JR
2219 x_update_cursor (f, 0);
2220 x_update_cursor (f, 1);
ee78dc32
GV
2221 }
2222 }
6fc2811b
JR
2223
2224 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2225}
2226
33d52f9c
GV
2227/* Set the border-color of frame F to pixel value PIX.
2228 Note that this does not fully take effect if done before
2229 F has an window. */
2230void
2231x_set_border_pixel (f, pix)
2232 struct frame *f;
2233 int pix;
2234{
2235 f->output_data.w32->border_pixel = pix;
2236
2237 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2238 {
2239 if (FRAME_VISIBLE_P (f))
2240 redraw_frame (f);
2241 }
2242}
2243
ee78dc32
GV
2244/* Set the border-color of frame F to value described by ARG.
2245 ARG can be a string naming a color.
2246 The border-color is used for the border that is drawn by the server.
2247 Note that this does not fully take effect if done before
2248 F has a window; it must be redone when the window is created. */
2249
2250void
2251x_set_border_color (f, arg, oldval)
2252 struct frame *f;
2253 Lisp_Object arg, oldval;
2254{
ee78dc32
GV
2255 int pix;
2256
b7826503 2257 CHECK_STRING (arg);
ee78dc32 2258 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2259 x_set_border_pixel (f, pix);
6fc2811b 2260 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2261}
2262
dfff8a69
JR
2263/* Value is the internal representation of the specified cursor type
2264 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2265 of the bar cursor. */
2266
2267enum text_cursor_kinds
2268x_specified_cursor_type (arg, width)
2269 Lisp_Object arg;
2270 int *width;
ee78dc32 2271{
dfff8a69
JR
2272 enum text_cursor_kinds type;
2273
ee78dc32
GV
2274 if (EQ (arg, Qbar))
2275 {
dfff8a69
JR
2276 type = BAR_CURSOR;
2277 *width = 2;
ee78dc32 2278 }
dfff8a69
JR
2279 else if (CONSP (arg)
2280 && EQ (XCAR (arg), Qbar)
2281 && INTEGERP (XCDR (arg))
2282 && XINT (XCDR (arg)) >= 0)
ee78dc32 2283 {
dfff8a69
JR
2284 type = BAR_CURSOR;
2285 *width = XINT (XCDR (arg));
ee78dc32 2286 }
dfff8a69
JR
2287 else if (NILP (arg))
2288 type = NO_CURSOR;
ee78dc32
GV
2289 else
2290 /* Treat anything unknown as "box cursor".
2291 It was bad to signal an error; people have trouble fixing
2292 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2293 type = FILLED_BOX_CURSOR;
2294
2295 return type;
2296}
2297
2298void
2299x_set_cursor_type (f, arg, oldval)
2300 FRAME_PTR f;
2301 Lisp_Object arg, oldval;
2302{
2303 int width;
2304
2305 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2306 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2307
2308 /* Make sure the cursor gets redrawn. This is overkill, but how
2309 often do people change cursor types? */
2310 update_mode_lines++;
2311}
dfff8a69 2312\f
ee78dc32
GV
2313void
2314x_set_icon_type (f, arg, oldval)
2315 struct frame *f;
2316 Lisp_Object arg, oldval;
2317{
ee78dc32
GV
2318 int result;
2319
eb7576ce
GV
2320 if (NILP (arg) && NILP (oldval))
2321 return;
2322
2323 if (STRINGP (arg) && STRINGP (oldval)
2324 && EQ (Fstring_equal (oldval, arg), Qt))
2325 return;
2326
2327 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2328 return;
2329
2330 BLOCK_INPUT;
ee78dc32 2331
eb7576ce 2332 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2333 if (result)
2334 {
2335 UNBLOCK_INPUT;
2336 error ("No icon window available");
2337 }
2338
ee78dc32 2339 UNBLOCK_INPUT;
ee78dc32
GV
2340}
2341
2342/* Return non-nil if frame F wants a bitmap icon. */
2343
2344Lisp_Object
2345x_icon_type (f)
2346 FRAME_PTR f;
2347{
2348 Lisp_Object tem;
2349
2350 tem = assq_no_quit (Qicon_type, f->param_alist);
2351 if (CONSP (tem))
8e713be6 2352 return XCDR (tem);
ee78dc32
GV
2353 else
2354 return Qnil;
2355}
2356
2357void
2358x_set_icon_name (f, arg, oldval)
2359 struct frame *f;
2360 Lisp_Object arg, oldval;
2361{
ee78dc32
GV
2362 if (STRINGP (arg))
2363 {
2364 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2365 return;
2366 }
2367 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2368 return;
2369
2370 f->icon_name = arg;
2371
2372#if 0
fbd6baed 2373 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2374 return;
2375
2376 BLOCK_INPUT;
2377
2378 result = x_text_icon (f,
1edf84e7 2379 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2380 ? f->icon_name
1edf84e7
GV
2381 : !NILP (f->title)
2382 ? f->title
ee78dc32
GV
2383 : f->name))->data);
2384
2385 if (result)
2386 {
2387 UNBLOCK_INPUT;
2388 error ("No icon window available");
2389 }
2390
2391 /* If the window was unmapped (and its icon was mapped),
2392 the new icon is not mapped, so map the window in its stead. */
2393 if (FRAME_VISIBLE_P (f))
2394 {
2395#ifdef USE_X_TOOLKIT
fbd6baed 2396 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2397#endif
fbd6baed 2398 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2399 }
2400
fbd6baed 2401 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2402 UNBLOCK_INPUT;
2403#endif
2404}
2405
2406extern Lisp_Object x_new_font ();
4587b026 2407extern Lisp_Object x_new_fontset();
ee78dc32
GV
2408
2409void
2410x_set_font (f, arg, oldval)
2411 struct frame *f;
2412 Lisp_Object arg, oldval;
2413{
2414 Lisp_Object result;
4587b026 2415 Lisp_Object fontset_name;
4b817373 2416 Lisp_Object frame;
3cf3436e 2417 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2418
b7826503 2419 CHECK_STRING (arg);
ee78dc32 2420
4587b026
GV
2421 fontset_name = Fquery_fontset (arg, Qnil);
2422
ee78dc32 2423 BLOCK_INPUT;
4587b026
GV
2424 result = (STRINGP (fontset_name)
2425 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2426 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2427 UNBLOCK_INPUT;
2428
2429 if (EQ (result, Qnil))
dfff8a69 2430 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2431 else if (EQ (result, Qt))
dfff8a69 2432 error ("The characters of the given font have varying widths");
ee78dc32
GV
2433 else if (STRINGP (result))
2434 {
3cf3436e
JR
2435 if (STRINGP (fontset_name))
2436 {
2437 /* Fontset names are built from ASCII font names, so the
2438 names may be equal despite there was a change. */
2439 if (old_fontset == FRAME_FONTSET (f))
2440 return;
2441 }
2442 else if (!NILP (Fequal (result, oldval)))
dc220243 2443 return;
3cf3436e 2444
ee78dc32 2445 store_frame_param (f, Qfont, result);
6fc2811b 2446 recompute_basic_faces (f);
ee78dc32
GV
2447 }
2448 else
2449 abort ();
4b817373 2450
6fc2811b
JR
2451 do_pending_window_change (0);
2452
2453 /* Don't call `face-set-after-frame-default' when faces haven't been
2454 initialized yet. This is the case when called from
2455 Fx_create_frame. In that case, the X widget or window doesn't
2456 exist either, and we can end up in x_report_frame_params with a
2457 null widget which gives a segfault. */
2458 if (FRAME_FACE_CACHE (f))
2459 {
2460 XSETFRAME (frame, f);
2461 call1 (Qface_set_after_frame_default, frame);
2462 }
ee78dc32
GV
2463}
2464
41c1bdd9
KS
2465static void
2466x_set_fringe_width (f, new_value, old_value)
2467 struct frame *f;
2468 Lisp_Object new_value, old_value;
2469{
2470 x_compute_fringe_widths (f, 1);
2471}
2472
ee78dc32
GV
2473void
2474x_set_border_width (f, arg, oldval)
2475 struct frame *f;
2476 Lisp_Object arg, oldval;
2477{
b7826503 2478 CHECK_NUMBER (arg);
ee78dc32 2479
fbd6baed 2480 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2481 return;
2482
fbd6baed 2483 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2484 error ("Cannot change the border width of a window");
2485
fbd6baed 2486 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2487}
2488
2489void
2490x_set_internal_border_width (f, arg, oldval)
2491 struct frame *f;
2492 Lisp_Object arg, oldval;
2493{
fbd6baed 2494 int old = f->output_data.w32->internal_border_width;
ee78dc32 2495
b7826503 2496 CHECK_NUMBER (arg);
fbd6baed
GV
2497 f->output_data.w32->internal_border_width = XINT (arg);
2498 if (f->output_data.w32->internal_border_width < 0)
2499 f->output_data.w32->internal_border_width = 0;
ee78dc32 2500
fbd6baed 2501 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2502 return;
2503
fbd6baed 2504 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2505 {
ee78dc32 2506 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2507 SET_FRAME_GARBAGED (f);
6fc2811b 2508 do_pending_window_change (0);
ee78dc32 2509 }
a05e2bae
JR
2510 else
2511 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2512}
2513
2514void
2515x_set_visibility (f, value, oldval)
2516 struct frame *f;
2517 Lisp_Object value, oldval;
2518{
2519 Lisp_Object frame;
2520 XSETFRAME (frame, f);
2521
2522 if (NILP (value))
2523 Fmake_frame_invisible (frame, Qt);
2524 else if (EQ (value, Qicon))
2525 Ficonify_frame (frame);
2526 else
2527 Fmake_frame_visible (frame);
2528}
2529
a1258667
JR
2530\f
2531/* Change window heights in windows rooted in WINDOW by N lines. */
2532
2533static void
2534x_change_window_heights (window, n)
2535 Lisp_Object window;
2536 int n;
2537{
2538 struct window *w = XWINDOW (window);
2539
2540 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2541 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2542
2543 if (INTEGERP (w->orig_top))
2544 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2545 if (INTEGERP (w->orig_height))
2546 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2547
2548 /* Handle just the top child in a vertical split. */
2549 if (!NILP (w->vchild))
2550 x_change_window_heights (w->vchild, n);
2551
2552 /* Adjust all children in a horizontal split. */
2553 for (window = w->hchild; !NILP (window); window = w->next)
2554 {
2555 w = XWINDOW (window);
2556 x_change_window_heights (window, n);
2557 }
2558}
2559
ee78dc32
GV
2560void
2561x_set_menu_bar_lines (f, value, oldval)
2562 struct frame *f;
2563 Lisp_Object value, oldval;
2564{
2565 int nlines;
2566 int olines = FRAME_MENU_BAR_LINES (f);
2567
2568 /* Right now, menu bars don't work properly in minibuf-only frames;
2569 most of the commands try to apply themselves to the minibuffer
6fc2811b 2570 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2571 in or split the minibuffer window. */
2572 if (FRAME_MINIBUF_ONLY_P (f))
2573 return;
2574
2575 if (INTEGERP (value))
2576 nlines = XINT (value);
2577 else
2578 nlines = 0;
2579
2580 FRAME_MENU_BAR_LINES (f) = 0;
2581 if (nlines)
2582 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2583 else
2584 {
2585 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2586 free_frame_menubar (f);
2587 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2588
2589 /* Adjust the frame size so that the client (text) dimensions
2590 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2591 set correctly. */
2592 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2593 do_pending_window_change (0);
ee78dc32 2594 }
6fc2811b
JR
2595 adjust_glyphs (f);
2596}
2597
2598
2599/* Set the number of lines used for the tool bar of frame F to VALUE.
2600 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2601 is the old number of tool bar lines. This function changes the
2602 height of all windows on frame F to match the new tool bar height.
2603 The frame's height doesn't change. */
2604
2605void
2606x_set_tool_bar_lines (f, value, oldval)
2607 struct frame *f;
2608 Lisp_Object value, oldval;
2609{
36f8209a
JR
2610 int delta, nlines, root_height;
2611 Lisp_Object root_window;
6fc2811b 2612
dc220243
JR
2613 /* Treat tool bars like menu bars. */
2614 if (FRAME_MINIBUF_ONLY_P (f))
2615 return;
2616
6fc2811b
JR
2617 /* Use VALUE only if an integer >= 0. */
2618 if (INTEGERP (value) && XINT (value) >= 0)
2619 nlines = XFASTINT (value);
2620 else
2621 nlines = 0;
2622
2623 /* Make sure we redisplay all windows in this frame. */
2624 ++windows_or_buffers_changed;
2625
2626 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2627
2628 /* Don't resize the tool-bar to more than we have room for. */
2629 root_window = FRAME_ROOT_WINDOW (f);
2630 root_height = XINT (XWINDOW (root_window)->height);
2631 if (root_height - delta < 1)
2632 {
2633 delta = root_height - 1;
2634 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2635 }
2636
6fc2811b 2637 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2638 x_change_window_heights (root_window, delta);
6fc2811b 2639 adjust_glyphs (f);
36f8209a
JR
2640
2641 /* We also have to make sure that the internal border at the top of
2642 the frame, below the menu bar or tool bar, is redrawn when the
2643 tool bar disappears. This is so because the internal border is
2644 below the tool bar if one is displayed, but is below the menu bar
2645 if there isn't a tool bar. The tool bar draws into the area
2646 below the menu bar. */
2647 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2648 {
2649 updating_frame = f;
2650 clear_frame ();
2651 clear_current_matrices (f);
2652 updating_frame = NULL;
2653 }
2654
2655 /* If the tool bar gets smaller, the internal border below it
2656 has to be cleared. It was formerly part of the display
2657 of the larger tool bar, and updating windows won't clear it. */
2658 if (delta < 0)
2659 {
2660 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2661 int width = PIXEL_WIDTH (f);
2662 int y = nlines * CANON_Y_UNIT (f);
2663
2664 BLOCK_INPUT;
2665 {
2666 HDC hdc = get_frame_dc (f);
2667 w32_clear_area (f, hdc, 0, y, width, height);
2668 release_frame_dc (f, hdc);
2669 }
2670 UNBLOCK_INPUT;
3cf3436e
JR
2671
2672 if (WINDOWP (f->tool_bar_window))
2673 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2674 }
ee78dc32
GV
2675}
2676
6fc2811b 2677
ee78dc32 2678/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2679 w32_id_name.
ee78dc32
GV
2680
2681 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2682 name; if NAME is a string, set F's name to NAME and set
2683 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2684
2685 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2686 suggesting a new name, which lisp code should override; if
2687 F->explicit_name is set, ignore the new name; otherwise, set it. */
2688
2689void
2690x_set_name (f, name, explicit)
2691 struct frame *f;
2692 Lisp_Object name;
2693 int explicit;
2694{
2695 /* Make sure that requests from lisp code override requests from
2696 Emacs redisplay code. */
2697 if (explicit)
2698 {
2699 /* If we're switching from explicit to implicit, we had better
2700 update the mode lines and thereby update the title. */
2701 if (f->explicit_name && NILP (name))
2702 update_mode_lines = 1;
2703
2704 f->explicit_name = ! NILP (name);
2705 }
2706 else if (f->explicit_name)
2707 return;
2708
fbd6baed 2709 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2710 if (NILP (name))
2711 {
2712 /* Check for no change needed in this very common case
2713 before we do any consing. */
fbd6baed 2714 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2715 XSTRING (f->name)->data))
2716 return;
fbd6baed 2717 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2718 }
2719 else
b7826503 2720 CHECK_STRING (name);
ee78dc32
GV
2721
2722 /* Don't change the name if it's already NAME. */
2723 if (! NILP (Fstring_equal (name, f->name)))
2724 return;
2725
1edf84e7
GV
2726 f->name = name;
2727
2728 /* For setting the frame title, the title parameter should override
2729 the name parameter. */
2730 if (! NILP (f->title))
2731 name = f->title;
2732
fbd6baed 2733 if (FRAME_W32_WINDOW (f))
ee78dc32 2734 {
6fc2811b 2735 if (STRING_MULTIBYTE (name))
dfff8a69 2736 name = ENCODE_SYSTEM (name);
6fc2811b 2737
ee78dc32 2738 BLOCK_INPUT;
fbd6baed 2739 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2740 UNBLOCK_INPUT;
2741 }
ee78dc32
GV
2742}
2743
2744/* This function should be called when the user's lisp code has
2745 specified a name for the frame; the name will override any set by the
2746 redisplay code. */
2747void
2748x_explicitly_set_name (f, arg, oldval)
2749 FRAME_PTR f;
2750 Lisp_Object arg, oldval;
2751{
2752 x_set_name (f, arg, 1);
2753}
2754
2755/* This function should be called by Emacs redisplay code to set the
2756 name; names set this way will never override names set by the user's
2757 lisp code. */
2758void
2759x_implicitly_set_name (f, arg, oldval)
2760 FRAME_PTR f;
2761 Lisp_Object arg, oldval;
2762{
2763 x_set_name (f, arg, 0);
2764}
1edf84e7
GV
2765\f
2766/* Change the title of frame F to NAME.
2767 If NAME is nil, use the frame name as the title.
2768
2769 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2770 name; if NAME is a string, set F's name to NAME and set
2771 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2772
2773 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2774 suggesting a new name, which lisp code should override; if
2775 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2776
1edf84e7 2777void
6fc2811b 2778x_set_title (f, name, old_name)
1edf84e7 2779 struct frame *f;
6fc2811b 2780 Lisp_Object name, old_name;
1edf84e7
GV
2781{
2782 /* Don't change the title if it's already NAME. */
2783 if (EQ (name, f->title))
2784 return;
2785
2786 update_mode_lines = 1;
2787
2788 f->title = name;
2789
2790 if (NILP (name))
2791 name = f->name;
2792
2793 if (FRAME_W32_WINDOW (f))
2794 {
6fc2811b 2795 if (STRING_MULTIBYTE (name))
dfff8a69 2796 name = ENCODE_SYSTEM (name);
6fc2811b 2797
1edf84e7
GV
2798 BLOCK_INPUT;
2799 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2800 UNBLOCK_INPUT;
2801 }
2802}
2803\f
ee78dc32
GV
2804void
2805x_set_autoraise (f, arg, oldval)
2806 struct frame *f;
2807 Lisp_Object arg, oldval;
2808{
2809 f->auto_raise = !EQ (Qnil, arg);
2810}
2811
2812void
2813x_set_autolower (f, arg, oldval)
2814 struct frame *f;
2815 Lisp_Object arg, oldval;
2816{
2817 f->auto_lower = !EQ (Qnil, arg);
2818}
2819
2820void
2821x_set_unsplittable (f, arg, oldval)
2822 struct frame *f;
2823 Lisp_Object arg, oldval;
2824{
2825 f->no_split = !NILP (arg);
2826}
2827
2828void
2829x_set_vertical_scroll_bars (f, arg, oldval)
2830 struct frame *f;
2831 Lisp_Object arg, oldval;
2832{
1026b400
RS
2833 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2834 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2835 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2836 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2837 {
1026b400
RS
2838 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2839 vertical_scroll_bar_none :
87996783
GV
2840 /* Put scroll bars on the right by default, as is conventional
2841 on MS-Windows. */
2842 EQ (Qleft, arg)
2843 ? vertical_scroll_bar_left
2844 : vertical_scroll_bar_right;
ee78dc32
GV
2845
2846 /* We set this parameter before creating the window for the
2847 frame, so we can get the geometry right from the start.
2848 However, if the window hasn't been created yet, we shouldn't
2849 call x_set_window_size. */
fbd6baed 2850 if (FRAME_W32_WINDOW (f))
ee78dc32 2851 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2852 do_pending_window_change (0);
ee78dc32
GV
2853 }
2854}
2855
2856void
2857x_set_scroll_bar_width (f, arg, oldval)
2858 struct frame *f;
2859 Lisp_Object arg, oldval;
2860{
6fc2811b
JR
2861 int wid = FONT_WIDTH (f->output_data.w32->font);
2862
ee78dc32
GV
2863 if (NILP (arg))
2864 {
6fc2811b
JR
2865 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2866 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2867 wid - 1) / wid;
2868 if (FRAME_W32_WINDOW (f))
2869 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2870 do_pending_window_change (0);
ee78dc32
GV
2871 }
2872 else if (INTEGERP (arg) && XINT (arg) > 0
2873 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2874 {
ee78dc32 2875 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2876 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2877 + wid-1) / wid;
fbd6baed 2878 if (FRAME_W32_WINDOW (f))
ee78dc32 2879 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2880 do_pending_window_change (0);
ee78dc32 2881 }
6fc2811b
JR
2882 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2883 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2884 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2885}
2886\f
2887/* Subroutines of creating an frame. */
2888
2889/* Make sure that Vx_resource_name is set to a reasonable value.
2890 Fix it up, or set it to `emacs' if it is too hopeless. */
2891
2892static void
2893validate_x_resource_name ()
2894{
6fc2811b 2895 int len = 0;
ee78dc32
GV
2896 /* Number of valid characters in the resource name. */
2897 int good_count = 0;
2898 /* Number of invalid characters in the resource name. */
2899 int bad_count = 0;
2900 Lisp_Object new;
2901 int i;
2902
2903 if (STRINGP (Vx_resource_name))
2904 {
2905 unsigned char *p = XSTRING (Vx_resource_name)->data;
2906 int i;
2907
dfff8a69 2908 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2909
2910 /* Only letters, digits, - and _ are valid in resource names.
2911 Count the valid characters and count the invalid ones. */
2912 for (i = 0; i < len; i++)
2913 {
2914 int c = p[i];
2915 if (! ((c >= 'a' && c <= 'z')
2916 || (c >= 'A' && c <= 'Z')
2917 || (c >= '0' && c <= '9')
2918 || c == '-' || c == '_'))
2919 bad_count++;
2920 else
2921 good_count++;
2922 }
2923 }
2924 else
2925 /* Not a string => completely invalid. */
2926 bad_count = 5, good_count = 0;
2927
2928 /* If name is valid already, return. */
2929 if (bad_count == 0)
2930 return;
2931
2932 /* If name is entirely invalid, or nearly so, use `emacs'. */
2933 if (good_count == 0
2934 || (good_count == 1 && bad_count > 0))
2935 {
2936 Vx_resource_name = build_string ("emacs");
2937 return;
2938 }
2939
2940 /* Name is partly valid. Copy it and replace the invalid characters
2941 with underscores. */
2942
2943 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2944
2945 for (i = 0; i < len; i++)
2946 {
2947 int c = XSTRING (new)->data[i];
2948 if (! ((c >= 'a' && c <= 'z')
2949 || (c >= 'A' && c <= 'Z')
2950 || (c >= '0' && c <= '9')
2951 || c == '-' || c == '_'))
2952 XSTRING (new)->data[i] = '_';
2953 }
2954}
2955
2956
2957extern char *x_get_string_resource ();
2958
2959DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
2960 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
2961This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2962class, where INSTANCE is the name under which Emacs was invoked, or
2963the name specified by the `-name' or `-rn' command-line arguments.
2964
2965The optional arguments COMPONENT and SUBCLASS add to the key and the
2966class, respectively. You must specify both of them or neither.
2967If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
2968and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
2969 (attribute, class, component, subclass)
2970 Lisp_Object attribute, class, component, subclass;
2971{
2972 register char *value;
2973 char *name_key;
2974 char *class_key;
2975
b7826503
PJ
2976 CHECK_STRING (attribute);
2977 CHECK_STRING (class);
ee78dc32
GV
2978
2979 if (!NILP (component))
b7826503 2980 CHECK_STRING (component);
ee78dc32 2981 if (!NILP (subclass))
b7826503 2982 CHECK_STRING (subclass);
ee78dc32
GV
2983 if (NILP (component) != NILP (subclass))
2984 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2985
2986 validate_x_resource_name ();
2987
2988 /* Allocate space for the components, the dots which separate them,
2989 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 2990 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 2991 + (STRINGP (component)
dfff8a69
JR
2992 ? STRING_BYTES (XSTRING (component)) : 0)
2993 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
2994 + 3);
2995
2996 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 2997 + STRING_BYTES (XSTRING (class))
ee78dc32 2998 + (STRINGP (subclass)
dfff8a69 2999 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
3000 + 3);
3001
3002 /* Start with emacs.FRAMENAME for the name (the specific one)
3003 and with `Emacs' for the class key (the general one). */
3004 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3005 strcpy (class_key, EMACS_CLASS);
3006
3007 strcat (class_key, ".");
3008 strcat (class_key, XSTRING (class)->data);
3009
3010 if (!NILP (component))
3011 {
3012 strcat (class_key, ".");
3013 strcat (class_key, XSTRING (subclass)->data);
3014
3015 strcat (name_key, ".");
3016 strcat (name_key, XSTRING (component)->data);
3017 }
3018
3019 strcat (name_key, ".");
3020 strcat (name_key, XSTRING (attribute)->data);
3021
3022 value = x_get_string_resource (Qnil,
3023 name_key, class_key);
3024
3025 if (value != (char *) 0)
3026 return build_string (value);
3027 else
3028 return Qnil;
3029}
3030
3031/* Used when C code wants a resource value. */
3032
3033char *
3034x_get_resource_string (attribute, class)
3035 char *attribute, *class;
3036{
ee78dc32
GV
3037 char *name_key;
3038 char *class_key;
6fc2811b 3039 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3040
3041 /* Allocate space for the components, the dots which separate them,
3042 and the final '\0'. */
dfff8a69 3043 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3044 + strlen (attribute) + 2);
3045 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3046 + strlen (class) + 2);
3047
3048 sprintf (name_key, "%s.%s",
3049 XSTRING (Vinvocation_name)->data,
3050 attribute);
3051 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3052
6fc2811b 3053 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3054}
3055
3056/* Types we might convert a resource string into. */
3057enum resource_types
6fc2811b
JR
3058{
3059 RES_TYPE_NUMBER,
3060 RES_TYPE_FLOAT,
3061 RES_TYPE_BOOLEAN,
3062 RES_TYPE_STRING,
3063 RES_TYPE_SYMBOL
3064};
ee78dc32
GV
3065
3066/* Return the value of parameter PARAM.
3067
3068 First search ALIST, then Vdefault_frame_alist, then the X defaults
3069 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3070
3071 Convert the resource to the type specified by desired_type.
3072
3073 If no default is specified, return Qunbound. If you call
6fc2811b 3074 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3075 and don't let it get stored in any Lisp-visible variables! */
3076
3077static Lisp_Object
6fc2811b 3078w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3079 Lisp_Object alist, param;
3080 char *attribute;
3081 char *class;
3082 enum resource_types type;
3083{
3084 register Lisp_Object tem;
3085
3086 tem = Fassq (param, alist);
3087 if (EQ (tem, Qnil))
3088 tem = Fassq (param, Vdefault_frame_alist);
3089 if (EQ (tem, Qnil))
3090 {
3091
3092 if (attribute)
3093 {
3094 tem = Fx_get_resource (build_string (attribute),
3095 build_string (class),
3096 Qnil, Qnil);
3097
3098 if (NILP (tem))
3099 return Qunbound;
3100
3101 switch (type)
3102 {
6fc2811b 3103 case RES_TYPE_NUMBER:
ee78dc32
GV
3104 return make_number (atoi (XSTRING (tem)->data));
3105
6fc2811b
JR
3106 case RES_TYPE_FLOAT:
3107 return make_float (atof (XSTRING (tem)->data));
3108
3109 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3110 tem = Fdowncase (tem);
3111 if (!strcmp (XSTRING (tem)->data, "on")
3112 || !strcmp (XSTRING (tem)->data, "true"))
3113 return Qt;
3114 else
3115 return Qnil;
3116
6fc2811b 3117 case RES_TYPE_STRING:
ee78dc32
GV
3118 return tem;
3119
6fc2811b 3120 case RES_TYPE_SYMBOL:
ee78dc32
GV
3121 /* As a special case, we map the values `true' and `on'
3122 to Qt, and `false' and `off' to Qnil. */
3123 {
3124 Lisp_Object lower;
3125 lower = Fdowncase (tem);
3126 if (!strcmp (XSTRING (lower)->data, "on")
3127 || !strcmp (XSTRING (lower)->data, "true"))
3128 return Qt;
3129 else if (!strcmp (XSTRING (lower)->data, "off")
3130 || !strcmp (XSTRING (lower)->data, "false"))
3131 return Qnil;
3132 else
3133 return Fintern (tem, Qnil);
3134 }
3135
3136 default:
3137 abort ();
3138 }
3139 }
3140 else
3141 return Qunbound;
3142 }
3143 return Fcdr (tem);
3144}
3145
3146/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3147 of the parameter named PROP (a Lisp symbol).
3148 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3149 on the frame named NAME.
3150 If that is not found either, use the value DEFLT. */
3151
3152static Lisp_Object
3153x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3154 struct frame *f;
3155 Lisp_Object alist;
3156 Lisp_Object prop;
3157 Lisp_Object deflt;
3158 char *xprop;
3159 char *xclass;
3160 enum resource_types type;
3161{
3162 Lisp_Object tem;
3163
6fc2811b 3164 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3165 if (EQ (tem, Qunbound))
3166 tem = deflt;
3167 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3168 return tem;
3169}
3170\f
3171DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3172 doc: /* Parse an X-style geometry string STRING.
3173Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3174The properties returned may include `top', `left', `height', and `width'.
3175The value of `left' or `top' may be an integer,
3176or a list (+ N) meaning N pixels relative to top/left corner,
3177or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3178 (string)
3179 Lisp_Object string;
3180{
3181 int geometry, x, y;
3182 unsigned int width, height;
3183 Lisp_Object result;
3184
b7826503 3185 CHECK_STRING (string);
ee78dc32
GV
3186
3187 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3188 &x, &y, &width, &height);
3189
3190 result = Qnil;
3191 if (geometry & XValue)
3192 {
3193 Lisp_Object element;
3194
3195 if (x >= 0 && (geometry & XNegative))
3196 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3197 else if (x < 0 && ! (geometry & XNegative))
3198 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3199 else
3200 element = Fcons (Qleft, make_number (x));
3201 result = Fcons (element, result);
3202 }
3203
3204 if (geometry & YValue)
3205 {
3206 Lisp_Object element;
3207
3208 if (y >= 0 && (geometry & YNegative))
3209 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3210 else if (y < 0 && ! (geometry & YNegative))
3211 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3212 else
3213 element = Fcons (Qtop, make_number (y));
3214 result = Fcons (element, result);
3215 }
3216
3217 if (geometry & WidthValue)
3218 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3219 if (geometry & HeightValue)
3220 result = Fcons (Fcons (Qheight, make_number (height)), result);
3221
3222 return result;
3223}
3224
3225/* Calculate the desired size and position of this window,
3226 and return the flags saying which aspects were specified.
3227
3228 This function does not make the coordinates positive. */
3229
3230#define DEFAULT_ROWS 40
3231#define DEFAULT_COLS 80
3232
3233static int
3234x_figure_window_size (f, parms)
3235 struct frame *f;
3236 Lisp_Object parms;
3237{
3238 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3239 long window_prompting = 0;
3240
3241 /* Default values if we fall through.
3242 Actually, if that happens we should get
3243 window manager prompting. */
1026b400 3244 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3245 f->height = DEFAULT_ROWS;
3246 /* Window managers expect that if program-specified
3247 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3248 f->output_data.w32->top_pos = 0;
3249 f->output_data.w32->left_pos = 0;
ee78dc32 3250
35b41202
JR
3251 /* Ensure that old new_width and new_height will not override the
3252 values set here. */
3253 FRAME_NEW_WIDTH (f) = 0;
3254 FRAME_NEW_HEIGHT (f) = 0;
3255
6fc2811b
JR
3256 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3257 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3258 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3259 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3260 {
3261 if (!EQ (tem0, Qunbound))
3262 {
b7826503 3263 CHECK_NUMBER (tem0);
ee78dc32
GV
3264 f->height = XINT (tem0);
3265 }
3266 if (!EQ (tem1, Qunbound))
3267 {
b7826503 3268 CHECK_NUMBER (tem1);
1026b400 3269 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3270 }
3271 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3272 window_prompting |= USSize;
3273 else
3274 window_prompting |= PSize;
3275 }
3276
fbd6baed 3277 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3278 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3279 ? 0
3280 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3281 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3282 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
41c1bdd9 3283 x_compute_fringe_widths (f, 0);
fbd6baed
GV
3284 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3285 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3286
6fc2811b
JR
3287 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3288 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3289 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3290 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3291 {
3292 if (EQ (tem0, Qminus))
3293 {
fbd6baed 3294 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3295 window_prompting |= YNegative;
3296 }
8e713be6
KR
3297 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3298 && CONSP (XCDR (tem0))
3299 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3300 {
8e713be6 3301 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3302 window_prompting |= YNegative;
3303 }
8e713be6
KR
3304 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3305 && CONSP (XCDR (tem0))
3306 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3307 {
8e713be6 3308 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3309 }
3310 else if (EQ (tem0, Qunbound))
fbd6baed 3311 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3312 else
3313 {
b7826503 3314 CHECK_NUMBER (tem0);
fbd6baed
GV
3315 f->output_data.w32->top_pos = XINT (tem0);
3316 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3317 window_prompting |= YNegative;
3318 }
3319
3320 if (EQ (tem1, Qminus))
3321 {
fbd6baed 3322 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3323 window_prompting |= XNegative;
3324 }
8e713be6
KR
3325 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3326 && CONSP (XCDR (tem1))
3327 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3328 {
8e713be6 3329 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3330 window_prompting |= XNegative;
3331 }
8e713be6
KR
3332 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3333 && CONSP (XCDR (tem1))
3334 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3335 {
8e713be6 3336 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3337 }
3338 else if (EQ (tem1, Qunbound))
fbd6baed 3339 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3340 else
3341 {
b7826503 3342 CHECK_NUMBER (tem1);
fbd6baed
GV
3343 f->output_data.w32->left_pos = XINT (tem1);
3344 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3345 window_prompting |= XNegative;
3346 }
3347
3348 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3349 window_prompting |= USPosition;
3350 else
3351 window_prompting |= PPosition;
3352 }
3353
3354 return window_prompting;
3355}
3356
3357\f
3358
fbd6baed 3359extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3360
3361BOOL
fbd6baed 3362w32_init_class (hinst)
ee78dc32
GV
3363 HINSTANCE hinst;
3364{
3365 WNDCLASS wc;
3366
5ac45f98 3367 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3368 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3369 wc.cbClsExtra = 0;
3370 wc.cbWndExtra = WND_EXTRA_BYTES;
3371 wc.hInstance = hinst;
3372 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3373 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3374 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3375 wc.lpszMenuName = NULL;
3376 wc.lpszClassName = EMACS_CLASS;
3377
3378 return (RegisterClass (&wc));
3379}
3380
3381HWND
fbd6baed 3382w32_createscrollbar (f, bar)
ee78dc32
GV
3383 struct frame *f;
3384 struct scroll_bar * bar;
3385{
3386 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3387 /* Position and size of scroll bar. */
6fc2811b
JR
3388 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3389 XINT(bar->top),
3390 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3391 XINT(bar->height),
fbd6baed 3392 FRAME_W32_WINDOW (f),
ee78dc32
GV
3393 NULL,
3394 hinst,
3395 NULL));
3396}
3397
3398void
fbd6baed 3399w32_createwindow (f)
ee78dc32
GV
3400 struct frame *f;
3401{
3402 HWND hwnd;
1edf84e7
GV
3403 RECT rect;
3404
3405 rect.left = rect.top = 0;
3406 rect.right = PIXEL_WIDTH (f);
3407 rect.bottom = PIXEL_HEIGHT (f);
3408
3409 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3410 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3411
3412 /* Do first time app init */
3413
3414 if (!hprevinst)
3415 {
fbd6baed 3416 w32_init_class (hinst);
ee78dc32
GV
3417 }
3418
1edf84e7
GV
3419 FRAME_W32_WINDOW (f) = hwnd
3420 = CreateWindow (EMACS_CLASS,
3421 f->namebuf,
9ead1b60 3422 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3423 f->output_data.w32->left_pos,
3424 f->output_data.w32->top_pos,
3425 rect.right - rect.left,
3426 rect.bottom - rect.top,
3427 NULL,
3428 NULL,
3429 hinst,
3430 NULL);
3431
ee78dc32
GV
3432 if (hwnd)
3433 {
1edf84e7
GV
3434 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3435 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3436 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3437 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3438 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3439
cb9e33d4
RS
3440 /* Enable drag-n-drop. */
3441 DragAcceptFiles (hwnd, TRUE);
3442
5ac45f98
GV
3443 /* Do this to discard the default setting specified by our parent. */
3444 ShowWindow (hwnd, SW_HIDE);
3c190163 3445 }
3c190163
GV
3446}
3447
ee78dc32
GV
3448void
3449my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3450 W32Msg * wmsg;
ee78dc32
GV
3451 HWND hwnd;
3452 UINT msg;
3453 WPARAM wParam;
3454 LPARAM lParam;
3455{
3456 wmsg->msg.hwnd = hwnd;
3457 wmsg->msg.message = msg;
3458 wmsg->msg.wParam = wParam;
3459 wmsg->msg.lParam = lParam;
3460 wmsg->msg.time = GetMessageTime ();
3461
3462 post_msg (wmsg);
3463}
3464
e9e23e23 3465/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3466 between left and right keys as advertised. We test for this
3467 support dynamically, and set a flag when the support is absent. If
3468 absent, we keep track of the left and right control and alt keys
3469 ourselves. This is particularly necessary on keyboards that rely
3470 upon the AltGr key, which is represented as having the left control
3471 and right alt keys pressed. For these keyboards, we need to know
3472 when the left alt key has been pressed in addition to the AltGr key
3473 so that we can properly support M-AltGr-key sequences (such as M-@
3474 on Swedish keyboards). */
3475
3476#define EMACS_LCONTROL 0
3477#define EMACS_RCONTROL 1
3478#define EMACS_LMENU 2
3479#define EMACS_RMENU 3
3480
3481static int modifiers[4];
3482static int modifiers_recorded;
3483static int modifier_key_support_tested;
3484
3485static void
3486test_modifier_support (unsigned int wparam)
3487{
3488 unsigned int l, r;
3489
3490 if (wparam != VK_CONTROL && wparam != VK_MENU)
3491 return;
3492 if (wparam == VK_CONTROL)
3493 {
3494 l = VK_LCONTROL;
3495 r = VK_RCONTROL;
3496 }
3497 else
3498 {
3499 l = VK_LMENU;
3500 r = VK_RMENU;
3501 }
3502 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3503 modifiers_recorded = 1;
3504 else
3505 modifiers_recorded = 0;
3506 modifier_key_support_tested = 1;
3507}
3508
3509static void
3510record_keydown (unsigned int wparam, unsigned int lparam)
3511{
3512 int i;
3513
3514 if (!modifier_key_support_tested)
3515 test_modifier_support (wparam);
3516
3517 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3518 return;
3519
3520 if (wparam == VK_CONTROL)
3521 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3522 else
3523 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3524
3525 modifiers[i] = 1;
3526}
3527
3528static void
3529record_keyup (unsigned int wparam, unsigned int lparam)
3530{
3531 int i;
3532
3533 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3534 return;
3535
3536 if (wparam == VK_CONTROL)
3537 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3538 else
3539 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3540
3541 modifiers[i] = 0;
3542}
3543
da36a4d6
GV
3544/* Emacs can lose focus while a modifier key has been pressed. When
3545 it regains focus, be conservative and clear all modifiers since
3546 we cannot reconstruct the left and right modifier state. */
3547static void
3548reset_modifiers ()
3549{
8681157a
RS
3550 SHORT ctrl, alt;
3551
adcc3809
GV
3552 if (GetFocus () == NULL)
3553 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3554 return;
8681157a
RS
3555
3556 ctrl = GetAsyncKeyState (VK_CONTROL);
3557 alt = GetAsyncKeyState (VK_MENU);
3558
8681157a
RS
3559 if (!(ctrl & 0x08000))
3560 /* Clear any recorded control modifier state. */
3561 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3562
3563 if (!(alt & 0x08000))
3564 /* Clear any recorded alt modifier state. */
3565 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3566
adcc3809
GV
3567 /* Update the state of all modifier keys, because modifiers used in
3568 hot-key combinations can get stuck on if Emacs loses focus as a
3569 result of a hot-key being pressed. */
3570 {
3571 BYTE keystate[256];
3572
3573#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3574
3575 GetKeyboardState (keystate);
3576 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3577 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3578 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3579 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3580 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3581 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3582 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3583 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3584 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3585 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3586 SetKeyboardState (keystate);
3587 }
da36a4d6
GV
3588}
3589
7830e24b
RS
3590/* Synchronize modifier state with what is reported with the current
3591 keystroke. Even if we cannot distinguish between left and right
3592 modifier keys, we know that, if no modifiers are set, then neither
3593 the left or right modifier should be set. */
3594static void
3595sync_modifiers ()
3596{
3597 if (!modifiers_recorded)
3598 return;
3599
3600 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3601 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3602
3603 if (!(GetKeyState (VK_MENU) & 0x8000))
3604 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3605}
3606
a1a80b40
GV
3607static int
3608modifier_set (int vkey)
3609{
ccc2d29c 3610 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3611 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3612 if (!modifiers_recorded)
3613 return (GetKeyState (vkey) & 0x8000);
3614
3615 switch (vkey)
3616 {
3617 case VK_LCONTROL:
3618 return modifiers[EMACS_LCONTROL];
3619 case VK_RCONTROL:
3620 return modifiers[EMACS_RCONTROL];
3621 case VK_LMENU:
3622 return modifiers[EMACS_LMENU];
3623 case VK_RMENU:
3624 return modifiers[EMACS_RMENU];
a1a80b40
GV
3625 }
3626 return (GetKeyState (vkey) & 0x8000);
3627}
3628
ccc2d29c
GV
3629/* Convert between the modifier bits W32 uses and the modifier bits
3630 Emacs uses. */
3631
3632unsigned int
3633w32_key_to_modifier (int key)
3634{
3635 Lisp_Object key_mapping;
3636
3637 switch (key)
3638 {
3639 case VK_LWIN:
3640 key_mapping = Vw32_lwindow_modifier;
3641 break;
3642 case VK_RWIN:
3643 key_mapping = Vw32_rwindow_modifier;
3644 break;
3645 case VK_APPS:
3646 key_mapping = Vw32_apps_modifier;
3647 break;
3648 case VK_SCROLL:
3649 key_mapping = Vw32_scroll_lock_modifier;
3650 break;
3651 default:
3652 key_mapping = Qnil;
3653 }
3654
adcc3809
GV
3655 /* NB. This code runs in the input thread, asychronously to the lisp
3656 thread, so we must be careful to ensure access to lisp data is
3657 thread-safe. The following code is safe because the modifier
3658 variable values are updated atomically from lisp and symbols are
3659 not relocated by GC. Also, we don't have to worry about seeing GC
3660 markbits here. */
3661 if (EQ (key_mapping, Qhyper))
ccc2d29c 3662 return hyper_modifier;
adcc3809 3663 if (EQ (key_mapping, Qsuper))
ccc2d29c 3664 return super_modifier;
adcc3809 3665 if (EQ (key_mapping, Qmeta))
ccc2d29c 3666 return meta_modifier;
adcc3809 3667 if (EQ (key_mapping, Qalt))
ccc2d29c 3668 return alt_modifier;
adcc3809 3669 if (EQ (key_mapping, Qctrl))
ccc2d29c 3670 return ctrl_modifier;
adcc3809 3671 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3672 return ctrl_modifier;
adcc3809 3673 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3674 return shift_modifier;
3675
3676 /* Don't generate any modifier if not explicitly requested. */
3677 return 0;
3678}
3679
3680unsigned int
3681w32_get_modifiers ()
3682{
3683 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3684 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3685 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3686 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3687 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3688 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3689 (modifier_set (VK_MENU) ?
3690 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3691}
3692
a1a80b40
GV
3693/* We map the VK_* modifiers into console modifier constants
3694 so that we can use the same routines to handle both console
3695 and window input. */
3696
3697static int
ccc2d29c 3698construct_console_modifiers ()
a1a80b40
GV
3699{
3700 int mods;
3701
a1a80b40
GV
3702 mods = 0;
3703 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3704 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3705 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3706 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3707 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3708 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3709 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3710 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3711 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3712 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3713 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3714
3715 return mods;
3716}
3717
ccc2d29c
GV
3718static int
3719w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3720{
ccc2d29c
GV
3721 int mods;
3722
3723 /* Convert to emacs modifiers. */
3724 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3725
3726 return mods;
3727}
da36a4d6 3728
ccc2d29c
GV
3729unsigned int
3730map_keypad_keys (unsigned int virt_key, unsigned int extended)
3731{
3732 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3733 return virt_key;
da36a4d6 3734
ccc2d29c 3735 if (virt_key == VK_RETURN)
da36a4d6
GV
3736 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3737
ccc2d29c
GV
3738 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3739 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3740
3741 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3742 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3743
3744 if (virt_key == VK_CLEAR)
3745 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3746
3747 return virt_key;
3748}
3749
3750/* List of special key combinations which w32 would normally capture,
3751 but emacs should grab instead. Not directly visible to lisp, to
3752 simplify synchronization. Each item is an integer encoding a virtual
3753 key code and modifier combination to capture. */
3754Lisp_Object w32_grabbed_keys;
3755
3756#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3757#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3758#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3759#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3760
3761/* Register hot-keys for reserved key combinations when Emacs has
3762 keyboard focus, since this is the only way Emacs can receive key
3763 combinations like Alt-Tab which are used by the system. */
3764
3765static void
3766register_hot_keys (hwnd)
3767 HWND hwnd;
3768{
3769 Lisp_Object keylist;
3770
3771 /* Use GC_CONSP, since we are called asynchronously. */
3772 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3773 {
3774 Lisp_Object key = XCAR (keylist);
3775
3776 /* Deleted entries get set to nil. */
3777 if (!INTEGERP (key))
3778 continue;
3779
3780 RegisterHotKey (hwnd, HOTKEY_ID (key),
3781 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3782 }
3783}
3784
3785static void
3786unregister_hot_keys (hwnd)
3787 HWND hwnd;
3788{
3789 Lisp_Object keylist;
3790
3791 /* Use GC_CONSP, since we are called asynchronously. */
3792 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3793 {
3794 Lisp_Object key = XCAR (keylist);
3795
3796 if (!INTEGERP (key))
3797 continue;
3798
3799 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3800 }
3801}
3802
5ac45f98
GV
3803/* Main message dispatch loop. */
3804
1edf84e7
GV
3805static void
3806w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3807{
3808 MSG msg;
ccc2d29c
GV
3809 int result;
3810 HWND focus_window;
93fbe8b7
GV
3811
3812 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3813
5ac45f98
GV
3814 while (GetMessage (&msg, NULL, 0, 0))
3815 {
3816 if (msg.hwnd == NULL)
3817 {
3818 switch (msg.message)
3819 {
3ef68e6b
AI
3820 case WM_NULL:
3821 /* Produced by complete_deferred_msg; just ignore. */
3822 break;
5ac45f98 3823 case WM_EMACS_CREATEWINDOW:
fbd6baed 3824 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3825 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3826 abort ();
5ac45f98 3827 break;
dfdb4047
GV
3828 case WM_EMACS_SETLOCALE:
3829 SetThreadLocale (msg.wParam);
3830 /* Reply is not expected. */
3831 break;
ccc2d29c
GV
3832 case WM_EMACS_SETKEYBOARDLAYOUT:
3833 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3834 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3835 result, 0))
3836 abort ();
3837 break;
3838 case WM_EMACS_REGISTER_HOT_KEY:
3839 focus_window = GetFocus ();
3840 if (focus_window != NULL)
3841 RegisterHotKey (focus_window,
3842 HOTKEY_ID (msg.wParam),
3843 HOTKEY_MODIFIERS (msg.wParam),
3844 HOTKEY_VK_CODE (msg.wParam));
3845 /* Reply is not expected. */
3846 break;
3847 case WM_EMACS_UNREGISTER_HOT_KEY:
3848 focus_window = GetFocus ();
3849 if (focus_window != NULL)
3850 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3851 /* Mark item as erased. NB: this code must be
3852 thread-safe. The next line is okay because the cons
3853 cell is never made into garbage and is not relocated by
3854 GC. */
f3fbd155 3855 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3856 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3857 abort ();
3858 break;
adcc3809
GV
3859 case WM_EMACS_TOGGLE_LOCK_KEY:
3860 {
3861 int vk_code = (int) msg.wParam;
3862 int cur_state = (GetKeyState (vk_code) & 1);
3863 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3864
3865 /* NB: This code must be thread-safe. It is safe to
3866 call NILP because symbols are not relocated by GC,
3867 and pointer here is not touched by GC (so the markbit
3868 can't be set). Numbers are safe because they are
3869 immediate values. */
3870 if (NILP (new_state)
3871 || (NUMBERP (new_state)
8edb0a6f 3872 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3873 {
3874 one_w32_display_info.faked_key = vk_code;
3875
3876 keybd_event ((BYTE) vk_code,
3877 (BYTE) MapVirtualKey (vk_code, 0),
3878 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3879 keybd_event ((BYTE) vk_code,
3880 (BYTE) MapVirtualKey (vk_code, 0),
3881 KEYEVENTF_EXTENDEDKEY | 0, 0);
3882 keybd_event ((BYTE) vk_code,
3883 (BYTE) MapVirtualKey (vk_code, 0),
3884 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3885 cur_state = !cur_state;
3886 }
3887 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3888 cur_state, 0))
3889 abort ();
3890 }
3891 break;
1edf84e7 3892 default:
1edf84e7 3893 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3894 }
3895 }
3896 else
3897 {
3898 DispatchMessage (&msg);
3899 }
1edf84e7
GV
3900
3901 /* Exit nested loop when our deferred message has completed. */
3902 if (msg_buf->completed)
3903 break;
5ac45f98 3904 }
1edf84e7
GV
3905}
3906
3907deferred_msg * deferred_msg_head;
3908
3909static deferred_msg *
3910find_deferred_msg (HWND hwnd, UINT msg)
3911{
3912 deferred_msg * item;
3913
3914 /* Don't actually need synchronization for read access, since
3915 modification of single pointer is always atomic. */
3916 /* enter_crit (); */
3917
3918 for (item = deferred_msg_head; item != NULL; item = item->next)
3919 if (item->w32msg.msg.hwnd == hwnd
3920 && item->w32msg.msg.message == msg)
3921 break;
3922
3923 /* leave_crit (); */
3924
3925 return item;
3926}
3927
3928static LRESULT
3929send_deferred_msg (deferred_msg * msg_buf,
3930 HWND hwnd,
3931 UINT msg,
3932 WPARAM wParam,
3933 LPARAM lParam)
3934{
3935 /* Only input thread can send deferred messages. */
3936 if (GetCurrentThreadId () != dwWindowsThreadId)
3937 abort ();
3938
3939 /* It is an error to send a message that is already deferred. */
3940 if (find_deferred_msg (hwnd, msg) != NULL)
3941 abort ();
3942
3943 /* Enforced synchronization is not needed because this is the only
3944 function that alters deferred_msg_head, and the following critical
3945 section is guaranteed to only be serially reentered (since only the
3946 input thread can call us). */
3947
3948 /* enter_crit (); */
3949
3950 msg_buf->completed = 0;
3951 msg_buf->next = deferred_msg_head;
3952 deferred_msg_head = msg_buf;
3953 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3954
3955 /* leave_crit (); */
3956
3957 /* Start a new nested message loop to process other messages until
3958 this one is completed. */
3959 w32_msg_pump (msg_buf);
3960
3961 deferred_msg_head = msg_buf->next;
3962
3963 return msg_buf->result;
3964}
3965
3966void
3967complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3968{
3969 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3970
3971 if (msg_buf == NULL)
3ef68e6b
AI
3972 /* Message may have been cancelled, so don't abort(). */
3973 return;
1edf84e7
GV
3974
3975 msg_buf->result = result;
3976 msg_buf->completed = 1;
3977
3978 /* Ensure input thread is woken so it notices the completion. */
3979 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3980}
3981
3ef68e6b
AI
3982void
3983cancel_all_deferred_msgs ()
3984{
3985 deferred_msg * item;
3986
3987 /* Don't actually need synchronization for read access, since
3988 modification of single pointer is always atomic. */
3989 /* enter_crit (); */
3990
3991 for (item = deferred_msg_head; item != NULL; item = item->next)
3992 {
3993 item->result = 0;
3994 item->completed = 1;
3995 }
3996
3997 /* leave_crit (); */
3998
3999 /* Ensure input thread is woken so it notices the completion. */
4000 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4001}
1edf84e7
GV
4002
4003DWORD
4004w32_msg_worker (dw)
4005 DWORD dw;
4006{
4007 MSG msg;
4008 deferred_msg dummy_buf;
4009
4010 /* Ensure our message queue is created */
4011
4012 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 4013
1edf84e7
GV
4014 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4015 abort ();
4016
4017 memset (&dummy_buf, 0, sizeof (dummy_buf));
4018 dummy_buf.w32msg.msg.hwnd = NULL;
4019 dummy_buf.w32msg.msg.message = WM_NULL;
4020
4021 /* This is the inital message loop which should only exit when the
4022 application quits. */
4023 w32_msg_pump (&dummy_buf);
4024
4025 return 0;
5ac45f98
GV
4026}
4027
3ef68e6b
AI
4028static void
4029post_character_message (hwnd, msg, wParam, lParam, modifiers)
4030 HWND hwnd;
4031 UINT msg;
4032 WPARAM wParam;
4033 LPARAM lParam;
4034 DWORD modifiers;
4035
4036{
4037 W32Msg wmsg;
4038
4039 wmsg.dwModifiers = modifiers;
4040
4041 /* Detect quit_char and set quit-flag directly. Note that we
4042 still need to post a message to ensure the main thread will be
4043 woken up if blocked in sys_select(), but we do NOT want to post
4044 the quit_char message itself (because it will usually be as if
4045 the user had typed quit_char twice). Instead, we post a dummy
4046 message that has no particular effect. */
4047 {
4048 int c = wParam;
4049 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4050 c = make_ctrl_char (c) & 0377;
7d081355
AI
4051 if (c == quit_char
4052 || (wmsg.dwModifiers == 0 &&
4053 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4054 {
4055 Vquit_flag = Qt;
4056
4057 /* The choice of message is somewhat arbitrary, as long as
4058 the main thread handler just ignores it. */
4059 msg = WM_NULL;
4060
4061 /* Interrupt any blocking system calls. */
4062 signal_quit ();
4063
4064 /* As a safety precaution, forcibly complete any deferred
4065 messages. This is a kludge, but I don't see any particularly
4066 clean way to handle the situation where a deferred message is
4067 "dropped" in the lisp thread, and will thus never be
4068 completed, eg. by the user trying to activate the menubar
4069 when the lisp thread is busy, and then typing C-g when the
4070 menubar doesn't open promptly (with the result that the
4071 menubar never responds at all because the deferred
4072 WM_INITMENU message is never completed). Another problem
4073 situation is when the lisp thread calls SendMessage (to send
4074 a window manager command) when a message has been deferred;
4075 the lisp thread gets blocked indefinitely waiting for the
4076 deferred message to be completed, which itself is waiting for
4077 the lisp thread to respond.
4078
4079 Note that we don't want to block the input thread waiting for
4080 a reponse from the lisp thread (although that would at least
4081 solve the deadlock problem above), because we want to be able
4082 to receive C-g to interrupt the lisp thread. */
4083 cancel_all_deferred_msgs ();
4084 }
4085 }
4086
4087 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4088}
4089
ee78dc32
GV
4090/* Main window procedure */
4091
ee78dc32 4092LRESULT CALLBACK
fbd6baed 4093w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4094 HWND hwnd;
4095 UINT msg;
4096 WPARAM wParam;
4097 LPARAM lParam;
4098{
4099 struct frame *f;
fbd6baed
GV
4100 struct w32_display_info *dpyinfo = &one_w32_display_info;
4101 W32Msg wmsg;
84fb1139 4102 int windows_translate;
576ba81c 4103 int key;
84fb1139 4104
a6085637
KH
4105 /* Note that it is okay to call x_window_to_frame, even though we are
4106 not running in the main lisp thread, because frame deletion
4107 requires the lisp thread to synchronize with this thread. Thus, if
4108 a frame struct is returned, it can be used without concern that the
4109 lisp thread might make it disappear while we are using it.
4110
4111 NB. Walking the frame list in this thread is safe (as long as
4112 writes of Lisp_Object slots are atomic, which they are on Windows).
4113 Although delete-frame can destructively modify the frame list while
4114 we are walking it, a garbage collection cannot occur until after
4115 delete-frame has synchronized with this thread.
4116
4117 It is also safe to use functions that make GDI calls, such as
fbd6baed 4118 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4119 from the frame struct using get_frame_dc which is thread-aware. */
4120
ee78dc32
GV
4121 switch (msg)
4122 {
4123 case WM_ERASEBKGND:
a6085637
KH
4124 f = x_window_to_frame (dpyinfo, hwnd);
4125 if (f)
4126 {
9badad41 4127 HDC hdc = get_frame_dc (f);
a6085637 4128 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4129 w32_clear_rect (f, hdc, &wmsg.rect);
4130 release_frame_dc (f, hdc);
ce6059da
AI
4131
4132#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4133 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4134 f,
4135 wmsg.rect.left, wmsg.rect.top,
4136 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4137#endif /* W32_DEBUG_DISPLAY */
a6085637 4138 }
5ac45f98
GV
4139 return 1;
4140 case WM_PALETTECHANGED:
4141 /* ignore our own changes */
4142 if ((HWND)wParam != hwnd)
4143 {
a6085637
KH
4144 f = x_window_to_frame (dpyinfo, hwnd);
4145 if (f)
4146 /* get_frame_dc will realize our palette and force all
4147 frames to be redrawn if needed. */
4148 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4149 }
4150 return 0;
ee78dc32 4151 case WM_PAINT:
ce6059da 4152 {
55dcfc15
AI
4153 PAINTSTRUCT paintStruct;
4154 RECT update_rect;
4155
18f0b342
AI
4156 f = x_window_to_frame (dpyinfo, hwnd);
4157 if (f == 0)
4158 {
4159 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4160 return 0;
4161 }
4162
55dcfc15
AI
4163 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4164 fails. Apparently this can happen under some
4165 circumstances. */
c0611964 4166 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
4167 {
4168 enter_crit ();
4169 BeginPaint (hwnd, &paintStruct);
4170
c0611964
AI
4171 if (w32_strict_painting)
4172 /* The rectangles returned by GetUpdateRect and BeginPaint
4173 do not always match. GetUpdateRect seems to be the
4174 more reliable of the two. */
4175 wmsg.rect = update_rect;
4176 else
4177 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
4178
4179#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4180 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4181 f,
4182 wmsg.rect.left, wmsg.rect.top,
4183 wmsg.rect.right, wmsg.rect.bottom));
4184 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4185 update_rect.left, update_rect.top,
4186 update_rect.right, update_rect.bottom));
4187#endif
4188 EndPaint (hwnd, &paintStruct);
4189 leave_crit ();
4190
4191 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4192
4193 return 0;
4194 }
c0611964
AI
4195
4196 /* If GetUpdateRect returns 0 (meaning there is no update
4197 region), assume the whole window needs to be repainted. */
4198 GetClientRect(hwnd, &wmsg.rect);
4199 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4200 return 0;
ee78dc32 4201 }
a1a80b40 4202
ccc2d29c
GV
4203 case WM_INPUTLANGCHANGE:
4204 /* Inform lisp thread of keyboard layout changes. */
4205 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4206
4207 /* Clear dead keys in the keyboard state; for simplicity only
4208 preserve modifier key states. */
4209 {
4210 int i;
4211 BYTE keystate[256];
4212
4213 GetKeyboardState (keystate);
4214 for (i = 0; i < 256; i++)
4215 if (1
4216 && i != VK_SHIFT
4217 && i != VK_LSHIFT
4218 && i != VK_RSHIFT
4219 && i != VK_CAPITAL
4220 && i != VK_NUMLOCK
4221 && i != VK_SCROLL
4222 && i != VK_CONTROL
4223 && i != VK_LCONTROL
4224 && i != VK_RCONTROL
4225 && i != VK_MENU
4226 && i != VK_LMENU
4227 && i != VK_RMENU
4228 && i != VK_LWIN
4229 && i != VK_RWIN)
4230 keystate[i] = 0;
4231 SetKeyboardState (keystate);
4232 }
4233 goto dflt;
4234
4235 case WM_HOTKEY:
4236 /* Synchronize hot keys with normal input. */
4237 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4238 return (0);
4239
a1a80b40
GV
4240 case WM_KEYUP:
4241 case WM_SYSKEYUP:
4242 record_keyup (wParam, lParam);
4243 goto dflt;
4244
ee78dc32
GV
4245 case WM_KEYDOWN:
4246 case WM_SYSKEYDOWN:
ccc2d29c
GV
4247 /* Ignore keystrokes we fake ourself; see below. */
4248 if (dpyinfo->faked_key == wParam)
4249 {
4250 dpyinfo->faked_key = 0;
576ba81c
AI
4251 /* Make sure TranslateMessage sees them though (as long as
4252 they don't produce WM_CHAR messages). This ensures that
4253 indicator lights are toggled promptly on Windows 9x, for
4254 example. */
4255 if (lispy_function_keys[wParam] != 0)
4256 {
4257 windows_translate = 1;
4258 goto translate;
4259 }
4260 return 0;
ccc2d29c
GV
4261 }
4262
7830e24b
RS
4263 /* Synchronize modifiers with current keystroke. */
4264 sync_modifiers ();
a1a80b40 4265 record_keydown (wParam, lParam);
ccc2d29c 4266 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4267
4268 windows_translate = 0;
ccc2d29c
GV
4269
4270 switch (wParam)
4271 {
4272 case VK_LWIN:
4273 if (NILP (Vw32_pass_lwindow_to_system))
4274 {
4275 /* Prevent system from acting on keyup (which opens the
4276 Start menu if no other key was pressed) by simulating a
4277 press of Space which we will ignore. */
4278 if (GetAsyncKeyState (wParam) & 1)
4279 {
adcc3809 4280 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4281 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4282 else
576ba81c
AI
4283 key = VK_SPACE;
4284 dpyinfo->faked_key = key;
4285 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4286 }
4287 }
4288 if (!NILP (Vw32_lwindow_modifier))
4289 return 0;
4290 break;
4291 case VK_RWIN:
4292 if (NILP (Vw32_pass_rwindow_to_system))
4293 {
4294 if (GetAsyncKeyState (wParam) & 1)
4295 {
adcc3809 4296 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4297 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4298 else
576ba81c
AI
4299 key = VK_SPACE;
4300 dpyinfo->faked_key = key;
4301 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4302 }
4303 }
4304 if (!NILP (Vw32_rwindow_modifier))
4305 return 0;
4306 break;
576ba81c 4307 case VK_APPS:
ccc2d29c
GV
4308 if (!NILP (Vw32_apps_modifier))
4309 return 0;
4310 break;
4311 case VK_MENU:
4312 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4313 /* Prevent DefWindowProc from activating the menu bar if an
4314 Alt key is pressed and released by itself. */
ccc2d29c 4315 return 0;
84fb1139 4316 windows_translate = 1;
ccc2d29c
GV
4317 break;
4318 case VK_CAPITAL:
4319 /* Decide whether to treat as modifier or function key. */
4320 if (NILP (Vw32_enable_caps_lock))
4321 goto disable_lock_key;
adcc3809
GV
4322 windows_translate = 1;
4323 break;
ccc2d29c
GV
4324 case VK_NUMLOCK:
4325 /* Decide whether to treat as modifier or function key. */
4326 if (NILP (Vw32_enable_num_lock))
4327 goto disable_lock_key;
adcc3809
GV
4328 windows_translate = 1;
4329 break;
ccc2d29c
GV
4330 case VK_SCROLL:
4331 /* Decide whether to treat as modifier or function key. */
4332 if (NILP (Vw32_scroll_lock_modifier))
4333 goto disable_lock_key;
adcc3809
GV
4334 windows_translate = 1;
4335 break;
ccc2d29c 4336 disable_lock_key:
adcc3809
GV
4337 /* Ensure the appropriate lock key state (and indicator light)
4338 remains in the same state. We do this by faking another
4339 press of the relevant key. Apparently, this really is the
4340 only way to toggle the state of the indicator lights. */
4341 dpyinfo->faked_key = wParam;
4342 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4343 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4344 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4345 KEYEVENTF_EXTENDEDKEY | 0, 0);
4346 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4347 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4348 /* Ensure indicator lights are updated promptly on Windows 9x
4349 (TranslateMessage apparently does this), after forwarding
4350 input event. */
4351 post_character_message (hwnd, msg, wParam, lParam,
4352 w32_get_key_modifiers (wParam, lParam));
4353 windows_translate = 1;
ccc2d29c
GV
4354 break;
4355 case VK_CONTROL:
4356 case VK_SHIFT:
4357 case VK_PROCESSKEY: /* Generated by IME. */
4358 windows_translate = 1;
4359 break;
adcc3809
GV
4360 case VK_CANCEL:
4361 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4362 which is confusing for purposes of key binding; convert
4363 VK_CANCEL events into VK_PAUSE events. */
4364 wParam = VK_PAUSE;
4365 break;
4366 case VK_PAUSE:
4367 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4368 for purposes of key binding; convert these back into
4369 VK_NUMLOCK events, at least when we want to see NumLock key
4370 presses. (Note that there is never any possibility that
4371 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4372 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4373 wParam = VK_NUMLOCK;
4374 break;
ccc2d29c
GV
4375 default:
4376 /* If not defined as a function key, change it to a WM_CHAR message. */
4377 if (lispy_function_keys[wParam] == 0)
4378 {
adcc3809
GV
4379 DWORD modifiers = construct_console_modifiers ();
4380
ccc2d29c
GV
4381 if (!NILP (Vw32_recognize_altgr)
4382 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4383 {
4384 /* Always let TranslateMessage handle AltGr key chords;
4385 for some reason, ToAscii doesn't always process AltGr
4386 chords correctly. */
4387 windows_translate = 1;
4388 }
adcc3809 4389 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4390 {
adcc3809
GV
4391 /* Handle key chords including any modifiers other
4392 than shift directly, in order to preserve as much
4393 modifier information as possible. */
ccc2d29c
GV
4394 if ('A' <= wParam && wParam <= 'Z')
4395 {
4396 /* Don't translate modified alphabetic keystrokes,
4397 so the user doesn't need to constantly switch
4398 layout to type control or meta keystrokes when
4399 the normal layout translates alphabetic
4400 characters to non-ascii characters. */
4401 if (!modifier_set (VK_SHIFT))
4402 wParam += ('a' - 'A');
4403 msg = WM_CHAR;
4404 }
4405 else
4406 {
4407 /* Try to handle other keystrokes by determining the
4408 base character (ie. translating the base key plus
4409 shift modifier). */
4410 int add;
4411 int isdead = 0;
4412 KEY_EVENT_RECORD key;
4413
4414 key.bKeyDown = TRUE;
4415 key.wRepeatCount = 1;
4416 key.wVirtualKeyCode = wParam;
4417 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4418 key.uChar.AsciiChar = 0;
adcc3809 4419 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4420
4421 add = w32_kbd_patch_key (&key);
4422 /* 0 means an unrecognised keycode, negative means
4423 dead key. Ignore both. */
4424 while (--add >= 0)
4425 {
4426 /* Forward asciified character sequence. */
4427 post_character_message
4428 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4429 w32_get_key_modifiers (wParam, lParam));
4430 w32_kbd_patch_key (&key);
4431 }
4432 return 0;
4433 }
4434 }
4435 else
4436 {
4437 /* Let TranslateMessage handle everything else. */
4438 windows_translate = 1;
4439 }
4440 }
4441 }
a1a80b40 4442
adcc3809 4443 translate:
84fb1139
KH
4444 if (windows_translate)
4445 {
e9e23e23 4446 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4447
e9e23e23
GV
4448 windows_msg.time = GetMessageTime ();
4449 TranslateMessage (&windows_msg);
84fb1139
KH
4450 goto dflt;
4451 }
4452
ee78dc32
GV
4453 /* Fall through */
4454
4455 case WM_SYSCHAR:
4456 case WM_CHAR:
ccc2d29c
GV
4457 post_character_message (hwnd, msg, wParam, lParam,
4458 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4459 break;
da36a4d6 4460
5ac45f98
GV
4461 /* Simulate middle mouse button events when left and right buttons
4462 are used together, but only if user has two button mouse. */
ee78dc32 4463 case WM_LBUTTONDOWN:
5ac45f98 4464 case WM_RBUTTONDOWN:
7ce9aaca 4465 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4466 goto handle_plain_button;
4467
4468 {
4469 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4470 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4471
3cb20f4a
RS
4472 if (button_state & this)
4473 return 0;
5ac45f98
GV
4474
4475 if (button_state == 0)
4476 SetCapture (hwnd);
4477
4478 button_state |= this;
4479
4480 if (button_state & other)
4481 {
84fb1139 4482 if (mouse_button_timer)
5ac45f98 4483 {
84fb1139
KH
4484 KillTimer (hwnd, mouse_button_timer);
4485 mouse_button_timer = 0;
5ac45f98
GV
4486
4487 /* Generate middle mouse event instead. */
4488 msg = WM_MBUTTONDOWN;
4489 button_state |= MMOUSE;
4490 }
4491 else if (button_state & MMOUSE)
4492 {
4493 /* Ignore button event if we've already generated a
4494 middle mouse down event. This happens if the
4495 user releases and press one of the two buttons
4496 after we've faked a middle mouse event. */
4497 return 0;
4498 }
4499 else
4500 {
4501 /* Flush out saved message. */
84fb1139 4502 post_msg (&saved_mouse_button_msg);
5ac45f98 4503 }
fbd6baed 4504 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4505 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4506
4507 /* Clear message buffer. */
84fb1139 4508 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4509 }
4510 else
4511 {
4512 /* Hold onto message for now. */
84fb1139 4513 mouse_button_timer =
adcc3809
GV
4514 SetTimer (hwnd, MOUSE_BUTTON_ID,
4515 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4516 saved_mouse_button_msg.msg.hwnd = hwnd;
4517 saved_mouse_button_msg.msg.message = msg;
4518 saved_mouse_button_msg.msg.wParam = wParam;
4519 saved_mouse_button_msg.msg.lParam = lParam;
4520 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4521 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4522 }
4523 }
4524 return 0;
4525
ee78dc32 4526 case WM_LBUTTONUP:
5ac45f98 4527 case WM_RBUTTONUP:
7ce9aaca 4528 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4529 goto handle_plain_button;
4530
4531 {
4532 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4533 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4534
3cb20f4a
RS
4535 if ((button_state & this) == 0)
4536 return 0;
5ac45f98
GV
4537
4538 button_state &= ~this;
4539
4540 if (button_state & MMOUSE)
4541 {
4542 /* Only generate event when second button is released. */
4543 if ((button_state & other) == 0)
4544 {
4545 msg = WM_MBUTTONUP;
4546 button_state &= ~MMOUSE;
4547
4548 if (button_state) abort ();
4549 }
4550 else
4551 return 0;
4552 }
4553 else
4554 {
4555 /* Flush out saved message if necessary. */
84fb1139 4556 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4557 {
84fb1139 4558 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4559 }
4560 }
fbd6baed 4561 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4562 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4563
4564 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4565 saved_mouse_button_msg.msg.hwnd = 0;
4566 KillTimer (hwnd, mouse_button_timer);
4567 mouse_button_timer = 0;
5ac45f98
GV
4568
4569 if (button_state == 0)
4570 ReleaseCapture ();
4571 }
4572 return 0;
4573
ee78dc32
GV
4574 case WM_MBUTTONDOWN:
4575 case WM_MBUTTONUP:
5ac45f98 4576 handle_plain_button:
ee78dc32
GV
4577 {
4578 BOOL up;
1edf84e7 4579 int button;
ee78dc32 4580
1edf84e7 4581 if (parse_button (msg, &button, &up))
ee78dc32
GV
4582 {
4583 if (up) ReleaseCapture ();
4584 else SetCapture (hwnd);
1edf84e7
GV
4585 button = (button == 0) ? LMOUSE :
4586 ((button == 1) ? MMOUSE : RMOUSE);
4587 if (up)
4588 button_state &= ~button;
4589 else
4590 button_state |= button;
ee78dc32
GV
4591 }
4592 }
4593
fbd6baed 4594 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4595 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5ac45f98
GV
4596 return 0;
4597
5ac45f98 4598 case WM_MOUSEMOVE:
9eb16b62
JR
4599 /* If the mouse has just moved into the frame, start tracking
4600 it, so we will be notified when it leaves the frame. Mouse
4601 tracking only works under W98 and NT4 and later. On earlier
4602 versions, there is no way of telling when the mouse leaves the
4603 frame, so we just have to put up with help-echo and mouse
4604 highlighting remaining while the frame is not active. */
4605 if (track_mouse_event_fn && !track_mouse_window)
4606 {
4607 TRACKMOUSEEVENT tme;
4608 tme.cbSize = sizeof (tme);
4609 tme.dwFlags = TME_LEAVE;
4610 tme.hwndTrack = hwnd;
4611
4612 track_mouse_event_fn (&tme);
4613 track_mouse_window = hwnd;
4614 }
4615 case WM_VSCROLL:
fbd6baed 4616 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4617 || (msg == WM_MOUSEMOVE && button_state == 0))
4618 {
fbd6baed 4619 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4620 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4621 return 0;
4622 }
4623
4624 /* Hang onto mouse move and scroll messages for a bit, to avoid
4625 sending such events to Emacs faster than it can process them.
4626 If we get more events before the timer from the first message
4627 expires, we just replace the first message. */
4628
4629 if (saved_mouse_move_msg.msg.hwnd == 0)
4630 mouse_move_timer =
adcc3809
GV
4631 SetTimer (hwnd, MOUSE_MOVE_ID,
4632 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4633
4634 /* Hold onto message for now. */
4635 saved_mouse_move_msg.msg.hwnd = hwnd;
4636 saved_mouse_move_msg.msg.message = msg;
4637 saved_mouse_move_msg.msg.wParam = wParam;
4638 saved_mouse_move_msg.msg.lParam = lParam;
4639 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4640 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4641
4642 return 0;
4643
1edf84e7
GV
4644 case WM_MOUSEWHEEL:
4645 wmsg.dwModifiers = w32_get_modifiers ();
4646 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4647 return 0;
4648
cb9e33d4
RS
4649 case WM_DROPFILES:
4650 wmsg.dwModifiers = w32_get_modifiers ();
4651 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4652 return 0;
4653
84fb1139
KH
4654 case WM_TIMER:
4655 /* Flush out saved messages if necessary. */
4656 if (wParam == mouse_button_timer)
5ac45f98 4657 {
84fb1139
KH
4658 if (saved_mouse_button_msg.msg.hwnd)
4659 {
4660 post_msg (&saved_mouse_button_msg);
4661 saved_mouse_button_msg.msg.hwnd = 0;
4662 }
4663 KillTimer (hwnd, mouse_button_timer);
4664 mouse_button_timer = 0;
4665 }
4666 else if (wParam == mouse_move_timer)
4667 {
4668 if (saved_mouse_move_msg.msg.hwnd)
4669 {
4670 post_msg (&saved_mouse_move_msg);
4671 saved_mouse_move_msg.msg.hwnd = 0;
4672 }
4673 KillTimer (hwnd, mouse_move_timer);
4674 mouse_move_timer = 0;
5ac45f98 4675 }
5ac45f98 4676 return 0;
84fb1139
KH
4677
4678 case WM_NCACTIVATE:
4679 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4680 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4681 The only indication we get that something happened is receiving
4682 this message afterwards. So this is a good time to reset our
4683 keyboard modifiers' state. */
4684 reset_modifiers ();
4685 goto dflt;
da36a4d6 4686
1edf84e7 4687 case WM_INITMENU:
487163ac
AI
4688 button_state = 0;
4689 ReleaseCapture ();
1edf84e7
GV
4690 /* We must ensure menu bar is fully constructed and up to date
4691 before allowing user interaction with it. To achieve this
4692 we send this message to the lisp thread and wait for a
4693 reply (whose value is not actually needed) to indicate that
4694 the menu bar is now ready for use, so we can now return.
4695
4696 To remain responsive in the meantime, we enter a nested message
4697 loop that can process all other messages.
4698
4699 However, we skip all this if the message results from calling
4700 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4701 thread a message because it is blocked on us at this point. We
4702 set menubar_active before calling TrackPopupMenu to indicate
4703 this (there is no possibility of confusion with real menubar
4704 being active). */
4705
4706 f = x_window_to_frame (dpyinfo, hwnd);
4707 if (f
4708 && (f->output_data.w32->menubar_active
4709 /* We can receive this message even in the absence of a
4710 menubar (ie. when the system menu is activated) - in this
4711 case we do NOT want to forward the message, otherwise it
4712 will cause the menubar to suddenly appear when the user
4713 had requested it to be turned off! */
4714 || f->output_data.w32->menubar_widget == NULL))
4715 return 0;
4716
4717 {
4718 deferred_msg msg_buf;
4719
4720 /* Detect if message has already been deferred; in this case
4721 we cannot return any sensible value to ignore this. */
4722 if (find_deferred_msg (hwnd, msg) != NULL)
4723 abort ();
4724
4725 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4726 }
4727
4728 case WM_EXITMENULOOP:
4729 f = x_window_to_frame (dpyinfo, hwnd);
4730
9eb16b62
JR
4731 /* Free memory used by owner-drawn and help-echo strings. */
4732 w32_free_menu_strings (hwnd);
4733
1edf84e7
GV
4734 /* Indicate that menubar can be modified again. */
4735 if (f)
4736 f->output_data.w32->menubar_active = 0;
4737 goto dflt;
4738
126f2e35 4739 case WM_MENUSELECT:
4e3a1c61
JR
4740 /* Direct handling of help_echo in menus. Should be safe now
4741 that we generate the help_echo by placing a help event in the
4742 keyboard buffer. */
ca56d953 4743 {
ca56d953
JR
4744 HMENU menu = (HMENU) lParam;
4745 UINT menu_item = (UINT) LOWORD (wParam);
4746 UINT flags = (UINT) HIWORD (wParam);
4747
4e3a1c61 4748 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4749 }
126f2e35
JR
4750 return 0;
4751
87996783
GV
4752 case WM_MEASUREITEM:
4753 f = x_window_to_frame (dpyinfo, hwnd);
4754 if (f)
4755 {
4756 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4757
4758 if (pMis->CtlType == ODT_MENU)
4759 {
4760 /* Work out dimensions for popup menu titles. */
4761 char * title = (char *) pMis->itemData;
4762 HDC hdc = GetDC (hwnd);
4763 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4764 LOGFONT menu_logfont;
4765 HFONT old_font;
4766 SIZE size;
4767
4768 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4769 menu_logfont.lfWeight = FW_BOLD;
4770 menu_font = CreateFontIndirect (&menu_logfont);
4771 old_font = SelectObject (hdc, menu_font);
4772
dfff8a69
JR
4773 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4774 if (title)
4775 {
4776 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4777 pMis->itemWidth = size.cx;
4778 if (pMis->itemHeight < size.cy)
4779 pMis->itemHeight = size.cy;
4780 }
4781 else
4782 pMis->itemWidth = 0;
87996783
GV
4783
4784 SelectObject (hdc, old_font);
4785 DeleteObject (menu_font);
4786 ReleaseDC (hwnd, hdc);
4787 return TRUE;
4788 }
4789 }
4790 return 0;
4791
4792 case WM_DRAWITEM:
4793 f = x_window_to_frame (dpyinfo, hwnd);
4794 if (f)
4795 {
4796 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4797
4798 if (pDis->CtlType == ODT_MENU)
4799 {
4800 /* Draw popup menu title. */
4801 char * title = (char *) pDis->itemData;
212da13b
JR
4802 if (title)
4803 {
4804 HDC hdc = pDis->hDC;
4805 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4806 LOGFONT menu_logfont;
4807 HFONT old_font;
4808
4809 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4810 menu_logfont.lfWeight = FW_BOLD;
4811 menu_font = CreateFontIndirect (&menu_logfont);
4812 old_font = SelectObject (hdc, menu_font);
4813
4814 /* Always draw title as if not selected. */
4815 ExtTextOut (hdc,
4816 pDis->rcItem.left
4817 + GetSystemMetrics (SM_CXMENUCHECK),
4818 pDis->rcItem.top,
4819 ETO_OPAQUE, &pDis->rcItem,
4820 title, strlen (title), NULL);
4821
4822 SelectObject (hdc, old_font);
4823 DeleteObject (menu_font);
4824 }
87996783
GV
4825 return TRUE;
4826 }
4827 }
4828 return 0;
4829
1edf84e7
GV
4830#if 0
4831 /* Still not right - can't distinguish between clicks in the
4832 client area of the frame from clicks forwarded from the scroll
4833 bars - may have to hook WM_NCHITTEST to remember the mouse
4834 position and then check if it is in the client area ourselves. */
4835 case WM_MOUSEACTIVATE:
4836 /* Discard the mouse click that activates a frame, allowing the
4837 user to click anywhere without changing point (or worse!).
4838 Don't eat mouse clicks on scrollbars though!! */
4839 if (LOWORD (lParam) == HTCLIENT )
4840 return MA_ACTIVATEANDEAT;
4841 goto dflt;
4842#endif
4843
9eb16b62
JR
4844 case WM_MOUSELEAVE:
4845 /* No longer tracking mouse. */
4846 track_mouse_window = NULL;
4847
1edf84e7 4848 case WM_ACTIVATEAPP:
ccc2d29c 4849 case WM_ACTIVATE:
1edf84e7
GV
4850 case WM_WINDOWPOSCHANGED:
4851 case WM_SHOWWINDOW:
4852 /* Inform lisp thread that a frame might have just been obscured
4853 or exposed, so should recheck visibility of all frames. */
4854 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4855 goto dflt;
4856
da36a4d6 4857 case WM_SETFOCUS:
adcc3809
GV
4858 dpyinfo->faked_key = 0;
4859 reset_modifiers ();
ccc2d29c
GV
4860 register_hot_keys (hwnd);
4861 goto command;
8681157a 4862 case WM_KILLFOCUS:
ccc2d29c 4863 unregister_hot_keys (hwnd);
487163ac
AI
4864 button_state = 0;
4865 ReleaseCapture ();
65906840
JR
4866 /* Relinquish the system caret. */
4867 if (w32_system_caret_hwnd)
4868 {
4869 DestroyCaret ();
4870 w32_system_caret_hwnd = NULL;
4871 }
ee78dc32
GV
4872 case WM_MOVE:
4873 case WM_SIZE:
ee78dc32 4874 case WM_COMMAND:
ccc2d29c 4875 command:
fbd6baed 4876 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4877 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4878 goto dflt;
8847d890
RS
4879
4880 case WM_CLOSE:
fbd6baed 4881 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4882 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4883 return 0;
4884
ee78dc32 4885 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
4886 /* Don't restrict the sizing of tip frames. */
4887 if (hwnd == tip_window)
4888 return 0;
ee78dc32
GV
4889 {
4890 WINDOWPLACEMENT wp;
4891 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4892
4893 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4894 GetWindowPlacement (hwnd, &wp);
4895
1edf84e7 4896 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4897 {
4898 RECT rect;
4899 int wdiff;
4900 int hdiff;
1edf84e7
GV
4901 DWORD font_width;
4902 DWORD line_height;
4903 DWORD internal_border;
4904 DWORD scrollbar_extra;
ee78dc32
GV
4905 RECT wr;
4906
5ac45f98 4907 wp.length = sizeof(wp);
ee78dc32
GV
4908 GetWindowRect (hwnd, &wr);
4909
3c190163 4910 enter_crit ();
ee78dc32 4911
1edf84e7
GV
4912 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4913 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4914 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4915 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4916
3c190163 4917 leave_crit ();
ee78dc32
GV
4918
4919 memset (&rect, 0, sizeof (rect));
4920 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4921 GetMenu (hwnd) != NULL);
4922
1edf84e7
GV
4923 /* Force width and height of client area to be exact
4924 multiples of the character cell dimensions. */
4925 wdiff = (lppos->cx - (rect.right - rect.left)
4926 - 2 * internal_border - scrollbar_extra)
4927 % font_width;
4928 hdiff = (lppos->cy - (rect.bottom - rect.top)
4929 - 2 * internal_border)
4930 % line_height;
ee78dc32
GV
4931
4932 if (wdiff || hdiff)
4933 {
4934 /* For right/bottom sizing we can just fix the sizes.
4935 However for top/left sizing we will need to fix the X
4936 and Y positions as well. */
4937
4938 lppos->cx -= wdiff;
4939 lppos->cy -= hdiff;
4940
4941 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4942 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4943 {
4944 if (lppos->x != wr.left || lppos->y != wr.top)
4945 {
4946 lppos->x += wdiff;
4947 lppos->y += hdiff;
4948 }
4949 else
4950 {
4951 lppos->flags |= SWP_NOMOVE;
4952 }
4953 }
4954
1edf84e7 4955 return 0;
ee78dc32
GV
4956 }
4957 }
4958 }
ee78dc32
GV
4959
4960 goto dflt;
1edf84e7 4961
b1f918f8
GV
4962 case WM_GETMINMAXINFO:
4963 /* Hack to correct bug that allows Emacs frames to be resized
4964 below the Minimum Tracking Size. */
4965 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
4966 /* Hack to allow resizing the Emacs frame above the screen size.
4967 Note that Windows 9x limits coordinates to 16-bits. */
4968 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
4969 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
4970 return 0;
4971
1edf84e7
GV
4972 case WM_EMACS_CREATESCROLLBAR:
4973 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4974 (struct scroll_bar *) lParam);
4975
5ac45f98 4976 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4977 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4978
dfdb4047 4979 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4980 {
4981 HWND foreground_window;
4982 DWORD foreground_thread, retval;
4983
4984 /* On NT 5.0, and apparently Windows 98, it is necessary to
4985 attach to the thread that currently has focus in order to
4986 pull the focus away from it. */
4987 foreground_window = GetForegroundWindow ();
4988 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4989 if (!foreground_window
4990 || foreground_thread == GetCurrentThreadId ()
4991 || !AttachThreadInput (GetCurrentThreadId (),
4992 foreground_thread, TRUE))
4993 foreground_thread = 0;
4994
4995 retval = SetForegroundWindow ((HWND) wParam);
4996
4997 /* Detach from the previous foreground thread. */
4998 if (foreground_thread)
4999 AttachThreadInput (GetCurrentThreadId (),
5000 foreground_thread, FALSE);
5001
5002 return retval;
5003 }
dfdb4047 5004
5ac45f98
GV
5005 case WM_EMACS_SETWINDOWPOS:
5006 {
1edf84e7
GV
5007 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5008 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5009 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5010 }
1edf84e7 5011
ee78dc32 5012 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5013 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5014 return DestroyWindow ((HWND) wParam);
5015
65906840
JR
5016 case WM_EMACS_DESTROY_CARET:
5017 w32_system_caret_hwnd = NULL;
5018 return DestroyCaret ();
5019
5020 case WM_EMACS_TRACK_CARET:
5021 /* If there is currently no system caret, create one. */
5022 if (w32_system_caret_hwnd == NULL)
5023 {
5024 w32_system_caret_hwnd = hwnd;
5025 CreateCaret (hwnd, NULL, w32_system_caret_width,
5026 w32_system_caret_height);
5027 }
5028 return SetCaretPos (w32_system_caret_x, w32_system_caret_y);
5029
1edf84e7
GV
5030 case WM_EMACS_TRACKPOPUPMENU:
5031 {
5032 UINT flags;
5033 POINT *pos;
5034 int retval;
5035 pos = (POINT *)lParam;
5036 flags = TPM_CENTERALIGN;
5037 if (button_state & LMOUSE)
5038 flags |= TPM_LEFTBUTTON;
5039 else if (button_state & RMOUSE)
5040 flags |= TPM_RIGHTBUTTON;
5041
87996783
GV
5042 /* Remember we did a SetCapture on the initial mouse down event,
5043 so for safety, we make sure the capture is cancelled now. */
5044 ReleaseCapture ();
490822ff 5045 button_state = 0;
87996783 5046
1edf84e7
GV
5047 /* Use menubar_active to indicate that WM_INITMENU is from
5048 TrackPopupMenu below, and should be ignored. */
5049 f = x_window_to_frame (dpyinfo, hwnd);
5050 if (f)
5051 f->output_data.w32->menubar_active = 1;
5052
5053 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5054 0, hwnd, NULL))
5055 {
5056 MSG amsg;
5057 /* Eat any mouse messages during popupmenu */
5058 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5059 PM_REMOVE));
5060 /* Get the menu selection, if any */
5061 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5062 {
5063 retval = LOWORD (amsg.wParam);
5064 }
5065 else
5066 {
5067 retval = 0;
5068 }
1edf84e7
GV
5069 }
5070 else
5071 {
5072 retval = -1;
5073 }
5074
5075 return retval;
5076 }
5077
ee78dc32 5078 default:
93fbe8b7
GV
5079 /* Check for messages registered at runtime. */
5080 if (msg == msh_mousewheel)
5081 {
5082 wmsg.dwModifiers = w32_get_modifiers ();
5083 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5084 return 0;
5085 }
5086
ee78dc32
GV
5087 dflt:
5088 return DefWindowProc (hwnd, msg, wParam, lParam);
5089 }
5090
1edf84e7
GV
5091
5092 /* The most common default return code for handled messages is 0. */
5093 return 0;
ee78dc32
GV
5094}
5095
5096void
5097my_create_window (f)
5098 struct frame * f;
5099{
5100 MSG msg;
5101
1edf84e7
GV
5102 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5103 abort ();
ee78dc32
GV
5104 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5105}
5106
ca56d953
JR
5107
5108/* Create a tooltip window. Unlike my_create_window, we do not do this
5109 indirectly via the Window thread, as we do not need to process Window
5110 messages for the tooltip. Creating tooltips indirectly also creates
5111 deadlocks when tooltips are created for menu items. */
5112void
5113my_create_tip_window (f)
5114 struct frame *f;
5115{
bfd6edcc 5116 RECT rect;
ca56d953 5117
bfd6edcc
JR
5118 rect.left = rect.top = 0;
5119 rect.right = PIXEL_WIDTH (f);
5120 rect.bottom = PIXEL_HEIGHT (f);
5121
5122 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5123 FRAME_EXTERNAL_MENU_BAR (f));
5124
5125 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5126 = CreateWindow (EMACS_CLASS,
5127 f->namebuf,
5128 f->output_data.w32->dwStyle,
5129 f->output_data.w32->left_pos,
5130 f->output_data.w32->top_pos,
bfd6edcc
JR
5131 rect.right - rect.left,
5132 rect.bottom - rect.top,
ca56d953
JR
5133 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5134 NULL,
5135 hinst,
5136 NULL);
5137
bfd6edcc 5138 if (tip_window)
ca56d953 5139 {
bfd6edcc
JR
5140 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5141 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5142 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5143 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5144
5145 /* Tip frames have no scrollbars. */
5146 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5147
5148 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5149 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5150 }
5151}
5152
5153
fbd6baed 5154/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5155
5156static void
fbd6baed 5157w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5158 struct frame *f;
5159 long window_prompting;
5160 int minibuffer_only;
5161{
5162 BLOCK_INPUT;
5163
5164 /* Use the resource name as the top-level window name
5165 for looking up resources. Make a non-Lisp copy
5166 for the window manager, so GC relocation won't bother it.
5167
5168 Elsewhere we specify the window name for the window manager. */
5169
5170 {
5171 char *str = (char *) XSTRING (Vx_resource_name)->data;
5172 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5173 strcpy (f->namebuf, str);
5174 }
5175
5176 my_create_window (f);
5177
5178 validate_x_resource_name ();
5179
5180 /* x_set_name normally ignores requests to set the name if the
5181 requested name is the same as the current name. This is the one
5182 place where that assumption isn't correct; f->name is set, but
5183 the server hasn't been told. */
5184 {
5185 Lisp_Object name;
5186 int explicit = f->explicit_name;
5187
5188 f->explicit_name = 0;
5189 name = f->name;
5190 f->name = Qnil;
5191 x_set_name (f, name, explicit);
5192 }
5193
5194 UNBLOCK_INPUT;
5195
5196 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5197 initialize_frame_menubar (f);
5198
fbd6baed 5199 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5200 error ("Unable to create window");
5201}
5202
5203/* Handle the icon stuff for this window. Perhaps later we might
5204 want an x_set_icon_position which can be called interactively as
5205 well. */
5206
5207static void
5208x_icon (f, parms)
5209 struct frame *f;
5210 Lisp_Object parms;
5211{
5212 Lisp_Object icon_x, icon_y;
5213
e9e23e23 5214 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5215 icons in the tray. */
6fc2811b
JR
5216 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5217 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5218 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5219 {
b7826503
PJ
5220 CHECK_NUMBER (icon_x);
5221 CHECK_NUMBER (icon_y);
ee78dc32
GV
5222 }
5223 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5224 error ("Both left and top icon corners of icon must be specified");
5225
5226 BLOCK_INPUT;
5227
5228 if (! EQ (icon_x, Qunbound))
5229 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5230
1edf84e7
GV
5231#if 0 /* TODO */
5232 /* Start up iconic or window? */
5233 x_wm_set_window_state
6fc2811b 5234 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5235 ? IconicState
5236 : NormalState));
5237
5238 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5239 ? f->icon_name
5240 : f->name))->data);
5241#endif
5242
ee78dc32
GV
5243 UNBLOCK_INPUT;
5244}
5245
6fc2811b
JR
5246
5247static void
5248x_make_gc (f)
5249 struct frame *f;
5250{
5251 XGCValues gc_values;
5252
5253 BLOCK_INPUT;
5254
5255 /* Create the GC's of this frame.
5256 Note that many default values are used. */
5257
5258 /* Normal video */
5259 gc_values.font = f->output_data.w32->font;
5260
5261 /* Cursor has cursor-color background, background-color foreground. */
5262 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5263 gc_values.background = f->output_data.w32->cursor_pixel;
5264 f->output_data.w32->cursor_gc
5265 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5266 (GCFont | GCForeground | GCBackground),
5267 &gc_values);
5268
5269 /* Reliefs. */
5270 f->output_data.w32->white_relief.gc = 0;
5271 f->output_data.w32->black_relief.gc = 0;
5272
5273 UNBLOCK_INPUT;
5274}
5275
5276
937e601e
AI
5277/* Handler for signals raised during x_create_frame and
5278 x_create_top_frame. FRAME is the frame which is partially
5279 constructed. */
5280
5281static Lisp_Object
5282unwind_create_frame (frame)
5283 Lisp_Object frame;
5284{
5285 struct frame *f = XFRAME (frame);
5286
5287 /* If frame is ``official'', nothing to do. */
5288 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5289 {
5290#ifdef GLYPH_DEBUG
5291 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5292#endif
5293
5294 x_free_frame_resources (f);
5295
5296 /* Check that reference counts are indeed correct. */
5297 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5298 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5299
5300 return Qt;
937e601e
AI
5301 }
5302
5303 return Qnil;
5304}
5305
5306
ee78dc32
GV
5307DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5308 1, 1, 0,
74e1aeec
JR
5309 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5310Returns an Emacs frame object.
5311ALIST is an alist of frame parameters.
5312If the parameters specify that the frame should not have a minibuffer,
5313and do not specify a specific minibuffer window to use,
5314then `default-minibuffer-frame' must be a frame whose minibuffer can
5315be shared by the new frame.
5316
5317This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5318 (parms)
5319 Lisp_Object parms;
5320{
5321 struct frame *f;
5322 Lisp_Object frame, tem;
5323 Lisp_Object name;
5324 int minibuffer_only = 0;
5325 long window_prompting = 0;
5326 int width, height;
dc220243 5327 int count = BINDING_STACK_SIZE ();
1edf84e7 5328 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5329 Lisp_Object display;
6fc2811b 5330 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5331 Lisp_Object parent;
5332 struct kboard *kb;
5333
4587b026
GV
5334 check_w32 ();
5335
ee78dc32
GV
5336 /* Use this general default value to start with
5337 until we know if this frame has a specified name. */
5338 Vx_resource_name = Vinvocation_name;
5339
6fc2811b 5340 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5341 if (EQ (display, Qunbound))
5342 display = Qnil;
5343 dpyinfo = check_x_display_info (display);
5344#ifdef MULTI_KBOARD
5345 kb = dpyinfo->kboard;
5346#else
5347 kb = &the_only_kboard;
5348#endif
5349
6fc2811b 5350 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5351 if (!STRINGP (name)
5352 && ! EQ (name, Qunbound)
5353 && ! NILP (name))
5354 error ("Invalid frame name--not a string or nil");
5355
5356 if (STRINGP (name))
5357 Vx_resource_name = name;
5358
5359 /* See if parent window is specified. */
6fc2811b 5360 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5361 if (EQ (parent, Qunbound))
5362 parent = Qnil;
5363 if (! NILP (parent))
b7826503 5364 CHECK_NUMBER (parent);
ee78dc32 5365
1edf84e7
GV
5366 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5367 /* No need to protect DISPLAY because that's not used after passing
5368 it to make_frame_without_minibuffer. */
5369 frame = Qnil;
5370 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5371 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5372 RES_TYPE_SYMBOL);
ee78dc32
GV
5373 if (EQ (tem, Qnone) || NILP (tem))
5374 f = make_frame_without_minibuffer (Qnil, kb, display);
5375 else if (EQ (tem, Qonly))
5376 {
5377 f = make_minibuffer_frame ();
5378 minibuffer_only = 1;
5379 }
5380 else if (WINDOWP (tem))
5381 f = make_frame_without_minibuffer (tem, kb, display);
5382 else
5383 f = make_frame (1);
5384
1edf84e7
GV
5385 XSETFRAME (frame, f);
5386
ee78dc32
GV
5387 /* Note that Windows does support scroll bars. */
5388 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5389 /* By default, make scrollbars the system standard width. */
5390 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5391
fbd6baed 5392 f->output_method = output_w32;
6fc2811b
JR
5393 f->output_data.w32 =
5394 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5395 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5396 FRAME_FONTSET (f) = -1;
937e601e 5397 record_unwind_protect (unwind_create_frame, frame);
4587b026 5398
1edf84e7 5399 f->icon_name
6fc2811b 5400 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5401 if (! STRINGP (f->icon_name))
5402 f->icon_name = Qnil;
5403
fbd6baed 5404/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5405#ifdef MULTI_KBOARD
5406 FRAME_KBOARD (f) = kb;
5407#endif
5408
5409 /* Specify the parent under which to make this window. */
5410
5411 if (!NILP (parent))
5412 {
1660f34a 5413 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5414 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5415 }
5416 else
5417 {
fbd6baed
GV
5418 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5419 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5420 }
5421
ee78dc32
GV
5422 /* Set the name; the functions to which we pass f expect the name to
5423 be set. */
5424 if (EQ (name, Qunbound) || NILP (name))
5425 {
fbd6baed 5426 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5427 f->explicit_name = 0;
5428 }
5429 else
5430 {
5431 f->name = name;
5432 f->explicit_name = 1;
5433 /* use the frame's title when getting resources for this frame. */
5434 specbind (Qx_resource_name, name);
5435 }
5436
5437 /* Extract the window parameters from the supplied values
5438 that are needed to determine window geometry. */
5439 {
5440 Lisp_Object font;
5441
6fc2811b
JR
5442 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5443
ee78dc32
GV
5444 BLOCK_INPUT;
5445 /* First, try whatever font the caller has specified. */
5446 if (STRINGP (font))
4587b026
GV
5447 {
5448 tem = Fquery_fontset (font, Qnil);
5449 if (STRINGP (tem))
5450 font = x_new_fontset (f, XSTRING (tem)->data);
5451 else
1075afa9 5452 font = x_new_font (f, XSTRING (font)->data);
4587b026 5453 }
ee78dc32
GV
5454 /* Try out a font which we hope has bold and italic variations. */
5455 if (!STRINGP (font))
e39649be 5456 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5457 if (! STRINGP (font))
6fc2811b 5458 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5459 /* If those didn't work, look for something which will at least work. */
5460 if (! STRINGP (font))
6fc2811b 5461 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5462 UNBLOCK_INPUT;
5463 if (! STRINGP (font))
1edf84e7 5464 font = build_string ("Fixedsys");
ee78dc32
GV
5465
5466 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5467 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5468 }
5469
5470 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5471 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5472 /* This defaults to 2 in order to match xterm. We recognize either
5473 internalBorderWidth or internalBorder (which is what xterm calls
5474 it). */
5475 if (NILP (Fassq (Qinternal_border_width, parms)))
5476 {
5477 Lisp_Object value;
5478
6fc2811b 5479 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5480 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5481 if (! EQ (value, Qunbound))
5482 parms = Fcons (Fcons (Qinternal_border_width, value),
5483 parms);
5484 }
1edf84e7 5485 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5486 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5487 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5488 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5489 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5490
5491 /* Also do the stuff which must be set before the window exists. */
5492 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5493 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5494 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5495 "background", "Background", RES_TYPE_STRING);
ee78dc32 5496 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5497 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5498 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5499 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5500 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5501 "borderColor", "BorderColor", RES_TYPE_STRING);
5502 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5503 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5504 x_default_parameter (f, parms, Qline_spacing, Qnil,
5505 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5506 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5507 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5508 x_default_parameter (f, parms, Qright_fringe, Qnil,
5509 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5510
ee78dc32 5511
6fc2811b
JR
5512 /* Init faces before x_default_parameter is called for scroll-bar
5513 parameters because that function calls x_set_scroll_bar_width,
5514 which calls change_frame_size, which calls Fset_window_buffer,
5515 which runs hooks, which call Fvertical_motion. At the end, we
5516 end up in init_iterator with a null face cache, which should not
5517 happen. */
5518 init_frame_faces (f);
5519
ee78dc32 5520 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5521 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5522 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5523 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5524 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5525 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5526 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5527 "title", "Title", RES_TYPE_STRING);
ee78dc32 5528
fbd6baed
GV
5529 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5530 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5531
5532 /* Add the tool-bar height to the initial frame height so that the
5533 user gets a text display area of the size he specified with -g or
5534 via .Xdefaults. Later changes of the tool-bar height don't
5535 change the frame size. This is done so that users can create
5536 tall Emacs frames without having to guess how tall the tool-bar
5537 will get. */
5538 if (FRAME_TOOL_BAR_LINES (f))
5539 {
5540 int margin, relief, bar_height;
5541
a05e2bae 5542 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5543 ? tool_bar_button_relief
5544 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5545
5546 if (INTEGERP (Vtool_bar_button_margin)
5547 && XINT (Vtool_bar_button_margin) > 0)
5548 margin = XFASTINT (Vtool_bar_button_margin);
5549 else if (CONSP (Vtool_bar_button_margin)
5550 && INTEGERP (XCDR (Vtool_bar_button_margin))
5551 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5552 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5553 else
5554 margin = 0;
5555
5556 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5557 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5558 }
5559
ee78dc32
GV
5560 window_prompting = x_figure_window_size (f, parms);
5561
5562 if (window_prompting & XNegative)
5563 {
5564 if (window_prompting & YNegative)
fbd6baed 5565 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5566 else
fbd6baed 5567 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5568 }
5569 else
5570 {
5571 if (window_prompting & YNegative)
fbd6baed 5572 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5573 else
fbd6baed 5574 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5575 }
5576
fbd6baed 5577 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5578
6fc2811b
JR
5579 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5580 f->no_split = minibuffer_only || EQ (tem, Qt);
5581
fbd6baed 5582 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5583 x_icon (f, parms);
6fc2811b
JR
5584
5585 x_make_gc (f);
5586
5587 /* Now consider the frame official. */
5588 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5589 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5590
5591 /* We need to do this after creating the window, so that the
5592 icon-creation functions can say whose icon they're describing. */
5593 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5594 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5595
5596 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5597 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5598 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5599 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5600 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5601 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5602 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5603 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5604
5605 /* Dimensions, especially f->height, must be done via change_frame_size.
5606 Change will not be effected unless different from the current
5607 f->height. */
5608 width = f->width;
5609 height = f->height;
dc220243 5610
1026b400
RS
5611 f->height = 0;
5612 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5613 change_frame_size (f, height, width, 1, 0, 0);
5614
6fc2811b
JR
5615 /* Tell the server what size and position, etc, we want, and how
5616 badly we want them. This should be done after we have the menu
5617 bar so that its size can be taken into account. */
ee78dc32
GV
5618 BLOCK_INPUT;
5619 x_wm_set_size_hint (f, window_prompting, 0);
5620 UNBLOCK_INPUT;
5621
4694d762
JR
5622 /* Set up faces after all frame parameters are known. This call
5623 also merges in face attributes specified for new frames. If we
5624 don't do this, the `menu' face for instance won't have the right
5625 colors, and the menu bar won't appear in the specified colors for
5626 new frames. */
5627 call1 (Qface_set_after_frame_default, frame);
5628
6fc2811b
JR
5629 /* Make the window appear on the frame and enable display, unless
5630 the caller says not to. However, with explicit parent, Emacs
5631 cannot control visibility, so don't try. */
fbd6baed 5632 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5633 {
5634 Lisp_Object visibility;
5635
6fc2811b 5636 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5637 if (EQ (visibility, Qunbound))
5638 visibility = Qt;
5639
5640 if (EQ (visibility, Qicon))
5641 x_iconify_frame (f);
5642 else if (! NILP (visibility))
5643 x_make_frame_visible (f);
5644 else
5645 /* Must have been Qnil. */
5646 ;
5647 }
6fc2811b 5648 UNGCPRO;
9e57df62
GM
5649
5650 /* Make sure windows on this frame appear in calls to next-window
5651 and similar functions. */
5652 Vwindow_list = Qnil;
5653
ee78dc32
GV
5654 return unbind_to (count, frame);
5655}
5656
5657/* FRAME is used only to get a handle on the X display. We don't pass the
5658 display info directly because we're called from frame.c, which doesn't
5659 know about that structure. */
5660Lisp_Object
5661x_get_focus_frame (frame)
5662 struct frame *frame;
5663{
fbd6baed 5664 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5665 Lisp_Object xfocus;
fbd6baed 5666 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5667 return Qnil;
5668
fbd6baed 5669 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5670 return xfocus;
5671}
1edf84e7
GV
5672
5673DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5674 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5675 (frame)
5676 Lisp_Object frame;
5677{
5678 x_focus_on_frame (check_x_frame (frame));
5679 return Qnil;
5680}
5681
ee78dc32 5682\f
767b1ff0
JR
5683/* Return the charset portion of a font name. */
5684char * xlfd_charset_of_font (char * fontname)
5685{
5686 char *charset, *encoding;
5687
5688 encoding = strrchr(fontname, '-');
ceb12877 5689 if (!encoding || encoding == fontname)
767b1ff0
JR
5690 return NULL;
5691
478ea067
AI
5692 for (charset = encoding - 1; charset >= fontname; charset--)
5693 if (*charset == '-')
5694 break;
767b1ff0 5695
478ea067 5696 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5697 return NULL;
5698
5699 return charset + 1;
5700}
5701
33d52f9c
GV
5702struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5703 int size, char* filename);
8edb0a6f 5704static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5705static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5706 char * charset);
5707static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5708
8edb0a6f 5709static struct font_info *
33d52f9c 5710w32_load_system_font (f,fontname,size)
55dcfc15
AI
5711 struct frame *f;
5712 char * fontname;
5713 int size;
ee78dc32 5714{
4587b026
GV
5715 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5716 Lisp_Object font_names;
5717
4587b026
GV
5718 /* Get a list of all the fonts that match this name. Once we
5719 have a list of matching fonts, we compare them against the fonts
5720 we already have loaded by comparing names. */
5721 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5722
5723 if (!NILP (font_names))
3c190163 5724 {
4587b026
GV
5725 Lisp_Object tail;
5726 int i;
4587b026
GV
5727
5728 /* First check if any are already loaded, as that is cheaper
5729 than loading another one. */
5730 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5731 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5732 if (dpyinfo->font_table[i].name
5733 && (!strcmp (dpyinfo->font_table[i].name,
5734 XSTRING (XCAR (tail))->data)
5735 || !strcmp (dpyinfo->font_table[i].full_name,
5736 XSTRING (XCAR (tail))->data)))
4587b026 5737 return (dpyinfo->font_table + i);
6fc2811b 5738
8e713be6 5739 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5740 }
1075afa9 5741 else if (w32_strict_fontnames)
5ca0cd71
GV
5742 {
5743 /* If EnumFontFamiliesEx was available, we got a full list of
5744 fonts back so stop now to avoid the possibility of loading a
5745 random font. If we had to fall back to EnumFontFamilies, the
5746 list is incomplete, so continue whether the font we want was
5747 listed or not. */
5748 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5749 FARPROC enum_font_families_ex
1075afa9 5750 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5751 if (enum_font_families_ex)
5752 return NULL;
5753 }
4587b026
GV
5754
5755 /* Load the font and add it to the table. */
5756 {
767b1ff0 5757 char *full_name, *encoding, *charset;
4587b026
GV
5758 XFontStruct *font;
5759 struct font_info *fontp;
3c190163 5760 LOGFONT lf;
4587b026 5761 BOOL ok;
19c291d3 5762 int codepage;
6fc2811b 5763 int i;
5ac45f98 5764
4587b026 5765 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5766 return (NULL);
5ac45f98 5767
4587b026
GV
5768 if (!*lf.lfFaceName)
5769 /* If no name was specified for the font, we get a random font
5770 from CreateFontIndirect - this is not particularly
5771 desirable, especially since CreateFontIndirect does not
5772 fill out the missing name in lf, so we never know what we
5773 ended up with. */
5774 return NULL;
5775
3c190163 5776 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5777 bzero (font, sizeof (*font));
5ac45f98 5778
33d52f9c
GV
5779 /* Set bdf to NULL to indicate that this is a Windows font. */
5780 font->bdf = NULL;
5ac45f98 5781
3c190163 5782 BLOCK_INPUT;
5ac45f98
GV
5783
5784 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5785
1a292d24
AI
5786 if (font->hfont == NULL)
5787 {
5788 ok = FALSE;
5789 }
5790 else
5791 {
5792 HDC hdc;
5793 HANDLE oldobj;
19c291d3
AI
5794
5795 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5796
5797 hdc = GetDC (dpyinfo->root_window);
5798 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5799
1a292d24 5800 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5801 if (codepage == CP_UNICODE)
5802 font->double_byte_p = 1;
5803 else
8b77111c
AI
5804 {
5805 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5806 don't report themselves as double byte fonts, when
5807 patently they are. So instead of trusting
5808 GetFontLanguageInfo, we check the properties of the
5809 codepage directly, since that is ultimately what we are
5810 working from anyway. */
5811 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5812 CPINFO cpi = {0};
5813 GetCPInfo (codepage, &cpi);
5814 font->double_byte_p = cpi.MaxCharSize > 1;
5815 }
5c6682be 5816
1a292d24
AI
5817 SelectObject (hdc, oldobj);
5818 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5819 /* Fill out details in lf according to the font that was
5820 actually loaded. */
5821 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5822 lf.lfWidth = font->tm.tmAveCharWidth;
5823 lf.lfWeight = font->tm.tmWeight;
5824 lf.lfItalic = font->tm.tmItalic;
5825 lf.lfCharSet = font->tm.tmCharSet;
5826 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5827 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5828 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5829 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5830
5831 w32_cache_char_metrics (font);
1a292d24 5832 }
5ac45f98 5833
1a292d24 5834 UNBLOCK_INPUT;
5ac45f98 5835
4587b026
GV
5836 if (!ok)
5837 {
1a292d24
AI
5838 w32_unload_font (dpyinfo, font);
5839 return (NULL);
5840 }
ee78dc32 5841
6fc2811b
JR
5842 /* Find a free slot in the font table. */
5843 for (i = 0; i < dpyinfo->n_fonts; ++i)
5844 if (dpyinfo->font_table[i].name == NULL)
5845 break;
5846
5847 /* If no free slot found, maybe enlarge the font table. */
5848 if (i == dpyinfo->n_fonts
5849 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5850 {
6fc2811b
JR
5851 int sz;
5852 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5853 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5854 dpyinfo->font_table
6fc2811b 5855 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5856 }
5857
6fc2811b
JR
5858 fontp = dpyinfo->font_table + i;
5859 if (i == dpyinfo->n_fonts)
5860 ++dpyinfo->n_fonts;
4587b026
GV
5861
5862 /* Now fill in the slots of *FONTP. */
5863 BLOCK_INPUT;
5864 fontp->font = font;
6fc2811b 5865 fontp->font_idx = i;
4587b026
GV
5866 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5867 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5868
767b1ff0
JR
5869 charset = xlfd_charset_of_font (fontname);
5870
19c291d3
AI
5871 /* Cache the W32 codepage for a font. This makes w32_encode_char
5872 (called for every glyph during redisplay) much faster. */
5873 fontp->codepage = codepage;
5874
4587b026
GV
5875 /* Work out the font's full name. */
5876 full_name = (char *)xmalloc (100);
767b1ff0 5877 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
5878 fontp->full_name = full_name;
5879 else
5880 {
5881 /* If all else fails - just use the name we used to load it. */
5882 xfree (full_name);
5883 fontp->full_name = fontp->name;
5884 }
5885
5886 fontp->size = FONT_WIDTH (font);
5887 fontp->height = FONT_HEIGHT (font);
5888
5889 /* The slot `encoding' specifies how to map a character
5890 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
5891 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5892 (0:0x20..0x7F, 1:0xA0..0xFF,
5893 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 5894 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 5895 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
5896 which is never used by any charset. If mapping can't be
5897 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5898
5899 /* SJIS fonts need to be set to type 4, all others seem to work as
5900 type FONT_ENCODING_NOT_DECIDED. */
5901 encoding = strrchr (fontp->name, '-');
5902 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5903 fontp->encoding[1] = 4;
33d52f9c 5904 else
1c885fe1 5905 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5906
5907 /* The following three values are set to 0 under W32, which is
5908 what they get set to if XGetFontProperty fails under X. */
5909 fontp->baseline_offset = 0;
5910 fontp->relative_compose = 0;
33d52f9c 5911 fontp->default_ascent = 0;
4587b026 5912
6fc2811b
JR
5913 /* Set global flag fonts_changed_p to non-zero if the font loaded
5914 has a character with a smaller width than any other character
5915 before, or if the font loaded has a smalle>r height than any
5916 other font loaded before. If this happens, it will make a
5917 glyph matrix reallocation necessary. */
5918 fonts_changed_p = x_compute_min_glyph_bounds (f);
4587b026 5919 UNBLOCK_INPUT;
4587b026
GV
5920 return fontp;
5921 }
5922}
5923
33d52f9c
GV
5924/* Load font named FONTNAME of size SIZE for frame F, and return a
5925 pointer to the structure font_info while allocating it dynamically.
5926 If loading fails, return NULL. */
5927struct font_info *
5928w32_load_font (f,fontname,size)
5929struct frame *f;
5930char * fontname;
5931int size;
5932{
5933 Lisp_Object bdf_fonts;
5934 struct font_info *retval = NULL;
5935
8edb0a6f 5936 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
5937
5938 while (!retval && CONSP (bdf_fonts))
5939 {
5940 char *bdf_name, *bdf_file;
5941 Lisp_Object bdf_pair;
5942
8e713be6
KR
5943 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5944 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5945 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
5946
5947 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5948
8e713be6 5949 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
5950 }
5951
5952 if (retval)
5953 return retval;
5954
5955 return w32_load_system_font(f, fontname, size);
5956}
5957
5958
ee78dc32 5959void
fbd6baed
GV
5960w32_unload_font (dpyinfo, font)
5961 struct w32_display_info *dpyinfo;
ee78dc32
GV
5962 XFontStruct * font;
5963{
5964 if (font)
5965 {
c6be3860 5966 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
5967 if (font->bdf) w32_free_bdf_font (font->bdf);
5968
3c190163 5969 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5970 xfree (font);
5971 }
5972}
5973
fbd6baed 5974/* The font conversion stuff between x and w32 */
ee78dc32
GV
5975
5976/* X font string is as follows (from faces.el)
5977 * (let ((- "[-?]")
5978 * (foundry "[^-]+")
5979 * (family "[^-]+")
5980 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5981 * (weight\? "\\([^-]*\\)") ; 1
5982 * (slant "\\([ior]\\)") ; 2
5983 * (slant\? "\\([^-]?\\)") ; 2
5984 * (swidth "\\([^-]*\\)") ; 3
5985 * (adstyle "[^-]*") ; 4
5986 * (pixelsize "[0-9]+")
5987 * (pointsize "[0-9][0-9]+")
5988 * (resx "[0-9][0-9]+")
5989 * (resy "[0-9][0-9]+")
5990 * (spacing "[cmp?*]")
5991 * (avgwidth "[0-9]+")
5992 * (registry "[^-]+")
5993 * (encoding "[^-]+")
5994 * )
ee78dc32 5995 */
ee78dc32 5996
8edb0a6f 5997static LONG
fbd6baed 5998x_to_w32_weight (lpw)
ee78dc32
GV
5999 char * lpw;
6000{
6001 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6002
6003 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6004 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6005 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6006 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6007 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6008 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6009 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6010 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6011 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6012 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6013 else
5ac45f98 6014 return FW_DONTCARE;
ee78dc32
GV
6015}
6016
5ac45f98 6017
8edb0a6f 6018static char *
fbd6baed 6019w32_to_x_weight (fnweight)
ee78dc32
GV
6020 int fnweight;
6021{
5ac45f98
GV
6022 if (fnweight >= FW_HEAVY) return "heavy";
6023 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6024 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6025 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6026 if (fnweight >= FW_MEDIUM) return "medium";
6027 if (fnweight >= FW_NORMAL) return "normal";
6028 if (fnweight >= FW_LIGHT) return "light";
6029 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6030 if (fnweight >= FW_THIN) return "thin";
6031 else
6032 return "*";
6033}
6034
8edb0a6f 6035static LONG
fbd6baed 6036x_to_w32_charset (lpcs)
5ac45f98
GV
6037 char * lpcs;
6038{
767b1ff0 6039 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6040 char *charset;
6041 int len = strlen (lpcs);
6042
6043 /* Support "*-#nnn" format for unknown charsets. */
6044 if (strncmp (lpcs, "*-#", 3) == 0)
6045 return atoi (lpcs + 3);
6046
6047 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6048 charset = alloca (len + 1);
6049 strcpy (charset, lpcs);
6050 lpcs = strchr (charset, '*');
6051 if (lpcs)
6052 *lpcs = 0;
4587b026 6053
dfff8a69
JR
6054 /* Look through w32-charset-info-alist for the character set.
6055 Format of each entry is
6056 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6057 */
8b77111c 6058 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6059
767b1ff0
JR
6060 if (NILP(this_entry))
6061 {
6062 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6063 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6064 return ANSI_CHARSET;
6065 else
6066 return DEFAULT_CHARSET;
6067 }
6068
6069 w32_charset = Fcar (Fcdr (this_entry));
6070
6071 // Translate Lisp symbol to number.
6072 if (w32_charset == Qw32_charset_ansi)
6073 return ANSI_CHARSET;
6074 if (w32_charset == Qw32_charset_symbol)
6075 return SYMBOL_CHARSET;
6076 if (w32_charset == Qw32_charset_shiftjis)
6077 return SHIFTJIS_CHARSET;
6078 if (w32_charset == Qw32_charset_hangeul)
6079 return HANGEUL_CHARSET;
6080 if (w32_charset == Qw32_charset_chinesebig5)
6081 return CHINESEBIG5_CHARSET;
6082 if (w32_charset == Qw32_charset_gb2312)
6083 return GB2312_CHARSET;
6084 if (w32_charset == Qw32_charset_oem)
6085 return OEM_CHARSET;
dfff8a69 6086#ifdef JOHAB_CHARSET
767b1ff0
JR
6087 if (w32_charset == Qw32_charset_johab)
6088 return JOHAB_CHARSET;
6089 if (w32_charset == Qw32_charset_easteurope)
6090 return EASTEUROPE_CHARSET;
6091 if (w32_charset == Qw32_charset_turkish)
6092 return TURKISH_CHARSET;
6093 if (w32_charset == Qw32_charset_baltic)
6094 return BALTIC_CHARSET;
6095 if (w32_charset == Qw32_charset_russian)
6096 return RUSSIAN_CHARSET;
6097 if (w32_charset == Qw32_charset_arabic)
6098 return ARABIC_CHARSET;
6099 if (w32_charset == Qw32_charset_greek)
6100 return GREEK_CHARSET;
6101 if (w32_charset == Qw32_charset_hebrew)
6102 return HEBREW_CHARSET;
6103 if (w32_charset == Qw32_charset_vietnamese)
6104 return VIETNAMESE_CHARSET;
6105 if (w32_charset == Qw32_charset_thai)
6106 return THAI_CHARSET;
6107 if (w32_charset == Qw32_charset_mac)
6108 return MAC_CHARSET;
dfff8a69 6109#endif /* JOHAB_CHARSET */
5ac45f98 6110#ifdef UNICODE_CHARSET
767b1ff0
JR
6111 if (w32_charset == Qw32_charset_unicode)
6112 return UNICODE_CHARSET;
5ac45f98 6113#endif
dfff8a69
JR
6114
6115 return DEFAULT_CHARSET;
5ac45f98
GV
6116}
6117
dfff8a69 6118
8edb0a6f 6119static char *
fbd6baed 6120w32_to_x_charset (fncharset)
5ac45f98
GV
6121 int fncharset;
6122{
5e905a57 6123 static char buf[32];
767b1ff0 6124 Lisp_Object charset_type;
1edf84e7 6125
5ac45f98
GV
6126 switch (fncharset)
6127 {
767b1ff0
JR
6128 case ANSI_CHARSET:
6129 /* Handle startup case of w32-charset-info-alist not
6130 being set up yet. */
6131 if (NILP(Vw32_charset_info_alist))
6132 return "iso8859-1";
6133 charset_type = Qw32_charset_ansi;
6134 break;
6135 case DEFAULT_CHARSET:
6136 charset_type = Qw32_charset_default;
6137 break;
6138 case SYMBOL_CHARSET:
6139 charset_type = Qw32_charset_symbol;
6140 break;
6141 case SHIFTJIS_CHARSET:
6142 charset_type = Qw32_charset_shiftjis;
6143 break;
6144 case HANGEUL_CHARSET:
6145 charset_type = Qw32_charset_hangeul;
6146 break;
6147 case GB2312_CHARSET:
6148 charset_type = Qw32_charset_gb2312;
6149 break;
6150 case CHINESEBIG5_CHARSET:
6151 charset_type = Qw32_charset_chinesebig5;
6152 break;
6153 case OEM_CHARSET:
6154 charset_type = Qw32_charset_oem;
6155 break;
4587b026
GV
6156
6157 /* More recent versions of Windows (95 and NT4.0) define more
6158 character sets. */
6159#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6160 case EASTEUROPE_CHARSET:
6161 charset_type = Qw32_charset_easteurope;
6162 break;
6163 case TURKISH_CHARSET:
6164 charset_type = Qw32_charset_turkish;
6165 break;
6166 case BALTIC_CHARSET:
6167 charset_type = Qw32_charset_baltic;
6168 break;
33d52f9c 6169 case RUSSIAN_CHARSET:
767b1ff0
JR
6170 charset_type = Qw32_charset_russian;
6171 break;
6172 case ARABIC_CHARSET:
6173 charset_type = Qw32_charset_arabic;
6174 break;
6175 case GREEK_CHARSET:
6176 charset_type = Qw32_charset_greek;
6177 break;
6178 case HEBREW_CHARSET:
6179 charset_type = Qw32_charset_hebrew;
6180 break;
6181 case VIETNAMESE_CHARSET:
6182 charset_type = Qw32_charset_vietnamese;
6183 break;
6184 case THAI_CHARSET:
6185 charset_type = Qw32_charset_thai;
6186 break;
6187 case MAC_CHARSET:
6188 charset_type = Qw32_charset_mac;
6189 break;
6190 case JOHAB_CHARSET:
6191 charset_type = Qw32_charset_johab;
6192 break;
4587b026
GV
6193#endif
6194
5ac45f98 6195#ifdef UNICODE_CHARSET
767b1ff0
JR
6196 case UNICODE_CHARSET:
6197 charset_type = Qw32_charset_unicode;
6198 break;
5ac45f98 6199#endif
767b1ff0
JR
6200 default:
6201 /* Encode numerical value of unknown charset. */
6202 sprintf (buf, "*-#%u", fncharset);
6203 return buf;
5ac45f98 6204 }
767b1ff0
JR
6205
6206 {
6207 Lisp_Object rest;
6208 char * best_match = NULL;
6209
6210 /* Look through w32-charset-info-alist for the character set.
6211 Prefer ISO codepages, and prefer lower numbers in the ISO
6212 range. Only return charsets for codepages which are installed.
6213
6214 Format of each entry is
6215 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6216 */
6217 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6218 {
6219 char * x_charset;
6220 Lisp_Object w32_charset;
6221 Lisp_Object codepage;
6222
6223 Lisp_Object this_entry = XCAR (rest);
6224
6225 /* Skip invalid entries in alist. */
6226 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6227 || !CONSP (XCDR (this_entry))
6228 || !SYMBOLP (XCAR (XCDR (this_entry))))
6229 continue;
6230
6231 x_charset = XSTRING (XCAR (this_entry))->data;
6232 w32_charset = XCAR (XCDR (this_entry));
6233 codepage = XCDR (XCDR (this_entry));
6234
6235 /* Look for Same charset and a valid codepage (or non-int
6236 which means ignore). */
6237 if (w32_charset == charset_type
6238 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6239 || IsValidCodePage (XINT (codepage))))
6240 {
6241 /* If we don't have a match already, then this is the
6242 best. */
6243 if (!best_match)
6244 best_match = x_charset;
6245 /* If this is an ISO codepage, and the best so far isn't,
6246 then this is better. */
6247 else if (stricmp (best_match, "iso") != 0
6248 && stricmp (x_charset, "iso") == 0)
6249 best_match = x_charset;
6250 /* If both are ISO8859 codepages, choose the one with the
6251 lowest number in the encoding field. */
6252 else if (stricmp (best_match, "iso8859-") == 0
6253 && stricmp (x_charset, "iso8859-") == 0)
6254 {
6255 int best_enc = atoi (best_match + 8);
6256 int this_enc = atoi (x_charset + 8);
6257 if (this_enc > 0 && this_enc < best_enc)
6258 best_match = x_charset;
6259 }
6260 }
6261 }
6262
6263 /* If no match, encode the numeric value. */
6264 if (!best_match)
6265 {
6266 sprintf (buf, "*-#%u", fncharset);
6267 return buf;
6268 }
6269
5e905a57
JR
6270 strncpy(buf, best_match, 31);
6271 buf[31] = '\0';
767b1ff0
JR
6272 return buf;
6273 }
ee78dc32
GV
6274}
6275
dfff8a69
JR
6276
6277/* Get the Windows codepage corresponding to the specified font. The
6278 charset info in the font name is used to look up
6279 w32-charset-to-codepage-alist. */
6280int
6281w32_codepage_for_font (char *fontname)
6282{
767b1ff0
JR
6283 Lisp_Object codepage, entry;
6284 char *charset_str, *charset, *end;
dfff8a69 6285
767b1ff0 6286 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6287 return CP_DEFAULT;
6288
767b1ff0
JR
6289 /* Extract charset part of font string. */
6290 charset = xlfd_charset_of_font (fontname);
6291
6292 if (!charset)
ceb12877 6293 return CP_UNKNOWN;
767b1ff0 6294
8b77111c 6295 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6296 strcpy (charset_str, charset);
6297
8b77111c 6298#if 0
dfff8a69
JR
6299 /* Remove leading "*-". */
6300 if (strncmp ("*-", charset_str, 2) == 0)
6301 charset = charset_str + 2;
6302 else
8b77111c 6303#endif
dfff8a69
JR
6304 charset = charset_str;
6305
6306 /* Stop match at wildcard (including preceding '-'). */
6307 if (end = strchr (charset, '*'))
6308 {
6309 if (end > charset && *(end-1) == '-')
6310 end--;
6311 *end = '\0';
6312 }
6313
767b1ff0
JR
6314 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6315 if (NILP (entry))
ceb12877 6316 return CP_UNKNOWN;
767b1ff0
JR
6317
6318 codepage = Fcdr (Fcdr (entry));
6319
6320 if (NILP (codepage))
6321 return CP_8BIT;
6322 else if (XFASTINT (codepage) == XFASTINT (Qt))
6323 return CP_UNICODE;
6324 else if (INTEGERP (codepage))
dfff8a69
JR
6325 return XINT (codepage);
6326 else
ceb12877 6327 return CP_UNKNOWN;
dfff8a69
JR
6328}
6329
6330
8edb0a6f 6331static BOOL
767b1ff0 6332w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6333 LOGFONT * lplogfont;
6334 char * lpxstr;
6335 int len;
767b1ff0 6336 char * specific_charset;
ee78dc32 6337{
6fc2811b 6338 char* fonttype;
f46e6225 6339 char *fontname;
3cb20f4a
RS
6340 char height_pixels[8];
6341 char height_dpi[8];
6342 char width_pixels[8];
4587b026 6343 char *fontname_dash;
d88c567c
JR
6344 int display_resy = one_w32_display_info.resy;
6345 int display_resx = one_w32_display_info.resx;
f46e6225
GV
6346 int bufsz;
6347 struct coding_system coding;
3cb20f4a
RS
6348
6349 if (!lpxstr) abort ();
ee78dc32 6350
3cb20f4a
RS
6351 if (!lplogfont)
6352 return FALSE;
6353
6fc2811b
JR
6354 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6355 fonttype = "raster";
6356 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6357 fonttype = "outline";
6358 else
6359 fonttype = "unknown";
6360
1fa3a200 6361 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6362 &coding);
aab5ac44
KH
6363 coding.src_multibyte = 0;
6364 coding.dst_multibyte = 1;
f46e6225
GV
6365 coding.mode |= CODING_MODE_LAST_BLOCK;
6366 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6367
6368 fontname = alloca(sizeof(*fontname) * bufsz);
6369 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6370 strlen(lplogfont->lfFaceName), bufsz - 1);
6371 *(fontname + coding.produced) = '\0';
4587b026
GV
6372
6373 /* Replace dashes with underscores so the dashes are not
f46e6225 6374 misinterpreted. */
4587b026
GV
6375 fontname_dash = fontname;
6376 while (fontname_dash = strchr (fontname_dash, '-'))
6377 *fontname_dash = '_';
6378
3cb20f4a 6379 if (lplogfont->lfHeight)
ee78dc32 6380 {
3cb20f4a
RS
6381 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6382 sprintf (height_dpi, "%u",
33d52f9c 6383 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6384 }
6385 else
ee78dc32 6386 {
3cb20f4a
RS
6387 strcpy (height_pixels, "*");
6388 strcpy (height_dpi, "*");
ee78dc32 6389 }
3cb20f4a
RS
6390 if (lplogfont->lfWidth)
6391 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6392 else
6393 strcpy (width_pixels, "*");
6394
6395 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6396 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6397 fonttype, /* foundry */
4587b026
GV
6398 fontname, /* family */
6399 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6400 lplogfont->lfItalic?'i':'r', /* slant */
6401 /* setwidth name */
6402 /* add style name */
6403 height_pixels, /* pixel size */
6404 height_dpi, /* point size */
33d52f9c
GV
6405 display_resx, /* resx */
6406 display_resy, /* resy */
4587b026
GV
6407 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6408 ? 'p' : 'c', /* spacing */
6409 width_pixels, /* avg width */
767b1ff0
JR
6410 specific_charset ? specific_charset
6411 : w32_to_x_charset (lplogfont->lfCharSet)
6412 /* charset registry and encoding */
3cb20f4a
RS
6413 );
6414
ee78dc32
GV
6415 lpxstr[len - 1] = 0; /* just to be sure */
6416 return (TRUE);
6417}
6418
8edb0a6f 6419static BOOL
fbd6baed 6420x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6421 char * lpxstr;
6422 LOGFONT * lplogfont;
6423{
f46e6225
GV
6424 struct coding_system coding;
6425
ee78dc32 6426 if (!lplogfont) return (FALSE);
f46e6225 6427
ee78dc32 6428 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6429
1a292d24 6430 /* Set default value for each field. */
771c47d5 6431#if 1
ee78dc32
GV
6432 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6433 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6434 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6435#else
6436 /* go for maximum quality */
6437 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6438 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6439 lplogfont->lfQuality = PROOF_QUALITY;
6440#endif
6441
1a292d24
AI
6442 lplogfont->lfCharSet = DEFAULT_CHARSET;
6443 lplogfont->lfWeight = FW_DONTCARE;
6444 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6445
5ac45f98
GV
6446 if (!lpxstr)
6447 return FALSE;
6448
6449 /* Provide a simple escape mechanism for specifying Windows font names
6450 * directly -- if font spec does not beginning with '-', assume this
6451 * format:
6452 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6453 */
ee78dc32 6454
5ac45f98
GV
6455 if (*lpxstr == '-')
6456 {
33d52f9c
GV
6457 int fields, tem;
6458 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6459 width[10], resy[10], remainder[50];
5ac45f98 6460 char * encoding;
d98c0337 6461 int dpi = one_w32_display_info.resy;
5ac45f98
GV
6462
6463 fields = sscanf (lpxstr,
8b77111c 6464 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6465 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6466 if (fields == EOF)
6467 return (FALSE);
6468
6469 /* In the general case when wildcards cover more than one field,
6470 we don't know which field is which, so don't fill any in.
6471 However, we need to cope with this particular form, which is
6472 generated by font_list_1 (invoked by try_font_list):
6473 "-raster-6x10-*-gb2312*-*"
6474 and make sure to correctly parse the charset field. */
6475 if (fields == 3)
6476 {
6477 fields = sscanf (lpxstr,
6478 "-%*[^-]-%49[^-]-*-%49s",
6479 name, remainder);
6480 }
6481 else if (fields < 9)
6482 {
6483 fields = 0;
6484 remainder[0] = 0;
6485 }
6fc2811b 6486
5ac45f98
GV
6487 if (fields > 0 && name[0] != '*')
6488 {
8ea3e054
RS
6489 int bufsize;
6490 unsigned char *buf;
6491
f46e6225 6492 setup_coding_system
1fa3a200 6493 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6494 coding.src_multibyte = 1;
6495 coding.dst_multibyte = 1;
8ea3e054
RS
6496 bufsize = encoding_buffer_size (&coding, strlen (name));
6497 buf = (unsigned char *) alloca (bufsize);
f46e6225 6498 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6499 encode_coding (&coding, name, buf, strlen (name), bufsize);
6500 if (coding.produced >= LF_FACESIZE)
6501 coding.produced = LF_FACESIZE - 1;
6502 buf[coding.produced] = 0;
6503 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6504 }
6505 else
6506 {
6fc2811b 6507 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6508 }
6509
6510 fields--;
6511
fbd6baed 6512 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6513
6514 fields--;
6515
c8874f14 6516 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6517
6518 fields--;
6519
6520 if (fields > 0 && pixels[0] != '*')
6521 lplogfont->lfHeight = atoi (pixels);
6522
6523 fields--;
5ac45f98 6524 fields--;
33d52f9c
GV
6525 if (fields > 0 && resy[0] != '*')
6526 {
6fc2811b 6527 tem = atoi (resy);
33d52f9c
GV
6528 if (tem > 0) dpi = tem;
6529 }
5ac45f98 6530
33d52f9c
GV
6531 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6532 lplogfont->lfHeight = atoi (height) * dpi / 720;
6533
6534 if (fields > 0)
5ac45f98
GV
6535 lplogfont->lfPitchAndFamily =
6536 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6537
6538 fields--;
6539
6540 if (fields > 0 && width[0] != '*')
6541 lplogfont->lfWidth = atoi (width) / 10;
6542
6543 fields--;
6544
4587b026 6545 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6546 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6547 {
5ac45f98
GV
6548 int len = strlen (remainder);
6549 if (len > 0 && remainder[len-1] == '-')
6550 remainder[len-1] = 0;
ee78dc32 6551 }
5ac45f98 6552 encoding = remainder;
8b77111c 6553#if 0
5ac45f98
GV
6554 if (strncmp (encoding, "*-", 2) == 0)
6555 encoding += 2;
8b77111c
AI
6556#endif
6557 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6558 }
6559 else
6560 {
6561 int fields;
6562 char name[100], height[10], width[10], weight[20];
a1a80b40 6563
5ac45f98
GV
6564 fields = sscanf (lpxstr,
6565 "%99[^:]:%9[^:]:%9[^:]:%19s",
6566 name, height, width, weight);
6567
6568 if (fields == EOF) return (FALSE);
6569
6570 if (fields > 0)
6571 {
6572 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6573 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6574 }
6575 else
6576 {
6577 lplogfont->lfFaceName[0] = 0;
6578 }
6579
6580 fields--;
6581
6582 if (fields > 0)
6583 lplogfont->lfHeight = atoi (height);
6584
6585 fields--;
6586
6587 if (fields > 0)
6588 lplogfont->lfWidth = atoi (width);
6589
6590 fields--;
6591
fbd6baed 6592 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6593 }
6594
6595 /* This makes TrueType fonts work better. */
6596 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6597
ee78dc32
GV
6598 return (TRUE);
6599}
6600
d88c567c
JR
6601/* Strip the pixel height and point height from the given xlfd, and
6602 return the pixel height. If no pixel height is specified, calculate
6603 one from the point height, or if that isn't defined either, return
6604 0 (which usually signifies a scalable font).
6605*/
8edb0a6f
JR
6606static int
6607xlfd_strip_height (char *fontname)
d88c567c 6608{
8edb0a6f 6609 int pixel_height, field_number;
d88c567c
JR
6610 char *read_from, *write_to;
6611
6612 xassert (fontname);
6613
6614 pixel_height = field_number = 0;
6615 write_to = NULL;
6616
6617 /* Look for height fields. */
6618 for (read_from = fontname; *read_from; read_from++)
6619 {
6620 if (*read_from == '-')
6621 {
6622 field_number++;
6623 if (field_number == 7) /* Pixel height. */
6624 {
6625 read_from++;
6626 write_to = read_from;
6627
6628 /* Find end of field. */
6629 for (;*read_from && *read_from != '-'; read_from++)
6630 ;
6631
6632 /* Split the fontname at end of field. */
6633 if (*read_from)
6634 {
6635 *read_from = '\0';
6636 read_from++;
6637 }
6638 pixel_height = atoi (write_to);
6639 /* Blank out field. */
6640 if (read_from > write_to)
6641 {
6642 *write_to = '-';
6643 write_to++;
6644 }
767b1ff0 6645 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6646 return now. */
6647 else
6648 return pixel_height;
6649
6650 /* If we got a pixel height, the point height can be
6651 ignored. Just blank it out and break now. */
6652 if (pixel_height)
6653 {
6654 /* Find end of point size field. */
6655 for (; *read_from && *read_from != '-'; read_from++)
6656 ;
6657
6658 if (*read_from)
6659 read_from++;
6660
6661 /* Blank out the point size field. */
6662 if (read_from > write_to)
6663 {
6664 *write_to = '-';
6665 write_to++;
6666 }
6667 else
6668 return pixel_height;
6669
6670 break;
6671 }
6672 /* If the point height is already blank, break now. */
6673 if (*read_from == '-')
6674 {
6675 read_from++;
6676 break;
6677 }
6678 }
6679 else if (field_number == 8)
6680 {
6681 /* If we didn't get a pixel height, try to get the point
6682 height and convert that. */
6683 int point_size;
6684 char *point_size_start = read_from++;
6685
6686 /* Find end of field. */
6687 for (; *read_from && *read_from != '-'; read_from++)
6688 ;
6689
6690 if (*read_from)
6691 {
6692 *read_from = '\0';
6693 read_from++;
6694 }
6695
6696 point_size = atoi (point_size_start);
6697
6698 /* Convert to pixel height. */
6699 pixel_height = point_size
6700 * one_w32_display_info.height_in / 720;
6701
6702 /* Blank out this field and break. */
6703 *write_to = '-';
6704 write_to++;
6705 break;
6706 }
6707 }
6708 }
6709
6710 /* Shift the rest of the font spec into place. */
6711 if (write_to && read_from > write_to)
6712 {
6713 for (; *read_from; read_from++, write_to++)
6714 *write_to = *read_from;
6715 *write_to = '\0';
6716 }
6717
6718 return pixel_height;
6719}
6720
6fc2811b 6721/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 6722static BOOL
6fc2811b
JR
6723w32_font_match (fontname, pattern)
6724 char * fontname;
6725 char * pattern;
ee78dc32 6726{
e7c72122 6727 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 6728 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6729 char *ptr;
ee78dc32 6730
d88c567c
JR
6731 /* Copy fontname so we can modify it during comparison. */
6732 strcpy (font_name_copy, fontname);
6733
6fc2811b
JR
6734 ptr = regex;
6735 *ptr++ = '^';
ee78dc32 6736
6fc2811b
JR
6737 /* Turn pattern into a regexp and do a regexp match. */
6738 for (; *pattern; pattern++)
6739 {
6740 if (*pattern == '?')
6741 *ptr++ = '.';
6742 else if (*pattern == '*')
6743 {
6744 *ptr++ = '.';
6745 *ptr++ = '*';
6746 }
33d52f9c 6747 else
6fc2811b 6748 *ptr++ = *pattern;
ee78dc32 6749 }
6fc2811b
JR
6750 *ptr = '$';
6751 *(ptr + 1) = '\0';
6752
d88c567c
JR
6753 /* Strip out font heights and compare them seperately, since
6754 rounding error can cause mismatches. This also allows a
6755 comparison between a font that declares only a pixel height and a
6756 pattern that declares the point height.
6757 */
6758 {
6759 int font_height, pattern_height;
6760
6761 font_height = xlfd_strip_height (font_name_copy);
6762 pattern_height = xlfd_strip_height (regex);
6763
6764 /* Compare now, and don't bother doing expensive regexp matching
6765 if the heights differ. */
6766 if (font_height && pattern_height && (font_height != pattern_height))
6767 return FALSE;
6768 }
6769
6fc2811b 6770 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 6771 font_name_copy) >= 0);
ee78dc32
GV
6772}
6773
5ca0cd71
GV
6774/* Callback functions, and a structure holding info they need, for
6775 listing system fonts on W32. We need one set of functions to do the
6776 job properly, but these don't work on NT 3.51 and earlier, so we
6777 have a second set which don't handle character sets properly to
6778 fall back on.
6779
6780 In both cases, there are two passes made. The first pass gets one
6781 font from each family, the second pass lists all the fonts from
6782 each family. */
6783
ee78dc32
GV
6784typedef struct enumfont_t
6785{
6786 HDC hdc;
6787 int numFonts;
3cb20f4a 6788 LOGFONT logfont;
ee78dc32
GV
6789 XFontStruct *size_ref;
6790 Lisp_Object *pattern;
ee78dc32
GV
6791 Lisp_Object *tail;
6792} enumfont_t;
6793
8edb0a6f 6794static int CALLBACK
ee78dc32
GV
6795enum_font_cb2 (lplf, lptm, FontType, lpef)
6796 ENUMLOGFONT * lplf;
6797 NEWTEXTMETRIC * lptm;
6798 int FontType;
6799 enumfont_t * lpef;
6800{
66895301
JR
6801 /* Ignore struck out and underlined versions of fonts. */
6802 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6803 return 1;
6804
6805 /* Only return fonts with names starting with @ if they were
6806 explicitly specified, since Microsoft uses an initial @ to
6807 denote fonts for vertical writing, without providing a more
6808 convenient way of identifying them. */
6809 if (lplf->elfLogFont.lfFaceName[0] == '@'
6810 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
6811 return 1;
6812
4587b026
GV
6813 /* Check that the character set matches if it was specified */
6814 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6815 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 6816 return 1;
4587b026 6817
ee78dc32
GV
6818 {
6819 char buf[100];
4587b026 6820 Lisp_Object width = Qnil;
767b1ff0 6821 char *charset = NULL;
ee78dc32 6822
6fc2811b
JR
6823 /* Truetype fonts do not report their true metrics until loaded */
6824 if (FontType != RASTER_FONTTYPE)
3cb20f4a 6825 {
6fc2811b
JR
6826 if (!NILP (*(lpef->pattern)))
6827 {
6828 /* Scalable fonts are as big as you want them to be. */
6829 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6830 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6831 width = make_number (lpef->logfont.lfWidth);
6832 }
6833 else
6834 {
6835 lplf->elfLogFont.lfHeight = 0;
6836 lplf->elfLogFont.lfWidth = 0;
6837 }
3cb20f4a 6838 }
6fc2811b 6839
f46e6225
GV
6840 /* Make sure the height used here is the same as everywhere
6841 else (ie character height, not cell height). */
6fc2811b
JR
6842 if (lplf->elfLogFont.lfHeight > 0)
6843 {
6844 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6845 if (FontType == RASTER_FONTTYPE)
6846 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6847 else
6848 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6849 }
4587b026 6850
767b1ff0
JR
6851 if (!NILP (*(lpef->pattern)))
6852 {
6853 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6854
6855 /* Ensure that charset is valid for this font. */
6856 if (charset
6857 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6858 charset = NULL;
6859 }
6860
6861 /* TODO: List all relevant charsets if charset not specified. */
6862 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
66895301 6863 return 1;
ee78dc32 6864
5ca0cd71
GV
6865 if (NILP (*(lpef->pattern))
6866 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 6867 {
4587b026 6868 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
8e713be6 6869 lpef->tail = &(XCDR (*lpef->tail));
ee78dc32
GV
6870 lpef->numFonts++;
6871 }
6872 }
6fc2811b 6873
5e905a57 6874 return 1;
ee78dc32
GV
6875}
6876
8edb0a6f 6877static int CALLBACK
ee78dc32
GV
6878enum_font_cb1 (lplf, lptm, FontType, lpef)
6879 ENUMLOGFONT * lplf;
6880 NEWTEXTMETRIC * lptm;
6881 int FontType;
6882 enumfont_t * lpef;
6883{
6884 return EnumFontFamilies (lpef->hdc,
6885 lplf->elfLogFont.lfFaceName,
6886 (FONTENUMPROC) enum_font_cb2,
6887 (LPARAM) lpef);
6888}
6889
6890
8edb0a6f 6891static int CALLBACK
5ca0cd71
GV
6892enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6893 ENUMLOGFONTEX * lplf;
6894 NEWTEXTMETRICEX * lptm;
6895 int font_type;
6896 enumfont_t * lpef;
6897{
6898 /* We are not interested in the extra info we get back from the 'Ex
6899 version - only the fact that we get character set variations
6900 enumerated seperately. */
6901 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6902 font_type, lpef);
6903}
6904
8edb0a6f 6905static int CALLBACK
5ca0cd71
GV
6906enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6907 ENUMLOGFONTEX * lplf;
6908 NEWTEXTMETRICEX * lptm;
6909 int font_type;
6910 enumfont_t * lpef;
6911{
6912 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6913 FARPROC enum_font_families_ex
6914 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6915 /* We don't really expect EnumFontFamiliesEx to disappear once we
6916 get here, so don't bother handling it gracefully. */
6917 if (enum_font_families_ex == NULL)
6918 error ("gdi32.dll has disappeared!");
6919 return enum_font_families_ex (lpef->hdc,
6920 &lplf->elfLogFont,
6921 (FONTENUMPROC) enum_fontex_cb2,
6922 (LPARAM) lpef, 0);
6923}
6924
4587b026
GV
6925/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6926 and xterm.c in Emacs 20.3) */
6927
8edb0a6f 6928static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6929{
6930 char *fontname, *ptnstr;
6931 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6932 int n_fonts = 0;
33d52f9c
GV
6933
6934 list = Vw32_bdf_filename_alist;
6935 ptnstr = XSTRING (pattern)->data;
6936
8e713be6 6937 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6938 {
8e713be6 6939 tem = XCAR (list);
33d52f9c 6940 if (CONSP (tem))
8e713be6 6941 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
6942 else if (STRINGP (tem))
6943 fontname = XSTRING (tem)->data;
6944 else
6945 continue;
6946
6947 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6948 {
8e713be6 6949 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6950 n_fonts++;
6951 if (n_fonts >= max_names)
6952 break;
6953 }
33d52f9c
GV
6954 }
6955
6956 return newlist;
6957}
6958
8edb0a6f
JR
6959static Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f,
6960 Lisp_Object pattern,
6961 int size, int max_names);
5ca0cd71 6962
4587b026
GV
6963/* Return a list of names of available fonts matching PATTERN on frame
6964 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6965 to be listed. Frame F NULL means we have not yet created any
6966 frame, which means we can't get proper size info, as we don't have
6967 a device context to use for GetTextMetrics.
6968 MAXNAMES sets a limit on how many fonts to match. */
6969
6970Lisp_Object
dc220243
JR
6971w32_list_fonts (f, pattern, size, maxnames)
6972 struct frame *f;
6973 Lisp_Object pattern;
6974 int size;
6975 int maxnames;
4587b026 6976{
6fc2811b 6977 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6978 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6979 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6980 int n_fonts = 0;
396594fe 6981
4587b026
GV
6982 patterns = Fassoc (pattern, Valternate_fontname_alist);
6983 if (NILP (patterns))
6984 patterns = Fcons (pattern, Qnil);
6985
8e713be6 6986 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6987 {
6988 enumfont_t ef;
767b1ff0 6989 int codepage;
4587b026 6990
8e713be6 6991 tpat = XCAR (patterns);
4587b026 6992
767b1ff0
JR
6993 if (!STRINGP (tpat))
6994 continue;
6995
6996 /* Avoid expensive EnumFontFamilies functions if we are not
6997 going to be able to output one of these anyway. */
6998 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6999 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7000 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7001 && !IsValidCodePage(codepage))
767b1ff0
JR
7002 continue;
7003
4587b026
GV
7004 /* See if we cached the result for this particular query.
7005 The cache is an alist of the form:
7006 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7007 */
8e713be6 7008 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7009 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7010 {
7011 list = Fcdr_safe (list);
7012 /* We have a cached list. Don't have to get the list again. */
7013 goto label_cached;
7014 }
7015
7016 BLOCK_INPUT;
7017 /* At first, put PATTERN in the cache. */
7018 list = Qnil;
33d52f9c
GV
7019 ef.pattern = &tpat;
7020 ef.tail = &list;
4587b026 7021 ef.numFonts = 0;
33d52f9c 7022
5ca0cd71
GV
7023 /* Use EnumFontFamiliesEx where it is available, as it knows
7024 about character sets. Fall back to EnumFontFamilies for
7025 older versions of NT that don't support the 'Ex function. */
767b1ff0 7026 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7027 {
5ca0cd71
GV
7028 LOGFONT font_match_pattern;
7029 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7030 FARPROC enum_font_families_ex
7031 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7032
7033 /* We do our own pattern matching so we can handle wildcards. */
7034 font_match_pattern.lfFaceName[0] = 0;
7035 font_match_pattern.lfPitchAndFamily = 0;
7036 /* We can use the charset, because if it is a wildcard it will
7037 be DEFAULT_CHARSET anyway. */
7038 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7039
33d52f9c 7040 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7041
5ca0cd71
GV
7042 if (enum_font_families_ex)
7043 enum_font_families_ex (ef.hdc,
7044 &font_match_pattern,
7045 (FONTENUMPROC) enum_fontex_cb1,
7046 (LPARAM) &ef, 0);
7047 else
7048 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7049 (LPARAM)&ef);
4587b026 7050
33d52f9c 7051 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7052 }
7053
7054 UNBLOCK_INPUT;
7055
7056 /* Make a list of the fonts we got back.
7057 Store that in the font cache for the display. */
f3fbd155
KR
7058 XSETCDR (dpyinfo->name_list_element,
7059 Fcons (Fcons (tpat, list),
7060 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7061
7062 label_cached:
7063 if (NILP (list)) continue; /* Try the remaining alternatives. */
7064
7065 newlist = second_best = Qnil;
7066
7067 /* Make a list of the fonts that have the right width. */
8e713be6 7068 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7069 {
7070 int found_size;
8e713be6 7071 tem = XCAR (list);
4587b026
GV
7072
7073 if (!CONSP (tem))
7074 continue;
8e713be6 7075 if (NILP (XCAR (tem)))
4587b026
GV
7076 continue;
7077 if (!size)
7078 {
8e713be6 7079 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7080 n_fonts++;
7081 if (n_fonts >= maxnames)
7082 break;
7083 else
7084 continue;
4587b026 7085 }
8e713be6 7086 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7087 {
7088 /* Since we don't yet know the size of the font, we must
7089 load it and try GetTextMetrics. */
4587b026
GV
7090 W32FontStruct thisinfo;
7091 LOGFONT lf;
7092 HDC hdc;
7093 HANDLE oldobj;
7094
8e713be6 7095 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7096 continue;
7097
7098 BLOCK_INPUT;
33d52f9c 7099 thisinfo.bdf = NULL;
4587b026
GV
7100 thisinfo.hfont = CreateFontIndirect (&lf);
7101 if (thisinfo.hfont == NULL)
7102 continue;
7103
7104 hdc = GetDC (dpyinfo->root_window);
7105 oldobj = SelectObject (hdc, thisinfo.hfont);
7106 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7107 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7108 else
f3fbd155 7109 XSETCDR (tem, make_number (0));
4587b026
GV
7110 SelectObject (hdc, oldobj);
7111 ReleaseDC (dpyinfo->root_window, hdc);
7112 DeleteObject(thisinfo.hfont);
7113 UNBLOCK_INPUT;
7114 }
8e713be6 7115 found_size = XINT (XCDR (tem));
4587b026 7116 if (found_size == size)
5ca0cd71 7117 {
8e713be6 7118 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7119 n_fonts++;
7120 if (n_fonts >= maxnames)
7121 break;
7122 }
4587b026
GV
7123 /* keep track of the closest matching size in case
7124 no exact match is found. */
7125 else if (found_size > 0)
7126 {
7127 if (NILP (second_best))
7128 second_best = tem;
5ca0cd71 7129
4587b026
GV
7130 else if (found_size < size)
7131 {
8e713be6
KR
7132 if (XINT (XCDR (second_best)) > size
7133 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7134 second_best = tem;
7135 }
7136 else
7137 {
8e713be6
KR
7138 if (XINT (XCDR (second_best)) > size
7139 && XINT (XCDR (second_best)) >
4587b026
GV
7140 found_size)
7141 second_best = tem;
7142 }
7143 }
7144 }
7145
7146 if (!NILP (newlist))
7147 break;
7148 else if (!NILP (second_best))
7149 {
8e713be6 7150 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7151 break;
7152 }
7153 }
7154
33d52f9c 7155 /* Include any bdf fonts. */
5ca0cd71 7156 if (n_fonts < maxnames)
33d52f9c
GV
7157 {
7158 Lisp_Object combined[2];
5ca0cd71 7159 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7160 combined[1] = newlist;
7161 newlist = Fnconc(2, combined);
7162 }
7163
5ca0cd71
GV
7164 /* If we can't find a font that matches, check if Windows would be
7165 able to synthesize it from a different style. */
6fc2811b 7166 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
5ca0cd71
GV
7167 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
7168
4587b026
GV
7169 return newlist;
7170}
7171
8edb0a6f 7172static Lisp_Object
5ca0cd71
GV
7173w32_list_synthesized_fonts (f, pattern, size, max_names)
7174 FRAME_PTR f;
7175 Lisp_Object pattern;
7176 int size;
7177 int max_names;
7178{
7179 int fields;
7180 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
7181 char style[20], slant;
8edb0a6f 7182 Lisp_Object matches, tem, synthed_matches = Qnil;
5ca0cd71
GV
7183
7184 full_pattn = XSTRING (pattern)->data;
7185
8b77111c 7186 pattn_part2 = alloca (XSTRING (pattern)->size + 1);
5ca0cd71
GV
7187 /* Allow some space for wildcard expansion. */
7188 new_pattn = alloca (XSTRING (pattern)->size + 100);
7189
7190 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
7191 foundary, family, style, &slant, pattn_part2);
7192 if (fields == EOF || fields < 5)
7193 return Qnil;
7194
7195 /* If the style and slant are wildcards already there is no point
7196 checking again (and we don't want to keep recursing). */
7197 if (*style == '*' && slant == '*')
7198 return Qnil;
7199
7200 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
7201
7202 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
7203
8e713be6 7204 for ( ; CONSP (matches); matches = XCDR (matches))
5ca0cd71 7205 {
8e713be6 7206 tem = XCAR (matches);
5ca0cd71
GV
7207 if (!STRINGP (tem))
7208 continue;
7209
7210 full_pattn = XSTRING (tem)->data;
7211 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
7212 foundary, family, pattn_part2);
7213 if (fields == EOF || fields < 3)
7214 continue;
7215
7216 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
7217 slant, pattn_part2);
7218
7219 synthed_matches = Fcons (build_string (new_pattn),
7220 synthed_matches);
7221 }
7222
7223 return synthed_matches;
7224}
7225
7226
4587b026
GV
7227/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7228struct font_info *
7229w32_get_font_info (f, font_idx)
7230 FRAME_PTR f;
7231 int font_idx;
7232{
7233 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7234}
7235
7236
7237struct font_info*
7238w32_query_font (struct frame *f, char *fontname)
7239{
7240 int i;
7241 struct font_info *pfi;
7242
7243 pfi = FRAME_W32_FONT_TABLE (f);
7244
7245 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7246 {
7247 if (strcmp(pfi->name, fontname) == 0) return pfi;
7248 }
7249
7250 return NULL;
7251}
7252
7253/* Find a CCL program for a font specified by FONTP, and set the member
7254 `encoder' of the structure. */
7255
7256void
7257w32_find_ccl_program (fontp)
7258 struct font_info *fontp;
7259{
3545439c 7260 Lisp_Object list, elt;
4587b026 7261
8e713be6 7262 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7263 {
8e713be6 7264 elt = XCAR (list);
4587b026 7265 if (CONSP (elt)
8e713be6
KR
7266 && STRINGP (XCAR (elt))
7267 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7268 >= 0))
3545439c
KH
7269 break;
7270 }
7271 if (! NILP (list))
7272 {
17eedd00
KH
7273 struct ccl_program *ccl
7274 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7275
8e713be6 7276 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7277 xfree (ccl);
7278 else
7279 fontp->font_encoder = ccl;
4587b026
GV
7280 }
7281}
7282
7283\f
8edb0a6f
JR
7284/* Find BDF files in a specified directory. (use GCPRO when calling,
7285 as this calls lisp to get a directory listing). */
7286static Lisp_Object
7287w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7288{
7289 Lisp_Object filelist, list = Qnil;
7290 char fontname[100];
7291
7292 if (!STRINGP(directory))
7293 return Qnil;
7294
7295 filelist = Fdirectory_files (directory, Qt,
7296 build_string (".*\\.[bB][dD][fF]"), Qt);
7297
7298 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7299 {
7300 Lisp_Object filename = XCAR (filelist);
7301 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7302 store_in_alist (&list, build_string (fontname), filename);
7303 }
7304 return list;
7305}
7306
6fc2811b
JR
7307DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7308 1, 1, 0,
b3700ae7
JR
7309 doc: /* Return a list of BDF fonts in DIR.
7310The list is suitable for appending to w32-bdf-filename-alist. Fonts
7311which do not contain an xlfd description will not be included in the
7312list. DIR may be a list of directories. */)
6fc2811b
JR
7313 (directory)
7314 Lisp_Object directory;
7315{
7316 Lisp_Object list = Qnil;
7317 struct gcpro gcpro1, gcpro2;
ee78dc32 7318
6fc2811b
JR
7319 if (!CONSP (directory))
7320 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7321
6fc2811b 7322 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7323 {
6fc2811b
JR
7324 Lisp_Object pair[2];
7325 pair[0] = list;
7326 pair[1] = Qnil;
7327 GCPRO2 (directory, list);
7328 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7329 list = Fnconc( 2, pair );
7330 UNGCPRO;
7331 }
7332 return list;
7333}
ee78dc32 7334
6fc2811b
JR
7335\f
7336DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7337 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7338 (color, frame)
7339 Lisp_Object color, frame;
7340{
7341 XColor foo;
7342 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7343
b7826503 7344 CHECK_STRING (color);
ee78dc32 7345
6fc2811b
JR
7346 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7347 return Qt;
7348 else
7349 return Qnil;
7350}
ee78dc32 7351
2d764c78 7352DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7353 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7354 (color, frame)
7355 Lisp_Object color, frame;
7356{
6fc2811b 7357 XColor foo;
ee78dc32
GV
7358 FRAME_PTR f = check_x_frame (frame);
7359
b7826503 7360 CHECK_STRING (color);
ee78dc32 7361
6fc2811b 7362 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7363 {
7364 Lisp_Object rgb[3];
7365
6fc2811b
JR
7366 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7367 | GetRValue (foo.pixel));
7368 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7369 | GetGValue (foo.pixel));
7370 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7371 | GetBValue (foo.pixel));
ee78dc32
GV
7372 return Flist (3, rgb);
7373 }
7374 else
7375 return Qnil;
7376}
7377
2d764c78 7378DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7379 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7380 (display)
7381 Lisp_Object display;
7382{
fbd6baed 7383 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7384
7385 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7386 return Qnil;
7387
7388 return Qt;
7389}
7390
74e1aeec
JR
7391DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7392 Sx_display_grayscale_p, 0, 1, 0,
7393 doc: /* Return t if the X display supports shades of gray.
7394Note that color displays do support shades of gray.
7395The optional argument DISPLAY specifies which display to ask about.
7396DISPLAY should be either a frame or a display name (a string).
7397If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7398 (display)
7399 Lisp_Object display;
7400{
fbd6baed 7401 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7402
7403 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7404 return Qnil;
7405
7406 return Qt;
7407}
7408
74e1aeec
JR
7409DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7410 Sx_display_pixel_width, 0, 1, 0,
7411 doc: /* Returns the width in pixels of DISPLAY.
7412The optional argument DISPLAY specifies which display to ask about.
7413DISPLAY should be either a frame or a display name (a string).
7414If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7415 (display)
7416 Lisp_Object display;
7417{
fbd6baed 7418 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7419
7420 return make_number (dpyinfo->width);
7421}
7422
7423DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7424 Sx_display_pixel_height, 0, 1, 0,
7425 doc: /* Returns the height in pixels of DISPLAY.
7426The optional argument DISPLAY specifies which display to ask about.
7427DISPLAY should be either a frame or a display name (a string).
7428If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7429 (display)
7430 Lisp_Object display;
7431{
fbd6baed 7432 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7433
7434 return make_number (dpyinfo->height);
7435}
7436
7437DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7438 0, 1, 0,
7439 doc: /* Returns the number of bitplanes of DISPLAY.
7440The optional argument DISPLAY specifies which display to ask about.
7441DISPLAY should be either a frame or a display name (a string).
7442If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7443 (display)
7444 Lisp_Object display;
7445{
fbd6baed 7446 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7447
7448 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7449}
7450
7451DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7452 0, 1, 0,
7453 doc: /* Returns the number of color cells of DISPLAY.
7454The optional argument DISPLAY specifies which display to ask about.
7455DISPLAY should be either a frame or a display name (a string).
7456If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7457 (display)
7458 Lisp_Object display;
7459{
fbd6baed 7460 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7461 HDC hdc;
7462 int cap;
7463
5ac45f98
GV
7464 hdc = GetDC (dpyinfo->root_window);
7465 if (dpyinfo->has_palette)
7466 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7467 else
7468 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b
AI
7469
7470 if (cap < 0)
7471 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
ee78dc32
GV
7472
7473 ReleaseDC (dpyinfo->root_window, hdc);
7474
7475 return make_number (cap);
7476}
7477
7478DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7479 Sx_server_max_request_size,
74e1aeec
JR
7480 0, 1, 0,
7481 doc: /* Returns the maximum request size of the server of DISPLAY.
7482The optional argument DISPLAY specifies which display to ask about.
7483DISPLAY should be either a frame or a display name (a string).
7484If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7485 (display)
7486 Lisp_Object display;
7487{
fbd6baed 7488 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7489
7490 return make_number (1);
7491}
7492
7493DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7494 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7495The optional argument DISPLAY specifies which display to ask about.
7496DISPLAY should be either a frame or a display name (a string).
7497If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7498 (display)
7499 Lisp_Object display;
7500{
dfff8a69 7501 return build_string ("Microsoft Corp.");
ee78dc32
GV
7502}
7503
7504DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7505 doc: /* Returns the version numbers of the server of DISPLAY.
7506The value is a list of three integers: the major and minor
7507version numbers, and the vendor-specific release
7508number. See also the function `x-server-vendor'.
7509
7510The optional argument DISPLAY specifies which display to ask about.
7511DISPLAY should be either a frame or a display name (a string).
7512If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7513 (display)
7514 Lisp_Object display;
7515{
fbd6baed 7516 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7517 Fcons (make_number (w32_minor_version),
7518 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7519}
7520
7521DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7522 doc: /* Returns the number of screens on the server of DISPLAY.
7523The optional argument DISPLAY specifies which display to ask about.
7524DISPLAY should be either a frame or a display name (a string).
7525If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7526 (display)
7527 Lisp_Object display;
7528{
ee78dc32
GV
7529 return make_number (1);
7530}
7531
74e1aeec
JR
7532DEFUN ("x-display-mm-height", Fx_display_mm_height,
7533 Sx_display_mm_height, 0, 1, 0,
7534 doc: /* Returns the height in millimeters of DISPLAY.
7535The optional argument DISPLAY specifies which display to ask about.
7536DISPLAY should be either a frame or a display name (a string).
7537If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7538 (display)
7539 Lisp_Object display;
7540{
fbd6baed 7541 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7542 HDC hdc;
7543 int cap;
7544
5ac45f98 7545 hdc = GetDC (dpyinfo->root_window);
3c190163 7546
ee78dc32 7547 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7548
ee78dc32
GV
7549 ReleaseDC (dpyinfo->root_window, hdc);
7550
7551 return make_number (cap);
7552}
7553
7554DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7555 doc: /* Returns the width in millimeters of DISPLAY.
7556The optional argument DISPLAY specifies which display to ask about.
7557DISPLAY should be either a frame or a display name (a string).
7558If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7559 (display)
7560 Lisp_Object display;
7561{
fbd6baed 7562 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7563
7564 HDC hdc;
7565 int cap;
7566
5ac45f98 7567 hdc = GetDC (dpyinfo->root_window);
3c190163 7568
ee78dc32 7569 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7570
ee78dc32
GV
7571 ReleaseDC (dpyinfo->root_window, hdc);
7572
7573 return make_number (cap);
7574}
7575
7576DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7577 Sx_display_backing_store, 0, 1, 0,
7578 doc: /* Returns an indication of whether DISPLAY does backing store.
7579The value may be `always', `when-mapped', or `not-useful'.
7580The optional argument DISPLAY specifies which display to ask about.
7581DISPLAY should be either a frame or a display name (a string).
7582If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7583 (display)
7584 Lisp_Object display;
7585{
7586 return intern ("not-useful");
7587}
7588
7589DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7590 Sx_display_visual_class, 0, 1, 0,
7591 doc: /* Returns the visual class of DISPLAY.
7592The value is one of the symbols `static-gray', `gray-scale',
7593`static-color', `pseudo-color', `true-color', or `direct-color'.
7594
7595The optional argument DISPLAY specifies which display to ask about.
7596DISPLAY should be either a frame or a display name (a string).
7597If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7598 (display)
7599 Lisp_Object display;
7600{
fbd6baed 7601 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7602 Lisp_Object result = Qnil;
ee78dc32 7603
abf8c61b
AI
7604 if (dpyinfo->has_palette)
7605 result = intern ("pseudo-color");
7606 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7607 result = intern ("static-grey");
7608 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7609 result = intern ("static-color");
7610 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7611 result = intern ("true-color");
ee78dc32 7612
abf8c61b 7613 return result;
ee78dc32
GV
7614}
7615
7616DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7617 Sx_display_save_under, 0, 1, 0,
7618 doc: /* Returns t if DISPLAY supports the save-under feature.
7619The optional argument DISPLAY specifies which display to ask about.
7620DISPLAY should be either a frame or a display name (a string).
7621If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7622 (display)
7623 Lisp_Object display;
7624{
6fc2811b
JR
7625 return Qnil;
7626}
7627\f
7628int
7629x_pixel_width (f)
7630 register struct frame *f;
7631{
7632 return PIXEL_WIDTH (f);
7633}
7634
7635int
7636x_pixel_height (f)
7637 register struct frame *f;
7638{
7639 return PIXEL_HEIGHT (f);
7640}
7641
7642int
7643x_char_width (f)
7644 register struct frame *f;
7645{
7646 return FONT_WIDTH (f->output_data.w32->font);
7647}
7648
7649int
7650x_char_height (f)
7651 register struct frame *f;
7652{
7653 return f->output_data.w32->line_height;
7654}
7655
7656int
7657x_screen_planes (f)
7658 register struct frame *f;
7659{
7660 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7661}
7662\f
7663/* Return the display structure for the display named NAME.
7664 Open a new connection if necessary. */
7665
7666struct w32_display_info *
7667x_display_info_for_name (name)
7668 Lisp_Object name;
7669{
7670 Lisp_Object names;
7671 struct w32_display_info *dpyinfo;
7672
b7826503 7673 CHECK_STRING (name);
6fc2811b
JR
7674
7675 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7676 dpyinfo;
7677 dpyinfo = dpyinfo->next, names = XCDR (names))
7678 {
7679 Lisp_Object tem;
7680 tem = Fstring_equal (XCAR (XCAR (names)), name);
7681 if (!NILP (tem))
7682 return dpyinfo;
7683 }
7684
7685 /* Use this general default value to start with. */
7686 Vx_resource_name = Vinvocation_name;
7687
7688 validate_x_resource_name ();
7689
7690 dpyinfo = w32_term_init (name, (unsigned char *)0,
7691 (char *) XSTRING (Vx_resource_name)->data);
7692
7693 if (dpyinfo == 0)
7694 error ("Cannot connect to server %s", XSTRING (name)->data);
7695
7696 w32_in_use = 1;
7697 XSETFASTINT (Vwindow_system_version, 3);
7698
7699 return dpyinfo;
7700}
7701
7702DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
7703 1, 3, 0, doc: /* Open a connection to a server.
7704DISPLAY is the name of the display to connect to.
7705Optional second arg XRM-STRING is a string of resources in xrdb format.
7706If the optional third arg MUST-SUCCEED is non-nil,
7707terminate Emacs if we can't open the connection. */)
6fc2811b
JR
7708 (display, xrm_string, must_succeed)
7709 Lisp_Object display, xrm_string, must_succeed;
7710{
7711 unsigned char *xrm_option;
7712 struct w32_display_info *dpyinfo;
7713
74e1aeec
JR
7714 /* If initialization has already been done, return now to avoid
7715 overwriting critical parts of one_w32_display_info. */
7716 if (w32_in_use)
7717 return Qnil;
7718
b7826503 7719 CHECK_STRING (display);
6fc2811b 7720 if (! NILP (xrm_string))
b7826503 7721 CHECK_STRING (xrm_string);
6fc2811b
JR
7722
7723 if (! EQ (Vwindow_system, intern ("w32")))
7724 error ("Not using Microsoft Windows");
7725
7726 /* Allow color mapping to be defined externally; first look in user's
7727 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7728 {
7729 Lisp_Object color_file;
7730 struct gcpro gcpro1;
7731
7732 color_file = build_string("~/rgb.txt");
7733
7734 GCPRO1 (color_file);
7735
7736 if (NILP (Ffile_readable_p (color_file)))
7737 color_file =
7738 Fexpand_file_name (build_string ("rgb.txt"),
7739 Fsymbol_value (intern ("data-directory")));
7740
7741 Vw32_color_map = Fw32_load_color_file (color_file);
7742
7743 UNGCPRO;
7744 }
7745 if (NILP (Vw32_color_map))
7746 Vw32_color_map = Fw32_default_color_map ();
7747
7748 if (! NILP (xrm_string))
7749 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7750 else
7751 xrm_option = (unsigned char *) 0;
7752
7753 /* Use this general default value to start with. */
7754 /* First remove .exe suffix from invocation-name - it looks ugly. */
7755 {
7756 char basename[ MAX_PATH ], *str;
7757
7758 strcpy (basename, XSTRING (Vinvocation_name)->data);
7759 str = strrchr (basename, '.');
7760 if (str) *str = 0;
7761 Vinvocation_name = build_string (basename);
7762 }
7763 Vx_resource_name = Vinvocation_name;
7764
7765 validate_x_resource_name ();
7766
7767 /* This is what opens the connection and sets x_current_display.
7768 This also initializes many symbols, such as those used for input. */
7769 dpyinfo = w32_term_init (display, xrm_option,
7770 (char *) XSTRING (Vx_resource_name)->data);
7771
7772 if (dpyinfo == 0)
7773 {
7774 if (!NILP (must_succeed))
7775 fatal ("Cannot connect to server %s.\n",
7776 XSTRING (display)->data);
7777 else
7778 error ("Cannot connect to server %s", XSTRING (display)->data);
7779 }
7780
7781 w32_in_use = 1;
7782
7783 XSETFASTINT (Vwindow_system_version, 3);
7784 return Qnil;
7785}
7786
7787DEFUN ("x-close-connection", Fx_close_connection,
7788 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
7789 doc: /* Close the connection to DISPLAY's server.
7790For DISPLAY, specify either a frame or a display name (a string).
7791If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
7792 (display)
7793 Lisp_Object display;
7794{
7795 struct w32_display_info *dpyinfo = check_x_display_info (display);
7796 int i;
7797
7798 if (dpyinfo->reference_count > 0)
7799 error ("Display still has frames on it");
7800
7801 BLOCK_INPUT;
7802 /* Free the fonts in the font table. */
7803 for (i = 0; i < dpyinfo->n_fonts; i++)
7804 if (dpyinfo->font_table[i].name)
7805 {
126f2e35
JR
7806 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7807 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 7808 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
7809 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7810 }
7811 x_destroy_all_bitmaps (dpyinfo);
7812
7813 x_delete_display (dpyinfo);
7814 UNBLOCK_INPUT;
7815
7816 return Qnil;
7817}
7818
7819DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 7820 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
7821 ()
7822{
7823 Lisp_Object tail, result;
7824
7825 result = Qnil;
7826 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7827 result = Fcons (XCAR (XCAR (tail)), result);
7828
7829 return result;
7830}
7831
7832DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
7833 doc: /* This is a noop on W32 systems. */)
7834 (on, display)
7835 Lisp_Object display, on;
6fc2811b 7836{
6fc2811b
JR
7837 return Qnil;
7838}
7839
7840\f
7841\f
7842/***********************************************************************
7843 Image types
7844 ***********************************************************************/
7845
7846/* Value is the number of elements of vector VECTOR. */
7847
7848#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7849
7850/* List of supported image types. Use define_image_type to add new
7851 types. Use lookup_image_type to find a type for a given symbol. */
7852
7853static struct image_type *image_types;
7854
6fc2811b
JR
7855/* The symbol `image' which is the car of the lists used to represent
7856 images in Lisp. */
7857
7858extern Lisp_Object Qimage;
7859
7860/* The symbol `xbm' which is used as the type symbol for XBM images. */
7861
7862Lisp_Object Qxbm;
7863
7864/* Keywords. */
7865
6fc2811b 7866extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
7867extern Lisp_Object QCdata;
7868Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
a93f4566 7869Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 7870Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
7871
7872/* Other symbols. */
7873
3cf3436e 7874Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
7875
7876/* Time in seconds after which images should be removed from the cache
7877 if not displayed. */
7878
7879Lisp_Object Vimage_cache_eviction_delay;
7880
7881/* Function prototypes. */
7882
7883static void define_image_type P_ ((struct image_type *type));
7884static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7885static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7886static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 7887static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
7888static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7889 Lisp_Object));
7890
dfff8a69 7891
6fc2811b
JR
7892/* Define a new image type from TYPE. This adds a copy of TYPE to
7893 image_types and adds the symbol *TYPE->type to Vimage_types. */
7894
7895static void
7896define_image_type (type)
7897 struct image_type *type;
7898{
7899 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7900 The initialized data segment is read-only. */
7901 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7902 bcopy (type, p, sizeof *p);
7903 p->next = image_types;
7904 image_types = p;
7905 Vimage_types = Fcons (*p->type, Vimage_types);
7906}
7907
7908
7909/* Look up image type SYMBOL, and return a pointer to its image_type
7910 structure. Value is null if SYMBOL is not a known image type. */
7911
7912static INLINE struct image_type *
7913lookup_image_type (symbol)
7914 Lisp_Object symbol;
7915{
7916 struct image_type *type;
7917
7918 for (type = image_types; type; type = type->next)
7919 if (EQ (symbol, *type->type))
7920 break;
7921
7922 return type;
7923}
7924
7925
7926/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7927 valid image specification is a list whose car is the symbol
7928 `image', and whose rest is a property list. The property list must
7929 contain a value for key `:type'. That value must be the name of a
7930 supported image type. The rest of the property list depends on the
7931 image type. */
7932
7933int
7934valid_image_p (object)
7935 Lisp_Object object;
7936{
7937 int valid_p = 0;
7938
7939 if (CONSP (object) && EQ (XCAR (object), Qimage))
7940 {
3cf3436e
JR
7941 Lisp_Object tem;
7942
7943 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
7944 if (EQ (XCAR (tem), QCtype))
7945 {
7946 tem = XCDR (tem);
7947 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
7948 {
7949 struct image_type *type;
7950 type = lookup_image_type (XCAR (tem));
7951 if (type)
7952 valid_p = type->valid_p (object);
7953 }
7954
7955 break;
7956 }
6fc2811b
JR
7957 }
7958
7959 return valid_p;
7960}
7961
7962
7963/* Log error message with format string FORMAT and argument ARG.
7964 Signaling an error, e.g. when an image cannot be loaded, is not a
7965 good idea because this would interrupt redisplay, and the error
7966 message display would lead to another redisplay. This function
7967 therefore simply displays a message. */
7968
7969static void
7970image_error (format, arg1, arg2)
7971 char *format;
7972 Lisp_Object arg1, arg2;
7973{
7974 add_to_log (format, arg1, arg2);
7975}
7976
7977
7978\f
7979/***********************************************************************
7980 Image specifications
7981 ***********************************************************************/
7982
7983enum image_value_type
7984{
7985 IMAGE_DONT_CHECK_VALUE_TYPE,
7986 IMAGE_STRING_VALUE,
3cf3436e 7987 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
7988 IMAGE_SYMBOL_VALUE,
7989 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 7990 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 7991 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 7992 IMAGE_ASCENT_VALUE,
6fc2811b
JR
7993 IMAGE_INTEGER_VALUE,
7994 IMAGE_FUNCTION_VALUE,
7995 IMAGE_NUMBER_VALUE,
7996 IMAGE_BOOL_VALUE
7997};
7998
7999/* Structure used when parsing image specifications. */
8000
8001struct image_keyword
8002{
8003 /* Name of keyword. */
8004 char *name;
8005
8006 /* The type of value allowed. */
8007 enum image_value_type type;
8008
8009 /* Non-zero means key must be present. */
8010 int mandatory_p;
8011
8012 /* Used to recognize duplicate keywords in a property list. */
8013 int count;
8014
8015 /* The value that was found. */
8016 Lisp_Object value;
8017};
8018
8019
8020static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8021 int, Lisp_Object));
8022static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8023
8024
8025/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8026 has the format (image KEYWORD VALUE ...). One of the keyword/
8027 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8028 image_keywords structures of size NKEYWORDS describing other
8029 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8030
8031static int
8032parse_image_spec (spec, keywords, nkeywords, type)
8033 Lisp_Object spec;
8034 struct image_keyword *keywords;
8035 int nkeywords;
8036 Lisp_Object type;
8037{
8038 int i;
8039 Lisp_Object plist;
8040
8041 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8042 return 0;
8043
8044 plist = XCDR (spec);
8045 while (CONSP (plist))
8046 {
8047 Lisp_Object key, value;
8048
8049 /* First element of a pair must be a symbol. */
8050 key = XCAR (plist);
8051 plist = XCDR (plist);
8052 if (!SYMBOLP (key))
8053 return 0;
8054
8055 /* There must follow a value. */
8056 if (!CONSP (plist))
8057 return 0;
8058 value = XCAR (plist);
8059 plist = XCDR (plist);
8060
8061 /* Find key in KEYWORDS. Error if not found. */
8062 for (i = 0; i < nkeywords; ++i)
8063 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8064 break;
8065
8066 if (i == nkeywords)
8067 continue;
8068
8069 /* Record that we recognized the keyword. If a keywords
8070 was found more than once, it's an error. */
8071 keywords[i].value = value;
8072 ++keywords[i].count;
8073
8074 if (keywords[i].count > 1)
8075 return 0;
8076
8077 /* Check type of value against allowed type. */
8078 switch (keywords[i].type)
8079 {
8080 case IMAGE_STRING_VALUE:
8081 if (!STRINGP (value))
8082 return 0;
8083 break;
8084
3cf3436e
JR
8085 case IMAGE_STRING_OR_NIL_VALUE:
8086 if (!STRINGP (value) && !NILP (value))
8087 return 0;
8088 break;
8089
6fc2811b
JR
8090 case IMAGE_SYMBOL_VALUE:
8091 if (!SYMBOLP (value))
8092 return 0;
8093 break;
8094
8095 case IMAGE_POSITIVE_INTEGER_VALUE:
8096 if (!INTEGERP (value) || XINT (value) <= 0)
8097 return 0;
8098 break;
8099
8edb0a6f
JR
8100 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8101 if (INTEGERP (value) && XINT (value) >= 0)
8102 break;
8103 if (CONSP (value)
8104 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8105 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8106 break;
8107 return 0;
8108
dfff8a69
JR
8109 case IMAGE_ASCENT_VALUE:
8110 if (SYMBOLP (value) && EQ (value, Qcenter))
8111 break;
8112 else if (INTEGERP (value)
8113 && XINT (value) >= 0
8114 && XINT (value) <= 100)
8115 break;
8116 return 0;
8117
6fc2811b
JR
8118 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8119 if (!INTEGERP (value) || XINT (value) < 0)
8120 return 0;
8121 break;
8122
8123 case IMAGE_DONT_CHECK_VALUE_TYPE:
8124 break;
8125
8126 case IMAGE_FUNCTION_VALUE:
8127 value = indirect_function (value);
8128 if (SUBRP (value)
8129 || COMPILEDP (value)
8130 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8131 break;
8132 return 0;
8133
8134 case IMAGE_NUMBER_VALUE:
8135 if (!INTEGERP (value) && !FLOATP (value))
8136 return 0;
8137 break;
8138
8139 case IMAGE_INTEGER_VALUE:
8140 if (!INTEGERP (value))
8141 return 0;
8142 break;
8143
8144 case IMAGE_BOOL_VALUE:
8145 if (!NILP (value) && !EQ (value, Qt))
8146 return 0;
8147 break;
8148
8149 default:
8150 abort ();
8151 break;
8152 }
8153
8154 if (EQ (key, QCtype) && !EQ (type, value))
8155 return 0;
8156 }
8157
8158 /* Check that all mandatory fields are present. */
8159 for (i = 0; i < nkeywords; ++i)
8160 if (keywords[i].mandatory_p && keywords[i].count == 0)
8161 return 0;
8162
8163 return NILP (plist);
8164}
8165
8166
8167/* Return the value of KEY in image specification SPEC. Value is nil
8168 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8169 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8170
8171static Lisp_Object
8172image_spec_value (spec, key, found)
8173 Lisp_Object spec, key;
8174 int *found;
8175{
8176 Lisp_Object tail;
8177
8178 xassert (valid_image_p (spec));
8179
8180 for (tail = XCDR (spec);
8181 CONSP (tail) && CONSP (XCDR (tail));
8182 tail = XCDR (XCDR (tail)))
8183 {
8184 if (EQ (XCAR (tail), key))
8185 {
8186 if (found)
8187 *found = 1;
8188 return XCAR (XCDR (tail));
8189 }
8190 }
8191
8192 if (found)
8193 *found = 0;
8194 return Qnil;
8195}
8196
8197
8198
8199\f
8200/***********************************************************************
8201 Image type independent image structures
8202 ***********************************************************************/
8203
8204static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8205static void free_image P_ ((struct frame *f, struct image *img));
8206
8207
8208/* Allocate and return a new image structure for image specification
8209 SPEC. SPEC has a hash value of HASH. */
8210
8211static struct image *
8212make_image (spec, hash)
8213 Lisp_Object spec;
8214 unsigned hash;
8215{
8216 struct image *img = (struct image *) xmalloc (sizeof *img);
8217
8218 xassert (valid_image_p (spec));
8219 bzero (img, sizeof *img);
8220 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8221 xassert (img->type != NULL);
8222 img->spec = spec;
8223 img->data.lisp_val = Qnil;
8224 img->ascent = DEFAULT_IMAGE_ASCENT;
8225 img->hash = hash;
8226 return img;
8227}
8228
8229
8230/* Free image IMG which was used on frame F, including its resources. */
8231
8232static void
8233free_image (f, img)
8234 struct frame *f;
8235 struct image *img;
8236{
8237 if (img)
8238 {
8239 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8240
8241 /* Remove IMG from the hash table of its cache. */
8242 if (img->prev)
8243 img->prev->next = img->next;
8244 else
8245 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8246
8247 if (img->next)
8248 img->next->prev = img->prev;
8249
8250 c->images[img->id] = NULL;
8251
8252 /* Free resources, then free IMG. */
8253 img->type->free (f, img);
8254 xfree (img);
8255 }
8256}
8257
8258
8259/* Prepare image IMG for display on frame F. Must be called before
8260 drawing an image. */
8261
8262void
8263prepare_image_for_display (f, img)
8264 struct frame *f;
8265 struct image *img;
8266{
8267 EMACS_TIME t;
8268
8269 /* We're about to display IMG, so set its timestamp to `now'. */
8270 EMACS_GET_TIME (t);
8271 img->timestamp = EMACS_SECS (t);
8272
8273 /* If IMG doesn't have a pixmap yet, load it now, using the image
8274 type dependent loader function. */
8275 if (img->pixmap == 0 && !img->load_failed_p)
8276 img->load_failed_p = img->type->load (f, img) == 0;
8277}
8278
8279
dfff8a69
JR
8280/* Value is the number of pixels for the ascent of image IMG when
8281 drawn in face FACE. */
8282
8283int
8284image_ascent (img, face)
8285 struct image *img;
8286 struct face *face;
8287{
8edb0a6f 8288 int height = img->height + img->vmargin;
dfff8a69
JR
8289 int ascent;
8290
8291 if (img->ascent == CENTERED_IMAGE_ASCENT)
8292 {
8293 if (face->font)
8294 ascent = height / 2 - (FONT_DESCENT(face->font)
8295 - FONT_BASE(face->font)) / 2;
8296 else
8297 ascent = height / 2;
8298 }
8299 else
8300 ascent = height * img->ascent / 100.0;
8301
8302 return ascent;
8303}
8304
8305
6fc2811b 8306\f
a05e2bae
JR
8307/* Image background colors. */
8308
8309static unsigned long
8310four_corners_best (ximg, width, height)
8311 XImage *ximg;
8312 unsigned long width, height;
8313{
8314#if 0 /* TODO: Image support. */
8315 unsigned long corners[4], best;
8316 int i, best_count;
8317
8318 /* Get the colors at the corners of ximg. */
8319 corners[0] = XGetPixel (ximg, 0, 0);
8320 corners[1] = XGetPixel (ximg, width - 1, 0);
8321 corners[2] = XGetPixel (ximg, width - 1, height - 1);
8322 corners[3] = XGetPixel (ximg, 0, height - 1);
8323
8324 /* Choose the most frequently found color as background. */
8325 for (i = best_count = 0; i < 4; ++i)
8326 {
8327 int j, n;
8328
8329 for (j = n = 0; j < 4; ++j)
8330 if (corners[i] == corners[j])
8331 ++n;
8332
8333 if (n > best_count)
8334 best = corners[i], best_count = n;
8335 }
8336
8337 return best;
8338#else
8339 return 0;
8340#endif
8341}
8342
8343/* Return the `background' field of IMG. If IMG doesn't have one yet,
8344 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8345 object to use for the heuristic. */
8346
8347unsigned long
8348image_background (img, f, ximg)
8349 struct image *img;
8350 struct frame *f;
8351 XImage *ximg;
8352{
8353 if (! img->background_valid)
8354 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8355 {
8356#if 0 /* TODO: Image support. */
8357 int free_ximg = !ximg;
8358
8359 if (! ximg)
8360 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8361 0, 0, img->width, img->height, ~0, ZPixmap);
8362
8363 img->background = four_corners_best (ximg, img->width, img->height);
8364
8365 if (free_ximg)
8366 XDestroyImage (ximg);
8367
8368 img->background_valid = 1;
8369#endif
8370 }
8371
8372 return img->background;
8373}
8374
8375/* Return the `background_transparent' field of IMG. If IMG doesn't
8376 have one yet, it is guessed heuristically. If non-zero, MASK is an
8377 existing XImage object to use for the heuristic. */
8378
8379int
8380image_background_transparent (img, f, mask)
8381 struct image *img;
8382 struct frame *f;
8383 XImage *mask;
8384{
8385 if (! img->background_transparent_valid)
8386 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8387 {
8388#if 0 /* TODO: Image support. */
8389 if (img->mask)
8390 {
8391 int free_mask = !mask;
8392
8393 if (! mask)
8394 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8395 0, 0, img->width, img->height, ~0, ZPixmap);
8396
8397 img->background_transparent
8398 = !four_corners_best (mask, img->width, img->height);
8399
8400 if (free_mask)
8401 XDestroyImage (mask);
8402 }
8403 else
8404#endif
8405 img->background_transparent = 0;
8406
8407 img->background_transparent_valid = 1;
8408 }
8409
8410 return img->background_transparent;
8411}
8412
8413\f
6fc2811b
JR
8414/***********************************************************************
8415 Helper functions for X image types
8416 ***********************************************************************/
8417
a05e2bae
JR
8418static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8419 int, int));
6fc2811b
JR
8420static void x_clear_image P_ ((struct frame *f, struct image *img));
8421static unsigned long x_alloc_image_color P_ ((struct frame *f,
8422 struct image *img,
8423 Lisp_Object color_name,
8424 unsigned long dflt));
8425
a05e2bae
JR
8426
8427/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8428 free the pixmap if any. MASK_P non-zero means clear the mask
8429 pixmap if any. COLORS_P non-zero means free colors allocated for
8430 the image, if any. */
8431
8432static void
8433x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8434 struct frame *f;
8435 struct image *img;
8436 int pixmap_p, mask_p, colors_p;
8437{
9eb16b62 8438#if 0 /* TODO: W32 image support */
a05e2bae
JR
8439 if (pixmap_p && img->pixmap)
8440 {
8441 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8442 img->pixmap = None;
8443 img->background_valid = 0;
8444 }
8445
8446 if (mask_p && img->mask)
8447 {
8448 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8449 img->mask = None;
8450 img->background_transparent_valid = 0;
8451 }
8452
8453 if (colors_p && img->ncolors)
8454 {
8455 x_free_colors (f, img->colors, img->ncolors);
8456 xfree (img->colors);
8457 img->colors = NULL;
8458 img->ncolors = 0;
8459 }
8460#endif
8461}
8462
6fc2811b
JR
8463/* Free X resources of image IMG which is used on frame F. */
8464
8465static void
8466x_clear_image (f, img)
8467 struct frame *f;
8468 struct image *img;
8469{
767b1ff0 8470#if 0 /* TODO: W32 image support */
6fc2811b
JR
8471
8472 if (img->pixmap)
8473 {
8474 BLOCK_INPUT;
8475 XFreePixmap (NULL, img->pixmap);
8476 img->pixmap = 0;
8477 UNBLOCK_INPUT;
8478 }
8479
8480 if (img->ncolors)
8481 {
8482 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8483
8484 /* If display has an immutable color map, freeing colors is not
8485 necessary and some servers don't allow it. So don't do it. */
8486 if (class != StaticColor
8487 && class != StaticGray
8488 && class != TrueColor)
8489 {
8490 Colormap cmap;
8491 BLOCK_INPUT;
8492 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8493 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8494 img->ncolors, 0);
8495 UNBLOCK_INPUT;
8496 }
8497
8498 xfree (img->colors);
8499 img->colors = NULL;
8500 img->ncolors = 0;
8501 }
8502#endif
8503}
8504
8505
8506/* Allocate color COLOR_NAME for image IMG on frame F. If color
8507 cannot be allocated, use DFLT. Add a newly allocated color to
8508 IMG->colors, so that it can be freed again. Value is the pixel
8509 color. */
8510
8511static unsigned long
8512x_alloc_image_color (f, img, color_name, dflt)
8513 struct frame *f;
8514 struct image *img;
8515 Lisp_Object color_name;
8516 unsigned long dflt;
8517{
767b1ff0 8518#if 0 /* TODO: allocing colors. */
6fc2811b
JR
8519 XColor color;
8520 unsigned long result;
8521
8522 xassert (STRINGP (color_name));
8523
8524 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8525 {
8526 /* This isn't called frequently so we get away with simply
8527 reallocating the color vector to the needed size, here. */
8528 ++img->ncolors;
8529 img->colors =
8530 (unsigned long *) xrealloc (img->colors,
8531 img->ncolors * sizeof *img->colors);
8532 img->colors[img->ncolors - 1] = color.pixel;
8533 result = color.pixel;
8534 }
8535 else
8536 result = dflt;
8537 return result;
8538#endif
8539 return 0;
8540}
8541
8542
8543\f
8544/***********************************************************************
8545 Image Cache
8546 ***********************************************************************/
8547
8548static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8549static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8550
8551
8552/* Return a new, initialized image cache that is allocated from the
8553 heap. Call free_image_cache to free an image cache. */
8554
8555struct image_cache *
8556make_image_cache ()
8557{
8558 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8559 int size;
8560
8561 bzero (c, sizeof *c);
8562 c->size = 50;
8563 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8564 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8565 c->buckets = (struct image **) xmalloc (size);
8566 bzero (c->buckets, size);
8567 return c;
8568}
8569
8570
8571/* Free image cache of frame F. Be aware that X frames share images
8572 caches. */
8573
8574void
8575free_image_cache (f)
8576 struct frame *f;
8577{
8578 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8579 if (c)
8580 {
8581 int i;
8582
8583 /* Cache should not be referenced by any frame when freed. */
8584 xassert (c->refcount == 0);
8585
8586 for (i = 0; i < c->used; ++i)
8587 free_image (f, c->images[i]);
8588 xfree (c->images);
8589 xfree (c);
8590 xfree (c->buckets);
8591 FRAME_X_IMAGE_CACHE (f) = NULL;
8592 }
8593}
8594
8595
8596/* Clear image cache of frame F. FORCE_P non-zero means free all
8597 images. FORCE_P zero means clear only images that haven't been
8598 displayed for some time. Should be called from time to time to
dfff8a69
JR
8599 reduce the number of loaded images. If image-eviction-seconds is
8600 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8601 at least that many seconds. */
8602
8603void
8604clear_image_cache (f, force_p)
8605 struct frame *f;
8606 int force_p;
8607{
8608 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8609
8610 if (c && INTEGERP (Vimage_cache_eviction_delay))
8611 {
8612 EMACS_TIME t;
8613 unsigned long old;
8614 int i, any_freed_p = 0;
8615
8616 EMACS_GET_TIME (t);
8617 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8618
8619 for (i = 0; i < c->used; ++i)
8620 {
8621 struct image *img = c->images[i];
8622 if (img != NULL
8623 && (force_p
8624 || (img->timestamp > old)))
8625 {
8626 free_image (f, img);
8627 any_freed_p = 1;
8628 }
8629 }
8630
8631 /* We may be clearing the image cache because, for example,
8632 Emacs was iconified for a longer period of time. In that
8633 case, current matrices may still contain references to
8634 images freed above. So, clear these matrices. */
8635 if (any_freed_p)
8636 {
8637 clear_current_matrices (f);
8638 ++windows_or_buffers_changed;
8639 }
8640 }
8641}
8642
8643
8644DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8645 0, 1, 0,
74e1aeec
JR
8646 doc: /* Clear the image cache of FRAME.
8647FRAME nil or omitted means use the selected frame.
8648FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
8649 (frame)
8650 Lisp_Object frame;
8651{
8652 if (EQ (frame, Qt))
8653 {
8654 Lisp_Object tail;
8655
8656 FOR_EACH_FRAME (tail, frame)
8657 if (FRAME_W32_P (XFRAME (frame)))
8658 clear_image_cache (XFRAME (frame), 1);
8659 }
8660 else
8661 clear_image_cache (check_x_frame (frame), 1);
8662
8663 return Qnil;
8664}
8665
8666
3cf3436e
JR
8667/* Compute masks and transform image IMG on frame F, as specified
8668 by the image's specification, */
8669
8670static void
8671postprocess_image (f, img)
8672 struct frame *f;
8673 struct image *img;
8674{
8675#if 0 /* TODO: image support. */
8676 /* Manipulation of the image's mask. */
8677 if (img->pixmap)
8678 {
8679 Lisp_Object conversion, spec;
8680 Lisp_Object mask;
8681
8682 spec = img->spec;
8683
8684 /* `:heuristic-mask t'
8685 `:mask heuristic'
8686 means build a mask heuristically.
8687 `:heuristic-mask (R G B)'
8688 `:mask (heuristic (R G B))'
8689 means build a mask from color (R G B) in the
8690 image.
8691 `:mask nil'
8692 means remove a mask, if any. */
8693
8694 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8695 if (!NILP (mask))
8696 x_build_heuristic_mask (f, img, mask);
8697 else
8698 {
8699 int found_p;
8700
8701 mask = image_spec_value (spec, QCmask, &found_p);
8702
8703 if (EQ (mask, Qheuristic))
8704 x_build_heuristic_mask (f, img, Qt);
8705 else if (CONSP (mask)
8706 && EQ (XCAR (mask), Qheuristic))
8707 {
8708 if (CONSP (XCDR (mask)))
8709 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8710 else
8711 x_build_heuristic_mask (f, img, XCDR (mask));
8712 }
8713 else if (NILP (mask) && found_p && img->mask)
8714 {
8715 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8716 img->mask = NULL;
8717 }
8718 }
8719
8720
8721 /* Should we apply an image transformation algorithm? */
8722 conversion = image_spec_value (spec, QCconversion, NULL);
8723 if (EQ (conversion, Qdisabled))
8724 x_disable_image (f, img);
8725 else if (EQ (conversion, Qlaplace))
8726 x_laplace (f, img);
8727 else if (EQ (conversion, Qemboss))
8728 x_emboss (f, img);
8729 else if (CONSP (conversion)
8730 && EQ (XCAR (conversion), Qedge_detection))
8731 {
8732 Lisp_Object tem;
8733 tem = XCDR (conversion);
8734 if (CONSP (tem))
8735 x_edge_detection (f, img,
8736 Fplist_get (tem, QCmatrix),
8737 Fplist_get (tem, QCcolor_adjustment));
8738 }
8739 }
8740#endif
8741}
8742
8743
6fc2811b
JR
8744/* Return the id of image with Lisp specification SPEC on frame F.
8745 SPEC must be a valid Lisp image specification (see valid_image_p). */
8746
8747int
8748lookup_image (f, spec)
8749 struct frame *f;
8750 Lisp_Object spec;
8751{
8752 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8753 struct image *img;
8754 int i;
8755 unsigned hash;
8756 struct gcpro gcpro1;
8757 EMACS_TIME now;
8758
8759 /* F must be a window-system frame, and SPEC must be a valid image
8760 specification. */
8761 xassert (FRAME_WINDOW_P (f));
8762 xassert (valid_image_p (spec));
8763
8764 GCPRO1 (spec);
8765
8766 /* Look up SPEC in the hash table of the image cache. */
8767 hash = sxhash (spec, 0);
8768 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8769
8770 for (img = c->buckets[i]; img; img = img->next)
8771 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8772 break;
8773
8774 /* If not found, create a new image and cache it. */
8775 if (img == NULL)
8776 {
3cf3436e
JR
8777 extern Lisp_Object Qpostscript;
8778
8edb0a6f 8779 BLOCK_INPUT;
6fc2811b
JR
8780 img = make_image (spec, hash);
8781 cache_image (f, img);
8782 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
8783
8784 /* If we can't load the image, and we don't have a width and
8785 height, use some arbitrary width and height so that we can
8786 draw a rectangle for it. */
8787 if (img->load_failed_p)
8788 {
8789 Lisp_Object value;
8790
8791 value = image_spec_value (spec, QCwidth, NULL);
8792 img->width = (INTEGERP (value)
8793 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8794 value = image_spec_value (spec, QCheight, NULL);
8795 img->height = (INTEGERP (value)
8796 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8797 }
8798 else
8799 {
8800 /* Handle image type independent image attributes
a05e2bae
JR
8801 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
8802 `:background COLOR'. */
8803 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
8804
8805 ascent = image_spec_value (spec, QCascent, NULL);
8806 if (INTEGERP (ascent))
8807 img->ascent = XFASTINT (ascent);
dfff8a69
JR
8808 else if (EQ (ascent, Qcenter))
8809 img->ascent = CENTERED_IMAGE_ASCENT;
8810
6fc2811b
JR
8811 margin = image_spec_value (spec, QCmargin, NULL);
8812 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
8813 img->vmargin = img->hmargin = XFASTINT (margin);
8814 else if (CONSP (margin) && INTEGERP (XCAR (margin))
8815 && INTEGERP (XCDR (margin)))
8816 {
8817 if (XINT (XCAR (margin)) > 0)
8818 img->hmargin = XFASTINT (XCAR (margin));
8819 if (XINT (XCDR (margin)) > 0)
8820 img->vmargin = XFASTINT (XCDR (margin));
8821 }
6fc2811b
JR
8822
8823 relief = image_spec_value (spec, QCrelief, NULL);
8824 if (INTEGERP (relief))
8825 {
8826 img->relief = XINT (relief);
8edb0a6f
JR
8827 img->hmargin += abs (img->relief);
8828 img->vmargin += abs (img->relief);
6fc2811b
JR
8829 }
8830
a05e2bae
JR
8831 if (! img->background_valid)
8832 {
8833 bg = image_spec_value (img->spec, QCbackground, NULL);
8834 if (!NILP (bg))
8835 {
8836 img->background
8837 = x_alloc_image_color (f, img, bg,
8838 FRAME_BACKGROUND_PIXEL (f));
8839 img->background_valid = 1;
8840 }
8841 }
8842
3cf3436e
JR
8843 /* Do image transformations and compute masks, unless we
8844 don't have the image yet. */
8845 if (!EQ (*img->type->type, Qpostscript))
8846 postprocess_image (f, img);
6fc2811b 8847 }
3cf3436e 8848
8edb0a6f
JR
8849 UNBLOCK_INPUT;
8850 xassert (!interrupt_input_blocked);
6fc2811b
JR
8851 }
8852
8853 /* We're using IMG, so set its timestamp to `now'. */
8854 EMACS_GET_TIME (now);
8855 img->timestamp = EMACS_SECS (now);
8856
8857 UNGCPRO;
8858
8859 /* Value is the image id. */
8860 return img->id;
8861}
8862
8863
8864/* Cache image IMG in the image cache of frame F. */
8865
8866static void
8867cache_image (f, img)
8868 struct frame *f;
8869 struct image *img;
8870{
8871 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8872 int i;
8873
8874 /* Find a free slot in c->images. */
8875 for (i = 0; i < c->used; ++i)
8876 if (c->images[i] == NULL)
8877 break;
8878
8879 /* If no free slot found, maybe enlarge c->images. */
8880 if (i == c->used && c->used == c->size)
8881 {
8882 c->size *= 2;
8883 c->images = (struct image **) xrealloc (c->images,
8884 c->size * sizeof *c->images);
8885 }
8886
8887 /* Add IMG to c->images, and assign IMG an id. */
8888 c->images[i] = img;
8889 img->id = i;
8890 if (i == c->used)
8891 ++c->used;
8892
8893 /* Add IMG to the cache's hash table. */
8894 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8895 img->next = c->buckets[i];
8896 if (img->next)
8897 img->next->prev = img;
8898 img->prev = NULL;
8899 c->buckets[i] = img;
8900}
8901
8902
8903/* Call FN on every image in the image cache of frame F. Used to mark
8904 Lisp Objects in the image cache. */
8905
8906void
8907forall_images_in_image_cache (f, fn)
8908 struct frame *f;
8909 void (*fn) P_ ((struct image *img));
8910{
8911 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8912 {
8913 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8914 if (c)
8915 {
8916 int i;
8917 for (i = 0; i < c->used; ++i)
8918 if (c->images[i])
8919 fn (c->images[i]);
8920 }
8921 }
8922}
8923
8924
8925\f
8926/***********************************************************************
8927 W32 support code
8928 ***********************************************************************/
8929
767b1ff0 8930#if 0 /* TODO: W32 specific image code. */
6fc2811b
JR
8931
8932static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8933 XImage **, Pixmap *));
8934static void x_destroy_x_image P_ ((XImage *));
8935static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8936
8937
8938/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8939 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8940 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8941 via xmalloc. Print error messages via image_error if an error
8942 occurs. Value is non-zero if successful. */
8943
8944static int
8945x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8946 struct frame *f;
8947 int width, height, depth;
8948 XImage **ximg;
8949 Pixmap *pixmap;
8950{
767b1ff0 8951#if 0 /* TODO: Image support for W32 */
6fc2811b
JR
8952 Display *display = FRAME_W32_DISPLAY (f);
8953 Screen *screen = FRAME_X_SCREEN (f);
8954 Window window = FRAME_W32_WINDOW (f);
8955
8956 xassert (interrupt_input_blocked);
8957
8958 if (depth <= 0)
a05e2bae 8959 depth = one_w32_display_info.n_cbits;
6fc2811b
JR
8960 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8961 depth, ZPixmap, 0, NULL, width, height,
8962 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8963 if (*ximg == NULL)
8964 {
8965 image_error ("Unable to allocate X image", Qnil, Qnil);
8966 return 0;
8967 }
8968
8969 /* Allocate image raster. */
8970 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8971
8972 /* Allocate a pixmap of the same size. */
8973 *pixmap = XCreatePixmap (display, window, width, height, depth);
8974 if (*pixmap == 0)
8975 {
8976 x_destroy_x_image (*ximg);
8977 *ximg = NULL;
8978 image_error ("Unable to create X pixmap", Qnil, Qnil);
8979 return 0;
8980 }
8981#endif
8982 return 1;
8983}
8984
8985
8986/* Destroy XImage XIMG. Free XIMG->data. */
8987
8988static void
8989x_destroy_x_image (ximg)
8990 XImage *ximg;
8991{
8992 xassert (interrupt_input_blocked);
8993 if (ximg)
8994 {
8995 xfree (ximg->data);
8996 ximg->data = NULL;
8997 XDestroyImage (ximg);
8998 }
8999}
9000
9001
9002/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9003 are width and height of both the image and pixmap. */
9004
9005static void
9006x_put_x_image (f, ximg, pixmap, width, height)
9007 struct frame *f;
9008 XImage *ximg;
9009 Pixmap pixmap;
9010{
9011 GC gc;
9012
9013 xassert (interrupt_input_blocked);
9014 gc = XCreateGC (NULL, pixmap, 0, NULL);
9015 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9016 XFreeGC (NULL, gc);
9017}
9018
9019#endif
9020
9021\f
9022/***********************************************************************
3cf3436e 9023 File Handling
6fc2811b
JR
9024 ***********************************************************************/
9025
9026static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9027static char *slurp_file P_ ((char *, int *));
9028
6fc2811b
JR
9029
9030/* Find image file FILE. Look in data-directory, then
9031 x-bitmap-file-path. Value is the full name of the file found, or
9032 nil if not found. */
9033
9034static Lisp_Object
9035x_find_image_file (file)
9036 Lisp_Object file;
9037{
9038 Lisp_Object file_found, search_path;
9039 struct gcpro gcpro1, gcpro2;
9040 int fd;
9041
9042 file_found = Qnil;
9043 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9044 GCPRO2 (file_found, search_path);
9045
9046 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 9047 fd = openp (search_path, file, Qnil, &file_found, 0);
6fc2811b 9048
939d6465 9049 if (fd == -1)
6fc2811b
JR
9050 file_found = Qnil;
9051 else
9052 close (fd);
9053
9054 UNGCPRO;
9055 return file_found;
9056}
9057
9058
3cf3436e
JR
9059/* Read FILE into memory. Value is a pointer to a buffer allocated
9060 with xmalloc holding FILE's contents. Value is null if an error
9061 occurred. *SIZE is set to the size of the file. */
9062
9063static char *
9064slurp_file (file, size)
9065 char *file;
9066 int *size;
9067{
9068 FILE *fp = NULL;
9069 char *buf = NULL;
9070 struct stat st;
9071
9072 if (stat (file, &st) == 0
9073 && (fp = fopen (file, "r")) != NULL
9074 && (buf = (char *) xmalloc (st.st_size),
9075 fread (buf, 1, st.st_size, fp) == st.st_size))
9076 {
9077 *size = st.st_size;
9078 fclose (fp);
9079 }
9080 else
9081 {
9082 if (fp)
9083 fclose (fp);
9084 if (buf)
9085 {
9086 xfree (buf);
9087 buf = NULL;
9088 }
9089 }
9090
9091 return buf;
9092}
9093
9094
6fc2811b
JR
9095\f
9096/***********************************************************************
9097 XBM images
9098 ***********************************************************************/
9099
9100static int xbm_load P_ ((struct frame *f, struct image *img));
9101static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9102 Lisp_Object file));
9103static int xbm_image_p P_ ((Lisp_Object object));
9104static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9105 unsigned char **));
9106
9107
9108/* Indices of image specification fields in xbm_format, below. */
9109
9110enum xbm_keyword_index
9111{
9112 XBM_TYPE,
9113 XBM_FILE,
9114 XBM_WIDTH,
9115 XBM_HEIGHT,
9116 XBM_DATA,
9117 XBM_FOREGROUND,
9118 XBM_BACKGROUND,
9119 XBM_ASCENT,
9120 XBM_MARGIN,
9121 XBM_RELIEF,
9122 XBM_ALGORITHM,
9123 XBM_HEURISTIC_MASK,
a05e2bae 9124 XBM_MASK,
6fc2811b
JR
9125 XBM_LAST
9126};
9127
9128/* Vector of image_keyword structures describing the format
9129 of valid XBM image specifications. */
9130
9131static struct image_keyword xbm_format[XBM_LAST] =
9132{
9133 {":type", IMAGE_SYMBOL_VALUE, 1},
9134 {":file", IMAGE_STRING_VALUE, 0},
9135 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9136 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9137 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
9138 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9139 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6fc2811b 9140 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9141 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9142 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9143 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
9144 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9145};
9146
9147/* Structure describing the image type XBM. */
9148
9149static struct image_type xbm_type =
9150{
9151 &Qxbm,
9152 xbm_image_p,
9153 xbm_load,
9154 x_clear_image,
9155 NULL
9156};
9157
9158/* Tokens returned from xbm_scan. */
9159
9160enum xbm_token
9161{
9162 XBM_TK_IDENT = 256,
9163 XBM_TK_NUMBER
9164};
9165
9166
9167/* Return non-zero if OBJECT is a valid XBM-type image specification.
9168 A valid specification is a list starting with the symbol `image'
9169 The rest of the list is a property list which must contain an
9170 entry `:type xbm..
9171
9172 If the specification specifies a file to load, it must contain
9173 an entry `:file FILENAME' where FILENAME is a string.
9174
9175 If the specification is for a bitmap loaded from memory it must
9176 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9177 WIDTH and HEIGHT are integers > 0. DATA may be:
9178
9179 1. a string large enough to hold the bitmap data, i.e. it must
9180 have a size >= (WIDTH + 7) / 8 * HEIGHT
9181
9182 2. a bool-vector of size >= WIDTH * HEIGHT
9183
9184 3. a vector of strings or bool-vectors, one for each line of the
9185 bitmap.
9186
9187 Both the file and data forms may contain the additional entries
9188 `:background COLOR' and `:foreground COLOR'. If not present,
9189 foreground and background of the frame on which the image is
9190 displayed, is used. */
9191
9192static int
9193xbm_image_p (object)
9194 Lisp_Object object;
9195{
9196 struct image_keyword kw[XBM_LAST];
9197
9198 bcopy (xbm_format, kw, sizeof kw);
9199 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9200 return 0;
9201
9202 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9203
9204 if (kw[XBM_FILE].count)
9205 {
9206 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9207 return 0;
9208 }
9209 else
9210 {
9211 Lisp_Object data;
9212 int width, height;
9213
9214 /* Entries for `:width', `:height' and `:data' must be present. */
9215 if (!kw[XBM_WIDTH].count
9216 || !kw[XBM_HEIGHT].count
9217 || !kw[XBM_DATA].count)
9218 return 0;
9219
9220 data = kw[XBM_DATA].value;
9221 width = XFASTINT (kw[XBM_WIDTH].value);
9222 height = XFASTINT (kw[XBM_HEIGHT].value);
9223
9224 /* Check type of data, and width and height against contents of
9225 data. */
9226 if (VECTORP (data))
9227 {
9228 int i;
9229
9230 /* Number of elements of the vector must be >= height. */
9231 if (XVECTOR (data)->size < height)
9232 return 0;
9233
9234 /* Each string or bool-vector in data must be large enough
9235 for one line of the image. */
9236 for (i = 0; i < height; ++i)
9237 {
9238 Lisp_Object elt = XVECTOR (data)->contents[i];
9239
9240 if (STRINGP (elt))
9241 {
9242 if (XSTRING (elt)->size
9243 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9244 return 0;
9245 }
9246 else if (BOOL_VECTOR_P (elt))
9247 {
9248 if (XBOOL_VECTOR (elt)->size < width)
9249 return 0;
9250 }
9251 else
9252 return 0;
9253 }
9254 }
9255 else if (STRINGP (data))
9256 {
9257 if (XSTRING (data)->size
9258 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9259 return 0;
9260 }
9261 else if (BOOL_VECTOR_P (data))
9262 {
9263 if (XBOOL_VECTOR (data)->size < width * height)
9264 return 0;
9265 }
9266 else
9267 return 0;
9268 }
9269
9270 /* Baseline must be a value between 0 and 100 (a percentage). */
9271 if (kw[XBM_ASCENT].count
9272 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9273 return 0;
9274
9275 return 1;
9276}
9277
9278
9279/* Scan a bitmap file. FP is the stream to read from. Value is
9280 either an enumerator from enum xbm_token, or a character for a
9281 single-character token, or 0 at end of file. If scanning an
9282 identifier, store the lexeme of the identifier in SVAL. If
9283 scanning a number, store its value in *IVAL. */
9284
9285static int
3cf3436e
JR
9286xbm_scan (s, end, sval, ival)
9287 char **s, *end;
6fc2811b
JR
9288 char *sval;
9289 int *ival;
9290{
9291 int c;
3cf3436e
JR
9292
9293 loop:
9294
6fc2811b 9295 /* Skip white space. */
3cf3436e 9296 while (*s < end &&(c = *(*s)++, isspace (c)))
6fc2811b
JR
9297 ;
9298
3cf3436e 9299 if (*s >= end)
6fc2811b
JR
9300 c = 0;
9301 else if (isdigit (c))
9302 {
9303 int value = 0, digit;
9304
3cf3436e 9305 if (c == '0' && *s < end)
6fc2811b 9306 {
3cf3436e 9307 c = *(*s)++;
6fc2811b
JR
9308 if (c == 'x' || c == 'X')
9309 {
3cf3436e 9310 while (*s < end)
6fc2811b 9311 {
3cf3436e 9312 c = *(*s)++;
6fc2811b
JR
9313 if (isdigit (c))
9314 digit = c - '0';
9315 else if (c >= 'a' && c <= 'f')
9316 digit = c - 'a' + 10;
9317 else if (c >= 'A' && c <= 'F')
9318 digit = c - 'A' + 10;
9319 else
9320 break;
9321 value = 16 * value + digit;
9322 }
9323 }
9324 else if (isdigit (c))
9325 {
9326 value = c - '0';
3cf3436e
JR
9327 while (*s < end
9328 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9329 value = 8 * value + c - '0';
9330 }
9331 }
9332 else
9333 {
9334 value = c - '0';
3cf3436e
JR
9335 while (*s < end
9336 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9337 value = 10 * value + c - '0';
9338 }
9339
3cf3436e
JR
9340 if (*s < end)
9341 *s = *s - 1;
6fc2811b
JR
9342 *ival = value;
9343 c = XBM_TK_NUMBER;
9344 }
9345 else if (isalpha (c) || c == '_')
9346 {
9347 *sval++ = c;
3cf3436e
JR
9348 while (*s < end
9349 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9350 *sval++ = c;
9351 *sval = 0;
3cf3436e
JR
9352 if (*s < end)
9353 *s = *s - 1;
6fc2811b
JR
9354 c = XBM_TK_IDENT;
9355 }
3cf3436e
JR
9356 else if (c == '/' && **s == '*')
9357 {
9358 /* C-style comment. */
9359 ++*s;
9360 while (**s && (**s != '*' || *(*s + 1) != '/'))
9361 ++*s;
9362 if (**s)
9363 {
9364 *s += 2;
9365 goto loop;
9366 }
9367 }
6fc2811b
JR
9368
9369 return c;
9370}
9371
9372
9373/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9374 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9375 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9376 the image. Return in *DATA the bitmap data allocated with xmalloc.
9377 Value is non-zero if successful. DATA null means just test if
9378 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9379
9380static int
3cf3436e
JR
9381xbm_read_bitmap_data (contents, end, width, height, data)
9382 char *contents, *end;
6fc2811b
JR
9383 int *width, *height;
9384 unsigned char **data;
9385{
3cf3436e 9386 char *s = contents;
6fc2811b
JR
9387 char buffer[BUFSIZ];
9388 int padding_p = 0;
9389 int v10 = 0;
9390 int bytes_per_line, i, nbytes;
9391 unsigned char *p;
9392 int value;
9393 int LA1;
9394
9395#define match() \
3cf3436e 9396 LA1 = xbm_scan (contents, end, buffer, &value)
6fc2811b
JR
9397
9398#define expect(TOKEN) \
9399 if (LA1 != (TOKEN)) \
9400 goto failure; \
9401 else \
9402 match ()
9403
9404#define expect_ident(IDENT) \
9405 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9406 match (); \
9407 else \
9408 goto failure
9409
6fc2811b 9410 *width = *height = -1;
3cf3436e
JR
9411 if (data)
9412 *data = NULL;
9413 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9414
9415 /* Parse defines for width, height and hot-spots. */
9416 while (LA1 == '#')
9417 {
9418 match ();
9419 expect_ident ("define");
9420 expect (XBM_TK_IDENT);
9421
9422 if (LA1 == XBM_TK_NUMBER);
9423 {
9424 char *p = strrchr (buffer, '_');
9425 p = p ? p + 1 : buffer;
9426 if (strcmp (p, "width") == 0)
9427 *width = value;
9428 else if (strcmp (p, "height") == 0)
9429 *height = value;
9430 }
9431 expect (XBM_TK_NUMBER);
9432 }
9433
9434 if (*width < 0 || *height < 0)
9435 goto failure;
3cf3436e
JR
9436 else if (data == NULL)
9437 goto success;
6fc2811b
JR
9438
9439 /* Parse bits. Must start with `static'. */
9440 expect_ident ("static");
9441 if (LA1 == XBM_TK_IDENT)
9442 {
9443 if (strcmp (buffer, "unsigned") == 0)
9444 {
9445 match ();
9446 expect_ident ("char");
9447 }
9448 else if (strcmp (buffer, "short") == 0)
9449 {
9450 match ();
9451 v10 = 1;
9452 if (*width % 16 && *width % 16 < 9)
9453 padding_p = 1;
9454 }
9455 else if (strcmp (buffer, "char") == 0)
9456 match ();
9457 else
9458 goto failure;
9459 }
9460 else
9461 goto failure;
9462
9463 expect (XBM_TK_IDENT);
9464 expect ('[');
9465 expect (']');
9466 expect ('=');
9467 expect ('{');
9468
9469 bytes_per_line = (*width + 7) / 8 + padding_p;
9470 nbytes = bytes_per_line * *height;
9471 p = *data = (char *) xmalloc (nbytes);
9472
9473 if (v10)
9474 {
9475
9476 for (i = 0; i < nbytes; i += 2)
9477 {
9478 int val = value;
9479 expect (XBM_TK_NUMBER);
9480
9481 *p++ = val;
9482 if (!padding_p || ((i + 2) % bytes_per_line))
9483 *p++ = value >> 8;
9484
9485 if (LA1 == ',' || LA1 == '}')
9486 match ();
9487 else
9488 goto failure;
9489 }
9490 }
9491 else
9492 {
9493 for (i = 0; i < nbytes; ++i)
9494 {
9495 int val = value;
9496 expect (XBM_TK_NUMBER);
9497
9498 *p++ = val;
9499
9500 if (LA1 == ',' || LA1 == '}')
9501 match ();
9502 else
9503 goto failure;
9504 }
9505 }
9506
3cf3436e 9507 success:
6fc2811b
JR
9508 return 1;
9509
9510 failure:
3cf3436e
JR
9511
9512 if (data && *data)
6fc2811b
JR
9513 {
9514 xfree (*data);
9515 *data = NULL;
9516 }
9517 return 0;
9518
9519#undef match
9520#undef expect
9521#undef expect_ident
9522}
9523
9524
3cf3436e
JR
9525/* Load XBM image IMG which will be displayed on frame F from buffer
9526 CONTENTS. END is the end of the buffer. Value is non-zero if
9527 successful. */
6fc2811b
JR
9528
9529static int
3cf3436e 9530xbm_load_image (f, img, contents, end)
6fc2811b
JR
9531 struct frame *f;
9532 struct image *img;
3cf3436e 9533 char *contents, *end;
6fc2811b
JR
9534{
9535 int rc;
9536 unsigned char *data;
9537 int success_p = 0;
6fc2811b 9538
3cf3436e 9539 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
9540 if (rc)
9541 {
9542 int depth = one_w32_display_info.n_cbits;
9543 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9544 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9545 Lisp_Object value;
9546
9547 xassert (img->width > 0 && img->height > 0);
9548
9549 /* Get foreground and background colors, maybe allocate colors. */
9550 value = image_spec_value (img->spec, QCforeground, NULL);
9551 if (!NILP (value))
9552 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
9553 value = image_spec_value (img->spec, QCbackground, NULL);
9554 if (!NILP (value))
a05e2bae
JR
9555 {
9556 background = x_alloc_image_color (f, img, value, background);
9557 img->background = background;
9558 img->background_valid = 1;
9559 }
9560
767b1ff0 9561#if 0 /* TODO : Port image display to W32 */
6fc2811b
JR
9562 img->pixmap
9563 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9564 FRAME_W32_WINDOW (f),
9565 data,
9566 img->width, img->height,
9567 foreground, background,
9568 depth);
a05e2bae 9569#endif
6fc2811b
JR
9570 xfree (data);
9571
9572 if (img->pixmap == 0)
9573 {
9574 x_clear_image (f, img);
3cf3436e 9575 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
9576 }
9577 else
9578 success_p = 1;
6fc2811b
JR
9579 }
9580 else
9581 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9582
6fc2811b
JR
9583 return success_p;
9584}
9585
9586
3cf3436e
JR
9587/* Value is non-zero if DATA looks like an in-memory XBM file. */
9588
9589static int
9590xbm_file_p (data)
9591 Lisp_Object data;
9592{
9593 int w, h;
9594 return (STRINGP (data)
9595 && xbm_read_bitmap_data (XSTRING (data)->data,
9596 (XSTRING (data)->data
9597 + STRING_BYTES (XSTRING (data))),
9598 &w, &h, NULL));
9599}
9600
9601
6fc2811b
JR
9602/* Fill image IMG which is used on frame F with pixmap data. Value is
9603 non-zero if successful. */
9604
9605static int
9606xbm_load (f, img)
9607 struct frame *f;
9608 struct image *img;
9609{
9610 int success_p = 0;
9611 Lisp_Object file_name;
9612
9613 xassert (xbm_image_p (img->spec));
9614
9615 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9616 file_name = image_spec_value (img->spec, QCfile, NULL);
9617 if (STRINGP (file_name))
3cf3436e
JR
9618 {
9619 Lisp_Object file;
9620 char *contents;
9621 int size;
9622 struct gcpro gcpro1;
9623
9624 file = x_find_image_file (file_name);
9625 GCPRO1 (file);
9626 if (!STRINGP (file))
9627 {
9628 image_error ("Cannot find image file `%s'", file_name, Qnil);
9629 UNGCPRO;
9630 return 0;
9631 }
9632
9633 contents = slurp_file (XSTRING (file)->data, &size);
9634 if (contents == NULL)
9635 {
9636 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9637 UNGCPRO;
9638 return 0;
9639 }
9640
9641 success_p = xbm_load_image (f, img, contents, contents + size);
9642 UNGCPRO;
9643 }
6fc2811b
JR
9644 else
9645 {
9646 struct image_keyword fmt[XBM_LAST];
9647 Lisp_Object data;
9648 int depth;
9649 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9650 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9651 char *bits;
9652 int parsed_p;
3cf3436e
JR
9653 int in_memory_file_p = 0;
9654
9655 /* See if data looks like an in-memory XBM file. */
9656 data = image_spec_value (img->spec, QCdata, NULL);
9657 in_memory_file_p = xbm_file_p (data);
6fc2811b
JR
9658
9659 /* Parse the list specification. */
9660 bcopy (xbm_format, fmt, sizeof fmt);
9661 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9662 xassert (parsed_p);
9663
9664 /* Get specified width, and height. */
3cf3436e
JR
9665 if (!in_memory_file_p)
9666 {
9667 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9668 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9669 xassert (img->width > 0 && img->height > 0);
9670 }
6fc2811b 9671 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
9672 if (fmt[XBM_FOREGROUND].count
9673 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
9674 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9675 foreground);
3cf3436e
JR
9676 if (fmt[XBM_BACKGROUND].count
9677 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
9678 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9679 background);
9680
3cf3436e
JR
9681 if (in_memory_file_p)
9682 success_p = xbm_load_image (f, img, XSTRING (data)->data,
9683 (XSTRING (data)->data
9684 + STRING_BYTES (XSTRING (data))));
9685 else
6fc2811b 9686 {
3cf3436e
JR
9687 if (VECTORP (data))
9688 {
9689 int i;
9690 char *p;
9691 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 9692
3cf3436e
JR
9693 p = bits = (char *) alloca (nbytes * img->height);
9694 for (i = 0; i < img->height; ++i, p += nbytes)
9695 {
9696 Lisp_Object line = XVECTOR (data)->contents[i];
9697 if (STRINGP (line))
9698 bcopy (XSTRING (line)->data, p, nbytes);
9699 else
9700 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9701 }
9702 }
9703 else if (STRINGP (data))
9704 bits = XSTRING (data)->data;
9705 else
9706 bits = XBOOL_VECTOR (data)->data;
9707#ifdef TODO /* image support. */
9708 /* Create the pixmap. */
a05e2bae 9709 depth = one_w32_display_info.n_cbits;
3cf3436e
JR
9710 img->pixmap
9711 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
9712 FRAME_X_WINDOW (f),
9713 bits,
9714 img->width, img->height,
9715 foreground, background,
9716 depth);
9717#endif
9718 if (img->pixmap)
9719 success_p = 1;
9720 else
6fc2811b 9721 {
3cf3436e
JR
9722 image_error ("Unable to create pixmap for XBM image `%s'",
9723 img->spec, Qnil);
9724 x_clear_image (f, img);
6fc2811b
JR
9725 }
9726 }
6fc2811b
JR
9727 }
9728
9729 return success_p;
9730}
9731
9732
9733\f
9734/***********************************************************************
9735 XPM images
9736 ***********************************************************************/
9737
9738#if HAVE_XPM
9739
9740static int xpm_image_p P_ ((Lisp_Object object));
9741static int xpm_load P_ ((struct frame *f, struct image *img));
9742static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9743
9744#include "X11/xpm.h"
9745
9746/* The symbol `xpm' identifying XPM-format images. */
9747
9748Lisp_Object Qxpm;
9749
9750/* Indices of image specification fields in xpm_format, below. */
9751
9752enum xpm_keyword_index
9753{
9754 XPM_TYPE,
9755 XPM_FILE,
9756 XPM_DATA,
9757 XPM_ASCENT,
9758 XPM_MARGIN,
9759 XPM_RELIEF,
9760 XPM_ALGORITHM,
9761 XPM_HEURISTIC_MASK,
a05e2bae 9762 XPM_MASK,
6fc2811b 9763 XPM_COLOR_SYMBOLS,
a05e2bae 9764 XPM_BACKGROUND,
6fc2811b
JR
9765 XPM_LAST
9766};
9767
9768/* Vector of image_keyword structures describing the format
9769 of valid XPM image specifications. */
9770
9771static struct image_keyword xpm_format[XPM_LAST] =
9772{
9773 {":type", IMAGE_SYMBOL_VALUE, 1},
9774 {":file", IMAGE_STRING_VALUE, 0},
9775 {":data", IMAGE_STRING_VALUE, 0},
9776 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9777 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9778 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9779 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 9780 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
9781 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9782 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9783 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
9784};
9785
9786/* Structure describing the image type XBM. */
9787
9788static struct image_type xpm_type =
9789{
9790 &Qxpm,
9791 xpm_image_p,
9792 xpm_load,
9793 x_clear_image,
9794 NULL
9795};
9796
9797
9798/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9799 for XPM images. Such a list must consist of conses whose car and
9800 cdr are strings. */
9801
9802static int
9803xpm_valid_color_symbols_p (color_symbols)
9804 Lisp_Object color_symbols;
9805{
9806 while (CONSP (color_symbols))
9807 {
9808 Lisp_Object sym = XCAR (color_symbols);
9809 if (!CONSP (sym)
9810 || !STRINGP (XCAR (sym))
9811 || !STRINGP (XCDR (sym)))
9812 break;
9813 color_symbols = XCDR (color_symbols);
9814 }
9815
9816 return NILP (color_symbols);
9817}
9818
9819
9820/* Value is non-zero if OBJECT is a valid XPM image specification. */
9821
9822static int
9823xpm_image_p (object)
9824 Lisp_Object object;
9825{
9826 struct image_keyword fmt[XPM_LAST];
9827 bcopy (xpm_format, fmt, sizeof fmt);
9828 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9829 /* Either `:file' or `:data' must be present. */
9830 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9831 /* Either no `:color-symbols' or it's a list of conses
9832 whose car and cdr are strings. */
9833 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9834 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9835 && (fmt[XPM_ASCENT].count == 0
9836 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9837}
9838
9839
9840/* Load image IMG which will be displayed on frame F. Value is
9841 non-zero if successful. */
9842
9843static int
9844xpm_load (f, img)
9845 struct frame *f;
9846 struct image *img;
9847{
9848 int rc, i;
9849 XpmAttributes attrs;
9850 Lisp_Object specified_file, color_symbols;
9851
9852 /* Configure the XPM lib. Use the visual of frame F. Allocate
9853 close colors. Return colors allocated. */
9854 bzero (&attrs, sizeof attrs);
dfff8a69
JR
9855 attrs.visual = FRAME_X_VISUAL (f);
9856 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 9857 attrs.valuemask |= XpmVisual;
dfff8a69 9858 attrs.valuemask |= XpmColormap;
6fc2811b 9859 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 9860#ifdef XpmAllocCloseColors
6fc2811b
JR
9861 attrs.alloc_close_colors = 1;
9862 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
9863#else
9864 attrs.closeness = 600;
9865 attrs.valuemask |= XpmCloseness;
9866#endif
6fc2811b
JR
9867
9868 /* If image specification contains symbolic color definitions, add
9869 these to `attrs'. */
9870 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9871 if (CONSP (color_symbols))
9872 {
9873 Lisp_Object tail;
9874 XpmColorSymbol *xpm_syms;
9875 int i, size;
9876
9877 attrs.valuemask |= XpmColorSymbols;
9878
9879 /* Count number of symbols. */
9880 attrs.numsymbols = 0;
9881 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9882 ++attrs.numsymbols;
9883
9884 /* Allocate an XpmColorSymbol array. */
9885 size = attrs.numsymbols * sizeof *xpm_syms;
9886 xpm_syms = (XpmColorSymbol *) alloca (size);
9887 bzero (xpm_syms, size);
9888 attrs.colorsymbols = xpm_syms;
9889
9890 /* Fill the color symbol array. */
9891 for (tail = color_symbols, i = 0;
9892 CONSP (tail);
9893 ++i, tail = XCDR (tail))
9894 {
9895 Lisp_Object name = XCAR (XCAR (tail));
9896 Lisp_Object color = XCDR (XCAR (tail));
9897 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9898 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9899 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9900 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9901 }
9902 }
9903
9904 /* Create a pixmap for the image, either from a file, or from a
9905 string buffer containing data in the same format as an XPM file. */
9906 BLOCK_INPUT;
9907 specified_file = image_spec_value (img->spec, QCfile, NULL);
9908 if (STRINGP (specified_file))
9909 {
9910 Lisp_Object file = x_find_image_file (specified_file);
9911 if (!STRINGP (file))
9912 {
9913 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9914 UNBLOCK_INPUT;
9915 return 0;
9916 }
9917
9918 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9919 XSTRING (file)->data, &img->pixmap, &img->mask,
9920 &attrs);
9921 }
9922 else
9923 {
9924 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9925 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9926 XSTRING (buffer)->data,
9927 &img->pixmap, &img->mask,
9928 &attrs);
9929 }
9930 UNBLOCK_INPUT;
9931
9932 if (rc == XpmSuccess)
9933 {
9934 /* Remember allocated colors. */
9935 img->ncolors = attrs.nalloc_pixels;
9936 img->colors = (unsigned long *) xmalloc (img->ncolors
9937 * sizeof *img->colors);
9938 for (i = 0; i < attrs.nalloc_pixels; ++i)
9939 img->colors[i] = attrs.alloc_pixels[i];
9940
9941 img->width = attrs.width;
9942 img->height = attrs.height;
9943 xassert (img->width > 0 && img->height > 0);
9944
9945 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9946 BLOCK_INPUT;
9947 XpmFreeAttributes (&attrs);
9948 UNBLOCK_INPUT;
9949 }
9950 else
9951 {
9952 switch (rc)
9953 {
9954 case XpmOpenFailed:
9955 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9956 break;
9957
9958 case XpmFileInvalid:
9959 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9960 break;
9961
9962 case XpmNoMemory:
9963 image_error ("Out of memory (%s)", img->spec, Qnil);
9964 break;
9965
9966 case XpmColorFailed:
9967 image_error ("Color allocation error (%s)", img->spec, Qnil);
9968 break;
9969
9970 default:
9971 image_error ("Unknown error (%s)", img->spec, Qnil);
9972 break;
9973 }
9974 }
9975
9976 return rc == XpmSuccess;
9977}
9978
9979#endif /* HAVE_XPM != 0 */
9980
9981\f
767b1ff0 9982#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
9983/***********************************************************************
9984 Color table
9985 ***********************************************************************/
9986
9987/* An entry in the color table mapping an RGB color to a pixel color. */
9988
9989struct ct_color
9990{
9991 int r, g, b;
9992 unsigned long pixel;
9993
9994 /* Next in color table collision list. */
9995 struct ct_color *next;
9996};
9997
9998/* The bucket vector size to use. Must be prime. */
9999
10000#define CT_SIZE 101
10001
10002/* Value is a hash of the RGB color given by R, G, and B. */
10003
10004#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10005
10006/* The color hash table. */
10007
10008struct ct_color **ct_table;
10009
10010/* Number of entries in the color table. */
10011
10012int ct_colors_allocated;
10013
10014/* Function prototypes. */
10015
10016static void init_color_table P_ ((void));
10017static void free_color_table P_ ((void));
10018static unsigned long *colors_in_color_table P_ ((int *n));
10019static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10020static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10021
10022
10023/* Initialize the color table. */
10024
10025static void
10026init_color_table ()
10027{
10028 int size = CT_SIZE * sizeof (*ct_table);
10029 ct_table = (struct ct_color **) xmalloc (size);
10030 bzero (ct_table, size);
10031 ct_colors_allocated = 0;
10032}
10033
10034
10035/* Free memory associated with the color table. */
10036
10037static void
10038free_color_table ()
10039{
10040 int i;
10041 struct ct_color *p, *next;
10042
10043 for (i = 0; i < CT_SIZE; ++i)
10044 for (p = ct_table[i]; p; p = next)
10045 {
10046 next = p->next;
10047 xfree (p);
10048 }
10049
10050 xfree (ct_table);
10051 ct_table = NULL;
10052}
10053
10054
10055/* Value is a pixel color for RGB color R, G, B on frame F. If an
10056 entry for that color already is in the color table, return the
10057 pixel color of that entry. Otherwise, allocate a new color for R,
10058 G, B, and make an entry in the color table. */
10059
10060static unsigned long
10061lookup_rgb_color (f, r, g, b)
10062 struct frame *f;
10063 int r, g, b;
10064{
10065 unsigned hash = CT_HASH_RGB (r, g, b);
10066 int i = hash % CT_SIZE;
10067 struct ct_color *p;
10068
10069 for (p = ct_table[i]; p; p = p->next)
10070 if (p->r == r && p->g == g && p->b == b)
10071 break;
10072
10073 if (p == NULL)
10074 {
10075 COLORREF color;
10076 Colormap cmap;
10077 int rc;
10078
10079 color = PALETTERGB (r, g, b);
10080
10081 ++ct_colors_allocated;
10082
10083 p = (struct ct_color *) xmalloc (sizeof *p);
10084 p->r = r;
10085 p->g = g;
10086 p->b = b;
10087 p->pixel = color;
10088 p->next = ct_table[i];
10089 ct_table[i] = p;
10090 }
10091
10092 return p->pixel;
10093}
10094
10095
10096/* Look up pixel color PIXEL which is used on frame F in the color
10097 table. If not already present, allocate it. Value is PIXEL. */
10098
10099static unsigned long
10100lookup_pixel_color (f, pixel)
10101 struct frame *f;
10102 unsigned long pixel;
10103{
10104 int i = pixel % CT_SIZE;
10105 struct ct_color *p;
10106
10107 for (p = ct_table[i]; p; p = p->next)
10108 if (p->pixel == pixel)
10109 break;
10110
10111 if (p == NULL)
10112 {
10113 XColor color;
10114 Colormap cmap;
10115 int rc;
10116
10117 BLOCK_INPUT;
10118
10119 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10120 color.pixel = pixel;
10121 XQueryColor (NULL, cmap, &color);
10122 rc = x_alloc_nearest_color (f, cmap, &color);
10123 UNBLOCK_INPUT;
10124
10125 if (rc)
10126 {
10127 ++ct_colors_allocated;
10128
10129 p = (struct ct_color *) xmalloc (sizeof *p);
10130 p->r = color.red;
10131 p->g = color.green;
10132 p->b = color.blue;
10133 p->pixel = pixel;
10134 p->next = ct_table[i];
10135 ct_table[i] = p;
10136 }
10137 else
10138 return FRAME_FOREGROUND_PIXEL (f);
10139 }
10140 return p->pixel;
10141}
10142
10143
10144/* Value is a vector of all pixel colors contained in the color table,
10145 allocated via xmalloc. Set *N to the number of colors. */
10146
10147static unsigned long *
10148colors_in_color_table (n)
10149 int *n;
10150{
10151 int i, j;
10152 struct ct_color *p;
10153 unsigned long *colors;
10154
10155 if (ct_colors_allocated == 0)
10156 {
10157 *n = 0;
10158 colors = NULL;
10159 }
10160 else
10161 {
10162 colors = (unsigned long *) xmalloc (ct_colors_allocated
10163 * sizeof *colors);
10164 *n = ct_colors_allocated;
10165
10166 for (i = j = 0; i < CT_SIZE; ++i)
10167 for (p = ct_table[i]; p; p = p->next)
10168 colors[j++] = p->pixel;
10169 }
10170
10171 return colors;
10172}
10173
767b1ff0 10174#endif /* TODO */
6fc2811b
JR
10175
10176\f
10177/***********************************************************************
10178 Algorithms
10179 ***********************************************************************/
3cf3436e
JR
10180#if 0 /* TODO: image support. */
10181static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10182static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10183static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10184
10185/* Non-zero means draw a cross on images having `:conversion
10186 disabled'. */
6fc2811b 10187
3cf3436e 10188int cross_disabled_images;
6fc2811b 10189
3cf3436e
JR
10190/* Edge detection matrices for different edge-detection
10191 strategies. */
6fc2811b 10192
3cf3436e
JR
10193static int emboss_matrix[9] = {
10194 /* x - 1 x x + 1 */
10195 2, -1, 0, /* y - 1 */
10196 -1, 0, 1, /* y */
10197 0, 1, -2 /* y + 1 */
10198};
10199
10200static int laplace_matrix[9] = {
10201 /* x - 1 x x + 1 */
10202 1, 0, 0, /* y - 1 */
10203 0, 0, 0, /* y */
10204 0, 0, -1 /* y + 1 */
10205};
10206
10207/* Value is the intensity of the color whose red/green/blue values
10208 are R, G, and B. */
10209
10210#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10211
10212
10213/* On frame F, return an array of XColor structures describing image
10214 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10215 non-zero means also fill the red/green/blue members of the XColor
10216 structures. Value is a pointer to the array of XColors structures,
10217 allocated with xmalloc; it must be freed by the caller. */
10218
10219static XColor *
10220x_to_xcolors (f, img, rgb_p)
10221 struct frame *f;
10222 struct image *img;
10223 int rgb_p;
10224{
10225 int x, y;
10226 XColor *colors, *p;
10227 XImage *ximg;
10228
10229 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10230
10231 /* Get the X image IMG->pixmap. */
10232 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10233 0, 0, img->width, img->height, ~0, ZPixmap);
10234
10235 /* Fill the `pixel' members of the XColor array. I wished there
10236 were an easy and portable way to circumvent XGetPixel. */
10237 p = colors;
10238 for (y = 0; y < img->height; ++y)
10239 {
10240 XColor *row = p;
10241
10242 for (x = 0; x < img->width; ++x, ++p)
10243 p->pixel = XGetPixel (ximg, x, y);
10244
10245 if (rgb_p)
10246 x_query_colors (f, row, img->width);
10247 }
10248
10249 XDestroyImage (ximg);
10250 return colors;
10251}
10252
10253
10254/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10255 RGB members are set. F is the frame on which this all happens.
10256 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10257
10258static void
3cf3436e 10259x_from_xcolors (f, img, colors)
6fc2811b 10260 struct frame *f;
3cf3436e 10261 struct image *img;
6fc2811b 10262 XColor *colors;
6fc2811b 10263{
3cf3436e
JR
10264 int x, y;
10265 XImage *oimg;
10266 Pixmap pixmap;
10267 XColor *p;
10268
10269 init_color_table ();
10270
10271 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10272 &oimg, &pixmap);
10273 p = colors;
10274 for (y = 0; y < img->height; ++y)
10275 for (x = 0; x < img->width; ++x, ++p)
10276 {
10277 unsigned long pixel;
10278 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10279 XPutPixel (oimg, x, y, pixel);
10280 }
6fc2811b 10281
3cf3436e
JR
10282 xfree (colors);
10283 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10284
3cf3436e
JR
10285 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10286 x_destroy_x_image (oimg);
10287 img->pixmap = pixmap;
10288 img->colors = colors_in_color_table (&img->ncolors);
10289 free_color_table ();
6fc2811b
JR
10290}
10291
10292
3cf3436e
JR
10293/* On frame F, perform edge-detection on image IMG.
10294
10295 MATRIX is a nine-element array specifying the transformation
10296 matrix. See emboss_matrix for an example.
10297
10298 COLOR_ADJUST is a color adjustment added to each pixel of the
10299 outgoing image. */
6fc2811b
JR
10300
10301static void
3cf3436e 10302x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10303 struct frame *f;
3cf3436e
JR
10304 struct image *img;
10305 int matrix[9], color_adjust;
6fc2811b 10306{
3cf3436e
JR
10307 XColor *colors = x_to_xcolors (f, img, 1);
10308 XColor *new, *p;
10309 int x, y, i, sum;
10310
10311 for (i = sum = 0; i < 9; ++i)
10312 sum += abs (matrix[i]);
10313
10314#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10315
10316 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10317
10318 for (y = 0; y < img->height; ++y)
10319 {
10320 p = COLOR (new, 0, y);
10321 p->red = p->green = p->blue = 0xffff/2;
10322 p = COLOR (new, img->width - 1, y);
10323 p->red = p->green = p->blue = 0xffff/2;
10324 }
6fc2811b 10325
3cf3436e
JR
10326 for (x = 1; x < img->width - 1; ++x)
10327 {
10328 p = COLOR (new, x, 0);
10329 p->red = p->green = p->blue = 0xffff/2;
10330 p = COLOR (new, x, img->height - 1);
10331 p->red = p->green = p->blue = 0xffff/2;
10332 }
10333
10334 for (y = 1; y < img->height - 1; ++y)
10335 {
10336 p = COLOR (new, 1, y);
10337
10338 for (x = 1; x < img->width - 1; ++x, ++p)
10339 {
10340 int r, g, b, y1, x1;
10341
10342 r = g = b = i = 0;
10343 for (y1 = y - 1; y1 < y + 2; ++y1)
10344 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10345 if (matrix[i])
10346 {
10347 XColor *t = COLOR (colors, x1, y1);
10348 r += matrix[i] * t->red;
10349 g += matrix[i] * t->green;
10350 b += matrix[i] * t->blue;
10351 }
10352
10353 r = (r / sum + color_adjust) & 0xffff;
10354 g = (g / sum + color_adjust) & 0xffff;
10355 b = (b / sum + color_adjust) & 0xffff;
10356 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10357 }
10358 }
10359
10360 xfree (colors);
10361 x_from_xcolors (f, img, new);
10362
10363#undef COLOR
10364}
10365
10366
10367/* Perform the pre-defined `emboss' edge-detection on image IMG
10368 on frame F. */
10369
10370static void
10371x_emboss (f, img)
10372 struct frame *f;
10373 struct image *img;
10374{
10375 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10376}
3cf3436e 10377
6fc2811b
JR
10378
10379/* Transform image IMG which is used on frame F with a Laplace
10380 edge-detection algorithm. The result is an image that can be used
10381 to draw disabled buttons, for example. */
10382
10383static void
10384x_laplace (f, img)
10385 struct frame *f;
10386 struct image *img;
10387{
3cf3436e
JR
10388 x_detect_edges (f, img, laplace_matrix, 45000);
10389}
6fc2811b 10390
6fc2811b 10391
3cf3436e
JR
10392/* Perform edge-detection on image IMG on frame F, with specified
10393 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10394
3cf3436e 10395 MATRIX must be either
6fc2811b 10396
3cf3436e
JR
10397 - a list of at least 9 numbers in row-major form
10398 - a vector of at least 9 numbers
6fc2811b 10399
3cf3436e
JR
10400 COLOR_ADJUST nil means use a default; otherwise it must be a
10401 number. */
6fc2811b 10402
3cf3436e
JR
10403static void
10404x_edge_detection (f, img, matrix, color_adjust)
10405 struct frame *f;
10406 struct image *img;
10407 Lisp_Object matrix, color_adjust;
10408{
10409 int i = 0;
10410 int trans[9];
10411
10412 if (CONSP (matrix))
6fc2811b 10413 {
3cf3436e
JR
10414 for (i = 0;
10415 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10416 ++i, matrix = XCDR (matrix))
10417 trans[i] = XFLOATINT (XCAR (matrix));
10418 }
10419 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10420 {
10421 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10422 trans[i] = XFLOATINT (AREF (matrix, i));
10423 }
10424
10425 if (NILP (color_adjust))
10426 color_adjust = make_number (0xffff / 2);
10427
10428 if (i == 9 && NUMBERP (color_adjust))
10429 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10430}
10431
6fc2811b 10432
3cf3436e 10433/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10434
3cf3436e
JR
10435static void
10436x_disable_image (f, img)
10437 struct frame *f;
10438 struct image *img;
10439{
10440 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10441
10442 if (dpyinfo->n_planes >= 2)
10443 {
10444 /* Color (or grayscale). Convert to gray, and equalize. Just
10445 drawing such images with a stipple can look very odd, so
10446 we're using this method instead. */
10447 XColor *colors = x_to_xcolors (f, img, 1);
10448 XColor *p, *end;
10449 const int h = 15000;
10450 const int l = 30000;
10451
10452 for (p = colors, end = colors + img->width * img->height;
10453 p < end;
10454 ++p)
6fc2811b 10455 {
3cf3436e
JR
10456 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10457 int i2 = (0xffff - h - l) * i / 0xffff + l;
10458 p->red = p->green = p->blue = i2;
6fc2811b
JR
10459 }
10460
3cf3436e 10461 x_from_xcolors (f, img, colors);
6fc2811b
JR
10462 }
10463
3cf3436e
JR
10464 /* Draw a cross over the disabled image, if we must or if we
10465 should. */
10466 if (dpyinfo->n_planes < 2 || cross_disabled_images)
10467 {
10468 Display *dpy = FRAME_X_DISPLAY (f);
10469 GC gc;
6fc2811b 10470
3cf3436e
JR
10471 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10472 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10473 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10474 img->width - 1, img->height - 1);
10475 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10476 img->width - 1, 0);
10477 XFreeGC (dpy, gc);
6fc2811b 10478
3cf3436e
JR
10479 if (img->mask)
10480 {
10481 gc = XCreateGC (dpy, img->mask, 0, NULL);
10482 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10483 XDrawLine (dpy, img->mask, gc, 0, 0,
10484 img->width - 1, img->height - 1);
10485 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10486 img->width - 1, 0);
10487 XFreeGC (dpy, gc);
10488 }
10489 }
6fc2811b
JR
10490}
10491
10492
10493/* Build a mask for image IMG which is used on frame F. FILE is the
10494 name of an image file, for error messages. HOW determines how to
10495 determine the background color of IMG. If it is a list '(R G B)',
10496 with R, G, and B being integers >= 0, take that as the color of the
10497 background. Otherwise, determine the background color of IMG
10498 heuristically. Value is non-zero if successful. */
10499
10500static int
10501x_build_heuristic_mask (f, img, how)
10502 struct frame *f;
10503 struct image *img;
10504 Lisp_Object how;
10505{
6fc2811b
JR
10506 Display *dpy = FRAME_W32_DISPLAY (f);
10507 XImage *ximg, *mask_img;
a05e2bae
JR
10508 int x, y, rc, use_img_background;
10509 unsigned long bg = 0;
10510
10511 if (img->mask)
10512 {
10513 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10514 img->mask = None;
10515 img->background_transparent_valid = 0;
10516 }
6fc2811b 10517
6fc2811b
JR
10518 /* Create an image and pixmap serving as mask. */
10519 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10520 &mask_img, &img->mask);
10521 if (!rc)
a05e2bae 10522 return 0;
6fc2811b
JR
10523
10524 /* Get the X image of IMG->pixmap. */
10525 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10526 ~0, ZPixmap);
10527
10528 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
10529 take that as color. Otherwise, use the image's background color. */
10530 use_img_background = 1;
6fc2811b
JR
10531
10532 if (CONSP (how))
10533 {
a05e2bae 10534 int rgb[3], i;
6fc2811b 10535
a05e2bae 10536 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
10537 {
10538 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10539 how = XCDR (how);
10540 }
10541
10542 if (i == 3 && NILP (how))
10543 {
10544 char color_name[30];
6fc2811b 10545 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
10546 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10547 use_img_background = 0;
6fc2811b
JR
10548 }
10549 }
10550
a05e2bae
JR
10551 if (use_img_background)
10552 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
10553
10554 /* Set all bits in mask_img to 1 whose color in ximg is different
10555 from the background color bg. */
10556 for (y = 0; y < img->height; ++y)
10557 for (x = 0; x < img->width; ++x)
10558 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
10559
a05e2bae
JR
10560 /* Fill in the background_transparent field while we have the mask handy. */
10561 image_background_transparent (img, f, mask_img);
10562
6fc2811b
JR
10563 /* Put mask_img into img->mask. */
10564 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10565 x_destroy_x_image (mask_img);
10566 XDestroyImage (ximg);
6fc2811b
JR
10567
10568 return 1;
10569}
3cf3436e 10570#endif /* TODO */
6fc2811b
JR
10571
10572\f
10573/***********************************************************************
10574 PBM (mono, gray, color)
10575 ***********************************************************************/
10576#ifdef HAVE_PBM
10577
10578static int pbm_image_p P_ ((Lisp_Object object));
10579static int pbm_load P_ ((struct frame *f, struct image *img));
10580static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10581
10582/* The symbol `pbm' identifying images of this type. */
10583
10584Lisp_Object Qpbm;
10585
10586/* Indices of image specification fields in gs_format, below. */
10587
10588enum pbm_keyword_index
10589{
10590 PBM_TYPE,
10591 PBM_FILE,
10592 PBM_DATA,
10593 PBM_ASCENT,
10594 PBM_MARGIN,
10595 PBM_RELIEF,
10596 PBM_ALGORITHM,
10597 PBM_HEURISTIC_MASK,
a05e2bae
JR
10598 PBM_MASK,
10599 PBM_FOREGROUND,
10600 PBM_BACKGROUND,
6fc2811b
JR
10601 PBM_LAST
10602};
10603
10604/* Vector of image_keyword structures describing the format
10605 of valid user-defined image specifications. */
10606
10607static struct image_keyword pbm_format[PBM_LAST] =
10608{
10609 {":type", IMAGE_SYMBOL_VALUE, 1},
10610 {":file", IMAGE_STRING_VALUE, 0},
10611 {":data", IMAGE_STRING_VALUE, 0},
10612 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10613 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10614 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10615 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
10616 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10617 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10618 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10619 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10620};
10621
10622/* Structure describing the image type `pbm'. */
10623
10624static struct image_type pbm_type =
10625{
10626 &Qpbm,
10627 pbm_image_p,
10628 pbm_load,
10629 x_clear_image,
10630 NULL
10631};
10632
10633
10634/* Return non-zero if OBJECT is a valid PBM image specification. */
10635
10636static int
10637pbm_image_p (object)
10638 Lisp_Object object;
10639{
10640 struct image_keyword fmt[PBM_LAST];
10641
10642 bcopy (pbm_format, fmt, sizeof fmt);
10643
10644 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
10645 || (fmt[PBM_ASCENT].count
10646 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
10647 return 0;
10648
10649 /* Must specify either :data or :file. */
10650 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10651}
10652
10653
10654/* Scan a decimal number from *S and return it. Advance *S while
10655 reading the number. END is the end of the string. Value is -1 at
10656 end of input. */
10657
10658static int
10659pbm_scan_number (s, end)
10660 unsigned char **s, *end;
10661{
10662 int c, val = -1;
10663
10664 while (*s < end)
10665 {
10666 /* Skip white-space. */
10667 while (*s < end && (c = *(*s)++, isspace (c)))
10668 ;
10669
10670 if (c == '#')
10671 {
10672 /* Skip comment to end of line. */
10673 while (*s < end && (c = *(*s)++, c != '\n'))
10674 ;
10675 }
10676 else if (isdigit (c))
10677 {
10678 /* Read decimal number. */
10679 val = c - '0';
10680 while (*s < end && (c = *(*s)++, isdigit (c)))
10681 val = 10 * val + c - '0';
10682 break;
10683 }
10684 else
10685 break;
10686 }
10687
10688 return val;
10689}
10690
10691
10692/* Read FILE into memory. Value is a pointer to a buffer allocated
10693 with xmalloc holding FILE's contents. Value is null if an error
10694 occured. *SIZE is set to the size of the file. */
10695
10696static char *
10697pbm_read_file (file, size)
10698 Lisp_Object file;
10699 int *size;
10700{
10701 FILE *fp = NULL;
10702 char *buf = NULL;
10703 struct stat st;
10704
10705 if (stat (XSTRING (file)->data, &st) == 0
10706 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10707 && (buf = (char *) xmalloc (st.st_size),
10708 fread (buf, 1, st.st_size, fp) == st.st_size))
10709 {
10710 *size = st.st_size;
10711 fclose (fp);
10712 }
10713 else
10714 {
10715 if (fp)
10716 fclose (fp);
10717 if (buf)
10718 {
10719 xfree (buf);
10720 buf = NULL;
10721 }
10722 }
10723
10724 return buf;
10725}
10726
10727
10728/* Load PBM image IMG for use on frame F. */
10729
10730static int
10731pbm_load (f, img)
10732 struct frame *f;
10733 struct image *img;
10734{
10735 int raw_p, x, y;
10736 int width, height, max_color_idx = 0;
10737 XImage *ximg;
10738 Lisp_Object file, specified_file;
10739 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10740 struct gcpro gcpro1;
10741 unsigned char *contents = NULL;
10742 unsigned char *end, *p;
10743 int size;
10744
10745 specified_file = image_spec_value (img->spec, QCfile, NULL);
10746 file = Qnil;
10747 GCPRO1 (file);
10748
10749 if (STRINGP (specified_file))
10750 {
10751 file = x_find_image_file (specified_file);
10752 if (!STRINGP (file))
10753 {
10754 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10755 UNGCPRO;
10756 return 0;
10757 }
10758
3cf3436e 10759 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
10760 if (contents == NULL)
10761 {
10762 image_error ("Error reading `%s'", file, Qnil);
10763 UNGCPRO;
10764 return 0;
10765 }
10766
10767 p = contents;
10768 end = contents + size;
10769 }
10770 else
10771 {
10772 Lisp_Object data;
10773 data = image_spec_value (img->spec, QCdata, NULL);
10774 p = XSTRING (data)->data;
10775 end = p + STRING_BYTES (XSTRING (data));
10776 }
10777
10778 /* Check magic number. */
10779 if (end - p < 2 || *p++ != 'P')
10780 {
10781 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10782 error:
10783 xfree (contents);
10784 UNGCPRO;
10785 return 0;
10786 }
10787
6fc2811b
JR
10788 switch (*p++)
10789 {
10790 case '1':
10791 raw_p = 0, type = PBM_MONO;
10792 break;
10793
10794 case '2':
10795 raw_p = 0, type = PBM_GRAY;
10796 break;
10797
10798 case '3':
10799 raw_p = 0, type = PBM_COLOR;
10800 break;
10801
10802 case '4':
10803 raw_p = 1, type = PBM_MONO;
10804 break;
10805
10806 case '5':
10807 raw_p = 1, type = PBM_GRAY;
10808 break;
10809
10810 case '6':
10811 raw_p = 1, type = PBM_COLOR;
10812 break;
10813
10814 default:
10815 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10816 goto error;
10817 }
10818
10819 /* Read width, height, maximum color-component. Characters
10820 starting with `#' up to the end of a line are ignored. */
10821 width = pbm_scan_number (&p, end);
10822 height = pbm_scan_number (&p, end);
10823
10824 if (type != PBM_MONO)
10825 {
10826 max_color_idx = pbm_scan_number (&p, end);
10827 if (raw_p && max_color_idx > 255)
10828 max_color_idx = 255;
10829 }
10830
10831 if (width < 0
10832 || height < 0
10833 || (type != PBM_MONO && max_color_idx < 0))
10834 goto error;
10835
6fc2811b
JR
10836 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10837 &ximg, &img->pixmap))
3cf3436e
JR
10838 goto error;
10839
6fc2811b
JR
10840 /* Initialize the color hash table. */
10841 init_color_table ();
10842
10843 if (type == PBM_MONO)
10844 {
10845 int c = 0, g;
3cf3436e
JR
10846 struct image_keyword fmt[PBM_LAST];
10847 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
10848 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
10849
10850 /* Parse the image specification. */
10851 bcopy (pbm_format, fmt, sizeof fmt);
10852 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
10853
10854 /* Get foreground and background colors, maybe allocate colors. */
10855 if (fmt[PBM_FOREGROUND].count
10856 && STRINGP (fmt[PBM_FOREGROUND].value))
10857 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
10858 if (fmt[PBM_BACKGROUND].count
10859 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
10860 {
10861 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
10862 img->background = bg;
10863 img->background_valid = 1;
10864 }
10865
6fc2811b
JR
10866 for (y = 0; y < height; ++y)
10867 for (x = 0; x < width; ++x)
10868 {
10869 if (raw_p)
10870 {
10871 if ((x & 7) == 0)
10872 c = *p++;
10873 g = c & 0x80;
10874 c <<= 1;
10875 }
10876 else
10877 g = pbm_scan_number (&p, end);
10878
3cf3436e 10879 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
10880 }
10881 }
10882 else
10883 {
10884 for (y = 0; y < height; ++y)
10885 for (x = 0; x < width; ++x)
10886 {
10887 int r, g, b;
10888
10889 if (type == PBM_GRAY)
10890 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10891 else if (raw_p)
10892 {
10893 r = *p++;
10894 g = *p++;
10895 b = *p++;
10896 }
10897 else
10898 {
10899 r = pbm_scan_number (&p, end);
10900 g = pbm_scan_number (&p, end);
10901 b = pbm_scan_number (&p, end);
10902 }
10903
10904 if (r < 0 || g < 0 || b < 0)
10905 {
dfff8a69 10906 xfree (ximg->data);
6fc2811b
JR
10907 ximg->data = NULL;
10908 XDestroyImage (ximg);
6fc2811b
JR
10909 image_error ("Invalid pixel value in image `%s'",
10910 img->spec, Qnil);
10911 goto error;
10912 }
10913
10914 /* RGB values are now in the range 0..max_color_idx.
10915 Scale this to the range 0..0xffff supported by X. */
10916 r = (double) r * 65535 / max_color_idx;
10917 g = (double) g * 65535 / max_color_idx;
10918 b = (double) b * 65535 / max_color_idx;
10919 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10920 }
10921 }
10922
10923 /* Store in IMG->colors the colors allocated for the image, and
10924 free the color table. */
10925 img->colors = colors_in_color_table (&img->ncolors);
10926 free_color_table ();
10927
a05e2bae
JR
10928 /* Maybe fill in the background field while we have ximg handy. */
10929 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10930 IMAGE_BACKGROUND (img, f, ximg);
10931
6fc2811b
JR
10932 /* Put the image into a pixmap. */
10933 x_put_x_image (f, ximg, img->pixmap, width, height);
10934 x_destroy_x_image (ximg);
6fc2811b
JR
10935
10936 img->width = width;
10937 img->height = height;
10938
10939 UNGCPRO;
10940 xfree (contents);
10941 return 1;
10942}
10943#endif /* HAVE_PBM */
10944
10945\f
10946/***********************************************************************
10947 PNG
10948 ***********************************************************************/
10949
10950#if HAVE_PNG
10951
10952#include <png.h>
10953
10954/* Function prototypes. */
10955
10956static int png_image_p P_ ((Lisp_Object object));
10957static int png_load P_ ((struct frame *f, struct image *img));
10958
10959/* The symbol `png' identifying images of this type. */
10960
10961Lisp_Object Qpng;
10962
10963/* Indices of image specification fields in png_format, below. */
10964
10965enum png_keyword_index
10966{
10967 PNG_TYPE,
10968 PNG_DATA,
10969 PNG_FILE,
10970 PNG_ASCENT,
10971 PNG_MARGIN,
10972 PNG_RELIEF,
10973 PNG_ALGORITHM,
10974 PNG_HEURISTIC_MASK,
a05e2bae
JR
10975 PNG_MASK,
10976 PNG_BACKGROUND,
6fc2811b
JR
10977 PNG_LAST
10978};
10979
10980/* Vector of image_keyword structures describing the format
10981 of valid user-defined image specifications. */
10982
10983static struct image_keyword png_format[PNG_LAST] =
10984{
10985 {":type", IMAGE_SYMBOL_VALUE, 1},
10986 {":data", IMAGE_STRING_VALUE, 0},
10987 {":file", IMAGE_STRING_VALUE, 0},
10988 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10989 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10990 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10991 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10992 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10993 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10994 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10995};
10996
10997/* Structure describing the image type `png'. */
10998
10999static struct image_type png_type =
11000{
11001 &Qpng,
11002 png_image_p,
11003 png_load,
11004 x_clear_image,
11005 NULL
11006};
11007
11008
11009/* Return non-zero if OBJECT is a valid PNG image specification. */
11010
11011static int
11012png_image_p (object)
11013 Lisp_Object object;
11014{
11015 struct image_keyword fmt[PNG_LAST];
11016 bcopy (png_format, fmt, sizeof fmt);
11017
11018 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11019 || (fmt[PNG_ASCENT].count
11020 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11021 return 0;
11022
11023 /* Must specify either the :data or :file keyword. */
11024 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11025}
11026
11027
11028/* Error and warning handlers installed when the PNG library
11029 is initialized. */
11030
11031static void
11032my_png_error (png_ptr, msg)
11033 png_struct *png_ptr;
11034 char *msg;
11035{
11036 xassert (png_ptr != NULL);
11037 image_error ("PNG error: %s", build_string (msg), Qnil);
11038 longjmp (png_ptr->jmpbuf, 1);
11039}
11040
11041
11042static void
11043my_png_warning (png_ptr, msg)
11044 png_struct *png_ptr;
11045 char *msg;
11046{
11047 xassert (png_ptr != NULL);
11048 image_error ("PNG warning: %s", build_string (msg), Qnil);
11049}
11050
6fc2811b
JR
11051/* Memory source for PNG decoding. */
11052
11053struct png_memory_storage
11054{
11055 unsigned char *bytes; /* The data */
11056 size_t len; /* How big is it? */
11057 int index; /* Where are we? */
11058};
11059
11060
11061/* Function set as reader function when reading PNG image from memory.
11062 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11063 bytes from the input to DATA. */
11064
11065static void
11066png_read_from_memory (png_ptr, data, length)
11067 png_structp png_ptr;
11068 png_bytep data;
11069 png_size_t length;
11070{
11071 struct png_memory_storage *tbr
11072 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11073
11074 if (length > tbr->len - tbr->index)
11075 png_error (png_ptr, "Read error");
11076
11077 bcopy (tbr->bytes + tbr->index, data, length);
11078 tbr->index = tbr->index + length;
11079}
11080
6fc2811b
JR
11081/* Load PNG image IMG for use on frame F. Value is non-zero if
11082 successful. */
11083
11084static int
11085png_load (f, img)
11086 struct frame *f;
11087 struct image *img;
11088{
11089 Lisp_Object file, specified_file;
11090 Lisp_Object specified_data;
11091 int x, y, i;
11092 XImage *ximg, *mask_img = NULL;
11093 struct gcpro gcpro1;
11094 png_struct *png_ptr = NULL;
11095 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11096 FILE *volatile fp = NULL;
6fc2811b 11097 png_byte sig[8];
a05e2bae
JR
11098 png_byte *volatile pixels = NULL;
11099 png_byte **volatile rows = NULL;
6fc2811b
JR
11100 png_uint_32 width, height;
11101 int bit_depth, color_type, interlace_type;
11102 png_byte channels;
11103 png_uint_32 row_bytes;
11104 int transparent_p;
11105 char *gamma_str;
11106 double screen_gamma, image_gamma;
11107 int intent;
11108 struct png_memory_storage tbr; /* Data to be read */
11109
11110 /* Find out what file to load. */
11111 specified_file = image_spec_value (img->spec, QCfile, NULL);
11112 specified_data = image_spec_value (img->spec, QCdata, NULL);
11113 file = Qnil;
11114 GCPRO1 (file);
11115
11116 if (NILP (specified_data))
11117 {
11118 file = x_find_image_file (specified_file);
11119 if (!STRINGP (file))
11120 {
11121 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11122 UNGCPRO;
11123 return 0;
11124 }
11125
11126 /* Open the image file. */
11127 fp = fopen (XSTRING (file)->data, "rb");
11128 if (!fp)
11129 {
11130 image_error ("Cannot open image file `%s'", file, Qnil);
11131 UNGCPRO;
11132 fclose (fp);
11133 return 0;
11134 }
11135
11136 /* Check PNG signature. */
11137 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11138 || !png_check_sig (sig, sizeof sig))
11139 {
11140 image_error ("Not a PNG file:` %s'", file, Qnil);
11141 UNGCPRO;
11142 fclose (fp);
11143 return 0;
11144 }
11145 }
11146 else
11147 {
11148 /* Read from memory. */
11149 tbr.bytes = XSTRING (specified_data)->data;
11150 tbr.len = STRING_BYTES (XSTRING (specified_data));
11151 tbr.index = 0;
11152
11153 /* Check PNG signature. */
11154 if (tbr.len < sizeof sig
11155 || !png_check_sig (tbr.bytes, sizeof sig))
11156 {
11157 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11158 UNGCPRO;
11159 return 0;
11160 }
11161
11162 /* Need to skip past the signature. */
11163 tbr.bytes += sizeof (sig);
11164 }
11165
6fc2811b
JR
11166 /* Initialize read and info structs for PNG lib. */
11167 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11168 my_png_error, my_png_warning);
11169 if (!png_ptr)
11170 {
11171 if (fp) fclose (fp);
11172 UNGCPRO;
11173 return 0;
11174 }
11175
11176 info_ptr = png_create_info_struct (png_ptr);
11177 if (!info_ptr)
11178 {
11179 png_destroy_read_struct (&png_ptr, NULL, NULL);
11180 if (fp) fclose (fp);
11181 UNGCPRO;
11182 return 0;
11183 }
11184
11185 end_info = png_create_info_struct (png_ptr);
11186 if (!end_info)
11187 {
11188 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11189 if (fp) fclose (fp);
11190 UNGCPRO;
11191 return 0;
11192 }
11193
11194 /* Set error jump-back. We come back here when the PNG library
11195 detects an error. */
11196 if (setjmp (png_ptr->jmpbuf))
11197 {
11198 error:
11199 if (png_ptr)
11200 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11201 xfree (pixels);
11202 xfree (rows);
11203 if (fp) fclose (fp);
11204 UNGCPRO;
11205 return 0;
11206 }
11207
11208 /* Read image info. */
11209 if (!NILP (specified_data))
11210 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11211 else
11212 png_init_io (png_ptr, fp);
11213
11214 png_set_sig_bytes (png_ptr, sizeof sig);
11215 png_read_info (png_ptr, info_ptr);
11216 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11217 &interlace_type, NULL, NULL);
11218
11219 /* If image contains simply transparency data, we prefer to
11220 construct a clipping mask. */
11221 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11222 transparent_p = 1;
11223 else
11224 transparent_p = 0;
11225
11226 /* This function is easier to write if we only have to handle
11227 one data format: RGB or RGBA with 8 bits per channel. Let's
11228 transform other formats into that format. */
11229
11230 /* Strip more than 8 bits per channel. */
11231 if (bit_depth == 16)
11232 png_set_strip_16 (png_ptr);
11233
11234 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11235 if available. */
11236 png_set_expand (png_ptr);
11237
11238 /* Convert grayscale images to RGB. */
11239 if (color_type == PNG_COLOR_TYPE_GRAY
11240 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11241 png_set_gray_to_rgb (png_ptr);
11242
11243 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11244 gamma_str = getenv ("SCREEN_GAMMA");
11245 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11246
11247 /* Tell the PNG lib to handle gamma correction for us. */
11248
11249#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11250 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11251 /* There is a special chunk in the image specifying the gamma. */
11252 png_set_sRGB (png_ptr, info_ptr, intent);
11253 else
11254#endif
11255 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11256 /* Image contains gamma information. */
11257 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11258 else
11259 /* Use a default of 0.5 for the image gamma. */
11260 png_set_gamma (png_ptr, screen_gamma, 0.5);
11261
11262 /* Handle alpha channel by combining the image with a background
11263 color. Do this only if a real alpha channel is supplied. For
11264 simple transparency, we prefer a clipping mask. */
11265 if (!transparent_p)
11266 {
11267 png_color_16 *image_background;
a05e2bae
JR
11268 Lisp_Object specified_bg
11269 = image_spec_value (img->spec, QCbackground, NULL);
11270
11271
11272 if (STRINGP (specified_bg))
11273 /* The user specified `:background', use that. */
11274 {
11275 COLORREF color;
11276 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11277 {
11278 png_color_16 user_bg;
11279
11280 bzero (&user_bg, sizeof user_bg);
11281 user_bg.red = color.red;
11282 user_bg.green = color.green;
11283 user_bg.blue = color.blue;
6fc2811b 11284
a05e2bae
JR
11285 png_set_background (png_ptr, &user_bg,
11286 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11287 }
11288 }
11289 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11290 /* Image contains a background color with which to
11291 combine the image. */
11292 png_set_background (png_ptr, image_background,
11293 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11294 else
11295 {
11296 /* Image does not contain a background color with which
11297 to combine the image data via an alpha channel. Use
11298 the frame's background instead. */
11299 XColor color;
11300 Colormap cmap;
11301 png_color_16 frame_background;
11302
a05e2bae 11303 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11304 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11305 x_query_color (f, &color);
6fc2811b
JR
11306
11307 bzero (&frame_background, sizeof frame_background);
11308 frame_background.red = color.red;
11309 frame_background.green = color.green;
11310 frame_background.blue = color.blue;
11311
11312 png_set_background (png_ptr, &frame_background,
11313 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11314 }
11315 }
11316
11317 /* Update info structure. */
11318 png_read_update_info (png_ptr, info_ptr);
11319
11320 /* Get number of channels. Valid values are 1 for grayscale images
11321 and images with a palette, 2 for grayscale images with transparency
11322 information (alpha channel), 3 for RGB images, and 4 for RGB
11323 images with alpha channel, i.e. RGBA. If conversions above were
11324 sufficient we should only have 3 or 4 channels here. */
11325 channels = png_get_channels (png_ptr, info_ptr);
11326 xassert (channels == 3 || channels == 4);
11327
11328 /* Number of bytes needed for one row of the image. */
11329 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11330
11331 /* Allocate memory for the image. */
11332 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11333 rows = (png_byte **) xmalloc (height * sizeof *rows);
11334 for (i = 0; i < height; ++i)
11335 rows[i] = pixels + i * row_bytes;
11336
11337 /* Read the entire image. */
11338 png_read_image (png_ptr, rows);
11339 png_read_end (png_ptr, info_ptr);
11340 if (fp)
11341 {
11342 fclose (fp);
11343 fp = NULL;
11344 }
11345
6fc2811b
JR
11346 /* Create the X image and pixmap. */
11347 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11348 &img->pixmap))
a05e2bae 11349 goto error;
6fc2811b
JR
11350
11351 /* Create an image and pixmap serving as mask if the PNG image
11352 contains an alpha channel. */
11353 if (channels == 4
11354 && !transparent_p
11355 && !x_create_x_image_and_pixmap (f, width, height, 1,
11356 &mask_img, &img->mask))
11357 {
11358 x_destroy_x_image (ximg);
11359 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11360 img->pixmap = 0;
6fc2811b
JR
11361 goto error;
11362 }
11363
11364 /* Fill the X image and mask from PNG data. */
11365 init_color_table ();
11366
11367 for (y = 0; y < height; ++y)
11368 {
11369 png_byte *p = rows[y];
11370
11371 for (x = 0; x < width; ++x)
11372 {
11373 unsigned r, g, b;
11374
11375 r = *p++ << 8;
11376 g = *p++ << 8;
11377 b = *p++ << 8;
11378 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11379
11380 /* An alpha channel, aka mask channel, associates variable
11381 transparency with an image. Where other image formats
11382 support binary transparency---fully transparent or fully
11383 opaque---PNG allows up to 254 levels of partial transparency.
11384 The PNG library implements partial transparency by combining
11385 the image with a specified background color.
11386
11387 I'm not sure how to handle this here nicely: because the
11388 background on which the image is displayed may change, for
11389 real alpha channel support, it would be necessary to create
11390 a new image for each possible background.
11391
11392 What I'm doing now is that a mask is created if we have
11393 boolean transparency information. Otherwise I'm using
11394 the frame's background color to combine the image with. */
11395
11396 if (channels == 4)
11397 {
11398 if (mask_img)
11399 XPutPixel (mask_img, x, y, *p > 0);
11400 ++p;
11401 }
11402 }
11403 }
11404
a05e2bae
JR
11405 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11406 /* Set IMG's background color from the PNG image, unless the user
11407 overrode it. */
11408 {
11409 png_color_16 *bg;
11410 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11411 {
11412 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11413 img->background_valid = 1;
11414 }
11415 }
11416
6fc2811b
JR
11417 /* Remember colors allocated for this image. */
11418 img->colors = colors_in_color_table (&img->ncolors);
11419 free_color_table ();
11420
11421 /* Clean up. */
11422 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11423 xfree (rows);
11424 xfree (pixels);
11425
11426 img->width = width;
11427 img->height = height;
11428
a05e2bae
JR
11429 /* Maybe fill in the background field while we have ximg handy. */
11430 IMAGE_BACKGROUND (img, f, ximg);
11431
6fc2811b
JR
11432 /* Put the image into the pixmap, then free the X image and its buffer. */
11433 x_put_x_image (f, ximg, img->pixmap, width, height);
11434 x_destroy_x_image (ximg);
11435
11436 /* Same for the mask. */
11437 if (mask_img)
11438 {
a05e2bae
JR
11439 /* Fill in the background_transparent field while we have the mask
11440 handy. */
11441 image_background_transparent (img, f, mask_img);
11442
6fc2811b
JR
11443 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11444 x_destroy_x_image (mask_img);
11445 }
11446
6fc2811b
JR
11447 UNGCPRO;
11448 return 1;
11449}
11450
11451#endif /* HAVE_PNG != 0 */
11452
11453
11454\f
11455/***********************************************************************
11456 JPEG
11457 ***********************************************************************/
11458
11459#if HAVE_JPEG
11460
11461/* Work around a warning about HAVE_STDLIB_H being redefined in
11462 jconfig.h. */
11463#ifdef HAVE_STDLIB_H
11464#define HAVE_STDLIB_H_1
11465#undef HAVE_STDLIB_H
11466#endif /* HAVE_STLIB_H */
11467
11468#include <jpeglib.h>
11469#include <jerror.h>
11470#include <setjmp.h>
11471
11472#ifdef HAVE_STLIB_H_1
11473#define HAVE_STDLIB_H 1
11474#endif
11475
11476static int jpeg_image_p P_ ((Lisp_Object object));
11477static int jpeg_load P_ ((struct frame *f, struct image *img));
11478
11479/* The symbol `jpeg' identifying images of this type. */
11480
11481Lisp_Object Qjpeg;
11482
11483/* Indices of image specification fields in gs_format, below. */
11484
11485enum jpeg_keyword_index
11486{
11487 JPEG_TYPE,
11488 JPEG_DATA,
11489 JPEG_FILE,
11490 JPEG_ASCENT,
11491 JPEG_MARGIN,
11492 JPEG_RELIEF,
11493 JPEG_ALGORITHM,
11494 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11495 JPEG_MASK,
11496 JPEG_BACKGROUND,
6fc2811b
JR
11497 JPEG_LAST
11498};
11499
11500/* Vector of image_keyword structures describing the format
11501 of valid user-defined image specifications. */
11502
11503static struct image_keyword jpeg_format[JPEG_LAST] =
11504{
11505 {":type", IMAGE_SYMBOL_VALUE, 1},
11506 {":data", IMAGE_STRING_VALUE, 0},
11507 {":file", IMAGE_STRING_VALUE, 0},
11508 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11509 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11510 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11511 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11512 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11513 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11514 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11515};
11516
11517/* Structure describing the image type `jpeg'. */
11518
11519static struct image_type jpeg_type =
11520{
11521 &Qjpeg,
11522 jpeg_image_p,
11523 jpeg_load,
11524 x_clear_image,
11525 NULL
11526};
11527
11528
11529/* Return non-zero if OBJECT is a valid JPEG image specification. */
11530
11531static int
11532jpeg_image_p (object)
11533 Lisp_Object object;
11534{
11535 struct image_keyword fmt[JPEG_LAST];
11536
11537 bcopy (jpeg_format, fmt, sizeof fmt);
11538
11539 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11540 || (fmt[JPEG_ASCENT].count
11541 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11542 return 0;
11543
11544 /* Must specify either the :data or :file keyword. */
11545 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11546}
11547
11548
11549struct my_jpeg_error_mgr
11550{
11551 struct jpeg_error_mgr pub;
11552 jmp_buf setjmp_buffer;
11553};
11554
11555static void
11556my_error_exit (cinfo)
11557 j_common_ptr cinfo;
11558{
11559 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11560 longjmp (mgr->setjmp_buffer, 1);
11561}
11562
6fc2811b
JR
11563/* Init source method for JPEG data source manager. Called by
11564 jpeg_read_header() before any data is actually read. See
11565 libjpeg.doc from the JPEG lib distribution. */
11566
11567static void
11568our_init_source (cinfo)
11569 j_decompress_ptr cinfo;
11570{
11571}
11572
11573
11574/* Fill input buffer method for JPEG data source manager. Called
11575 whenever more data is needed. We read the whole image in one step,
11576 so this only adds a fake end of input marker at the end. */
11577
11578static boolean
11579our_fill_input_buffer (cinfo)
11580 j_decompress_ptr cinfo;
11581{
11582 /* Insert a fake EOI marker. */
11583 struct jpeg_source_mgr *src = cinfo->src;
11584 static JOCTET buffer[2];
11585
11586 buffer[0] = (JOCTET) 0xFF;
11587 buffer[1] = (JOCTET) JPEG_EOI;
11588
11589 src->next_input_byte = buffer;
11590 src->bytes_in_buffer = 2;
11591 return TRUE;
11592}
11593
11594
11595/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11596 is the JPEG data source manager. */
11597
11598static void
11599our_skip_input_data (cinfo, num_bytes)
11600 j_decompress_ptr cinfo;
11601 long num_bytes;
11602{
11603 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11604
11605 if (src)
11606 {
11607 if (num_bytes > src->bytes_in_buffer)
11608 ERREXIT (cinfo, JERR_INPUT_EOF);
11609
11610 src->bytes_in_buffer -= num_bytes;
11611 src->next_input_byte += num_bytes;
11612 }
11613}
11614
11615
11616/* Method to terminate data source. Called by
11617 jpeg_finish_decompress() after all data has been processed. */
11618
11619static void
11620our_term_source (cinfo)
11621 j_decompress_ptr cinfo;
11622{
11623}
11624
11625
11626/* Set up the JPEG lib for reading an image from DATA which contains
11627 LEN bytes. CINFO is the decompression info structure created for
11628 reading the image. */
11629
11630static void
11631jpeg_memory_src (cinfo, data, len)
11632 j_decompress_ptr cinfo;
11633 JOCTET *data;
11634 unsigned int len;
11635{
11636 struct jpeg_source_mgr *src;
11637
11638 if (cinfo->src == NULL)
11639 {
11640 /* First time for this JPEG object? */
11641 cinfo->src = (struct jpeg_source_mgr *)
11642 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11643 sizeof (struct jpeg_source_mgr));
11644 src = (struct jpeg_source_mgr *) cinfo->src;
11645 src->next_input_byte = data;
11646 }
11647
11648 src = (struct jpeg_source_mgr *) cinfo->src;
11649 src->init_source = our_init_source;
11650 src->fill_input_buffer = our_fill_input_buffer;
11651 src->skip_input_data = our_skip_input_data;
11652 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
11653 src->term_source = our_term_source;
11654 src->bytes_in_buffer = len;
11655 src->next_input_byte = data;
11656}
11657
11658
11659/* Load image IMG for use on frame F. Patterned after example.c
11660 from the JPEG lib. */
11661
11662static int
11663jpeg_load (f, img)
11664 struct frame *f;
11665 struct image *img;
11666{
11667 struct jpeg_decompress_struct cinfo;
11668 struct my_jpeg_error_mgr mgr;
11669 Lisp_Object file, specified_file;
11670 Lisp_Object specified_data;
a05e2bae 11671 FILE * volatile fp = NULL;
6fc2811b
JR
11672 JSAMPARRAY buffer;
11673 int row_stride, x, y;
11674 XImage *ximg = NULL;
11675 int rc;
11676 unsigned long *colors;
11677 int width, height;
11678 struct gcpro gcpro1;
11679
11680 /* Open the JPEG file. */
11681 specified_file = image_spec_value (img->spec, QCfile, NULL);
11682 specified_data = image_spec_value (img->spec, QCdata, NULL);
11683 file = Qnil;
11684 GCPRO1 (file);
11685
6fc2811b
JR
11686 if (NILP (specified_data))
11687 {
11688 file = x_find_image_file (specified_file);
11689 if (!STRINGP (file))
11690 {
11691 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11692 UNGCPRO;
11693 return 0;
11694 }
11695
11696 fp = fopen (XSTRING (file)->data, "r");
11697 if (fp == NULL)
11698 {
11699 image_error ("Cannot open `%s'", file, Qnil);
11700 UNGCPRO;
11701 return 0;
11702 }
11703 }
11704
11705 /* Customize libjpeg's error handling to call my_error_exit when an
11706 error is detected. This function will perform a longjmp. */
6fc2811b 11707 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 11708 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
11709
11710 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
11711 {
11712 if (rc == 1)
11713 {
11714 /* Called from my_error_exit. Display a JPEG error. */
11715 char buffer[JMSG_LENGTH_MAX];
11716 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11717 image_error ("Error reading JPEG image `%s': %s", img->spec,
11718 build_string (buffer));
11719 }
11720
11721 /* Close the input file and destroy the JPEG object. */
11722 if (fp)
11723 fclose (fp);
11724 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
11725
11726 /* If we already have an XImage, free that. */
11727 x_destroy_x_image (ximg);
11728
11729 /* Free pixmap and colors. */
11730 x_clear_image (f, img);
11731
6fc2811b
JR
11732 UNGCPRO;
11733 return 0;
11734 }
11735
11736 /* Create the JPEG decompression object. Let it read from fp.
11737 Read the JPEG image header. */
11738 jpeg_create_decompress (&cinfo);
11739
11740 if (NILP (specified_data))
11741 jpeg_stdio_src (&cinfo, fp);
11742 else
11743 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
11744 STRING_BYTES (XSTRING (specified_data)));
11745
11746 jpeg_read_header (&cinfo, TRUE);
11747
11748 /* Customize decompression so that color quantization will be used.
11749 Start decompression. */
11750 cinfo.quantize_colors = TRUE;
11751 jpeg_start_decompress (&cinfo);
11752 width = img->width = cinfo.output_width;
11753 height = img->height = cinfo.output_height;
11754
6fc2811b
JR
11755 /* Create X image and pixmap. */
11756 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11757 &img->pixmap))
a05e2bae 11758 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
11759
11760 /* Allocate colors. When color quantization is used,
11761 cinfo.actual_number_of_colors has been set with the number of
11762 colors generated, and cinfo.colormap is a two-dimensional array
11763 of color indices in the range 0..cinfo.actual_number_of_colors.
11764 No more than 255 colors will be generated. */
11765 {
11766 int i, ir, ig, ib;
11767
11768 if (cinfo.out_color_components > 2)
11769 ir = 0, ig = 1, ib = 2;
11770 else if (cinfo.out_color_components > 1)
11771 ir = 0, ig = 1, ib = 0;
11772 else
11773 ir = 0, ig = 0, ib = 0;
11774
11775 /* Use the color table mechanism because it handles colors that
11776 cannot be allocated nicely. Such colors will be replaced with
11777 a default color, and we don't have to care about which colors
11778 can be freed safely, and which can't. */
11779 init_color_table ();
11780 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11781 * sizeof *colors);
11782
11783 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11784 {
11785 /* Multiply RGB values with 255 because X expects RGB values
11786 in the range 0..0xffff. */
11787 int r = cinfo.colormap[ir][i] << 8;
11788 int g = cinfo.colormap[ig][i] << 8;
11789 int b = cinfo.colormap[ib][i] << 8;
11790 colors[i] = lookup_rgb_color (f, r, g, b);
11791 }
11792
11793 /* Remember those colors actually allocated. */
11794 img->colors = colors_in_color_table (&img->ncolors);
11795 free_color_table ();
11796 }
11797
11798 /* Read pixels. */
11799 row_stride = width * cinfo.output_components;
11800 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11801 row_stride, 1);
11802 for (y = 0; y < height; ++y)
11803 {
11804 jpeg_read_scanlines (&cinfo, buffer, 1);
11805 for (x = 0; x < cinfo.output_width; ++x)
11806 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11807 }
11808
11809 /* Clean up. */
11810 jpeg_finish_decompress (&cinfo);
11811 jpeg_destroy_decompress (&cinfo);
11812 if (fp)
11813 fclose (fp);
11814
a05e2bae
JR
11815 /* Maybe fill in the background field while we have ximg handy. */
11816 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11817 IMAGE_BACKGROUND (img, f, ximg);
11818
6fc2811b
JR
11819 /* Put the image into the pixmap. */
11820 x_put_x_image (f, ximg, img->pixmap, width, height);
11821 x_destroy_x_image (ximg);
11822 UNBLOCK_INPUT;
11823 UNGCPRO;
11824 return 1;
11825}
11826
11827#endif /* HAVE_JPEG */
11828
11829
11830\f
11831/***********************************************************************
11832 TIFF
11833 ***********************************************************************/
11834
11835#if HAVE_TIFF
11836
11837#include <tiffio.h>
11838
11839static int tiff_image_p P_ ((Lisp_Object object));
11840static int tiff_load P_ ((struct frame *f, struct image *img));
11841
11842/* The symbol `tiff' identifying images of this type. */
11843
11844Lisp_Object Qtiff;
11845
11846/* Indices of image specification fields in tiff_format, below. */
11847
11848enum tiff_keyword_index
11849{
11850 TIFF_TYPE,
11851 TIFF_DATA,
11852 TIFF_FILE,
11853 TIFF_ASCENT,
11854 TIFF_MARGIN,
11855 TIFF_RELIEF,
11856 TIFF_ALGORITHM,
11857 TIFF_HEURISTIC_MASK,
a05e2bae
JR
11858 TIFF_MASK,
11859 TIFF_BACKGROUND,
6fc2811b
JR
11860 TIFF_LAST
11861};
11862
11863/* Vector of image_keyword structures describing the format
11864 of valid user-defined image specifications. */
11865
11866static struct image_keyword tiff_format[TIFF_LAST] =
11867{
11868 {":type", IMAGE_SYMBOL_VALUE, 1},
11869 {":data", IMAGE_STRING_VALUE, 0},
11870 {":file", IMAGE_STRING_VALUE, 0},
11871 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11872 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11873 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11874 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11875 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11876 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11877 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11878};
11879
11880/* Structure describing the image type `tiff'. */
11881
11882static struct image_type tiff_type =
11883{
11884 &Qtiff,
11885 tiff_image_p,
11886 tiff_load,
11887 x_clear_image,
11888 NULL
11889};
11890
11891
11892/* Return non-zero if OBJECT is a valid TIFF image specification. */
11893
11894static int
11895tiff_image_p (object)
11896 Lisp_Object object;
11897{
11898 struct image_keyword fmt[TIFF_LAST];
11899 bcopy (tiff_format, fmt, sizeof fmt);
11900
11901 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11902 || (fmt[TIFF_ASCENT].count
11903 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11904 return 0;
11905
11906 /* Must specify either the :data or :file keyword. */
11907 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11908}
11909
11910
11911/* Reading from a memory buffer for TIFF images Based on the PNG
11912 memory source, but we have to provide a lot of extra functions.
11913 Blah.
11914
11915 We really only need to implement read and seek, but I am not
11916 convinced that the TIFF library is smart enough not to destroy
11917 itself if we only hand it the function pointers we need to
11918 override. */
11919
11920typedef struct
11921{
11922 unsigned char *bytes;
11923 size_t len;
11924 int index;
11925}
11926tiff_memory_source;
11927
11928static size_t
11929tiff_read_from_memory (data, buf, size)
11930 thandle_t data;
11931 tdata_t buf;
11932 tsize_t size;
11933{
11934 tiff_memory_source *src = (tiff_memory_source *) data;
11935
11936 if (size > src->len - src->index)
11937 return (size_t) -1;
11938 bcopy (src->bytes + src->index, buf, size);
11939 src->index += size;
11940 return size;
11941}
11942
11943static size_t
11944tiff_write_from_memory (data, buf, size)
11945 thandle_t data;
11946 tdata_t buf;
11947 tsize_t size;
11948{
11949 return (size_t) -1;
11950}
11951
11952static toff_t
11953tiff_seek_in_memory (data, off, whence)
11954 thandle_t data;
11955 toff_t off;
11956 int whence;
11957{
11958 tiff_memory_source *src = (tiff_memory_source *) data;
11959 int idx;
11960
11961 switch (whence)
11962 {
11963 case SEEK_SET: /* Go from beginning of source. */
11964 idx = off;
11965 break;
11966
11967 case SEEK_END: /* Go from end of source. */
11968 idx = src->len + off;
11969 break;
11970
11971 case SEEK_CUR: /* Go from current position. */
11972 idx = src->index + off;
11973 break;
11974
11975 default: /* Invalid `whence'. */
11976 return -1;
11977 }
11978
11979 if (idx > src->len || idx < 0)
11980 return -1;
11981
11982 src->index = idx;
11983 return src->index;
11984}
11985
11986static int
11987tiff_close_memory (data)
11988 thandle_t data;
11989{
11990 /* NOOP */
11991 return 0;
11992}
11993
11994static int
11995tiff_mmap_memory (data, pbase, psize)
11996 thandle_t data;
11997 tdata_t *pbase;
11998 toff_t *psize;
11999{
12000 /* It is already _IN_ memory. */
12001 return 0;
12002}
12003
12004static void
12005tiff_unmap_memory (data, base, size)
12006 thandle_t data;
12007 tdata_t base;
12008 toff_t size;
12009{
12010 /* We don't need to do this. */
12011}
12012
12013static toff_t
12014tiff_size_of_memory (data)
12015 thandle_t data;
12016{
12017 return ((tiff_memory_source *) data)->len;
12018}
12019
3cf3436e
JR
12020
12021static void
12022tiff_error_handler (title, format, ap)
12023 const char *title, *format;
12024 va_list ap;
12025{
12026 char buf[512];
12027 int len;
12028
12029 len = sprintf (buf, "TIFF error: %s ", title);
12030 vsprintf (buf + len, format, ap);
12031 add_to_log (buf, Qnil, Qnil);
12032}
12033
12034
12035static void
12036tiff_warning_handler (title, format, ap)
12037 const char *title, *format;
12038 va_list ap;
12039{
12040 char buf[512];
12041 int len;
12042
12043 len = sprintf (buf, "TIFF warning: %s ", title);
12044 vsprintf (buf + len, format, ap);
12045 add_to_log (buf, Qnil, Qnil);
12046}
12047
12048
6fc2811b
JR
12049/* Load TIFF image IMG for use on frame F. Value is non-zero if
12050 successful. */
12051
12052static int
12053tiff_load (f, img)
12054 struct frame *f;
12055 struct image *img;
12056{
12057 Lisp_Object file, specified_file;
12058 Lisp_Object specified_data;
12059 TIFF *tiff;
12060 int width, height, x, y;
12061 uint32 *buf;
12062 int rc;
12063 XImage *ximg;
12064 struct gcpro gcpro1;
12065 tiff_memory_source memsrc;
12066
12067 specified_file = image_spec_value (img->spec, QCfile, NULL);
12068 specified_data = image_spec_value (img->spec, QCdata, NULL);
12069 file = Qnil;
12070 GCPRO1 (file);
12071
3cf3436e
JR
12072 TIFFSetErrorHandler (tiff_error_handler);
12073 TIFFSetWarningHandler (tiff_warning_handler);
12074
6fc2811b
JR
12075 if (NILP (specified_data))
12076 {
12077 /* Read from a file */
12078 file = x_find_image_file (specified_file);
12079 if (!STRINGP (file))
3cf3436e
JR
12080 {
12081 image_error ("Cannot find image file `%s'", file, Qnil);
12082 UNGCPRO;
12083 return 0;
12084 }
12085
6fc2811b
JR
12086 /* Try to open the image file. */
12087 tiff = TIFFOpen (XSTRING (file)->data, "r");
12088 if (tiff == NULL)
3cf3436e
JR
12089 {
12090 image_error ("Cannot open `%s'", file, Qnil);
12091 UNGCPRO;
12092 return 0;
12093 }
6fc2811b
JR
12094 }
12095 else
12096 {
12097 /* Memory source! */
12098 memsrc.bytes = XSTRING (specified_data)->data;
12099 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12100 memsrc.index = 0;
12101
12102 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12103 (TIFFReadWriteProc) tiff_read_from_memory,
12104 (TIFFReadWriteProc) tiff_write_from_memory,
12105 tiff_seek_in_memory,
12106 tiff_close_memory,
12107 tiff_size_of_memory,
12108 tiff_mmap_memory,
12109 tiff_unmap_memory);
12110
12111 if (!tiff)
12112 {
12113 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12114 UNGCPRO;
12115 return 0;
12116 }
12117 }
12118
12119 /* Get width and height of the image, and allocate a raster buffer
12120 of width x height 32-bit values. */
12121 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12122 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12123 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12124
12125 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12126 TIFFClose (tiff);
12127 if (!rc)
12128 {
12129 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12130 xfree (buf);
12131 UNGCPRO;
12132 return 0;
12133 }
12134
6fc2811b
JR
12135 /* Create the X image and pixmap. */
12136 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12137 {
6fc2811b
JR
12138 xfree (buf);
12139 UNGCPRO;
12140 return 0;
12141 }
12142
12143 /* Initialize the color table. */
12144 init_color_table ();
12145
12146 /* Process the pixel raster. Origin is in the lower-left corner. */
12147 for (y = 0; y < height; ++y)
12148 {
12149 uint32 *row = buf + y * width;
12150
12151 for (x = 0; x < width; ++x)
12152 {
12153 uint32 abgr = row[x];
12154 int r = TIFFGetR (abgr) << 8;
12155 int g = TIFFGetG (abgr) << 8;
12156 int b = TIFFGetB (abgr) << 8;
12157 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12158 }
12159 }
12160
12161 /* Remember the colors allocated for the image. Free the color table. */
12162 img->colors = colors_in_color_table (&img->ncolors);
12163 free_color_table ();
12164
a05e2bae
JR
12165 img->width = width;
12166 img->height = height;
12167
12168 /* Maybe fill in the background field while we have ximg handy. */
12169 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12170 IMAGE_BACKGROUND (img, f, ximg);
12171
6fc2811b
JR
12172 /* Put the image into the pixmap, then free the X image and its buffer. */
12173 x_put_x_image (f, ximg, img->pixmap, width, height);
12174 x_destroy_x_image (ximg);
12175 xfree (buf);
6fc2811b
JR
12176
12177 UNGCPRO;
12178 return 1;
12179}
12180
12181#endif /* HAVE_TIFF != 0 */
12182
12183
12184\f
12185/***********************************************************************
12186 GIF
12187 ***********************************************************************/
12188
12189#if HAVE_GIF
12190
12191#include <gif_lib.h>
12192
12193static int gif_image_p P_ ((Lisp_Object object));
12194static int gif_load P_ ((struct frame *f, struct image *img));
12195
12196/* The symbol `gif' identifying images of this type. */
12197
12198Lisp_Object Qgif;
12199
12200/* Indices of image specification fields in gif_format, below. */
12201
12202enum gif_keyword_index
12203{
12204 GIF_TYPE,
12205 GIF_DATA,
12206 GIF_FILE,
12207 GIF_ASCENT,
12208 GIF_MARGIN,
12209 GIF_RELIEF,
12210 GIF_ALGORITHM,
12211 GIF_HEURISTIC_MASK,
a05e2bae 12212 GIF_MASK,
6fc2811b 12213 GIF_IMAGE,
a05e2bae 12214 GIF_BACKGROUND,
6fc2811b
JR
12215 GIF_LAST
12216};
12217
12218/* Vector of image_keyword structures describing the format
12219 of valid user-defined image specifications. */
12220
12221static struct image_keyword gif_format[GIF_LAST] =
12222{
12223 {":type", IMAGE_SYMBOL_VALUE, 1},
12224 {":data", IMAGE_STRING_VALUE, 0},
12225 {":file", IMAGE_STRING_VALUE, 0},
12226 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12227 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12228 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12229 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12230 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12231 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12232 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12233 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12234};
12235
12236/* Structure describing the image type `gif'. */
12237
12238static struct image_type gif_type =
12239{
12240 &Qgif,
12241 gif_image_p,
12242 gif_load,
12243 x_clear_image,
12244 NULL
12245};
12246
12247/* Return non-zero if OBJECT is a valid GIF image specification. */
12248
12249static int
12250gif_image_p (object)
12251 Lisp_Object object;
12252{
12253 struct image_keyword fmt[GIF_LAST];
12254 bcopy (gif_format, fmt, sizeof fmt);
12255
12256 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12257 || (fmt[GIF_ASCENT].count
12258 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12259 return 0;
12260
12261 /* Must specify either the :data or :file keyword. */
12262 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12263}
12264
12265/* Reading a GIF image from memory
12266 Based on the PNG memory stuff to a certain extent. */
12267
12268typedef struct
12269{
12270 unsigned char *bytes;
12271 size_t len;
12272 int index;
12273}
12274gif_memory_source;
12275
12276/* Make the current memory source available to gif_read_from_memory.
12277 It's done this way because not all versions of libungif support
12278 a UserData field in the GifFileType structure. */
12279static gif_memory_source *current_gif_memory_src;
12280
12281static int
12282gif_read_from_memory (file, buf, len)
12283 GifFileType *file;
12284 GifByteType *buf;
12285 int len;
12286{
12287 gif_memory_source *src = current_gif_memory_src;
12288
12289 if (len > src->len - src->index)
12290 return -1;
12291
12292 bcopy (src->bytes + src->index, buf, len);
12293 src->index += len;
12294 return len;
12295}
12296
12297
12298/* Load GIF image IMG for use on frame F. Value is non-zero if
12299 successful. */
12300
12301static int
12302gif_load (f, img)
12303 struct frame *f;
12304 struct image *img;
12305{
12306 Lisp_Object file, specified_file;
12307 Lisp_Object specified_data;
12308 int rc, width, height, x, y, i;
12309 XImage *ximg;
12310 ColorMapObject *gif_color_map;
12311 unsigned long pixel_colors[256];
12312 GifFileType *gif;
12313 struct gcpro gcpro1;
12314 Lisp_Object image;
12315 int ino, image_left, image_top, image_width, image_height;
12316 gif_memory_source memsrc;
12317 unsigned char *raster;
12318
12319 specified_file = image_spec_value (img->spec, QCfile, NULL);
12320 specified_data = image_spec_value (img->spec, QCdata, NULL);
12321 file = Qnil;
dfff8a69 12322 GCPRO1 (file);
6fc2811b
JR
12323
12324 if (NILP (specified_data))
12325 {
12326 file = x_find_image_file (specified_file);
6fc2811b
JR
12327 if (!STRINGP (file))
12328 {
12329 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12330 UNGCPRO;
12331 return 0;
12332 }
12333
12334 /* Open the GIF file. */
12335 gif = DGifOpenFileName (XSTRING (file)->data);
12336 if (gif == NULL)
12337 {
12338 image_error ("Cannot open `%s'", file, Qnil);
12339 UNGCPRO;
12340 return 0;
12341 }
12342 }
12343 else
12344 {
12345 /* Read from memory! */
12346 current_gif_memory_src = &memsrc;
12347 memsrc.bytes = XSTRING (specified_data)->data;
12348 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12349 memsrc.index = 0;
12350
12351 gif = DGifOpen(&memsrc, gif_read_from_memory);
12352 if (!gif)
12353 {
12354 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12355 UNGCPRO;
12356 return 0;
12357 }
12358 }
12359
12360 /* Read entire contents. */
12361 rc = DGifSlurp (gif);
12362 if (rc == GIF_ERROR)
12363 {
12364 image_error ("Error reading `%s'", img->spec, Qnil);
12365 DGifCloseFile (gif);
12366 UNGCPRO;
12367 return 0;
12368 }
12369
12370 image = image_spec_value (img->spec, QCindex, NULL);
12371 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12372 if (ino >= gif->ImageCount)
12373 {
12374 image_error ("Invalid image number `%s' in image `%s'",
12375 image, img->spec);
12376 DGifCloseFile (gif);
12377 UNGCPRO;
12378 return 0;
12379 }
12380
12381 width = img->width = gif->SWidth;
12382 height = img->height = gif->SHeight;
12383
6fc2811b
JR
12384 /* Create the X image and pixmap. */
12385 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12386 {
6fc2811b
JR
12387 DGifCloseFile (gif);
12388 UNGCPRO;
12389 return 0;
12390 }
12391
12392 /* Allocate colors. */
12393 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12394 if (!gif_color_map)
12395 gif_color_map = gif->SColorMap;
12396 init_color_table ();
12397 bzero (pixel_colors, sizeof pixel_colors);
12398
12399 for (i = 0; i < gif_color_map->ColorCount; ++i)
12400 {
12401 int r = gif_color_map->Colors[i].Red << 8;
12402 int g = gif_color_map->Colors[i].Green << 8;
12403 int b = gif_color_map->Colors[i].Blue << 8;
12404 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12405 }
12406
12407 img->colors = colors_in_color_table (&img->ncolors);
12408 free_color_table ();
12409
12410 /* Clear the part of the screen image that are not covered by
12411 the image from the GIF file. Full animated GIF support
12412 requires more than can be done here (see the gif89 spec,
12413 disposal methods). Let's simply assume that the part
12414 not covered by a sub-image is in the frame's background color. */
12415 image_top = gif->SavedImages[ino].ImageDesc.Top;
12416 image_left = gif->SavedImages[ino].ImageDesc.Left;
12417 image_width = gif->SavedImages[ino].ImageDesc.Width;
12418 image_height = gif->SavedImages[ino].ImageDesc.Height;
12419
12420 for (y = 0; y < image_top; ++y)
12421 for (x = 0; x < width; ++x)
12422 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12423
12424 for (y = image_top + image_height; y < height; ++y)
12425 for (x = 0; x < width; ++x)
12426 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12427
12428 for (y = image_top; y < image_top + image_height; ++y)
12429 {
12430 for (x = 0; x < image_left; ++x)
12431 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12432 for (x = image_left + image_width; x < width; ++x)
12433 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12434 }
12435
12436 /* Read the GIF image into the X image. We use a local variable
12437 `raster' here because RasterBits below is a char *, and invites
12438 problems with bytes >= 0x80. */
12439 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12440
12441 if (gif->SavedImages[ino].ImageDesc.Interlace)
12442 {
12443 static int interlace_start[] = {0, 4, 2, 1};
12444 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12445 int pass;
6fc2811b
JR
12446 int row = interlace_start[0];
12447
12448 pass = 0;
12449
12450 for (y = 0; y < image_height; y++)
12451 {
12452 if (row >= image_height)
12453 {
12454 row = interlace_start[++pass];
12455 while (row >= image_height)
12456 row = interlace_start[++pass];
12457 }
12458
12459 for (x = 0; x < image_width; x++)
12460 {
12461 int i = raster[(y * image_width) + x];
12462 XPutPixel (ximg, x + image_left, row + image_top,
12463 pixel_colors[i]);
12464 }
12465
12466 row += interlace_increment[pass];
12467 }
12468 }
12469 else
12470 {
12471 for (y = 0; y < image_height; ++y)
12472 for (x = 0; x < image_width; ++x)
12473 {
12474 int i = raster[y* image_width + x];
12475 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12476 }
12477 }
12478
12479 DGifCloseFile (gif);
a05e2bae
JR
12480
12481 /* Maybe fill in the background field while we have ximg handy. */
12482 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12483 IMAGE_BACKGROUND (img, f, ximg);
12484
6fc2811b
JR
12485 /* Put the image into the pixmap, then free the X image and its buffer. */
12486 x_put_x_image (f, ximg, img->pixmap, width, height);
12487 x_destroy_x_image (ximg);
6fc2811b
JR
12488
12489 UNGCPRO;
12490 return 1;
12491}
12492
12493#endif /* HAVE_GIF != 0 */
12494
12495
12496\f
12497/***********************************************************************
12498 Ghostscript
12499 ***********************************************************************/
12500
3cf3436e
JR
12501Lisp_Object Qpostscript;
12502
6fc2811b
JR
12503#ifdef HAVE_GHOSTSCRIPT
12504static int gs_image_p P_ ((Lisp_Object object));
12505static int gs_load P_ ((struct frame *f, struct image *img));
12506static void gs_clear_image P_ ((struct frame *f, struct image *img));
12507
12508/* The symbol `postscript' identifying images of this type. */
12509
6fc2811b
JR
12510/* Keyword symbols. */
12511
12512Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12513
12514/* Indices of image specification fields in gs_format, below. */
12515
12516enum gs_keyword_index
12517{
12518 GS_TYPE,
12519 GS_PT_WIDTH,
12520 GS_PT_HEIGHT,
12521 GS_FILE,
12522 GS_LOADER,
12523 GS_BOUNDING_BOX,
12524 GS_ASCENT,
12525 GS_MARGIN,
12526 GS_RELIEF,
12527 GS_ALGORITHM,
12528 GS_HEURISTIC_MASK,
a05e2bae
JR
12529 GS_MASK,
12530 GS_BACKGROUND,
6fc2811b
JR
12531 GS_LAST
12532};
12533
12534/* Vector of image_keyword structures describing the format
12535 of valid user-defined image specifications. */
12536
12537static struct image_keyword gs_format[GS_LAST] =
12538{
12539 {":type", IMAGE_SYMBOL_VALUE, 1},
12540 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12541 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12542 {":file", IMAGE_STRING_VALUE, 1},
12543 {":loader", IMAGE_FUNCTION_VALUE, 0},
12544 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12545 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12546 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12547 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12548 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12549 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12550 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12551 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12552};
12553
12554/* Structure describing the image type `ghostscript'. */
12555
12556static struct image_type gs_type =
12557{
12558 &Qpostscript,
12559 gs_image_p,
12560 gs_load,
12561 gs_clear_image,
12562 NULL
12563};
12564
12565
12566/* Free X resources of Ghostscript image IMG which is used on frame F. */
12567
12568static void
12569gs_clear_image (f, img)
12570 struct frame *f;
12571 struct image *img;
12572{
12573 /* IMG->data.ptr_val may contain a recorded colormap. */
12574 xfree (img->data.ptr_val);
12575 x_clear_image (f, img);
12576}
12577
12578
12579/* Return non-zero if OBJECT is a valid Ghostscript image
12580 specification. */
12581
12582static int
12583gs_image_p (object)
12584 Lisp_Object object;
12585{
12586 struct image_keyword fmt[GS_LAST];
12587 Lisp_Object tem;
12588 int i;
12589
12590 bcopy (gs_format, fmt, sizeof fmt);
12591
12592 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
12593 || (fmt[GS_ASCENT].count
12594 && XFASTINT (fmt[GS_ASCENT].value) > 100))
12595 return 0;
12596
12597 /* Bounding box must be a list or vector containing 4 integers. */
12598 tem = fmt[GS_BOUNDING_BOX].value;
12599 if (CONSP (tem))
12600 {
12601 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12602 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12603 return 0;
12604 if (!NILP (tem))
12605 return 0;
12606 }
12607 else if (VECTORP (tem))
12608 {
12609 if (XVECTOR (tem)->size != 4)
12610 return 0;
12611 for (i = 0; i < 4; ++i)
12612 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12613 return 0;
12614 }
12615 else
12616 return 0;
12617
12618 return 1;
12619}
12620
12621
12622/* Load Ghostscript image IMG for use on frame F. Value is non-zero
12623 if successful. */
12624
12625static int
12626gs_load (f, img)
12627 struct frame *f;
12628 struct image *img;
12629{
12630 char buffer[100];
12631 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12632 struct gcpro gcpro1, gcpro2;
12633 Lisp_Object frame;
12634 double in_width, in_height;
12635 Lisp_Object pixel_colors = Qnil;
12636
12637 /* Compute pixel size of pixmap needed from the given size in the
12638 image specification. Sizes in the specification are in pt. 1 pt
12639 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12640 info. */
12641 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12642 in_width = XFASTINT (pt_width) / 72.0;
12643 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12644 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12645 in_height = XFASTINT (pt_height) / 72.0;
12646 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12647
12648 /* Create the pixmap. */
12649 BLOCK_INPUT;
12650 xassert (img->pixmap == 0);
12651 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12652 img->width, img->height,
a05e2bae 12653 one_w32_display_info.n_cbits);
6fc2811b
JR
12654 UNBLOCK_INPUT;
12655
12656 if (!img->pixmap)
12657 {
12658 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12659 return 0;
12660 }
12661
12662 /* Call the loader to fill the pixmap. It returns a process object
12663 if successful. We do not record_unwind_protect here because
12664 other places in redisplay like calling window scroll functions
12665 don't either. Let the Lisp loader use `unwind-protect' instead. */
12666 GCPRO2 (window_and_pixmap_id, pixel_colors);
12667
12668 sprintf (buffer, "%lu %lu",
12669 (unsigned long) FRAME_W32_WINDOW (f),
12670 (unsigned long) img->pixmap);
12671 window_and_pixmap_id = build_string (buffer);
12672
12673 sprintf (buffer, "%lu %lu",
12674 FRAME_FOREGROUND_PIXEL (f),
12675 FRAME_BACKGROUND_PIXEL (f));
12676 pixel_colors = build_string (buffer);
12677
12678 XSETFRAME (frame, f);
12679 loader = image_spec_value (img->spec, QCloader, NULL);
12680 if (NILP (loader))
12681 loader = intern ("gs-load-image");
12682
12683 img->data.lisp_val = call6 (loader, frame, img->spec,
12684 make_number (img->width),
12685 make_number (img->height),
12686 window_and_pixmap_id,
12687 pixel_colors);
12688 UNGCPRO;
12689 return PROCESSP (img->data.lisp_val);
12690}
12691
12692
12693/* Kill the Ghostscript process that was started to fill PIXMAP on
12694 frame F. Called from XTread_socket when receiving an event
12695 telling Emacs that Ghostscript has finished drawing. */
12696
12697void
12698x_kill_gs_process (pixmap, f)
12699 Pixmap pixmap;
12700 struct frame *f;
12701{
12702 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
12703 int class, i;
12704 struct image *img;
12705
12706 /* Find the image containing PIXMAP. */
12707 for (i = 0; i < c->used; ++i)
12708 if (c->images[i]->pixmap == pixmap)
12709 break;
12710
3cf3436e
JR
12711 /* Should someone in between have cleared the image cache, for
12712 instance, give up. */
12713 if (i == c->used)
12714 return;
12715
6fc2811b
JR
12716 /* Kill the GS process. We should have found PIXMAP in the image
12717 cache and its image should contain a process object. */
6fc2811b
JR
12718 img = c->images[i];
12719 xassert (PROCESSP (img->data.lisp_val));
12720 Fkill_process (img->data.lisp_val, Qnil);
12721 img->data.lisp_val = Qnil;
12722
12723 /* On displays with a mutable colormap, figure out the colors
12724 allocated for the image by looking at the pixels of an XImage for
12725 img->pixmap. */
12726 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
12727 if (class != StaticColor && class != StaticGray && class != TrueColor)
12728 {
12729 XImage *ximg;
12730
12731 BLOCK_INPUT;
12732
12733 /* Try to get an XImage for img->pixmep. */
12734 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
12735 0, 0, img->width, img->height, ~0, ZPixmap);
12736 if (ximg)
12737 {
12738 int x, y;
12739
12740 /* Initialize the color table. */
12741 init_color_table ();
12742
12743 /* For each pixel of the image, look its color up in the
12744 color table. After having done so, the color table will
12745 contain an entry for each color used by the image. */
12746 for (y = 0; y < img->height; ++y)
12747 for (x = 0; x < img->width; ++x)
12748 {
12749 unsigned long pixel = XGetPixel (ximg, x, y);
12750 lookup_pixel_color (f, pixel);
12751 }
12752
12753 /* Record colors in the image. Free color table and XImage. */
12754 img->colors = colors_in_color_table (&img->ncolors);
12755 free_color_table ();
12756 XDestroyImage (ximg);
12757
12758#if 0 /* This doesn't seem to be the case. If we free the colors
12759 here, we get a BadAccess later in x_clear_image when
12760 freeing the colors. */
12761 /* We have allocated colors once, but Ghostscript has also
12762 allocated colors on behalf of us. So, to get the
12763 reference counts right, free them once. */
12764 if (img->ncolors)
3cf3436e 12765 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 12766 img->colors, img->ncolors, 0);
6fc2811b
JR
12767#endif
12768 }
12769 else
12770 image_error ("Cannot get X image of `%s'; colors will not be freed",
12771 img->spec, Qnil);
12772
12773 UNBLOCK_INPUT;
12774 }
3cf3436e
JR
12775
12776 /* Now that we have the pixmap, compute mask and transform the
12777 image if requested. */
12778 BLOCK_INPUT;
12779 postprocess_image (f, img);
12780 UNBLOCK_INPUT;
6fc2811b
JR
12781}
12782
12783#endif /* HAVE_GHOSTSCRIPT */
12784
12785\f
12786/***********************************************************************
12787 Window properties
12788 ***********************************************************************/
12789
12790DEFUN ("x-change-window-property", Fx_change_window_property,
12791 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
12792 doc: /* Change window property PROP to VALUE on the X window of FRAME.
12793PROP and VALUE must be strings. FRAME nil or omitted means use the
12794selected frame. Value is VALUE. */)
6fc2811b
JR
12795 (prop, value, frame)
12796 Lisp_Object frame, prop, value;
12797{
767b1ff0 12798#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12799 struct frame *f = check_x_frame (frame);
12800 Atom prop_atom;
12801
b7826503
PJ
12802 CHECK_STRING (prop);
12803 CHECK_STRING (value);
6fc2811b
JR
12804
12805 BLOCK_INPUT;
12806 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12807 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12808 prop_atom, XA_STRING, 8, PropModeReplace,
12809 XSTRING (value)->data, XSTRING (value)->size);
12810
12811 /* Make sure the property is set when we return. */
12812 XFlush (FRAME_W32_DISPLAY (f));
12813 UNBLOCK_INPUT;
12814
767b1ff0 12815#endif /* TODO */
6fc2811b
JR
12816
12817 return value;
12818}
12819
12820
12821DEFUN ("x-delete-window-property", Fx_delete_window_property,
12822 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
12823 doc: /* Remove window property PROP from X window of FRAME.
12824FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
12825 (prop, frame)
12826 Lisp_Object prop, frame;
12827{
767b1ff0 12828#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12829
12830 struct frame *f = check_x_frame (frame);
12831 Atom prop_atom;
12832
b7826503 12833 CHECK_STRING (prop);
6fc2811b
JR
12834 BLOCK_INPUT;
12835 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12836 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12837
12838 /* Make sure the property is removed when we return. */
12839 XFlush (FRAME_W32_DISPLAY (f));
12840 UNBLOCK_INPUT;
767b1ff0 12841#endif /* TODO */
6fc2811b
JR
12842
12843 return prop;
12844}
12845
12846
12847DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12848 1, 2, 0,
74e1aeec
JR
12849 doc: /* Value is the value of window property PROP on FRAME.
12850If FRAME is nil or omitted, use the selected frame. Value is nil
12851if FRAME hasn't a property with name PROP or if PROP has no string
12852value. */)
6fc2811b
JR
12853 (prop, frame)
12854 Lisp_Object prop, frame;
12855{
767b1ff0 12856#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12857
12858 struct frame *f = check_x_frame (frame);
12859 Atom prop_atom;
12860 int rc;
12861 Lisp_Object prop_value = Qnil;
12862 char *tmp_data = NULL;
12863 Atom actual_type;
12864 int actual_format;
12865 unsigned long actual_size, bytes_remaining;
12866
b7826503 12867 CHECK_STRING (prop);
6fc2811b
JR
12868 BLOCK_INPUT;
12869 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12870 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12871 prop_atom, 0, 0, False, XA_STRING,
12872 &actual_type, &actual_format, &actual_size,
12873 &bytes_remaining, (unsigned char **) &tmp_data);
12874 if (rc == Success)
12875 {
12876 int size = bytes_remaining;
12877
12878 XFree (tmp_data);
12879 tmp_data = NULL;
12880
12881 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12882 prop_atom, 0, bytes_remaining,
12883 False, XA_STRING,
12884 &actual_type, &actual_format,
12885 &actual_size, &bytes_remaining,
12886 (unsigned char **) &tmp_data);
12887 if (rc == Success)
12888 prop_value = make_string (tmp_data, size);
12889
12890 XFree (tmp_data);
12891 }
12892
12893 UNBLOCK_INPUT;
12894
12895 return prop_value;
12896
767b1ff0 12897#endif /* TODO */
6fc2811b
JR
12898 return Qnil;
12899}
12900
12901
12902\f
12903/***********************************************************************
12904 Busy cursor
12905 ***********************************************************************/
12906
f79e6790 12907/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 12908 an hourglass cursor on all frames. */
6fc2811b 12909
0af913d7 12910static struct atimer *hourglass_atimer;
6fc2811b 12911
0af913d7 12912/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 12913
0af913d7 12914static int hourglass_shown_p;
6fc2811b 12915
0af913d7 12916/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 12917
0af913d7 12918static Lisp_Object Vhourglass_delay;
6fc2811b 12919
0af913d7 12920/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
12921 cursor. */
12922
0af913d7 12923#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
12924
12925/* Function prototypes. */
12926
0af913d7
GM
12927static void show_hourglass P_ ((struct atimer *));
12928static void hide_hourglass P_ ((void));
f79e6790
JR
12929
12930
0af913d7 12931/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
12932
12933void
0af913d7 12934start_hourglass ()
f79e6790 12935{
767b1ff0 12936#if 0 /* TODO: cursor shape changes. */
f79e6790 12937 EMACS_TIME delay;
dfff8a69 12938 int secs, usecs = 0;
f79e6790 12939
0af913d7 12940 cancel_hourglass ();
f79e6790 12941
0af913d7
GM
12942 if (INTEGERP (Vhourglass_delay)
12943 && XINT (Vhourglass_delay) > 0)
12944 secs = XFASTINT (Vhourglass_delay);
12945 else if (FLOATP (Vhourglass_delay)
12946 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
12947 {
12948 Lisp_Object tem;
0af913d7 12949 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 12950 secs = XFASTINT (tem);
0af913d7 12951 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 12952 }
f79e6790 12953 else
0af913d7 12954 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 12955
dfff8a69 12956 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
12957 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
12958 show_hourglass, NULL);
f79e6790
JR
12959#endif
12960}
12961
12962
0af913d7
GM
12963/* Cancel the hourglass cursor timer if active, hide an hourglass
12964 cursor if shown. */
f79e6790
JR
12965
12966void
0af913d7 12967cancel_hourglass ()
f79e6790 12968{
0af913d7 12969 if (hourglass_atimer)
dfff8a69 12970 {
0af913d7
GM
12971 cancel_atimer (hourglass_atimer);
12972 hourglass_atimer = NULL;
dfff8a69
JR
12973 }
12974
0af913d7
GM
12975 if (hourglass_shown_p)
12976 hide_hourglass ();
f79e6790
JR
12977}
12978
12979
0af913d7
GM
12980/* Timer function of hourglass_atimer. TIMER is equal to
12981 hourglass_atimer.
f79e6790 12982
0af913d7
GM
12983 Display an hourglass cursor on all frames by mapping the frames'
12984 hourglass_window. Set the hourglass_p flag in the frames'
12985 output_data.x structure to indicate that an hourglass cursor is
12986 shown on the frames. */
f79e6790
JR
12987
12988static void
0af913d7 12989show_hourglass (timer)
f79e6790 12990 struct atimer *timer;
6fc2811b 12991{
767b1ff0 12992#if 0 /* TODO: cursor shape changes. */
f79e6790 12993 /* The timer implementation will cancel this timer automatically
0af913d7 12994 after this function has run. Set hourglass_atimer to null
f79e6790 12995 so that we know the timer doesn't have to be canceled. */
0af913d7 12996 hourglass_atimer = NULL;
f79e6790 12997
0af913d7 12998 if (!hourglass_shown_p)
6fc2811b
JR
12999 {
13000 Lisp_Object rest, frame;
f79e6790
JR
13001
13002 BLOCK_INPUT;
13003
6fc2811b 13004 FOR_EACH_FRAME (rest, frame)
dc220243 13005 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13006 {
13007 struct frame *f = XFRAME (frame);
f79e6790 13008
0af913d7 13009 f->output_data.w32->hourglass_p = 1;
f79e6790 13010
0af913d7 13011 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13012 {
13013 unsigned long mask = CWCursor;
13014 XSetWindowAttributes attrs;
f79e6790 13015
0af913d7 13016 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13017
0af913d7 13018 f->output_data.w32->hourglass_window
f79e6790 13019 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13020 FRAME_OUTER_WINDOW (f),
13021 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13022 InputOnly,
13023 CopyFromParent,
6fc2811b
JR
13024 mask, &attrs);
13025 }
f79e6790 13026
0af913d7
GM
13027 XMapRaised (FRAME_X_DISPLAY (f),
13028 f->output_data.w32->hourglass_window);
f79e6790 13029 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13030 }
6fc2811b 13031
0af913d7 13032 hourglass_shown_p = 1;
f79e6790
JR
13033 UNBLOCK_INPUT;
13034 }
13035#endif
6fc2811b
JR
13036}
13037
13038
0af913d7 13039/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13040
f79e6790 13041static void
0af913d7 13042hide_hourglass ()
f79e6790 13043{
767b1ff0 13044#if 0 /* TODO: cursor shape changes. */
0af913d7 13045 if (hourglass_shown_p)
6fc2811b 13046 {
f79e6790
JR
13047 Lisp_Object rest, frame;
13048
13049 BLOCK_INPUT;
13050 FOR_EACH_FRAME (rest, frame)
6fc2811b 13051 {
f79e6790
JR
13052 struct frame *f = XFRAME (frame);
13053
dc220243 13054 if (FRAME_W32_P (f)
f79e6790 13055 /* Watch out for newly created frames. */
0af913d7 13056 && f->output_data.x->hourglass_window)
f79e6790 13057 {
0af913d7
GM
13058 XUnmapWindow (FRAME_X_DISPLAY (f),
13059 f->output_data.x->hourglass_window);
13060 /* Sync here because XTread_socket looks at the
13061 hourglass_p flag that is reset to zero below. */
f79e6790 13062 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13063 f->output_data.x->hourglass_p = 0;
f79e6790 13064 }
6fc2811b 13065 }
6fc2811b 13066
0af913d7 13067 hourglass_shown_p = 0;
f79e6790
JR
13068 UNBLOCK_INPUT;
13069 }
13070#endif
6fc2811b
JR
13071}
13072
13073
13074\f
13075/***********************************************************************
13076 Tool tips
13077 ***********************************************************************/
13078
13079static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13080 Lisp_Object, Lisp_Object));
13081static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13082 Lisp_Object, int, int, int *, int *));
6fc2811b 13083
3cf3436e 13084/* The frame of a currently visible tooltip. */
6fc2811b 13085
937e601e 13086Lisp_Object tip_frame;
6fc2811b
JR
13087
13088/* If non-nil, a timer started that hides the last tooltip when it
13089 fires. */
13090
13091Lisp_Object tip_timer;
13092Window tip_window;
13093
3cf3436e
JR
13094/* If non-nil, a vector of 3 elements containing the last args
13095 with which x-show-tip was called. See there. */
13096
13097Lisp_Object last_show_tip_args;
13098
13099/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13100
13101Lisp_Object Vx_max_tooltip_size;
13102
13103
937e601e
AI
13104static Lisp_Object
13105unwind_create_tip_frame (frame)
13106 Lisp_Object frame;
13107{
c844a81a
GM
13108 Lisp_Object deleted;
13109
13110 deleted = unwind_create_frame (frame);
13111 if (EQ (deleted, Qt))
13112 {
13113 tip_window = NULL;
13114 tip_frame = Qnil;
13115 }
13116
13117 return deleted;
937e601e
AI
13118}
13119
13120
6fc2811b 13121/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13122 PARMS is a list of frame parameters. TEXT is the string to
13123 display in the tip frame. Value is the frame.
937e601e
AI
13124
13125 Note that functions called here, esp. x_default_parameter can
13126 signal errors, for instance when a specified color name is
13127 undefined. We have to make sure that we're in a consistent state
13128 when this happens. */
6fc2811b
JR
13129
13130static Lisp_Object
3cf3436e 13131x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13132 struct w32_display_info *dpyinfo;
3cf3436e 13133 Lisp_Object parms, text;
6fc2811b 13134{
6fc2811b
JR
13135 struct frame *f;
13136 Lisp_Object frame, tem;
13137 Lisp_Object name;
13138 long window_prompting = 0;
13139 int width, height;
dc220243 13140 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13141 struct gcpro gcpro1, gcpro2, gcpro3;
13142 struct kboard *kb;
3cf3436e
JR
13143 int face_change_count_before = face_change_count;
13144 Lisp_Object buffer;
13145 struct buffer *old_buffer;
6fc2811b 13146
ca56d953 13147 check_w32 ();
6fc2811b
JR
13148
13149 /* Use this general default value to start with until we know if
13150 this frame has a specified name. */
13151 Vx_resource_name = Vinvocation_name;
13152
13153#ifdef MULTI_KBOARD
13154 kb = dpyinfo->kboard;
13155#else
13156 kb = &the_only_kboard;
13157#endif
13158
13159 /* Get the name of the frame to use for resource lookup. */
13160 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13161 if (!STRINGP (name)
13162 && !EQ (name, Qunbound)
13163 && !NILP (name))
13164 error ("Invalid frame name--not a string or nil");
13165 Vx_resource_name = name;
13166
13167 frame = Qnil;
13168 GCPRO3 (parms, name, frame);
9eb16b62
JR
13169 /* Make a frame without minibuffer nor mode-line. */
13170 f = make_frame (0);
13171 f->wants_modeline = 0;
6fc2811b 13172 XSETFRAME (frame, f);
3cf3436e
JR
13173
13174 buffer = Fget_buffer_create (build_string (" *tip*"));
13175 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13176 old_buffer = current_buffer;
13177 set_buffer_internal_1 (XBUFFER (buffer));
13178 current_buffer->truncate_lines = Qnil;
13179 Ferase_buffer ();
13180 Finsert (1, &text);
13181 set_buffer_internal_1 (old_buffer);
13182
6fc2811b 13183 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13184 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13185
3cf3436e
JR
13186 /* By setting the output method, we're essentially saying that
13187 the frame is live, as per FRAME_LIVE_P. If we get a signal
13188 from this point on, x_destroy_window might screw up reference
13189 counts etc. */
d88c567c 13190 f->output_method = output_w32;
6fc2811b
JR
13191 f->output_data.w32 =
13192 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13193 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13194
13195 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13196 f->icon_name = Qnil;
13197
ca56d953 13198#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13199 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13200 dpyinfo_refcount = dpyinfo->reference_count;
13201#endif /* GLYPH_DEBUG */
6fc2811b
JR
13202#ifdef MULTI_KBOARD
13203 FRAME_KBOARD (f) = kb;
13204#endif
13205 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13206 f->output_data.w32->explicit_parent = 0;
13207
13208 /* Set the name; the functions to which we pass f expect the name to
13209 be set. */
13210 if (EQ (name, Qunbound) || NILP (name))
13211 {
ca56d953 13212 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13213 f->explicit_name = 0;
13214 }
13215 else
13216 {
13217 f->name = name;
13218 f->explicit_name = 1;
13219 /* use the frame's title when getting resources for this frame. */
13220 specbind (Qx_resource_name, name);
13221 }
13222
6fc2811b
JR
13223 /* Extract the window parameters from the supplied values
13224 that are needed to determine window geometry. */
13225 {
13226 Lisp_Object font;
13227
13228 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13229
13230 BLOCK_INPUT;
13231 /* First, try whatever font the caller has specified. */
13232 if (STRINGP (font))
13233 {
13234 tem = Fquery_fontset (font, Qnil);
13235 if (STRINGP (tem))
13236 font = x_new_fontset (f, XSTRING (tem)->data);
13237 else
13238 font = x_new_font (f, XSTRING (font)->data);
13239 }
13240
13241 /* Try out a font which we hope has bold and italic variations. */
13242 if (!STRINGP (font))
ca56d953 13243 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13244 if (! STRINGP (font))
ca56d953 13245 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13246 /* If those didn't work, look for something which will at least work. */
13247 if (! STRINGP (font))
ca56d953 13248 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13249 UNBLOCK_INPUT;
13250 if (! STRINGP (font))
ca56d953 13251 font = build_string ("Fixedsys");
6fc2811b
JR
13252
13253 x_default_parameter (f, parms, Qfont, font,
13254 "font", "Font", RES_TYPE_STRING);
13255 }
13256
13257 x_default_parameter (f, parms, Qborder_width, make_number (2),
13258 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13259 /* This defaults to 2 in order to match xterm. We recognize either
13260 internalBorderWidth or internalBorder (which is what xterm calls
13261 it). */
13262 if (NILP (Fassq (Qinternal_border_width, parms)))
13263 {
13264 Lisp_Object value;
13265
13266 value = w32_get_arg (parms, Qinternal_border_width,
13267 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13268 if (! EQ (value, Qunbound))
13269 parms = Fcons (Fcons (Qinternal_border_width, value),
13270 parms);
13271 }
bfd6edcc 13272 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13273 "internalBorderWidth", "internalBorderWidth",
13274 RES_TYPE_NUMBER);
13275
13276 /* Also do the stuff which must be set before the window exists. */
13277 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13278 "foreground", "Foreground", RES_TYPE_STRING);
13279 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13280 "background", "Background", RES_TYPE_STRING);
13281 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13282 "pointerColor", "Foreground", RES_TYPE_STRING);
13283 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13284 "cursorColor", "Foreground", RES_TYPE_STRING);
13285 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13286 "borderColor", "BorderColor", RES_TYPE_STRING);
13287
13288 /* Init faces before x_default_parameter is called for scroll-bar
13289 parameters because that function calls x_set_scroll_bar_width,
13290 which calls change_frame_size, which calls Fset_window_buffer,
13291 which runs hooks, which call Fvertical_motion. At the end, we
13292 end up in init_iterator with a null face cache, which should not
13293 happen. */
13294 init_frame_faces (f);
ca56d953
JR
13295
13296 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13297 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13298
6fc2811b
JR
13299 window_prompting = x_figure_window_size (f, parms);
13300
9eb16b62
JR
13301 /* No fringes on tip frame. */
13302 f->output_data.w32->fringes_extra = 0;
13303 f->output_data.w32->fringe_cols = 0;
13304 f->output_data.w32->left_fringe_width = 0;
13305 f->output_data.w32->right_fringe_width = 0;
13306
6fc2811b
JR
13307 if (window_prompting & XNegative)
13308 {
13309 if (window_prompting & YNegative)
13310 f->output_data.w32->win_gravity = SouthEastGravity;
13311 else
13312 f->output_data.w32->win_gravity = NorthEastGravity;
13313 }
13314 else
13315 {
13316 if (window_prompting & YNegative)
13317 f->output_data.w32->win_gravity = SouthWestGravity;
13318 else
13319 f->output_data.w32->win_gravity = NorthWestGravity;
13320 }
13321
13322 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13323
13324 BLOCK_INPUT;
13325 my_create_tip_window (f);
13326 UNBLOCK_INPUT;
6fc2811b
JR
13327
13328 x_make_gc (f);
13329
13330 x_default_parameter (f, parms, Qauto_raise, Qnil,
13331 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13332 x_default_parameter (f, parms, Qauto_lower, Qnil,
13333 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13334 x_default_parameter (f, parms, Qcursor_type, Qbox,
13335 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13336
13337 /* Dimensions, especially f->height, must be done via change_frame_size.
13338 Change will not be effected unless different from the current
13339 f->height. */
13340 width = f->width;
13341 height = f->height;
13342 f->height = 0;
13343 SET_FRAME_WIDTH (f, 0);
13344 change_frame_size (f, height, width, 1, 0, 0);
13345
3cf3436e
JR
13346 /* Set up faces after all frame parameters are known. This call
13347 also merges in face attributes specified for new frames.
13348
13349 Frame parameters may be changed if .Xdefaults contains
13350 specifications for the default font. For example, if there is an
13351 `Emacs.default.attributeBackground: pink', the `background-color'
13352 attribute of the frame get's set, which let's the internal border
13353 of the tooltip frame appear in pink. Prevent this. */
13354 {
13355 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13356
13357 /* Set tip_frame here, so that */
13358 tip_frame = frame;
13359 call1 (Qface_set_after_frame_default, frame);
13360
13361 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13362 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13363 Qnil));
13364 }
13365
6fc2811b
JR
13366 f->no_split = 1;
13367
13368 UNGCPRO;
13369
13370 /* It is now ok to make the frame official even if we get an error
13371 below. And the frame needs to be on Vframe_list or making it
13372 visible won't work. */
13373 Vframe_list = Fcons (frame, Vframe_list);
13374
13375 /* Now that the frame is official, it counts as a reference to
13376 its display. */
13377 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13378
3cf3436e
JR
13379 /* Setting attributes of faces of the tooltip frame from resources
13380 and similar will increment face_change_count, which leads to the
13381 clearing of all current matrices. Since this isn't necessary
13382 here, avoid it by resetting face_change_count to the value it
13383 had before we created the tip frame. */
13384 face_change_count = face_change_count_before;
13385
13386 /* Discard the unwind_protect. */
6fc2811b 13387 return unbind_to (count, frame);
ee78dc32
GV
13388}
13389
3cf3436e
JR
13390
13391/* Compute where to display tip frame F. PARMS is the list of frame
13392 parameters for F. DX and DY are specified offsets from the current
13393 location of the mouse. WIDTH and HEIGHT are the width and height
13394 of the tooltip. Return coordinates relative to the root window of
13395 the display in *ROOT_X, and *ROOT_Y. */
13396
13397static void
13398compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13399 struct frame *f;
13400 Lisp_Object parms, dx, dy;
13401 int width, height;
13402 int *root_x, *root_y;
13403{
3cf3436e 13404 Lisp_Object left, top;
3cf3436e
JR
13405
13406 /* User-specified position? */
13407 left = Fcdr (Fassq (Qleft, parms));
13408 top = Fcdr (Fassq (Qtop, parms));
13409
13410 /* Move the tooltip window where the mouse pointer is. Resize and
13411 show it. */
ca56d953 13412 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13413 {
ca56d953
JR
13414 POINT pt;
13415
3cf3436e 13416 BLOCK_INPUT;
ca56d953
JR
13417 GetCursorPos (&pt);
13418 *root_x = pt.x;
13419 *root_y = pt.y;
3cf3436e
JR
13420 UNBLOCK_INPUT;
13421 }
13422
13423 if (INTEGERP (top))
13424 *root_y = XINT (top);
13425 else if (*root_y + XINT (dy) - height < 0)
13426 *root_y -= XINT (dy);
13427 else
13428 {
13429 *root_y -= height;
13430 *root_y += XINT (dy);
13431 }
13432
13433 if (INTEGERP (left))
13434 *root_x = XINT (left);
bfd6edcc 13435 else if (*root_x + XINT (dx) + width > FRAME_W32_DISPLAY_INFO (f)->width)
3cf3436e
JR
13436 *root_x -= width + XINT (dx);
13437 else
13438 *root_x += XINT (dx);
3cf3436e
JR
13439}
13440
13441
71eab8d1 13442DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13443 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13444A tooltip window is a small window displaying a string.
13445
13446FRAME nil or omitted means use the selected frame.
13447
13448PARMS is an optional list of frame parameters which can be
13449used to change the tooltip's appearance.
13450
ca56d953
JR
13451Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13452means use the default timeout of 5 seconds.
74e1aeec 13453
ca56d953 13454If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13455the tooltip is displayed at that x-position. Otherwise it is
13456displayed at the mouse position, with offset DX added (default is 5 if
13457DX isn't specified). Likewise for the y-position; if a `top' frame
13458parameter is specified, it determines the y-position of the tooltip
13459window, otherwise it is displayed at the mouse position, with offset
13460DY added (default is -10).
13461
13462A tooltip's maximum size is specified by `x-max-tooltip-size'.
13463Text larger than the specified size is clipped. */)
71eab8d1
AI
13464 (string, frame, parms, timeout, dx, dy)
13465 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13466{
6fc2811b
JR
13467 struct frame *f;
13468 struct window *w;
3cf3436e 13469 int root_x, root_y;
6fc2811b
JR
13470 struct buffer *old_buffer;
13471 struct text_pos pos;
13472 int i, width, height;
6fc2811b
JR
13473 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13474 int old_windows_or_buffers_changed = windows_or_buffers_changed;
ca56d953 13475 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13476
13477 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13478
dfff8a69 13479 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13480
b7826503 13481 CHECK_STRING (string);
6fc2811b
JR
13482 f = check_x_frame (frame);
13483 if (NILP (timeout))
13484 timeout = make_number (5);
13485 else
b7826503 13486 CHECK_NATNUM (timeout);
ee78dc32 13487
71eab8d1
AI
13488 if (NILP (dx))
13489 dx = make_number (5);
13490 else
b7826503 13491 CHECK_NUMBER (dx);
71eab8d1
AI
13492
13493 if (NILP (dy))
dc220243 13494 dy = make_number (-10);
71eab8d1 13495 else
b7826503 13496 CHECK_NUMBER (dy);
71eab8d1 13497
dc220243
JR
13498 if (NILP (last_show_tip_args))
13499 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13500
13501 if (!NILP (tip_frame))
13502 {
13503 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13504 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13505 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13506
13507 if (EQ (frame, last_frame)
13508 && !NILP (Fequal (last_string, string))
13509 && !NILP (Fequal (last_parms, parms)))
13510 {
13511 struct frame *f = XFRAME (tip_frame);
13512
13513 /* Only DX and DY have changed. */
13514 if (!NILP (tip_timer))
13515 {
13516 Lisp_Object timer = tip_timer;
13517 tip_timer = Qnil;
13518 call1 (Qcancel_timer, timer);
13519 }
13520
13521 BLOCK_INPUT;
ca56d953
JR
13522 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13523 PIXEL_HEIGHT (f), &root_x, &root_y);
13524 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13525 root_x, root_y, 0, 0,
13526 SWP_NOSIZE | SWP_NOACTIVATE);
dc220243
JR
13527 UNBLOCK_INPUT;
13528 goto start_timer;
13529 }
13530 }
13531
6fc2811b
JR
13532 /* Hide a previous tip, if any. */
13533 Fx_hide_tip ();
ee78dc32 13534
dc220243
JR
13535 ASET (last_show_tip_args, 0, string);
13536 ASET (last_show_tip_args, 1, frame);
13537 ASET (last_show_tip_args, 2, parms);
13538
6fc2811b
JR
13539 /* Add default values to frame parameters. */
13540 if (NILP (Fassq (Qname, parms)))
13541 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13542 if (NILP (Fassq (Qinternal_border_width, parms)))
13543 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13544 if (NILP (Fassq (Qborder_width, parms)))
13545 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13546 if (NILP (Fassq (Qborder_color, parms)))
13547 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13548 if (NILP (Fassq (Qbackground_color, parms)))
13549 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13550 parms);
13551
0e3fcdef
JR
13552 /* Block input until the tip has been fully drawn, to avoid crashes
13553 when drawing tips in menus. */
13554 BLOCK_INPUT;
13555
6fc2811b
JR
13556 /* Create a frame for the tooltip, and record it in the global
13557 variable tip_frame. */
ca56d953 13558 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 13559 f = XFRAME (frame);
6fc2811b 13560
3cf3436e 13561 /* Set up the frame's root window. */
6fc2811b
JR
13562 w = XWINDOW (FRAME_ROOT_WINDOW (f));
13563 w->left = w->top = make_number (0);
3cf3436e
JR
13564
13565 if (CONSP (Vx_max_tooltip_size)
13566 && INTEGERP (XCAR (Vx_max_tooltip_size))
13567 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13568 && INTEGERP (XCDR (Vx_max_tooltip_size))
13569 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13570 {
13571 w->width = XCAR (Vx_max_tooltip_size);
13572 w->height = XCDR (Vx_max_tooltip_size);
13573 }
13574 else
13575 {
13576 w->width = make_number (80);
13577 w->height = make_number (40);
13578 }
13579
13580 f->window_width = XINT (w->width);
6fc2811b
JR
13581 adjust_glyphs (f);
13582 w->pseudo_window_p = 1;
13583
13584 /* Display the tooltip text in a temporary buffer. */
6fc2811b 13585 old_buffer = current_buffer;
3cf3436e
JR
13586 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13587 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
13588 clear_glyph_matrix (w->desired_matrix);
13589 clear_glyph_matrix (w->current_matrix);
13590 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13591 try_window (FRAME_ROOT_WINDOW (f), pos);
13592
13593 /* Compute width and height of the tooltip. */
13594 width = height = 0;
13595 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 13596 {
6fc2811b
JR
13597 struct glyph_row *row = &w->desired_matrix->rows[i];
13598 struct glyph *last;
13599 int row_width;
13600
13601 /* Stop at the first empty row at the end. */
13602 if (!row->enabled_p || !row->displays_text_p)
13603 break;
13604
13605 /* Let the row go over the full width of the frame. */
13606 row->full_width_p = 1;
13607
4e3a1c61
JR
13608#ifdef TODO /* Investigate why some fonts need more width than is
13609 calculated for some tooltips. */
6fc2811b
JR
13610 /* There's a glyph at the end of rows that is use to place
13611 the cursor there. Don't include the width of this glyph. */
13612 if (row->used[TEXT_AREA])
13613 {
13614 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13615 row_width = row->pixel_width - last->pixel_width;
13616 }
13617 else
4e3a1c61 13618#endif
6fc2811b
JR
13619 row_width = row->pixel_width;
13620
ca56d953 13621 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 13622 height += row->height;
6fc2811b 13623 width = max (width, row_width);
ee78dc32
GV
13624 }
13625
6fc2811b
JR
13626 /* Add the frame's internal border to the width and height the X
13627 window should have. */
13628 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13629 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 13630
6fc2811b
JR
13631 /* Move the tooltip window where the mouse pointer is. Resize and
13632 show it. */
3cf3436e 13633 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 13634
bfd6edcc
JR
13635 {
13636 /* Adjust Window size to take border into account. */
13637 RECT rect;
13638 rect.left = rect.top = 0;
13639 rect.right = width;
13640 rect.bottom = height;
13641 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
13642 FRAME_EXTERNAL_MENU_BAR (f));
13643
13644 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13645 root_x, root_y, rect.right - rect.left,
13646 rect.bottom - rect.top, SWP_NOACTIVATE);
13647
13648 /* Let redisplay know that we have made the frame visible already. */
13649 f->async_visible = 1;
13650
13651 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
13652 }
ee78dc32 13653
6fc2811b
JR
13654 /* Draw into the window. */
13655 w->must_be_updated_p = 1;
13656 update_single_window (w, 1);
ee78dc32 13657
0e3fcdef
JR
13658 UNBLOCK_INPUT;
13659
6fc2811b
JR
13660 /* Restore original current buffer. */
13661 set_buffer_internal_1 (old_buffer);
13662 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 13663
dc220243 13664 start_timer:
6fc2811b
JR
13665 /* Let the tip disappear after timeout seconds. */
13666 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13667 intern ("x-hide-tip"));
ee78dc32 13668
dfff8a69 13669 UNGCPRO;
6fc2811b 13670 return unbind_to (count, Qnil);
ee78dc32
GV
13671}
13672
ee78dc32 13673
6fc2811b 13674DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
13675 doc: /* Hide the current tooltip window, if there is any.
13676Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
13677 ()
13678{
937e601e
AI
13679 int count;
13680 Lisp_Object deleted, frame, timer;
13681 struct gcpro gcpro1, gcpro2;
13682
13683 /* Return quickly if nothing to do. */
13684 if (NILP (tip_timer) && NILP (tip_frame))
13685 return Qnil;
13686
13687 frame = tip_frame;
13688 timer = tip_timer;
13689 GCPRO2 (frame, timer);
13690 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 13691
937e601e 13692 count = BINDING_STACK_SIZE ();
6fc2811b 13693 specbind (Qinhibit_redisplay, Qt);
937e601e 13694 specbind (Qinhibit_quit, Qt);
6fc2811b 13695
937e601e 13696 if (!NILP (timer))
dc220243 13697 call1 (Qcancel_timer, timer);
ee78dc32 13698
937e601e 13699 if (FRAMEP (frame))
6fc2811b 13700 {
937e601e
AI
13701 Fdelete_frame (frame, Qnil);
13702 deleted = Qt;
6fc2811b 13703 }
1edf84e7 13704
937e601e
AI
13705 UNGCPRO;
13706 return unbind_to (count, deleted);
6fc2811b 13707}
5ac45f98 13708
5ac45f98 13709
6fc2811b
JR
13710\f
13711/***********************************************************************
13712 File selection dialog
13713 ***********************************************************************/
13714
13715extern Lisp_Object Qfile_name_history;
13716
13717DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
13718 doc: /* Read file name, prompting with PROMPT in directory DIR.
13719Use a file selection dialog.
13720Select DEFAULT-FILENAME in the dialog's file selection box, if
13721specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
13722 (prompt, dir, default_filename, mustmatch)
13723 Lisp_Object prompt, dir, default_filename, mustmatch;
13724{
13725 struct frame *f = SELECTED_FRAME ();
13726 Lisp_Object file = Qnil;
13727 int count = specpdl_ptr - specpdl;
13728 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
13729 char filename[MAX_PATH + 1];
13730 char init_dir[MAX_PATH + 1];
13731 int use_dialog_p = 1;
13732
13733 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
13734 CHECK_STRING (prompt);
13735 CHECK_STRING (dir);
6fc2811b
JR
13736
13737 /* Create the dialog with PROMPT as title, using DIR as initial
13738 directory and using "*" as pattern. */
13739 dir = Fexpand_file_name (dir, Qnil);
13740 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
13741 init_dir[MAX_PATH] = '\0';
13742 unixtodos_filename (init_dir);
13743
13744 if (STRINGP (default_filename))
13745 {
13746 char *file_name_only;
13747 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 13748
6fc2811b 13749 unixtodos_filename (full_path_name);
5ac45f98 13750
6fc2811b
JR
13751 file_name_only = strrchr (full_path_name, '\\');
13752 if (!file_name_only)
13753 file_name_only = full_path_name;
13754 else
13755 {
13756 file_name_only++;
5ac45f98 13757
6fc2811b
JR
13758 /* If default_file_name is a directory, don't use the open
13759 file dialog, as it does not support selecting
13760 directories. */
13761 if (!(*file_name_only))
13762 use_dialog_p = 0;
13763 }
ee78dc32 13764
6fc2811b
JR
13765 strncpy (filename, file_name_only, MAX_PATH);
13766 filename[MAX_PATH] = '\0';
13767 }
ee78dc32 13768 else
6fc2811b 13769 filename[0] = '\0';
ee78dc32 13770
6fc2811b
JR
13771 if (use_dialog_p)
13772 {
13773 OPENFILENAME file_details;
5ac45f98 13774
6fc2811b
JR
13775 /* Prevent redisplay. */
13776 specbind (Qinhibit_redisplay, Qt);
13777 BLOCK_INPUT;
ee78dc32 13778
6fc2811b
JR
13779 bzero (&file_details, sizeof (file_details));
13780 file_details.lStructSize = sizeof (file_details);
13781 file_details.hwndOwner = FRAME_W32_WINDOW (f);
3cf3436e
JR
13782 /* Undocumented Bug in Common File Dialog:
13783 If a filter is not specified, shell links are not resolved. */
13784 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
6fc2811b
JR
13785 file_details.lpstrFile = filename;
13786 file_details.nMaxFile = sizeof (filename);
13787 file_details.lpstrInitialDir = init_dir;
13788 file_details.lpstrTitle = XSTRING (prompt)->data;
13789 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 13790
6fc2811b
JR
13791 if (!NILP (mustmatch))
13792 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 13793
6fc2811b
JR
13794 if (GetOpenFileName (&file_details))
13795 {
13796 dostounix_filename (filename);
13797 file = build_string (filename);
13798 }
ee78dc32 13799 else
6fc2811b
JR
13800 file = Qnil;
13801
13802 UNBLOCK_INPUT;
13803 file = unbind_to (count, file);
ee78dc32 13804 }
6fc2811b
JR
13805 /* Open File dialog will not allow folders to be selected, so resort
13806 to minibuffer completing reads for directories. */
13807 else
13808 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
13809 dir, mustmatch, dir, Qfile_name_history,
13810 default_filename, Qnil);
ee78dc32 13811
6fc2811b 13812 UNGCPRO;
1edf84e7 13813
6fc2811b
JR
13814 /* Make "Cancel" equivalent to C-g. */
13815 if (NILP (file))
13816 Fsignal (Qquit, Qnil);
ee78dc32 13817
dfff8a69 13818 return unbind_to (count, file);
6fc2811b 13819}
ee78dc32 13820
ee78dc32 13821
6fc2811b 13822\f
6fc2811b
JR
13823/***********************************************************************
13824 w32 specialized functions
13825 ***********************************************************************/
ee78dc32 13826
fbd6baed 13827DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
74e1aeec
JR
13828 doc: /* Select a font using the W32 font dialog.
13829Returns an X font string corresponding to the selection. */)
ee78dc32
GV
13830 (frame)
13831 Lisp_Object frame;
13832{
13833 FRAME_PTR f = check_x_frame (frame);
13834 CHOOSEFONT cf;
13835 LOGFONT lf;
f46e6225
GV
13836 TEXTMETRIC tm;
13837 HDC hdc;
13838 HANDLE oldobj;
ee78dc32
GV
13839 char buf[100];
13840
13841 bzero (&cf, sizeof (cf));
f46e6225 13842 bzero (&lf, sizeof (lf));
ee78dc32
GV
13843
13844 cf.lStructSize = sizeof (cf);
fbd6baed 13845 cf.hwndOwner = FRAME_W32_WINDOW (f);
6fc2811b 13846 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
ee78dc32
GV
13847 cf.lpLogFont = &lf;
13848
f46e6225
GV
13849 /* Initialize as much of the font details as we can from the current
13850 default font. */
13851 hdc = GetDC (FRAME_W32_WINDOW (f));
13852 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
13853 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
13854 if (GetTextMetrics (hdc, &tm))
13855 {
13856 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
13857 lf.lfWeight = tm.tmWeight;
13858 lf.lfItalic = tm.tmItalic;
13859 lf.lfUnderline = tm.tmUnderlined;
13860 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
13861 lf.lfCharSet = tm.tmCharSet;
13862 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
13863 }
13864 SelectObject (hdc, oldobj);
6fc2811b 13865 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 13866
767b1ff0 13867 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 13868 return Qnil;
ee78dc32
GV
13869
13870 return build_string (buf);
13871}
13872
74e1aeec
JR
13873DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
13874 Sw32_send_sys_command, 1, 2, 0,
13875 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
13876Some useful values for command are 0xf030 to maximise frame (0xf020
13877to minimize), 0xf120 to restore frame to original size, and 0xf100
13878to activate the menubar for keyboard access. 0xf140 activates the
13879screen saver if defined.
13880
13881If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
13882 (command, frame)
13883 Lisp_Object command, frame;
13884{
1edf84e7
GV
13885 FRAME_PTR f = check_x_frame (frame);
13886
b7826503 13887 CHECK_NUMBER (command);
1edf84e7 13888
ce6059da 13889 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
13890
13891 return Qnil;
13892}
13893
55dcfc15 13894DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
13895 doc: /* Get Windows to perform OPERATION on DOCUMENT.
13896This is a wrapper around the ShellExecute system function, which
13897invokes the application registered to handle OPERATION for DOCUMENT.
13898OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
13899nil for the default action), and DOCUMENT is typically the name of a
13900document file or URL, but can also be a program executable to run or
13901a directory to open in the Windows Explorer.
13902
13903If DOCUMENT is a program executable, PARAMETERS can be a string
13904containing command line parameters, but otherwise should be nil.
13905
13906SHOW-FLAG can be used to control whether the invoked application is hidden
13907or minimized. If SHOW-FLAG is nil, the application is displayed normally,
13908otherwise it is an integer representing a ShowWindow flag:
13909
13910 0 - start hidden
13911 1 - start normally
13912 3 - start maximized
13913 6 - start minimized */)
55dcfc15
AI
13914 (operation, document, parameters, show_flag)
13915 Lisp_Object operation, document, parameters, show_flag;
13916{
13917 Lisp_Object current_dir;
13918
b7826503 13919 CHECK_STRING (document);
55dcfc15
AI
13920
13921 /* Encode filename and current directory. */
13922 current_dir = ENCODE_FILE (current_buffer->directory);
13923 document = ENCODE_FILE (document);
13924 if ((int) ShellExecute (NULL,
6fc2811b
JR
13925 (STRINGP (operation) ?
13926 XSTRING (operation)->data : NULL),
55dcfc15
AI
13927 XSTRING (document)->data,
13928 (STRINGP (parameters) ?
13929 XSTRING (parameters)->data : NULL),
13930 XSTRING (current_dir)->data,
13931 (INTEGERP (show_flag) ?
13932 XINT (show_flag) : SW_SHOWDEFAULT))
13933 > 32)
13934 return Qt;
90d97e64 13935 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
13936}
13937
ccc2d29c
GV
13938/* Lookup virtual keycode from string representing the name of a
13939 non-ascii keystroke into the corresponding virtual key, using
13940 lispy_function_keys. */
13941static int
13942lookup_vk_code (char *key)
13943{
13944 int i;
13945
13946 for (i = 0; i < 256; i++)
13947 if (lispy_function_keys[i] != 0
13948 && strcmp (lispy_function_keys[i], key) == 0)
13949 return i;
13950
13951 return -1;
13952}
13953
13954/* Convert a one-element vector style key sequence to a hot key
13955 definition. */
13956static int
13957w32_parse_hot_key (key)
13958 Lisp_Object key;
13959{
13960 /* Copied from Fdefine_key and store_in_keymap. */
13961 register Lisp_Object c;
13962 int vk_code;
13963 int lisp_modifiers;
13964 int w32_modifiers;
13965 struct gcpro gcpro1;
13966
b7826503 13967 CHECK_VECTOR (key);
ccc2d29c
GV
13968
13969 if (XFASTINT (Flength (key)) != 1)
13970 return Qnil;
13971
13972 GCPRO1 (key);
13973
13974 c = Faref (key, make_number (0));
13975
13976 if (CONSP (c) && lucid_event_type_list_p (c))
13977 c = Fevent_convert_list (c);
13978
13979 UNGCPRO;
13980
13981 if (! INTEGERP (c) && ! SYMBOLP (c))
13982 error ("Key definition is invalid");
13983
13984 /* Work out the base key and the modifiers. */
13985 if (SYMBOLP (c))
13986 {
13987 c = parse_modifiers (c);
13988 lisp_modifiers = Fcar (Fcdr (c));
13989 c = Fcar (c);
13990 if (!SYMBOLP (c))
13991 abort ();
13992 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
13993 }
13994 else if (INTEGERP (c))
13995 {
13996 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13997 /* Many ascii characters are their own virtual key code. */
13998 vk_code = XINT (c) & CHARACTERBITS;
13999 }
14000
14001 if (vk_code < 0 || vk_code > 255)
14002 return Qnil;
14003
14004 if ((lisp_modifiers & meta_modifier) != 0
14005 && !NILP (Vw32_alt_is_meta))
14006 lisp_modifiers |= alt_modifier;
14007
71eab8d1
AI
14008 /* Supply defs missing from mingw32. */
14009#ifndef MOD_ALT
14010#define MOD_ALT 0x0001
14011#define MOD_CONTROL 0x0002
14012#define MOD_SHIFT 0x0004
14013#define MOD_WIN 0x0008
14014#endif
14015
ccc2d29c
GV
14016 /* Convert lisp modifiers to Windows hot-key form. */
14017 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14018 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14019 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14020 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14021
14022 return HOTKEY (vk_code, w32_modifiers);
14023}
14024
74e1aeec
JR
14025DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14026 Sw32_register_hot_key, 1, 1, 0,
14027 doc: /* Register KEY as a hot-key combination.
14028Certain key combinations like Alt-Tab are reserved for system use on
14029Windows, and therefore are normally intercepted by the system. However,
14030most of these key combinations can be received by registering them as
14031hot-keys, overriding their special meaning.
14032
14033KEY must be a one element key definition in vector form that would be
14034acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14035modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14036is always interpreted as the Windows modifier keys.
14037
14038The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14039 (key)
14040 Lisp_Object key;
14041{
14042 key = w32_parse_hot_key (key);
14043
14044 if (NILP (Fmemq (key, w32_grabbed_keys)))
14045 {
14046 /* Reuse an empty slot if possible. */
14047 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14048
14049 /* Safe to add new key to list, even if we have focus. */
14050 if (NILP (item))
14051 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14052 else
f3fbd155 14053 XSETCAR (item, key);
ccc2d29c
GV
14054
14055 /* Notify input thread about new hot-key definition, so that it
14056 takes effect without needing to switch focus. */
14057 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14058 (WPARAM) key, 0);
14059 }
14060
14061 return key;
14062}
14063
74e1aeec
JR
14064DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14065 Sw32_unregister_hot_key, 1, 1, 0,
14066 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14067 (key)
14068 Lisp_Object key;
14069{
14070 Lisp_Object item;
14071
14072 if (!INTEGERP (key))
14073 key = w32_parse_hot_key (key);
14074
14075 item = Fmemq (key, w32_grabbed_keys);
14076
14077 if (!NILP (item))
14078 {
14079 /* Notify input thread about hot-key definition being removed, so
14080 that it takes effect without needing focus switch. */
14081 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14082 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14083 {
14084 MSG msg;
14085 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14086 }
14087 return Qt;
14088 }
14089 return Qnil;
14090}
14091
74e1aeec
JR
14092DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14093 Sw32_registered_hot_keys, 0, 0, 0,
14094 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14095 ()
14096{
14097 return Fcopy_sequence (w32_grabbed_keys);
14098}
14099
74e1aeec
JR
14100DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14101 Sw32_reconstruct_hot_key, 1, 1, 0,
14102 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14103 (hotkeyid)
14104 Lisp_Object hotkeyid;
14105{
14106 int vk_code, w32_modifiers;
14107 Lisp_Object key;
14108
b7826503 14109 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14110
14111 vk_code = HOTKEY_VK_CODE (hotkeyid);
14112 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14113
14114 if (lispy_function_keys[vk_code])
14115 key = intern (lispy_function_keys[vk_code]);
14116 else
14117 key = make_number (vk_code);
14118
14119 key = Fcons (key, Qnil);
14120 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14121 key = Fcons (Qshift, key);
ccc2d29c 14122 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14123 key = Fcons (Qctrl, key);
ccc2d29c 14124 if (w32_modifiers & MOD_ALT)
3ef68e6b 14125 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14126 if (w32_modifiers & MOD_WIN)
3ef68e6b 14127 key = Fcons (Qhyper, key);
ccc2d29c
GV
14128
14129 return key;
14130}
adcc3809 14131
74e1aeec
JR
14132DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14133 Sw32_toggle_lock_key, 1, 2, 0,
14134 doc: /* Toggle the state of the lock key KEY.
14135KEY can be `capslock', `kp-numlock', or `scroll'.
14136If the optional parameter NEW-STATE is a number, then the state of KEY
14137is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14138 (key, new_state)
14139 Lisp_Object key, new_state;
14140{
14141 int vk_code;
adcc3809
GV
14142
14143 if (EQ (key, intern ("capslock")))
14144 vk_code = VK_CAPITAL;
14145 else if (EQ (key, intern ("kp-numlock")))
14146 vk_code = VK_NUMLOCK;
14147 else if (EQ (key, intern ("scroll")))
14148 vk_code = VK_SCROLL;
14149 else
14150 return Qnil;
14151
14152 if (!dwWindowsThreadId)
14153 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14154
14155 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14156 (WPARAM) vk_code, (LPARAM) new_state))
14157 {
14158 MSG msg;
14159 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14160 return make_number (msg.wParam);
14161 }
14162 return Qnil;
14163}
ee78dc32 14164\f
2254bcde 14165DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14166 doc: /* Return storage information about the file system FILENAME is on.
14167Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14168storage of the file system, FREE is the free storage, and AVAIL is the
14169storage available to a non-superuser. All 3 numbers are in bytes.
14170If the underlying system call fails, value is nil. */)
2254bcde
AI
14171 (filename)
14172 Lisp_Object filename;
14173{
14174 Lisp_Object encoded, value;
14175
b7826503 14176 CHECK_STRING (filename);
2254bcde
AI
14177 filename = Fexpand_file_name (filename, Qnil);
14178 encoded = ENCODE_FILE (filename);
14179
14180 value = Qnil;
14181
14182 /* Determining the required information on Windows turns out, sadly,
14183 to be more involved than one would hope. The original Win32 api
14184 call for this will return bogus information on some systems, but we
14185 must dynamically probe for the replacement api, since that was
14186 added rather late on. */
14187 {
14188 HMODULE hKernel = GetModuleHandle ("kernel32");
14189 BOOL (*pfn_GetDiskFreeSpaceEx)
14190 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14191 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14192
14193 /* On Windows, we may need to specify the root directory of the
14194 volume holding FILENAME. */
14195 char rootname[MAX_PATH];
14196 char *name = XSTRING (encoded)->data;
14197
14198 /* find the root name of the volume if given */
14199 if (isalpha (name[0]) && name[1] == ':')
14200 {
14201 rootname[0] = name[0];
14202 rootname[1] = name[1];
14203 rootname[2] = '\\';
14204 rootname[3] = 0;
14205 }
14206 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14207 {
14208 char *str = rootname;
14209 int slashes = 4;
14210 do
14211 {
14212 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14213 break;
14214 *str++ = *name++;
14215 }
14216 while ( *name );
14217
14218 *str++ = '\\';
14219 *str = 0;
14220 }
14221
14222 if (pfn_GetDiskFreeSpaceEx)
14223 {
14224 LARGE_INTEGER availbytes;
14225 LARGE_INTEGER freebytes;
14226 LARGE_INTEGER totalbytes;
14227
14228 if (pfn_GetDiskFreeSpaceEx(rootname,
14229 &availbytes,
14230 &totalbytes,
14231 &freebytes))
14232 value = list3 (make_float ((double) totalbytes.QuadPart),
14233 make_float ((double) freebytes.QuadPart),
14234 make_float ((double) availbytes.QuadPart));
14235 }
14236 else
14237 {
14238 DWORD sectors_per_cluster;
14239 DWORD bytes_per_sector;
14240 DWORD free_clusters;
14241 DWORD total_clusters;
14242
14243 if (GetDiskFreeSpace(rootname,
14244 &sectors_per_cluster,
14245 &bytes_per_sector,
14246 &free_clusters,
14247 &total_clusters))
14248 value = list3 (make_float ((double) total_clusters
14249 * sectors_per_cluster * bytes_per_sector),
14250 make_float ((double) free_clusters
14251 * sectors_per_cluster * bytes_per_sector),
14252 make_float ((double) free_clusters
14253 * sectors_per_cluster * bytes_per_sector));
14254 }
14255 }
14256
14257 return value;
14258}
14259\f
0e3fcdef
JR
14260/***********************************************************************
14261 Initialization
14262 ***********************************************************************/
14263
14264void
fbd6baed 14265syms_of_w32fns ()
ee78dc32 14266{
9eb16b62
JR
14267 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14268
1edf84e7
GV
14269 /* This is zero if not using MS-Windows. */
14270 w32_in_use = 0;
14271
9eb16b62
JR
14272 /* TrackMouseEvent not available in all versions of Windows, so must load
14273 it dynamically. Do it once, here, instead of every time it is used. */
14274 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14275 track_mouse_window = NULL;
14276
ee78dc32
GV
14277 /* The section below is built by the lisp expression at the top of the file,
14278 just above where these variables are declared. */
14279 /*&&& init symbols here &&&*/
14280 Qauto_raise = intern ("auto-raise");
14281 staticpro (&Qauto_raise);
14282 Qauto_lower = intern ("auto-lower");
14283 staticpro (&Qauto_lower);
ee78dc32
GV
14284 Qbar = intern ("bar");
14285 staticpro (&Qbar);
14286 Qborder_color = intern ("border-color");
14287 staticpro (&Qborder_color);
14288 Qborder_width = intern ("border-width");
14289 staticpro (&Qborder_width);
14290 Qbox = intern ("box");
14291 staticpro (&Qbox);
14292 Qcursor_color = intern ("cursor-color");
14293 staticpro (&Qcursor_color);
14294 Qcursor_type = intern ("cursor-type");
14295 staticpro (&Qcursor_type);
ee78dc32
GV
14296 Qgeometry = intern ("geometry");
14297 staticpro (&Qgeometry);
14298 Qicon_left = intern ("icon-left");
14299 staticpro (&Qicon_left);
14300 Qicon_top = intern ("icon-top");
14301 staticpro (&Qicon_top);
14302 Qicon_type = intern ("icon-type");
14303 staticpro (&Qicon_type);
14304 Qicon_name = intern ("icon-name");
14305 staticpro (&Qicon_name);
14306 Qinternal_border_width = intern ("internal-border-width");
14307 staticpro (&Qinternal_border_width);
14308 Qleft = intern ("left");
14309 staticpro (&Qleft);
1026b400
RS
14310 Qright = intern ("right");
14311 staticpro (&Qright);
ee78dc32
GV
14312 Qmouse_color = intern ("mouse-color");
14313 staticpro (&Qmouse_color);
14314 Qnone = intern ("none");
14315 staticpro (&Qnone);
14316 Qparent_id = intern ("parent-id");
14317 staticpro (&Qparent_id);
14318 Qscroll_bar_width = intern ("scroll-bar-width");
14319 staticpro (&Qscroll_bar_width);
14320 Qsuppress_icon = intern ("suppress-icon");
14321 staticpro (&Qsuppress_icon);
ee78dc32
GV
14322 Qundefined_color = intern ("undefined-color");
14323 staticpro (&Qundefined_color);
14324 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14325 staticpro (&Qvertical_scroll_bars);
14326 Qvisibility = intern ("visibility");
14327 staticpro (&Qvisibility);
14328 Qwindow_id = intern ("window-id");
14329 staticpro (&Qwindow_id);
14330 Qx_frame_parameter = intern ("x-frame-parameter");
14331 staticpro (&Qx_frame_parameter);
14332 Qx_resource_name = intern ("x-resource-name");
14333 staticpro (&Qx_resource_name);
14334 Quser_position = intern ("user-position");
14335 staticpro (&Quser_position);
14336 Quser_size = intern ("user-size");
14337 staticpro (&Quser_size);
6fc2811b
JR
14338 Qscreen_gamma = intern ("screen-gamma");
14339 staticpro (&Qscreen_gamma);
dfff8a69
JR
14340 Qline_spacing = intern ("line-spacing");
14341 staticpro (&Qline_spacing);
14342 Qcenter = intern ("center");
14343 staticpro (&Qcenter);
dc220243
JR
14344 Qcancel_timer = intern ("cancel-timer");
14345 staticpro (&Qcancel_timer);
ee78dc32
GV
14346 /* This is the end of symbol initialization. */
14347
adcc3809
GV
14348 Qhyper = intern ("hyper");
14349 staticpro (&Qhyper);
14350 Qsuper = intern ("super");
14351 staticpro (&Qsuper);
14352 Qmeta = intern ("meta");
14353 staticpro (&Qmeta);
14354 Qalt = intern ("alt");
14355 staticpro (&Qalt);
14356 Qctrl = intern ("ctrl");
14357 staticpro (&Qctrl);
14358 Qcontrol = intern ("control");
14359 staticpro (&Qcontrol);
14360 Qshift = intern ("shift");
14361 staticpro (&Qshift);
14362
6fc2811b
JR
14363 /* Text property `display' should be nonsticky by default. */
14364 Vtext_property_default_nonsticky
14365 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14366
14367
14368 Qlaplace = intern ("laplace");
14369 staticpro (&Qlaplace);
3cf3436e
JR
14370 Qemboss = intern ("emboss");
14371 staticpro (&Qemboss);
14372 Qedge_detection = intern ("edge-detection");
14373 staticpro (&Qedge_detection);
14374 Qheuristic = intern ("heuristic");
14375 staticpro (&Qheuristic);
14376 QCmatrix = intern (":matrix");
14377 staticpro (&QCmatrix);
14378 QCcolor_adjustment = intern (":color-adjustment");
14379 staticpro (&QCcolor_adjustment);
14380 QCmask = intern (":mask");
14381 staticpro (&QCmask);
6fc2811b 14382
4b817373
RS
14383 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14384 staticpro (&Qface_set_after_frame_default);
14385
ee78dc32
GV
14386 Fput (Qundefined_color, Qerror_conditions,
14387 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14388 Fput (Qundefined_color, Qerror_message,
14389 build_string ("Undefined color"));
14390
ccc2d29c
GV
14391 staticpro (&w32_grabbed_keys);
14392 w32_grabbed_keys = Qnil;
14393
fbd6baed 14394 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14395 doc: /* An array of color name mappings for windows. */);
fbd6baed 14396 Vw32_color_map = Qnil;
ee78dc32 14397
fbd6baed 14398 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14399 doc: /* Non-nil if alt key presses are passed on to Windows.
14400When non-nil, for example, alt pressed and released and then space will
14401open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14402 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14403
fbd6baed 14404 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14405 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14406When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14407 Vw32_alt_is_meta = Qt;
8c205c63 14408
7d081355 14409 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14410 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14411 XSETINT (Vw32_quit_key, 0);
14412
ccc2d29c
GV
14413 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14414 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14415 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14416When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14417 Vw32_pass_lwindow_to_system = Qt;
14418
14419 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14420 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14421 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14422When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14423 Vw32_pass_rwindow_to_system = Qt;
14424
adcc3809
GV
14425 DEFVAR_INT ("w32-phantom-key-code",
14426 &Vw32_phantom_key_code,
74e1aeec
JR
14427 doc: /* Virtual key code used to generate \"phantom\" key presses.
14428Value is a number between 0 and 255.
14429
14430Phantom key presses are generated in order to stop the system from
14431acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14432`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14433 /* Although 255 is technically not a valid key code, it works and
14434 means that this hack won't interfere with any real key code. */
14435 Vw32_phantom_key_code = 255;
adcc3809 14436
ccc2d29c
GV
14437 DEFVAR_LISP ("w32-enable-num-lock",
14438 &Vw32_enable_num_lock,
74e1aeec
JR
14439 doc: /* Non-nil if Num Lock should act normally.
14440Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14441 Vw32_enable_num_lock = Qt;
14442
14443 DEFVAR_LISP ("w32-enable-caps-lock",
14444 &Vw32_enable_caps_lock,
74e1aeec
JR
14445 doc: /* Non-nil if Caps Lock should act normally.
14446Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14447 Vw32_enable_caps_lock = Qt;
14448
14449 DEFVAR_LISP ("w32-scroll-lock-modifier",
14450 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14451 doc: /* Modifier to use for the Scroll Lock on state.
14452The value can be hyper, super, meta, alt, control or shift for the
14453respective modifier, or nil to see Scroll Lock as the key `scroll'.
14454Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14455 Vw32_scroll_lock_modifier = Qt;
14456
14457 DEFVAR_LISP ("w32-lwindow-modifier",
14458 &Vw32_lwindow_modifier,
74e1aeec
JR
14459 doc: /* Modifier to use for the left \"Windows\" key.
14460The value can be hyper, super, meta, alt, control or shift for the
14461respective modifier, or nil to appear as the key `lwindow'.
14462Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14463 Vw32_lwindow_modifier = Qnil;
14464
14465 DEFVAR_LISP ("w32-rwindow-modifier",
14466 &Vw32_rwindow_modifier,
74e1aeec
JR
14467 doc: /* Modifier to use for the right \"Windows\" key.
14468The value can be hyper, super, meta, alt, control or shift for the
14469respective modifier, or nil to appear as the key `rwindow'.
14470Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14471 Vw32_rwindow_modifier = Qnil;
14472
14473 DEFVAR_LISP ("w32-apps-modifier",
14474 &Vw32_apps_modifier,
74e1aeec
JR
14475 doc: /* Modifier to use for the \"Apps\" key.
14476The value can be hyper, super, meta, alt, control or shift for the
14477respective modifier, or nil to appear as the key `apps'.
14478Any other value will cause the key to be ignored. */);
ccc2d29c 14479 Vw32_apps_modifier = Qnil;
da36a4d6 14480
212da13b 14481 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
74e1aeec 14482 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
6fc2811b 14483 Vw32_enable_synthesized_fonts = Qnil;
5ac45f98 14484
fbd6baed 14485 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 14486 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 14487 Vw32_enable_palette = Qt;
5ac45f98 14488
fbd6baed
GV
14489 DEFVAR_INT ("w32-mouse-button-tolerance",
14490 &Vw32_mouse_button_tolerance,
74e1aeec
JR
14491 doc: /* Analogue of double click interval for faking middle mouse events.
14492The value is the minimum time in milliseconds that must elapse between
14493left/right button down events before they are considered distinct events.
14494If both mouse buttons are depressed within this interval, a middle mouse
14495button down event is generated instead. */);
fbd6baed 14496 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 14497
fbd6baed
GV
14498 DEFVAR_INT ("w32-mouse-move-interval",
14499 &Vw32_mouse_move_interval,
74e1aeec
JR
14500 doc: /* Minimum interval between mouse move events.
14501The value is the minimum time in milliseconds that must elapse between
14502successive mouse move (or scroll bar drag) events before they are
14503reported as lisp events. */);
247be837 14504 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 14505
ee78dc32
GV
14506 init_x_parm_symbols ();
14507
14508 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 14509 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
14510 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14511
14512 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
14513 doc: /* The shape of the pointer when over text.
14514Changing the value does not affect existing frames
14515unless you set the mouse color. */);
ee78dc32
GV
14516 Vx_pointer_shape = Qnil;
14517
14518 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
14519 doc: /* The name Emacs uses to look up resources; for internal use only.
14520`x-get-resource' uses this as the first component of the instance name
14521when requesting resource values.
14522Emacs initially sets `x-resource-name' to the name under which Emacs
14523was invoked, or to the value specified with the `-name' or `-rn'
14524switches, if present. */);
ee78dc32
GV
14525 Vx_resource_name = Qnil;
14526
14527 Vx_nontext_pointer_shape = Qnil;
14528
14529 Vx_mode_pointer_shape = Qnil;
14530
0af913d7 14531 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
14532 doc: /* The shape of the pointer when Emacs is busy.
14533This variable takes effect when you create a new frame
14534or when you set the mouse color. */);
0af913d7 14535 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 14536
0af913d7 14537 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 14538 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 14539 display_hourglass_p = 1;
6fc2811b 14540
0af913d7 14541 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
14542 doc: /* *Seconds to wait before displaying an hourglass pointer.
14543Value must be an integer or float. */);
0af913d7 14544 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 14545
6fc2811b 14546 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 14547 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
14548 doc: /* The shape of the pointer when over mouse-sensitive text.
14549This variable takes effect when you create a new frame
14550or when you set the mouse color. */);
ee78dc32
GV
14551 Vx_sensitive_text_pointer_shape = Qnil;
14552
4694d762
JR
14553 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14554 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
14555 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14556This variable takes effect when you create a new frame
14557or when you set the mouse color. */);
4694d762
JR
14558 Vx_window_horizontal_drag_shape = Qnil;
14559
ee78dc32 14560 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 14561 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
14562 Vx_cursor_fore_pixel = Qnil;
14563
3cf3436e 14564 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
14565 doc: /* Maximum size for tooltips.
14566Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
14567 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
14568
ee78dc32 14569 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
14570 doc: /* Non-nil if no window manager is in use.
14571Emacs doesn't try to figure this out; this is always nil
14572unless you set it to something else. */);
ee78dc32
GV
14573 /* We don't have any way to find this out, so set it to nil
14574 and maybe the user would like to set it to t. */
14575 Vx_no_window_manager = Qnil;
14576
4587b026
GV
14577 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14578 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
14579 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14580
14581Since Emacs gets width of a font matching with this regexp from
14582PIXEL_SIZE field of the name, font finding mechanism gets faster for
14583such a font. This is especially effective for such large fonts as
14584Chinese, Japanese, and Korean. */);
4587b026
GV
14585 Vx_pixel_size_width_font_regexp = Qnil;
14586
6fc2811b 14587 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
14588 doc: /* Time after which cached images are removed from the cache.
14589When an image has not been displayed this many seconds, remove it
14590from the image cache. Value must be an integer or nil with nil
14591meaning don't clear the cache. */);
6fc2811b
JR
14592 Vimage_cache_eviction_delay = make_number (30 * 60);
14593
33d52f9c
GV
14594 DEFVAR_LISP ("w32-bdf-filename-alist",
14595 &Vw32_bdf_filename_alist,
74e1aeec 14596 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
14597 Vw32_bdf_filename_alist = Qnil;
14598
1075afa9
GV
14599 DEFVAR_BOOL ("w32-strict-fontnames",
14600 &w32_strict_fontnames,
74e1aeec
JR
14601 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14602Default is nil, which allows old fontnames that are not XLFD compliant,
14603and allows third-party CJK display to work by specifying false charset
14604fields to trick Emacs into translating to Big5, SJIS etc.
14605Setting this to t will prevent wrong fonts being selected when
14606fontsets are automatically created. */);
1075afa9
GV
14607 w32_strict_fontnames = 0;
14608
c0611964
AI
14609 DEFVAR_BOOL ("w32-strict-painting",
14610 &w32_strict_painting,
74e1aeec
JR
14611 doc: /* Non-nil means use strict rules for repainting frames.
14612Set this to nil to get the old behaviour for repainting; this should
14613only be necessary if the default setting causes problems. */);
c0611964
AI
14614 w32_strict_painting = 1;
14615
dfff8a69
JR
14616 DEFVAR_LISP ("w32-charset-info-alist",
14617 &Vw32_charset_info_alist,
b3700ae7
JR
14618 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14619Each entry should be of the form:
74e1aeec
JR
14620
14621 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14622
14623where CHARSET_NAME is a string used in font names to identify the charset,
14624WINDOWS_CHARSET is a symbol that can be one of:
14625w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14626w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14627w32-charset-chinesebig5,
dfff8a69 14628#ifdef JOHAB_CHARSET
74e1aeec
JR
14629w32-charset-johab, w32-charset-hebrew,
14630w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14631w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14632w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
14633#endif
14634#ifdef UNICODE_CHARSET
74e1aeec 14635w32-charset-unicode,
dfff8a69 14636#endif
74e1aeec
JR
14637or w32-charset-oem.
14638CODEPAGE should be an integer specifying the codepage that should be used
14639to display the character set, t to do no translation and output as Unicode,
14640or nil to do no translation and output as 8 bit (or multibyte on far-east
14641versions of Windows) characters. */);
dfff8a69
JR
14642 Vw32_charset_info_alist = Qnil;
14643
14644 staticpro (&Qw32_charset_ansi);
14645 Qw32_charset_ansi = intern ("w32-charset-ansi");
14646 staticpro (&Qw32_charset_symbol);
14647 Qw32_charset_symbol = intern ("w32-charset-symbol");
14648 staticpro (&Qw32_charset_shiftjis);
14649 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
14650 staticpro (&Qw32_charset_hangeul);
14651 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
14652 staticpro (&Qw32_charset_chinesebig5);
14653 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
14654 staticpro (&Qw32_charset_gb2312);
14655 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
14656 staticpro (&Qw32_charset_oem);
14657 Qw32_charset_oem = intern ("w32-charset-oem");
14658
14659#ifdef JOHAB_CHARSET
14660 {
14661 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
14662 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
14663 doc: /* Internal variable. */);
dfff8a69
JR
14664
14665 staticpro (&Qw32_charset_johab);
14666 Qw32_charset_johab = intern ("w32-charset-johab");
14667 staticpro (&Qw32_charset_easteurope);
14668 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
14669 staticpro (&Qw32_charset_turkish);
14670 Qw32_charset_turkish = intern ("w32-charset-turkish");
14671 staticpro (&Qw32_charset_baltic);
14672 Qw32_charset_baltic = intern ("w32-charset-baltic");
14673 staticpro (&Qw32_charset_russian);
14674 Qw32_charset_russian = intern ("w32-charset-russian");
14675 staticpro (&Qw32_charset_arabic);
14676 Qw32_charset_arabic = intern ("w32-charset-arabic");
14677 staticpro (&Qw32_charset_greek);
14678 Qw32_charset_greek = intern ("w32-charset-greek");
14679 staticpro (&Qw32_charset_hebrew);
14680 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
14681 staticpro (&Qw32_charset_vietnamese);
14682 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
14683 staticpro (&Qw32_charset_thai);
14684 Qw32_charset_thai = intern ("w32-charset-thai");
14685 staticpro (&Qw32_charset_mac);
14686 Qw32_charset_mac = intern ("w32-charset-mac");
14687 }
14688#endif
14689
14690#ifdef UNICODE_CHARSET
14691 {
14692 static int w32_unicode_charset_defined = 1;
14693 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
14694 &w32_unicode_charset_defined,
14695 doc: /* Internal variable. */);
dfff8a69
JR
14696
14697 staticpro (&Qw32_charset_unicode);
14698 Qw32_charset_unicode = intern ("w32-charset-unicode");
14699#endif
14700
ee78dc32 14701 defsubr (&Sx_get_resource);
767b1ff0 14702#if 0 /* TODO: Port to W32 */
6fc2811b
JR
14703 defsubr (&Sx_change_window_property);
14704 defsubr (&Sx_delete_window_property);
14705 defsubr (&Sx_window_property);
14706#endif
2d764c78 14707 defsubr (&Sxw_display_color_p);
ee78dc32 14708 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
14709 defsubr (&Sxw_color_defined_p);
14710 defsubr (&Sxw_color_values);
ee78dc32
GV
14711 defsubr (&Sx_server_max_request_size);
14712 defsubr (&Sx_server_vendor);
14713 defsubr (&Sx_server_version);
14714 defsubr (&Sx_display_pixel_width);
14715 defsubr (&Sx_display_pixel_height);
14716 defsubr (&Sx_display_mm_width);
14717 defsubr (&Sx_display_mm_height);
14718 defsubr (&Sx_display_screens);
14719 defsubr (&Sx_display_planes);
14720 defsubr (&Sx_display_color_cells);
14721 defsubr (&Sx_display_visual_class);
14722 defsubr (&Sx_display_backing_store);
14723 defsubr (&Sx_display_save_under);
14724 defsubr (&Sx_parse_geometry);
14725 defsubr (&Sx_create_frame);
ee78dc32
GV
14726 defsubr (&Sx_open_connection);
14727 defsubr (&Sx_close_connection);
14728 defsubr (&Sx_display_list);
14729 defsubr (&Sx_synchronize);
14730
fbd6baed 14731 /* W32 specific functions */
ee78dc32 14732
1edf84e7 14733 defsubr (&Sw32_focus_frame);
fbd6baed
GV
14734 defsubr (&Sw32_select_font);
14735 defsubr (&Sw32_define_rgb_color);
14736 defsubr (&Sw32_default_color_map);
14737 defsubr (&Sw32_load_color_file);
1edf84e7 14738 defsubr (&Sw32_send_sys_command);
55dcfc15 14739 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
14740 defsubr (&Sw32_register_hot_key);
14741 defsubr (&Sw32_unregister_hot_key);
14742 defsubr (&Sw32_registered_hot_keys);
14743 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 14744 defsubr (&Sw32_toggle_lock_key);
33d52f9c 14745 defsubr (&Sw32_find_bdf_fonts);
4587b026 14746
2254bcde
AI
14747 defsubr (&Sfile_system_info);
14748
4587b026
GV
14749 /* Setting callback functions for fontset handler. */
14750 get_font_info_func = w32_get_font_info;
6fc2811b
JR
14751
14752#if 0 /* This function pointer doesn't seem to be used anywhere.
14753 And the pointer assigned has the wrong type, anyway. */
4587b026 14754 list_fonts_func = w32_list_fonts;
6fc2811b
JR
14755#endif
14756
4587b026
GV
14757 load_font_func = w32_load_font;
14758 find_ccl_program_func = w32_find_ccl_program;
14759 query_font_func = w32_query_font;
14760 set_frame_fontset_func = x_set_font;
14761 check_window_system_func = check_w32;
6fc2811b 14762
767b1ff0 14763#if 0 /* TODO Image support for W32 */
6fc2811b
JR
14764 /* Images. */
14765 Qxbm = intern ("xbm");
14766 staticpro (&Qxbm);
14767 QCtype = intern (":type");
14768 staticpro (&QCtype);
a93f4566
GM
14769 QCconversion = intern (":conversion");
14770 staticpro (&QCconversion);
6fc2811b
JR
14771 QCheuristic_mask = intern (":heuristic-mask");
14772 staticpro (&QCheuristic_mask);
14773 QCcolor_symbols = intern (":color-symbols");
14774 staticpro (&QCcolor_symbols);
6fc2811b
JR
14775 QCascent = intern (":ascent");
14776 staticpro (&QCascent);
14777 QCmargin = intern (":margin");
14778 staticpro (&QCmargin);
14779 QCrelief = intern (":relief");
14780 staticpro (&QCrelief);
14781 Qpostscript = intern ("postscript");
14782 staticpro (&Qpostscript);
14783 QCloader = intern (":loader");
14784 staticpro (&QCloader);
14785 QCbounding_box = intern (":bounding-box");
14786 staticpro (&QCbounding_box);
14787 QCpt_width = intern (":pt-width");
14788 staticpro (&QCpt_width);
14789 QCpt_height = intern (":pt-height");
14790 staticpro (&QCpt_height);
14791 QCindex = intern (":index");
14792 staticpro (&QCindex);
14793 Qpbm = intern ("pbm");
14794 staticpro (&Qpbm);
14795
14796#if HAVE_XPM
14797 Qxpm = intern ("xpm");
14798 staticpro (&Qxpm);
14799#endif
14800
14801#if HAVE_JPEG
14802 Qjpeg = intern ("jpeg");
14803 staticpro (&Qjpeg);
14804#endif
14805
14806#if HAVE_TIFF
14807 Qtiff = intern ("tiff");
14808 staticpro (&Qtiff);
14809#endif
14810
14811#if HAVE_GIF
14812 Qgif = intern ("gif");
14813 staticpro (&Qgif);
14814#endif
14815
14816#if HAVE_PNG
14817 Qpng = intern ("png");
14818 staticpro (&Qpng);
14819#endif
14820
14821 defsubr (&Sclear_image_cache);
14822
14823#if GLYPH_DEBUG
14824 defsubr (&Simagep);
14825 defsubr (&Slookup_image);
14826#endif
767b1ff0 14827#endif /* TODO */
6fc2811b 14828
0af913d7
GM
14829 hourglass_atimer = NULL;
14830 hourglass_shown_p = 0;
6fc2811b
JR
14831 defsubr (&Sx_show_tip);
14832 defsubr (&Sx_hide_tip);
6fc2811b 14833 tip_timer = Qnil;
57fa2774
JR
14834 staticpro (&tip_timer);
14835 tip_frame = Qnil;
14836 staticpro (&tip_frame);
6fc2811b 14837
ca56d953
JR
14838 last_show_tip_args = Qnil;
14839 staticpro (&last_show_tip_args);
14840
6fc2811b
JR
14841 defsubr (&Sx_file_dialog);
14842}
14843
14844
14845void
14846init_xfns ()
14847{
14848 image_types = NULL;
14849 Vimage_types = Qnil;
14850
767b1ff0 14851#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
14852 define_image_type (&xbm_type);
14853 define_image_type (&gs_type);
14854 define_image_type (&pbm_type);
14855
14856#if HAVE_XPM
14857 define_image_type (&xpm_type);
14858#endif
14859
14860#if HAVE_JPEG
14861 define_image_type (&jpeg_type);
14862#endif
14863
14864#if HAVE_TIFF
14865 define_image_type (&tiff_type);
14866#endif
14867
14868#if HAVE_GIF
14869 define_image_type (&gif_type);
14870#endif
14871
14872#if HAVE_PNG
14873 define_image_type (&png_type);
14874#endif
767b1ff0 14875#endif /* TODO */
ee78dc32
GV
14876}
14877
14878#undef abort
14879
14880void
fbd6baed 14881w32_abort()
ee78dc32 14882{
5ac45f98
GV
14883 int button;
14884 button = MessageBox (NULL,
14885 "A fatal error has occurred!\n\n"
14886 "Select Abort to exit, Retry to debug, Ignore to continue",
14887 "Emacs Abort Dialog",
14888 MB_ICONEXCLAMATION | MB_TASKMODAL
14889 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
14890 switch (button)
14891 {
14892 case IDRETRY:
14893 DebugBreak ();
14894 break;
14895 case IDIGNORE:
14896 break;
14897 case IDABORT:
14898 default:
14899 abort ();
14900 break;
14901 }
ee78dc32 14902}
d573caac 14903
83c75055
GV
14904/* For convenience when debugging. */
14905int
14906w32_last_error()
14907{
14908 return GetLastError ();
14909}