(comint-redirect-send-command-to-process): Restore previous current buffer.
[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
74214547
JR
145/* Flag to indicate if XBUTTON events should be passed on to Windows. */
146int w32_pass_extra_mouse_buttons_to_system;
147
ee78dc32
GV
148/* The name we're using in resource queries. */
149Lisp_Object Vx_resource_name;
150
151/* Non nil if no window manager is in use. */
152Lisp_Object Vx_no_window_manager;
153
0af913d7 154/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 155
0af913d7 156int display_hourglass_p;
6fc2811b 157
ee78dc32
GV
158/* The background and shape of the mouse pointer, and shape when not
159 over text or in the modeline. */
dfff8a69 160
ee78dc32 161Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 162Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 163
ee78dc32 164/* The shape when over mouse-sensitive text. */
dfff8a69 165
ee78dc32
GV
166Lisp_Object Vx_sensitive_text_pointer_shape;
167
168/* Color of chars displayed in cursor box. */
dfff8a69 169
ee78dc32
GV
170Lisp_Object Vx_cursor_fore_pixel;
171
1edf84e7 172/* Nonzero if using Windows. */
dfff8a69 173
1edf84e7
GV
174static int w32_in_use;
175
ee78dc32 176/* Search path for bitmap files. */
dfff8a69 177
ee78dc32
GV
178Lisp_Object Vx_bitmap_file_path;
179
4587b026 180/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 181
4587b026
GV
182Lisp_Object Vx_pixel_size_width_font_regexp;
183
33d52f9c
GV
184/* Alist of bdf fonts and the files that define them. */
185Lisp_Object Vw32_bdf_filename_alist;
186
f46e6225 187/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
188int w32_strict_fontnames;
189
c0611964
AI
190/* A flag to control whether we should only repaint if GetUpdateRect
191 indicates there is an update region. */
192int w32_strict_painting;
193
dfff8a69
JR
194/* Associative list linking character set strings to Windows codepages. */
195Lisp_Object Vw32_charset_info_alist;
196
197/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
198#ifndef VIETNAMESE_CHARSET
199#define VIETNAMESE_CHARSET 163
200#endif
201
ee78dc32
GV
202Lisp_Object Qauto_raise;
203Lisp_Object Qauto_lower;
ee78dc32
GV
204Lisp_Object Qbar;
205Lisp_Object Qborder_color;
206Lisp_Object Qborder_width;
207Lisp_Object Qbox;
208Lisp_Object Qcursor_color;
209Lisp_Object Qcursor_type;
ee78dc32
GV
210Lisp_Object Qgeometry;
211Lisp_Object Qicon_left;
212Lisp_Object Qicon_top;
213Lisp_Object Qicon_type;
214Lisp_Object Qicon_name;
215Lisp_Object Qinternal_border_width;
216Lisp_Object Qleft;
1026b400 217Lisp_Object Qright;
ee78dc32
GV
218Lisp_Object Qmouse_color;
219Lisp_Object Qnone;
220Lisp_Object Qparent_id;
221Lisp_Object Qscroll_bar_width;
222Lisp_Object Qsuppress_icon;
ee78dc32
GV
223Lisp_Object Qundefined_color;
224Lisp_Object Qvertical_scroll_bars;
225Lisp_Object Qvisibility;
226Lisp_Object Qwindow_id;
227Lisp_Object Qx_frame_parameter;
228Lisp_Object Qx_resource_name;
229Lisp_Object Quser_position;
230Lisp_Object Quser_size;
6fc2811b 231Lisp_Object Qscreen_gamma;
dfff8a69
JR
232Lisp_Object Qline_spacing;
233Lisp_Object Qcenter;
dc220243 234Lisp_Object Qcancel_timer;
adcc3809
GV
235Lisp_Object Qhyper;
236Lisp_Object Qsuper;
237Lisp_Object Qmeta;
238Lisp_Object Qalt;
239Lisp_Object Qctrl;
240Lisp_Object Qcontrol;
241Lisp_Object Qshift;
242
dfff8a69
JR
243Lisp_Object Qw32_charset_ansi;
244Lisp_Object Qw32_charset_default;
245Lisp_Object Qw32_charset_symbol;
246Lisp_Object Qw32_charset_shiftjis;
767b1ff0 247Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
248Lisp_Object Qw32_charset_gb2312;
249Lisp_Object Qw32_charset_chinesebig5;
250Lisp_Object Qw32_charset_oem;
251
71eab8d1
AI
252#ifndef JOHAB_CHARSET
253#define JOHAB_CHARSET 130
254#endif
dfff8a69
JR
255#ifdef JOHAB_CHARSET
256Lisp_Object Qw32_charset_easteurope;
257Lisp_Object Qw32_charset_turkish;
258Lisp_Object Qw32_charset_baltic;
259Lisp_Object Qw32_charset_russian;
260Lisp_Object Qw32_charset_arabic;
261Lisp_Object Qw32_charset_greek;
262Lisp_Object Qw32_charset_hebrew;
767b1ff0 263Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
264Lisp_Object Qw32_charset_thai;
265Lisp_Object Qw32_charset_johab;
266Lisp_Object Qw32_charset_mac;
267#endif
268
269#ifdef UNICODE_CHARSET
270Lisp_Object Qw32_charset_unicode;
271#endif
272
6fc2811b
JR
273extern Lisp_Object Qtop;
274extern Lisp_Object Qdisplay;
275extern Lisp_Object Qtool_bar_lines;
276
5ac45f98
GV
277/* State variables for emulating a three button mouse. */
278#define LMOUSE 1
279#define MMOUSE 2
280#define RMOUSE 4
281
282static int button_state = 0;
fbd6baed 283static W32Msg saved_mouse_button_msg;
84fb1139 284static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 285static W32Msg saved_mouse_move_msg;
84fb1139
KH
286static unsigned mouse_move_timer;
287
9eb16b62
JR
288/* Window that is tracking the mouse. */
289static HWND track_mouse_window;
290FARPROC track_mouse_event_fn;
291
93fbe8b7
GV
292/* W95 mousewheel handler */
293unsigned int msh_mousewheel = 0;
294
84fb1139
KH
295#define MOUSE_BUTTON_ID 1
296#define MOUSE_MOVE_ID 2
5ac45f98 297
ee78dc32 298/* The below are defined in frame.c. */
dfff8a69 299
ee78dc32 300extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 301extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 302extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
303
304extern Lisp_Object Vwindow_system_version;
305
4b817373
RS
306Lisp_Object Qface_set_after_frame_default;
307
937e601e
AI
308#ifdef GLYPH_DEBUG
309int image_cache_refcount, dpyinfo_refcount;
310#endif
311
312
fbd6baed
GV
313/* From w32term.c. */
314extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 315extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 316
65906840
JR
317extern HWND w32_system_caret_hwnd;
318extern int w32_system_caret_width;
319extern int w32_system_caret_height;
320extern int w32_system_caret_x;
321extern int w32_system_caret_y;
322
ee78dc32 323\f
1edf84e7
GV
324/* Error if we are not connected to MS-Windows. */
325void
326check_w32 ()
327{
328 if (! w32_in_use)
329 error ("MS-Windows not in use or not initialized");
330}
331
332/* Nonzero if we can use mouse menus.
333 You should not call this unless HAVE_MENUS is defined. */
334
335int
336have_menus_p ()
337{
338 return w32_in_use;
339}
340
ee78dc32 341/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 342 and checking validity for W32. */
ee78dc32
GV
343
344FRAME_PTR
345check_x_frame (frame)
346 Lisp_Object frame;
347{
348 FRAME_PTR f;
349
350 if (NILP (frame))
6fc2811b 351 frame = selected_frame;
b7826503 352 CHECK_LIVE_FRAME (frame);
6fc2811b 353 f = XFRAME (frame);
fbd6baed
GV
354 if (! FRAME_W32_P (f))
355 error ("non-w32 frame used");
ee78dc32
GV
356 return f;
357}
358
359/* Let the user specify an display with a frame.
fbd6baed 360 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
361 the first display on the list. */
362
fbd6baed 363static struct w32_display_info *
ee78dc32
GV
364check_x_display_info (frame)
365 Lisp_Object frame;
366{
367 if (NILP (frame))
368 {
6fc2811b
JR
369 struct frame *sf = XFRAME (selected_frame);
370
371 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
372 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 373 else
fbd6baed 374 return &one_w32_display_info;
ee78dc32
GV
375 }
376 else if (STRINGP (frame))
377 return x_display_info_for_name (frame);
378 else
379 {
380 FRAME_PTR f;
381
b7826503 382 CHECK_LIVE_FRAME (frame);
ee78dc32 383 f = XFRAME (frame);
fbd6baed
GV
384 if (! FRAME_W32_P (f))
385 error ("non-w32 frame used");
386 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
387 }
388}
389\f
fbd6baed 390/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
391 It could be the frame's main window or an icon window. */
392
393/* This function can be called during GC, so use GC_xxx type test macros. */
394
395struct frame *
396x_window_to_frame (dpyinfo, wdesc)
fbd6baed 397 struct w32_display_info *dpyinfo;
ee78dc32
GV
398 HWND wdesc;
399{
400 Lisp_Object tail, frame;
401 struct frame *f;
402
8e713be6 403 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 404 {
8e713be6 405 frame = XCAR (tail);
ee78dc32
GV
406 if (!GC_FRAMEP (frame))
407 continue;
408 f = XFRAME (frame);
2d764c78 409 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 410 continue;
0af913d7 411 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
412 return f;
413
fbd6baed 414 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
415 return f;
416 }
417 return 0;
418}
419
420\f
421
422/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
423 id, which is just an int that this section returns. Bitmaps are
424 reference counted so they can be shared among frames.
425
426 Bitmap indices are guaranteed to be > 0, so a negative number can
427 be used to indicate no bitmap.
428
429 If you use x_create_bitmap_from_data, then you must keep track of
430 the bitmaps yourself. That is, creating a bitmap from the same
431 data more than once will not be caught. */
432
433
434/* Functions to access the contents of a bitmap, given an id. */
435
436int
437x_bitmap_height (f, id)
438 FRAME_PTR f;
439 int id;
440{
fbd6baed 441 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
442}
443
444int
445x_bitmap_width (f, id)
446 FRAME_PTR f;
447 int id;
448{
fbd6baed 449 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
450}
451
452int
453x_bitmap_pixmap (f, id)
454 FRAME_PTR f;
455 int id;
456{
fbd6baed 457 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
458}
459
460
461/* Allocate a new bitmap record. Returns index of new record. */
462
463static int
464x_allocate_bitmap_record (f)
465 FRAME_PTR f;
466{
fbd6baed 467 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
468 int i;
469
470 if (dpyinfo->bitmaps == NULL)
471 {
472 dpyinfo->bitmaps_size = 10;
473 dpyinfo->bitmaps
fbd6baed 474 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
475 dpyinfo->bitmaps_last = 1;
476 return 1;
477 }
478
479 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
480 return ++dpyinfo->bitmaps_last;
481
482 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
483 if (dpyinfo->bitmaps[i].refcount == 0)
484 return i + 1;
485
486 dpyinfo->bitmaps_size *= 2;
487 dpyinfo->bitmaps
fbd6baed
GV
488 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
489 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
490 return ++dpyinfo->bitmaps_last;
491}
492
493/* Add one reference to the reference count of the bitmap with id ID. */
494
495void
496x_reference_bitmap (f, id)
497 FRAME_PTR f;
498 int id;
499{
fbd6baed 500 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
501}
502
503/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
504
505int
506x_create_bitmap_from_data (f, bits, width, height)
507 struct frame *f;
508 char *bits;
509 unsigned int width, height;
510{
fbd6baed 511 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
512 Pixmap bitmap;
513 int id;
514
515 bitmap = CreateBitmap (width, height,
fbd6baed
GV
516 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
517 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
518 bits);
519
520 if (! bitmap)
521 return -1;
522
523 id = x_allocate_bitmap_record (f);
524 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
525 dpyinfo->bitmaps[id - 1].file = NULL;
526 dpyinfo->bitmaps[id - 1].hinst = NULL;
527 dpyinfo->bitmaps[id - 1].refcount = 1;
528 dpyinfo->bitmaps[id - 1].depth = 1;
529 dpyinfo->bitmaps[id - 1].height = height;
530 dpyinfo->bitmaps[id - 1].width = width;
531
532 return id;
533}
534
535/* Create bitmap from file FILE for frame F. */
536
537int
538x_create_bitmap_from_file (f, file)
539 struct frame *f;
540 Lisp_Object file;
541{
542 return -1;
767b1ff0 543#if 0 /* TODO : bitmap support */
fbd6baed 544 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 545 unsigned int width, height;
6fc2811b 546 HBITMAP bitmap;
ee78dc32
GV
547 int xhot, yhot, result, id;
548 Lisp_Object found;
549 int fd;
550 char *filename;
551 HINSTANCE hinst;
552
553 /* Look for an existing bitmap with the same name. */
554 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
555 {
556 if (dpyinfo->bitmaps[id].refcount
557 && dpyinfo->bitmaps[id].file
558 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
559 {
560 ++dpyinfo->bitmaps[id].refcount;
561 return id + 1;
562 }
563 }
564
565 /* Search bitmap-file-path for the file, if appropriate. */
c0ec53ad 566 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
ee78dc32
GV
567 if (fd < 0)
568 return -1;
6fc2811b 569 emacs_close (fd);
ee78dc32
GV
570
571 filename = (char *) XSTRING (found)->data;
572
573 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
574
575 if (hinst == NULL)
576 return -1;
577
578
fbd6baed 579 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
580 filename, &width, &height, &bitmap, &xhot, &yhot);
581 if (result != BitmapSuccess)
582 return -1;
583
584 id = x_allocate_bitmap_record (f);
585 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
586 dpyinfo->bitmaps[id - 1].refcount = 1;
587 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
588 dpyinfo->bitmaps[id - 1].depth = 1;
589 dpyinfo->bitmaps[id - 1].height = height;
590 dpyinfo->bitmaps[id - 1].width = width;
591 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
592
593 return id;
767b1ff0 594#endif /* TODO */
ee78dc32
GV
595}
596
597/* Remove reference to bitmap with id number ID. */
598
33d52f9c 599void
ee78dc32
GV
600x_destroy_bitmap (f, id)
601 FRAME_PTR f;
602 int id;
603{
fbd6baed 604 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
605
606 if (id > 0)
607 {
608 --dpyinfo->bitmaps[id - 1].refcount;
609 if (dpyinfo->bitmaps[id - 1].refcount == 0)
610 {
611 BLOCK_INPUT;
612 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
613 if (dpyinfo->bitmaps[id - 1].file)
614 {
6fc2811b 615 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
616 dpyinfo->bitmaps[id - 1].file = NULL;
617 }
618 UNBLOCK_INPUT;
619 }
620 }
621}
622
623/* Free all the bitmaps for the display specified by DPYINFO. */
624
625static void
626x_destroy_all_bitmaps (dpyinfo)
fbd6baed 627 struct w32_display_info *dpyinfo;
ee78dc32
GV
628{
629 int i;
630 for (i = 0; i < dpyinfo->bitmaps_last; i++)
631 if (dpyinfo->bitmaps[i].refcount > 0)
632 {
633 DeleteObject (dpyinfo->bitmaps[i].pixmap);
634 if (dpyinfo->bitmaps[i].file)
6fc2811b 635 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
636 }
637 dpyinfo->bitmaps_last = 0;
638}
639\f
fbd6baed 640/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
641 to the ways of passing the parameter values to the window system.
642
643 The name of a parameter, as a Lisp symbol,
644 has an `x-frame-parameter' property which is an integer in Lisp
645 but can be interpreted as an `enum x_frame_parm' in C. */
646
647enum x_frame_parm
648{
649 X_PARM_FOREGROUND_COLOR,
650 X_PARM_BACKGROUND_COLOR,
651 X_PARM_MOUSE_COLOR,
652 X_PARM_CURSOR_COLOR,
653 X_PARM_BORDER_COLOR,
654 X_PARM_ICON_TYPE,
655 X_PARM_FONT,
656 X_PARM_BORDER_WIDTH,
657 X_PARM_INTERNAL_BORDER_WIDTH,
658 X_PARM_NAME,
659 X_PARM_AUTORAISE,
660 X_PARM_AUTOLOWER,
661 X_PARM_VERT_SCROLL_BAR,
662 X_PARM_VISIBILITY,
663 X_PARM_MENU_BAR_LINES
664};
665
666
667struct x_frame_parm_table
668{
669 char *name;
6fc2811b 670 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
671};
672
ca56d953
JR
673BOOL my_show_window P_ ((struct frame *, HWND, int));
674void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
675static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
676static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
677static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 678/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 679void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 680static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
681void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
682void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
683void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
684void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
685void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
686void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
687void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
688void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 689static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
690void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
691void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
692 Lisp_Object));
693void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
694void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
695void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
697 Lisp_Object));
698void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
701void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
702void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
703void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
704static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
705static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
706 Lisp_Object));
ee78dc32
GV
707
708static struct x_frame_parm_table x_frame_parms[] =
709{
72e4adef
JR
710 {"auto-raise", x_set_autoraise},
711 {"auto-lower", x_set_autolower},
712 {"background-color", x_set_background_color},
713 {"border-color", x_set_border_color},
714 {"border-width", x_set_border_width},
715 {"cursor-color", x_set_cursor_color},
716 {"cursor-type", x_set_cursor_type},
717 {"font", x_set_font},
718 {"foreground-color", x_set_foreground_color},
719 {"icon-name", x_set_icon_name},
720 {"icon-type", x_set_icon_type},
721 {"internal-border-width", x_set_internal_border_width},
722 {"menu-bar-lines", x_set_menu_bar_lines},
723 {"mouse-color", x_set_mouse_color},
724 {"name", x_explicitly_set_name},
725 {"scroll-bar-width", x_set_scroll_bar_width},
726 {"title", x_set_title},
727 {"unsplittable", x_set_unsplittable},
728 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
729 {"visibility", x_set_visibility},
730 {"tool-bar-lines", x_set_tool_bar_lines},
731 {"screen-gamma", x_set_screen_gamma},
732 {"line-spacing", x_set_line_spacing},
733 {"left-fringe", x_set_fringe_width},
734 {"right-fringe", x_set_fringe_width}
ee78dc32
GV
735};
736
737/* Attach the `x-frame-parameter' properties to
fbd6baed 738 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 739
dfff8a69 740void
ee78dc32
GV
741init_x_parm_symbols ()
742{
743 int i;
744
745 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
746 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
747 make_number (i));
748}
749\f
dfff8a69 750/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
751 If a parameter is not specially recognized, do nothing;
752 otherwise call the `x_set_...' function for that parameter. */
753
754void
755x_set_frame_parameters (f, alist)
756 FRAME_PTR f;
757 Lisp_Object alist;
758{
759 Lisp_Object tail;
760
761 /* If both of these parameters are present, it's more efficient to
762 set them both at once. So we wait until we've looked at the
763 entire list before we set them. */
b839712d 764 int width, height;
ee78dc32
GV
765
766 /* Same here. */
767 Lisp_Object left, top;
768
769 /* Same with these. */
770 Lisp_Object icon_left, icon_top;
771
772 /* Record in these vectors all the parms specified. */
773 Lisp_Object *parms;
774 Lisp_Object *values;
a797a73d 775 int i, p;
ee78dc32
GV
776 int left_no_change = 0, top_no_change = 0;
777 int icon_left_no_change = 0, icon_top_no_change = 0;
778
5878523b
RS
779 struct gcpro gcpro1, gcpro2;
780
ee78dc32
GV
781 i = 0;
782 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
783 i++;
784
785 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
786 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
787
788 /* Extract parm names and values into those vectors. */
789
790 i = 0;
791 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
792 {
6fc2811b 793 Lisp_Object elt;
ee78dc32
GV
794
795 elt = Fcar (tail);
796 parms[i] = Fcar (elt);
797 values[i] = Fcdr (elt);
798 i++;
799 }
5878523b
RS
800 /* TAIL and ALIST are not used again below here. */
801 alist = tail = Qnil;
802
803 GCPRO2 (*parms, *values);
804 gcpro1.nvars = i;
805 gcpro2.nvars = i;
806
807 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
808 because their values appear in VALUES and strings are not valid. */
b839712d 809 top = left = Qunbound;
ee78dc32
GV
810 icon_left = icon_top = Qunbound;
811
b839712d 812 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
813 if (FRAME_NEW_WIDTH (f))
814 width = FRAME_NEW_WIDTH (f);
815 else
816 width = FRAME_WIDTH (f);
817
818 if (FRAME_NEW_HEIGHT (f))
819 height = FRAME_NEW_HEIGHT (f);
820 else
821 height = FRAME_HEIGHT (f);
b839712d 822
a797a73d
GV
823 /* Process foreground_color and background_color before anything else.
824 They are independent of other properties, but other properties (e.g.,
825 cursor_color) are dependent upon them. */
41c1bdd9 826 /* Process default font as well, since fringe widths depends on it. */
a797a73d
GV
827 for (p = 0; p < i; p++)
828 {
829 Lisp_Object prop, val;
830
831 prop = parms[p];
832 val = values[p];
41c1bdd9
KS
833 if (EQ (prop, Qforeground_color)
834 || EQ (prop, Qbackground_color)
835 || EQ (prop, Qfont))
a797a73d
GV
836 {
837 register Lisp_Object param_index, old_value;
838
a797a73d 839 old_value = get_frame_param (f, prop);
a05e2bae
JR
840
841 if (NILP (Fequal (val, old_value)))
842 {
843 store_frame_param (f, prop, val);
844
845 param_index = Fget (prop, Qx_frame_parameter);
846 if (NATNUMP (param_index)
847 && (XFASTINT (param_index)
848 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
849 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
850 }
a797a73d
GV
851 }
852 }
853
ee78dc32
GV
854 /* Now process them in reverse of specified order. */
855 for (i--; i >= 0; i--)
856 {
857 Lisp_Object prop, val;
858
859 prop = parms[i];
860 val = values[i];
861
b839712d
RS
862 if (EQ (prop, Qwidth) && NUMBERP (val))
863 width = XFASTINT (val);
864 else if (EQ (prop, Qheight) && NUMBERP (val))
865 height = XFASTINT (val);
ee78dc32
GV
866 else if (EQ (prop, Qtop))
867 top = val;
868 else if (EQ (prop, Qleft))
869 left = val;
870 else if (EQ (prop, Qicon_top))
871 icon_top = val;
872 else if (EQ (prop, Qicon_left))
873 icon_left = val;
41c1bdd9
KS
874 else if (EQ (prop, Qforeground_color)
875 || EQ (prop, Qbackground_color)
876 || EQ (prop, Qfont))
a797a73d
GV
877 /* Processed above. */
878 continue;
ee78dc32
GV
879 else
880 {
881 register Lisp_Object param_index, old_value;
882
ee78dc32 883 old_value = get_frame_param (f, prop);
a05e2bae 884
ee78dc32 885 store_frame_param (f, prop, val);
a05e2bae
JR
886
887 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
888 if (NATNUMP (param_index)
889 && (XFASTINT (param_index)
890 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 891 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
892 }
893 }
894
895 /* Don't die if just one of these was set. */
896 if (EQ (left, Qunbound))
897 {
898 left_no_change = 1;
fbd6baed
GV
899 if (f->output_data.w32->left_pos < 0)
900 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 901 else
fbd6baed 902 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
903 }
904 if (EQ (top, Qunbound))
905 {
906 top_no_change = 1;
fbd6baed
GV
907 if (f->output_data.w32->top_pos < 0)
908 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 909 else
fbd6baed 910 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
911 }
912
913 /* If one of the icon positions was not set, preserve or default it. */
914 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
915 {
916 icon_left_no_change = 1;
917 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
918 if (NILP (icon_left))
919 XSETINT (icon_left, 0);
920 }
921 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
922 {
923 icon_top_no_change = 1;
924 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
925 if (NILP (icon_top))
926 XSETINT (icon_top, 0);
927 }
928
ee78dc32
GV
929 /* Don't set these parameters unless they've been explicitly
930 specified. The window might be mapped or resized while we're in
931 this function, and we don't want to override that unless the lisp
932 code has asked for it.
933
934 Don't set these parameters unless they actually differ from the
935 window's current parameters; the window may not actually exist
936 yet. */
937 {
938 Lisp_Object frame;
939
940 check_frame_size (f, &height, &width);
941
942 XSETFRAME (frame, f);
943
dfff8a69
JR
944 if (width != FRAME_WIDTH (f)
945 || height != FRAME_HEIGHT (f)
946 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 947 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
948
949 if ((!NILP (left) || !NILP (top))
950 && ! (left_no_change && top_no_change)
fbd6baed
GV
951 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
952 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
953 {
954 int leftpos = 0;
955 int toppos = 0;
956
957 /* Record the signs. */
fbd6baed 958 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 959 if (EQ (left, Qminus))
fbd6baed 960 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
961 else if (INTEGERP (left))
962 {
963 leftpos = XINT (left);
964 if (leftpos < 0)
fbd6baed 965 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 966 }
8e713be6
KR
967 else if (CONSP (left) && EQ (XCAR (left), Qminus)
968 && CONSP (XCDR (left))
969 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 970 {
8e713be6 971 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 972 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 973 }
8e713be6
KR
974 else if (CONSP (left) && EQ (XCAR (left), Qplus)
975 && CONSP (XCDR (left))
976 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 977 {
8e713be6 978 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
979 }
980
981 if (EQ (top, Qminus))
fbd6baed 982 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
983 else if (INTEGERP (top))
984 {
985 toppos = XINT (top);
986 if (toppos < 0)
fbd6baed 987 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 988 }
8e713be6
KR
989 else if (CONSP (top) && EQ (XCAR (top), Qminus)
990 && CONSP (XCDR (top))
991 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 992 {
8e713be6 993 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 994 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 995 }
8e713be6
KR
996 else if (CONSP (top) && EQ (XCAR (top), Qplus)
997 && CONSP (XCDR (top))
998 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 999 {
8e713be6 1000 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1001 }
1002
1003
1004 /* Store the numeric value of the position. */
fbd6baed
GV
1005 f->output_data.w32->top_pos = toppos;
1006 f->output_data.w32->left_pos = leftpos;
ee78dc32 1007
fbd6baed 1008 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1009
1010 /* Actually set that position, and convert to absolute. */
1011 x_set_offset (f, leftpos, toppos, -1);
1012 }
1013
1014 if ((!NILP (icon_left) || !NILP (icon_top))
1015 && ! (icon_left_no_change && icon_top_no_change))
1016 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1017 }
5878523b
RS
1018
1019 UNGCPRO;
ee78dc32
GV
1020}
1021
1022/* Store the screen positions of frame F into XPTR and YPTR.
1023 These are the positions of the containing window manager window,
1024 not Emacs's own window. */
1025
1026void
1027x_real_positions (f, xptr, yptr)
1028 FRAME_PTR f;
1029 int *xptr, *yptr;
1030{
1031 POINT pt;
3c190163
GV
1032
1033 {
1034 RECT rect;
ee78dc32 1035
fbd6baed
GV
1036 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1037 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 1038
3c190163
GV
1039 pt.x = rect.left;
1040 pt.y = rect.top;
1041 }
ee78dc32 1042
fbd6baed 1043 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
1044
1045 *xptr = pt.x;
1046 *yptr = pt.y;
1047}
1048
1049/* Insert a description of internally-recorded parameters of frame X
1050 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1051 Only parameters that are specific to W32
ee78dc32
GV
1052 and whose values are not correctly recorded in the frame's
1053 param_alist need to be considered here. */
1054
dfff8a69 1055void
ee78dc32
GV
1056x_report_frame_params (f, alistptr)
1057 struct frame *f;
1058 Lisp_Object *alistptr;
1059{
1060 char buf[16];
1061 Lisp_Object tem;
1062
1063 /* Represent negative positions (off the top or left screen edge)
1064 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1065 XSETINT (tem, f->output_data.w32->left_pos);
1066 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1067 store_in_alist (alistptr, Qleft, tem);
1068 else
1069 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1070
fbd6baed
GV
1071 XSETINT (tem, f->output_data.w32->top_pos);
1072 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1073 store_in_alist (alistptr, Qtop, tem);
1074 else
1075 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1076
1077 store_in_alist (alistptr, Qborder_width,
fbd6baed 1078 make_number (f->output_data.w32->border_width));
ee78dc32 1079 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1080 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1081 store_in_alist (alistptr, Qleft_fringe,
1082 make_number (f->output_data.w32->left_fringe_width));
1083 store_in_alist (alistptr, Qright_fringe,
1084 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1085 store_in_alist (alistptr, Qscroll_bar_width,
1086 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1087 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1088 : 0));
fbd6baed 1089 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1090 store_in_alist (alistptr, Qwindow_id,
1091 build_string (buf));
1092 store_in_alist (alistptr, Qicon_name, f->icon_name);
1093 FRAME_SAMPLE_VISIBILITY (f);
1094 store_in_alist (alistptr, Qvisibility,
1095 (FRAME_VISIBLE_P (f) ? Qt
1096 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1097 store_in_alist (alistptr, Qdisplay,
8e713be6 1098 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1099}
1100\f
1101
74e1aeec
JR
1102DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1103 Sw32_define_rgb_color, 4, 4, 0,
1104 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1105This adds or updates a named color to w32-color-map, making it
1106available for use. The original entry's RGB ref is returned, or nil
1107if the entry is new. */)
5ac45f98
GV
1108 (red, green, blue, name)
1109 Lisp_Object red, green, blue, name;
ee78dc32 1110{
5ac45f98
GV
1111 Lisp_Object rgb;
1112 Lisp_Object oldrgb = Qnil;
1113 Lisp_Object entry;
1114
b7826503
PJ
1115 CHECK_NUMBER (red);
1116 CHECK_NUMBER (green);
1117 CHECK_NUMBER (blue);
1118 CHECK_STRING (name);
ee78dc32 1119
5ac45f98 1120 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1121
5ac45f98 1122 BLOCK_INPUT;
ee78dc32 1123
fbd6baed
GV
1124 /* replace existing entry in w32-color-map or add new entry. */
1125 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1126 if (NILP (entry))
1127 {
1128 entry = Fcons (name, rgb);
fbd6baed 1129 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1130 }
1131 else
1132 {
1133 oldrgb = Fcdr (entry);
1134 Fsetcdr (entry, rgb);
1135 }
1136
1137 UNBLOCK_INPUT;
1138
1139 return (oldrgb);
ee78dc32
GV
1140}
1141
74e1aeec
JR
1142DEFUN ("w32-load-color-file", Fw32_load_color_file,
1143 Sw32_load_color_file, 1, 1, 0,
1144 doc: /* Create an alist of color entries from an external file.
1145Assign this value to w32-color-map to replace the existing color map.
1146
1147The file should define one named RGB color per line like so:
1148 R G B name
1149where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1150 (filename)
1151 Lisp_Object filename;
1152{
1153 FILE *fp;
1154 Lisp_Object cmap = Qnil;
1155 Lisp_Object abspath;
1156
b7826503 1157 CHECK_STRING (filename);
5ac45f98
GV
1158 abspath = Fexpand_file_name (filename, Qnil);
1159
1160 fp = fopen (XSTRING (filename)->data, "rt");
1161 if (fp)
1162 {
1163 char buf[512];
1164 int red, green, blue;
1165 int num;
1166
1167 BLOCK_INPUT;
1168
1169 while (fgets (buf, sizeof (buf), fp) != NULL) {
1170 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1171 {
1172 char *name = buf + num;
1173 num = strlen (name) - 1;
1174 if (name[num] == '\n')
1175 name[num] = 0;
1176 cmap = Fcons (Fcons (build_string (name),
1177 make_number (RGB (red, green, blue))),
1178 cmap);
1179 }
1180 }
1181 fclose (fp);
1182
1183 UNBLOCK_INPUT;
1184 }
1185
1186 return cmap;
1187}
ee78dc32 1188
fbd6baed 1189/* The default colors for the w32 color map */
ee78dc32
GV
1190typedef struct colormap_t
1191{
1192 char *name;
1193 COLORREF colorref;
1194} colormap_t;
1195
fbd6baed 1196colormap_t w32_color_map[] =
ee78dc32 1197{
1da8a614
GV
1198 {"snow" , PALETTERGB (255,250,250)},
1199 {"ghost white" , PALETTERGB (248,248,255)},
1200 {"GhostWhite" , PALETTERGB (248,248,255)},
1201 {"white smoke" , PALETTERGB (245,245,245)},
1202 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1203 {"gainsboro" , PALETTERGB (220,220,220)},
1204 {"floral white" , PALETTERGB (255,250,240)},
1205 {"FloralWhite" , PALETTERGB (255,250,240)},
1206 {"old lace" , PALETTERGB (253,245,230)},
1207 {"OldLace" , PALETTERGB (253,245,230)},
1208 {"linen" , PALETTERGB (250,240,230)},
1209 {"antique white" , PALETTERGB (250,235,215)},
1210 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1211 {"papaya whip" , PALETTERGB (255,239,213)},
1212 {"PapayaWhip" , PALETTERGB (255,239,213)},
1213 {"blanched almond" , PALETTERGB (255,235,205)},
1214 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1215 {"bisque" , PALETTERGB (255,228,196)},
1216 {"peach puff" , PALETTERGB (255,218,185)},
1217 {"PeachPuff" , PALETTERGB (255,218,185)},
1218 {"navajo white" , PALETTERGB (255,222,173)},
1219 {"NavajoWhite" , PALETTERGB (255,222,173)},
1220 {"moccasin" , PALETTERGB (255,228,181)},
1221 {"cornsilk" , PALETTERGB (255,248,220)},
1222 {"ivory" , PALETTERGB (255,255,240)},
1223 {"lemon chiffon" , PALETTERGB (255,250,205)},
1224 {"LemonChiffon" , PALETTERGB (255,250,205)},
1225 {"seashell" , PALETTERGB (255,245,238)},
1226 {"honeydew" , PALETTERGB (240,255,240)},
1227 {"mint cream" , PALETTERGB (245,255,250)},
1228 {"MintCream" , PALETTERGB (245,255,250)},
1229 {"azure" , PALETTERGB (240,255,255)},
1230 {"alice blue" , PALETTERGB (240,248,255)},
1231 {"AliceBlue" , PALETTERGB (240,248,255)},
1232 {"lavender" , PALETTERGB (230,230,250)},
1233 {"lavender blush" , PALETTERGB (255,240,245)},
1234 {"LavenderBlush" , PALETTERGB (255,240,245)},
1235 {"misty rose" , PALETTERGB (255,228,225)},
1236 {"MistyRose" , PALETTERGB (255,228,225)},
1237 {"white" , PALETTERGB (255,255,255)},
1238 {"black" , PALETTERGB ( 0, 0, 0)},
1239 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1240 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1241 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1242 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1243 {"dim gray" , PALETTERGB (105,105,105)},
1244 {"DimGray" , PALETTERGB (105,105,105)},
1245 {"dim grey" , PALETTERGB (105,105,105)},
1246 {"DimGrey" , PALETTERGB (105,105,105)},
1247 {"slate gray" , PALETTERGB (112,128,144)},
1248 {"SlateGray" , PALETTERGB (112,128,144)},
1249 {"slate grey" , PALETTERGB (112,128,144)},
1250 {"SlateGrey" , PALETTERGB (112,128,144)},
1251 {"light slate gray" , PALETTERGB (119,136,153)},
1252 {"LightSlateGray" , PALETTERGB (119,136,153)},
1253 {"light slate grey" , PALETTERGB (119,136,153)},
1254 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1255 {"gray" , PALETTERGB (190,190,190)},
1256 {"grey" , PALETTERGB (190,190,190)},
1257 {"light grey" , PALETTERGB (211,211,211)},
1258 {"LightGrey" , PALETTERGB (211,211,211)},
1259 {"light gray" , PALETTERGB (211,211,211)},
1260 {"LightGray" , PALETTERGB (211,211,211)},
1261 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1262 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1263 {"navy" , PALETTERGB ( 0, 0,128)},
1264 {"navy blue" , PALETTERGB ( 0, 0,128)},
1265 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1266 {"cornflower blue" , PALETTERGB (100,149,237)},
1267 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1268 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1269 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1270 {"slate blue" , PALETTERGB (106, 90,205)},
1271 {"SlateBlue" , PALETTERGB (106, 90,205)},
1272 {"medium slate blue" , PALETTERGB (123,104,238)},
1273 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1274 {"light slate blue" , PALETTERGB (132,112,255)},
1275 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1276 {"medium blue" , PALETTERGB ( 0, 0,205)},
1277 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1278 {"royal blue" , PALETTERGB ( 65,105,225)},
1279 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1280 {"blue" , PALETTERGB ( 0, 0,255)},
1281 {"dodger blue" , PALETTERGB ( 30,144,255)},
1282 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1283 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1284 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1285 {"sky blue" , PALETTERGB (135,206,235)},
1286 {"SkyBlue" , PALETTERGB (135,206,235)},
1287 {"light sky blue" , PALETTERGB (135,206,250)},
1288 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1289 {"steel blue" , PALETTERGB ( 70,130,180)},
1290 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1291 {"light steel blue" , PALETTERGB (176,196,222)},
1292 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1293 {"light blue" , PALETTERGB (173,216,230)},
1294 {"LightBlue" , PALETTERGB (173,216,230)},
1295 {"powder blue" , PALETTERGB (176,224,230)},
1296 {"PowderBlue" , PALETTERGB (176,224,230)},
1297 {"pale turquoise" , PALETTERGB (175,238,238)},
1298 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1299 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1300 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1301 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1302 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1303 {"turquoise" , PALETTERGB ( 64,224,208)},
1304 {"cyan" , PALETTERGB ( 0,255,255)},
1305 {"light cyan" , PALETTERGB (224,255,255)},
1306 {"LightCyan" , PALETTERGB (224,255,255)},
1307 {"cadet blue" , PALETTERGB ( 95,158,160)},
1308 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1309 {"medium aquamarine" , PALETTERGB (102,205,170)},
1310 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1311 {"aquamarine" , PALETTERGB (127,255,212)},
1312 {"dark green" , PALETTERGB ( 0,100, 0)},
1313 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1314 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1315 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1316 {"dark sea green" , PALETTERGB (143,188,143)},
1317 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1318 {"sea green" , PALETTERGB ( 46,139, 87)},
1319 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1320 {"medium sea green" , PALETTERGB ( 60,179,113)},
1321 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1322 {"light sea green" , PALETTERGB ( 32,178,170)},
1323 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1324 {"pale green" , PALETTERGB (152,251,152)},
1325 {"PaleGreen" , PALETTERGB (152,251,152)},
1326 {"spring green" , PALETTERGB ( 0,255,127)},
1327 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1328 {"lawn green" , PALETTERGB (124,252, 0)},
1329 {"LawnGreen" , PALETTERGB (124,252, 0)},
1330 {"green" , PALETTERGB ( 0,255, 0)},
1331 {"chartreuse" , PALETTERGB (127,255, 0)},
1332 {"medium spring green" , PALETTERGB ( 0,250,154)},
1333 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1334 {"green yellow" , PALETTERGB (173,255, 47)},
1335 {"GreenYellow" , PALETTERGB (173,255, 47)},
1336 {"lime green" , PALETTERGB ( 50,205, 50)},
1337 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1338 {"yellow green" , PALETTERGB (154,205, 50)},
1339 {"YellowGreen" , PALETTERGB (154,205, 50)},
1340 {"forest green" , PALETTERGB ( 34,139, 34)},
1341 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1342 {"olive drab" , PALETTERGB (107,142, 35)},
1343 {"OliveDrab" , PALETTERGB (107,142, 35)},
1344 {"dark khaki" , PALETTERGB (189,183,107)},
1345 {"DarkKhaki" , PALETTERGB (189,183,107)},
1346 {"khaki" , PALETTERGB (240,230,140)},
1347 {"pale goldenrod" , PALETTERGB (238,232,170)},
1348 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1349 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1350 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1351 {"light yellow" , PALETTERGB (255,255,224)},
1352 {"LightYellow" , PALETTERGB (255,255,224)},
1353 {"yellow" , PALETTERGB (255,255, 0)},
1354 {"gold" , PALETTERGB (255,215, 0)},
1355 {"light goldenrod" , PALETTERGB (238,221,130)},
1356 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1357 {"goldenrod" , PALETTERGB (218,165, 32)},
1358 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1359 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1360 {"rosy brown" , PALETTERGB (188,143,143)},
1361 {"RosyBrown" , PALETTERGB (188,143,143)},
1362 {"indian red" , PALETTERGB (205, 92, 92)},
1363 {"IndianRed" , PALETTERGB (205, 92, 92)},
1364 {"saddle brown" , PALETTERGB (139, 69, 19)},
1365 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1366 {"sienna" , PALETTERGB (160, 82, 45)},
1367 {"peru" , PALETTERGB (205,133, 63)},
1368 {"burlywood" , PALETTERGB (222,184,135)},
1369 {"beige" , PALETTERGB (245,245,220)},
1370 {"wheat" , PALETTERGB (245,222,179)},
1371 {"sandy brown" , PALETTERGB (244,164, 96)},
1372 {"SandyBrown" , PALETTERGB (244,164, 96)},
1373 {"tan" , PALETTERGB (210,180,140)},
1374 {"chocolate" , PALETTERGB (210,105, 30)},
1375 {"firebrick" , PALETTERGB (178,34, 34)},
1376 {"brown" , PALETTERGB (165,42, 42)},
1377 {"dark salmon" , PALETTERGB (233,150,122)},
1378 {"DarkSalmon" , PALETTERGB (233,150,122)},
1379 {"salmon" , PALETTERGB (250,128,114)},
1380 {"light salmon" , PALETTERGB (255,160,122)},
1381 {"LightSalmon" , PALETTERGB (255,160,122)},
1382 {"orange" , PALETTERGB (255,165, 0)},
1383 {"dark orange" , PALETTERGB (255,140, 0)},
1384 {"DarkOrange" , PALETTERGB (255,140, 0)},
1385 {"coral" , PALETTERGB (255,127, 80)},
1386 {"light coral" , PALETTERGB (240,128,128)},
1387 {"LightCoral" , PALETTERGB (240,128,128)},
1388 {"tomato" , PALETTERGB (255, 99, 71)},
1389 {"orange red" , PALETTERGB (255, 69, 0)},
1390 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1391 {"red" , PALETTERGB (255, 0, 0)},
1392 {"hot pink" , PALETTERGB (255,105,180)},
1393 {"HotPink" , PALETTERGB (255,105,180)},
1394 {"deep pink" , PALETTERGB (255, 20,147)},
1395 {"DeepPink" , PALETTERGB (255, 20,147)},
1396 {"pink" , PALETTERGB (255,192,203)},
1397 {"light pink" , PALETTERGB (255,182,193)},
1398 {"LightPink" , PALETTERGB (255,182,193)},
1399 {"pale violet red" , PALETTERGB (219,112,147)},
1400 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1401 {"maroon" , PALETTERGB (176, 48, 96)},
1402 {"medium violet red" , PALETTERGB (199, 21,133)},
1403 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1404 {"violet red" , PALETTERGB (208, 32,144)},
1405 {"VioletRed" , PALETTERGB (208, 32,144)},
1406 {"magenta" , PALETTERGB (255, 0,255)},
1407 {"violet" , PALETTERGB (238,130,238)},
1408 {"plum" , PALETTERGB (221,160,221)},
1409 {"orchid" , PALETTERGB (218,112,214)},
1410 {"medium orchid" , PALETTERGB (186, 85,211)},
1411 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1412 {"dark orchid" , PALETTERGB (153, 50,204)},
1413 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1414 {"dark violet" , PALETTERGB (148, 0,211)},
1415 {"DarkViolet" , PALETTERGB (148, 0,211)},
1416 {"blue violet" , PALETTERGB (138, 43,226)},
1417 {"BlueViolet" , PALETTERGB (138, 43,226)},
1418 {"purple" , PALETTERGB (160, 32,240)},
1419 {"medium purple" , PALETTERGB (147,112,219)},
1420 {"MediumPurple" , PALETTERGB (147,112,219)},
1421 {"thistle" , PALETTERGB (216,191,216)},
1422 {"gray0" , PALETTERGB ( 0, 0, 0)},
1423 {"grey0" , PALETTERGB ( 0, 0, 0)},
1424 {"dark grey" , PALETTERGB (169,169,169)},
1425 {"DarkGrey" , PALETTERGB (169,169,169)},
1426 {"dark gray" , PALETTERGB (169,169,169)},
1427 {"DarkGray" , PALETTERGB (169,169,169)},
1428 {"dark blue" , PALETTERGB ( 0, 0,139)},
1429 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1430 {"dark cyan" , PALETTERGB ( 0,139,139)},
1431 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1432 {"dark magenta" , PALETTERGB (139, 0,139)},
1433 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1434 {"dark red" , PALETTERGB (139, 0, 0)},
1435 {"DarkRed" , PALETTERGB (139, 0, 0)},
1436 {"light green" , PALETTERGB (144,238,144)},
1437 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1438};
1439
fbd6baed 1440DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1441 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1442 ()
1443{
1444 int i;
fbd6baed 1445 colormap_t *pc = w32_color_map;
ee78dc32
GV
1446 Lisp_Object cmap;
1447
1448 BLOCK_INPUT;
1449
1450 cmap = Qnil;
1451
fbd6baed 1452 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1453 pc++, i++)
1454 cmap = Fcons (Fcons (build_string (pc->name),
1455 make_number (pc->colorref)),
1456 cmap);
1457
1458 UNBLOCK_INPUT;
1459
1460 return (cmap);
1461}
ee78dc32
GV
1462
1463Lisp_Object
fbd6baed 1464w32_to_x_color (rgb)
ee78dc32
GV
1465 Lisp_Object rgb;
1466{
1467 Lisp_Object color;
1468
b7826503 1469 CHECK_NUMBER (rgb);
ee78dc32
GV
1470
1471 BLOCK_INPUT;
1472
fbd6baed 1473 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1474
1475 UNBLOCK_INPUT;
1476
1477 if (!NILP (color))
1478 return (Fcar (color));
1479 else
1480 return Qnil;
1481}
1482
5d7fed93
GV
1483COLORREF
1484w32_color_map_lookup (colorname)
1485 char *colorname;
1486{
1487 Lisp_Object tail, ret = Qnil;
1488
1489 BLOCK_INPUT;
1490
1491 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1492 {
1493 register Lisp_Object elt, tem;
1494
1495 elt = Fcar (tail);
1496 if (!CONSP (elt)) continue;
1497
1498 tem = Fcar (elt);
1499
1500 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1501 {
1502 ret = XUINT (Fcdr (elt));
1503 break;
1504 }
1505
1506 QUIT;
1507 }
1508
1509
1510 UNBLOCK_INPUT;
1511
1512 return ret;
1513}
1514
ee78dc32 1515COLORREF
fbd6baed 1516x_to_w32_color (colorname)
ee78dc32
GV
1517 char * colorname;
1518{
8edb0a6f
JR
1519 register Lisp_Object ret = Qnil;
1520
ee78dc32 1521 BLOCK_INPUT;
1edf84e7
GV
1522
1523 if (colorname[0] == '#')
1524 {
1525 /* Could be an old-style RGB Device specification. */
1526 char *color;
1527 int size;
1528 color = colorname + 1;
1529
1530 size = strlen(color);
1531 if (size == 3 || size == 6 || size == 9 || size == 12)
1532 {
1533 UINT colorval;
1534 int i, pos;
1535 pos = 0;
1536 size /= 3;
1537 colorval = 0;
1538
1539 for (i = 0; i < 3; i++)
1540 {
1541 char *end;
1542 char t;
1543 unsigned long value;
1544
1545 /* The check for 'x' in the following conditional takes into
1546 account the fact that strtol allows a "0x" in front of
1547 our numbers, and we don't. */
1548 if (!isxdigit(color[0]) || color[1] == 'x')
1549 break;
1550 t = color[size];
1551 color[size] = '\0';
1552 value = strtoul(color, &end, 16);
1553 color[size] = t;
1554 if (errno == ERANGE || end - color != size)
1555 break;
1556 switch (size)
1557 {
1558 case 1:
1559 value = value * 0x10;
1560 break;
1561 case 2:
1562 break;
1563 case 3:
1564 value /= 0x10;
1565 break;
1566 case 4:
1567 value /= 0x100;
1568 break;
1569 }
1570 colorval |= (value << pos);
1571 pos += 0x8;
1572 if (i == 2)
1573 {
1574 UNBLOCK_INPUT;
1575 return (colorval);
1576 }
1577 color = end;
1578 }
1579 }
1580 }
1581 else if (strnicmp(colorname, "rgb:", 4) == 0)
1582 {
1583 char *color;
1584 UINT colorval;
1585 int i, pos;
1586 pos = 0;
1587
1588 colorval = 0;
1589 color = colorname + 4;
1590 for (i = 0; i < 3; i++)
1591 {
1592 char *end;
1593 unsigned long value;
1594
1595 /* The check for 'x' in the following conditional takes into
1596 account the fact that strtol allows a "0x" in front of
1597 our numbers, and we don't. */
1598 if (!isxdigit(color[0]) || color[1] == 'x')
1599 break;
1600 value = strtoul(color, &end, 16);
1601 if (errno == ERANGE)
1602 break;
1603 switch (end - color)
1604 {
1605 case 1:
1606 value = value * 0x10 + value;
1607 break;
1608 case 2:
1609 break;
1610 case 3:
1611 value /= 0x10;
1612 break;
1613 case 4:
1614 value /= 0x100;
1615 break;
1616 default:
1617 value = ULONG_MAX;
1618 }
1619 if (value == ULONG_MAX)
1620 break;
1621 colorval |= (value << pos);
1622 pos += 0x8;
1623 if (i == 2)
1624 {
1625 if (*end != '\0')
1626 break;
1627 UNBLOCK_INPUT;
1628 return (colorval);
1629 }
1630 if (*end != '/')
1631 break;
1632 color = end + 1;
1633 }
1634 }
1635 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1636 {
1637 /* This is an RGB Intensity specification. */
1638 char *color;
1639 UINT colorval;
1640 int i, pos;
1641 pos = 0;
1642
1643 colorval = 0;
1644 color = colorname + 5;
1645 for (i = 0; i < 3; i++)
1646 {
1647 char *end;
1648 double value;
1649 UINT val;
1650
1651 value = strtod(color, &end);
1652 if (errno == ERANGE)
1653 break;
1654 if (value < 0.0 || value > 1.0)
1655 break;
1656 val = (UINT)(0x100 * value);
1657 /* We used 0x100 instead of 0xFF to give an continuous
1658 range between 0.0 and 1.0 inclusive. The next statement
1659 fixes the 1.0 case. */
1660 if (val == 0x100)
1661 val = 0xFF;
1662 colorval |= (val << pos);
1663 pos += 0x8;
1664 if (i == 2)
1665 {
1666 if (*end != '\0')
1667 break;
1668 UNBLOCK_INPUT;
1669 return (colorval);
1670 }
1671 if (*end != '/')
1672 break;
1673 color = end + 1;
1674 }
1675 }
1676 /* I am not going to attempt to handle any of the CIE color schemes
1677 or TekHVC, since I don't know the algorithms for conversion to
1678 RGB. */
f695b4b1
GV
1679
1680 /* If we fail to lookup the color name in w32_color_map, then check the
1681 colorname to see if it can be crudely approximated: If the X color
1682 ends in a number (e.g., "darkseagreen2"), strip the number and
1683 return the result of looking up the base color name. */
1684 ret = w32_color_map_lookup (colorname);
1685 if (NILP (ret))
ee78dc32 1686 {
f695b4b1 1687 int len = strlen (colorname);
ee78dc32 1688
f695b4b1
GV
1689 if (isdigit (colorname[len - 1]))
1690 {
8b77111c 1691 char *ptr, *approx = alloca (len + 1);
ee78dc32 1692
f695b4b1
GV
1693 strcpy (approx, colorname);
1694 ptr = &approx[len - 1];
1695 while (ptr > approx && isdigit (*ptr))
1696 *ptr-- = '\0';
ee78dc32 1697
f695b4b1 1698 ret = w32_color_map_lookup (approx);
ee78dc32 1699 }
ee78dc32
GV
1700 }
1701
1702 UNBLOCK_INPUT;
ee78dc32
GV
1703 return ret;
1704}
1705
5ac45f98
GV
1706
1707void
fbd6baed 1708w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1709{
fbd6baed 1710 struct w32_palette_entry * list;
5ac45f98
GV
1711 LOGPALETTE * log_palette;
1712 HPALETTE new_palette;
1713 int i;
1714
1715 /* don't bother trying to create palette if not supported */
fbd6baed 1716 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1717 return;
1718
1719 log_palette = (LOGPALETTE *)
1720 alloca (sizeof (LOGPALETTE) +
fbd6baed 1721 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1722 log_palette->palVersion = 0x300;
fbd6baed 1723 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1724
fbd6baed 1725 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1726 for (i = 0;
fbd6baed 1727 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1728 i++, list = list->next)
1729 log_palette->palPalEntry[i] = list->entry;
1730
1731 new_palette = CreatePalette (log_palette);
1732
1733 enter_crit ();
1734
fbd6baed
GV
1735 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1736 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1737 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1738
1739 /* Realize display palette and garbage all frames. */
1740 release_frame_dc (f, get_frame_dc (f));
1741
1742 leave_crit ();
1743}
1744
fbd6baed
GV
1745#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1746#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1747 do \
1748 { \
1749 pe.peRed = GetRValue (color); \
1750 pe.peGreen = GetGValue (color); \
1751 pe.peBlue = GetBValue (color); \
1752 pe.peFlags = 0; \
1753 } while (0)
1754
1755#if 0
1756/* Keep these around in case we ever want to track color usage. */
1757void
fbd6baed 1758w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1759{
fbd6baed 1760 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1761
fbd6baed 1762 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1763 return;
1764
1765 /* check if color is already mapped */
1766 while (list)
1767 {
fbd6baed 1768 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1769 {
1770 ++list->refcount;
1771 return;
1772 }
1773 list = list->next;
1774 }
1775
1776 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1777 list = (struct w32_palette_entry *)
1778 xmalloc (sizeof (struct w32_palette_entry));
1779 SET_W32_COLOR (list->entry, color);
5ac45f98 1780 list->refcount = 1;
fbd6baed
GV
1781 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1782 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1783 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1784
1785 /* set flag that palette must be regenerated */
fbd6baed 1786 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1787}
1788
1789void
fbd6baed 1790w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1791{
fbd6baed
GV
1792 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1793 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1794
fbd6baed 1795 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1796 return;
1797
1798 /* check if color is already mapped */
1799 while (list)
1800 {
fbd6baed 1801 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1802 {
1803 if (--list->refcount == 0)
1804 {
1805 *prev = list->next;
1806 xfree (list);
fbd6baed 1807 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1808 break;
1809 }
1810 else
1811 return;
1812 }
1813 prev = &list->next;
1814 list = list->next;
1815 }
1816
1817 /* set flag that palette must be regenerated */
fbd6baed 1818 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1819}
1820#endif
1821
6fc2811b
JR
1822
1823/* Gamma-correct COLOR on frame F. */
1824
1825void
1826gamma_correct (f, color)
1827 struct frame *f;
1828 COLORREF *color;
1829{
1830 if (f->gamma)
1831 {
1832 *color = PALETTERGB (
1833 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1834 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1835 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1836 }
1837}
1838
1839
ee78dc32
GV
1840/* Decide if color named COLOR is valid for the display associated with
1841 the selected frame; if so, return the rgb values in COLOR_DEF.
1842 If ALLOC is nonzero, allocate a new colormap cell. */
1843
1844int
6fc2811b 1845w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1846 FRAME_PTR f;
1847 char *color;
6fc2811b 1848 XColor *color_def;
ee78dc32
GV
1849 int alloc;
1850{
1851 register Lisp_Object tem;
6fc2811b 1852 COLORREF w32_color_ref;
3c190163 1853
fbd6baed 1854 tem = x_to_w32_color (color);
3c190163 1855
ee78dc32
GV
1856 if (!NILP (tem))
1857 {
d88c567c
JR
1858 if (f)
1859 {
1860 /* Apply gamma correction. */
1861 w32_color_ref = XUINT (tem);
1862 gamma_correct (f, &w32_color_ref);
1863 XSETINT (tem, w32_color_ref);
1864 }
9badad41
JR
1865
1866 /* Map this color to the palette if it is enabled. */
fbd6baed 1867 if (!NILP (Vw32_enable_palette))
5ac45f98 1868 {
fbd6baed 1869 struct w32_palette_entry * entry =
d88c567c 1870 one_w32_display_info.color_list;
fbd6baed 1871 struct w32_palette_entry ** prev =
d88c567c 1872 &one_w32_display_info.color_list;
5ac45f98
GV
1873
1874 /* check if color is already mapped */
1875 while (entry)
1876 {
fbd6baed 1877 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1878 break;
1879 prev = &entry->next;
1880 entry = entry->next;
1881 }
1882
1883 if (entry == NULL && alloc)
1884 {
1885 /* not already mapped, so add to list */
fbd6baed
GV
1886 entry = (struct w32_palette_entry *)
1887 xmalloc (sizeof (struct w32_palette_entry));
1888 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1889 entry->next = NULL;
1890 *prev = entry;
d88c567c 1891 one_w32_display_info.num_colors++;
5ac45f98
GV
1892
1893 /* set flag that palette must be regenerated */
d88c567c 1894 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1895 }
1896 }
1897 /* Ensure COLORREF value is snapped to nearest color in (default)
1898 palette by simulating the PALETTERGB macro. This works whether
1899 or not the display device has a palette. */
6fc2811b
JR
1900 w32_color_ref = XUINT (tem) | 0x2000000;
1901
6fc2811b
JR
1902 color_def->pixel = w32_color_ref;
1903 color_def->red = GetRValue (w32_color_ref);
1904 color_def->green = GetGValue (w32_color_ref);
1905 color_def->blue = GetBValue (w32_color_ref);
1906
ee78dc32 1907 return 1;
5ac45f98 1908 }
7fb46567 1909 else
3c190163
GV
1910 {
1911 return 0;
1912 }
ee78dc32
GV
1913}
1914
1915/* Given a string ARG naming a color, compute a pixel value from it
1916 suitable for screen F.
1917 If F is not a color screen, return DEF (default) regardless of what
1918 ARG says. */
1919
1920int
1921x_decode_color (f, arg, def)
1922 FRAME_PTR f;
1923 Lisp_Object arg;
1924 int def;
1925{
6fc2811b 1926 XColor cdef;
ee78dc32 1927
b7826503 1928 CHECK_STRING (arg);
ee78dc32
GV
1929
1930 if (strcmp (XSTRING (arg)->data, "black") == 0)
1931 return BLACK_PIX_DEFAULT (f);
1932 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1933 return WHITE_PIX_DEFAULT (f);
1934
fbd6baed 1935 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1936 return def;
1937
6fc2811b 1938 /* w32_defined_color is responsible for coping with failures
ee78dc32 1939 by looking for a near-miss. */
6fc2811b
JR
1940 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1941 return cdef.pixel;
ee78dc32
GV
1942
1943 /* defined_color failed; return an ultimate default. */
1944 return def;
1945}
1946\f
dfff8a69
JR
1947/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1948 the previous value of that parameter, NEW_VALUE is the new value. */
1949
1950static void
1951x_set_line_spacing (f, new_value, old_value)
1952 struct frame *f;
1953 Lisp_Object new_value, old_value;
1954{
1955 if (NILP (new_value))
1956 f->extra_line_spacing = 0;
1957 else if (NATNUMP (new_value))
1958 f->extra_line_spacing = XFASTINT (new_value);
1959 else
1a948b17 1960 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
1961 Fcons (new_value, Qnil)));
1962 if (FRAME_VISIBLE_P (f))
1963 redraw_frame (f);
1964}
1965
1966
6fc2811b
JR
1967/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1968 the previous value of that parameter, NEW_VALUE is the new value. */
1969
1970static void
1971x_set_screen_gamma (f, new_value, old_value)
1972 struct frame *f;
1973 Lisp_Object new_value, old_value;
1974{
1975 if (NILP (new_value))
1976 f->gamma = 0;
1977 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1978 /* The value 0.4545 is the normal viewing gamma. */
1979 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1980 else
1a948b17 1981 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
1982 Fcons (new_value, Qnil)));
1983
1984 clear_face_cache (0);
1985}
1986
1987
ee78dc32
GV
1988/* Functions called only from `x_set_frame_param'
1989 to set individual parameters.
1990
fbd6baed 1991 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1992 the frame is being created and its window does not exist yet.
1993 In that case, just record the parameter's new value
1994 in the standard place; do not attempt to change the window. */
1995
1996void
1997x_set_foreground_color (f, arg, oldval)
1998 struct frame *f;
1999 Lisp_Object arg, oldval;
2000{
3cf3436e
JR
2001 struct w32_output *x = f->output_data.w32;
2002 PIX_TYPE fg, old_fg;
2003
2004 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2005 old_fg = FRAME_FOREGROUND_PIXEL (f);
2006 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2007
fbd6baed 2008 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2009 {
3cf3436e
JR
2010 if (x->cursor_pixel == old_fg)
2011 x->cursor_pixel = fg;
2012
6fc2811b 2013 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2014 if (FRAME_VISIBLE_P (f))
2015 redraw_frame (f);
2016 }
2017}
2018
2019void
2020x_set_background_color (f, arg, oldval)
2021 struct frame *f;
2022 Lisp_Object arg, oldval;
2023{
6fc2811b 2024 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2025 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2026
fbd6baed 2027 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2028 {
6fc2811b
JR
2029 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2030 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2031
6fc2811b 2032 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2033
2034 if (FRAME_VISIBLE_P (f))
2035 redraw_frame (f);
2036 }
2037}
2038
2039void
2040x_set_mouse_color (f, arg, oldval)
2041 struct frame *f;
2042 Lisp_Object arg, oldval;
2043{
ee78dc32 2044 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2045 int count;
ee78dc32
GV
2046 int mask_color;
2047
2048 if (!EQ (Qnil, arg))
fbd6baed 2049 f->output_data.w32->mouse_pixel
ee78dc32 2050 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2051 mask_color = FRAME_BACKGROUND_PIXEL (f);
2052
2053 /* Don't let pointers be invisible. */
fbd6baed 2054 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2055 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2056 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2057
767b1ff0 2058#if 0 /* TODO : cursor changes */
ee78dc32
GV
2059 BLOCK_INPUT;
2060
2061 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2062 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2063
2064 if (!EQ (Qnil, Vx_pointer_shape))
2065 {
b7826503 2066 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2067 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2068 }
2069 else
fbd6baed
GV
2070 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2071 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2072
2073 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2074 {
b7826503 2075 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2076 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2077 XINT (Vx_nontext_pointer_shape));
2078 }
2079 else
fbd6baed
GV
2080 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2081 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2082
0af913d7 2083 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2084 {
b7826503 2085 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2086 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2087 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2088 }
2089 else
0af913d7 2090 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b
JR
2091 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2092
2093 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2094 if (!EQ (Qnil, Vx_mode_pointer_shape))
2095 {
b7826503 2096 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2097 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2098 XINT (Vx_mode_pointer_shape));
2099 }
2100 else
fbd6baed
GV
2101 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2102 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2103
2104 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2105 {
b7826503 2106 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2107 cross_cursor
fbd6baed 2108 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2109 XINT (Vx_sensitive_text_pointer_shape));
2110 }
2111 else
fbd6baed 2112 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2113
4694d762
JR
2114 if (!NILP (Vx_window_horizontal_drag_shape))
2115 {
b7826503 2116 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2117 horizontal_drag_cursor
2118 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2119 XINT (Vx_window_horizontal_drag_shape));
2120 }
2121 else
2122 horizontal_drag_cursor
2123 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2124
ee78dc32 2125 /* Check and report errors with the above calls. */
fbd6baed 2126 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2127 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2128
2129 {
2130 XColor fore_color, back_color;
2131
fbd6baed 2132 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2133 back_color.pixel = mask_color;
fbd6baed
GV
2134 XQueryColor (FRAME_W32_DISPLAY (f),
2135 DefaultColormap (FRAME_W32_DISPLAY (f),
2136 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2137 &fore_color);
fbd6baed
GV
2138 XQueryColor (FRAME_W32_DISPLAY (f),
2139 DefaultColormap (FRAME_W32_DISPLAY (f),
2140 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2141 &back_color);
fbd6baed 2142 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2143 &fore_color, &back_color);
fbd6baed 2144 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2145 &fore_color, &back_color);
fbd6baed 2146 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2147 &fore_color, &back_color);
fbd6baed 2148 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2149 &fore_color, &back_color);
0af913d7 2150 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2151 &fore_color, &back_color);
ee78dc32
GV
2152 }
2153
fbd6baed 2154 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2155 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2156
fbd6baed
GV
2157 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2158 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2159 f->output_data.w32->text_cursor = cursor;
2160
2161 if (nontext_cursor != f->output_data.w32->nontext_cursor
2162 && f->output_data.w32->nontext_cursor != 0)
2163 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2164 f->output_data.w32->nontext_cursor = nontext_cursor;
2165
0af913d7
GM
2166 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2167 && f->output_data.w32->hourglass_cursor != 0)
2168 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2169 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2170
fbd6baed
GV
2171 if (mode_cursor != f->output_data.w32->modeline_cursor
2172 && f->output_data.w32->modeline_cursor != 0)
2173 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2174 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2175
fbd6baed
GV
2176 if (cross_cursor != f->output_data.w32->cross_cursor
2177 && f->output_data.w32->cross_cursor != 0)
2178 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2179 f->output_data.w32->cross_cursor = cross_cursor;
2180
2181 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2182 UNBLOCK_INPUT;
6fc2811b
JR
2183
2184 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2185#endif /* TODO */
ee78dc32
GV
2186}
2187
70a0239a
JR
2188/* Defined in w32term.c. */
2189void x_update_cursor (struct frame *f, int on_p);
2190
ee78dc32
GV
2191void
2192x_set_cursor_color (f, arg, oldval)
2193 struct frame *f;
2194 Lisp_Object arg, oldval;
2195{
70a0239a 2196 unsigned long fore_pixel, pixel;
ee78dc32 2197
dfff8a69 2198 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2199 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2200 WHITE_PIX_DEFAULT (f));
ee78dc32 2201 else
6fc2811b 2202 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2203
6759f872 2204 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2205
2206 /* Make sure that the cursor color differs from the background color. */
70a0239a 2207 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2208 {
70a0239a
JR
2209 pixel = f->output_data.w32->mouse_pixel;
2210 if (pixel == fore_pixel)
6fc2811b 2211 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2212 }
70a0239a 2213
6fc2811b 2214 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
70a0239a 2215 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2216
fbd6baed 2217 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2218 {
2219 if (FRAME_VISIBLE_P (f))
2220 {
70a0239a
JR
2221 x_update_cursor (f, 0);
2222 x_update_cursor (f, 1);
ee78dc32
GV
2223 }
2224 }
6fc2811b
JR
2225
2226 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2227}
2228
33d52f9c
GV
2229/* Set the border-color of frame F to pixel value PIX.
2230 Note that this does not fully take effect if done before
2231 F has an window. */
2232void
2233x_set_border_pixel (f, pix)
2234 struct frame *f;
2235 int pix;
2236{
2237 f->output_data.w32->border_pixel = pix;
2238
2239 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2240 {
2241 if (FRAME_VISIBLE_P (f))
2242 redraw_frame (f);
2243 }
2244}
2245
ee78dc32
GV
2246/* Set the border-color of frame F to value described by ARG.
2247 ARG can be a string naming a color.
2248 The border-color is used for the border that is drawn by the server.
2249 Note that this does not fully take effect if done before
2250 F has a window; it must be redone when the window is created. */
2251
2252void
2253x_set_border_color (f, arg, oldval)
2254 struct frame *f;
2255 Lisp_Object arg, oldval;
2256{
ee78dc32
GV
2257 int pix;
2258
b7826503 2259 CHECK_STRING (arg);
ee78dc32 2260 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2261 x_set_border_pixel (f, pix);
6fc2811b 2262 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2263}
2264
dfff8a69
JR
2265/* Value is the internal representation of the specified cursor type
2266 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2267 of the bar cursor. */
2268
2269enum text_cursor_kinds
2270x_specified_cursor_type (arg, width)
2271 Lisp_Object arg;
2272 int *width;
ee78dc32 2273{
dfff8a69
JR
2274 enum text_cursor_kinds type;
2275
ee78dc32
GV
2276 if (EQ (arg, Qbar))
2277 {
dfff8a69
JR
2278 type = BAR_CURSOR;
2279 *width = 2;
ee78dc32 2280 }
dfff8a69
JR
2281 else if (CONSP (arg)
2282 && EQ (XCAR (arg), Qbar)
2283 && INTEGERP (XCDR (arg))
2284 && XINT (XCDR (arg)) >= 0)
ee78dc32 2285 {
dfff8a69
JR
2286 type = BAR_CURSOR;
2287 *width = XINT (XCDR (arg));
ee78dc32 2288 }
dfff8a69
JR
2289 else if (NILP (arg))
2290 type = NO_CURSOR;
ee78dc32
GV
2291 else
2292 /* Treat anything unknown as "box cursor".
2293 It was bad to signal an error; people have trouble fixing
2294 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2295 type = FILLED_BOX_CURSOR;
2296
2297 return type;
2298}
2299
2300void
2301x_set_cursor_type (f, arg, oldval)
2302 FRAME_PTR f;
2303 Lisp_Object arg, oldval;
2304{
2305 int width;
2306
2307 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2308 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2309
2310 /* Make sure the cursor gets redrawn. This is overkill, but how
2311 often do people change cursor types? */
2312 update_mode_lines++;
2313}
dfff8a69 2314\f
ee78dc32
GV
2315void
2316x_set_icon_type (f, arg, oldval)
2317 struct frame *f;
2318 Lisp_Object arg, oldval;
2319{
ee78dc32
GV
2320 int result;
2321
eb7576ce
GV
2322 if (NILP (arg) && NILP (oldval))
2323 return;
2324
2325 if (STRINGP (arg) && STRINGP (oldval)
2326 && EQ (Fstring_equal (oldval, arg), Qt))
2327 return;
2328
2329 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2330 return;
2331
2332 BLOCK_INPUT;
ee78dc32 2333
eb7576ce 2334 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2335 if (result)
2336 {
2337 UNBLOCK_INPUT;
2338 error ("No icon window available");
2339 }
2340
ee78dc32 2341 UNBLOCK_INPUT;
ee78dc32
GV
2342}
2343
2344/* Return non-nil if frame F wants a bitmap icon. */
2345
2346Lisp_Object
2347x_icon_type (f)
2348 FRAME_PTR f;
2349{
2350 Lisp_Object tem;
2351
2352 tem = assq_no_quit (Qicon_type, f->param_alist);
2353 if (CONSP (tem))
8e713be6 2354 return XCDR (tem);
ee78dc32
GV
2355 else
2356 return Qnil;
2357}
2358
2359void
2360x_set_icon_name (f, arg, oldval)
2361 struct frame *f;
2362 Lisp_Object arg, oldval;
2363{
ee78dc32
GV
2364 if (STRINGP (arg))
2365 {
2366 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2367 return;
2368 }
2369 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2370 return;
2371
2372 f->icon_name = arg;
2373
2374#if 0
fbd6baed 2375 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2376 return;
2377
2378 BLOCK_INPUT;
2379
2380 result = x_text_icon (f,
1edf84e7 2381 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2382 ? f->icon_name
1edf84e7
GV
2383 : !NILP (f->title)
2384 ? f->title
ee78dc32
GV
2385 : f->name))->data);
2386
2387 if (result)
2388 {
2389 UNBLOCK_INPUT;
2390 error ("No icon window available");
2391 }
2392
2393 /* If the window was unmapped (and its icon was mapped),
2394 the new icon is not mapped, so map the window in its stead. */
2395 if (FRAME_VISIBLE_P (f))
2396 {
2397#ifdef USE_X_TOOLKIT
fbd6baed 2398 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2399#endif
fbd6baed 2400 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2401 }
2402
fbd6baed 2403 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2404 UNBLOCK_INPUT;
2405#endif
2406}
2407
2408extern Lisp_Object x_new_font ();
4587b026 2409extern Lisp_Object x_new_fontset();
ee78dc32
GV
2410
2411void
2412x_set_font (f, arg, oldval)
2413 struct frame *f;
2414 Lisp_Object arg, oldval;
2415{
2416 Lisp_Object result;
4587b026 2417 Lisp_Object fontset_name;
4b817373 2418 Lisp_Object frame;
3cf3436e 2419 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2420
b7826503 2421 CHECK_STRING (arg);
ee78dc32 2422
4587b026
GV
2423 fontset_name = Fquery_fontset (arg, Qnil);
2424
ee78dc32 2425 BLOCK_INPUT;
4587b026
GV
2426 result = (STRINGP (fontset_name)
2427 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2428 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2429 UNBLOCK_INPUT;
2430
2431 if (EQ (result, Qnil))
dfff8a69 2432 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2433 else if (EQ (result, Qt))
dfff8a69 2434 error ("The characters of the given font have varying widths");
ee78dc32
GV
2435 else if (STRINGP (result))
2436 {
3cf3436e
JR
2437 if (STRINGP (fontset_name))
2438 {
2439 /* Fontset names are built from ASCII font names, so the
2440 names may be equal despite there was a change. */
2441 if (old_fontset == FRAME_FONTSET (f))
2442 return;
2443 }
2444 else if (!NILP (Fequal (result, oldval)))
dc220243 2445 return;
3cf3436e 2446
ee78dc32 2447 store_frame_param (f, Qfont, result);
6fc2811b 2448 recompute_basic_faces (f);
ee78dc32
GV
2449 }
2450 else
2451 abort ();
4b817373 2452
6fc2811b
JR
2453 do_pending_window_change (0);
2454
2455 /* Don't call `face-set-after-frame-default' when faces haven't been
2456 initialized yet. This is the case when called from
2457 Fx_create_frame. In that case, the X widget or window doesn't
2458 exist either, and we can end up in x_report_frame_params with a
2459 null widget which gives a segfault. */
2460 if (FRAME_FACE_CACHE (f))
2461 {
2462 XSETFRAME (frame, f);
2463 call1 (Qface_set_after_frame_default, frame);
2464 }
ee78dc32
GV
2465}
2466
41c1bdd9
KS
2467static void
2468x_set_fringe_width (f, new_value, old_value)
2469 struct frame *f;
2470 Lisp_Object new_value, old_value;
2471{
2472 x_compute_fringe_widths (f, 1);
2473}
2474
ee78dc32
GV
2475void
2476x_set_border_width (f, arg, oldval)
2477 struct frame *f;
2478 Lisp_Object arg, oldval;
2479{
b7826503 2480 CHECK_NUMBER (arg);
ee78dc32 2481
fbd6baed 2482 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2483 return;
2484
fbd6baed 2485 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2486 error ("Cannot change the border width of a window");
2487
fbd6baed 2488 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2489}
2490
2491void
2492x_set_internal_border_width (f, arg, oldval)
2493 struct frame *f;
2494 Lisp_Object arg, oldval;
2495{
fbd6baed 2496 int old = f->output_data.w32->internal_border_width;
ee78dc32 2497
b7826503 2498 CHECK_NUMBER (arg);
fbd6baed
GV
2499 f->output_data.w32->internal_border_width = XINT (arg);
2500 if (f->output_data.w32->internal_border_width < 0)
2501 f->output_data.w32->internal_border_width = 0;
ee78dc32 2502
fbd6baed 2503 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2504 return;
2505
fbd6baed 2506 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2507 {
ee78dc32 2508 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2509 SET_FRAME_GARBAGED (f);
6fc2811b 2510 do_pending_window_change (0);
ee78dc32 2511 }
a05e2bae
JR
2512 else
2513 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2514}
2515
2516void
2517x_set_visibility (f, value, oldval)
2518 struct frame *f;
2519 Lisp_Object value, oldval;
2520{
2521 Lisp_Object frame;
2522 XSETFRAME (frame, f);
2523
2524 if (NILP (value))
2525 Fmake_frame_invisible (frame, Qt);
2526 else if (EQ (value, Qicon))
2527 Ficonify_frame (frame);
2528 else
2529 Fmake_frame_visible (frame);
2530}
2531
a1258667
JR
2532\f
2533/* Change window heights in windows rooted in WINDOW by N lines. */
2534
2535static void
2536x_change_window_heights (window, n)
2537 Lisp_Object window;
2538 int n;
2539{
2540 struct window *w = XWINDOW (window);
2541
2542 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2543 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2544
2545 if (INTEGERP (w->orig_top))
2546 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2547 if (INTEGERP (w->orig_height))
2548 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2549
2550 /* Handle just the top child in a vertical split. */
2551 if (!NILP (w->vchild))
2552 x_change_window_heights (w->vchild, n);
2553
2554 /* Adjust all children in a horizontal split. */
2555 for (window = w->hchild; !NILP (window); window = w->next)
2556 {
2557 w = XWINDOW (window);
2558 x_change_window_heights (window, n);
2559 }
2560}
2561
ee78dc32
GV
2562void
2563x_set_menu_bar_lines (f, value, oldval)
2564 struct frame *f;
2565 Lisp_Object value, oldval;
2566{
2567 int nlines;
2568 int olines = FRAME_MENU_BAR_LINES (f);
2569
2570 /* Right now, menu bars don't work properly in minibuf-only frames;
2571 most of the commands try to apply themselves to the minibuffer
6fc2811b 2572 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2573 in or split the minibuffer window. */
2574 if (FRAME_MINIBUF_ONLY_P (f))
2575 return;
2576
2577 if (INTEGERP (value))
2578 nlines = XINT (value);
2579 else
2580 nlines = 0;
2581
2582 FRAME_MENU_BAR_LINES (f) = 0;
2583 if (nlines)
2584 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2585 else
2586 {
2587 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2588 free_frame_menubar (f);
2589 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2590
2591 /* Adjust the frame size so that the client (text) dimensions
2592 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2593 set correctly. */
2594 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2595 do_pending_window_change (0);
ee78dc32 2596 }
6fc2811b
JR
2597 adjust_glyphs (f);
2598}
2599
2600
2601/* Set the number of lines used for the tool bar of frame F to VALUE.
2602 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2603 is the old number of tool bar lines. This function changes the
2604 height of all windows on frame F to match the new tool bar height.
2605 The frame's height doesn't change. */
2606
2607void
2608x_set_tool_bar_lines (f, value, oldval)
2609 struct frame *f;
2610 Lisp_Object value, oldval;
2611{
36f8209a
JR
2612 int delta, nlines, root_height;
2613 Lisp_Object root_window;
6fc2811b 2614
dc220243
JR
2615 /* Treat tool bars like menu bars. */
2616 if (FRAME_MINIBUF_ONLY_P (f))
2617 return;
2618
6fc2811b
JR
2619 /* Use VALUE only if an integer >= 0. */
2620 if (INTEGERP (value) && XINT (value) >= 0)
2621 nlines = XFASTINT (value);
2622 else
2623 nlines = 0;
2624
2625 /* Make sure we redisplay all windows in this frame. */
2626 ++windows_or_buffers_changed;
2627
2628 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2629
2630 /* Don't resize the tool-bar to more than we have room for. */
2631 root_window = FRAME_ROOT_WINDOW (f);
2632 root_height = XINT (XWINDOW (root_window)->height);
2633 if (root_height - delta < 1)
2634 {
2635 delta = root_height - 1;
2636 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2637 }
2638
6fc2811b 2639 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2640 x_change_window_heights (root_window, delta);
6fc2811b 2641 adjust_glyphs (f);
36f8209a
JR
2642
2643 /* We also have to make sure that the internal border at the top of
2644 the frame, below the menu bar or tool bar, is redrawn when the
2645 tool bar disappears. This is so because the internal border is
2646 below the tool bar if one is displayed, but is below the menu bar
2647 if there isn't a tool bar. The tool bar draws into the area
2648 below the menu bar. */
2649 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2650 {
2651 updating_frame = f;
2652 clear_frame ();
2653 clear_current_matrices (f);
2654 updating_frame = NULL;
2655 }
2656
2657 /* If the tool bar gets smaller, the internal border below it
2658 has to be cleared. It was formerly part of the display
2659 of the larger tool bar, and updating windows won't clear it. */
2660 if (delta < 0)
2661 {
2662 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2663 int width = PIXEL_WIDTH (f);
2664 int y = nlines * CANON_Y_UNIT (f);
2665
2666 BLOCK_INPUT;
2667 {
2668 HDC hdc = get_frame_dc (f);
2669 w32_clear_area (f, hdc, 0, y, width, height);
2670 release_frame_dc (f, hdc);
2671 }
2672 UNBLOCK_INPUT;
3cf3436e
JR
2673
2674 if (WINDOWP (f->tool_bar_window))
2675 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2676 }
ee78dc32
GV
2677}
2678
6fc2811b 2679
ee78dc32 2680/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2681 w32_id_name.
ee78dc32
GV
2682
2683 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2684 name; if NAME is a string, set F's name to NAME and set
2685 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2686
2687 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2688 suggesting a new name, which lisp code should override; if
2689 F->explicit_name is set, ignore the new name; otherwise, set it. */
2690
2691void
2692x_set_name (f, name, explicit)
2693 struct frame *f;
2694 Lisp_Object name;
2695 int explicit;
2696{
2697 /* Make sure that requests from lisp code override requests from
2698 Emacs redisplay code. */
2699 if (explicit)
2700 {
2701 /* If we're switching from explicit to implicit, we had better
2702 update the mode lines and thereby update the title. */
2703 if (f->explicit_name && NILP (name))
2704 update_mode_lines = 1;
2705
2706 f->explicit_name = ! NILP (name);
2707 }
2708 else if (f->explicit_name)
2709 return;
2710
fbd6baed 2711 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2712 if (NILP (name))
2713 {
2714 /* Check for no change needed in this very common case
2715 before we do any consing. */
fbd6baed 2716 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2717 XSTRING (f->name)->data))
2718 return;
fbd6baed 2719 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2720 }
2721 else
b7826503 2722 CHECK_STRING (name);
ee78dc32
GV
2723
2724 /* Don't change the name if it's already NAME. */
2725 if (! NILP (Fstring_equal (name, f->name)))
2726 return;
2727
1edf84e7
GV
2728 f->name = name;
2729
2730 /* For setting the frame title, the title parameter should override
2731 the name parameter. */
2732 if (! NILP (f->title))
2733 name = f->title;
2734
fbd6baed 2735 if (FRAME_W32_WINDOW (f))
ee78dc32 2736 {
6fc2811b 2737 if (STRING_MULTIBYTE (name))
dfff8a69 2738 name = ENCODE_SYSTEM (name);
6fc2811b 2739
ee78dc32 2740 BLOCK_INPUT;
fbd6baed 2741 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2742 UNBLOCK_INPUT;
2743 }
ee78dc32
GV
2744}
2745
2746/* This function should be called when the user's lisp code has
2747 specified a name for the frame; the name will override any set by the
2748 redisplay code. */
2749void
2750x_explicitly_set_name (f, arg, oldval)
2751 FRAME_PTR f;
2752 Lisp_Object arg, oldval;
2753{
2754 x_set_name (f, arg, 1);
2755}
2756
2757/* This function should be called by Emacs redisplay code to set the
2758 name; names set this way will never override names set by the user's
2759 lisp code. */
2760void
2761x_implicitly_set_name (f, arg, oldval)
2762 FRAME_PTR f;
2763 Lisp_Object arg, oldval;
2764{
2765 x_set_name (f, arg, 0);
2766}
1edf84e7
GV
2767\f
2768/* Change the title of frame F to NAME.
2769 If NAME is nil, use the frame name as the title.
2770
2771 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2772 name; if NAME is a string, set F's name to NAME and set
2773 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2774
2775 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2776 suggesting a new name, which lisp code should override; if
2777 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2778
1edf84e7 2779void
6fc2811b 2780x_set_title (f, name, old_name)
1edf84e7 2781 struct frame *f;
6fc2811b 2782 Lisp_Object name, old_name;
1edf84e7
GV
2783{
2784 /* Don't change the title if it's already NAME. */
2785 if (EQ (name, f->title))
2786 return;
2787
2788 update_mode_lines = 1;
2789
2790 f->title = name;
2791
2792 if (NILP (name))
2793 name = f->name;
2794
2795 if (FRAME_W32_WINDOW (f))
2796 {
6fc2811b 2797 if (STRING_MULTIBYTE (name))
dfff8a69 2798 name = ENCODE_SYSTEM (name);
6fc2811b 2799
1edf84e7
GV
2800 BLOCK_INPUT;
2801 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2802 UNBLOCK_INPUT;
2803 }
2804}
2805\f
ee78dc32
GV
2806void
2807x_set_autoraise (f, arg, oldval)
2808 struct frame *f;
2809 Lisp_Object arg, oldval;
2810{
2811 f->auto_raise = !EQ (Qnil, arg);
2812}
2813
2814void
2815x_set_autolower (f, arg, oldval)
2816 struct frame *f;
2817 Lisp_Object arg, oldval;
2818{
2819 f->auto_lower = !EQ (Qnil, arg);
2820}
2821
2822void
2823x_set_unsplittable (f, arg, oldval)
2824 struct frame *f;
2825 Lisp_Object arg, oldval;
2826{
2827 f->no_split = !NILP (arg);
2828}
2829
2830void
2831x_set_vertical_scroll_bars (f, arg, oldval)
2832 struct frame *f;
2833 Lisp_Object arg, oldval;
2834{
1026b400
RS
2835 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2836 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2837 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2838 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2839 {
1026b400
RS
2840 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2841 vertical_scroll_bar_none :
87996783
GV
2842 /* Put scroll bars on the right by default, as is conventional
2843 on MS-Windows. */
2844 EQ (Qleft, arg)
2845 ? vertical_scroll_bar_left
2846 : vertical_scroll_bar_right;
ee78dc32
GV
2847
2848 /* We set this parameter before creating the window for the
2849 frame, so we can get the geometry right from the start.
2850 However, if the window hasn't been created yet, we shouldn't
2851 call x_set_window_size. */
fbd6baed 2852 if (FRAME_W32_WINDOW (f))
ee78dc32 2853 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2854 do_pending_window_change (0);
ee78dc32
GV
2855 }
2856}
2857
2858void
2859x_set_scroll_bar_width (f, arg, oldval)
2860 struct frame *f;
2861 Lisp_Object arg, oldval;
2862{
6fc2811b
JR
2863 int wid = FONT_WIDTH (f->output_data.w32->font);
2864
ee78dc32
GV
2865 if (NILP (arg))
2866 {
6fc2811b
JR
2867 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2868 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2869 wid - 1) / wid;
2870 if (FRAME_W32_WINDOW (f))
2871 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2872 do_pending_window_change (0);
ee78dc32
GV
2873 }
2874 else if (INTEGERP (arg) && XINT (arg) > 0
2875 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2876 {
ee78dc32 2877 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2878 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2879 + wid-1) / wid;
fbd6baed 2880 if (FRAME_W32_WINDOW (f))
ee78dc32 2881 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2882 do_pending_window_change (0);
ee78dc32 2883 }
6fc2811b
JR
2884 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2885 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2886 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2887}
2888\f
2889/* Subroutines of creating an frame. */
2890
2891/* Make sure that Vx_resource_name is set to a reasonable value.
2892 Fix it up, or set it to `emacs' if it is too hopeless. */
2893
2894static void
2895validate_x_resource_name ()
2896{
6fc2811b 2897 int len = 0;
ee78dc32
GV
2898 /* Number of valid characters in the resource name. */
2899 int good_count = 0;
2900 /* Number of invalid characters in the resource name. */
2901 int bad_count = 0;
2902 Lisp_Object new;
2903 int i;
2904
2905 if (STRINGP (Vx_resource_name))
2906 {
2907 unsigned char *p = XSTRING (Vx_resource_name)->data;
2908 int i;
2909
dfff8a69 2910 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2911
2912 /* Only letters, digits, - and _ are valid in resource names.
2913 Count the valid characters and count the invalid ones. */
2914 for (i = 0; i < len; i++)
2915 {
2916 int c = p[i];
2917 if (! ((c >= 'a' && c <= 'z')
2918 || (c >= 'A' && c <= 'Z')
2919 || (c >= '0' && c <= '9')
2920 || c == '-' || c == '_'))
2921 bad_count++;
2922 else
2923 good_count++;
2924 }
2925 }
2926 else
2927 /* Not a string => completely invalid. */
2928 bad_count = 5, good_count = 0;
2929
2930 /* If name is valid already, return. */
2931 if (bad_count == 0)
2932 return;
2933
2934 /* If name is entirely invalid, or nearly so, use `emacs'. */
2935 if (good_count == 0
2936 || (good_count == 1 && bad_count > 0))
2937 {
2938 Vx_resource_name = build_string ("emacs");
2939 return;
2940 }
2941
2942 /* Name is partly valid. Copy it and replace the invalid characters
2943 with underscores. */
2944
2945 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2946
2947 for (i = 0; i < len; i++)
2948 {
2949 int c = XSTRING (new)->data[i];
2950 if (! ((c >= 'a' && c <= 'z')
2951 || (c >= 'A' && c <= 'Z')
2952 || (c >= '0' && c <= '9')
2953 || c == '-' || c == '_'))
2954 XSTRING (new)->data[i] = '_';
2955 }
2956}
2957
2958
2959extern char *x_get_string_resource ();
2960
2961DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
2962 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
2963This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2964class, where INSTANCE is the name under which Emacs was invoked, or
2965the name specified by the `-name' or `-rn' command-line arguments.
2966
2967The optional arguments COMPONENT and SUBCLASS add to the key and the
2968class, respectively. You must specify both of them or neither.
2969If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
2970and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
2971 (attribute, class, component, subclass)
2972 Lisp_Object attribute, class, component, subclass;
2973{
2974 register char *value;
2975 char *name_key;
2976 char *class_key;
2977
b7826503
PJ
2978 CHECK_STRING (attribute);
2979 CHECK_STRING (class);
ee78dc32
GV
2980
2981 if (!NILP (component))
b7826503 2982 CHECK_STRING (component);
ee78dc32 2983 if (!NILP (subclass))
b7826503 2984 CHECK_STRING (subclass);
ee78dc32
GV
2985 if (NILP (component) != NILP (subclass))
2986 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2987
2988 validate_x_resource_name ();
2989
2990 /* Allocate space for the components, the dots which separate them,
2991 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 2992 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 2993 + (STRINGP (component)
dfff8a69
JR
2994 ? STRING_BYTES (XSTRING (component)) : 0)
2995 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
2996 + 3);
2997
2998 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 2999 + STRING_BYTES (XSTRING (class))
ee78dc32 3000 + (STRINGP (subclass)
dfff8a69 3001 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
3002 + 3);
3003
3004 /* Start with emacs.FRAMENAME for the name (the specific one)
3005 and with `Emacs' for the class key (the general one). */
3006 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3007 strcpy (class_key, EMACS_CLASS);
3008
3009 strcat (class_key, ".");
3010 strcat (class_key, XSTRING (class)->data);
3011
3012 if (!NILP (component))
3013 {
3014 strcat (class_key, ".");
3015 strcat (class_key, XSTRING (subclass)->data);
3016
3017 strcat (name_key, ".");
3018 strcat (name_key, XSTRING (component)->data);
3019 }
3020
3021 strcat (name_key, ".");
3022 strcat (name_key, XSTRING (attribute)->data);
3023
3024 value = x_get_string_resource (Qnil,
3025 name_key, class_key);
3026
3027 if (value != (char *) 0)
3028 return build_string (value);
3029 else
3030 return Qnil;
3031}
3032
3033/* Used when C code wants a resource value. */
3034
3035char *
3036x_get_resource_string (attribute, class)
3037 char *attribute, *class;
3038{
ee78dc32
GV
3039 char *name_key;
3040 char *class_key;
6fc2811b 3041 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3042
3043 /* Allocate space for the components, the dots which separate them,
3044 and the final '\0'. */
dfff8a69 3045 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3046 + strlen (attribute) + 2);
3047 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3048 + strlen (class) + 2);
3049
3050 sprintf (name_key, "%s.%s",
3051 XSTRING (Vinvocation_name)->data,
3052 attribute);
3053 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3054
6fc2811b 3055 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3056}
3057
3058/* Types we might convert a resource string into. */
3059enum resource_types
6fc2811b
JR
3060{
3061 RES_TYPE_NUMBER,
3062 RES_TYPE_FLOAT,
3063 RES_TYPE_BOOLEAN,
3064 RES_TYPE_STRING,
3065 RES_TYPE_SYMBOL
3066};
ee78dc32
GV
3067
3068/* Return the value of parameter PARAM.
3069
3070 First search ALIST, then Vdefault_frame_alist, then the X defaults
3071 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3072
3073 Convert the resource to the type specified by desired_type.
3074
3075 If no default is specified, return Qunbound. If you call
6fc2811b 3076 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3077 and don't let it get stored in any Lisp-visible variables! */
3078
3079static Lisp_Object
6fc2811b 3080w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3081 Lisp_Object alist, param;
3082 char *attribute;
3083 char *class;
3084 enum resource_types type;
3085{
3086 register Lisp_Object tem;
3087
3088 tem = Fassq (param, alist);
3089 if (EQ (tem, Qnil))
3090 tem = Fassq (param, Vdefault_frame_alist);
3091 if (EQ (tem, Qnil))
3092 {
3093
3094 if (attribute)
3095 {
3096 tem = Fx_get_resource (build_string (attribute),
3097 build_string (class),
3098 Qnil, Qnil);
3099
3100 if (NILP (tem))
3101 return Qunbound;
3102
3103 switch (type)
3104 {
6fc2811b 3105 case RES_TYPE_NUMBER:
ee78dc32
GV
3106 return make_number (atoi (XSTRING (tem)->data));
3107
6fc2811b
JR
3108 case RES_TYPE_FLOAT:
3109 return make_float (atof (XSTRING (tem)->data));
3110
3111 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3112 tem = Fdowncase (tem);
3113 if (!strcmp (XSTRING (tem)->data, "on")
3114 || !strcmp (XSTRING (tem)->data, "true"))
3115 return Qt;
3116 else
3117 return Qnil;
3118
6fc2811b 3119 case RES_TYPE_STRING:
ee78dc32
GV
3120 return tem;
3121
6fc2811b 3122 case RES_TYPE_SYMBOL:
ee78dc32
GV
3123 /* As a special case, we map the values `true' and `on'
3124 to Qt, and `false' and `off' to Qnil. */
3125 {
3126 Lisp_Object lower;
3127 lower = Fdowncase (tem);
3128 if (!strcmp (XSTRING (lower)->data, "on")
3129 || !strcmp (XSTRING (lower)->data, "true"))
3130 return Qt;
3131 else if (!strcmp (XSTRING (lower)->data, "off")
3132 || !strcmp (XSTRING (lower)->data, "false"))
3133 return Qnil;
3134 else
3135 return Fintern (tem, Qnil);
3136 }
3137
3138 default:
3139 abort ();
3140 }
3141 }
3142 else
3143 return Qunbound;
3144 }
3145 return Fcdr (tem);
3146}
3147
3148/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3149 of the parameter named PROP (a Lisp symbol).
3150 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3151 on the frame named NAME.
3152 If that is not found either, use the value DEFLT. */
3153
3154static Lisp_Object
3155x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3156 struct frame *f;
3157 Lisp_Object alist;
3158 Lisp_Object prop;
3159 Lisp_Object deflt;
3160 char *xprop;
3161 char *xclass;
3162 enum resource_types type;
3163{
3164 Lisp_Object tem;
3165
6fc2811b 3166 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3167 if (EQ (tem, Qunbound))
3168 tem = deflt;
3169 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3170 return tem;
3171}
3172\f
3173DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3174 doc: /* Parse an X-style geometry string STRING.
3175Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3176The properties returned may include `top', `left', `height', and `width'.
3177The value of `left' or `top' may be an integer,
3178or a list (+ N) meaning N pixels relative to top/left corner,
3179or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3180 (string)
3181 Lisp_Object string;
3182{
3183 int geometry, x, y;
3184 unsigned int width, height;
3185 Lisp_Object result;
3186
b7826503 3187 CHECK_STRING (string);
ee78dc32
GV
3188
3189 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3190 &x, &y, &width, &height);
3191
3192 result = Qnil;
3193 if (geometry & XValue)
3194 {
3195 Lisp_Object element;
3196
3197 if (x >= 0 && (geometry & XNegative))
3198 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3199 else if (x < 0 && ! (geometry & XNegative))
3200 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3201 else
3202 element = Fcons (Qleft, make_number (x));
3203 result = Fcons (element, result);
3204 }
3205
3206 if (geometry & YValue)
3207 {
3208 Lisp_Object element;
3209
3210 if (y >= 0 && (geometry & YNegative))
3211 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3212 else if (y < 0 && ! (geometry & YNegative))
3213 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3214 else
3215 element = Fcons (Qtop, make_number (y));
3216 result = Fcons (element, result);
3217 }
3218
3219 if (geometry & WidthValue)
3220 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3221 if (geometry & HeightValue)
3222 result = Fcons (Fcons (Qheight, make_number (height)), result);
3223
3224 return result;
3225}
3226
3227/* Calculate the desired size and position of this window,
3228 and return the flags saying which aspects were specified.
3229
3230 This function does not make the coordinates positive. */
3231
3232#define DEFAULT_ROWS 40
3233#define DEFAULT_COLS 80
3234
3235static int
3236x_figure_window_size (f, parms)
3237 struct frame *f;
3238 Lisp_Object parms;
3239{
3240 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3241 long window_prompting = 0;
3242
3243 /* Default values if we fall through.
3244 Actually, if that happens we should get
3245 window manager prompting. */
1026b400 3246 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3247 f->height = DEFAULT_ROWS;
3248 /* Window managers expect that if program-specified
3249 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3250 f->output_data.w32->top_pos = 0;
3251 f->output_data.w32->left_pos = 0;
ee78dc32 3252
35b41202
JR
3253 /* Ensure that old new_width and new_height will not override the
3254 values set here. */
3255 FRAME_NEW_WIDTH (f) = 0;
3256 FRAME_NEW_HEIGHT (f) = 0;
3257
6fc2811b
JR
3258 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3259 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3260 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3261 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3262 {
3263 if (!EQ (tem0, Qunbound))
3264 {
b7826503 3265 CHECK_NUMBER (tem0);
ee78dc32
GV
3266 f->height = XINT (tem0);
3267 }
3268 if (!EQ (tem1, Qunbound))
3269 {
b7826503 3270 CHECK_NUMBER (tem1);
1026b400 3271 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3272 }
3273 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3274 window_prompting |= USSize;
3275 else
3276 window_prompting |= PSize;
3277 }
3278
fbd6baed 3279 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3280 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3281 ? 0
3282 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3283 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3284 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
41c1bdd9 3285 x_compute_fringe_widths (f, 0);
fbd6baed
GV
3286 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3287 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3288
6fc2811b
JR
3289 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3290 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3291 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3292 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3293 {
3294 if (EQ (tem0, Qminus))
3295 {
fbd6baed 3296 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3297 window_prompting |= YNegative;
3298 }
8e713be6
KR
3299 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3300 && CONSP (XCDR (tem0))
3301 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3302 {
8e713be6 3303 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3304 window_prompting |= YNegative;
3305 }
8e713be6
KR
3306 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3307 && CONSP (XCDR (tem0))
3308 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3309 {
8e713be6 3310 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3311 }
3312 else if (EQ (tem0, Qunbound))
fbd6baed 3313 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3314 else
3315 {
b7826503 3316 CHECK_NUMBER (tem0);
fbd6baed
GV
3317 f->output_data.w32->top_pos = XINT (tem0);
3318 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3319 window_prompting |= YNegative;
3320 }
3321
3322 if (EQ (tem1, Qminus))
3323 {
fbd6baed 3324 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3325 window_prompting |= XNegative;
3326 }
8e713be6
KR
3327 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3328 && CONSP (XCDR (tem1))
3329 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3330 {
8e713be6 3331 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3332 window_prompting |= XNegative;
3333 }
8e713be6
KR
3334 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3335 && CONSP (XCDR (tem1))
3336 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3337 {
8e713be6 3338 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3339 }
3340 else if (EQ (tem1, Qunbound))
fbd6baed 3341 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3342 else
3343 {
b7826503 3344 CHECK_NUMBER (tem1);
fbd6baed
GV
3345 f->output_data.w32->left_pos = XINT (tem1);
3346 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3347 window_prompting |= XNegative;
3348 }
3349
3350 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3351 window_prompting |= USPosition;
3352 else
3353 window_prompting |= PPosition;
3354 }
3355
3356 return window_prompting;
3357}
3358
3359\f
3360
fbd6baed 3361extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3362
3363BOOL
fbd6baed 3364w32_init_class (hinst)
ee78dc32
GV
3365 HINSTANCE hinst;
3366{
3367 WNDCLASS wc;
3368
5ac45f98 3369 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3370 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3371 wc.cbClsExtra = 0;
3372 wc.cbWndExtra = WND_EXTRA_BYTES;
3373 wc.hInstance = hinst;
3374 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3375 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3376 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3377 wc.lpszMenuName = NULL;
3378 wc.lpszClassName = EMACS_CLASS;
3379
3380 return (RegisterClass (&wc));
3381}
3382
3383HWND
fbd6baed 3384w32_createscrollbar (f, bar)
ee78dc32
GV
3385 struct frame *f;
3386 struct scroll_bar * bar;
3387{
3388 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3389 /* Position and size of scroll bar. */
6fc2811b
JR
3390 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3391 XINT(bar->top),
3392 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3393 XINT(bar->height),
fbd6baed 3394 FRAME_W32_WINDOW (f),
ee78dc32
GV
3395 NULL,
3396 hinst,
3397 NULL));
3398}
3399
3400void
fbd6baed 3401w32_createwindow (f)
ee78dc32
GV
3402 struct frame *f;
3403{
3404 HWND hwnd;
1edf84e7
GV
3405 RECT rect;
3406
3407 rect.left = rect.top = 0;
3408 rect.right = PIXEL_WIDTH (f);
3409 rect.bottom = PIXEL_HEIGHT (f);
3410
3411 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3412 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3413
3414 /* Do first time app init */
3415
3416 if (!hprevinst)
3417 {
fbd6baed 3418 w32_init_class (hinst);
ee78dc32
GV
3419 }
3420
1edf84e7
GV
3421 FRAME_W32_WINDOW (f) = hwnd
3422 = CreateWindow (EMACS_CLASS,
3423 f->namebuf,
9ead1b60 3424 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3425 f->output_data.w32->left_pos,
3426 f->output_data.w32->top_pos,
3427 rect.right - rect.left,
3428 rect.bottom - rect.top,
3429 NULL,
3430 NULL,
3431 hinst,
3432 NULL);
3433
ee78dc32
GV
3434 if (hwnd)
3435 {
1edf84e7
GV
3436 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3437 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3438 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3439 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3440 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3441
cb9e33d4
RS
3442 /* Enable drag-n-drop. */
3443 DragAcceptFiles (hwnd, TRUE);
3444
5ac45f98
GV
3445 /* Do this to discard the default setting specified by our parent. */
3446 ShowWindow (hwnd, SW_HIDE);
3c190163 3447 }
3c190163
GV
3448}
3449
ee78dc32
GV
3450void
3451my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3452 W32Msg * wmsg;
ee78dc32
GV
3453 HWND hwnd;
3454 UINT msg;
3455 WPARAM wParam;
3456 LPARAM lParam;
3457{
3458 wmsg->msg.hwnd = hwnd;
3459 wmsg->msg.message = msg;
3460 wmsg->msg.wParam = wParam;
3461 wmsg->msg.lParam = lParam;
3462 wmsg->msg.time = GetMessageTime ();
3463
3464 post_msg (wmsg);
3465}
3466
e9e23e23 3467/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3468 between left and right keys as advertised. We test for this
3469 support dynamically, and set a flag when the support is absent. If
3470 absent, we keep track of the left and right control and alt keys
3471 ourselves. This is particularly necessary on keyboards that rely
3472 upon the AltGr key, which is represented as having the left control
3473 and right alt keys pressed. For these keyboards, we need to know
3474 when the left alt key has been pressed in addition to the AltGr key
3475 so that we can properly support M-AltGr-key sequences (such as M-@
3476 on Swedish keyboards). */
3477
3478#define EMACS_LCONTROL 0
3479#define EMACS_RCONTROL 1
3480#define EMACS_LMENU 2
3481#define EMACS_RMENU 3
3482
3483static int modifiers[4];
3484static int modifiers_recorded;
3485static int modifier_key_support_tested;
3486
3487static void
3488test_modifier_support (unsigned int wparam)
3489{
3490 unsigned int l, r;
3491
3492 if (wparam != VK_CONTROL && wparam != VK_MENU)
3493 return;
3494 if (wparam == VK_CONTROL)
3495 {
3496 l = VK_LCONTROL;
3497 r = VK_RCONTROL;
3498 }
3499 else
3500 {
3501 l = VK_LMENU;
3502 r = VK_RMENU;
3503 }
3504 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3505 modifiers_recorded = 1;
3506 else
3507 modifiers_recorded = 0;
3508 modifier_key_support_tested = 1;
3509}
3510
3511static void
3512record_keydown (unsigned int wparam, unsigned int lparam)
3513{
3514 int i;
3515
3516 if (!modifier_key_support_tested)
3517 test_modifier_support (wparam);
3518
3519 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3520 return;
3521
3522 if (wparam == VK_CONTROL)
3523 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3524 else
3525 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3526
3527 modifiers[i] = 1;
3528}
3529
3530static void
3531record_keyup (unsigned int wparam, unsigned int lparam)
3532{
3533 int i;
3534
3535 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3536 return;
3537
3538 if (wparam == VK_CONTROL)
3539 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3540 else
3541 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3542
3543 modifiers[i] = 0;
3544}
3545
da36a4d6
GV
3546/* Emacs can lose focus while a modifier key has been pressed. When
3547 it regains focus, be conservative and clear all modifiers since
3548 we cannot reconstruct the left and right modifier state. */
3549static void
3550reset_modifiers ()
3551{
8681157a
RS
3552 SHORT ctrl, alt;
3553
adcc3809
GV
3554 if (GetFocus () == NULL)
3555 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3556 return;
8681157a
RS
3557
3558 ctrl = GetAsyncKeyState (VK_CONTROL);
3559 alt = GetAsyncKeyState (VK_MENU);
3560
8681157a
RS
3561 if (!(ctrl & 0x08000))
3562 /* Clear any recorded control modifier state. */
3563 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3564
3565 if (!(alt & 0x08000))
3566 /* Clear any recorded alt modifier state. */
3567 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3568
adcc3809
GV
3569 /* Update the state of all modifier keys, because modifiers used in
3570 hot-key combinations can get stuck on if Emacs loses focus as a
3571 result of a hot-key being pressed. */
3572 {
3573 BYTE keystate[256];
3574
3575#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3576
3577 GetKeyboardState (keystate);
3578 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3579 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3580 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3581 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3582 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3583 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3584 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3585 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3586 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3587 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3588 SetKeyboardState (keystate);
3589 }
da36a4d6
GV
3590}
3591
7830e24b
RS
3592/* Synchronize modifier state with what is reported with the current
3593 keystroke. Even if we cannot distinguish between left and right
3594 modifier keys, we know that, if no modifiers are set, then neither
3595 the left or right modifier should be set. */
3596static void
3597sync_modifiers ()
3598{
3599 if (!modifiers_recorded)
3600 return;
3601
3602 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3603 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3604
3605 if (!(GetKeyState (VK_MENU) & 0x8000))
3606 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3607}
3608
a1a80b40
GV
3609static int
3610modifier_set (int vkey)
3611{
ccc2d29c 3612 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3613 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3614 if (!modifiers_recorded)
3615 return (GetKeyState (vkey) & 0x8000);
3616
3617 switch (vkey)
3618 {
3619 case VK_LCONTROL:
3620 return modifiers[EMACS_LCONTROL];
3621 case VK_RCONTROL:
3622 return modifiers[EMACS_RCONTROL];
3623 case VK_LMENU:
3624 return modifiers[EMACS_LMENU];
3625 case VK_RMENU:
3626 return modifiers[EMACS_RMENU];
a1a80b40
GV
3627 }
3628 return (GetKeyState (vkey) & 0x8000);
3629}
3630
ccc2d29c
GV
3631/* Convert between the modifier bits W32 uses and the modifier bits
3632 Emacs uses. */
3633
3634unsigned int
3635w32_key_to_modifier (int key)
3636{
3637 Lisp_Object key_mapping;
3638
3639 switch (key)
3640 {
3641 case VK_LWIN:
3642 key_mapping = Vw32_lwindow_modifier;
3643 break;
3644 case VK_RWIN:
3645 key_mapping = Vw32_rwindow_modifier;
3646 break;
3647 case VK_APPS:
3648 key_mapping = Vw32_apps_modifier;
3649 break;
3650 case VK_SCROLL:
3651 key_mapping = Vw32_scroll_lock_modifier;
3652 break;
3653 default:
3654 key_mapping = Qnil;
3655 }
3656
adcc3809
GV
3657 /* NB. This code runs in the input thread, asychronously to the lisp
3658 thread, so we must be careful to ensure access to lisp data is
3659 thread-safe. The following code is safe because the modifier
3660 variable values are updated atomically from lisp and symbols are
3661 not relocated by GC. Also, we don't have to worry about seeing GC
3662 markbits here. */
3663 if (EQ (key_mapping, Qhyper))
ccc2d29c 3664 return hyper_modifier;
adcc3809 3665 if (EQ (key_mapping, Qsuper))
ccc2d29c 3666 return super_modifier;
adcc3809 3667 if (EQ (key_mapping, Qmeta))
ccc2d29c 3668 return meta_modifier;
adcc3809 3669 if (EQ (key_mapping, Qalt))
ccc2d29c 3670 return alt_modifier;
adcc3809 3671 if (EQ (key_mapping, Qctrl))
ccc2d29c 3672 return ctrl_modifier;
adcc3809 3673 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3674 return ctrl_modifier;
adcc3809 3675 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3676 return shift_modifier;
3677
3678 /* Don't generate any modifier if not explicitly requested. */
3679 return 0;
3680}
3681
3682unsigned int
3683w32_get_modifiers ()
3684{
3685 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3686 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3687 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3688 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3689 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3690 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3691 (modifier_set (VK_MENU) ?
3692 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3693}
3694
a1a80b40
GV
3695/* We map the VK_* modifiers into console modifier constants
3696 so that we can use the same routines to handle both console
3697 and window input. */
3698
3699static int
ccc2d29c 3700construct_console_modifiers ()
a1a80b40
GV
3701{
3702 int mods;
3703
a1a80b40
GV
3704 mods = 0;
3705 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3706 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3707 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3708 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3709 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3710 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3711 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3712 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3713 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3714 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3715 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3716
3717 return mods;
3718}
3719
ccc2d29c
GV
3720static int
3721w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3722{
ccc2d29c
GV
3723 int mods;
3724
3725 /* Convert to emacs modifiers. */
3726 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3727
3728 return mods;
3729}
da36a4d6 3730
ccc2d29c
GV
3731unsigned int
3732map_keypad_keys (unsigned int virt_key, unsigned int extended)
3733{
3734 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3735 return virt_key;
da36a4d6 3736
ccc2d29c 3737 if (virt_key == VK_RETURN)
da36a4d6
GV
3738 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3739
ccc2d29c
GV
3740 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3741 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3742
3743 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3744 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3745
3746 if (virt_key == VK_CLEAR)
3747 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3748
3749 return virt_key;
3750}
3751
3752/* List of special key combinations which w32 would normally capture,
3753 but emacs should grab instead. Not directly visible to lisp, to
3754 simplify synchronization. Each item is an integer encoding a virtual
3755 key code and modifier combination to capture. */
3756Lisp_Object w32_grabbed_keys;
3757
3758#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3759#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3760#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3761#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3762
3763/* Register hot-keys for reserved key combinations when Emacs has
3764 keyboard focus, since this is the only way Emacs can receive key
3765 combinations like Alt-Tab which are used by the system. */
3766
3767static void
3768register_hot_keys (hwnd)
3769 HWND hwnd;
3770{
3771 Lisp_Object keylist;
3772
3773 /* Use GC_CONSP, since we are called asynchronously. */
3774 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3775 {
3776 Lisp_Object key = XCAR (keylist);
3777
3778 /* Deleted entries get set to nil. */
3779 if (!INTEGERP (key))
3780 continue;
3781
3782 RegisterHotKey (hwnd, HOTKEY_ID (key),
3783 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3784 }
3785}
3786
3787static void
3788unregister_hot_keys (hwnd)
3789 HWND hwnd;
3790{
3791 Lisp_Object keylist;
3792
3793 /* Use GC_CONSP, since we are called asynchronously. */
3794 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3795 {
3796 Lisp_Object key = XCAR (keylist);
3797
3798 if (!INTEGERP (key))
3799 continue;
3800
3801 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3802 }
3803}
3804
5ac45f98
GV
3805/* Main message dispatch loop. */
3806
1edf84e7
GV
3807static void
3808w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3809{
3810 MSG msg;
ccc2d29c
GV
3811 int result;
3812 HWND focus_window;
93fbe8b7
GV
3813
3814 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3815
5ac45f98
GV
3816 while (GetMessage (&msg, NULL, 0, 0))
3817 {
3818 if (msg.hwnd == NULL)
3819 {
3820 switch (msg.message)
3821 {
3ef68e6b
AI
3822 case WM_NULL:
3823 /* Produced by complete_deferred_msg; just ignore. */
3824 break;
5ac45f98 3825 case WM_EMACS_CREATEWINDOW:
fbd6baed 3826 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3827 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3828 abort ();
5ac45f98 3829 break;
dfdb4047
GV
3830 case WM_EMACS_SETLOCALE:
3831 SetThreadLocale (msg.wParam);
3832 /* Reply is not expected. */
3833 break;
ccc2d29c
GV
3834 case WM_EMACS_SETKEYBOARDLAYOUT:
3835 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3836 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3837 result, 0))
3838 abort ();
3839 break;
3840 case WM_EMACS_REGISTER_HOT_KEY:
3841 focus_window = GetFocus ();
3842 if (focus_window != NULL)
3843 RegisterHotKey (focus_window,
3844 HOTKEY_ID (msg.wParam),
3845 HOTKEY_MODIFIERS (msg.wParam),
3846 HOTKEY_VK_CODE (msg.wParam));
3847 /* Reply is not expected. */
3848 break;
3849 case WM_EMACS_UNREGISTER_HOT_KEY:
3850 focus_window = GetFocus ();
3851 if (focus_window != NULL)
3852 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3853 /* Mark item as erased. NB: this code must be
3854 thread-safe. The next line is okay because the cons
3855 cell is never made into garbage and is not relocated by
3856 GC. */
f3fbd155 3857 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3858 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3859 abort ();
3860 break;
adcc3809
GV
3861 case WM_EMACS_TOGGLE_LOCK_KEY:
3862 {
3863 int vk_code = (int) msg.wParam;
3864 int cur_state = (GetKeyState (vk_code) & 1);
3865 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3866
3867 /* NB: This code must be thread-safe. It is safe to
3868 call NILP because symbols are not relocated by GC,
3869 and pointer here is not touched by GC (so the markbit
3870 can't be set). Numbers are safe because they are
3871 immediate values. */
3872 if (NILP (new_state)
3873 || (NUMBERP (new_state)
8edb0a6f 3874 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3875 {
3876 one_w32_display_info.faked_key = vk_code;
3877
3878 keybd_event ((BYTE) vk_code,
3879 (BYTE) MapVirtualKey (vk_code, 0),
3880 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3881 keybd_event ((BYTE) vk_code,
3882 (BYTE) MapVirtualKey (vk_code, 0),
3883 KEYEVENTF_EXTENDEDKEY | 0, 0);
3884 keybd_event ((BYTE) vk_code,
3885 (BYTE) MapVirtualKey (vk_code, 0),
3886 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3887 cur_state = !cur_state;
3888 }
3889 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3890 cur_state, 0))
3891 abort ();
3892 }
3893 break;
1edf84e7 3894 default:
1edf84e7 3895 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3896 }
3897 }
3898 else
3899 {
3900 DispatchMessage (&msg);
3901 }
1edf84e7
GV
3902
3903 /* Exit nested loop when our deferred message has completed. */
3904 if (msg_buf->completed)
3905 break;
5ac45f98 3906 }
1edf84e7
GV
3907}
3908
3909deferred_msg * deferred_msg_head;
3910
3911static deferred_msg *
3912find_deferred_msg (HWND hwnd, UINT msg)
3913{
3914 deferred_msg * item;
3915
3916 /* Don't actually need synchronization for read access, since
3917 modification of single pointer is always atomic. */
3918 /* enter_crit (); */
3919
3920 for (item = deferred_msg_head; item != NULL; item = item->next)
3921 if (item->w32msg.msg.hwnd == hwnd
3922 && item->w32msg.msg.message == msg)
3923 break;
3924
3925 /* leave_crit (); */
3926
3927 return item;
3928}
3929
3930static LRESULT
3931send_deferred_msg (deferred_msg * msg_buf,
3932 HWND hwnd,
3933 UINT msg,
3934 WPARAM wParam,
3935 LPARAM lParam)
3936{
3937 /* Only input thread can send deferred messages. */
3938 if (GetCurrentThreadId () != dwWindowsThreadId)
3939 abort ();
3940
3941 /* It is an error to send a message that is already deferred. */
3942 if (find_deferred_msg (hwnd, msg) != NULL)
3943 abort ();
3944
3945 /* Enforced synchronization is not needed because this is the only
3946 function that alters deferred_msg_head, and the following critical
3947 section is guaranteed to only be serially reentered (since only the
3948 input thread can call us). */
3949
3950 /* enter_crit (); */
3951
3952 msg_buf->completed = 0;
3953 msg_buf->next = deferred_msg_head;
3954 deferred_msg_head = msg_buf;
3955 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3956
3957 /* leave_crit (); */
3958
3959 /* Start a new nested message loop to process other messages until
3960 this one is completed. */
3961 w32_msg_pump (msg_buf);
3962
3963 deferred_msg_head = msg_buf->next;
3964
3965 return msg_buf->result;
3966}
3967
3968void
3969complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3970{
3971 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3972
3973 if (msg_buf == NULL)
3ef68e6b
AI
3974 /* Message may have been cancelled, so don't abort(). */
3975 return;
1edf84e7
GV
3976
3977 msg_buf->result = result;
3978 msg_buf->completed = 1;
3979
3980 /* Ensure input thread is woken so it notices the completion. */
3981 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3982}
3983
3ef68e6b
AI
3984void
3985cancel_all_deferred_msgs ()
3986{
3987 deferred_msg * item;
3988
3989 /* Don't actually need synchronization for read access, since
3990 modification of single pointer is always atomic. */
3991 /* enter_crit (); */
3992
3993 for (item = deferred_msg_head; item != NULL; item = item->next)
3994 {
3995 item->result = 0;
3996 item->completed = 1;
3997 }
3998
3999 /* leave_crit (); */
4000
4001 /* Ensure input thread is woken so it notices the completion. */
4002 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4003}
1edf84e7
GV
4004
4005DWORD
4006w32_msg_worker (dw)
4007 DWORD dw;
4008{
4009 MSG msg;
4010 deferred_msg dummy_buf;
4011
4012 /* Ensure our message queue is created */
4013
4014 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 4015
1edf84e7
GV
4016 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4017 abort ();
4018
4019 memset (&dummy_buf, 0, sizeof (dummy_buf));
4020 dummy_buf.w32msg.msg.hwnd = NULL;
4021 dummy_buf.w32msg.msg.message = WM_NULL;
4022
4023 /* This is the inital message loop which should only exit when the
4024 application quits. */
4025 w32_msg_pump (&dummy_buf);
4026
4027 return 0;
5ac45f98
GV
4028}
4029
3ef68e6b
AI
4030static void
4031post_character_message (hwnd, msg, wParam, lParam, modifiers)
4032 HWND hwnd;
4033 UINT msg;
4034 WPARAM wParam;
4035 LPARAM lParam;
4036 DWORD modifiers;
4037
4038{
4039 W32Msg wmsg;
4040
4041 wmsg.dwModifiers = modifiers;
4042
4043 /* Detect quit_char and set quit-flag directly. Note that we
4044 still need to post a message to ensure the main thread will be
4045 woken up if blocked in sys_select(), but we do NOT want to post
4046 the quit_char message itself (because it will usually be as if
4047 the user had typed quit_char twice). Instead, we post a dummy
4048 message that has no particular effect. */
4049 {
4050 int c = wParam;
4051 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4052 c = make_ctrl_char (c) & 0377;
7d081355
AI
4053 if (c == quit_char
4054 || (wmsg.dwModifiers == 0 &&
4055 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4056 {
4057 Vquit_flag = Qt;
4058
4059 /* The choice of message is somewhat arbitrary, as long as
4060 the main thread handler just ignores it. */
4061 msg = WM_NULL;
4062
4063 /* Interrupt any blocking system calls. */
4064 signal_quit ();
4065
4066 /* As a safety precaution, forcibly complete any deferred
4067 messages. This is a kludge, but I don't see any particularly
4068 clean way to handle the situation where a deferred message is
4069 "dropped" in the lisp thread, and will thus never be
4070 completed, eg. by the user trying to activate the menubar
4071 when the lisp thread is busy, and then typing C-g when the
4072 menubar doesn't open promptly (with the result that the
4073 menubar never responds at all because the deferred
4074 WM_INITMENU message is never completed). Another problem
4075 situation is when the lisp thread calls SendMessage (to send
4076 a window manager command) when a message has been deferred;
4077 the lisp thread gets blocked indefinitely waiting for the
4078 deferred message to be completed, which itself is waiting for
4079 the lisp thread to respond.
4080
4081 Note that we don't want to block the input thread waiting for
4082 a reponse from the lisp thread (although that would at least
4083 solve the deadlock problem above), because we want to be able
4084 to receive C-g to interrupt the lisp thread. */
4085 cancel_all_deferred_msgs ();
4086 }
4087 }
4088
4089 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4090}
4091
ee78dc32
GV
4092/* Main window procedure */
4093
ee78dc32 4094LRESULT CALLBACK
fbd6baed 4095w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4096 HWND hwnd;
4097 UINT msg;
4098 WPARAM wParam;
4099 LPARAM lParam;
4100{
4101 struct frame *f;
fbd6baed
GV
4102 struct w32_display_info *dpyinfo = &one_w32_display_info;
4103 W32Msg wmsg;
84fb1139 4104 int windows_translate;
576ba81c 4105 int key;
84fb1139 4106
a6085637
KH
4107 /* Note that it is okay to call x_window_to_frame, even though we are
4108 not running in the main lisp thread, because frame deletion
4109 requires the lisp thread to synchronize with this thread. Thus, if
4110 a frame struct is returned, it can be used without concern that the
4111 lisp thread might make it disappear while we are using it.
4112
4113 NB. Walking the frame list in this thread is safe (as long as
4114 writes of Lisp_Object slots are atomic, which they are on Windows).
4115 Although delete-frame can destructively modify the frame list while
4116 we are walking it, a garbage collection cannot occur until after
4117 delete-frame has synchronized with this thread.
4118
4119 It is also safe to use functions that make GDI calls, such as
fbd6baed 4120 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4121 from the frame struct using get_frame_dc which is thread-aware. */
4122
ee78dc32
GV
4123 switch (msg)
4124 {
4125 case WM_ERASEBKGND:
a6085637
KH
4126 f = x_window_to_frame (dpyinfo, hwnd);
4127 if (f)
4128 {
9badad41 4129 HDC hdc = get_frame_dc (f);
a6085637 4130 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4131 w32_clear_rect (f, hdc, &wmsg.rect);
4132 release_frame_dc (f, hdc);
ce6059da
AI
4133
4134#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4135 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4136 f,
4137 wmsg.rect.left, wmsg.rect.top,
4138 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4139#endif /* W32_DEBUG_DISPLAY */
a6085637 4140 }
5ac45f98
GV
4141 return 1;
4142 case WM_PALETTECHANGED:
4143 /* ignore our own changes */
4144 if ((HWND)wParam != hwnd)
4145 {
a6085637
KH
4146 f = x_window_to_frame (dpyinfo, hwnd);
4147 if (f)
4148 /* get_frame_dc will realize our palette and force all
4149 frames to be redrawn if needed. */
4150 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4151 }
4152 return 0;
ee78dc32 4153 case WM_PAINT:
ce6059da 4154 {
55dcfc15
AI
4155 PAINTSTRUCT paintStruct;
4156 RECT update_rect;
4157
18f0b342
AI
4158 f = x_window_to_frame (dpyinfo, hwnd);
4159 if (f == 0)
4160 {
4161 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4162 return 0;
4163 }
4164
55dcfc15
AI
4165 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4166 fails. Apparently this can happen under some
4167 circumstances. */
c0611964 4168 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
4169 {
4170 enter_crit ();
4171 BeginPaint (hwnd, &paintStruct);
4172
c0611964
AI
4173 if (w32_strict_painting)
4174 /* The rectangles returned by GetUpdateRect and BeginPaint
4175 do not always match. GetUpdateRect seems to be the
4176 more reliable of the two. */
4177 wmsg.rect = update_rect;
4178 else
4179 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
4180
4181#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4182 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4183 f,
4184 wmsg.rect.left, wmsg.rect.top,
4185 wmsg.rect.right, wmsg.rect.bottom));
4186 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4187 update_rect.left, update_rect.top,
4188 update_rect.right, update_rect.bottom));
4189#endif
4190 EndPaint (hwnd, &paintStruct);
4191 leave_crit ();
4192
4193 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4194
4195 return 0;
4196 }
c0611964
AI
4197
4198 /* If GetUpdateRect returns 0 (meaning there is no update
4199 region), assume the whole window needs to be repainted. */
4200 GetClientRect(hwnd, &wmsg.rect);
4201 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4202 return 0;
ee78dc32 4203 }
a1a80b40 4204
ccc2d29c
GV
4205 case WM_INPUTLANGCHANGE:
4206 /* Inform lisp thread of keyboard layout changes. */
4207 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4208
4209 /* Clear dead keys in the keyboard state; for simplicity only
4210 preserve modifier key states. */
4211 {
4212 int i;
4213 BYTE keystate[256];
4214
4215 GetKeyboardState (keystate);
4216 for (i = 0; i < 256; i++)
4217 if (1
4218 && i != VK_SHIFT
4219 && i != VK_LSHIFT
4220 && i != VK_RSHIFT
4221 && i != VK_CAPITAL
4222 && i != VK_NUMLOCK
4223 && i != VK_SCROLL
4224 && i != VK_CONTROL
4225 && i != VK_LCONTROL
4226 && i != VK_RCONTROL
4227 && i != VK_MENU
4228 && i != VK_LMENU
4229 && i != VK_RMENU
4230 && i != VK_LWIN
4231 && i != VK_RWIN)
4232 keystate[i] = 0;
4233 SetKeyboardState (keystate);
4234 }
4235 goto dflt;
4236
4237 case WM_HOTKEY:
4238 /* Synchronize hot keys with normal input. */
4239 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4240 return (0);
4241
a1a80b40
GV
4242 case WM_KEYUP:
4243 case WM_SYSKEYUP:
4244 record_keyup (wParam, lParam);
4245 goto dflt;
4246
ee78dc32
GV
4247 case WM_KEYDOWN:
4248 case WM_SYSKEYDOWN:
ccc2d29c
GV
4249 /* Ignore keystrokes we fake ourself; see below. */
4250 if (dpyinfo->faked_key == wParam)
4251 {
4252 dpyinfo->faked_key = 0;
576ba81c
AI
4253 /* Make sure TranslateMessage sees them though (as long as
4254 they don't produce WM_CHAR messages). This ensures that
4255 indicator lights are toggled promptly on Windows 9x, for
4256 example. */
4257 if (lispy_function_keys[wParam] != 0)
4258 {
4259 windows_translate = 1;
4260 goto translate;
4261 }
4262 return 0;
ccc2d29c
GV
4263 }
4264
7830e24b
RS
4265 /* Synchronize modifiers with current keystroke. */
4266 sync_modifiers ();
a1a80b40 4267 record_keydown (wParam, lParam);
ccc2d29c 4268 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4269
4270 windows_translate = 0;
ccc2d29c
GV
4271
4272 switch (wParam)
4273 {
4274 case VK_LWIN:
4275 if (NILP (Vw32_pass_lwindow_to_system))
4276 {
4277 /* Prevent system from acting on keyup (which opens the
4278 Start menu if no other key was pressed) by simulating a
4279 press of Space which we will ignore. */
4280 if (GetAsyncKeyState (wParam) & 1)
4281 {
adcc3809 4282 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4283 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4284 else
576ba81c
AI
4285 key = VK_SPACE;
4286 dpyinfo->faked_key = key;
4287 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4288 }
4289 }
4290 if (!NILP (Vw32_lwindow_modifier))
4291 return 0;
4292 break;
4293 case VK_RWIN:
4294 if (NILP (Vw32_pass_rwindow_to_system))
4295 {
4296 if (GetAsyncKeyState (wParam) & 1)
4297 {
adcc3809 4298 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4299 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4300 else
576ba81c
AI
4301 key = VK_SPACE;
4302 dpyinfo->faked_key = key;
4303 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4304 }
4305 }
4306 if (!NILP (Vw32_rwindow_modifier))
4307 return 0;
4308 break;
576ba81c 4309 case VK_APPS:
ccc2d29c
GV
4310 if (!NILP (Vw32_apps_modifier))
4311 return 0;
4312 break;
4313 case VK_MENU:
4314 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4315 /* Prevent DefWindowProc from activating the menu bar if an
4316 Alt key is pressed and released by itself. */
ccc2d29c 4317 return 0;
84fb1139 4318 windows_translate = 1;
ccc2d29c
GV
4319 break;
4320 case VK_CAPITAL:
4321 /* Decide whether to treat as modifier or function key. */
4322 if (NILP (Vw32_enable_caps_lock))
4323 goto disable_lock_key;
adcc3809
GV
4324 windows_translate = 1;
4325 break;
ccc2d29c
GV
4326 case VK_NUMLOCK:
4327 /* Decide whether to treat as modifier or function key. */
4328 if (NILP (Vw32_enable_num_lock))
4329 goto disable_lock_key;
adcc3809
GV
4330 windows_translate = 1;
4331 break;
ccc2d29c
GV
4332 case VK_SCROLL:
4333 /* Decide whether to treat as modifier or function key. */
4334 if (NILP (Vw32_scroll_lock_modifier))
4335 goto disable_lock_key;
adcc3809
GV
4336 windows_translate = 1;
4337 break;
ccc2d29c 4338 disable_lock_key:
adcc3809
GV
4339 /* Ensure the appropriate lock key state (and indicator light)
4340 remains in the same state. We do this by faking another
4341 press of the relevant key. Apparently, this really is the
4342 only way to toggle the state of the indicator lights. */
4343 dpyinfo->faked_key = wParam;
4344 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4345 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4346 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4347 KEYEVENTF_EXTENDEDKEY | 0, 0);
4348 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4349 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4350 /* Ensure indicator lights are updated promptly on Windows 9x
4351 (TranslateMessage apparently does this), after forwarding
4352 input event. */
4353 post_character_message (hwnd, msg, wParam, lParam,
4354 w32_get_key_modifiers (wParam, lParam));
4355 windows_translate = 1;
ccc2d29c
GV
4356 break;
4357 case VK_CONTROL:
4358 case VK_SHIFT:
4359 case VK_PROCESSKEY: /* Generated by IME. */
4360 windows_translate = 1;
4361 break;
adcc3809
GV
4362 case VK_CANCEL:
4363 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4364 which is confusing for purposes of key binding; convert
4365 VK_CANCEL events into VK_PAUSE events. */
4366 wParam = VK_PAUSE;
4367 break;
4368 case VK_PAUSE:
4369 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4370 for purposes of key binding; convert these back into
4371 VK_NUMLOCK events, at least when we want to see NumLock key
4372 presses. (Note that there is never any possibility that
4373 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4374 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4375 wParam = VK_NUMLOCK;
4376 break;
ccc2d29c
GV
4377 default:
4378 /* If not defined as a function key, change it to a WM_CHAR message. */
4379 if (lispy_function_keys[wParam] == 0)
4380 {
adcc3809
GV
4381 DWORD modifiers = construct_console_modifiers ();
4382
ccc2d29c
GV
4383 if (!NILP (Vw32_recognize_altgr)
4384 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4385 {
4386 /* Always let TranslateMessage handle AltGr key chords;
4387 for some reason, ToAscii doesn't always process AltGr
4388 chords correctly. */
4389 windows_translate = 1;
4390 }
adcc3809 4391 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4392 {
adcc3809
GV
4393 /* Handle key chords including any modifiers other
4394 than shift directly, in order to preserve as much
4395 modifier information as possible. */
ccc2d29c
GV
4396 if ('A' <= wParam && wParam <= 'Z')
4397 {
4398 /* Don't translate modified alphabetic keystrokes,
4399 so the user doesn't need to constantly switch
4400 layout to type control or meta keystrokes when
4401 the normal layout translates alphabetic
4402 characters to non-ascii characters. */
4403 if (!modifier_set (VK_SHIFT))
4404 wParam += ('a' - 'A');
4405 msg = WM_CHAR;
4406 }
4407 else
4408 {
4409 /* Try to handle other keystrokes by determining the
4410 base character (ie. translating the base key plus
4411 shift modifier). */
4412 int add;
4413 int isdead = 0;
4414 KEY_EVENT_RECORD key;
4415
4416 key.bKeyDown = TRUE;
4417 key.wRepeatCount = 1;
4418 key.wVirtualKeyCode = wParam;
4419 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4420 key.uChar.AsciiChar = 0;
adcc3809 4421 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4422
4423 add = w32_kbd_patch_key (&key);
4424 /* 0 means an unrecognised keycode, negative means
4425 dead key. Ignore both. */
4426 while (--add >= 0)
4427 {
4428 /* Forward asciified character sequence. */
4429 post_character_message
4430 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4431 w32_get_key_modifiers (wParam, lParam));
4432 w32_kbd_patch_key (&key);
4433 }
4434 return 0;
4435 }
4436 }
4437 else
4438 {
4439 /* Let TranslateMessage handle everything else. */
4440 windows_translate = 1;
4441 }
4442 }
4443 }
a1a80b40 4444
adcc3809 4445 translate:
84fb1139
KH
4446 if (windows_translate)
4447 {
e9e23e23 4448 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4449
e9e23e23
GV
4450 windows_msg.time = GetMessageTime ();
4451 TranslateMessage (&windows_msg);
84fb1139
KH
4452 goto dflt;
4453 }
4454
ee78dc32
GV
4455 /* Fall through */
4456
4457 case WM_SYSCHAR:
4458 case WM_CHAR:
ccc2d29c
GV
4459 post_character_message (hwnd, msg, wParam, lParam,
4460 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4461 break;
da36a4d6 4462
5ac45f98
GV
4463 /* Simulate middle mouse button events when left and right buttons
4464 are used together, but only if user has two button mouse. */
ee78dc32 4465 case WM_LBUTTONDOWN:
5ac45f98 4466 case WM_RBUTTONDOWN:
7ce9aaca 4467 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4468 goto handle_plain_button;
4469
4470 {
4471 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4472 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4473
3cb20f4a
RS
4474 if (button_state & this)
4475 return 0;
5ac45f98
GV
4476
4477 if (button_state == 0)
4478 SetCapture (hwnd);
4479
4480 button_state |= this;
4481
4482 if (button_state & other)
4483 {
84fb1139 4484 if (mouse_button_timer)
5ac45f98 4485 {
84fb1139
KH
4486 KillTimer (hwnd, mouse_button_timer);
4487 mouse_button_timer = 0;
5ac45f98
GV
4488
4489 /* Generate middle mouse event instead. */
4490 msg = WM_MBUTTONDOWN;
4491 button_state |= MMOUSE;
4492 }
4493 else if (button_state & MMOUSE)
4494 {
4495 /* Ignore button event if we've already generated a
4496 middle mouse down event. This happens if the
4497 user releases and press one of the two buttons
4498 after we've faked a middle mouse event. */
4499 return 0;
4500 }
4501 else
4502 {
4503 /* Flush out saved message. */
84fb1139 4504 post_msg (&saved_mouse_button_msg);
5ac45f98 4505 }
fbd6baed 4506 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4507 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4508
4509 /* Clear message buffer. */
84fb1139 4510 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4511 }
4512 else
4513 {
4514 /* Hold onto message for now. */
84fb1139 4515 mouse_button_timer =
adcc3809
GV
4516 SetTimer (hwnd, MOUSE_BUTTON_ID,
4517 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4518 saved_mouse_button_msg.msg.hwnd = hwnd;
4519 saved_mouse_button_msg.msg.message = msg;
4520 saved_mouse_button_msg.msg.wParam = wParam;
4521 saved_mouse_button_msg.msg.lParam = lParam;
4522 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4523 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4524 }
4525 }
4526 return 0;
4527
ee78dc32 4528 case WM_LBUTTONUP:
5ac45f98 4529 case WM_RBUTTONUP:
7ce9aaca 4530 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4531 goto handle_plain_button;
4532
4533 {
4534 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4535 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4536
3cb20f4a
RS
4537 if ((button_state & this) == 0)
4538 return 0;
5ac45f98
GV
4539
4540 button_state &= ~this;
4541
4542 if (button_state & MMOUSE)
4543 {
4544 /* Only generate event when second button is released. */
4545 if ((button_state & other) == 0)
4546 {
4547 msg = WM_MBUTTONUP;
4548 button_state &= ~MMOUSE;
4549
4550 if (button_state) abort ();
4551 }
4552 else
4553 return 0;
4554 }
4555 else
4556 {
4557 /* Flush out saved message if necessary. */
84fb1139 4558 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4559 {
84fb1139 4560 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4561 }
4562 }
fbd6baed 4563 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4564 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4565
4566 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4567 saved_mouse_button_msg.msg.hwnd = 0;
4568 KillTimer (hwnd, mouse_button_timer);
4569 mouse_button_timer = 0;
5ac45f98
GV
4570
4571 if (button_state == 0)
4572 ReleaseCapture ();
4573 }
4574 return 0;
4575
74214547
JR
4576 case WM_XBUTTONDOWN:
4577 case WM_XBUTTONUP:
4578 if (w32_pass_extra_mouse_buttons_to_system)
4579 goto dflt;
4580 /* else fall through and process them. */
ee78dc32
GV
4581 case WM_MBUTTONDOWN:
4582 case WM_MBUTTONUP:
5ac45f98 4583 handle_plain_button:
ee78dc32
GV
4584 {
4585 BOOL up;
1edf84e7 4586 int button;
ee78dc32 4587
74214547 4588 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
4589 {
4590 if (up) ReleaseCapture ();
4591 else SetCapture (hwnd);
1edf84e7
GV
4592 button = (button == 0) ? LMOUSE :
4593 ((button == 1) ? MMOUSE : RMOUSE);
4594 if (up)
4595 button_state &= ~button;
4596 else
4597 button_state |= button;
ee78dc32
GV
4598 }
4599 }
4600
fbd6baed 4601 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4602 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
4603
4604 /* Need to return true for XBUTTON messages, false for others,
4605 to indicate that we processed the message. */
4606 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 4607
5ac45f98 4608 case WM_MOUSEMOVE:
9eb16b62
JR
4609 /* If the mouse has just moved into the frame, start tracking
4610 it, so we will be notified when it leaves the frame. Mouse
4611 tracking only works under W98 and NT4 and later. On earlier
4612 versions, there is no way of telling when the mouse leaves the
4613 frame, so we just have to put up with help-echo and mouse
4614 highlighting remaining while the frame is not active. */
4615 if (track_mouse_event_fn && !track_mouse_window)
4616 {
4617 TRACKMOUSEEVENT tme;
4618 tme.cbSize = sizeof (tme);
4619 tme.dwFlags = TME_LEAVE;
4620 tme.hwndTrack = hwnd;
4621
4622 track_mouse_event_fn (&tme);
4623 track_mouse_window = hwnd;
4624 }
4625 case WM_VSCROLL:
fbd6baed 4626 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4627 || (msg == WM_MOUSEMOVE && button_state == 0))
4628 {
fbd6baed 4629 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4630 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4631 return 0;
4632 }
4633
4634 /* Hang onto mouse move and scroll messages for a bit, to avoid
4635 sending such events to Emacs faster than it can process them.
4636 If we get more events before the timer from the first message
4637 expires, we just replace the first message. */
4638
4639 if (saved_mouse_move_msg.msg.hwnd == 0)
4640 mouse_move_timer =
adcc3809
GV
4641 SetTimer (hwnd, MOUSE_MOVE_ID,
4642 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4643
4644 /* Hold onto message for now. */
4645 saved_mouse_move_msg.msg.hwnd = hwnd;
4646 saved_mouse_move_msg.msg.message = msg;
4647 saved_mouse_move_msg.msg.wParam = wParam;
4648 saved_mouse_move_msg.msg.lParam = lParam;
4649 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4650 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4651
4652 return 0;
4653
1edf84e7
GV
4654 case WM_MOUSEWHEEL:
4655 wmsg.dwModifiers = w32_get_modifiers ();
4656 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4657 return 0;
4658
cb9e33d4
RS
4659 case WM_DROPFILES:
4660 wmsg.dwModifiers = w32_get_modifiers ();
4661 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4662 return 0;
4663
84fb1139
KH
4664 case WM_TIMER:
4665 /* Flush out saved messages if necessary. */
4666 if (wParam == mouse_button_timer)
5ac45f98 4667 {
84fb1139
KH
4668 if (saved_mouse_button_msg.msg.hwnd)
4669 {
4670 post_msg (&saved_mouse_button_msg);
4671 saved_mouse_button_msg.msg.hwnd = 0;
4672 }
4673 KillTimer (hwnd, mouse_button_timer);
4674 mouse_button_timer = 0;
4675 }
4676 else if (wParam == mouse_move_timer)
4677 {
4678 if (saved_mouse_move_msg.msg.hwnd)
4679 {
4680 post_msg (&saved_mouse_move_msg);
4681 saved_mouse_move_msg.msg.hwnd = 0;
4682 }
4683 KillTimer (hwnd, mouse_move_timer);
4684 mouse_move_timer = 0;
5ac45f98 4685 }
5ac45f98 4686 return 0;
84fb1139
KH
4687
4688 case WM_NCACTIVATE:
4689 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4690 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4691 The only indication we get that something happened is receiving
4692 this message afterwards. So this is a good time to reset our
4693 keyboard modifiers' state. */
4694 reset_modifiers ();
4695 goto dflt;
da36a4d6 4696
1edf84e7 4697 case WM_INITMENU:
487163ac
AI
4698 button_state = 0;
4699 ReleaseCapture ();
1edf84e7
GV
4700 /* We must ensure menu bar is fully constructed and up to date
4701 before allowing user interaction with it. To achieve this
4702 we send this message to the lisp thread and wait for a
4703 reply (whose value is not actually needed) to indicate that
4704 the menu bar is now ready for use, so we can now return.
4705
4706 To remain responsive in the meantime, we enter a nested message
4707 loop that can process all other messages.
4708
4709 However, we skip all this if the message results from calling
4710 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4711 thread a message because it is blocked on us at this point. We
4712 set menubar_active before calling TrackPopupMenu to indicate
4713 this (there is no possibility of confusion with real menubar
4714 being active). */
4715
4716 f = x_window_to_frame (dpyinfo, hwnd);
4717 if (f
4718 && (f->output_data.w32->menubar_active
4719 /* We can receive this message even in the absence of a
4720 menubar (ie. when the system menu is activated) - in this
4721 case we do NOT want to forward the message, otherwise it
4722 will cause the menubar to suddenly appear when the user
4723 had requested it to be turned off! */
4724 || f->output_data.w32->menubar_widget == NULL))
4725 return 0;
4726
4727 {
4728 deferred_msg msg_buf;
4729
4730 /* Detect if message has already been deferred; in this case
4731 we cannot return any sensible value to ignore this. */
4732 if (find_deferred_msg (hwnd, msg) != NULL)
4733 abort ();
4734
4735 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4736 }
4737
4738 case WM_EXITMENULOOP:
4739 f = x_window_to_frame (dpyinfo, hwnd);
4740
9eb16b62
JR
4741 /* Free memory used by owner-drawn and help-echo strings. */
4742 w32_free_menu_strings (hwnd);
4743
1edf84e7
GV
4744 /* Indicate that menubar can be modified again. */
4745 if (f)
4746 f->output_data.w32->menubar_active = 0;
4747 goto dflt;
4748
126f2e35 4749 case WM_MENUSELECT:
4e3a1c61
JR
4750 /* Direct handling of help_echo in menus. Should be safe now
4751 that we generate the help_echo by placing a help event in the
4752 keyboard buffer. */
ca56d953 4753 {
ca56d953
JR
4754 HMENU menu = (HMENU) lParam;
4755 UINT menu_item = (UINT) LOWORD (wParam);
4756 UINT flags = (UINT) HIWORD (wParam);
4757
4e3a1c61 4758 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4759 }
126f2e35
JR
4760 return 0;
4761
87996783
GV
4762 case WM_MEASUREITEM:
4763 f = x_window_to_frame (dpyinfo, hwnd);
4764 if (f)
4765 {
4766 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4767
4768 if (pMis->CtlType == ODT_MENU)
4769 {
4770 /* Work out dimensions for popup menu titles. */
4771 char * title = (char *) pMis->itemData;
4772 HDC hdc = GetDC (hwnd);
4773 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4774 LOGFONT menu_logfont;
4775 HFONT old_font;
4776 SIZE size;
4777
4778 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4779 menu_logfont.lfWeight = FW_BOLD;
4780 menu_font = CreateFontIndirect (&menu_logfont);
4781 old_font = SelectObject (hdc, menu_font);
4782
dfff8a69
JR
4783 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4784 if (title)
4785 {
4786 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4787 pMis->itemWidth = size.cx;
4788 if (pMis->itemHeight < size.cy)
4789 pMis->itemHeight = size.cy;
4790 }
4791 else
4792 pMis->itemWidth = 0;
87996783
GV
4793
4794 SelectObject (hdc, old_font);
4795 DeleteObject (menu_font);
4796 ReleaseDC (hwnd, hdc);
4797 return TRUE;
4798 }
4799 }
4800 return 0;
4801
4802 case WM_DRAWITEM:
4803 f = x_window_to_frame (dpyinfo, hwnd);
4804 if (f)
4805 {
4806 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4807
4808 if (pDis->CtlType == ODT_MENU)
4809 {
4810 /* Draw popup menu title. */
4811 char * title = (char *) pDis->itemData;
212da13b
JR
4812 if (title)
4813 {
4814 HDC hdc = pDis->hDC;
4815 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4816 LOGFONT menu_logfont;
4817 HFONT old_font;
4818
4819 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4820 menu_logfont.lfWeight = FW_BOLD;
4821 menu_font = CreateFontIndirect (&menu_logfont);
4822 old_font = SelectObject (hdc, menu_font);
4823
4824 /* Always draw title as if not selected. */
4825 ExtTextOut (hdc,
4826 pDis->rcItem.left
4827 + GetSystemMetrics (SM_CXMENUCHECK),
4828 pDis->rcItem.top,
4829 ETO_OPAQUE, &pDis->rcItem,
4830 title, strlen (title), NULL);
4831
4832 SelectObject (hdc, old_font);
4833 DeleteObject (menu_font);
4834 }
87996783
GV
4835 return TRUE;
4836 }
4837 }
4838 return 0;
4839
1edf84e7
GV
4840#if 0
4841 /* Still not right - can't distinguish between clicks in the
4842 client area of the frame from clicks forwarded from the scroll
4843 bars - may have to hook WM_NCHITTEST to remember the mouse
4844 position and then check if it is in the client area ourselves. */
4845 case WM_MOUSEACTIVATE:
4846 /* Discard the mouse click that activates a frame, allowing the
4847 user to click anywhere without changing point (or worse!).
4848 Don't eat mouse clicks on scrollbars though!! */
4849 if (LOWORD (lParam) == HTCLIENT )
4850 return MA_ACTIVATEANDEAT;
4851 goto dflt;
4852#endif
4853
9eb16b62
JR
4854 case WM_MOUSELEAVE:
4855 /* No longer tracking mouse. */
4856 track_mouse_window = NULL;
4857
1edf84e7 4858 case WM_ACTIVATEAPP:
ccc2d29c 4859 case WM_ACTIVATE:
1edf84e7
GV
4860 case WM_WINDOWPOSCHANGED:
4861 case WM_SHOWWINDOW:
4862 /* Inform lisp thread that a frame might have just been obscured
4863 or exposed, so should recheck visibility of all frames. */
4864 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4865 goto dflt;
4866
da36a4d6 4867 case WM_SETFOCUS:
adcc3809
GV
4868 dpyinfo->faked_key = 0;
4869 reset_modifiers ();
ccc2d29c
GV
4870 register_hot_keys (hwnd);
4871 goto command;
8681157a 4872 case WM_KILLFOCUS:
ccc2d29c 4873 unregister_hot_keys (hwnd);
487163ac
AI
4874 button_state = 0;
4875 ReleaseCapture ();
65906840
JR
4876 /* Relinquish the system caret. */
4877 if (w32_system_caret_hwnd)
4878 {
4879 DestroyCaret ();
4880 w32_system_caret_hwnd = NULL;
4881 }
ee78dc32
GV
4882 case WM_MOVE:
4883 case WM_SIZE:
ee78dc32 4884 case WM_COMMAND:
ccc2d29c 4885 command:
fbd6baed 4886 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4887 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4888 goto dflt;
8847d890
RS
4889
4890 case WM_CLOSE:
fbd6baed 4891 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4892 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4893 return 0;
4894
ee78dc32 4895 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
4896 /* Don't restrict the sizing of tip frames. */
4897 if (hwnd == tip_window)
4898 return 0;
ee78dc32
GV
4899 {
4900 WINDOWPLACEMENT wp;
4901 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4902
4903 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4904 GetWindowPlacement (hwnd, &wp);
4905
1edf84e7 4906 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4907 {
4908 RECT rect;
4909 int wdiff;
4910 int hdiff;
1edf84e7
GV
4911 DWORD font_width;
4912 DWORD line_height;
4913 DWORD internal_border;
4914 DWORD scrollbar_extra;
ee78dc32
GV
4915 RECT wr;
4916
5ac45f98 4917 wp.length = sizeof(wp);
ee78dc32
GV
4918 GetWindowRect (hwnd, &wr);
4919
3c190163 4920 enter_crit ();
ee78dc32 4921
1edf84e7
GV
4922 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4923 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4924 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4925 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4926
3c190163 4927 leave_crit ();
ee78dc32
GV
4928
4929 memset (&rect, 0, sizeof (rect));
4930 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4931 GetMenu (hwnd) != NULL);
4932
1edf84e7
GV
4933 /* Force width and height of client area to be exact
4934 multiples of the character cell dimensions. */
4935 wdiff = (lppos->cx - (rect.right - rect.left)
4936 - 2 * internal_border - scrollbar_extra)
4937 % font_width;
4938 hdiff = (lppos->cy - (rect.bottom - rect.top)
4939 - 2 * internal_border)
4940 % line_height;
ee78dc32
GV
4941
4942 if (wdiff || hdiff)
4943 {
4944 /* For right/bottom sizing we can just fix the sizes.
4945 However for top/left sizing we will need to fix the X
4946 and Y positions as well. */
4947
4948 lppos->cx -= wdiff;
4949 lppos->cy -= hdiff;
4950
4951 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4952 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4953 {
4954 if (lppos->x != wr.left || lppos->y != wr.top)
4955 {
4956 lppos->x += wdiff;
4957 lppos->y += hdiff;
4958 }
4959 else
4960 {
4961 lppos->flags |= SWP_NOMOVE;
4962 }
4963 }
4964
1edf84e7 4965 return 0;
ee78dc32
GV
4966 }
4967 }
4968 }
ee78dc32
GV
4969
4970 goto dflt;
1edf84e7 4971
b1f918f8
GV
4972 case WM_GETMINMAXINFO:
4973 /* Hack to correct bug that allows Emacs frames to be resized
4974 below the Minimum Tracking Size. */
4975 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
4976 /* Hack to allow resizing the Emacs frame above the screen size.
4977 Note that Windows 9x limits coordinates to 16-bits. */
4978 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
4979 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
4980 return 0;
4981
1edf84e7
GV
4982 case WM_EMACS_CREATESCROLLBAR:
4983 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4984 (struct scroll_bar *) lParam);
4985
5ac45f98 4986 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4987 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4988
dfdb4047 4989 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4990 {
4991 HWND foreground_window;
4992 DWORD foreground_thread, retval;
4993
4994 /* On NT 5.0, and apparently Windows 98, it is necessary to
4995 attach to the thread that currently has focus in order to
4996 pull the focus away from it. */
4997 foreground_window = GetForegroundWindow ();
4998 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4999 if (!foreground_window
5000 || foreground_thread == GetCurrentThreadId ()
5001 || !AttachThreadInput (GetCurrentThreadId (),
5002 foreground_thread, TRUE))
5003 foreground_thread = 0;
5004
5005 retval = SetForegroundWindow ((HWND) wParam);
5006
5007 /* Detach from the previous foreground thread. */
5008 if (foreground_thread)
5009 AttachThreadInput (GetCurrentThreadId (),
5010 foreground_thread, FALSE);
5011
5012 return retval;
5013 }
dfdb4047 5014
5ac45f98
GV
5015 case WM_EMACS_SETWINDOWPOS:
5016 {
1edf84e7
GV
5017 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5018 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5019 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5020 }
1edf84e7 5021
ee78dc32 5022 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5023 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5024 return DestroyWindow ((HWND) wParam);
5025
65906840
JR
5026 case WM_EMACS_DESTROY_CARET:
5027 w32_system_caret_hwnd = NULL;
5028 return DestroyCaret ();
5029
5030 case WM_EMACS_TRACK_CARET:
5031 /* If there is currently no system caret, create one. */
5032 if (w32_system_caret_hwnd == NULL)
5033 {
5034 w32_system_caret_hwnd = hwnd;
5035 CreateCaret (hwnd, NULL, w32_system_caret_width,
5036 w32_system_caret_height);
5037 }
5038 return SetCaretPos (w32_system_caret_x, w32_system_caret_y);
5039
1edf84e7
GV
5040 case WM_EMACS_TRACKPOPUPMENU:
5041 {
5042 UINT flags;
5043 POINT *pos;
5044 int retval;
5045 pos = (POINT *)lParam;
5046 flags = TPM_CENTERALIGN;
5047 if (button_state & LMOUSE)
5048 flags |= TPM_LEFTBUTTON;
5049 else if (button_state & RMOUSE)
5050 flags |= TPM_RIGHTBUTTON;
5051
87996783
GV
5052 /* Remember we did a SetCapture on the initial mouse down event,
5053 so for safety, we make sure the capture is cancelled now. */
5054 ReleaseCapture ();
490822ff 5055 button_state = 0;
87996783 5056
1edf84e7
GV
5057 /* Use menubar_active to indicate that WM_INITMENU is from
5058 TrackPopupMenu below, and should be ignored. */
5059 f = x_window_to_frame (dpyinfo, hwnd);
5060 if (f)
5061 f->output_data.w32->menubar_active = 1;
5062
5063 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5064 0, hwnd, NULL))
5065 {
5066 MSG amsg;
5067 /* Eat any mouse messages during popupmenu */
5068 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5069 PM_REMOVE));
5070 /* Get the menu selection, if any */
5071 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5072 {
5073 retval = LOWORD (amsg.wParam);
5074 }
5075 else
5076 {
5077 retval = 0;
5078 }
1edf84e7
GV
5079 }
5080 else
5081 {
5082 retval = -1;
5083 }
5084
5085 return retval;
5086 }
5087
ee78dc32 5088 default:
93fbe8b7
GV
5089 /* Check for messages registered at runtime. */
5090 if (msg == msh_mousewheel)
5091 {
5092 wmsg.dwModifiers = w32_get_modifiers ();
5093 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5094 return 0;
5095 }
5096
ee78dc32
GV
5097 dflt:
5098 return DefWindowProc (hwnd, msg, wParam, lParam);
5099 }
5100
1edf84e7
GV
5101
5102 /* The most common default return code for handled messages is 0. */
5103 return 0;
ee78dc32
GV
5104}
5105
5106void
5107my_create_window (f)
5108 struct frame * f;
5109{
5110 MSG msg;
5111
1edf84e7
GV
5112 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5113 abort ();
ee78dc32
GV
5114 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5115}
5116
ca56d953
JR
5117
5118/* Create a tooltip window. Unlike my_create_window, we do not do this
5119 indirectly via the Window thread, as we do not need to process Window
5120 messages for the tooltip. Creating tooltips indirectly also creates
5121 deadlocks when tooltips are created for menu items. */
5122void
5123my_create_tip_window (f)
5124 struct frame *f;
5125{
bfd6edcc 5126 RECT rect;
ca56d953 5127
bfd6edcc
JR
5128 rect.left = rect.top = 0;
5129 rect.right = PIXEL_WIDTH (f);
5130 rect.bottom = PIXEL_HEIGHT (f);
5131
5132 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5133 FRAME_EXTERNAL_MENU_BAR (f));
5134
5135 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5136 = CreateWindow (EMACS_CLASS,
5137 f->namebuf,
5138 f->output_data.w32->dwStyle,
5139 f->output_data.w32->left_pos,
5140 f->output_data.w32->top_pos,
bfd6edcc
JR
5141 rect.right - rect.left,
5142 rect.bottom - rect.top,
ca56d953
JR
5143 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5144 NULL,
5145 hinst,
5146 NULL);
5147
bfd6edcc 5148 if (tip_window)
ca56d953 5149 {
bfd6edcc
JR
5150 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5151 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5152 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5153 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5154
5155 /* Tip frames have no scrollbars. */
5156 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5157
5158 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5159 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5160 }
5161}
5162
5163
fbd6baed 5164/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5165
5166static void
fbd6baed 5167w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5168 struct frame *f;
5169 long window_prompting;
5170 int minibuffer_only;
5171{
5172 BLOCK_INPUT;
5173
5174 /* Use the resource name as the top-level window name
5175 for looking up resources. Make a non-Lisp copy
5176 for the window manager, so GC relocation won't bother it.
5177
5178 Elsewhere we specify the window name for the window manager. */
5179
5180 {
5181 char *str = (char *) XSTRING (Vx_resource_name)->data;
5182 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5183 strcpy (f->namebuf, str);
5184 }
5185
5186 my_create_window (f);
5187
5188 validate_x_resource_name ();
5189
5190 /* x_set_name normally ignores requests to set the name if the
5191 requested name is the same as the current name. This is the one
5192 place where that assumption isn't correct; f->name is set, but
5193 the server hasn't been told. */
5194 {
5195 Lisp_Object name;
5196 int explicit = f->explicit_name;
5197
5198 f->explicit_name = 0;
5199 name = f->name;
5200 f->name = Qnil;
5201 x_set_name (f, name, explicit);
5202 }
5203
5204 UNBLOCK_INPUT;
5205
5206 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5207 initialize_frame_menubar (f);
5208
fbd6baed 5209 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5210 error ("Unable to create window");
5211}
5212
5213/* Handle the icon stuff for this window. Perhaps later we might
5214 want an x_set_icon_position which can be called interactively as
5215 well. */
5216
5217static void
5218x_icon (f, parms)
5219 struct frame *f;
5220 Lisp_Object parms;
5221{
5222 Lisp_Object icon_x, icon_y;
5223
e9e23e23 5224 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5225 icons in the tray. */
6fc2811b
JR
5226 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5227 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5228 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5229 {
b7826503
PJ
5230 CHECK_NUMBER (icon_x);
5231 CHECK_NUMBER (icon_y);
ee78dc32
GV
5232 }
5233 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5234 error ("Both left and top icon corners of icon must be specified");
5235
5236 BLOCK_INPUT;
5237
5238 if (! EQ (icon_x, Qunbound))
5239 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5240
1edf84e7
GV
5241#if 0 /* TODO */
5242 /* Start up iconic or window? */
5243 x_wm_set_window_state
6fc2811b 5244 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5245 ? IconicState
5246 : NormalState));
5247
5248 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5249 ? f->icon_name
5250 : f->name))->data);
5251#endif
5252
ee78dc32
GV
5253 UNBLOCK_INPUT;
5254}
5255
6fc2811b
JR
5256
5257static void
5258x_make_gc (f)
5259 struct frame *f;
5260{
5261 XGCValues gc_values;
5262
5263 BLOCK_INPUT;
5264
5265 /* Create the GC's of this frame.
5266 Note that many default values are used. */
5267
5268 /* Normal video */
5269 gc_values.font = f->output_data.w32->font;
5270
5271 /* Cursor has cursor-color background, background-color foreground. */
5272 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5273 gc_values.background = f->output_data.w32->cursor_pixel;
5274 f->output_data.w32->cursor_gc
5275 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5276 (GCFont | GCForeground | GCBackground),
5277 &gc_values);
5278
5279 /* Reliefs. */
5280 f->output_data.w32->white_relief.gc = 0;
5281 f->output_data.w32->black_relief.gc = 0;
5282
5283 UNBLOCK_INPUT;
5284}
5285
5286
937e601e
AI
5287/* Handler for signals raised during x_create_frame and
5288 x_create_top_frame. FRAME is the frame which is partially
5289 constructed. */
5290
5291static Lisp_Object
5292unwind_create_frame (frame)
5293 Lisp_Object frame;
5294{
5295 struct frame *f = XFRAME (frame);
5296
5297 /* If frame is ``official'', nothing to do. */
5298 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5299 {
5300#ifdef GLYPH_DEBUG
5301 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5302#endif
5303
5304 x_free_frame_resources (f);
5305
5306 /* Check that reference counts are indeed correct. */
5307 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5308 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5309
5310 return Qt;
937e601e
AI
5311 }
5312
5313 return Qnil;
5314}
5315
5316
ee78dc32
GV
5317DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5318 1, 1, 0,
74e1aeec
JR
5319 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5320Returns an Emacs frame object.
5321ALIST is an alist of frame parameters.
5322If the parameters specify that the frame should not have a minibuffer,
5323and do not specify a specific minibuffer window to use,
5324then `default-minibuffer-frame' must be a frame whose minibuffer can
5325be shared by the new frame.
5326
5327This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5328 (parms)
5329 Lisp_Object parms;
5330{
5331 struct frame *f;
5332 Lisp_Object frame, tem;
5333 Lisp_Object name;
5334 int minibuffer_only = 0;
5335 long window_prompting = 0;
5336 int width, height;
dc220243 5337 int count = BINDING_STACK_SIZE ();
1edf84e7 5338 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5339 Lisp_Object display;
6fc2811b 5340 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5341 Lisp_Object parent;
5342 struct kboard *kb;
5343
4587b026
GV
5344 check_w32 ();
5345
ee78dc32
GV
5346 /* Use this general default value to start with
5347 until we know if this frame has a specified name. */
5348 Vx_resource_name = Vinvocation_name;
5349
6fc2811b 5350 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5351 if (EQ (display, Qunbound))
5352 display = Qnil;
5353 dpyinfo = check_x_display_info (display);
5354#ifdef MULTI_KBOARD
5355 kb = dpyinfo->kboard;
5356#else
5357 kb = &the_only_kboard;
5358#endif
5359
6fc2811b 5360 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5361 if (!STRINGP (name)
5362 && ! EQ (name, Qunbound)
5363 && ! NILP (name))
5364 error ("Invalid frame name--not a string or nil");
5365
5366 if (STRINGP (name))
5367 Vx_resource_name = name;
5368
5369 /* See if parent window is specified. */
6fc2811b 5370 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5371 if (EQ (parent, Qunbound))
5372 parent = Qnil;
5373 if (! NILP (parent))
b7826503 5374 CHECK_NUMBER (parent);
ee78dc32 5375
1edf84e7
GV
5376 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5377 /* No need to protect DISPLAY because that's not used after passing
5378 it to make_frame_without_minibuffer. */
5379 frame = Qnil;
5380 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5381 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5382 RES_TYPE_SYMBOL);
ee78dc32
GV
5383 if (EQ (tem, Qnone) || NILP (tem))
5384 f = make_frame_without_minibuffer (Qnil, kb, display);
5385 else if (EQ (tem, Qonly))
5386 {
5387 f = make_minibuffer_frame ();
5388 minibuffer_only = 1;
5389 }
5390 else if (WINDOWP (tem))
5391 f = make_frame_without_minibuffer (tem, kb, display);
5392 else
5393 f = make_frame (1);
5394
1edf84e7
GV
5395 XSETFRAME (frame, f);
5396
ee78dc32
GV
5397 /* Note that Windows does support scroll bars. */
5398 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5399 /* By default, make scrollbars the system standard width. */
5400 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5401
fbd6baed 5402 f->output_method = output_w32;
6fc2811b
JR
5403 f->output_data.w32 =
5404 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5405 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5406 FRAME_FONTSET (f) = -1;
937e601e 5407 record_unwind_protect (unwind_create_frame, frame);
4587b026 5408
1edf84e7 5409 f->icon_name
6fc2811b 5410 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5411 if (! STRINGP (f->icon_name))
5412 f->icon_name = Qnil;
5413
fbd6baed 5414/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5415#ifdef MULTI_KBOARD
5416 FRAME_KBOARD (f) = kb;
5417#endif
5418
5419 /* Specify the parent under which to make this window. */
5420
5421 if (!NILP (parent))
5422 {
1660f34a 5423 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5424 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5425 }
5426 else
5427 {
fbd6baed
GV
5428 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5429 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5430 }
5431
ee78dc32
GV
5432 /* Set the name; the functions to which we pass f expect the name to
5433 be set. */
5434 if (EQ (name, Qunbound) || NILP (name))
5435 {
fbd6baed 5436 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5437 f->explicit_name = 0;
5438 }
5439 else
5440 {
5441 f->name = name;
5442 f->explicit_name = 1;
5443 /* use the frame's title when getting resources for this frame. */
5444 specbind (Qx_resource_name, name);
5445 }
5446
5447 /* Extract the window parameters from the supplied values
5448 that are needed to determine window geometry. */
5449 {
5450 Lisp_Object font;
5451
6fc2811b
JR
5452 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5453
ee78dc32
GV
5454 BLOCK_INPUT;
5455 /* First, try whatever font the caller has specified. */
5456 if (STRINGP (font))
4587b026
GV
5457 {
5458 tem = Fquery_fontset (font, Qnil);
5459 if (STRINGP (tem))
5460 font = x_new_fontset (f, XSTRING (tem)->data);
5461 else
1075afa9 5462 font = x_new_font (f, XSTRING (font)->data);
4587b026 5463 }
ee78dc32
GV
5464 /* Try out a font which we hope has bold and italic variations. */
5465 if (!STRINGP (font))
e39649be 5466 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5467 if (! STRINGP (font))
6fc2811b 5468 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5469 /* If those didn't work, look for something which will at least work. */
5470 if (! STRINGP (font))
6fc2811b 5471 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5472 UNBLOCK_INPUT;
5473 if (! STRINGP (font))
1edf84e7 5474 font = build_string ("Fixedsys");
ee78dc32
GV
5475
5476 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5477 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5478 }
5479
5480 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5481 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5482 /* This defaults to 2 in order to match xterm. We recognize either
5483 internalBorderWidth or internalBorder (which is what xterm calls
5484 it). */
5485 if (NILP (Fassq (Qinternal_border_width, parms)))
5486 {
5487 Lisp_Object value;
5488
6fc2811b 5489 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5490 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5491 if (! EQ (value, Qunbound))
5492 parms = Fcons (Fcons (Qinternal_border_width, value),
5493 parms);
5494 }
1edf84e7 5495 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5496 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5497 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5498 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5499 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5500
5501 /* Also do the stuff which must be set before the window exists. */
5502 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5503 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5504 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5505 "background", "Background", RES_TYPE_STRING);
ee78dc32 5506 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5507 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5508 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5509 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5510 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5511 "borderColor", "BorderColor", RES_TYPE_STRING);
5512 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5513 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5514 x_default_parameter (f, parms, Qline_spacing, Qnil,
5515 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5516 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5517 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5518 x_default_parameter (f, parms, Qright_fringe, Qnil,
5519 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5520
ee78dc32 5521
6fc2811b
JR
5522 /* Init faces before x_default_parameter is called for scroll-bar
5523 parameters because that function calls x_set_scroll_bar_width,
5524 which calls change_frame_size, which calls Fset_window_buffer,
5525 which runs hooks, which call Fvertical_motion. At the end, we
5526 end up in init_iterator with a null face cache, which should not
5527 happen. */
5528 init_frame_faces (f);
5529
ee78dc32 5530 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5531 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5532 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5533 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5534 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5535 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5536 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5537 "title", "Title", RES_TYPE_STRING);
ee78dc32 5538
fbd6baed
GV
5539 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5540 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5541
5542 /* Add the tool-bar height to the initial frame height so that the
5543 user gets a text display area of the size he specified with -g or
5544 via .Xdefaults. Later changes of the tool-bar height don't
5545 change the frame size. This is done so that users can create
5546 tall Emacs frames without having to guess how tall the tool-bar
5547 will get. */
5548 if (FRAME_TOOL_BAR_LINES (f))
5549 {
5550 int margin, relief, bar_height;
5551
a05e2bae 5552 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5553 ? tool_bar_button_relief
5554 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5555
5556 if (INTEGERP (Vtool_bar_button_margin)
5557 && XINT (Vtool_bar_button_margin) > 0)
5558 margin = XFASTINT (Vtool_bar_button_margin);
5559 else if (CONSP (Vtool_bar_button_margin)
5560 && INTEGERP (XCDR (Vtool_bar_button_margin))
5561 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5562 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5563 else
5564 margin = 0;
5565
5566 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5567 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5568 }
5569
ee78dc32
GV
5570 window_prompting = x_figure_window_size (f, parms);
5571
5572 if (window_prompting & XNegative)
5573 {
5574 if (window_prompting & YNegative)
fbd6baed 5575 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5576 else
fbd6baed 5577 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5578 }
5579 else
5580 {
5581 if (window_prompting & YNegative)
fbd6baed 5582 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5583 else
fbd6baed 5584 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5585 }
5586
fbd6baed 5587 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5588
6fc2811b
JR
5589 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5590 f->no_split = minibuffer_only || EQ (tem, Qt);
5591
fbd6baed 5592 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5593 x_icon (f, parms);
6fc2811b
JR
5594
5595 x_make_gc (f);
5596
5597 /* Now consider the frame official. */
5598 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5599 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5600
5601 /* We need to do this after creating the window, so that the
5602 icon-creation functions can say whose icon they're describing. */
5603 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5604 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5605
5606 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5607 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5608 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5609 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5610 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5611 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5612 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5613 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5614
5615 /* Dimensions, especially f->height, must be done via change_frame_size.
5616 Change will not be effected unless different from the current
5617 f->height. */
5618 width = f->width;
5619 height = f->height;
dc220243 5620
1026b400
RS
5621 f->height = 0;
5622 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5623 change_frame_size (f, height, width, 1, 0, 0);
5624
6fc2811b
JR
5625 /* Tell the server what size and position, etc, we want, and how
5626 badly we want them. This should be done after we have the menu
5627 bar so that its size can be taken into account. */
ee78dc32
GV
5628 BLOCK_INPUT;
5629 x_wm_set_size_hint (f, window_prompting, 0);
5630 UNBLOCK_INPUT;
5631
4694d762
JR
5632 /* Set up faces after all frame parameters are known. This call
5633 also merges in face attributes specified for new frames. If we
5634 don't do this, the `menu' face for instance won't have the right
5635 colors, and the menu bar won't appear in the specified colors for
5636 new frames. */
5637 call1 (Qface_set_after_frame_default, frame);
5638
6fc2811b
JR
5639 /* Make the window appear on the frame and enable display, unless
5640 the caller says not to. However, with explicit parent, Emacs
5641 cannot control visibility, so don't try. */
fbd6baed 5642 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5643 {
5644 Lisp_Object visibility;
5645
6fc2811b 5646 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5647 if (EQ (visibility, Qunbound))
5648 visibility = Qt;
5649
5650 if (EQ (visibility, Qicon))
5651 x_iconify_frame (f);
5652 else if (! NILP (visibility))
5653 x_make_frame_visible (f);
5654 else
5655 /* Must have been Qnil. */
5656 ;
5657 }
6fc2811b 5658 UNGCPRO;
9e57df62
GM
5659
5660 /* Make sure windows on this frame appear in calls to next-window
5661 and similar functions. */
5662 Vwindow_list = Qnil;
5663
ee78dc32
GV
5664 return unbind_to (count, frame);
5665}
5666
5667/* FRAME is used only to get a handle on the X display. We don't pass the
5668 display info directly because we're called from frame.c, which doesn't
5669 know about that structure. */
5670Lisp_Object
5671x_get_focus_frame (frame)
5672 struct frame *frame;
5673{
fbd6baed 5674 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5675 Lisp_Object xfocus;
fbd6baed 5676 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5677 return Qnil;
5678
fbd6baed 5679 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5680 return xfocus;
5681}
1edf84e7
GV
5682
5683DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5684 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5685 (frame)
5686 Lisp_Object frame;
5687{
5688 x_focus_on_frame (check_x_frame (frame));
5689 return Qnil;
5690}
5691
ee78dc32 5692\f
767b1ff0
JR
5693/* Return the charset portion of a font name. */
5694char * xlfd_charset_of_font (char * fontname)
5695{
5696 char *charset, *encoding;
5697
5698 encoding = strrchr(fontname, '-');
ceb12877 5699 if (!encoding || encoding == fontname)
767b1ff0
JR
5700 return NULL;
5701
478ea067
AI
5702 for (charset = encoding - 1; charset >= fontname; charset--)
5703 if (*charset == '-')
5704 break;
767b1ff0 5705
478ea067 5706 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5707 return NULL;
5708
5709 return charset + 1;
5710}
5711
33d52f9c
GV
5712struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5713 int size, char* filename);
8edb0a6f 5714static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5715static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5716 char * charset);
5717static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5718
8edb0a6f 5719static struct font_info *
33d52f9c 5720w32_load_system_font (f,fontname,size)
55dcfc15
AI
5721 struct frame *f;
5722 char * fontname;
5723 int size;
ee78dc32 5724{
4587b026
GV
5725 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5726 Lisp_Object font_names;
5727
4587b026
GV
5728 /* Get a list of all the fonts that match this name. Once we
5729 have a list of matching fonts, we compare them against the fonts
5730 we already have loaded by comparing names. */
5731 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5732
5733 if (!NILP (font_names))
3c190163 5734 {
4587b026
GV
5735 Lisp_Object tail;
5736 int i;
4587b026
GV
5737
5738 /* First check if any are already loaded, as that is cheaper
5739 than loading another one. */
5740 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5741 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5742 if (dpyinfo->font_table[i].name
5743 && (!strcmp (dpyinfo->font_table[i].name,
5744 XSTRING (XCAR (tail))->data)
5745 || !strcmp (dpyinfo->font_table[i].full_name,
5746 XSTRING (XCAR (tail))->data)))
4587b026 5747 return (dpyinfo->font_table + i);
6fc2811b 5748
8e713be6 5749 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5750 }
1075afa9 5751 else if (w32_strict_fontnames)
5ca0cd71
GV
5752 {
5753 /* If EnumFontFamiliesEx was available, we got a full list of
5754 fonts back so stop now to avoid the possibility of loading a
5755 random font. If we had to fall back to EnumFontFamilies, the
5756 list is incomplete, so continue whether the font we want was
5757 listed or not. */
5758 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5759 FARPROC enum_font_families_ex
1075afa9 5760 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5761 if (enum_font_families_ex)
5762 return NULL;
5763 }
4587b026
GV
5764
5765 /* Load the font and add it to the table. */
5766 {
767b1ff0 5767 char *full_name, *encoding, *charset;
4587b026
GV
5768 XFontStruct *font;
5769 struct font_info *fontp;
3c190163 5770 LOGFONT lf;
4587b026 5771 BOOL ok;
19c291d3 5772 int codepage;
6fc2811b 5773 int i;
5ac45f98 5774
4587b026 5775 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5776 return (NULL);
5ac45f98 5777
4587b026
GV
5778 if (!*lf.lfFaceName)
5779 /* If no name was specified for the font, we get a random font
5780 from CreateFontIndirect - this is not particularly
5781 desirable, especially since CreateFontIndirect does not
5782 fill out the missing name in lf, so we never know what we
5783 ended up with. */
5784 return NULL;
5785
3c190163 5786 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5787 bzero (font, sizeof (*font));
5ac45f98 5788
33d52f9c
GV
5789 /* Set bdf to NULL to indicate that this is a Windows font. */
5790 font->bdf = NULL;
5ac45f98 5791
3c190163 5792 BLOCK_INPUT;
5ac45f98
GV
5793
5794 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5795
1a292d24
AI
5796 if (font->hfont == NULL)
5797 {
5798 ok = FALSE;
5799 }
5800 else
5801 {
5802 HDC hdc;
5803 HANDLE oldobj;
19c291d3
AI
5804
5805 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5806
5807 hdc = GetDC (dpyinfo->root_window);
5808 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5809
1a292d24 5810 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5811 if (codepage == CP_UNICODE)
5812 font->double_byte_p = 1;
5813 else
8b77111c
AI
5814 {
5815 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5816 don't report themselves as double byte fonts, when
5817 patently they are. So instead of trusting
5818 GetFontLanguageInfo, we check the properties of the
5819 codepage directly, since that is ultimately what we are
5820 working from anyway. */
5821 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5822 CPINFO cpi = {0};
5823 GetCPInfo (codepage, &cpi);
5824 font->double_byte_p = cpi.MaxCharSize > 1;
5825 }
5c6682be 5826
1a292d24
AI
5827 SelectObject (hdc, oldobj);
5828 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5829 /* Fill out details in lf according to the font that was
5830 actually loaded. */
5831 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5832 lf.lfWidth = font->tm.tmAveCharWidth;
5833 lf.lfWeight = font->tm.tmWeight;
5834 lf.lfItalic = font->tm.tmItalic;
5835 lf.lfCharSet = font->tm.tmCharSet;
5836 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5837 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5838 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5839 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5840
5841 w32_cache_char_metrics (font);
1a292d24 5842 }
5ac45f98 5843
1a292d24 5844 UNBLOCK_INPUT;
5ac45f98 5845
4587b026
GV
5846 if (!ok)
5847 {
1a292d24
AI
5848 w32_unload_font (dpyinfo, font);
5849 return (NULL);
5850 }
ee78dc32 5851
6fc2811b
JR
5852 /* Find a free slot in the font table. */
5853 for (i = 0; i < dpyinfo->n_fonts; ++i)
5854 if (dpyinfo->font_table[i].name == NULL)
5855 break;
5856
5857 /* If no free slot found, maybe enlarge the font table. */
5858 if (i == dpyinfo->n_fonts
5859 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5860 {
6fc2811b
JR
5861 int sz;
5862 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5863 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5864 dpyinfo->font_table
6fc2811b 5865 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5866 }
5867
6fc2811b
JR
5868 fontp = dpyinfo->font_table + i;
5869 if (i == dpyinfo->n_fonts)
5870 ++dpyinfo->n_fonts;
4587b026
GV
5871
5872 /* Now fill in the slots of *FONTP. */
5873 BLOCK_INPUT;
5874 fontp->font = font;
6fc2811b 5875 fontp->font_idx = i;
4587b026
GV
5876 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5877 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5878
767b1ff0
JR
5879 charset = xlfd_charset_of_font (fontname);
5880
19c291d3
AI
5881 /* Cache the W32 codepage for a font. This makes w32_encode_char
5882 (called for every glyph during redisplay) much faster. */
5883 fontp->codepage = codepage;
5884
4587b026
GV
5885 /* Work out the font's full name. */
5886 full_name = (char *)xmalloc (100);
767b1ff0 5887 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
5888 fontp->full_name = full_name;
5889 else
5890 {
5891 /* If all else fails - just use the name we used to load it. */
5892 xfree (full_name);
5893 fontp->full_name = fontp->name;
5894 }
5895
5896 fontp->size = FONT_WIDTH (font);
5897 fontp->height = FONT_HEIGHT (font);
5898
5899 /* The slot `encoding' specifies how to map a character
5900 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
5901 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5902 (0:0x20..0x7F, 1:0xA0..0xFF,
5903 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 5904 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 5905 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
5906 which is never used by any charset. If mapping can't be
5907 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5908
5909 /* SJIS fonts need to be set to type 4, all others seem to work as
5910 type FONT_ENCODING_NOT_DECIDED. */
5911 encoding = strrchr (fontp->name, '-');
5912 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5913 fontp->encoding[1] = 4;
33d52f9c 5914 else
1c885fe1 5915 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5916
5917 /* The following three values are set to 0 under W32, which is
5918 what they get set to if XGetFontProperty fails under X. */
5919 fontp->baseline_offset = 0;
5920 fontp->relative_compose = 0;
33d52f9c 5921 fontp->default_ascent = 0;
4587b026 5922
6fc2811b
JR
5923 /* Set global flag fonts_changed_p to non-zero if the font loaded
5924 has a character with a smaller width than any other character
5925 before, or if the font loaded has a smalle>r height than any
5926 other font loaded before. If this happens, it will make a
5927 glyph matrix reallocation necessary. */
5928 fonts_changed_p = x_compute_min_glyph_bounds (f);
4587b026 5929 UNBLOCK_INPUT;
4587b026
GV
5930 return fontp;
5931 }
5932}
5933
33d52f9c
GV
5934/* Load font named FONTNAME of size SIZE for frame F, and return a
5935 pointer to the structure font_info while allocating it dynamically.
5936 If loading fails, return NULL. */
5937struct font_info *
5938w32_load_font (f,fontname,size)
5939struct frame *f;
5940char * fontname;
5941int size;
5942{
5943 Lisp_Object bdf_fonts;
5944 struct font_info *retval = NULL;
5945
8edb0a6f 5946 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
5947
5948 while (!retval && CONSP (bdf_fonts))
5949 {
5950 char *bdf_name, *bdf_file;
5951 Lisp_Object bdf_pair;
5952
8e713be6
KR
5953 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5954 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5955 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
5956
5957 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5958
8e713be6 5959 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
5960 }
5961
5962 if (retval)
5963 return retval;
5964
5965 return w32_load_system_font(f, fontname, size);
5966}
5967
5968
ee78dc32 5969void
fbd6baed
GV
5970w32_unload_font (dpyinfo, font)
5971 struct w32_display_info *dpyinfo;
ee78dc32
GV
5972 XFontStruct * font;
5973{
5974 if (font)
5975 {
c6be3860 5976 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
5977 if (font->bdf) w32_free_bdf_font (font->bdf);
5978
3c190163 5979 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5980 xfree (font);
5981 }
5982}
5983
fbd6baed 5984/* The font conversion stuff between x and w32 */
ee78dc32
GV
5985
5986/* X font string is as follows (from faces.el)
5987 * (let ((- "[-?]")
5988 * (foundry "[^-]+")
5989 * (family "[^-]+")
5990 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5991 * (weight\? "\\([^-]*\\)") ; 1
5992 * (slant "\\([ior]\\)") ; 2
5993 * (slant\? "\\([^-]?\\)") ; 2
5994 * (swidth "\\([^-]*\\)") ; 3
5995 * (adstyle "[^-]*") ; 4
5996 * (pixelsize "[0-9]+")
5997 * (pointsize "[0-9][0-9]+")
5998 * (resx "[0-9][0-9]+")
5999 * (resy "[0-9][0-9]+")
6000 * (spacing "[cmp?*]")
6001 * (avgwidth "[0-9]+")
6002 * (registry "[^-]+")
6003 * (encoding "[^-]+")
6004 * )
ee78dc32 6005 */
ee78dc32 6006
8edb0a6f 6007static LONG
fbd6baed 6008x_to_w32_weight (lpw)
ee78dc32
GV
6009 char * lpw;
6010{
6011 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6012
6013 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6014 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6015 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6016 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6017 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6018 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6019 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6020 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6021 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6022 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6023 else
5ac45f98 6024 return FW_DONTCARE;
ee78dc32
GV
6025}
6026
5ac45f98 6027
8edb0a6f 6028static char *
fbd6baed 6029w32_to_x_weight (fnweight)
ee78dc32
GV
6030 int fnweight;
6031{
5ac45f98
GV
6032 if (fnweight >= FW_HEAVY) return "heavy";
6033 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6034 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6035 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6036 if (fnweight >= FW_MEDIUM) return "medium";
6037 if (fnweight >= FW_NORMAL) return "normal";
6038 if (fnweight >= FW_LIGHT) return "light";
6039 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6040 if (fnweight >= FW_THIN) return "thin";
6041 else
6042 return "*";
6043}
6044
8edb0a6f 6045static LONG
fbd6baed 6046x_to_w32_charset (lpcs)
5ac45f98
GV
6047 char * lpcs;
6048{
767b1ff0 6049 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6050 char *charset;
6051 int len = strlen (lpcs);
6052
6053 /* Support "*-#nnn" format for unknown charsets. */
6054 if (strncmp (lpcs, "*-#", 3) == 0)
6055 return atoi (lpcs + 3);
6056
6057 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6058 charset = alloca (len + 1);
6059 strcpy (charset, lpcs);
6060 lpcs = strchr (charset, '*');
6061 if (lpcs)
6062 *lpcs = 0;
4587b026 6063
dfff8a69
JR
6064 /* Look through w32-charset-info-alist for the character set.
6065 Format of each entry is
6066 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6067 */
8b77111c 6068 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6069
767b1ff0
JR
6070 if (NILP(this_entry))
6071 {
6072 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6073 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6074 return ANSI_CHARSET;
6075 else
6076 return DEFAULT_CHARSET;
6077 }
6078
6079 w32_charset = Fcar (Fcdr (this_entry));
6080
6081 // Translate Lisp symbol to number.
6082 if (w32_charset == Qw32_charset_ansi)
6083 return ANSI_CHARSET;
6084 if (w32_charset == Qw32_charset_symbol)
6085 return SYMBOL_CHARSET;
6086 if (w32_charset == Qw32_charset_shiftjis)
6087 return SHIFTJIS_CHARSET;
6088 if (w32_charset == Qw32_charset_hangeul)
6089 return HANGEUL_CHARSET;
6090 if (w32_charset == Qw32_charset_chinesebig5)
6091 return CHINESEBIG5_CHARSET;
6092 if (w32_charset == Qw32_charset_gb2312)
6093 return GB2312_CHARSET;
6094 if (w32_charset == Qw32_charset_oem)
6095 return OEM_CHARSET;
dfff8a69 6096#ifdef JOHAB_CHARSET
767b1ff0
JR
6097 if (w32_charset == Qw32_charset_johab)
6098 return JOHAB_CHARSET;
6099 if (w32_charset == Qw32_charset_easteurope)
6100 return EASTEUROPE_CHARSET;
6101 if (w32_charset == Qw32_charset_turkish)
6102 return TURKISH_CHARSET;
6103 if (w32_charset == Qw32_charset_baltic)
6104 return BALTIC_CHARSET;
6105 if (w32_charset == Qw32_charset_russian)
6106 return RUSSIAN_CHARSET;
6107 if (w32_charset == Qw32_charset_arabic)
6108 return ARABIC_CHARSET;
6109 if (w32_charset == Qw32_charset_greek)
6110 return GREEK_CHARSET;
6111 if (w32_charset == Qw32_charset_hebrew)
6112 return HEBREW_CHARSET;
6113 if (w32_charset == Qw32_charset_vietnamese)
6114 return VIETNAMESE_CHARSET;
6115 if (w32_charset == Qw32_charset_thai)
6116 return THAI_CHARSET;
6117 if (w32_charset == Qw32_charset_mac)
6118 return MAC_CHARSET;
dfff8a69 6119#endif /* JOHAB_CHARSET */
5ac45f98 6120#ifdef UNICODE_CHARSET
767b1ff0
JR
6121 if (w32_charset == Qw32_charset_unicode)
6122 return UNICODE_CHARSET;
5ac45f98 6123#endif
dfff8a69
JR
6124
6125 return DEFAULT_CHARSET;
5ac45f98
GV
6126}
6127
dfff8a69 6128
8edb0a6f 6129static char *
fbd6baed 6130w32_to_x_charset (fncharset)
5ac45f98
GV
6131 int fncharset;
6132{
5e905a57 6133 static char buf[32];
767b1ff0 6134 Lisp_Object charset_type;
1edf84e7 6135
5ac45f98
GV
6136 switch (fncharset)
6137 {
767b1ff0
JR
6138 case ANSI_CHARSET:
6139 /* Handle startup case of w32-charset-info-alist not
6140 being set up yet. */
6141 if (NILP(Vw32_charset_info_alist))
6142 return "iso8859-1";
6143 charset_type = Qw32_charset_ansi;
6144 break;
6145 case DEFAULT_CHARSET:
6146 charset_type = Qw32_charset_default;
6147 break;
6148 case SYMBOL_CHARSET:
6149 charset_type = Qw32_charset_symbol;
6150 break;
6151 case SHIFTJIS_CHARSET:
6152 charset_type = Qw32_charset_shiftjis;
6153 break;
6154 case HANGEUL_CHARSET:
6155 charset_type = Qw32_charset_hangeul;
6156 break;
6157 case GB2312_CHARSET:
6158 charset_type = Qw32_charset_gb2312;
6159 break;
6160 case CHINESEBIG5_CHARSET:
6161 charset_type = Qw32_charset_chinesebig5;
6162 break;
6163 case OEM_CHARSET:
6164 charset_type = Qw32_charset_oem;
6165 break;
4587b026
GV
6166
6167 /* More recent versions of Windows (95 and NT4.0) define more
6168 character sets. */
6169#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6170 case EASTEUROPE_CHARSET:
6171 charset_type = Qw32_charset_easteurope;
6172 break;
6173 case TURKISH_CHARSET:
6174 charset_type = Qw32_charset_turkish;
6175 break;
6176 case BALTIC_CHARSET:
6177 charset_type = Qw32_charset_baltic;
6178 break;
33d52f9c 6179 case RUSSIAN_CHARSET:
767b1ff0
JR
6180 charset_type = Qw32_charset_russian;
6181 break;
6182 case ARABIC_CHARSET:
6183 charset_type = Qw32_charset_arabic;
6184 break;
6185 case GREEK_CHARSET:
6186 charset_type = Qw32_charset_greek;
6187 break;
6188 case HEBREW_CHARSET:
6189 charset_type = Qw32_charset_hebrew;
6190 break;
6191 case VIETNAMESE_CHARSET:
6192 charset_type = Qw32_charset_vietnamese;
6193 break;
6194 case THAI_CHARSET:
6195 charset_type = Qw32_charset_thai;
6196 break;
6197 case MAC_CHARSET:
6198 charset_type = Qw32_charset_mac;
6199 break;
6200 case JOHAB_CHARSET:
6201 charset_type = Qw32_charset_johab;
6202 break;
4587b026
GV
6203#endif
6204
5ac45f98 6205#ifdef UNICODE_CHARSET
767b1ff0
JR
6206 case UNICODE_CHARSET:
6207 charset_type = Qw32_charset_unicode;
6208 break;
5ac45f98 6209#endif
767b1ff0
JR
6210 default:
6211 /* Encode numerical value of unknown charset. */
6212 sprintf (buf, "*-#%u", fncharset);
6213 return buf;
5ac45f98 6214 }
767b1ff0
JR
6215
6216 {
6217 Lisp_Object rest;
6218 char * best_match = NULL;
6219
6220 /* Look through w32-charset-info-alist for the character set.
6221 Prefer ISO codepages, and prefer lower numbers in the ISO
6222 range. Only return charsets for codepages which are installed.
6223
6224 Format of each entry is
6225 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6226 */
6227 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6228 {
6229 char * x_charset;
6230 Lisp_Object w32_charset;
6231 Lisp_Object codepage;
6232
6233 Lisp_Object this_entry = XCAR (rest);
6234
6235 /* Skip invalid entries in alist. */
6236 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6237 || !CONSP (XCDR (this_entry))
6238 || !SYMBOLP (XCAR (XCDR (this_entry))))
6239 continue;
6240
6241 x_charset = XSTRING (XCAR (this_entry))->data;
6242 w32_charset = XCAR (XCDR (this_entry));
6243 codepage = XCDR (XCDR (this_entry));
6244
6245 /* Look for Same charset and a valid codepage (or non-int
6246 which means ignore). */
6247 if (w32_charset == charset_type
6248 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6249 || IsValidCodePage (XINT (codepage))))
6250 {
6251 /* If we don't have a match already, then this is the
6252 best. */
6253 if (!best_match)
6254 best_match = x_charset;
6255 /* If this is an ISO codepage, and the best so far isn't,
6256 then this is better. */
6257 else if (stricmp (best_match, "iso") != 0
6258 && stricmp (x_charset, "iso") == 0)
6259 best_match = x_charset;
6260 /* If both are ISO8859 codepages, choose the one with the
6261 lowest number in the encoding field. */
6262 else if (stricmp (best_match, "iso8859-") == 0
6263 && stricmp (x_charset, "iso8859-") == 0)
6264 {
6265 int best_enc = atoi (best_match + 8);
6266 int this_enc = atoi (x_charset + 8);
6267 if (this_enc > 0 && this_enc < best_enc)
6268 best_match = x_charset;
6269 }
6270 }
6271 }
6272
6273 /* If no match, encode the numeric value. */
6274 if (!best_match)
6275 {
6276 sprintf (buf, "*-#%u", fncharset);
6277 return buf;
6278 }
6279
5e905a57
JR
6280 strncpy(buf, best_match, 31);
6281 buf[31] = '\0';
767b1ff0
JR
6282 return buf;
6283 }
ee78dc32
GV
6284}
6285
dfff8a69
JR
6286
6287/* Get the Windows codepage corresponding to the specified font. The
6288 charset info in the font name is used to look up
6289 w32-charset-to-codepage-alist. */
6290int
6291w32_codepage_for_font (char *fontname)
6292{
767b1ff0
JR
6293 Lisp_Object codepage, entry;
6294 char *charset_str, *charset, *end;
dfff8a69 6295
767b1ff0 6296 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6297 return CP_DEFAULT;
6298
767b1ff0
JR
6299 /* Extract charset part of font string. */
6300 charset = xlfd_charset_of_font (fontname);
6301
6302 if (!charset)
ceb12877 6303 return CP_UNKNOWN;
767b1ff0 6304
8b77111c 6305 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6306 strcpy (charset_str, charset);
6307
8b77111c 6308#if 0
dfff8a69
JR
6309 /* Remove leading "*-". */
6310 if (strncmp ("*-", charset_str, 2) == 0)
6311 charset = charset_str + 2;
6312 else
8b77111c 6313#endif
dfff8a69
JR
6314 charset = charset_str;
6315
6316 /* Stop match at wildcard (including preceding '-'). */
6317 if (end = strchr (charset, '*'))
6318 {
6319 if (end > charset && *(end-1) == '-')
6320 end--;
6321 *end = '\0';
6322 }
6323
767b1ff0
JR
6324 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6325 if (NILP (entry))
ceb12877 6326 return CP_UNKNOWN;
767b1ff0
JR
6327
6328 codepage = Fcdr (Fcdr (entry));
6329
6330 if (NILP (codepage))
6331 return CP_8BIT;
6332 else if (XFASTINT (codepage) == XFASTINT (Qt))
6333 return CP_UNICODE;
6334 else if (INTEGERP (codepage))
dfff8a69
JR
6335 return XINT (codepage);
6336 else
ceb12877 6337 return CP_UNKNOWN;
dfff8a69
JR
6338}
6339
6340
8edb0a6f 6341static BOOL
767b1ff0 6342w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6343 LOGFONT * lplogfont;
6344 char * lpxstr;
6345 int len;
767b1ff0 6346 char * specific_charset;
ee78dc32 6347{
6fc2811b 6348 char* fonttype;
f46e6225 6349 char *fontname;
3cb20f4a
RS
6350 char height_pixels[8];
6351 char height_dpi[8];
6352 char width_pixels[8];
4587b026 6353 char *fontname_dash;
d88c567c
JR
6354 int display_resy = one_w32_display_info.resy;
6355 int display_resx = one_w32_display_info.resx;
f46e6225
GV
6356 int bufsz;
6357 struct coding_system coding;
3cb20f4a
RS
6358
6359 if (!lpxstr) abort ();
ee78dc32 6360
3cb20f4a
RS
6361 if (!lplogfont)
6362 return FALSE;
6363
6fc2811b
JR
6364 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6365 fonttype = "raster";
6366 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6367 fonttype = "outline";
6368 else
6369 fonttype = "unknown";
6370
1fa3a200 6371 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6372 &coding);
aab5ac44
KH
6373 coding.src_multibyte = 0;
6374 coding.dst_multibyte = 1;
f46e6225
GV
6375 coding.mode |= CODING_MODE_LAST_BLOCK;
6376 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6377
6378 fontname = alloca(sizeof(*fontname) * bufsz);
6379 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6380 strlen(lplogfont->lfFaceName), bufsz - 1);
6381 *(fontname + coding.produced) = '\0';
4587b026
GV
6382
6383 /* Replace dashes with underscores so the dashes are not
f46e6225 6384 misinterpreted. */
4587b026
GV
6385 fontname_dash = fontname;
6386 while (fontname_dash = strchr (fontname_dash, '-'))
6387 *fontname_dash = '_';
6388
3cb20f4a 6389 if (lplogfont->lfHeight)
ee78dc32 6390 {
3cb20f4a
RS
6391 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6392 sprintf (height_dpi, "%u",
33d52f9c 6393 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6394 }
6395 else
ee78dc32 6396 {
3cb20f4a
RS
6397 strcpy (height_pixels, "*");
6398 strcpy (height_dpi, "*");
ee78dc32 6399 }
3cb20f4a
RS
6400 if (lplogfont->lfWidth)
6401 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6402 else
6403 strcpy (width_pixels, "*");
6404
6405 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6406 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6407 fonttype, /* foundry */
4587b026
GV
6408 fontname, /* family */
6409 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6410 lplogfont->lfItalic?'i':'r', /* slant */
6411 /* setwidth name */
6412 /* add style name */
6413 height_pixels, /* pixel size */
6414 height_dpi, /* point size */
33d52f9c
GV
6415 display_resx, /* resx */
6416 display_resy, /* resy */
4587b026
GV
6417 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6418 ? 'p' : 'c', /* spacing */
6419 width_pixels, /* avg width */
767b1ff0
JR
6420 specific_charset ? specific_charset
6421 : w32_to_x_charset (lplogfont->lfCharSet)
6422 /* charset registry and encoding */
3cb20f4a
RS
6423 );
6424
ee78dc32
GV
6425 lpxstr[len - 1] = 0; /* just to be sure */
6426 return (TRUE);
6427}
6428
8edb0a6f 6429static BOOL
fbd6baed 6430x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6431 char * lpxstr;
6432 LOGFONT * lplogfont;
6433{
f46e6225
GV
6434 struct coding_system coding;
6435
ee78dc32 6436 if (!lplogfont) return (FALSE);
f46e6225 6437
ee78dc32 6438 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6439
1a292d24 6440 /* Set default value for each field. */
771c47d5 6441#if 1
ee78dc32
GV
6442 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6443 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6444 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6445#else
6446 /* go for maximum quality */
6447 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6448 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6449 lplogfont->lfQuality = PROOF_QUALITY;
6450#endif
6451
1a292d24
AI
6452 lplogfont->lfCharSet = DEFAULT_CHARSET;
6453 lplogfont->lfWeight = FW_DONTCARE;
6454 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6455
5ac45f98
GV
6456 if (!lpxstr)
6457 return FALSE;
6458
6459 /* Provide a simple escape mechanism for specifying Windows font names
6460 * directly -- if font spec does not beginning with '-', assume this
6461 * format:
6462 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6463 */
ee78dc32 6464
5ac45f98
GV
6465 if (*lpxstr == '-')
6466 {
33d52f9c
GV
6467 int fields, tem;
6468 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6469 width[10], resy[10], remainder[50];
5ac45f98 6470 char * encoding;
d98c0337 6471 int dpi = one_w32_display_info.resy;
5ac45f98
GV
6472
6473 fields = sscanf (lpxstr,
8b77111c 6474 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6475 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6476 if (fields == EOF)
6477 return (FALSE);
6478
6479 /* In the general case when wildcards cover more than one field,
6480 we don't know which field is which, so don't fill any in.
6481 However, we need to cope with this particular form, which is
6482 generated by font_list_1 (invoked by try_font_list):
6483 "-raster-6x10-*-gb2312*-*"
6484 and make sure to correctly parse the charset field. */
6485 if (fields == 3)
6486 {
6487 fields = sscanf (lpxstr,
6488 "-%*[^-]-%49[^-]-*-%49s",
6489 name, remainder);
6490 }
6491 else if (fields < 9)
6492 {
6493 fields = 0;
6494 remainder[0] = 0;
6495 }
6fc2811b 6496
5ac45f98
GV
6497 if (fields > 0 && name[0] != '*')
6498 {
8ea3e054
RS
6499 int bufsize;
6500 unsigned char *buf;
6501
f46e6225 6502 setup_coding_system
1fa3a200 6503 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6504 coding.src_multibyte = 1;
6505 coding.dst_multibyte = 1;
8ea3e054
RS
6506 bufsize = encoding_buffer_size (&coding, strlen (name));
6507 buf = (unsigned char *) alloca (bufsize);
f46e6225 6508 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6509 encode_coding (&coding, name, buf, strlen (name), bufsize);
6510 if (coding.produced >= LF_FACESIZE)
6511 coding.produced = LF_FACESIZE - 1;
6512 buf[coding.produced] = 0;
6513 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6514 }
6515 else
6516 {
6fc2811b 6517 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6518 }
6519
6520 fields--;
6521
fbd6baed 6522 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6523
6524 fields--;
6525
c8874f14 6526 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6527
6528 fields--;
6529
6530 if (fields > 0 && pixels[0] != '*')
6531 lplogfont->lfHeight = atoi (pixels);
6532
6533 fields--;
5ac45f98 6534 fields--;
33d52f9c
GV
6535 if (fields > 0 && resy[0] != '*')
6536 {
6fc2811b 6537 tem = atoi (resy);
33d52f9c
GV
6538 if (tem > 0) dpi = tem;
6539 }
5ac45f98 6540
33d52f9c
GV
6541 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6542 lplogfont->lfHeight = atoi (height) * dpi / 720;
6543
6544 if (fields > 0)
5ac45f98
GV
6545 lplogfont->lfPitchAndFamily =
6546 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6547
6548 fields--;
6549
6550 if (fields > 0 && width[0] != '*')
6551 lplogfont->lfWidth = atoi (width) / 10;
6552
6553 fields--;
6554
4587b026 6555 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6556 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6557 {
5ac45f98
GV
6558 int len = strlen (remainder);
6559 if (len > 0 && remainder[len-1] == '-')
6560 remainder[len-1] = 0;
ee78dc32 6561 }
5ac45f98 6562 encoding = remainder;
8b77111c 6563#if 0
5ac45f98
GV
6564 if (strncmp (encoding, "*-", 2) == 0)
6565 encoding += 2;
8b77111c
AI
6566#endif
6567 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6568 }
6569 else
6570 {
6571 int fields;
6572 char name[100], height[10], width[10], weight[20];
a1a80b40 6573
5ac45f98
GV
6574 fields = sscanf (lpxstr,
6575 "%99[^:]:%9[^:]:%9[^:]:%19s",
6576 name, height, width, weight);
6577
6578 if (fields == EOF) return (FALSE);
6579
6580 if (fields > 0)
6581 {
6582 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6583 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6584 }
6585 else
6586 {
6587 lplogfont->lfFaceName[0] = 0;
6588 }
6589
6590 fields--;
6591
6592 if (fields > 0)
6593 lplogfont->lfHeight = atoi (height);
6594
6595 fields--;
6596
6597 if (fields > 0)
6598 lplogfont->lfWidth = atoi (width);
6599
6600 fields--;
6601
fbd6baed 6602 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6603 }
6604
6605 /* This makes TrueType fonts work better. */
6606 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6607
ee78dc32
GV
6608 return (TRUE);
6609}
6610
d88c567c
JR
6611/* Strip the pixel height and point height from the given xlfd, and
6612 return the pixel height. If no pixel height is specified, calculate
6613 one from the point height, or if that isn't defined either, return
6614 0 (which usually signifies a scalable font).
6615*/
8edb0a6f
JR
6616static int
6617xlfd_strip_height (char *fontname)
d88c567c 6618{
8edb0a6f 6619 int pixel_height, field_number;
d88c567c
JR
6620 char *read_from, *write_to;
6621
6622 xassert (fontname);
6623
6624 pixel_height = field_number = 0;
6625 write_to = NULL;
6626
6627 /* Look for height fields. */
6628 for (read_from = fontname; *read_from; read_from++)
6629 {
6630 if (*read_from == '-')
6631 {
6632 field_number++;
6633 if (field_number == 7) /* Pixel height. */
6634 {
6635 read_from++;
6636 write_to = read_from;
6637
6638 /* Find end of field. */
6639 for (;*read_from && *read_from != '-'; read_from++)
6640 ;
6641
6642 /* Split the fontname at end of field. */
6643 if (*read_from)
6644 {
6645 *read_from = '\0';
6646 read_from++;
6647 }
6648 pixel_height = atoi (write_to);
6649 /* Blank out field. */
6650 if (read_from > write_to)
6651 {
6652 *write_to = '-';
6653 write_to++;
6654 }
767b1ff0 6655 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6656 return now. */
6657 else
6658 return pixel_height;
6659
6660 /* If we got a pixel height, the point height can be
6661 ignored. Just blank it out and break now. */
6662 if (pixel_height)
6663 {
6664 /* Find end of point size field. */
6665 for (; *read_from && *read_from != '-'; read_from++)
6666 ;
6667
6668 if (*read_from)
6669 read_from++;
6670
6671 /* Blank out the point size field. */
6672 if (read_from > write_to)
6673 {
6674 *write_to = '-';
6675 write_to++;
6676 }
6677 else
6678 return pixel_height;
6679
6680 break;
6681 }
6682 /* If the point height is already blank, break now. */
6683 if (*read_from == '-')
6684 {
6685 read_from++;
6686 break;
6687 }
6688 }
6689 else if (field_number == 8)
6690 {
6691 /* If we didn't get a pixel height, try to get the point
6692 height and convert that. */
6693 int point_size;
6694 char *point_size_start = read_from++;
6695
6696 /* Find end of field. */
6697 for (; *read_from && *read_from != '-'; read_from++)
6698 ;
6699
6700 if (*read_from)
6701 {
6702 *read_from = '\0';
6703 read_from++;
6704 }
6705
6706 point_size = atoi (point_size_start);
6707
6708 /* Convert to pixel height. */
6709 pixel_height = point_size
6710 * one_w32_display_info.height_in / 720;
6711
6712 /* Blank out this field and break. */
6713 *write_to = '-';
6714 write_to++;
6715 break;
6716 }
6717 }
6718 }
6719
6720 /* Shift the rest of the font spec into place. */
6721 if (write_to && read_from > write_to)
6722 {
6723 for (; *read_from; read_from++, write_to++)
6724 *write_to = *read_from;
6725 *write_to = '\0';
6726 }
6727
6728 return pixel_height;
6729}
6730
6fc2811b 6731/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 6732static BOOL
6fc2811b
JR
6733w32_font_match (fontname, pattern)
6734 char * fontname;
6735 char * pattern;
ee78dc32 6736{
e7c72122 6737 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 6738 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6739 char *ptr;
ee78dc32 6740
d88c567c
JR
6741 /* Copy fontname so we can modify it during comparison. */
6742 strcpy (font_name_copy, fontname);
6743
6fc2811b
JR
6744 ptr = regex;
6745 *ptr++ = '^';
ee78dc32 6746
6fc2811b
JR
6747 /* Turn pattern into a regexp and do a regexp match. */
6748 for (; *pattern; pattern++)
6749 {
6750 if (*pattern == '?')
6751 *ptr++ = '.';
6752 else if (*pattern == '*')
6753 {
6754 *ptr++ = '.';
6755 *ptr++ = '*';
6756 }
33d52f9c 6757 else
6fc2811b 6758 *ptr++ = *pattern;
ee78dc32 6759 }
6fc2811b
JR
6760 *ptr = '$';
6761 *(ptr + 1) = '\0';
6762
d88c567c
JR
6763 /* Strip out font heights and compare them seperately, since
6764 rounding error can cause mismatches. This also allows a
6765 comparison between a font that declares only a pixel height and a
6766 pattern that declares the point height.
6767 */
6768 {
6769 int font_height, pattern_height;
6770
6771 font_height = xlfd_strip_height (font_name_copy);
6772 pattern_height = xlfd_strip_height (regex);
6773
6774 /* Compare now, and don't bother doing expensive regexp matching
6775 if the heights differ. */
6776 if (font_height && pattern_height && (font_height != pattern_height))
6777 return FALSE;
6778 }
6779
6fc2811b 6780 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 6781 font_name_copy) >= 0);
ee78dc32
GV
6782}
6783
5ca0cd71
GV
6784/* Callback functions, and a structure holding info they need, for
6785 listing system fonts on W32. We need one set of functions to do the
6786 job properly, but these don't work on NT 3.51 and earlier, so we
6787 have a second set which don't handle character sets properly to
6788 fall back on.
6789
6790 In both cases, there are two passes made. The first pass gets one
6791 font from each family, the second pass lists all the fonts from
6792 each family. */
6793
ee78dc32
GV
6794typedef struct enumfont_t
6795{
6796 HDC hdc;
6797 int numFonts;
3cb20f4a 6798 LOGFONT logfont;
ee78dc32
GV
6799 XFontStruct *size_ref;
6800 Lisp_Object *pattern;
ee78dc32
GV
6801 Lisp_Object *tail;
6802} enumfont_t;
6803
8edb0a6f 6804static int CALLBACK
ee78dc32
GV
6805enum_font_cb2 (lplf, lptm, FontType, lpef)
6806 ENUMLOGFONT * lplf;
6807 NEWTEXTMETRIC * lptm;
6808 int FontType;
6809 enumfont_t * lpef;
6810{
66895301
JR
6811 /* Ignore struck out and underlined versions of fonts. */
6812 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6813 return 1;
6814
6815 /* Only return fonts with names starting with @ if they were
6816 explicitly specified, since Microsoft uses an initial @ to
6817 denote fonts for vertical writing, without providing a more
6818 convenient way of identifying them. */
6819 if (lplf->elfLogFont.lfFaceName[0] == '@'
6820 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
6821 return 1;
6822
4587b026
GV
6823 /* Check that the character set matches if it was specified */
6824 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6825 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 6826 return 1;
4587b026 6827
ee78dc32
GV
6828 {
6829 char buf[100];
4587b026 6830 Lisp_Object width = Qnil;
767b1ff0 6831 char *charset = NULL;
ee78dc32 6832
6fc2811b
JR
6833 /* Truetype fonts do not report their true metrics until loaded */
6834 if (FontType != RASTER_FONTTYPE)
3cb20f4a 6835 {
6fc2811b
JR
6836 if (!NILP (*(lpef->pattern)))
6837 {
6838 /* Scalable fonts are as big as you want them to be. */
6839 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6840 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6841 width = make_number (lpef->logfont.lfWidth);
6842 }
6843 else
6844 {
6845 lplf->elfLogFont.lfHeight = 0;
6846 lplf->elfLogFont.lfWidth = 0;
6847 }
3cb20f4a 6848 }
6fc2811b 6849
f46e6225
GV
6850 /* Make sure the height used here is the same as everywhere
6851 else (ie character height, not cell height). */
6fc2811b
JR
6852 if (lplf->elfLogFont.lfHeight > 0)
6853 {
6854 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6855 if (FontType == RASTER_FONTTYPE)
6856 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6857 else
6858 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6859 }
4587b026 6860
767b1ff0
JR
6861 if (!NILP (*(lpef->pattern)))
6862 {
6863 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6864
6865 /* Ensure that charset is valid for this font. */
6866 if (charset
6867 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6868 charset = NULL;
6869 }
6870
6871 /* TODO: List all relevant charsets if charset not specified. */
6872 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
66895301 6873 return 1;
ee78dc32 6874
5ca0cd71
GV
6875 if (NILP (*(lpef->pattern))
6876 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 6877 {
4587b026 6878 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
8e713be6 6879 lpef->tail = &(XCDR (*lpef->tail));
ee78dc32
GV
6880 lpef->numFonts++;
6881 }
6882 }
6fc2811b 6883
5e905a57 6884 return 1;
ee78dc32
GV
6885}
6886
8edb0a6f 6887static int CALLBACK
ee78dc32
GV
6888enum_font_cb1 (lplf, lptm, FontType, lpef)
6889 ENUMLOGFONT * lplf;
6890 NEWTEXTMETRIC * lptm;
6891 int FontType;
6892 enumfont_t * lpef;
6893{
6894 return EnumFontFamilies (lpef->hdc,
6895 lplf->elfLogFont.lfFaceName,
6896 (FONTENUMPROC) enum_font_cb2,
6897 (LPARAM) lpef);
6898}
6899
6900
8edb0a6f 6901static int CALLBACK
5ca0cd71
GV
6902enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6903 ENUMLOGFONTEX * lplf;
6904 NEWTEXTMETRICEX * lptm;
6905 int font_type;
6906 enumfont_t * lpef;
6907{
6908 /* We are not interested in the extra info we get back from the 'Ex
6909 version - only the fact that we get character set variations
6910 enumerated seperately. */
6911 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6912 font_type, lpef);
6913}
6914
8edb0a6f 6915static int CALLBACK
5ca0cd71
GV
6916enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6917 ENUMLOGFONTEX * lplf;
6918 NEWTEXTMETRICEX * lptm;
6919 int font_type;
6920 enumfont_t * lpef;
6921{
6922 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6923 FARPROC enum_font_families_ex
6924 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6925 /* We don't really expect EnumFontFamiliesEx to disappear once we
6926 get here, so don't bother handling it gracefully. */
6927 if (enum_font_families_ex == NULL)
6928 error ("gdi32.dll has disappeared!");
6929 return enum_font_families_ex (lpef->hdc,
6930 &lplf->elfLogFont,
6931 (FONTENUMPROC) enum_fontex_cb2,
6932 (LPARAM) lpef, 0);
6933}
6934
4587b026
GV
6935/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6936 and xterm.c in Emacs 20.3) */
6937
8edb0a6f 6938static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6939{
6940 char *fontname, *ptnstr;
6941 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6942 int n_fonts = 0;
33d52f9c
GV
6943
6944 list = Vw32_bdf_filename_alist;
6945 ptnstr = XSTRING (pattern)->data;
6946
8e713be6 6947 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6948 {
8e713be6 6949 tem = XCAR (list);
33d52f9c 6950 if (CONSP (tem))
8e713be6 6951 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
6952 else if (STRINGP (tem))
6953 fontname = XSTRING (tem)->data;
6954 else
6955 continue;
6956
6957 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6958 {
8e713be6 6959 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6960 n_fonts++;
6961 if (n_fonts >= max_names)
6962 break;
6963 }
33d52f9c
GV
6964 }
6965
6966 return newlist;
6967}
6968
8edb0a6f
JR
6969static Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f,
6970 Lisp_Object pattern,
6971 int size, int max_names);
5ca0cd71 6972
4587b026
GV
6973/* Return a list of names of available fonts matching PATTERN on frame
6974 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6975 to be listed. Frame F NULL means we have not yet created any
6976 frame, which means we can't get proper size info, as we don't have
6977 a device context to use for GetTextMetrics.
6978 MAXNAMES sets a limit on how many fonts to match. */
6979
6980Lisp_Object
dc220243
JR
6981w32_list_fonts (f, pattern, size, maxnames)
6982 struct frame *f;
6983 Lisp_Object pattern;
6984 int size;
6985 int maxnames;
4587b026 6986{
6fc2811b 6987 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6988 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6989 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6990 int n_fonts = 0;
396594fe 6991
4587b026
GV
6992 patterns = Fassoc (pattern, Valternate_fontname_alist);
6993 if (NILP (patterns))
6994 patterns = Fcons (pattern, Qnil);
6995
8e713be6 6996 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6997 {
6998 enumfont_t ef;
767b1ff0 6999 int codepage;
4587b026 7000
8e713be6 7001 tpat = XCAR (patterns);
4587b026 7002
767b1ff0
JR
7003 if (!STRINGP (tpat))
7004 continue;
7005
7006 /* Avoid expensive EnumFontFamilies functions if we are not
7007 going to be able to output one of these anyway. */
7008 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7009 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7010 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7011 && !IsValidCodePage(codepage))
767b1ff0
JR
7012 continue;
7013
4587b026
GV
7014 /* See if we cached the result for this particular query.
7015 The cache is an alist of the form:
7016 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7017 */
8e713be6 7018 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7019 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7020 {
7021 list = Fcdr_safe (list);
7022 /* We have a cached list. Don't have to get the list again. */
7023 goto label_cached;
7024 }
7025
7026 BLOCK_INPUT;
7027 /* At first, put PATTERN in the cache. */
7028 list = Qnil;
33d52f9c
GV
7029 ef.pattern = &tpat;
7030 ef.tail = &list;
4587b026 7031 ef.numFonts = 0;
33d52f9c 7032
5ca0cd71
GV
7033 /* Use EnumFontFamiliesEx where it is available, as it knows
7034 about character sets. Fall back to EnumFontFamilies for
7035 older versions of NT that don't support the 'Ex function. */
767b1ff0 7036 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7037 {
5ca0cd71
GV
7038 LOGFONT font_match_pattern;
7039 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7040 FARPROC enum_font_families_ex
7041 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7042
7043 /* We do our own pattern matching so we can handle wildcards. */
7044 font_match_pattern.lfFaceName[0] = 0;
7045 font_match_pattern.lfPitchAndFamily = 0;
7046 /* We can use the charset, because if it is a wildcard it will
7047 be DEFAULT_CHARSET anyway. */
7048 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7049
33d52f9c 7050 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7051
5ca0cd71
GV
7052 if (enum_font_families_ex)
7053 enum_font_families_ex (ef.hdc,
7054 &font_match_pattern,
7055 (FONTENUMPROC) enum_fontex_cb1,
7056 (LPARAM) &ef, 0);
7057 else
7058 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7059 (LPARAM)&ef);
4587b026 7060
33d52f9c 7061 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7062 }
7063
7064 UNBLOCK_INPUT;
7065
7066 /* Make a list of the fonts we got back.
7067 Store that in the font cache for the display. */
f3fbd155
KR
7068 XSETCDR (dpyinfo->name_list_element,
7069 Fcons (Fcons (tpat, list),
7070 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7071
7072 label_cached:
7073 if (NILP (list)) continue; /* Try the remaining alternatives. */
7074
7075 newlist = second_best = Qnil;
7076
7077 /* Make a list of the fonts that have the right width. */
8e713be6 7078 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7079 {
7080 int found_size;
8e713be6 7081 tem = XCAR (list);
4587b026
GV
7082
7083 if (!CONSP (tem))
7084 continue;
8e713be6 7085 if (NILP (XCAR (tem)))
4587b026
GV
7086 continue;
7087 if (!size)
7088 {
8e713be6 7089 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7090 n_fonts++;
7091 if (n_fonts >= maxnames)
7092 break;
7093 else
7094 continue;
4587b026 7095 }
8e713be6 7096 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7097 {
7098 /* Since we don't yet know the size of the font, we must
7099 load it and try GetTextMetrics. */
4587b026
GV
7100 W32FontStruct thisinfo;
7101 LOGFONT lf;
7102 HDC hdc;
7103 HANDLE oldobj;
7104
8e713be6 7105 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7106 continue;
7107
7108 BLOCK_INPUT;
33d52f9c 7109 thisinfo.bdf = NULL;
4587b026
GV
7110 thisinfo.hfont = CreateFontIndirect (&lf);
7111 if (thisinfo.hfont == NULL)
7112 continue;
7113
7114 hdc = GetDC (dpyinfo->root_window);
7115 oldobj = SelectObject (hdc, thisinfo.hfont);
7116 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7117 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7118 else
f3fbd155 7119 XSETCDR (tem, make_number (0));
4587b026
GV
7120 SelectObject (hdc, oldobj);
7121 ReleaseDC (dpyinfo->root_window, hdc);
7122 DeleteObject(thisinfo.hfont);
7123 UNBLOCK_INPUT;
7124 }
8e713be6 7125 found_size = XINT (XCDR (tem));
4587b026 7126 if (found_size == size)
5ca0cd71 7127 {
8e713be6 7128 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7129 n_fonts++;
7130 if (n_fonts >= maxnames)
7131 break;
7132 }
4587b026
GV
7133 /* keep track of the closest matching size in case
7134 no exact match is found. */
7135 else if (found_size > 0)
7136 {
7137 if (NILP (second_best))
7138 second_best = tem;
5ca0cd71 7139
4587b026
GV
7140 else if (found_size < size)
7141 {
8e713be6
KR
7142 if (XINT (XCDR (second_best)) > size
7143 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7144 second_best = tem;
7145 }
7146 else
7147 {
8e713be6
KR
7148 if (XINT (XCDR (second_best)) > size
7149 && XINT (XCDR (second_best)) >
4587b026
GV
7150 found_size)
7151 second_best = tem;
7152 }
7153 }
7154 }
7155
7156 if (!NILP (newlist))
7157 break;
7158 else if (!NILP (second_best))
7159 {
8e713be6 7160 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7161 break;
7162 }
7163 }
7164
33d52f9c 7165 /* Include any bdf fonts. */
5ca0cd71 7166 if (n_fonts < maxnames)
33d52f9c
GV
7167 {
7168 Lisp_Object combined[2];
5ca0cd71 7169 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7170 combined[1] = newlist;
7171 newlist = Fnconc(2, combined);
7172 }
7173
5ca0cd71
GV
7174 /* If we can't find a font that matches, check if Windows would be
7175 able to synthesize it from a different style. */
6fc2811b 7176 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
5ca0cd71
GV
7177 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
7178
4587b026
GV
7179 return newlist;
7180}
7181
8edb0a6f 7182static Lisp_Object
5ca0cd71
GV
7183w32_list_synthesized_fonts (f, pattern, size, max_names)
7184 FRAME_PTR f;
7185 Lisp_Object pattern;
7186 int size;
7187 int max_names;
7188{
7189 int fields;
7190 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
7191 char style[20], slant;
8edb0a6f 7192 Lisp_Object matches, tem, synthed_matches = Qnil;
5ca0cd71
GV
7193
7194 full_pattn = XSTRING (pattern)->data;
7195
8b77111c 7196 pattn_part2 = alloca (XSTRING (pattern)->size + 1);
5ca0cd71
GV
7197 /* Allow some space for wildcard expansion. */
7198 new_pattn = alloca (XSTRING (pattern)->size + 100);
7199
7200 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
7201 foundary, family, style, &slant, pattn_part2);
7202 if (fields == EOF || fields < 5)
7203 return Qnil;
7204
7205 /* If the style and slant are wildcards already there is no point
7206 checking again (and we don't want to keep recursing). */
7207 if (*style == '*' && slant == '*')
7208 return Qnil;
7209
7210 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
7211
7212 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
7213
8e713be6 7214 for ( ; CONSP (matches); matches = XCDR (matches))
5ca0cd71 7215 {
8e713be6 7216 tem = XCAR (matches);
5ca0cd71
GV
7217 if (!STRINGP (tem))
7218 continue;
7219
7220 full_pattn = XSTRING (tem)->data;
7221 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
7222 foundary, family, pattn_part2);
7223 if (fields == EOF || fields < 3)
7224 continue;
7225
7226 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
7227 slant, pattn_part2);
7228
7229 synthed_matches = Fcons (build_string (new_pattn),
7230 synthed_matches);
7231 }
7232
7233 return synthed_matches;
7234}
7235
7236
4587b026
GV
7237/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7238struct font_info *
7239w32_get_font_info (f, font_idx)
7240 FRAME_PTR f;
7241 int font_idx;
7242{
7243 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7244}
7245
7246
7247struct font_info*
7248w32_query_font (struct frame *f, char *fontname)
7249{
7250 int i;
7251 struct font_info *pfi;
7252
7253 pfi = FRAME_W32_FONT_TABLE (f);
7254
7255 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7256 {
7257 if (strcmp(pfi->name, fontname) == 0) return pfi;
7258 }
7259
7260 return NULL;
7261}
7262
7263/* Find a CCL program for a font specified by FONTP, and set the member
7264 `encoder' of the structure. */
7265
7266void
7267w32_find_ccl_program (fontp)
7268 struct font_info *fontp;
7269{
3545439c 7270 Lisp_Object list, elt;
4587b026 7271
8e713be6 7272 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7273 {
8e713be6 7274 elt = XCAR (list);
4587b026 7275 if (CONSP (elt)
8e713be6
KR
7276 && STRINGP (XCAR (elt))
7277 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7278 >= 0))
3545439c
KH
7279 break;
7280 }
7281 if (! NILP (list))
7282 {
17eedd00
KH
7283 struct ccl_program *ccl
7284 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7285
8e713be6 7286 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7287 xfree (ccl);
7288 else
7289 fontp->font_encoder = ccl;
4587b026
GV
7290 }
7291}
7292
7293\f
8edb0a6f
JR
7294/* Find BDF files in a specified directory. (use GCPRO when calling,
7295 as this calls lisp to get a directory listing). */
7296static Lisp_Object
7297w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7298{
7299 Lisp_Object filelist, list = Qnil;
7300 char fontname[100];
7301
7302 if (!STRINGP(directory))
7303 return Qnil;
7304
7305 filelist = Fdirectory_files (directory, Qt,
7306 build_string (".*\\.[bB][dD][fF]"), Qt);
7307
7308 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7309 {
7310 Lisp_Object filename = XCAR (filelist);
7311 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7312 store_in_alist (&list, build_string (fontname), filename);
7313 }
7314 return list;
7315}
7316
6fc2811b
JR
7317DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7318 1, 1, 0,
b3700ae7
JR
7319 doc: /* Return a list of BDF fonts in DIR.
7320The list is suitable for appending to w32-bdf-filename-alist. Fonts
7321which do not contain an xlfd description will not be included in the
7322list. DIR may be a list of directories. */)
6fc2811b
JR
7323 (directory)
7324 Lisp_Object directory;
7325{
7326 Lisp_Object list = Qnil;
7327 struct gcpro gcpro1, gcpro2;
ee78dc32 7328
6fc2811b
JR
7329 if (!CONSP (directory))
7330 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7331
6fc2811b 7332 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7333 {
6fc2811b
JR
7334 Lisp_Object pair[2];
7335 pair[0] = list;
7336 pair[1] = Qnil;
7337 GCPRO2 (directory, list);
7338 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7339 list = Fnconc( 2, pair );
7340 UNGCPRO;
7341 }
7342 return list;
7343}
ee78dc32 7344
6fc2811b
JR
7345\f
7346DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7347 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7348 (color, frame)
7349 Lisp_Object color, frame;
7350{
7351 XColor foo;
7352 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7353
b7826503 7354 CHECK_STRING (color);
ee78dc32 7355
6fc2811b
JR
7356 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7357 return Qt;
7358 else
7359 return Qnil;
7360}
ee78dc32 7361
2d764c78 7362DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7363 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7364 (color, frame)
7365 Lisp_Object color, frame;
7366{
6fc2811b 7367 XColor foo;
ee78dc32
GV
7368 FRAME_PTR f = check_x_frame (frame);
7369
b7826503 7370 CHECK_STRING (color);
ee78dc32 7371
6fc2811b 7372 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7373 {
7374 Lisp_Object rgb[3];
7375
6fc2811b
JR
7376 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7377 | GetRValue (foo.pixel));
7378 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7379 | GetGValue (foo.pixel));
7380 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7381 | GetBValue (foo.pixel));
ee78dc32
GV
7382 return Flist (3, rgb);
7383 }
7384 else
7385 return Qnil;
7386}
7387
2d764c78 7388DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7389 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7390 (display)
7391 Lisp_Object display;
7392{
fbd6baed 7393 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7394
7395 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7396 return Qnil;
7397
7398 return Qt;
7399}
7400
74e1aeec
JR
7401DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7402 Sx_display_grayscale_p, 0, 1, 0,
7403 doc: /* Return t if the X display supports shades of gray.
7404Note that color displays do support shades of gray.
7405The optional argument DISPLAY specifies which display to ask about.
7406DISPLAY should be either a frame or a display name (a string).
7407If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7408 (display)
7409 Lisp_Object display;
7410{
fbd6baed 7411 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7412
7413 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7414 return Qnil;
7415
7416 return Qt;
7417}
7418
74e1aeec
JR
7419DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7420 Sx_display_pixel_width, 0, 1, 0,
7421 doc: /* Returns the width in pixels of DISPLAY.
7422The optional argument DISPLAY specifies which display to ask about.
7423DISPLAY should be either a frame or a display name (a string).
7424If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7425 (display)
7426 Lisp_Object display;
7427{
fbd6baed 7428 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7429
7430 return make_number (dpyinfo->width);
7431}
7432
7433DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7434 Sx_display_pixel_height, 0, 1, 0,
7435 doc: /* Returns the height in pixels of DISPLAY.
7436The optional argument DISPLAY specifies which display to ask about.
7437DISPLAY should be either a frame or a display name (a string).
7438If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7439 (display)
7440 Lisp_Object display;
7441{
fbd6baed 7442 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7443
7444 return make_number (dpyinfo->height);
7445}
7446
7447DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7448 0, 1, 0,
7449 doc: /* Returns the number of bitplanes of DISPLAY.
7450The optional argument DISPLAY specifies which display to ask about.
7451DISPLAY should be either a frame or a display name (a string).
7452If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7453 (display)
7454 Lisp_Object display;
7455{
fbd6baed 7456 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7457
7458 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7459}
7460
7461DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7462 0, 1, 0,
7463 doc: /* Returns the number of color cells of DISPLAY.
7464The optional argument DISPLAY specifies which display to ask about.
7465DISPLAY should be either a frame or a display name (a string).
7466If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7467 (display)
7468 Lisp_Object display;
7469{
fbd6baed 7470 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7471 HDC hdc;
7472 int cap;
7473
5ac45f98
GV
7474 hdc = GetDC (dpyinfo->root_window);
7475 if (dpyinfo->has_palette)
7476 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7477 else
7478 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b
AI
7479
7480 if (cap < 0)
7481 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
ee78dc32
GV
7482
7483 ReleaseDC (dpyinfo->root_window, hdc);
7484
7485 return make_number (cap);
7486}
7487
7488DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7489 Sx_server_max_request_size,
74e1aeec
JR
7490 0, 1, 0,
7491 doc: /* Returns the maximum request size of the server of DISPLAY.
7492The optional argument DISPLAY specifies which display to ask about.
7493DISPLAY should be either a frame or a display name (a string).
7494If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7495 (display)
7496 Lisp_Object display;
7497{
fbd6baed 7498 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7499
7500 return make_number (1);
7501}
7502
7503DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7504 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7505The optional argument DISPLAY specifies which display to ask about.
7506DISPLAY should be either a frame or a display name (a string).
7507If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7508 (display)
7509 Lisp_Object display;
7510{
dfff8a69 7511 return build_string ("Microsoft Corp.");
ee78dc32
GV
7512}
7513
7514DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7515 doc: /* Returns the version numbers of the server of DISPLAY.
7516The value is a list of three integers: the major and minor
7517version numbers, and the vendor-specific release
7518number. See also the function `x-server-vendor'.
7519
7520The optional argument DISPLAY specifies which display to ask about.
7521DISPLAY should be either a frame or a display name (a string).
7522If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7523 (display)
7524 Lisp_Object display;
7525{
fbd6baed 7526 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7527 Fcons (make_number (w32_minor_version),
7528 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7529}
7530
7531DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7532 doc: /* Returns the number of screens on the server of DISPLAY.
7533The optional argument DISPLAY specifies which display to ask about.
7534DISPLAY should be either a frame or a display name (a string).
7535If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7536 (display)
7537 Lisp_Object display;
7538{
ee78dc32
GV
7539 return make_number (1);
7540}
7541
74e1aeec
JR
7542DEFUN ("x-display-mm-height", Fx_display_mm_height,
7543 Sx_display_mm_height, 0, 1, 0,
7544 doc: /* Returns the height in millimeters of DISPLAY.
7545The optional argument DISPLAY specifies which display to ask about.
7546DISPLAY should be either a frame or a display name (a string).
7547If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7548 (display)
7549 Lisp_Object display;
7550{
fbd6baed 7551 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7552 HDC hdc;
7553 int cap;
7554
5ac45f98 7555 hdc = GetDC (dpyinfo->root_window);
3c190163 7556
ee78dc32 7557 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7558
ee78dc32
GV
7559 ReleaseDC (dpyinfo->root_window, hdc);
7560
7561 return make_number (cap);
7562}
7563
7564DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7565 doc: /* Returns the width in millimeters of DISPLAY.
7566The optional argument DISPLAY specifies which display to ask about.
7567DISPLAY should be either a frame or a display name (a string).
7568If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7569 (display)
7570 Lisp_Object display;
7571{
fbd6baed 7572 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7573
7574 HDC hdc;
7575 int cap;
7576
5ac45f98 7577 hdc = GetDC (dpyinfo->root_window);
3c190163 7578
ee78dc32 7579 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7580
ee78dc32
GV
7581 ReleaseDC (dpyinfo->root_window, hdc);
7582
7583 return make_number (cap);
7584}
7585
7586DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7587 Sx_display_backing_store, 0, 1, 0,
7588 doc: /* Returns an indication of whether DISPLAY does backing store.
7589The value may be `always', `when-mapped', or `not-useful'.
7590The optional argument DISPLAY specifies which display to ask about.
7591DISPLAY should be either a frame or a display name (a string).
7592If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7593 (display)
7594 Lisp_Object display;
7595{
7596 return intern ("not-useful");
7597}
7598
7599DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7600 Sx_display_visual_class, 0, 1, 0,
7601 doc: /* Returns the visual class of DISPLAY.
7602The value is one of the symbols `static-gray', `gray-scale',
7603`static-color', `pseudo-color', `true-color', or `direct-color'.
7604
7605The optional argument DISPLAY specifies which display to ask about.
7606DISPLAY should be either a frame or a display name (a string).
7607If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7608 (display)
7609 Lisp_Object display;
7610{
fbd6baed 7611 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7612 Lisp_Object result = Qnil;
ee78dc32 7613
abf8c61b
AI
7614 if (dpyinfo->has_palette)
7615 result = intern ("pseudo-color");
7616 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7617 result = intern ("static-grey");
7618 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7619 result = intern ("static-color");
7620 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7621 result = intern ("true-color");
ee78dc32 7622
abf8c61b 7623 return result;
ee78dc32
GV
7624}
7625
7626DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7627 Sx_display_save_under, 0, 1, 0,
7628 doc: /* Returns t if DISPLAY supports the save-under feature.
7629The optional argument DISPLAY specifies which display to ask about.
7630DISPLAY should be either a frame or a display name (a string).
7631If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7632 (display)
7633 Lisp_Object display;
7634{
6fc2811b
JR
7635 return Qnil;
7636}
7637\f
7638int
7639x_pixel_width (f)
7640 register struct frame *f;
7641{
7642 return PIXEL_WIDTH (f);
7643}
7644
7645int
7646x_pixel_height (f)
7647 register struct frame *f;
7648{
7649 return PIXEL_HEIGHT (f);
7650}
7651
7652int
7653x_char_width (f)
7654 register struct frame *f;
7655{
7656 return FONT_WIDTH (f->output_data.w32->font);
7657}
7658
7659int
7660x_char_height (f)
7661 register struct frame *f;
7662{
7663 return f->output_data.w32->line_height;
7664}
7665
7666int
7667x_screen_planes (f)
7668 register struct frame *f;
7669{
7670 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7671}
7672\f
7673/* Return the display structure for the display named NAME.
7674 Open a new connection if necessary. */
7675
7676struct w32_display_info *
7677x_display_info_for_name (name)
7678 Lisp_Object name;
7679{
7680 Lisp_Object names;
7681 struct w32_display_info *dpyinfo;
7682
b7826503 7683 CHECK_STRING (name);
6fc2811b
JR
7684
7685 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7686 dpyinfo;
7687 dpyinfo = dpyinfo->next, names = XCDR (names))
7688 {
7689 Lisp_Object tem;
7690 tem = Fstring_equal (XCAR (XCAR (names)), name);
7691 if (!NILP (tem))
7692 return dpyinfo;
7693 }
7694
7695 /* Use this general default value to start with. */
7696 Vx_resource_name = Vinvocation_name;
7697
7698 validate_x_resource_name ();
7699
7700 dpyinfo = w32_term_init (name, (unsigned char *)0,
7701 (char *) XSTRING (Vx_resource_name)->data);
7702
7703 if (dpyinfo == 0)
7704 error ("Cannot connect to server %s", XSTRING (name)->data);
7705
7706 w32_in_use = 1;
7707 XSETFASTINT (Vwindow_system_version, 3);
7708
7709 return dpyinfo;
7710}
7711
7712DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
7713 1, 3, 0, doc: /* Open a connection to a server.
7714DISPLAY is the name of the display to connect to.
7715Optional second arg XRM-STRING is a string of resources in xrdb format.
7716If the optional third arg MUST-SUCCEED is non-nil,
7717terminate Emacs if we can't open the connection. */)
6fc2811b
JR
7718 (display, xrm_string, must_succeed)
7719 Lisp_Object display, xrm_string, must_succeed;
7720{
7721 unsigned char *xrm_option;
7722 struct w32_display_info *dpyinfo;
7723
74e1aeec
JR
7724 /* If initialization has already been done, return now to avoid
7725 overwriting critical parts of one_w32_display_info. */
7726 if (w32_in_use)
7727 return Qnil;
7728
b7826503 7729 CHECK_STRING (display);
6fc2811b 7730 if (! NILP (xrm_string))
b7826503 7731 CHECK_STRING (xrm_string);
6fc2811b
JR
7732
7733 if (! EQ (Vwindow_system, intern ("w32")))
7734 error ("Not using Microsoft Windows");
7735
7736 /* Allow color mapping to be defined externally; first look in user's
7737 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7738 {
7739 Lisp_Object color_file;
7740 struct gcpro gcpro1;
7741
7742 color_file = build_string("~/rgb.txt");
7743
7744 GCPRO1 (color_file);
7745
7746 if (NILP (Ffile_readable_p (color_file)))
7747 color_file =
7748 Fexpand_file_name (build_string ("rgb.txt"),
7749 Fsymbol_value (intern ("data-directory")));
7750
7751 Vw32_color_map = Fw32_load_color_file (color_file);
7752
7753 UNGCPRO;
7754 }
7755 if (NILP (Vw32_color_map))
7756 Vw32_color_map = Fw32_default_color_map ();
7757
7758 if (! NILP (xrm_string))
7759 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7760 else
7761 xrm_option = (unsigned char *) 0;
7762
7763 /* Use this general default value to start with. */
7764 /* First remove .exe suffix from invocation-name - it looks ugly. */
7765 {
7766 char basename[ MAX_PATH ], *str;
7767
7768 strcpy (basename, XSTRING (Vinvocation_name)->data);
7769 str = strrchr (basename, '.');
7770 if (str) *str = 0;
7771 Vinvocation_name = build_string (basename);
7772 }
7773 Vx_resource_name = Vinvocation_name;
7774
7775 validate_x_resource_name ();
7776
7777 /* This is what opens the connection and sets x_current_display.
7778 This also initializes many symbols, such as those used for input. */
7779 dpyinfo = w32_term_init (display, xrm_option,
7780 (char *) XSTRING (Vx_resource_name)->data);
7781
7782 if (dpyinfo == 0)
7783 {
7784 if (!NILP (must_succeed))
7785 fatal ("Cannot connect to server %s.\n",
7786 XSTRING (display)->data);
7787 else
7788 error ("Cannot connect to server %s", XSTRING (display)->data);
7789 }
7790
7791 w32_in_use = 1;
7792
7793 XSETFASTINT (Vwindow_system_version, 3);
7794 return Qnil;
7795}
7796
7797DEFUN ("x-close-connection", Fx_close_connection,
7798 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
7799 doc: /* Close the connection to DISPLAY's server.
7800For DISPLAY, specify either a frame or a display name (a string).
7801If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
7802 (display)
7803 Lisp_Object display;
7804{
7805 struct w32_display_info *dpyinfo = check_x_display_info (display);
7806 int i;
7807
7808 if (dpyinfo->reference_count > 0)
7809 error ("Display still has frames on it");
7810
7811 BLOCK_INPUT;
7812 /* Free the fonts in the font table. */
7813 for (i = 0; i < dpyinfo->n_fonts; i++)
7814 if (dpyinfo->font_table[i].name)
7815 {
126f2e35
JR
7816 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7817 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 7818 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
7819 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7820 }
7821 x_destroy_all_bitmaps (dpyinfo);
7822
7823 x_delete_display (dpyinfo);
7824 UNBLOCK_INPUT;
7825
7826 return Qnil;
7827}
7828
7829DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 7830 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
7831 ()
7832{
7833 Lisp_Object tail, result;
7834
7835 result = Qnil;
7836 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7837 result = Fcons (XCAR (XCAR (tail)), result);
7838
7839 return result;
7840}
7841
7842DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
7843 doc: /* This is a noop on W32 systems. */)
7844 (on, display)
7845 Lisp_Object display, on;
6fc2811b 7846{
6fc2811b
JR
7847 return Qnil;
7848}
7849
7850\f
7851\f
7852/***********************************************************************
7853 Image types
7854 ***********************************************************************/
7855
7856/* Value is the number of elements of vector VECTOR. */
7857
7858#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7859
7860/* List of supported image types. Use define_image_type to add new
7861 types. Use lookup_image_type to find a type for a given symbol. */
7862
7863static struct image_type *image_types;
7864
6fc2811b
JR
7865/* The symbol `image' which is the car of the lists used to represent
7866 images in Lisp. */
7867
7868extern Lisp_Object Qimage;
7869
7870/* The symbol `xbm' which is used as the type symbol for XBM images. */
7871
7872Lisp_Object Qxbm;
7873
7874/* Keywords. */
7875
6fc2811b 7876extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
7877extern Lisp_Object QCdata;
7878Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
a93f4566 7879Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 7880Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
7881
7882/* Other symbols. */
7883
3cf3436e 7884Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
7885
7886/* Time in seconds after which images should be removed from the cache
7887 if not displayed. */
7888
7889Lisp_Object Vimage_cache_eviction_delay;
7890
7891/* Function prototypes. */
7892
7893static void define_image_type P_ ((struct image_type *type));
7894static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7895static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7896static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 7897static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
7898static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7899 Lisp_Object));
7900
dfff8a69 7901
6fc2811b
JR
7902/* Define a new image type from TYPE. This adds a copy of TYPE to
7903 image_types and adds the symbol *TYPE->type to Vimage_types. */
7904
7905static void
7906define_image_type (type)
7907 struct image_type *type;
7908{
7909 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7910 The initialized data segment is read-only. */
7911 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7912 bcopy (type, p, sizeof *p);
7913 p->next = image_types;
7914 image_types = p;
7915 Vimage_types = Fcons (*p->type, Vimage_types);
7916}
7917
7918
7919/* Look up image type SYMBOL, and return a pointer to its image_type
7920 structure. Value is null if SYMBOL is not a known image type. */
7921
7922static INLINE struct image_type *
7923lookup_image_type (symbol)
7924 Lisp_Object symbol;
7925{
7926 struct image_type *type;
7927
7928 for (type = image_types; type; type = type->next)
7929 if (EQ (symbol, *type->type))
7930 break;
7931
7932 return type;
7933}
7934
7935
7936/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7937 valid image specification is a list whose car is the symbol
7938 `image', and whose rest is a property list. The property list must
7939 contain a value for key `:type'. That value must be the name of a
7940 supported image type. The rest of the property list depends on the
7941 image type. */
7942
7943int
7944valid_image_p (object)
7945 Lisp_Object object;
7946{
7947 int valid_p = 0;
7948
7949 if (CONSP (object) && EQ (XCAR (object), Qimage))
7950 {
3cf3436e
JR
7951 Lisp_Object tem;
7952
7953 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
7954 if (EQ (XCAR (tem), QCtype))
7955 {
7956 tem = XCDR (tem);
7957 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
7958 {
7959 struct image_type *type;
7960 type = lookup_image_type (XCAR (tem));
7961 if (type)
7962 valid_p = type->valid_p (object);
7963 }
7964
7965 break;
7966 }
6fc2811b
JR
7967 }
7968
7969 return valid_p;
7970}
7971
7972
7973/* Log error message with format string FORMAT and argument ARG.
7974 Signaling an error, e.g. when an image cannot be loaded, is not a
7975 good idea because this would interrupt redisplay, and the error
7976 message display would lead to another redisplay. This function
7977 therefore simply displays a message. */
7978
7979static void
7980image_error (format, arg1, arg2)
7981 char *format;
7982 Lisp_Object arg1, arg2;
7983{
7984 add_to_log (format, arg1, arg2);
7985}
7986
7987
7988\f
7989/***********************************************************************
7990 Image specifications
7991 ***********************************************************************/
7992
7993enum image_value_type
7994{
7995 IMAGE_DONT_CHECK_VALUE_TYPE,
7996 IMAGE_STRING_VALUE,
3cf3436e 7997 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
7998 IMAGE_SYMBOL_VALUE,
7999 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8000 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8001 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8002 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8003 IMAGE_INTEGER_VALUE,
8004 IMAGE_FUNCTION_VALUE,
8005 IMAGE_NUMBER_VALUE,
8006 IMAGE_BOOL_VALUE
8007};
8008
8009/* Structure used when parsing image specifications. */
8010
8011struct image_keyword
8012{
8013 /* Name of keyword. */
8014 char *name;
8015
8016 /* The type of value allowed. */
8017 enum image_value_type type;
8018
8019 /* Non-zero means key must be present. */
8020 int mandatory_p;
8021
8022 /* Used to recognize duplicate keywords in a property list. */
8023 int count;
8024
8025 /* The value that was found. */
8026 Lisp_Object value;
8027};
8028
8029
8030static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8031 int, Lisp_Object));
8032static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8033
8034
8035/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8036 has the format (image KEYWORD VALUE ...). One of the keyword/
8037 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8038 image_keywords structures of size NKEYWORDS describing other
8039 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8040
8041static int
8042parse_image_spec (spec, keywords, nkeywords, type)
8043 Lisp_Object spec;
8044 struct image_keyword *keywords;
8045 int nkeywords;
8046 Lisp_Object type;
8047{
8048 int i;
8049 Lisp_Object plist;
8050
8051 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8052 return 0;
8053
8054 plist = XCDR (spec);
8055 while (CONSP (plist))
8056 {
8057 Lisp_Object key, value;
8058
8059 /* First element of a pair must be a symbol. */
8060 key = XCAR (plist);
8061 plist = XCDR (plist);
8062 if (!SYMBOLP (key))
8063 return 0;
8064
8065 /* There must follow a value. */
8066 if (!CONSP (plist))
8067 return 0;
8068 value = XCAR (plist);
8069 plist = XCDR (plist);
8070
8071 /* Find key in KEYWORDS. Error if not found. */
8072 for (i = 0; i < nkeywords; ++i)
8073 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8074 break;
8075
8076 if (i == nkeywords)
8077 continue;
8078
8079 /* Record that we recognized the keyword. If a keywords
8080 was found more than once, it's an error. */
8081 keywords[i].value = value;
8082 ++keywords[i].count;
8083
8084 if (keywords[i].count > 1)
8085 return 0;
8086
8087 /* Check type of value against allowed type. */
8088 switch (keywords[i].type)
8089 {
8090 case IMAGE_STRING_VALUE:
8091 if (!STRINGP (value))
8092 return 0;
8093 break;
8094
3cf3436e
JR
8095 case IMAGE_STRING_OR_NIL_VALUE:
8096 if (!STRINGP (value) && !NILP (value))
8097 return 0;
8098 break;
8099
6fc2811b
JR
8100 case IMAGE_SYMBOL_VALUE:
8101 if (!SYMBOLP (value))
8102 return 0;
8103 break;
8104
8105 case IMAGE_POSITIVE_INTEGER_VALUE:
8106 if (!INTEGERP (value) || XINT (value) <= 0)
8107 return 0;
8108 break;
8109
8edb0a6f
JR
8110 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8111 if (INTEGERP (value) && XINT (value) >= 0)
8112 break;
8113 if (CONSP (value)
8114 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8115 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8116 break;
8117 return 0;
8118
dfff8a69
JR
8119 case IMAGE_ASCENT_VALUE:
8120 if (SYMBOLP (value) && EQ (value, Qcenter))
8121 break;
8122 else if (INTEGERP (value)
8123 && XINT (value) >= 0
8124 && XINT (value) <= 100)
8125 break;
8126 return 0;
8127
6fc2811b
JR
8128 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8129 if (!INTEGERP (value) || XINT (value) < 0)
8130 return 0;
8131 break;
8132
8133 case IMAGE_DONT_CHECK_VALUE_TYPE:
8134 break;
8135
8136 case IMAGE_FUNCTION_VALUE:
8137 value = indirect_function (value);
8138 if (SUBRP (value)
8139 || COMPILEDP (value)
8140 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8141 break;
8142 return 0;
8143
8144 case IMAGE_NUMBER_VALUE:
8145 if (!INTEGERP (value) && !FLOATP (value))
8146 return 0;
8147 break;
8148
8149 case IMAGE_INTEGER_VALUE:
8150 if (!INTEGERP (value))
8151 return 0;
8152 break;
8153
8154 case IMAGE_BOOL_VALUE:
8155 if (!NILP (value) && !EQ (value, Qt))
8156 return 0;
8157 break;
8158
8159 default:
8160 abort ();
8161 break;
8162 }
8163
8164 if (EQ (key, QCtype) && !EQ (type, value))
8165 return 0;
8166 }
8167
8168 /* Check that all mandatory fields are present. */
8169 for (i = 0; i < nkeywords; ++i)
8170 if (keywords[i].mandatory_p && keywords[i].count == 0)
8171 return 0;
8172
8173 return NILP (plist);
8174}
8175
8176
8177/* Return the value of KEY in image specification SPEC. Value is nil
8178 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8179 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8180
8181static Lisp_Object
8182image_spec_value (spec, key, found)
8183 Lisp_Object spec, key;
8184 int *found;
8185{
8186 Lisp_Object tail;
8187
8188 xassert (valid_image_p (spec));
8189
8190 for (tail = XCDR (spec);
8191 CONSP (tail) && CONSP (XCDR (tail));
8192 tail = XCDR (XCDR (tail)))
8193 {
8194 if (EQ (XCAR (tail), key))
8195 {
8196 if (found)
8197 *found = 1;
8198 return XCAR (XCDR (tail));
8199 }
8200 }
8201
8202 if (found)
8203 *found = 0;
8204 return Qnil;
8205}
8206
8207
8208
8209\f
8210/***********************************************************************
8211 Image type independent image structures
8212 ***********************************************************************/
8213
8214static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8215static void free_image P_ ((struct frame *f, struct image *img));
8216
8217
8218/* Allocate and return a new image structure for image specification
8219 SPEC. SPEC has a hash value of HASH. */
8220
8221static struct image *
8222make_image (spec, hash)
8223 Lisp_Object spec;
8224 unsigned hash;
8225{
8226 struct image *img = (struct image *) xmalloc (sizeof *img);
8227
8228 xassert (valid_image_p (spec));
8229 bzero (img, sizeof *img);
8230 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8231 xassert (img->type != NULL);
8232 img->spec = spec;
8233 img->data.lisp_val = Qnil;
8234 img->ascent = DEFAULT_IMAGE_ASCENT;
8235 img->hash = hash;
8236 return img;
8237}
8238
8239
8240/* Free image IMG which was used on frame F, including its resources. */
8241
8242static void
8243free_image (f, img)
8244 struct frame *f;
8245 struct image *img;
8246{
8247 if (img)
8248 {
8249 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8250
8251 /* Remove IMG from the hash table of its cache. */
8252 if (img->prev)
8253 img->prev->next = img->next;
8254 else
8255 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8256
8257 if (img->next)
8258 img->next->prev = img->prev;
8259
8260 c->images[img->id] = NULL;
8261
8262 /* Free resources, then free IMG. */
8263 img->type->free (f, img);
8264 xfree (img);
8265 }
8266}
8267
8268
8269/* Prepare image IMG for display on frame F. Must be called before
8270 drawing an image. */
8271
8272void
8273prepare_image_for_display (f, img)
8274 struct frame *f;
8275 struct image *img;
8276{
8277 EMACS_TIME t;
8278
8279 /* We're about to display IMG, so set its timestamp to `now'. */
8280 EMACS_GET_TIME (t);
8281 img->timestamp = EMACS_SECS (t);
8282
8283 /* If IMG doesn't have a pixmap yet, load it now, using the image
8284 type dependent loader function. */
8285 if (img->pixmap == 0 && !img->load_failed_p)
8286 img->load_failed_p = img->type->load (f, img) == 0;
8287}
8288
8289
dfff8a69
JR
8290/* Value is the number of pixels for the ascent of image IMG when
8291 drawn in face FACE. */
8292
8293int
8294image_ascent (img, face)
8295 struct image *img;
8296 struct face *face;
8297{
8edb0a6f 8298 int height = img->height + img->vmargin;
dfff8a69
JR
8299 int ascent;
8300
8301 if (img->ascent == CENTERED_IMAGE_ASCENT)
8302 {
8303 if (face->font)
8304 ascent = height / 2 - (FONT_DESCENT(face->font)
8305 - FONT_BASE(face->font)) / 2;
8306 else
8307 ascent = height / 2;
8308 }
8309 else
8310 ascent = height * img->ascent / 100.0;
8311
8312 return ascent;
8313}
8314
8315
6fc2811b 8316\f
a05e2bae
JR
8317/* Image background colors. */
8318
8319static unsigned long
8320four_corners_best (ximg, width, height)
8321 XImage *ximg;
8322 unsigned long width, height;
8323{
8324#if 0 /* TODO: Image support. */
8325 unsigned long corners[4], best;
8326 int i, best_count;
8327
8328 /* Get the colors at the corners of ximg. */
8329 corners[0] = XGetPixel (ximg, 0, 0);
8330 corners[1] = XGetPixel (ximg, width - 1, 0);
8331 corners[2] = XGetPixel (ximg, width - 1, height - 1);
8332 corners[3] = XGetPixel (ximg, 0, height - 1);
8333
8334 /* Choose the most frequently found color as background. */
8335 for (i = best_count = 0; i < 4; ++i)
8336 {
8337 int j, n;
8338
8339 for (j = n = 0; j < 4; ++j)
8340 if (corners[i] == corners[j])
8341 ++n;
8342
8343 if (n > best_count)
8344 best = corners[i], best_count = n;
8345 }
8346
8347 return best;
8348#else
8349 return 0;
8350#endif
8351}
8352
8353/* Return the `background' field of IMG. If IMG doesn't have one yet,
8354 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8355 object to use for the heuristic. */
8356
8357unsigned long
8358image_background (img, f, ximg)
8359 struct image *img;
8360 struct frame *f;
8361 XImage *ximg;
8362{
8363 if (! img->background_valid)
8364 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8365 {
8366#if 0 /* TODO: Image support. */
8367 int free_ximg = !ximg;
8368
8369 if (! ximg)
8370 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8371 0, 0, img->width, img->height, ~0, ZPixmap);
8372
8373 img->background = four_corners_best (ximg, img->width, img->height);
8374
8375 if (free_ximg)
8376 XDestroyImage (ximg);
8377
8378 img->background_valid = 1;
8379#endif
8380 }
8381
8382 return img->background;
8383}
8384
8385/* Return the `background_transparent' field of IMG. If IMG doesn't
8386 have one yet, it is guessed heuristically. If non-zero, MASK is an
8387 existing XImage object to use for the heuristic. */
8388
8389int
8390image_background_transparent (img, f, mask)
8391 struct image *img;
8392 struct frame *f;
8393 XImage *mask;
8394{
8395 if (! img->background_transparent_valid)
8396 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8397 {
8398#if 0 /* TODO: Image support. */
8399 if (img->mask)
8400 {
8401 int free_mask = !mask;
8402
8403 if (! mask)
8404 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8405 0, 0, img->width, img->height, ~0, ZPixmap);
8406
8407 img->background_transparent
8408 = !four_corners_best (mask, img->width, img->height);
8409
8410 if (free_mask)
8411 XDestroyImage (mask);
8412 }
8413 else
8414#endif
8415 img->background_transparent = 0;
8416
8417 img->background_transparent_valid = 1;
8418 }
8419
8420 return img->background_transparent;
8421}
8422
8423\f
6fc2811b
JR
8424/***********************************************************************
8425 Helper functions for X image types
8426 ***********************************************************************/
8427
a05e2bae
JR
8428static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8429 int, int));
6fc2811b
JR
8430static void x_clear_image P_ ((struct frame *f, struct image *img));
8431static unsigned long x_alloc_image_color P_ ((struct frame *f,
8432 struct image *img,
8433 Lisp_Object color_name,
8434 unsigned long dflt));
8435
a05e2bae
JR
8436
8437/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8438 free the pixmap if any. MASK_P non-zero means clear the mask
8439 pixmap if any. COLORS_P non-zero means free colors allocated for
8440 the image, if any. */
8441
8442static void
8443x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8444 struct frame *f;
8445 struct image *img;
8446 int pixmap_p, mask_p, colors_p;
8447{
9eb16b62 8448#if 0 /* TODO: W32 image support */
a05e2bae
JR
8449 if (pixmap_p && img->pixmap)
8450 {
8451 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8452 img->pixmap = None;
8453 img->background_valid = 0;
8454 }
8455
8456 if (mask_p && img->mask)
8457 {
8458 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8459 img->mask = None;
8460 img->background_transparent_valid = 0;
8461 }
8462
8463 if (colors_p && img->ncolors)
8464 {
8465 x_free_colors (f, img->colors, img->ncolors);
8466 xfree (img->colors);
8467 img->colors = NULL;
8468 img->ncolors = 0;
8469 }
8470#endif
8471}
8472
6fc2811b
JR
8473/* Free X resources of image IMG which is used on frame F. */
8474
8475static void
8476x_clear_image (f, img)
8477 struct frame *f;
8478 struct image *img;
8479{
767b1ff0 8480#if 0 /* TODO: W32 image support */
6fc2811b
JR
8481
8482 if (img->pixmap)
8483 {
8484 BLOCK_INPUT;
8485 XFreePixmap (NULL, img->pixmap);
8486 img->pixmap = 0;
8487 UNBLOCK_INPUT;
8488 }
8489
8490 if (img->ncolors)
8491 {
8492 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8493
8494 /* If display has an immutable color map, freeing colors is not
8495 necessary and some servers don't allow it. So don't do it. */
8496 if (class != StaticColor
8497 && class != StaticGray
8498 && class != TrueColor)
8499 {
8500 Colormap cmap;
8501 BLOCK_INPUT;
8502 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8503 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8504 img->ncolors, 0);
8505 UNBLOCK_INPUT;
8506 }
8507
8508 xfree (img->colors);
8509 img->colors = NULL;
8510 img->ncolors = 0;
8511 }
8512#endif
8513}
8514
8515
8516/* Allocate color COLOR_NAME for image IMG on frame F. If color
8517 cannot be allocated, use DFLT. Add a newly allocated color to
8518 IMG->colors, so that it can be freed again. Value is the pixel
8519 color. */
8520
8521static unsigned long
8522x_alloc_image_color (f, img, color_name, dflt)
8523 struct frame *f;
8524 struct image *img;
8525 Lisp_Object color_name;
8526 unsigned long dflt;
8527{
767b1ff0 8528#if 0 /* TODO: allocing colors. */
6fc2811b
JR
8529 XColor color;
8530 unsigned long result;
8531
8532 xassert (STRINGP (color_name));
8533
8534 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8535 {
8536 /* This isn't called frequently so we get away with simply
8537 reallocating the color vector to the needed size, here. */
8538 ++img->ncolors;
8539 img->colors =
8540 (unsigned long *) xrealloc (img->colors,
8541 img->ncolors * sizeof *img->colors);
8542 img->colors[img->ncolors - 1] = color.pixel;
8543 result = color.pixel;
8544 }
8545 else
8546 result = dflt;
8547 return result;
8548#endif
8549 return 0;
8550}
8551
8552
8553\f
8554/***********************************************************************
8555 Image Cache
8556 ***********************************************************************/
8557
8558static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8559static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8560
8561
8562/* Return a new, initialized image cache that is allocated from the
8563 heap. Call free_image_cache to free an image cache. */
8564
8565struct image_cache *
8566make_image_cache ()
8567{
8568 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8569 int size;
8570
8571 bzero (c, sizeof *c);
8572 c->size = 50;
8573 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8574 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8575 c->buckets = (struct image **) xmalloc (size);
8576 bzero (c->buckets, size);
8577 return c;
8578}
8579
8580
8581/* Free image cache of frame F. Be aware that X frames share images
8582 caches. */
8583
8584void
8585free_image_cache (f)
8586 struct frame *f;
8587{
8588 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8589 if (c)
8590 {
8591 int i;
8592
8593 /* Cache should not be referenced by any frame when freed. */
8594 xassert (c->refcount == 0);
8595
8596 for (i = 0; i < c->used; ++i)
8597 free_image (f, c->images[i]);
8598 xfree (c->images);
8599 xfree (c);
8600 xfree (c->buckets);
8601 FRAME_X_IMAGE_CACHE (f) = NULL;
8602 }
8603}
8604
8605
8606/* Clear image cache of frame F. FORCE_P non-zero means free all
8607 images. FORCE_P zero means clear only images that haven't been
8608 displayed for some time. Should be called from time to time to
dfff8a69
JR
8609 reduce the number of loaded images. If image-eviction-seconds is
8610 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8611 at least that many seconds. */
8612
8613void
8614clear_image_cache (f, force_p)
8615 struct frame *f;
8616 int force_p;
8617{
8618 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8619
8620 if (c && INTEGERP (Vimage_cache_eviction_delay))
8621 {
8622 EMACS_TIME t;
8623 unsigned long old;
8624 int i, any_freed_p = 0;
8625
8626 EMACS_GET_TIME (t);
8627 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8628
8629 for (i = 0; i < c->used; ++i)
8630 {
8631 struct image *img = c->images[i];
8632 if (img != NULL
8633 && (force_p
8634 || (img->timestamp > old)))
8635 {
8636 free_image (f, img);
8637 any_freed_p = 1;
8638 }
8639 }
8640
8641 /* We may be clearing the image cache because, for example,
8642 Emacs was iconified for a longer period of time. In that
8643 case, current matrices may still contain references to
8644 images freed above. So, clear these matrices. */
8645 if (any_freed_p)
8646 {
8647 clear_current_matrices (f);
8648 ++windows_or_buffers_changed;
8649 }
8650 }
8651}
8652
8653
8654DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8655 0, 1, 0,
74e1aeec
JR
8656 doc: /* Clear the image cache of FRAME.
8657FRAME nil or omitted means use the selected frame.
8658FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
8659 (frame)
8660 Lisp_Object frame;
8661{
8662 if (EQ (frame, Qt))
8663 {
8664 Lisp_Object tail;
8665
8666 FOR_EACH_FRAME (tail, frame)
8667 if (FRAME_W32_P (XFRAME (frame)))
8668 clear_image_cache (XFRAME (frame), 1);
8669 }
8670 else
8671 clear_image_cache (check_x_frame (frame), 1);
8672
8673 return Qnil;
8674}
8675
8676
3cf3436e
JR
8677/* Compute masks and transform image IMG on frame F, as specified
8678 by the image's specification, */
8679
8680static void
8681postprocess_image (f, img)
8682 struct frame *f;
8683 struct image *img;
8684{
8685#if 0 /* TODO: image support. */
8686 /* Manipulation of the image's mask. */
8687 if (img->pixmap)
8688 {
8689 Lisp_Object conversion, spec;
8690 Lisp_Object mask;
8691
8692 spec = img->spec;
8693
8694 /* `:heuristic-mask t'
8695 `:mask heuristic'
8696 means build a mask heuristically.
8697 `:heuristic-mask (R G B)'
8698 `:mask (heuristic (R G B))'
8699 means build a mask from color (R G B) in the
8700 image.
8701 `:mask nil'
8702 means remove a mask, if any. */
8703
8704 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8705 if (!NILP (mask))
8706 x_build_heuristic_mask (f, img, mask);
8707 else
8708 {
8709 int found_p;
8710
8711 mask = image_spec_value (spec, QCmask, &found_p);
8712
8713 if (EQ (mask, Qheuristic))
8714 x_build_heuristic_mask (f, img, Qt);
8715 else if (CONSP (mask)
8716 && EQ (XCAR (mask), Qheuristic))
8717 {
8718 if (CONSP (XCDR (mask)))
8719 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8720 else
8721 x_build_heuristic_mask (f, img, XCDR (mask));
8722 }
8723 else if (NILP (mask) && found_p && img->mask)
8724 {
8725 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8726 img->mask = NULL;
8727 }
8728 }
8729
8730
8731 /* Should we apply an image transformation algorithm? */
8732 conversion = image_spec_value (spec, QCconversion, NULL);
8733 if (EQ (conversion, Qdisabled))
8734 x_disable_image (f, img);
8735 else if (EQ (conversion, Qlaplace))
8736 x_laplace (f, img);
8737 else if (EQ (conversion, Qemboss))
8738 x_emboss (f, img);
8739 else if (CONSP (conversion)
8740 && EQ (XCAR (conversion), Qedge_detection))
8741 {
8742 Lisp_Object tem;
8743 tem = XCDR (conversion);
8744 if (CONSP (tem))
8745 x_edge_detection (f, img,
8746 Fplist_get (tem, QCmatrix),
8747 Fplist_get (tem, QCcolor_adjustment));
8748 }
8749 }
8750#endif
8751}
8752
8753
6fc2811b
JR
8754/* Return the id of image with Lisp specification SPEC on frame F.
8755 SPEC must be a valid Lisp image specification (see valid_image_p). */
8756
8757int
8758lookup_image (f, spec)
8759 struct frame *f;
8760 Lisp_Object spec;
8761{
8762 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8763 struct image *img;
8764 int i;
8765 unsigned hash;
8766 struct gcpro gcpro1;
8767 EMACS_TIME now;
8768
8769 /* F must be a window-system frame, and SPEC must be a valid image
8770 specification. */
8771 xassert (FRAME_WINDOW_P (f));
8772 xassert (valid_image_p (spec));
8773
8774 GCPRO1 (spec);
8775
8776 /* Look up SPEC in the hash table of the image cache. */
8777 hash = sxhash (spec, 0);
8778 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8779
8780 for (img = c->buckets[i]; img; img = img->next)
8781 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8782 break;
8783
8784 /* If not found, create a new image and cache it. */
8785 if (img == NULL)
8786 {
3cf3436e
JR
8787 extern Lisp_Object Qpostscript;
8788
8edb0a6f 8789 BLOCK_INPUT;
6fc2811b
JR
8790 img = make_image (spec, hash);
8791 cache_image (f, img);
8792 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
8793
8794 /* If we can't load the image, and we don't have a width and
8795 height, use some arbitrary width and height so that we can
8796 draw a rectangle for it. */
8797 if (img->load_failed_p)
8798 {
8799 Lisp_Object value;
8800
8801 value = image_spec_value (spec, QCwidth, NULL);
8802 img->width = (INTEGERP (value)
8803 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8804 value = image_spec_value (spec, QCheight, NULL);
8805 img->height = (INTEGERP (value)
8806 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8807 }
8808 else
8809 {
8810 /* Handle image type independent image attributes
a05e2bae
JR
8811 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
8812 `:background COLOR'. */
8813 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
8814
8815 ascent = image_spec_value (spec, QCascent, NULL);
8816 if (INTEGERP (ascent))
8817 img->ascent = XFASTINT (ascent);
dfff8a69
JR
8818 else if (EQ (ascent, Qcenter))
8819 img->ascent = CENTERED_IMAGE_ASCENT;
8820
6fc2811b
JR
8821 margin = image_spec_value (spec, QCmargin, NULL);
8822 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
8823 img->vmargin = img->hmargin = XFASTINT (margin);
8824 else if (CONSP (margin) && INTEGERP (XCAR (margin))
8825 && INTEGERP (XCDR (margin)))
8826 {
8827 if (XINT (XCAR (margin)) > 0)
8828 img->hmargin = XFASTINT (XCAR (margin));
8829 if (XINT (XCDR (margin)) > 0)
8830 img->vmargin = XFASTINT (XCDR (margin));
8831 }
6fc2811b
JR
8832
8833 relief = image_spec_value (spec, QCrelief, NULL);
8834 if (INTEGERP (relief))
8835 {
8836 img->relief = XINT (relief);
8edb0a6f
JR
8837 img->hmargin += abs (img->relief);
8838 img->vmargin += abs (img->relief);
6fc2811b
JR
8839 }
8840
a05e2bae
JR
8841 if (! img->background_valid)
8842 {
8843 bg = image_spec_value (img->spec, QCbackground, NULL);
8844 if (!NILP (bg))
8845 {
8846 img->background
8847 = x_alloc_image_color (f, img, bg,
8848 FRAME_BACKGROUND_PIXEL (f));
8849 img->background_valid = 1;
8850 }
8851 }
8852
3cf3436e
JR
8853 /* Do image transformations and compute masks, unless we
8854 don't have the image yet. */
8855 if (!EQ (*img->type->type, Qpostscript))
8856 postprocess_image (f, img);
6fc2811b 8857 }
3cf3436e 8858
8edb0a6f
JR
8859 UNBLOCK_INPUT;
8860 xassert (!interrupt_input_blocked);
6fc2811b
JR
8861 }
8862
8863 /* We're using IMG, so set its timestamp to `now'. */
8864 EMACS_GET_TIME (now);
8865 img->timestamp = EMACS_SECS (now);
8866
8867 UNGCPRO;
8868
8869 /* Value is the image id. */
8870 return img->id;
8871}
8872
8873
8874/* Cache image IMG in the image cache of frame F. */
8875
8876static void
8877cache_image (f, img)
8878 struct frame *f;
8879 struct image *img;
8880{
8881 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8882 int i;
8883
8884 /* Find a free slot in c->images. */
8885 for (i = 0; i < c->used; ++i)
8886 if (c->images[i] == NULL)
8887 break;
8888
8889 /* If no free slot found, maybe enlarge c->images. */
8890 if (i == c->used && c->used == c->size)
8891 {
8892 c->size *= 2;
8893 c->images = (struct image **) xrealloc (c->images,
8894 c->size * sizeof *c->images);
8895 }
8896
8897 /* Add IMG to c->images, and assign IMG an id. */
8898 c->images[i] = img;
8899 img->id = i;
8900 if (i == c->used)
8901 ++c->used;
8902
8903 /* Add IMG to the cache's hash table. */
8904 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8905 img->next = c->buckets[i];
8906 if (img->next)
8907 img->next->prev = img;
8908 img->prev = NULL;
8909 c->buckets[i] = img;
8910}
8911
8912
8913/* Call FN on every image in the image cache of frame F. Used to mark
8914 Lisp Objects in the image cache. */
8915
8916void
8917forall_images_in_image_cache (f, fn)
8918 struct frame *f;
8919 void (*fn) P_ ((struct image *img));
8920{
8921 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8922 {
8923 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8924 if (c)
8925 {
8926 int i;
8927 for (i = 0; i < c->used; ++i)
8928 if (c->images[i])
8929 fn (c->images[i]);
8930 }
8931 }
8932}
8933
8934
8935\f
8936/***********************************************************************
8937 W32 support code
8938 ***********************************************************************/
8939
767b1ff0 8940#if 0 /* TODO: W32 specific image code. */
6fc2811b
JR
8941
8942static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8943 XImage **, Pixmap *));
8944static void x_destroy_x_image P_ ((XImage *));
8945static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8946
8947
8948/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8949 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8950 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8951 via xmalloc. Print error messages via image_error if an error
8952 occurs. Value is non-zero if successful. */
8953
8954static int
8955x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8956 struct frame *f;
8957 int width, height, depth;
8958 XImage **ximg;
8959 Pixmap *pixmap;
8960{
767b1ff0 8961#if 0 /* TODO: Image support for W32 */
6fc2811b
JR
8962 Display *display = FRAME_W32_DISPLAY (f);
8963 Screen *screen = FRAME_X_SCREEN (f);
8964 Window window = FRAME_W32_WINDOW (f);
8965
8966 xassert (interrupt_input_blocked);
8967
8968 if (depth <= 0)
a05e2bae 8969 depth = one_w32_display_info.n_cbits;
6fc2811b
JR
8970 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8971 depth, ZPixmap, 0, NULL, width, height,
8972 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8973 if (*ximg == NULL)
8974 {
8975 image_error ("Unable to allocate X image", Qnil, Qnil);
8976 return 0;
8977 }
8978
8979 /* Allocate image raster. */
8980 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8981
8982 /* Allocate a pixmap of the same size. */
8983 *pixmap = XCreatePixmap (display, window, width, height, depth);
8984 if (*pixmap == 0)
8985 {
8986 x_destroy_x_image (*ximg);
8987 *ximg = NULL;
8988 image_error ("Unable to create X pixmap", Qnil, Qnil);
8989 return 0;
8990 }
8991#endif
8992 return 1;
8993}
8994
8995
8996/* Destroy XImage XIMG. Free XIMG->data. */
8997
8998static void
8999x_destroy_x_image (ximg)
9000 XImage *ximg;
9001{
9002 xassert (interrupt_input_blocked);
9003 if (ximg)
9004 {
9005 xfree (ximg->data);
9006 ximg->data = NULL;
9007 XDestroyImage (ximg);
9008 }
9009}
9010
9011
9012/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9013 are width and height of both the image and pixmap. */
9014
9015static void
9016x_put_x_image (f, ximg, pixmap, width, height)
9017 struct frame *f;
9018 XImage *ximg;
9019 Pixmap pixmap;
9020{
9021 GC gc;
9022
9023 xassert (interrupt_input_blocked);
9024 gc = XCreateGC (NULL, pixmap, 0, NULL);
9025 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9026 XFreeGC (NULL, gc);
9027}
9028
9029#endif
9030
9031\f
9032/***********************************************************************
3cf3436e 9033 File Handling
6fc2811b
JR
9034 ***********************************************************************/
9035
9036static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9037static char *slurp_file P_ ((char *, int *));
9038
6fc2811b
JR
9039
9040/* Find image file FILE. Look in data-directory, then
9041 x-bitmap-file-path. Value is the full name of the file found, or
9042 nil if not found. */
9043
9044static Lisp_Object
9045x_find_image_file (file)
9046 Lisp_Object file;
9047{
9048 Lisp_Object file_found, search_path;
9049 struct gcpro gcpro1, gcpro2;
9050 int fd;
9051
9052 file_found = Qnil;
9053 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9054 GCPRO2 (file_found, search_path);
9055
9056 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
c0ec53ad 9057 fd = openp (search_path, file, Qnil, &file_found, 0);
6fc2811b 9058
939d6465 9059 if (fd == -1)
6fc2811b
JR
9060 file_found = Qnil;
9061 else
9062 close (fd);
9063
9064 UNGCPRO;
9065 return file_found;
9066}
9067
9068
3cf3436e
JR
9069/* Read FILE into memory. Value is a pointer to a buffer allocated
9070 with xmalloc holding FILE's contents. Value is null if an error
9071 occurred. *SIZE is set to the size of the file. */
9072
9073static char *
9074slurp_file (file, size)
9075 char *file;
9076 int *size;
9077{
9078 FILE *fp = NULL;
9079 char *buf = NULL;
9080 struct stat st;
9081
9082 if (stat (file, &st) == 0
9083 && (fp = fopen (file, "r")) != NULL
9084 && (buf = (char *) xmalloc (st.st_size),
9085 fread (buf, 1, st.st_size, fp) == st.st_size))
9086 {
9087 *size = st.st_size;
9088 fclose (fp);
9089 }
9090 else
9091 {
9092 if (fp)
9093 fclose (fp);
9094 if (buf)
9095 {
9096 xfree (buf);
9097 buf = NULL;
9098 }
9099 }
9100
9101 return buf;
9102}
9103
9104
6fc2811b
JR
9105\f
9106/***********************************************************************
9107 XBM images
9108 ***********************************************************************/
9109
9110static int xbm_load P_ ((struct frame *f, struct image *img));
9111static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9112 Lisp_Object file));
9113static int xbm_image_p P_ ((Lisp_Object object));
9114static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9115 unsigned char **));
9116
9117
9118/* Indices of image specification fields in xbm_format, below. */
9119
9120enum xbm_keyword_index
9121{
9122 XBM_TYPE,
9123 XBM_FILE,
9124 XBM_WIDTH,
9125 XBM_HEIGHT,
9126 XBM_DATA,
9127 XBM_FOREGROUND,
9128 XBM_BACKGROUND,
9129 XBM_ASCENT,
9130 XBM_MARGIN,
9131 XBM_RELIEF,
9132 XBM_ALGORITHM,
9133 XBM_HEURISTIC_MASK,
a05e2bae 9134 XBM_MASK,
6fc2811b
JR
9135 XBM_LAST
9136};
9137
9138/* Vector of image_keyword structures describing the format
9139 of valid XBM image specifications. */
9140
9141static struct image_keyword xbm_format[XBM_LAST] =
9142{
9143 {":type", IMAGE_SYMBOL_VALUE, 1},
9144 {":file", IMAGE_STRING_VALUE, 0},
9145 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9146 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9147 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
9148 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9149 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
6fc2811b 9150 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9151 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9152 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9153 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
9154 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9155};
9156
9157/* Structure describing the image type XBM. */
9158
9159static struct image_type xbm_type =
9160{
9161 &Qxbm,
9162 xbm_image_p,
9163 xbm_load,
9164 x_clear_image,
9165 NULL
9166};
9167
9168/* Tokens returned from xbm_scan. */
9169
9170enum xbm_token
9171{
9172 XBM_TK_IDENT = 256,
9173 XBM_TK_NUMBER
9174};
9175
9176
9177/* Return non-zero if OBJECT is a valid XBM-type image specification.
9178 A valid specification is a list starting with the symbol `image'
9179 The rest of the list is a property list which must contain an
9180 entry `:type xbm..
9181
9182 If the specification specifies a file to load, it must contain
9183 an entry `:file FILENAME' where FILENAME is a string.
9184
9185 If the specification is for a bitmap loaded from memory it must
9186 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9187 WIDTH and HEIGHT are integers > 0. DATA may be:
9188
9189 1. a string large enough to hold the bitmap data, i.e. it must
9190 have a size >= (WIDTH + 7) / 8 * HEIGHT
9191
9192 2. a bool-vector of size >= WIDTH * HEIGHT
9193
9194 3. a vector of strings or bool-vectors, one for each line of the
9195 bitmap.
9196
9197 Both the file and data forms may contain the additional entries
9198 `:background COLOR' and `:foreground COLOR'. If not present,
9199 foreground and background of the frame on which the image is
9200 displayed, is used. */
9201
9202static int
9203xbm_image_p (object)
9204 Lisp_Object object;
9205{
9206 struct image_keyword kw[XBM_LAST];
9207
9208 bcopy (xbm_format, kw, sizeof kw);
9209 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9210 return 0;
9211
9212 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9213
9214 if (kw[XBM_FILE].count)
9215 {
9216 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9217 return 0;
9218 }
9219 else
9220 {
9221 Lisp_Object data;
9222 int width, height;
9223
9224 /* Entries for `:width', `:height' and `:data' must be present. */
9225 if (!kw[XBM_WIDTH].count
9226 || !kw[XBM_HEIGHT].count
9227 || !kw[XBM_DATA].count)
9228 return 0;
9229
9230 data = kw[XBM_DATA].value;
9231 width = XFASTINT (kw[XBM_WIDTH].value);
9232 height = XFASTINT (kw[XBM_HEIGHT].value);
9233
9234 /* Check type of data, and width and height against contents of
9235 data. */
9236 if (VECTORP (data))
9237 {
9238 int i;
9239
9240 /* Number of elements of the vector must be >= height. */
9241 if (XVECTOR (data)->size < height)
9242 return 0;
9243
9244 /* Each string or bool-vector in data must be large enough
9245 for one line of the image. */
9246 for (i = 0; i < height; ++i)
9247 {
9248 Lisp_Object elt = XVECTOR (data)->contents[i];
9249
9250 if (STRINGP (elt))
9251 {
9252 if (XSTRING (elt)->size
9253 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9254 return 0;
9255 }
9256 else if (BOOL_VECTOR_P (elt))
9257 {
9258 if (XBOOL_VECTOR (elt)->size < width)
9259 return 0;
9260 }
9261 else
9262 return 0;
9263 }
9264 }
9265 else if (STRINGP (data))
9266 {
9267 if (XSTRING (data)->size
9268 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9269 return 0;
9270 }
9271 else if (BOOL_VECTOR_P (data))
9272 {
9273 if (XBOOL_VECTOR (data)->size < width * height)
9274 return 0;
9275 }
9276 else
9277 return 0;
9278 }
9279
9280 /* Baseline must be a value between 0 and 100 (a percentage). */
9281 if (kw[XBM_ASCENT].count
9282 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9283 return 0;
9284
9285 return 1;
9286}
9287
9288
9289/* Scan a bitmap file. FP is the stream to read from. Value is
9290 either an enumerator from enum xbm_token, or a character for a
9291 single-character token, or 0 at end of file. If scanning an
9292 identifier, store the lexeme of the identifier in SVAL. If
9293 scanning a number, store its value in *IVAL. */
9294
9295static int
3cf3436e
JR
9296xbm_scan (s, end, sval, ival)
9297 char **s, *end;
6fc2811b
JR
9298 char *sval;
9299 int *ival;
9300{
9301 int c;
3cf3436e
JR
9302
9303 loop:
9304
6fc2811b 9305 /* Skip white space. */
3cf3436e 9306 while (*s < end &&(c = *(*s)++, isspace (c)))
6fc2811b
JR
9307 ;
9308
3cf3436e 9309 if (*s >= end)
6fc2811b
JR
9310 c = 0;
9311 else if (isdigit (c))
9312 {
9313 int value = 0, digit;
9314
3cf3436e 9315 if (c == '0' && *s < end)
6fc2811b 9316 {
3cf3436e 9317 c = *(*s)++;
6fc2811b
JR
9318 if (c == 'x' || c == 'X')
9319 {
3cf3436e 9320 while (*s < end)
6fc2811b 9321 {
3cf3436e 9322 c = *(*s)++;
6fc2811b
JR
9323 if (isdigit (c))
9324 digit = c - '0';
9325 else if (c >= 'a' && c <= 'f')
9326 digit = c - 'a' + 10;
9327 else if (c >= 'A' && c <= 'F')
9328 digit = c - 'A' + 10;
9329 else
9330 break;
9331 value = 16 * value + digit;
9332 }
9333 }
9334 else if (isdigit (c))
9335 {
9336 value = c - '0';
3cf3436e
JR
9337 while (*s < end
9338 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9339 value = 8 * value + c - '0';
9340 }
9341 }
9342 else
9343 {
9344 value = c - '0';
3cf3436e
JR
9345 while (*s < end
9346 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9347 value = 10 * value + c - '0';
9348 }
9349
3cf3436e
JR
9350 if (*s < end)
9351 *s = *s - 1;
6fc2811b
JR
9352 *ival = value;
9353 c = XBM_TK_NUMBER;
9354 }
9355 else if (isalpha (c) || c == '_')
9356 {
9357 *sval++ = c;
3cf3436e
JR
9358 while (*s < end
9359 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9360 *sval++ = c;
9361 *sval = 0;
3cf3436e
JR
9362 if (*s < end)
9363 *s = *s - 1;
6fc2811b
JR
9364 c = XBM_TK_IDENT;
9365 }
3cf3436e
JR
9366 else if (c == '/' && **s == '*')
9367 {
9368 /* C-style comment. */
9369 ++*s;
9370 while (**s && (**s != '*' || *(*s + 1) != '/'))
9371 ++*s;
9372 if (**s)
9373 {
9374 *s += 2;
9375 goto loop;
9376 }
9377 }
6fc2811b
JR
9378
9379 return c;
9380}
9381
9382
9383/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9384 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9385 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9386 the image. Return in *DATA the bitmap data allocated with xmalloc.
9387 Value is non-zero if successful. DATA null means just test if
9388 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9389
9390static int
3cf3436e
JR
9391xbm_read_bitmap_data (contents, end, width, height, data)
9392 char *contents, *end;
6fc2811b
JR
9393 int *width, *height;
9394 unsigned char **data;
9395{
3cf3436e 9396 char *s = contents;
6fc2811b
JR
9397 char buffer[BUFSIZ];
9398 int padding_p = 0;
9399 int v10 = 0;
9400 int bytes_per_line, i, nbytes;
9401 unsigned char *p;
9402 int value;
9403 int LA1;
9404
9405#define match() \
3cf3436e 9406 LA1 = xbm_scan (contents, end, buffer, &value)
6fc2811b
JR
9407
9408#define expect(TOKEN) \
9409 if (LA1 != (TOKEN)) \
9410 goto failure; \
9411 else \
9412 match ()
9413
9414#define expect_ident(IDENT) \
9415 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9416 match (); \
9417 else \
9418 goto failure
9419
6fc2811b 9420 *width = *height = -1;
3cf3436e
JR
9421 if (data)
9422 *data = NULL;
9423 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9424
9425 /* Parse defines for width, height and hot-spots. */
9426 while (LA1 == '#')
9427 {
9428 match ();
9429 expect_ident ("define");
9430 expect (XBM_TK_IDENT);
9431
9432 if (LA1 == XBM_TK_NUMBER);
9433 {
9434 char *p = strrchr (buffer, '_');
9435 p = p ? p + 1 : buffer;
9436 if (strcmp (p, "width") == 0)
9437 *width = value;
9438 else if (strcmp (p, "height") == 0)
9439 *height = value;
9440 }
9441 expect (XBM_TK_NUMBER);
9442 }
9443
9444 if (*width < 0 || *height < 0)
9445 goto failure;
3cf3436e
JR
9446 else if (data == NULL)
9447 goto success;
6fc2811b
JR
9448
9449 /* Parse bits. Must start with `static'. */
9450 expect_ident ("static");
9451 if (LA1 == XBM_TK_IDENT)
9452 {
9453 if (strcmp (buffer, "unsigned") == 0)
9454 {
9455 match ();
9456 expect_ident ("char");
9457 }
9458 else if (strcmp (buffer, "short") == 0)
9459 {
9460 match ();
9461 v10 = 1;
9462 if (*width % 16 && *width % 16 < 9)
9463 padding_p = 1;
9464 }
9465 else if (strcmp (buffer, "char") == 0)
9466 match ();
9467 else
9468 goto failure;
9469 }
9470 else
9471 goto failure;
9472
9473 expect (XBM_TK_IDENT);
9474 expect ('[');
9475 expect (']');
9476 expect ('=');
9477 expect ('{');
9478
9479 bytes_per_line = (*width + 7) / 8 + padding_p;
9480 nbytes = bytes_per_line * *height;
9481 p = *data = (char *) xmalloc (nbytes);
9482
9483 if (v10)
9484 {
9485
9486 for (i = 0; i < nbytes; i += 2)
9487 {
9488 int val = value;
9489 expect (XBM_TK_NUMBER);
9490
9491 *p++ = val;
9492 if (!padding_p || ((i + 2) % bytes_per_line))
9493 *p++ = value >> 8;
9494
9495 if (LA1 == ',' || LA1 == '}')
9496 match ();
9497 else
9498 goto failure;
9499 }
9500 }
9501 else
9502 {
9503 for (i = 0; i < nbytes; ++i)
9504 {
9505 int val = value;
9506 expect (XBM_TK_NUMBER);
9507
9508 *p++ = val;
9509
9510 if (LA1 == ',' || LA1 == '}')
9511 match ();
9512 else
9513 goto failure;
9514 }
9515 }
9516
3cf3436e 9517 success:
6fc2811b
JR
9518 return 1;
9519
9520 failure:
3cf3436e
JR
9521
9522 if (data && *data)
6fc2811b
JR
9523 {
9524 xfree (*data);
9525 *data = NULL;
9526 }
9527 return 0;
9528
9529#undef match
9530#undef expect
9531#undef expect_ident
9532}
9533
9534
3cf3436e
JR
9535/* Load XBM image IMG which will be displayed on frame F from buffer
9536 CONTENTS. END is the end of the buffer. Value is non-zero if
9537 successful. */
6fc2811b
JR
9538
9539static int
3cf3436e 9540xbm_load_image (f, img, contents, end)
6fc2811b
JR
9541 struct frame *f;
9542 struct image *img;
3cf3436e 9543 char *contents, *end;
6fc2811b
JR
9544{
9545 int rc;
9546 unsigned char *data;
9547 int success_p = 0;
6fc2811b 9548
3cf3436e 9549 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
9550 if (rc)
9551 {
9552 int depth = one_w32_display_info.n_cbits;
9553 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9554 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9555 Lisp_Object value;
9556
9557 xassert (img->width > 0 && img->height > 0);
9558
9559 /* Get foreground and background colors, maybe allocate colors. */
9560 value = image_spec_value (img->spec, QCforeground, NULL);
9561 if (!NILP (value))
9562 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
9563 value = image_spec_value (img->spec, QCbackground, NULL);
9564 if (!NILP (value))
a05e2bae
JR
9565 {
9566 background = x_alloc_image_color (f, img, value, background);
9567 img->background = background;
9568 img->background_valid = 1;
9569 }
9570
767b1ff0 9571#if 0 /* TODO : Port image display to W32 */
6fc2811b
JR
9572 img->pixmap
9573 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9574 FRAME_W32_WINDOW (f),
9575 data,
9576 img->width, img->height,
9577 foreground, background,
9578 depth);
a05e2bae 9579#endif
6fc2811b
JR
9580 xfree (data);
9581
9582 if (img->pixmap == 0)
9583 {
9584 x_clear_image (f, img);
3cf3436e 9585 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
9586 }
9587 else
9588 success_p = 1;
6fc2811b
JR
9589 }
9590 else
9591 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9592
6fc2811b
JR
9593 return success_p;
9594}
9595
9596
3cf3436e
JR
9597/* Value is non-zero if DATA looks like an in-memory XBM file. */
9598
9599static int
9600xbm_file_p (data)
9601 Lisp_Object data;
9602{
9603 int w, h;
9604 return (STRINGP (data)
9605 && xbm_read_bitmap_data (XSTRING (data)->data,
9606 (XSTRING (data)->data
9607 + STRING_BYTES (XSTRING (data))),
9608 &w, &h, NULL));
9609}
9610
9611
6fc2811b
JR
9612/* Fill image IMG which is used on frame F with pixmap data. Value is
9613 non-zero if successful. */
9614
9615static int
9616xbm_load (f, img)
9617 struct frame *f;
9618 struct image *img;
9619{
9620 int success_p = 0;
9621 Lisp_Object file_name;
9622
9623 xassert (xbm_image_p (img->spec));
9624
9625 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9626 file_name = image_spec_value (img->spec, QCfile, NULL);
9627 if (STRINGP (file_name))
3cf3436e
JR
9628 {
9629 Lisp_Object file;
9630 char *contents;
9631 int size;
9632 struct gcpro gcpro1;
9633
9634 file = x_find_image_file (file_name);
9635 GCPRO1 (file);
9636 if (!STRINGP (file))
9637 {
9638 image_error ("Cannot find image file `%s'", file_name, Qnil);
9639 UNGCPRO;
9640 return 0;
9641 }
9642
9643 contents = slurp_file (XSTRING (file)->data, &size);
9644 if (contents == NULL)
9645 {
9646 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9647 UNGCPRO;
9648 return 0;
9649 }
9650
9651 success_p = xbm_load_image (f, img, contents, contents + size);
9652 UNGCPRO;
9653 }
6fc2811b
JR
9654 else
9655 {
9656 struct image_keyword fmt[XBM_LAST];
9657 Lisp_Object data;
9658 int depth;
9659 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9660 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9661 char *bits;
9662 int parsed_p;
3cf3436e
JR
9663 int in_memory_file_p = 0;
9664
9665 /* See if data looks like an in-memory XBM file. */
9666 data = image_spec_value (img->spec, QCdata, NULL);
9667 in_memory_file_p = xbm_file_p (data);
6fc2811b
JR
9668
9669 /* Parse the list specification. */
9670 bcopy (xbm_format, fmt, sizeof fmt);
9671 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9672 xassert (parsed_p);
9673
9674 /* Get specified width, and height. */
3cf3436e
JR
9675 if (!in_memory_file_p)
9676 {
9677 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9678 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9679 xassert (img->width > 0 && img->height > 0);
9680 }
6fc2811b 9681 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
9682 if (fmt[XBM_FOREGROUND].count
9683 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
9684 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9685 foreground);
3cf3436e
JR
9686 if (fmt[XBM_BACKGROUND].count
9687 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
9688 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9689 background);
9690
3cf3436e
JR
9691 if (in_memory_file_p)
9692 success_p = xbm_load_image (f, img, XSTRING (data)->data,
9693 (XSTRING (data)->data
9694 + STRING_BYTES (XSTRING (data))));
9695 else
6fc2811b 9696 {
3cf3436e
JR
9697 if (VECTORP (data))
9698 {
9699 int i;
9700 char *p;
9701 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 9702
3cf3436e
JR
9703 p = bits = (char *) alloca (nbytes * img->height);
9704 for (i = 0; i < img->height; ++i, p += nbytes)
9705 {
9706 Lisp_Object line = XVECTOR (data)->contents[i];
9707 if (STRINGP (line))
9708 bcopy (XSTRING (line)->data, p, nbytes);
9709 else
9710 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9711 }
9712 }
9713 else if (STRINGP (data))
9714 bits = XSTRING (data)->data;
9715 else
9716 bits = XBOOL_VECTOR (data)->data;
9717#ifdef TODO /* image support. */
9718 /* Create the pixmap. */
a05e2bae 9719 depth = one_w32_display_info.n_cbits;
3cf3436e
JR
9720 img->pixmap
9721 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
9722 FRAME_X_WINDOW (f),
9723 bits,
9724 img->width, img->height,
9725 foreground, background,
9726 depth);
9727#endif
9728 if (img->pixmap)
9729 success_p = 1;
9730 else
6fc2811b 9731 {
3cf3436e
JR
9732 image_error ("Unable to create pixmap for XBM image `%s'",
9733 img->spec, Qnil);
9734 x_clear_image (f, img);
6fc2811b
JR
9735 }
9736 }
6fc2811b
JR
9737 }
9738
9739 return success_p;
9740}
9741
9742
9743\f
9744/***********************************************************************
9745 XPM images
9746 ***********************************************************************/
9747
9748#if HAVE_XPM
9749
9750static int xpm_image_p P_ ((Lisp_Object object));
9751static int xpm_load P_ ((struct frame *f, struct image *img));
9752static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9753
9754#include "X11/xpm.h"
9755
9756/* The symbol `xpm' identifying XPM-format images. */
9757
9758Lisp_Object Qxpm;
9759
9760/* Indices of image specification fields in xpm_format, below. */
9761
9762enum xpm_keyword_index
9763{
9764 XPM_TYPE,
9765 XPM_FILE,
9766 XPM_DATA,
9767 XPM_ASCENT,
9768 XPM_MARGIN,
9769 XPM_RELIEF,
9770 XPM_ALGORITHM,
9771 XPM_HEURISTIC_MASK,
a05e2bae 9772 XPM_MASK,
6fc2811b 9773 XPM_COLOR_SYMBOLS,
a05e2bae 9774 XPM_BACKGROUND,
6fc2811b
JR
9775 XPM_LAST
9776};
9777
9778/* Vector of image_keyword structures describing the format
9779 of valid XPM image specifications. */
9780
9781static struct image_keyword xpm_format[XPM_LAST] =
9782{
9783 {":type", IMAGE_SYMBOL_VALUE, 1},
9784 {":file", IMAGE_STRING_VALUE, 0},
9785 {":data", IMAGE_STRING_VALUE, 0},
9786 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9787 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9788 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9789 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 9790 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
9791 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9792 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9793 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
9794};
9795
9796/* Structure describing the image type XBM. */
9797
9798static struct image_type xpm_type =
9799{
9800 &Qxpm,
9801 xpm_image_p,
9802 xpm_load,
9803 x_clear_image,
9804 NULL
9805};
9806
9807
9808/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9809 for XPM images. Such a list must consist of conses whose car and
9810 cdr are strings. */
9811
9812static int
9813xpm_valid_color_symbols_p (color_symbols)
9814 Lisp_Object color_symbols;
9815{
9816 while (CONSP (color_symbols))
9817 {
9818 Lisp_Object sym = XCAR (color_symbols);
9819 if (!CONSP (sym)
9820 || !STRINGP (XCAR (sym))
9821 || !STRINGP (XCDR (sym)))
9822 break;
9823 color_symbols = XCDR (color_symbols);
9824 }
9825
9826 return NILP (color_symbols);
9827}
9828
9829
9830/* Value is non-zero if OBJECT is a valid XPM image specification. */
9831
9832static int
9833xpm_image_p (object)
9834 Lisp_Object object;
9835{
9836 struct image_keyword fmt[XPM_LAST];
9837 bcopy (xpm_format, fmt, sizeof fmt);
9838 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9839 /* Either `:file' or `:data' must be present. */
9840 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9841 /* Either no `:color-symbols' or it's a list of conses
9842 whose car and cdr are strings. */
9843 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9844 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9845 && (fmt[XPM_ASCENT].count == 0
9846 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9847}
9848
9849
9850/* Load image IMG which will be displayed on frame F. Value is
9851 non-zero if successful. */
9852
9853static int
9854xpm_load (f, img)
9855 struct frame *f;
9856 struct image *img;
9857{
9858 int rc, i;
9859 XpmAttributes attrs;
9860 Lisp_Object specified_file, color_symbols;
9861
9862 /* Configure the XPM lib. Use the visual of frame F. Allocate
9863 close colors. Return colors allocated. */
9864 bzero (&attrs, sizeof attrs);
dfff8a69
JR
9865 attrs.visual = FRAME_X_VISUAL (f);
9866 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 9867 attrs.valuemask |= XpmVisual;
dfff8a69 9868 attrs.valuemask |= XpmColormap;
6fc2811b 9869 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 9870#ifdef XpmAllocCloseColors
6fc2811b
JR
9871 attrs.alloc_close_colors = 1;
9872 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
9873#else
9874 attrs.closeness = 600;
9875 attrs.valuemask |= XpmCloseness;
9876#endif
6fc2811b
JR
9877
9878 /* If image specification contains symbolic color definitions, add
9879 these to `attrs'. */
9880 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9881 if (CONSP (color_symbols))
9882 {
9883 Lisp_Object tail;
9884 XpmColorSymbol *xpm_syms;
9885 int i, size;
9886
9887 attrs.valuemask |= XpmColorSymbols;
9888
9889 /* Count number of symbols. */
9890 attrs.numsymbols = 0;
9891 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9892 ++attrs.numsymbols;
9893
9894 /* Allocate an XpmColorSymbol array. */
9895 size = attrs.numsymbols * sizeof *xpm_syms;
9896 xpm_syms = (XpmColorSymbol *) alloca (size);
9897 bzero (xpm_syms, size);
9898 attrs.colorsymbols = xpm_syms;
9899
9900 /* Fill the color symbol array. */
9901 for (tail = color_symbols, i = 0;
9902 CONSP (tail);
9903 ++i, tail = XCDR (tail))
9904 {
9905 Lisp_Object name = XCAR (XCAR (tail));
9906 Lisp_Object color = XCDR (XCAR (tail));
9907 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9908 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9909 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9910 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9911 }
9912 }
9913
9914 /* Create a pixmap for the image, either from a file, or from a
9915 string buffer containing data in the same format as an XPM file. */
9916 BLOCK_INPUT;
9917 specified_file = image_spec_value (img->spec, QCfile, NULL);
9918 if (STRINGP (specified_file))
9919 {
9920 Lisp_Object file = x_find_image_file (specified_file);
9921 if (!STRINGP (file))
9922 {
9923 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9924 UNBLOCK_INPUT;
9925 return 0;
9926 }
9927
9928 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9929 XSTRING (file)->data, &img->pixmap, &img->mask,
9930 &attrs);
9931 }
9932 else
9933 {
9934 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9935 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9936 XSTRING (buffer)->data,
9937 &img->pixmap, &img->mask,
9938 &attrs);
9939 }
9940 UNBLOCK_INPUT;
9941
9942 if (rc == XpmSuccess)
9943 {
9944 /* Remember allocated colors. */
9945 img->ncolors = attrs.nalloc_pixels;
9946 img->colors = (unsigned long *) xmalloc (img->ncolors
9947 * sizeof *img->colors);
9948 for (i = 0; i < attrs.nalloc_pixels; ++i)
9949 img->colors[i] = attrs.alloc_pixels[i];
9950
9951 img->width = attrs.width;
9952 img->height = attrs.height;
9953 xassert (img->width > 0 && img->height > 0);
9954
9955 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9956 BLOCK_INPUT;
9957 XpmFreeAttributes (&attrs);
9958 UNBLOCK_INPUT;
9959 }
9960 else
9961 {
9962 switch (rc)
9963 {
9964 case XpmOpenFailed:
9965 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9966 break;
9967
9968 case XpmFileInvalid:
9969 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9970 break;
9971
9972 case XpmNoMemory:
9973 image_error ("Out of memory (%s)", img->spec, Qnil);
9974 break;
9975
9976 case XpmColorFailed:
9977 image_error ("Color allocation error (%s)", img->spec, Qnil);
9978 break;
9979
9980 default:
9981 image_error ("Unknown error (%s)", img->spec, Qnil);
9982 break;
9983 }
9984 }
9985
9986 return rc == XpmSuccess;
9987}
9988
9989#endif /* HAVE_XPM != 0 */
9990
9991\f
767b1ff0 9992#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
9993/***********************************************************************
9994 Color table
9995 ***********************************************************************/
9996
9997/* An entry in the color table mapping an RGB color to a pixel color. */
9998
9999struct ct_color
10000{
10001 int r, g, b;
10002 unsigned long pixel;
10003
10004 /* Next in color table collision list. */
10005 struct ct_color *next;
10006};
10007
10008/* The bucket vector size to use. Must be prime. */
10009
10010#define CT_SIZE 101
10011
10012/* Value is a hash of the RGB color given by R, G, and B. */
10013
10014#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10015
10016/* The color hash table. */
10017
10018struct ct_color **ct_table;
10019
10020/* Number of entries in the color table. */
10021
10022int ct_colors_allocated;
10023
10024/* Function prototypes. */
10025
10026static void init_color_table P_ ((void));
10027static void free_color_table P_ ((void));
10028static unsigned long *colors_in_color_table P_ ((int *n));
10029static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10030static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10031
10032
10033/* Initialize the color table. */
10034
10035static void
10036init_color_table ()
10037{
10038 int size = CT_SIZE * sizeof (*ct_table);
10039 ct_table = (struct ct_color **) xmalloc (size);
10040 bzero (ct_table, size);
10041 ct_colors_allocated = 0;
10042}
10043
10044
10045/* Free memory associated with the color table. */
10046
10047static void
10048free_color_table ()
10049{
10050 int i;
10051 struct ct_color *p, *next;
10052
10053 for (i = 0; i < CT_SIZE; ++i)
10054 for (p = ct_table[i]; p; p = next)
10055 {
10056 next = p->next;
10057 xfree (p);
10058 }
10059
10060 xfree (ct_table);
10061 ct_table = NULL;
10062}
10063
10064
10065/* Value is a pixel color for RGB color R, G, B on frame F. If an
10066 entry for that color already is in the color table, return the
10067 pixel color of that entry. Otherwise, allocate a new color for R,
10068 G, B, and make an entry in the color table. */
10069
10070static unsigned long
10071lookup_rgb_color (f, r, g, b)
10072 struct frame *f;
10073 int r, g, b;
10074{
10075 unsigned hash = CT_HASH_RGB (r, g, b);
10076 int i = hash % CT_SIZE;
10077 struct ct_color *p;
10078
10079 for (p = ct_table[i]; p; p = p->next)
10080 if (p->r == r && p->g == g && p->b == b)
10081 break;
10082
10083 if (p == NULL)
10084 {
10085 COLORREF color;
10086 Colormap cmap;
10087 int rc;
10088
10089 color = PALETTERGB (r, g, b);
10090
10091 ++ct_colors_allocated;
10092
10093 p = (struct ct_color *) xmalloc (sizeof *p);
10094 p->r = r;
10095 p->g = g;
10096 p->b = b;
10097 p->pixel = color;
10098 p->next = ct_table[i];
10099 ct_table[i] = p;
10100 }
10101
10102 return p->pixel;
10103}
10104
10105
10106/* Look up pixel color PIXEL which is used on frame F in the color
10107 table. If not already present, allocate it. Value is PIXEL. */
10108
10109static unsigned long
10110lookup_pixel_color (f, pixel)
10111 struct frame *f;
10112 unsigned long pixel;
10113{
10114 int i = pixel % CT_SIZE;
10115 struct ct_color *p;
10116
10117 for (p = ct_table[i]; p; p = p->next)
10118 if (p->pixel == pixel)
10119 break;
10120
10121 if (p == NULL)
10122 {
10123 XColor color;
10124 Colormap cmap;
10125 int rc;
10126
10127 BLOCK_INPUT;
10128
10129 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10130 color.pixel = pixel;
10131 XQueryColor (NULL, cmap, &color);
10132 rc = x_alloc_nearest_color (f, cmap, &color);
10133 UNBLOCK_INPUT;
10134
10135 if (rc)
10136 {
10137 ++ct_colors_allocated;
10138
10139 p = (struct ct_color *) xmalloc (sizeof *p);
10140 p->r = color.red;
10141 p->g = color.green;
10142 p->b = color.blue;
10143 p->pixel = pixel;
10144 p->next = ct_table[i];
10145 ct_table[i] = p;
10146 }
10147 else
10148 return FRAME_FOREGROUND_PIXEL (f);
10149 }
10150 return p->pixel;
10151}
10152
10153
10154/* Value is a vector of all pixel colors contained in the color table,
10155 allocated via xmalloc. Set *N to the number of colors. */
10156
10157static unsigned long *
10158colors_in_color_table (n)
10159 int *n;
10160{
10161 int i, j;
10162 struct ct_color *p;
10163 unsigned long *colors;
10164
10165 if (ct_colors_allocated == 0)
10166 {
10167 *n = 0;
10168 colors = NULL;
10169 }
10170 else
10171 {
10172 colors = (unsigned long *) xmalloc (ct_colors_allocated
10173 * sizeof *colors);
10174 *n = ct_colors_allocated;
10175
10176 for (i = j = 0; i < CT_SIZE; ++i)
10177 for (p = ct_table[i]; p; p = p->next)
10178 colors[j++] = p->pixel;
10179 }
10180
10181 return colors;
10182}
10183
767b1ff0 10184#endif /* TODO */
6fc2811b
JR
10185
10186\f
10187/***********************************************************************
10188 Algorithms
10189 ***********************************************************************/
3cf3436e
JR
10190#if 0 /* TODO: image support. */
10191static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10192static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10193static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10194
10195/* Non-zero means draw a cross on images having `:conversion
10196 disabled'. */
6fc2811b 10197
3cf3436e 10198int cross_disabled_images;
6fc2811b 10199
3cf3436e
JR
10200/* Edge detection matrices for different edge-detection
10201 strategies. */
6fc2811b 10202
3cf3436e
JR
10203static int emboss_matrix[9] = {
10204 /* x - 1 x x + 1 */
10205 2, -1, 0, /* y - 1 */
10206 -1, 0, 1, /* y */
10207 0, 1, -2 /* y + 1 */
10208};
10209
10210static int laplace_matrix[9] = {
10211 /* x - 1 x x + 1 */
10212 1, 0, 0, /* y - 1 */
10213 0, 0, 0, /* y */
10214 0, 0, -1 /* y + 1 */
10215};
10216
10217/* Value is the intensity of the color whose red/green/blue values
10218 are R, G, and B. */
10219
10220#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10221
10222
10223/* On frame F, return an array of XColor structures describing image
10224 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10225 non-zero means also fill the red/green/blue members of the XColor
10226 structures. Value is a pointer to the array of XColors structures,
10227 allocated with xmalloc; it must be freed by the caller. */
10228
10229static XColor *
10230x_to_xcolors (f, img, rgb_p)
10231 struct frame *f;
10232 struct image *img;
10233 int rgb_p;
10234{
10235 int x, y;
10236 XColor *colors, *p;
10237 XImage *ximg;
10238
10239 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10240
10241 /* Get the X image IMG->pixmap. */
10242 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10243 0, 0, img->width, img->height, ~0, ZPixmap);
10244
10245 /* Fill the `pixel' members of the XColor array. I wished there
10246 were an easy and portable way to circumvent XGetPixel. */
10247 p = colors;
10248 for (y = 0; y < img->height; ++y)
10249 {
10250 XColor *row = p;
10251
10252 for (x = 0; x < img->width; ++x, ++p)
10253 p->pixel = XGetPixel (ximg, x, y);
10254
10255 if (rgb_p)
10256 x_query_colors (f, row, img->width);
10257 }
10258
10259 XDestroyImage (ximg);
10260 return colors;
10261}
10262
10263
10264/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10265 RGB members are set. F is the frame on which this all happens.
10266 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10267
10268static void
3cf3436e 10269x_from_xcolors (f, img, colors)
6fc2811b 10270 struct frame *f;
3cf3436e 10271 struct image *img;
6fc2811b 10272 XColor *colors;
6fc2811b 10273{
3cf3436e
JR
10274 int x, y;
10275 XImage *oimg;
10276 Pixmap pixmap;
10277 XColor *p;
10278
10279 init_color_table ();
10280
10281 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10282 &oimg, &pixmap);
10283 p = colors;
10284 for (y = 0; y < img->height; ++y)
10285 for (x = 0; x < img->width; ++x, ++p)
10286 {
10287 unsigned long pixel;
10288 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10289 XPutPixel (oimg, x, y, pixel);
10290 }
6fc2811b 10291
3cf3436e
JR
10292 xfree (colors);
10293 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10294
3cf3436e
JR
10295 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10296 x_destroy_x_image (oimg);
10297 img->pixmap = pixmap;
10298 img->colors = colors_in_color_table (&img->ncolors);
10299 free_color_table ();
6fc2811b
JR
10300}
10301
10302
3cf3436e
JR
10303/* On frame F, perform edge-detection on image IMG.
10304
10305 MATRIX is a nine-element array specifying the transformation
10306 matrix. See emboss_matrix for an example.
10307
10308 COLOR_ADJUST is a color adjustment added to each pixel of the
10309 outgoing image. */
6fc2811b
JR
10310
10311static void
3cf3436e 10312x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10313 struct frame *f;
3cf3436e
JR
10314 struct image *img;
10315 int matrix[9], color_adjust;
6fc2811b 10316{
3cf3436e
JR
10317 XColor *colors = x_to_xcolors (f, img, 1);
10318 XColor *new, *p;
10319 int x, y, i, sum;
10320
10321 for (i = sum = 0; i < 9; ++i)
10322 sum += abs (matrix[i]);
10323
10324#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10325
10326 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10327
10328 for (y = 0; y < img->height; ++y)
10329 {
10330 p = COLOR (new, 0, y);
10331 p->red = p->green = p->blue = 0xffff/2;
10332 p = COLOR (new, img->width - 1, y);
10333 p->red = p->green = p->blue = 0xffff/2;
10334 }
6fc2811b 10335
3cf3436e
JR
10336 for (x = 1; x < img->width - 1; ++x)
10337 {
10338 p = COLOR (new, x, 0);
10339 p->red = p->green = p->blue = 0xffff/2;
10340 p = COLOR (new, x, img->height - 1);
10341 p->red = p->green = p->blue = 0xffff/2;
10342 }
10343
10344 for (y = 1; y < img->height - 1; ++y)
10345 {
10346 p = COLOR (new, 1, y);
10347
10348 for (x = 1; x < img->width - 1; ++x, ++p)
10349 {
10350 int r, g, b, y1, x1;
10351
10352 r = g = b = i = 0;
10353 for (y1 = y - 1; y1 < y + 2; ++y1)
10354 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10355 if (matrix[i])
10356 {
10357 XColor *t = COLOR (colors, x1, y1);
10358 r += matrix[i] * t->red;
10359 g += matrix[i] * t->green;
10360 b += matrix[i] * t->blue;
10361 }
10362
10363 r = (r / sum + color_adjust) & 0xffff;
10364 g = (g / sum + color_adjust) & 0xffff;
10365 b = (b / sum + color_adjust) & 0xffff;
10366 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10367 }
10368 }
10369
10370 xfree (colors);
10371 x_from_xcolors (f, img, new);
10372
10373#undef COLOR
10374}
10375
10376
10377/* Perform the pre-defined `emboss' edge-detection on image IMG
10378 on frame F. */
10379
10380static void
10381x_emboss (f, img)
10382 struct frame *f;
10383 struct image *img;
10384{
10385 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10386}
3cf3436e 10387
6fc2811b
JR
10388
10389/* Transform image IMG which is used on frame F with a Laplace
10390 edge-detection algorithm. The result is an image that can be used
10391 to draw disabled buttons, for example. */
10392
10393static void
10394x_laplace (f, img)
10395 struct frame *f;
10396 struct image *img;
10397{
3cf3436e
JR
10398 x_detect_edges (f, img, laplace_matrix, 45000);
10399}
6fc2811b 10400
6fc2811b 10401
3cf3436e
JR
10402/* Perform edge-detection on image IMG on frame F, with specified
10403 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10404
3cf3436e 10405 MATRIX must be either
6fc2811b 10406
3cf3436e
JR
10407 - a list of at least 9 numbers in row-major form
10408 - a vector of at least 9 numbers
6fc2811b 10409
3cf3436e
JR
10410 COLOR_ADJUST nil means use a default; otherwise it must be a
10411 number. */
6fc2811b 10412
3cf3436e
JR
10413static void
10414x_edge_detection (f, img, matrix, color_adjust)
10415 struct frame *f;
10416 struct image *img;
10417 Lisp_Object matrix, color_adjust;
10418{
10419 int i = 0;
10420 int trans[9];
10421
10422 if (CONSP (matrix))
6fc2811b 10423 {
3cf3436e
JR
10424 for (i = 0;
10425 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10426 ++i, matrix = XCDR (matrix))
10427 trans[i] = XFLOATINT (XCAR (matrix));
10428 }
10429 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10430 {
10431 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10432 trans[i] = XFLOATINT (AREF (matrix, i));
10433 }
10434
10435 if (NILP (color_adjust))
10436 color_adjust = make_number (0xffff / 2);
10437
10438 if (i == 9 && NUMBERP (color_adjust))
10439 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10440}
10441
6fc2811b 10442
3cf3436e 10443/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10444
3cf3436e
JR
10445static void
10446x_disable_image (f, img)
10447 struct frame *f;
10448 struct image *img;
10449{
10450 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10451
10452 if (dpyinfo->n_planes >= 2)
10453 {
10454 /* Color (or grayscale). Convert to gray, and equalize. Just
10455 drawing such images with a stipple can look very odd, so
10456 we're using this method instead. */
10457 XColor *colors = x_to_xcolors (f, img, 1);
10458 XColor *p, *end;
10459 const int h = 15000;
10460 const int l = 30000;
10461
10462 for (p = colors, end = colors + img->width * img->height;
10463 p < end;
10464 ++p)
6fc2811b 10465 {
3cf3436e
JR
10466 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10467 int i2 = (0xffff - h - l) * i / 0xffff + l;
10468 p->red = p->green = p->blue = i2;
6fc2811b
JR
10469 }
10470
3cf3436e 10471 x_from_xcolors (f, img, colors);
6fc2811b
JR
10472 }
10473
3cf3436e
JR
10474 /* Draw a cross over the disabled image, if we must or if we
10475 should. */
10476 if (dpyinfo->n_planes < 2 || cross_disabled_images)
10477 {
10478 Display *dpy = FRAME_X_DISPLAY (f);
10479 GC gc;
6fc2811b 10480
3cf3436e
JR
10481 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10482 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10483 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10484 img->width - 1, img->height - 1);
10485 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10486 img->width - 1, 0);
10487 XFreeGC (dpy, gc);
6fc2811b 10488
3cf3436e
JR
10489 if (img->mask)
10490 {
10491 gc = XCreateGC (dpy, img->mask, 0, NULL);
10492 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10493 XDrawLine (dpy, img->mask, gc, 0, 0,
10494 img->width - 1, img->height - 1);
10495 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10496 img->width - 1, 0);
10497 XFreeGC (dpy, gc);
10498 }
10499 }
6fc2811b
JR
10500}
10501
10502
10503/* Build a mask for image IMG which is used on frame F. FILE is the
10504 name of an image file, for error messages. HOW determines how to
10505 determine the background color of IMG. If it is a list '(R G B)',
10506 with R, G, and B being integers >= 0, take that as the color of the
10507 background. Otherwise, determine the background color of IMG
10508 heuristically. Value is non-zero if successful. */
10509
10510static int
10511x_build_heuristic_mask (f, img, how)
10512 struct frame *f;
10513 struct image *img;
10514 Lisp_Object how;
10515{
6fc2811b
JR
10516 Display *dpy = FRAME_W32_DISPLAY (f);
10517 XImage *ximg, *mask_img;
a05e2bae
JR
10518 int x, y, rc, use_img_background;
10519 unsigned long bg = 0;
10520
10521 if (img->mask)
10522 {
10523 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10524 img->mask = None;
10525 img->background_transparent_valid = 0;
10526 }
6fc2811b 10527
6fc2811b
JR
10528 /* Create an image and pixmap serving as mask. */
10529 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10530 &mask_img, &img->mask);
10531 if (!rc)
a05e2bae 10532 return 0;
6fc2811b
JR
10533
10534 /* Get the X image of IMG->pixmap. */
10535 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10536 ~0, ZPixmap);
10537
10538 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
10539 take that as color. Otherwise, use the image's background color. */
10540 use_img_background = 1;
6fc2811b
JR
10541
10542 if (CONSP (how))
10543 {
a05e2bae 10544 int rgb[3], i;
6fc2811b 10545
a05e2bae 10546 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
10547 {
10548 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10549 how = XCDR (how);
10550 }
10551
10552 if (i == 3 && NILP (how))
10553 {
10554 char color_name[30];
6fc2811b 10555 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
10556 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10557 use_img_background = 0;
6fc2811b
JR
10558 }
10559 }
10560
a05e2bae
JR
10561 if (use_img_background)
10562 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
10563
10564 /* Set all bits in mask_img to 1 whose color in ximg is different
10565 from the background color bg. */
10566 for (y = 0; y < img->height; ++y)
10567 for (x = 0; x < img->width; ++x)
10568 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
10569
a05e2bae
JR
10570 /* Fill in the background_transparent field while we have the mask handy. */
10571 image_background_transparent (img, f, mask_img);
10572
6fc2811b
JR
10573 /* Put mask_img into img->mask. */
10574 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10575 x_destroy_x_image (mask_img);
10576 XDestroyImage (ximg);
6fc2811b
JR
10577
10578 return 1;
10579}
3cf3436e 10580#endif /* TODO */
6fc2811b
JR
10581
10582\f
10583/***********************************************************************
10584 PBM (mono, gray, color)
10585 ***********************************************************************/
10586#ifdef HAVE_PBM
10587
10588static int pbm_image_p P_ ((Lisp_Object object));
10589static int pbm_load P_ ((struct frame *f, struct image *img));
10590static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10591
10592/* The symbol `pbm' identifying images of this type. */
10593
10594Lisp_Object Qpbm;
10595
10596/* Indices of image specification fields in gs_format, below. */
10597
10598enum pbm_keyword_index
10599{
10600 PBM_TYPE,
10601 PBM_FILE,
10602 PBM_DATA,
10603 PBM_ASCENT,
10604 PBM_MARGIN,
10605 PBM_RELIEF,
10606 PBM_ALGORITHM,
10607 PBM_HEURISTIC_MASK,
a05e2bae
JR
10608 PBM_MASK,
10609 PBM_FOREGROUND,
10610 PBM_BACKGROUND,
6fc2811b
JR
10611 PBM_LAST
10612};
10613
10614/* Vector of image_keyword structures describing the format
10615 of valid user-defined image specifications. */
10616
10617static struct image_keyword pbm_format[PBM_LAST] =
10618{
10619 {":type", IMAGE_SYMBOL_VALUE, 1},
10620 {":file", IMAGE_STRING_VALUE, 0},
10621 {":data", IMAGE_STRING_VALUE, 0},
10622 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10623 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10624 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10625 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
10626 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10627 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10628 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10629 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10630};
10631
10632/* Structure describing the image type `pbm'. */
10633
10634static struct image_type pbm_type =
10635{
10636 &Qpbm,
10637 pbm_image_p,
10638 pbm_load,
10639 x_clear_image,
10640 NULL
10641};
10642
10643
10644/* Return non-zero if OBJECT is a valid PBM image specification. */
10645
10646static int
10647pbm_image_p (object)
10648 Lisp_Object object;
10649{
10650 struct image_keyword fmt[PBM_LAST];
10651
10652 bcopy (pbm_format, fmt, sizeof fmt);
10653
10654 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
10655 || (fmt[PBM_ASCENT].count
10656 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
10657 return 0;
10658
10659 /* Must specify either :data or :file. */
10660 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10661}
10662
10663
10664/* Scan a decimal number from *S and return it. Advance *S while
10665 reading the number. END is the end of the string. Value is -1 at
10666 end of input. */
10667
10668static int
10669pbm_scan_number (s, end)
10670 unsigned char **s, *end;
10671{
10672 int c, val = -1;
10673
10674 while (*s < end)
10675 {
10676 /* Skip white-space. */
10677 while (*s < end && (c = *(*s)++, isspace (c)))
10678 ;
10679
10680 if (c == '#')
10681 {
10682 /* Skip comment to end of line. */
10683 while (*s < end && (c = *(*s)++, c != '\n'))
10684 ;
10685 }
10686 else if (isdigit (c))
10687 {
10688 /* Read decimal number. */
10689 val = c - '0';
10690 while (*s < end && (c = *(*s)++, isdigit (c)))
10691 val = 10 * val + c - '0';
10692 break;
10693 }
10694 else
10695 break;
10696 }
10697
10698 return val;
10699}
10700
10701
10702/* Read FILE into memory. Value is a pointer to a buffer allocated
10703 with xmalloc holding FILE's contents. Value is null if an error
10704 occured. *SIZE is set to the size of the file. */
10705
10706static char *
10707pbm_read_file (file, size)
10708 Lisp_Object file;
10709 int *size;
10710{
10711 FILE *fp = NULL;
10712 char *buf = NULL;
10713 struct stat st;
10714
10715 if (stat (XSTRING (file)->data, &st) == 0
10716 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10717 && (buf = (char *) xmalloc (st.st_size),
10718 fread (buf, 1, st.st_size, fp) == st.st_size))
10719 {
10720 *size = st.st_size;
10721 fclose (fp);
10722 }
10723 else
10724 {
10725 if (fp)
10726 fclose (fp);
10727 if (buf)
10728 {
10729 xfree (buf);
10730 buf = NULL;
10731 }
10732 }
10733
10734 return buf;
10735}
10736
10737
10738/* Load PBM image IMG for use on frame F. */
10739
10740static int
10741pbm_load (f, img)
10742 struct frame *f;
10743 struct image *img;
10744{
10745 int raw_p, x, y;
10746 int width, height, max_color_idx = 0;
10747 XImage *ximg;
10748 Lisp_Object file, specified_file;
10749 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10750 struct gcpro gcpro1;
10751 unsigned char *contents = NULL;
10752 unsigned char *end, *p;
10753 int size;
10754
10755 specified_file = image_spec_value (img->spec, QCfile, NULL);
10756 file = Qnil;
10757 GCPRO1 (file);
10758
10759 if (STRINGP (specified_file))
10760 {
10761 file = x_find_image_file (specified_file);
10762 if (!STRINGP (file))
10763 {
10764 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10765 UNGCPRO;
10766 return 0;
10767 }
10768
3cf3436e 10769 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
10770 if (contents == NULL)
10771 {
10772 image_error ("Error reading `%s'", file, Qnil);
10773 UNGCPRO;
10774 return 0;
10775 }
10776
10777 p = contents;
10778 end = contents + size;
10779 }
10780 else
10781 {
10782 Lisp_Object data;
10783 data = image_spec_value (img->spec, QCdata, NULL);
10784 p = XSTRING (data)->data;
10785 end = p + STRING_BYTES (XSTRING (data));
10786 }
10787
10788 /* Check magic number. */
10789 if (end - p < 2 || *p++ != 'P')
10790 {
10791 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10792 error:
10793 xfree (contents);
10794 UNGCPRO;
10795 return 0;
10796 }
10797
6fc2811b
JR
10798 switch (*p++)
10799 {
10800 case '1':
10801 raw_p = 0, type = PBM_MONO;
10802 break;
10803
10804 case '2':
10805 raw_p = 0, type = PBM_GRAY;
10806 break;
10807
10808 case '3':
10809 raw_p = 0, type = PBM_COLOR;
10810 break;
10811
10812 case '4':
10813 raw_p = 1, type = PBM_MONO;
10814 break;
10815
10816 case '5':
10817 raw_p = 1, type = PBM_GRAY;
10818 break;
10819
10820 case '6':
10821 raw_p = 1, type = PBM_COLOR;
10822 break;
10823
10824 default:
10825 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10826 goto error;
10827 }
10828
10829 /* Read width, height, maximum color-component. Characters
10830 starting with `#' up to the end of a line are ignored. */
10831 width = pbm_scan_number (&p, end);
10832 height = pbm_scan_number (&p, end);
10833
10834 if (type != PBM_MONO)
10835 {
10836 max_color_idx = pbm_scan_number (&p, end);
10837 if (raw_p && max_color_idx > 255)
10838 max_color_idx = 255;
10839 }
10840
10841 if (width < 0
10842 || height < 0
10843 || (type != PBM_MONO && max_color_idx < 0))
10844 goto error;
10845
6fc2811b
JR
10846 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10847 &ximg, &img->pixmap))
3cf3436e
JR
10848 goto error;
10849
6fc2811b
JR
10850 /* Initialize the color hash table. */
10851 init_color_table ();
10852
10853 if (type == PBM_MONO)
10854 {
10855 int c = 0, g;
3cf3436e
JR
10856 struct image_keyword fmt[PBM_LAST];
10857 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
10858 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
10859
10860 /* Parse the image specification. */
10861 bcopy (pbm_format, fmt, sizeof fmt);
10862 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
10863
10864 /* Get foreground and background colors, maybe allocate colors. */
10865 if (fmt[PBM_FOREGROUND].count
10866 && STRINGP (fmt[PBM_FOREGROUND].value))
10867 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
10868 if (fmt[PBM_BACKGROUND].count
10869 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
10870 {
10871 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
10872 img->background = bg;
10873 img->background_valid = 1;
10874 }
10875
6fc2811b
JR
10876 for (y = 0; y < height; ++y)
10877 for (x = 0; x < width; ++x)
10878 {
10879 if (raw_p)
10880 {
10881 if ((x & 7) == 0)
10882 c = *p++;
10883 g = c & 0x80;
10884 c <<= 1;
10885 }
10886 else
10887 g = pbm_scan_number (&p, end);
10888
3cf3436e 10889 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
10890 }
10891 }
10892 else
10893 {
10894 for (y = 0; y < height; ++y)
10895 for (x = 0; x < width; ++x)
10896 {
10897 int r, g, b;
10898
10899 if (type == PBM_GRAY)
10900 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10901 else if (raw_p)
10902 {
10903 r = *p++;
10904 g = *p++;
10905 b = *p++;
10906 }
10907 else
10908 {
10909 r = pbm_scan_number (&p, end);
10910 g = pbm_scan_number (&p, end);
10911 b = pbm_scan_number (&p, end);
10912 }
10913
10914 if (r < 0 || g < 0 || b < 0)
10915 {
dfff8a69 10916 xfree (ximg->data);
6fc2811b
JR
10917 ximg->data = NULL;
10918 XDestroyImage (ximg);
6fc2811b
JR
10919 image_error ("Invalid pixel value in image `%s'",
10920 img->spec, Qnil);
10921 goto error;
10922 }
10923
10924 /* RGB values are now in the range 0..max_color_idx.
10925 Scale this to the range 0..0xffff supported by X. */
10926 r = (double) r * 65535 / max_color_idx;
10927 g = (double) g * 65535 / max_color_idx;
10928 b = (double) b * 65535 / max_color_idx;
10929 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10930 }
10931 }
10932
10933 /* Store in IMG->colors the colors allocated for the image, and
10934 free the color table. */
10935 img->colors = colors_in_color_table (&img->ncolors);
10936 free_color_table ();
10937
a05e2bae
JR
10938 /* Maybe fill in the background field while we have ximg handy. */
10939 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10940 IMAGE_BACKGROUND (img, f, ximg);
10941
6fc2811b
JR
10942 /* Put the image into a pixmap. */
10943 x_put_x_image (f, ximg, img->pixmap, width, height);
10944 x_destroy_x_image (ximg);
6fc2811b
JR
10945
10946 img->width = width;
10947 img->height = height;
10948
10949 UNGCPRO;
10950 xfree (contents);
10951 return 1;
10952}
10953#endif /* HAVE_PBM */
10954
10955\f
10956/***********************************************************************
10957 PNG
10958 ***********************************************************************/
10959
10960#if HAVE_PNG
10961
10962#include <png.h>
10963
10964/* Function prototypes. */
10965
10966static int png_image_p P_ ((Lisp_Object object));
10967static int png_load P_ ((struct frame *f, struct image *img));
10968
10969/* The symbol `png' identifying images of this type. */
10970
10971Lisp_Object Qpng;
10972
10973/* Indices of image specification fields in png_format, below. */
10974
10975enum png_keyword_index
10976{
10977 PNG_TYPE,
10978 PNG_DATA,
10979 PNG_FILE,
10980 PNG_ASCENT,
10981 PNG_MARGIN,
10982 PNG_RELIEF,
10983 PNG_ALGORITHM,
10984 PNG_HEURISTIC_MASK,
a05e2bae
JR
10985 PNG_MASK,
10986 PNG_BACKGROUND,
6fc2811b
JR
10987 PNG_LAST
10988};
10989
10990/* Vector of image_keyword structures describing the format
10991 of valid user-defined image specifications. */
10992
10993static struct image_keyword png_format[PNG_LAST] =
10994{
10995 {":type", IMAGE_SYMBOL_VALUE, 1},
10996 {":data", IMAGE_STRING_VALUE, 0},
10997 {":file", IMAGE_STRING_VALUE, 0},
10998 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10999 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11000 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11001 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
11002 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11003 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11004 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11005};
11006
11007/* Structure describing the image type `png'. */
11008
11009static struct image_type png_type =
11010{
11011 &Qpng,
11012 png_image_p,
11013 png_load,
11014 x_clear_image,
11015 NULL
11016};
11017
11018
11019/* Return non-zero if OBJECT is a valid PNG image specification. */
11020
11021static int
11022png_image_p (object)
11023 Lisp_Object object;
11024{
11025 struct image_keyword fmt[PNG_LAST];
11026 bcopy (png_format, fmt, sizeof fmt);
11027
11028 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11029 || (fmt[PNG_ASCENT].count
11030 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11031 return 0;
11032
11033 /* Must specify either the :data or :file keyword. */
11034 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11035}
11036
11037
11038/* Error and warning handlers installed when the PNG library
11039 is initialized. */
11040
11041static void
11042my_png_error (png_ptr, msg)
11043 png_struct *png_ptr;
11044 char *msg;
11045{
11046 xassert (png_ptr != NULL);
11047 image_error ("PNG error: %s", build_string (msg), Qnil);
11048 longjmp (png_ptr->jmpbuf, 1);
11049}
11050
11051
11052static void
11053my_png_warning (png_ptr, msg)
11054 png_struct *png_ptr;
11055 char *msg;
11056{
11057 xassert (png_ptr != NULL);
11058 image_error ("PNG warning: %s", build_string (msg), Qnil);
11059}
11060
6fc2811b
JR
11061/* Memory source for PNG decoding. */
11062
11063struct png_memory_storage
11064{
11065 unsigned char *bytes; /* The data */
11066 size_t len; /* How big is it? */
11067 int index; /* Where are we? */
11068};
11069
11070
11071/* Function set as reader function when reading PNG image from memory.
11072 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11073 bytes from the input to DATA. */
11074
11075static void
11076png_read_from_memory (png_ptr, data, length)
11077 png_structp png_ptr;
11078 png_bytep data;
11079 png_size_t length;
11080{
11081 struct png_memory_storage *tbr
11082 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11083
11084 if (length > tbr->len - tbr->index)
11085 png_error (png_ptr, "Read error");
11086
11087 bcopy (tbr->bytes + tbr->index, data, length);
11088 tbr->index = tbr->index + length;
11089}
11090
6fc2811b
JR
11091/* Load PNG image IMG for use on frame F. Value is non-zero if
11092 successful. */
11093
11094static int
11095png_load (f, img)
11096 struct frame *f;
11097 struct image *img;
11098{
11099 Lisp_Object file, specified_file;
11100 Lisp_Object specified_data;
11101 int x, y, i;
11102 XImage *ximg, *mask_img = NULL;
11103 struct gcpro gcpro1;
11104 png_struct *png_ptr = NULL;
11105 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11106 FILE *volatile fp = NULL;
6fc2811b 11107 png_byte sig[8];
a05e2bae
JR
11108 png_byte *volatile pixels = NULL;
11109 png_byte **volatile rows = NULL;
6fc2811b
JR
11110 png_uint_32 width, height;
11111 int bit_depth, color_type, interlace_type;
11112 png_byte channels;
11113 png_uint_32 row_bytes;
11114 int transparent_p;
11115 char *gamma_str;
11116 double screen_gamma, image_gamma;
11117 int intent;
11118 struct png_memory_storage tbr; /* Data to be read */
11119
11120 /* Find out what file to load. */
11121 specified_file = image_spec_value (img->spec, QCfile, NULL);
11122 specified_data = image_spec_value (img->spec, QCdata, NULL);
11123 file = Qnil;
11124 GCPRO1 (file);
11125
11126 if (NILP (specified_data))
11127 {
11128 file = x_find_image_file (specified_file);
11129 if (!STRINGP (file))
11130 {
11131 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11132 UNGCPRO;
11133 return 0;
11134 }
11135
11136 /* Open the image file. */
11137 fp = fopen (XSTRING (file)->data, "rb");
11138 if (!fp)
11139 {
11140 image_error ("Cannot open image file `%s'", file, Qnil);
11141 UNGCPRO;
11142 fclose (fp);
11143 return 0;
11144 }
11145
11146 /* Check PNG signature. */
11147 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11148 || !png_check_sig (sig, sizeof sig))
11149 {
11150 image_error ("Not a PNG file:` %s'", file, Qnil);
11151 UNGCPRO;
11152 fclose (fp);
11153 return 0;
11154 }
11155 }
11156 else
11157 {
11158 /* Read from memory. */
11159 tbr.bytes = XSTRING (specified_data)->data;
11160 tbr.len = STRING_BYTES (XSTRING (specified_data));
11161 tbr.index = 0;
11162
11163 /* Check PNG signature. */
11164 if (tbr.len < sizeof sig
11165 || !png_check_sig (tbr.bytes, sizeof sig))
11166 {
11167 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11168 UNGCPRO;
11169 return 0;
11170 }
11171
11172 /* Need to skip past the signature. */
11173 tbr.bytes += sizeof (sig);
11174 }
11175
6fc2811b
JR
11176 /* Initialize read and info structs for PNG lib. */
11177 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11178 my_png_error, my_png_warning);
11179 if (!png_ptr)
11180 {
11181 if (fp) fclose (fp);
11182 UNGCPRO;
11183 return 0;
11184 }
11185
11186 info_ptr = png_create_info_struct (png_ptr);
11187 if (!info_ptr)
11188 {
11189 png_destroy_read_struct (&png_ptr, NULL, NULL);
11190 if (fp) fclose (fp);
11191 UNGCPRO;
11192 return 0;
11193 }
11194
11195 end_info = png_create_info_struct (png_ptr);
11196 if (!end_info)
11197 {
11198 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11199 if (fp) fclose (fp);
11200 UNGCPRO;
11201 return 0;
11202 }
11203
11204 /* Set error jump-back. We come back here when the PNG library
11205 detects an error. */
11206 if (setjmp (png_ptr->jmpbuf))
11207 {
11208 error:
11209 if (png_ptr)
11210 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11211 xfree (pixels);
11212 xfree (rows);
11213 if (fp) fclose (fp);
11214 UNGCPRO;
11215 return 0;
11216 }
11217
11218 /* Read image info. */
11219 if (!NILP (specified_data))
11220 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11221 else
11222 png_init_io (png_ptr, fp);
11223
11224 png_set_sig_bytes (png_ptr, sizeof sig);
11225 png_read_info (png_ptr, info_ptr);
11226 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11227 &interlace_type, NULL, NULL);
11228
11229 /* If image contains simply transparency data, we prefer to
11230 construct a clipping mask. */
11231 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11232 transparent_p = 1;
11233 else
11234 transparent_p = 0;
11235
11236 /* This function is easier to write if we only have to handle
11237 one data format: RGB or RGBA with 8 bits per channel. Let's
11238 transform other formats into that format. */
11239
11240 /* Strip more than 8 bits per channel. */
11241 if (bit_depth == 16)
11242 png_set_strip_16 (png_ptr);
11243
11244 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11245 if available. */
11246 png_set_expand (png_ptr);
11247
11248 /* Convert grayscale images to RGB. */
11249 if (color_type == PNG_COLOR_TYPE_GRAY
11250 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11251 png_set_gray_to_rgb (png_ptr);
11252
11253 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11254 gamma_str = getenv ("SCREEN_GAMMA");
11255 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11256
11257 /* Tell the PNG lib to handle gamma correction for us. */
11258
11259#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11260 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11261 /* There is a special chunk in the image specifying the gamma. */
11262 png_set_sRGB (png_ptr, info_ptr, intent);
11263 else
11264#endif
11265 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11266 /* Image contains gamma information. */
11267 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11268 else
11269 /* Use a default of 0.5 for the image gamma. */
11270 png_set_gamma (png_ptr, screen_gamma, 0.5);
11271
11272 /* Handle alpha channel by combining the image with a background
11273 color. Do this only if a real alpha channel is supplied. For
11274 simple transparency, we prefer a clipping mask. */
11275 if (!transparent_p)
11276 {
11277 png_color_16 *image_background;
a05e2bae
JR
11278 Lisp_Object specified_bg
11279 = image_spec_value (img->spec, QCbackground, NULL);
11280
11281
11282 if (STRINGP (specified_bg))
11283 /* The user specified `:background', use that. */
11284 {
11285 COLORREF color;
11286 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11287 {
11288 png_color_16 user_bg;
11289
11290 bzero (&user_bg, sizeof user_bg);
11291 user_bg.red = color.red;
11292 user_bg.green = color.green;
11293 user_bg.blue = color.blue;
6fc2811b 11294
a05e2bae
JR
11295 png_set_background (png_ptr, &user_bg,
11296 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11297 }
11298 }
11299 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11300 /* Image contains a background color with which to
11301 combine the image. */
11302 png_set_background (png_ptr, image_background,
11303 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11304 else
11305 {
11306 /* Image does not contain a background color with which
11307 to combine the image data via an alpha channel. Use
11308 the frame's background instead. */
11309 XColor color;
11310 Colormap cmap;
11311 png_color_16 frame_background;
11312
a05e2bae 11313 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11314 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11315 x_query_color (f, &color);
6fc2811b
JR
11316
11317 bzero (&frame_background, sizeof frame_background);
11318 frame_background.red = color.red;
11319 frame_background.green = color.green;
11320 frame_background.blue = color.blue;
11321
11322 png_set_background (png_ptr, &frame_background,
11323 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11324 }
11325 }
11326
11327 /* Update info structure. */
11328 png_read_update_info (png_ptr, info_ptr);
11329
11330 /* Get number of channels. Valid values are 1 for grayscale images
11331 and images with a palette, 2 for grayscale images with transparency
11332 information (alpha channel), 3 for RGB images, and 4 for RGB
11333 images with alpha channel, i.e. RGBA. If conversions above were
11334 sufficient we should only have 3 or 4 channels here. */
11335 channels = png_get_channels (png_ptr, info_ptr);
11336 xassert (channels == 3 || channels == 4);
11337
11338 /* Number of bytes needed for one row of the image. */
11339 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11340
11341 /* Allocate memory for the image. */
11342 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11343 rows = (png_byte **) xmalloc (height * sizeof *rows);
11344 for (i = 0; i < height; ++i)
11345 rows[i] = pixels + i * row_bytes;
11346
11347 /* Read the entire image. */
11348 png_read_image (png_ptr, rows);
11349 png_read_end (png_ptr, info_ptr);
11350 if (fp)
11351 {
11352 fclose (fp);
11353 fp = NULL;
11354 }
11355
6fc2811b
JR
11356 /* Create the X image and pixmap. */
11357 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11358 &img->pixmap))
a05e2bae 11359 goto error;
6fc2811b
JR
11360
11361 /* Create an image and pixmap serving as mask if the PNG image
11362 contains an alpha channel. */
11363 if (channels == 4
11364 && !transparent_p
11365 && !x_create_x_image_and_pixmap (f, width, height, 1,
11366 &mask_img, &img->mask))
11367 {
11368 x_destroy_x_image (ximg);
11369 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11370 img->pixmap = 0;
6fc2811b
JR
11371 goto error;
11372 }
11373
11374 /* Fill the X image and mask from PNG data. */
11375 init_color_table ();
11376
11377 for (y = 0; y < height; ++y)
11378 {
11379 png_byte *p = rows[y];
11380
11381 for (x = 0; x < width; ++x)
11382 {
11383 unsigned r, g, b;
11384
11385 r = *p++ << 8;
11386 g = *p++ << 8;
11387 b = *p++ << 8;
11388 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11389
11390 /* An alpha channel, aka mask channel, associates variable
11391 transparency with an image. Where other image formats
11392 support binary transparency---fully transparent or fully
11393 opaque---PNG allows up to 254 levels of partial transparency.
11394 The PNG library implements partial transparency by combining
11395 the image with a specified background color.
11396
11397 I'm not sure how to handle this here nicely: because the
11398 background on which the image is displayed may change, for
11399 real alpha channel support, it would be necessary to create
11400 a new image for each possible background.
11401
11402 What I'm doing now is that a mask is created if we have
11403 boolean transparency information. Otherwise I'm using
11404 the frame's background color to combine the image with. */
11405
11406 if (channels == 4)
11407 {
11408 if (mask_img)
11409 XPutPixel (mask_img, x, y, *p > 0);
11410 ++p;
11411 }
11412 }
11413 }
11414
a05e2bae
JR
11415 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11416 /* Set IMG's background color from the PNG image, unless the user
11417 overrode it. */
11418 {
11419 png_color_16 *bg;
11420 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11421 {
11422 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11423 img->background_valid = 1;
11424 }
11425 }
11426
6fc2811b
JR
11427 /* Remember colors allocated for this image. */
11428 img->colors = colors_in_color_table (&img->ncolors);
11429 free_color_table ();
11430
11431 /* Clean up. */
11432 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11433 xfree (rows);
11434 xfree (pixels);
11435
11436 img->width = width;
11437 img->height = height;
11438
a05e2bae
JR
11439 /* Maybe fill in the background field while we have ximg handy. */
11440 IMAGE_BACKGROUND (img, f, ximg);
11441
6fc2811b
JR
11442 /* Put the image into the pixmap, then free the X image and its buffer. */
11443 x_put_x_image (f, ximg, img->pixmap, width, height);
11444 x_destroy_x_image (ximg);
11445
11446 /* Same for the mask. */
11447 if (mask_img)
11448 {
a05e2bae
JR
11449 /* Fill in the background_transparent field while we have the mask
11450 handy. */
11451 image_background_transparent (img, f, mask_img);
11452
6fc2811b
JR
11453 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11454 x_destroy_x_image (mask_img);
11455 }
11456
6fc2811b
JR
11457 UNGCPRO;
11458 return 1;
11459}
11460
11461#endif /* HAVE_PNG != 0 */
11462
11463
11464\f
11465/***********************************************************************
11466 JPEG
11467 ***********************************************************************/
11468
11469#if HAVE_JPEG
11470
11471/* Work around a warning about HAVE_STDLIB_H being redefined in
11472 jconfig.h. */
11473#ifdef HAVE_STDLIB_H
11474#define HAVE_STDLIB_H_1
11475#undef HAVE_STDLIB_H
11476#endif /* HAVE_STLIB_H */
11477
11478#include <jpeglib.h>
11479#include <jerror.h>
11480#include <setjmp.h>
11481
11482#ifdef HAVE_STLIB_H_1
11483#define HAVE_STDLIB_H 1
11484#endif
11485
11486static int jpeg_image_p P_ ((Lisp_Object object));
11487static int jpeg_load P_ ((struct frame *f, struct image *img));
11488
11489/* The symbol `jpeg' identifying images of this type. */
11490
11491Lisp_Object Qjpeg;
11492
11493/* Indices of image specification fields in gs_format, below. */
11494
11495enum jpeg_keyword_index
11496{
11497 JPEG_TYPE,
11498 JPEG_DATA,
11499 JPEG_FILE,
11500 JPEG_ASCENT,
11501 JPEG_MARGIN,
11502 JPEG_RELIEF,
11503 JPEG_ALGORITHM,
11504 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11505 JPEG_MASK,
11506 JPEG_BACKGROUND,
6fc2811b
JR
11507 JPEG_LAST
11508};
11509
11510/* Vector of image_keyword structures describing the format
11511 of valid user-defined image specifications. */
11512
11513static struct image_keyword jpeg_format[JPEG_LAST] =
11514{
11515 {":type", IMAGE_SYMBOL_VALUE, 1},
11516 {":data", IMAGE_STRING_VALUE, 0},
11517 {":file", IMAGE_STRING_VALUE, 0},
11518 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11519 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11520 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11521 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11522 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11523 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11524 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11525};
11526
11527/* Structure describing the image type `jpeg'. */
11528
11529static struct image_type jpeg_type =
11530{
11531 &Qjpeg,
11532 jpeg_image_p,
11533 jpeg_load,
11534 x_clear_image,
11535 NULL
11536};
11537
11538
11539/* Return non-zero if OBJECT is a valid JPEG image specification. */
11540
11541static int
11542jpeg_image_p (object)
11543 Lisp_Object object;
11544{
11545 struct image_keyword fmt[JPEG_LAST];
11546
11547 bcopy (jpeg_format, fmt, sizeof fmt);
11548
11549 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11550 || (fmt[JPEG_ASCENT].count
11551 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11552 return 0;
11553
11554 /* Must specify either the :data or :file keyword. */
11555 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11556}
11557
11558
11559struct my_jpeg_error_mgr
11560{
11561 struct jpeg_error_mgr pub;
11562 jmp_buf setjmp_buffer;
11563};
11564
11565static void
11566my_error_exit (cinfo)
11567 j_common_ptr cinfo;
11568{
11569 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11570 longjmp (mgr->setjmp_buffer, 1);
11571}
11572
6fc2811b
JR
11573/* Init source method for JPEG data source manager. Called by
11574 jpeg_read_header() before any data is actually read. See
11575 libjpeg.doc from the JPEG lib distribution. */
11576
11577static void
11578our_init_source (cinfo)
11579 j_decompress_ptr cinfo;
11580{
11581}
11582
11583
11584/* Fill input buffer method for JPEG data source manager. Called
11585 whenever more data is needed. We read the whole image in one step,
11586 so this only adds a fake end of input marker at the end. */
11587
11588static boolean
11589our_fill_input_buffer (cinfo)
11590 j_decompress_ptr cinfo;
11591{
11592 /* Insert a fake EOI marker. */
11593 struct jpeg_source_mgr *src = cinfo->src;
11594 static JOCTET buffer[2];
11595
11596 buffer[0] = (JOCTET) 0xFF;
11597 buffer[1] = (JOCTET) JPEG_EOI;
11598
11599 src->next_input_byte = buffer;
11600 src->bytes_in_buffer = 2;
11601 return TRUE;
11602}
11603
11604
11605/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11606 is the JPEG data source manager. */
11607
11608static void
11609our_skip_input_data (cinfo, num_bytes)
11610 j_decompress_ptr cinfo;
11611 long num_bytes;
11612{
11613 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11614
11615 if (src)
11616 {
11617 if (num_bytes > src->bytes_in_buffer)
11618 ERREXIT (cinfo, JERR_INPUT_EOF);
11619
11620 src->bytes_in_buffer -= num_bytes;
11621 src->next_input_byte += num_bytes;
11622 }
11623}
11624
11625
11626/* Method to terminate data source. Called by
11627 jpeg_finish_decompress() after all data has been processed. */
11628
11629static void
11630our_term_source (cinfo)
11631 j_decompress_ptr cinfo;
11632{
11633}
11634
11635
11636/* Set up the JPEG lib for reading an image from DATA which contains
11637 LEN bytes. CINFO is the decompression info structure created for
11638 reading the image. */
11639
11640static void
11641jpeg_memory_src (cinfo, data, len)
11642 j_decompress_ptr cinfo;
11643 JOCTET *data;
11644 unsigned int len;
11645{
11646 struct jpeg_source_mgr *src;
11647
11648 if (cinfo->src == NULL)
11649 {
11650 /* First time for this JPEG object? */
11651 cinfo->src = (struct jpeg_source_mgr *)
11652 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11653 sizeof (struct jpeg_source_mgr));
11654 src = (struct jpeg_source_mgr *) cinfo->src;
11655 src->next_input_byte = data;
11656 }
11657
11658 src = (struct jpeg_source_mgr *) cinfo->src;
11659 src->init_source = our_init_source;
11660 src->fill_input_buffer = our_fill_input_buffer;
11661 src->skip_input_data = our_skip_input_data;
11662 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
11663 src->term_source = our_term_source;
11664 src->bytes_in_buffer = len;
11665 src->next_input_byte = data;
11666}
11667
11668
11669/* Load image IMG for use on frame F. Patterned after example.c
11670 from the JPEG lib. */
11671
11672static int
11673jpeg_load (f, img)
11674 struct frame *f;
11675 struct image *img;
11676{
11677 struct jpeg_decompress_struct cinfo;
11678 struct my_jpeg_error_mgr mgr;
11679 Lisp_Object file, specified_file;
11680 Lisp_Object specified_data;
a05e2bae 11681 FILE * volatile fp = NULL;
6fc2811b
JR
11682 JSAMPARRAY buffer;
11683 int row_stride, x, y;
11684 XImage *ximg = NULL;
11685 int rc;
11686 unsigned long *colors;
11687 int width, height;
11688 struct gcpro gcpro1;
11689
11690 /* Open the JPEG file. */
11691 specified_file = image_spec_value (img->spec, QCfile, NULL);
11692 specified_data = image_spec_value (img->spec, QCdata, NULL);
11693 file = Qnil;
11694 GCPRO1 (file);
11695
6fc2811b
JR
11696 if (NILP (specified_data))
11697 {
11698 file = x_find_image_file (specified_file);
11699 if (!STRINGP (file))
11700 {
11701 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11702 UNGCPRO;
11703 return 0;
11704 }
11705
11706 fp = fopen (XSTRING (file)->data, "r");
11707 if (fp == NULL)
11708 {
11709 image_error ("Cannot open `%s'", file, Qnil);
11710 UNGCPRO;
11711 return 0;
11712 }
11713 }
11714
11715 /* Customize libjpeg's error handling to call my_error_exit when an
11716 error is detected. This function will perform a longjmp. */
6fc2811b 11717 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 11718 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
11719
11720 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
11721 {
11722 if (rc == 1)
11723 {
11724 /* Called from my_error_exit. Display a JPEG error. */
11725 char buffer[JMSG_LENGTH_MAX];
11726 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11727 image_error ("Error reading JPEG image `%s': %s", img->spec,
11728 build_string (buffer));
11729 }
11730
11731 /* Close the input file and destroy the JPEG object. */
11732 if (fp)
11733 fclose (fp);
11734 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
11735
11736 /* If we already have an XImage, free that. */
11737 x_destroy_x_image (ximg);
11738
11739 /* Free pixmap and colors. */
11740 x_clear_image (f, img);
11741
6fc2811b
JR
11742 UNGCPRO;
11743 return 0;
11744 }
11745
11746 /* Create the JPEG decompression object. Let it read from fp.
11747 Read the JPEG image header. */
11748 jpeg_create_decompress (&cinfo);
11749
11750 if (NILP (specified_data))
11751 jpeg_stdio_src (&cinfo, fp);
11752 else
11753 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
11754 STRING_BYTES (XSTRING (specified_data)));
11755
11756 jpeg_read_header (&cinfo, TRUE);
11757
11758 /* Customize decompression so that color quantization will be used.
11759 Start decompression. */
11760 cinfo.quantize_colors = TRUE;
11761 jpeg_start_decompress (&cinfo);
11762 width = img->width = cinfo.output_width;
11763 height = img->height = cinfo.output_height;
11764
6fc2811b
JR
11765 /* Create X image and pixmap. */
11766 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11767 &img->pixmap))
a05e2bae 11768 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
11769
11770 /* Allocate colors. When color quantization is used,
11771 cinfo.actual_number_of_colors has been set with the number of
11772 colors generated, and cinfo.colormap is a two-dimensional array
11773 of color indices in the range 0..cinfo.actual_number_of_colors.
11774 No more than 255 colors will be generated. */
11775 {
11776 int i, ir, ig, ib;
11777
11778 if (cinfo.out_color_components > 2)
11779 ir = 0, ig = 1, ib = 2;
11780 else if (cinfo.out_color_components > 1)
11781 ir = 0, ig = 1, ib = 0;
11782 else
11783 ir = 0, ig = 0, ib = 0;
11784
11785 /* Use the color table mechanism because it handles colors that
11786 cannot be allocated nicely. Such colors will be replaced with
11787 a default color, and we don't have to care about which colors
11788 can be freed safely, and which can't. */
11789 init_color_table ();
11790 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11791 * sizeof *colors);
11792
11793 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11794 {
11795 /* Multiply RGB values with 255 because X expects RGB values
11796 in the range 0..0xffff. */
11797 int r = cinfo.colormap[ir][i] << 8;
11798 int g = cinfo.colormap[ig][i] << 8;
11799 int b = cinfo.colormap[ib][i] << 8;
11800 colors[i] = lookup_rgb_color (f, r, g, b);
11801 }
11802
11803 /* Remember those colors actually allocated. */
11804 img->colors = colors_in_color_table (&img->ncolors);
11805 free_color_table ();
11806 }
11807
11808 /* Read pixels. */
11809 row_stride = width * cinfo.output_components;
11810 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11811 row_stride, 1);
11812 for (y = 0; y < height; ++y)
11813 {
11814 jpeg_read_scanlines (&cinfo, buffer, 1);
11815 for (x = 0; x < cinfo.output_width; ++x)
11816 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11817 }
11818
11819 /* Clean up. */
11820 jpeg_finish_decompress (&cinfo);
11821 jpeg_destroy_decompress (&cinfo);
11822 if (fp)
11823 fclose (fp);
11824
a05e2bae
JR
11825 /* Maybe fill in the background field while we have ximg handy. */
11826 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11827 IMAGE_BACKGROUND (img, f, ximg);
11828
6fc2811b
JR
11829 /* Put the image into the pixmap. */
11830 x_put_x_image (f, ximg, img->pixmap, width, height);
11831 x_destroy_x_image (ximg);
11832 UNBLOCK_INPUT;
11833 UNGCPRO;
11834 return 1;
11835}
11836
11837#endif /* HAVE_JPEG */
11838
11839
11840\f
11841/***********************************************************************
11842 TIFF
11843 ***********************************************************************/
11844
11845#if HAVE_TIFF
11846
11847#include <tiffio.h>
11848
11849static int tiff_image_p P_ ((Lisp_Object object));
11850static int tiff_load P_ ((struct frame *f, struct image *img));
11851
11852/* The symbol `tiff' identifying images of this type. */
11853
11854Lisp_Object Qtiff;
11855
11856/* Indices of image specification fields in tiff_format, below. */
11857
11858enum tiff_keyword_index
11859{
11860 TIFF_TYPE,
11861 TIFF_DATA,
11862 TIFF_FILE,
11863 TIFF_ASCENT,
11864 TIFF_MARGIN,
11865 TIFF_RELIEF,
11866 TIFF_ALGORITHM,
11867 TIFF_HEURISTIC_MASK,
a05e2bae
JR
11868 TIFF_MASK,
11869 TIFF_BACKGROUND,
6fc2811b
JR
11870 TIFF_LAST
11871};
11872
11873/* Vector of image_keyword structures describing the format
11874 of valid user-defined image specifications. */
11875
11876static struct image_keyword tiff_format[TIFF_LAST] =
11877{
11878 {":type", IMAGE_SYMBOL_VALUE, 1},
11879 {":data", IMAGE_STRING_VALUE, 0},
11880 {":file", IMAGE_STRING_VALUE, 0},
11881 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11882 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11883 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11884 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11885 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11886 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11887 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11888};
11889
11890/* Structure describing the image type `tiff'. */
11891
11892static struct image_type tiff_type =
11893{
11894 &Qtiff,
11895 tiff_image_p,
11896 tiff_load,
11897 x_clear_image,
11898 NULL
11899};
11900
11901
11902/* Return non-zero if OBJECT is a valid TIFF image specification. */
11903
11904static int
11905tiff_image_p (object)
11906 Lisp_Object object;
11907{
11908 struct image_keyword fmt[TIFF_LAST];
11909 bcopy (tiff_format, fmt, sizeof fmt);
11910
11911 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11912 || (fmt[TIFF_ASCENT].count
11913 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11914 return 0;
11915
11916 /* Must specify either the :data or :file keyword. */
11917 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11918}
11919
11920
11921/* Reading from a memory buffer for TIFF images Based on the PNG
11922 memory source, but we have to provide a lot of extra functions.
11923 Blah.
11924
11925 We really only need to implement read and seek, but I am not
11926 convinced that the TIFF library is smart enough not to destroy
11927 itself if we only hand it the function pointers we need to
11928 override. */
11929
11930typedef struct
11931{
11932 unsigned char *bytes;
11933 size_t len;
11934 int index;
11935}
11936tiff_memory_source;
11937
11938static size_t
11939tiff_read_from_memory (data, buf, size)
11940 thandle_t data;
11941 tdata_t buf;
11942 tsize_t size;
11943{
11944 tiff_memory_source *src = (tiff_memory_source *) data;
11945
11946 if (size > src->len - src->index)
11947 return (size_t) -1;
11948 bcopy (src->bytes + src->index, buf, size);
11949 src->index += size;
11950 return size;
11951}
11952
11953static size_t
11954tiff_write_from_memory (data, buf, size)
11955 thandle_t data;
11956 tdata_t buf;
11957 tsize_t size;
11958{
11959 return (size_t) -1;
11960}
11961
11962static toff_t
11963tiff_seek_in_memory (data, off, whence)
11964 thandle_t data;
11965 toff_t off;
11966 int whence;
11967{
11968 tiff_memory_source *src = (tiff_memory_source *) data;
11969 int idx;
11970
11971 switch (whence)
11972 {
11973 case SEEK_SET: /* Go from beginning of source. */
11974 idx = off;
11975 break;
11976
11977 case SEEK_END: /* Go from end of source. */
11978 idx = src->len + off;
11979 break;
11980
11981 case SEEK_CUR: /* Go from current position. */
11982 idx = src->index + off;
11983 break;
11984
11985 default: /* Invalid `whence'. */
11986 return -1;
11987 }
11988
11989 if (idx > src->len || idx < 0)
11990 return -1;
11991
11992 src->index = idx;
11993 return src->index;
11994}
11995
11996static int
11997tiff_close_memory (data)
11998 thandle_t data;
11999{
12000 /* NOOP */
12001 return 0;
12002}
12003
12004static int
12005tiff_mmap_memory (data, pbase, psize)
12006 thandle_t data;
12007 tdata_t *pbase;
12008 toff_t *psize;
12009{
12010 /* It is already _IN_ memory. */
12011 return 0;
12012}
12013
12014static void
12015tiff_unmap_memory (data, base, size)
12016 thandle_t data;
12017 tdata_t base;
12018 toff_t size;
12019{
12020 /* We don't need to do this. */
12021}
12022
12023static toff_t
12024tiff_size_of_memory (data)
12025 thandle_t data;
12026{
12027 return ((tiff_memory_source *) data)->len;
12028}
12029
3cf3436e
JR
12030
12031static void
12032tiff_error_handler (title, format, ap)
12033 const char *title, *format;
12034 va_list ap;
12035{
12036 char buf[512];
12037 int len;
12038
12039 len = sprintf (buf, "TIFF error: %s ", title);
12040 vsprintf (buf + len, format, ap);
12041 add_to_log (buf, Qnil, Qnil);
12042}
12043
12044
12045static void
12046tiff_warning_handler (title, format, ap)
12047 const char *title, *format;
12048 va_list ap;
12049{
12050 char buf[512];
12051 int len;
12052
12053 len = sprintf (buf, "TIFF warning: %s ", title);
12054 vsprintf (buf + len, format, ap);
12055 add_to_log (buf, Qnil, Qnil);
12056}
12057
12058
6fc2811b
JR
12059/* Load TIFF image IMG for use on frame F. Value is non-zero if
12060 successful. */
12061
12062static int
12063tiff_load (f, img)
12064 struct frame *f;
12065 struct image *img;
12066{
12067 Lisp_Object file, specified_file;
12068 Lisp_Object specified_data;
12069 TIFF *tiff;
12070 int width, height, x, y;
12071 uint32 *buf;
12072 int rc;
12073 XImage *ximg;
12074 struct gcpro gcpro1;
12075 tiff_memory_source memsrc;
12076
12077 specified_file = image_spec_value (img->spec, QCfile, NULL);
12078 specified_data = image_spec_value (img->spec, QCdata, NULL);
12079 file = Qnil;
12080 GCPRO1 (file);
12081
3cf3436e
JR
12082 TIFFSetErrorHandler (tiff_error_handler);
12083 TIFFSetWarningHandler (tiff_warning_handler);
12084
6fc2811b
JR
12085 if (NILP (specified_data))
12086 {
12087 /* Read from a file */
12088 file = x_find_image_file (specified_file);
12089 if (!STRINGP (file))
3cf3436e
JR
12090 {
12091 image_error ("Cannot find image file `%s'", file, Qnil);
12092 UNGCPRO;
12093 return 0;
12094 }
12095
6fc2811b
JR
12096 /* Try to open the image file. */
12097 tiff = TIFFOpen (XSTRING (file)->data, "r");
12098 if (tiff == NULL)
3cf3436e
JR
12099 {
12100 image_error ("Cannot open `%s'", file, Qnil);
12101 UNGCPRO;
12102 return 0;
12103 }
6fc2811b
JR
12104 }
12105 else
12106 {
12107 /* Memory source! */
12108 memsrc.bytes = XSTRING (specified_data)->data;
12109 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12110 memsrc.index = 0;
12111
12112 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12113 (TIFFReadWriteProc) tiff_read_from_memory,
12114 (TIFFReadWriteProc) tiff_write_from_memory,
12115 tiff_seek_in_memory,
12116 tiff_close_memory,
12117 tiff_size_of_memory,
12118 tiff_mmap_memory,
12119 tiff_unmap_memory);
12120
12121 if (!tiff)
12122 {
12123 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12124 UNGCPRO;
12125 return 0;
12126 }
12127 }
12128
12129 /* Get width and height of the image, and allocate a raster buffer
12130 of width x height 32-bit values. */
12131 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12132 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12133 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12134
12135 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12136 TIFFClose (tiff);
12137 if (!rc)
12138 {
12139 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12140 xfree (buf);
12141 UNGCPRO;
12142 return 0;
12143 }
12144
6fc2811b
JR
12145 /* Create the X image and pixmap. */
12146 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12147 {
6fc2811b
JR
12148 xfree (buf);
12149 UNGCPRO;
12150 return 0;
12151 }
12152
12153 /* Initialize the color table. */
12154 init_color_table ();
12155
12156 /* Process the pixel raster. Origin is in the lower-left corner. */
12157 for (y = 0; y < height; ++y)
12158 {
12159 uint32 *row = buf + y * width;
12160
12161 for (x = 0; x < width; ++x)
12162 {
12163 uint32 abgr = row[x];
12164 int r = TIFFGetR (abgr) << 8;
12165 int g = TIFFGetG (abgr) << 8;
12166 int b = TIFFGetB (abgr) << 8;
12167 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12168 }
12169 }
12170
12171 /* Remember the colors allocated for the image. Free the color table. */
12172 img->colors = colors_in_color_table (&img->ncolors);
12173 free_color_table ();
12174
a05e2bae
JR
12175 img->width = width;
12176 img->height = height;
12177
12178 /* Maybe fill in the background field while we have ximg handy. */
12179 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12180 IMAGE_BACKGROUND (img, f, ximg);
12181
6fc2811b
JR
12182 /* Put the image into the pixmap, then free the X image and its buffer. */
12183 x_put_x_image (f, ximg, img->pixmap, width, height);
12184 x_destroy_x_image (ximg);
12185 xfree (buf);
6fc2811b
JR
12186
12187 UNGCPRO;
12188 return 1;
12189}
12190
12191#endif /* HAVE_TIFF != 0 */
12192
12193
12194\f
12195/***********************************************************************
12196 GIF
12197 ***********************************************************************/
12198
12199#if HAVE_GIF
12200
12201#include <gif_lib.h>
12202
12203static int gif_image_p P_ ((Lisp_Object object));
12204static int gif_load P_ ((struct frame *f, struct image *img));
12205
12206/* The symbol `gif' identifying images of this type. */
12207
12208Lisp_Object Qgif;
12209
12210/* Indices of image specification fields in gif_format, below. */
12211
12212enum gif_keyword_index
12213{
12214 GIF_TYPE,
12215 GIF_DATA,
12216 GIF_FILE,
12217 GIF_ASCENT,
12218 GIF_MARGIN,
12219 GIF_RELIEF,
12220 GIF_ALGORITHM,
12221 GIF_HEURISTIC_MASK,
a05e2bae 12222 GIF_MASK,
6fc2811b 12223 GIF_IMAGE,
a05e2bae 12224 GIF_BACKGROUND,
6fc2811b
JR
12225 GIF_LAST
12226};
12227
12228/* Vector of image_keyword structures describing the format
12229 of valid user-defined image specifications. */
12230
12231static struct image_keyword gif_format[GIF_LAST] =
12232{
12233 {":type", IMAGE_SYMBOL_VALUE, 1},
12234 {":data", IMAGE_STRING_VALUE, 0},
12235 {":file", IMAGE_STRING_VALUE, 0},
12236 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12237 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12238 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12239 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12240 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12241 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12242 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12243 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12244};
12245
12246/* Structure describing the image type `gif'. */
12247
12248static struct image_type gif_type =
12249{
12250 &Qgif,
12251 gif_image_p,
12252 gif_load,
12253 x_clear_image,
12254 NULL
12255};
12256
12257/* Return non-zero if OBJECT is a valid GIF image specification. */
12258
12259static int
12260gif_image_p (object)
12261 Lisp_Object object;
12262{
12263 struct image_keyword fmt[GIF_LAST];
12264 bcopy (gif_format, fmt, sizeof fmt);
12265
12266 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12267 || (fmt[GIF_ASCENT].count
12268 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12269 return 0;
12270
12271 /* Must specify either the :data or :file keyword. */
12272 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12273}
12274
12275/* Reading a GIF image from memory
12276 Based on the PNG memory stuff to a certain extent. */
12277
12278typedef struct
12279{
12280 unsigned char *bytes;
12281 size_t len;
12282 int index;
12283}
12284gif_memory_source;
12285
12286/* Make the current memory source available to gif_read_from_memory.
12287 It's done this way because not all versions of libungif support
12288 a UserData field in the GifFileType structure. */
12289static gif_memory_source *current_gif_memory_src;
12290
12291static int
12292gif_read_from_memory (file, buf, len)
12293 GifFileType *file;
12294 GifByteType *buf;
12295 int len;
12296{
12297 gif_memory_source *src = current_gif_memory_src;
12298
12299 if (len > src->len - src->index)
12300 return -1;
12301
12302 bcopy (src->bytes + src->index, buf, len);
12303 src->index += len;
12304 return len;
12305}
12306
12307
12308/* Load GIF image IMG for use on frame F. Value is non-zero if
12309 successful. */
12310
12311static int
12312gif_load (f, img)
12313 struct frame *f;
12314 struct image *img;
12315{
12316 Lisp_Object file, specified_file;
12317 Lisp_Object specified_data;
12318 int rc, width, height, x, y, i;
12319 XImage *ximg;
12320 ColorMapObject *gif_color_map;
12321 unsigned long pixel_colors[256];
12322 GifFileType *gif;
12323 struct gcpro gcpro1;
12324 Lisp_Object image;
12325 int ino, image_left, image_top, image_width, image_height;
12326 gif_memory_source memsrc;
12327 unsigned char *raster;
12328
12329 specified_file = image_spec_value (img->spec, QCfile, NULL);
12330 specified_data = image_spec_value (img->spec, QCdata, NULL);
12331 file = Qnil;
dfff8a69 12332 GCPRO1 (file);
6fc2811b
JR
12333
12334 if (NILP (specified_data))
12335 {
12336 file = x_find_image_file (specified_file);
6fc2811b
JR
12337 if (!STRINGP (file))
12338 {
12339 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12340 UNGCPRO;
12341 return 0;
12342 }
12343
12344 /* Open the GIF file. */
12345 gif = DGifOpenFileName (XSTRING (file)->data);
12346 if (gif == NULL)
12347 {
12348 image_error ("Cannot open `%s'", file, Qnil);
12349 UNGCPRO;
12350 return 0;
12351 }
12352 }
12353 else
12354 {
12355 /* Read from memory! */
12356 current_gif_memory_src = &memsrc;
12357 memsrc.bytes = XSTRING (specified_data)->data;
12358 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12359 memsrc.index = 0;
12360
12361 gif = DGifOpen(&memsrc, gif_read_from_memory);
12362 if (!gif)
12363 {
12364 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12365 UNGCPRO;
12366 return 0;
12367 }
12368 }
12369
12370 /* Read entire contents. */
12371 rc = DGifSlurp (gif);
12372 if (rc == GIF_ERROR)
12373 {
12374 image_error ("Error reading `%s'", img->spec, Qnil);
12375 DGifCloseFile (gif);
12376 UNGCPRO;
12377 return 0;
12378 }
12379
12380 image = image_spec_value (img->spec, QCindex, NULL);
12381 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12382 if (ino >= gif->ImageCount)
12383 {
12384 image_error ("Invalid image number `%s' in image `%s'",
12385 image, img->spec);
12386 DGifCloseFile (gif);
12387 UNGCPRO;
12388 return 0;
12389 }
12390
12391 width = img->width = gif->SWidth;
12392 height = img->height = gif->SHeight;
12393
6fc2811b
JR
12394 /* Create the X image and pixmap. */
12395 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12396 {
6fc2811b
JR
12397 DGifCloseFile (gif);
12398 UNGCPRO;
12399 return 0;
12400 }
12401
12402 /* Allocate colors. */
12403 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12404 if (!gif_color_map)
12405 gif_color_map = gif->SColorMap;
12406 init_color_table ();
12407 bzero (pixel_colors, sizeof pixel_colors);
12408
12409 for (i = 0; i < gif_color_map->ColorCount; ++i)
12410 {
12411 int r = gif_color_map->Colors[i].Red << 8;
12412 int g = gif_color_map->Colors[i].Green << 8;
12413 int b = gif_color_map->Colors[i].Blue << 8;
12414 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12415 }
12416
12417 img->colors = colors_in_color_table (&img->ncolors);
12418 free_color_table ();
12419
12420 /* Clear the part of the screen image that are not covered by
12421 the image from the GIF file. Full animated GIF support
12422 requires more than can be done here (see the gif89 spec,
12423 disposal methods). Let's simply assume that the part
12424 not covered by a sub-image is in the frame's background color. */
12425 image_top = gif->SavedImages[ino].ImageDesc.Top;
12426 image_left = gif->SavedImages[ino].ImageDesc.Left;
12427 image_width = gif->SavedImages[ino].ImageDesc.Width;
12428 image_height = gif->SavedImages[ino].ImageDesc.Height;
12429
12430 for (y = 0; y < image_top; ++y)
12431 for (x = 0; x < width; ++x)
12432 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12433
12434 for (y = image_top + image_height; y < height; ++y)
12435 for (x = 0; x < width; ++x)
12436 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12437
12438 for (y = image_top; y < image_top + image_height; ++y)
12439 {
12440 for (x = 0; x < image_left; ++x)
12441 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12442 for (x = image_left + image_width; x < width; ++x)
12443 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12444 }
12445
12446 /* Read the GIF image into the X image. We use a local variable
12447 `raster' here because RasterBits below is a char *, and invites
12448 problems with bytes >= 0x80. */
12449 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12450
12451 if (gif->SavedImages[ino].ImageDesc.Interlace)
12452 {
12453 static int interlace_start[] = {0, 4, 2, 1};
12454 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12455 int pass;
6fc2811b
JR
12456 int row = interlace_start[0];
12457
12458 pass = 0;
12459
12460 for (y = 0; y < image_height; y++)
12461 {
12462 if (row >= image_height)
12463 {
12464 row = interlace_start[++pass];
12465 while (row >= image_height)
12466 row = interlace_start[++pass];
12467 }
12468
12469 for (x = 0; x < image_width; x++)
12470 {
12471 int i = raster[(y * image_width) + x];
12472 XPutPixel (ximg, x + image_left, row + image_top,
12473 pixel_colors[i]);
12474 }
12475
12476 row += interlace_increment[pass];
12477 }
12478 }
12479 else
12480 {
12481 for (y = 0; y < image_height; ++y)
12482 for (x = 0; x < image_width; ++x)
12483 {
12484 int i = raster[y* image_width + x];
12485 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12486 }
12487 }
12488
12489 DGifCloseFile (gif);
a05e2bae
JR
12490
12491 /* Maybe fill in the background field while we have ximg handy. */
12492 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12493 IMAGE_BACKGROUND (img, f, ximg);
12494
6fc2811b
JR
12495 /* Put the image into the pixmap, then free the X image and its buffer. */
12496 x_put_x_image (f, ximg, img->pixmap, width, height);
12497 x_destroy_x_image (ximg);
6fc2811b
JR
12498
12499 UNGCPRO;
12500 return 1;
12501}
12502
12503#endif /* HAVE_GIF != 0 */
12504
12505
12506\f
12507/***********************************************************************
12508 Ghostscript
12509 ***********************************************************************/
12510
3cf3436e
JR
12511Lisp_Object Qpostscript;
12512
6fc2811b
JR
12513#ifdef HAVE_GHOSTSCRIPT
12514static int gs_image_p P_ ((Lisp_Object object));
12515static int gs_load P_ ((struct frame *f, struct image *img));
12516static void gs_clear_image P_ ((struct frame *f, struct image *img));
12517
12518/* The symbol `postscript' identifying images of this type. */
12519
6fc2811b
JR
12520/* Keyword symbols. */
12521
12522Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12523
12524/* Indices of image specification fields in gs_format, below. */
12525
12526enum gs_keyword_index
12527{
12528 GS_TYPE,
12529 GS_PT_WIDTH,
12530 GS_PT_HEIGHT,
12531 GS_FILE,
12532 GS_LOADER,
12533 GS_BOUNDING_BOX,
12534 GS_ASCENT,
12535 GS_MARGIN,
12536 GS_RELIEF,
12537 GS_ALGORITHM,
12538 GS_HEURISTIC_MASK,
a05e2bae
JR
12539 GS_MASK,
12540 GS_BACKGROUND,
6fc2811b
JR
12541 GS_LAST
12542};
12543
12544/* Vector of image_keyword structures describing the format
12545 of valid user-defined image specifications. */
12546
12547static struct image_keyword gs_format[GS_LAST] =
12548{
12549 {":type", IMAGE_SYMBOL_VALUE, 1},
12550 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12551 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12552 {":file", IMAGE_STRING_VALUE, 1},
12553 {":loader", IMAGE_FUNCTION_VALUE, 0},
12554 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12555 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12556 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12557 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12558 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12559 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12560 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12561 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12562};
12563
12564/* Structure describing the image type `ghostscript'. */
12565
12566static struct image_type gs_type =
12567{
12568 &Qpostscript,
12569 gs_image_p,
12570 gs_load,
12571 gs_clear_image,
12572 NULL
12573};
12574
12575
12576/* Free X resources of Ghostscript image IMG which is used on frame F. */
12577
12578static void
12579gs_clear_image (f, img)
12580 struct frame *f;
12581 struct image *img;
12582{
12583 /* IMG->data.ptr_val may contain a recorded colormap. */
12584 xfree (img->data.ptr_val);
12585 x_clear_image (f, img);
12586}
12587
12588
12589/* Return non-zero if OBJECT is a valid Ghostscript image
12590 specification. */
12591
12592static int
12593gs_image_p (object)
12594 Lisp_Object object;
12595{
12596 struct image_keyword fmt[GS_LAST];
12597 Lisp_Object tem;
12598 int i;
12599
12600 bcopy (gs_format, fmt, sizeof fmt);
12601
12602 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
12603 || (fmt[GS_ASCENT].count
12604 && XFASTINT (fmt[GS_ASCENT].value) > 100))
12605 return 0;
12606
12607 /* Bounding box must be a list or vector containing 4 integers. */
12608 tem = fmt[GS_BOUNDING_BOX].value;
12609 if (CONSP (tem))
12610 {
12611 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12612 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12613 return 0;
12614 if (!NILP (tem))
12615 return 0;
12616 }
12617 else if (VECTORP (tem))
12618 {
12619 if (XVECTOR (tem)->size != 4)
12620 return 0;
12621 for (i = 0; i < 4; ++i)
12622 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12623 return 0;
12624 }
12625 else
12626 return 0;
12627
12628 return 1;
12629}
12630
12631
12632/* Load Ghostscript image IMG for use on frame F. Value is non-zero
12633 if successful. */
12634
12635static int
12636gs_load (f, img)
12637 struct frame *f;
12638 struct image *img;
12639{
12640 char buffer[100];
12641 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12642 struct gcpro gcpro1, gcpro2;
12643 Lisp_Object frame;
12644 double in_width, in_height;
12645 Lisp_Object pixel_colors = Qnil;
12646
12647 /* Compute pixel size of pixmap needed from the given size in the
12648 image specification. Sizes in the specification are in pt. 1 pt
12649 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12650 info. */
12651 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12652 in_width = XFASTINT (pt_width) / 72.0;
12653 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12654 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12655 in_height = XFASTINT (pt_height) / 72.0;
12656 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12657
12658 /* Create the pixmap. */
12659 BLOCK_INPUT;
12660 xassert (img->pixmap == 0);
12661 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12662 img->width, img->height,
a05e2bae 12663 one_w32_display_info.n_cbits);
6fc2811b
JR
12664 UNBLOCK_INPUT;
12665
12666 if (!img->pixmap)
12667 {
12668 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12669 return 0;
12670 }
12671
12672 /* Call the loader to fill the pixmap. It returns a process object
12673 if successful. We do not record_unwind_protect here because
12674 other places in redisplay like calling window scroll functions
12675 don't either. Let the Lisp loader use `unwind-protect' instead. */
12676 GCPRO2 (window_and_pixmap_id, pixel_colors);
12677
12678 sprintf (buffer, "%lu %lu",
12679 (unsigned long) FRAME_W32_WINDOW (f),
12680 (unsigned long) img->pixmap);
12681 window_and_pixmap_id = build_string (buffer);
12682
12683 sprintf (buffer, "%lu %lu",
12684 FRAME_FOREGROUND_PIXEL (f),
12685 FRAME_BACKGROUND_PIXEL (f));
12686 pixel_colors = build_string (buffer);
12687
12688 XSETFRAME (frame, f);
12689 loader = image_spec_value (img->spec, QCloader, NULL);
12690 if (NILP (loader))
12691 loader = intern ("gs-load-image");
12692
12693 img->data.lisp_val = call6 (loader, frame, img->spec,
12694 make_number (img->width),
12695 make_number (img->height),
12696 window_and_pixmap_id,
12697 pixel_colors);
12698 UNGCPRO;
12699 return PROCESSP (img->data.lisp_val);
12700}
12701
12702
12703/* Kill the Ghostscript process that was started to fill PIXMAP on
12704 frame F. Called from XTread_socket when receiving an event
12705 telling Emacs that Ghostscript has finished drawing. */
12706
12707void
12708x_kill_gs_process (pixmap, f)
12709 Pixmap pixmap;
12710 struct frame *f;
12711{
12712 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
12713 int class, i;
12714 struct image *img;
12715
12716 /* Find the image containing PIXMAP. */
12717 for (i = 0; i < c->used; ++i)
12718 if (c->images[i]->pixmap == pixmap)
12719 break;
12720
3cf3436e
JR
12721 /* Should someone in between have cleared the image cache, for
12722 instance, give up. */
12723 if (i == c->used)
12724 return;
12725
6fc2811b
JR
12726 /* Kill the GS process. We should have found PIXMAP in the image
12727 cache and its image should contain a process object. */
6fc2811b
JR
12728 img = c->images[i];
12729 xassert (PROCESSP (img->data.lisp_val));
12730 Fkill_process (img->data.lisp_val, Qnil);
12731 img->data.lisp_val = Qnil;
12732
12733 /* On displays with a mutable colormap, figure out the colors
12734 allocated for the image by looking at the pixels of an XImage for
12735 img->pixmap. */
12736 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
12737 if (class != StaticColor && class != StaticGray && class != TrueColor)
12738 {
12739 XImage *ximg;
12740
12741 BLOCK_INPUT;
12742
12743 /* Try to get an XImage for img->pixmep. */
12744 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
12745 0, 0, img->width, img->height, ~0, ZPixmap);
12746 if (ximg)
12747 {
12748 int x, y;
12749
12750 /* Initialize the color table. */
12751 init_color_table ();
12752
12753 /* For each pixel of the image, look its color up in the
12754 color table. After having done so, the color table will
12755 contain an entry for each color used by the image. */
12756 for (y = 0; y < img->height; ++y)
12757 for (x = 0; x < img->width; ++x)
12758 {
12759 unsigned long pixel = XGetPixel (ximg, x, y);
12760 lookup_pixel_color (f, pixel);
12761 }
12762
12763 /* Record colors in the image. Free color table and XImage. */
12764 img->colors = colors_in_color_table (&img->ncolors);
12765 free_color_table ();
12766 XDestroyImage (ximg);
12767
12768#if 0 /* This doesn't seem to be the case. If we free the colors
12769 here, we get a BadAccess later in x_clear_image when
12770 freeing the colors. */
12771 /* We have allocated colors once, but Ghostscript has also
12772 allocated colors on behalf of us. So, to get the
12773 reference counts right, free them once. */
12774 if (img->ncolors)
3cf3436e 12775 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 12776 img->colors, img->ncolors, 0);
6fc2811b
JR
12777#endif
12778 }
12779 else
12780 image_error ("Cannot get X image of `%s'; colors will not be freed",
12781 img->spec, Qnil);
12782
12783 UNBLOCK_INPUT;
12784 }
3cf3436e
JR
12785
12786 /* Now that we have the pixmap, compute mask and transform the
12787 image if requested. */
12788 BLOCK_INPUT;
12789 postprocess_image (f, img);
12790 UNBLOCK_INPUT;
6fc2811b
JR
12791}
12792
12793#endif /* HAVE_GHOSTSCRIPT */
12794
12795\f
12796/***********************************************************************
12797 Window properties
12798 ***********************************************************************/
12799
12800DEFUN ("x-change-window-property", Fx_change_window_property,
12801 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
12802 doc: /* Change window property PROP to VALUE on the X window of FRAME.
12803PROP and VALUE must be strings. FRAME nil or omitted means use the
12804selected frame. Value is VALUE. */)
6fc2811b
JR
12805 (prop, value, frame)
12806 Lisp_Object frame, prop, value;
12807{
767b1ff0 12808#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12809 struct frame *f = check_x_frame (frame);
12810 Atom prop_atom;
12811
b7826503
PJ
12812 CHECK_STRING (prop);
12813 CHECK_STRING (value);
6fc2811b
JR
12814
12815 BLOCK_INPUT;
12816 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12817 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12818 prop_atom, XA_STRING, 8, PropModeReplace,
12819 XSTRING (value)->data, XSTRING (value)->size);
12820
12821 /* Make sure the property is set when we return. */
12822 XFlush (FRAME_W32_DISPLAY (f));
12823 UNBLOCK_INPUT;
12824
767b1ff0 12825#endif /* TODO */
6fc2811b
JR
12826
12827 return value;
12828}
12829
12830
12831DEFUN ("x-delete-window-property", Fx_delete_window_property,
12832 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
12833 doc: /* Remove window property PROP from X window of FRAME.
12834FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
12835 (prop, frame)
12836 Lisp_Object prop, frame;
12837{
767b1ff0 12838#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12839
12840 struct frame *f = check_x_frame (frame);
12841 Atom prop_atom;
12842
b7826503 12843 CHECK_STRING (prop);
6fc2811b
JR
12844 BLOCK_INPUT;
12845 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12846 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12847
12848 /* Make sure the property is removed when we return. */
12849 XFlush (FRAME_W32_DISPLAY (f));
12850 UNBLOCK_INPUT;
767b1ff0 12851#endif /* TODO */
6fc2811b
JR
12852
12853 return prop;
12854}
12855
12856
12857DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12858 1, 2, 0,
74e1aeec
JR
12859 doc: /* Value is the value of window property PROP on FRAME.
12860If FRAME is nil or omitted, use the selected frame. Value is nil
12861if FRAME hasn't a property with name PROP or if PROP has no string
12862value. */)
6fc2811b
JR
12863 (prop, frame)
12864 Lisp_Object prop, frame;
12865{
767b1ff0 12866#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12867
12868 struct frame *f = check_x_frame (frame);
12869 Atom prop_atom;
12870 int rc;
12871 Lisp_Object prop_value = Qnil;
12872 char *tmp_data = NULL;
12873 Atom actual_type;
12874 int actual_format;
12875 unsigned long actual_size, bytes_remaining;
12876
b7826503 12877 CHECK_STRING (prop);
6fc2811b
JR
12878 BLOCK_INPUT;
12879 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12880 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12881 prop_atom, 0, 0, False, XA_STRING,
12882 &actual_type, &actual_format, &actual_size,
12883 &bytes_remaining, (unsigned char **) &tmp_data);
12884 if (rc == Success)
12885 {
12886 int size = bytes_remaining;
12887
12888 XFree (tmp_data);
12889 tmp_data = NULL;
12890
12891 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12892 prop_atom, 0, bytes_remaining,
12893 False, XA_STRING,
12894 &actual_type, &actual_format,
12895 &actual_size, &bytes_remaining,
12896 (unsigned char **) &tmp_data);
12897 if (rc == Success)
12898 prop_value = make_string (tmp_data, size);
12899
12900 XFree (tmp_data);
12901 }
12902
12903 UNBLOCK_INPUT;
12904
12905 return prop_value;
12906
767b1ff0 12907#endif /* TODO */
6fc2811b
JR
12908 return Qnil;
12909}
12910
12911
12912\f
12913/***********************************************************************
12914 Busy cursor
12915 ***********************************************************************/
12916
f79e6790 12917/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 12918 an hourglass cursor on all frames. */
6fc2811b 12919
0af913d7 12920static struct atimer *hourglass_atimer;
6fc2811b 12921
0af913d7 12922/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 12923
0af913d7 12924static int hourglass_shown_p;
6fc2811b 12925
0af913d7 12926/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 12927
0af913d7 12928static Lisp_Object Vhourglass_delay;
6fc2811b 12929
0af913d7 12930/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
12931 cursor. */
12932
0af913d7 12933#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
12934
12935/* Function prototypes. */
12936
0af913d7
GM
12937static void show_hourglass P_ ((struct atimer *));
12938static void hide_hourglass P_ ((void));
f79e6790
JR
12939
12940
0af913d7 12941/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
12942
12943void
0af913d7 12944start_hourglass ()
f79e6790 12945{
767b1ff0 12946#if 0 /* TODO: cursor shape changes. */
f79e6790 12947 EMACS_TIME delay;
dfff8a69 12948 int secs, usecs = 0;
f79e6790 12949
0af913d7 12950 cancel_hourglass ();
f79e6790 12951
0af913d7
GM
12952 if (INTEGERP (Vhourglass_delay)
12953 && XINT (Vhourglass_delay) > 0)
12954 secs = XFASTINT (Vhourglass_delay);
12955 else if (FLOATP (Vhourglass_delay)
12956 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
12957 {
12958 Lisp_Object tem;
0af913d7 12959 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 12960 secs = XFASTINT (tem);
0af913d7 12961 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 12962 }
f79e6790 12963 else
0af913d7 12964 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 12965
dfff8a69 12966 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
12967 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
12968 show_hourglass, NULL);
f79e6790
JR
12969#endif
12970}
12971
12972
0af913d7
GM
12973/* Cancel the hourglass cursor timer if active, hide an hourglass
12974 cursor if shown. */
f79e6790
JR
12975
12976void
0af913d7 12977cancel_hourglass ()
f79e6790 12978{
0af913d7 12979 if (hourglass_atimer)
dfff8a69 12980 {
0af913d7
GM
12981 cancel_atimer (hourglass_atimer);
12982 hourglass_atimer = NULL;
dfff8a69
JR
12983 }
12984
0af913d7
GM
12985 if (hourglass_shown_p)
12986 hide_hourglass ();
f79e6790
JR
12987}
12988
12989
0af913d7
GM
12990/* Timer function of hourglass_atimer. TIMER is equal to
12991 hourglass_atimer.
f79e6790 12992
0af913d7
GM
12993 Display an hourglass cursor on all frames by mapping the frames'
12994 hourglass_window. Set the hourglass_p flag in the frames'
12995 output_data.x structure to indicate that an hourglass cursor is
12996 shown on the frames. */
f79e6790
JR
12997
12998static void
0af913d7 12999show_hourglass (timer)
f79e6790 13000 struct atimer *timer;
6fc2811b 13001{
767b1ff0 13002#if 0 /* TODO: cursor shape changes. */
f79e6790 13003 /* The timer implementation will cancel this timer automatically
0af913d7 13004 after this function has run. Set hourglass_atimer to null
f79e6790 13005 so that we know the timer doesn't have to be canceled. */
0af913d7 13006 hourglass_atimer = NULL;
f79e6790 13007
0af913d7 13008 if (!hourglass_shown_p)
6fc2811b
JR
13009 {
13010 Lisp_Object rest, frame;
f79e6790
JR
13011
13012 BLOCK_INPUT;
13013
6fc2811b 13014 FOR_EACH_FRAME (rest, frame)
dc220243 13015 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13016 {
13017 struct frame *f = XFRAME (frame);
f79e6790 13018
0af913d7 13019 f->output_data.w32->hourglass_p = 1;
f79e6790 13020
0af913d7 13021 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13022 {
13023 unsigned long mask = CWCursor;
13024 XSetWindowAttributes attrs;
f79e6790 13025
0af913d7 13026 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13027
0af913d7 13028 f->output_data.w32->hourglass_window
f79e6790 13029 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13030 FRAME_OUTER_WINDOW (f),
13031 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13032 InputOnly,
13033 CopyFromParent,
6fc2811b
JR
13034 mask, &attrs);
13035 }
f79e6790 13036
0af913d7
GM
13037 XMapRaised (FRAME_X_DISPLAY (f),
13038 f->output_data.w32->hourglass_window);
f79e6790 13039 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13040 }
6fc2811b 13041
0af913d7 13042 hourglass_shown_p = 1;
f79e6790
JR
13043 UNBLOCK_INPUT;
13044 }
13045#endif
6fc2811b
JR
13046}
13047
13048
0af913d7 13049/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13050
f79e6790 13051static void
0af913d7 13052hide_hourglass ()
f79e6790 13053{
767b1ff0 13054#if 0 /* TODO: cursor shape changes. */
0af913d7 13055 if (hourglass_shown_p)
6fc2811b 13056 {
f79e6790
JR
13057 Lisp_Object rest, frame;
13058
13059 BLOCK_INPUT;
13060 FOR_EACH_FRAME (rest, frame)
6fc2811b 13061 {
f79e6790
JR
13062 struct frame *f = XFRAME (frame);
13063
dc220243 13064 if (FRAME_W32_P (f)
f79e6790 13065 /* Watch out for newly created frames. */
0af913d7 13066 && f->output_data.x->hourglass_window)
f79e6790 13067 {
0af913d7
GM
13068 XUnmapWindow (FRAME_X_DISPLAY (f),
13069 f->output_data.x->hourglass_window);
13070 /* Sync here because XTread_socket looks at the
13071 hourglass_p flag that is reset to zero below. */
f79e6790 13072 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13073 f->output_data.x->hourglass_p = 0;
f79e6790 13074 }
6fc2811b 13075 }
6fc2811b 13076
0af913d7 13077 hourglass_shown_p = 0;
f79e6790
JR
13078 UNBLOCK_INPUT;
13079 }
13080#endif
6fc2811b
JR
13081}
13082
13083
13084\f
13085/***********************************************************************
13086 Tool tips
13087 ***********************************************************************/
13088
13089static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13090 Lisp_Object, Lisp_Object));
13091static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13092 Lisp_Object, int, int, int *, int *));
6fc2811b 13093
3cf3436e 13094/* The frame of a currently visible tooltip. */
6fc2811b 13095
937e601e 13096Lisp_Object tip_frame;
6fc2811b
JR
13097
13098/* If non-nil, a timer started that hides the last tooltip when it
13099 fires. */
13100
13101Lisp_Object tip_timer;
13102Window tip_window;
13103
3cf3436e
JR
13104/* If non-nil, a vector of 3 elements containing the last args
13105 with which x-show-tip was called. See there. */
13106
13107Lisp_Object last_show_tip_args;
13108
13109/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13110
13111Lisp_Object Vx_max_tooltip_size;
13112
13113
937e601e
AI
13114static Lisp_Object
13115unwind_create_tip_frame (frame)
13116 Lisp_Object frame;
13117{
c844a81a
GM
13118 Lisp_Object deleted;
13119
13120 deleted = unwind_create_frame (frame);
13121 if (EQ (deleted, Qt))
13122 {
13123 tip_window = NULL;
13124 tip_frame = Qnil;
13125 }
13126
13127 return deleted;
937e601e
AI
13128}
13129
13130
6fc2811b 13131/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13132 PARMS is a list of frame parameters. TEXT is the string to
13133 display in the tip frame. Value is the frame.
937e601e
AI
13134
13135 Note that functions called here, esp. x_default_parameter can
13136 signal errors, for instance when a specified color name is
13137 undefined. We have to make sure that we're in a consistent state
13138 when this happens. */
6fc2811b
JR
13139
13140static Lisp_Object
3cf3436e 13141x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13142 struct w32_display_info *dpyinfo;
3cf3436e 13143 Lisp_Object parms, text;
6fc2811b 13144{
6fc2811b
JR
13145 struct frame *f;
13146 Lisp_Object frame, tem;
13147 Lisp_Object name;
13148 long window_prompting = 0;
13149 int width, height;
dc220243 13150 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13151 struct gcpro gcpro1, gcpro2, gcpro3;
13152 struct kboard *kb;
3cf3436e
JR
13153 int face_change_count_before = face_change_count;
13154 Lisp_Object buffer;
13155 struct buffer *old_buffer;
6fc2811b 13156
ca56d953 13157 check_w32 ();
6fc2811b
JR
13158
13159 /* Use this general default value to start with until we know if
13160 this frame has a specified name. */
13161 Vx_resource_name = Vinvocation_name;
13162
13163#ifdef MULTI_KBOARD
13164 kb = dpyinfo->kboard;
13165#else
13166 kb = &the_only_kboard;
13167#endif
13168
13169 /* Get the name of the frame to use for resource lookup. */
13170 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13171 if (!STRINGP (name)
13172 && !EQ (name, Qunbound)
13173 && !NILP (name))
13174 error ("Invalid frame name--not a string or nil");
13175 Vx_resource_name = name;
13176
13177 frame = Qnil;
13178 GCPRO3 (parms, name, frame);
9eb16b62
JR
13179 /* Make a frame without minibuffer nor mode-line. */
13180 f = make_frame (0);
13181 f->wants_modeline = 0;
6fc2811b 13182 XSETFRAME (frame, f);
3cf3436e
JR
13183
13184 buffer = Fget_buffer_create (build_string (" *tip*"));
13185 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13186 old_buffer = current_buffer;
13187 set_buffer_internal_1 (XBUFFER (buffer));
13188 current_buffer->truncate_lines = Qnil;
13189 Ferase_buffer ();
13190 Finsert (1, &text);
13191 set_buffer_internal_1 (old_buffer);
13192
6fc2811b 13193 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13194 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13195
3cf3436e
JR
13196 /* By setting the output method, we're essentially saying that
13197 the frame is live, as per FRAME_LIVE_P. If we get a signal
13198 from this point on, x_destroy_window might screw up reference
13199 counts etc. */
d88c567c 13200 f->output_method = output_w32;
6fc2811b
JR
13201 f->output_data.w32 =
13202 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13203 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13204
13205 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13206 f->icon_name = Qnil;
13207
ca56d953 13208#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13209 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13210 dpyinfo_refcount = dpyinfo->reference_count;
13211#endif /* GLYPH_DEBUG */
6fc2811b
JR
13212#ifdef MULTI_KBOARD
13213 FRAME_KBOARD (f) = kb;
13214#endif
13215 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13216 f->output_data.w32->explicit_parent = 0;
13217
13218 /* Set the name; the functions to which we pass f expect the name to
13219 be set. */
13220 if (EQ (name, Qunbound) || NILP (name))
13221 {
ca56d953 13222 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13223 f->explicit_name = 0;
13224 }
13225 else
13226 {
13227 f->name = name;
13228 f->explicit_name = 1;
13229 /* use the frame's title when getting resources for this frame. */
13230 specbind (Qx_resource_name, name);
13231 }
13232
6fc2811b
JR
13233 /* Extract the window parameters from the supplied values
13234 that are needed to determine window geometry. */
13235 {
13236 Lisp_Object font;
13237
13238 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13239
13240 BLOCK_INPUT;
13241 /* First, try whatever font the caller has specified. */
13242 if (STRINGP (font))
13243 {
13244 tem = Fquery_fontset (font, Qnil);
13245 if (STRINGP (tem))
13246 font = x_new_fontset (f, XSTRING (tem)->data);
13247 else
13248 font = x_new_font (f, XSTRING (font)->data);
13249 }
13250
13251 /* Try out a font which we hope has bold and italic variations. */
13252 if (!STRINGP (font))
ca56d953 13253 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13254 if (! STRINGP (font))
ca56d953 13255 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13256 /* If those didn't work, look for something which will at least work. */
13257 if (! STRINGP (font))
ca56d953 13258 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13259 UNBLOCK_INPUT;
13260 if (! STRINGP (font))
ca56d953 13261 font = build_string ("Fixedsys");
6fc2811b
JR
13262
13263 x_default_parameter (f, parms, Qfont, font,
13264 "font", "Font", RES_TYPE_STRING);
13265 }
13266
13267 x_default_parameter (f, parms, Qborder_width, make_number (2),
13268 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13269 /* This defaults to 2 in order to match xterm. We recognize either
13270 internalBorderWidth or internalBorder (which is what xterm calls
13271 it). */
13272 if (NILP (Fassq (Qinternal_border_width, parms)))
13273 {
13274 Lisp_Object value;
13275
13276 value = w32_get_arg (parms, Qinternal_border_width,
13277 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13278 if (! EQ (value, Qunbound))
13279 parms = Fcons (Fcons (Qinternal_border_width, value),
13280 parms);
13281 }
bfd6edcc 13282 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13283 "internalBorderWidth", "internalBorderWidth",
13284 RES_TYPE_NUMBER);
13285
13286 /* Also do the stuff which must be set before the window exists. */
13287 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13288 "foreground", "Foreground", RES_TYPE_STRING);
13289 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13290 "background", "Background", RES_TYPE_STRING);
13291 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13292 "pointerColor", "Foreground", RES_TYPE_STRING);
13293 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13294 "cursorColor", "Foreground", RES_TYPE_STRING);
13295 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13296 "borderColor", "BorderColor", RES_TYPE_STRING);
13297
13298 /* Init faces before x_default_parameter is called for scroll-bar
13299 parameters because that function calls x_set_scroll_bar_width,
13300 which calls change_frame_size, which calls Fset_window_buffer,
13301 which runs hooks, which call Fvertical_motion. At the end, we
13302 end up in init_iterator with a null face cache, which should not
13303 happen. */
13304 init_frame_faces (f);
ca56d953
JR
13305
13306 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13307 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13308
6fc2811b
JR
13309 window_prompting = x_figure_window_size (f, parms);
13310
9eb16b62
JR
13311 /* No fringes on tip frame. */
13312 f->output_data.w32->fringes_extra = 0;
13313 f->output_data.w32->fringe_cols = 0;
13314 f->output_data.w32->left_fringe_width = 0;
13315 f->output_data.w32->right_fringe_width = 0;
13316
6fc2811b
JR
13317 if (window_prompting & XNegative)
13318 {
13319 if (window_prompting & YNegative)
13320 f->output_data.w32->win_gravity = SouthEastGravity;
13321 else
13322 f->output_data.w32->win_gravity = NorthEastGravity;
13323 }
13324 else
13325 {
13326 if (window_prompting & YNegative)
13327 f->output_data.w32->win_gravity = SouthWestGravity;
13328 else
13329 f->output_data.w32->win_gravity = NorthWestGravity;
13330 }
13331
13332 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13333
13334 BLOCK_INPUT;
13335 my_create_tip_window (f);
13336 UNBLOCK_INPUT;
6fc2811b
JR
13337
13338 x_make_gc (f);
13339
13340 x_default_parameter (f, parms, Qauto_raise, Qnil,
13341 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13342 x_default_parameter (f, parms, Qauto_lower, Qnil,
13343 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13344 x_default_parameter (f, parms, Qcursor_type, Qbox,
13345 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13346
13347 /* Dimensions, especially f->height, must be done via change_frame_size.
13348 Change will not be effected unless different from the current
13349 f->height. */
13350 width = f->width;
13351 height = f->height;
13352 f->height = 0;
13353 SET_FRAME_WIDTH (f, 0);
13354 change_frame_size (f, height, width, 1, 0, 0);
13355
3cf3436e
JR
13356 /* Set up faces after all frame parameters are known. This call
13357 also merges in face attributes specified for new frames.
13358
13359 Frame parameters may be changed if .Xdefaults contains
13360 specifications for the default font. For example, if there is an
13361 `Emacs.default.attributeBackground: pink', the `background-color'
13362 attribute of the frame get's set, which let's the internal border
13363 of the tooltip frame appear in pink. Prevent this. */
13364 {
13365 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13366
13367 /* Set tip_frame here, so that */
13368 tip_frame = frame;
13369 call1 (Qface_set_after_frame_default, frame);
13370
13371 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13372 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13373 Qnil));
13374 }
13375
6fc2811b
JR
13376 f->no_split = 1;
13377
13378 UNGCPRO;
13379
13380 /* It is now ok to make the frame official even if we get an error
13381 below. And the frame needs to be on Vframe_list or making it
13382 visible won't work. */
13383 Vframe_list = Fcons (frame, Vframe_list);
13384
13385 /* Now that the frame is official, it counts as a reference to
13386 its display. */
13387 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13388
3cf3436e
JR
13389 /* Setting attributes of faces of the tooltip frame from resources
13390 and similar will increment face_change_count, which leads to the
13391 clearing of all current matrices. Since this isn't necessary
13392 here, avoid it by resetting face_change_count to the value it
13393 had before we created the tip frame. */
13394 face_change_count = face_change_count_before;
13395
13396 /* Discard the unwind_protect. */
6fc2811b 13397 return unbind_to (count, frame);
ee78dc32
GV
13398}
13399
3cf3436e
JR
13400
13401/* Compute where to display tip frame F. PARMS is the list of frame
13402 parameters for F. DX and DY are specified offsets from the current
13403 location of the mouse. WIDTH and HEIGHT are the width and height
13404 of the tooltip. Return coordinates relative to the root window of
13405 the display in *ROOT_X, and *ROOT_Y. */
13406
13407static void
13408compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13409 struct frame *f;
13410 Lisp_Object parms, dx, dy;
13411 int width, height;
13412 int *root_x, *root_y;
13413{
3cf3436e 13414 Lisp_Object left, top;
3cf3436e
JR
13415
13416 /* User-specified position? */
13417 left = Fcdr (Fassq (Qleft, parms));
13418 top = Fcdr (Fassq (Qtop, parms));
13419
13420 /* Move the tooltip window where the mouse pointer is. Resize and
13421 show it. */
ca56d953 13422 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13423 {
ca56d953
JR
13424 POINT pt;
13425
3cf3436e 13426 BLOCK_INPUT;
ca56d953
JR
13427 GetCursorPos (&pt);
13428 *root_x = pt.x;
13429 *root_y = pt.y;
3cf3436e
JR
13430 UNBLOCK_INPUT;
13431 }
13432
13433 if (INTEGERP (top))
13434 *root_y = XINT (top);
13435 else if (*root_y + XINT (dy) - height < 0)
13436 *root_y -= XINT (dy);
13437 else
13438 {
13439 *root_y -= height;
13440 *root_y += XINT (dy);
13441 }
13442
13443 if (INTEGERP (left))
13444 *root_x = XINT (left);
72e4adef
JR
13445 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13446 /* It fits to the right of the pointer. */
13447 *root_x += XINT (dx);
13448 else if (width + XINT (dx) <= *root_x)
13449 /* It fits to the left of the pointer. */
3cf3436e
JR
13450 *root_x -= width + XINT (dx);
13451 else
72e4adef
JR
13452 /* Put it left justified on the screen -- it ought to fit that way. */
13453 *root_x = 0;
3cf3436e
JR
13454}
13455
13456
71eab8d1 13457DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13458 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13459A tooltip window is a small window displaying a string.
13460
13461FRAME nil or omitted means use the selected frame.
13462
13463PARMS is an optional list of frame parameters which can be
13464used to change the tooltip's appearance.
13465
ca56d953
JR
13466Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13467means use the default timeout of 5 seconds.
74e1aeec 13468
ca56d953 13469If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13470the tooltip is displayed at that x-position. Otherwise it is
13471displayed at the mouse position, with offset DX added (default is 5 if
13472DX isn't specified). Likewise for the y-position; if a `top' frame
13473parameter is specified, it determines the y-position of the tooltip
13474window, otherwise it is displayed at the mouse position, with offset
13475DY added (default is -10).
13476
13477A tooltip's maximum size is specified by `x-max-tooltip-size'.
13478Text larger than the specified size is clipped. */)
71eab8d1
AI
13479 (string, frame, parms, timeout, dx, dy)
13480 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13481{
6fc2811b
JR
13482 struct frame *f;
13483 struct window *w;
3cf3436e 13484 int root_x, root_y;
6fc2811b
JR
13485 struct buffer *old_buffer;
13486 struct text_pos pos;
13487 int i, width, height;
6fc2811b
JR
13488 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13489 int old_windows_or_buffers_changed = windows_or_buffers_changed;
ca56d953 13490 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13491
13492 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13493
dfff8a69 13494 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13495
b7826503 13496 CHECK_STRING (string);
6fc2811b
JR
13497 f = check_x_frame (frame);
13498 if (NILP (timeout))
13499 timeout = make_number (5);
13500 else
b7826503 13501 CHECK_NATNUM (timeout);
ee78dc32 13502
71eab8d1
AI
13503 if (NILP (dx))
13504 dx = make_number (5);
13505 else
b7826503 13506 CHECK_NUMBER (dx);
71eab8d1
AI
13507
13508 if (NILP (dy))
dc220243 13509 dy = make_number (-10);
71eab8d1 13510 else
b7826503 13511 CHECK_NUMBER (dy);
71eab8d1 13512
dc220243
JR
13513 if (NILP (last_show_tip_args))
13514 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13515
13516 if (!NILP (tip_frame))
13517 {
13518 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13519 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13520 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13521
13522 if (EQ (frame, last_frame)
13523 && !NILP (Fequal (last_string, string))
13524 && !NILP (Fequal (last_parms, parms)))
13525 {
13526 struct frame *f = XFRAME (tip_frame);
13527
13528 /* Only DX and DY have changed. */
13529 if (!NILP (tip_timer))
13530 {
13531 Lisp_Object timer = tip_timer;
13532 tip_timer = Qnil;
13533 call1 (Qcancel_timer, timer);
13534 }
13535
13536 BLOCK_INPUT;
ca56d953
JR
13537 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13538 PIXEL_HEIGHT (f), &root_x, &root_y);
13539 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13540 root_x, root_y, 0, 0,
13541 SWP_NOSIZE | SWP_NOACTIVATE);
dc220243
JR
13542 UNBLOCK_INPUT;
13543 goto start_timer;
13544 }
13545 }
13546
6fc2811b
JR
13547 /* Hide a previous tip, if any. */
13548 Fx_hide_tip ();
ee78dc32 13549
dc220243
JR
13550 ASET (last_show_tip_args, 0, string);
13551 ASET (last_show_tip_args, 1, frame);
13552 ASET (last_show_tip_args, 2, parms);
13553
6fc2811b
JR
13554 /* Add default values to frame parameters. */
13555 if (NILP (Fassq (Qname, parms)))
13556 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13557 if (NILP (Fassq (Qinternal_border_width, parms)))
13558 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13559 if (NILP (Fassq (Qborder_width, parms)))
13560 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13561 if (NILP (Fassq (Qborder_color, parms)))
13562 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13563 if (NILP (Fassq (Qbackground_color, parms)))
13564 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13565 parms);
13566
0e3fcdef
JR
13567 /* Block input until the tip has been fully drawn, to avoid crashes
13568 when drawing tips in menus. */
13569 BLOCK_INPUT;
13570
6fc2811b
JR
13571 /* Create a frame for the tooltip, and record it in the global
13572 variable tip_frame. */
ca56d953 13573 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 13574 f = XFRAME (frame);
6fc2811b 13575
3cf3436e 13576 /* Set up the frame's root window. */
6fc2811b
JR
13577 w = XWINDOW (FRAME_ROOT_WINDOW (f));
13578 w->left = w->top = make_number (0);
3cf3436e
JR
13579
13580 if (CONSP (Vx_max_tooltip_size)
13581 && INTEGERP (XCAR (Vx_max_tooltip_size))
13582 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13583 && INTEGERP (XCDR (Vx_max_tooltip_size))
13584 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13585 {
13586 w->width = XCAR (Vx_max_tooltip_size);
13587 w->height = XCDR (Vx_max_tooltip_size);
13588 }
13589 else
13590 {
13591 w->width = make_number (80);
13592 w->height = make_number (40);
13593 }
13594
13595 f->window_width = XINT (w->width);
6fc2811b
JR
13596 adjust_glyphs (f);
13597 w->pseudo_window_p = 1;
13598
13599 /* Display the tooltip text in a temporary buffer. */
6fc2811b 13600 old_buffer = current_buffer;
3cf3436e
JR
13601 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13602 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
13603 clear_glyph_matrix (w->desired_matrix);
13604 clear_glyph_matrix (w->current_matrix);
13605 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13606 try_window (FRAME_ROOT_WINDOW (f), pos);
13607
13608 /* Compute width and height of the tooltip. */
13609 width = height = 0;
13610 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 13611 {
6fc2811b
JR
13612 struct glyph_row *row = &w->desired_matrix->rows[i];
13613 struct glyph *last;
13614 int row_width;
13615
13616 /* Stop at the first empty row at the end. */
13617 if (!row->enabled_p || !row->displays_text_p)
13618 break;
13619
13620 /* Let the row go over the full width of the frame. */
13621 row->full_width_p = 1;
13622
4e3a1c61
JR
13623#ifdef TODO /* Investigate why some fonts need more width than is
13624 calculated for some tooltips. */
6fc2811b
JR
13625 /* There's a glyph at the end of rows that is use to place
13626 the cursor there. Don't include the width of this glyph. */
13627 if (row->used[TEXT_AREA])
13628 {
13629 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13630 row_width = row->pixel_width - last->pixel_width;
13631 }
13632 else
4e3a1c61 13633#endif
6fc2811b
JR
13634 row_width = row->pixel_width;
13635
ca56d953 13636 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 13637 height += row->height;
6fc2811b 13638 width = max (width, row_width);
ee78dc32
GV
13639 }
13640
6fc2811b
JR
13641 /* Add the frame's internal border to the width and height the X
13642 window should have. */
13643 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13644 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 13645
6fc2811b
JR
13646 /* Move the tooltip window where the mouse pointer is. Resize and
13647 show it. */
3cf3436e 13648 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 13649
bfd6edcc
JR
13650 {
13651 /* Adjust Window size to take border into account. */
13652 RECT rect;
13653 rect.left = rect.top = 0;
13654 rect.right = width;
13655 rect.bottom = height;
13656 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
13657 FRAME_EXTERNAL_MENU_BAR (f));
13658
13659 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13660 root_x, root_y, rect.right - rect.left,
13661 rect.bottom - rect.top, SWP_NOACTIVATE);
13662
13663 /* Let redisplay know that we have made the frame visible already. */
13664 f->async_visible = 1;
13665
13666 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
13667 }
ee78dc32 13668
6fc2811b
JR
13669 /* Draw into the window. */
13670 w->must_be_updated_p = 1;
13671 update_single_window (w, 1);
ee78dc32 13672
0e3fcdef
JR
13673 UNBLOCK_INPUT;
13674
6fc2811b
JR
13675 /* Restore original current buffer. */
13676 set_buffer_internal_1 (old_buffer);
13677 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 13678
dc220243 13679 start_timer:
6fc2811b
JR
13680 /* Let the tip disappear after timeout seconds. */
13681 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13682 intern ("x-hide-tip"));
ee78dc32 13683
dfff8a69 13684 UNGCPRO;
6fc2811b 13685 return unbind_to (count, Qnil);
ee78dc32
GV
13686}
13687
ee78dc32 13688
6fc2811b 13689DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
13690 doc: /* Hide the current tooltip window, if there is any.
13691Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
13692 ()
13693{
937e601e
AI
13694 int count;
13695 Lisp_Object deleted, frame, timer;
13696 struct gcpro gcpro1, gcpro2;
13697
13698 /* Return quickly if nothing to do. */
13699 if (NILP (tip_timer) && NILP (tip_frame))
13700 return Qnil;
13701
13702 frame = tip_frame;
13703 timer = tip_timer;
13704 GCPRO2 (frame, timer);
13705 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 13706
937e601e 13707 count = BINDING_STACK_SIZE ();
6fc2811b 13708 specbind (Qinhibit_redisplay, Qt);
937e601e 13709 specbind (Qinhibit_quit, Qt);
6fc2811b 13710
937e601e 13711 if (!NILP (timer))
dc220243 13712 call1 (Qcancel_timer, timer);
ee78dc32 13713
937e601e 13714 if (FRAMEP (frame))
6fc2811b 13715 {
937e601e
AI
13716 Fdelete_frame (frame, Qnil);
13717 deleted = Qt;
6fc2811b 13718 }
1edf84e7 13719
937e601e
AI
13720 UNGCPRO;
13721 return unbind_to (count, deleted);
6fc2811b 13722}
5ac45f98 13723
5ac45f98 13724
6fc2811b
JR
13725\f
13726/***********************************************************************
13727 File selection dialog
13728 ***********************************************************************/
13729
13730extern Lisp_Object Qfile_name_history;
13731
13732DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
13733 doc: /* Read file name, prompting with PROMPT in directory DIR.
13734Use a file selection dialog.
13735Select DEFAULT-FILENAME in the dialog's file selection box, if
13736specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
13737 (prompt, dir, default_filename, mustmatch)
13738 Lisp_Object prompt, dir, default_filename, mustmatch;
13739{
13740 struct frame *f = SELECTED_FRAME ();
13741 Lisp_Object file = Qnil;
13742 int count = specpdl_ptr - specpdl;
13743 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
13744 char filename[MAX_PATH + 1];
13745 char init_dir[MAX_PATH + 1];
13746 int use_dialog_p = 1;
13747
13748 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
13749 CHECK_STRING (prompt);
13750 CHECK_STRING (dir);
6fc2811b
JR
13751
13752 /* Create the dialog with PROMPT as title, using DIR as initial
13753 directory and using "*" as pattern. */
13754 dir = Fexpand_file_name (dir, Qnil);
13755 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
13756 init_dir[MAX_PATH] = '\0';
13757 unixtodos_filename (init_dir);
13758
13759 if (STRINGP (default_filename))
13760 {
13761 char *file_name_only;
13762 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 13763
6fc2811b 13764 unixtodos_filename (full_path_name);
5ac45f98 13765
6fc2811b
JR
13766 file_name_only = strrchr (full_path_name, '\\');
13767 if (!file_name_only)
13768 file_name_only = full_path_name;
13769 else
13770 {
13771 file_name_only++;
5ac45f98 13772
6fc2811b
JR
13773 /* If default_file_name is a directory, don't use the open
13774 file dialog, as it does not support selecting
13775 directories. */
13776 if (!(*file_name_only))
13777 use_dialog_p = 0;
13778 }
ee78dc32 13779
6fc2811b
JR
13780 strncpy (filename, file_name_only, MAX_PATH);
13781 filename[MAX_PATH] = '\0';
13782 }
ee78dc32 13783 else
6fc2811b 13784 filename[0] = '\0';
ee78dc32 13785
6fc2811b
JR
13786 if (use_dialog_p)
13787 {
13788 OPENFILENAME file_details;
5ac45f98 13789
6fc2811b
JR
13790 /* Prevent redisplay. */
13791 specbind (Qinhibit_redisplay, Qt);
13792 BLOCK_INPUT;
ee78dc32 13793
6fc2811b
JR
13794 bzero (&file_details, sizeof (file_details));
13795 file_details.lStructSize = sizeof (file_details);
13796 file_details.hwndOwner = FRAME_W32_WINDOW (f);
3cf3436e
JR
13797 /* Undocumented Bug in Common File Dialog:
13798 If a filter is not specified, shell links are not resolved. */
13799 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
6fc2811b
JR
13800 file_details.lpstrFile = filename;
13801 file_details.nMaxFile = sizeof (filename);
13802 file_details.lpstrInitialDir = init_dir;
13803 file_details.lpstrTitle = XSTRING (prompt)->data;
13804 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 13805
6fc2811b
JR
13806 if (!NILP (mustmatch))
13807 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 13808
6fc2811b
JR
13809 if (GetOpenFileName (&file_details))
13810 {
13811 dostounix_filename (filename);
13812 file = build_string (filename);
13813 }
ee78dc32 13814 else
6fc2811b
JR
13815 file = Qnil;
13816
13817 UNBLOCK_INPUT;
13818 file = unbind_to (count, file);
ee78dc32 13819 }
6fc2811b
JR
13820 /* Open File dialog will not allow folders to be selected, so resort
13821 to minibuffer completing reads for directories. */
13822 else
13823 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
13824 dir, mustmatch, dir, Qfile_name_history,
13825 default_filename, Qnil);
ee78dc32 13826
6fc2811b 13827 UNGCPRO;
1edf84e7 13828
6fc2811b
JR
13829 /* Make "Cancel" equivalent to C-g. */
13830 if (NILP (file))
13831 Fsignal (Qquit, Qnil);
ee78dc32 13832
dfff8a69 13833 return unbind_to (count, file);
6fc2811b 13834}
ee78dc32 13835
ee78dc32 13836
6fc2811b 13837\f
6fc2811b
JR
13838/***********************************************************************
13839 w32 specialized functions
13840 ***********************************************************************/
ee78dc32 13841
fbd6baed 13842DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
74e1aeec
JR
13843 doc: /* Select a font using the W32 font dialog.
13844Returns an X font string corresponding to the selection. */)
ee78dc32
GV
13845 (frame)
13846 Lisp_Object frame;
13847{
13848 FRAME_PTR f = check_x_frame (frame);
13849 CHOOSEFONT cf;
13850 LOGFONT lf;
f46e6225
GV
13851 TEXTMETRIC tm;
13852 HDC hdc;
13853 HANDLE oldobj;
ee78dc32
GV
13854 char buf[100];
13855
13856 bzero (&cf, sizeof (cf));
f46e6225 13857 bzero (&lf, sizeof (lf));
ee78dc32
GV
13858
13859 cf.lStructSize = sizeof (cf);
fbd6baed 13860 cf.hwndOwner = FRAME_W32_WINDOW (f);
6fc2811b 13861 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
ee78dc32
GV
13862 cf.lpLogFont = &lf;
13863
f46e6225
GV
13864 /* Initialize as much of the font details as we can from the current
13865 default font. */
13866 hdc = GetDC (FRAME_W32_WINDOW (f));
13867 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
13868 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
13869 if (GetTextMetrics (hdc, &tm))
13870 {
13871 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
13872 lf.lfWeight = tm.tmWeight;
13873 lf.lfItalic = tm.tmItalic;
13874 lf.lfUnderline = tm.tmUnderlined;
13875 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
13876 lf.lfCharSet = tm.tmCharSet;
13877 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
13878 }
13879 SelectObject (hdc, oldobj);
6fc2811b 13880 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 13881
767b1ff0 13882 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 13883 return Qnil;
ee78dc32
GV
13884
13885 return build_string (buf);
13886}
13887
74e1aeec
JR
13888DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
13889 Sw32_send_sys_command, 1, 2, 0,
13890 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
13891Some useful values for command are 0xf030 to maximise frame (0xf020
13892to minimize), 0xf120 to restore frame to original size, and 0xf100
13893to activate the menubar for keyboard access. 0xf140 activates the
13894screen saver if defined.
13895
13896If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
13897 (command, frame)
13898 Lisp_Object command, frame;
13899{
1edf84e7
GV
13900 FRAME_PTR f = check_x_frame (frame);
13901
b7826503 13902 CHECK_NUMBER (command);
1edf84e7 13903
ce6059da 13904 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
13905
13906 return Qnil;
13907}
13908
55dcfc15 13909DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
13910 doc: /* Get Windows to perform OPERATION on DOCUMENT.
13911This is a wrapper around the ShellExecute system function, which
13912invokes the application registered to handle OPERATION for DOCUMENT.
13913OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
13914nil for the default action), and DOCUMENT is typically the name of a
13915document file or URL, but can also be a program executable to run or
13916a directory to open in the Windows Explorer.
13917
13918If DOCUMENT is a program executable, PARAMETERS can be a string
13919containing command line parameters, but otherwise should be nil.
13920
13921SHOW-FLAG can be used to control whether the invoked application is hidden
13922or minimized. If SHOW-FLAG is nil, the application is displayed normally,
13923otherwise it is an integer representing a ShowWindow flag:
13924
13925 0 - start hidden
13926 1 - start normally
13927 3 - start maximized
13928 6 - start minimized */)
55dcfc15
AI
13929 (operation, document, parameters, show_flag)
13930 Lisp_Object operation, document, parameters, show_flag;
13931{
13932 Lisp_Object current_dir;
13933
b7826503 13934 CHECK_STRING (document);
55dcfc15
AI
13935
13936 /* Encode filename and current directory. */
13937 current_dir = ENCODE_FILE (current_buffer->directory);
13938 document = ENCODE_FILE (document);
13939 if ((int) ShellExecute (NULL,
6fc2811b
JR
13940 (STRINGP (operation) ?
13941 XSTRING (operation)->data : NULL),
55dcfc15
AI
13942 XSTRING (document)->data,
13943 (STRINGP (parameters) ?
13944 XSTRING (parameters)->data : NULL),
13945 XSTRING (current_dir)->data,
13946 (INTEGERP (show_flag) ?
13947 XINT (show_flag) : SW_SHOWDEFAULT))
13948 > 32)
13949 return Qt;
90d97e64 13950 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
13951}
13952
ccc2d29c
GV
13953/* Lookup virtual keycode from string representing the name of a
13954 non-ascii keystroke into the corresponding virtual key, using
13955 lispy_function_keys. */
13956static int
13957lookup_vk_code (char *key)
13958{
13959 int i;
13960
13961 for (i = 0; i < 256; i++)
13962 if (lispy_function_keys[i] != 0
13963 && strcmp (lispy_function_keys[i], key) == 0)
13964 return i;
13965
13966 return -1;
13967}
13968
13969/* Convert a one-element vector style key sequence to a hot key
13970 definition. */
13971static int
13972w32_parse_hot_key (key)
13973 Lisp_Object key;
13974{
13975 /* Copied from Fdefine_key and store_in_keymap. */
13976 register Lisp_Object c;
13977 int vk_code;
13978 int lisp_modifiers;
13979 int w32_modifiers;
13980 struct gcpro gcpro1;
13981
b7826503 13982 CHECK_VECTOR (key);
ccc2d29c
GV
13983
13984 if (XFASTINT (Flength (key)) != 1)
13985 return Qnil;
13986
13987 GCPRO1 (key);
13988
13989 c = Faref (key, make_number (0));
13990
13991 if (CONSP (c) && lucid_event_type_list_p (c))
13992 c = Fevent_convert_list (c);
13993
13994 UNGCPRO;
13995
13996 if (! INTEGERP (c) && ! SYMBOLP (c))
13997 error ("Key definition is invalid");
13998
13999 /* Work out the base key and the modifiers. */
14000 if (SYMBOLP (c))
14001 {
14002 c = parse_modifiers (c);
14003 lisp_modifiers = Fcar (Fcdr (c));
14004 c = Fcar (c);
14005 if (!SYMBOLP (c))
14006 abort ();
14007 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
14008 }
14009 else if (INTEGERP (c))
14010 {
14011 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14012 /* Many ascii characters are their own virtual key code. */
14013 vk_code = XINT (c) & CHARACTERBITS;
14014 }
14015
14016 if (vk_code < 0 || vk_code > 255)
14017 return Qnil;
14018
14019 if ((lisp_modifiers & meta_modifier) != 0
14020 && !NILP (Vw32_alt_is_meta))
14021 lisp_modifiers |= alt_modifier;
14022
71eab8d1
AI
14023 /* Supply defs missing from mingw32. */
14024#ifndef MOD_ALT
14025#define MOD_ALT 0x0001
14026#define MOD_CONTROL 0x0002
14027#define MOD_SHIFT 0x0004
14028#define MOD_WIN 0x0008
14029#endif
14030
ccc2d29c
GV
14031 /* Convert lisp modifiers to Windows hot-key form. */
14032 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14033 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14034 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14035 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14036
14037 return HOTKEY (vk_code, w32_modifiers);
14038}
14039
74e1aeec
JR
14040DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14041 Sw32_register_hot_key, 1, 1, 0,
14042 doc: /* Register KEY as a hot-key combination.
14043Certain key combinations like Alt-Tab are reserved for system use on
14044Windows, and therefore are normally intercepted by the system. However,
14045most of these key combinations can be received by registering them as
14046hot-keys, overriding their special meaning.
14047
14048KEY must be a one element key definition in vector form that would be
14049acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14050modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14051is always interpreted as the Windows modifier keys.
14052
14053The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14054 (key)
14055 Lisp_Object key;
14056{
14057 key = w32_parse_hot_key (key);
14058
14059 if (NILP (Fmemq (key, w32_grabbed_keys)))
14060 {
14061 /* Reuse an empty slot if possible. */
14062 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14063
14064 /* Safe to add new key to list, even if we have focus. */
14065 if (NILP (item))
14066 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14067 else
f3fbd155 14068 XSETCAR (item, key);
ccc2d29c
GV
14069
14070 /* Notify input thread about new hot-key definition, so that it
14071 takes effect without needing to switch focus. */
14072 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14073 (WPARAM) key, 0);
14074 }
14075
14076 return key;
14077}
14078
74e1aeec
JR
14079DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14080 Sw32_unregister_hot_key, 1, 1, 0,
14081 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14082 (key)
14083 Lisp_Object key;
14084{
14085 Lisp_Object item;
14086
14087 if (!INTEGERP (key))
14088 key = w32_parse_hot_key (key);
14089
14090 item = Fmemq (key, w32_grabbed_keys);
14091
14092 if (!NILP (item))
14093 {
14094 /* Notify input thread about hot-key definition being removed, so
14095 that it takes effect without needing focus switch. */
14096 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14097 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14098 {
14099 MSG msg;
14100 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14101 }
14102 return Qt;
14103 }
14104 return Qnil;
14105}
14106
74e1aeec
JR
14107DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14108 Sw32_registered_hot_keys, 0, 0, 0,
14109 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14110 ()
14111{
14112 return Fcopy_sequence (w32_grabbed_keys);
14113}
14114
74e1aeec
JR
14115DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14116 Sw32_reconstruct_hot_key, 1, 1, 0,
14117 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14118 (hotkeyid)
14119 Lisp_Object hotkeyid;
14120{
14121 int vk_code, w32_modifiers;
14122 Lisp_Object key;
14123
b7826503 14124 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14125
14126 vk_code = HOTKEY_VK_CODE (hotkeyid);
14127 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14128
14129 if (lispy_function_keys[vk_code])
14130 key = intern (lispy_function_keys[vk_code]);
14131 else
14132 key = make_number (vk_code);
14133
14134 key = Fcons (key, Qnil);
14135 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14136 key = Fcons (Qshift, key);
ccc2d29c 14137 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14138 key = Fcons (Qctrl, key);
ccc2d29c 14139 if (w32_modifiers & MOD_ALT)
3ef68e6b 14140 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14141 if (w32_modifiers & MOD_WIN)
3ef68e6b 14142 key = Fcons (Qhyper, key);
ccc2d29c
GV
14143
14144 return key;
14145}
adcc3809 14146
74e1aeec
JR
14147DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14148 Sw32_toggle_lock_key, 1, 2, 0,
14149 doc: /* Toggle the state of the lock key KEY.
14150KEY can be `capslock', `kp-numlock', or `scroll'.
14151If the optional parameter NEW-STATE is a number, then the state of KEY
14152is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14153 (key, new_state)
14154 Lisp_Object key, new_state;
14155{
14156 int vk_code;
adcc3809
GV
14157
14158 if (EQ (key, intern ("capslock")))
14159 vk_code = VK_CAPITAL;
14160 else if (EQ (key, intern ("kp-numlock")))
14161 vk_code = VK_NUMLOCK;
14162 else if (EQ (key, intern ("scroll")))
14163 vk_code = VK_SCROLL;
14164 else
14165 return Qnil;
14166
14167 if (!dwWindowsThreadId)
14168 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14169
14170 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14171 (WPARAM) vk_code, (LPARAM) new_state))
14172 {
14173 MSG msg;
14174 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14175 return make_number (msg.wParam);
14176 }
14177 return Qnil;
14178}
ee78dc32 14179\f
2254bcde 14180DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14181 doc: /* Return storage information about the file system FILENAME is on.
14182Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14183storage of the file system, FREE is the free storage, and AVAIL is the
14184storage available to a non-superuser. All 3 numbers are in bytes.
14185If the underlying system call fails, value is nil. */)
2254bcde
AI
14186 (filename)
14187 Lisp_Object filename;
14188{
14189 Lisp_Object encoded, value;
14190
b7826503 14191 CHECK_STRING (filename);
2254bcde
AI
14192 filename = Fexpand_file_name (filename, Qnil);
14193 encoded = ENCODE_FILE (filename);
14194
14195 value = Qnil;
14196
14197 /* Determining the required information on Windows turns out, sadly,
14198 to be more involved than one would hope. The original Win32 api
14199 call for this will return bogus information on some systems, but we
14200 must dynamically probe for the replacement api, since that was
14201 added rather late on. */
14202 {
14203 HMODULE hKernel = GetModuleHandle ("kernel32");
14204 BOOL (*pfn_GetDiskFreeSpaceEx)
14205 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14206 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14207
14208 /* On Windows, we may need to specify the root directory of the
14209 volume holding FILENAME. */
14210 char rootname[MAX_PATH];
14211 char *name = XSTRING (encoded)->data;
14212
14213 /* find the root name of the volume if given */
14214 if (isalpha (name[0]) && name[1] == ':')
14215 {
14216 rootname[0] = name[0];
14217 rootname[1] = name[1];
14218 rootname[2] = '\\';
14219 rootname[3] = 0;
14220 }
14221 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14222 {
14223 char *str = rootname;
14224 int slashes = 4;
14225 do
14226 {
14227 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14228 break;
14229 *str++ = *name++;
14230 }
14231 while ( *name );
14232
14233 *str++ = '\\';
14234 *str = 0;
14235 }
14236
14237 if (pfn_GetDiskFreeSpaceEx)
14238 {
14239 LARGE_INTEGER availbytes;
14240 LARGE_INTEGER freebytes;
14241 LARGE_INTEGER totalbytes;
14242
14243 if (pfn_GetDiskFreeSpaceEx(rootname,
14244 &availbytes,
14245 &totalbytes,
14246 &freebytes))
14247 value = list3 (make_float ((double) totalbytes.QuadPart),
14248 make_float ((double) freebytes.QuadPart),
14249 make_float ((double) availbytes.QuadPart));
14250 }
14251 else
14252 {
14253 DWORD sectors_per_cluster;
14254 DWORD bytes_per_sector;
14255 DWORD free_clusters;
14256 DWORD total_clusters;
14257
14258 if (GetDiskFreeSpace(rootname,
14259 &sectors_per_cluster,
14260 &bytes_per_sector,
14261 &free_clusters,
14262 &total_clusters))
14263 value = list3 (make_float ((double) total_clusters
14264 * sectors_per_cluster * bytes_per_sector),
14265 make_float ((double) free_clusters
14266 * sectors_per_cluster * bytes_per_sector),
14267 make_float ((double) free_clusters
14268 * sectors_per_cluster * bytes_per_sector));
14269 }
14270 }
14271
14272 return value;
14273}
14274\f
0e3fcdef
JR
14275/***********************************************************************
14276 Initialization
14277 ***********************************************************************/
14278
14279void
fbd6baed 14280syms_of_w32fns ()
ee78dc32 14281{
9eb16b62
JR
14282 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14283
1edf84e7
GV
14284 /* This is zero if not using MS-Windows. */
14285 w32_in_use = 0;
14286
9eb16b62
JR
14287 /* TrackMouseEvent not available in all versions of Windows, so must load
14288 it dynamically. Do it once, here, instead of every time it is used. */
14289 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14290 track_mouse_window = NULL;
14291
ee78dc32
GV
14292 /* The section below is built by the lisp expression at the top of the file,
14293 just above where these variables are declared. */
14294 /*&&& init symbols here &&&*/
14295 Qauto_raise = intern ("auto-raise");
14296 staticpro (&Qauto_raise);
14297 Qauto_lower = intern ("auto-lower");
14298 staticpro (&Qauto_lower);
ee78dc32
GV
14299 Qbar = intern ("bar");
14300 staticpro (&Qbar);
14301 Qborder_color = intern ("border-color");
14302 staticpro (&Qborder_color);
14303 Qborder_width = intern ("border-width");
14304 staticpro (&Qborder_width);
14305 Qbox = intern ("box");
14306 staticpro (&Qbox);
14307 Qcursor_color = intern ("cursor-color");
14308 staticpro (&Qcursor_color);
14309 Qcursor_type = intern ("cursor-type");
14310 staticpro (&Qcursor_type);
ee78dc32
GV
14311 Qgeometry = intern ("geometry");
14312 staticpro (&Qgeometry);
14313 Qicon_left = intern ("icon-left");
14314 staticpro (&Qicon_left);
14315 Qicon_top = intern ("icon-top");
14316 staticpro (&Qicon_top);
14317 Qicon_type = intern ("icon-type");
14318 staticpro (&Qicon_type);
14319 Qicon_name = intern ("icon-name");
14320 staticpro (&Qicon_name);
14321 Qinternal_border_width = intern ("internal-border-width");
14322 staticpro (&Qinternal_border_width);
14323 Qleft = intern ("left");
14324 staticpro (&Qleft);
1026b400
RS
14325 Qright = intern ("right");
14326 staticpro (&Qright);
ee78dc32
GV
14327 Qmouse_color = intern ("mouse-color");
14328 staticpro (&Qmouse_color);
14329 Qnone = intern ("none");
14330 staticpro (&Qnone);
14331 Qparent_id = intern ("parent-id");
14332 staticpro (&Qparent_id);
14333 Qscroll_bar_width = intern ("scroll-bar-width");
14334 staticpro (&Qscroll_bar_width);
14335 Qsuppress_icon = intern ("suppress-icon");
14336 staticpro (&Qsuppress_icon);
ee78dc32
GV
14337 Qundefined_color = intern ("undefined-color");
14338 staticpro (&Qundefined_color);
14339 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14340 staticpro (&Qvertical_scroll_bars);
14341 Qvisibility = intern ("visibility");
14342 staticpro (&Qvisibility);
14343 Qwindow_id = intern ("window-id");
14344 staticpro (&Qwindow_id);
14345 Qx_frame_parameter = intern ("x-frame-parameter");
14346 staticpro (&Qx_frame_parameter);
14347 Qx_resource_name = intern ("x-resource-name");
14348 staticpro (&Qx_resource_name);
14349 Quser_position = intern ("user-position");
14350 staticpro (&Quser_position);
14351 Quser_size = intern ("user-size");
14352 staticpro (&Quser_size);
6fc2811b
JR
14353 Qscreen_gamma = intern ("screen-gamma");
14354 staticpro (&Qscreen_gamma);
dfff8a69
JR
14355 Qline_spacing = intern ("line-spacing");
14356 staticpro (&Qline_spacing);
14357 Qcenter = intern ("center");
14358 staticpro (&Qcenter);
dc220243
JR
14359 Qcancel_timer = intern ("cancel-timer");
14360 staticpro (&Qcancel_timer);
ee78dc32
GV
14361 /* This is the end of symbol initialization. */
14362
adcc3809
GV
14363 Qhyper = intern ("hyper");
14364 staticpro (&Qhyper);
14365 Qsuper = intern ("super");
14366 staticpro (&Qsuper);
14367 Qmeta = intern ("meta");
14368 staticpro (&Qmeta);
14369 Qalt = intern ("alt");
14370 staticpro (&Qalt);
14371 Qctrl = intern ("ctrl");
14372 staticpro (&Qctrl);
14373 Qcontrol = intern ("control");
14374 staticpro (&Qcontrol);
14375 Qshift = intern ("shift");
14376 staticpro (&Qshift);
14377
6fc2811b
JR
14378 /* Text property `display' should be nonsticky by default. */
14379 Vtext_property_default_nonsticky
14380 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14381
14382
14383 Qlaplace = intern ("laplace");
14384 staticpro (&Qlaplace);
3cf3436e
JR
14385 Qemboss = intern ("emboss");
14386 staticpro (&Qemboss);
14387 Qedge_detection = intern ("edge-detection");
14388 staticpro (&Qedge_detection);
14389 Qheuristic = intern ("heuristic");
14390 staticpro (&Qheuristic);
14391 QCmatrix = intern (":matrix");
14392 staticpro (&QCmatrix);
14393 QCcolor_adjustment = intern (":color-adjustment");
14394 staticpro (&QCcolor_adjustment);
14395 QCmask = intern (":mask");
14396 staticpro (&QCmask);
6fc2811b 14397
4b817373
RS
14398 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14399 staticpro (&Qface_set_after_frame_default);
14400
ee78dc32
GV
14401 Fput (Qundefined_color, Qerror_conditions,
14402 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14403 Fput (Qundefined_color, Qerror_message,
14404 build_string ("Undefined color"));
14405
ccc2d29c
GV
14406 staticpro (&w32_grabbed_keys);
14407 w32_grabbed_keys = Qnil;
14408
fbd6baed 14409 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14410 doc: /* An array of color name mappings for windows. */);
fbd6baed 14411 Vw32_color_map = Qnil;
ee78dc32 14412
fbd6baed 14413 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14414 doc: /* Non-nil if alt key presses are passed on to Windows.
14415When non-nil, for example, alt pressed and released and then space will
14416open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14417 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14418
fbd6baed 14419 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14420 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14421When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14422 Vw32_alt_is_meta = Qt;
8c205c63 14423
7d081355 14424 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14425 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14426 XSETINT (Vw32_quit_key, 0);
14427
ccc2d29c
GV
14428 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14429 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14430 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14431When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14432 Vw32_pass_lwindow_to_system = Qt;
14433
14434 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14435 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14436 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14437When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14438 Vw32_pass_rwindow_to_system = Qt;
14439
adcc3809
GV
14440 DEFVAR_INT ("w32-phantom-key-code",
14441 &Vw32_phantom_key_code,
74e1aeec
JR
14442 doc: /* Virtual key code used to generate \"phantom\" key presses.
14443Value is a number between 0 and 255.
14444
14445Phantom key presses are generated in order to stop the system from
14446acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14447`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14448 /* Although 255 is technically not a valid key code, it works and
14449 means that this hack won't interfere with any real key code. */
14450 Vw32_phantom_key_code = 255;
adcc3809 14451
ccc2d29c
GV
14452 DEFVAR_LISP ("w32-enable-num-lock",
14453 &Vw32_enable_num_lock,
74e1aeec
JR
14454 doc: /* Non-nil if Num Lock should act normally.
14455Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14456 Vw32_enable_num_lock = Qt;
14457
14458 DEFVAR_LISP ("w32-enable-caps-lock",
14459 &Vw32_enable_caps_lock,
74e1aeec
JR
14460 doc: /* Non-nil if Caps Lock should act normally.
14461Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14462 Vw32_enable_caps_lock = Qt;
14463
14464 DEFVAR_LISP ("w32-scroll-lock-modifier",
14465 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14466 doc: /* Modifier to use for the Scroll Lock on state.
14467The value can be hyper, super, meta, alt, control or shift for the
14468respective modifier, or nil to see Scroll Lock as the key `scroll'.
14469Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14470 Vw32_scroll_lock_modifier = Qt;
14471
14472 DEFVAR_LISP ("w32-lwindow-modifier",
14473 &Vw32_lwindow_modifier,
74e1aeec
JR
14474 doc: /* Modifier to use for the left \"Windows\" key.
14475The value can be hyper, super, meta, alt, control or shift for the
14476respective modifier, or nil to appear as the key `lwindow'.
14477Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14478 Vw32_lwindow_modifier = Qnil;
14479
14480 DEFVAR_LISP ("w32-rwindow-modifier",
14481 &Vw32_rwindow_modifier,
74e1aeec
JR
14482 doc: /* Modifier to use for the right \"Windows\" key.
14483The value can be hyper, super, meta, alt, control or shift for the
14484respective modifier, or nil to appear as the key `rwindow'.
14485Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14486 Vw32_rwindow_modifier = Qnil;
14487
14488 DEFVAR_LISP ("w32-apps-modifier",
14489 &Vw32_apps_modifier,
74e1aeec
JR
14490 doc: /* Modifier to use for the \"Apps\" key.
14491The value can be hyper, super, meta, alt, control or shift for the
14492respective modifier, or nil to appear as the key `apps'.
14493Any other value will cause the key to be ignored. */);
ccc2d29c 14494 Vw32_apps_modifier = Qnil;
da36a4d6 14495
212da13b 14496 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
74e1aeec 14497 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
6fc2811b 14498 Vw32_enable_synthesized_fonts = Qnil;
5ac45f98 14499
fbd6baed 14500 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 14501 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 14502 Vw32_enable_palette = Qt;
5ac45f98 14503
fbd6baed
GV
14504 DEFVAR_INT ("w32-mouse-button-tolerance",
14505 &Vw32_mouse_button_tolerance,
74e1aeec
JR
14506 doc: /* Analogue of double click interval for faking middle mouse events.
14507The value is the minimum time in milliseconds that must elapse between
14508left/right button down events before they are considered distinct events.
14509If both mouse buttons are depressed within this interval, a middle mouse
14510button down event is generated instead. */);
fbd6baed 14511 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 14512
fbd6baed
GV
14513 DEFVAR_INT ("w32-mouse-move-interval",
14514 &Vw32_mouse_move_interval,
74e1aeec
JR
14515 doc: /* Minimum interval between mouse move events.
14516The value is the minimum time in milliseconds that must elapse between
14517successive mouse move (or scroll bar drag) events before they are
14518reported as lisp events. */);
247be837 14519 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 14520
74214547
JR
14521 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
14522 &w32_pass_extra_mouse_buttons_to_system,
14523 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
14524Recent versions of Windows support mice with up to five buttons.
14525Since most applications don't support these extra buttons, most mouse
14526drivers will allow you to map them to functions at the system level.
14527If this variable is non-nil, Emacs will pass them on, allowing the
14528system to handle them. */);
14529 w32_pass_extra_mouse_buttons_to_system = 0;
14530
ee78dc32
GV
14531 init_x_parm_symbols ();
14532
14533 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 14534 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
14535 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14536
14537 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
14538 doc: /* The shape of the pointer when over text.
14539Changing the value does not affect existing frames
14540unless you set the mouse color. */);
ee78dc32
GV
14541 Vx_pointer_shape = Qnil;
14542
14543 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
14544 doc: /* The name Emacs uses to look up resources; for internal use only.
14545`x-get-resource' uses this as the first component of the instance name
14546when requesting resource values.
14547Emacs initially sets `x-resource-name' to the name under which Emacs
14548was invoked, or to the value specified with the `-name' or `-rn'
14549switches, if present. */);
ee78dc32
GV
14550 Vx_resource_name = Qnil;
14551
14552 Vx_nontext_pointer_shape = Qnil;
14553
14554 Vx_mode_pointer_shape = Qnil;
14555
0af913d7 14556 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
14557 doc: /* The shape of the pointer when Emacs is busy.
14558This variable takes effect when you create a new frame
14559or when you set the mouse color. */);
0af913d7 14560 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 14561
0af913d7 14562 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 14563 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 14564 display_hourglass_p = 1;
6fc2811b 14565
0af913d7 14566 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
14567 doc: /* *Seconds to wait before displaying an hourglass pointer.
14568Value must be an integer or float. */);
0af913d7 14569 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 14570
6fc2811b 14571 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 14572 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
14573 doc: /* The shape of the pointer when over mouse-sensitive text.
14574This variable takes effect when you create a new frame
14575or when you set the mouse color. */);
ee78dc32
GV
14576 Vx_sensitive_text_pointer_shape = Qnil;
14577
4694d762
JR
14578 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14579 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
14580 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14581This variable takes effect when you create a new frame
14582or when you set the mouse color. */);
4694d762
JR
14583 Vx_window_horizontal_drag_shape = Qnil;
14584
ee78dc32 14585 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 14586 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
14587 Vx_cursor_fore_pixel = Qnil;
14588
3cf3436e 14589 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
14590 doc: /* Maximum size for tooltips.
14591Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
14592 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
14593
ee78dc32 14594 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
14595 doc: /* Non-nil if no window manager is in use.
14596Emacs doesn't try to figure this out; this is always nil
14597unless you set it to something else. */);
ee78dc32
GV
14598 /* We don't have any way to find this out, so set it to nil
14599 and maybe the user would like to set it to t. */
14600 Vx_no_window_manager = Qnil;
14601
4587b026
GV
14602 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14603 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
14604 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14605
14606Since Emacs gets width of a font matching with this regexp from
14607PIXEL_SIZE field of the name, font finding mechanism gets faster for
14608such a font. This is especially effective for such large fonts as
14609Chinese, Japanese, and Korean. */);
4587b026
GV
14610 Vx_pixel_size_width_font_regexp = Qnil;
14611
6fc2811b 14612 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
14613 doc: /* Time after which cached images are removed from the cache.
14614When an image has not been displayed this many seconds, remove it
14615from the image cache. Value must be an integer or nil with nil
14616meaning don't clear the cache. */);
6fc2811b
JR
14617 Vimage_cache_eviction_delay = make_number (30 * 60);
14618
33d52f9c
GV
14619 DEFVAR_LISP ("w32-bdf-filename-alist",
14620 &Vw32_bdf_filename_alist,
74e1aeec 14621 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
14622 Vw32_bdf_filename_alist = Qnil;
14623
1075afa9
GV
14624 DEFVAR_BOOL ("w32-strict-fontnames",
14625 &w32_strict_fontnames,
74e1aeec
JR
14626 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14627Default is nil, which allows old fontnames that are not XLFD compliant,
14628and allows third-party CJK display to work by specifying false charset
14629fields to trick Emacs into translating to Big5, SJIS etc.
14630Setting this to t will prevent wrong fonts being selected when
14631fontsets are automatically created. */);
1075afa9
GV
14632 w32_strict_fontnames = 0;
14633
c0611964
AI
14634 DEFVAR_BOOL ("w32-strict-painting",
14635 &w32_strict_painting,
74e1aeec
JR
14636 doc: /* Non-nil means use strict rules for repainting frames.
14637Set this to nil to get the old behaviour for repainting; this should
14638only be necessary if the default setting causes problems. */);
c0611964
AI
14639 w32_strict_painting = 1;
14640
dfff8a69
JR
14641 DEFVAR_LISP ("w32-charset-info-alist",
14642 &Vw32_charset_info_alist,
b3700ae7
JR
14643 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14644Each entry should be of the form:
74e1aeec
JR
14645
14646 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14647
14648where CHARSET_NAME is a string used in font names to identify the charset,
14649WINDOWS_CHARSET is a symbol that can be one of:
14650w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14651w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14652w32-charset-chinesebig5,
dfff8a69 14653#ifdef JOHAB_CHARSET
74e1aeec
JR
14654w32-charset-johab, w32-charset-hebrew,
14655w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14656w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14657w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
14658#endif
14659#ifdef UNICODE_CHARSET
74e1aeec 14660w32-charset-unicode,
dfff8a69 14661#endif
74e1aeec
JR
14662or w32-charset-oem.
14663CODEPAGE should be an integer specifying the codepage that should be used
14664to display the character set, t to do no translation and output as Unicode,
14665or nil to do no translation and output as 8 bit (or multibyte on far-east
14666versions of Windows) characters. */);
dfff8a69
JR
14667 Vw32_charset_info_alist = Qnil;
14668
14669 staticpro (&Qw32_charset_ansi);
14670 Qw32_charset_ansi = intern ("w32-charset-ansi");
14671 staticpro (&Qw32_charset_symbol);
14672 Qw32_charset_symbol = intern ("w32-charset-symbol");
14673 staticpro (&Qw32_charset_shiftjis);
14674 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
14675 staticpro (&Qw32_charset_hangeul);
14676 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
14677 staticpro (&Qw32_charset_chinesebig5);
14678 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
14679 staticpro (&Qw32_charset_gb2312);
14680 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
14681 staticpro (&Qw32_charset_oem);
14682 Qw32_charset_oem = intern ("w32-charset-oem");
14683
14684#ifdef JOHAB_CHARSET
14685 {
14686 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
14687 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
14688 doc: /* Internal variable. */);
dfff8a69
JR
14689
14690 staticpro (&Qw32_charset_johab);
14691 Qw32_charset_johab = intern ("w32-charset-johab");
14692 staticpro (&Qw32_charset_easteurope);
14693 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
14694 staticpro (&Qw32_charset_turkish);
14695 Qw32_charset_turkish = intern ("w32-charset-turkish");
14696 staticpro (&Qw32_charset_baltic);
14697 Qw32_charset_baltic = intern ("w32-charset-baltic");
14698 staticpro (&Qw32_charset_russian);
14699 Qw32_charset_russian = intern ("w32-charset-russian");
14700 staticpro (&Qw32_charset_arabic);
14701 Qw32_charset_arabic = intern ("w32-charset-arabic");
14702 staticpro (&Qw32_charset_greek);
14703 Qw32_charset_greek = intern ("w32-charset-greek");
14704 staticpro (&Qw32_charset_hebrew);
14705 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
14706 staticpro (&Qw32_charset_vietnamese);
14707 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
14708 staticpro (&Qw32_charset_thai);
14709 Qw32_charset_thai = intern ("w32-charset-thai");
14710 staticpro (&Qw32_charset_mac);
14711 Qw32_charset_mac = intern ("w32-charset-mac");
14712 }
14713#endif
14714
14715#ifdef UNICODE_CHARSET
14716 {
14717 static int w32_unicode_charset_defined = 1;
14718 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
14719 &w32_unicode_charset_defined,
14720 doc: /* Internal variable. */);
dfff8a69
JR
14721
14722 staticpro (&Qw32_charset_unicode);
14723 Qw32_charset_unicode = intern ("w32-charset-unicode");
14724#endif
14725
ee78dc32 14726 defsubr (&Sx_get_resource);
767b1ff0 14727#if 0 /* TODO: Port to W32 */
6fc2811b
JR
14728 defsubr (&Sx_change_window_property);
14729 defsubr (&Sx_delete_window_property);
14730 defsubr (&Sx_window_property);
14731#endif
2d764c78 14732 defsubr (&Sxw_display_color_p);
ee78dc32 14733 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
14734 defsubr (&Sxw_color_defined_p);
14735 defsubr (&Sxw_color_values);
ee78dc32
GV
14736 defsubr (&Sx_server_max_request_size);
14737 defsubr (&Sx_server_vendor);
14738 defsubr (&Sx_server_version);
14739 defsubr (&Sx_display_pixel_width);
14740 defsubr (&Sx_display_pixel_height);
14741 defsubr (&Sx_display_mm_width);
14742 defsubr (&Sx_display_mm_height);
14743 defsubr (&Sx_display_screens);
14744 defsubr (&Sx_display_planes);
14745 defsubr (&Sx_display_color_cells);
14746 defsubr (&Sx_display_visual_class);
14747 defsubr (&Sx_display_backing_store);
14748 defsubr (&Sx_display_save_under);
14749 defsubr (&Sx_parse_geometry);
14750 defsubr (&Sx_create_frame);
ee78dc32
GV
14751 defsubr (&Sx_open_connection);
14752 defsubr (&Sx_close_connection);
14753 defsubr (&Sx_display_list);
14754 defsubr (&Sx_synchronize);
14755
fbd6baed 14756 /* W32 specific functions */
ee78dc32 14757
1edf84e7 14758 defsubr (&Sw32_focus_frame);
fbd6baed
GV
14759 defsubr (&Sw32_select_font);
14760 defsubr (&Sw32_define_rgb_color);
14761 defsubr (&Sw32_default_color_map);
14762 defsubr (&Sw32_load_color_file);
1edf84e7 14763 defsubr (&Sw32_send_sys_command);
55dcfc15 14764 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
14765 defsubr (&Sw32_register_hot_key);
14766 defsubr (&Sw32_unregister_hot_key);
14767 defsubr (&Sw32_registered_hot_keys);
14768 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 14769 defsubr (&Sw32_toggle_lock_key);
33d52f9c 14770 defsubr (&Sw32_find_bdf_fonts);
4587b026 14771
2254bcde
AI
14772 defsubr (&Sfile_system_info);
14773
4587b026
GV
14774 /* Setting callback functions for fontset handler. */
14775 get_font_info_func = w32_get_font_info;
6fc2811b
JR
14776
14777#if 0 /* This function pointer doesn't seem to be used anywhere.
14778 And the pointer assigned has the wrong type, anyway. */
4587b026 14779 list_fonts_func = w32_list_fonts;
6fc2811b
JR
14780#endif
14781
4587b026
GV
14782 load_font_func = w32_load_font;
14783 find_ccl_program_func = w32_find_ccl_program;
14784 query_font_func = w32_query_font;
14785 set_frame_fontset_func = x_set_font;
14786 check_window_system_func = check_w32;
6fc2811b 14787
767b1ff0 14788#if 0 /* TODO Image support for W32 */
6fc2811b
JR
14789 /* Images. */
14790 Qxbm = intern ("xbm");
14791 staticpro (&Qxbm);
14792 QCtype = intern (":type");
14793 staticpro (&QCtype);
a93f4566
GM
14794 QCconversion = intern (":conversion");
14795 staticpro (&QCconversion);
6fc2811b
JR
14796 QCheuristic_mask = intern (":heuristic-mask");
14797 staticpro (&QCheuristic_mask);
14798 QCcolor_symbols = intern (":color-symbols");
14799 staticpro (&QCcolor_symbols);
6fc2811b
JR
14800 QCascent = intern (":ascent");
14801 staticpro (&QCascent);
14802 QCmargin = intern (":margin");
14803 staticpro (&QCmargin);
14804 QCrelief = intern (":relief");
14805 staticpro (&QCrelief);
14806 Qpostscript = intern ("postscript");
14807 staticpro (&Qpostscript);
14808 QCloader = intern (":loader");
14809 staticpro (&QCloader);
14810 QCbounding_box = intern (":bounding-box");
14811 staticpro (&QCbounding_box);
14812 QCpt_width = intern (":pt-width");
14813 staticpro (&QCpt_width);
14814 QCpt_height = intern (":pt-height");
14815 staticpro (&QCpt_height);
14816 QCindex = intern (":index");
14817 staticpro (&QCindex);
14818 Qpbm = intern ("pbm");
14819 staticpro (&Qpbm);
14820
14821#if HAVE_XPM
14822 Qxpm = intern ("xpm");
14823 staticpro (&Qxpm);
14824#endif
14825
14826#if HAVE_JPEG
14827 Qjpeg = intern ("jpeg");
14828 staticpro (&Qjpeg);
14829#endif
14830
14831#if HAVE_TIFF
14832 Qtiff = intern ("tiff");
14833 staticpro (&Qtiff);
14834#endif
14835
14836#if HAVE_GIF
14837 Qgif = intern ("gif");
14838 staticpro (&Qgif);
14839#endif
14840
14841#if HAVE_PNG
14842 Qpng = intern ("png");
14843 staticpro (&Qpng);
14844#endif
14845
14846 defsubr (&Sclear_image_cache);
14847
14848#if GLYPH_DEBUG
14849 defsubr (&Simagep);
14850 defsubr (&Slookup_image);
14851#endif
767b1ff0 14852#endif /* TODO */
6fc2811b 14853
0af913d7
GM
14854 hourglass_atimer = NULL;
14855 hourglass_shown_p = 0;
6fc2811b
JR
14856 defsubr (&Sx_show_tip);
14857 defsubr (&Sx_hide_tip);
6fc2811b 14858 tip_timer = Qnil;
57fa2774
JR
14859 staticpro (&tip_timer);
14860 tip_frame = Qnil;
14861 staticpro (&tip_frame);
6fc2811b 14862
ca56d953
JR
14863 last_show_tip_args = Qnil;
14864 staticpro (&last_show_tip_args);
14865
6fc2811b
JR
14866 defsubr (&Sx_file_dialog);
14867}
14868
14869
14870void
14871init_xfns ()
14872{
14873 image_types = NULL;
14874 Vimage_types = Qnil;
14875
767b1ff0 14876#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
14877 define_image_type (&xbm_type);
14878 define_image_type (&gs_type);
14879 define_image_type (&pbm_type);
14880
14881#if HAVE_XPM
14882 define_image_type (&xpm_type);
14883#endif
14884
14885#if HAVE_JPEG
14886 define_image_type (&jpeg_type);
14887#endif
14888
14889#if HAVE_TIFF
14890 define_image_type (&tiff_type);
14891#endif
14892
14893#if HAVE_GIF
14894 define_image_type (&gif_type);
14895#endif
14896
14897#if HAVE_PNG
14898 define_image_type (&png_type);
14899#endif
767b1ff0 14900#endif /* TODO */
ee78dc32
GV
14901}
14902
14903#undef abort
14904
14905void
fbd6baed 14906w32_abort()
ee78dc32 14907{
5ac45f98
GV
14908 int button;
14909 button = MessageBox (NULL,
14910 "A fatal error has occurred!\n\n"
14911 "Select Abort to exit, Retry to debug, Ignore to continue",
14912 "Emacs Abort Dialog",
14913 MB_ICONEXCLAMATION | MB_TASKMODAL
14914 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
14915 switch (button)
14916 {
14917 case IDRETRY:
14918 DebugBreak ();
14919 break;
14920 case IDIGNORE:
14921 break;
14922 case IDABORT:
14923 default:
14924 abort ();
14925 break;
14926 }
ee78dc32 14927}
d573caac 14928
83c75055
GV
14929/* For convenience when debugging. */
14930int
14931w32_last_error()
14932{
14933 return GetLastError ();
14934}