(reseat_1): Set iterator's end_charpos to ZV.
[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
GV
34#include "w32term.h"
35#include "frame.h"
36#include "window.h"
37#include "buffer.h"
126f2e35 38#include "fontset.h"
6fc2811b 39#include "intervals.h"
ee78dc32
GV
40#include "keyboard.h"
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
71eab8d1
AI
55#define max(a, b) ((a) > (b) ? (a) : (b))
56
ee78dc32 57extern void free_frame_menubar ();
6fc2811b 58extern double atof ();
adcc3809 59extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
5ac45f98 60extern int quit_char;
ee78dc32 61
6fc2811b
JR
62/* A definition of XColor for non-X frames. */
63#ifndef HAVE_X_WINDOWS
64typedef struct {
65 unsigned long pixel;
66 unsigned short red, green, blue;
67 char flags;
68 char pad;
69} XColor;
70#endif
71
ccc2d29c
GV
72extern char *lispy_function_keys[];
73
6fc2811b
JR
74/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
75 it, and including `bitmaps/gray' more than once is a problem when
76 config.h defines `static' as an empty replacement string. */
77
78int gray_bitmap_width = gray_width;
79int gray_bitmap_height = gray_height;
80unsigned char *gray_bitmap_bits = gray_bits;
81
ee78dc32 82/* The colormap for converting color names to RGB values */
fbd6baed 83Lisp_Object Vw32_color_map;
ee78dc32 84
da36a4d6 85/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 86Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 87
8c205c63
RS
88/* Non nil if alt key is translated to meta_modifier, nil if it is translated
89 to alt_modifier. */
fbd6baed 90Lisp_Object Vw32_alt_is_meta;
8c205c63 91
7d081355
AI
92/* If non-zero, the windows virtual key code for an alternative quit key. */
93Lisp_Object Vw32_quit_key;
94
ccc2d29c
GV
95/* Non nil if left window key events are passed on to Windows (this only
96 affects whether "tapping" the key opens the Start menu). */
97Lisp_Object Vw32_pass_lwindow_to_system;
98
99/* Non nil if right window key events are passed on to Windows (this
100 only affects whether "tapping" the key opens the Start menu). */
101Lisp_Object Vw32_pass_rwindow_to_system;
102
adcc3809
GV
103/* Virtual key code used to generate "phantom" key presses in order
104 to stop system from acting on Windows key events. */
105Lisp_Object Vw32_phantom_key_code;
106
ccc2d29c
GV
107/* Modifier associated with the left "Windows" key, or nil to act as a
108 normal key. */
109Lisp_Object Vw32_lwindow_modifier;
110
111/* Modifier associated with the right "Windows" key, or nil to act as a
112 normal key. */
113Lisp_Object Vw32_rwindow_modifier;
114
115/* Modifier associated with the "Apps" key, or nil to act as a normal
116 key. */
117Lisp_Object Vw32_apps_modifier;
118
119/* Value is nil if Num Lock acts as a function key. */
120Lisp_Object Vw32_enable_num_lock;
121
122/* Value is nil if Caps Lock acts as a function key. */
123Lisp_Object Vw32_enable_caps_lock;
124
125/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
126Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 127
7ce9aaca 128/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b
JR
129 and italic versions of fonts. */
130Lisp_Object Vw32_enable_synthesized_fonts;
5ac45f98
GV
131
132/* Enable palette management. */
fbd6baed 133Lisp_Object Vw32_enable_palette;
5ac45f98
GV
134
135/* Control how close left/right button down events must be to
136 be converted to a middle button down event. */
fbd6baed 137Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 138
84fb1139
KH
139/* Minimum interval between mouse movement (and scroll bar drag)
140 events that are passed on to the event loop. */
fbd6baed 141Lisp_Object Vw32_mouse_move_interval;
84fb1139 142
ee78dc32
GV
143/* The name we're using in resource queries. */
144Lisp_Object Vx_resource_name;
145
146/* Non nil if no window manager is in use. */
147Lisp_Object Vx_no_window_manager;
148
6fc2811b 149/* Non-zero means we're allowed to display a busy cursor. */
dfff8a69 150
6fc2811b
JR
151int display_busy_cursor_p;
152
ee78dc32
GV
153/* The background and shape of the mouse pointer, and shape when not
154 over text or in the modeline. */
dfff8a69 155
ee78dc32 156Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
4694d762 157Lisp_Object Vx_busy_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 158
ee78dc32 159/* The shape when over mouse-sensitive text. */
dfff8a69 160
ee78dc32
GV
161Lisp_Object Vx_sensitive_text_pointer_shape;
162
163/* Color of chars displayed in cursor box. */
dfff8a69 164
ee78dc32
GV
165Lisp_Object Vx_cursor_fore_pixel;
166
1edf84e7 167/* Nonzero if using Windows. */
dfff8a69 168
1edf84e7
GV
169static int w32_in_use;
170
ee78dc32 171/* Search path for bitmap files. */
dfff8a69 172
ee78dc32
GV
173Lisp_Object Vx_bitmap_file_path;
174
4587b026 175/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 176
4587b026
GV
177Lisp_Object Vx_pixel_size_width_font_regexp;
178
33d52f9c
GV
179/* Alist of bdf fonts and the files that define them. */
180Lisp_Object Vw32_bdf_filename_alist;
181
f46e6225
GV
182Lisp_Object Vw32_system_coding_system;
183
f46e6225 184/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
185int w32_strict_fontnames;
186
c0611964
AI
187/* A flag to control whether we should only repaint if GetUpdateRect
188 indicates there is an update region. */
189int w32_strict_painting;
190
dfff8a69
JR
191/* Associative list linking character set strings to Windows codepages. */
192Lisp_Object Vw32_charset_info_alist;
193
194/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
195#ifndef VIETNAMESE_CHARSET
196#define VIETNAMESE_CHARSET 163
197#endif
198
ee78dc32
GV
199Lisp_Object Qauto_raise;
200Lisp_Object Qauto_lower;
ee78dc32
GV
201Lisp_Object Qbar;
202Lisp_Object Qborder_color;
203Lisp_Object Qborder_width;
204Lisp_Object Qbox;
205Lisp_Object Qcursor_color;
206Lisp_Object Qcursor_type;
ee78dc32
GV
207Lisp_Object Qgeometry;
208Lisp_Object Qicon_left;
209Lisp_Object Qicon_top;
210Lisp_Object Qicon_type;
211Lisp_Object Qicon_name;
212Lisp_Object Qinternal_border_width;
213Lisp_Object Qleft;
1026b400 214Lisp_Object Qright;
ee78dc32
GV
215Lisp_Object Qmouse_color;
216Lisp_Object Qnone;
217Lisp_Object Qparent_id;
218Lisp_Object Qscroll_bar_width;
219Lisp_Object Qsuppress_icon;
ee78dc32
GV
220Lisp_Object Qundefined_color;
221Lisp_Object Qvertical_scroll_bars;
222Lisp_Object Qvisibility;
223Lisp_Object Qwindow_id;
224Lisp_Object Qx_frame_parameter;
225Lisp_Object Qx_resource_name;
226Lisp_Object Quser_position;
227Lisp_Object Quser_size;
6fc2811b 228Lisp_Object Qscreen_gamma;
dfff8a69
JR
229Lisp_Object Qline_spacing;
230Lisp_Object Qcenter;
dc220243 231Lisp_Object Qcancel_timer;
adcc3809
GV
232Lisp_Object Qhyper;
233Lisp_Object Qsuper;
234Lisp_Object Qmeta;
235Lisp_Object Qalt;
236Lisp_Object Qctrl;
237Lisp_Object Qcontrol;
238Lisp_Object Qshift;
239
dfff8a69
JR
240Lisp_Object Qw32_charset_ansi;
241Lisp_Object Qw32_charset_default;
242Lisp_Object Qw32_charset_symbol;
243Lisp_Object Qw32_charset_shiftjis;
767b1ff0 244Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
245Lisp_Object Qw32_charset_gb2312;
246Lisp_Object Qw32_charset_chinesebig5;
247Lisp_Object Qw32_charset_oem;
248
71eab8d1
AI
249#ifndef JOHAB_CHARSET
250#define JOHAB_CHARSET 130
251#endif
dfff8a69
JR
252#ifdef JOHAB_CHARSET
253Lisp_Object Qw32_charset_easteurope;
254Lisp_Object Qw32_charset_turkish;
255Lisp_Object Qw32_charset_baltic;
256Lisp_Object Qw32_charset_russian;
257Lisp_Object Qw32_charset_arabic;
258Lisp_Object Qw32_charset_greek;
259Lisp_Object Qw32_charset_hebrew;
767b1ff0 260Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
261Lisp_Object Qw32_charset_thai;
262Lisp_Object Qw32_charset_johab;
263Lisp_Object Qw32_charset_mac;
264#endif
265
266#ifdef UNICODE_CHARSET
267Lisp_Object Qw32_charset_unicode;
268#endif
269
6fc2811b
JR
270extern Lisp_Object Qtop;
271extern Lisp_Object Qdisplay;
272extern Lisp_Object Qtool_bar_lines;
273
5ac45f98
GV
274/* State variables for emulating a three button mouse. */
275#define LMOUSE 1
276#define MMOUSE 2
277#define RMOUSE 4
278
279static int button_state = 0;
fbd6baed 280static W32Msg saved_mouse_button_msg;
84fb1139 281static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 282static W32Msg saved_mouse_move_msg;
84fb1139
KH
283static unsigned mouse_move_timer;
284
93fbe8b7
GV
285/* W95 mousewheel handler */
286unsigned int msh_mousewheel = 0;
287
84fb1139
KH
288#define MOUSE_BUTTON_ID 1
289#define MOUSE_MOVE_ID 2
5ac45f98 290
ee78dc32 291/* The below are defined in frame.c. */
dfff8a69 292
ee78dc32 293extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 294extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 295extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
296
297extern Lisp_Object Vwindow_system_version;
298
4b817373
RS
299Lisp_Object Qface_set_after_frame_default;
300
937e601e
AI
301#ifdef GLYPH_DEBUG
302int image_cache_refcount, dpyinfo_refcount;
303#endif
304
305
fbd6baed
GV
306/* From w32term.c. */
307extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 308extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 309
ee78dc32 310\f
1edf84e7
GV
311/* Error if we are not connected to MS-Windows. */
312void
313check_w32 ()
314{
315 if (! w32_in_use)
316 error ("MS-Windows not in use or not initialized");
317}
318
319/* Nonzero if we can use mouse menus.
320 You should not call this unless HAVE_MENUS is defined. */
321
322int
323have_menus_p ()
324{
325 return w32_in_use;
326}
327
ee78dc32 328/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 329 and checking validity for W32. */
ee78dc32
GV
330
331FRAME_PTR
332check_x_frame (frame)
333 Lisp_Object frame;
334{
335 FRAME_PTR f;
336
337 if (NILP (frame))
6fc2811b
JR
338 frame = selected_frame;
339 CHECK_LIVE_FRAME (frame, 0);
340 f = XFRAME (frame);
fbd6baed
GV
341 if (! FRAME_W32_P (f))
342 error ("non-w32 frame used");
ee78dc32
GV
343 return f;
344}
345
346/* Let the user specify an display with a frame.
fbd6baed 347 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
348 the first display on the list. */
349
fbd6baed 350static struct w32_display_info *
ee78dc32
GV
351check_x_display_info (frame)
352 Lisp_Object frame;
353{
354 if (NILP (frame))
355 {
6fc2811b
JR
356 struct frame *sf = XFRAME (selected_frame);
357
358 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
359 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 360 else
fbd6baed 361 return &one_w32_display_info;
ee78dc32
GV
362 }
363 else if (STRINGP (frame))
364 return x_display_info_for_name (frame);
365 else
366 {
367 FRAME_PTR f;
368
369 CHECK_LIVE_FRAME (frame, 0);
370 f = XFRAME (frame);
fbd6baed
GV
371 if (! FRAME_W32_P (f))
372 error ("non-w32 frame used");
373 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
374 }
375}
376\f
fbd6baed 377/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
378 It could be the frame's main window or an icon window. */
379
380/* This function can be called during GC, so use GC_xxx type test macros. */
381
382struct frame *
383x_window_to_frame (dpyinfo, wdesc)
fbd6baed 384 struct w32_display_info *dpyinfo;
ee78dc32
GV
385 HWND wdesc;
386{
387 Lisp_Object tail, frame;
388 struct frame *f;
389
8e713be6 390 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 391 {
8e713be6 392 frame = XCAR (tail);
ee78dc32
GV
393 if (!GC_FRAMEP (frame))
394 continue;
395 f = XFRAME (frame);
2d764c78 396 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 397 continue;
f79e6790
JR
398 if (f->output_data.w32->busy_window == wdesc)
399 return f;
400
767b1ff0 401 /* TODO: Check tooltips when supported. */
fbd6baed 402 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
403 return f;
404 }
405 return 0;
406}
407
408\f
409
410/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
411 id, which is just an int that this section returns. Bitmaps are
412 reference counted so they can be shared among frames.
413
414 Bitmap indices are guaranteed to be > 0, so a negative number can
415 be used to indicate no bitmap.
416
417 If you use x_create_bitmap_from_data, then you must keep track of
418 the bitmaps yourself. That is, creating a bitmap from the same
419 data more than once will not be caught. */
420
421
422/* Functions to access the contents of a bitmap, given an id. */
423
424int
425x_bitmap_height (f, id)
426 FRAME_PTR f;
427 int id;
428{
fbd6baed 429 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
430}
431
432int
433x_bitmap_width (f, id)
434 FRAME_PTR f;
435 int id;
436{
fbd6baed 437 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
438}
439
440int
441x_bitmap_pixmap (f, id)
442 FRAME_PTR f;
443 int id;
444{
fbd6baed 445 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
446}
447
448
449/* Allocate a new bitmap record. Returns index of new record. */
450
451static int
452x_allocate_bitmap_record (f)
453 FRAME_PTR f;
454{
fbd6baed 455 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
456 int i;
457
458 if (dpyinfo->bitmaps == NULL)
459 {
460 dpyinfo->bitmaps_size = 10;
461 dpyinfo->bitmaps
fbd6baed 462 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
463 dpyinfo->bitmaps_last = 1;
464 return 1;
465 }
466
467 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
468 return ++dpyinfo->bitmaps_last;
469
470 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
471 if (dpyinfo->bitmaps[i].refcount == 0)
472 return i + 1;
473
474 dpyinfo->bitmaps_size *= 2;
475 dpyinfo->bitmaps
fbd6baed
GV
476 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
477 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
478 return ++dpyinfo->bitmaps_last;
479}
480
481/* Add one reference to the reference count of the bitmap with id ID. */
482
483void
484x_reference_bitmap (f, id)
485 FRAME_PTR f;
486 int id;
487{
fbd6baed 488 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
489}
490
491/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
492
493int
494x_create_bitmap_from_data (f, bits, width, height)
495 struct frame *f;
496 char *bits;
497 unsigned int width, height;
498{
fbd6baed 499 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
500 Pixmap bitmap;
501 int id;
502
503 bitmap = CreateBitmap (width, height,
fbd6baed
GV
504 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
505 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
506 bits);
507
508 if (! bitmap)
509 return -1;
510
511 id = x_allocate_bitmap_record (f);
512 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
513 dpyinfo->bitmaps[id - 1].file = NULL;
514 dpyinfo->bitmaps[id - 1].hinst = NULL;
515 dpyinfo->bitmaps[id - 1].refcount = 1;
516 dpyinfo->bitmaps[id - 1].depth = 1;
517 dpyinfo->bitmaps[id - 1].height = height;
518 dpyinfo->bitmaps[id - 1].width = width;
519
520 return id;
521}
522
523/* Create bitmap from file FILE for frame F. */
524
525int
526x_create_bitmap_from_file (f, file)
527 struct frame *f;
528 Lisp_Object file;
529{
530 return -1;
767b1ff0 531#if 0 /* TODO : bitmap support */
fbd6baed 532 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 533 unsigned int width, height;
6fc2811b 534 HBITMAP bitmap;
ee78dc32
GV
535 int xhot, yhot, result, id;
536 Lisp_Object found;
537 int fd;
538 char *filename;
539 HINSTANCE hinst;
540
541 /* Look for an existing bitmap with the same name. */
542 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
543 {
544 if (dpyinfo->bitmaps[id].refcount
545 && dpyinfo->bitmaps[id].file
546 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
547 {
548 ++dpyinfo->bitmaps[id].refcount;
549 return id + 1;
550 }
551 }
552
553 /* Search bitmap-file-path for the file, if appropriate. */
554 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
555 if (fd < 0)
556 return -1;
6fc2811b 557 emacs_close (fd);
ee78dc32
GV
558
559 filename = (char *) XSTRING (found)->data;
560
561 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
562
563 if (hinst == NULL)
564 return -1;
565
566
fbd6baed 567 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
568 filename, &width, &height, &bitmap, &xhot, &yhot);
569 if (result != BitmapSuccess)
570 return -1;
571
572 id = x_allocate_bitmap_record (f);
573 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
574 dpyinfo->bitmaps[id - 1].refcount = 1;
575 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
576 dpyinfo->bitmaps[id - 1].depth = 1;
577 dpyinfo->bitmaps[id - 1].height = height;
578 dpyinfo->bitmaps[id - 1].width = width;
579 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
580
581 return id;
767b1ff0 582#endif /* TODO */
ee78dc32
GV
583}
584
585/* Remove reference to bitmap with id number ID. */
586
33d52f9c 587void
ee78dc32
GV
588x_destroy_bitmap (f, id)
589 FRAME_PTR f;
590 int id;
591{
fbd6baed 592 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
593
594 if (id > 0)
595 {
596 --dpyinfo->bitmaps[id - 1].refcount;
597 if (dpyinfo->bitmaps[id - 1].refcount == 0)
598 {
599 BLOCK_INPUT;
600 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
601 if (dpyinfo->bitmaps[id - 1].file)
602 {
6fc2811b 603 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
604 dpyinfo->bitmaps[id - 1].file = NULL;
605 }
606 UNBLOCK_INPUT;
607 }
608 }
609}
610
611/* Free all the bitmaps for the display specified by DPYINFO. */
612
613static void
614x_destroy_all_bitmaps (dpyinfo)
fbd6baed 615 struct w32_display_info *dpyinfo;
ee78dc32
GV
616{
617 int i;
618 for (i = 0; i < dpyinfo->bitmaps_last; i++)
619 if (dpyinfo->bitmaps[i].refcount > 0)
620 {
621 DeleteObject (dpyinfo->bitmaps[i].pixmap);
622 if (dpyinfo->bitmaps[i].file)
6fc2811b 623 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
624 }
625 dpyinfo->bitmaps_last = 0;
626}
627\f
fbd6baed 628/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
629 to the ways of passing the parameter values to the window system.
630
631 The name of a parameter, as a Lisp symbol,
632 has an `x-frame-parameter' property which is an integer in Lisp
633 but can be interpreted as an `enum x_frame_parm' in C. */
634
635enum x_frame_parm
636{
637 X_PARM_FOREGROUND_COLOR,
638 X_PARM_BACKGROUND_COLOR,
639 X_PARM_MOUSE_COLOR,
640 X_PARM_CURSOR_COLOR,
641 X_PARM_BORDER_COLOR,
642 X_PARM_ICON_TYPE,
643 X_PARM_FONT,
644 X_PARM_BORDER_WIDTH,
645 X_PARM_INTERNAL_BORDER_WIDTH,
646 X_PARM_NAME,
647 X_PARM_AUTORAISE,
648 X_PARM_AUTOLOWER,
649 X_PARM_VERT_SCROLL_BAR,
650 X_PARM_VISIBILITY,
651 X_PARM_MENU_BAR_LINES
652};
653
654
655struct x_frame_parm_table
656{
657 char *name;
6fc2811b 658 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
659};
660
937e601e
AI
661static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
662static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
663static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 664/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 665void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 666static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
667void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
668void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
669void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
670void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
671void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
672void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
673void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
674void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
675void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
676void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
677 Lisp_Object));
678void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
679void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
680void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
681void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
682 Lisp_Object));
683void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
684void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
685void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
686void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
687void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
688void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
689static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
690
691static struct x_frame_parm_table x_frame_parms[] =
692{
1edf84e7
GV
693 "auto-raise", x_set_autoraise,
694 "auto-lower", x_set_autolower,
ee78dc32 695 "background-color", x_set_background_color,
ee78dc32 696 "border-color", x_set_border_color,
1edf84e7
GV
697 "border-width", x_set_border_width,
698 "cursor-color", x_set_cursor_color,
ee78dc32 699 "cursor-type", x_set_cursor_type,
ee78dc32 700 "font", x_set_font,
1edf84e7
GV
701 "foreground-color", x_set_foreground_color,
702 "icon-name", x_set_icon_name,
703 "icon-type", x_set_icon_type,
ee78dc32 704 "internal-border-width", x_set_internal_border_width,
ee78dc32 705 "menu-bar-lines", x_set_menu_bar_lines,
1edf84e7
GV
706 "mouse-color", x_set_mouse_color,
707 "name", x_explicitly_set_name,
ee78dc32 708 "scroll-bar-width", x_set_scroll_bar_width,
1edf84e7 709 "title", x_set_title,
ee78dc32 710 "unsplittable", x_set_unsplittable,
1edf84e7
GV
711 "vertical-scroll-bars", x_set_vertical_scroll_bars,
712 "visibility", x_set_visibility,
6fc2811b 713 "tool-bar-lines", x_set_tool_bar_lines,
dfff8a69
JR
714 "screen-gamma", x_set_screen_gamma,
715 "line-spacing", x_set_line_spacing
ee78dc32
GV
716};
717
718/* Attach the `x-frame-parameter' properties to
fbd6baed 719 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 720
dfff8a69 721void
ee78dc32
GV
722init_x_parm_symbols ()
723{
724 int i;
725
726 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
727 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
728 make_number (i));
729}
730\f
dfff8a69 731/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
732 If a parameter is not specially recognized, do nothing;
733 otherwise call the `x_set_...' function for that parameter. */
734
735void
736x_set_frame_parameters (f, alist)
737 FRAME_PTR f;
738 Lisp_Object alist;
739{
740 Lisp_Object tail;
741
742 /* If both of these parameters are present, it's more efficient to
743 set them both at once. So we wait until we've looked at the
744 entire list before we set them. */
b839712d 745 int width, height;
ee78dc32
GV
746
747 /* Same here. */
748 Lisp_Object left, top;
749
750 /* Same with these. */
751 Lisp_Object icon_left, icon_top;
752
753 /* Record in these vectors all the parms specified. */
754 Lisp_Object *parms;
755 Lisp_Object *values;
a797a73d 756 int i, p;
ee78dc32
GV
757 int left_no_change = 0, top_no_change = 0;
758 int icon_left_no_change = 0, icon_top_no_change = 0;
759
5878523b
RS
760 struct gcpro gcpro1, gcpro2;
761
ee78dc32
GV
762 i = 0;
763 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
764 i++;
765
766 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
767 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
768
769 /* Extract parm names and values into those vectors. */
770
771 i = 0;
772 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
773 {
6fc2811b 774 Lisp_Object elt;
ee78dc32
GV
775
776 elt = Fcar (tail);
777 parms[i] = Fcar (elt);
778 values[i] = Fcdr (elt);
779 i++;
780 }
5878523b
RS
781 /* TAIL and ALIST are not used again below here. */
782 alist = tail = Qnil;
783
784 GCPRO2 (*parms, *values);
785 gcpro1.nvars = i;
786 gcpro2.nvars = i;
787
788 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
789 because their values appear in VALUES and strings are not valid. */
b839712d 790 top = left = Qunbound;
ee78dc32
GV
791 icon_left = icon_top = Qunbound;
792
b839712d 793 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
794 if (FRAME_NEW_WIDTH (f))
795 width = FRAME_NEW_WIDTH (f);
796 else
797 width = FRAME_WIDTH (f);
798
799 if (FRAME_NEW_HEIGHT (f))
800 height = FRAME_NEW_HEIGHT (f);
801 else
802 height = FRAME_HEIGHT (f);
b839712d 803
a797a73d
GV
804 /* Process foreground_color and background_color before anything else.
805 They are independent of other properties, but other properties (e.g.,
806 cursor_color) are dependent upon them. */
807 for (p = 0; p < i; p++)
808 {
809 Lisp_Object prop, val;
810
811 prop = parms[p];
812 val = values[p];
813 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
814 {
815 register Lisp_Object param_index, old_value;
816
817 param_index = Fget (prop, Qx_frame_parameter);
818 old_value = get_frame_param (f, prop);
819 store_frame_param (f, prop, val);
820 if (NATNUMP (param_index)
821 && (XFASTINT (param_index)
822 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
823 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
824 }
825 }
826
ee78dc32
GV
827 /* Now process them in reverse of specified order. */
828 for (i--; i >= 0; i--)
829 {
830 Lisp_Object prop, val;
831
832 prop = parms[i];
833 val = values[i];
834
b839712d
RS
835 if (EQ (prop, Qwidth) && NUMBERP (val))
836 width = XFASTINT (val);
837 else if (EQ (prop, Qheight) && NUMBERP (val))
838 height = XFASTINT (val);
ee78dc32
GV
839 else if (EQ (prop, Qtop))
840 top = val;
841 else if (EQ (prop, Qleft))
842 left = val;
843 else if (EQ (prop, Qicon_top))
844 icon_top = val;
845 else if (EQ (prop, Qicon_left))
846 icon_left = val;
a797a73d
GV
847 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
848 /* Processed above. */
849 continue;
ee78dc32
GV
850 else
851 {
852 register Lisp_Object param_index, old_value;
853
854 param_index = Fget (prop, Qx_frame_parameter);
855 old_value = get_frame_param (f, prop);
856 store_frame_param (f, prop, val);
857 if (NATNUMP (param_index)
858 && (XFASTINT (param_index)
859 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 860 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
861 }
862 }
863
864 /* Don't die if just one of these was set. */
865 if (EQ (left, Qunbound))
866 {
867 left_no_change = 1;
fbd6baed
GV
868 if (f->output_data.w32->left_pos < 0)
869 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 870 else
fbd6baed 871 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
872 }
873 if (EQ (top, Qunbound))
874 {
875 top_no_change = 1;
fbd6baed
GV
876 if (f->output_data.w32->top_pos < 0)
877 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 878 else
fbd6baed 879 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
880 }
881
882 /* If one of the icon positions was not set, preserve or default it. */
883 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
884 {
885 icon_left_no_change = 1;
886 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
887 if (NILP (icon_left))
888 XSETINT (icon_left, 0);
889 }
890 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
891 {
892 icon_top_no_change = 1;
893 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
894 if (NILP (icon_top))
895 XSETINT (icon_top, 0);
896 }
897
ee78dc32
GV
898 /* Don't set these parameters unless they've been explicitly
899 specified. The window might be mapped or resized while we're in
900 this function, and we don't want to override that unless the lisp
901 code has asked for it.
902
903 Don't set these parameters unless they actually differ from the
904 window's current parameters; the window may not actually exist
905 yet. */
906 {
907 Lisp_Object frame;
908
909 check_frame_size (f, &height, &width);
910
911 XSETFRAME (frame, f);
912
dfff8a69
JR
913 if (width != FRAME_WIDTH (f)
914 || height != FRAME_HEIGHT (f)
915 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 916 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
917
918 if ((!NILP (left) || !NILP (top))
919 && ! (left_no_change && top_no_change)
fbd6baed
GV
920 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
921 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
922 {
923 int leftpos = 0;
924 int toppos = 0;
925
926 /* Record the signs. */
fbd6baed 927 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 928 if (EQ (left, Qminus))
fbd6baed 929 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
930 else if (INTEGERP (left))
931 {
932 leftpos = XINT (left);
933 if (leftpos < 0)
fbd6baed 934 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 935 }
8e713be6
KR
936 else if (CONSP (left) && EQ (XCAR (left), Qminus)
937 && CONSP (XCDR (left))
938 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 939 {
8e713be6 940 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 941 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 942 }
8e713be6
KR
943 else if (CONSP (left) && EQ (XCAR (left), Qplus)
944 && CONSP (XCDR (left))
945 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 946 {
8e713be6 947 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
948 }
949
950 if (EQ (top, Qminus))
fbd6baed 951 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
952 else if (INTEGERP (top))
953 {
954 toppos = XINT (top);
955 if (toppos < 0)
fbd6baed 956 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 957 }
8e713be6
KR
958 else if (CONSP (top) && EQ (XCAR (top), Qminus)
959 && CONSP (XCDR (top))
960 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 961 {
8e713be6 962 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 963 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 964 }
8e713be6
KR
965 else if (CONSP (top) && EQ (XCAR (top), Qplus)
966 && CONSP (XCDR (top))
967 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 968 {
8e713be6 969 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
970 }
971
972
973 /* Store the numeric value of the position. */
fbd6baed
GV
974 f->output_data.w32->top_pos = toppos;
975 f->output_data.w32->left_pos = leftpos;
ee78dc32 976
fbd6baed 977 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
978
979 /* Actually set that position, and convert to absolute. */
980 x_set_offset (f, leftpos, toppos, -1);
981 }
982
983 if ((!NILP (icon_left) || !NILP (icon_top))
984 && ! (icon_left_no_change && icon_top_no_change))
985 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
986 }
5878523b
RS
987
988 UNGCPRO;
ee78dc32
GV
989}
990
991/* Store the screen positions of frame F into XPTR and YPTR.
992 These are the positions of the containing window manager window,
993 not Emacs's own window. */
994
995void
996x_real_positions (f, xptr, yptr)
997 FRAME_PTR f;
998 int *xptr, *yptr;
999{
1000 POINT pt;
3c190163
GV
1001
1002 {
1003 RECT rect;
ee78dc32 1004
fbd6baed
GV
1005 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1006 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 1007
3c190163
GV
1008 pt.x = rect.left;
1009 pt.y = rect.top;
1010 }
ee78dc32 1011
fbd6baed 1012 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
1013
1014 *xptr = pt.x;
1015 *yptr = pt.y;
1016}
1017
1018/* Insert a description of internally-recorded parameters of frame X
1019 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1020 Only parameters that are specific to W32
ee78dc32
GV
1021 and whose values are not correctly recorded in the frame's
1022 param_alist need to be considered here. */
1023
dfff8a69 1024void
ee78dc32
GV
1025x_report_frame_params (f, alistptr)
1026 struct frame *f;
1027 Lisp_Object *alistptr;
1028{
1029 char buf[16];
1030 Lisp_Object tem;
1031
1032 /* Represent negative positions (off the top or left screen edge)
1033 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1034 XSETINT (tem, f->output_data.w32->left_pos);
1035 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1036 store_in_alist (alistptr, Qleft, tem);
1037 else
1038 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1039
fbd6baed
GV
1040 XSETINT (tem, f->output_data.w32->top_pos);
1041 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1042 store_in_alist (alistptr, Qtop, tem);
1043 else
1044 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1045
1046 store_in_alist (alistptr, Qborder_width,
fbd6baed 1047 make_number (f->output_data.w32->border_width));
ee78dc32 1048 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed
GV
1049 make_number (f->output_data.w32->internal_border_width));
1050 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1051 store_in_alist (alistptr, Qwindow_id,
1052 build_string (buf));
1053 store_in_alist (alistptr, Qicon_name, f->icon_name);
1054 FRAME_SAMPLE_VISIBILITY (f);
1055 store_in_alist (alistptr, Qvisibility,
1056 (FRAME_VISIBLE_P (f) ? Qt
1057 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1058 store_in_alist (alistptr, Qdisplay,
8e713be6 1059 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1060}
1061\f
1062
fbd6baed 1063DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
5ac45f98 1064 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
fbd6baed 1065This adds or updates a named color to w32-color-map, making it available for use.\n\
5ac45f98
GV
1066The original entry's RGB ref is returned, or nil if the entry is new.")
1067 (red, green, blue, name)
1068 Lisp_Object red, green, blue, name;
ee78dc32 1069{
5ac45f98
GV
1070 Lisp_Object rgb;
1071 Lisp_Object oldrgb = Qnil;
1072 Lisp_Object entry;
1073
1074 CHECK_NUMBER (red, 0);
1075 CHECK_NUMBER (green, 0);
1076 CHECK_NUMBER (blue, 0);
1077 CHECK_STRING (name, 0);
ee78dc32 1078
5ac45f98 1079 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1080
5ac45f98 1081 BLOCK_INPUT;
ee78dc32 1082
fbd6baed
GV
1083 /* replace existing entry in w32-color-map or add new entry. */
1084 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1085 if (NILP (entry))
1086 {
1087 entry = Fcons (name, rgb);
fbd6baed 1088 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1089 }
1090 else
1091 {
1092 oldrgb = Fcdr (entry);
1093 Fsetcdr (entry, rgb);
1094 }
1095
1096 UNBLOCK_INPUT;
1097
1098 return (oldrgb);
ee78dc32
GV
1099}
1100
fbd6baed 1101DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
5ac45f98 1102 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
fbd6baed 1103Assign this value to w32-color-map to replace the existing color map.\n\
5ac45f98
GV
1104\
1105The file should define one named RGB color per line like so:\
1106 R G B name\n\
1107where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1108 (filename)
1109 Lisp_Object filename;
1110{
1111 FILE *fp;
1112 Lisp_Object cmap = Qnil;
1113 Lisp_Object abspath;
1114
1115 CHECK_STRING (filename, 0);
1116 abspath = Fexpand_file_name (filename, Qnil);
1117
1118 fp = fopen (XSTRING (filename)->data, "rt");
1119 if (fp)
1120 {
1121 char buf[512];
1122 int red, green, blue;
1123 int num;
1124
1125 BLOCK_INPUT;
1126
1127 while (fgets (buf, sizeof (buf), fp) != NULL) {
1128 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1129 {
1130 char *name = buf + num;
1131 num = strlen (name) - 1;
1132 if (name[num] == '\n')
1133 name[num] = 0;
1134 cmap = Fcons (Fcons (build_string (name),
1135 make_number (RGB (red, green, blue))),
1136 cmap);
1137 }
1138 }
1139 fclose (fp);
1140
1141 UNBLOCK_INPUT;
1142 }
1143
1144 return cmap;
1145}
ee78dc32 1146
fbd6baed 1147/* The default colors for the w32 color map */
ee78dc32
GV
1148typedef struct colormap_t
1149{
1150 char *name;
1151 COLORREF colorref;
1152} colormap_t;
1153
fbd6baed 1154colormap_t w32_color_map[] =
ee78dc32 1155{
1da8a614
GV
1156 {"snow" , PALETTERGB (255,250,250)},
1157 {"ghost white" , PALETTERGB (248,248,255)},
1158 {"GhostWhite" , PALETTERGB (248,248,255)},
1159 {"white smoke" , PALETTERGB (245,245,245)},
1160 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1161 {"gainsboro" , PALETTERGB (220,220,220)},
1162 {"floral white" , PALETTERGB (255,250,240)},
1163 {"FloralWhite" , PALETTERGB (255,250,240)},
1164 {"old lace" , PALETTERGB (253,245,230)},
1165 {"OldLace" , PALETTERGB (253,245,230)},
1166 {"linen" , PALETTERGB (250,240,230)},
1167 {"antique white" , PALETTERGB (250,235,215)},
1168 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1169 {"papaya whip" , PALETTERGB (255,239,213)},
1170 {"PapayaWhip" , PALETTERGB (255,239,213)},
1171 {"blanched almond" , PALETTERGB (255,235,205)},
1172 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1173 {"bisque" , PALETTERGB (255,228,196)},
1174 {"peach puff" , PALETTERGB (255,218,185)},
1175 {"PeachPuff" , PALETTERGB (255,218,185)},
1176 {"navajo white" , PALETTERGB (255,222,173)},
1177 {"NavajoWhite" , PALETTERGB (255,222,173)},
1178 {"moccasin" , PALETTERGB (255,228,181)},
1179 {"cornsilk" , PALETTERGB (255,248,220)},
1180 {"ivory" , PALETTERGB (255,255,240)},
1181 {"lemon chiffon" , PALETTERGB (255,250,205)},
1182 {"LemonChiffon" , PALETTERGB (255,250,205)},
1183 {"seashell" , PALETTERGB (255,245,238)},
1184 {"honeydew" , PALETTERGB (240,255,240)},
1185 {"mint cream" , PALETTERGB (245,255,250)},
1186 {"MintCream" , PALETTERGB (245,255,250)},
1187 {"azure" , PALETTERGB (240,255,255)},
1188 {"alice blue" , PALETTERGB (240,248,255)},
1189 {"AliceBlue" , PALETTERGB (240,248,255)},
1190 {"lavender" , PALETTERGB (230,230,250)},
1191 {"lavender blush" , PALETTERGB (255,240,245)},
1192 {"LavenderBlush" , PALETTERGB (255,240,245)},
1193 {"misty rose" , PALETTERGB (255,228,225)},
1194 {"MistyRose" , PALETTERGB (255,228,225)},
1195 {"white" , PALETTERGB (255,255,255)},
1196 {"black" , PALETTERGB ( 0, 0, 0)},
1197 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1198 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1199 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1200 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1201 {"dim gray" , PALETTERGB (105,105,105)},
1202 {"DimGray" , PALETTERGB (105,105,105)},
1203 {"dim grey" , PALETTERGB (105,105,105)},
1204 {"DimGrey" , PALETTERGB (105,105,105)},
1205 {"slate gray" , PALETTERGB (112,128,144)},
1206 {"SlateGray" , PALETTERGB (112,128,144)},
1207 {"slate grey" , PALETTERGB (112,128,144)},
1208 {"SlateGrey" , PALETTERGB (112,128,144)},
1209 {"light slate gray" , PALETTERGB (119,136,153)},
1210 {"LightSlateGray" , PALETTERGB (119,136,153)},
1211 {"light slate grey" , PALETTERGB (119,136,153)},
1212 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1213 {"gray" , PALETTERGB (190,190,190)},
1214 {"grey" , PALETTERGB (190,190,190)},
1215 {"light grey" , PALETTERGB (211,211,211)},
1216 {"LightGrey" , PALETTERGB (211,211,211)},
1217 {"light gray" , PALETTERGB (211,211,211)},
1218 {"LightGray" , PALETTERGB (211,211,211)},
1219 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1220 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1221 {"navy" , PALETTERGB ( 0, 0,128)},
1222 {"navy blue" , PALETTERGB ( 0, 0,128)},
1223 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1224 {"cornflower blue" , PALETTERGB (100,149,237)},
1225 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1226 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1227 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1228 {"slate blue" , PALETTERGB (106, 90,205)},
1229 {"SlateBlue" , PALETTERGB (106, 90,205)},
1230 {"medium slate blue" , PALETTERGB (123,104,238)},
1231 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1232 {"light slate blue" , PALETTERGB (132,112,255)},
1233 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1234 {"medium blue" , PALETTERGB ( 0, 0,205)},
1235 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1236 {"royal blue" , PALETTERGB ( 65,105,225)},
1237 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1238 {"blue" , PALETTERGB ( 0, 0,255)},
1239 {"dodger blue" , PALETTERGB ( 30,144,255)},
1240 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1241 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1242 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1243 {"sky blue" , PALETTERGB (135,206,235)},
1244 {"SkyBlue" , PALETTERGB (135,206,235)},
1245 {"light sky blue" , PALETTERGB (135,206,250)},
1246 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1247 {"steel blue" , PALETTERGB ( 70,130,180)},
1248 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1249 {"light steel blue" , PALETTERGB (176,196,222)},
1250 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1251 {"light blue" , PALETTERGB (173,216,230)},
1252 {"LightBlue" , PALETTERGB (173,216,230)},
1253 {"powder blue" , PALETTERGB (176,224,230)},
1254 {"PowderBlue" , PALETTERGB (176,224,230)},
1255 {"pale turquoise" , PALETTERGB (175,238,238)},
1256 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1257 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1258 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1259 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1260 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1261 {"turquoise" , PALETTERGB ( 64,224,208)},
1262 {"cyan" , PALETTERGB ( 0,255,255)},
1263 {"light cyan" , PALETTERGB (224,255,255)},
1264 {"LightCyan" , PALETTERGB (224,255,255)},
1265 {"cadet blue" , PALETTERGB ( 95,158,160)},
1266 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1267 {"medium aquamarine" , PALETTERGB (102,205,170)},
1268 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1269 {"aquamarine" , PALETTERGB (127,255,212)},
1270 {"dark green" , PALETTERGB ( 0,100, 0)},
1271 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1272 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1273 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1274 {"dark sea green" , PALETTERGB (143,188,143)},
1275 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1276 {"sea green" , PALETTERGB ( 46,139, 87)},
1277 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1278 {"medium sea green" , PALETTERGB ( 60,179,113)},
1279 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1280 {"light sea green" , PALETTERGB ( 32,178,170)},
1281 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1282 {"pale green" , PALETTERGB (152,251,152)},
1283 {"PaleGreen" , PALETTERGB (152,251,152)},
1284 {"spring green" , PALETTERGB ( 0,255,127)},
1285 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1286 {"lawn green" , PALETTERGB (124,252, 0)},
1287 {"LawnGreen" , PALETTERGB (124,252, 0)},
1288 {"green" , PALETTERGB ( 0,255, 0)},
1289 {"chartreuse" , PALETTERGB (127,255, 0)},
1290 {"medium spring green" , PALETTERGB ( 0,250,154)},
1291 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1292 {"green yellow" , PALETTERGB (173,255, 47)},
1293 {"GreenYellow" , PALETTERGB (173,255, 47)},
1294 {"lime green" , PALETTERGB ( 50,205, 50)},
1295 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1296 {"yellow green" , PALETTERGB (154,205, 50)},
1297 {"YellowGreen" , PALETTERGB (154,205, 50)},
1298 {"forest green" , PALETTERGB ( 34,139, 34)},
1299 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1300 {"olive drab" , PALETTERGB (107,142, 35)},
1301 {"OliveDrab" , PALETTERGB (107,142, 35)},
1302 {"dark khaki" , PALETTERGB (189,183,107)},
1303 {"DarkKhaki" , PALETTERGB (189,183,107)},
1304 {"khaki" , PALETTERGB (240,230,140)},
1305 {"pale goldenrod" , PALETTERGB (238,232,170)},
1306 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1307 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1308 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1309 {"light yellow" , PALETTERGB (255,255,224)},
1310 {"LightYellow" , PALETTERGB (255,255,224)},
1311 {"yellow" , PALETTERGB (255,255, 0)},
1312 {"gold" , PALETTERGB (255,215, 0)},
1313 {"light goldenrod" , PALETTERGB (238,221,130)},
1314 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1315 {"goldenrod" , PALETTERGB (218,165, 32)},
1316 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1317 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1318 {"rosy brown" , PALETTERGB (188,143,143)},
1319 {"RosyBrown" , PALETTERGB (188,143,143)},
1320 {"indian red" , PALETTERGB (205, 92, 92)},
1321 {"IndianRed" , PALETTERGB (205, 92, 92)},
1322 {"saddle brown" , PALETTERGB (139, 69, 19)},
1323 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1324 {"sienna" , PALETTERGB (160, 82, 45)},
1325 {"peru" , PALETTERGB (205,133, 63)},
1326 {"burlywood" , PALETTERGB (222,184,135)},
1327 {"beige" , PALETTERGB (245,245,220)},
1328 {"wheat" , PALETTERGB (245,222,179)},
1329 {"sandy brown" , PALETTERGB (244,164, 96)},
1330 {"SandyBrown" , PALETTERGB (244,164, 96)},
1331 {"tan" , PALETTERGB (210,180,140)},
1332 {"chocolate" , PALETTERGB (210,105, 30)},
1333 {"firebrick" , PALETTERGB (178,34, 34)},
1334 {"brown" , PALETTERGB (165,42, 42)},
1335 {"dark salmon" , PALETTERGB (233,150,122)},
1336 {"DarkSalmon" , PALETTERGB (233,150,122)},
1337 {"salmon" , PALETTERGB (250,128,114)},
1338 {"light salmon" , PALETTERGB (255,160,122)},
1339 {"LightSalmon" , PALETTERGB (255,160,122)},
1340 {"orange" , PALETTERGB (255,165, 0)},
1341 {"dark orange" , PALETTERGB (255,140, 0)},
1342 {"DarkOrange" , PALETTERGB (255,140, 0)},
1343 {"coral" , PALETTERGB (255,127, 80)},
1344 {"light coral" , PALETTERGB (240,128,128)},
1345 {"LightCoral" , PALETTERGB (240,128,128)},
1346 {"tomato" , PALETTERGB (255, 99, 71)},
1347 {"orange red" , PALETTERGB (255, 69, 0)},
1348 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1349 {"red" , PALETTERGB (255, 0, 0)},
1350 {"hot pink" , PALETTERGB (255,105,180)},
1351 {"HotPink" , PALETTERGB (255,105,180)},
1352 {"deep pink" , PALETTERGB (255, 20,147)},
1353 {"DeepPink" , PALETTERGB (255, 20,147)},
1354 {"pink" , PALETTERGB (255,192,203)},
1355 {"light pink" , PALETTERGB (255,182,193)},
1356 {"LightPink" , PALETTERGB (255,182,193)},
1357 {"pale violet red" , PALETTERGB (219,112,147)},
1358 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1359 {"maroon" , PALETTERGB (176, 48, 96)},
1360 {"medium violet red" , PALETTERGB (199, 21,133)},
1361 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1362 {"violet red" , PALETTERGB (208, 32,144)},
1363 {"VioletRed" , PALETTERGB (208, 32,144)},
1364 {"magenta" , PALETTERGB (255, 0,255)},
1365 {"violet" , PALETTERGB (238,130,238)},
1366 {"plum" , PALETTERGB (221,160,221)},
1367 {"orchid" , PALETTERGB (218,112,214)},
1368 {"medium orchid" , PALETTERGB (186, 85,211)},
1369 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1370 {"dark orchid" , PALETTERGB (153, 50,204)},
1371 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1372 {"dark violet" , PALETTERGB (148, 0,211)},
1373 {"DarkViolet" , PALETTERGB (148, 0,211)},
1374 {"blue violet" , PALETTERGB (138, 43,226)},
1375 {"BlueViolet" , PALETTERGB (138, 43,226)},
1376 {"purple" , PALETTERGB (160, 32,240)},
1377 {"medium purple" , PALETTERGB (147,112,219)},
1378 {"MediumPurple" , PALETTERGB (147,112,219)},
1379 {"thistle" , PALETTERGB (216,191,216)},
1380 {"gray0" , PALETTERGB ( 0, 0, 0)},
1381 {"grey0" , PALETTERGB ( 0, 0, 0)},
1382 {"dark grey" , PALETTERGB (169,169,169)},
1383 {"DarkGrey" , PALETTERGB (169,169,169)},
1384 {"dark gray" , PALETTERGB (169,169,169)},
1385 {"DarkGray" , PALETTERGB (169,169,169)},
1386 {"dark blue" , PALETTERGB ( 0, 0,139)},
1387 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1388 {"dark cyan" , PALETTERGB ( 0,139,139)},
1389 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1390 {"dark magenta" , PALETTERGB (139, 0,139)},
1391 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1392 {"dark red" , PALETTERGB (139, 0, 0)},
1393 {"DarkRed" , PALETTERGB (139, 0, 0)},
1394 {"light green" , PALETTERGB (144,238,144)},
1395 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1396};
1397
fbd6baed 1398DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
ee78dc32
GV
1399 0, 0, 0, "Return the default color map.")
1400 ()
1401{
1402 int i;
fbd6baed 1403 colormap_t *pc = w32_color_map;
ee78dc32
GV
1404 Lisp_Object cmap;
1405
1406 BLOCK_INPUT;
1407
1408 cmap = Qnil;
1409
fbd6baed 1410 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1411 pc++, i++)
1412 cmap = Fcons (Fcons (build_string (pc->name),
1413 make_number (pc->colorref)),
1414 cmap);
1415
1416 UNBLOCK_INPUT;
1417
1418 return (cmap);
1419}
ee78dc32
GV
1420
1421Lisp_Object
fbd6baed 1422w32_to_x_color (rgb)
ee78dc32
GV
1423 Lisp_Object rgb;
1424{
1425 Lisp_Object color;
1426
1427 CHECK_NUMBER (rgb, 0);
1428
1429 BLOCK_INPUT;
1430
fbd6baed 1431 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1432
1433 UNBLOCK_INPUT;
1434
1435 if (!NILP (color))
1436 return (Fcar (color));
1437 else
1438 return Qnil;
1439}
1440
5d7fed93
GV
1441COLORREF
1442w32_color_map_lookup (colorname)
1443 char *colorname;
1444{
1445 Lisp_Object tail, ret = Qnil;
1446
1447 BLOCK_INPUT;
1448
1449 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1450 {
1451 register Lisp_Object elt, tem;
1452
1453 elt = Fcar (tail);
1454 if (!CONSP (elt)) continue;
1455
1456 tem = Fcar (elt);
1457
1458 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1459 {
1460 ret = XUINT (Fcdr (elt));
1461 break;
1462 }
1463
1464 QUIT;
1465 }
1466
1467
1468 UNBLOCK_INPUT;
1469
1470 return ret;
1471}
1472
ee78dc32 1473COLORREF
fbd6baed 1474x_to_w32_color (colorname)
ee78dc32
GV
1475 char * colorname;
1476{
8edb0a6f
JR
1477 register Lisp_Object ret = Qnil;
1478
ee78dc32 1479 BLOCK_INPUT;
1edf84e7
GV
1480
1481 if (colorname[0] == '#')
1482 {
1483 /* Could be an old-style RGB Device specification. */
1484 char *color;
1485 int size;
1486 color = colorname + 1;
1487
1488 size = strlen(color);
1489 if (size == 3 || size == 6 || size == 9 || size == 12)
1490 {
1491 UINT colorval;
1492 int i, pos;
1493 pos = 0;
1494 size /= 3;
1495 colorval = 0;
1496
1497 for (i = 0; i < 3; i++)
1498 {
1499 char *end;
1500 char t;
1501 unsigned long value;
1502
1503 /* The check for 'x' in the following conditional takes into
1504 account the fact that strtol allows a "0x" in front of
1505 our numbers, and we don't. */
1506 if (!isxdigit(color[0]) || color[1] == 'x')
1507 break;
1508 t = color[size];
1509 color[size] = '\0';
1510 value = strtoul(color, &end, 16);
1511 color[size] = t;
1512 if (errno == ERANGE || end - color != size)
1513 break;
1514 switch (size)
1515 {
1516 case 1:
1517 value = value * 0x10;
1518 break;
1519 case 2:
1520 break;
1521 case 3:
1522 value /= 0x10;
1523 break;
1524 case 4:
1525 value /= 0x100;
1526 break;
1527 }
1528 colorval |= (value << pos);
1529 pos += 0x8;
1530 if (i == 2)
1531 {
1532 UNBLOCK_INPUT;
1533 return (colorval);
1534 }
1535 color = end;
1536 }
1537 }
1538 }
1539 else if (strnicmp(colorname, "rgb:", 4) == 0)
1540 {
1541 char *color;
1542 UINT colorval;
1543 int i, pos;
1544 pos = 0;
1545
1546 colorval = 0;
1547 color = colorname + 4;
1548 for (i = 0; i < 3; i++)
1549 {
1550 char *end;
1551 unsigned long value;
1552
1553 /* The check for 'x' in the following conditional takes into
1554 account the fact that strtol allows a "0x" in front of
1555 our numbers, and we don't. */
1556 if (!isxdigit(color[0]) || color[1] == 'x')
1557 break;
1558 value = strtoul(color, &end, 16);
1559 if (errno == ERANGE)
1560 break;
1561 switch (end - color)
1562 {
1563 case 1:
1564 value = value * 0x10 + value;
1565 break;
1566 case 2:
1567 break;
1568 case 3:
1569 value /= 0x10;
1570 break;
1571 case 4:
1572 value /= 0x100;
1573 break;
1574 default:
1575 value = ULONG_MAX;
1576 }
1577 if (value == ULONG_MAX)
1578 break;
1579 colorval |= (value << pos);
1580 pos += 0x8;
1581 if (i == 2)
1582 {
1583 if (*end != '\0')
1584 break;
1585 UNBLOCK_INPUT;
1586 return (colorval);
1587 }
1588 if (*end != '/')
1589 break;
1590 color = end + 1;
1591 }
1592 }
1593 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1594 {
1595 /* This is an RGB Intensity specification. */
1596 char *color;
1597 UINT colorval;
1598 int i, pos;
1599 pos = 0;
1600
1601 colorval = 0;
1602 color = colorname + 5;
1603 for (i = 0; i < 3; i++)
1604 {
1605 char *end;
1606 double value;
1607 UINT val;
1608
1609 value = strtod(color, &end);
1610 if (errno == ERANGE)
1611 break;
1612 if (value < 0.0 || value > 1.0)
1613 break;
1614 val = (UINT)(0x100 * value);
1615 /* We used 0x100 instead of 0xFF to give an continuous
1616 range between 0.0 and 1.0 inclusive. The next statement
1617 fixes the 1.0 case. */
1618 if (val == 0x100)
1619 val = 0xFF;
1620 colorval |= (val << pos);
1621 pos += 0x8;
1622 if (i == 2)
1623 {
1624 if (*end != '\0')
1625 break;
1626 UNBLOCK_INPUT;
1627 return (colorval);
1628 }
1629 if (*end != '/')
1630 break;
1631 color = end + 1;
1632 }
1633 }
1634 /* I am not going to attempt to handle any of the CIE color schemes
1635 or TekHVC, since I don't know the algorithms for conversion to
1636 RGB. */
f695b4b1
GV
1637
1638 /* If we fail to lookup the color name in w32_color_map, then check the
1639 colorname to see if it can be crudely approximated: If the X color
1640 ends in a number (e.g., "darkseagreen2"), strip the number and
1641 return the result of looking up the base color name. */
1642 ret = w32_color_map_lookup (colorname);
1643 if (NILP (ret))
ee78dc32 1644 {
f695b4b1 1645 int len = strlen (colorname);
ee78dc32 1646
f695b4b1
GV
1647 if (isdigit (colorname[len - 1]))
1648 {
1649 char *ptr, *approx = alloca (len);
ee78dc32 1650
f695b4b1
GV
1651 strcpy (approx, colorname);
1652 ptr = &approx[len - 1];
1653 while (ptr > approx && isdigit (*ptr))
1654 *ptr-- = '\0';
ee78dc32 1655
f695b4b1 1656 ret = w32_color_map_lookup (approx);
ee78dc32 1657 }
ee78dc32
GV
1658 }
1659
1660 UNBLOCK_INPUT;
ee78dc32
GV
1661 return ret;
1662}
1663
5ac45f98
GV
1664
1665void
fbd6baed 1666w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1667{
fbd6baed 1668 struct w32_palette_entry * list;
5ac45f98
GV
1669 LOGPALETTE * log_palette;
1670 HPALETTE new_palette;
1671 int i;
1672
1673 /* don't bother trying to create palette if not supported */
fbd6baed 1674 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1675 return;
1676
1677 log_palette = (LOGPALETTE *)
1678 alloca (sizeof (LOGPALETTE) +
fbd6baed 1679 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1680 log_palette->palVersion = 0x300;
fbd6baed 1681 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1682
fbd6baed 1683 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1684 for (i = 0;
fbd6baed 1685 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1686 i++, list = list->next)
1687 log_palette->palPalEntry[i] = list->entry;
1688
1689 new_palette = CreatePalette (log_palette);
1690
1691 enter_crit ();
1692
fbd6baed
GV
1693 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1694 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1695 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1696
1697 /* Realize display palette and garbage all frames. */
1698 release_frame_dc (f, get_frame_dc (f));
1699
1700 leave_crit ();
1701}
1702
fbd6baed
GV
1703#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1704#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1705 do \
1706 { \
1707 pe.peRed = GetRValue (color); \
1708 pe.peGreen = GetGValue (color); \
1709 pe.peBlue = GetBValue (color); \
1710 pe.peFlags = 0; \
1711 } while (0)
1712
1713#if 0
1714/* Keep these around in case we ever want to track color usage. */
1715void
fbd6baed 1716w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1717{
fbd6baed 1718 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1719
fbd6baed 1720 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1721 return;
1722
1723 /* check if color is already mapped */
1724 while (list)
1725 {
fbd6baed 1726 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1727 {
1728 ++list->refcount;
1729 return;
1730 }
1731 list = list->next;
1732 }
1733
1734 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1735 list = (struct w32_palette_entry *)
1736 xmalloc (sizeof (struct w32_palette_entry));
1737 SET_W32_COLOR (list->entry, color);
5ac45f98 1738 list->refcount = 1;
fbd6baed
GV
1739 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1740 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1741 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1742
1743 /* set flag that palette must be regenerated */
fbd6baed 1744 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1745}
1746
1747void
fbd6baed 1748w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1749{
fbd6baed
GV
1750 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1751 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1752
fbd6baed 1753 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1754 return;
1755
1756 /* check if color is already mapped */
1757 while (list)
1758 {
fbd6baed 1759 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1760 {
1761 if (--list->refcount == 0)
1762 {
1763 *prev = list->next;
1764 xfree (list);
fbd6baed 1765 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1766 break;
1767 }
1768 else
1769 return;
1770 }
1771 prev = &list->next;
1772 list = list->next;
1773 }
1774
1775 /* set flag that palette must be regenerated */
fbd6baed 1776 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1777}
1778#endif
1779
6fc2811b
JR
1780
1781/* Gamma-correct COLOR on frame F. */
1782
1783void
1784gamma_correct (f, color)
1785 struct frame *f;
1786 COLORREF *color;
1787{
1788 if (f->gamma)
1789 {
1790 *color = PALETTERGB (
1791 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1792 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1793 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1794 }
1795}
1796
1797
ee78dc32
GV
1798/* Decide if color named COLOR is valid for the display associated with
1799 the selected frame; if so, return the rgb values in COLOR_DEF.
1800 If ALLOC is nonzero, allocate a new colormap cell. */
1801
1802int
6fc2811b 1803w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1804 FRAME_PTR f;
1805 char *color;
6fc2811b 1806 XColor *color_def;
ee78dc32
GV
1807 int alloc;
1808{
1809 register Lisp_Object tem;
6fc2811b 1810 COLORREF w32_color_ref;
3c190163 1811
fbd6baed 1812 tem = x_to_w32_color (color);
3c190163 1813
ee78dc32
GV
1814 if (!NILP (tem))
1815 {
d88c567c
JR
1816 if (f)
1817 {
1818 /* Apply gamma correction. */
1819 w32_color_ref = XUINT (tem);
1820 gamma_correct (f, &w32_color_ref);
1821 XSETINT (tem, w32_color_ref);
1822 }
9badad41
JR
1823
1824 /* Map this color to the palette if it is enabled. */
fbd6baed 1825 if (!NILP (Vw32_enable_palette))
5ac45f98 1826 {
fbd6baed 1827 struct w32_palette_entry * entry =
d88c567c 1828 one_w32_display_info.color_list;
fbd6baed 1829 struct w32_palette_entry ** prev =
d88c567c 1830 &one_w32_display_info.color_list;
5ac45f98
GV
1831
1832 /* check if color is already mapped */
1833 while (entry)
1834 {
fbd6baed 1835 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1836 break;
1837 prev = &entry->next;
1838 entry = entry->next;
1839 }
1840
1841 if (entry == NULL && alloc)
1842 {
1843 /* not already mapped, so add to list */
fbd6baed
GV
1844 entry = (struct w32_palette_entry *)
1845 xmalloc (sizeof (struct w32_palette_entry));
1846 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1847 entry->next = NULL;
1848 *prev = entry;
d88c567c 1849 one_w32_display_info.num_colors++;
5ac45f98
GV
1850
1851 /* set flag that palette must be regenerated */
d88c567c 1852 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1853 }
1854 }
1855 /* Ensure COLORREF value is snapped to nearest color in (default)
1856 palette by simulating the PALETTERGB macro. This works whether
1857 or not the display device has a palette. */
6fc2811b
JR
1858 w32_color_ref = XUINT (tem) | 0x2000000;
1859
6fc2811b
JR
1860 color_def->pixel = w32_color_ref;
1861 color_def->red = GetRValue (w32_color_ref);
1862 color_def->green = GetGValue (w32_color_ref);
1863 color_def->blue = GetBValue (w32_color_ref);
1864
ee78dc32 1865 return 1;
5ac45f98 1866 }
7fb46567 1867 else
3c190163
GV
1868 {
1869 return 0;
1870 }
ee78dc32
GV
1871}
1872
1873/* Given a string ARG naming a color, compute a pixel value from it
1874 suitable for screen F.
1875 If F is not a color screen, return DEF (default) regardless of what
1876 ARG says. */
1877
1878int
1879x_decode_color (f, arg, def)
1880 FRAME_PTR f;
1881 Lisp_Object arg;
1882 int def;
1883{
6fc2811b 1884 XColor cdef;
ee78dc32
GV
1885
1886 CHECK_STRING (arg, 0);
1887
1888 if (strcmp (XSTRING (arg)->data, "black") == 0)
1889 return BLACK_PIX_DEFAULT (f);
1890 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1891 return WHITE_PIX_DEFAULT (f);
1892
fbd6baed 1893 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1894 return def;
1895
6fc2811b 1896 /* w32_defined_color is responsible for coping with failures
ee78dc32 1897 by looking for a near-miss. */
6fc2811b
JR
1898 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1899 return cdef.pixel;
ee78dc32
GV
1900
1901 /* defined_color failed; return an ultimate default. */
1902 return def;
1903}
1904\f
dfff8a69
JR
1905/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1906 the previous value of that parameter, NEW_VALUE is the new value. */
1907
1908static void
1909x_set_line_spacing (f, new_value, old_value)
1910 struct frame *f;
1911 Lisp_Object new_value, old_value;
1912{
1913 if (NILP (new_value))
1914 f->extra_line_spacing = 0;
1915 else if (NATNUMP (new_value))
1916 f->extra_line_spacing = XFASTINT (new_value);
1917 else
1a948b17 1918 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
1919 Fcons (new_value, Qnil)));
1920 if (FRAME_VISIBLE_P (f))
1921 redraw_frame (f);
1922}
1923
1924
6fc2811b
JR
1925/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1926 the previous value of that parameter, NEW_VALUE is the new value. */
1927
1928static void
1929x_set_screen_gamma (f, new_value, old_value)
1930 struct frame *f;
1931 Lisp_Object new_value, old_value;
1932{
1933 if (NILP (new_value))
1934 f->gamma = 0;
1935 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1936 /* The value 0.4545 is the normal viewing gamma. */
1937 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1938 else
1a948b17 1939 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
1940 Fcons (new_value, Qnil)));
1941
1942 clear_face_cache (0);
1943}
1944
1945
ee78dc32
GV
1946/* Functions called only from `x_set_frame_param'
1947 to set individual parameters.
1948
fbd6baed 1949 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1950 the frame is being created and its window does not exist yet.
1951 In that case, just record the parameter's new value
1952 in the standard place; do not attempt to change the window. */
1953
1954void
1955x_set_foreground_color (f, arg, oldval)
1956 struct frame *f;
1957 Lisp_Object arg, oldval;
1958{
6fc2811b 1959 FRAME_FOREGROUND_PIXEL (f)
ee78dc32 1960 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
5ac45f98 1961
fbd6baed 1962 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1963 {
6fc2811b 1964 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
1965 if (FRAME_VISIBLE_P (f))
1966 redraw_frame (f);
1967 }
1968}
1969
1970void
1971x_set_background_color (f, arg, oldval)
1972 struct frame *f;
1973 Lisp_Object arg, oldval;
1974{
6fc2811b 1975 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
1976 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1977
fbd6baed 1978 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1979 {
6fc2811b
JR
1980 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
1981 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 1982
6fc2811b 1983 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
1984
1985 if (FRAME_VISIBLE_P (f))
1986 redraw_frame (f);
1987 }
1988}
1989
1990void
1991x_set_mouse_color (f, arg, oldval)
1992 struct frame *f;
1993 Lisp_Object arg, oldval;
1994{
ee78dc32 1995 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 1996 int count;
ee78dc32
GV
1997 int mask_color;
1998
1999 if (!EQ (Qnil, arg))
fbd6baed 2000 f->output_data.w32->mouse_pixel
ee78dc32 2001 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2002 mask_color = FRAME_BACKGROUND_PIXEL (f);
2003
2004 /* Don't let pointers be invisible. */
fbd6baed 2005 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2006 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2007 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2008
767b1ff0 2009#if 0 /* TODO : cursor changes */
ee78dc32
GV
2010 BLOCK_INPUT;
2011
2012 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2013 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2014
2015 if (!EQ (Qnil, Vx_pointer_shape))
2016 {
2017 CHECK_NUMBER (Vx_pointer_shape, 0);
fbd6baed 2018 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2019 }
2020 else
fbd6baed
GV
2021 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2022 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2023
2024 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2025 {
2026 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
fbd6baed 2027 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2028 XINT (Vx_nontext_pointer_shape));
2029 }
2030 else
fbd6baed
GV
2031 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2032 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2033
6fc2811b
JR
2034 if (!EQ (Qnil, Vx_busy_pointer_shape))
2035 {
2036 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
2037 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2038 XINT (Vx_busy_pointer_shape));
2039 }
2040 else
2041 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2042 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2043
2044 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2045 if (!EQ (Qnil, Vx_mode_pointer_shape))
2046 {
2047 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
fbd6baed 2048 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2049 XINT (Vx_mode_pointer_shape));
2050 }
2051 else
fbd6baed
GV
2052 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2053 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2054
2055 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2056 {
2057 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2058 cross_cursor
fbd6baed 2059 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2060 XINT (Vx_sensitive_text_pointer_shape));
2061 }
2062 else
fbd6baed 2063 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2064
4694d762
JR
2065 if (!NILP (Vx_window_horizontal_drag_shape))
2066 {
2067 CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
2068 horizontal_drag_cursor
2069 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2070 XINT (Vx_window_horizontal_drag_shape));
2071 }
2072 else
2073 horizontal_drag_cursor
2074 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2075
ee78dc32 2076 /* Check and report errors with the above calls. */
fbd6baed 2077 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2078 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2079
2080 {
2081 XColor fore_color, back_color;
2082
fbd6baed 2083 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2084 back_color.pixel = mask_color;
fbd6baed
GV
2085 XQueryColor (FRAME_W32_DISPLAY (f),
2086 DefaultColormap (FRAME_W32_DISPLAY (f),
2087 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2088 &fore_color);
fbd6baed
GV
2089 XQueryColor (FRAME_W32_DISPLAY (f),
2090 DefaultColormap (FRAME_W32_DISPLAY (f),
2091 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2092 &back_color);
fbd6baed 2093 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2094 &fore_color, &back_color);
fbd6baed 2095 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2096 &fore_color, &back_color);
fbd6baed 2097 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2098 &fore_color, &back_color);
fbd6baed 2099 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2100 &fore_color, &back_color);
6fc2811b
JR
2101 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2102 &fore_color, &back_color);
ee78dc32
GV
2103 }
2104
fbd6baed 2105 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2106 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2107
fbd6baed
GV
2108 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2109 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2110 f->output_data.w32->text_cursor = cursor;
2111
2112 if (nontext_cursor != f->output_data.w32->nontext_cursor
2113 && f->output_data.w32->nontext_cursor != 0)
2114 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2115 f->output_data.w32->nontext_cursor = nontext_cursor;
2116
6fc2811b
JR
2117 if (busy_cursor != f->output_data.w32->busy_cursor
2118 && f->output_data.w32->busy_cursor != 0)
2119 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2120 f->output_data.w32->busy_cursor = busy_cursor;
2121
fbd6baed
GV
2122 if (mode_cursor != f->output_data.w32->modeline_cursor
2123 && f->output_data.w32->modeline_cursor != 0)
2124 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2125 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2126
fbd6baed
GV
2127 if (cross_cursor != f->output_data.w32->cross_cursor
2128 && f->output_data.w32->cross_cursor != 0)
2129 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2130 f->output_data.w32->cross_cursor = cross_cursor;
2131
2132 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2133 UNBLOCK_INPUT;
6fc2811b
JR
2134
2135 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2136#endif /* TODO */
ee78dc32
GV
2137}
2138
70a0239a
JR
2139/* Defined in w32term.c. */
2140void x_update_cursor (struct frame *f, int on_p);
2141
ee78dc32
GV
2142void
2143x_set_cursor_color (f, arg, oldval)
2144 struct frame *f;
2145 Lisp_Object arg, oldval;
2146{
70a0239a 2147 unsigned long fore_pixel, pixel;
ee78dc32 2148
dfff8a69 2149 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2150 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2151 WHITE_PIX_DEFAULT (f));
ee78dc32 2152 else
6fc2811b 2153 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2154
6759f872 2155 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2156
2157 /* Make sure that the cursor color differs from the background color. */
70a0239a 2158 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2159 {
70a0239a
JR
2160 pixel = f->output_data.w32->mouse_pixel;
2161 if (pixel == fore_pixel)
6fc2811b 2162 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2163 }
70a0239a 2164
6fc2811b 2165 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
70a0239a 2166 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2167
fbd6baed 2168 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2169 {
2170 if (FRAME_VISIBLE_P (f))
2171 {
70a0239a
JR
2172 x_update_cursor (f, 0);
2173 x_update_cursor (f, 1);
ee78dc32
GV
2174 }
2175 }
6fc2811b
JR
2176
2177 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2178}
2179
33d52f9c
GV
2180/* Set the border-color of frame F to pixel value PIX.
2181 Note that this does not fully take effect if done before
2182 F has an window. */
2183void
2184x_set_border_pixel (f, pix)
2185 struct frame *f;
2186 int pix;
2187{
2188 f->output_data.w32->border_pixel = pix;
2189
2190 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2191 {
2192 if (FRAME_VISIBLE_P (f))
2193 redraw_frame (f);
2194 }
2195}
2196
ee78dc32
GV
2197/* Set the border-color of frame F to value described by ARG.
2198 ARG can be a string naming a color.
2199 The border-color is used for the border that is drawn by the server.
2200 Note that this does not fully take effect if done before
2201 F has a window; it must be redone when the window is created. */
2202
2203void
2204x_set_border_color (f, arg, oldval)
2205 struct frame *f;
2206 Lisp_Object arg, oldval;
2207{
ee78dc32
GV
2208 int pix;
2209
2210 CHECK_STRING (arg, 0);
ee78dc32 2211 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2212 x_set_border_pixel (f, pix);
6fc2811b 2213 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2214}
2215
dfff8a69
JR
2216/* Value is the internal representation of the specified cursor type
2217 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2218 of the bar cursor. */
2219
2220enum text_cursor_kinds
2221x_specified_cursor_type (arg, width)
2222 Lisp_Object arg;
2223 int *width;
ee78dc32 2224{
dfff8a69
JR
2225 enum text_cursor_kinds type;
2226
ee78dc32
GV
2227 if (EQ (arg, Qbar))
2228 {
dfff8a69
JR
2229 type = BAR_CURSOR;
2230 *width = 2;
ee78dc32 2231 }
dfff8a69
JR
2232 else if (CONSP (arg)
2233 && EQ (XCAR (arg), Qbar)
2234 && INTEGERP (XCDR (arg))
2235 && XINT (XCDR (arg)) >= 0)
ee78dc32 2236 {
dfff8a69
JR
2237 type = BAR_CURSOR;
2238 *width = XINT (XCDR (arg));
ee78dc32 2239 }
dfff8a69
JR
2240 else if (NILP (arg))
2241 type = NO_CURSOR;
ee78dc32
GV
2242 else
2243 /* Treat anything unknown as "box cursor".
2244 It was bad to signal an error; people have trouble fixing
2245 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2246 type = FILLED_BOX_CURSOR;
2247
2248 return type;
2249}
2250
2251void
2252x_set_cursor_type (f, arg, oldval)
2253 FRAME_PTR f;
2254 Lisp_Object arg, oldval;
2255{
2256 int width;
2257
2258 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2259 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2260
2261 /* Make sure the cursor gets redrawn. This is overkill, but how
2262 often do people change cursor types? */
2263 update_mode_lines++;
2264}
dfff8a69 2265\f
ee78dc32
GV
2266void
2267x_set_icon_type (f, arg, oldval)
2268 struct frame *f;
2269 Lisp_Object arg, oldval;
2270{
ee78dc32
GV
2271 int result;
2272
eb7576ce
GV
2273 if (NILP (arg) && NILP (oldval))
2274 return;
2275
2276 if (STRINGP (arg) && STRINGP (oldval)
2277 && EQ (Fstring_equal (oldval, arg), Qt))
2278 return;
2279
2280 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2281 return;
2282
2283 BLOCK_INPUT;
ee78dc32 2284
eb7576ce 2285 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2286 if (result)
2287 {
2288 UNBLOCK_INPUT;
2289 error ("No icon window available");
2290 }
2291
ee78dc32 2292 UNBLOCK_INPUT;
ee78dc32
GV
2293}
2294
2295/* Return non-nil if frame F wants a bitmap icon. */
2296
2297Lisp_Object
2298x_icon_type (f)
2299 FRAME_PTR f;
2300{
2301 Lisp_Object tem;
2302
2303 tem = assq_no_quit (Qicon_type, f->param_alist);
2304 if (CONSP (tem))
8e713be6 2305 return XCDR (tem);
ee78dc32
GV
2306 else
2307 return Qnil;
2308}
2309
2310void
2311x_set_icon_name (f, arg, oldval)
2312 struct frame *f;
2313 Lisp_Object arg, oldval;
2314{
ee78dc32
GV
2315 if (STRINGP (arg))
2316 {
2317 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2318 return;
2319 }
2320 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2321 return;
2322
2323 f->icon_name = arg;
2324
2325#if 0
fbd6baed 2326 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2327 return;
2328
2329 BLOCK_INPUT;
2330
2331 result = x_text_icon (f,
1edf84e7 2332 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2333 ? f->icon_name
1edf84e7
GV
2334 : !NILP (f->title)
2335 ? f->title
ee78dc32
GV
2336 : f->name))->data);
2337
2338 if (result)
2339 {
2340 UNBLOCK_INPUT;
2341 error ("No icon window available");
2342 }
2343
2344 /* If the window was unmapped (and its icon was mapped),
2345 the new icon is not mapped, so map the window in its stead. */
2346 if (FRAME_VISIBLE_P (f))
2347 {
2348#ifdef USE_X_TOOLKIT
fbd6baed 2349 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2350#endif
fbd6baed 2351 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2352 }
2353
fbd6baed 2354 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2355 UNBLOCK_INPUT;
2356#endif
2357}
2358
2359extern Lisp_Object x_new_font ();
4587b026 2360extern Lisp_Object x_new_fontset();
ee78dc32
GV
2361
2362void
2363x_set_font (f, arg, oldval)
2364 struct frame *f;
2365 Lisp_Object arg, oldval;
2366{
2367 Lisp_Object result;
4587b026 2368 Lisp_Object fontset_name;
4b817373 2369 Lisp_Object frame;
ee78dc32
GV
2370
2371 CHECK_STRING (arg, 1);
2372
4587b026
GV
2373 fontset_name = Fquery_fontset (arg, Qnil);
2374
ee78dc32 2375 BLOCK_INPUT;
4587b026
GV
2376 result = (STRINGP (fontset_name)
2377 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2378 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2379 UNBLOCK_INPUT;
2380
2381 if (EQ (result, Qnil))
dfff8a69 2382 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2383 else if (EQ (result, Qt))
dfff8a69 2384 error ("The characters of the given font have varying widths");
ee78dc32
GV
2385 else if (STRINGP (result))
2386 {
dc220243
JR
2387 if (!NILP (Fequal (result, oldval)))
2388 return;
ee78dc32 2389 store_frame_param (f, Qfont, result);
6fc2811b 2390 recompute_basic_faces (f);
ee78dc32
GV
2391 }
2392 else
2393 abort ();
4b817373 2394
6fc2811b
JR
2395 do_pending_window_change (0);
2396
2397 /* Don't call `face-set-after-frame-default' when faces haven't been
2398 initialized yet. This is the case when called from
2399 Fx_create_frame. In that case, the X widget or window doesn't
2400 exist either, and we can end up in x_report_frame_params with a
2401 null widget which gives a segfault. */
2402 if (FRAME_FACE_CACHE (f))
2403 {
2404 XSETFRAME (frame, f);
2405 call1 (Qface_set_after_frame_default, frame);
2406 }
ee78dc32
GV
2407}
2408
2409void
2410x_set_border_width (f, arg, oldval)
2411 struct frame *f;
2412 Lisp_Object arg, oldval;
2413{
2414 CHECK_NUMBER (arg, 0);
2415
fbd6baed 2416 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2417 return;
2418
fbd6baed 2419 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2420 error ("Cannot change the border width of a window");
2421
fbd6baed 2422 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2423}
2424
2425void
2426x_set_internal_border_width (f, arg, oldval)
2427 struct frame *f;
2428 Lisp_Object arg, oldval;
2429{
fbd6baed 2430 int old = f->output_data.w32->internal_border_width;
ee78dc32
GV
2431
2432 CHECK_NUMBER (arg, 0);
fbd6baed
GV
2433 f->output_data.w32->internal_border_width = XINT (arg);
2434 if (f->output_data.w32->internal_border_width < 0)
2435 f->output_data.w32->internal_border_width = 0;
ee78dc32 2436
fbd6baed 2437 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2438 return;
2439
fbd6baed 2440 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2441 {
ee78dc32 2442 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2443 SET_FRAME_GARBAGED (f);
6fc2811b 2444 do_pending_window_change (0);
ee78dc32
GV
2445 }
2446}
2447
2448void
2449x_set_visibility (f, value, oldval)
2450 struct frame *f;
2451 Lisp_Object value, oldval;
2452{
2453 Lisp_Object frame;
2454 XSETFRAME (frame, f);
2455
2456 if (NILP (value))
2457 Fmake_frame_invisible (frame, Qt);
2458 else if (EQ (value, Qicon))
2459 Ficonify_frame (frame);
2460 else
2461 Fmake_frame_visible (frame);
2462}
2463
a1258667
JR
2464\f
2465/* Change window heights in windows rooted in WINDOW by N lines. */
2466
2467static void
2468x_change_window_heights (window, n)
2469 Lisp_Object window;
2470 int n;
2471{
2472 struct window *w = XWINDOW (window);
2473
2474 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2475 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2476
2477 if (INTEGERP (w->orig_top))
2478 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2479 if (INTEGERP (w->orig_height))
2480 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2481
2482 /* Handle just the top child in a vertical split. */
2483 if (!NILP (w->vchild))
2484 x_change_window_heights (w->vchild, n);
2485
2486 /* Adjust all children in a horizontal split. */
2487 for (window = w->hchild; !NILP (window); window = w->next)
2488 {
2489 w = XWINDOW (window);
2490 x_change_window_heights (window, n);
2491 }
2492}
2493
ee78dc32
GV
2494void
2495x_set_menu_bar_lines (f, value, oldval)
2496 struct frame *f;
2497 Lisp_Object value, oldval;
2498{
2499 int nlines;
2500 int olines = FRAME_MENU_BAR_LINES (f);
2501
2502 /* Right now, menu bars don't work properly in minibuf-only frames;
2503 most of the commands try to apply themselves to the minibuffer
6fc2811b 2504 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2505 in or split the minibuffer window. */
2506 if (FRAME_MINIBUF_ONLY_P (f))
2507 return;
2508
2509 if (INTEGERP (value))
2510 nlines = XINT (value);
2511 else
2512 nlines = 0;
2513
2514 FRAME_MENU_BAR_LINES (f) = 0;
2515 if (nlines)
2516 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2517 else
2518 {
2519 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2520 free_frame_menubar (f);
2521 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2522
2523 /* Adjust the frame size so that the client (text) dimensions
2524 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2525 set correctly. */
2526 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2527 do_pending_window_change (0);
ee78dc32 2528 }
6fc2811b
JR
2529 adjust_glyphs (f);
2530}
2531
2532
2533/* Set the number of lines used for the tool bar of frame F to VALUE.
2534 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2535 is the old number of tool bar lines. This function changes the
2536 height of all windows on frame F to match the new tool bar height.
2537 The frame's height doesn't change. */
2538
2539void
2540x_set_tool_bar_lines (f, value, oldval)
2541 struct frame *f;
2542 Lisp_Object value, oldval;
2543{
36f8209a
JR
2544 int delta, nlines, root_height;
2545 Lisp_Object root_window;
6fc2811b 2546
dc220243
JR
2547 /* Treat tool bars like menu bars. */
2548 if (FRAME_MINIBUF_ONLY_P (f))
2549 return;
2550
6fc2811b
JR
2551 /* Use VALUE only if an integer >= 0. */
2552 if (INTEGERP (value) && XINT (value) >= 0)
2553 nlines = XFASTINT (value);
2554 else
2555 nlines = 0;
2556
2557 /* Make sure we redisplay all windows in this frame. */
2558 ++windows_or_buffers_changed;
2559
2560 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2561
2562 /* Don't resize the tool-bar to more than we have room for. */
2563 root_window = FRAME_ROOT_WINDOW (f);
2564 root_height = XINT (XWINDOW (root_window)->height);
2565 if (root_height - delta < 1)
2566 {
2567 delta = root_height - 1;
2568 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2569 }
2570
6fc2811b 2571 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2572 x_change_window_heights (root_window, delta);
6fc2811b 2573 adjust_glyphs (f);
36f8209a
JR
2574
2575 /* We also have to make sure that the internal border at the top of
2576 the frame, below the menu bar or tool bar, is redrawn when the
2577 tool bar disappears. This is so because the internal border is
2578 below the tool bar if one is displayed, but is below the menu bar
2579 if there isn't a tool bar. The tool bar draws into the area
2580 below the menu bar. */
2581 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2582 {
2583 updating_frame = f;
2584 clear_frame ();
2585 clear_current_matrices (f);
2586 updating_frame = NULL;
2587 }
2588
2589 /* If the tool bar gets smaller, the internal border below it
2590 has to be cleared. It was formerly part of the display
2591 of the larger tool bar, and updating windows won't clear it. */
2592 if (delta < 0)
2593 {
2594 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2595 int width = PIXEL_WIDTH (f);
2596 int y = nlines * CANON_Y_UNIT (f);
2597
2598 BLOCK_INPUT;
2599 {
2600 HDC hdc = get_frame_dc (f);
2601 w32_clear_area (f, hdc, 0, y, width, height);
2602 release_frame_dc (f, hdc);
2603 }
2604 UNBLOCK_INPUT;
2605 }
ee78dc32
GV
2606}
2607
6fc2811b 2608
ee78dc32 2609/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2610 w32_id_name.
ee78dc32
GV
2611
2612 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2613 name; if NAME is a string, set F's name to NAME and set
2614 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2615
2616 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2617 suggesting a new name, which lisp code should override; if
2618 F->explicit_name is set, ignore the new name; otherwise, set it. */
2619
2620void
2621x_set_name (f, name, explicit)
2622 struct frame *f;
2623 Lisp_Object name;
2624 int explicit;
2625{
2626 /* Make sure that requests from lisp code override requests from
2627 Emacs redisplay code. */
2628 if (explicit)
2629 {
2630 /* If we're switching from explicit to implicit, we had better
2631 update the mode lines and thereby update the title. */
2632 if (f->explicit_name && NILP (name))
2633 update_mode_lines = 1;
2634
2635 f->explicit_name = ! NILP (name);
2636 }
2637 else if (f->explicit_name)
2638 return;
2639
fbd6baed 2640 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2641 if (NILP (name))
2642 {
2643 /* Check for no change needed in this very common case
2644 before we do any consing. */
fbd6baed 2645 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2646 XSTRING (f->name)->data))
2647 return;
fbd6baed 2648 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2649 }
2650 else
2651 CHECK_STRING (name, 0);
2652
2653 /* Don't change the name if it's already NAME. */
2654 if (! NILP (Fstring_equal (name, f->name)))
2655 return;
2656
1edf84e7
GV
2657 f->name = name;
2658
2659 /* For setting the frame title, the title parameter should override
2660 the name parameter. */
2661 if (! NILP (f->title))
2662 name = f->title;
2663
fbd6baed 2664 if (FRAME_W32_WINDOW (f))
ee78dc32 2665 {
6fc2811b 2666 if (STRING_MULTIBYTE (name))
dfff8a69 2667 name = ENCODE_SYSTEM (name);
6fc2811b 2668
ee78dc32 2669 BLOCK_INPUT;
fbd6baed 2670 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2671 UNBLOCK_INPUT;
2672 }
ee78dc32
GV
2673}
2674
2675/* This function should be called when the user's lisp code has
2676 specified a name for the frame; the name will override any set by the
2677 redisplay code. */
2678void
2679x_explicitly_set_name (f, arg, oldval)
2680 FRAME_PTR f;
2681 Lisp_Object arg, oldval;
2682{
2683 x_set_name (f, arg, 1);
2684}
2685
2686/* This function should be called by Emacs redisplay code to set the
2687 name; names set this way will never override names set by the user's
2688 lisp code. */
2689void
2690x_implicitly_set_name (f, arg, oldval)
2691 FRAME_PTR f;
2692 Lisp_Object arg, oldval;
2693{
2694 x_set_name (f, arg, 0);
2695}
1edf84e7
GV
2696\f
2697/* Change the title of frame F to NAME.
2698 If NAME is nil, use the frame name as the title.
2699
2700 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2701 name; if NAME is a string, set F's name to NAME and set
2702 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2703
2704 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2705 suggesting a new name, which lisp code should override; if
2706 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2707
1edf84e7 2708void
6fc2811b 2709x_set_title (f, name, old_name)
1edf84e7 2710 struct frame *f;
6fc2811b 2711 Lisp_Object name, old_name;
1edf84e7
GV
2712{
2713 /* Don't change the title if it's already NAME. */
2714 if (EQ (name, f->title))
2715 return;
2716
2717 update_mode_lines = 1;
2718
2719 f->title = name;
2720
2721 if (NILP (name))
2722 name = f->name;
2723
2724 if (FRAME_W32_WINDOW (f))
2725 {
6fc2811b 2726 if (STRING_MULTIBYTE (name))
dfff8a69 2727 name = ENCODE_SYSTEM (name);
6fc2811b 2728
1edf84e7
GV
2729 BLOCK_INPUT;
2730 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2731 UNBLOCK_INPUT;
2732 }
2733}
2734\f
ee78dc32
GV
2735void
2736x_set_autoraise (f, arg, oldval)
2737 struct frame *f;
2738 Lisp_Object arg, oldval;
2739{
2740 f->auto_raise = !EQ (Qnil, arg);
2741}
2742
2743void
2744x_set_autolower (f, arg, oldval)
2745 struct frame *f;
2746 Lisp_Object arg, oldval;
2747{
2748 f->auto_lower = !EQ (Qnil, arg);
2749}
2750
2751void
2752x_set_unsplittable (f, arg, oldval)
2753 struct frame *f;
2754 Lisp_Object arg, oldval;
2755{
2756 f->no_split = !NILP (arg);
2757}
2758
2759void
2760x_set_vertical_scroll_bars (f, arg, oldval)
2761 struct frame *f;
2762 Lisp_Object arg, oldval;
2763{
1026b400
RS
2764 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2765 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2766 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2767 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2768 {
1026b400
RS
2769 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2770 vertical_scroll_bar_none :
87996783
GV
2771 /* Put scroll bars on the right by default, as is conventional
2772 on MS-Windows. */
2773 EQ (Qleft, arg)
2774 ? vertical_scroll_bar_left
2775 : vertical_scroll_bar_right;
ee78dc32
GV
2776
2777 /* We set this parameter before creating the window for the
2778 frame, so we can get the geometry right from the start.
2779 However, if the window hasn't been created yet, we shouldn't
2780 call x_set_window_size. */
fbd6baed 2781 if (FRAME_W32_WINDOW (f))
ee78dc32 2782 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2783 do_pending_window_change (0);
ee78dc32
GV
2784 }
2785}
2786
2787void
2788x_set_scroll_bar_width (f, arg, oldval)
2789 struct frame *f;
2790 Lisp_Object arg, oldval;
2791{
6fc2811b
JR
2792 int wid = FONT_WIDTH (f->output_data.w32->font);
2793
ee78dc32
GV
2794 if (NILP (arg))
2795 {
6fc2811b
JR
2796 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2797 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2798 wid - 1) / wid;
2799 if (FRAME_W32_WINDOW (f))
2800 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2801 do_pending_window_change (0);
ee78dc32
GV
2802 }
2803 else if (INTEGERP (arg) && XINT (arg) > 0
2804 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2805 {
ee78dc32 2806 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2807 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2808 + wid-1) / wid;
fbd6baed 2809 if (FRAME_W32_WINDOW (f))
ee78dc32 2810 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2811 do_pending_window_change (0);
ee78dc32 2812 }
6fc2811b
JR
2813 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2814 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2815 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2816}
2817\f
2818/* Subroutines of creating an frame. */
2819
2820/* Make sure that Vx_resource_name is set to a reasonable value.
2821 Fix it up, or set it to `emacs' if it is too hopeless. */
2822
2823static void
2824validate_x_resource_name ()
2825{
6fc2811b 2826 int len = 0;
ee78dc32
GV
2827 /* Number of valid characters in the resource name. */
2828 int good_count = 0;
2829 /* Number of invalid characters in the resource name. */
2830 int bad_count = 0;
2831 Lisp_Object new;
2832 int i;
2833
2834 if (STRINGP (Vx_resource_name))
2835 {
2836 unsigned char *p = XSTRING (Vx_resource_name)->data;
2837 int i;
2838
dfff8a69 2839 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2840
2841 /* Only letters, digits, - and _ are valid in resource names.
2842 Count the valid characters and count the invalid ones. */
2843 for (i = 0; i < len; i++)
2844 {
2845 int c = p[i];
2846 if (! ((c >= 'a' && c <= 'z')
2847 || (c >= 'A' && c <= 'Z')
2848 || (c >= '0' && c <= '9')
2849 || c == '-' || c == '_'))
2850 bad_count++;
2851 else
2852 good_count++;
2853 }
2854 }
2855 else
2856 /* Not a string => completely invalid. */
2857 bad_count = 5, good_count = 0;
2858
2859 /* If name is valid already, return. */
2860 if (bad_count == 0)
2861 return;
2862
2863 /* If name is entirely invalid, or nearly so, use `emacs'. */
2864 if (good_count == 0
2865 || (good_count == 1 && bad_count > 0))
2866 {
2867 Vx_resource_name = build_string ("emacs");
2868 return;
2869 }
2870
2871 /* Name is partly valid. Copy it and replace the invalid characters
2872 with underscores. */
2873
2874 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2875
2876 for (i = 0; i < len; i++)
2877 {
2878 int c = XSTRING (new)->data[i];
2879 if (! ((c >= 'a' && c <= 'z')
2880 || (c >= 'A' && c <= 'Z')
2881 || (c >= '0' && c <= '9')
2882 || c == '-' || c == '_'))
2883 XSTRING (new)->data[i] = '_';
2884 }
2885}
2886
2887
2888extern char *x_get_string_resource ();
2889
2890DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2891 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2892This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2893class, where INSTANCE is the name under which Emacs was invoked, or\n\
2894the name specified by the `-name' or `-rn' command-line arguments.\n\
2895\n\
2896The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2897class, respectively. You must specify both of them or neither.\n\
2898If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2899and the class is `Emacs.CLASS.SUBCLASS'.")
2900 (attribute, class, component, subclass)
2901 Lisp_Object attribute, class, component, subclass;
2902{
2903 register char *value;
2904 char *name_key;
2905 char *class_key;
2906
2907 CHECK_STRING (attribute, 0);
2908 CHECK_STRING (class, 0);
2909
2910 if (!NILP (component))
2911 CHECK_STRING (component, 1);
2912 if (!NILP (subclass))
2913 CHECK_STRING (subclass, 2);
2914 if (NILP (component) != NILP (subclass))
2915 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2916
2917 validate_x_resource_name ();
2918
2919 /* Allocate space for the components, the dots which separate them,
2920 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 2921 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 2922 + (STRINGP (component)
dfff8a69
JR
2923 ? STRING_BYTES (XSTRING (component)) : 0)
2924 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
2925 + 3);
2926
2927 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 2928 + STRING_BYTES (XSTRING (class))
ee78dc32 2929 + (STRINGP (subclass)
dfff8a69 2930 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
2931 + 3);
2932
2933 /* Start with emacs.FRAMENAME for the name (the specific one)
2934 and with `Emacs' for the class key (the general one). */
2935 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2936 strcpy (class_key, EMACS_CLASS);
2937
2938 strcat (class_key, ".");
2939 strcat (class_key, XSTRING (class)->data);
2940
2941 if (!NILP (component))
2942 {
2943 strcat (class_key, ".");
2944 strcat (class_key, XSTRING (subclass)->data);
2945
2946 strcat (name_key, ".");
2947 strcat (name_key, XSTRING (component)->data);
2948 }
2949
2950 strcat (name_key, ".");
2951 strcat (name_key, XSTRING (attribute)->data);
2952
2953 value = x_get_string_resource (Qnil,
2954 name_key, class_key);
2955
2956 if (value != (char *) 0)
2957 return build_string (value);
2958 else
2959 return Qnil;
2960}
2961
2962/* Used when C code wants a resource value. */
2963
2964char *
2965x_get_resource_string (attribute, class)
2966 char *attribute, *class;
2967{
ee78dc32
GV
2968 char *name_key;
2969 char *class_key;
6fc2811b 2970 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
2971
2972 /* Allocate space for the components, the dots which separate them,
2973 and the final '\0'. */
dfff8a69 2974 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
2975 + strlen (attribute) + 2);
2976 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2977 + strlen (class) + 2);
2978
2979 sprintf (name_key, "%s.%s",
2980 XSTRING (Vinvocation_name)->data,
2981 attribute);
2982 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2983
6fc2811b 2984 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
2985}
2986
2987/* Types we might convert a resource string into. */
2988enum resource_types
6fc2811b
JR
2989{
2990 RES_TYPE_NUMBER,
2991 RES_TYPE_FLOAT,
2992 RES_TYPE_BOOLEAN,
2993 RES_TYPE_STRING,
2994 RES_TYPE_SYMBOL
2995};
ee78dc32
GV
2996
2997/* Return the value of parameter PARAM.
2998
2999 First search ALIST, then Vdefault_frame_alist, then the X defaults
3000 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3001
3002 Convert the resource to the type specified by desired_type.
3003
3004 If no default is specified, return Qunbound. If you call
6fc2811b 3005 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3006 and don't let it get stored in any Lisp-visible variables! */
3007
3008static Lisp_Object
6fc2811b 3009w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3010 Lisp_Object alist, param;
3011 char *attribute;
3012 char *class;
3013 enum resource_types type;
3014{
3015 register Lisp_Object tem;
3016
3017 tem = Fassq (param, alist);
3018 if (EQ (tem, Qnil))
3019 tem = Fassq (param, Vdefault_frame_alist);
3020 if (EQ (tem, Qnil))
3021 {
3022
3023 if (attribute)
3024 {
3025 tem = Fx_get_resource (build_string (attribute),
3026 build_string (class),
3027 Qnil, Qnil);
3028
3029 if (NILP (tem))
3030 return Qunbound;
3031
3032 switch (type)
3033 {
6fc2811b 3034 case RES_TYPE_NUMBER:
ee78dc32
GV
3035 return make_number (atoi (XSTRING (tem)->data));
3036
6fc2811b
JR
3037 case RES_TYPE_FLOAT:
3038 return make_float (atof (XSTRING (tem)->data));
3039
3040 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3041 tem = Fdowncase (tem);
3042 if (!strcmp (XSTRING (tem)->data, "on")
3043 || !strcmp (XSTRING (tem)->data, "true"))
3044 return Qt;
3045 else
3046 return Qnil;
3047
6fc2811b 3048 case RES_TYPE_STRING:
ee78dc32
GV
3049 return tem;
3050
6fc2811b 3051 case RES_TYPE_SYMBOL:
ee78dc32
GV
3052 /* As a special case, we map the values `true' and `on'
3053 to Qt, and `false' and `off' to Qnil. */
3054 {
3055 Lisp_Object lower;
3056 lower = Fdowncase (tem);
3057 if (!strcmp (XSTRING (lower)->data, "on")
3058 || !strcmp (XSTRING (lower)->data, "true"))
3059 return Qt;
3060 else if (!strcmp (XSTRING (lower)->data, "off")
3061 || !strcmp (XSTRING (lower)->data, "false"))
3062 return Qnil;
3063 else
3064 return Fintern (tem, Qnil);
3065 }
3066
3067 default:
3068 abort ();
3069 }
3070 }
3071 else
3072 return Qunbound;
3073 }
3074 return Fcdr (tem);
3075}
3076
3077/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3078 of the parameter named PROP (a Lisp symbol).
3079 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3080 on the frame named NAME.
3081 If that is not found either, use the value DEFLT. */
3082
3083static Lisp_Object
3084x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3085 struct frame *f;
3086 Lisp_Object alist;
3087 Lisp_Object prop;
3088 Lisp_Object deflt;
3089 char *xprop;
3090 char *xclass;
3091 enum resource_types type;
3092{
3093 Lisp_Object tem;
3094
6fc2811b 3095 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3096 if (EQ (tem, Qunbound))
3097 tem = deflt;
3098 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3099 return tem;
3100}
3101\f
3102DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3103 "Parse an X-style geometry string STRING.\n\
3104Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3105The properties returned may include `top', `left', `height', and `width'.\n\
3106The value of `left' or `top' may be an integer,\n\
3107or a list (+ N) meaning N pixels relative to top/left corner,\n\
3108or a list (- N) meaning -N pixels relative to bottom/right corner.")
3109 (string)
3110 Lisp_Object string;
3111{
3112 int geometry, x, y;
3113 unsigned int width, height;
3114 Lisp_Object result;
3115
3116 CHECK_STRING (string, 0);
3117
3118 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3119 &x, &y, &width, &height);
3120
3121 result = Qnil;
3122 if (geometry & XValue)
3123 {
3124 Lisp_Object element;
3125
3126 if (x >= 0 && (geometry & XNegative))
3127 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3128 else if (x < 0 && ! (geometry & XNegative))
3129 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3130 else
3131 element = Fcons (Qleft, make_number (x));
3132 result = Fcons (element, result);
3133 }
3134
3135 if (geometry & YValue)
3136 {
3137 Lisp_Object element;
3138
3139 if (y >= 0 && (geometry & YNegative))
3140 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3141 else if (y < 0 && ! (geometry & YNegative))
3142 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3143 else
3144 element = Fcons (Qtop, make_number (y));
3145 result = Fcons (element, result);
3146 }
3147
3148 if (geometry & WidthValue)
3149 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3150 if (geometry & HeightValue)
3151 result = Fcons (Fcons (Qheight, make_number (height)), result);
3152
3153 return result;
3154}
3155
3156/* Calculate the desired size and position of this window,
3157 and return the flags saying which aspects were specified.
3158
3159 This function does not make the coordinates positive. */
3160
3161#define DEFAULT_ROWS 40
3162#define DEFAULT_COLS 80
3163
3164static int
3165x_figure_window_size (f, parms)
3166 struct frame *f;
3167 Lisp_Object parms;
3168{
3169 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3170 long window_prompting = 0;
3171
3172 /* Default values if we fall through.
3173 Actually, if that happens we should get
3174 window manager prompting. */
1026b400 3175 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3176 f->height = DEFAULT_ROWS;
3177 /* Window managers expect that if program-specified
3178 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3179 f->output_data.w32->top_pos = 0;
3180 f->output_data.w32->left_pos = 0;
ee78dc32 3181
35b41202
JR
3182 /* Ensure that old new_width and new_height will not override the
3183 values set here. */
3184 FRAME_NEW_WIDTH (f) = 0;
3185 FRAME_NEW_HEIGHT (f) = 0;
3186
6fc2811b
JR
3187 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3188 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3189 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3190 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3191 {
3192 if (!EQ (tem0, Qunbound))
3193 {
3194 CHECK_NUMBER (tem0, 0);
3195 f->height = XINT (tem0);
3196 }
3197 if (!EQ (tem1, Qunbound))
3198 {
3199 CHECK_NUMBER (tem1, 0);
1026b400 3200 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3201 }
3202 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3203 window_prompting |= USSize;
3204 else
3205 window_prompting |= PSize;
3206 }
3207
fbd6baed 3208 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3209 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3210 ? 0
3211 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3212 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3213 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
6fc2811b
JR
3214 f->output_data.w32->flags_areas_extra
3215 = FRAME_FLAGS_AREA_WIDTH (f);
fbd6baed
GV
3216 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3217 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3218
6fc2811b
JR
3219 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3220 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3221 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3222 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3223 {
3224 if (EQ (tem0, Qminus))
3225 {
fbd6baed 3226 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3227 window_prompting |= YNegative;
3228 }
8e713be6
KR
3229 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3230 && CONSP (XCDR (tem0))
3231 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3232 {
8e713be6 3233 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3234 window_prompting |= YNegative;
3235 }
8e713be6
KR
3236 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3237 && CONSP (XCDR (tem0))
3238 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3239 {
8e713be6 3240 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3241 }
3242 else if (EQ (tem0, Qunbound))
fbd6baed 3243 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3244 else
3245 {
3246 CHECK_NUMBER (tem0, 0);
fbd6baed
GV
3247 f->output_data.w32->top_pos = XINT (tem0);
3248 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3249 window_prompting |= YNegative;
3250 }
3251
3252 if (EQ (tem1, Qminus))
3253 {
fbd6baed 3254 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3255 window_prompting |= XNegative;
3256 }
8e713be6
KR
3257 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3258 && CONSP (XCDR (tem1))
3259 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3260 {
8e713be6 3261 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3262 window_prompting |= XNegative;
3263 }
8e713be6
KR
3264 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3265 && CONSP (XCDR (tem1))
3266 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3267 {
8e713be6 3268 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3269 }
3270 else if (EQ (tem1, Qunbound))
fbd6baed 3271 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3272 else
3273 {
3274 CHECK_NUMBER (tem1, 0);
fbd6baed
GV
3275 f->output_data.w32->left_pos = XINT (tem1);
3276 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3277 window_prompting |= XNegative;
3278 }
3279
3280 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3281 window_prompting |= USPosition;
3282 else
3283 window_prompting |= PPosition;
3284 }
3285
3286 return window_prompting;
3287}
3288
3289\f
3290
fbd6baed 3291extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3292
3293BOOL
fbd6baed 3294w32_init_class (hinst)
ee78dc32
GV
3295 HINSTANCE hinst;
3296{
3297 WNDCLASS wc;
3298
5ac45f98 3299 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3300 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3301 wc.cbClsExtra = 0;
3302 wc.cbWndExtra = WND_EXTRA_BYTES;
3303 wc.hInstance = hinst;
3304 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3305 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3306 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3307 wc.lpszMenuName = NULL;
3308 wc.lpszClassName = EMACS_CLASS;
3309
3310 return (RegisterClass (&wc));
3311}
3312
3313HWND
fbd6baed 3314w32_createscrollbar (f, bar)
ee78dc32
GV
3315 struct frame *f;
3316 struct scroll_bar * bar;
3317{
3318 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3319 /* Position and size of scroll bar. */
6fc2811b
JR
3320 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3321 XINT(bar->top),
3322 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3323 XINT(bar->height),
fbd6baed 3324 FRAME_W32_WINDOW (f),
ee78dc32
GV
3325 NULL,
3326 hinst,
3327 NULL));
3328}
3329
3330void
fbd6baed 3331w32_createwindow (f)
ee78dc32
GV
3332 struct frame *f;
3333{
3334 HWND hwnd;
1edf84e7
GV
3335 RECT rect;
3336
3337 rect.left = rect.top = 0;
3338 rect.right = PIXEL_WIDTH (f);
3339 rect.bottom = PIXEL_HEIGHT (f);
3340
3341 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3342 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3343
3344 /* Do first time app init */
3345
3346 if (!hprevinst)
3347 {
fbd6baed 3348 w32_init_class (hinst);
ee78dc32
GV
3349 }
3350
1edf84e7
GV
3351 FRAME_W32_WINDOW (f) = hwnd
3352 = CreateWindow (EMACS_CLASS,
3353 f->namebuf,
3354 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3355 f->output_data.w32->left_pos,
3356 f->output_data.w32->top_pos,
3357 rect.right - rect.left,
3358 rect.bottom - rect.top,
3359 NULL,
3360 NULL,
3361 hinst,
3362 NULL);
3363
ee78dc32
GV
3364 if (hwnd)
3365 {
1edf84e7
GV
3366 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3367 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3368 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3369 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3370 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3371
cb9e33d4
RS
3372 /* Enable drag-n-drop. */
3373 DragAcceptFiles (hwnd, TRUE);
3374
5ac45f98
GV
3375 /* Do this to discard the default setting specified by our parent. */
3376 ShowWindow (hwnd, SW_HIDE);
3c190163 3377 }
3c190163
GV
3378}
3379
ee78dc32
GV
3380void
3381my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3382 W32Msg * wmsg;
ee78dc32
GV
3383 HWND hwnd;
3384 UINT msg;
3385 WPARAM wParam;
3386 LPARAM lParam;
3387{
3388 wmsg->msg.hwnd = hwnd;
3389 wmsg->msg.message = msg;
3390 wmsg->msg.wParam = wParam;
3391 wmsg->msg.lParam = lParam;
3392 wmsg->msg.time = GetMessageTime ();
3393
3394 post_msg (wmsg);
3395}
3396
e9e23e23 3397/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3398 between left and right keys as advertised. We test for this
3399 support dynamically, and set a flag when the support is absent. If
3400 absent, we keep track of the left and right control and alt keys
3401 ourselves. This is particularly necessary on keyboards that rely
3402 upon the AltGr key, which is represented as having the left control
3403 and right alt keys pressed. For these keyboards, we need to know
3404 when the left alt key has been pressed in addition to the AltGr key
3405 so that we can properly support M-AltGr-key sequences (such as M-@
3406 on Swedish keyboards). */
3407
3408#define EMACS_LCONTROL 0
3409#define EMACS_RCONTROL 1
3410#define EMACS_LMENU 2
3411#define EMACS_RMENU 3
3412
3413static int modifiers[4];
3414static int modifiers_recorded;
3415static int modifier_key_support_tested;
3416
3417static void
3418test_modifier_support (unsigned int wparam)
3419{
3420 unsigned int l, r;
3421
3422 if (wparam != VK_CONTROL && wparam != VK_MENU)
3423 return;
3424 if (wparam == VK_CONTROL)
3425 {
3426 l = VK_LCONTROL;
3427 r = VK_RCONTROL;
3428 }
3429 else
3430 {
3431 l = VK_LMENU;
3432 r = VK_RMENU;
3433 }
3434 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3435 modifiers_recorded = 1;
3436 else
3437 modifiers_recorded = 0;
3438 modifier_key_support_tested = 1;
3439}
3440
3441static void
3442record_keydown (unsigned int wparam, unsigned int lparam)
3443{
3444 int i;
3445
3446 if (!modifier_key_support_tested)
3447 test_modifier_support (wparam);
3448
3449 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3450 return;
3451
3452 if (wparam == VK_CONTROL)
3453 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3454 else
3455 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3456
3457 modifiers[i] = 1;
3458}
3459
3460static void
3461record_keyup (unsigned int wparam, unsigned int lparam)
3462{
3463 int i;
3464
3465 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3466 return;
3467
3468 if (wparam == VK_CONTROL)
3469 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3470 else
3471 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3472
3473 modifiers[i] = 0;
3474}
3475
da36a4d6
GV
3476/* Emacs can lose focus while a modifier key has been pressed. When
3477 it regains focus, be conservative and clear all modifiers since
3478 we cannot reconstruct the left and right modifier state. */
3479static void
3480reset_modifiers ()
3481{
8681157a
RS
3482 SHORT ctrl, alt;
3483
adcc3809
GV
3484 if (GetFocus () == NULL)
3485 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3486 return;
8681157a
RS
3487
3488 ctrl = GetAsyncKeyState (VK_CONTROL);
3489 alt = GetAsyncKeyState (VK_MENU);
3490
8681157a
RS
3491 if (!(ctrl & 0x08000))
3492 /* Clear any recorded control modifier state. */
3493 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3494
3495 if (!(alt & 0x08000))
3496 /* Clear any recorded alt modifier state. */
3497 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3498
adcc3809
GV
3499 /* Update the state of all modifier keys, because modifiers used in
3500 hot-key combinations can get stuck on if Emacs loses focus as a
3501 result of a hot-key being pressed. */
3502 {
3503 BYTE keystate[256];
3504
3505#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3506
3507 GetKeyboardState (keystate);
3508 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3509 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3510 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3511 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3512 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3513 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3514 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3515 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3516 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3517 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3518 SetKeyboardState (keystate);
3519 }
da36a4d6
GV
3520}
3521
7830e24b
RS
3522/* Synchronize modifier state with what is reported with the current
3523 keystroke. Even if we cannot distinguish between left and right
3524 modifier keys, we know that, if no modifiers are set, then neither
3525 the left or right modifier should be set. */
3526static void
3527sync_modifiers ()
3528{
3529 if (!modifiers_recorded)
3530 return;
3531
3532 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3533 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3534
3535 if (!(GetKeyState (VK_MENU) & 0x8000))
3536 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3537}
3538
a1a80b40
GV
3539static int
3540modifier_set (int vkey)
3541{
ccc2d29c 3542 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3543 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3544 if (!modifiers_recorded)
3545 return (GetKeyState (vkey) & 0x8000);
3546
3547 switch (vkey)
3548 {
3549 case VK_LCONTROL:
3550 return modifiers[EMACS_LCONTROL];
3551 case VK_RCONTROL:
3552 return modifiers[EMACS_RCONTROL];
3553 case VK_LMENU:
3554 return modifiers[EMACS_LMENU];
3555 case VK_RMENU:
3556 return modifiers[EMACS_RMENU];
a1a80b40
GV
3557 }
3558 return (GetKeyState (vkey) & 0x8000);
3559}
3560
ccc2d29c
GV
3561/* Convert between the modifier bits W32 uses and the modifier bits
3562 Emacs uses. */
3563
3564unsigned int
3565w32_key_to_modifier (int key)
3566{
3567 Lisp_Object key_mapping;
3568
3569 switch (key)
3570 {
3571 case VK_LWIN:
3572 key_mapping = Vw32_lwindow_modifier;
3573 break;
3574 case VK_RWIN:
3575 key_mapping = Vw32_rwindow_modifier;
3576 break;
3577 case VK_APPS:
3578 key_mapping = Vw32_apps_modifier;
3579 break;
3580 case VK_SCROLL:
3581 key_mapping = Vw32_scroll_lock_modifier;
3582 break;
3583 default:
3584 key_mapping = Qnil;
3585 }
3586
adcc3809
GV
3587 /* NB. This code runs in the input thread, asychronously to the lisp
3588 thread, so we must be careful to ensure access to lisp data is
3589 thread-safe. The following code is safe because the modifier
3590 variable values are updated atomically from lisp and symbols are
3591 not relocated by GC. Also, we don't have to worry about seeing GC
3592 markbits here. */
3593 if (EQ (key_mapping, Qhyper))
ccc2d29c 3594 return hyper_modifier;
adcc3809 3595 if (EQ (key_mapping, Qsuper))
ccc2d29c 3596 return super_modifier;
adcc3809 3597 if (EQ (key_mapping, Qmeta))
ccc2d29c 3598 return meta_modifier;
adcc3809 3599 if (EQ (key_mapping, Qalt))
ccc2d29c 3600 return alt_modifier;
adcc3809 3601 if (EQ (key_mapping, Qctrl))
ccc2d29c 3602 return ctrl_modifier;
adcc3809 3603 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3604 return ctrl_modifier;
adcc3809 3605 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3606 return shift_modifier;
3607
3608 /* Don't generate any modifier if not explicitly requested. */
3609 return 0;
3610}
3611
3612unsigned int
3613w32_get_modifiers ()
3614{
3615 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3616 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3617 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3618 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3619 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3620 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3621 (modifier_set (VK_MENU) ?
3622 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3623}
3624
a1a80b40
GV
3625/* We map the VK_* modifiers into console modifier constants
3626 so that we can use the same routines to handle both console
3627 and window input. */
3628
3629static int
ccc2d29c 3630construct_console_modifiers ()
a1a80b40
GV
3631{
3632 int mods;
3633
a1a80b40
GV
3634 mods = 0;
3635 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3636 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3637 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3638 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3639 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3640 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3641 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3642 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3643 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3644 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3645 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3646
3647 return mods;
3648}
3649
ccc2d29c
GV
3650static int
3651w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3652{
ccc2d29c
GV
3653 int mods;
3654
3655 /* Convert to emacs modifiers. */
3656 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3657
3658 return mods;
3659}
da36a4d6 3660
ccc2d29c
GV
3661unsigned int
3662map_keypad_keys (unsigned int virt_key, unsigned int extended)
3663{
3664 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3665 return virt_key;
da36a4d6 3666
ccc2d29c 3667 if (virt_key == VK_RETURN)
da36a4d6
GV
3668 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3669
ccc2d29c
GV
3670 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3671 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3672
3673 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3674 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3675
3676 if (virt_key == VK_CLEAR)
3677 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3678
3679 return virt_key;
3680}
3681
3682/* List of special key combinations which w32 would normally capture,
3683 but emacs should grab instead. Not directly visible to lisp, to
3684 simplify synchronization. Each item is an integer encoding a virtual
3685 key code and modifier combination to capture. */
3686Lisp_Object w32_grabbed_keys;
3687
3688#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3689#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3690#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3691#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3692
3693/* Register hot-keys for reserved key combinations when Emacs has
3694 keyboard focus, since this is the only way Emacs can receive key
3695 combinations like Alt-Tab which are used by the system. */
3696
3697static void
3698register_hot_keys (hwnd)
3699 HWND hwnd;
3700{
3701 Lisp_Object keylist;
3702
3703 /* Use GC_CONSP, since we are called asynchronously. */
3704 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3705 {
3706 Lisp_Object key = XCAR (keylist);
3707
3708 /* Deleted entries get set to nil. */
3709 if (!INTEGERP (key))
3710 continue;
3711
3712 RegisterHotKey (hwnd, HOTKEY_ID (key),
3713 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3714 }
3715}
3716
3717static void
3718unregister_hot_keys (hwnd)
3719 HWND hwnd;
3720{
3721 Lisp_Object keylist;
3722
3723 /* Use GC_CONSP, since we are called asynchronously. */
3724 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3725 {
3726 Lisp_Object key = XCAR (keylist);
3727
3728 if (!INTEGERP (key))
3729 continue;
3730
3731 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3732 }
3733}
3734
5ac45f98
GV
3735/* Main message dispatch loop. */
3736
1edf84e7
GV
3737static void
3738w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3739{
3740 MSG msg;
ccc2d29c
GV
3741 int result;
3742 HWND focus_window;
93fbe8b7
GV
3743
3744 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3745
5ac45f98
GV
3746 while (GetMessage (&msg, NULL, 0, 0))
3747 {
3748 if (msg.hwnd == NULL)
3749 {
3750 switch (msg.message)
3751 {
3ef68e6b
AI
3752 case WM_NULL:
3753 /* Produced by complete_deferred_msg; just ignore. */
3754 break;
5ac45f98 3755 case WM_EMACS_CREATEWINDOW:
fbd6baed 3756 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3757 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3758 abort ();
5ac45f98 3759 break;
dfdb4047
GV
3760 case WM_EMACS_SETLOCALE:
3761 SetThreadLocale (msg.wParam);
3762 /* Reply is not expected. */
3763 break;
ccc2d29c
GV
3764 case WM_EMACS_SETKEYBOARDLAYOUT:
3765 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3766 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3767 result, 0))
3768 abort ();
3769 break;
3770 case WM_EMACS_REGISTER_HOT_KEY:
3771 focus_window = GetFocus ();
3772 if (focus_window != NULL)
3773 RegisterHotKey (focus_window,
3774 HOTKEY_ID (msg.wParam),
3775 HOTKEY_MODIFIERS (msg.wParam),
3776 HOTKEY_VK_CODE (msg.wParam));
3777 /* Reply is not expected. */
3778 break;
3779 case WM_EMACS_UNREGISTER_HOT_KEY:
3780 focus_window = GetFocus ();
3781 if (focus_window != NULL)
3782 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3783 /* Mark item as erased. NB: this code must be
3784 thread-safe. The next line is okay because the cons
3785 cell is never made into garbage and is not relocated by
3786 GC. */
ccc2d29c
GV
3787 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3788 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3789 abort ();
3790 break;
adcc3809
GV
3791 case WM_EMACS_TOGGLE_LOCK_KEY:
3792 {
3793 int vk_code = (int) msg.wParam;
3794 int cur_state = (GetKeyState (vk_code) & 1);
3795 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3796
3797 /* NB: This code must be thread-safe. It is safe to
3798 call NILP because symbols are not relocated by GC,
3799 and pointer here is not touched by GC (so the markbit
3800 can't be set). Numbers are safe because they are
3801 immediate values. */
3802 if (NILP (new_state)
3803 || (NUMBERP (new_state)
8edb0a6f 3804 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3805 {
3806 one_w32_display_info.faked_key = vk_code;
3807
3808 keybd_event ((BYTE) vk_code,
3809 (BYTE) MapVirtualKey (vk_code, 0),
3810 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3811 keybd_event ((BYTE) vk_code,
3812 (BYTE) MapVirtualKey (vk_code, 0),
3813 KEYEVENTF_EXTENDEDKEY | 0, 0);
3814 keybd_event ((BYTE) vk_code,
3815 (BYTE) MapVirtualKey (vk_code, 0),
3816 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3817 cur_state = !cur_state;
3818 }
3819 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3820 cur_state, 0))
3821 abort ();
3822 }
3823 break;
1edf84e7 3824 default:
1edf84e7 3825 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3826 }
3827 }
3828 else
3829 {
3830 DispatchMessage (&msg);
3831 }
1edf84e7
GV
3832
3833 /* Exit nested loop when our deferred message has completed. */
3834 if (msg_buf->completed)
3835 break;
5ac45f98 3836 }
1edf84e7
GV
3837}
3838
3839deferred_msg * deferred_msg_head;
3840
3841static deferred_msg *
3842find_deferred_msg (HWND hwnd, UINT msg)
3843{
3844 deferred_msg * item;
3845
3846 /* Don't actually need synchronization for read access, since
3847 modification of single pointer is always atomic. */
3848 /* enter_crit (); */
3849
3850 for (item = deferred_msg_head; item != NULL; item = item->next)
3851 if (item->w32msg.msg.hwnd == hwnd
3852 && item->w32msg.msg.message == msg)
3853 break;
3854
3855 /* leave_crit (); */
3856
3857 return item;
3858}
3859
3860static LRESULT
3861send_deferred_msg (deferred_msg * msg_buf,
3862 HWND hwnd,
3863 UINT msg,
3864 WPARAM wParam,
3865 LPARAM lParam)
3866{
3867 /* Only input thread can send deferred messages. */
3868 if (GetCurrentThreadId () != dwWindowsThreadId)
3869 abort ();
3870
3871 /* It is an error to send a message that is already deferred. */
3872 if (find_deferred_msg (hwnd, msg) != NULL)
3873 abort ();
3874
3875 /* Enforced synchronization is not needed because this is the only
3876 function that alters deferred_msg_head, and the following critical
3877 section is guaranteed to only be serially reentered (since only the
3878 input thread can call us). */
3879
3880 /* enter_crit (); */
3881
3882 msg_buf->completed = 0;
3883 msg_buf->next = deferred_msg_head;
3884 deferred_msg_head = msg_buf;
3885 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3886
3887 /* leave_crit (); */
3888
3889 /* Start a new nested message loop to process other messages until
3890 this one is completed. */
3891 w32_msg_pump (msg_buf);
3892
3893 deferred_msg_head = msg_buf->next;
3894
3895 return msg_buf->result;
3896}
3897
3898void
3899complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3900{
3901 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3902
3903 if (msg_buf == NULL)
3ef68e6b
AI
3904 /* Message may have been cancelled, so don't abort(). */
3905 return;
1edf84e7
GV
3906
3907 msg_buf->result = result;
3908 msg_buf->completed = 1;
3909
3910 /* Ensure input thread is woken so it notices the completion. */
3911 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3912}
3913
3ef68e6b
AI
3914void
3915cancel_all_deferred_msgs ()
3916{
3917 deferred_msg * item;
3918
3919 /* Don't actually need synchronization for read access, since
3920 modification of single pointer is always atomic. */
3921 /* enter_crit (); */
3922
3923 for (item = deferred_msg_head; item != NULL; item = item->next)
3924 {
3925 item->result = 0;
3926 item->completed = 1;
3927 }
3928
3929 /* leave_crit (); */
3930
3931 /* Ensure input thread is woken so it notices the completion. */
3932 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3933}
1edf84e7
GV
3934
3935DWORD
3936w32_msg_worker (dw)
3937 DWORD dw;
3938{
3939 MSG msg;
3940 deferred_msg dummy_buf;
3941
3942 /* Ensure our message queue is created */
3943
3944 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 3945
1edf84e7
GV
3946 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3947 abort ();
3948
3949 memset (&dummy_buf, 0, sizeof (dummy_buf));
3950 dummy_buf.w32msg.msg.hwnd = NULL;
3951 dummy_buf.w32msg.msg.message = WM_NULL;
3952
3953 /* This is the inital message loop which should only exit when the
3954 application quits. */
3955 w32_msg_pump (&dummy_buf);
3956
3957 return 0;
5ac45f98
GV
3958}
3959
3ef68e6b
AI
3960static void
3961post_character_message (hwnd, msg, wParam, lParam, modifiers)
3962 HWND hwnd;
3963 UINT msg;
3964 WPARAM wParam;
3965 LPARAM lParam;
3966 DWORD modifiers;
3967
3968{
3969 W32Msg wmsg;
3970
3971 wmsg.dwModifiers = modifiers;
3972
3973 /* Detect quit_char and set quit-flag directly. Note that we
3974 still need to post a message to ensure the main thread will be
3975 woken up if blocked in sys_select(), but we do NOT want to post
3976 the quit_char message itself (because it will usually be as if
3977 the user had typed quit_char twice). Instead, we post a dummy
3978 message that has no particular effect. */
3979 {
3980 int c = wParam;
3981 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3982 c = make_ctrl_char (c) & 0377;
7d081355
AI
3983 if (c == quit_char
3984 || (wmsg.dwModifiers == 0 &&
3985 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
3986 {
3987 Vquit_flag = Qt;
3988
3989 /* The choice of message is somewhat arbitrary, as long as
3990 the main thread handler just ignores it. */
3991 msg = WM_NULL;
3992
3993 /* Interrupt any blocking system calls. */
3994 signal_quit ();
3995
3996 /* As a safety precaution, forcibly complete any deferred
3997 messages. This is a kludge, but I don't see any particularly
3998 clean way to handle the situation where a deferred message is
3999 "dropped" in the lisp thread, and will thus never be
4000 completed, eg. by the user trying to activate the menubar
4001 when the lisp thread is busy, and then typing C-g when the
4002 menubar doesn't open promptly (with the result that the
4003 menubar never responds at all because the deferred
4004 WM_INITMENU message is never completed). Another problem
4005 situation is when the lisp thread calls SendMessage (to send
4006 a window manager command) when a message has been deferred;
4007 the lisp thread gets blocked indefinitely waiting for the
4008 deferred message to be completed, which itself is waiting for
4009 the lisp thread to respond.
4010
4011 Note that we don't want to block the input thread waiting for
4012 a reponse from the lisp thread (although that would at least
4013 solve the deadlock problem above), because we want to be able
4014 to receive C-g to interrupt the lisp thread. */
4015 cancel_all_deferred_msgs ();
4016 }
4017 }
4018
4019 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4020}
4021
ee78dc32
GV
4022/* Main window procedure */
4023
ee78dc32 4024LRESULT CALLBACK
fbd6baed 4025w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4026 HWND hwnd;
4027 UINT msg;
4028 WPARAM wParam;
4029 LPARAM lParam;
4030{
4031 struct frame *f;
fbd6baed
GV
4032 struct w32_display_info *dpyinfo = &one_w32_display_info;
4033 W32Msg wmsg;
84fb1139 4034 int windows_translate;
576ba81c 4035 int key;
84fb1139 4036
a6085637
KH
4037 /* Note that it is okay to call x_window_to_frame, even though we are
4038 not running in the main lisp thread, because frame deletion
4039 requires the lisp thread to synchronize with this thread. Thus, if
4040 a frame struct is returned, it can be used without concern that the
4041 lisp thread might make it disappear while we are using it.
4042
4043 NB. Walking the frame list in this thread is safe (as long as
4044 writes of Lisp_Object slots are atomic, which they are on Windows).
4045 Although delete-frame can destructively modify the frame list while
4046 we are walking it, a garbage collection cannot occur until after
4047 delete-frame has synchronized with this thread.
4048
4049 It is also safe to use functions that make GDI calls, such as
fbd6baed 4050 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4051 from the frame struct using get_frame_dc which is thread-aware. */
4052
ee78dc32
GV
4053 switch (msg)
4054 {
4055 case WM_ERASEBKGND:
a6085637
KH
4056 f = x_window_to_frame (dpyinfo, hwnd);
4057 if (f)
4058 {
9badad41 4059 HDC hdc = get_frame_dc (f);
a6085637 4060 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4061 w32_clear_rect (f, hdc, &wmsg.rect);
4062 release_frame_dc (f, hdc);
ce6059da
AI
4063
4064#if defined (W32_DEBUG_DISPLAY)
4065 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
4066 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
4067 wmsg.rect.bottom));
4068#endif /* W32_DEBUG_DISPLAY */
a6085637 4069 }
5ac45f98
GV
4070 return 1;
4071 case WM_PALETTECHANGED:
4072 /* ignore our own changes */
4073 if ((HWND)wParam != hwnd)
4074 {
a6085637
KH
4075 f = x_window_to_frame (dpyinfo, hwnd);
4076 if (f)
4077 /* get_frame_dc will realize our palette and force all
4078 frames to be redrawn if needed. */
4079 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4080 }
4081 return 0;
ee78dc32 4082 case WM_PAINT:
ce6059da 4083 {
55dcfc15
AI
4084 PAINTSTRUCT paintStruct;
4085 RECT update_rect;
4086
4087 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4088 fails. Apparently this can happen under some
4089 circumstances. */
c0611964 4090 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
4091 {
4092 enter_crit ();
4093 BeginPaint (hwnd, &paintStruct);
4094
c0611964
AI
4095 if (w32_strict_painting)
4096 /* The rectangles returned by GetUpdateRect and BeginPaint
4097 do not always match. GetUpdateRect seems to be the
4098 more reliable of the two. */
4099 wmsg.rect = update_rect;
4100 else
4101 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
4102
4103#if defined (W32_DEBUG_DISPLAY)
4104 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
4105 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
4106 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
4107 update_rect.left, update_rect.top,
4108 update_rect.right, update_rect.bottom));
4109#endif
4110 EndPaint (hwnd, &paintStruct);
4111 leave_crit ();
4112
4113 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4114
4115 return 0;
4116 }
c0611964
AI
4117
4118 /* If GetUpdateRect returns 0 (meaning there is no update
4119 region), assume the whole window needs to be repainted. */
4120 GetClientRect(hwnd, &wmsg.rect);
4121 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4122 return 0;
ee78dc32 4123 }
a1a80b40 4124
ccc2d29c
GV
4125 case WM_INPUTLANGCHANGE:
4126 /* Inform lisp thread of keyboard layout changes. */
4127 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4128
4129 /* Clear dead keys in the keyboard state; for simplicity only
4130 preserve modifier key states. */
4131 {
4132 int i;
4133 BYTE keystate[256];
4134
4135 GetKeyboardState (keystate);
4136 for (i = 0; i < 256; i++)
4137 if (1
4138 && i != VK_SHIFT
4139 && i != VK_LSHIFT
4140 && i != VK_RSHIFT
4141 && i != VK_CAPITAL
4142 && i != VK_NUMLOCK
4143 && i != VK_SCROLL
4144 && i != VK_CONTROL
4145 && i != VK_LCONTROL
4146 && i != VK_RCONTROL
4147 && i != VK_MENU
4148 && i != VK_LMENU
4149 && i != VK_RMENU
4150 && i != VK_LWIN
4151 && i != VK_RWIN)
4152 keystate[i] = 0;
4153 SetKeyboardState (keystate);
4154 }
4155 goto dflt;
4156
4157 case WM_HOTKEY:
4158 /* Synchronize hot keys with normal input. */
4159 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4160 return (0);
4161
a1a80b40
GV
4162 case WM_KEYUP:
4163 case WM_SYSKEYUP:
4164 record_keyup (wParam, lParam);
4165 goto dflt;
4166
ee78dc32
GV
4167 case WM_KEYDOWN:
4168 case WM_SYSKEYDOWN:
ccc2d29c
GV
4169 /* Ignore keystrokes we fake ourself; see below. */
4170 if (dpyinfo->faked_key == wParam)
4171 {
4172 dpyinfo->faked_key = 0;
576ba81c
AI
4173 /* Make sure TranslateMessage sees them though (as long as
4174 they don't produce WM_CHAR messages). This ensures that
4175 indicator lights are toggled promptly on Windows 9x, for
4176 example. */
4177 if (lispy_function_keys[wParam] != 0)
4178 {
4179 windows_translate = 1;
4180 goto translate;
4181 }
4182 return 0;
ccc2d29c
GV
4183 }
4184
7830e24b
RS
4185 /* Synchronize modifiers with current keystroke. */
4186 sync_modifiers ();
a1a80b40 4187 record_keydown (wParam, lParam);
ccc2d29c 4188 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4189
4190 windows_translate = 0;
ccc2d29c
GV
4191
4192 switch (wParam)
4193 {
4194 case VK_LWIN:
4195 if (NILP (Vw32_pass_lwindow_to_system))
4196 {
4197 /* Prevent system from acting on keyup (which opens the
4198 Start menu if no other key was pressed) by simulating a
4199 press of Space which we will ignore. */
4200 if (GetAsyncKeyState (wParam) & 1)
4201 {
adcc3809 4202 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4203 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4204 else
576ba81c
AI
4205 key = VK_SPACE;
4206 dpyinfo->faked_key = key;
4207 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4208 }
4209 }
4210 if (!NILP (Vw32_lwindow_modifier))
4211 return 0;
4212 break;
4213 case VK_RWIN:
4214 if (NILP (Vw32_pass_rwindow_to_system))
4215 {
4216 if (GetAsyncKeyState (wParam) & 1)
4217 {
adcc3809 4218 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4219 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4220 else
576ba81c
AI
4221 key = VK_SPACE;
4222 dpyinfo->faked_key = key;
4223 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4224 }
4225 }
4226 if (!NILP (Vw32_rwindow_modifier))
4227 return 0;
4228 break;
576ba81c 4229 case VK_APPS:
ccc2d29c
GV
4230 if (!NILP (Vw32_apps_modifier))
4231 return 0;
4232 break;
4233 case VK_MENU:
4234 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4235 /* Prevent DefWindowProc from activating the menu bar if an
4236 Alt key is pressed and released by itself. */
ccc2d29c 4237 return 0;
84fb1139 4238 windows_translate = 1;
ccc2d29c
GV
4239 break;
4240 case VK_CAPITAL:
4241 /* Decide whether to treat as modifier or function key. */
4242 if (NILP (Vw32_enable_caps_lock))
4243 goto disable_lock_key;
adcc3809
GV
4244 windows_translate = 1;
4245 break;
ccc2d29c
GV
4246 case VK_NUMLOCK:
4247 /* Decide whether to treat as modifier or function key. */
4248 if (NILP (Vw32_enable_num_lock))
4249 goto disable_lock_key;
adcc3809
GV
4250 windows_translate = 1;
4251 break;
ccc2d29c
GV
4252 case VK_SCROLL:
4253 /* Decide whether to treat as modifier or function key. */
4254 if (NILP (Vw32_scroll_lock_modifier))
4255 goto disable_lock_key;
adcc3809
GV
4256 windows_translate = 1;
4257 break;
ccc2d29c 4258 disable_lock_key:
adcc3809
GV
4259 /* Ensure the appropriate lock key state (and indicator light)
4260 remains in the same state. We do this by faking another
4261 press of the relevant key. Apparently, this really is the
4262 only way to toggle the state of the indicator lights. */
4263 dpyinfo->faked_key = wParam;
4264 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4265 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4266 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4267 KEYEVENTF_EXTENDEDKEY | 0, 0);
4268 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4269 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4270 /* Ensure indicator lights are updated promptly on Windows 9x
4271 (TranslateMessage apparently does this), after forwarding
4272 input event. */
4273 post_character_message (hwnd, msg, wParam, lParam,
4274 w32_get_key_modifiers (wParam, lParam));
4275 windows_translate = 1;
ccc2d29c
GV
4276 break;
4277 case VK_CONTROL:
4278 case VK_SHIFT:
4279 case VK_PROCESSKEY: /* Generated by IME. */
4280 windows_translate = 1;
4281 break;
adcc3809
GV
4282 case VK_CANCEL:
4283 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4284 which is confusing for purposes of key binding; convert
4285 VK_CANCEL events into VK_PAUSE events. */
4286 wParam = VK_PAUSE;
4287 break;
4288 case VK_PAUSE:
4289 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4290 for purposes of key binding; convert these back into
4291 VK_NUMLOCK events, at least when we want to see NumLock key
4292 presses. (Note that there is never any possibility that
4293 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4294 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4295 wParam = VK_NUMLOCK;
4296 break;
ccc2d29c
GV
4297 default:
4298 /* If not defined as a function key, change it to a WM_CHAR message. */
4299 if (lispy_function_keys[wParam] == 0)
4300 {
adcc3809
GV
4301 DWORD modifiers = construct_console_modifiers ();
4302
ccc2d29c
GV
4303 if (!NILP (Vw32_recognize_altgr)
4304 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4305 {
4306 /* Always let TranslateMessage handle AltGr key chords;
4307 for some reason, ToAscii doesn't always process AltGr
4308 chords correctly. */
4309 windows_translate = 1;
4310 }
adcc3809 4311 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4312 {
adcc3809
GV
4313 /* Handle key chords including any modifiers other
4314 than shift directly, in order to preserve as much
4315 modifier information as possible. */
ccc2d29c
GV
4316 if ('A' <= wParam && wParam <= 'Z')
4317 {
4318 /* Don't translate modified alphabetic keystrokes,
4319 so the user doesn't need to constantly switch
4320 layout to type control or meta keystrokes when
4321 the normal layout translates alphabetic
4322 characters to non-ascii characters. */
4323 if (!modifier_set (VK_SHIFT))
4324 wParam += ('a' - 'A');
4325 msg = WM_CHAR;
4326 }
4327 else
4328 {
4329 /* Try to handle other keystrokes by determining the
4330 base character (ie. translating the base key plus
4331 shift modifier). */
4332 int add;
4333 int isdead = 0;
4334 KEY_EVENT_RECORD key;
4335
4336 key.bKeyDown = TRUE;
4337 key.wRepeatCount = 1;
4338 key.wVirtualKeyCode = wParam;
4339 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4340 key.uChar.AsciiChar = 0;
adcc3809 4341 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4342
4343 add = w32_kbd_patch_key (&key);
4344 /* 0 means an unrecognised keycode, negative means
4345 dead key. Ignore both. */
4346 while (--add >= 0)
4347 {
4348 /* Forward asciified character sequence. */
4349 post_character_message
4350 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4351 w32_get_key_modifiers (wParam, lParam));
4352 w32_kbd_patch_key (&key);
4353 }
4354 return 0;
4355 }
4356 }
4357 else
4358 {
4359 /* Let TranslateMessage handle everything else. */
4360 windows_translate = 1;
4361 }
4362 }
4363 }
a1a80b40 4364
adcc3809 4365 translate:
84fb1139
KH
4366 if (windows_translate)
4367 {
e9e23e23 4368 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4369
e9e23e23
GV
4370 windows_msg.time = GetMessageTime ();
4371 TranslateMessage (&windows_msg);
84fb1139
KH
4372 goto dflt;
4373 }
4374
ee78dc32
GV
4375 /* Fall through */
4376
4377 case WM_SYSCHAR:
4378 case WM_CHAR:
ccc2d29c
GV
4379 post_character_message (hwnd, msg, wParam, lParam,
4380 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4381 break;
da36a4d6 4382
5ac45f98
GV
4383 /* Simulate middle mouse button events when left and right buttons
4384 are used together, but only if user has two button mouse. */
ee78dc32 4385 case WM_LBUTTONDOWN:
5ac45f98 4386 case WM_RBUTTONDOWN:
7ce9aaca 4387 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4388 goto handle_plain_button;
4389
4390 {
4391 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4392 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4393
3cb20f4a
RS
4394 if (button_state & this)
4395 return 0;
5ac45f98
GV
4396
4397 if (button_state == 0)
4398 SetCapture (hwnd);
4399
4400 button_state |= this;
4401
4402 if (button_state & other)
4403 {
84fb1139 4404 if (mouse_button_timer)
5ac45f98 4405 {
84fb1139
KH
4406 KillTimer (hwnd, mouse_button_timer);
4407 mouse_button_timer = 0;
5ac45f98
GV
4408
4409 /* Generate middle mouse event instead. */
4410 msg = WM_MBUTTONDOWN;
4411 button_state |= MMOUSE;
4412 }
4413 else if (button_state & MMOUSE)
4414 {
4415 /* Ignore button event if we've already generated a
4416 middle mouse down event. This happens if the
4417 user releases and press one of the two buttons
4418 after we've faked a middle mouse event. */
4419 return 0;
4420 }
4421 else
4422 {
4423 /* Flush out saved message. */
84fb1139 4424 post_msg (&saved_mouse_button_msg);
5ac45f98 4425 }
fbd6baed 4426 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4427 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4428
4429 /* Clear message buffer. */
84fb1139 4430 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4431 }
4432 else
4433 {
4434 /* Hold onto message for now. */
84fb1139 4435 mouse_button_timer =
adcc3809
GV
4436 SetTimer (hwnd, MOUSE_BUTTON_ID,
4437 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4438 saved_mouse_button_msg.msg.hwnd = hwnd;
4439 saved_mouse_button_msg.msg.message = msg;
4440 saved_mouse_button_msg.msg.wParam = wParam;
4441 saved_mouse_button_msg.msg.lParam = lParam;
4442 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4443 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4444 }
4445 }
4446 return 0;
4447
ee78dc32 4448 case WM_LBUTTONUP:
5ac45f98 4449 case WM_RBUTTONUP:
7ce9aaca 4450 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4451 goto handle_plain_button;
4452
4453 {
4454 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4455 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4456
3cb20f4a
RS
4457 if ((button_state & this) == 0)
4458 return 0;
5ac45f98
GV
4459
4460 button_state &= ~this;
4461
4462 if (button_state & MMOUSE)
4463 {
4464 /* Only generate event when second button is released. */
4465 if ((button_state & other) == 0)
4466 {
4467 msg = WM_MBUTTONUP;
4468 button_state &= ~MMOUSE;
4469
4470 if (button_state) abort ();
4471 }
4472 else
4473 return 0;
4474 }
4475 else
4476 {
4477 /* Flush out saved message if necessary. */
84fb1139 4478 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4479 {
84fb1139 4480 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4481 }
4482 }
fbd6baed 4483 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4484 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4485
4486 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4487 saved_mouse_button_msg.msg.hwnd = 0;
4488 KillTimer (hwnd, mouse_button_timer);
4489 mouse_button_timer = 0;
5ac45f98
GV
4490
4491 if (button_state == 0)
4492 ReleaseCapture ();
4493 }
4494 return 0;
4495
ee78dc32
GV
4496 case WM_MBUTTONDOWN:
4497 case WM_MBUTTONUP:
5ac45f98 4498 handle_plain_button:
ee78dc32
GV
4499 {
4500 BOOL up;
1edf84e7 4501 int button;
ee78dc32 4502
1edf84e7 4503 if (parse_button (msg, &button, &up))
ee78dc32
GV
4504 {
4505 if (up) ReleaseCapture ();
4506 else SetCapture (hwnd);
1edf84e7
GV
4507 button = (button == 0) ? LMOUSE :
4508 ((button == 1) ? MMOUSE : RMOUSE);
4509 if (up)
4510 button_state &= ~button;
4511 else
4512 button_state |= button;
ee78dc32
GV
4513 }
4514 }
4515
fbd6baed 4516 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4517 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5ac45f98
GV
4518 return 0;
4519
84fb1139 4520 case WM_VSCROLL:
5ac45f98 4521 case WM_MOUSEMOVE:
fbd6baed 4522 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4523 || (msg == WM_MOUSEMOVE && button_state == 0))
4524 {
fbd6baed 4525 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4526 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4527 return 0;
4528 }
4529
4530 /* Hang onto mouse move and scroll messages for a bit, to avoid
4531 sending such events to Emacs faster than it can process them.
4532 If we get more events before the timer from the first message
4533 expires, we just replace the first message. */
4534
4535 if (saved_mouse_move_msg.msg.hwnd == 0)
4536 mouse_move_timer =
adcc3809
GV
4537 SetTimer (hwnd, MOUSE_MOVE_ID,
4538 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4539
4540 /* Hold onto message for now. */
4541 saved_mouse_move_msg.msg.hwnd = hwnd;
4542 saved_mouse_move_msg.msg.message = msg;
4543 saved_mouse_move_msg.msg.wParam = wParam;
4544 saved_mouse_move_msg.msg.lParam = lParam;
4545 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4546 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4547
4548 return 0;
4549
1edf84e7
GV
4550 case WM_MOUSEWHEEL:
4551 wmsg.dwModifiers = w32_get_modifiers ();
4552 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4553 return 0;
4554
cb9e33d4
RS
4555 case WM_DROPFILES:
4556 wmsg.dwModifiers = w32_get_modifiers ();
4557 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4558 return 0;
4559
84fb1139
KH
4560 case WM_TIMER:
4561 /* Flush out saved messages if necessary. */
4562 if (wParam == mouse_button_timer)
5ac45f98 4563 {
84fb1139
KH
4564 if (saved_mouse_button_msg.msg.hwnd)
4565 {
4566 post_msg (&saved_mouse_button_msg);
4567 saved_mouse_button_msg.msg.hwnd = 0;
4568 }
4569 KillTimer (hwnd, mouse_button_timer);
4570 mouse_button_timer = 0;
4571 }
4572 else if (wParam == mouse_move_timer)
4573 {
4574 if (saved_mouse_move_msg.msg.hwnd)
4575 {
4576 post_msg (&saved_mouse_move_msg);
4577 saved_mouse_move_msg.msg.hwnd = 0;
4578 }
4579 KillTimer (hwnd, mouse_move_timer);
4580 mouse_move_timer = 0;
5ac45f98 4581 }
5ac45f98 4582 return 0;
84fb1139
KH
4583
4584 case WM_NCACTIVATE:
4585 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4586 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4587 The only indication we get that something happened is receiving
4588 this message afterwards. So this is a good time to reset our
4589 keyboard modifiers' state. */
4590 reset_modifiers ();
4591 goto dflt;
da36a4d6 4592
1edf84e7 4593 case WM_INITMENU:
487163ac
AI
4594 button_state = 0;
4595 ReleaseCapture ();
1edf84e7
GV
4596 /* We must ensure menu bar is fully constructed and up to date
4597 before allowing user interaction with it. To achieve this
4598 we send this message to the lisp thread and wait for a
4599 reply (whose value is not actually needed) to indicate that
4600 the menu bar is now ready for use, so we can now return.
4601
4602 To remain responsive in the meantime, we enter a nested message
4603 loop that can process all other messages.
4604
4605 However, we skip all this if the message results from calling
4606 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4607 thread a message because it is blocked on us at this point. We
4608 set menubar_active before calling TrackPopupMenu to indicate
4609 this (there is no possibility of confusion with real menubar
4610 being active). */
4611
4612 f = x_window_to_frame (dpyinfo, hwnd);
4613 if (f
4614 && (f->output_data.w32->menubar_active
4615 /* We can receive this message even in the absence of a
4616 menubar (ie. when the system menu is activated) - in this
4617 case we do NOT want to forward the message, otherwise it
4618 will cause the menubar to suddenly appear when the user
4619 had requested it to be turned off! */
4620 || f->output_data.w32->menubar_widget == NULL))
4621 return 0;
4622
4623 {
4624 deferred_msg msg_buf;
4625
4626 /* Detect if message has already been deferred; in this case
4627 we cannot return any sensible value to ignore this. */
4628 if (find_deferred_msg (hwnd, msg) != NULL)
4629 abort ();
4630
4631 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4632 }
4633
4634 case WM_EXITMENULOOP:
4635 f = x_window_to_frame (dpyinfo, hwnd);
4636
4637 /* Indicate that menubar can be modified again. */
4638 if (f)
4639 f->output_data.w32->menubar_active = 0;
4640 goto dflt;
4641
126f2e35
JR
4642 case WM_MENUSELECT:
4643 wmsg.dwModifiers = w32_get_modifiers ();
4644 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4645 return 0;
4646
87996783
GV
4647 case WM_MEASUREITEM:
4648 f = x_window_to_frame (dpyinfo, hwnd);
4649 if (f)
4650 {
4651 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4652
4653 if (pMis->CtlType == ODT_MENU)
4654 {
4655 /* Work out dimensions for popup menu titles. */
4656 char * title = (char *) pMis->itemData;
4657 HDC hdc = GetDC (hwnd);
4658 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4659 LOGFONT menu_logfont;
4660 HFONT old_font;
4661 SIZE size;
4662
4663 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4664 menu_logfont.lfWeight = FW_BOLD;
4665 menu_font = CreateFontIndirect (&menu_logfont);
4666 old_font = SelectObject (hdc, menu_font);
4667
dfff8a69
JR
4668 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4669 if (title)
4670 {
4671 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4672 pMis->itemWidth = size.cx;
4673 if (pMis->itemHeight < size.cy)
4674 pMis->itemHeight = size.cy;
4675 }
4676 else
4677 pMis->itemWidth = 0;
87996783
GV
4678
4679 SelectObject (hdc, old_font);
4680 DeleteObject (menu_font);
4681 ReleaseDC (hwnd, hdc);
4682 return TRUE;
4683 }
4684 }
4685 return 0;
4686
4687 case WM_DRAWITEM:
4688 f = x_window_to_frame (dpyinfo, hwnd);
4689 if (f)
4690 {
4691 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4692
4693 if (pDis->CtlType == ODT_MENU)
4694 {
4695 /* Draw popup menu title. */
4696 char * title = (char *) pDis->itemData;
212da13b
JR
4697 if (title)
4698 {
4699 HDC hdc = pDis->hDC;
4700 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4701 LOGFONT menu_logfont;
4702 HFONT old_font;
4703
4704 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4705 menu_logfont.lfWeight = FW_BOLD;
4706 menu_font = CreateFontIndirect (&menu_logfont);
4707 old_font = SelectObject (hdc, menu_font);
4708
4709 /* Always draw title as if not selected. */
4710 ExtTextOut (hdc,
4711 pDis->rcItem.left
4712 + GetSystemMetrics (SM_CXMENUCHECK),
4713 pDis->rcItem.top,
4714 ETO_OPAQUE, &pDis->rcItem,
4715 title, strlen (title), NULL);
4716
4717 SelectObject (hdc, old_font);
4718 DeleteObject (menu_font);
4719 }
87996783
GV
4720 return TRUE;
4721 }
4722 }
4723 return 0;
4724
1edf84e7
GV
4725#if 0
4726 /* Still not right - can't distinguish between clicks in the
4727 client area of the frame from clicks forwarded from the scroll
4728 bars - may have to hook WM_NCHITTEST to remember the mouse
4729 position and then check if it is in the client area ourselves. */
4730 case WM_MOUSEACTIVATE:
4731 /* Discard the mouse click that activates a frame, allowing the
4732 user to click anywhere without changing point (or worse!).
4733 Don't eat mouse clicks on scrollbars though!! */
4734 if (LOWORD (lParam) == HTCLIENT )
4735 return MA_ACTIVATEANDEAT;
4736 goto dflt;
4737#endif
4738
1edf84e7 4739 case WM_ACTIVATEAPP:
ccc2d29c 4740 case WM_ACTIVATE:
1edf84e7
GV
4741 case WM_WINDOWPOSCHANGED:
4742 case WM_SHOWWINDOW:
4743 /* Inform lisp thread that a frame might have just been obscured
4744 or exposed, so should recheck visibility of all frames. */
4745 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4746 goto dflt;
4747
da36a4d6 4748 case WM_SETFOCUS:
adcc3809
GV
4749 dpyinfo->faked_key = 0;
4750 reset_modifiers ();
ccc2d29c
GV
4751 register_hot_keys (hwnd);
4752 goto command;
8681157a 4753 case WM_KILLFOCUS:
ccc2d29c 4754 unregister_hot_keys (hwnd);
487163ac
AI
4755 button_state = 0;
4756 ReleaseCapture ();
ee78dc32
GV
4757 case WM_MOVE:
4758 case WM_SIZE:
ee78dc32 4759 case WM_COMMAND:
ccc2d29c 4760 command:
fbd6baed 4761 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4762 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4763 goto dflt;
8847d890
RS
4764
4765 case WM_CLOSE:
fbd6baed 4766 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4767 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4768 return 0;
4769
ee78dc32
GV
4770 case WM_WINDOWPOSCHANGING:
4771 {
4772 WINDOWPLACEMENT wp;
4773 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4774
4775 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4776 GetWindowPlacement (hwnd, &wp);
4777
1edf84e7 4778 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4779 {
4780 RECT rect;
4781 int wdiff;
4782 int hdiff;
1edf84e7
GV
4783 DWORD font_width;
4784 DWORD line_height;
4785 DWORD internal_border;
4786 DWORD scrollbar_extra;
ee78dc32
GV
4787 RECT wr;
4788
5ac45f98 4789 wp.length = sizeof(wp);
ee78dc32
GV
4790 GetWindowRect (hwnd, &wr);
4791
3c190163 4792 enter_crit ();
ee78dc32 4793
1edf84e7
GV
4794 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4795 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4796 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4797 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4798
3c190163 4799 leave_crit ();
ee78dc32
GV
4800
4801 memset (&rect, 0, sizeof (rect));
4802 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4803 GetMenu (hwnd) != NULL);
4804
1edf84e7
GV
4805 /* Force width and height of client area to be exact
4806 multiples of the character cell dimensions. */
4807 wdiff = (lppos->cx - (rect.right - rect.left)
4808 - 2 * internal_border - scrollbar_extra)
4809 % font_width;
4810 hdiff = (lppos->cy - (rect.bottom - rect.top)
4811 - 2 * internal_border)
4812 % line_height;
ee78dc32
GV
4813
4814 if (wdiff || hdiff)
4815 {
4816 /* For right/bottom sizing we can just fix the sizes.
4817 However for top/left sizing we will need to fix the X
4818 and Y positions as well. */
4819
4820 lppos->cx -= wdiff;
4821 lppos->cy -= hdiff;
4822
4823 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4824 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4825 {
4826 if (lppos->x != wr.left || lppos->y != wr.top)
4827 {
4828 lppos->x += wdiff;
4829 lppos->y += hdiff;
4830 }
4831 else
4832 {
4833 lppos->flags |= SWP_NOMOVE;
4834 }
4835 }
4836
1edf84e7 4837 return 0;
ee78dc32
GV
4838 }
4839 }
4840 }
ee78dc32
GV
4841
4842 goto dflt;
1edf84e7 4843
b1f918f8
GV
4844 case WM_GETMINMAXINFO:
4845 /* Hack to correct bug that allows Emacs frames to be resized
4846 below the Minimum Tracking Size. */
4847 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4848 return 0;
4849
1edf84e7
GV
4850 case WM_EMACS_CREATESCROLLBAR:
4851 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4852 (struct scroll_bar *) lParam);
4853
5ac45f98 4854 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4855 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4856
dfdb4047 4857 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4858 {
4859 HWND foreground_window;
4860 DWORD foreground_thread, retval;
4861
4862 /* On NT 5.0, and apparently Windows 98, it is necessary to
4863 attach to the thread that currently has focus in order to
4864 pull the focus away from it. */
4865 foreground_window = GetForegroundWindow ();
4866 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4867 if (!foreground_window
4868 || foreground_thread == GetCurrentThreadId ()
4869 || !AttachThreadInput (GetCurrentThreadId (),
4870 foreground_thread, TRUE))
4871 foreground_thread = 0;
4872
4873 retval = SetForegroundWindow ((HWND) wParam);
4874
4875 /* Detach from the previous foreground thread. */
4876 if (foreground_thread)
4877 AttachThreadInput (GetCurrentThreadId (),
4878 foreground_thread, FALSE);
4879
4880 return retval;
4881 }
dfdb4047 4882
5ac45f98
GV
4883 case WM_EMACS_SETWINDOWPOS:
4884 {
1edf84e7
GV
4885 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4886 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
4887 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4888 }
1edf84e7 4889
ee78dc32 4890 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 4891 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
4892 return DestroyWindow ((HWND) wParam);
4893
4894 case WM_EMACS_TRACKPOPUPMENU:
4895 {
4896 UINT flags;
4897 POINT *pos;
4898 int retval;
4899 pos = (POINT *)lParam;
4900 flags = TPM_CENTERALIGN;
4901 if (button_state & LMOUSE)
4902 flags |= TPM_LEFTBUTTON;
4903 else if (button_state & RMOUSE)
4904 flags |= TPM_RIGHTBUTTON;
4905
87996783
GV
4906 /* Remember we did a SetCapture on the initial mouse down event,
4907 so for safety, we make sure the capture is cancelled now. */
4908 ReleaseCapture ();
490822ff 4909 button_state = 0;
87996783 4910
1edf84e7
GV
4911 /* Use menubar_active to indicate that WM_INITMENU is from
4912 TrackPopupMenu below, and should be ignored. */
4913 f = x_window_to_frame (dpyinfo, hwnd);
4914 if (f)
4915 f->output_data.w32->menubar_active = 1;
4916
4917 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4918 0, hwnd, NULL))
4919 {
4920 MSG amsg;
4921 /* Eat any mouse messages during popupmenu */
4922 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4923 PM_REMOVE));
4924 /* Get the menu selection, if any */
4925 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4926 {
4927 retval = LOWORD (amsg.wParam);
4928 }
4929 else
4930 {
4931 retval = 0;
4932 }
1edf84e7
GV
4933 }
4934 else
4935 {
4936 retval = -1;
4937 }
4938
4939 return retval;
4940 }
4941
ee78dc32 4942 default:
93fbe8b7
GV
4943 /* Check for messages registered at runtime. */
4944 if (msg == msh_mousewheel)
4945 {
4946 wmsg.dwModifiers = w32_get_modifiers ();
4947 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4948 return 0;
4949 }
4950
ee78dc32
GV
4951 dflt:
4952 return DefWindowProc (hwnd, msg, wParam, lParam);
4953 }
4954
1edf84e7
GV
4955
4956 /* The most common default return code for handled messages is 0. */
4957 return 0;
ee78dc32
GV
4958}
4959
4960void
4961my_create_window (f)
4962 struct frame * f;
4963{
4964 MSG msg;
4965
1edf84e7
GV
4966 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4967 abort ();
ee78dc32
GV
4968 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4969}
4970
fbd6baed 4971/* Create and set up the w32 window for frame F. */
ee78dc32
GV
4972
4973static void
fbd6baed 4974w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
4975 struct frame *f;
4976 long window_prompting;
4977 int minibuffer_only;
4978{
4979 BLOCK_INPUT;
4980
4981 /* Use the resource name as the top-level window name
4982 for looking up resources. Make a non-Lisp copy
4983 for the window manager, so GC relocation won't bother it.
4984
4985 Elsewhere we specify the window name for the window manager. */
4986
4987 {
4988 char *str = (char *) XSTRING (Vx_resource_name)->data;
4989 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4990 strcpy (f->namebuf, str);
4991 }
4992
4993 my_create_window (f);
4994
4995 validate_x_resource_name ();
4996
4997 /* x_set_name normally ignores requests to set the name if the
4998 requested name is the same as the current name. This is the one
4999 place where that assumption isn't correct; f->name is set, but
5000 the server hasn't been told. */
5001 {
5002 Lisp_Object name;
5003 int explicit = f->explicit_name;
5004
5005 f->explicit_name = 0;
5006 name = f->name;
5007 f->name = Qnil;
5008 x_set_name (f, name, explicit);
5009 }
5010
5011 UNBLOCK_INPUT;
5012
5013 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5014 initialize_frame_menubar (f);
5015
fbd6baed 5016 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5017 error ("Unable to create window");
5018}
5019
5020/* Handle the icon stuff for this window. Perhaps later we might
5021 want an x_set_icon_position which can be called interactively as
5022 well. */
5023
5024static void
5025x_icon (f, parms)
5026 struct frame *f;
5027 Lisp_Object parms;
5028{
5029 Lisp_Object icon_x, icon_y;
5030
e9e23e23 5031 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5032 icons in the tray. */
6fc2811b
JR
5033 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5034 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5035 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5036 {
5037 CHECK_NUMBER (icon_x, 0);
5038 CHECK_NUMBER (icon_y, 0);
5039 }
5040 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5041 error ("Both left and top icon corners of icon must be specified");
5042
5043 BLOCK_INPUT;
5044
5045 if (! EQ (icon_x, Qunbound))
5046 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5047
1edf84e7
GV
5048#if 0 /* TODO */
5049 /* Start up iconic or window? */
5050 x_wm_set_window_state
6fc2811b 5051 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5052 ? IconicState
5053 : NormalState));
5054
5055 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5056 ? f->icon_name
5057 : f->name))->data);
5058#endif
5059
ee78dc32
GV
5060 UNBLOCK_INPUT;
5061}
5062
6fc2811b
JR
5063
5064static void
5065x_make_gc (f)
5066 struct frame *f;
5067{
5068 XGCValues gc_values;
5069
5070 BLOCK_INPUT;
5071
5072 /* Create the GC's of this frame.
5073 Note that many default values are used. */
5074
5075 /* Normal video */
5076 gc_values.font = f->output_data.w32->font;
5077
5078 /* Cursor has cursor-color background, background-color foreground. */
5079 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5080 gc_values.background = f->output_data.w32->cursor_pixel;
5081 f->output_data.w32->cursor_gc
5082 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5083 (GCFont | GCForeground | GCBackground),
5084 &gc_values);
5085
5086 /* Reliefs. */
5087 f->output_data.w32->white_relief.gc = 0;
5088 f->output_data.w32->black_relief.gc = 0;
5089
5090 UNBLOCK_INPUT;
5091}
5092
5093
937e601e
AI
5094/* Handler for signals raised during x_create_frame and
5095 x_create_top_frame. FRAME is the frame which is partially
5096 constructed. */
5097
5098static Lisp_Object
5099unwind_create_frame (frame)
5100 Lisp_Object frame;
5101{
5102 struct frame *f = XFRAME (frame);
5103
5104 /* If frame is ``official'', nothing to do. */
5105 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5106 {
5107#ifdef GLYPH_DEBUG
5108 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5109#endif
5110
5111 x_free_frame_resources (f);
5112
5113 /* Check that reference counts are indeed correct. */
5114 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5115 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5116
5117 return Qt;
937e601e
AI
5118 }
5119
5120 return Qnil;
5121}
5122
5123
ee78dc32
GV
5124DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5125 1, 1, 0,
5126 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5127Returns an Emacs frame object.\n\
5128ALIST is an alist of frame parameters.\n\
5129If the parameters specify that the frame should not have a minibuffer,\n\
5130and do not specify a specific minibuffer window to use,\n\
5131then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5132be shared by the new frame.\n\
5133\n\
5134This function is an internal primitive--use `make-frame' instead.")
5135 (parms)
5136 Lisp_Object parms;
5137{
5138 struct frame *f;
5139 Lisp_Object frame, tem;
5140 Lisp_Object name;
5141 int minibuffer_only = 0;
5142 long window_prompting = 0;
5143 int width, height;
dc220243 5144 int count = BINDING_STACK_SIZE ();
1edf84e7 5145 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5146 Lisp_Object display;
6fc2811b 5147 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5148 Lisp_Object parent;
5149 struct kboard *kb;
5150
4587b026
GV
5151 check_w32 ();
5152
ee78dc32
GV
5153 /* Use this general default value to start with
5154 until we know if this frame has a specified name. */
5155 Vx_resource_name = Vinvocation_name;
5156
6fc2811b 5157 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5158 if (EQ (display, Qunbound))
5159 display = Qnil;
5160 dpyinfo = check_x_display_info (display);
5161#ifdef MULTI_KBOARD
5162 kb = dpyinfo->kboard;
5163#else
5164 kb = &the_only_kboard;
5165#endif
5166
6fc2811b 5167 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5168 if (!STRINGP (name)
5169 && ! EQ (name, Qunbound)
5170 && ! NILP (name))
5171 error ("Invalid frame name--not a string or nil");
5172
5173 if (STRINGP (name))
5174 Vx_resource_name = name;
5175
5176 /* See if parent window is specified. */
6fc2811b 5177 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5178 if (EQ (parent, Qunbound))
5179 parent = Qnil;
5180 if (! NILP (parent))
5181 CHECK_NUMBER (parent, 0);
5182
1edf84e7
GV
5183 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5184 /* No need to protect DISPLAY because that's not used after passing
5185 it to make_frame_without_minibuffer. */
5186 frame = Qnil;
5187 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5188 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5189 RES_TYPE_SYMBOL);
ee78dc32
GV
5190 if (EQ (tem, Qnone) || NILP (tem))
5191 f = make_frame_without_minibuffer (Qnil, kb, display);
5192 else if (EQ (tem, Qonly))
5193 {
5194 f = make_minibuffer_frame ();
5195 minibuffer_only = 1;
5196 }
5197 else if (WINDOWP (tem))
5198 f = make_frame_without_minibuffer (tem, kb, display);
5199 else
5200 f = make_frame (1);
5201
1edf84e7
GV
5202 XSETFRAME (frame, f);
5203
ee78dc32
GV
5204 /* Note that Windows does support scroll bars. */
5205 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5206 /* By default, make scrollbars the system standard width. */
5207 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5208
fbd6baed 5209 f->output_method = output_w32;
6fc2811b
JR
5210 f->output_data.w32 =
5211 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5212 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5213 FRAME_FONTSET (f) = -1;
937e601e 5214 record_unwind_protect (unwind_create_frame, frame);
4587b026 5215
1edf84e7 5216 f->icon_name
6fc2811b 5217 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5218 if (! STRINGP (f->icon_name))
5219 f->icon_name = Qnil;
5220
fbd6baed 5221/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5222#ifdef MULTI_KBOARD
5223 FRAME_KBOARD (f) = kb;
5224#endif
5225
5226 /* Specify the parent under which to make this window. */
5227
5228 if (!NILP (parent))
5229 {
1660f34a 5230 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5231 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5232 }
5233 else
5234 {
fbd6baed
GV
5235 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5236 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5237 }
5238
ee78dc32
GV
5239 /* Set the name; the functions to which we pass f expect the name to
5240 be set. */
5241 if (EQ (name, Qunbound) || NILP (name))
5242 {
fbd6baed 5243 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5244 f->explicit_name = 0;
5245 }
5246 else
5247 {
5248 f->name = name;
5249 f->explicit_name = 1;
5250 /* use the frame's title when getting resources for this frame. */
5251 specbind (Qx_resource_name, name);
5252 }
5253
5254 /* Extract the window parameters from the supplied values
5255 that are needed to determine window geometry. */
5256 {
5257 Lisp_Object font;
5258
6fc2811b
JR
5259 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5260
ee78dc32
GV
5261 BLOCK_INPUT;
5262 /* First, try whatever font the caller has specified. */
5263 if (STRINGP (font))
4587b026
GV
5264 {
5265 tem = Fquery_fontset (font, Qnil);
5266 if (STRINGP (tem))
5267 font = x_new_fontset (f, XSTRING (tem)->data);
5268 else
1075afa9 5269 font = x_new_font (f, XSTRING (font)->data);
4587b026 5270 }
ee78dc32
GV
5271 /* Try out a font which we hope has bold and italic variations. */
5272 if (!STRINGP (font))
e39649be 5273 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5274 if (! STRINGP (font))
6fc2811b 5275 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5276 /* If those didn't work, look for something which will at least work. */
5277 if (! STRINGP (font))
6fc2811b 5278 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5279 UNBLOCK_INPUT;
5280 if (! STRINGP (font))
1edf84e7 5281 font = build_string ("Fixedsys");
ee78dc32
GV
5282
5283 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5284 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5285 }
5286
5287 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5288 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5289 /* This defaults to 2 in order to match xterm. We recognize either
5290 internalBorderWidth or internalBorder (which is what xterm calls
5291 it). */
5292 if (NILP (Fassq (Qinternal_border_width, parms)))
5293 {
5294 Lisp_Object value;
5295
6fc2811b 5296 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5297 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5298 if (! EQ (value, Qunbound))
5299 parms = Fcons (Fcons (Qinternal_border_width, value),
5300 parms);
5301 }
1edf84e7 5302 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5303 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5304 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5305 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5306 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5307
5308 /* Also do the stuff which must be set before the window exists. */
5309 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5310 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5311 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5312 "background", "Background", RES_TYPE_STRING);
ee78dc32 5313 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5314 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5315 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5316 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5317 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5318 "borderColor", "BorderColor", RES_TYPE_STRING);
5319 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5320 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5321 x_default_parameter (f, parms, Qline_spacing, Qnil,
5322 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
6fc2811b 5323
ee78dc32 5324
6fc2811b
JR
5325 /* Init faces before x_default_parameter is called for scroll-bar
5326 parameters because that function calls x_set_scroll_bar_width,
5327 which calls change_frame_size, which calls Fset_window_buffer,
5328 which runs hooks, which call Fvertical_motion. At the end, we
5329 end up in init_iterator with a null face cache, which should not
5330 happen. */
5331 init_frame_faces (f);
5332
ee78dc32 5333 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b
JR
5334 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5335 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5336 "toolBar", "ToolBar", RES_TYPE_NUMBER);
1edf84e7 5337 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5338 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5339 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5340 "title", "Title", RES_TYPE_STRING);
ee78dc32 5341
fbd6baed
GV
5342 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5343 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
ee78dc32
GV
5344 window_prompting = x_figure_window_size (f, parms);
5345
5346 if (window_prompting & XNegative)
5347 {
5348 if (window_prompting & YNegative)
fbd6baed 5349 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5350 else
fbd6baed 5351 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5352 }
5353 else
5354 {
5355 if (window_prompting & YNegative)
fbd6baed 5356 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5357 else
fbd6baed 5358 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5359 }
5360
fbd6baed 5361 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5362
6fc2811b
JR
5363 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5364 f->no_split = minibuffer_only || EQ (tem, Qt);
5365
5366 /* Create the window. Add the tool-bar height to the initial frame
5367 height so that the user gets a text display area of the size he
5368 specified with -g or via the registry. Later changes of the
5369 tool-bar height don't change the frame size. This is done so that
5370 users can create tall Emacs frames without having to guess how
5371 tall the tool-bar will get. */
5372 f->height += FRAME_TOOL_BAR_LINES (f);
fbd6baed 5373 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5374 x_icon (f, parms);
6fc2811b
JR
5375
5376 x_make_gc (f);
5377
5378 /* Now consider the frame official. */
5379 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5380 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5381
5382 /* We need to do this after creating the window, so that the
5383 icon-creation functions can say whose icon they're describing. */
5384 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5385 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5386
5387 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5388 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5389 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5390 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5391 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5392 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5393 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5394 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5395
5396 /* Dimensions, especially f->height, must be done via change_frame_size.
5397 Change will not be effected unless different from the current
5398 f->height. */
5399 width = f->width;
5400 height = f->height;
dc220243
JR
5401
5402 /* Add the tool-bar height to the initial frame height so that the
5403 user gets a text display area of the size he specified with -g or
5404 via .Xdefaults. Later changes of the tool-bar height don't
5405 change the frame size. This is done so that users can create
5406 tall Emacs frames without having to guess how tall the tool-bar
5407 will get. */
5408 if (FRAME_TOOL_BAR_LINES (f))
5409 {
5410 int margin, relief, bar_height;
5411
5412 relief = (tool_bar_button_relief > 0
5413 ? tool_bar_button_relief
5414 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5415
5416 if (INTEGERP (Vtool_bar_button_margin)
5417 && XINT (Vtool_bar_button_margin) > 0)
5418 margin = XFASTINT (Vtool_bar_button_margin);
5419 else if (CONSP (Vtool_bar_button_margin)
5420 && INTEGERP (XCDR (Vtool_bar_button_margin))
5421 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5422 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5423 else
5424 margin = 0;
5425
5426 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5427 height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5428 }
5429
1026b400
RS
5430 f->height = 0;
5431 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5432 change_frame_size (f, height, width, 1, 0, 0);
5433
6fc2811b
JR
5434 /* Tell the server what size and position, etc, we want, and how
5435 badly we want them. This should be done after we have the menu
5436 bar so that its size can be taken into account. */
ee78dc32
GV
5437 BLOCK_INPUT;
5438 x_wm_set_size_hint (f, window_prompting, 0);
5439 UNBLOCK_INPUT;
5440
4694d762
JR
5441 /* Set up faces after all frame parameters are known. This call
5442 also merges in face attributes specified for new frames. If we
5443 don't do this, the `menu' face for instance won't have the right
5444 colors, and the menu bar won't appear in the specified colors for
5445 new frames. */
5446 call1 (Qface_set_after_frame_default, frame);
5447
6fc2811b
JR
5448 /* Make the window appear on the frame and enable display, unless
5449 the caller says not to. However, with explicit parent, Emacs
5450 cannot control visibility, so don't try. */
fbd6baed 5451 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5452 {
5453 Lisp_Object visibility;
5454
6fc2811b 5455 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5456 if (EQ (visibility, Qunbound))
5457 visibility = Qt;
5458
5459 if (EQ (visibility, Qicon))
5460 x_iconify_frame (f);
5461 else if (! NILP (visibility))
5462 x_make_frame_visible (f);
5463 else
5464 /* Must have been Qnil. */
5465 ;
5466 }
6fc2811b 5467 UNGCPRO;
ee78dc32
GV
5468 return unbind_to (count, frame);
5469}
5470
5471/* FRAME is used only to get a handle on the X display. We don't pass the
5472 display info directly because we're called from frame.c, which doesn't
5473 know about that structure. */
5474Lisp_Object
5475x_get_focus_frame (frame)
5476 struct frame *frame;
5477{
fbd6baed 5478 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5479 Lisp_Object xfocus;
fbd6baed 5480 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5481 return Qnil;
5482
fbd6baed 5483 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5484 return xfocus;
5485}
1edf84e7
GV
5486
5487DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5488 "Give FRAME input focus, raising to foreground if necessary.")
5489 (frame)
5490 Lisp_Object frame;
5491{
5492 x_focus_on_frame (check_x_frame (frame));
5493 return Qnil;
5494}
5495
ee78dc32 5496\f
767b1ff0
JR
5497/* Return the charset portion of a font name. */
5498char * xlfd_charset_of_font (char * fontname)
5499{
5500 char *charset, *encoding;
5501
5502 encoding = strrchr(fontname, '-');
ceb12877 5503 if (!encoding || encoding == fontname)
767b1ff0
JR
5504 return NULL;
5505
478ea067
AI
5506 for (charset = encoding - 1; charset >= fontname; charset--)
5507 if (*charset == '-')
5508 break;
767b1ff0 5509
478ea067 5510 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5511 return NULL;
5512
5513 return charset + 1;
5514}
5515
33d52f9c
GV
5516struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5517 int size, char* filename);
8edb0a6f 5518static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
767b1ff0 5519BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len, char * charset);
33d52f9c 5520
8edb0a6f 5521static struct font_info *
33d52f9c 5522w32_load_system_font (f,fontname,size)
55dcfc15
AI
5523 struct frame *f;
5524 char * fontname;
5525 int size;
ee78dc32 5526{
4587b026
GV
5527 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5528 Lisp_Object font_names;
5529
4587b026
GV
5530 /* Get a list of all the fonts that match this name. Once we
5531 have a list of matching fonts, we compare them against the fonts
5532 we already have loaded by comparing names. */
5533 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5534
5535 if (!NILP (font_names))
3c190163 5536 {
4587b026
GV
5537 Lisp_Object tail;
5538 int i;
4587b026
GV
5539
5540 /* First check if any are already loaded, as that is cheaper
5541 than loading another one. */
5542 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5543 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5544 if (dpyinfo->font_table[i].name
5545 && (!strcmp (dpyinfo->font_table[i].name,
5546 XSTRING (XCAR (tail))->data)
5547 || !strcmp (dpyinfo->font_table[i].full_name,
5548 XSTRING (XCAR (tail))->data)))
4587b026 5549 return (dpyinfo->font_table + i);
6fc2811b 5550
8e713be6 5551 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5552 }
1075afa9 5553 else if (w32_strict_fontnames)
5ca0cd71
GV
5554 {
5555 /* If EnumFontFamiliesEx was available, we got a full list of
5556 fonts back so stop now to avoid the possibility of loading a
5557 random font. If we had to fall back to EnumFontFamilies, the
5558 list is incomplete, so continue whether the font we want was
5559 listed or not. */
5560 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5561 FARPROC enum_font_families_ex
1075afa9 5562 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5563 if (enum_font_families_ex)
5564 return NULL;
5565 }
4587b026
GV
5566
5567 /* Load the font and add it to the table. */
5568 {
767b1ff0 5569 char *full_name, *encoding, *charset;
4587b026
GV
5570 XFontStruct *font;
5571 struct font_info *fontp;
3c190163 5572 LOGFONT lf;
4587b026 5573 BOOL ok;
6fc2811b 5574 int i;
5ac45f98 5575
4587b026 5576 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5577 return (NULL);
5ac45f98 5578
4587b026
GV
5579 if (!*lf.lfFaceName)
5580 /* If no name was specified for the font, we get a random font
5581 from CreateFontIndirect - this is not particularly
5582 desirable, especially since CreateFontIndirect does not
5583 fill out the missing name in lf, so we never know what we
5584 ended up with. */
5585 return NULL;
5586
3c190163 5587 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5588 bzero (font, sizeof (*font));
5ac45f98 5589
33d52f9c
GV
5590 /* Set bdf to NULL to indicate that this is a Windows font. */
5591 font->bdf = NULL;
5ac45f98 5592
3c190163 5593 BLOCK_INPUT;
5ac45f98
GV
5594
5595 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5596
1a292d24
AI
5597 if (font->hfont == NULL)
5598 {
5599 ok = FALSE;
5600 }
5601 else
5602 {
5603 HDC hdc;
5604 HANDLE oldobj;
5c6682be 5605 int codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5606
5607 hdc = GetDC (dpyinfo->root_window);
5608 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5609
1a292d24 5610 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5611 if (codepage == CP_UNICODE)
5612 font->double_byte_p = 1;
5613 else
5614 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
5615
1a292d24
AI
5616 SelectObject (hdc, oldobj);
5617 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5618 /* Fill out details in lf according to the font that was
5619 actually loaded. */
5620 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5621 lf.lfWidth = font->tm.tmAveCharWidth;
5622 lf.lfWeight = font->tm.tmWeight;
5623 lf.lfItalic = font->tm.tmItalic;
5624 lf.lfCharSet = font->tm.tmCharSet;
5625 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5626 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5627 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5628 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5629
5630 w32_cache_char_metrics (font);
1a292d24 5631 }
5ac45f98 5632
1a292d24 5633 UNBLOCK_INPUT;
5ac45f98 5634
4587b026
GV
5635 if (!ok)
5636 {
1a292d24
AI
5637 w32_unload_font (dpyinfo, font);
5638 return (NULL);
5639 }
ee78dc32 5640
6fc2811b
JR
5641 /* Find a free slot in the font table. */
5642 for (i = 0; i < dpyinfo->n_fonts; ++i)
5643 if (dpyinfo->font_table[i].name == NULL)
5644 break;
5645
5646 /* If no free slot found, maybe enlarge the font table. */
5647 if (i == dpyinfo->n_fonts
5648 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 5649 {
6fc2811b
JR
5650 int sz;
5651 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5652 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 5653 dpyinfo->font_table
6fc2811b 5654 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
5655 }
5656
6fc2811b
JR
5657 fontp = dpyinfo->font_table + i;
5658 if (i == dpyinfo->n_fonts)
5659 ++dpyinfo->n_fonts;
4587b026
GV
5660
5661 /* Now fill in the slots of *FONTP. */
5662 BLOCK_INPUT;
5663 fontp->font = font;
6fc2811b 5664 fontp->font_idx = i;
4587b026
GV
5665 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5666 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5667
767b1ff0
JR
5668 charset = xlfd_charset_of_font (fontname);
5669
4587b026
GV
5670 /* Work out the font's full name. */
5671 full_name = (char *)xmalloc (100);
767b1ff0 5672 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
5673 fontp->full_name = full_name;
5674 else
5675 {
5676 /* If all else fails - just use the name we used to load it. */
5677 xfree (full_name);
5678 fontp->full_name = fontp->name;
5679 }
5680
5681 fontp->size = FONT_WIDTH (font);
5682 fontp->height = FONT_HEIGHT (font);
5683
5684 /* The slot `encoding' specifies how to map a character
5685 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
5686 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5687 (0:0x20..0x7F, 1:0xA0..0xFF,
5688 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 5689 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 5690 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
5691 which is never used by any charset. If mapping can't be
5692 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5693
5694 /* SJIS fonts need to be set to type 4, all others seem to work as
5695 type FONT_ENCODING_NOT_DECIDED. */
5696 encoding = strrchr (fontp->name, '-');
5697 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5698 fontp->encoding[1] = 4;
33d52f9c 5699 else
1c885fe1 5700 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5701
5702 /* The following three values are set to 0 under W32, which is
5703 what they get set to if XGetFontProperty fails under X. */
5704 fontp->baseline_offset = 0;
5705 fontp->relative_compose = 0;
33d52f9c 5706 fontp->default_ascent = 0;
4587b026 5707
6fc2811b
JR
5708 /* Set global flag fonts_changed_p to non-zero if the font loaded
5709 has a character with a smaller width than any other character
5710 before, or if the font loaded has a smalle>r height than any
5711 other font loaded before. If this happens, it will make a
5712 glyph matrix reallocation necessary. */
5713 fonts_changed_p = x_compute_min_glyph_bounds (f);
4587b026 5714 UNBLOCK_INPUT;
4587b026
GV
5715 return fontp;
5716 }
5717}
5718
33d52f9c
GV
5719/* Load font named FONTNAME of size SIZE for frame F, and return a
5720 pointer to the structure font_info while allocating it dynamically.
5721 If loading fails, return NULL. */
5722struct font_info *
5723w32_load_font (f,fontname,size)
5724struct frame *f;
5725char * fontname;
5726int size;
5727{
5728 Lisp_Object bdf_fonts;
5729 struct font_info *retval = NULL;
5730
8edb0a6f 5731 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
5732
5733 while (!retval && CONSP (bdf_fonts))
5734 {
5735 char *bdf_name, *bdf_file;
5736 Lisp_Object bdf_pair;
5737
8e713be6
KR
5738 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5739 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5740 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
5741
5742 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5743
8e713be6 5744 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
5745 }
5746
5747 if (retval)
5748 return retval;
5749
5750 return w32_load_system_font(f, fontname, size);
5751}
5752
5753
ee78dc32 5754void
fbd6baed
GV
5755w32_unload_font (dpyinfo, font)
5756 struct w32_display_info *dpyinfo;
ee78dc32
GV
5757 XFontStruct * font;
5758{
5759 if (font)
5760 {
c6be3860 5761 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
5762 if (font->bdf) w32_free_bdf_font (font->bdf);
5763
3c190163 5764 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5765 xfree (font);
5766 }
5767}
5768
fbd6baed 5769/* The font conversion stuff between x and w32 */
ee78dc32
GV
5770
5771/* X font string is as follows (from faces.el)
5772 * (let ((- "[-?]")
5773 * (foundry "[^-]+")
5774 * (family "[^-]+")
5775 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5776 * (weight\? "\\([^-]*\\)") ; 1
5777 * (slant "\\([ior]\\)") ; 2
5778 * (slant\? "\\([^-]?\\)") ; 2
5779 * (swidth "\\([^-]*\\)") ; 3
5780 * (adstyle "[^-]*") ; 4
5781 * (pixelsize "[0-9]+")
5782 * (pointsize "[0-9][0-9]+")
5783 * (resx "[0-9][0-9]+")
5784 * (resy "[0-9][0-9]+")
5785 * (spacing "[cmp?*]")
5786 * (avgwidth "[0-9]+")
5787 * (registry "[^-]+")
5788 * (encoding "[^-]+")
5789 * )
ee78dc32 5790 */
ee78dc32 5791
8edb0a6f 5792static LONG
fbd6baed 5793x_to_w32_weight (lpw)
ee78dc32
GV
5794 char * lpw;
5795{
5796 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
5797
5798 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5799 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5800 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5801 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 5802 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
5803 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5804 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5805 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5806 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5807 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 5808 else
5ac45f98 5809 return FW_DONTCARE;
ee78dc32
GV
5810}
5811
5ac45f98 5812
8edb0a6f 5813static char *
fbd6baed 5814w32_to_x_weight (fnweight)
ee78dc32
GV
5815 int fnweight;
5816{
5ac45f98
GV
5817 if (fnweight >= FW_HEAVY) return "heavy";
5818 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5819 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 5820 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
5821 if (fnweight >= FW_MEDIUM) return "medium";
5822 if (fnweight >= FW_NORMAL) return "normal";
5823 if (fnweight >= FW_LIGHT) return "light";
5824 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5825 if (fnweight >= FW_THIN) return "thin";
5826 else
5827 return "*";
5828}
5829
8edb0a6f 5830static LONG
fbd6baed 5831x_to_w32_charset (lpcs)
5ac45f98
GV
5832 char * lpcs;
5833{
767b1ff0 5834 Lisp_Object this_entry, w32_charset;
4587b026 5835
dfff8a69
JR
5836 /* Look through w32-charset-info-alist for the character set.
5837 Format of each entry is
5838 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5839 */
767b1ff0 5840 this_entry = Fassoc (build_string(lpcs), Vw32_charset_info_alist);
4587b026 5841
767b1ff0
JR
5842 if (NILP(this_entry))
5843 {
5844 /* At startup, we want iso8859-1 fonts to come up properly. */
5845 if (stricmp(lpcs, "iso8859-1") == 0)
5846 return ANSI_CHARSET;
5847 else
5848 return DEFAULT_CHARSET;
5849 }
5850
5851 w32_charset = Fcar (Fcdr (this_entry));
5852
5853 // Translate Lisp symbol to number.
5854 if (w32_charset == Qw32_charset_ansi)
5855 return ANSI_CHARSET;
5856 if (w32_charset == Qw32_charset_symbol)
5857 return SYMBOL_CHARSET;
5858 if (w32_charset == Qw32_charset_shiftjis)
5859 return SHIFTJIS_CHARSET;
5860 if (w32_charset == Qw32_charset_hangeul)
5861 return HANGEUL_CHARSET;
5862 if (w32_charset == Qw32_charset_chinesebig5)
5863 return CHINESEBIG5_CHARSET;
5864 if (w32_charset == Qw32_charset_gb2312)
5865 return GB2312_CHARSET;
5866 if (w32_charset == Qw32_charset_oem)
5867 return OEM_CHARSET;
dfff8a69 5868#ifdef JOHAB_CHARSET
767b1ff0
JR
5869 if (w32_charset == Qw32_charset_johab)
5870 return JOHAB_CHARSET;
5871 if (w32_charset == Qw32_charset_easteurope)
5872 return EASTEUROPE_CHARSET;
5873 if (w32_charset == Qw32_charset_turkish)
5874 return TURKISH_CHARSET;
5875 if (w32_charset == Qw32_charset_baltic)
5876 return BALTIC_CHARSET;
5877 if (w32_charset == Qw32_charset_russian)
5878 return RUSSIAN_CHARSET;
5879 if (w32_charset == Qw32_charset_arabic)
5880 return ARABIC_CHARSET;
5881 if (w32_charset == Qw32_charset_greek)
5882 return GREEK_CHARSET;
5883 if (w32_charset == Qw32_charset_hebrew)
5884 return HEBREW_CHARSET;
5885 if (w32_charset == Qw32_charset_vietnamese)
5886 return VIETNAMESE_CHARSET;
5887 if (w32_charset == Qw32_charset_thai)
5888 return THAI_CHARSET;
5889 if (w32_charset == Qw32_charset_mac)
5890 return MAC_CHARSET;
dfff8a69 5891#endif /* JOHAB_CHARSET */
5ac45f98 5892#ifdef UNICODE_CHARSET
767b1ff0
JR
5893 if (w32_charset == Qw32_charset_unicode)
5894 return UNICODE_CHARSET;
5ac45f98 5895#endif
dfff8a69
JR
5896
5897 return DEFAULT_CHARSET;
5ac45f98
GV
5898}
5899
dfff8a69 5900
8edb0a6f 5901static char *
fbd6baed 5902w32_to_x_charset (fncharset)
5ac45f98
GV
5903 int fncharset;
5904{
1edf84e7 5905 static char buf[16];
767b1ff0 5906 Lisp_Object charset_type;
1edf84e7 5907
5ac45f98
GV
5908 switch (fncharset)
5909 {
767b1ff0
JR
5910 case ANSI_CHARSET:
5911 /* Handle startup case of w32-charset-info-alist not
5912 being set up yet. */
5913 if (NILP(Vw32_charset_info_alist))
5914 return "iso8859-1";
5915 charset_type = Qw32_charset_ansi;
5916 break;
5917 case DEFAULT_CHARSET:
5918 charset_type = Qw32_charset_default;
5919 break;
5920 case SYMBOL_CHARSET:
5921 charset_type = Qw32_charset_symbol;
5922 break;
5923 case SHIFTJIS_CHARSET:
5924 charset_type = Qw32_charset_shiftjis;
5925 break;
5926 case HANGEUL_CHARSET:
5927 charset_type = Qw32_charset_hangeul;
5928 break;
5929 case GB2312_CHARSET:
5930 charset_type = Qw32_charset_gb2312;
5931 break;
5932 case CHINESEBIG5_CHARSET:
5933 charset_type = Qw32_charset_chinesebig5;
5934 break;
5935 case OEM_CHARSET:
5936 charset_type = Qw32_charset_oem;
5937 break;
4587b026
GV
5938
5939 /* More recent versions of Windows (95 and NT4.0) define more
5940 character sets. */
5941#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
5942 case EASTEUROPE_CHARSET:
5943 charset_type = Qw32_charset_easteurope;
5944 break;
5945 case TURKISH_CHARSET:
5946 charset_type = Qw32_charset_turkish;
5947 break;
5948 case BALTIC_CHARSET:
5949 charset_type = Qw32_charset_baltic;
5950 break;
33d52f9c 5951 case RUSSIAN_CHARSET:
767b1ff0
JR
5952 charset_type = Qw32_charset_russian;
5953 break;
5954 case ARABIC_CHARSET:
5955 charset_type = Qw32_charset_arabic;
5956 break;
5957 case GREEK_CHARSET:
5958 charset_type = Qw32_charset_greek;
5959 break;
5960 case HEBREW_CHARSET:
5961 charset_type = Qw32_charset_hebrew;
5962 break;
5963 case VIETNAMESE_CHARSET:
5964 charset_type = Qw32_charset_vietnamese;
5965 break;
5966 case THAI_CHARSET:
5967 charset_type = Qw32_charset_thai;
5968 break;
5969 case MAC_CHARSET:
5970 charset_type = Qw32_charset_mac;
5971 break;
5972 case JOHAB_CHARSET:
5973 charset_type = Qw32_charset_johab;
5974 break;
4587b026
GV
5975#endif
5976
5ac45f98 5977#ifdef UNICODE_CHARSET
767b1ff0
JR
5978 case UNICODE_CHARSET:
5979 charset_type = Qw32_charset_unicode;
5980 break;
5ac45f98 5981#endif
767b1ff0
JR
5982 default:
5983 /* Encode numerical value of unknown charset. */
5984 sprintf (buf, "*-#%u", fncharset);
5985 return buf;
5ac45f98 5986 }
767b1ff0
JR
5987
5988 {
5989 Lisp_Object rest;
5990 char * best_match = NULL;
5991
5992 /* Look through w32-charset-info-alist for the character set.
5993 Prefer ISO codepages, and prefer lower numbers in the ISO
5994 range. Only return charsets for codepages which are installed.
5995
5996 Format of each entry is
5997 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5998 */
5999 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6000 {
6001 char * x_charset;
6002 Lisp_Object w32_charset;
6003 Lisp_Object codepage;
6004
6005 Lisp_Object this_entry = XCAR (rest);
6006
6007 /* Skip invalid entries in alist. */
6008 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6009 || !CONSP (XCDR (this_entry))
6010 || !SYMBOLP (XCAR (XCDR (this_entry))))
6011 continue;
6012
6013 x_charset = XSTRING (XCAR (this_entry))->data;
6014 w32_charset = XCAR (XCDR (this_entry));
6015 codepage = XCDR (XCDR (this_entry));
6016
6017 /* Look for Same charset and a valid codepage (or non-int
6018 which means ignore). */
6019 if (w32_charset == charset_type
6020 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6021 || IsValidCodePage (XINT (codepage))))
6022 {
6023 /* If we don't have a match already, then this is the
6024 best. */
6025 if (!best_match)
6026 best_match = x_charset;
6027 /* If this is an ISO codepage, and the best so far isn't,
6028 then this is better. */
6029 else if (stricmp (best_match, "iso") != 0
6030 && stricmp (x_charset, "iso") == 0)
6031 best_match = x_charset;
6032 /* If both are ISO8859 codepages, choose the one with the
6033 lowest number in the encoding field. */
6034 else if (stricmp (best_match, "iso8859-") == 0
6035 && stricmp (x_charset, "iso8859-") == 0)
6036 {
6037 int best_enc = atoi (best_match + 8);
6038 int this_enc = atoi (x_charset + 8);
6039 if (this_enc > 0 && this_enc < best_enc)
6040 best_match = x_charset;
6041 }
6042 }
6043 }
6044
6045 /* If no match, encode the numeric value. */
6046 if (!best_match)
6047 {
6048 sprintf (buf, "*-#%u", fncharset);
6049 return buf;
6050 }
6051
6052 strncpy(buf, best_match, 15);
6053 buf[15] = '\0';
6054 return buf;
6055 }
ee78dc32
GV
6056}
6057
dfff8a69
JR
6058
6059/* Get the Windows codepage corresponding to the specified font. The
6060 charset info in the font name is used to look up
6061 w32-charset-to-codepage-alist. */
6062int
6063w32_codepage_for_font (char *fontname)
6064{
767b1ff0
JR
6065 Lisp_Object codepage, entry;
6066 char *charset_str, *charset, *end;
dfff8a69 6067
767b1ff0 6068 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6069 return CP_DEFAULT;
6070
767b1ff0
JR
6071 /* Extract charset part of font string. */
6072 charset = xlfd_charset_of_font (fontname);
6073
6074 if (!charset)
ceb12877 6075 return CP_UNKNOWN;
767b1ff0
JR
6076
6077 charset_str = (char *) alloca (strlen (charset));
6078 strcpy (charset_str, charset);
6079
dfff8a69
JR
6080 /* Remove leading "*-". */
6081 if (strncmp ("*-", charset_str, 2) == 0)
6082 charset = charset_str + 2;
6083 else
6084 charset = charset_str;
6085
6086 /* Stop match at wildcard (including preceding '-'). */
6087 if (end = strchr (charset, '*'))
6088 {
6089 if (end > charset && *(end-1) == '-')
6090 end--;
6091 *end = '\0';
6092 }
6093
767b1ff0
JR
6094 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6095 if (NILP (entry))
ceb12877 6096 return CP_UNKNOWN;
767b1ff0
JR
6097
6098 codepage = Fcdr (Fcdr (entry));
6099
6100 if (NILP (codepage))
6101 return CP_8BIT;
6102 else if (XFASTINT (codepage) == XFASTINT (Qt))
6103 return CP_UNICODE;
6104 else if (INTEGERP (codepage))
dfff8a69
JR
6105 return XINT (codepage);
6106 else
ceb12877 6107 return CP_UNKNOWN;
dfff8a69
JR
6108}
6109
6110
8edb0a6f 6111static BOOL
767b1ff0 6112w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6113 LOGFONT * lplogfont;
6114 char * lpxstr;
6115 int len;
767b1ff0 6116 char * specific_charset;
ee78dc32 6117{
6fc2811b 6118 char* fonttype;
f46e6225 6119 char *fontname;
3cb20f4a
RS
6120 char height_pixels[8];
6121 char height_dpi[8];
6122 char width_pixels[8];
4587b026 6123 char *fontname_dash;
d88c567c
JR
6124 int display_resy = one_w32_display_info.resy;
6125 int display_resx = one_w32_display_info.resx;
f46e6225
GV
6126 int bufsz;
6127 struct coding_system coding;
3cb20f4a
RS
6128
6129 if (!lpxstr) abort ();
ee78dc32 6130
3cb20f4a
RS
6131 if (!lplogfont)
6132 return FALSE;
6133
6fc2811b
JR
6134 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6135 fonttype = "raster";
6136 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6137 fonttype = "outline";
6138 else
6139 fonttype = "unknown";
6140
f46e6225
GV
6141 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
6142 &coding);
aab5ac44
KH
6143 coding.src_multibyte = 0;
6144 coding.dst_multibyte = 1;
f46e6225
GV
6145 coding.mode |= CODING_MODE_LAST_BLOCK;
6146 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6147
6148 fontname = alloca(sizeof(*fontname) * bufsz);
6149 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6150 strlen(lplogfont->lfFaceName), bufsz - 1);
6151 *(fontname + coding.produced) = '\0';
4587b026
GV
6152
6153 /* Replace dashes with underscores so the dashes are not
f46e6225 6154 misinterpreted. */
4587b026
GV
6155 fontname_dash = fontname;
6156 while (fontname_dash = strchr (fontname_dash, '-'))
6157 *fontname_dash = '_';
6158
3cb20f4a 6159 if (lplogfont->lfHeight)
ee78dc32 6160 {
3cb20f4a
RS
6161 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6162 sprintf (height_dpi, "%u",
33d52f9c 6163 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6164 }
6165 else
ee78dc32 6166 {
3cb20f4a
RS
6167 strcpy (height_pixels, "*");
6168 strcpy (height_dpi, "*");
ee78dc32 6169 }
3cb20f4a
RS
6170 if (lplogfont->lfWidth)
6171 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6172 else
6173 strcpy (width_pixels, "*");
6174
6175 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6176 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6177 fonttype, /* foundry */
4587b026
GV
6178 fontname, /* family */
6179 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6180 lplogfont->lfItalic?'i':'r', /* slant */
6181 /* setwidth name */
6182 /* add style name */
6183 height_pixels, /* pixel size */
6184 height_dpi, /* point size */
33d52f9c
GV
6185 display_resx, /* resx */
6186 display_resy, /* resy */
4587b026
GV
6187 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6188 ? 'p' : 'c', /* spacing */
6189 width_pixels, /* avg width */
767b1ff0
JR
6190 specific_charset ? specific_charset
6191 : w32_to_x_charset (lplogfont->lfCharSet)
6192 /* charset registry and encoding */
3cb20f4a
RS
6193 );
6194
ee78dc32
GV
6195 lpxstr[len - 1] = 0; /* just to be sure */
6196 return (TRUE);
6197}
6198
8edb0a6f 6199static BOOL
fbd6baed 6200x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6201 char * lpxstr;
6202 LOGFONT * lplogfont;
6203{
f46e6225
GV
6204 struct coding_system coding;
6205
ee78dc32 6206 if (!lplogfont) return (FALSE);
f46e6225 6207
ee78dc32 6208 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6209
1a292d24 6210 /* Set default value for each field. */
771c47d5 6211#if 1
ee78dc32
GV
6212 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6213 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6214 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6215#else
6216 /* go for maximum quality */
6217 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6218 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6219 lplogfont->lfQuality = PROOF_QUALITY;
6220#endif
6221
1a292d24
AI
6222 lplogfont->lfCharSet = DEFAULT_CHARSET;
6223 lplogfont->lfWeight = FW_DONTCARE;
6224 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6225
5ac45f98
GV
6226 if (!lpxstr)
6227 return FALSE;
6228
6229 /* Provide a simple escape mechanism for specifying Windows font names
6230 * directly -- if font spec does not beginning with '-', assume this
6231 * format:
6232 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6233 */
ee78dc32 6234
5ac45f98
GV
6235 if (*lpxstr == '-')
6236 {
33d52f9c
GV
6237 int fields, tem;
6238 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6239 width[10], resy[10], remainder[20];
5ac45f98 6240 char * encoding;
d98c0337 6241 int dpi = one_w32_display_info.resy;
5ac45f98
GV
6242
6243 fields = sscanf (lpxstr,
33d52f9c
GV
6244 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
6245 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5ac45f98
GV
6246 if (fields == EOF) return (FALSE);
6247
6fc2811b
JR
6248 /* If wildcards cover more than one field, we don't know which
6249 field is which, so don't fill any in. */
6250
6251 if (fields < 9)
6252 fields = 0;
6253
5ac45f98
GV
6254 if (fields > 0 && name[0] != '*')
6255 {
8ea3e054
RS
6256 int bufsize;
6257 unsigned char *buf;
6258
f46e6225
GV
6259 setup_coding_system
6260 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
aab5ac44
KH
6261 coding.src_multibyte = 1;
6262 coding.dst_multibyte = 1;
8ea3e054
RS
6263 bufsize = encoding_buffer_size (&coding, strlen (name));
6264 buf = (unsigned char *) alloca (bufsize);
f46e6225 6265 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6266 encode_coding (&coding, name, buf, strlen (name), bufsize);
6267 if (coding.produced >= LF_FACESIZE)
6268 coding.produced = LF_FACESIZE - 1;
6269 buf[coding.produced] = 0;
6270 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6271 }
6272 else
6273 {
6fc2811b 6274 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6275 }
6276
6277 fields--;
6278
fbd6baed 6279 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6280
6281 fields--;
6282
c8874f14 6283 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6284
6285 fields--;
6286
6287 if (fields > 0 && pixels[0] != '*')
6288 lplogfont->lfHeight = atoi (pixels);
6289
6290 fields--;
5ac45f98 6291 fields--;
33d52f9c
GV
6292 if (fields > 0 && resy[0] != '*')
6293 {
6fc2811b 6294 tem = atoi (resy);
33d52f9c
GV
6295 if (tem > 0) dpi = tem;
6296 }
5ac45f98 6297
33d52f9c
GV
6298 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6299 lplogfont->lfHeight = atoi (height) * dpi / 720;
6300
6301 if (fields > 0)
5ac45f98
GV
6302 lplogfont->lfPitchAndFamily =
6303 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6304
6305 fields--;
6306
6307 if (fields > 0 && width[0] != '*')
6308 lplogfont->lfWidth = atoi (width) / 10;
6309
6310 fields--;
6311
4587b026 6312 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6313 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6314 {
5ac45f98
GV
6315 int len = strlen (remainder);
6316 if (len > 0 && remainder[len-1] == '-')
6317 remainder[len-1] = 0;
ee78dc32 6318 }
5ac45f98
GV
6319 encoding = remainder;
6320 if (strncmp (encoding, "*-", 2) == 0)
6321 encoding += 2;
fbd6baed 6322 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
5ac45f98
GV
6323 }
6324 else
6325 {
6326 int fields;
6327 char name[100], height[10], width[10], weight[20];
a1a80b40 6328
5ac45f98
GV
6329 fields = sscanf (lpxstr,
6330 "%99[^:]:%9[^:]:%9[^:]:%19s",
6331 name, height, width, weight);
6332
6333 if (fields == EOF) return (FALSE);
6334
6335 if (fields > 0)
6336 {
6337 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6338 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6339 }
6340 else
6341 {
6342 lplogfont->lfFaceName[0] = 0;
6343 }
6344
6345 fields--;
6346
6347 if (fields > 0)
6348 lplogfont->lfHeight = atoi (height);
6349
6350 fields--;
6351
6352 if (fields > 0)
6353 lplogfont->lfWidth = atoi (width);
6354
6355 fields--;
6356
fbd6baed 6357 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6358 }
6359
6360 /* This makes TrueType fonts work better. */
6361 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6362
ee78dc32
GV
6363 return (TRUE);
6364}
6365
d88c567c
JR
6366/* Strip the pixel height and point height from the given xlfd, and
6367 return the pixel height. If no pixel height is specified, calculate
6368 one from the point height, or if that isn't defined either, return
6369 0 (which usually signifies a scalable font).
6370*/
8edb0a6f
JR
6371static int
6372xlfd_strip_height (char *fontname)
d88c567c 6373{
8edb0a6f 6374 int pixel_height, field_number;
d88c567c
JR
6375 char *read_from, *write_to;
6376
6377 xassert (fontname);
6378
6379 pixel_height = field_number = 0;
6380 write_to = NULL;
6381
6382 /* Look for height fields. */
6383 for (read_from = fontname; *read_from; read_from++)
6384 {
6385 if (*read_from == '-')
6386 {
6387 field_number++;
6388 if (field_number == 7) /* Pixel height. */
6389 {
6390 read_from++;
6391 write_to = read_from;
6392
6393 /* Find end of field. */
6394 for (;*read_from && *read_from != '-'; read_from++)
6395 ;
6396
6397 /* Split the fontname at end of field. */
6398 if (*read_from)
6399 {
6400 *read_from = '\0';
6401 read_from++;
6402 }
6403 pixel_height = atoi (write_to);
6404 /* Blank out field. */
6405 if (read_from > write_to)
6406 {
6407 *write_to = '-';
6408 write_to++;
6409 }
767b1ff0 6410 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6411 return now. */
6412 else
6413 return pixel_height;
6414
6415 /* If we got a pixel height, the point height can be
6416 ignored. Just blank it out and break now. */
6417 if (pixel_height)
6418 {
6419 /* Find end of point size field. */
6420 for (; *read_from && *read_from != '-'; read_from++)
6421 ;
6422
6423 if (*read_from)
6424 read_from++;
6425
6426 /* Blank out the point size field. */
6427 if (read_from > write_to)
6428 {
6429 *write_to = '-';
6430 write_to++;
6431 }
6432 else
6433 return pixel_height;
6434
6435 break;
6436 }
6437 /* If the point height is already blank, break now. */
6438 if (*read_from == '-')
6439 {
6440 read_from++;
6441 break;
6442 }
6443 }
6444 else if (field_number == 8)
6445 {
6446 /* If we didn't get a pixel height, try to get the point
6447 height and convert that. */
6448 int point_size;
6449 char *point_size_start = read_from++;
6450
6451 /* Find end of field. */
6452 for (; *read_from && *read_from != '-'; read_from++)
6453 ;
6454
6455 if (*read_from)
6456 {
6457 *read_from = '\0';
6458 read_from++;
6459 }
6460
6461 point_size = atoi (point_size_start);
6462
6463 /* Convert to pixel height. */
6464 pixel_height = point_size
6465 * one_w32_display_info.height_in / 720;
6466
6467 /* Blank out this field and break. */
6468 *write_to = '-';
6469 write_to++;
6470 break;
6471 }
6472 }
6473 }
6474
6475 /* Shift the rest of the font spec into place. */
6476 if (write_to && read_from > write_to)
6477 {
6478 for (; *read_from; read_from++, write_to++)
6479 *write_to = *read_from;
6480 *write_to = '\0';
6481 }
6482
6483 return pixel_height;
6484}
6485
6fc2811b 6486/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 6487static BOOL
6fc2811b
JR
6488w32_font_match (fontname, pattern)
6489 char * fontname;
6490 char * pattern;
ee78dc32 6491{
e7c72122 6492 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 6493 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 6494 char *ptr;
ee78dc32 6495
d88c567c
JR
6496 /* Copy fontname so we can modify it during comparison. */
6497 strcpy (font_name_copy, fontname);
6498
6fc2811b
JR
6499 ptr = regex;
6500 *ptr++ = '^';
ee78dc32 6501
6fc2811b
JR
6502 /* Turn pattern into a regexp and do a regexp match. */
6503 for (; *pattern; pattern++)
6504 {
6505 if (*pattern == '?')
6506 *ptr++ = '.';
6507 else if (*pattern == '*')
6508 {
6509 *ptr++ = '.';
6510 *ptr++ = '*';
6511 }
33d52f9c 6512 else
6fc2811b 6513 *ptr++ = *pattern;
ee78dc32 6514 }
6fc2811b
JR
6515 *ptr = '$';
6516 *(ptr + 1) = '\0';
6517
d88c567c
JR
6518 /* Strip out font heights and compare them seperately, since
6519 rounding error can cause mismatches. This also allows a
6520 comparison between a font that declares only a pixel height and a
6521 pattern that declares the point height.
6522 */
6523 {
6524 int font_height, pattern_height;
6525
6526 font_height = xlfd_strip_height (font_name_copy);
6527 pattern_height = xlfd_strip_height (regex);
6528
6529 /* Compare now, and don't bother doing expensive regexp matching
6530 if the heights differ. */
6531 if (font_height && pattern_height && (font_height != pattern_height))
6532 return FALSE;
6533 }
6534
6fc2811b 6535 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 6536 font_name_copy) >= 0);
ee78dc32
GV
6537}
6538
5ca0cd71
GV
6539/* Callback functions, and a structure holding info they need, for
6540 listing system fonts on W32. We need one set of functions to do the
6541 job properly, but these don't work on NT 3.51 and earlier, so we
6542 have a second set which don't handle character sets properly to
6543 fall back on.
6544
6545 In both cases, there are two passes made. The first pass gets one
6546 font from each family, the second pass lists all the fonts from
6547 each family. */
6548
ee78dc32
GV
6549typedef struct enumfont_t
6550{
6551 HDC hdc;
6552 int numFonts;
3cb20f4a 6553 LOGFONT logfont;
ee78dc32
GV
6554 XFontStruct *size_ref;
6555 Lisp_Object *pattern;
ee78dc32
GV
6556 Lisp_Object *tail;
6557} enumfont_t;
6558
8edb0a6f 6559static int CALLBACK
ee78dc32
GV
6560enum_font_cb2 (lplf, lptm, FontType, lpef)
6561 ENUMLOGFONT * lplf;
6562 NEWTEXTMETRIC * lptm;
6563 int FontType;
6564 enumfont_t * lpef;
6565{
1edf84e7 6566 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
ee78dc32
GV
6567 return (1);
6568
4587b026
GV
6569 /* Check that the character set matches if it was specified */
6570 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6571 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6572 return (1);
6573
ee78dc32
GV
6574 {
6575 char buf[100];
4587b026 6576 Lisp_Object width = Qnil;
767b1ff0 6577 char *charset = NULL;
ee78dc32 6578
6fc2811b
JR
6579 /* Truetype fonts do not report their true metrics until loaded */
6580 if (FontType != RASTER_FONTTYPE)
3cb20f4a 6581 {
6fc2811b
JR
6582 if (!NILP (*(lpef->pattern)))
6583 {
6584 /* Scalable fonts are as big as you want them to be. */
6585 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6586 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6587 width = make_number (lpef->logfont.lfWidth);
6588 }
6589 else
6590 {
6591 lplf->elfLogFont.lfHeight = 0;
6592 lplf->elfLogFont.lfWidth = 0;
6593 }
3cb20f4a 6594 }
6fc2811b 6595
f46e6225
GV
6596 /* Make sure the height used here is the same as everywhere
6597 else (ie character height, not cell height). */
6fc2811b
JR
6598 if (lplf->elfLogFont.lfHeight > 0)
6599 {
6600 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6601 if (FontType == RASTER_FONTTYPE)
6602 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6603 else
6604 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6605 }
4587b026 6606
767b1ff0
JR
6607 if (!NILP (*(lpef->pattern)))
6608 {
6609 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6610
6611 /* Ensure that charset is valid for this font. */
6612 if (charset
6613 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6614 charset = NULL;
6615 }
6616
6617 /* TODO: List all relevant charsets if charset not specified. */
6618 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
33d52f9c 6619 return (0);
ee78dc32 6620
5ca0cd71
GV
6621 if (NILP (*(lpef->pattern))
6622 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 6623 {
4587b026 6624 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
8e713be6 6625 lpef->tail = &(XCDR (*lpef->tail));
ee78dc32
GV
6626 lpef->numFonts++;
6627 }
6628 }
6fc2811b 6629
ee78dc32
GV
6630 return (1);
6631}
6632
8edb0a6f 6633static int CALLBACK
ee78dc32
GV
6634enum_font_cb1 (lplf, lptm, FontType, lpef)
6635 ENUMLOGFONT * lplf;
6636 NEWTEXTMETRIC * lptm;
6637 int FontType;
6638 enumfont_t * lpef;
6639{
6640 return EnumFontFamilies (lpef->hdc,
6641 lplf->elfLogFont.lfFaceName,
6642 (FONTENUMPROC) enum_font_cb2,
6643 (LPARAM) lpef);
6644}
6645
6646
8edb0a6f 6647static int CALLBACK
5ca0cd71
GV
6648enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6649 ENUMLOGFONTEX * lplf;
6650 NEWTEXTMETRICEX * lptm;
6651 int font_type;
6652 enumfont_t * lpef;
6653{
6654 /* We are not interested in the extra info we get back from the 'Ex
6655 version - only the fact that we get character set variations
6656 enumerated seperately. */
6657 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6658 font_type, lpef);
6659}
6660
8edb0a6f 6661static int CALLBACK
5ca0cd71
GV
6662enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6663 ENUMLOGFONTEX * lplf;
6664 NEWTEXTMETRICEX * lptm;
6665 int font_type;
6666 enumfont_t * lpef;
6667{
6668 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6669 FARPROC enum_font_families_ex
6670 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6671 /* We don't really expect EnumFontFamiliesEx to disappear once we
6672 get here, so don't bother handling it gracefully. */
6673 if (enum_font_families_ex == NULL)
6674 error ("gdi32.dll has disappeared!");
6675 return enum_font_families_ex (lpef->hdc,
6676 &lplf->elfLogFont,
6677 (FONTENUMPROC) enum_fontex_cb2,
6678 (LPARAM) lpef, 0);
6679}
6680
4587b026
GV
6681/* Interface to fontset handler. (adapted from mw32font.c in Meadow
6682 and xterm.c in Emacs 20.3) */
6683
8edb0a6f 6684static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
6685{
6686 char *fontname, *ptnstr;
6687 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 6688 int n_fonts = 0;
33d52f9c
GV
6689
6690 list = Vw32_bdf_filename_alist;
6691 ptnstr = XSTRING (pattern)->data;
6692
8e713be6 6693 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 6694 {
8e713be6 6695 tem = XCAR (list);
33d52f9c 6696 if (CONSP (tem))
8e713be6 6697 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
6698 else if (STRINGP (tem))
6699 fontname = XSTRING (tem)->data;
6700 else
6701 continue;
6702
6703 if (w32_font_match (fontname, ptnstr))
5ca0cd71 6704 {
8e713be6 6705 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6706 n_fonts++;
6707 if (n_fonts >= max_names)
6708 break;
6709 }
33d52f9c
GV
6710 }
6711
6712 return newlist;
6713}
6714
8edb0a6f
JR
6715static Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f,
6716 Lisp_Object pattern,
6717 int size, int max_names);
5ca0cd71 6718
4587b026
GV
6719/* Return a list of names of available fonts matching PATTERN on frame
6720 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6721 to be listed. Frame F NULL means we have not yet created any
6722 frame, which means we can't get proper size info, as we don't have
6723 a device context to use for GetTextMetrics.
6724 MAXNAMES sets a limit on how many fonts to match. */
6725
6726Lisp_Object
dc220243
JR
6727w32_list_fonts (f, pattern, size, maxnames)
6728 struct frame *f;
6729 Lisp_Object pattern;
6730 int size;
6731 int maxnames;
4587b026 6732{
6fc2811b 6733 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 6734 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 6735 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 6736 int n_fonts = 0;
396594fe 6737
4587b026
GV
6738 patterns = Fassoc (pattern, Valternate_fontname_alist);
6739 if (NILP (patterns))
6740 patterns = Fcons (pattern, Qnil);
6741
8e713be6 6742 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
6743 {
6744 enumfont_t ef;
767b1ff0 6745 int codepage;
4587b026 6746
8e713be6 6747 tpat = XCAR (patterns);
4587b026 6748
767b1ff0
JR
6749 if (!STRINGP (tpat))
6750 continue;
6751
6752 /* Avoid expensive EnumFontFamilies functions if we are not
6753 going to be able to output one of these anyway. */
6754 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6755 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
6756 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6757 && !IsValidCodePage(codepage))
767b1ff0
JR
6758 continue;
6759
4587b026
GV
6760 /* See if we cached the result for this particular query.
6761 The cache is an alist of the form:
6762 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6763 */
8e713be6 6764 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 6765 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
6766 {
6767 list = Fcdr_safe (list);
6768 /* We have a cached list. Don't have to get the list again. */
6769 goto label_cached;
6770 }
6771
6772 BLOCK_INPUT;
6773 /* At first, put PATTERN in the cache. */
6774 list = Qnil;
33d52f9c
GV
6775 ef.pattern = &tpat;
6776 ef.tail = &list;
4587b026 6777 ef.numFonts = 0;
33d52f9c 6778
5ca0cd71
GV
6779 /* Use EnumFontFamiliesEx where it is available, as it knows
6780 about character sets. Fall back to EnumFontFamilies for
6781 older versions of NT that don't support the 'Ex function. */
767b1ff0 6782 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 6783 {
5ca0cd71
GV
6784 LOGFONT font_match_pattern;
6785 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6786 FARPROC enum_font_families_ex
6787 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6788
6789 /* We do our own pattern matching so we can handle wildcards. */
6790 font_match_pattern.lfFaceName[0] = 0;
6791 font_match_pattern.lfPitchAndFamily = 0;
6792 /* We can use the charset, because if it is a wildcard it will
6793 be DEFAULT_CHARSET anyway. */
6794 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6795
33d52f9c 6796 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 6797
5ca0cd71
GV
6798 if (enum_font_families_ex)
6799 enum_font_families_ex (ef.hdc,
6800 &font_match_pattern,
6801 (FONTENUMPROC) enum_fontex_cb1,
6802 (LPARAM) &ef, 0);
6803 else
6804 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6805 (LPARAM)&ef);
4587b026 6806
33d52f9c 6807 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
6808 }
6809
6810 UNBLOCK_INPUT;
6811
6812 /* Make a list of the fonts we got back.
6813 Store that in the font cache for the display. */
8e713be6 6814 XCDR (dpyinfo->name_list_element)
33d52f9c 6815 = Fcons (Fcons (tpat, list),
8e713be6 6816 XCDR (dpyinfo->name_list_element));
4587b026
GV
6817
6818 label_cached:
6819 if (NILP (list)) continue; /* Try the remaining alternatives. */
6820
6821 newlist = second_best = Qnil;
6822
6823 /* Make a list of the fonts that have the right width. */
8e713be6 6824 for (; CONSP (list); list = XCDR (list))
4587b026
GV
6825 {
6826 int found_size;
8e713be6 6827 tem = XCAR (list);
4587b026
GV
6828
6829 if (!CONSP (tem))
6830 continue;
8e713be6 6831 if (NILP (XCAR (tem)))
4587b026
GV
6832 continue;
6833 if (!size)
6834 {
8e713be6 6835 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6836 n_fonts++;
6837 if (n_fonts >= maxnames)
6838 break;
6839 else
6840 continue;
4587b026 6841 }
8e713be6 6842 if (!INTEGERP (XCDR (tem)))
4587b026
GV
6843 {
6844 /* Since we don't yet know the size of the font, we must
6845 load it and try GetTextMetrics. */
4587b026
GV
6846 W32FontStruct thisinfo;
6847 LOGFONT lf;
6848 HDC hdc;
6849 HANDLE oldobj;
6850
8e713be6 6851 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
6852 continue;
6853
6854 BLOCK_INPUT;
33d52f9c 6855 thisinfo.bdf = NULL;
4587b026
GV
6856 thisinfo.hfont = CreateFontIndirect (&lf);
6857 if (thisinfo.hfont == NULL)
6858 continue;
6859
6860 hdc = GetDC (dpyinfo->root_window);
6861 oldobj = SelectObject (hdc, thisinfo.hfont);
6862 if (GetTextMetrics (hdc, &thisinfo.tm))
8e713be6 6863 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
4587b026 6864 else
8e713be6 6865 XCDR (tem) = make_number (0);
4587b026
GV
6866 SelectObject (hdc, oldobj);
6867 ReleaseDC (dpyinfo->root_window, hdc);
6868 DeleteObject(thisinfo.hfont);
6869 UNBLOCK_INPUT;
6870 }
8e713be6 6871 found_size = XINT (XCDR (tem));
4587b026 6872 if (found_size == size)
5ca0cd71 6873 {
8e713be6 6874 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
6875 n_fonts++;
6876 if (n_fonts >= maxnames)
6877 break;
6878 }
4587b026
GV
6879 /* keep track of the closest matching size in case
6880 no exact match is found. */
6881 else if (found_size > 0)
6882 {
6883 if (NILP (second_best))
6884 second_best = tem;
5ca0cd71 6885
4587b026
GV
6886 else if (found_size < size)
6887 {
8e713be6
KR
6888 if (XINT (XCDR (second_best)) > size
6889 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
6890 second_best = tem;
6891 }
6892 else
6893 {
8e713be6
KR
6894 if (XINT (XCDR (second_best)) > size
6895 && XINT (XCDR (second_best)) >
4587b026
GV
6896 found_size)
6897 second_best = tem;
6898 }
6899 }
6900 }
6901
6902 if (!NILP (newlist))
6903 break;
6904 else if (!NILP (second_best))
6905 {
8e713be6 6906 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
6907 break;
6908 }
6909 }
6910
33d52f9c 6911 /* Include any bdf fonts. */
5ca0cd71 6912 if (n_fonts < maxnames)
33d52f9c
GV
6913 {
6914 Lisp_Object combined[2];
5ca0cd71 6915 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
6916 combined[1] = newlist;
6917 newlist = Fnconc(2, combined);
6918 }
6919
5ca0cd71
GV
6920 /* If we can't find a font that matches, check if Windows would be
6921 able to synthesize it from a different style. */
6fc2811b 6922 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
5ca0cd71
GV
6923 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6924
4587b026
GV
6925 return newlist;
6926}
6927
8edb0a6f 6928static Lisp_Object
5ca0cd71
GV
6929w32_list_synthesized_fonts (f, pattern, size, max_names)
6930 FRAME_PTR f;
6931 Lisp_Object pattern;
6932 int size;
6933 int max_names;
6934{
6935 int fields;
6936 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6937 char style[20], slant;
8edb0a6f 6938 Lisp_Object matches, tem, synthed_matches = Qnil;
5ca0cd71
GV
6939
6940 full_pattn = XSTRING (pattern)->data;
6941
6942 pattn_part2 = alloca (XSTRING (pattern)->size);
6943 /* Allow some space for wildcard expansion. */
6944 new_pattn = alloca (XSTRING (pattern)->size + 100);
6945
6946 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6947 foundary, family, style, &slant, pattn_part2);
6948 if (fields == EOF || fields < 5)
6949 return Qnil;
6950
6951 /* If the style and slant are wildcards already there is no point
6952 checking again (and we don't want to keep recursing). */
6953 if (*style == '*' && slant == '*')
6954 return Qnil;
6955
6956 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6957
6958 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6959
8e713be6 6960 for ( ; CONSP (matches); matches = XCDR (matches))
5ca0cd71 6961 {
8e713be6 6962 tem = XCAR (matches);
5ca0cd71
GV
6963 if (!STRINGP (tem))
6964 continue;
6965
6966 full_pattn = XSTRING (tem)->data;
6967 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6968 foundary, family, pattn_part2);
6969 if (fields == EOF || fields < 3)
6970 continue;
6971
6972 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6973 slant, pattn_part2);
6974
6975 synthed_matches = Fcons (build_string (new_pattn),
6976 synthed_matches);
6977 }
6978
6979 return synthed_matches;
6980}
6981
6982
4587b026
GV
6983/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6984struct font_info *
6985w32_get_font_info (f, font_idx)
6986 FRAME_PTR f;
6987 int font_idx;
6988{
6989 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6990}
6991
6992
6993struct font_info*
6994w32_query_font (struct frame *f, char *fontname)
6995{
6996 int i;
6997 struct font_info *pfi;
6998
6999 pfi = FRAME_W32_FONT_TABLE (f);
7000
7001 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7002 {
7003 if (strcmp(pfi->name, fontname) == 0) return pfi;
7004 }
7005
7006 return NULL;
7007}
7008
7009/* Find a CCL program for a font specified by FONTP, and set the member
7010 `encoder' of the structure. */
7011
7012void
7013w32_find_ccl_program (fontp)
7014 struct font_info *fontp;
7015{
3545439c 7016 Lisp_Object list, elt;
4587b026 7017
8e713be6 7018 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7019 {
8e713be6 7020 elt = XCAR (list);
4587b026 7021 if (CONSP (elt)
8e713be6
KR
7022 && STRINGP (XCAR (elt))
7023 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7024 >= 0))
3545439c
KH
7025 break;
7026 }
7027 if (! NILP (list))
7028 {
17eedd00
KH
7029 struct ccl_program *ccl
7030 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7031
8e713be6 7032 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7033 xfree (ccl);
7034 else
7035 fontp->font_encoder = ccl;
4587b026
GV
7036 }
7037}
7038
7039\f
8edb0a6f
JR
7040/* Find BDF files in a specified directory. (use GCPRO when calling,
7041 as this calls lisp to get a directory listing). */
7042static Lisp_Object
7043w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7044{
7045 Lisp_Object filelist, list = Qnil;
7046 char fontname[100];
7047
7048 if (!STRINGP(directory))
7049 return Qnil;
7050
7051 filelist = Fdirectory_files (directory, Qt,
7052 build_string (".*\\.[bB][dD][fF]"), Qt);
7053
7054 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7055 {
7056 Lisp_Object filename = XCAR (filelist);
7057 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7058 store_in_alist (&list, build_string (fontname), filename);
7059 }
7060 return list;
7061}
7062
6fc2811b
JR
7063DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7064 1, 1, 0,
7065 "Return a list of BDF fonts in DIR, suitable for appending to\n\
767b1ff0 7066w32-bdf-filename-alist. Fonts which do not contain an xlfd description\n\
6fc2811b
JR
7067will not be included in the list. DIR may be a list of directories.")
7068 (directory)
7069 Lisp_Object directory;
7070{
7071 Lisp_Object list = Qnil;
7072 struct gcpro gcpro1, gcpro2;
ee78dc32 7073
6fc2811b
JR
7074 if (!CONSP (directory))
7075 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7076
6fc2811b 7077 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7078 {
6fc2811b
JR
7079 Lisp_Object pair[2];
7080 pair[0] = list;
7081 pair[1] = Qnil;
7082 GCPRO2 (directory, list);
7083 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7084 list = Fnconc( 2, pair );
7085 UNGCPRO;
7086 }
7087 return list;
7088}
ee78dc32 7089
6fc2811b
JR
7090\f
7091DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
dfff8a69 7092 "Internal function called by `color-defined-p', which see.")
6fc2811b
JR
7093 (color, frame)
7094 Lisp_Object color, frame;
7095{
7096 XColor foo;
7097 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7098
6fc2811b 7099 CHECK_STRING (color, 1);
ee78dc32 7100
6fc2811b
JR
7101 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7102 return Qt;
7103 else
7104 return Qnil;
7105}
ee78dc32 7106
2d764c78 7107DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
dfff8a69 7108 "Internal function called by `color-values', which see.")
ee78dc32
GV
7109 (color, frame)
7110 Lisp_Object color, frame;
7111{
6fc2811b 7112 XColor foo;
ee78dc32
GV
7113 FRAME_PTR f = check_x_frame (frame);
7114
7115 CHECK_STRING (color, 1);
7116
6fc2811b 7117 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7118 {
7119 Lisp_Object rgb[3];
7120
6fc2811b
JR
7121 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7122 | GetRValue (foo.pixel));
7123 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7124 | GetGValue (foo.pixel));
7125 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7126 | GetBValue (foo.pixel));
ee78dc32
GV
7127 return Flist (3, rgb);
7128 }
7129 else
7130 return Qnil;
7131}
7132
2d764c78 7133DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
dfff8a69 7134 "Internal function called by `display-color-p', which see.")
ee78dc32
GV
7135 (display)
7136 Lisp_Object display;
7137{
fbd6baed 7138 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7139
7140 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7141 return Qnil;
7142
7143 return Qt;
7144}
7145
7146DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
7147 0, 1, 0,
7148 "Return t if the X display supports shades of gray.\n\
7149Note that color displays do support shades of gray.\n\
7150The optional argument DISPLAY specifies which display to ask about.\n\
7151DISPLAY should be either a frame or a display name (a string).\n\
7152If omitted or nil, that stands for the selected frame's display.")
7153 (display)
7154 Lisp_Object display;
7155{
fbd6baed 7156 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7157
7158 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7159 return Qnil;
7160
7161 return Qt;
7162}
7163
7164DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
7165 0, 1, 0,
7166 "Returns the width in pixels of the X display DISPLAY.\n\
7167The optional argument DISPLAY specifies which display to ask about.\n\
7168DISPLAY should be either a frame or a display name (a string).\n\
7169If omitted or nil, that stands for the selected frame's display.")
7170 (display)
7171 Lisp_Object display;
7172{
fbd6baed 7173 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7174
7175 return make_number (dpyinfo->width);
7176}
7177
7178DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7179 Sx_display_pixel_height, 0, 1, 0,
7180 "Returns the height in pixels of the X display DISPLAY.\n\
7181The optional argument DISPLAY specifies which display to ask about.\n\
7182DISPLAY should be either a frame or a display name (a string).\n\
7183If omitted or nil, that stands for the selected frame's display.")
7184 (display)
7185 Lisp_Object display;
7186{
fbd6baed 7187 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7188
7189 return make_number (dpyinfo->height);
7190}
7191
7192DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7193 0, 1, 0,
7194 "Returns the number of bitplanes of the display DISPLAY.\n\
7195The optional argument DISPLAY specifies which display to ask about.\n\
7196DISPLAY should be either a frame or a display name (a string).\n\
7197If omitted or nil, that stands for the selected frame's display.")
7198 (display)
7199 Lisp_Object display;
7200{
fbd6baed 7201 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7202
7203 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7204}
7205
7206DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7207 0, 1, 0,
7208 "Returns the number of color cells of the display DISPLAY.\n\
7209The optional argument DISPLAY specifies which display to ask about.\n\
7210DISPLAY should be either a frame or a display name (a string).\n\
7211If omitted or nil, that stands for the selected frame's display.")
7212 (display)
7213 Lisp_Object display;
7214{
fbd6baed 7215 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7216 HDC hdc;
7217 int cap;
7218
5ac45f98
GV
7219 hdc = GetDC (dpyinfo->root_window);
7220 if (dpyinfo->has_palette)
7221 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7222 else
7223 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b
AI
7224
7225 if (cap < 0)
7226 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
ee78dc32
GV
7227
7228 ReleaseDC (dpyinfo->root_window, hdc);
7229
7230 return make_number (cap);
7231}
7232
7233DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7234 Sx_server_max_request_size,
7235 0, 1, 0,
7236 "Returns the maximum request size of the server of display DISPLAY.\n\
7237The optional argument DISPLAY specifies which display to ask about.\n\
7238DISPLAY should be either a frame or a display name (a string).\n\
7239If omitted or nil, that stands for the selected frame's display.")
7240 (display)
7241 Lisp_Object display;
7242{
fbd6baed 7243 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7244
7245 return make_number (1);
7246}
7247
7248DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
fbd6baed 7249 "Returns the vendor ID string of the W32 system (Microsoft).\n\
ee78dc32
GV
7250The optional argument DISPLAY specifies which display to ask about.\n\
7251DISPLAY should be either a frame or a display name (a string).\n\
7252If omitted or nil, that stands for the selected frame's display.")
7253 (display)
7254 Lisp_Object display;
7255{
dfff8a69 7256 return build_string ("Microsoft Corp.");
ee78dc32
GV
7257}
7258
7259DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7260 "Returns the version numbers of the server of display DISPLAY.\n\
7261The value is a list of three integers: the major and minor\n\
7262version numbers, and the vendor-specific release\n\
7263number. See also the function `x-server-vendor'.\n\n\
7264The optional argument DISPLAY specifies which display to ask about.\n\
7265DISPLAY should be either a frame or a display name (a string).\n\
7266If omitted or nil, that stands for the selected frame's display.")
7267 (display)
7268 Lisp_Object display;
7269{
fbd6baed 7270 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7271 Fcons (make_number (w32_minor_version),
7272 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7273}
7274
7275DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7276 "Returns the number of screens on the server of display DISPLAY.\n\
7277The optional argument DISPLAY specifies which display to ask about.\n\
7278DISPLAY should be either a frame or a display name (a string).\n\
7279If omitted or nil, that stands for the selected frame's display.")
7280 (display)
7281 Lisp_Object display;
7282{
ee78dc32
GV
7283 return make_number (1);
7284}
7285
7286DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7287 "Returns the height in millimeters of the X display DISPLAY.\n\
7288The optional argument DISPLAY specifies which display to ask about.\n\
7289DISPLAY should be either a frame or a display name (a string).\n\
7290If omitted or nil, that stands for the selected frame's display.")
7291 (display)
7292 Lisp_Object display;
7293{
fbd6baed 7294 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7295 HDC hdc;
7296 int cap;
7297
5ac45f98 7298 hdc = GetDC (dpyinfo->root_window);
3c190163 7299
ee78dc32 7300 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7301
ee78dc32
GV
7302 ReleaseDC (dpyinfo->root_window, hdc);
7303
7304 return make_number (cap);
7305}
7306
7307DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7308 "Returns the width in millimeters of the X display DISPLAY.\n\
7309The optional argument DISPLAY specifies which display to ask about.\n\
7310DISPLAY should be either a frame or a display name (a string).\n\
7311If omitted or nil, that stands for the selected frame's display.")
7312 (display)
7313 Lisp_Object display;
7314{
fbd6baed 7315 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7316
7317 HDC hdc;
7318 int cap;
7319
5ac45f98 7320 hdc = GetDC (dpyinfo->root_window);
3c190163 7321
ee78dc32 7322 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7323
ee78dc32
GV
7324 ReleaseDC (dpyinfo->root_window, hdc);
7325
7326 return make_number (cap);
7327}
7328
7329DEFUN ("x-display-backing-store", Fx_display_backing_store,
7330 Sx_display_backing_store, 0, 1, 0,
7331 "Returns an indication of whether display DISPLAY does backing store.\n\
7332The value may be `always', `when-mapped', or `not-useful'.\n\
7333The optional argument DISPLAY specifies which display to ask about.\n\
7334DISPLAY should be either a frame or a display name (a string).\n\
7335If omitted or nil, that stands for the selected frame's display.")
7336 (display)
7337 Lisp_Object display;
7338{
7339 return intern ("not-useful");
7340}
7341
7342DEFUN ("x-display-visual-class", Fx_display_visual_class,
7343 Sx_display_visual_class, 0, 1, 0,
7344 "Returns the visual class of the display DISPLAY.\n\
7345The value is one of the symbols `static-gray', `gray-scale',\n\
7346`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7347The optional argument DISPLAY specifies which display to ask about.\n\
7348DISPLAY should be either a frame or a display name (a string).\n\
7349If omitted or nil, that stands for the selected frame's display.")
7350 (display)
7351 Lisp_Object display;
7352{
fbd6baed 7353 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7354 Lisp_Object result = Qnil;
ee78dc32 7355
abf8c61b
AI
7356 if (dpyinfo->has_palette)
7357 result = intern ("pseudo-color");
7358 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7359 result = intern ("static-grey");
7360 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7361 result = intern ("static-color");
7362 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7363 result = intern ("true-color");
ee78dc32 7364
abf8c61b 7365 return result;
ee78dc32
GV
7366}
7367
7368DEFUN ("x-display-save-under", Fx_display_save_under,
7369 Sx_display_save_under, 0, 1, 0,
7370 "Returns t if the display DISPLAY supports the save-under feature.\n\
7371The optional argument DISPLAY specifies which display to ask about.\n\
7372DISPLAY should be either a frame or a display name (a string).\n\
7373If omitted or nil, that stands for the selected frame's display.")
7374 (display)
7375 Lisp_Object display;
7376{
6fc2811b
JR
7377 return Qnil;
7378}
7379\f
7380int
7381x_pixel_width (f)
7382 register struct frame *f;
7383{
7384 return PIXEL_WIDTH (f);
7385}
7386
7387int
7388x_pixel_height (f)
7389 register struct frame *f;
7390{
7391 return PIXEL_HEIGHT (f);
7392}
7393
7394int
7395x_char_width (f)
7396 register struct frame *f;
7397{
7398 return FONT_WIDTH (f->output_data.w32->font);
7399}
7400
7401int
7402x_char_height (f)
7403 register struct frame *f;
7404{
7405 return f->output_data.w32->line_height;
7406}
7407
7408int
7409x_screen_planes (f)
7410 register struct frame *f;
7411{
7412 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7413}
7414\f
7415/* Return the display structure for the display named NAME.
7416 Open a new connection if necessary. */
7417
7418struct w32_display_info *
7419x_display_info_for_name (name)
7420 Lisp_Object name;
7421{
7422 Lisp_Object names;
7423 struct w32_display_info *dpyinfo;
7424
7425 CHECK_STRING (name, 0);
7426
7427 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7428 dpyinfo;
7429 dpyinfo = dpyinfo->next, names = XCDR (names))
7430 {
7431 Lisp_Object tem;
7432 tem = Fstring_equal (XCAR (XCAR (names)), name);
7433 if (!NILP (tem))
7434 return dpyinfo;
7435 }
7436
7437 /* Use this general default value to start with. */
7438 Vx_resource_name = Vinvocation_name;
7439
7440 validate_x_resource_name ();
7441
7442 dpyinfo = w32_term_init (name, (unsigned char *)0,
7443 (char *) XSTRING (Vx_resource_name)->data);
7444
7445 if (dpyinfo == 0)
7446 error ("Cannot connect to server %s", XSTRING (name)->data);
7447
7448 w32_in_use = 1;
7449 XSETFASTINT (Vwindow_system_version, 3);
7450
7451 return dpyinfo;
7452}
7453
7454DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7455 1, 3, 0, "Open a connection to a server.\n\
7456DISPLAY is the name of the display to connect to.\n\
7457Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7458If the optional third arg MUST-SUCCEED is non-nil,\n\
7459terminate Emacs if we can't open the connection.")
7460 (display, xrm_string, must_succeed)
7461 Lisp_Object display, xrm_string, must_succeed;
7462{
7463 unsigned char *xrm_option;
7464 struct w32_display_info *dpyinfo;
7465
7466 CHECK_STRING (display, 0);
7467 if (! NILP (xrm_string))
7468 CHECK_STRING (xrm_string, 1);
7469
7470 if (! EQ (Vwindow_system, intern ("w32")))
7471 error ("Not using Microsoft Windows");
7472
7473 /* Allow color mapping to be defined externally; first look in user's
7474 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7475 {
7476 Lisp_Object color_file;
7477 struct gcpro gcpro1;
7478
7479 color_file = build_string("~/rgb.txt");
7480
7481 GCPRO1 (color_file);
7482
7483 if (NILP (Ffile_readable_p (color_file)))
7484 color_file =
7485 Fexpand_file_name (build_string ("rgb.txt"),
7486 Fsymbol_value (intern ("data-directory")));
7487
7488 Vw32_color_map = Fw32_load_color_file (color_file);
7489
7490 UNGCPRO;
7491 }
7492 if (NILP (Vw32_color_map))
7493 Vw32_color_map = Fw32_default_color_map ();
7494
7495 if (! NILP (xrm_string))
7496 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7497 else
7498 xrm_option = (unsigned char *) 0;
7499
7500 /* Use this general default value to start with. */
7501 /* First remove .exe suffix from invocation-name - it looks ugly. */
7502 {
7503 char basename[ MAX_PATH ], *str;
7504
7505 strcpy (basename, XSTRING (Vinvocation_name)->data);
7506 str = strrchr (basename, '.');
7507 if (str) *str = 0;
7508 Vinvocation_name = build_string (basename);
7509 }
7510 Vx_resource_name = Vinvocation_name;
7511
7512 validate_x_resource_name ();
7513
7514 /* This is what opens the connection and sets x_current_display.
7515 This also initializes many symbols, such as those used for input. */
7516 dpyinfo = w32_term_init (display, xrm_option,
7517 (char *) XSTRING (Vx_resource_name)->data);
7518
7519 if (dpyinfo == 0)
7520 {
7521 if (!NILP (must_succeed))
7522 fatal ("Cannot connect to server %s.\n",
7523 XSTRING (display)->data);
7524 else
7525 error ("Cannot connect to server %s", XSTRING (display)->data);
7526 }
7527
7528 w32_in_use = 1;
7529
7530 XSETFASTINT (Vwindow_system_version, 3);
7531 return Qnil;
7532}
7533
7534DEFUN ("x-close-connection", Fx_close_connection,
7535 Sx_close_connection, 1, 1, 0,
7536 "Close the connection to DISPLAY's server.\n\
7537For DISPLAY, specify either a frame or a display name (a string).\n\
7538If DISPLAY is nil, that stands for the selected frame's display.")
7539 (display)
7540 Lisp_Object display;
7541{
7542 struct w32_display_info *dpyinfo = check_x_display_info (display);
7543 int i;
7544
7545 if (dpyinfo->reference_count > 0)
7546 error ("Display still has frames on it");
7547
7548 BLOCK_INPUT;
7549 /* Free the fonts in the font table. */
7550 for (i = 0; i < dpyinfo->n_fonts; i++)
7551 if (dpyinfo->font_table[i].name)
7552 {
126f2e35
JR
7553 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7554 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 7555 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
7556 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7557 }
7558 x_destroy_all_bitmaps (dpyinfo);
7559
7560 x_delete_display (dpyinfo);
7561 UNBLOCK_INPUT;
7562
7563 return Qnil;
7564}
7565
7566DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7567 "Return the list of display names that Emacs has connections to.")
7568 ()
7569{
7570 Lisp_Object tail, result;
7571
7572 result = Qnil;
7573 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7574 result = Fcons (XCAR (XCAR (tail)), result);
7575
7576 return result;
7577}
7578
7579DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7580 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7581If ON is nil, allow buffering of requests.\n\
7582This is a noop on W32 systems.\n\
7583The optional second argument DISPLAY specifies which display to act on.\n\
7584DISPLAY should be either a frame or a display name (a string).\n\
7585If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7586 (on, display)
7587 Lisp_Object display, on;
7588{
6fc2811b
JR
7589 return Qnil;
7590}
7591
7592\f
7593\f
7594/***********************************************************************
7595 Image types
7596 ***********************************************************************/
7597
7598/* Value is the number of elements of vector VECTOR. */
7599
7600#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7601
7602/* List of supported image types. Use define_image_type to add new
7603 types. Use lookup_image_type to find a type for a given symbol. */
7604
7605static struct image_type *image_types;
7606
6fc2811b
JR
7607/* The symbol `image' which is the car of the lists used to represent
7608 images in Lisp. */
7609
7610extern Lisp_Object Qimage;
7611
7612/* The symbol `xbm' which is used as the type symbol for XBM images. */
7613
7614Lisp_Object Qxbm;
7615
7616/* Keywords. */
7617
6fc2811b 7618extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
dfff8a69
JR
7619extern Lisp_Object QCdata;
7620Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
a93f4566 7621Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
dfff8a69 7622Lisp_Object QCindex;
6fc2811b
JR
7623
7624/* Other symbols. */
7625
7626Lisp_Object Qlaplace;
7627
7628/* Time in seconds after which images should be removed from the cache
7629 if not displayed. */
7630
7631Lisp_Object Vimage_cache_eviction_delay;
7632
7633/* Function prototypes. */
7634
7635static void define_image_type P_ ((struct image_type *type));
7636static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7637static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7638static void x_laplace P_ ((struct frame *, struct image *));
7639static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7640 Lisp_Object));
7641
dfff8a69 7642
6fc2811b
JR
7643/* Define a new image type from TYPE. This adds a copy of TYPE to
7644 image_types and adds the symbol *TYPE->type to Vimage_types. */
7645
7646static void
7647define_image_type (type)
7648 struct image_type *type;
7649{
7650 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7651 The initialized data segment is read-only. */
7652 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7653 bcopy (type, p, sizeof *p);
7654 p->next = image_types;
7655 image_types = p;
7656 Vimage_types = Fcons (*p->type, Vimage_types);
7657}
7658
7659
7660/* Look up image type SYMBOL, and return a pointer to its image_type
7661 structure. Value is null if SYMBOL is not a known image type. */
7662
7663static INLINE struct image_type *
7664lookup_image_type (symbol)
7665 Lisp_Object symbol;
7666{
7667 struct image_type *type;
7668
7669 for (type = image_types; type; type = type->next)
7670 if (EQ (symbol, *type->type))
7671 break;
7672
7673 return type;
7674}
7675
7676
7677/* Value is non-zero if OBJECT is a valid Lisp image specification. A
7678 valid image specification is a list whose car is the symbol
7679 `image', and whose rest is a property list. The property list must
7680 contain a value for key `:type'. That value must be the name of a
7681 supported image type. The rest of the property list depends on the
7682 image type. */
7683
7684int
7685valid_image_p (object)
7686 Lisp_Object object;
7687{
7688 int valid_p = 0;
7689
7690 if (CONSP (object) && EQ (XCAR (object), Qimage))
7691 {
7692 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7693 struct image_type *type = lookup_image_type (symbol);
7694
7695 if (type)
7696 valid_p = type->valid_p (object);
7697 }
7698
7699 return valid_p;
7700}
7701
7702
7703/* Log error message with format string FORMAT and argument ARG.
7704 Signaling an error, e.g. when an image cannot be loaded, is not a
7705 good idea because this would interrupt redisplay, and the error
7706 message display would lead to another redisplay. This function
7707 therefore simply displays a message. */
7708
7709static void
7710image_error (format, arg1, arg2)
7711 char *format;
7712 Lisp_Object arg1, arg2;
7713{
7714 add_to_log (format, arg1, arg2);
7715}
7716
7717
7718\f
7719/***********************************************************************
7720 Image specifications
7721 ***********************************************************************/
7722
7723enum image_value_type
7724{
7725 IMAGE_DONT_CHECK_VALUE_TYPE,
7726 IMAGE_STRING_VALUE,
7727 IMAGE_SYMBOL_VALUE,
7728 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 7729 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 7730 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 7731 IMAGE_ASCENT_VALUE,
6fc2811b
JR
7732 IMAGE_INTEGER_VALUE,
7733 IMAGE_FUNCTION_VALUE,
7734 IMAGE_NUMBER_VALUE,
7735 IMAGE_BOOL_VALUE
7736};
7737
7738/* Structure used when parsing image specifications. */
7739
7740struct image_keyword
7741{
7742 /* Name of keyword. */
7743 char *name;
7744
7745 /* The type of value allowed. */
7746 enum image_value_type type;
7747
7748 /* Non-zero means key must be present. */
7749 int mandatory_p;
7750
7751 /* Used to recognize duplicate keywords in a property list. */
7752 int count;
7753
7754 /* The value that was found. */
7755 Lisp_Object value;
7756};
7757
7758
7759static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7760 int, Lisp_Object));
7761static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7762
7763
7764/* Parse image spec SPEC according to KEYWORDS. A valid image spec
7765 has the format (image KEYWORD VALUE ...). One of the keyword/
7766 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7767 image_keywords structures of size NKEYWORDS describing other
7768 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7769
7770static int
7771parse_image_spec (spec, keywords, nkeywords, type)
7772 Lisp_Object spec;
7773 struct image_keyword *keywords;
7774 int nkeywords;
7775 Lisp_Object type;
7776{
7777 int i;
7778 Lisp_Object plist;
7779
7780 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7781 return 0;
7782
7783 plist = XCDR (spec);
7784 while (CONSP (plist))
7785 {
7786 Lisp_Object key, value;
7787
7788 /* First element of a pair must be a symbol. */
7789 key = XCAR (plist);
7790 plist = XCDR (plist);
7791 if (!SYMBOLP (key))
7792 return 0;
7793
7794 /* There must follow a value. */
7795 if (!CONSP (plist))
7796 return 0;
7797 value = XCAR (plist);
7798 plist = XCDR (plist);
7799
7800 /* Find key in KEYWORDS. Error if not found. */
7801 for (i = 0; i < nkeywords; ++i)
7802 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7803 break;
7804
7805 if (i == nkeywords)
7806 continue;
7807
7808 /* Record that we recognized the keyword. If a keywords
7809 was found more than once, it's an error. */
7810 keywords[i].value = value;
7811 ++keywords[i].count;
7812
7813 if (keywords[i].count > 1)
7814 return 0;
7815
7816 /* Check type of value against allowed type. */
7817 switch (keywords[i].type)
7818 {
7819 case IMAGE_STRING_VALUE:
7820 if (!STRINGP (value))
7821 return 0;
7822 break;
7823
7824 case IMAGE_SYMBOL_VALUE:
7825 if (!SYMBOLP (value))
7826 return 0;
7827 break;
7828
7829 case IMAGE_POSITIVE_INTEGER_VALUE:
7830 if (!INTEGERP (value) || XINT (value) <= 0)
7831 return 0;
7832 break;
7833
8edb0a6f
JR
7834 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
7835 if (INTEGERP (value) && XINT (value) >= 0)
7836 break;
7837 if (CONSP (value)
7838 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
7839 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
7840 break;
7841 return 0;
7842
dfff8a69
JR
7843 case IMAGE_ASCENT_VALUE:
7844 if (SYMBOLP (value) && EQ (value, Qcenter))
7845 break;
7846 else if (INTEGERP (value)
7847 && XINT (value) >= 0
7848 && XINT (value) <= 100)
7849 break;
7850 return 0;
7851
6fc2811b
JR
7852 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7853 if (!INTEGERP (value) || XINT (value) < 0)
7854 return 0;
7855 break;
7856
7857 case IMAGE_DONT_CHECK_VALUE_TYPE:
7858 break;
7859
7860 case IMAGE_FUNCTION_VALUE:
7861 value = indirect_function (value);
7862 if (SUBRP (value)
7863 || COMPILEDP (value)
7864 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7865 break;
7866 return 0;
7867
7868 case IMAGE_NUMBER_VALUE:
7869 if (!INTEGERP (value) && !FLOATP (value))
7870 return 0;
7871 break;
7872
7873 case IMAGE_INTEGER_VALUE:
7874 if (!INTEGERP (value))
7875 return 0;
7876 break;
7877
7878 case IMAGE_BOOL_VALUE:
7879 if (!NILP (value) && !EQ (value, Qt))
7880 return 0;
7881 break;
7882
7883 default:
7884 abort ();
7885 break;
7886 }
7887
7888 if (EQ (key, QCtype) && !EQ (type, value))
7889 return 0;
7890 }
7891
7892 /* Check that all mandatory fields are present. */
7893 for (i = 0; i < nkeywords; ++i)
7894 if (keywords[i].mandatory_p && keywords[i].count == 0)
7895 return 0;
7896
7897 return NILP (plist);
7898}
7899
7900
7901/* Return the value of KEY in image specification SPEC. Value is nil
7902 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7903 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7904
7905static Lisp_Object
7906image_spec_value (spec, key, found)
7907 Lisp_Object spec, key;
7908 int *found;
7909{
7910 Lisp_Object tail;
7911
7912 xassert (valid_image_p (spec));
7913
7914 for (tail = XCDR (spec);
7915 CONSP (tail) && CONSP (XCDR (tail));
7916 tail = XCDR (XCDR (tail)))
7917 {
7918 if (EQ (XCAR (tail), key))
7919 {
7920 if (found)
7921 *found = 1;
7922 return XCAR (XCDR (tail));
7923 }
7924 }
7925
7926 if (found)
7927 *found = 0;
7928 return Qnil;
7929}
7930
7931
7932
7933\f
7934/***********************************************************************
7935 Image type independent image structures
7936 ***********************************************************************/
7937
7938static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7939static void free_image P_ ((struct frame *f, struct image *img));
7940
7941
7942/* Allocate and return a new image structure for image specification
7943 SPEC. SPEC has a hash value of HASH. */
7944
7945static struct image *
7946make_image (spec, hash)
7947 Lisp_Object spec;
7948 unsigned hash;
7949{
7950 struct image *img = (struct image *) xmalloc (sizeof *img);
7951
7952 xassert (valid_image_p (spec));
7953 bzero (img, sizeof *img);
7954 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7955 xassert (img->type != NULL);
7956 img->spec = spec;
7957 img->data.lisp_val = Qnil;
7958 img->ascent = DEFAULT_IMAGE_ASCENT;
7959 img->hash = hash;
7960 return img;
7961}
7962
7963
7964/* Free image IMG which was used on frame F, including its resources. */
7965
7966static void
7967free_image (f, img)
7968 struct frame *f;
7969 struct image *img;
7970{
7971 if (img)
7972 {
7973 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7974
7975 /* Remove IMG from the hash table of its cache. */
7976 if (img->prev)
7977 img->prev->next = img->next;
7978 else
7979 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7980
7981 if (img->next)
7982 img->next->prev = img->prev;
7983
7984 c->images[img->id] = NULL;
7985
7986 /* Free resources, then free IMG. */
7987 img->type->free (f, img);
7988 xfree (img);
7989 }
7990}
7991
7992
7993/* Prepare image IMG for display on frame F. Must be called before
7994 drawing an image. */
7995
7996void
7997prepare_image_for_display (f, img)
7998 struct frame *f;
7999 struct image *img;
8000{
8001 EMACS_TIME t;
8002
8003 /* We're about to display IMG, so set its timestamp to `now'. */
8004 EMACS_GET_TIME (t);
8005 img->timestamp = EMACS_SECS (t);
8006
8007 /* If IMG doesn't have a pixmap yet, load it now, using the image
8008 type dependent loader function. */
8009 if (img->pixmap == 0 && !img->load_failed_p)
8010 img->load_failed_p = img->type->load (f, img) == 0;
8011}
8012
8013
dfff8a69
JR
8014/* Value is the number of pixels for the ascent of image IMG when
8015 drawn in face FACE. */
8016
8017int
8018image_ascent (img, face)
8019 struct image *img;
8020 struct face *face;
8021{
8edb0a6f 8022 int height = img->height + img->vmargin;
dfff8a69
JR
8023 int ascent;
8024
8025 if (img->ascent == CENTERED_IMAGE_ASCENT)
8026 {
8027 if (face->font)
8028 ascent = height / 2 - (FONT_DESCENT(face->font)
8029 - FONT_BASE(face->font)) / 2;
8030 else
8031 ascent = height / 2;
8032 }
8033 else
8034 ascent = height * img->ascent / 100.0;
8035
8036 return ascent;
8037}
8038
8039
6fc2811b
JR
8040\f
8041/***********************************************************************
8042 Helper functions for X image types
8043 ***********************************************************************/
8044
8045static void x_clear_image P_ ((struct frame *f, struct image *img));
8046static unsigned long x_alloc_image_color P_ ((struct frame *f,
8047 struct image *img,
8048 Lisp_Object color_name,
8049 unsigned long dflt));
8050
8051/* Free X resources of image IMG which is used on frame F. */
8052
8053static void
8054x_clear_image (f, img)
8055 struct frame *f;
8056 struct image *img;
8057{
767b1ff0 8058#if 0 /* TODO: W32 image support */
6fc2811b
JR
8059
8060 if (img->pixmap)
8061 {
8062 BLOCK_INPUT;
8063 XFreePixmap (NULL, img->pixmap);
8064 img->pixmap = 0;
8065 UNBLOCK_INPUT;
8066 }
8067
8068 if (img->ncolors)
8069 {
8070 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8071
8072 /* If display has an immutable color map, freeing colors is not
8073 necessary and some servers don't allow it. So don't do it. */
8074 if (class != StaticColor
8075 && class != StaticGray
8076 && class != TrueColor)
8077 {
8078 Colormap cmap;
8079 BLOCK_INPUT;
8080 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8081 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8082 img->ncolors, 0);
8083 UNBLOCK_INPUT;
8084 }
8085
8086 xfree (img->colors);
8087 img->colors = NULL;
8088 img->ncolors = 0;
8089 }
8090#endif
8091}
8092
8093
8094/* Allocate color COLOR_NAME for image IMG on frame F. If color
8095 cannot be allocated, use DFLT. Add a newly allocated color to
8096 IMG->colors, so that it can be freed again. Value is the pixel
8097 color. */
8098
8099static unsigned long
8100x_alloc_image_color (f, img, color_name, dflt)
8101 struct frame *f;
8102 struct image *img;
8103 Lisp_Object color_name;
8104 unsigned long dflt;
8105{
767b1ff0 8106#if 0 /* TODO: allocing colors. */
6fc2811b
JR
8107 XColor color;
8108 unsigned long result;
8109
8110 xassert (STRINGP (color_name));
8111
8112 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8113 {
8114 /* This isn't called frequently so we get away with simply
8115 reallocating the color vector to the needed size, here. */
8116 ++img->ncolors;
8117 img->colors =
8118 (unsigned long *) xrealloc (img->colors,
8119 img->ncolors * sizeof *img->colors);
8120 img->colors[img->ncolors - 1] = color.pixel;
8121 result = color.pixel;
8122 }
8123 else
8124 result = dflt;
8125 return result;
8126#endif
8127 return 0;
8128}
8129
8130
8131\f
8132/***********************************************************************
8133 Image Cache
8134 ***********************************************************************/
8135
8136static void cache_image P_ ((struct frame *f, struct image *img));
8137
8138
8139/* Return a new, initialized image cache that is allocated from the
8140 heap. Call free_image_cache to free an image cache. */
8141
8142struct image_cache *
8143make_image_cache ()
8144{
8145 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8146 int size;
8147
8148 bzero (c, sizeof *c);
8149 c->size = 50;
8150 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8151 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8152 c->buckets = (struct image **) xmalloc (size);
8153 bzero (c->buckets, size);
8154 return c;
8155}
8156
8157
8158/* Free image cache of frame F. Be aware that X frames share images
8159 caches. */
8160
8161void
8162free_image_cache (f)
8163 struct frame *f;
8164{
8165 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8166 if (c)
8167 {
8168 int i;
8169
8170 /* Cache should not be referenced by any frame when freed. */
8171 xassert (c->refcount == 0);
8172
8173 for (i = 0; i < c->used; ++i)
8174 free_image (f, c->images[i]);
8175 xfree (c->images);
8176 xfree (c);
8177 xfree (c->buckets);
8178 FRAME_X_IMAGE_CACHE (f) = NULL;
8179 }
8180}
8181
8182
8183/* Clear image cache of frame F. FORCE_P non-zero means free all
8184 images. FORCE_P zero means clear only images that haven't been
8185 displayed for some time. Should be called from time to time to
dfff8a69
JR
8186 reduce the number of loaded images. If image-eviction-seconds is
8187 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8188 at least that many seconds. */
8189
8190void
8191clear_image_cache (f, force_p)
8192 struct frame *f;
8193 int force_p;
8194{
8195 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8196
8197 if (c && INTEGERP (Vimage_cache_eviction_delay))
8198 {
8199 EMACS_TIME t;
8200 unsigned long old;
8201 int i, any_freed_p = 0;
8202
8203 EMACS_GET_TIME (t);
8204 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8205
8206 for (i = 0; i < c->used; ++i)
8207 {
8208 struct image *img = c->images[i];
8209 if (img != NULL
8210 && (force_p
8211 || (img->timestamp > old)))
8212 {
8213 free_image (f, img);
8214 any_freed_p = 1;
8215 }
8216 }
8217
8218 /* We may be clearing the image cache because, for example,
8219 Emacs was iconified for a longer period of time. In that
8220 case, current matrices may still contain references to
8221 images freed above. So, clear these matrices. */
8222 if (any_freed_p)
8223 {
8224 clear_current_matrices (f);
8225 ++windows_or_buffers_changed;
8226 }
8227 }
8228}
8229
8230
8231DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8232 0, 1, 0,
8233 "Clear the image cache of FRAME.\n\
8234FRAME nil or omitted means use the selected frame.\n\
8235FRAME t means clear the image caches of all frames.")
8236 (frame)
8237 Lisp_Object frame;
8238{
8239 if (EQ (frame, Qt))
8240 {
8241 Lisp_Object tail;
8242
8243 FOR_EACH_FRAME (tail, frame)
8244 if (FRAME_W32_P (XFRAME (frame)))
8245 clear_image_cache (XFRAME (frame), 1);
8246 }
8247 else
8248 clear_image_cache (check_x_frame (frame), 1);
8249
8250 return Qnil;
8251}
8252
8253
8254/* Return the id of image with Lisp specification SPEC on frame F.
8255 SPEC must be a valid Lisp image specification (see valid_image_p). */
8256
8257int
8258lookup_image (f, spec)
8259 struct frame *f;
8260 Lisp_Object spec;
8261{
8262 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8263 struct image *img;
8264 int i;
8265 unsigned hash;
8266 struct gcpro gcpro1;
8267 EMACS_TIME now;
8268
8269 /* F must be a window-system frame, and SPEC must be a valid image
8270 specification. */
8271 xassert (FRAME_WINDOW_P (f));
8272 xassert (valid_image_p (spec));
8273
8274 GCPRO1 (spec);
8275
8276 /* Look up SPEC in the hash table of the image cache. */
8277 hash = sxhash (spec, 0);
8278 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8279
8280 for (img = c->buckets[i]; img; img = img->next)
8281 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8282 break;
8283
8284 /* If not found, create a new image and cache it. */
8285 if (img == NULL)
8286 {
8edb0a6f 8287 BLOCK_INPUT;
6fc2811b
JR
8288 img = make_image (spec, hash);
8289 cache_image (f, img);
8290 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
8291
8292 /* If we can't load the image, and we don't have a width and
8293 height, use some arbitrary width and height so that we can
8294 draw a rectangle for it. */
8295 if (img->load_failed_p)
8296 {
8297 Lisp_Object value;
8298
8299 value = image_spec_value (spec, QCwidth, NULL);
8300 img->width = (INTEGERP (value)
8301 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8302 value = image_spec_value (spec, QCheight, NULL);
8303 img->height = (INTEGERP (value)
8304 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8305 }
8306 else
8307 {
8308 /* Handle image type independent image attributes
8309 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
8edb0a6f 8310 Lisp_Object ascent, margin, relief;
6fc2811b
JR
8311
8312 ascent = image_spec_value (spec, QCascent, NULL);
8313 if (INTEGERP (ascent))
8314 img->ascent = XFASTINT (ascent);
dfff8a69
JR
8315 else if (EQ (ascent, Qcenter))
8316 img->ascent = CENTERED_IMAGE_ASCENT;
8317
6fc2811b
JR
8318 margin = image_spec_value (spec, QCmargin, NULL);
8319 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
8320 img->vmargin = img->hmargin = XFASTINT (margin);
8321 else if (CONSP (margin) && INTEGERP (XCAR (margin))
8322 && INTEGERP (XCDR (margin)))
8323 {
8324 if (XINT (XCAR (margin)) > 0)
8325 img->hmargin = XFASTINT (XCAR (margin));
8326 if (XINT (XCDR (margin)) > 0)
8327 img->vmargin = XFASTINT (XCDR (margin));
8328 }
6fc2811b
JR
8329
8330 relief = image_spec_value (spec, QCrelief, NULL);
8331 if (INTEGERP (relief))
8332 {
8333 img->relief = XINT (relief);
8edb0a6f
JR
8334 img->hmargin += abs (img->relief);
8335 img->vmargin += abs (img->relief);
6fc2811b
JR
8336 }
8337
8edb0a6f
JR
8338#if 0 /* TODO: image mask and algorithm. */
8339 /* Manipulation of the image's mask. */
8340 if (img->pixmap)
8341 {
8342 /* `:heuristic-mask t'
8343 `:mask heuristic'
8344 means build a mask heuristically.
8345 `:heuristic-mask (R G B)'
8346 `:mask (heuristic (R G B))'
8347 means build a mask from color (R G B) in the
8348 image.
8349 `:mask nil'
8350 means remove a mask, if any. */
8351
8352 Lisp_Object mask;
8353
8354 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8355 if (!NILP (mask))
8356 x_build_heuristic_mask (f, img, mask);
8357 else
8358 {
8359 int found_p;
8360
8361 mask = image_spec_value (spec, QCmask, &found_p);
8362
8363 if (EQ (mask, Qheuristic))
8364 x_build_heuristic_mask (f, img, Qt);
8365 else if (CONSP (mask)
8366 && EQ (XCAR (mask), Qheuristic))
8367 {
8368 if (CONSP (XCDR (mask)))
8369 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8370 else
8371 x_build_heuristic_mask (f, img, XCDR (mask));
8372 }
8373 else if (NILP (mask) && found_p && img->mask)
8374 {
8375 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8376 img->mask = None;
8377 }
8378 }
8379 }
8380
8381 /* Should we apply an image transformation algorithm? */
8382 if (img->pixmap)
8383 {
a93f4566 8384 Lisp_Object conversion;
8edb0a6f 8385
a93f4566
GM
8386 algorithm = image_spec_value (spec, QCconversion, NULL);
8387 if (EQ (conversion, Qdisabled))
8edb0a6f 8388 x_disable_image (f, img);
a93f4566 8389 else if (EQ (conversion, Qlaplace))
8edb0a6f 8390 x_laplace (f, img);
a93f4566 8391 else if (EQ (conversion, Qemboss))
8edb0a6f 8392 x_emboss (f, img);
a93f4566
GM
8393 else if (CONSP (conversion)
8394 && EQ (XCAR (conversion), Qedge_detection))
8edb0a6f
JR
8395 {
8396 Lisp_Object tem;
a93f4566 8397 tem = XCDR (conversion);
8edb0a6f
JR
8398 if (CONSP (tem))
8399 x_edge_detection (f, img,
8400 Fplist_get (tem, QCmatrix),
8401 Fplist_get (tem, QCcolor_adjustment));
8402 }
8403 }
8404#endif /* TODO. */
6fc2811b 8405 }
8edb0a6f
JR
8406 UNBLOCK_INPUT;
8407 xassert (!interrupt_input_blocked);
6fc2811b
JR
8408 }
8409
8410 /* We're using IMG, so set its timestamp to `now'. */
8411 EMACS_GET_TIME (now);
8412 img->timestamp = EMACS_SECS (now);
8413
8414 UNGCPRO;
8415
8416 /* Value is the image id. */
8417 return img->id;
8418}
8419
8420
8421/* Cache image IMG in the image cache of frame F. */
8422
8423static void
8424cache_image (f, img)
8425 struct frame *f;
8426 struct image *img;
8427{
8428 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8429 int i;
8430
8431 /* Find a free slot in c->images. */
8432 for (i = 0; i < c->used; ++i)
8433 if (c->images[i] == NULL)
8434 break;
8435
8436 /* If no free slot found, maybe enlarge c->images. */
8437 if (i == c->used && c->used == c->size)
8438 {
8439 c->size *= 2;
8440 c->images = (struct image **) xrealloc (c->images,
8441 c->size * sizeof *c->images);
8442 }
8443
8444 /* Add IMG to c->images, and assign IMG an id. */
8445 c->images[i] = img;
8446 img->id = i;
8447 if (i == c->used)
8448 ++c->used;
8449
8450 /* Add IMG to the cache's hash table. */
8451 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8452 img->next = c->buckets[i];
8453 if (img->next)
8454 img->next->prev = img;
8455 img->prev = NULL;
8456 c->buckets[i] = img;
8457}
8458
8459
8460/* Call FN on every image in the image cache of frame F. Used to mark
8461 Lisp Objects in the image cache. */
8462
8463void
8464forall_images_in_image_cache (f, fn)
8465 struct frame *f;
8466 void (*fn) P_ ((struct image *img));
8467{
8468 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8469 {
8470 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8471 if (c)
8472 {
8473 int i;
8474 for (i = 0; i < c->used; ++i)
8475 if (c->images[i])
8476 fn (c->images[i]);
8477 }
8478 }
8479}
8480
8481
8482\f
8483/***********************************************************************
8484 W32 support code
8485 ***********************************************************************/
8486
767b1ff0 8487#if 0 /* TODO: W32 specific image code. */
6fc2811b
JR
8488
8489static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8490 XImage **, Pixmap *));
8491static void x_destroy_x_image P_ ((XImage *));
8492static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8493
8494
8495/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8496 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8497 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8498 via xmalloc. Print error messages via image_error if an error
8499 occurs. Value is non-zero if successful. */
8500
8501static int
8502x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8503 struct frame *f;
8504 int width, height, depth;
8505 XImage **ximg;
8506 Pixmap *pixmap;
8507{
767b1ff0 8508#if 0 /* TODO: Image support for W32 */
6fc2811b
JR
8509 Display *display = FRAME_W32_DISPLAY (f);
8510 Screen *screen = FRAME_X_SCREEN (f);
8511 Window window = FRAME_W32_WINDOW (f);
8512
8513 xassert (interrupt_input_blocked);
8514
8515 if (depth <= 0)
8516 depth = DefaultDepthOfScreen (screen);
8517 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8518 depth, ZPixmap, 0, NULL, width, height,
8519 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8520 if (*ximg == NULL)
8521 {
8522 image_error ("Unable to allocate X image", Qnil, Qnil);
8523 return 0;
8524 }
8525
8526 /* Allocate image raster. */
8527 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8528
8529 /* Allocate a pixmap of the same size. */
8530 *pixmap = XCreatePixmap (display, window, width, height, depth);
8531 if (*pixmap == 0)
8532 {
8533 x_destroy_x_image (*ximg);
8534 *ximg = NULL;
8535 image_error ("Unable to create X pixmap", Qnil, Qnil);
8536 return 0;
8537 }
8538#endif
8539 return 1;
8540}
8541
8542
8543/* Destroy XImage XIMG. Free XIMG->data. */
8544
8545static void
8546x_destroy_x_image (ximg)
8547 XImage *ximg;
8548{
8549 xassert (interrupt_input_blocked);
8550 if (ximg)
8551 {
8552 xfree (ximg->data);
8553 ximg->data = NULL;
8554 XDestroyImage (ximg);
8555 }
8556}
8557
8558
8559/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8560 are width and height of both the image and pixmap. */
8561
8562static void
8563x_put_x_image (f, ximg, pixmap, width, height)
8564 struct frame *f;
8565 XImage *ximg;
8566 Pixmap pixmap;
8567{
8568 GC gc;
8569
8570 xassert (interrupt_input_blocked);
8571 gc = XCreateGC (NULL, pixmap, 0, NULL);
8572 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8573 XFreeGC (NULL, gc);
8574}
8575
8576#endif
8577
8578\f
8579/***********************************************************************
8580 Searching files
8581 ***********************************************************************/
8582
8583static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8584
8585/* Find image file FILE. Look in data-directory, then
8586 x-bitmap-file-path. Value is the full name of the file found, or
8587 nil if not found. */
8588
8589static Lisp_Object
8590x_find_image_file (file)
8591 Lisp_Object file;
8592{
8593 Lisp_Object file_found, search_path;
8594 struct gcpro gcpro1, gcpro2;
8595 int fd;
8596
8597 file_found = Qnil;
8598 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8599 GCPRO2 (file_found, search_path);
8600
8601 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8602 fd = openp (search_path, file, "", &file_found, 0);
8603
939d6465 8604 if (fd == -1)
6fc2811b
JR
8605 file_found = Qnil;
8606 else
8607 close (fd);
8608
8609 UNGCPRO;
8610 return file_found;
8611}
8612
8613
8614\f
8615/***********************************************************************
8616 XBM images
8617 ***********************************************************************/
8618
8619static int xbm_load P_ ((struct frame *f, struct image *img));
8620static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8621 Lisp_Object file));
8622static int xbm_image_p P_ ((Lisp_Object object));
8623static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8624 unsigned char **));
8625
8626
8627/* Indices of image specification fields in xbm_format, below. */
8628
8629enum xbm_keyword_index
8630{
8631 XBM_TYPE,
8632 XBM_FILE,
8633 XBM_WIDTH,
8634 XBM_HEIGHT,
8635 XBM_DATA,
8636 XBM_FOREGROUND,
8637 XBM_BACKGROUND,
8638 XBM_ASCENT,
8639 XBM_MARGIN,
8640 XBM_RELIEF,
8641 XBM_ALGORITHM,
8642 XBM_HEURISTIC_MASK,
8643 XBM_LAST
8644};
8645
8646/* Vector of image_keyword structures describing the format
8647 of valid XBM image specifications. */
8648
8649static struct image_keyword xbm_format[XBM_LAST] =
8650{
8651 {":type", IMAGE_SYMBOL_VALUE, 1},
8652 {":file", IMAGE_STRING_VALUE, 0},
8653 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8654 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8655 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8656 {":foreground", IMAGE_STRING_VALUE, 0},
8657 {":background", IMAGE_STRING_VALUE, 0},
8658 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 8659 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 8660 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 8661 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
8662 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8663};
8664
8665/* Structure describing the image type XBM. */
8666
8667static struct image_type xbm_type =
8668{
8669 &Qxbm,
8670 xbm_image_p,
8671 xbm_load,
8672 x_clear_image,
8673 NULL
8674};
8675
8676/* Tokens returned from xbm_scan. */
8677
8678enum xbm_token
8679{
8680 XBM_TK_IDENT = 256,
8681 XBM_TK_NUMBER
8682};
8683
8684
8685/* Return non-zero if OBJECT is a valid XBM-type image specification.
8686 A valid specification is a list starting with the symbol `image'
8687 The rest of the list is a property list which must contain an
8688 entry `:type xbm..
8689
8690 If the specification specifies a file to load, it must contain
8691 an entry `:file FILENAME' where FILENAME is a string.
8692
8693 If the specification is for a bitmap loaded from memory it must
8694 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8695 WIDTH and HEIGHT are integers > 0. DATA may be:
8696
8697 1. a string large enough to hold the bitmap data, i.e. it must
8698 have a size >= (WIDTH + 7) / 8 * HEIGHT
8699
8700 2. a bool-vector of size >= WIDTH * HEIGHT
8701
8702 3. a vector of strings or bool-vectors, one for each line of the
8703 bitmap.
8704
8705 Both the file and data forms may contain the additional entries
8706 `:background COLOR' and `:foreground COLOR'. If not present,
8707 foreground and background of the frame on which the image is
8708 displayed, is used. */
8709
8710static int
8711xbm_image_p (object)
8712 Lisp_Object object;
8713{
8714 struct image_keyword kw[XBM_LAST];
8715
8716 bcopy (xbm_format, kw, sizeof kw);
8717 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8718 return 0;
8719
8720 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8721
8722 if (kw[XBM_FILE].count)
8723 {
8724 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8725 return 0;
8726 }
8727 else
8728 {
8729 Lisp_Object data;
8730 int width, height;
8731
8732 /* Entries for `:width', `:height' and `:data' must be present. */
8733 if (!kw[XBM_WIDTH].count
8734 || !kw[XBM_HEIGHT].count
8735 || !kw[XBM_DATA].count)
8736 return 0;
8737
8738 data = kw[XBM_DATA].value;
8739 width = XFASTINT (kw[XBM_WIDTH].value);
8740 height = XFASTINT (kw[XBM_HEIGHT].value);
8741
8742 /* Check type of data, and width and height against contents of
8743 data. */
8744 if (VECTORP (data))
8745 {
8746 int i;
8747
8748 /* Number of elements of the vector must be >= height. */
8749 if (XVECTOR (data)->size < height)
8750 return 0;
8751
8752 /* Each string or bool-vector in data must be large enough
8753 for one line of the image. */
8754 for (i = 0; i < height; ++i)
8755 {
8756 Lisp_Object elt = XVECTOR (data)->contents[i];
8757
8758 if (STRINGP (elt))
8759 {
8760 if (XSTRING (elt)->size
8761 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8762 return 0;
8763 }
8764 else if (BOOL_VECTOR_P (elt))
8765 {
8766 if (XBOOL_VECTOR (elt)->size < width)
8767 return 0;
8768 }
8769 else
8770 return 0;
8771 }
8772 }
8773 else if (STRINGP (data))
8774 {
8775 if (XSTRING (data)->size
8776 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8777 return 0;
8778 }
8779 else if (BOOL_VECTOR_P (data))
8780 {
8781 if (XBOOL_VECTOR (data)->size < width * height)
8782 return 0;
8783 }
8784 else
8785 return 0;
8786 }
8787
8788 /* Baseline must be a value between 0 and 100 (a percentage). */
8789 if (kw[XBM_ASCENT].count
8790 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8791 return 0;
8792
8793 return 1;
8794}
8795
8796
8797/* Scan a bitmap file. FP is the stream to read from. Value is
8798 either an enumerator from enum xbm_token, or a character for a
8799 single-character token, or 0 at end of file. If scanning an
8800 identifier, store the lexeme of the identifier in SVAL. If
8801 scanning a number, store its value in *IVAL. */
8802
8803static int
8804xbm_scan (fp, sval, ival)
8805 FILE *fp;
8806 char *sval;
8807 int *ival;
8808{
8809 int c;
8810
8811 /* Skip white space. */
8812 while ((c = fgetc (fp)) != EOF && isspace (c))
8813 ;
8814
8815 if (c == EOF)
8816 c = 0;
8817 else if (isdigit (c))
8818 {
8819 int value = 0, digit;
8820
8821 if (c == '0')
8822 {
8823 c = fgetc (fp);
8824 if (c == 'x' || c == 'X')
8825 {
8826 while ((c = fgetc (fp)) != EOF)
8827 {
8828 if (isdigit (c))
8829 digit = c - '0';
8830 else if (c >= 'a' && c <= 'f')
8831 digit = c - 'a' + 10;
8832 else if (c >= 'A' && c <= 'F')
8833 digit = c - 'A' + 10;
8834 else
8835 break;
8836 value = 16 * value + digit;
8837 }
8838 }
8839 else if (isdigit (c))
8840 {
8841 value = c - '0';
8842 while ((c = fgetc (fp)) != EOF
8843 && isdigit (c))
8844 value = 8 * value + c - '0';
8845 }
8846 }
8847 else
8848 {
8849 value = c - '0';
8850 while ((c = fgetc (fp)) != EOF
8851 && isdigit (c))
8852 value = 10 * value + c - '0';
8853 }
8854
8855 if (c != EOF)
8856 ungetc (c, fp);
8857 *ival = value;
8858 c = XBM_TK_NUMBER;
8859 }
8860 else if (isalpha (c) || c == '_')
8861 {
8862 *sval++ = c;
8863 while ((c = fgetc (fp)) != EOF
8864 && (isalnum (c) || c == '_'))
8865 *sval++ = c;
8866 *sval = 0;
8867 if (c != EOF)
8868 ungetc (c, fp);
8869 c = XBM_TK_IDENT;
8870 }
8871
8872 return c;
8873}
8874
8875
8876/* Replacement for XReadBitmapFileData which isn't available under old
8877 X versions. FILE is the name of the bitmap file to read. Set
8878 *WIDTH and *HEIGHT to the width and height of the image. Return in
8879 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8880 successful. */
8881
8882static int
8883xbm_read_bitmap_file_data (file, width, height, data)
8884 char *file;
8885 int *width, *height;
8886 unsigned char **data;
8887{
8888 FILE *fp;
8889 char buffer[BUFSIZ];
8890 int padding_p = 0;
8891 int v10 = 0;
8892 int bytes_per_line, i, nbytes;
8893 unsigned char *p;
8894 int value;
8895 int LA1;
8896
8897#define match() \
8898 LA1 = xbm_scan (fp, buffer, &value)
8899
8900#define expect(TOKEN) \
8901 if (LA1 != (TOKEN)) \
8902 goto failure; \
8903 else \
8904 match ()
8905
8906#define expect_ident(IDENT) \
8907 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8908 match (); \
8909 else \
8910 goto failure
8911
8912 fp = fopen (file, "r");
8913 if (fp == NULL)
8914 return 0;
8915
8916 *width = *height = -1;
8917 *data = NULL;
8918 LA1 = xbm_scan (fp, buffer, &value);
8919
8920 /* Parse defines for width, height and hot-spots. */
8921 while (LA1 == '#')
8922 {
8923 match ();
8924 expect_ident ("define");
8925 expect (XBM_TK_IDENT);
8926
8927 if (LA1 == XBM_TK_NUMBER);
8928 {
8929 char *p = strrchr (buffer, '_');
8930 p = p ? p + 1 : buffer;
8931 if (strcmp (p, "width") == 0)
8932 *width = value;
8933 else if (strcmp (p, "height") == 0)
8934 *height = value;
8935 }
8936 expect (XBM_TK_NUMBER);
8937 }
8938
8939 if (*width < 0 || *height < 0)
8940 goto failure;
8941
8942 /* Parse bits. Must start with `static'. */
8943 expect_ident ("static");
8944 if (LA1 == XBM_TK_IDENT)
8945 {
8946 if (strcmp (buffer, "unsigned") == 0)
8947 {
8948 match ();
8949 expect_ident ("char");
8950 }
8951 else if (strcmp (buffer, "short") == 0)
8952 {
8953 match ();
8954 v10 = 1;
8955 if (*width % 16 && *width % 16 < 9)
8956 padding_p = 1;
8957 }
8958 else if (strcmp (buffer, "char") == 0)
8959 match ();
8960 else
8961 goto failure;
8962 }
8963 else
8964 goto failure;
8965
8966 expect (XBM_TK_IDENT);
8967 expect ('[');
8968 expect (']');
8969 expect ('=');
8970 expect ('{');
8971
8972 bytes_per_line = (*width + 7) / 8 + padding_p;
8973 nbytes = bytes_per_line * *height;
8974 p = *data = (char *) xmalloc (nbytes);
8975
8976 if (v10)
8977 {
8978
8979 for (i = 0; i < nbytes; i += 2)
8980 {
8981 int val = value;
8982 expect (XBM_TK_NUMBER);
8983
8984 *p++ = val;
8985 if (!padding_p || ((i + 2) % bytes_per_line))
8986 *p++ = value >> 8;
8987
8988 if (LA1 == ',' || LA1 == '}')
8989 match ();
8990 else
8991 goto failure;
8992 }
8993 }
8994 else
8995 {
8996 for (i = 0; i < nbytes; ++i)
8997 {
8998 int val = value;
8999 expect (XBM_TK_NUMBER);
9000
9001 *p++ = val;
9002
9003 if (LA1 == ',' || LA1 == '}')
9004 match ();
9005 else
9006 goto failure;
9007 }
9008 }
9009
9010 fclose (fp);
9011 return 1;
9012
9013 failure:
9014
9015 fclose (fp);
9016 if (*data)
9017 {
9018 xfree (*data);
9019 *data = NULL;
9020 }
9021 return 0;
9022
9023#undef match
9024#undef expect
9025#undef expect_ident
9026}
9027
9028
9029/* Load XBM image IMG which will be displayed on frame F from file
9030 SPECIFIED_FILE. Value is non-zero if successful. */
9031
9032static int
9033xbm_load_image_from_file (f, img, specified_file)
9034 struct frame *f;
9035 struct image *img;
9036 Lisp_Object specified_file;
9037{
9038 int rc;
9039 unsigned char *data;
9040 int success_p = 0;
9041 Lisp_Object file;
9042 struct gcpro gcpro1;
9043
9044 xassert (STRINGP (specified_file));
9045 file = Qnil;
9046 GCPRO1 (file);
9047
9048 file = x_find_image_file (specified_file);
9049 if (!STRINGP (file))
9050 {
9051 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9052 UNGCPRO;
9053 return 0;
9054 }
9055
9056 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
9057 &img->height, &data);
9058 if (rc)
9059 {
9060 int depth = one_w32_display_info.n_cbits;
9061 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9062 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9063 Lisp_Object value;
9064
9065 xassert (img->width > 0 && img->height > 0);
9066
9067 /* Get foreground and background colors, maybe allocate colors. */
9068 value = image_spec_value (img->spec, QCforeground, NULL);
9069 if (!NILP (value))
9070 foreground = x_alloc_image_color (f, img, value, foreground);
9071
9072 value = image_spec_value (img->spec, QCbackground, NULL);
9073 if (!NILP (value))
9074 background = x_alloc_image_color (f, img, value, background);
9075
767b1ff0 9076#if 0 /* TODO : Port image display to W32 */
6fc2811b
JR
9077 BLOCK_INPUT;
9078 img->pixmap
9079 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9080 FRAME_W32_WINDOW (f),
9081 data,
9082 img->width, img->height,
9083 foreground, background,
9084 depth);
9085 xfree (data);
9086
9087 if (img->pixmap == 0)
9088 {
9089 x_clear_image (f, img);
9090 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
9091 }
9092 else
9093 success_p = 1;
9094
9095 UNBLOCK_INPUT;
9096#endif
9097 }
9098 else
9099 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9100
9101 UNGCPRO;
9102 return success_p;
9103}
9104
9105
9106/* Fill image IMG which is used on frame F with pixmap data. Value is
9107 non-zero if successful. */
9108
9109static int
9110xbm_load (f, img)
9111 struct frame *f;
9112 struct image *img;
9113{
9114 int success_p = 0;
9115 Lisp_Object file_name;
9116
9117 xassert (xbm_image_p (img->spec));
9118
9119 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9120 file_name = image_spec_value (img->spec, QCfile, NULL);
9121 if (STRINGP (file_name))
9122 success_p = xbm_load_image_from_file (f, img, file_name);
9123 else
9124 {
9125 struct image_keyword fmt[XBM_LAST];
9126 Lisp_Object data;
9127 int depth;
9128 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9129 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9130 char *bits;
9131 int parsed_p;
9132
9133 /* Parse the list specification. */
9134 bcopy (xbm_format, fmt, sizeof fmt);
9135 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9136 xassert (parsed_p);
9137
9138 /* Get specified width, and height. */
9139 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9140 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9141 xassert (img->width > 0 && img->height > 0);
9142
9143 BLOCK_INPUT;
9144
9145 if (fmt[XBM_ASCENT].count)
9146 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
9147
9148 /* Get foreground and background colors, maybe allocate colors. */
9149 if (fmt[XBM_FOREGROUND].count)
9150 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9151 foreground);
9152 if (fmt[XBM_BACKGROUND].count)
9153 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9154 background);
9155
9156 /* Set bits to the bitmap image data. */
9157 data = fmt[XBM_DATA].value;
9158 if (VECTORP (data))
9159 {
9160 int i;
9161 char *p;
9162 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
9163
9164 p = bits = (char *) alloca (nbytes * img->height);
9165 for (i = 0; i < img->height; ++i, p += nbytes)
9166 {
9167 Lisp_Object line = XVECTOR (data)->contents[i];
9168 if (STRINGP (line))
9169 bcopy (XSTRING (line)->data, p, nbytes);
9170 else
9171 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9172 }
9173 }
9174 else if (STRINGP (data))
9175 bits = XSTRING (data)->data;
9176 else
9177 bits = XBOOL_VECTOR (data)->data;
9178
767b1ff0 9179#if 0 /* TODO : W32 XPM code */
6fc2811b
JR
9180 /* Create the pixmap. */
9181 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
9182 img->pixmap
9183 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9184 FRAME_W32_WINDOW (f),
9185 bits,
9186 img->width, img->height,
9187 foreground, background,
9188 depth);
767b1ff0 9189#endif /* TODO */
6fc2811b
JR
9190
9191 if (img->pixmap)
9192 success_p = 1;
9193 else
9194 {
9195 image_error ("Unable to create pixmap for XBM image `%s'",
9196 img->spec, Qnil);
9197 x_clear_image (f, img);
9198 }
9199
9200 UNBLOCK_INPUT;
9201 }
9202
9203 return success_p;
9204}
9205
9206
9207\f
9208/***********************************************************************
9209 XPM images
9210 ***********************************************************************/
9211
9212#if HAVE_XPM
9213
9214static int xpm_image_p P_ ((Lisp_Object object));
9215static int xpm_load P_ ((struct frame *f, struct image *img));
9216static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9217
9218#include "X11/xpm.h"
9219
9220/* The symbol `xpm' identifying XPM-format images. */
9221
9222Lisp_Object Qxpm;
9223
9224/* Indices of image specification fields in xpm_format, below. */
9225
9226enum xpm_keyword_index
9227{
9228 XPM_TYPE,
9229 XPM_FILE,
9230 XPM_DATA,
9231 XPM_ASCENT,
9232 XPM_MARGIN,
9233 XPM_RELIEF,
9234 XPM_ALGORITHM,
9235 XPM_HEURISTIC_MASK,
9236 XPM_COLOR_SYMBOLS,
9237 XPM_LAST
9238};
9239
9240/* Vector of image_keyword structures describing the format
9241 of valid XPM image specifications. */
9242
9243static struct image_keyword xpm_format[XPM_LAST] =
9244{
9245 {":type", IMAGE_SYMBOL_VALUE, 1},
9246 {":file", IMAGE_STRING_VALUE, 0},
9247 {":data", IMAGE_STRING_VALUE, 0},
9248 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9249 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9250 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9251 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
9252 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9253 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9254};
9255
9256/* Structure describing the image type XBM. */
9257
9258static struct image_type xpm_type =
9259{
9260 &Qxpm,
9261 xpm_image_p,
9262 xpm_load,
9263 x_clear_image,
9264 NULL
9265};
9266
9267
9268/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9269 for XPM images. Such a list must consist of conses whose car and
9270 cdr are strings. */
9271
9272static int
9273xpm_valid_color_symbols_p (color_symbols)
9274 Lisp_Object color_symbols;
9275{
9276 while (CONSP (color_symbols))
9277 {
9278 Lisp_Object sym = XCAR (color_symbols);
9279 if (!CONSP (sym)
9280 || !STRINGP (XCAR (sym))
9281 || !STRINGP (XCDR (sym)))
9282 break;
9283 color_symbols = XCDR (color_symbols);
9284 }
9285
9286 return NILP (color_symbols);
9287}
9288
9289
9290/* Value is non-zero if OBJECT is a valid XPM image specification. */
9291
9292static int
9293xpm_image_p (object)
9294 Lisp_Object object;
9295{
9296 struct image_keyword fmt[XPM_LAST];
9297 bcopy (xpm_format, fmt, sizeof fmt);
9298 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9299 /* Either `:file' or `:data' must be present. */
9300 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9301 /* Either no `:color-symbols' or it's a list of conses
9302 whose car and cdr are strings. */
9303 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9304 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9305 && (fmt[XPM_ASCENT].count == 0
9306 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9307}
9308
9309
9310/* Load image IMG which will be displayed on frame F. Value is
9311 non-zero if successful. */
9312
9313static int
9314xpm_load (f, img)
9315 struct frame *f;
9316 struct image *img;
9317{
9318 int rc, i;
9319 XpmAttributes attrs;
9320 Lisp_Object specified_file, color_symbols;
9321
9322 /* Configure the XPM lib. Use the visual of frame F. Allocate
9323 close colors. Return colors allocated. */
9324 bzero (&attrs, sizeof attrs);
dfff8a69
JR
9325 attrs.visual = FRAME_X_VISUAL (f);
9326 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 9327 attrs.valuemask |= XpmVisual;
dfff8a69 9328 attrs.valuemask |= XpmColormap;
6fc2811b 9329 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 9330#ifdef XpmAllocCloseColors
6fc2811b
JR
9331 attrs.alloc_close_colors = 1;
9332 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
9333#else
9334 attrs.closeness = 600;
9335 attrs.valuemask |= XpmCloseness;
9336#endif
6fc2811b
JR
9337
9338 /* If image specification contains symbolic color definitions, add
9339 these to `attrs'. */
9340 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9341 if (CONSP (color_symbols))
9342 {
9343 Lisp_Object tail;
9344 XpmColorSymbol *xpm_syms;
9345 int i, size;
9346
9347 attrs.valuemask |= XpmColorSymbols;
9348
9349 /* Count number of symbols. */
9350 attrs.numsymbols = 0;
9351 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9352 ++attrs.numsymbols;
9353
9354 /* Allocate an XpmColorSymbol array. */
9355 size = attrs.numsymbols * sizeof *xpm_syms;
9356 xpm_syms = (XpmColorSymbol *) alloca (size);
9357 bzero (xpm_syms, size);
9358 attrs.colorsymbols = xpm_syms;
9359
9360 /* Fill the color symbol array. */
9361 for (tail = color_symbols, i = 0;
9362 CONSP (tail);
9363 ++i, tail = XCDR (tail))
9364 {
9365 Lisp_Object name = XCAR (XCAR (tail));
9366 Lisp_Object color = XCDR (XCAR (tail));
9367 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9368 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9369 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9370 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9371 }
9372 }
9373
9374 /* Create a pixmap for the image, either from a file, or from a
9375 string buffer containing data in the same format as an XPM file. */
9376 BLOCK_INPUT;
9377 specified_file = image_spec_value (img->spec, QCfile, NULL);
9378 if (STRINGP (specified_file))
9379 {
9380 Lisp_Object file = x_find_image_file (specified_file);
9381 if (!STRINGP (file))
9382 {
9383 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9384 UNBLOCK_INPUT;
9385 return 0;
9386 }
9387
9388 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9389 XSTRING (file)->data, &img->pixmap, &img->mask,
9390 &attrs);
9391 }
9392 else
9393 {
9394 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9395 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9396 XSTRING (buffer)->data,
9397 &img->pixmap, &img->mask,
9398 &attrs);
9399 }
9400 UNBLOCK_INPUT;
9401
9402 if (rc == XpmSuccess)
9403 {
9404 /* Remember allocated colors. */
9405 img->ncolors = attrs.nalloc_pixels;
9406 img->colors = (unsigned long *) xmalloc (img->ncolors
9407 * sizeof *img->colors);
9408 for (i = 0; i < attrs.nalloc_pixels; ++i)
9409 img->colors[i] = attrs.alloc_pixels[i];
9410
9411 img->width = attrs.width;
9412 img->height = attrs.height;
9413 xassert (img->width > 0 && img->height > 0);
9414
9415 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9416 BLOCK_INPUT;
9417 XpmFreeAttributes (&attrs);
9418 UNBLOCK_INPUT;
9419 }
9420 else
9421 {
9422 switch (rc)
9423 {
9424 case XpmOpenFailed:
9425 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9426 break;
9427
9428 case XpmFileInvalid:
9429 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9430 break;
9431
9432 case XpmNoMemory:
9433 image_error ("Out of memory (%s)", img->spec, Qnil);
9434 break;
9435
9436 case XpmColorFailed:
9437 image_error ("Color allocation error (%s)", img->spec, Qnil);
9438 break;
9439
9440 default:
9441 image_error ("Unknown error (%s)", img->spec, Qnil);
9442 break;
9443 }
9444 }
9445
9446 return rc == XpmSuccess;
9447}
9448
9449#endif /* HAVE_XPM != 0 */
9450
9451\f
767b1ff0 9452#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
9453/***********************************************************************
9454 Color table
9455 ***********************************************************************/
9456
9457/* An entry in the color table mapping an RGB color to a pixel color. */
9458
9459struct ct_color
9460{
9461 int r, g, b;
9462 unsigned long pixel;
9463
9464 /* Next in color table collision list. */
9465 struct ct_color *next;
9466};
9467
9468/* The bucket vector size to use. Must be prime. */
9469
9470#define CT_SIZE 101
9471
9472/* Value is a hash of the RGB color given by R, G, and B. */
9473
9474#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9475
9476/* The color hash table. */
9477
9478struct ct_color **ct_table;
9479
9480/* Number of entries in the color table. */
9481
9482int ct_colors_allocated;
9483
9484/* Function prototypes. */
9485
9486static void init_color_table P_ ((void));
9487static void free_color_table P_ ((void));
9488static unsigned long *colors_in_color_table P_ ((int *n));
9489static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9490static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9491
9492
9493/* Initialize the color table. */
9494
9495static void
9496init_color_table ()
9497{
9498 int size = CT_SIZE * sizeof (*ct_table);
9499 ct_table = (struct ct_color **) xmalloc (size);
9500 bzero (ct_table, size);
9501 ct_colors_allocated = 0;
9502}
9503
9504
9505/* Free memory associated with the color table. */
9506
9507static void
9508free_color_table ()
9509{
9510 int i;
9511 struct ct_color *p, *next;
9512
9513 for (i = 0; i < CT_SIZE; ++i)
9514 for (p = ct_table[i]; p; p = next)
9515 {
9516 next = p->next;
9517 xfree (p);
9518 }
9519
9520 xfree (ct_table);
9521 ct_table = NULL;
9522}
9523
9524
9525/* Value is a pixel color for RGB color R, G, B on frame F. If an
9526 entry for that color already is in the color table, return the
9527 pixel color of that entry. Otherwise, allocate a new color for R,
9528 G, B, and make an entry in the color table. */
9529
9530static unsigned long
9531lookup_rgb_color (f, r, g, b)
9532 struct frame *f;
9533 int r, g, b;
9534{
9535 unsigned hash = CT_HASH_RGB (r, g, b);
9536 int i = hash % CT_SIZE;
9537 struct ct_color *p;
9538
9539 for (p = ct_table[i]; p; p = p->next)
9540 if (p->r == r && p->g == g && p->b == b)
9541 break;
9542
9543 if (p == NULL)
9544 {
9545 COLORREF color;
9546 Colormap cmap;
9547 int rc;
9548
9549 color = PALETTERGB (r, g, b);
9550
9551 ++ct_colors_allocated;
9552
9553 p = (struct ct_color *) xmalloc (sizeof *p);
9554 p->r = r;
9555 p->g = g;
9556 p->b = b;
9557 p->pixel = color;
9558 p->next = ct_table[i];
9559 ct_table[i] = p;
9560 }
9561
9562 return p->pixel;
9563}
9564
9565
9566/* Look up pixel color PIXEL which is used on frame F in the color
9567 table. If not already present, allocate it. Value is PIXEL. */
9568
9569static unsigned long
9570lookup_pixel_color (f, pixel)
9571 struct frame *f;
9572 unsigned long pixel;
9573{
9574 int i = pixel % CT_SIZE;
9575 struct ct_color *p;
9576
9577 for (p = ct_table[i]; p; p = p->next)
9578 if (p->pixel == pixel)
9579 break;
9580
9581 if (p == NULL)
9582 {
9583 XColor color;
9584 Colormap cmap;
9585 int rc;
9586
9587 BLOCK_INPUT;
9588
9589 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9590 color.pixel = pixel;
9591 XQueryColor (NULL, cmap, &color);
9592 rc = x_alloc_nearest_color (f, cmap, &color);
9593 UNBLOCK_INPUT;
9594
9595 if (rc)
9596 {
9597 ++ct_colors_allocated;
9598
9599 p = (struct ct_color *) xmalloc (sizeof *p);
9600 p->r = color.red;
9601 p->g = color.green;
9602 p->b = color.blue;
9603 p->pixel = pixel;
9604 p->next = ct_table[i];
9605 ct_table[i] = p;
9606 }
9607 else
9608 return FRAME_FOREGROUND_PIXEL (f);
9609 }
9610 return p->pixel;
9611}
9612
9613
9614/* Value is a vector of all pixel colors contained in the color table,
9615 allocated via xmalloc. Set *N to the number of colors. */
9616
9617static unsigned long *
9618colors_in_color_table (n)
9619 int *n;
9620{
9621 int i, j;
9622 struct ct_color *p;
9623 unsigned long *colors;
9624
9625 if (ct_colors_allocated == 0)
9626 {
9627 *n = 0;
9628 colors = NULL;
9629 }
9630 else
9631 {
9632 colors = (unsigned long *) xmalloc (ct_colors_allocated
9633 * sizeof *colors);
9634 *n = ct_colors_allocated;
9635
9636 for (i = j = 0; i < CT_SIZE; ++i)
9637 for (p = ct_table[i]; p; p = p->next)
9638 colors[j++] = p->pixel;
9639 }
9640
9641 return colors;
9642}
9643
767b1ff0 9644#endif /* TODO */
6fc2811b
JR
9645
9646\f
9647/***********************************************************************
9648 Algorithms
9649 ***********************************************************************/
9650
767b1ff0 9651#if 0 /* TODO : W32 versions of low level algorithms */
6fc2811b
JR
9652static void x_laplace_write_row P_ ((struct frame *, long *,
9653 int, XImage *, int));
9654static void x_laplace_read_row P_ ((struct frame *, Colormap,
9655 XColor *, int, XImage *, int));
9656
9657
9658/* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9659 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9660 the width of one row in the image. */
9661
9662static void
9663x_laplace_read_row (f, cmap, colors, width, ximg, y)
9664 struct frame *f;
9665 Colormap cmap;
9666 XColor *colors;
9667 int width;
9668 XImage *ximg;
9669 int y;
9670{
9671 int x;
9672
9673 for (x = 0; x < width; ++x)
9674 colors[x].pixel = XGetPixel (ximg, x, y);
9675
9676 XQueryColors (NULL, cmap, colors, width);
9677}
9678
9679
9680/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9681 containing the pixel colors to write. F is the frame we are
9682 working on. */
9683
9684static void
9685x_laplace_write_row (f, pixels, width, ximg, y)
9686 struct frame *f;
9687 long *pixels;
9688 int width;
9689 XImage *ximg;
9690 int y;
9691{
9692 int x;
9693
9694 for (x = 0; x < width; ++x)
9695 XPutPixel (ximg, x, y, pixels[x]);
9696}
9697#endif
9698
9699/* Transform image IMG which is used on frame F with a Laplace
9700 edge-detection algorithm. The result is an image that can be used
9701 to draw disabled buttons, for example. */
9702
9703static void
9704x_laplace (f, img)
9705 struct frame *f;
9706 struct image *img;
9707{
767b1ff0 9708#if 0 /* TODO : W32 version */
6fc2811b
JR
9709 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9710 XImage *ximg, *oimg;
9711 XColor *in[3];
9712 long *out;
9713 Pixmap pixmap;
9714 int x, y, i;
9715 long pixel;
9716 int in_y, out_y, rc;
9717 int mv2 = 45000;
9718
9719 BLOCK_INPUT;
9720
9721 /* Get the X image IMG->pixmap. */
9722 ximg = XGetImage (NULL, img->pixmap,
9723 0, 0, img->width, img->height, ~0, ZPixmap);
9724
9725 /* Allocate 3 input rows, and one output row of colors. */
9726 for (i = 0; i < 3; ++i)
9727 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9728 out = (long *) alloca (img->width * sizeof (long));
9729
9730 /* Create an X image for output. */
9731 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9732 &oimg, &pixmap);
9733
9734 /* Fill first two rows. */
9735 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9736 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9737 in_y = 2;
9738
9739 /* Write first row, all zeros. */
9740 init_color_table ();
9741 pixel = lookup_rgb_color (f, 0, 0, 0);
9742 for (x = 0; x < img->width; ++x)
9743 out[x] = pixel;
9744 x_laplace_write_row (f, out, img->width, oimg, 0);
9745 out_y = 1;
9746
9747 for (y = 2; y < img->height; ++y)
9748 {
9749 int rowa = y % 3;
9750 int rowb = (y + 2) % 3;
9751
9752 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9753
9754 for (x = 0; x < img->width - 2; ++x)
9755 {
9756 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9757 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9758 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9759
9760 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9761 b & 0xffff);
9762 }
9763
9764 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9765 }
9766
9767 /* Write last line, all zeros. */
9768 for (x = 0; x < img->width; ++x)
9769 out[x] = pixel;
9770 x_laplace_write_row (f, out, img->width, oimg, out_y);
9771
9772 /* Free the input image, and free resources of IMG. */
9773 XDestroyImage (ximg);
9774 x_clear_image (f, img);
9775
9776 /* Put the output image into pixmap, and destroy it. */
9777 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9778 x_destroy_x_image (oimg);
9779
9780 /* Remember new pixmap and colors in IMG. */
9781 img->pixmap = pixmap;
9782 img->colors = colors_in_color_table (&img->ncolors);
9783 free_color_table ();
9784
9785 UNBLOCK_INPUT;
767b1ff0 9786#endif /* TODO */
6fc2811b
JR
9787}
9788
9789
9790/* Build a mask for image IMG which is used on frame F. FILE is the
9791 name of an image file, for error messages. HOW determines how to
9792 determine the background color of IMG. If it is a list '(R G B)',
9793 with R, G, and B being integers >= 0, take that as the color of the
9794 background. Otherwise, determine the background color of IMG
9795 heuristically. Value is non-zero if successful. */
9796
9797static int
9798x_build_heuristic_mask (f, img, how)
9799 struct frame *f;
9800 struct image *img;
9801 Lisp_Object how;
9802{
767b1ff0 9803#if 0 /* TODO : W32 version */
6fc2811b
JR
9804 Display *dpy = FRAME_W32_DISPLAY (f);
9805 XImage *ximg, *mask_img;
9806 int x, y, rc, look_at_corners_p;
9807 unsigned long bg;
9808
9809 BLOCK_INPUT;
9810
9811 /* Create an image and pixmap serving as mask. */
9812 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9813 &mask_img, &img->mask);
9814 if (!rc)
9815 {
9816 UNBLOCK_INPUT;
9817 return 0;
9818 }
9819
9820 /* Get the X image of IMG->pixmap. */
9821 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9822 ~0, ZPixmap);
9823
9824 /* Determine the background color of ximg. If HOW is `(R G B)'
9825 take that as color. Otherwise, try to determine the color
9826 heuristically. */
9827 look_at_corners_p = 1;
9828
9829 if (CONSP (how))
9830 {
9831 int rgb[3], i = 0;
9832
9833 while (i < 3
9834 && CONSP (how)
9835 && NATNUMP (XCAR (how)))
9836 {
9837 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9838 how = XCDR (how);
9839 }
9840
9841 if (i == 3 && NILP (how))
9842 {
9843 char color_name[30];
9844 XColor exact, color;
9845 Colormap cmap;
9846
9847 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9848
9849 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9850 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9851 {
9852 bg = color.pixel;
9853 look_at_corners_p = 0;
9854 }
9855 }
9856 }
9857
9858 if (look_at_corners_p)
9859 {
9860 unsigned long corners[4];
9861 int i, best_count;
9862
9863 /* Get the colors at the corners of ximg. */
9864 corners[0] = XGetPixel (ximg, 0, 0);
9865 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9866 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9867 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9868
9869 /* Choose the most frequently found color as background. */
9870 for (i = best_count = 0; i < 4; ++i)
9871 {
9872 int j, n;
9873
9874 for (j = n = 0; j < 4; ++j)
9875 if (corners[i] == corners[j])
9876 ++n;
9877
9878 if (n > best_count)
9879 bg = corners[i], best_count = n;
9880 }
9881 }
9882
9883 /* Set all bits in mask_img to 1 whose color in ximg is different
9884 from the background color bg. */
9885 for (y = 0; y < img->height; ++y)
9886 for (x = 0; x < img->width; ++x)
9887 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9888
9889 /* Put mask_img into img->mask. */
9890 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9891 x_destroy_x_image (mask_img);
9892 XDestroyImage (ximg);
9893
9894 UNBLOCK_INPUT;
767b1ff0 9895#endif /* TODO */
6fc2811b
JR
9896
9897 return 1;
9898}
9899
9900
9901\f
9902/***********************************************************************
9903 PBM (mono, gray, color)
9904 ***********************************************************************/
9905#ifdef HAVE_PBM
9906
9907static int pbm_image_p P_ ((Lisp_Object object));
9908static int pbm_load P_ ((struct frame *f, struct image *img));
9909static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9910
9911/* The symbol `pbm' identifying images of this type. */
9912
9913Lisp_Object Qpbm;
9914
9915/* Indices of image specification fields in gs_format, below. */
9916
9917enum pbm_keyword_index
9918{
9919 PBM_TYPE,
9920 PBM_FILE,
9921 PBM_DATA,
9922 PBM_ASCENT,
9923 PBM_MARGIN,
9924 PBM_RELIEF,
9925 PBM_ALGORITHM,
9926 PBM_HEURISTIC_MASK,
9927 PBM_LAST
9928};
9929
9930/* Vector of image_keyword structures describing the format
9931 of valid user-defined image specifications. */
9932
9933static struct image_keyword pbm_format[PBM_LAST] =
9934{
9935 {":type", IMAGE_SYMBOL_VALUE, 1},
9936 {":file", IMAGE_STRING_VALUE, 0},
9937 {":data", IMAGE_STRING_VALUE, 0},
9938 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 9939 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9940 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9941 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
9942 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9943};
9944
9945/* Structure describing the image type `pbm'. */
9946
9947static struct image_type pbm_type =
9948{
9949 &Qpbm,
9950 pbm_image_p,
9951 pbm_load,
9952 x_clear_image,
9953 NULL
9954};
9955
9956
9957/* Return non-zero if OBJECT is a valid PBM image specification. */
9958
9959static int
9960pbm_image_p (object)
9961 Lisp_Object object;
9962{
9963 struct image_keyword fmt[PBM_LAST];
9964
9965 bcopy (pbm_format, fmt, sizeof fmt);
9966
9967 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9968 || (fmt[PBM_ASCENT].count
9969 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9970 return 0;
9971
9972 /* Must specify either :data or :file. */
9973 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9974}
9975
9976
9977/* Scan a decimal number from *S and return it. Advance *S while
9978 reading the number. END is the end of the string. Value is -1 at
9979 end of input. */
9980
9981static int
9982pbm_scan_number (s, end)
9983 unsigned char **s, *end;
9984{
9985 int c, val = -1;
9986
9987 while (*s < end)
9988 {
9989 /* Skip white-space. */
9990 while (*s < end && (c = *(*s)++, isspace (c)))
9991 ;
9992
9993 if (c == '#')
9994 {
9995 /* Skip comment to end of line. */
9996 while (*s < end && (c = *(*s)++, c != '\n'))
9997 ;
9998 }
9999 else if (isdigit (c))
10000 {
10001 /* Read decimal number. */
10002 val = c - '0';
10003 while (*s < end && (c = *(*s)++, isdigit (c)))
10004 val = 10 * val + c - '0';
10005 break;
10006 }
10007 else
10008 break;
10009 }
10010
10011 return val;
10012}
10013
10014
10015/* Read FILE into memory. Value is a pointer to a buffer allocated
10016 with xmalloc holding FILE's contents. Value is null if an error
10017 occured. *SIZE is set to the size of the file. */
10018
10019static char *
10020pbm_read_file (file, size)
10021 Lisp_Object file;
10022 int *size;
10023{
10024 FILE *fp = NULL;
10025 char *buf = NULL;
10026 struct stat st;
10027
10028 if (stat (XSTRING (file)->data, &st) == 0
10029 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10030 && (buf = (char *) xmalloc (st.st_size),
10031 fread (buf, 1, st.st_size, fp) == st.st_size))
10032 {
10033 *size = st.st_size;
10034 fclose (fp);
10035 }
10036 else
10037 {
10038 if (fp)
10039 fclose (fp);
10040 if (buf)
10041 {
10042 xfree (buf);
10043 buf = NULL;
10044 }
10045 }
10046
10047 return buf;
10048}
10049
10050
10051/* Load PBM image IMG for use on frame F. */
10052
10053static int
10054pbm_load (f, img)
10055 struct frame *f;
10056 struct image *img;
10057{
10058 int raw_p, x, y;
10059 int width, height, max_color_idx = 0;
10060 XImage *ximg;
10061 Lisp_Object file, specified_file;
10062 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10063 struct gcpro gcpro1;
10064 unsigned char *contents = NULL;
10065 unsigned char *end, *p;
10066 int size;
10067
10068 specified_file = image_spec_value (img->spec, QCfile, NULL);
10069 file = Qnil;
10070 GCPRO1 (file);
10071
10072 if (STRINGP (specified_file))
10073 {
10074 file = x_find_image_file (specified_file);
10075 if (!STRINGP (file))
10076 {
10077 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10078 UNGCPRO;
10079 return 0;
10080 }
10081
10082 contents = pbm_read_file (file, &size);
10083 if (contents == NULL)
10084 {
10085 image_error ("Error reading `%s'", file, Qnil);
10086 UNGCPRO;
10087 return 0;
10088 }
10089
10090 p = contents;
10091 end = contents + size;
10092 }
10093 else
10094 {
10095 Lisp_Object data;
10096 data = image_spec_value (img->spec, QCdata, NULL);
10097 p = XSTRING (data)->data;
10098 end = p + STRING_BYTES (XSTRING (data));
10099 }
10100
10101 /* Check magic number. */
10102 if (end - p < 2 || *p++ != 'P')
10103 {
10104 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10105 error:
10106 xfree (contents);
10107 UNGCPRO;
10108 return 0;
10109 }
10110
6fc2811b
JR
10111 switch (*p++)
10112 {
10113 case '1':
10114 raw_p = 0, type = PBM_MONO;
10115 break;
10116
10117 case '2':
10118 raw_p = 0, type = PBM_GRAY;
10119 break;
10120
10121 case '3':
10122 raw_p = 0, type = PBM_COLOR;
10123 break;
10124
10125 case '4':
10126 raw_p = 1, type = PBM_MONO;
10127 break;
10128
10129 case '5':
10130 raw_p = 1, type = PBM_GRAY;
10131 break;
10132
10133 case '6':
10134 raw_p = 1, type = PBM_COLOR;
10135 break;
10136
10137 default:
10138 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10139 goto error;
10140 }
10141
10142 /* Read width, height, maximum color-component. Characters
10143 starting with `#' up to the end of a line are ignored. */
10144 width = pbm_scan_number (&p, end);
10145 height = pbm_scan_number (&p, end);
10146
10147 if (type != PBM_MONO)
10148 {
10149 max_color_idx = pbm_scan_number (&p, end);
10150 if (raw_p && max_color_idx > 255)
10151 max_color_idx = 255;
10152 }
10153
10154 if (width < 0
10155 || height < 0
10156 || (type != PBM_MONO && max_color_idx < 0))
10157 goto error;
10158
10159 BLOCK_INPUT;
10160 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10161 &ximg, &img->pixmap))
10162 {
10163 UNBLOCK_INPUT;
10164 goto error;
10165 }
10166
10167 /* Initialize the color hash table. */
10168 init_color_table ();
10169
10170 if (type == PBM_MONO)
10171 {
10172 int c = 0, g;
10173
10174 for (y = 0; y < height; ++y)
10175 for (x = 0; x < width; ++x)
10176 {
10177 if (raw_p)
10178 {
10179 if ((x & 7) == 0)
10180 c = *p++;
10181 g = c & 0x80;
10182 c <<= 1;
10183 }
10184 else
10185 g = pbm_scan_number (&p, end);
10186
10187 XPutPixel (ximg, x, y, (g
10188 ? FRAME_FOREGROUND_PIXEL (f)
10189 : FRAME_BACKGROUND_PIXEL (f)));
10190 }
10191 }
10192 else
10193 {
10194 for (y = 0; y < height; ++y)
10195 for (x = 0; x < width; ++x)
10196 {
10197 int r, g, b;
10198
10199 if (type == PBM_GRAY)
10200 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10201 else if (raw_p)
10202 {
10203 r = *p++;
10204 g = *p++;
10205 b = *p++;
10206 }
10207 else
10208 {
10209 r = pbm_scan_number (&p, end);
10210 g = pbm_scan_number (&p, end);
10211 b = pbm_scan_number (&p, end);
10212 }
10213
10214 if (r < 0 || g < 0 || b < 0)
10215 {
dfff8a69 10216 xfree (ximg->data);
6fc2811b
JR
10217 ximg->data = NULL;
10218 XDestroyImage (ximg);
10219 UNBLOCK_INPUT;
10220 image_error ("Invalid pixel value in image `%s'",
10221 img->spec, Qnil);
10222 goto error;
10223 }
10224
10225 /* RGB values are now in the range 0..max_color_idx.
10226 Scale this to the range 0..0xffff supported by X. */
10227 r = (double) r * 65535 / max_color_idx;
10228 g = (double) g * 65535 / max_color_idx;
10229 b = (double) b * 65535 / max_color_idx;
10230 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10231 }
10232 }
10233
10234 /* Store in IMG->colors the colors allocated for the image, and
10235 free the color table. */
10236 img->colors = colors_in_color_table (&img->ncolors);
10237 free_color_table ();
10238
10239 /* Put the image into a pixmap. */
10240 x_put_x_image (f, ximg, img->pixmap, width, height);
10241 x_destroy_x_image (ximg);
10242 UNBLOCK_INPUT;
10243
10244 img->width = width;
10245 img->height = height;
10246
10247 UNGCPRO;
10248 xfree (contents);
10249 return 1;
10250}
10251#endif /* HAVE_PBM */
10252
10253\f
10254/***********************************************************************
10255 PNG
10256 ***********************************************************************/
10257
10258#if HAVE_PNG
10259
10260#include <png.h>
10261
10262/* Function prototypes. */
10263
10264static int png_image_p P_ ((Lisp_Object object));
10265static int png_load P_ ((struct frame *f, struct image *img));
10266
10267/* The symbol `png' identifying images of this type. */
10268
10269Lisp_Object Qpng;
10270
10271/* Indices of image specification fields in png_format, below. */
10272
10273enum png_keyword_index
10274{
10275 PNG_TYPE,
10276 PNG_DATA,
10277 PNG_FILE,
10278 PNG_ASCENT,
10279 PNG_MARGIN,
10280 PNG_RELIEF,
10281 PNG_ALGORITHM,
10282 PNG_HEURISTIC_MASK,
10283 PNG_LAST
10284};
10285
10286/* Vector of image_keyword structures describing the format
10287 of valid user-defined image specifications. */
10288
10289static struct image_keyword png_format[PNG_LAST] =
10290{
10291 {":type", IMAGE_SYMBOL_VALUE, 1},
10292 {":data", IMAGE_STRING_VALUE, 0},
10293 {":file", IMAGE_STRING_VALUE, 0},
10294 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10295 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10296 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10297 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
10298 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10299};
10300
10301/* Structure describing the image type `png'. */
10302
10303static struct image_type png_type =
10304{
10305 &Qpng,
10306 png_image_p,
10307 png_load,
10308 x_clear_image,
10309 NULL
10310};
10311
10312
10313/* Return non-zero if OBJECT is a valid PNG image specification. */
10314
10315static int
10316png_image_p (object)
10317 Lisp_Object object;
10318{
10319 struct image_keyword fmt[PNG_LAST];
10320 bcopy (png_format, fmt, sizeof fmt);
10321
10322 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
10323 || (fmt[PNG_ASCENT].count
10324 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
10325 return 0;
10326
10327 /* Must specify either the :data or :file keyword. */
10328 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
10329}
10330
10331
10332/* Error and warning handlers installed when the PNG library
10333 is initialized. */
10334
10335static void
10336my_png_error (png_ptr, msg)
10337 png_struct *png_ptr;
10338 char *msg;
10339{
10340 xassert (png_ptr != NULL);
10341 image_error ("PNG error: %s", build_string (msg), Qnil);
10342 longjmp (png_ptr->jmpbuf, 1);
10343}
10344
10345
10346static void
10347my_png_warning (png_ptr, msg)
10348 png_struct *png_ptr;
10349 char *msg;
10350{
10351 xassert (png_ptr != NULL);
10352 image_error ("PNG warning: %s", build_string (msg), Qnil);
10353}
10354
6fc2811b
JR
10355/* Memory source for PNG decoding. */
10356
10357struct png_memory_storage
10358{
10359 unsigned char *bytes; /* The data */
10360 size_t len; /* How big is it? */
10361 int index; /* Where are we? */
10362};
10363
10364
10365/* Function set as reader function when reading PNG image from memory.
10366 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10367 bytes from the input to DATA. */
10368
10369static void
10370png_read_from_memory (png_ptr, data, length)
10371 png_structp png_ptr;
10372 png_bytep data;
10373 png_size_t length;
10374{
10375 struct png_memory_storage *tbr
10376 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
10377
10378 if (length > tbr->len - tbr->index)
10379 png_error (png_ptr, "Read error");
10380
10381 bcopy (tbr->bytes + tbr->index, data, length);
10382 tbr->index = tbr->index + length;
10383}
10384
6fc2811b
JR
10385/* Load PNG image IMG for use on frame F. Value is non-zero if
10386 successful. */
10387
10388static int
10389png_load (f, img)
10390 struct frame *f;
10391 struct image *img;
10392{
10393 Lisp_Object file, specified_file;
10394 Lisp_Object specified_data;
10395 int x, y, i;
10396 XImage *ximg, *mask_img = NULL;
10397 struct gcpro gcpro1;
10398 png_struct *png_ptr = NULL;
10399 png_info *info_ptr = NULL, *end_info = NULL;
10400 FILE *fp = NULL;
10401 png_byte sig[8];
10402 png_byte *pixels = NULL;
10403 png_byte **rows = NULL;
10404 png_uint_32 width, height;
10405 int bit_depth, color_type, interlace_type;
10406 png_byte channels;
10407 png_uint_32 row_bytes;
10408 int transparent_p;
10409 char *gamma_str;
10410 double screen_gamma, image_gamma;
10411 int intent;
10412 struct png_memory_storage tbr; /* Data to be read */
10413
10414 /* Find out what file to load. */
10415 specified_file = image_spec_value (img->spec, QCfile, NULL);
10416 specified_data = image_spec_value (img->spec, QCdata, NULL);
10417 file = Qnil;
10418 GCPRO1 (file);
10419
10420 if (NILP (specified_data))
10421 {
10422 file = x_find_image_file (specified_file);
10423 if (!STRINGP (file))
10424 {
10425 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10426 UNGCPRO;
10427 return 0;
10428 }
10429
10430 /* Open the image file. */
10431 fp = fopen (XSTRING (file)->data, "rb");
10432 if (!fp)
10433 {
10434 image_error ("Cannot open image file `%s'", file, Qnil);
10435 UNGCPRO;
10436 fclose (fp);
10437 return 0;
10438 }
10439
10440 /* Check PNG signature. */
10441 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10442 || !png_check_sig (sig, sizeof sig))
10443 {
10444 image_error ("Not a PNG file:` %s'", file, Qnil);
10445 UNGCPRO;
10446 fclose (fp);
10447 return 0;
10448 }
10449 }
10450 else
10451 {
10452 /* Read from memory. */
10453 tbr.bytes = XSTRING (specified_data)->data;
10454 tbr.len = STRING_BYTES (XSTRING (specified_data));
10455 tbr.index = 0;
10456
10457 /* Check PNG signature. */
10458 if (tbr.len < sizeof sig
10459 || !png_check_sig (tbr.bytes, sizeof sig))
10460 {
10461 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10462 UNGCPRO;
10463 return 0;
10464 }
10465
10466 /* Need to skip past the signature. */
10467 tbr.bytes += sizeof (sig);
10468 }
10469
6fc2811b
JR
10470 /* Initialize read and info structs for PNG lib. */
10471 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10472 my_png_error, my_png_warning);
10473 if (!png_ptr)
10474 {
10475 if (fp) fclose (fp);
10476 UNGCPRO;
10477 return 0;
10478 }
10479
10480 info_ptr = png_create_info_struct (png_ptr);
10481 if (!info_ptr)
10482 {
10483 png_destroy_read_struct (&png_ptr, NULL, NULL);
10484 if (fp) fclose (fp);
10485 UNGCPRO;
10486 return 0;
10487 }
10488
10489 end_info = png_create_info_struct (png_ptr);
10490 if (!end_info)
10491 {
10492 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10493 if (fp) fclose (fp);
10494 UNGCPRO;
10495 return 0;
10496 }
10497
10498 /* Set error jump-back. We come back here when the PNG library
10499 detects an error. */
10500 if (setjmp (png_ptr->jmpbuf))
10501 {
10502 error:
10503 if (png_ptr)
10504 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10505 xfree (pixels);
10506 xfree (rows);
10507 if (fp) fclose (fp);
10508 UNGCPRO;
10509 return 0;
10510 }
10511
10512 /* Read image info. */
10513 if (!NILP (specified_data))
10514 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10515 else
10516 png_init_io (png_ptr, fp);
10517
10518 png_set_sig_bytes (png_ptr, sizeof sig);
10519 png_read_info (png_ptr, info_ptr);
10520 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10521 &interlace_type, NULL, NULL);
10522
10523 /* If image contains simply transparency data, we prefer to
10524 construct a clipping mask. */
10525 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10526 transparent_p = 1;
10527 else
10528 transparent_p = 0;
10529
10530 /* This function is easier to write if we only have to handle
10531 one data format: RGB or RGBA with 8 bits per channel. Let's
10532 transform other formats into that format. */
10533
10534 /* Strip more than 8 bits per channel. */
10535 if (bit_depth == 16)
10536 png_set_strip_16 (png_ptr);
10537
10538 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10539 if available. */
10540 png_set_expand (png_ptr);
10541
10542 /* Convert grayscale images to RGB. */
10543 if (color_type == PNG_COLOR_TYPE_GRAY
10544 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10545 png_set_gray_to_rgb (png_ptr);
10546
10547 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10548 gamma_str = getenv ("SCREEN_GAMMA");
10549 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10550
10551 /* Tell the PNG lib to handle gamma correction for us. */
10552
10553#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10554 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10555 /* There is a special chunk in the image specifying the gamma. */
10556 png_set_sRGB (png_ptr, info_ptr, intent);
10557 else
10558#endif
10559 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10560 /* Image contains gamma information. */
10561 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10562 else
10563 /* Use a default of 0.5 for the image gamma. */
10564 png_set_gamma (png_ptr, screen_gamma, 0.5);
10565
10566 /* Handle alpha channel by combining the image with a background
10567 color. Do this only if a real alpha channel is supplied. For
10568 simple transparency, we prefer a clipping mask. */
10569 if (!transparent_p)
10570 {
10571 png_color_16 *image_background;
10572
10573 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10574 /* Image contains a background color with which to
10575 combine the image. */
10576 png_set_background (png_ptr, image_background,
10577 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10578 else
10579 {
10580 /* Image does not contain a background color with which
10581 to combine the image data via an alpha channel. Use
10582 the frame's background instead. */
10583 XColor color;
10584 Colormap cmap;
10585 png_color_16 frame_background;
10586
10587 BLOCK_INPUT;
10588 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10589 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10590 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10591 UNBLOCK_INPUT;
10592
10593 bzero (&frame_background, sizeof frame_background);
10594 frame_background.red = color.red;
10595 frame_background.green = color.green;
10596 frame_background.blue = color.blue;
10597
10598 png_set_background (png_ptr, &frame_background,
10599 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10600 }
10601 }
10602
10603 /* Update info structure. */
10604 png_read_update_info (png_ptr, info_ptr);
10605
10606 /* Get number of channels. Valid values are 1 for grayscale images
10607 and images with a palette, 2 for grayscale images with transparency
10608 information (alpha channel), 3 for RGB images, and 4 for RGB
10609 images with alpha channel, i.e. RGBA. If conversions above were
10610 sufficient we should only have 3 or 4 channels here. */
10611 channels = png_get_channels (png_ptr, info_ptr);
10612 xassert (channels == 3 || channels == 4);
10613
10614 /* Number of bytes needed for one row of the image. */
10615 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10616
10617 /* Allocate memory for the image. */
10618 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10619 rows = (png_byte **) xmalloc (height * sizeof *rows);
10620 for (i = 0; i < height; ++i)
10621 rows[i] = pixels + i * row_bytes;
10622
10623 /* Read the entire image. */
10624 png_read_image (png_ptr, rows);
10625 png_read_end (png_ptr, info_ptr);
10626 if (fp)
10627 {
10628 fclose (fp);
10629 fp = NULL;
10630 }
10631
10632 BLOCK_INPUT;
10633
10634 /* Create the X image and pixmap. */
10635 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10636 &img->pixmap))
10637 {
10638 UNBLOCK_INPUT;
10639 goto error;
10640 }
10641
10642 /* Create an image and pixmap serving as mask if the PNG image
10643 contains an alpha channel. */
10644 if (channels == 4
10645 && !transparent_p
10646 && !x_create_x_image_and_pixmap (f, width, height, 1,
10647 &mask_img, &img->mask))
10648 {
10649 x_destroy_x_image (ximg);
10650 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10651 img->pixmap = 0;
10652 UNBLOCK_INPUT;
10653 goto error;
10654 }
10655
10656 /* Fill the X image and mask from PNG data. */
10657 init_color_table ();
10658
10659 for (y = 0; y < height; ++y)
10660 {
10661 png_byte *p = rows[y];
10662
10663 for (x = 0; x < width; ++x)
10664 {
10665 unsigned r, g, b;
10666
10667 r = *p++ << 8;
10668 g = *p++ << 8;
10669 b = *p++ << 8;
10670 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10671
10672 /* An alpha channel, aka mask channel, associates variable
10673 transparency with an image. Where other image formats
10674 support binary transparency---fully transparent or fully
10675 opaque---PNG allows up to 254 levels of partial transparency.
10676 The PNG library implements partial transparency by combining
10677 the image with a specified background color.
10678
10679 I'm not sure how to handle this here nicely: because the
10680 background on which the image is displayed may change, for
10681 real alpha channel support, it would be necessary to create
10682 a new image for each possible background.
10683
10684 What I'm doing now is that a mask is created if we have
10685 boolean transparency information. Otherwise I'm using
10686 the frame's background color to combine the image with. */
10687
10688 if (channels == 4)
10689 {
10690 if (mask_img)
10691 XPutPixel (mask_img, x, y, *p > 0);
10692 ++p;
10693 }
10694 }
10695 }
10696
10697 /* Remember colors allocated for this image. */
10698 img->colors = colors_in_color_table (&img->ncolors);
10699 free_color_table ();
10700
10701 /* Clean up. */
10702 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10703 xfree (rows);
10704 xfree (pixels);
10705
10706 img->width = width;
10707 img->height = height;
10708
10709 /* Put the image into the pixmap, then free the X image and its buffer. */
10710 x_put_x_image (f, ximg, img->pixmap, width, height);
10711 x_destroy_x_image (ximg);
10712
10713 /* Same for the mask. */
10714 if (mask_img)
10715 {
10716 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10717 x_destroy_x_image (mask_img);
10718 }
10719
10720 UNBLOCK_INPUT;
10721 UNGCPRO;
10722 return 1;
10723}
10724
10725#endif /* HAVE_PNG != 0 */
10726
10727
10728\f
10729/***********************************************************************
10730 JPEG
10731 ***********************************************************************/
10732
10733#if HAVE_JPEG
10734
10735/* Work around a warning about HAVE_STDLIB_H being redefined in
10736 jconfig.h. */
10737#ifdef HAVE_STDLIB_H
10738#define HAVE_STDLIB_H_1
10739#undef HAVE_STDLIB_H
10740#endif /* HAVE_STLIB_H */
10741
10742#include <jpeglib.h>
10743#include <jerror.h>
10744#include <setjmp.h>
10745
10746#ifdef HAVE_STLIB_H_1
10747#define HAVE_STDLIB_H 1
10748#endif
10749
10750static int jpeg_image_p P_ ((Lisp_Object object));
10751static int jpeg_load P_ ((struct frame *f, struct image *img));
10752
10753/* The symbol `jpeg' identifying images of this type. */
10754
10755Lisp_Object Qjpeg;
10756
10757/* Indices of image specification fields in gs_format, below. */
10758
10759enum jpeg_keyword_index
10760{
10761 JPEG_TYPE,
10762 JPEG_DATA,
10763 JPEG_FILE,
10764 JPEG_ASCENT,
10765 JPEG_MARGIN,
10766 JPEG_RELIEF,
10767 JPEG_ALGORITHM,
10768 JPEG_HEURISTIC_MASK,
10769 JPEG_LAST
10770};
10771
10772/* Vector of image_keyword structures describing the format
10773 of valid user-defined image specifications. */
10774
10775static struct image_keyword jpeg_format[JPEG_LAST] =
10776{
10777 {":type", IMAGE_SYMBOL_VALUE, 1},
10778 {":data", IMAGE_STRING_VALUE, 0},
10779 {":file", IMAGE_STRING_VALUE, 0},
10780 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10781 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10782 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10783 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
10784 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10785};
10786
10787/* Structure describing the image type `jpeg'. */
10788
10789static struct image_type jpeg_type =
10790{
10791 &Qjpeg,
10792 jpeg_image_p,
10793 jpeg_load,
10794 x_clear_image,
10795 NULL
10796};
10797
10798
10799/* Return non-zero if OBJECT is a valid JPEG image specification. */
10800
10801static int
10802jpeg_image_p (object)
10803 Lisp_Object object;
10804{
10805 struct image_keyword fmt[JPEG_LAST];
10806
10807 bcopy (jpeg_format, fmt, sizeof fmt);
10808
10809 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10810 || (fmt[JPEG_ASCENT].count
10811 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10812 return 0;
10813
10814 /* Must specify either the :data or :file keyword. */
10815 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10816}
10817
10818
10819struct my_jpeg_error_mgr
10820{
10821 struct jpeg_error_mgr pub;
10822 jmp_buf setjmp_buffer;
10823};
10824
10825static void
10826my_error_exit (cinfo)
10827 j_common_ptr cinfo;
10828{
10829 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10830 longjmp (mgr->setjmp_buffer, 1);
10831}
10832
6fc2811b
JR
10833/* Init source method for JPEG data source manager. Called by
10834 jpeg_read_header() before any data is actually read. See
10835 libjpeg.doc from the JPEG lib distribution. */
10836
10837static void
10838our_init_source (cinfo)
10839 j_decompress_ptr cinfo;
10840{
10841}
10842
10843
10844/* Fill input buffer method for JPEG data source manager. Called
10845 whenever more data is needed. We read the whole image in one step,
10846 so this only adds a fake end of input marker at the end. */
10847
10848static boolean
10849our_fill_input_buffer (cinfo)
10850 j_decompress_ptr cinfo;
10851{
10852 /* Insert a fake EOI marker. */
10853 struct jpeg_source_mgr *src = cinfo->src;
10854 static JOCTET buffer[2];
10855
10856 buffer[0] = (JOCTET) 0xFF;
10857 buffer[1] = (JOCTET) JPEG_EOI;
10858
10859 src->next_input_byte = buffer;
10860 src->bytes_in_buffer = 2;
10861 return TRUE;
10862}
10863
10864
10865/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10866 is the JPEG data source manager. */
10867
10868static void
10869our_skip_input_data (cinfo, num_bytes)
10870 j_decompress_ptr cinfo;
10871 long num_bytes;
10872{
10873 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10874
10875 if (src)
10876 {
10877 if (num_bytes > src->bytes_in_buffer)
10878 ERREXIT (cinfo, JERR_INPUT_EOF);
10879
10880 src->bytes_in_buffer -= num_bytes;
10881 src->next_input_byte += num_bytes;
10882 }
10883}
10884
10885
10886/* Method to terminate data source. Called by
10887 jpeg_finish_decompress() after all data has been processed. */
10888
10889static void
10890our_term_source (cinfo)
10891 j_decompress_ptr cinfo;
10892{
10893}
10894
10895
10896/* Set up the JPEG lib for reading an image from DATA which contains
10897 LEN bytes. CINFO is the decompression info structure created for
10898 reading the image. */
10899
10900static void
10901jpeg_memory_src (cinfo, data, len)
10902 j_decompress_ptr cinfo;
10903 JOCTET *data;
10904 unsigned int len;
10905{
10906 struct jpeg_source_mgr *src;
10907
10908 if (cinfo->src == NULL)
10909 {
10910 /* First time for this JPEG object? */
10911 cinfo->src = (struct jpeg_source_mgr *)
10912 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10913 sizeof (struct jpeg_source_mgr));
10914 src = (struct jpeg_source_mgr *) cinfo->src;
10915 src->next_input_byte = data;
10916 }
10917
10918 src = (struct jpeg_source_mgr *) cinfo->src;
10919 src->init_source = our_init_source;
10920 src->fill_input_buffer = our_fill_input_buffer;
10921 src->skip_input_data = our_skip_input_data;
10922 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10923 src->term_source = our_term_source;
10924 src->bytes_in_buffer = len;
10925 src->next_input_byte = data;
10926}
10927
10928
10929/* Load image IMG for use on frame F. Patterned after example.c
10930 from the JPEG lib. */
10931
10932static int
10933jpeg_load (f, img)
10934 struct frame *f;
10935 struct image *img;
10936{
10937 struct jpeg_decompress_struct cinfo;
10938 struct my_jpeg_error_mgr mgr;
10939 Lisp_Object file, specified_file;
10940 Lisp_Object specified_data;
10941 FILE *fp = NULL;
10942 JSAMPARRAY buffer;
10943 int row_stride, x, y;
10944 XImage *ximg = NULL;
10945 int rc;
10946 unsigned long *colors;
10947 int width, height;
10948 struct gcpro gcpro1;
10949
10950 /* Open the JPEG file. */
10951 specified_file = image_spec_value (img->spec, QCfile, NULL);
10952 specified_data = image_spec_value (img->spec, QCdata, NULL);
10953 file = Qnil;
10954 GCPRO1 (file);
10955
6fc2811b
JR
10956 if (NILP (specified_data))
10957 {
10958 file = x_find_image_file (specified_file);
10959 if (!STRINGP (file))
10960 {
10961 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10962 UNGCPRO;
10963 return 0;
10964 }
10965
10966 fp = fopen (XSTRING (file)->data, "r");
10967 if (fp == NULL)
10968 {
10969 image_error ("Cannot open `%s'", file, Qnil);
10970 UNGCPRO;
10971 return 0;
10972 }
10973 }
10974
10975 /* Customize libjpeg's error handling to call my_error_exit when an
10976 error is detected. This function will perform a longjmp. */
10977 mgr.pub.error_exit = my_error_exit;
10978 cinfo.err = jpeg_std_error (&mgr.pub);
10979
10980 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10981 {
10982 if (rc == 1)
10983 {
10984 /* Called from my_error_exit. Display a JPEG error. */
10985 char buffer[JMSG_LENGTH_MAX];
10986 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10987 image_error ("Error reading JPEG image `%s': %s", img->spec,
10988 build_string (buffer));
10989 }
10990
10991 /* Close the input file and destroy the JPEG object. */
10992 if (fp)
10993 fclose (fp);
10994 jpeg_destroy_decompress (&cinfo);
10995
10996 BLOCK_INPUT;
10997
10998 /* If we already have an XImage, free that. */
10999 x_destroy_x_image (ximg);
11000
11001 /* Free pixmap and colors. */
11002 x_clear_image (f, img);
11003
11004 UNBLOCK_INPUT;
11005 UNGCPRO;
11006 return 0;
11007 }
11008
11009 /* Create the JPEG decompression object. Let it read from fp.
11010 Read the JPEG image header. */
11011 jpeg_create_decompress (&cinfo);
11012
11013 if (NILP (specified_data))
11014 jpeg_stdio_src (&cinfo, fp);
11015 else
11016 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
11017 STRING_BYTES (XSTRING (specified_data)));
11018
11019 jpeg_read_header (&cinfo, TRUE);
11020
11021 /* Customize decompression so that color quantization will be used.
11022 Start decompression. */
11023 cinfo.quantize_colors = TRUE;
11024 jpeg_start_decompress (&cinfo);
11025 width = img->width = cinfo.output_width;
11026 height = img->height = cinfo.output_height;
11027
11028 BLOCK_INPUT;
11029
11030 /* Create X image and pixmap. */
11031 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11032 &img->pixmap))
11033 {
11034 UNBLOCK_INPUT;
11035 longjmp (mgr.setjmp_buffer, 2);
11036 }
11037
11038 /* Allocate colors. When color quantization is used,
11039 cinfo.actual_number_of_colors has been set with the number of
11040 colors generated, and cinfo.colormap is a two-dimensional array
11041 of color indices in the range 0..cinfo.actual_number_of_colors.
11042 No more than 255 colors will be generated. */
11043 {
11044 int i, ir, ig, ib;
11045
11046 if (cinfo.out_color_components > 2)
11047 ir = 0, ig = 1, ib = 2;
11048 else if (cinfo.out_color_components > 1)
11049 ir = 0, ig = 1, ib = 0;
11050 else
11051 ir = 0, ig = 0, ib = 0;
11052
11053 /* Use the color table mechanism because it handles colors that
11054 cannot be allocated nicely. Such colors will be replaced with
11055 a default color, and we don't have to care about which colors
11056 can be freed safely, and which can't. */
11057 init_color_table ();
11058 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11059 * sizeof *colors);
11060
11061 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11062 {
11063 /* Multiply RGB values with 255 because X expects RGB values
11064 in the range 0..0xffff. */
11065 int r = cinfo.colormap[ir][i] << 8;
11066 int g = cinfo.colormap[ig][i] << 8;
11067 int b = cinfo.colormap[ib][i] << 8;
11068 colors[i] = lookup_rgb_color (f, r, g, b);
11069 }
11070
11071 /* Remember those colors actually allocated. */
11072 img->colors = colors_in_color_table (&img->ncolors);
11073 free_color_table ();
11074 }
11075
11076 /* Read pixels. */
11077 row_stride = width * cinfo.output_components;
11078 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11079 row_stride, 1);
11080 for (y = 0; y < height; ++y)
11081 {
11082 jpeg_read_scanlines (&cinfo, buffer, 1);
11083 for (x = 0; x < cinfo.output_width; ++x)
11084 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11085 }
11086
11087 /* Clean up. */
11088 jpeg_finish_decompress (&cinfo);
11089 jpeg_destroy_decompress (&cinfo);
11090 if (fp)
11091 fclose (fp);
11092
11093 /* Put the image into the pixmap. */
11094 x_put_x_image (f, ximg, img->pixmap, width, height);
11095 x_destroy_x_image (ximg);
11096 UNBLOCK_INPUT;
11097 UNGCPRO;
11098 return 1;
11099}
11100
11101#endif /* HAVE_JPEG */
11102
11103
11104\f
11105/***********************************************************************
11106 TIFF
11107 ***********************************************************************/
11108
11109#if HAVE_TIFF
11110
11111#include <tiffio.h>
11112
11113static int tiff_image_p P_ ((Lisp_Object object));
11114static int tiff_load P_ ((struct frame *f, struct image *img));
11115
11116/* The symbol `tiff' identifying images of this type. */
11117
11118Lisp_Object Qtiff;
11119
11120/* Indices of image specification fields in tiff_format, below. */
11121
11122enum tiff_keyword_index
11123{
11124 TIFF_TYPE,
11125 TIFF_DATA,
11126 TIFF_FILE,
11127 TIFF_ASCENT,
11128 TIFF_MARGIN,
11129 TIFF_RELIEF,
11130 TIFF_ALGORITHM,
11131 TIFF_HEURISTIC_MASK,
11132 TIFF_LAST
11133};
11134
11135/* Vector of image_keyword structures describing the format
11136 of valid user-defined image specifications. */
11137
11138static struct image_keyword tiff_format[TIFF_LAST] =
11139{
11140 {":type", IMAGE_SYMBOL_VALUE, 1},
11141 {":data", IMAGE_STRING_VALUE, 0},
11142 {":file", IMAGE_STRING_VALUE, 0},
11143 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11144 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11145 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11146 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
11147 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11148};
11149
11150/* Structure describing the image type `tiff'. */
11151
11152static struct image_type tiff_type =
11153{
11154 &Qtiff,
11155 tiff_image_p,
11156 tiff_load,
11157 x_clear_image,
11158 NULL
11159};
11160
11161
11162/* Return non-zero if OBJECT is a valid TIFF image specification. */
11163
11164static int
11165tiff_image_p (object)
11166 Lisp_Object object;
11167{
11168 struct image_keyword fmt[TIFF_LAST];
11169 bcopy (tiff_format, fmt, sizeof fmt);
11170
11171 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11172 || (fmt[TIFF_ASCENT].count
11173 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11174 return 0;
11175
11176 /* Must specify either the :data or :file keyword. */
11177 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11178}
11179
11180
11181/* Reading from a memory buffer for TIFF images Based on the PNG
11182 memory source, but we have to provide a lot of extra functions.
11183 Blah.
11184
11185 We really only need to implement read and seek, but I am not
11186 convinced that the TIFF library is smart enough not to destroy
11187 itself if we only hand it the function pointers we need to
11188 override. */
11189
11190typedef struct
11191{
11192 unsigned char *bytes;
11193 size_t len;
11194 int index;
11195}
11196tiff_memory_source;
11197
11198static size_t
11199tiff_read_from_memory (data, buf, size)
11200 thandle_t data;
11201 tdata_t buf;
11202 tsize_t size;
11203{
11204 tiff_memory_source *src = (tiff_memory_source *) data;
11205
11206 if (size > src->len - src->index)
11207 return (size_t) -1;
11208 bcopy (src->bytes + src->index, buf, size);
11209 src->index += size;
11210 return size;
11211}
11212
11213static size_t
11214tiff_write_from_memory (data, buf, size)
11215 thandle_t data;
11216 tdata_t buf;
11217 tsize_t size;
11218{
11219 return (size_t) -1;
11220}
11221
11222static toff_t
11223tiff_seek_in_memory (data, off, whence)
11224 thandle_t data;
11225 toff_t off;
11226 int whence;
11227{
11228 tiff_memory_source *src = (tiff_memory_source *) data;
11229 int idx;
11230
11231 switch (whence)
11232 {
11233 case SEEK_SET: /* Go from beginning of source. */
11234 idx = off;
11235 break;
11236
11237 case SEEK_END: /* Go from end of source. */
11238 idx = src->len + off;
11239 break;
11240
11241 case SEEK_CUR: /* Go from current position. */
11242 idx = src->index + off;
11243 break;
11244
11245 default: /* Invalid `whence'. */
11246 return -1;
11247 }
11248
11249 if (idx > src->len || idx < 0)
11250 return -1;
11251
11252 src->index = idx;
11253 return src->index;
11254}
11255
11256static int
11257tiff_close_memory (data)
11258 thandle_t data;
11259{
11260 /* NOOP */
11261 return 0;
11262}
11263
11264static int
11265tiff_mmap_memory (data, pbase, psize)
11266 thandle_t data;
11267 tdata_t *pbase;
11268 toff_t *psize;
11269{
11270 /* It is already _IN_ memory. */
11271 return 0;
11272}
11273
11274static void
11275tiff_unmap_memory (data, base, size)
11276 thandle_t data;
11277 tdata_t base;
11278 toff_t size;
11279{
11280 /* We don't need to do this. */
11281}
11282
11283static toff_t
11284tiff_size_of_memory (data)
11285 thandle_t data;
11286{
11287 return ((tiff_memory_source *) data)->len;
11288}
11289
6fc2811b
JR
11290/* Load TIFF image IMG for use on frame F. Value is non-zero if
11291 successful. */
11292
11293static int
11294tiff_load (f, img)
11295 struct frame *f;
11296 struct image *img;
11297{
11298 Lisp_Object file, specified_file;
11299 Lisp_Object specified_data;
11300 TIFF *tiff;
11301 int width, height, x, y;
11302 uint32 *buf;
11303 int rc;
11304 XImage *ximg;
11305 struct gcpro gcpro1;
11306 tiff_memory_source memsrc;
11307
11308 specified_file = image_spec_value (img->spec, QCfile, NULL);
11309 specified_data = image_spec_value (img->spec, QCdata, NULL);
11310 file = Qnil;
11311 GCPRO1 (file);
11312
11313 if (NILP (specified_data))
11314 {
11315 /* Read from a file */
11316 file = x_find_image_file (specified_file);
11317 if (!STRINGP (file))
11318 {
11319 image_error ("Cannot find image file `%s'", file, Qnil);
11320 UNGCPRO;
11321 return 0;
11322 }
11323
11324 /* Try to open the image file. */
11325 tiff = TIFFOpen (XSTRING (file)->data, "r");
11326 if (tiff == NULL)
11327 {
11328 image_error ("Cannot open `%s'", file, Qnil);
11329 UNGCPRO;
11330 return 0;
11331 }
11332 }
11333 else
11334 {
11335 /* Memory source! */
11336 memsrc.bytes = XSTRING (specified_data)->data;
11337 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11338 memsrc.index = 0;
11339
11340 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
11341 (TIFFReadWriteProc) tiff_read_from_memory,
11342 (TIFFReadWriteProc) tiff_write_from_memory,
11343 tiff_seek_in_memory,
11344 tiff_close_memory,
11345 tiff_size_of_memory,
11346 tiff_mmap_memory,
11347 tiff_unmap_memory);
11348
11349 if (!tiff)
11350 {
11351 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
11352 UNGCPRO;
11353 return 0;
11354 }
11355 }
11356
11357 /* Get width and height of the image, and allocate a raster buffer
11358 of width x height 32-bit values. */
11359 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11360 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
11361 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
11362
11363 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
11364 TIFFClose (tiff);
11365 if (!rc)
11366 {
11367 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11368 xfree (buf);
11369 UNGCPRO;
11370 return 0;
11371 }
11372
11373 BLOCK_INPUT;
11374
11375 /* Create the X image and pixmap. */
11376 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11377 {
11378 UNBLOCK_INPUT;
11379 xfree (buf);
11380 UNGCPRO;
11381 return 0;
11382 }
11383
11384 /* Initialize the color table. */
11385 init_color_table ();
11386
11387 /* Process the pixel raster. Origin is in the lower-left corner. */
11388 for (y = 0; y < height; ++y)
11389 {
11390 uint32 *row = buf + y * width;
11391
11392 for (x = 0; x < width; ++x)
11393 {
11394 uint32 abgr = row[x];
11395 int r = TIFFGetR (abgr) << 8;
11396 int g = TIFFGetG (abgr) << 8;
11397 int b = TIFFGetB (abgr) << 8;
11398 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11399 }
11400 }
11401
11402 /* Remember the colors allocated for the image. Free the color table. */
11403 img->colors = colors_in_color_table (&img->ncolors);
11404 free_color_table ();
11405
11406 /* Put the image into the pixmap, then free the X image and its buffer. */
11407 x_put_x_image (f, ximg, img->pixmap, width, height);
11408 x_destroy_x_image (ximg);
11409 xfree (buf);
11410 UNBLOCK_INPUT;
11411
11412 img->width = width;
11413 img->height = height;
11414
11415 UNGCPRO;
11416 return 1;
11417}
11418
11419#endif /* HAVE_TIFF != 0 */
11420
11421
11422\f
11423/***********************************************************************
11424 GIF
11425 ***********************************************************************/
11426
11427#if HAVE_GIF
11428
11429#include <gif_lib.h>
11430
11431static int gif_image_p P_ ((Lisp_Object object));
11432static int gif_load P_ ((struct frame *f, struct image *img));
11433
11434/* The symbol `gif' identifying images of this type. */
11435
11436Lisp_Object Qgif;
11437
11438/* Indices of image specification fields in gif_format, below. */
11439
11440enum gif_keyword_index
11441{
11442 GIF_TYPE,
11443 GIF_DATA,
11444 GIF_FILE,
11445 GIF_ASCENT,
11446 GIF_MARGIN,
11447 GIF_RELIEF,
11448 GIF_ALGORITHM,
11449 GIF_HEURISTIC_MASK,
11450 GIF_IMAGE,
11451 GIF_LAST
11452};
11453
11454/* Vector of image_keyword structures describing the format
11455 of valid user-defined image specifications. */
11456
11457static struct image_keyword gif_format[GIF_LAST] =
11458{
11459 {":type", IMAGE_SYMBOL_VALUE, 1},
11460 {":data", IMAGE_STRING_VALUE, 0},
11461 {":file", IMAGE_STRING_VALUE, 0},
11462 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11463 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11464 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11465 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
11466 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11467 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11468};
11469
11470/* Structure describing the image type `gif'. */
11471
11472static struct image_type gif_type =
11473{
11474 &Qgif,
11475 gif_image_p,
11476 gif_load,
11477 x_clear_image,
11478 NULL
11479};
11480
11481/* Return non-zero if OBJECT is a valid GIF image specification. */
11482
11483static int
11484gif_image_p (object)
11485 Lisp_Object object;
11486{
11487 struct image_keyword fmt[GIF_LAST];
11488 bcopy (gif_format, fmt, sizeof fmt);
11489
11490 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11491 || (fmt[GIF_ASCENT].count
11492 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11493 return 0;
11494
11495 /* Must specify either the :data or :file keyword. */
11496 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11497}
11498
11499/* Reading a GIF image from memory
11500 Based on the PNG memory stuff to a certain extent. */
11501
11502typedef struct
11503{
11504 unsigned char *bytes;
11505 size_t len;
11506 int index;
11507}
11508gif_memory_source;
11509
11510/* Make the current memory source available to gif_read_from_memory.
11511 It's done this way because not all versions of libungif support
11512 a UserData field in the GifFileType structure. */
11513static gif_memory_source *current_gif_memory_src;
11514
11515static int
11516gif_read_from_memory (file, buf, len)
11517 GifFileType *file;
11518 GifByteType *buf;
11519 int len;
11520{
11521 gif_memory_source *src = current_gif_memory_src;
11522
11523 if (len > src->len - src->index)
11524 return -1;
11525
11526 bcopy (src->bytes + src->index, buf, len);
11527 src->index += len;
11528 return len;
11529}
11530
11531
11532/* Load GIF image IMG for use on frame F. Value is non-zero if
11533 successful. */
11534
11535static int
11536gif_load (f, img)
11537 struct frame *f;
11538 struct image *img;
11539{
11540 Lisp_Object file, specified_file;
11541 Lisp_Object specified_data;
11542 int rc, width, height, x, y, i;
11543 XImage *ximg;
11544 ColorMapObject *gif_color_map;
11545 unsigned long pixel_colors[256];
11546 GifFileType *gif;
11547 struct gcpro gcpro1;
11548 Lisp_Object image;
11549 int ino, image_left, image_top, image_width, image_height;
11550 gif_memory_source memsrc;
11551 unsigned char *raster;
11552
11553 specified_file = image_spec_value (img->spec, QCfile, NULL);
11554 specified_data = image_spec_value (img->spec, QCdata, NULL);
11555 file = Qnil;
dfff8a69 11556 GCPRO1 (file);
6fc2811b
JR
11557
11558 if (NILP (specified_data))
11559 {
11560 file = x_find_image_file (specified_file);
6fc2811b
JR
11561 if (!STRINGP (file))
11562 {
11563 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11564 UNGCPRO;
11565 return 0;
11566 }
11567
11568 /* Open the GIF file. */
11569 gif = DGifOpenFileName (XSTRING (file)->data);
11570 if (gif == NULL)
11571 {
11572 image_error ("Cannot open `%s'", file, Qnil);
11573 UNGCPRO;
11574 return 0;
11575 }
11576 }
11577 else
11578 {
11579 /* Read from memory! */
11580 current_gif_memory_src = &memsrc;
11581 memsrc.bytes = XSTRING (specified_data)->data;
11582 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11583 memsrc.index = 0;
11584
11585 gif = DGifOpen(&memsrc, gif_read_from_memory);
11586 if (!gif)
11587 {
11588 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11589 UNGCPRO;
11590 return 0;
11591 }
11592 }
11593
11594 /* Read entire contents. */
11595 rc = DGifSlurp (gif);
11596 if (rc == GIF_ERROR)
11597 {
11598 image_error ("Error reading `%s'", img->spec, Qnil);
11599 DGifCloseFile (gif);
11600 UNGCPRO;
11601 return 0;
11602 }
11603
11604 image = image_spec_value (img->spec, QCindex, NULL);
11605 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11606 if (ino >= gif->ImageCount)
11607 {
11608 image_error ("Invalid image number `%s' in image `%s'",
11609 image, img->spec);
11610 DGifCloseFile (gif);
11611 UNGCPRO;
11612 return 0;
11613 }
11614
11615 width = img->width = gif->SWidth;
11616 height = img->height = gif->SHeight;
11617
11618 BLOCK_INPUT;
11619
11620 /* Create the X image and pixmap. */
11621 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11622 {
11623 UNBLOCK_INPUT;
11624 DGifCloseFile (gif);
11625 UNGCPRO;
11626 return 0;
11627 }
11628
11629 /* Allocate colors. */
11630 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11631 if (!gif_color_map)
11632 gif_color_map = gif->SColorMap;
11633 init_color_table ();
11634 bzero (pixel_colors, sizeof pixel_colors);
11635
11636 for (i = 0; i < gif_color_map->ColorCount; ++i)
11637 {
11638 int r = gif_color_map->Colors[i].Red << 8;
11639 int g = gif_color_map->Colors[i].Green << 8;
11640 int b = gif_color_map->Colors[i].Blue << 8;
11641 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11642 }
11643
11644 img->colors = colors_in_color_table (&img->ncolors);
11645 free_color_table ();
11646
11647 /* Clear the part of the screen image that are not covered by
11648 the image from the GIF file. Full animated GIF support
11649 requires more than can be done here (see the gif89 spec,
11650 disposal methods). Let's simply assume that the part
11651 not covered by a sub-image is in the frame's background color. */
11652 image_top = gif->SavedImages[ino].ImageDesc.Top;
11653 image_left = gif->SavedImages[ino].ImageDesc.Left;
11654 image_width = gif->SavedImages[ino].ImageDesc.Width;
11655 image_height = gif->SavedImages[ino].ImageDesc.Height;
11656
11657 for (y = 0; y < image_top; ++y)
11658 for (x = 0; x < width; ++x)
11659 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11660
11661 for (y = image_top + image_height; y < height; ++y)
11662 for (x = 0; x < width; ++x)
11663 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11664
11665 for (y = image_top; y < image_top + image_height; ++y)
11666 {
11667 for (x = 0; x < image_left; ++x)
11668 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11669 for (x = image_left + image_width; x < width; ++x)
11670 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11671 }
11672
11673 /* Read the GIF image into the X image. We use a local variable
11674 `raster' here because RasterBits below is a char *, and invites
11675 problems with bytes >= 0x80. */
11676 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11677
11678 if (gif->SavedImages[ino].ImageDesc.Interlace)
11679 {
11680 static int interlace_start[] = {0, 4, 2, 1};
11681 static int interlace_increment[] = {8, 8, 4, 2};
11682 int pass, inc;
11683 int row = interlace_start[0];
11684
11685 pass = 0;
11686
11687 for (y = 0; y < image_height; y++)
11688 {
11689 if (row >= image_height)
11690 {
11691 row = interlace_start[++pass];
11692 while (row >= image_height)
11693 row = interlace_start[++pass];
11694 }
11695
11696 for (x = 0; x < image_width; x++)
11697 {
11698 int i = raster[(y * image_width) + x];
11699 XPutPixel (ximg, x + image_left, row + image_top,
11700 pixel_colors[i]);
11701 }
11702
11703 row += interlace_increment[pass];
11704 }
11705 }
11706 else
11707 {
11708 for (y = 0; y < image_height; ++y)
11709 for (x = 0; x < image_width; ++x)
11710 {
11711 int i = raster[y* image_width + x];
11712 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11713 }
11714 }
11715
11716 DGifCloseFile (gif);
11717
11718 /* Put the image into the pixmap, then free the X image and its buffer. */
11719 x_put_x_image (f, ximg, img->pixmap, width, height);
11720 x_destroy_x_image (ximg);
11721 UNBLOCK_INPUT;
11722
11723 UNGCPRO;
11724 return 1;
11725}
11726
11727#endif /* HAVE_GIF != 0 */
11728
11729
11730\f
11731/***********************************************************************
11732 Ghostscript
11733 ***********************************************************************/
11734
11735#ifdef HAVE_GHOSTSCRIPT
11736static int gs_image_p P_ ((Lisp_Object object));
11737static int gs_load P_ ((struct frame *f, struct image *img));
11738static void gs_clear_image P_ ((struct frame *f, struct image *img));
11739
11740/* The symbol `postscript' identifying images of this type. */
11741
11742Lisp_Object Qpostscript;
11743
11744/* Keyword symbols. */
11745
11746Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11747
11748/* Indices of image specification fields in gs_format, below. */
11749
11750enum gs_keyword_index
11751{
11752 GS_TYPE,
11753 GS_PT_WIDTH,
11754 GS_PT_HEIGHT,
11755 GS_FILE,
11756 GS_LOADER,
11757 GS_BOUNDING_BOX,
11758 GS_ASCENT,
11759 GS_MARGIN,
11760 GS_RELIEF,
11761 GS_ALGORITHM,
11762 GS_HEURISTIC_MASK,
11763 GS_LAST
11764};
11765
11766/* Vector of image_keyword structures describing the format
11767 of valid user-defined image specifications. */
11768
11769static struct image_keyword gs_format[GS_LAST] =
11770{
11771 {":type", IMAGE_SYMBOL_VALUE, 1},
11772 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11773 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11774 {":file", IMAGE_STRING_VALUE, 1},
11775 {":loader", IMAGE_FUNCTION_VALUE, 0},
11776 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11777 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11778 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11779 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11780 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b
JR
11781 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11782};
11783
11784/* Structure describing the image type `ghostscript'. */
11785
11786static struct image_type gs_type =
11787{
11788 &Qpostscript,
11789 gs_image_p,
11790 gs_load,
11791 gs_clear_image,
11792 NULL
11793};
11794
11795
11796/* Free X resources of Ghostscript image IMG which is used on frame F. */
11797
11798static void
11799gs_clear_image (f, img)
11800 struct frame *f;
11801 struct image *img;
11802{
11803 /* IMG->data.ptr_val may contain a recorded colormap. */
11804 xfree (img->data.ptr_val);
11805 x_clear_image (f, img);
11806}
11807
11808
11809/* Return non-zero if OBJECT is a valid Ghostscript image
11810 specification. */
11811
11812static int
11813gs_image_p (object)
11814 Lisp_Object object;
11815{
11816 struct image_keyword fmt[GS_LAST];
11817 Lisp_Object tem;
11818 int i;
11819
11820 bcopy (gs_format, fmt, sizeof fmt);
11821
11822 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11823 || (fmt[GS_ASCENT].count
11824 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11825 return 0;
11826
11827 /* Bounding box must be a list or vector containing 4 integers. */
11828 tem = fmt[GS_BOUNDING_BOX].value;
11829 if (CONSP (tem))
11830 {
11831 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11832 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11833 return 0;
11834 if (!NILP (tem))
11835 return 0;
11836 }
11837 else if (VECTORP (tem))
11838 {
11839 if (XVECTOR (tem)->size != 4)
11840 return 0;
11841 for (i = 0; i < 4; ++i)
11842 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11843 return 0;
11844 }
11845 else
11846 return 0;
11847
11848 return 1;
11849}
11850
11851
11852/* Load Ghostscript image IMG for use on frame F. Value is non-zero
11853 if successful. */
11854
11855static int
11856gs_load (f, img)
11857 struct frame *f;
11858 struct image *img;
11859{
11860 char buffer[100];
11861 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11862 struct gcpro gcpro1, gcpro2;
11863 Lisp_Object frame;
11864 double in_width, in_height;
11865 Lisp_Object pixel_colors = Qnil;
11866
11867 /* Compute pixel size of pixmap needed from the given size in the
11868 image specification. Sizes in the specification are in pt. 1 pt
11869 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11870 info. */
11871 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11872 in_width = XFASTINT (pt_width) / 72.0;
11873 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11874 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11875 in_height = XFASTINT (pt_height) / 72.0;
11876 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11877
11878 /* Create the pixmap. */
11879 BLOCK_INPUT;
11880 xassert (img->pixmap == 0);
11881 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11882 img->width, img->height,
11883 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11884 UNBLOCK_INPUT;
11885
11886 if (!img->pixmap)
11887 {
11888 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11889 return 0;
11890 }
11891
11892 /* Call the loader to fill the pixmap. It returns a process object
11893 if successful. We do not record_unwind_protect here because
11894 other places in redisplay like calling window scroll functions
11895 don't either. Let the Lisp loader use `unwind-protect' instead. */
11896 GCPRO2 (window_and_pixmap_id, pixel_colors);
11897
11898 sprintf (buffer, "%lu %lu",
11899 (unsigned long) FRAME_W32_WINDOW (f),
11900 (unsigned long) img->pixmap);
11901 window_and_pixmap_id = build_string (buffer);
11902
11903 sprintf (buffer, "%lu %lu",
11904 FRAME_FOREGROUND_PIXEL (f),
11905 FRAME_BACKGROUND_PIXEL (f));
11906 pixel_colors = build_string (buffer);
11907
11908 XSETFRAME (frame, f);
11909 loader = image_spec_value (img->spec, QCloader, NULL);
11910 if (NILP (loader))
11911 loader = intern ("gs-load-image");
11912
11913 img->data.lisp_val = call6 (loader, frame, img->spec,
11914 make_number (img->width),
11915 make_number (img->height),
11916 window_and_pixmap_id,
11917 pixel_colors);
11918 UNGCPRO;
11919 return PROCESSP (img->data.lisp_val);
11920}
11921
11922
11923/* Kill the Ghostscript process that was started to fill PIXMAP on
11924 frame F. Called from XTread_socket when receiving an event
11925 telling Emacs that Ghostscript has finished drawing. */
11926
11927void
11928x_kill_gs_process (pixmap, f)
11929 Pixmap pixmap;
11930 struct frame *f;
11931{
11932 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11933 int class, i;
11934 struct image *img;
11935
11936 /* Find the image containing PIXMAP. */
11937 for (i = 0; i < c->used; ++i)
11938 if (c->images[i]->pixmap == pixmap)
11939 break;
11940
11941 /* Kill the GS process. We should have found PIXMAP in the image
11942 cache and its image should contain a process object. */
11943 xassert (i < c->used);
11944 img = c->images[i];
11945 xassert (PROCESSP (img->data.lisp_val));
11946 Fkill_process (img->data.lisp_val, Qnil);
11947 img->data.lisp_val = Qnil;
11948
11949 /* On displays with a mutable colormap, figure out the colors
11950 allocated for the image by looking at the pixels of an XImage for
11951 img->pixmap. */
11952 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11953 if (class != StaticColor && class != StaticGray && class != TrueColor)
11954 {
11955 XImage *ximg;
11956
11957 BLOCK_INPUT;
11958
11959 /* Try to get an XImage for img->pixmep. */
11960 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11961 0, 0, img->width, img->height, ~0, ZPixmap);
11962 if (ximg)
11963 {
11964 int x, y;
11965
11966 /* Initialize the color table. */
11967 init_color_table ();
11968
11969 /* For each pixel of the image, look its color up in the
11970 color table. After having done so, the color table will
11971 contain an entry for each color used by the image. */
11972 for (y = 0; y < img->height; ++y)
11973 for (x = 0; x < img->width; ++x)
11974 {
11975 unsigned long pixel = XGetPixel (ximg, x, y);
11976 lookup_pixel_color (f, pixel);
11977 }
11978
11979 /* Record colors in the image. Free color table and XImage. */
11980 img->colors = colors_in_color_table (&img->ncolors);
11981 free_color_table ();
11982 XDestroyImage (ximg);
11983
11984#if 0 /* This doesn't seem to be the case. If we free the colors
11985 here, we get a BadAccess later in x_clear_image when
11986 freeing the colors. */
11987 /* We have allocated colors once, but Ghostscript has also
11988 allocated colors on behalf of us. So, to get the
11989 reference counts right, free them once. */
11990 if (img->ncolors)
11991 {
11992 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11993 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11994 img->colors, img->ncolors, 0);
11995 }
11996#endif
11997 }
11998 else
11999 image_error ("Cannot get X image of `%s'; colors will not be freed",
12000 img->spec, Qnil);
12001
12002 UNBLOCK_INPUT;
12003 }
12004}
12005
12006#endif /* HAVE_GHOSTSCRIPT */
12007
12008\f
12009/***********************************************************************
12010 Window properties
12011 ***********************************************************************/
12012
12013DEFUN ("x-change-window-property", Fx_change_window_property,
12014 Sx_change_window_property, 2, 3, 0,
12015 "Change window property PROP to VALUE on the X window of FRAME.\n\
12016PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
12017selected frame. Value is VALUE.")
12018 (prop, value, frame)
12019 Lisp_Object frame, prop, value;
12020{
767b1ff0 12021#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12022 struct frame *f = check_x_frame (frame);
12023 Atom prop_atom;
12024
12025 CHECK_STRING (prop, 1);
12026 CHECK_STRING (value, 2);
12027
12028 BLOCK_INPUT;
12029 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12030 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12031 prop_atom, XA_STRING, 8, PropModeReplace,
12032 XSTRING (value)->data, XSTRING (value)->size);
12033
12034 /* Make sure the property is set when we return. */
12035 XFlush (FRAME_W32_DISPLAY (f));
12036 UNBLOCK_INPUT;
12037
767b1ff0 12038#endif /* TODO */
6fc2811b
JR
12039
12040 return value;
12041}
12042
12043
12044DEFUN ("x-delete-window-property", Fx_delete_window_property,
12045 Sx_delete_window_property, 1, 2, 0,
12046 "Remove window property PROP from X window of FRAME.\n\
12047FRAME nil or omitted means use the selected frame. Value is PROP.")
12048 (prop, frame)
12049 Lisp_Object prop, frame;
12050{
767b1ff0 12051#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12052
12053 struct frame *f = check_x_frame (frame);
12054 Atom prop_atom;
12055
12056 CHECK_STRING (prop, 1);
12057 BLOCK_INPUT;
12058 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12059 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12060
12061 /* Make sure the property is removed when we return. */
12062 XFlush (FRAME_W32_DISPLAY (f));
12063 UNBLOCK_INPUT;
767b1ff0 12064#endif /* TODO */
6fc2811b
JR
12065
12066 return prop;
12067}
12068
12069
12070DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12071 1, 2, 0,
12072 "Value is the value of window property PROP on FRAME.\n\
12073If FRAME is nil or omitted, use the selected frame. Value is nil\n\
12074if FRAME hasn't a property with name PROP or if PROP has no string\n\
12075value.")
12076 (prop, frame)
12077 Lisp_Object prop, frame;
12078{
767b1ff0 12079#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
12080
12081 struct frame *f = check_x_frame (frame);
12082 Atom prop_atom;
12083 int rc;
12084 Lisp_Object prop_value = Qnil;
12085 char *tmp_data = NULL;
12086 Atom actual_type;
12087 int actual_format;
12088 unsigned long actual_size, bytes_remaining;
12089
12090 CHECK_STRING (prop, 1);
12091 BLOCK_INPUT;
12092 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12093 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12094 prop_atom, 0, 0, False, XA_STRING,
12095 &actual_type, &actual_format, &actual_size,
12096 &bytes_remaining, (unsigned char **) &tmp_data);
12097 if (rc == Success)
12098 {
12099 int size = bytes_remaining;
12100
12101 XFree (tmp_data);
12102 tmp_data = NULL;
12103
12104 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12105 prop_atom, 0, bytes_remaining,
12106 False, XA_STRING,
12107 &actual_type, &actual_format,
12108 &actual_size, &bytes_remaining,
12109 (unsigned char **) &tmp_data);
12110 if (rc == Success)
12111 prop_value = make_string (tmp_data, size);
12112
12113 XFree (tmp_data);
12114 }
12115
12116 UNBLOCK_INPUT;
12117
12118 return prop_value;
12119
767b1ff0 12120#endif /* TODO */
6fc2811b
JR
12121 return Qnil;
12122}
12123
12124
12125\f
12126/***********************************************************************
12127 Busy cursor
12128 ***********************************************************************/
12129
f79e6790
JR
12130/* If non-null, an asynchronous timer that, when it expires, displays
12131 a busy cursor on all frames. */
6fc2811b 12132
f79e6790 12133static struct atimer *busy_cursor_atimer;
6fc2811b 12134
f79e6790 12135/* Non-zero means a busy cursor is currently shown. */
6fc2811b 12136
f79e6790 12137static int busy_cursor_shown_p;
6fc2811b 12138
f79e6790 12139/* Number of seconds to wait before displaying a busy cursor. */
6fc2811b 12140
f79e6790 12141static Lisp_Object Vbusy_cursor_delay;
6fc2811b 12142
f79e6790
JR
12143/* Default number of seconds to wait before displaying a busy
12144 cursor. */
12145
12146#define DEFAULT_BUSY_CURSOR_DELAY 1
12147
12148/* Function prototypes. */
12149
12150static void show_busy_cursor P_ ((struct atimer *));
12151static void hide_busy_cursor P_ ((void));
12152
12153
12154/* Cancel a currently active busy-cursor timer, and start a new one. */
12155
12156void
12157start_busy_cursor ()
12158{
767b1ff0 12159#if 0 /* TODO: cursor shape changes. */
f79e6790 12160 EMACS_TIME delay;
dfff8a69 12161 int secs, usecs = 0;
f79e6790
JR
12162
12163 cancel_busy_cursor ();
12164
12165 if (INTEGERP (Vbusy_cursor_delay)
12166 && XINT (Vbusy_cursor_delay) > 0)
12167 secs = XFASTINT (Vbusy_cursor_delay);
dfff8a69
JR
12168 else if (FLOATP (Vbusy_cursor_delay)
12169 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
12170 {
12171 Lisp_Object tem;
12172 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
12173 secs = XFASTINT (tem);
12174 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
12175 }
f79e6790
JR
12176 else
12177 secs = DEFAULT_BUSY_CURSOR_DELAY;
12178
dfff8a69 12179 EMACS_SET_SECS_USECS (delay, secs, usecs);
f79e6790
JR
12180 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
12181 show_busy_cursor, NULL);
12182#endif
12183}
12184
12185
12186/* Cancel the busy cursor timer if active, hide a busy cursor if
12187 shown. */
12188
12189void
12190cancel_busy_cursor ()
12191{
12192 if (busy_cursor_atimer)
dfff8a69
JR
12193 {
12194 cancel_atimer (busy_cursor_atimer);
12195 busy_cursor_atimer = NULL;
12196 }
12197
f79e6790
JR
12198 if (busy_cursor_shown_p)
12199 hide_busy_cursor ();
12200}
12201
12202
12203/* Timer function of busy_cursor_atimer. TIMER is equal to
12204 busy_cursor_atimer.
12205
12206 Display a busy cursor on all frames by mapping the frames'
12207 busy_window. Set the busy_p flag in the frames' output_data.x
12208 structure to indicate that a busy cursor is shown on the
12209 frames. */
12210
12211static void
12212show_busy_cursor (timer)
12213 struct atimer *timer;
6fc2811b 12214{
767b1ff0 12215#if 0 /* TODO: cursor shape changes. */
f79e6790
JR
12216 /* The timer implementation will cancel this timer automatically
12217 after this function has run. Set busy_cursor_atimer to null
12218 so that we know the timer doesn't have to be canceled. */
12219 busy_cursor_atimer = NULL;
12220
12221 if (!busy_cursor_shown_p)
6fc2811b
JR
12222 {
12223 Lisp_Object rest, frame;
f79e6790
JR
12224
12225 BLOCK_INPUT;
12226
6fc2811b 12227 FOR_EACH_FRAME (rest, frame)
dc220243 12228 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
12229 {
12230 struct frame *f = XFRAME (frame);
f79e6790 12231
6fc2811b 12232 f->output_data.w32->busy_p = 1;
f79e6790 12233
6fc2811b
JR
12234 if (!f->output_data.w32->busy_window)
12235 {
12236 unsigned long mask = CWCursor;
12237 XSetWindowAttributes attrs;
f79e6790 12238
6fc2811b 12239 attrs.cursor = f->output_data.w32->busy_cursor;
f79e6790 12240
6fc2811b 12241 f->output_data.w32->busy_window
f79e6790 12242 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
12243 FRAME_OUTER_WINDOW (f),
12244 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
12245 InputOnly,
12246 CopyFromParent,
6fc2811b
JR
12247 mask, &attrs);
12248 }
f79e6790
JR
12249
12250 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
12251 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 12252 }
6fc2811b 12253
f79e6790
JR
12254 busy_cursor_shown_p = 1;
12255 UNBLOCK_INPUT;
12256 }
12257#endif
6fc2811b
JR
12258}
12259
12260
f79e6790 12261/* Hide the busy cursor on all frames, if it is currently shown. */
6fc2811b 12262
f79e6790
JR
12263static void
12264hide_busy_cursor ()
12265{
767b1ff0 12266#if 0 /* TODO: cursor shape changes. */
f79e6790 12267 if (busy_cursor_shown_p)
6fc2811b 12268 {
f79e6790
JR
12269 Lisp_Object rest, frame;
12270
12271 BLOCK_INPUT;
12272 FOR_EACH_FRAME (rest, frame)
6fc2811b 12273 {
f79e6790
JR
12274 struct frame *f = XFRAME (frame);
12275
dc220243 12276 if (FRAME_W32_P (f)
f79e6790
JR
12277 /* Watch out for newly created frames. */
12278 && f->output_data.x->busy_window)
12279 {
12280 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
12281 /* Sync here because XTread_socket looks at the busy_p flag
12282 that is reset to zero below. */
12283 XSync (FRAME_X_DISPLAY (f), False);
12284 f->output_data.x->busy_p = 0;
12285 }
6fc2811b 12286 }
6fc2811b 12287
f79e6790
JR
12288 busy_cursor_shown_p = 0;
12289 UNBLOCK_INPUT;
12290 }
12291#endif
6fc2811b
JR
12292}
12293
12294
12295\f
12296/***********************************************************************
12297 Tool tips
12298 ***********************************************************************/
12299
12300static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
12301 Lisp_Object));
12302
12303/* The frame of a currently visible tooltip, or null. */
12304
937e601e 12305Lisp_Object tip_frame;
6fc2811b
JR
12306
12307/* If non-nil, a timer started that hides the last tooltip when it
12308 fires. */
12309
12310Lisp_Object tip_timer;
12311Window tip_window;
12312
937e601e
AI
12313static Lisp_Object
12314unwind_create_tip_frame (frame)
12315 Lisp_Object frame;
12316{
c844a81a
GM
12317 Lisp_Object deleted;
12318
12319 deleted = unwind_create_frame (frame);
12320 if (EQ (deleted, Qt))
12321 {
12322 tip_window = NULL;
12323 tip_frame = Qnil;
12324 }
12325
12326 return deleted;
937e601e
AI
12327}
12328
12329
6fc2811b 12330/* Create a frame for a tooltip on the display described by DPYINFO.
937e601e
AI
12331 PARMS is a list of frame parameters. Value is the frame.
12332
12333 Note that functions called here, esp. x_default_parameter can
12334 signal errors, for instance when a specified color name is
12335 undefined. We have to make sure that we're in a consistent state
12336 when this happens. */
6fc2811b
JR
12337
12338static Lisp_Object
12339x_create_tip_frame (dpyinfo, parms)
12340 struct w32_display_info *dpyinfo;
12341 Lisp_Object parms;
12342{
767b1ff0 12343#if 0 /* TODO : w32 version */
6fc2811b
JR
12344 struct frame *f;
12345 Lisp_Object frame, tem;
12346 Lisp_Object name;
12347 long window_prompting = 0;
12348 int width, height;
dc220243 12349 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
12350 struct gcpro gcpro1, gcpro2, gcpro3;
12351 struct kboard *kb;
12352
12353 check_x ();
12354
12355 /* Use this general default value to start with until we know if
12356 this frame has a specified name. */
12357 Vx_resource_name = Vinvocation_name;
12358
12359#ifdef MULTI_KBOARD
12360 kb = dpyinfo->kboard;
12361#else
12362 kb = &the_only_kboard;
12363#endif
12364
12365 /* Get the name of the frame to use for resource lookup. */
12366 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
12367 if (!STRINGP (name)
12368 && !EQ (name, Qunbound)
12369 && !NILP (name))
12370 error ("Invalid frame name--not a string or nil");
12371 Vx_resource_name = name;
12372
12373 frame = Qnil;
12374 GCPRO3 (parms, name, frame);
937e601e 12375 f = make_frame (1);
6fc2811b
JR
12376 XSETFRAME (frame, f);
12377 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 12378 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 12379
d88c567c 12380 f->output_method = output_w32;
6fc2811b
JR
12381 f->output_data.w32 =
12382 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12383 bzero (f->output_data.w32, sizeof (struct w32_output));
12384#if 0
12385 f->output_data.w32->icon_bitmap = -1;
12386#endif
12387 f->output_data.w32->fontset = -1;
12388 f->icon_name = Qnil;
12389
937e601e
AI
12390#ifdef GLYPH_DEBUG
12391 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
12392 dpyinfo_refcount = dpyinfo->reference_count;
12393#endif /* GLYPH_DEBUG */
6fc2811b
JR
12394#ifdef MULTI_KBOARD
12395 FRAME_KBOARD (f) = kb;
12396#endif
12397 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12398 f->output_data.w32->explicit_parent = 0;
12399
12400 /* Set the name; the functions to which we pass f expect the name to
12401 be set. */
12402 if (EQ (name, Qunbound) || NILP (name))
12403 {
12404 f->name = build_string (dpyinfo->x_id_name);
12405 f->explicit_name = 0;
12406 }
12407 else
12408 {
12409 f->name = name;
12410 f->explicit_name = 1;
12411 /* use the frame's title when getting resources for this frame. */
12412 specbind (Qx_resource_name, name);
12413 }
12414
6fc2811b
JR
12415 /* Extract the window parameters from the supplied values
12416 that are needed to determine window geometry. */
12417 {
12418 Lisp_Object font;
12419
12420 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12421
12422 BLOCK_INPUT;
12423 /* First, try whatever font the caller has specified. */
12424 if (STRINGP (font))
12425 {
12426 tem = Fquery_fontset (font, Qnil);
12427 if (STRINGP (tem))
12428 font = x_new_fontset (f, XSTRING (tem)->data);
12429 else
12430 font = x_new_font (f, XSTRING (font)->data);
12431 }
12432
12433 /* Try out a font which we hope has bold and italic variations. */
12434 if (!STRINGP (font))
e39649be 12435 font = x_new_font (f, "-*-courier new-normal-r-*-*-*-100-*-*-*-*-iso8859-1");
6fc2811b
JR
12436 if (!STRINGP (font))
12437 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12438 if (! STRINGP (font))
12439 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12440 if (! STRINGP (font))
12441 /* This was formerly the first thing tried, but it finds too many fonts
12442 and takes too long. */
12443 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12444 /* If those didn't work, look for something which will at least work. */
12445 if (! STRINGP (font))
12446 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12447 UNBLOCK_INPUT;
12448 if (! STRINGP (font))
12449 font = build_string ("fixed");
12450
12451 x_default_parameter (f, parms, Qfont, font,
12452 "font", "Font", RES_TYPE_STRING);
12453 }
12454
12455 x_default_parameter (f, parms, Qborder_width, make_number (2),
12456 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12457
12458 /* This defaults to 2 in order to match xterm. We recognize either
12459 internalBorderWidth or internalBorder (which is what xterm calls
12460 it). */
12461 if (NILP (Fassq (Qinternal_border_width, parms)))
12462 {
12463 Lisp_Object value;
12464
12465 value = w32_get_arg (parms, Qinternal_border_width,
12466 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12467 if (! EQ (value, Qunbound))
12468 parms = Fcons (Fcons (Qinternal_border_width, value),
12469 parms);
12470 }
12471
12472 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12473 "internalBorderWidth", "internalBorderWidth",
12474 RES_TYPE_NUMBER);
12475
12476 /* Also do the stuff which must be set before the window exists. */
12477 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12478 "foreground", "Foreground", RES_TYPE_STRING);
12479 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12480 "background", "Background", RES_TYPE_STRING);
12481 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12482 "pointerColor", "Foreground", RES_TYPE_STRING);
12483 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12484 "cursorColor", "Foreground", RES_TYPE_STRING);
12485 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12486 "borderColor", "BorderColor", RES_TYPE_STRING);
12487
12488 /* Init faces before x_default_parameter is called for scroll-bar
12489 parameters because that function calls x_set_scroll_bar_width,
12490 which calls change_frame_size, which calls Fset_window_buffer,
12491 which runs hooks, which call Fvertical_motion. At the end, we
12492 end up in init_iterator with a null face cache, which should not
12493 happen. */
12494 init_frame_faces (f);
12495
12496 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12497 window_prompting = x_figure_window_size (f, parms);
12498
12499 if (window_prompting & XNegative)
12500 {
12501 if (window_prompting & YNegative)
12502 f->output_data.w32->win_gravity = SouthEastGravity;
12503 else
12504 f->output_data.w32->win_gravity = NorthEastGravity;
12505 }
12506 else
12507 {
12508 if (window_prompting & YNegative)
12509 f->output_data.w32->win_gravity = SouthWestGravity;
12510 else
12511 f->output_data.w32->win_gravity = NorthWestGravity;
12512 }
12513
12514 f->output_data.w32->size_hint_flags = window_prompting;
12515 {
12516 XSetWindowAttributes attrs;
12517 unsigned long mask;
12518
12519 BLOCK_INPUT;
12520 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12521 /* Window managers looks at the override-redirect flag to
12522 determine whether or net to give windows a decoration (Xlib
12523 3.2.8). */
12524 attrs.override_redirect = True;
12525 attrs.save_under = True;
12526 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12527 /* Arrange for getting MapNotify and UnmapNotify events. */
12528 attrs.event_mask = StructureNotifyMask;
12529 tip_window
12530 = FRAME_W32_WINDOW (f)
12531 = XCreateWindow (FRAME_W32_DISPLAY (f),
12532 FRAME_W32_DISPLAY_INFO (f)->root_window,
12533 /* x, y, width, height */
12534 0, 0, 1, 1,
12535 /* Border. */
12536 1,
12537 CopyFromParent, InputOutput, CopyFromParent,
12538 mask, &attrs);
12539 UNBLOCK_INPUT;
12540 }
12541
12542 x_make_gc (f);
12543
12544 x_default_parameter (f, parms, Qauto_raise, Qnil,
12545 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12546 x_default_parameter (f, parms, Qauto_lower, Qnil,
12547 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12548 x_default_parameter (f, parms, Qcursor_type, Qbox,
12549 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12550
12551 /* Dimensions, especially f->height, must be done via change_frame_size.
12552 Change will not be effected unless different from the current
12553 f->height. */
12554 width = f->width;
12555 height = f->height;
12556 f->height = 0;
12557 SET_FRAME_WIDTH (f, 0);
12558 change_frame_size (f, height, width, 1, 0, 0);
12559
12560 f->no_split = 1;
12561
12562 UNGCPRO;
12563
12564 /* It is now ok to make the frame official even if we get an error
12565 below. And the frame needs to be on Vframe_list or making it
12566 visible won't work. */
12567 Vframe_list = Fcons (frame, Vframe_list);
937e601e 12568 tip_frame = frame;
6fc2811b
JR
12569
12570 /* Now that the frame is official, it counts as a reference to
12571 its display. */
12572 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 12573
6fc2811b 12574 return unbind_to (count, frame);
767b1ff0 12575#endif /* TODO */
6fc2811b 12576 return Qnil;
ee78dc32
GV
12577}
12578
767b1ff0 12579#ifdef TODO /* Tooltip support not complete. */
71eab8d1 12580DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
6fc2811b 12581 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
dc220243 12582A tooltip window is a small window displaying a string.\n\
71eab8d1 12583\n\
6fc2811b 12584FRAME nil or omitted means use the selected frame.\n\
71eab8d1 12585\n\
6fc2811b
JR
12586PARMS is an optional list of frame parameters which can be\n\
12587used to change the tooltip's appearance.\n\
71eab8d1 12588\n\
6fc2811b 12589Automatically hide the tooltip after TIMEOUT seconds.\n\
71eab8d1
AI
12590TIMEOUT nil means use the default timeout of 5 seconds.\n\
12591\n\
12592If the list of frame parameters PARAMS contains a `left' parameters,\n\
12593the tooltip is displayed at that x-position. Otherwise it is\n\
12594displayed at the mouse position, with offset DX added (default is 5 if\n\
12595DX isn't specified). Likewise for the y-position; if a `top' frame\n\
12596parameter is specified, it determines the y-position of the tooltip\n\
12597window, otherwise it is displayed at the mouse position, with offset\n\
dc220243 12598DY added (default is 10).")
71eab8d1
AI
12599 (string, frame, parms, timeout, dx, dy)
12600 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 12601{
6fc2811b
JR
12602 struct frame *f;
12603 struct window *w;
12604 Window root, child;
71eab8d1 12605 Lisp_Object buffer, top, left;
6fc2811b
JR
12606 struct buffer *old_buffer;
12607 struct text_pos pos;
12608 int i, width, height;
12609 int root_x, root_y, win_x, win_y;
12610 unsigned pmask;
12611 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12612 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12613 int count = specpdl_ptr - specpdl;
12614
12615 specbind (Qinhibit_redisplay, Qt);
ee78dc32 12616
dfff8a69 12617 GCPRO4 (string, parms, frame, timeout);
ee78dc32 12618
6fc2811b
JR
12619 CHECK_STRING (string, 0);
12620 f = check_x_frame (frame);
12621 if (NILP (timeout))
12622 timeout = make_number (5);
12623 else
12624 CHECK_NATNUM (timeout, 2);
ee78dc32 12625
71eab8d1
AI
12626 if (NILP (dx))
12627 dx = make_number (5);
12628 else
12629 CHECK_NUMBER (dx, 5);
12630
12631 if (NILP (dy))
dc220243 12632 dy = make_number (-10);
71eab8d1
AI
12633 else
12634 CHECK_NUMBER (dy, 6);
12635
dc220243
JR
12636 if (NILP (last_show_tip_args))
12637 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
12638
12639 if (!NILP (tip_frame))
12640 {
12641 Lisp_Object last_string = AREF (last_show_tip_args, 0);
12642 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
12643 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
12644
12645 if (EQ (frame, last_frame)
12646 && !NILP (Fequal (last_string, string))
12647 && !NILP (Fequal (last_parms, parms)))
12648 {
12649 struct frame *f = XFRAME (tip_frame);
12650
12651 /* Only DX and DY have changed. */
12652 if (!NILP (tip_timer))
12653 {
12654 Lisp_Object timer = tip_timer;
12655 tip_timer = Qnil;
12656 call1 (Qcancel_timer, timer);
12657 }
12658
12659 BLOCK_INPUT;
12660 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
12661 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12662 root_x, root_y - PIXEL_HEIGHT (f));
12663 UNBLOCK_INPUT;
12664 goto start_timer;
12665 }
12666 }
12667
6fc2811b
JR
12668 /* Hide a previous tip, if any. */
12669 Fx_hide_tip ();
ee78dc32 12670
dc220243
JR
12671 ASET (last_show_tip_args, 0, string);
12672 ASET (last_show_tip_args, 1, frame);
12673 ASET (last_show_tip_args, 2, parms);
12674
6fc2811b
JR
12675 /* Add default values to frame parameters. */
12676 if (NILP (Fassq (Qname, parms)))
12677 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12678 if (NILP (Fassq (Qinternal_border_width, parms)))
12679 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12680 if (NILP (Fassq (Qborder_width, parms)))
12681 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12682 if (NILP (Fassq (Qborder_color, parms)))
12683 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12684 if (NILP (Fassq (Qbackground_color, parms)))
12685 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12686 parms);
12687
12688 /* Create a frame for the tooltip, and record it in the global
12689 variable tip_frame. */
12690 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
937e601e 12691 f = XFRAME (frame);
6fc2811b
JR
12692
12693 /* Set up the frame's root window. Currently we use a size of 80
12694 columns x 40 lines. If someone wants to show a larger tip, he
12695 will loose. I don't think this is a realistic case. */
12696 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12697 w->left = w->top = make_number (0);
dc220243
JR
12698 w->width = make_number (80);
12699 w->height = make_number (40);
6fc2811b
JR
12700 adjust_glyphs (f);
12701 w->pseudo_window_p = 1;
12702
12703 /* Display the tooltip text in a temporary buffer. */
12704 buffer = Fget_buffer_create (build_string (" *tip*"));
12705 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12706 old_buffer = current_buffer;
12707 set_buffer_internal_1 (XBUFFER (buffer));
12708 Ferase_buffer ();
dc220243 12709 Finsert (1, &string);
6fc2811b
JR
12710 clear_glyph_matrix (w->desired_matrix);
12711 clear_glyph_matrix (w->current_matrix);
12712 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12713 try_window (FRAME_ROOT_WINDOW (f), pos);
12714
12715 /* Compute width and height of the tooltip. */
12716 width = height = 0;
12717 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 12718 {
6fc2811b
JR
12719 struct glyph_row *row = &w->desired_matrix->rows[i];
12720 struct glyph *last;
12721 int row_width;
12722
12723 /* Stop at the first empty row at the end. */
12724 if (!row->enabled_p || !row->displays_text_p)
12725 break;
12726
12727 /* Let the row go over the full width of the frame. */
12728 row->full_width_p = 1;
12729
12730 /* There's a glyph at the end of rows that is use to place
12731 the cursor there. Don't include the width of this glyph. */
12732 if (row->used[TEXT_AREA])
12733 {
12734 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12735 row_width = row->pixel_width - last->pixel_width;
12736 }
12737 else
12738 row_width = row->pixel_width;
12739
12740 height += row->height;
12741 width = max (width, row_width);
ee78dc32
GV
12742 }
12743
6fc2811b
JR
12744 /* Add the frame's internal border to the width and height the X
12745 window should have. */
12746 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12747 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 12748
6fc2811b
JR
12749 /* Move the tooltip window where the mouse pointer is. Resize and
12750 show it. */
dc220243 12751 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
71eab8d1 12752
dc220243 12753#if 0 /* TODO : W32 specifics */
71eab8d1
AI
12754 BLOCK_INPUT;
12755 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12756 root_x, root_y - height, width, height);
12757 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
6fc2811b 12758 UNBLOCK_INPUT;
767b1ff0 12759#endif /* TODO */
ee78dc32 12760
6fc2811b
JR
12761 /* Draw into the window. */
12762 w->must_be_updated_p = 1;
12763 update_single_window (w, 1);
ee78dc32 12764
6fc2811b
JR
12765 /* Restore original current buffer. */
12766 set_buffer_internal_1 (old_buffer);
12767 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 12768
dc220243 12769 start_timer:
6fc2811b
JR
12770 /* Let the tip disappear after timeout seconds. */
12771 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12772 intern ("x-hide-tip"));
ee78dc32 12773
dfff8a69 12774 UNGCPRO;
6fc2811b 12775 return unbind_to (count, Qnil);
ee78dc32
GV
12776}
12777
ee78dc32 12778
6fc2811b
JR
12779DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12780 "Hide the current tooltip window, if there is any.\n\
12781Value is t is tooltip was open, nil otherwise.")
12782 ()
12783{
937e601e
AI
12784 int count;
12785 Lisp_Object deleted, frame, timer;
12786 struct gcpro gcpro1, gcpro2;
12787
12788 /* Return quickly if nothing to do. */
12789 if (NILP (tip_timer) && NILP (tip_frame))
12790 return Qnil;
12791
12792 frame = tip_frame;
12793 timer = tip_timer;
12794 GCPRO2 (frame, timer);
12795 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 12796
937e601e 12797 count = BINDING_STACK_SIZE ();
6fc2811b 12798 specbind (Qinhibit_redisplay, Qt);
937e601e 12799 specbind (Qinhibit_quit, Qt);
6fc2811b 12800
937e601e 12801 if (!NILP (timer))
dc220243 12802 call1 (Qcancel_timer, timer);
ee78dc32 12803
937e601e 12804 if (FRAMEP (frame))
6fc2811b 12805 {
937e601e
AI
12806 Fdelete_frame (frame, Qnil);
12807 deleted = Qt;
6fc2811b 12808 }
1edf84e7 12809
937e601e
AI
12810 UNGCPRO;
12811 return unbind_to (count, deleted);
6fc2811b 12812}
767b1ff0 12813#endif
5ac45f98 12814
5ac45f98 12815
6fc2811b
JR
12816\f
12817/***********************************************************************
12818 File selection dialog
12819 ***********************************************************************/
12820
12821extern Lisp_Object Qfile_name_history;
12822
12823DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12824 "Read file name, prompting with PROMPT in directory DIR.\n\
12825Use a file selection dialog.\n\
12826Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12827specified. Don't let the user enter a file name in the file\n\
12828selection dialog's entry field, if MUSTMATCH is non-nil.")
12829 (prompt, dir, default_filename, mustmatch)
12830 Lisp_Object prompt, dir, default_filename, mustmatch;
12831{
12832 struct frame *f = SELECTED_FRAME ();
12833 Lisp_Object file = Qnil;
12834 int count = specpdl_ptr - specpdl;
12835 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12836 char filename[MAX_PATH + 1];
12837 char init_dir[MAX_PATH + 1];
12838 int use_dialog_p = 1;
12839
12840 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12841 CHECK_STRING (prompt, 0);
12842 CHECK_STRING (dir, 1);
12843
12844 /* Create the dialog with PROMPT as title, using DIR as initial
12845 directory and using "*" as pattern. */
12846 dir = Fexpand_file_name (dir, Qnil);
12847 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12848 init_dir[MAX_PATH] = '\0';
12849 unixtodos_filename (init_dir);
12850
12851 if (STRINGP (default_filename))
12852 {
12853 char *file_name_only;
12854 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 12855
6fc2811b 12856 unixtodos_filename (full_path_name);
5ac45f98 12857
6fc2811b
JR
12858 file_name_only = strrchr (full_path_name, '\\');
12859 if (!file_name_only)
12860 file_name_only = full_path_name;
12861 else
12862 {
12863 file_name_only++;
5ac45f98 12864
6fc2811b
JR
12865 /* If default_file_name is a directory, don't use the open
12866 file dialog, as it does not support selecting
12867 directories. */
12868 if (!(*file_name_only))
12869 use_dialog_p = 0;
12870 }
ee78dc32 12871
6fc2811b
JR
12872 strncpy (filename, file_name_only, MAX_PATH);
12873 filename[MAX_PATH] = '\0';
12874 }
ee78dc32 12875 else
6fc2811b 12876 filename[0] = '\0';
ee78dc32 12877
6fc2811b
JR
12878 if (use_dialog_p)
12879 {
12880 OPENFILENAME file_details;
5ac45f98 12881
6fc2811b
JR
12882 /* Prevent redisplay. */
12883 specbind (Qinhibit_redisplay, Qt);
12884 BLOCK_INPUT;
ee78dc32 12885
6fc2811b
JR
12886 bzero (&file_details, sizeof (file_details));
12887 file_details.lStructSize = sizeof (file_details);
12888 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12889 file_details.lpstrFile = filename;
12890 file_details.nMaxFile = sizeof (filename);
12891 file_details.lpstrInitialDir = init_dir;
12892 file_details.lpstrTitle = XSTRING (prompt)->data;
12893 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 12894
6fc2811b
JR
12895 if (!NILP (mustmatch))
12896 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 12897
6fc2811b
JR
12898 if (GetOpenFileName (&file_details))
12899 {
12900 dostounix_filename (filename);
12901 file = build_string (filename);
12902 }
ee78dc32 12903 else
6fc2811b
JR
12904 file = Qnil;
12905
12906 UNBLOCK_INPUT;
12907 file = unbind_to (count, file);
ee78dc32 12908 }
6fc2811b
JR
12909 /* Open File dialog will not allow folders to be selected, so resort
12910 to minibuffer completing reads for directories. */
12911 else
12912 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12913 dir, mustmatch, dir, Qfile_name_history,
12914 default_filename, Qnil);
ee78dc32 12915
6fc2811b 12916 UNGCPRO;
1edf84e7 12917
6fc2811b
JR
12918 /* Make "Cancel" equivalent to C-g. */
12919 if (NILP (file))
12920 Fsignal (Qquit, Qnil);
ee78dc32 12921
dfff8a69 12922 return unbind_to (count, file);
6fc2811b 12923}
ee78dc32 12924
ee78dc32 12925
6fc2811b
JR
12926\f
12927/***********************************************************************
12928 Tests
12929 ***********************************************************************/
ee78dc32 12930
6fc2811b 12931#if GLYPH_DEBUG
ee78dc32 12932
6fc2811b
JR
12933DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12934 "Value is non-nil if SPEC is a valid image specification.")
12935 (spec)
12936 Lisp_Object spec;
12937{
12938 return valid_image_p (spec) ? Qt : Qnil;
ee78dc32
GV
12939}
12940
ee78dc32 12941
6fc2811b
JR
12942DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12943 (spec)
12944 Lisp_Object spec;
12945{
12946 int id = -1;
12947
12948 if (valid_image_p (spec))
12949 id = lookup_image (SELECTED_FRAME (), spec);
ee78dc32 12950
6fc2811b
JR
12951 debug_print (spec);
12952 return make_number (id);
ee78dc32
GV
12953}
12954
6fc2811b 12955#endif /* GLYPH_DEBUG != 0 */
ee78dc32 12956
ee78dc32
GV
12957
12958\f
6fc2811b
JR
12959/***********************************************************************
12960 w32 specialized functions
12961 ***********************************************************************/
ee78dc32 12962
fbd6baed
GV
12963DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12964 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
ee78dc32
GV
12965 (frame)
12966 Lisp_Object frame;
12967{
12968 FRAME_PTR f = check_x_frame (frame);
12969 CHOOSEFONT cf;
12970 LOGFONT lf;
f46e6225
GV
12971 TEXTMETRIC tm;
12972 HDC hdc;
12973 HANDLE oldobj;
ee78dc32
GV
12974 char buf[100];
12975
12976 bzero (&cf, sizeof (cf));
f46e6225 12977 bzero (&lf, sizeof (lf));
ee78dc32
GV
12978
12979 cf.lStructSize = sizeof (cf);
fbd6baed 12980 cf.hwndOwner = FRAME_W32_WINDOW (f);
6fc2811b 12981 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
ee78dc32
GV
12982 cf.lpLogFont = &lf;
12983
f46e6225
GV
12984 /* Initialize as much of the font details as we can from the current
12985 default font. */
12986 hdc = GetDC (FRAME_W32_WINDOW (f));
12987 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12988 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12989 if (GetTextMetrics (hdc, &tm))
12990 {
12991 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12992 lf.lfWeight = tm.tmWeight;
12993 lf.lfItalic = tm.tmItalic;
12994 lf.lfUnderline = tm.tmUnderlined;
12995 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
12996 lf.lfCharSet = tm.tmCharSet;
12997 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12998 }
12999 SelectObject (hdc, oldobj);
6fc2811b 13000 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 13001
767b1ff0 13002 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 13003 return Qnil;
ee78dc32
GV
13004
13005 return build_string (buf);
13006}
13007
1edf84e7
GV
13008DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
13009 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
13010Some useful values for command are 0xf030 to maximise frame (0xf020\n\
13011to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
13012to activate the menubar for keyboard access. 0xf140 activates the\n\
13013screen saver if defined.\n\
13014\n\
13015If optional parameter FRAME is not specified, use selected frame.")
13016 (command, frame)
13017 Lisp_Object command, frame;
13018{
1edf84e7
GV
13019 FRAME_PTR f = check_x_frame (frame);
13020
13021 CHECK_NUMBER (command, 0);
13022
ce6059da 13023 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
13024
13025 return Qnil;
13026}
13027
55dcfc15
AI
13028DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
13029 "Get Windows to perform OPERATION on DOCUMENT.\n\
13030This is a wrapper around the ShellExecute system function, which\n\
13031invokes the application registered to handle OPERATION for DOCUMENT.\n\
6fc2811b
JR
13032OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
13033nil for the default action), and DOCUMENT is typically the name of a\n\
13034document file or URL, but can also be a program executable to run or\n\
13035a directory to open in the Windows Explorer.\n\
55dcfc15 13036\n\
6fc2811b
JR
13037If DOCUMENT is a program executable, PARAMETERS can be a string\n\
13038containing command line parameters, but otherwise should be nil.\n\
55dcfc15
AI
13039\n\
13040SHOW-FLAG can be used to control whether the invoked application is hidden\n\
6fc2811b 13041or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
55dcfc15
AI
13042otherwise it is an integer representing a ShowWindow flag:\n\
13043\n\
13044 0 - start hidden\n\
13045 1 - start normally\n\
13046 3 - start maximized\n\
13047 6 - start minimized")
13048 (operation, document, parameters, show_flag)
13049 Lisp_Object operation, document, parameters, show_flag;
13050{
13051 Lisp_Object current_dir;
13052
55dcfc15
AI
13053 CHECK_STRING (document, 0);
13054
13055 /* Encode filename and current directory. */
13056 current_dir = ENCODE_FILE (current_buffer->directory);
13057 document = ENCODE_FILE (document);
13058 if ((int) ShellExecute (NULL,
6fc2811b
JR
13059 (STRINGP (operation) ?
13060 XSTRING (operation)->data : NULL),
55dcfc15
AI
13061 XSTRING (document)->data,
13062 (STRINGP (parameters) ?
13063 XSTRING (parameters)->data : NULL),
13064 XSTRING (current_dir)->data,
13065 (INTEGERP (show_flag) ?
13066 XINT (show_flag) : SW_SHOWDEFAULT))
13067 > 32)
13068 return Qt;
90d97e64 13069 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
13070}
13071
ccc2d29c
GV
13072/* Lookup virtual keycode from string representing the name of a
13073 non-ascii keystroke into the corresponding virtual key, using
13074 lispy_function_keys. */
13075static int
13076lookup_vk_code (char *key)
13077{
13078 int i;
13079
13080 for (i = 0; i < 256; i++)
13081 if (lispy_function_keys[i] != 0
13082 && strcmp (lispy_function_keys[i], key) == 0)
13083 return i;
13084
13085 return -1;
13086}
13087
13088/* Convert a one-element vector style key sequence to a hot key
13089 definition. */
13090static int
13091w32_parse_hot_key (key)
13092 Lisp_Object key;
13093{
13094 /* Copied from Fdefine_key and store_in_keymap. */
13095 register Lisp_Object c;
13096 int vk_code;
13097 int lisp_modifiers;
13098 int w32_modifiers;
13099 struct gcpro gcpro1;
13100
13101 CHECK_VECTOR (key, 0);
13102
13103 if (XFASTINT (Flength (key)) != 1)
13104 return Qnil;
13105
13106 GCPRO1 (key);
13107
13108 c = Faref (key, make_number (0));
13109
13110 if (CONSP (c) && lucid_event_type_list_p (c))
13111 c = Fevent_convert_list (c);
13112
13113 UNGCPRO;
13114
13115 if (! INTEGERP (c) && ! SYMBOLP (c))
13116 error ("Key definition is invalid");
13117
13118 /* Work out the base key and the modifiers. */
13119 if (SYMBOLP (c))
13120 {
13121 c = parse_modifiers (c);
13122 lisp_modifiers = Fcar (Fcdr (c));
13123 c = Fcar (c);
13124 if (!SYMBOLP (c))
13125 abort ();
13126 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
13127 }
13128 else if (INTEGERP (c))
13129 {
13130 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13131 /* Many ascii characters are their own virtual key code. */
13132 vk_code = XINT (c) & CHARACTERBITS;
13133 }
13134
13135 if (vk_code < 0 || vk_code > 255)
13136 return Qnil;
13137
13138 if ((lisp_modifiers & meta_modifier) != 0
13139 && !NILP (Vw32_alt_is_meta))
13140 lisp_modifiers |= alt_modifier;
13141
71eab8d1
AI
13142 /* Supply defs missing from mingw32. */
13143#ifndef MOD_ALT
13144#define MOD_ALT 0x0001
13145#define MOD_CONTROL 0x0002
13146#define MOD_SHIFT 0x0004
13147#define MOD_WIN 0x0008
13148#endif
13149
ccc2d29c
GV
13150 /* Convert lisp modifiers to Windows hot-key form. */
13151 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
13152 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
13153 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
13154 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
13155
13156 return HOTKEY (vk_code, w32_modifiers);
13157}
13158
13159DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
13160 "Register KEY as a hot-key combination.\n\
13161Certain key combinations like Alt-Tab are reserved for system use on\n\
13162Windows, and therefore are normally intercepted by the system. However,\n\
13163most of these key combinations can be received by registering them as\n\
13164hot-keys, overriding their special meaning.\n\
13165\n\
13166KEY must be a one element key definition in vector form that would be\n\
13167acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
13168modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
13169is always interpreted as the Windows modifier keys.\n\
13170\n\
13171The return value is the hotkey-id if registered, otherwise nil.")
13172 (key)
13173 Lisp_Object key;
13174{
13175 key = w32_parse_hot_key (key);
13176
13177 if (NILP (Fmemq (key, w32_grabbed_keys)))
13178 {
13179 /* Reuse an empty slot if possible. */
13180 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
13181
13182 /* Safe to add new key to list, even if we have focus. */
13183 if (NILP (item))
13184 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
13185 else
13186 XCAR (item) = key;
13187
13188 /* Notify input thread about new hot-key definition, so that it
13189 takes effect without needing to switch focus. */
13190 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
13191 (WPARAM) key, 0);
13192 }
13193
13194 return key;
13195}
13196
13197DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
13198 "Unregister HOTKEY as a hot-key combination.")
13199 (key)
13200 Lisp_Object key;
13201{
13202 Lisp_Object item;
13203
13204 if (!INTEGERP (key))
13205 key = w32_parse_hot_key (key);
13206
13207 item = Fmemq (key, w32_grabbed_keys);
13208
13209 if (!NILP (item))
13210 {
13211 /* Notify input thread about hot-key definition being removed, so
13212 that it takes effect without needing focus switch. */
13213 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
13214 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
13215 {
13216 MSG msg;
13217 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13218 }
13219 return Qt;
13220 }
13221 return Qnil;
13222}
13223
13224DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
13225 "Return list of registered hot-key IDs.")
13226 ()
13227{
13228 return Fcopy_sequence (w32_grabbed_keys);
13229}
13230
13231DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
13232 "Convert hot-key ID to a lisp key combination.")
13233 (hotkeyid)
13234 Lisp_Object hotkeyid;
13235{
13236 int vk_code, w32_modifiers;
13237 Lisp_Object key;
13238
13239 CHECK_NUMBER (hotkeyid, 0);
13240
13241 vk_code = HOTKEY_VK_CODE (hotkeyid);
13242 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
13243
13244 if (lispy_function_keys[vk_code])
13245 key = intern (lispy_function_keys[vk_code]);
13246 else
13247 key = make_number (vk_code);
13248
13249 key = Fcons (key, Qnil);
13250 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 13251 key = Fcons (Qshift, key);
ccc2d29c 13252 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 13253 key = Fcons (Qctrl, key);
ccc2d29c 13254 if (w32_modifiers & MOD_ALT)
3ef68e6b 13255 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 13256 if (w32_modifiers & MOD_WIN)
3ef68e6b 13257 key = Fcons (Qhyper, key);
ccc2d29c
GV
13258
13259 return key;
13260}
adcc3809
GV
13261
13262DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
13263 "Toggle the state of the lock key KEY.\n\
13264KEY can be `capslock', `kp-numlock', or `scroll'.\n\
13265If the optional parameter NEW-STATE is a number, then the state of KEY\n\
13266is set to off if the low bit of NEW-STATE is zero, otherwise on.")
13267 (key, new_state)
13268 Lisp_Object key, new_state;
13269{
13270 int vk_code;
adcc3809
GV
13271
13272 if (EQ (key, intern ("capslock")))
13273 vk_code = VK_CAPITAL;
13274 else if (EQ (key, intern ("kp-numlock")))
13275 vk_code = VK_NUMLOCK;
13276 else if (EQ (key, intern ("scroll")))
13277 vk_code = VK_SCROLL;
13278 else
13279 return Qnil;
13280
13281 if (!dwWindowsThreadId)
13282 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
13283
13284 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
13285 (WPARAM) vk_code, (LPARAM) new_state))
13286 {
13287 MSG msg;
13288 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13289 return make_number (msg.wParam);
13290 }
13291 return Qnil;
13292}
ee78dc32 13293\f
2254bcde
AI
13294DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
13295 "Return storage information about the file system FILENAME is on.\n\
13296Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total\n\
13297storage of the file system, FREE is the free storage, and AVAIL is the\n\
13298storage available to a non-superuser. All 3 numbers are in bytes.\n\
13299If the underlying system call fails, value is nil.")
13300 (filename)
13301 Lisp_Object filename;
13302{
13303 Lisp_Object encoded, value;
13304
13305 CHECK_STRING (filename, 0);
13306 filename = Fexpand_file_name (filename, Qnil);
13307 encoded = ENCODE_FILE (filename);
13308
13309 value = Qnil;
13310
13311 /* Determining the required information on Windows turns out, sadly,
13312 to be more involved than one would hope. The original Win32 api
13313 call for this will return bogus information on some systems, but we
13314 must dynamically probe for the replacement api, since that was
13315 added rather late on. */
13316 {
13317 HMODULE hKernel = GetModuleHandle ("kernel32");
13318 BOOL (*pfn_GetDiskFreeSpaceEx)
13319 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
13320 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
13321
13322 /* On Windows, we may need to specify the root directory of the
13323 volume holding FILENAME. */
13324 char rootname[MAX_PATH];
13325 char *name = XSTRING (encoded)->data;
13326
13327 /* find the root name of the volume if given */
13328 if (isalpha (name[0]) && name[1] == ':')
13329 {
13330 rootname[0] = name[0];
13331 rootname[1] = name[1];
13332 rootname[2] = '\\';
13333 rootname[3] = 0;
13334 }
13335 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
13336 {
13337 char *str = rootname;
13338 int slashes = 4;
13339 do
13340 {
13341 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
13342 break;
13343 *str++ = *name++;
13344 }
13345 while ( *name );
13346
13347 *str++ = '\\';
13348 *str = 0;
13349 }
13350
13351 if (pfn_GetDiskFreeSpaceEx)
13352 {
13353 LARGE_INTEGER availbytes;
13354 LARGE_INTEGER freebytes;
13355 LARGE_INTEGER totalbytes;
13356
13357 if (pfn_GetDiskFreeSpaceEx(rootname,
13358 &availbytes,
13359 &totalbytes,
13360 &freebytes))
13361 value = list3 (make_float ((double) totalbytes.QuadPart),
13362 make_float ((double) freebytes.QuadPart),
13363 make_float ((double) availbytes.QuadPart));
13364 }
13365 else
13366 {
13367 DWORD sectors_per_cluster;
13368 DWORD bytes_per_sector;
13369 DWORD free_clusters;
13370 DWORD total_clusters;
13371
13372 if (GetDiskFreeSpace(rootname,
13373 &sectors_per_cluster,
13374 &bytes_per_sector,
13375 &free_clusters,
13376 &total_clusters))
13377 value = list3 (make_float ((double) total_clusters
13378 * sectors_per_cluster * bytes_per_sector),
13379 make_float ((double) free_clusters
13380 * sectors_per_cluster * bytes_per_sector),
13381 make_float ((double) free_clusters
13382 * sectors_per_cluster * bytes_per_sector));
13383 }
13384 }
13385
13386 return value;
13387}
13388\f
fbd6baed 13389syms_of_w32fns ()
ee78dc32 13390{
1edf84e7
GV
13391 /* This is zero if not using MS-Windows. */
13392 w32_in_use = 0;
13393
ee78dc32
GV
13394 /* The section below is built by the lisp expression at the top of the file,
13395 just above where these variables are declared. */
13396 /*&&& init symbols here &&&*/
13397 Qauto_raise = intern ("auto-raise");
13398 staticpro (&Qauto_raise);
13399 Qauto_lower = intern ("auto-lower");
13400 staticpro (&Qauto_lower);
ee78dc32
GV
13401 Qbar = intern ("bar");
13402 staticpro (&Qbar);
13403 Qborder_color = intern ("border-color");
13404 staticpro (&Qborder_color);
13405 Qborder_width = intern ("border-width");
13406 staticpro (&Qborder_width);
13407 Qbox = intern ("box");
13408 staticpro (&Qbox);
13409 Qcursor_color = intern ("cursor-color");
13410 staticpro (&Qcursor_color);
13411 Qcursor_type = intern ("cursor-type");
13412 staticpro (&Qcursor_type);
ee78dc32
GV
13413 Qgeometry = intern ("geometry");
13414 staticpro (&Qgeometry);
13415 Qicon_left = intern ("icon-left");
13416 staticpro (&Qicon_left);
13417 Qicon_top = intern ("icon-top");
13418 staticpro (&Qicon_top);
13419 Qicon_type = intern ("icon-type");
13420 staticpro (&Qicon_type);
13421 Qicon_name = intern ("icon-name");
13422 staticpro (&Qicon_name);
13423 Qinternal_border_width = intern ("internal-border-width");
13424 staticpro (&Qinternal_border_width);
13425 Qleft = intern ("left");
13426 staticpro (&Qleft);
1026b400
RS
13427 Qright = intern ("right");
13428 staticpro (&Qright);
ee78dc32
GV
13429 Qmouse_color = intern ("mouse-color");
13430 staticpro (&Qmouse_color);
13431 Qnone = intern ("none");
13432 staticpro (&Qnone);
13433 Qparent_id = intern ("parent-id");
13434 staticpro (&Qparent_id);
13435 Qscroll_bar_width = intern ("scroll-bar-width");
13436 staticpro (&Qscroll_bar_width);
13437 Qsuppress_icon = intern ("suppress-icon");
13438 staticpro (&Qsuppress_icon);
ee78dc32
GV
13439 Qundefined_color = intern ("undefined-color");
13440 staticpro (&Qundefined_color);
13441 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
13442 staticpro (&Qvertical_scroll_bars);
13443 Qvisibility = intern ("visibility");
13444 staticpro (&Qvisibility);
13445 Qwindow_id = intern ("window-id");
13446 staticpro (&Qwindow_id);
13447 Qx_frame_parameter = intern ("x-frame-parameter");
13448 staticpro (&Qx_frame_parameter);
13449 Qx_resource_name = intern ("x-resource-name");
13450 staticpro (&Qx_resource_name);
13451 Quser_position = intern ("user-position");
13452 staticpro (&Quser_position);
13453 Quser_size = intern ("user-size");
13454 staticpro (&Quser_size);
6fc2811b
JR
13455 Qscreen_gamma = intern ("screen-gamma");
13456 staticpro (&Qscreen_gamma);
dfff8a69
JR
13457 Qline_spacing = intern ("line-spacing");
13458 staticpro (&Qline_spacing);
13459 Qcenter = intern ("center");
13460 staticpro (&Qcenter);
dc220243
JR
13461 Qcancel_timer = intern ("cancel-timer");
13462 staticpro (&Qcancel_timer);
ee78dc32
GV
13463 /* This is the end of symbol initialization. */
13464
adcc3809
GV
13465 Qhyper = intern ("hyper");
13466 staticpro (&Qhyper);
13467 Qsuper = intern ("super");
13468 staticpro (&Qsuper);
13469 Qmeta = intern ("meta");
13470 staticpro (&Qmeta);
13471 Qalt = intern ("alt");
13472 staticpro (&Qalt);
13473 Qctrl = intern ("ctrl");
13474 staticpro (&Qctrl);
13475 Qcontrol = intern ("control");
13476 staticpro (&Qcontrol);
13477 Qshift = intern ("shift");
13478 staticpro (&Qshift);
13479
6fc2811b
JR
13480 /* Text property `display' should be nonsticky by default. */
13481 Vtext_property_default_nonsticky
13482 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
13483
13484
13485 Qlaplace = intern ("laplace");
13486 staticpro (&Qlaplace);
13487
4b817373
RS
13488 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
13489 staticpro (&Qface_set_after_frame_default);
13490
ee78dc32
GV
13491 Fput (Qundefined_color, Qerror_conditions,
13492 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
13493 Fput (Qundefined_color, Qerror_message,
13494 build_string ("Undefined color"));
13495
ccc2d29c
GV
13496 staticpro (&w32_grabbed_keys);
13497 w32_grabbed_keys = Qnil;
13498
fbd6baed 13499 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
ccc2d29c 13500 "An array of color name mappings for windows.");
fbd6baed 13501 Vw32_color_map = Qnil;
ee78dc32 13502
fbd6baed 13503 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
da36a4d6
GV
13504 "Non-nil if alt key presses are passed on to Windows.\n\
13505When non-nil, for example, alt pressed and released and then space will\n\
13506open the System menu. When nil, Emacs silently swallows alt key events.");
fbd6baed 13507 Vw32_pass_alt_to_system = Qnil;
da36a4d6 13508
fbd6baed 13509 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
8c205c63
RS
13510 "Non-nil if the alt key is to be considered the same as the meta key.\n\
13511When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
fbd6baed 13512 Vw32_alt_is_meta = Qt;
8c205c63 13513
7d081355
AI
13514 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
13515 "If non-zero, the virtual key code for an alternative quit key.");
13516 XSETINT (Vw32_quit_key, 0);
13517
ccc2d29c
GV
13518 DEFVAR_LISP ("w32-pass-lwindow-to-system",
13519 &Vw32_pass_lwindow_to_system,
13520 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
13521When non-nil, the Start menu is opened by tapping the key.");
13522 Vw32_pass_lwindow_to_system = Qt;
13523
13524 DEFVAR_LISP ("w32-pass-rwindow-to-system",
13525 &Vw32_pass_rwindow_to_system,
13526 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
13527When non-nil, the Start menu is opened by tapping the key.");
13528 Vw32_pass_rwindow_to_system = Qt;
13529
adcc3809
GV
13530 DEFVAR_INT ("w32-phantom-key-code",
13531 &Vw32_phantom_key_code,
13532 "Virtual key code used to generate \"phantom\" key presses.\n\
13533Value is a number between 0 and 255.\n\
13534\n\
13535Phantom key presses are generated in order to stop the system from\n\
13536acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
13537`w32-pass-rwindow-to-system' is nil.");
ce6059da
AI
13538 /* Although 255 is technically not a valid key code, it works and
13539 means that this hack won't interfere with any real key code. */
13540 Vw32_phantom_key_code = 255;
adcc3809 13541
ccc2d29c
GV
13542 DEFVAR_LISP ("w32-enable-num-lock",
13543 &Vw32_enable_num_lock,
13544 "Non-nil if Num Lock should act normally.\n\
13545Set to nil to see Num Lock as the key `kp-numlock'.");
13546 Vw32_enable_num_lock = Qt;
13547
13548 DEFVAR_LISP ("w32-enable-caps-lock",
13549 &Vw32_enable_caps_lock,
13550 "Non-nil if Caps Lock should act normally.\n\
13551Set to nil to see Caps Lock as the key `capslock'.");
13552 Vw32_enable_caps_lock = Qt;
13553
13554 DEFVAR_LISP ("w32-scroll-lock-modifier",
13555 &Vw32_scroll_lock_modifier,
13556 "Modifier to use for the Scroll Lock on state.\n\
13557The value can be hyper, super, meta, alt, control or shift for the\n\
13558respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
13559Any other value will cause the key to be ignored.");
13560 Vw32_scroll_lock_modifier = Qt;
13561
13562 DEFVAR_LISP ("w32-lwindow-modifier",
13563 &Vw32_lwindow_modifier,
13564 "Modifier to use for the left \"Windows\" key.\n\
13565The value can be hyper, super, meta, alt, control or shift for the\n\
13566respective modifier, or nil to appear as the key `lwindow'.\n\
13567Any other value will cause the key to be ignored.");
13568 Vw32_lwindow_modifier = Qnil;
13569
13570 DEFVAR_LISP ("w32-rwindow-modifier",
13571 &Vw32_rwindow_modifier,
13572 "Modifier to use for the right \"Windows\" key.\n\
13573The value can be hyper, super, meta, alt, control or shift for the\n\
13574respective modifier, or nil to appear as the key `rwindow'.\n\
13575Any other value will cause the key to be ignored.");
13576 Vw32_rwindow_modifier = Qnil;
13577
13578 DEFVAR_LISP ("w32-apps-modifier",
13579 &Vw32_apps_modifier,
13580 "Modifier to use for the \"Apps\" key.\n\
13581The value can be hyper, super, meta, alt, control or shift for the\n\
13582respective modifier, or nil to appear as the key `apps'.\n\
13583Any other value will cause the key to be ignored.");
13584 Vw32_apps_modifier = Qnil;
da36a4d6 13585
212da13b 13586 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
6fc2811b
JR
13587 "Non-nil enables selection of artificially italicized and bold fonts.");
13588 Vw32_enable_synthesized_fonts = Qnil;
5ac45f98 13589
fbd6baed 13590 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
6fc2811b 13591 "Non-nil enables Windows palette management to map colors exactly.");
fbd6baed 13592 Vw32_enable_palette = Qt;
5ac45f98 13593
fbd6baed
GV
13594 DEFVAR_INT ("w32-mouse-button-tolerance",
13595 &Vw32_mouse_button_tolerance,
6fc2811b 13596 "Analogue of double click interval for faking middle mouse events.\n\
5ac45f98
GV
13597The value is the minimum time in milliseconds that must elapse between\n\
13598left/right button down events before they are considered distinct events.\n\
13599If both mouse buttons are depressed within this interval, a middle mouse\n\
13600button down event is generated instead.");
fbd6baed 13601 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 13602
fbd6baed
GV
13603 DEFVAR_INT ("w32-mouse-move-interval",
13604 &Vw32_mouse_move_interval,
84fb1139
KH
13605 "Minimum interval between mouse move events.\n\
13606The value is the minimum time in milliseconds that must elapse between\n\
13607successive mouse move (or scroll bar drag) events before they are\n\
13608reported as lisp events.");
247be837 13609 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 13610
ee78dc32
GV
13611 init_x_parm_symbols ();
13612
13613 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
fbd6baed 13614 "List of directories to search for bitmap files for w32.");
ee78dc32
GV
13615 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13616
13617 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13618 "The shape of the pointer when over text.\n\
13619Changing the value does not affect existing frames\n\
13620unless you set the mouse color.");
13621 Vx_pointer_shape = Qnil;
13622
13623 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13624 "The name Emacs uses to look up resources; for internal use only.\n\
13625`x-get-resource' uses this as the first component of the instance name\n\
13626when requesting resource values.\n\
13627Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13628was invoked, or to the value specified with the `-name' or `-rn'\n\
13629switches, if present.");
13630 Vx_resource_name = Qnil;
13631
13632 Vx_nontext_pointer_shape = Qnil;
13633
13634 Vx_mode_pointer_shape = Qnil;
13635
6fc2811b
JR
13636 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
13637 "The shape of the pointer when Emacs is busy.\n\
13638This variable takes effect when you create a new frame\n\
13639or when you set the mouse color.");
13640 Vx_busy_pointer_shape = Qnil;
13641
13642 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
13643 "Non-zero means Emacs displays a busy cursor on window systems.");
13644 display_busy_cursor_p = 1;
13645
f79e6790
JR
13646 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
13647 "*Seconds to wait before displaying a busy-cursor.\n\
dfff8a69 13648Value must be an integer or float.");
f79e6790
JR
13649 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
13650
6fc2811b 13651 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32
GV
13652 &Vx_sensitive_text_pointer_shape,
13653 "The shape of the pointer when over mouse-sensitive text.\n\
13654This variable takes effect when you create a new frame\n\
13655or when you set the mouse color.");
13656 Vx_sensitive_text_pointer_shape = Qnil;
13657
4694d762
JR
13658 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
13659 &Vx_window_horizontal_drag_shape,
13660 "Pointer shape to use for indicating a window can be dragged horizontally.\n\
13661This variable takes effect when you create a new frame\n\
13662or when you set the mouse color.");
13663 Vx_window_horizontal_drag_shape = Qnil;
13664
ee78dc32
GV
13665 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13666 "A string indicating the foreground color of the cursor box.");
13667 Vx_cursor_fore_pixel = Qnil;
13668
13669 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13670 "Non-nil if no window manager is in use.\n\
13671Emacs doesn't try to figure this out; this is always nil\n\
13672unless you set it to something else.");
13673 /* We don't have any way to find this out, so set it to nil
13674 and maybe the user would like to set it to t. */
13675 Vx_no_window_manager = Qnil;
13676
4587b026
GV
13677 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13678 &Vx_pixel_size_width_font_regexp,
13679 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13680\n\
13681Since Emacs gets width of a font matching with this regexp from\n\
13682PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13683such a font. This is especially effective for such large fonts as\n\
13684Chinese, Japanese, and Korean.");
13685 Vx_pixel_size_width_font_regexp = Qnil;
13686
6fc2811b
JR
13687 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13688 "Time after which cached images are removed from the cache.\n\
13689When an image has not been displayed this many seconds, remove it\n\
13690from the image cache. Value must be an integer or nil with nil\n\
13691meaning don't clear the cache.");
13692 Vimage_cache_eviction_delay = make_number (30 * 60);
13693
33d52f9c
GV
13694 DEFVAR_LISP ("w32-bdf-filename-alist",
13695 &Vw32_bdf_filename_alist,
13696 "List of bdf fonts and their corresponding filenames.");
13697 Vw32_bdf_filename_alist = Qnil;
13698
1075afa9
GV
13699 DEFVAR_BOOL ("w32-strict-fontnames",
13700 &w32_strict_fontnames,
13701 "Non-nil means only use fonts that are exact matches for those requested.\n\
13702Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13703and allows third-party CJK display to work by specifying false charset\n\
13704fields to trick Emacs into translating to Big5, SJIS etc.\n\
13705Setting this to t will prevent wrong fonts being selected when\n\
13706fontsets are automatically created.");
13707 w32_strict_fontnames = 0;
13708
c0611964
AI
13709 DEFVAR_BOOL ("w32-strict-painting",
13710 &w32_strict_painting,
13711 "Non-nil means use strict rules for repainting frames.\n\
13712Set this to nil to get the old behaviour for repainting; this should\n\
13713only be necessary if the default setting causes problems.");
13714 w32_strict_painting = 1;
13715
f46e6225
GV
13716 DEFVAR_LISP ("w32-system-coding-system",
13717 &Vw32_system_coding_system,
13718 "Coding system used by Windows system functions, such as for font names.");
13719 Vw32_system_coding_system = Qnil;
13720
dfff8a69
JR
13721 DEFVAR_LISP ("w32-charset-info-alist",
13722 &Vw32_charset_info_alist,
13723 "Alist linking Emacs character sets to Windows fonts\n\
13724and codepages. Each entry should be of the form:\n\
13725\n\
13726 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13727\n\
13728where CHARSET_NAME is a string used in font names to identify the charset,\n\
13729WINDOWS_CHARSET is a symbol that can be one of:\n\
13730w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
767b1ff0 13731w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,\n\
dfff8a69
JR
13732w32-charset-chinesebig5, "
13733#ifdef JOHAB_CHARSET
13734"w32-charset-johab, w32-charset-hebrew,\n\
13735w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13736w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13737w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13738#endif
13739#ifdef UNICODE_CHARSET
13740"w32-charset-unicode, "
13741#endif
13742"or w32-charset-oem.\n\
13743CODEPAGE should be an integer specifying the codepage that should be used\n\
13744to display the character set, t to do no translation and output as Unicode,\n\
13745or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13746versions of Windows) characters.");
13747 Vw32_charset_info_alist = Qnil;
13748
13749 staticpro (&Qw32_charset_ansi);
13750 Qw32_charset_ansi = intern ("w32-charset-ansi");
13751 staticpro (&Qw32_charset_symbol);
13752 Qw32_charset_symbol = intern ("w32-charset-symbol");
13753 staticpro (&Qw32_charset_shiftjis);
13754 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
13755 staticpro (&Qw32_charset_hangeul);
13756 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
13757 staticpro (&Qw32_charset_chinesebig5);
13758 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13759 staticpro (&Qw32_charset_gb2312);
13760 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13761 staticpro (&Qw32_charset_oem);
13762 Qw32_charset_oem = intern ("w32-charset-oem");
13763
13764#ifdef JOHAB_CHARSET
13765 {
13766 static int w32_extra_charsets_defined = 1;
767b1ff0 13767 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined, "");
dfff8a69
JR
13768
13769 staticpro (&Qw32_charset_johab);
13770 Qw32_charset_johab = intern ("w32-charset-johab");
13771 staticpro (&Qw32_charset_easteurope);
13772 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13773 staticpro (&Qw32_charset_turkish);
13774 Qw32_charset_turkish = intern ("w32-charset-turkish");
13775 staticpro (&Qw32_charset_baltic);
13776 Qw32_charset_baltic = intern ("w32-charset-baltic");
13777 staticpro (&Qw32_charset_russian);
13778 Qw32_charset_russian = intern ("w32-charset-russian");
13779 staticpro (&Qw32_charset_arabic);
13780 Qw32_charset_arabic = intern ("w32-charset-arabic");
13781 staticpro (&Qw32_charset_greek);
13782 Qw32_charset_greek = intern ("w32-charset-greek");
13783 staticpro (&Qw32_charset_hebrew);
13784 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
13785 staticpro (&Qw32_charset_vietnamese);
13786 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
13787 staticpro (&Qw32_charset_thai);
13788 Qw32_charset_thai = intern ("w32-charset-thai");
13789 staticpro (&Qw32_charset_mac);
13790 Qw32_charset_mac = intern ("w32-charset-mac");
13791 }
13792#endif
13793
13794#ifdef UNICODE_CHARSET
13795 {
13796 static int w32_unicode_charset_defined = 1;
13797 DEFVAR_BOOL ("w32-unicode-charset-defined",
767b1ff0 13798 &w32_unicode_charset_defined, "");
dfff8a69
JR
13799
13800 staticpro (&Qw32_charset_unicode);
13801 Qw32_charset_unicode = intern ("w32-charset-unicode");
13802#endif
13803
ee78dc32 13804 defsubr (&Sx_get_resource);
767b1ff0 13805#if 0 /* TODO: Port to W32 */
6fc2811b
JR
13806 defsubr (&Sx_change_window_property);
13807 defsubr (&Sx_delete_window_property);
13808 defsubr (&Sx_window_property);
13809#endif
2d764c78 13810 defsubr (&Sxw_display_color_p);
ee78dc32 13811 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
13812 defsubr (&Sxw_color_defined_p);
13813 defsubr (&Sxw_color_values);
ee78dc32
GV
13814 defsubr (&Sx_server_max_request_size);
13815 defsubr (&Sx_server_vendor);
13816 defsubr (&Sx_server_version);
13817 defsubr (&Sx_display_pixel_width);
13818 defsubr (&Sx_display_pixel_height);
13819 defsubr (&Sx_display_mm_width);
13820 defsubr (&Sx_display_mm_height);
13821 defsubr (&Sx_display_screens);
13822 defsubr (&Sx_display_planes);
13823 defsubr (&Sx_display_color_cells);
13824 defsubr (&Sx_display_visual_class);
13825 defsubr (&Sx_display_backing_store);
13826 defsubr (&Sx_display_save_under);
13827 defsubr (&Sx_parse_geometry);
13828 defsubr (&Sx_create_frame);
ee78dc32
GV
13829 defsubr (&Sx_open_connection);
13830 defsubr (&Sx_close_connection);
13831 defsubr (&Sx_display_list);
13832 defsubr (&Sx_synchronize);
13833
fbd6baed 13834 /* W32 specific functions */
ee78dc32 13835
1edf84e7 13836 defsubr (&Sw32_focus_frame);
fbd6baed
GV
13837 defsubr (&Sw32_select_font);
13838 defsubr (&Sw32_define_rgb_color);
13839 defsubr (&Sw32_default_color_map);
13840 defsubr (&Sw32_load_color_file);
1edf84e7 13841 defsubr (&Sw32_send_sys_command);
55dcfc15 13842 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
13843 defsubr (&Sw32_register_hot_key);
13844 defsubr (&Sw32_unregister_hot_key);
13845 defsubr (&Sw32_registered_hot_keys);
13846 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 13847 defsubr (&Sw32_toggle_lock_key);
33d52f9c 13848 defsubr (&Sw32_find_bdf_fonts);
4587b026 13849
2254bcde
AI
13850 defsubr (&Sfile_system_info);
13851
4587b026
GV
13852 /* Setting callback functions for fontset handler. */
13853 get_font_info_func = w32_get_font_info;
6fc2811b
JR
13854
13855#if 0 /* This function pointer doesn't seem to be used anywhere.
13856 And the pointer assigned has the wrong type, anyway. */
4587b026 13857 list_fonts_func = w32_list_fonts;
6fc2811b
JR
13858#endif
13859
4587b026
GV
13860 load_font_func = w32_load_font;
13861 find_ccl_program_func = w32_find_ccl_program;
13862 query_font_func = w32_query_font;
13863 set_frame_fontset_func = x_set_font;
13864 check_window_system_func = check_w32;
6fc2811b 13865
767b1ff0 13866#if 0 /* TODO Image support for W32 */
6fc2811b
JR
13867 /* Images. */
13868 Qxbm = intern ("xbm");
13869 staticpro (&Qxbm);
13870 QCtype = intern (":type");
13871 staticpro (&QCtype);
a93f4566
GM
13872 QCconversion = intern (":conversion");
13873 staticpro (&QCconversion);
6fc2811b
JR
13874 QCheuristic_mask = intern (":heuristic-mask");
13875 staticpro (&QCheuristic_mask);
13876 QCcolor_symbols = intern (":color-symbols");
13877 staticpro (&QCcolor_symbols);
6fc2811b
JR
13878 QCascent = intern (":ascent");
13879 staticpro (&QCascent);
13880 QCmargin = intern (":margin");
13881 staticpro (&QCmargin);
13882 QCrelief = intern (":relief");
13883 staticpro (&QCrelief);
13884 Qpostscript = intern ("postscript");
13885 staticpro (&Qpostscript);
13886 QCloader = intern (":loader");
13887 staticpro (&QCloader);
13888 QCbounding_box = intern (":bounding-box");
13889 staticpro (&QCbounding_box);
13890 QCpt_width = intern (":pt-width");
13891 staticpro (&QCpt_width);
13892 QCpt_height = intern (":pt-height");
13893 staticpro (&QCpt_height);
13894 QCindex = intern (":index");
13895 staticpro (&QCindex);
13896 Qpbm = intern ("pbm");
13897 staticpro (&Qpbm);
13898
13899#if HAVE_XPM
13900 Qxpm = intern ("xpm");
13901 staticpro (&Qxpm);
13902#endif
13903
13904#if HAVE_JPEG
13905 Qjpeg = intern ("jpeg");
13906 staticpro (&Qjpeg);
13907#endif
13908
13909#if HAVE_TIFF
13910 Qtiff = intern ("tiff");
13911 staticpro (&Qtiff);
13912#endif
13913
13914#if HAVE_GIF
13915 Qgif = intern ("gif");
13916 staticpro (&Qgif);
13917#endif
13918
13919#if HAVE_PNG
13920 Qpng = intern ("png");
13921 staticpro (&Qpng);
13922#endif
13923
13924 defsubr (&Sclear_image_cache);
13925
13926#if GLYPH_DEBUG
13927 defsubr (&Simagep);
13928 defsubr (&Slookup_image);
13929#endif
767b1ff0 13930#endif /* TODO */
6fc2811b 13931
dfff8a69
JR
13932 busy_cursor_atimer = NULL;
13933 busy_cursor_shown_p = 0;
767b1ff0 13934#ifdef TODO /* Tooltip support not complete. */
6fc2811b
JR
13935 defsubr (&Sx_show_tip);
13936 defsubr (&Sx_hide_tip);
767b1ff0 13937#endif
6fc2811b 13938 tip_timer = Qnil;
57fa2774
JR
13939 staticpro (&tip_timer);
13940 tip_frame = Qnil;
13941 staticpro (&tip_frame);
6fc2811b
JR
13942
13943 defsubr (&Sx_file_dialog);
13944}
13945
13946
13947void
13948init_xfns ()
13949{
13950 image_types = NULL;
13951 Vimage_types = Qnil;
13952
767b1ff0 13953#if 0 /* TODO : Image support for W32 */
6fc2811b
JR
13954 define_image_type (&xbm_type);
13955 define_image_type (&gs_type);
13956 define_image_type (&pbm_type);
13957
13958#if HAVE_XPM
13959 define_image_type (&xpm_type);
13960#endif
13961
13962#if HAVE_JPEG
13963 define_image_type (&jpeg_type);
13964#endif
13965
13966#if HAVE_TIFF
13967 define_image_type (&tiff_type);
13968#endif
13969
13970#if HAVE_GIF
13971 define_image_type (&gif_type);
13972#endif
13973
13974#if HAVE_PNG
13975 define_image_type (&png_type);
13976#endif
767b1ff0 13977#endif /* TODO */
ee78dc32
GV
13978}
13979
13980#undef abort
13981
13982void
fbd6baed 13983w32_abort()
ee78dc32 13984{
5ac45f98
GV
13985 int button;
13986 button = MessageBox (NULL,
13987 "A fatal error has occurred!\n\n"
13988 "Select Abort to exit, Retry to debug, Ignore to continue",
13989 "Emacs Abort Dialog",
13990 MB_ICONEXCLAMATION | MB_TASKMODAL
13991 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
13992 switch (button)
13993 {
13994 case IDRETRY:
13995 DebugBreak ();
13996 break;
13997 case IDIGNORE:
13998 break;
13999 case IDABORT:
14000 default:
14001 abort ();
14002 break;
14003 }
ee78dc32 14004}
d573caac 14005
83c75055
GV
14006/* For convenience when debugging. */
14007int
14008w32_last_error()
14009{
14010 return GetLastError ();
14011}