(cua-enable-cua-keys)
[bpt/emacs.git] / src / w32fns.c
CommitLineData
e9e23e23 1/* Graphical user interface functions for the Microsoft W32 API.
a93f4566 2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
6fc2811b 3 Free Software Foundation, Inc.
ee78dc32
GV
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
ee78dc32
GV
21
22/* Added by Kevin Gallo */
23
ee78dc32 24#include <config.h>
1edf84e7
GV
25
26#include <signal.h>
ee78dc32 27#include <stdio.h>
1edf84e7
GV
28#include <limits.h>
29#include <errno.h>
ee78dc32
GV
30
31#include "lisp.h"
4587b026 32#include "charset.h"
71eab8d1 33#include "dispextern.h"
ee78dc32 34#include "w32term.h"
c7501041 35#include "keyboard.h"
ee78dc32
GV
36#include "frame.h"
37#include "window.h"
38#include "buffer.h"
126f2e35 39#include "fontset.h"
6fc2811b 40#include "intervals.h"
ee78dc32 41#include "blockinput.h"
57bda87a 42#include "epaths.h"
489f9371 43#include "w32heap.h"
ee78dc32 44#include "termhooks.h"
4587b026 45#include "coding.h"
3545439c 46#include "ccl.h"
6fc2811b
JR
47#include "systime.h"
48
49#include "bitmaps/gray.xbm"
ee78dc32
GV
50
51#include <commdlg.h>
cb9e33d4 52#include <shellapi.h>
6fc2811b 53#include <ctype.h>
ee78dc32 54
ee78dc32 55extern void free_frame_menubar ();
9eb16b62 56extern void x_compute_fringe_widths P_ ((struct frame *, int));
6fc2811b 57extern double atof ();
9eb16b62
JR
58extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
59extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
60extern void w32_free_menu_strings P_ ((HWND));
61
5ac45f98 62extern int quit_char;
ee78dc32 63
6fc2811b
JR
64/* A definition of XColor for non-X frames. */
65#ifndef HAVE_X_WINDOWS
66typedef struct {
67 unsigned long pixel;
68 unsigned short red, green, blue;
69 char flags;
70 char pad;
71} XColor;
72#endif
73
ccc2d29c
GV
74extern char *lispy_function_keys[];
75
6fc2811b
JR
76/* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
77 it, and including `bitmaps/gray' more than once is a problem when
78 config.h defines `static' as an empty replacement string. */
79
80int gray_bitmap_width = gray_width;
81int gray_bitmap_height = gray_height;
82unsigned char *gray_bitmap_bits = gray_bits;
83
ee78dc32 84/* The colormap for converting color names to RGB values */
fbd6baed 85Lisp_Object Vw32_color_map;
ee78dc32 86
da36a4d6 87/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 88Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 89
8c205c63
RS
90/* Non nil if alt key is translated to meta_modifier, nil if it is translated
91 to alt_modifier. */
fbd6baed 92Lisp_Object Vw32_alt_is_meta;
8c205c63 93
7d081355
AI
94/* If non-zero, the windows virtual key code for an alternative quit key. */
95Lisp_Object Vw32_quit_key;
96
ccc2d29c
GV
97/* Non nil if left window key events are passed on to Windows (this only
98 affects whether "tapping" the key opens the Start menu). */
99Lisp_Object Vw32_pass_lwindow_to_system;
100
101/* Non nil if right window key events are passed on to Windows (this
102 only affects whether "tapping" the key opens the Start menu). */
103Lisp_Object Vw32_pass_rwindow_to_system;
104
adcc3809
GV
105/* Virtual key code used to generate "phantom" key presses in order
106 to stop system from acting on Windows key events. */
107Lisp_Object Vw32_phantom_key_code;
108
ccc2d29c
GV
109/* Modifier associated with the left "Windows" key, or nil to act as a
110 normal key. */
111Lisp_Object Vw32_lwindow_modifier;
112
113/* Modifier associated with the right "Windows" key, or nil to act as a
114 normal key. */
115Lisp_Object Vw32_rwindow_modifier;
116
117/* Modifier associated with the "Apps" key, or nil to act as a normal
118 key. */
119Lisp_Object Vw32_apps_modifier;
120
121/* Value is nil if Num Lock acts as a function key. */
122Lisp_Object Vw32_enable_num_lock;
123
124/* Value is nil if Caps Lock acts as a function key. */
125Lisp_Object Vw32_enable_caps_lock;
126
127/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
128Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 129
7ce9aaca 130/* Switch to control whether we inhibit requests for synthesized bold
6fc2811b 131 and italic versions of fonts. */
d84b082d 132int w32_enable_synthesized_fonts;
5ac45f98
GV
133
134/* Enable palette management. */
fbd6baed 135Lisp_Object Vw32_enable_palette;
5ac45f98
GV
136
137/* Control how close left/right button down events must be to
138 be converted to a middle button down event. */
fbd6baed 139Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 140
84fb1139
KH
141/* Minimum interval between mouse movement (and scroll bar drag)
142 events that are passed on to the event loop. */
fbd6baed 143Lisp_Object Vw32_mouse_move_interval;
84fb1139 144
74214547
JR
145/* Flag to indicate if XBUTTON events should be passed on to Windows. */
146int w32_pass_extra_mouse_buttons_to_system;
147
ee78dc32
GV
148/* The name we're using in resource queries. */
149Lisp_Object Vx_resource_name;
150
151/* Non nil if no window manager is in use. */
152Lisp_Object Vx_no_window_manager;
153
0af913d7 154/* Non-zero means we're allowed to display a hourglass pointer. */
dfff8a69 155
0af913d7 156int display_hourglass_p;
6fc2811b 157
ee78dc32
GV
158/* The background and shape of the mouse pointer, and shape when not
159 over text or in the modeline. */
dfff8a69 160
ee78dc32 161Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
0af913d7 162Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
6fc2811b 163
ee78dc32 164/* The shape when over mouse-sensitive text. */
dfff8a69 165
ee78dc32
GV
166Lisp_Object Vx_sensitive_text_pointer_shape;
167
168/* Color of chars displayed in cursor box. */
dfff8a69 169
ee78dc32
GV
170Lisp_Object Vx_cursor_fore_pixel;
171
1edf84e7 172/* Nonzero if using Windows. */
dfff8a69 173
1edf84e7
GV
174static int w32_in_use;
175
ee78dc32 176/* Search path for bitmap files. */
dfff8a69 177
ee78dc32
GV
178Lisp_Object Vx_bitmap_file_path;
179
4587b026 180/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
dfff8a69 181
4587b026
GV
182Lisp_Object Vx_pixel_size_width_font_regexp;
183
33d52f9c
GV
184/* Alist of bdf fonts and the files that define them. */
185Lisp_Object Vw32_bdf_filename_alist;
186
f46e6225 187/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
188int w32_strict_fontnames;
189
c0611964
AI
190/* A flag to control whether we should only repaint if GetUpdateRect
191 indicates there is an update region. */
192int w32_strict_painting;
193
dfff8a69
JR
194/* Associative list linking character set strings to Windows codepages. */
195Lisp_Object Vw32_charset_info_alist;
196
197/* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
198#ifndef VIETNAMESE_CHARSET
199#define VIETNAMESE_CHARSET 163
200#endif
201
ee78dc32
GV
202Lisp_Object Qauto_raise;
203Lisp_Object Qauto_lower;
ee78dc32
GV
204Lisp_Object Qbar;
205Lisp_Object Qborder_color;
206Lisp_Object Qborder_width;
207Lisp_Object Qbox;
208Lisp_Object Qcursor_color;
209Lisp_Object Qcursor_type;
ee78dc32
GV
210Lisp_Object Qgeometry;
211Lisp_Object Qicon_left;
212Lisp_Object Qicon_top;
213Lisp_Object Qicon_type;
214Lisp_Object Qicon_name;
215Lisp_Object Qinternal_border_width;
216Lisp_Object Qleft;
1026b400 217Lisp_Object Qright;
ee78dc32
GV
218Lisp_Object Qmouse_color;
219Lisp_Object Qnone;
220Lisp_Object Qparent_id;
221Lisp_Object Qscroll_bar_width;
222Lisp_Object Qsuppress_icon;
ee78dc32
GV
223Lisp_Object Qundefined_color;
224Lisp_Object Qvertical_scroll_bars;
225Lisp_Object Qvisibility;
226Lisp_Object Qwindow_id;
227Lisp_Object Qx_frame_parameter;
228Lisp_Object Qx_resource_name;
229Lisp_Object Quser_position;
230Lisp_Object Quser_size;
6fc2811b 231Lisp_Object Qscreen_gamma;
dfff8a69
JR
232Lisp_Object Qline_spacing;
233Lisp_Object Qcenter;
dc220243 234Lisp_Object Qcancel_timer;
adcc3809
GV
235Lisp_Object Qhyper;
236Lisp_Object Qsuper;
237Lisp_Object Qmeta;
238Lisp_Object Qalt;
239Lisp_Object Qctrl;
240Lisp_Object Qcontrol;
241Lisp_Object Qshift;
242
dfff8a69
JR
243Lisp_Object Qw32_charset_ansi;
244Lisp_Object Qw32_charset_default;
245Lisp_Object Qw32_charset_symbol;
246Lisp_Object Qw32_charset_shiftjis;
767b1ff0 247Lisp_Object Qw32_charset_hangeul;
dfff8a69
JR
248Lisp_Object Qw32_charset_gb2312;
249Lisp_Object Qw32_charset_chinesebig5;
250Lisp_Object Qw32_charset_oem;
251
71eab8d1
AI
252#ifndef JOHAB_CHARSET
253#define JOHAB_CHARSET 130
254#endif
dfff8a69
JR
255#ifdef JOHAB_CHARSET
256Lisp_Object Qw32_charset_easteurope;
257Lisp_Object Qw32_charset_turkish;
258Lisp_Object Qw32_charset_baltic;
259Lisp_Object Qw32_charset_russian;
260Lisp_Object Qw32_charset_arabic;
261Lisp_Object Qw32_charset_greek;
262Lisp_Object Qw32_charset_hebrew;
767b1ff0 263Lisp_Object Qw32_charset_vietnamese;
dfff8a69
JR
264Lisp_Object Qw32_charset_thai;
265Lisp_Object Qw32_charset_johab;
266Lisp_Object Qw32_charset_mac;
267#endif
268
269#ifdef UNICODE_CHARSET
270Lisp_Object Qw32_charset_unicode;
271#endif
272
f7b9d4d1
JR
273Lisp_Object Qfullscreen;
274Lisp_Object Qfullwidth;
275Lisp_Object Qfullheight;
276Lisp_Object Qfullboth;
277
6fc2811b
JR
278extern Lisp_Object Qtop;
279extern Lisp_Object Qdisplay;
6fc2811b 280
5ac45f98
GV
281/* State variables for emulating a three button mouse. */
282#define LMOUSE 1
283#define MMOUSE 2
284#define RMOUSE 4
285
286static int button_state = 0;
fbd6baed 287static W32Msg saved_mouse_button_msg;
48094ace 288static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
fbd6baed 289static W32Msg saved_mouse_move_msg;
48094ace 290static unsigned mouse_move_timer = 0;
84fb1139 291
9eb16b62
JR
292/* Window that is tracking the mouse. */
293static HWND track_mouse_window;
294FARPROC track_mouse_event_fn;
295
93fbe8b7
GV
296/* W95 mousewheel handler */
297unsigned int msh_mousewheel = 0;
298
48094ace 299/* Timers */
84fb1139
KH
300#define MOUSE_BUTTON_ID 1
301#define MOUSE_MOVE_ID 2
48094ace
JR
302#define MENU_FREE_ID 3
303/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
304 is received. */
305#define MENU_FREE_DELAY 1000
306static unsigned menu_free_timer = 0;
5ac45f98 307
ee78dc32 308/* The below are defined in frame.c. */
dfff8a69 309
ee78dc32 310extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 311extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
6fc2811b 312extern Lisp_Object Qtool_bar_lines;
ee78dc32
GV
313
314extern Lisp_Object Vwindow_system_version;
315
4b817373
RS
316Lisp_Object Qface_set_after_frame_default;
317
937e601e
AI
318#ifdef GLYPH_DEBUG
319int image_cache_refcount, dpyinfo_refcount;
320#endif
321
322
fbd6baed
GV
323/* From w32term.c. */
324extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 325extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 326
65906840 327extern HWND w32_system_caret_hwnd;
93f2ca61 328
65906840
JR
329extern int w32_system_caret_height;
330extern int w32_system_caret_x;
331extern int w32_system_caret_y;
93f2ca61
JR
332extern int w32_use_visible_system_caret;
333
d285988b 334static HWND w32_visible_system_caret_hwnd;
65906840 335
ee78dc32 336\f
1edf84e7
GV
337/* Error if we are not connected to MS-Windows. */
338void
339check_w32 ()
340{
341 if (! w32_in_use)
342 error ("MS-Windows not in use or not initialized");
343}
344
345/* Nonzero if we can use mouse menus.
346 You should not call this unless HAVE_MENUS is defined. */
347
348int
349have_menus_p ()
350{
351 return w32_in_use;
352}
353
ee78dc32 354/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 355 and checking validity for W32. */
ee78dc32
GV
356
357FRAME_PTR
358check_x_frame (frame)
359 Lisp_Object frame;
360{
361 FRAME_PTR f;
362
363 if (NILP (frame))
6fc2811b 364 frame = selected_frame;
b7826503 365 CHECK_LIVE_FRAME (frame);
6fc2811b 366 f = XFRAME (frame);
fbd6baed
GV
367 if (! FRAME_W32_P (f))
368 error ("non-w32 frame used");
ee78dc32
GV
369 return f;
370}
371
372/* Let the user specify an display with a frame.
fbd6baed 373 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
374 the first display on the list. */
375
fbd6baed 376static struct w32_display_info *
ee78dc32
GV
377check_x_display_info (frame)
378 Lisp_Object frame;
379{
380 if (NILP (frame))
381 {
6fc2811b
JR
382 struct frame *sf = XFRAME (selected_frame);
383
384 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
385 return FRAME_W32_DISPLAY_INFO (sf);
ee78dc32 386 else
fbd6baed 387 return &one_w32_display_info;
ee78dc32
GV
388 }
389 else if (STRINGP (frame))
390 return x_display_info_for_name (frame);
391 else
392 {
393 FRAME_PTR f;
394
b7826503 395 CHECK_LIVE_FRAME (frame);
ee78dc32 396 f = XFRAME (frame);
fbd6baed
GV
397 if (! FRAME_W32_P (f))
398 error ("non-w32 frame used");
399 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
400 }
401}
402\f
fbd6baed 403/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
404 It could be the frame's main window or an icon window. */
405
406/* This function can be called during GC, so use GC_xxx type test macros. */
407
408struct frame *
409x_window_to_frame (dpyinfo, wdesc)
fbd6baed 410 struct w32_display_info *dpyinfo;
ee78dc32
GV
411 HWND wdesc;
412{
413 Lisp_Object tail, frame;
414 struct frame *f;
415
8e713be6 416 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
ee78dc32 417 {
8e713be6 418 frame = XCAR (tail);
ee78dc32
GV
419 if (!GC_FRAMEP (frame))
420 continue;
421 f = XFRAME (frame);
2d764c78 422 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 423 continue;
0af913d7 424 if (f->output_data.w32->hourglass_window == wdesc)
f79e6790
JR
425 return f;
426
fbd6baed 427 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
428 return f;
429 }
430 return 0;
431}
432
433\f
434
435/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
436 id, which is just an int that this section returns. Bitmaps are
437 reference counted so they can be shared among frames.
438
439 Bitmap indices are guaranteed to be > 0, so a negative number can
440 be used to indicate no bitmap.
441
442 If you use x_create_bitmap_from_data, then you must keep track of
443 the bitmaps yourself. That is, creating a bitmap from the same
444 data more than once will not be caught. */
445
446
447/* Functions to access the contents of a bitmap, given an id. */
448
449int
450x_bitmap_height (f, id)
451 FRAME_PTR f;
452 int id;
453{
fbd6baed 454 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
455}
456
457int
458x_bitmap_width (f, id)
459 FRAME_PTR f;
460 int id;
461{
fbd6baed 462 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
463}
464
465int
466x_bitmap_pixmap (f, id)
467 FRAME_PTR f;
468 int id;
469{
fbd6baed 470 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
471}
472
473
474/* Allocate a new bitmap record. Returns index of new record. */
475
476static int
477x_allocate_bitmap_record (f)
478 FRAME_PTR f;
479{
fbd6baed 480 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
481 int i;
482
483 if (dpyinfo->bitmaps == NULL)
484 {
485 dpyinfo->bitmaps_size = 10;
486 dpyinfo->bitmaps
fbd6baed 487 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
488 dpyinfo->bitmaps_last = 1;
489 return 1;
490 }
491
492 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
493 return ++dpyinfo->bitmaps_last;
494
495 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
496 if (dpyinfo->bitmaps[i].refcount == 0)
497 return i + 1;
498
499 dpyinfo->bitmaps_size *= 2;
500 dpyinfo->bitmaps
fbd6baed
GV
501 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
502 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
503 return ++dpyinfo->bitmaps_last;
504}
505
506/* Add one reference to the reference count of the bitmap with id ID. */
507
508void
509x_reference_bitmap (f, id)
510 FRAME_PTR f;
511 int id;
512{
fbd6baed 513 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
514}
515
516/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
517
518int
519x_create_bitmap_from_data (f, bits, width, height)
520 struct frame *f;
521 char *bits;
522 unsigned int width, height;
523{
fbd6baed 524 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
525 Pixmap bitmap;
526 int id;
527
528 bitmap = CreateBitmap (width, height,
fbd6baed
GV
529 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
530 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
531 bits);
532
533 if (! bitmap)
534 return -1;
535
536 id = x_allocate_bitmap_record (f);
537 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
538 dpyinfo->bitmaps[id - 1].file = NULL;
539 dpyinfo->bitmaps[id - 1].hinst = NULL;
540 dpyinfo->bitmaps[id - 1].refcount = 1;
541 dpyinfo->bitmaps[id - 1].depth = 1;
542 dpyinfo->bitmaps[id - 1].height = height;
543 dpyinfo->bitmaps[id - 1].width = width;
544
545 return id;
546}
547
548/* Create bitmap from file FILE for frame F. */
549
550int
551x_create_bitmap_from_file (f, file)
552 struct frame *f;
553 Lisp_Object file;
554{
555 return -1;
767b1ff0 556#if 0 /* TODO : bitmap support */
fbd6baed 557 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32 558 unsigned int width, height;
6fc2811b 559 HBITMAP bitmap;
ee78dc32
GV
560 int xhot, yhot, result, id;
561 Lisp_Object found;
562 int fd;
563 char *filename;
564 HINSTANCE hinst;
565
566 /* Look for an existing bitmap with the same name. */
567 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
568 {
569 if (dpyinfo->bitmaps[id].refcount
570 && dpyinfo->bitmaps[id].file
571 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
572 {
573 ++dpyinfo->bitmaps[id].refcount;
574 return id + 1;
575 }
576 }
577
578 /* Search bitmap-file-path for the file, if appropriate. */
de2413e9 579 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
ee78dc32
GV
580 if (fd < 0)
581 return -1;
6fc2811b 582 emacs_close (fd);
ee78dc32
GV
583
584 filename = (char *) XSTRING (found)->data;
585
586 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
587
588 if (hinst == NULL)
589 return -1;
590
591
fbd6baed 592 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
593 filename, &width, &height, &bitmap, &xhot, &yhot);
594 if (result != BitmapSuccess)
595 return -1;
596
597 id = x_allocate_bitmap_record (f);
598 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
599 dpyinfo->bitmaps[id - 1].refcount = 1;
600 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
601 dpyinfo->bitmaps[id - 1].depth = 1;
602 dpyinfo->bitmaps[id - 1].height = height;
603 dpyinfo->bitmaps[id - 1].width = width;
604 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
605
606 return id;
767b1ff0 607#endif /* TODO */
ee78dc32
GV
608}
609
610/* Remove reference to bitmap with id number ID. */
611
33d52f9c 612void
ee78dc32
GV
613x_destroy_bitmap (f, id)
614 FRAME_PTR f;
615 int id;
616{
fbd6baed 617 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
618
619 if (id > 0)
620 {
621 --dpyinfo->bitmaps[id - 1].refcount;
622 if (dpyinfo->bitmaps[id - 1].refcount == 0)
623 {
624 BLOCK_INPUT;
625 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
626 if (dpyinfo->bitmaps[id - 1].file)
627 {
6fc2811b 628 xfree (dpyinfo->bitmaps[id - 1].file);
ee78dc32
GV
629 dpyinfo->bitmaps[id - 1].file = NULL;
630 }
631 UNBLOCK_INPUT;
632 }
633 }
634}
635
636/* Free all the bitmaps for the display specified by DPYINFO. */
637
638static void
639x_destroy_all_bitmaps (dpyinfo)
fbd6baed 640 struct w32_display_info *dpyinfo;
ee78dc32
GV
641{
642 int i;
643 for (i = 0; i < dpyinfo->bitmaps_last; i++)
644 if (dpyinfo->bitmaps[i].refcount > 0)
645 {
646 DeleteObject (dpyinfo->bitmaps[i].pixmap);
647 if (dpyinfo->bitmaps[i].file)
6fc2811b 648 xfree (dpyinfo->bitmaps[i].file);
ee78dc32
GV
649 }
650 dpyinfo->bitmaps_last = 0;
651}
652\f
fbd6baed 653/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
654 to the ways of passing the parameter values to the window system.
655
656 The name of a parameter, as a Lisp symbol,
657 has an `x-frame-parameter' property which is an integer in Lisp
658 but can be interpreted as an `enum x_frame_parm' in C. */
659
660enum x_frame_parm
661{
662 X_PARM_FOREGROUND_COLOR,
663 X_PARM_BACKGROUND_COLOR,
664 X_PARM_MOUSE_COLOR,
665 X_PARM_CURSOR_COLOR,
666 X_PARM_BORDER_COLOR,
667 X_PARM_ICON_TYPE,
668 X_PARM_FONT,
669 X_PARM_BORDER_WIDTH,
670 X_PARM_INTERNAL_BORDER_WIDTH,
671 X_PARM_NAME,
672 X_PARM_AUTORAISE,
673 X_PARM_AUTOLOWER,
674 X_PARM_VERT_SCROLL_BAR,
675 X_PARM_VISIBILITY,
676 X_PARM_MENU_BAR_LINES
677};
678
679
680struct x_frame_parm_table
681{
682 char *name;
6fc2811b 683 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
ee78dc32
GV
684};
685
ca56d953
JR
686BOOL my_show_window P_ ((struct frame *, HWND, int));
687void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
937e601e
AI
688static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
689static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
690static void x_change_window_heights P_ ((Lisp_Object, int));
767b1ff0 691/* TODO: Native Input Method support; see x_create_im. */
6fc2811b 692void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
dfff8a69 693static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
f7b9d4d1 694static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
695void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
696void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
697void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
698void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
699void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
700void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
701void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
702void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
41c1bdd9 703static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
6fc2811b
JR
704void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
705void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
706 Lisp_Object));
707void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
708void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
709void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
710void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
711 Lisp_Object));
712void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
713void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
714void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
715void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
716void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
717void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
718static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
3cf3436e
JR
719static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
720 Lisp_Object));
ee78dc32
GV
721
722static struct x_frame_parm_table x_frame_parms[] =
723{
72e4adef
JR
724 {"auto-raise", x_set_autoraise},
725 {"auto-lower", x_set_autolower},
726 {"background-color", x_set_background_color},
727 {"border-color", x_set_border_color},
728 {"border-width", x_set_border_width},
729 {"cursor-color", x_set_cursor_color},
730 {"cursor-type", x_set_cursor_type},
731 {"font", x_set_font},
732 {"foreground-color", x_set_foreground_color},
733 {"icon-name", x_set_icon_name},
734 {"icon-type", x_set_icon_type},
735 {"internal-border-width", x_set_internal_border_width},
736 {"menu-bar-lines", x_set_menu_bar_lines},
737 {"mouse-color", x_set_mouse_color},
738 {"name", x_explicitly_set_name},
739 {"scroll-bar-width", x_set_scroll_bar_width},
740 {"title", x_set_title},
741 {"unsplittable", x_set_unsplittable},
742 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
743 {"visibility", x_set_visibility},
744 {"tool-bar-lines", x_set_tool_bar_lines},
745 {"screen-gamma", x_set_screen_gamma},
746 {"line-spacing", x_set_line_spacing},
747 {"left-fringe", x_set_fringe_width},
f7b9d4d1
JR
748 {"right-fringe", x_set_fringe_width},
749 {"fullscreen", x_set_fullscreen},
ee78dc32
GV
750};
751
752/* Attach the `x-frame-parameter' properties to
fbd6baed 753 the Lisp symbol names of parameters relevant to W32. */
ee78dc32 754
dfff8a69 755void
ee78dc32
GV
756init_x_parm_symbols ()
757{
758 int i;
759
760 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
761 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
762 make_number (i));
763}
764\f
f7b9d4d1
JR
765/* Really try to move where we want to be in case of fullscreen. Some WMs
766 moves the window where we tell them. Some (mwm, twm) moves the outer
767 window manager window there instead.
768 Try to compensate for those WM here. */
769static void
770x_fullscreen_move (f, new_top, new_left)
771 struct frame *f;
772 int new_top;
773 int new_left;
774{
775 if (new_top != f->output_data.w32->top_pos
776 || new_left != f->output_data.w32->left_pos)
777 {
778 int move_x = new_left;
779 int move_y = new_top;
780
781 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
782 x_set_offset (f, move_x, move_y, 1);
783 }
784}
785
dfff8a69 786/* Change the parameters of frame F as specified by ALIST.
ee78dc32
GV
787 If a parameter is not specially recognized, do nothing;
788 otherwise call the `x_set_...' function for that parameter. */
789
790void
791x_set_frame_parameters (f, alist)
792 FRAME_PTR f;
793 Lisp_Object alist;
794{
795 Lisp_Object tail;
796
797 /* If both of these parameters are present, it's more efficient to
798 set them both at once. So we wait until we've looked at the
799 entire list before we set them. */
b839712d 800 int width, height;
ee78dc32
GV
801
802 /* Same here. */
803 Lisp_Object left, top;
804
805 /* Same with these. */
806 Lisp_Object icon_left, icon_top;
807
808 /* Record in these vectors all the parms specified. */
809 Lisp_Object *parms;
810 Lisp_Object *values;
a797a73d 811 int i, p;
ee78dc32
GV
812 int left_no_change = 0, top_no_change = 0;
813 int icon_left_no_change = 0, icon_top_no_change = 0;
f7b9d4d1 814 int fullscreen_is_being_set = 0;
ee78dc32 815
5878523b
RS
816 struct gcpro gcpro1, gcpro2;
817
ee78dc32
GV
818 i = 0;
819 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
820 i++;
821
822 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
823 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
824
825 /* Extract parm names and values into those vectors. */
826
827 i = 0;
828 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
829 {
6fc2811b 830 Lisp_Object elt;
ee78dc32
GV
831
832 elt = Fcar (tail);
833 parms[i] = Fcar (elt);
834 values[i] = Fcdr (elt);
835 i++;
836 }
5878523b
RS
837 /* TAIL and ALIST are not used again below here. */
838 alist = tail = Qnil;
839
840 GCPRO2 (*parms, *values);
841 gcpro1.nvars = i;
842 gcpro2.nvars = i;
843
844 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
845 because their values appear in VALUES and strings are not valid. */
b839712d 846 top = left = Qunbound;
ee78dc32
GV
847 icon_left = icon_top = Qunbound;
848
b839712d 849 /* Provide default values for HEIGHT and WIDTH. */
dfff8a69
JR
850 if (FRAME_NEW_WIDTH (f))
851 width = FRAME_NEW_WIDTH (f);
852 else
853 width = FRAME_WIDTH (f);
854
855 if (FRAME_NEW_HEIGHT (f))
856 height = FRAME_NEW_HEIGHT (f);
857 else
858 height = FRAME_HEIGHT (f);
b839712d 859
a797a73d
GV
860 /* Process foreground_color and background_color before anything else.
861 They are independent of other properties, but other properties (e.g.,
862 cursor_color) are dependent upon them. */
41c1bdd9 863 /* Process default font as well, since fringe widths depends on it. */
a797a73d
GV
864 for (p = 0; p < i; p++)
865 {
866 Lisp_Object prop, val;
867
868 prop = parms[p];
869 val = values[p];
41c1bdd9
KS
870 if (EQ (prop, Qforeground_color)
871 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
872 || EQ (prop, Qfont)
873 || EQ (prop, Qfullscreen))
a797a73d
GV
874 {
875 register Lisp_Object param_index, old_value;
876
a797a73d 877 old_value = get_frame_param (f, prop);
f7b9d4d1 878 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
a05e2bae
JR
879
880 if (NILP (Fequal (val, old_value)))
881 {
882 store_frame_param (f, prop, val);
883
884 param_index = Fget (prop, Qx_frame_parameter);
885 if (NATNUMP (param_index)
886 && (XFASTINT (param_index)
887 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
888 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
889 }
a797a73d
GV
890 }
891 }
892
ee78dc32
GV
893 /* Now process them in reverse of specified order. */
894 for (i--; i >= 0; i--)
895 {
896 Lisp_Object prop, val;
897
898 prop = parms[i];
899 val = values[i];
900
b839712d
RS
901 if (EQ (prop, Qwidth) && NUMBERP (val))
902 width = XFASTINT (val);
903 else if (EQ (prop, Qheight) && NUMBERP (val))
904 height = XFASTINT (val);
ee78dc32
GV
905 else if (EQ (prop, Qtop))
906 top = val;
907 else if (EQ (prop, Qleft))
908 left = val;
909 else if (EQ (prop, Qicon_top))
910 icon_top = val;
911 else if (EQ (prop, Qicon_left))
912 icon_left = val;
41c1bdd9
KS
913 else if (EQ (prop, Qforeground_color)
914 || EQ (prop, Qbackground_color)
f7b9d4d1
JR
915 || EQ (prop, Qfont)
916 || EQ (prop, Qfullscreen))
a797a73d
GV
917 /* Processed above. */
918 continue;
ee78dc32
GV
919 else
920 {
921 register Lisp_Object param_index, old_value;
922
ee78dc32 923 old_value = get_frame_param (f, prop);
a05e2bae 924
ee78dc32 925 store_frame_param (f, prop, val);
a05e2bae
JR
926
927 param_index = Fget (prop, Qx_frame_parameter);
ee78dc32
GV
928 if (NATNUMP (param_index)
929 && (XFASTINT (param_index)
930 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 931 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
932 }
933 }
934
935 /* Don't die if just one of these was set. */
936 if (EQ (left, Qunbound))
937 {
938 left_no_change = 1;
fbd6baed
GV
939 if (f->output_data.w32->left_pos < 0)
940 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 941 else
fbd6baed 942 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
943 }
944 if (EQ (top, Qunbound))
945 {
946 top_no_change = 1;
fbd6baed
GV
947 if (f->output_data.w32->top_pos < 0)
948 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 949 else
fbd6baed 950 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
951 }
952
953 /* If one of the icon positions was not set, preserve or default it. */
954 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
955 {
956 icon_left_no_change = 1;
957 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
958 if (NILP (icon_left))
959 XSETINT (icon_left, 0);
960 }
961 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
962 {
963 icon_top_no_change = 1;
964 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
965 if (NILP (icon_top))
966 XSETINT (icon_top, 0);
967 }
968
f7b9d4d1
JR
969 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
970 {
971 /* If the frame is visible already and the fullscreen parameter is
972 being set, it is too late to set WM manager hints to specify
973 size and position.
974 Here we first get the width, height and position that applies to
975 fullscreen. We then move the frame to the appropriate
976 position. Resize of the frame is taken care of in the code after
977 this if-statement. */
978 int new_left, new_top;
979
980 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
981 x_fullscreen_move (f, new_top, new_left);
982 }
983
ee78dc32
GV
984 /* Don't set these parameters unless they've been explicitly
985 specified. The window might be mapped or resized while we're in
986 this function, and we don't want to override that unless the lisp
987 code has asked for it.
988
989 Don't set these parameters unless they actually differ from the
990 window's current parameters; the window may not actually exist
991 yet. */
992 {
993 Lisp_Object frame;
994
995 check_frame_size (f, &height, &width);
996
997 XSETFRAME (frame, f);
998
dfff8a69
JR
999 if (width != FRAME_WIDTH (f)
1000 || height != FRAME_HEIGHT (f)
1001 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
b839712d 1002 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
1003
1004 if ((!NILP (left) || !NILP (top))
1005 && ! (left_no_change && top_no_change)
fbd6baed
GV
1006 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1007 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
1008 {
1009 int leftpos = 0;
1010 int toppos = 0;
1011
1012 /* Record the signs. */
fbd6baed 1013 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 1014 if (EQ (left, Qminus))
fbd6baed 1015 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
1016 else if (INTEGERP (left))
1017 {
1018 leftpos = XINT (left);
1019 if (leftpos < 0)
fbd6baed 1020 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1021 }
8e713be6
KR
1022 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1023 && CONSP (XCDR (left))
1024 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1025 {
8e713be6 1026 leftpos = - XINT (XCAR (XCDR (left)));
fbd6baed 1027 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32 1028 }
8e713be6
KR
1029 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1030 && CONSP (XCDR (left))
1031 && INTEGERP (XCAR (XCDR (left))))
ee78dc32 1032 {
8e713be6 1033 leftpos = XINT (XCAR (XCDR (left)));
ee78dc32
GV
1034 }
1035
1036 if (EQ (top, Qminus))
fbd6baed 1037 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
1038 else if (INTEGERP (top))
1039 {
1040 toppos = XINT (top);
1041 if (toppos < 0)
fbd6baed 1042 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1043 }
8e713be6
KR
1044 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1045 && CONSP (XCDR (top))
1046 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1047 {
8e713be6 1048 toppos = - XINT (XCAR (XCDR (top)));
fbd6baed 1049 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32 1050 }
8e713be6
KR
1051 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1052 && CONSP (XCDR (top))
1053 && INTEGERP (XCAR (XCDR (top))))
ee78dc32 1054 {
8e713be6 1055 toppos = XINT (XCAR (XCDR (top)));
ee78dc32
GV
1056 }
1057
1058
1059 /* Store the numeric value of the position. */
fbd6baed
GV
1060 f->output_data.w32->top_pos = toppos;
1061 f->output_data.w32->left_pos = leftpos;
ee78dc32 1062
fbd6baed 1063 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
1064
1065 /* Actually set that position, and convert to absolute. */
1066 x_set_offset (f, leftpos, toppos, -1);
1067 }
1068
1069 if ((!NILP (icon_left) || !NILP (icon_top))
1070 && ! (icon_left_no_change && icon_top_no_change))
1071 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1072 }
5878523b
RS
1073
1074 UNGCPRO;
ee78dc32
GV
1075}
1076
1077/* Store the screen positions of frame F into XPTR and YPTR.
1078 These are the positions of the containing window manager window,
1079 not Emacs's own window. */
1080
1081void
1082x_real_positions (f, xptr, yptr)
1083 FRAME_PTR f;
1084 int *xptr, *yptr;
1085{
1086 POINT pt;
f7b9d4d1 1087 RECT rect;
3c190163 1088
f7b9d4d1
JR
1089 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1090 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1091
1092 pt.x = rect.left;
1093 pt.y = rect.top;
ee78dc32 1094
fbd6baed 1095 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32 1096
f7b9d4d1
JR
1097 /* Remember x_pixels_diff and y_pixels_diff. */
1098 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1099 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1100
ee78dc32
GV
1101 *xptr = pt.x;
1102 *yptr = pt.y;
1103}
1104
1105/* Insert a description of internally-recorded parameters of frame X
1106 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 1107 Only parameters that are specific to W32
ee78dc32
GV
1108 and whose values are not correctly recorded in the frame's
1109 param_alist need to be considered here. */
1110
dfff8a69 1111void
ee78dc32
GV
1112x_report_frame_params (f, alistptr)
1113 struct frame *f;
1114 Lisp_Object *alistptr;
1115{
1116 char buf[16];
1117 Lisp_Object tem;
1118
1119 /* Represent negative positions (off the top or left screen edge)
1120 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
1121 XSETINT (tem, f->output_data.w32->left_pos);
1122 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
1123 store_in_alist (alistptr, Qleft, tem);
1124 else
1125 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1126
fbd6baed
GV
1127 XSETINT (tem, f->output_data.w32->top_pos);
1128 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
1129 store_in_alist (alistptr, Qtop, tem);
1130 else
1131 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1132
1133 store_in_alist (alistptr, Qborder_width,
fbd6baed 1134 make_number (f->output_data.w32->border_width));
ee78dc32 1135 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed 1136 make_number (f->output_data.w32->internal_border_width));
e90c3f90
KS
1137 store_in_alist (alistptr, Qleft_fringe,
1138 make_number (f->output_data.w32->left_fringe_width));
1139 store_in_alist (alistptr, Qright_fringe,
1140 make_number (f->output_data.w32->right_fringe_width));
aa17b858
EZ
1141 store_in_alist (alistptr, Qscroll_bar_width,
1142 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1143 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1144 : 0));
fbd6baed 1145 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
1146 store_in_alist (alistptr, Qwindow_id,
1147 build_string (buf));
1148 store_in_alist (alistptr, Qicon_name, f->icon_name);
1149 FRAME_SAMPLE_VISIBILITY (f);
1150 store_in_alist (alistptr, Qvisibility,
1151 (FRAME_VISIBLE_P (f) ? Qt
1152 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1153 store_in_alist (alistptr, Qdisplay,
8e713be6 1154 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
ee78dc32
GV
1155}
1156\f
1157
74e1aeec
JR
1158DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1159 Sw32_define_rgb_color, 4, 4, 0,
1160 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1161This adds or updates a named color to w32-color-map, making it
1162available for use. The original entry's RGB ref is returned, or nil
1163if the entry is new. */)
5ac45f98
GV
1164 (red, green, blue, name)
1165 Lisp_Object red, green, blue, name;
ee78dc32 1166{
5ac45f98
GV
1167 Lisp_Object rgb;
1168 Lisp_Object oldrgb = Qnil;
1169 Lisp_Object entry;
1170
b7826503
PJ
1171 CHECK_NUMBER (red);
1172 CHECK_NUMBER (green);
1173 CHECK_NUMBER (blue);
1174 CHECK_STRING (name);
ee78dc32 1175
5ac45f98 1176 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 1177
5ac45f98 1178 BLOCK_INPUT;
ee78dc32 1179
fbd6baed
GV
1180 /* replace existing entry in w32-color-map or add new entry. */
1181 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
1182 if (NILP (entry))
1183 {
1184 entry = Fcons (name, rgb);
fbd6baed 1185 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
1186 }
1187 else
1188 {
1189 oldrgb = Fcdr (entry);
1190 Fsetcdr (entry, rgb);
1191 }
1192
1193 UNBLOCK_INPUT;
1194
1195 return (oldrgb);
ee78dc32
GV
1196}
1197
74e1aeec
JR
1198DEFUN ("w32-load-color-file", Fw32_load_color_file,
1199 Sw32_load_color_file, 1, 1, 0,
1200 doc: /* Create an alist of color entries from an external file.
1201Assign this value to w32-color-map to replace the existing color map.
1202
1203The file should define one named RGB color per line like so:
1204 R G B name
1205where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
5ac45f98
GV
1206 (filename)
1207 Lisp_Object filename;
1208{
1209 FILE *fp;
1210 Lisp_Object cmap = Qnil;
1211 Lisp_Object abspath;
1212
b7826503 1213 CHECK_STRING (filename);
5ac45f98
GV
1214 abspath = Fexpand_file_name (filename, Qnil);
1215
1216 fp = fopen (XSTRING (filename)->data, "rt");
1217 if (fp)
1218 {
1219 char buf[512];
1220 int red, green, blue;
1221 int num;
1222
1223 BLOCK_INPUT;
1224
1225 while (fgets (buf, sizeof (buf), fp) != NULL) {
1226 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1227 {
1228 char *name = buf + num;
1229 num = strlen (name) - 1;
1230 if (name[num] == '\n')
1231 name[num] = 0;
1232 cmap = Fcons (Fcons (build_string (name),
1233 make_number (RGB (red, green, blue))),
1234 cmap);
1235 }
1236 }
1237 fclose (fp);
1238
1239 UNBLOCK_INPUT;
1240 }
1241
1242 return cmap;
1243}
ee78dc32 1244
fbd6baed 1245/* The default colors for the w32 color map */
ee78dc32
GV
1246typedef struct colormap_t
1247{
1248 char *name;
1249 COLORREF colorref;
1250} colormap_t;
1251
fbd6baed 1252colormap_t w32_color_map[] =
ee78dc32 1253{
1da8a614
GV
1254 {"snow" , PALETTERGB (255,250,250)},
1255 {"ghost white" , PALETTERGB (248,248,255)},
1256 {"GhostWhite" , PALETTERGB (248,248,255)},
1257 {"white smoke" , PALETTERGB (245,245,245)},
1258 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1259 {"gainsboro" , PALETTERGB (220,220,220)},
1260 {"floral white" , PALETTERGB (255,250,240)},
1261 {"FloralWhite" , PALETTERGB (255,250,240)},
1262 {"old lace" , PALETTERGB (253,245,230)},
1263 {"OldLace" , PALETTERGB (253,245,230)},
1264 {"linen" , PALETTERGB (250,240,230)},
1265 {"antique white" , PALETTERGB (250,235,215)},
1266 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1267 {"papaya whip" , PALETTERGB (255,239,213)},
1268 {"PapayaWhip" , PALETTERGB (255,239,213)},
1269 {"blanched almond" , PALETTERGB (255,235,205)},
1270 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1271 {"bisque" , PALETTERGB (255,228,196)},
1272 {"peach puff" , PALETTERGB (255,218,185)},
1273 {"PeachPuff" , PALETTERGB (255,218,185)},
1274 {"navajo white" , PALETTERGB (255,222,173)},
1275 {"NavajoWhite" , PALETTERGB (255,222,173)},
1276 {"moccasin" , PALETTERGB (255,228,181)},
1277 {"cornsilk" , PALETTERGB (255,248,220)},
1278 {"ivory" , PALETTERGB (255,255,240)},
1279 {"lemon chiffon" , PALETTERGB (255,250,205)},
1280 {"LemonChiffon" , PALETTERGB (255,250,205)},
1281 {"seashell" , PALETTERGB (255,245,238)},
1282 {"honeydew" , PALETTERGB (240,255,240)},
1283 {"mint cream" , PALETTERGB (245,255,250)},
1284 {"MintCream" , PALETTERGB (245,255,250)},
1285 {"azure" , PALETTERGB (240,255,255)},
1286 {"alice blue" , PALETTERGB (240,248,255)},
1287 {"AliceBlue" , PALETTERGB (240,248,255)},
1288 {"lavender" , PALETTERGB (230,230,250)},
1289 {"lavender blush" , PALETTERGB (255,240,245)},
1290 {"LavenderBlush" , PALETTERGB (255,240,245)},
1291 {"misty rose" , PALETTERGB (255,228,225)},
1292 {"MistyRose" , PALETTERGB (255,228,225)},
1293 {"white" , PALETTERGB (255,255,255)},
1294 {"black" , PALETTERGB ( 0, 0, 0)},
1295 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1296 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1297 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1298 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1299 {"dim gray" , PALETTERGB (105,105,105)},
1300 {"DimGray" , PALETTERGB (105,105,105)},
1301 {"dim grey" , PALETTERGB (105,105,105)},
1302 {"DimGrey" , PALETTERGB (105,105,105)},
1303 {"slate gray" , PALETTERGB (112,128,144)},
1304 {"SlateGray" , PALETTERGB (112,128,144)},
1305 {"slate grey" , PALETTERGB (112,128,144)},
1306 {"SlateGrey" , PALETTERGB (112,128,144)},
1307 {"light slate gray" , PALETTERGB (119,136,153)},
1308 {"LightSlateGray" , PALETTERGB (119,136,153)},
1309 {"light slate grey" , PALETTERGB (119,136,153)},
1310 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1311 {"gray" , PALETTERGB (190,190,190)},
1312 {"grey" , PALETTERGB (190,190,190)},
1313 {"light grey" , PALETTERGB (211,211,211)},
1314 {"LightGrey" , PALETTERGB (211,211,211)},
1315 {"light gray" , PALETTERGB (211,211,211)},
1316 {"LightGray" , PALETTERGB (211,211,211)},
1317 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1318 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1319 {"navy" , PALETTERGB ( 0, 0,128)},
1320 {"navy blue" , PALETTERGB ( 0, 0,128)},
1321 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1322 {"cornflower blue" , PALETTERGB (100,149,237)},
1323 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1324 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1325 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1326 {"slate blue" , PALETTERGB (106, 90,205)},
1327 {"SlateBlue" , PALETTERGB (106, 90,205)},
1328 {"medium slate blue" , PALETTERGB (123,104,238)},
1329 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1330 {"light slate blue" , PALETTERGB (132,112,255)},
1331 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1332 {"medium blue" , PALETTERGB ( 0, 0,205)},
1333 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1334 {"royal blue" , PALETTERGB ( 65,105,225)},
1335 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1336 {"blue" , PALETTERGB ( 0, 0,255)},
1337 {"dodger blue" , PALETTERGB ( 30,144,255)},
1338 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1339 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1340 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1341 {"sky blue" , PALETTERGB (135,206,235)},
1342 {"SkyBlue" , PALETTERGB (135,206,235)},
1343 {"light sky blue" , PALETTERGB (135,206,250)},
1344 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1345 {"steel blue" , PALETTERGB ( 70,130,180)},
1346 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1347 {"light steel blue" , PALETTERGB (176,196,222)},
1348 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1349 {"light blue" , PALETTERGB (173,216,230)},
1350 {"LightBlue" , PALETTERGB (173,216,230)},
1351 {"powder blue" , PALETTERGB (176,224,230)},
1352 {"PowderBlue" , PALETTERGB (176,224,230)},
1353 {"pale turquoise" , PALETTERGB (175,238,238)},
1354 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1355 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1356 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1357 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1358 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1359 {"turquoise" , PALETTERGB ( 64,224,208)},
1360 {"cyan" , PALETTERGB ( 0,255,255)},
1361 {"light cyan" , PALETTERGB (224,255,255)},
1362 {"LightCyan" , PALETTERGB (224,255,255)},
1363 {"cadet blue" , PALETTERGB ( 95,158,160)},
1364 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1365 {"medium aquamarine" , PALETTERGB (102,205,170)},
1366 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1367 {"aquamarine" , PALETTERGB (127,255,212)},
1368 {"dark green" , PALETTERGB ( 0,100, 0)},
1369 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1370 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1371 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1372 {"dark sea green" , PALETTERGB (143,188,143)},
1373 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1374 {"sea green" , PALETTERGB ( 46,139, 87)},
1375 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1376 {"medium sea green" , PALETTERGB ( 60,179,113)},
1377 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1378 {"light sea green" , PALETTERGB ( 32,178,170)},
1379 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1380 {"pale green" , PALETTERGB (152,251,152)},
1381 {"PaleGreen" , PALETTERGB (152,251,152)},
1382 {"spring green" , PALETTERGB ( 0,255,127)},
1383 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1384 {"lawn green" , PALETTERGB (124,252, 0)},
1385 {"LawnGreen" , PALETTERGB (124,252, 0)},
1386 {"green" , PALETTERGB ( 0,255, 0)},
1387 {"chartreuse" , PALETTERGB (127,255, 0)},
1388 {"medium spring green" , PALETTERGB ( 0,250,154)},
1389 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1390 {"green yellow" , PALETTERGB (173,255, 47)},
1391 {"GreenYellow" , PALETTERGB (173,255, 47)},
1392 {"lime green" , PALETTERGB ( 50,205, 50)},
1393 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1394 {"yellow green" , PALETTERGB (154,205, 50)},
1395 {"YellowGreen" , PALETTERGB (154,205, 50)},
1396 {"forest green" , PALETTERGB ( 34,139, 34)},
1397 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1398 {"olive drab" , PALETTERGB (107,142, 35)},
1399 {"OliveDrab" , PALETTERGB (107,142, 35)},
1400 {"dark khaki" , PALETTERGB (189,183,107)},
1401 {"DarkKhaki" , PALETTERGB (189,183,107)},
1402 {"khaki" , PALETTERGB (240,230,140)},
1403 {"pale goldenrod" , PALETTERGB (238,232,170)},
1404 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1405 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1406 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1407 {"light yellow" , PALETTERGB (255,255,224)},
1408 {"LightYellow" , PALETTERGB (255,255,224)},
1409 {"yellow" , PALETTERGB (255,255, 0)},
1410 {"gold" , PALETTERGB (255,215, 0)},
1411 {"light goldenrod" , PALETTERGB (238,221,130)},
1412 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1413 {"goldenrod" , PALETTERGB (218,165, 32)},
1414 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1415 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1416 {"rosy brown" , PALETTERGB (188,143,143)},
1417 {"RosyBrown" , PALETTERGB (188,143,143)},
1418 {"indian red" , PALETTERGB (205, 92, 92)},
1419 {"IndianRed" , PALETTERGB (205, 92, 92)},
1420 {"saddle brown" , PALETTERGB (139, 69, 19)},
1421 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1422 {"sienna" , PALETTERGB (160, 82, 45)},
1423 {"peru" , PALETTERGB (205,133, 63)},
1424 {"burlywood" , PALETTERGB (222,184,135)},
1425 {"beige" , PALETTERGB (245,245,220)},
1426 {"wheat" , PALETTERGB (245,222,179)},
1427 {"sandy brown" , PALETTERGB (244,164, 96)},
1428 {"SandyBrown" , PALETTERGB (244,164, 96)},
1429 {"tan" , PALETTERGB (210,180,140)},
1430 {"chocolate" , PALETTERGB (210,105, 30)},
1431 {"firebrick" , PALETTERGB (178,34, 34)},
1432 {"brown" , PALETTERGB (165,42, 42)},
1433 {"dark salmon" , PALETTERGB (233,150,122)},
1434 {"DarkSalmon" , PALETTERGB (233,150,122)},
1435 {"salmon" , PALETTERGB (250,128,114)},
1436 {"light salmon" , PALETTERGB (255,160,122)},
1437 {"LightSalmon" , PALETTERGB (255,160,122)},
1438 {"orange" , PALETTERGB (255,165, 0)},
1439 {"dark orange" , PALETTERGB (255,140, 0)},
1440 {"DarkOrange" , PALETTERGB (255,140, 0)},
1441 {"coral" , PALETTERGB (255,127, 80)},
1442 {"light coral" , PALETTERGB (240,128,128)},
1443 {"LightCoral" , PALETTERGB (240,128,128)},
1444 {"tomato" , PALETTERGB (255, 99, 71)},
1445 {"orange red" , PALETTERGB (255, 69, 0)},
1446 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1447 {"red" , PALETTERGB (255, 0, 0)},
1448 {"hot pink" , PALETTERGB (255,105,180)},
1449 {"HotPink" , PALETTERGB (255,105,180)},
1450 {"deep pink" , PALETTERGB (255, 20,147)},
1451 {"DeepPink" , PALETTERGB (255, 20,147)},
1452 {"pink" , PALETTERGB (255,192,203)},
1453 {"light pink" , PALETTERGB (255,182,193)},
1454 {"LightPink" , PALETTERGB (255,182,193)},
1455 {"pale violet red" , PALETTERGB (219,112,147)},
1456 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1457 {"maroon" , PALETTERGB (176, 48, 96)},
1458 {"medium violet red" , PALETTERGB (199, 21,133)},
1459 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1460 {"violet red" , PALETTERGB (208, 32,144)},
1461 {"VioletRed" , PALETTERGB (208, 32,144)},
1462 {"magenta" , PALETTERGB (255, 0,255)},
1463 {"violet" , PALETTERGB (238,130,238)},
1464 {"plum" , PALETTERGB (221,160,221)},
1465 {"orchid" , PALETTERGB (218,112,214)},
1466 {"medium orchid" , PALETTERGB (186, 85,211)},
1467 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1468 {"dark orchid" , PALETTERGB (153, 50,204)},
1469 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1470 {"dark violet" , PALETTERGB (148, 0,211)},
1471 {"DarkViolet" , PALETTERGB (148, 0,211)},
1472 {"blue violet" , PALETTERGB (138, 43,226)},
1473 {"BlueViolet" , PALETTERGB (138, 43,226)},
1474 {"purple" , PALETTERGB (160, 32,240)},
1475 {"medium purple" , PALETTERGB (147,112,219)},
1476 {"MediumPurple" , PALETTERGB (147,112,219)},
1477 {"thistle" , PALETTERGB (216,191,216)},
1478 {"gray0" , PALETTERGB ( 0, 0, 0)},
1479 {"grey0" , PALETTERGB ( 0, 0, 0)},
1480 {"dark grey" , PALETTERGB (169,169,169)},
1481 {"DarkGrey" , PALETTERGB (169,169,169)},
1482 {"dark gray" , PALETTERGB (169,169,169)},
1483 {"DarkGray" , PALETTERGB (169,169,169)},
1484 {"dark blue" , PALETTERGB ( 0, 0,139)},
1485 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1486 {"dark cyan" , PALETTERGB ( 0,139,139)},
1487 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1488 {"dark magenta" , PALETTERGB (139, 0,139)},
1489 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1490 {"dark red" , PALETTERGB (139, 0, 0)},
1491 {"DarkRed" , PALETTERGB (139, 0, 0)},
1492 {"light green" , PALETTERGB (144,238,144)},
1493 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1494};
1495
fbd6baed 1496DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
74e1aeec 1497 0, 0, 0, doc: /* Return the default color map. */)
ee78dc32
GV
1498 ()
1499{
1500 int i;
fbd6baed 1501 colormap_t *pc = w32_color_map;
ee78dc32
GV
1502 Lisp_Object cmap;
1503
1504 BLOCK_INPUT;
1505
1506 cmap = Qnil;
1507
fbd6baed 1508 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1509 pc++, i++)
1510 cmap = Fcons (Fcons (build_string (pc->name),
1511 make_number (pc->colorref)),
1512 cmap);
1513
1514 UNBLOCK_INPUT;
1515
1516 return (cmap);
1517}
ee78dc32
GV
1518
1519Lisp_Object
fbd6baed 1520w32_to_x_color (rgb)
ee78dc32
GV
1521 Lisp_Object rgb;
1522{
1523 Lisp_Object color;
1524
b7826503 1525 CHECK_NUMBER (rgb);
ee78dc32
GV
1526
1527 BLOCK_INPUT;
1528
fbd6baed 1529 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1530
1531 UNBLOCK_INPUT;
1532
1533 if (!NILP (color))
1534 return (Fcar (color));
1535 else
1536 return Qnil;
1537}
1538
5d7fed93
GV
1539COLORREF
1540w32_color_map_lookup (colorname)
1541 char *colorname;
1542{
1543 Lisp_Object tail, ret = Qnil;
1544
1545 BLOCK_INPUT;
1546
1547 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1548 {
1549 register Lisp_Object elt, tem;
1550
1551 elt = Fcar (tail);
1552 if (!CONSP (elt)) continue;
1553
1554 tem = Fcar (elt);
1555
1556 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1557 {
1558 ret = XUINT (Fcdr (elt));
1559 break;
1560 }
1561
1562 QUIT;
1563 }
1564
1565
1566 UNBLOCK_INPUT;
1567
1568 return ret;
1569}
1570
ee78dc32 1571COLORREF
fbd6baed 1572x_to_w32_color (colorname)
ee78dc32
GV
1573 char * colorname;
1574{
8edb0a6f
JR
1575 register Lisp_Object ret = Qnil;
1576
ee78dc32 1577 BLOCK_INPUT;
1edf84e7
GV
1578
1579 if (colorname[0] == '#')
1580 {
1581 /* Could be an old-style RGB Device specification. */
1582 char *color;
1583 int size;
1584 color = colorname + 1;
1585
1586 size = strlen(color);
1587 if (size == 3 || size == 6 || size == 9 || size == 12)
1588 {
1589 UINT colorval;
1590 int i, pos;
1591 pos = 0;
1592 size /= 3;
1593 colorval = 0;
1594
1595 for (i = 0; i < 3; i++)
1596 {
1597 char *end;
1598 char t;
1599 unsigned long value;
1600
1601 /* The check for 'x' in the following conditional takes into
1602 account the fact that strtol allows a "0x" in front of
1603 our numbers, and we don't. */
1604 if (!isxdigit(color[0]) || color[1] == 'x')
1605 break;
1606 t = color[size];
1607 color[size] = '\0';
1608 value = strtoul(color, &end, 16);
1609 color[size] = t;
1610 if (errno == ERANGE || end - color != size)
1611 break;
1612 switch (size)
1613 {
1614 case 1:
1615 value = value * 0x10;
1616 break;
1617 case 2:
1618 break;
1619 case 3:
1620 value /= 0x10;
1621 break;
1622 case 4:
1623 value /= 0x100;
1624 break;
1625 }
1626 colorval |= (value << pos);
1627 pos += 0x8;
1628 if (i == 2)
1629 {
1630 UNBLOCK_INPUT;
1631 return (colorval);
1632 }
1633 color = end;
1634 }
1635 }
1636 }
1637 else if (strnicmp(colorname, "rgb:", 4) == 0)
1638 {
1639 char *color;
1640 UINT colorval;
1641 int i, pos;
1642 pos = 0;
1643
1644 colorval = 0;
1645 color = colorname + 4;
1646 for (i = 0; i < 3; i++)
1647 {
1648 char *end;
1649 unsigned long value;
1650
1651 /* The check for 'x' in the following conditional takes into
1652 account the fact that strtol allows a "0x" in front of
1653 our numbers, and we don't. */
1654 if (!isxdigit(color[0]) || color[1] == 'x')
1655 break;
1656 value = strtoul(color, &end, 16);
1657 if (errno == ERANGE)
1658 break;
1659 switch (end - color)
1660 {
1661 case 1:
1662 value = value * 0x10 + value;
1663 break;
1664 case 2:
1665 break;
1666 case 3:
1667 value /= 0x10;
1668 break;
1669 case 4:
1670 value /= 0x100;
1671 break;
1672 default:
1673 value = ULONG_MAX;
1674 }
1675 if (value == ULONG_MAX)
1676 break;
1677 colorval |= (value << pos);
1678 pos += 0x8;
1679 if (i == 2)
1680 {
1681 if (*end != '\0')
1682 break;
1683 UNBLOCK_INPUT;
1684 return (colorval);
1685 }
1686 if (*end != '/')
1687 break;
1688 color = end + 1;
1689 }
1690 }
1691 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1692 {
1693 /* This is an RGB Intensity specification. */
1694 char *color;
1695 UINT colorval;
1696 int i, pos;
1697 pos = 0;
1698
1699 colorval = 0;
1700 color = colorname + 5;
1701 for (i = 0; i < 3; i++)
1702 {
1703 char *end;
1704 double value;
1705 UINT val;
1706
1707 value = strtod(color, &end);
1708 if (errno == ERANGE)
1709 break;
1710 if (value < 0.0 || value > 1.0)
1711 break;
1712 val = (UINT)(0x100 * value);
1713 /* We used 0x100 instead of 0xFF to give an continuous
1714 range between 0.0 and 1.0 inclusive. The next statement
1715 fixes the 1.0 case. */
1716 if (val == 0x100)
1717 val = 0xFF;
1718 colorval |= (val << pos);
1719 pos += 0x8;
1720 if (i == 2)
1721 {
1722 if (*end != '\0')
1723 break;
1724 UNBLOCK_INPUT;
1725 return (colorval);
1726 }
1727 if (*end != '/')
1728 break;
1729 color = end + 1;
1730 }
1731 }
1732 /* I am not going to attempt to handle any of the CIE color schemes
1733 or TekHVC, since I don't know the algorithms for conversion to
1734 RGB. */
f695b4b1
GV
1735
1736 /* If we fail to lookup the color name in w32_color_map, then check the
1737 colorname to see if it can be crudely approximated: If the X color
1738 ends in a number (e.g., "darkseagreen2"), strip the number and
1739 return the result of looking up the base color name. */
1740 ret = w32_color_map_lookup (colorname);
1741 if (NILP (ret))
ee78dc32 1742 {
f695b4b1 1743 int len = strlen (colorname);
ee78dc32 1744
f695b4b1
GV
1745 if (isdigit (colorname[len - 1]))
1746 {
8b77111c 1747 char *ptr, *approx = alloca (len + 1);
ee78dc32 1748
f695b4b1
GV
1749 strcpy (approx, colorname);
1750 ptr = &approx[len - 1];
1751 while (ptr > approx && isdigit (*ptr))
1752 *ptr-- = '\0';
ee78dc32 1753
f695b4b1 1754 ret = w32_color_map_lookup (approx);
ee78dc32 1755 }
ee78dc32
GV
1756 }
1757
1758 UNBLOCK_INPUT;
ee78dc32
GV
1759 return ret;
1760}
1761
5ac45f98
GV
1762
1763void
fbd6baed 1764w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1765{
fbd6baed 1766 struct w32_palette_entry * list;
5ac45f98
GV
1767 LOGPALETTE * log_palette;
1768 HPALETTE new_palette;
1769 int i;
1770
1771 /* don't bother trying to create palette if not supported */
fbd6baed 1772 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1773 return;
1774
1775 log_palette = (LOGPALETTE *)
1776 alloca (sizeof (LOGPALETTE) +
fbd6baed 1777 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1778 log_palette->palVersion = 0x300;
fbd6baed 1779 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1780
fbd6baed 1781 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1782 for (i = 0;
fbd6baed 1783 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1784 i++, list = list->next)
1785 log_palette->palPalEntry[i] = list->entry;
1786
1787 new_palette = CreatePalette (log_palette);
1788
1789 enter_crit ();
1790
fbd6baed
GV
1791 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1792 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1793 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1794
1795 /* Realize display palette and garbage all frames. */
1796 release_frame_dc (f, get_frame_dc (f));
1797
1798 leave_crit ();
1799}
1800
fbd6baed
GV
1801#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1802#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1803 do \
1804 { \
1805 pe.peRed = GetRValue (color); \
1806 pe.peGreen = GetGValue (color); \
1807 pe.peBlue = GetBValue (color); \
1808 pe.peFlags = 0; \
1809 } while (0)
1810
1811#if 0
1812/* Keep these around in case we ever want to track color usage. */
1813void
fbd6baed 1814w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1815{
fbd6baed 1816 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1817
fbd6baed 1818 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1819 return;
1820
1821 /* check if color is already mapped */
1822 while (list)
1823 {
fbd6baed 1824 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1825 {
1826 ++list->refcount;
1827 return;
1828 }
1829 list = list->next;
1830 }
1831
1832 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1833 list = (struct w32_palette_entry *)
1834 xmalloc (sizeof (struct w32_palette_entry));
1835 SET_W32_COLOR (list->entry, color);
5ac45f98 1836 list->refcount = 1;
fbd6baed
GV
1837 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1838 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1839 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1840
1841 /* set flag that palette must be regenerated */
fbd6baed 1842 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1843}
1844
1845void
fbd6baed 1846w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1847{
fbd6baed
GV
1848 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1849 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1850
fbd6baed 1851 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1852 return;
1853
1854 /* check if color is already mapped */
1855 while (list)
1856 {
fbd6baed 1857 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1858 {
1859 if (--list->refcount == 0)
1860 {
1861 *prev = list->next;
1862 xfree (list);
fbd6baed 1863 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1864 break;
1865 }
1866 else
1867 return;
1868 }
1869 prev = &list->next;
1870 list = list->next;
1871 }
1872
1873 /* set flag that palette must be regenerated */
fbd6baed 1874 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1875}
1876#endif
1877
6fc2811b
JR
1878
1879/* Gamma-correct COLOR on frame F. */
1880
1881void
1882gamma_correct (f, color)
1883 struct frame *f;
1884 COLORREF *color;
1885{
1886 if (f->gamma)
1887 {
1888 *color = PALETTERGB (
1889 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1890 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1891 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1892 }
1893}
1894
1895
ee78dc32
GV
1896/* Decide if color named COLOR is valid for the display associated with
1897 the selected frame; if so, return the rgb values in COLOR_DEF.
1898 If ALLOC is nonzero, allocate a new colormap cell. */
1899
1900int
6fc2811b 1901w32_defined_color (f, color, color_def, alloc)
ee78dc32
GV
1902 FRAME_PTR f;
1903 char *color;
6fc2811b 1904 XColor *color_def;
ee78dc32
GV
1905 int alloc;
1906{
1907 register Lisp_Object tem;
6fc2811b 1908 COLORREF w32_color_ref;
3c190163 1909
fbd6baed 1910 tem = x_to_w32_color (color);
3c190163 1911
ee78dc32
GV
1912 if (!NILP (tem))
1913 {
d88c567c
JR
1914 if (f)
1915 {
1916 /* Apply gamma correction. */
1917 w32_color_ref = XUINT (tem);
1918 gamma_correct (f, &w32_color_ref);
1919 XSETINT (tem, w32_color_ref);
1920 }
9badad41
JR
1921
1922 /* Map this color to the palette if it is enabled. */
fbd6baed 1923 if (!NILP (Vw32_enable_palette))
5ac45f98 1924 {
fbd6baed 1925 struct w32_palette_entry * entry =
d88c567c 1926 one_w32_display_info.color_list;
fbd6baed 1927 struct w32_palette_entry ** prev =
d88c567c 1928 &one_w32_display_info.color_list;
5ac45f98
GV
1929
1930 /* check if color is already mapped */
1931 while (entry)
1932 {
fbd6baed 1933 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1934 break;
1935 prev = &entry->next;
1936 entry = entry->next;
1937 }
1938
1939 if (entry == NULL && alloc)
1940 {
1941 /* not already mapped, so add to list */
fbd6baed
GV
1942 entry = (struct w32_palette_entry *)
1943 xmalloc (sizeof (struct w32_palette_entry));
1944 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1945 entry->next = NULL;
1946 *prev = entry;
d88c567c 1947 one_w32_display_info.num_colors++;
5ac45f98
GV
1948
1949 /* set flag that palette must be regenerated */
d88c567c 1950 one_w32_display_info.regen_palette = TRUE;
5ac45f98
GV
1951 }
1952 }
1953 /* Ensure COLORREF value is snapped to nearest color in (default)
1954 palette by simulating the PALETTERGB macro. This works whether
1955 or not the display device has a palette. */
6fc2811b
JR
1956 w32_color_ref = XUINT (tem) | 0x2000000;
1957
6fc2811b
JR
1958 color_def->pixel = w32_color_ref;
1959 color_def->red = GetRValue (w32_color_ref);
1960 color_def->green = GetGValue (w32_color_ref);
1961 color_def->blue = GetBValue (w32_color_ref);
1962
ee78dc32 1963 return 1;
5ac45f98 1964 }
7fb46567 1965 else
3c190163
GV
1966 {
1967 return 0;
1968 }
ee78dc32
GV
1969}
1970
1971/* Given a string ARG naming a color, compute a pixel value from it
1972 suitable for screen F.
1973 If F is not a color screen, return DEF (default) regardless of what
1974 ARG says. */
1975
1976int
1977x_decode_color (f, arg, def)
1978 FRAME_PTR f;
1979 Lisp_Object arg;
1980 int def;
1981{
6fc2811b 1982 XColor cdef;
ee78dc32 1983
b7826503 1984 CHECK_STRING (arg);
ee78dc32
GV
1985
1986 if (strcmp (XSTRING (arg)->data, "black") == 0)
1987 return BLACK_PIX_DEFAULT (f);
1988 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1989 return WHITE_PIX_DEFAULT (f);
1990
fbd6baed 1991 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1992 return def;
1993
6fc2811b 1994 /* w32_defined_color is responsible for coping with failures
ee78dc32 1995 by looking for a near-miss. */
6fc2811b
JR
1996 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1997 return cdef.pixel;
ee78dc32
GV
1998
1999 /* defined_color failed; return an ultimate default. */
2000 return def;
2001}
2002\f
dfff8a69
JR
2003/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2004 the previous value of that parameter, NEW_VALUE is the new value. */
2005
2006static void
2007x_set_line_spacing (f, new_value, old_value)
2008 struct frame *f;
2009 Lisp_Object new_value, old_value;
2010{
2011 if (NILP (new_value))
2012 f->extra_line_spacing = 0;
2013 else if (NATNUMP (new_value))
2014 f->extra_line_spacing = XFASTINT (new_value);
2015 else
1a948b17 2016 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
dfff8a69
JR
2017 Fcons (new_value, Qnil)));
2018 if (FRAME_VISIBLE_P (f))
2019 redraw_frame (f);
2020}
2021
2022
f7b9d4d1
JR
2023/* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2024 the previous value of that parameter, NEW_VALUE is the new value. */
2025
2026static void
2027x_set_fullscreen (f, new_value, old_value)
2028 struct frame *f;
2029 Lisp_Object new_value, old_value;
2030{
2031 if (NILP (new_value))
2032 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2033 else if (EQ (new_value, Qfullboth))
2034 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2035 else if (EQ (new_value, Qfullwidth))
2036 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2037 else if (EQ (new_value, Qfullheight))
2038 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2039}
2040
2041
6fc2811b
JR
2042/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2043 the previous value of that parameter, NEW_VALUE is the new value. */
2044
2045static void
2046x_set_screen_gamma (f, new_value, old_value)
2047 struct frame *f;
2048 Lisp_Object new_value, old_value;
2049{
2050 if (NILP (new_value))
2051 f->gamma = 0;
2052 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2053 /* The value 0.4545 is the normal viewing gamma. */
2054 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2055 else
1a948b17 2056 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
6fc2811b
JR
2057 Fcons (new_value, Qnil)));
2058
2059 clear_face_cache (0);
2060}
2061
2062
ee78dc32
GV
2063/* Functions called only from `x_set_frame_param'
2064 to set individual parameters.
2065
fbd6baed 2066 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
2067 the frame is being created and its window does not exist yet.
2068 In that case, just record the parameter's new value
2069 in the standard place; do not attempt to change the window. */
2070
2071void
2072x_set_foreground_color (f, arg, oldval)
2073 struct frame *f;
2074 Lisp_Object arg, oldval;
2075{
3cf3436e
JR
2076 struct w32_output *x = f->output_data.w32;
2077 PIX_TYPE fg, old_fg;
2078
2079 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2080 old_fg = FRAME_FOREGROUND_PIXEL (f);
2081 FRAME_FOREGROUND_PIXEL (f) = fg;
5ac45f98 2082
fbd6baed 2083 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2084 {
3cf3436e
JR
2085 if (x->cursor_pixel == old_fg)
2086 x->cursor_pixel = fg;
2087
6fc2811b 2088 update_face_from_frame_parameter (f, Qforeground_color, arg);
ee78dc32
GV
2089 if (FRAME_VISIBLE_P (f))
2090 redraw_frame (f);
2091 }
2092}
2093
2094void
2095x_set_background_color (f, arg, oldval)
2096 struct frame *f;
2097 Lisp_Object arg, oldval;
2098{
6fc2811b 2099 FRAME_BACKGROUND_PIXEL (f)
ee78dc32
GV
2100 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2101
fbd6baed 2102 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2103 {
6fc2811b
JR
2104 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2105 FRAME_BACKGROUND_PIXEL (f));
ee78dc32 2106
6fc2811b 2107 update_face_from_frame_parameter (f, Qbackground_color, arg);
ee78dc32
GV
2108
2109 if (FRAME_VISIBLE_P (f))
2110 redraw_frame (f);
2111 }
2112}
2113
2114void
2115x_set_mouse_color (f, arg, oldval)
2116 struct frame *f;
2117 Lisp_Object arg, oldval;
2118{
ee78dc32 2119 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
dfc465d3 2120 int count;
ee78dc32
GV
2121 int mask_color;
2122
2123 if (!EQ (Qnil, arg))
fbd6baed 2124 f->output_data.w32->mouse_pixel
ee78dc32 2125 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
6fc2811b
JR
2126 mask_color = FRAME_BACKGROUND_PIXEL (f);
2127
2128 /* Don't let pointers be invisible. */
fbd6baed 2129 if (mask_color == f->output_data.w32->mouse_pixel
6fc2811b
JR
2130 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2131 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
ee78dc32 2132
767b1ff0 2133#if 0 /* TODO : cursor changes */
ee78dc32
GV
2134 BLOCK_INPUT;
2135
2136 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 2137 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2138
2139 if (!EQ (Qnil, Vx_pointer_shape))
2140 {
b7826503 2141 CHECK_NUMBER (Vx_pointer_shape);
fbd6baed 2142 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
2143 }
2144 else
fbd6baed
GV
2145 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2146 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
2147
2148 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2149 {
b7826503 2150 CHECK_NUMBER (Vx_nontext_pointer_shape);
fbd6baed 2151 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2152 XINT (Vx_nontext_pointer_shape));
2153 }
2154 else
fbd6baed
GV
2155 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2156 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32 2157
0af913d7 2158 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
6fc2811b 2159 {
b7826503 2160 CHECK_NUMBER (Vx_hourglass_pointer_shape);
0af913d7
GM
2161 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2162 XINT (Vx_hourglass_pointer_shape));
6fc2811b
JR
2163 }
2164 else
0af913d7 2165 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
6fc2811b
JR
2166 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2167
2168 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
2169 if (!EQ (Qnil, Vx_mode_pointer_shape))
2170 {
b7826503 2171 CHECK_NUMBER (Vx_mode_pointer_shape);
fbd6baed 2172 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2173 XINT (Vx_mode_pointer_shape));
2174 }
2175 else
fbd6baed
GV
2176 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2177 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
2178
2179 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2180 {
b7826503 2181 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
ee78dc32 2182 cross_cursor
fbd6baed 2183 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
2184 XINT (Vx_sensitive_text_pointer_shape));
2185 }
2186 else
fbd6baed 2187 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32 2188
4694d762
JR
2189 if (!NILP (Vx_window_horizontal_drag_shape))
2190 {
b7826503 2191 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
4694d762
JR
2192 horizontal_drag_cursor
2193 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2194 XINT (Vx_window_horizontal_drag_shape));
2195 }
2196 else
2197 horizontal_drag_cursor
2198 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2199
ee78dc32 2200 /* Check and report errors with the above calls. */
fbd6baed 2201 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 2202 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
2203
2204 {
2205 XColor fore_color, back_color;
2206
fbd6baed 2207 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 2208 back_color.pixel = mask_color;
fbd6baed
GV
2209 XQueryColor (FRAME_W32_DISPLAY (f),
2210 DefaultColormap (FRAME_W32_DISPLAY (f),
2211 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2212 &fore_color);
fbd6baed
GV
2213 XQueryColor (FRAME_W32_DISPLAY (f),
2214 DefaultColormap (FRAME_W32_DISPLAY (f),
2215 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 2216 &back_color);
fbd6baed 2217 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 2218 &fore_color, &back_color);
fbd6baed 2219 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 2220 &fore_color, &back_color);
fbd6baed 2221 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 2222 &fore_color, &back_color);
fbd6baed 2223 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32 2224 &fore_color, &back_color);
0af913d7 2225 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
6fc2811b 2226 &fore_color, &back_color);
ee78dc32
GV
2227 }
2228
fbd6baed 2229 if (FRAME_W32_WINDOW (f) != 0)
6fc2811b 2230 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32 2231
fbd6baed
GV
2232 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2233 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2234 f->output_data.w32->text_cursor = cursor;
2235
2236 if (nontext_cursor != f->output_data.w32->nontext_cursor
2237 && f->output_data.w32->nontext_cursor != 0)
2238 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2239 f->output_data.w32->nontext_cursor = nontext_cursor;
2240
0af913d7
GM
2241 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2242 && f->output_data.w32->hourglass_cursor != 0)
2243 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2244 f->output_data.w32->hourglass_cursor = hourglass_cursor;
6fc2811b 2245
fbd6baed
GV
2246 if (mode_cursor != f->output_data.w32->modeline_cursor
2247 && f->output_data.w32->modeline_cursor != 0)
2248 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2249 f->output_data.w32->modeline_cursor = mode_cursor;
6fc2811b 2250
fbd6baed
GV
2251 if (cross_cursor != f->output_data.w32->cross_cursor
2252 && f->output_data.w32->cross_cursor != 0)
2253 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2254 f->output_data.w32->cross_cursor = cross_cursor;
2255
2256 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32 2257 UNBLOCK_INPUT;
6fc2811b
JR
2258
2259 update_face_from_frame_parameter (f, Qmouse_color, arg);
767b1ff0 2260#endif /* TODO */
ee78dc32
GV
2261}
2262
70a0239a
JR
2263/* Defined in w32term.c. */
2264void x_update_cursor (struct frame *f, int on_p);
2265
ee78dc32
GV
2266void
2267x_set_cursor_color (f, arg, oldval)
2268 struct frame *f;
2269 Lisp_Object arg, oldval;
2270{
70a0239a 2271 unsigned long fore_pixel, pixel;
ee78dc32 2272
dfff8a69 2273 if (!NILP (Vx_cursor_fore_pixel))
ee78dc32 2274 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
70a0239a 2275 WHITE_PIX_DEFAULT (f));
ee78dc32 2276 else
6fc2811b 2277 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
70a0239a 2278
6759f872 2279 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
2280
2281 /* Make sure that the cursor color differs from the background color. */
70a0239a 2282 if (pixel == FRAME_BACKGROUND_PIXEL (f))
ee78dc32 2283 {
70a0239a
JR
2284 pixel = f->output_data.w32->mouse_pixel;
2285 if (pixel == fore_pixel)
6fc2811b 2286 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
ee78dc32 2287 }
70a0239a 2288
ac849ba4 2289 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
70a0239a 2290 f->output_data.w32->cursor_pixel = pixel;
ee78dc32 2291
fbd6baed 2292 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2293 {
0327b4cc
JR
2294 BLOCK_INPUT;
2295 /* Update frame's cursor_gc. */
2296 f->output_data.w32->cursor_gc->foreground = fore_pixel;
2297 f->output_data.w32->cursor_gc->background = pixel;
2298
2299 UNBLOCK_INPUT;
2300
ee78dc32
GV
2301 if (FRAME_VISIBLE_P (f))
2302 {
70a0239a
JR
2303 x_update_cursor (f, 0);
2304 x_update_cursor (f, 1);
ee78dc32
GV
2305 }
2306 }
6fc2811b
JR
2307
2308 update_face_from_frame_parameter (f, Qcursor_color, arg);
ee78dc32
GV
2309}
2310
33d52f9c
GV
2311/* Set the border-color of frame F to pixel value PIX.
2312 Note that this does not fully take effect if done before
2313 F has an window. */
2314void
2315x_set_border_pixel (f, pix)
2316 struct frame *f;
2317 int pix;
2318{
2319 f->output_data.w32->border_pixel = pix;
2320
2321 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2322 {
2323 if (FRAME_VISIBLE_P (f))
2324 redraw_frame (f);
2325 }
2326}
2327
ee78dc32
GV
2328/* Set the border-color of frame F to value described by ARG.
2329 ARG can be a string naming a color.
2330 The border-color is used for the border that is drawn by the server.
2331 Note that this does not fully take effect if done before
2332 F has a window; it must be redone when the window is created. */
2333
2334void
2335x_set_border_color (f, arg, oldval)
2336 struct frame *f;
2337 Lisp_Object arg, oldval;
2338{
ee78dc32
GV
2339 int pix;
2340
b7826503 2341 CHECK_STRING (arg);
ee78dc32 2342 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32 2343 x_set_border_pixel (f, pix);
6fc2811b 2344 update_face_from_frame_parameter (f, Qborder_color, arg);
ee78dc32
GV
2345}
2346
dfff8a69
JR
2347/* Value is the internal representation of the specified cursor type
2348 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2349 of the bar cursor. */
2350
2351enum text_cursor_kinds
2352x_specified_cursor_type (arg, width)
2353 Lisp_Object arg;
2354 int *width;
ee78dc32 2355{
dfff8a69
JR
2356 enum text_cursor_kinds type;
2357
ee78dc32
GV
2358 if (EQ (arg, Qbar))
2359 {
dfff8a69
JR
2360 type = BAR_CURSOR;
2361 *width = 2;
ee78dc32 2362 }
dfff8a69
JR
2363 else if (CONSP (arg)
2364 && EQ (XCAR (arg), Qbar)
2365 && INTEGERP (XCDR (arg))
2366 && XINT (XCDR (arg)) >= 0)
ee78dc32 2367 {
dfff8a69
JR
2368 type = BAR_CURSOR;
2369 *width = XINT (XCDR (arg));
ee78dc32 2370 }
dfff8a69
JR
2371 else if (NILP (arg))
2372 type = NO_CURSOR;
ee78dc32
GV
2373 else
2374 /* Treat anything unknown as "box cursor".
2375 It was bad to signal an error; people have trouble fixing
2376 .Xdefaults with Emacs, when it has something bad in it. */
dfff8a69
JR
2377 type = FILLED_BOX_CURSOR;
2378
2379 return type;
2380}
2381
2382void
2383x_set_cursor_type (f, arg, oldval)
2384 FRAME_PTR f;
2385 Lisp_Object arg, oldval;
2386{
2387 int width;
2388
2389 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2390 f->output_data.w32->cursor_width = width;
ee78dc32
GV
2391
2392 /* Make sure the cursor gets redrawn. This is overkill, but how
2393 often do people change cursor types? */
2394 update_mode_lines++;
2395}
dfff8a69 2396\f
ee78dc32
GV
2397void
2398x_set_icon_type (f, arg, oldval)
2399 struct frame *f;
2400 Lisp_Object arg, oldval;
2401{
ee78dc32
GV
2402 int result;
2403
eb7576ce
GV
2404 if (NILP (arg) && NILP (oldval))
2405 return;
2406
2407 if (STRINGP (arg) && STRINGP (oldval)
2408 && EQ (Fstring_equal (oldval, arg), Qt))
2409 return;
2410
2411 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
ee78dc32
GV
2412 return;
2413
2414 BLOCK_INPUT;
ee78dc32 2415
eb7576ce 2416 result = x_bitmap_icon (f, arg);
ee78dc32
GV
2417 if (result)
2418 {
2419 UNBLOCK_INPUT;
2420 error ("No icon window available");
2421 }
2422
ee78dc32 2423 UNBLOCK_INPUT;
ee78dc32
GV
2424}
2425
2426/* Return non-nil if frame F wants a bitmap icon. */
2427
2428Lisp_Object
2429x_icon_type (f)
2430 FRAME_PTR f;
2431{
2432 Lisp_Object tem;
2433
2434 tem = assq_no_quit (Qicon_type, f->param_alist);
2435 if (CONSP (tem))
8e713be6 2436 return XCDR (tem);
ee78dc32
GV
2437 else
2438 return Qnil;
2439}
2440
2441void
2442x_set_icon_name (f, arg, oldval)
2443 struct frame *f;
2444 Lisp_Object arg, oldval;
2445{
ee78dc32
GV
2446 if (STRINGP (arg))
2447 {
2448 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2449 return;
2450 }
2451 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2452 return;
2453
2454 f->icon_name = arg;
2455
2456#if 0
fbd6baed 2457 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2458 return;
2459
2460 BLOCK_INPUT;
2461
2462 result = x_text_icon (f,
1edf84e7 2463 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2464 ? f->icon_name
1edf84e7
GV
2465 : !NILP (f->title)
2466 ? f->title
ee78dc32
GV
2467 : f->name))->data);
2468
2469 if (result)
2470 {
2471 UNBLOCK_INPUT;
2472 error ("No icon window available");
2473 }
2474
2475 /* If the window was unmapped (and its icon was mapped),
2476 the new icon is not mapped, so map the window in its stead. */
2477 if (FRAME_VISIBLE_P (f))
2478 {
2479#ifdef USE_X_TOOLKIT
fbd6baed 2480 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2481#endif
fbd6baed 2482 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2483 }
2484
fbd6baed 2485 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2486 UNBLOCK_INPUT;
2487#endif
2488}
2489
2490extern Lisp_Object x_new_font ();
4587b026 2491extern Lisp_Object x_new_fontset();
ee78dc32
GV
2492
2493void
2494x_set_font (f, arg, oldval)
2495 struct frame *f;
2496 Lisp_Object arg, oldval;
2497{
2498 Lisp_Object result;
4587b026 2499 Lisp_Object fontset_name;
4b817373 2500 Lisp_Object frame;
3cf3436e 2501 int old_fontset = FRAME_FONTSET(f);
ee78dc32 2502
b7826503 2503 CHECK_STRING (arg);
ee78dc32 2504
4587b026
GV
2505 fontset_name = Fquery_fontset (arg, Qnil);
2506
ee78dc32 2507 BLOCK_INPUT;
4587b026
GV
2508 result = (STRINGP (fontset_name)
2509 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2510 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2511 UNBLOCK_INPUT;
2512
2513 if (EQ (result, Qnil))
dfff8a69 2514 error ("Font `%s' is not defined", XSTRING (arg)->data);
ee78dc32 2515 else if (EQ (result, Qt))
dfff8a69 2516 error ("The characters of the given font have varying widths");
ee78dc32
GV
2517 else if (STRINGP (result))
2518 {
3cf3436e
JR
2519 if (STRINGP (fontset_name))
2520 {
2521 /* Fontset names are built from ASCII font names, so the
2522 names may be equal despite there was a change. */
2523 if (old_fontset == FRAME_FONTSET (f))
2524 return;
2525 }
2526 else if (!NILP (Fequal (result, oldval)))
dc220243 2527 return;
3cf3436e 2528
ee78dc32 2529 store_frame_param (f, Qfont, result);
6fc2811b 2530 recompute_basic_faces (f);
ee78dc32
GV
2531 }
2532 else
2533 abort ();
4b817373 2534
6fc2811b
JR
2535 do_pending_window_change (0);
2536
2537 /* Don't call `face-set-after-frame-default' when faces haven't been
2538 initialized yet. This is the case when called from
2539 Fx_create_frame. In that case, the X widget or window doesn't
2540 exist either, and we can end up in x_report_frame_params with a
2541 null widget which gives a segfault. */
2542 if (FRAME_FACE_CACHE (f))
2543 {
2544 XSETFRAME (frame, f);
2545 call1 (Qface_set_after_frame_default, frame);
2546 }
ee78dc32
GV
2547}
2548
41c1bdd9
KS
2549static void
2550x_set_fringe_width (f, new_value, old_value)
2551 struct frame *f;
2552 Lisp_Object new_value, old_value;
2553{
2554 x_compute_fringe_widths (f, 1);
2555}
2556
ee78dc32
GV
2557void
2558x_set_border_width (f, arg, oldval)
2559 struct frame *f;
2560 Lisp_Object arg, oldval;
2561{
b7826503 2562 CHECK_NUMBER (arg);
ee78dc32 2563
fbd6baed 2564 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2565 return;
2566
fbd6baed 2567 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2568 error ("Cannot change the border width of a window");
2569
fbd6baed 2570 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2571}
2572
2573void
2574x_set_internal_border_width (f, arg, oldval)
2575 struct frame *f;
2576 Lisp_Object arg, oldval;
2577{
fbd6baed 2578 int old = f->output_data.w32->internal_border_width;
ee78dc32 2579
b7826503 2580 CHECK_NUMBER (arg);
fbd6baed
GV
2581 f->output_data.w32->internal_border_width = XINT (arg);
2582 if (f->output_data.w32->internal_border_width < 0)
2583 f->output_data.w32->internal_border_width = 0;
ee78dc32 2584
fbd6baed 2585 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2586 return;
2587
fbd6baed 2588 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 2589 {
ee78dc32 2590 x_set_window_size (f, 0, f->width, f->height);
ee78dc32 2591 SET_FRAME_GARBAGED (f);
6fc2811b 2592 do_pending_window_change (0);
ee78dc32 2593 }
a05e2bae
JR
2594 else
2595 SET_FRAME_GARBAGED (f);
ee78dc32
GV
2596}
2597
2598void
2599x_set_visibility (f, value, oldval)
2600 struct frame *f;
2601 Lisp_Object value, oldval;
2602{
2603 Lisp_Object frame;
2604 XSETFRAME (frame, f);
2605
2606 if (NILP (value))
2607 Fmake_frame_invisible (frame, Qt);
2608 else if (EQ (value, Qicon))
2609 Ficonify_frame (frame);
2610 else
2611 Fmake_frame_visible (frame);
2612}
2613
a1258667
JR
2614\f
2615/* Change window heights in windows rooted in WINDOW by N lines. */
2616
2617static void
2618x_change_window_heights (window, n)
2619 Lisp_Object window;
2620 int n;
2621{
2622 struct window *w = XWINDOW (window);
2623
2624 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2625 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2626
2627 if (INTEGERP (w->orig_top))
2628 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2629 if (INTEGERP (w->orig_height))
2630 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2631
2632 /* Handle just the top child in a vertical split. */
2633 if (!NILP (w->vchild))
2634 x_change_window_heights (w->vchild, n);
2635
2636 /* Adjust all children in a horizontal split. */
2637 for (window = w->hchild; !NILP (window); window = w->next)
2638 {
2639 w = XWINDOW (window);
2640 x_change_window_heights (window, n);
2641 }
2642}
2643
ee78dc32
GV
2644void
2645x_set_menu_bar_lines (f, value, oldval)
2646 struct frame *f;
2647 Lisp_Object value, oldval;
2648{
2649 int nlines;
2650 int olines = FRAME_MENU_BAR_LINES (f);
2651
2652 /* Right now, menu bars don't work properly in minibuf-only frames;
2653 most of the commands try to apply themselves to the minibuffer
6fc2811b 2654 frame itself, and get an error because you can't switch buffers
ee78dc32
GV
2655 in or split the minibuffer window. */
2656 if (FRAME_MINIBUF_ONLY_P (f))
2657 return;
2658
2659 if (INTEGERP (value))
2660 nlines = XINT (value);
2661 else
2662 nlines = 0;
2663
2664 FRAME_MENU_BAR_LINES (f) = 0;
2665 if (nlines)
2666 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2667 else
2668 {
2669 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2670 free_frame_menubar (f);
2671 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2672
2673 /* Adjust the frame size so that the client (text) dimensions
2674 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2675 set correctly. */
2676 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2677 do_pending_window_change (0);
ee78dc32 2678 }
6fc2811b
JR
2679 adjust_glyphs (f);
2680}
2681
2682
2683/* Set the number of lines used for the tool bar of frame F to VALUE.
2684 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2685 is the old number of tool bar lines. This function changes the
2686 height of all windows on frame F to match the new tool bar height.
2687 The frame's height doesn't change. */
2688
2689void
2690x_set_tool_bar_lines (f, value, oldval)
2691 struct frame *f;
2692 Lisp_Object value, oldval;
2693{
36f8209a
JR
2694 int delta, nlines, root_height;
2695 Lisp_Object root_window;
6fc2811b 2696
dc220243
JR
2697 /* Treat tool bars like menu bars. */
2698 if (FRAME_MINIBUF_ONLY_P (f))
2699 return;
2700
6fc2811b
JR
2701 /* Use VALUE only if an integer >= 0. */
2702 if (INTEGERP (value) && XINT (value) >= 0)
2703 nlines = XFASTINT (value);
2704 else
2705 nlines = 0;
2706
2707 /* Make sure we redisplay all windows in this frame. */
2708 ++windows_or_buffers_changed;
2709
2710 delta = nlines - FRAME_TOOL_BAR_LINES (f);
36f8209a
JR
2711
2712 /* Don't resize the tool-bar to more than we have room for. */
2713 root_window = FRAME_ROOT_WINDOW (f);
2714 root_height = XINT (XWINDOW (root_window)->height);
2715 if (root_height - delta < 1)
2716 {
2717 delta = root_height - 1;
2718 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2719 }
2720
6fc2811b 2721 FRAME_TOOL_BAR_LINES (f) = nlines;
36f8209a 2722 x_change_window_heights (root_window, delta);
6fc2811b 2723 adjust_glyphs (f);
36f8209a
JR
2724
2725 /* We also have to make sure that the internal border at the top of
2726 the frame, below the menu bar or tool bar, is redrawn when the
2727 tool bar disappears. This is so because the internal border is
2728 below the tool bar if one is displayed, but is below the menu bar
2729 if there isn't a tool bar. The tool bar draws into the area
2730 below the menu bar. */
2731 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2732 {
2733 updating_frame = f;
2734 clear_frame ();
2735 clear_current_matrices (f);
2736 updating_frame = NULL;
2737 }
2738
2739 /* If the tool bar gets smaller, the internal border below it
2740 has to be cleared. It was formerly part of the display
2741 of the larger tool bar, and updating windows won't clear it. */
2742 if (delta < 0)
2743 {
2744 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2745 int width = PIXEL_WIDTH (f);
2746 int y = nlines * CANON_Y_UNIT (f);
2747
2748 BLOCK_INPUT;
2749 {
2750 HDC hdc = get_frame_dc (f);
2751 w32_clear_area (f, hdc, 0, y, width, height);
2752 release_frame_dc (f, hdc);
2753 }
2754 UNBLOCK_INPUT;
3cf3436e
JR
2755
2756 if (WINDOWP (f->tool_bar_window))
2757 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
36f8209a 2758 }
ee78dc32
GV
2759}
2760
6fc2811b 2761
ee78dc32 2762/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2763 w32_id_name.
ee78dc32
GV
2764
2765 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2766 name; if NAME is a string, set F's name to NAME and set
2767 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2768
2769 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2770 suggesting a new name, which lisp code should override; if
2771 F->explicit_name is set, ignore the new name; otherwise, set it. */
2772
2773void
2774x_set_name (f, name, explicit)
2775 struct frame *f;
2776 Lisp_Object name;
2777 int explicit;
2778{
2779 /* Make sure that requests from lisp code override requests from
2780 Emacs redisplay code. */
2781 if (explicit)
2782 {
2783 /* If we're switching from explicit to implicit, we had better
2784 update the mode lines and thereby update the title. */
2785 if (f->explicit_name && NILP (name))
2786 update_mode_lines = 1;
2787
2788 f->explicit_name = ! NILP (name);
2789 }
2790 else if (f->explicit_name)
2791 return;
2792
fbd6baed 2793 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2794 if (NILP (name))
2795 {
2796 /* Check for no change needed in this very common case
2797 before we do any consing. */
fbd6baed 2798 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2799 XSTRING (f->name)->data))
2800 return;
fbd6baed 2801 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2802 }
2803 else
b7826503 2804 CHECK_STRING (name);
ee78dc32
GV
2805
2806 /* Don't change the name if it's already NAME. */
2807 if (! NILP (Fstring_equal (name, f->name)))
2808 return;
2809
1edf84e7
GV
2810 f->name = name;
2811
2812 /* For setting the frame title, the title parameter should override
2813 the name parameter. */
2814 if (! NILP (f->title))
2815 name = f->title;
2816
fbd6baed 2817 if (FRAME_W32_WINDOW (f))
ee78dc32 2818 {
6fc2811b 2819 if (STRING_MULTIBYTE (name))
dfff8a69 2820 name = ENCODE_SYSTEM (name);
6fc2811b 2821
ee78dc32 2822 BLOCK_INPUT;
fbd6baed 2823 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2824 UNBLOCK_INPUT;
2825 }
ee78dc32
GV
2826}
2827
2828/* This function should be called when the user's lisp code has
2829 specified a name for the frame; the name will override any set by the
2830 redisplay code. */
2831void
2832x_explicitly_set_name (f, arg, oldval)
2833 FRAME_PTR f;
2834 Lisp_Object arg, oldval;
2835{
2836 x_set_name (f, arg, 1);
2837}
2838
2839/* This function should be called by Emacs redisplay code to set the
2840 name; names set this way will never override names set by the user's
2841 lisp code. */
2842void
2843x_implicitly_set_name (f, arg, oldval)
2844 FRAME_PTR f;
2845 Lisp_Object arg, oldval;
2846{
2847 x_set_name (f, arg, 0);
2848}
1edf84e7
GV
2849\f
2850/* Change the title of frame F to NAME.
2851 If NAME is nil, use the frame name as the title.
2852
2853 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2854 name; if NAME is a string, set F's name to NAME and set
2855 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2856
2857 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2858 suggesting a new name, which lisp code should override; if
2859 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2860
1edf84e7 2861void
6fc2811b 2862x_set_title (f, name, old_name)
1edf84e7 2863 struct frame *f;
6fc2811b 2864 Lisp_Object name, old_name;
1edf84e7
GV
2865{
2866 /* Don't change the title if it's already NAME. */
2867 if (EQ (name, f->title))
2868 return;
2869
2870 update_mode_lines = 1;
2871
2872 f->title = name;
2873
2874 if (NILP (name))
2875 name = f->name;
2876
2877 if (FRAME_W32_WINDOW (f))
2878 {
6fc2811b 2879 if (STRING_MULTIBYTE (name))
dfff8a69 2880 name = ENCODE_SYSTEM (name);
6fc2811b 2881
1edf84e7
GV
2882 BLOCK_INPUT;
2883 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2884 UNBLOCK_INPUT;
2885 }
2886}
2887\f
ee78dc32
GV
2888void
2889x_set_autoraise (f, arg, oldval)
2890 struct frame *f;
2891 Lisp_Object arg, oldval;
2892{
2893 f->auto_raise = !EQ (Qnil, arg);
2894}
2895
2896void
2897x_set_autolower (f, arg, oldval)
2898 struct frame *f;
2899 Lisp_Object arg, oldval;
2900{
2901 f->auto_lower = !EQ (Qnil, arg);
2902}
2903
2904void
2905x_set_unsplittable (f, arg, oldval)
2906 struct frame *f;
2907 Lisp_Object arg, oldval;
2908{
2909 f->no_split = !NILP (arg);
2910}
2911
2912void
2913x_set_vertical_scroll_bars (f, arg, oldval)
2914 struct frame *f;
2915 Lisp_Object arg, oldval;
2916{
1026b400
RS
2917 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2918 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2919 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2920 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2921 {
1026b400
RS
2922 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2923 vertical_scroll_bar_none :
87996783
GV
2924 /* Put scroll bars on the right by default, as is conventional
2925 on MS-Windows. */
2926 EQ (Qleft, arg)
2927 ? vertical_scroll_bar_left
2928 : vertical_scroll_bar_right;
ee78dc32
GV
2929
2930 /* We set this parameter before creating the window for the
2931 frame, so we can get the geometry right from the start.
2932 However, if the window hasn't been created yet, we shouldn't
2933 call x_set_window_size. */
fbd6baed 2934 if (FRAME_W32_WINDOW (f))
ee78dc32 2935 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2936 do_pending_window_change (0);
ee78dc32
GV
2937 }
2938}
2939
2940void
2941x_set_scroll_bar_width (f, arg, oldval)
2942 struct frame *f;
2943 Lisp_Object arg, oldval;
2944{
6fc2811b
JR
2945 int wid = FONT_WIDTH (f->output_data.w32->font);
2946
ee78dc32
GV
2947 if (NILP (arg))
2948 {
6fc2811b
JR
2949 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2950 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2951 wid - 1) / wid;
2952 if (FRAME_W32_WINDOW (f))
2953 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2954 do_pending_window_change (0);
ee78dc32
GV
2955 }
2956 else if (INTEGERP (arg) && XINT (arg) > 0
2957 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2958 {
ee78dc32 2959 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
6fc2811b
JR
2960 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2961 + wid-1) / wid;
fbd6baed 2962 if (FRAME_W32_WINDOW (f))
ee78dc32 2963 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
6fc2811b 2964 do_pending_window_change (0);
ee78dc32 2965 }
6fc2811b
JR
2966 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2967 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2968 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
ee78dc32
GV
2969}
2970\f
2971/* Subroutines of creating an frame. */
2972
2973/* Make sure that Vx_resource_name is set to a reasonable value.
2974 Fix it up, or set it to `emacs' if it is too hopeless. */
2975
2976static void
2977validate_x_resource_name ()
2978{
6fc2811b 2979 int len = 0;
ee78dc32
GV
2980 /* Number of valid characters in the resource name. */
2981 int good_count = 0;
2982 /* Number of invalid characters in the resource name. */
2983 int bad_count = 0;
2984 Lisp_Object new;
2985 int i;
2986
2987 if (STRINGP (Vx_resource_name))
2988 {
2989 unsigned char *p = XSTRING (Vx_resource_name)->data;
2990 int i;
2991
dfff8a69 2992 len = STRING_BYTES (XSTRING (Vx_resource_name));
ee78dc32
GV
2993
2994 /* Only letters, digits, - and _ are valid in resource names.
2995 Count the valid characters and count the invalid ones. */
2996 for (i = 0; i < len; i++)
2997 {
2998 int c = p[i];
2999 if (! ((c >= 'a' && c <= 'z')
3000 || (c >= 'A' && c <= 'Z')
3001 || (c >= '0' && c <= '9')
3002 || c == '-' || c == '_'))
3003 bad_count++;
3004 else
3005 good_count++;
3006 }
3007 }
3008 else
3009 /* Not a string => completely invalid. */
3010 bad_count = 5, good_count = 0;
3011
3012 /* If name is valid already, return. */
3013 if (bad_count == 0)
3014 return;
3015
3016 /* If name is entirely invalid, or nearly so, use `emacs'. */
3017 if (good_count == 0
3018 || (good_count == 1 && bad_count > 0))
3019 {
3020 Vx_resource_name = build_string ("emacs");
3021 return;
3022 }
3023
3024 /* Name is partly valid. Copy it and replace the invalid characters
3025 with underscores. */
3026
3027 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3028
3029 for (i = 0; i < len; i++)
3030 {
3031 int c = XSTRING (new)->data[i];
3032 if (! ((c >= 'a' && c <= 'z')
3033 || (c >= 'A' && c <= 'Z')
3034 || (c >= '0' && c <= '9')
3035 || c == '-' || c == '_'))
3036 XSTRING (new)->data[i] = '_';
3037 }
3038}
3039
3040
3041extern char *x_get_string_resource ();
3042
3043DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
74e1aeec
JR
3044 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3045This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3046class, where INSTANCE is the name under which Emacs was invoked, or
3047the name specified by the `-name' or `-rn' command-line arguments.
3048
3049The optional arguments COMPONENT and SUBCLASS add to the key and the
3050class, respectively. You must specify both of them or neither.
3051If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3052and the class is `Emacs.CLASS.SUBCLASS'. */)
ee78dc32
GV
3053 (attribute, class, component, subclass)
3054 Lisp_Object attribute, class, component, subclass;
3055{
3056 register char *value;
3057 char *name_key;
3058 char *class_key;
3059
b7826503
PJ
3060 CHECK_STRING (attribute);
3061 CHECK_STRING (class);
ee78dc32
GV
3062
3063 if (!NILP (component))
b7826503 3064 CHECK_STRING (component);
ee78dc32 3065 if (!NILP (subclass))
b7826503 3066 CHECK_STRING (subclass);
ee78dc32
GV
3067 if (NILP (component) != NILP (subclass))
3068 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3069
3070 validate_x_resource_name ();
3071
3072 /* Allocate space for the components, the dots which separate them,
3073 and the final '\0'. Make them big enough for the worst case. */
dfff8a69 3074 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
ee78dc32 3075 + (STRINGP (component)
dfff8a69
JR
3076 ? STRING_BYTES (XSTRING (component)) : 0)
3077 + STRING_BYTES (XSTRING (attribute))
ee78dc32
GV
3078 + 3);
3079
3080 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
dfff8a69 3081 + STRING_BYTES (XSTRING (class))
ee78dc32 3082 + (STRINGP (subclass)
dfff8a69 3083 ? STRING_BYTES (XSTRING (subclass)) : 0)
ee78dc32
GV
3084 + 3);
3085
3086 /* Start with emacs.FRAMENAME for the name (the specific one)
3087 and with `Emacs' for the class key (the general one). */
3088 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3089 strcpy (class_key, EMACS_CLASS);
3090
3091 strcat (class_key, ".");
3092 strcat (class_key, XSTRING (class)->data);
3093
3094 if (!NILP (component))
3095 {
3096 strcat (class_key, ".");
3097 strcat (class_key, XSTRING (subclass)->data);
3098
3099 strcat (name_key, ".");
3100 strcat (name_key, XSTRING (component)->data);
3101 }
3102
3103 strcat (name_key, ".");
3104 strcat (name_key, XSTRING (attribute)->data);
3105
3106 value = x_get_string_resource (Qnil,
3107 name_key, class_key);
3108
3109 if (value != (char *) 0)
3110 return build_string (value);
3111 else
3112 return Qnil;
3113}
3114
3115/* Used when C code wants a resource value. */
3116
3117char *
3118x_get_resource_string (attribute, class)
3119 char *attribute, *class;
3120{
ee78dc32
GV
3121 char *name_key;
3122 char *class_key;
6fc2811b 3123 struct frame *sf = SELECTED_FRAME ();
ee78dc32
GV
3124
3125 /* Allocate space for the components, the dots which separate them,
3126 and the final '\0'. */
dfff8a69 3127 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
ee78dc32
GV
3128 + strlen (attribute) + 2);
3129 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3130 + strlen (class) + 2);
3131
3132 sprintf (name_key, "%s.%s",
3133 XSTRING (Vinvocation_name)->data,
3134 attribute);
3135 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3136
6fc2811b 3137 return x_get_string_resource (sf, name_key, class_key);
ee78dc32
GV
3138}
3139
3140/* Types we might convert a resource string into. */
3141enum resource_types
6fc2811b
JR
3142{
3143 RES_TYPE_NUMBER,
3144 RES_TYPE_FLOAT,
3145 RES_TYPE_BOOLEAN,
3146 RES_TYPE_STRING,
3147 RES_TYPE_SYMBOL
3148};
ee78dc32
GV
3149
3150/* Return the value of parameter PARAM.
3151
3152 First search ALIST, then Vdefault_frame_alist, then the X defaults
3153 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3154
3155 Convert the resource to the type specified by desired_type.
3156
3157 If no default is specified, return Qunbound. If you call
6fc2811b 3158 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
ee78dc32
GV
3159 and don't let it get stored in any Lisp-visible variables! */
3160
3161static Lisp_Object
6fc2811b 3162w32_get_arg (alist, param, attribute, class, type)
ee78dc32
GV
3163 Lisp_Object alist, param;
3164 char *attribute;
3165 char *class;
3166 enum resource_types type;
3167{
3168 register Lisp_Object tem;
3169
3170 tem = Fassq (param, alist);
3171 if (EQ (tem, Qnil))
3172 tem = Fassq (param, Vdefault_frame_alist);
3173 if (EQ (tem, Qnil))
3174 {
3175
3176 if (attribute)
3177 {
3178 tem = Fx_get_resource (build_string (attribute),
3179 build_string (class),
3180 Qnil, Qnil);
3181
3182 if (NILP (tem))
3183 return Qunbound;
3184
3185 switch (type)
3186 {
6fc2811b 3187 case RES_TYPE_NUMBER:
ee78dc32
GV
3188 return make_number (atoi (XSTRING (tem)->data));
3189
6fc2811b
JR
3190 case RES_TYPE_FLOAT:
3191 return make_float (atof (XSTRING (tem)->data));
3192
3193 case RES_TYPE_BOOLEAN:
ee78dc32
GV
3194 tem = Fdowncase (tem);
3195 if (!strcmp (XSTRING (tem)->data, "on")
3196 || !strcmp (XSTRING (tem)->data, "true"))
3197 return Qt;
3198 else
3199 return Qnil;
3200
6fc2811b 3201 case RES_TYPE_STRING:
ee78dc32
GV
3202 return tem;
3203
6fc2811b 3204 case RES_TYPE_SYMBOL:
ee78dc32
GV
3205 /* As a special case, we map the values `true' and `on'
3206 to Qt, and `false' and `off' to Qnil. */
3207 {
3208 Lisp_Object lower;
3209 lower = Fdowncase (tem);
3210 if (!strcmp (XSTRING (lower)->data, "on")
3211 || !strcmp (XSTRING (lower)->data, "true"))
3212 return Qt;
3213 else if (!strcmp (XSTRING (lower)->data, "off")
3214 || !strcmp (XSTRING (lower)->data, "false"))
3215 return Qnil;
3216 else
3217 return Fintern (tem, Qnil);
3218 }
3219
3220 default:
3221 abort ();
3222 }
3223 }
3224 else
3225 return Qunbound;
3226 }
3227 return Fcdr (tem);
3228}
3229
3230/* Record in frame F the specified or default value according to ALIST
dfff8a69
JR
3231 of the parameter named PROP (a Lisp symbol).
3232 If no value is specified for PROP, look for an X default for XPROP
ee78dc32
GV
3233 on the frame named NAME.
3234 If that is not found either, use the value DEFLT. */
3235
3236static Lisp_Object
3237x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3238 struct frame *f;
3239 Lisp_Object alist;
3240 Lisp_Object prop;
3241 Lisp_Object deflt;
3242 char *xprop;
3243 char *xclass;
3244 enum resource_types type;
3245{
3246 Lisp_Object tem;
3247
6fc2811b 3248 tem = w32_get_arg (alist, prop, xprop, xclass, type);
ee78dc32
GV
3249 if (EQ (tem, Qunbound))
3250 tem = deflt;
3251 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3252 return tem;
3253}
3254\f
3255DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
74e1aeec
JR
3256 doc: /* Parse an X-style geometry string STRING.
3257Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3258The properties returned may include `top', `left', `height', and `width'.
3259The value of `left' or `top' may be an integer,
3260or a list (+ N) meaning N pixels relative to top/left corner,
3261or a list (- N) meaning -N pixels relative to bottom/right corner. */)
ee78dc32
GV
3262 (string)
3263 Lisp_Object string;
3264{
3265 int geometry, x, y;
3266 unsigned int width, height;
3267 Lisp_Object result;
3268
b7826503 3269 CHECK_STRING (string);
ee78dc32
GV
3270
3271 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3272 &x, &y, &width, &height);
3273
3274 result = Qnil;
3275 if (geometry & XValue)
3276 {
3277 Lisp_Object element;
3278
3279 if (x >= 0 && (geometry & XNegative))
3280 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3281 else if (x < 0 && ! (geometry & XNegative))
3282 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3283 else
3284 element = Fcons (Qleft, make_number (x));
3285 result = Fcons (element, result);
3286 }
3287
3288 if (geometry & YValue)
3289 {
3290 Lisp_Object element;
3291
3292 if (y >= 0 && (geometry & YNegative))
3293 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3294 else if (y < 0 && ! (geometry & YNegative))
3295 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3296 else
3297 element = Fcons (Qtop, make_number (y));
3298 result = Fcons (element, result);
3299 }
3300
3301 if (geometry & WidthValue)
3302 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3303 if (geometry & HeightValue)
3304 result = Fcons (Fcons (Qheight, make_number (height)), result);
3305
3306 return result;
3307}
3308
3309/* Calculate the desired size and position of this window,
3310 and return the flags saying which aspects were specified.
3311
3312 This function does not make the coordinates positive. */
3313
3314#define DEFAULT_ROWS 40
3315#define DEFAULT_COLS 80
3316
3317static int
3318x_figure_window_size (f, parms)
3319 struct frame *f;
3320 Lisp_Object parms;
3321{
3322 register Lisp_Object tem0, tem1, tem2;
ee78dc32
GV
3323 long window_prompting = 0;
3324
3325 /* Default values if we fall through.
3326 Actually, if that happens we should get
3327 window manager prompting. */
1026b400 3328 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
3329 f->height = DEFAULT_ROWS;
3330 /* Window managers expect that if program-specified
3331 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
3332 f->output_data.w32->top_pos = 0;
3333 f->output_data.w32->left_pos = 0;
ee78dc32 3334
35b41202
JR
3335 /* Ensure that old new_width and new_height will not override the
3336 values set here. */
3337 FRAME_NEW_WIDTH (f) = 0;
3338 FRAME_NEW_HEIGHT (f) = 0;
3339
6fc2811b
JR
3340 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3341 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3342 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3343 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3344 {
3345 if (!EQ (tem0, Qunbound))
3346 {
b7826503 3347 CHECK_NUMBER (tem0);
ee78dc32
GV
3348 f->height = XINT (tem0);
3349 }
3350 if (!EQ (tem1, Qunbound))
3351 {
b7826503 3352 CHECK_NUMBER (tem1);
1026b400 3353 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
3354 }
3355 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3356 window_prompting |= USSize;
3357 else
3358 window_prompting |= PSize;
3359 }
3360
fbd6baed 3361 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
3362 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3363 ? 0
3364 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3365 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed 3366 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
f7b9d4d1 3367
41c1bdd9 3368 x_compute_fringe_widths (f, 0);
f7b9d4d1 3369
fbd6baed
GV
3370 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3371 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32 3372
6fc2811b
JR
3373 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3374 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3375 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
3376 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3377 {
3378 if (EQ (tem0, Qminus))
3379 {
fbd6baed 3380 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3381 window_prompting |= YNegative;
3382 }
8e713be6
KR
3383 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3384 && CONSP (XCDR (tem0))
3385 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3386 {
8e713be6 3387 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3388 window_prompting |= YNegative;
3389 }
8e713be6
KR
3390 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3391 && CONSP (XCDR (tem0))
3392 && INTEGERP (XCAR (XCDR (tem0))))
ee78dc32 3393 {
8e713be6 3394 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
ee78dc32
GV
3395 }
3396 else if (EQ (tem0, Qunbound))
fbd6baed 3397 f->output_data.w32->top_pos = 0;
ee78dc32
GV
3398 else
3399 {
b7826503 3400 CHECK_NUMBER (tem0);
fbd6baed
GV
3401 f->output_data.w32->top_pos = XINT (tem0);
3402 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
3403 window_prompting |= YNegative;
3404 }
3405
3406 if (EQ (tem1, Qminus))
3407 {
fbd6baed 3408 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3409 window_prompting |= XNegative;
3410 }
8e713be6
KR
3411 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3412 && CONSP (XCDR (tem1))
3413 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3414 {
8e713be6 3415 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3416 window_prompting |= XNegative;
3417 }
8e713be6
KR
3418 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3419 && CONSP (XCDR (tem1))
3420 && INTEGERP (XCAR (XCDR (tem1))))
ee78dc32 3421 {
8e713be6 3422 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
ee78dc32
GV
3423 }
3424 else if (EQ (tem1, Qunbound))
fbd6baed 3425 f->output_data.w32->left_pos = 0;
ee78dc32
GV
3426 else
3427 {
b7826503 3428 CHECK_NUMBER (tem1);
fbd6baed
GV
3429 f->output_data.w32->left_pos = XINT (tem1);
3430 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
3431 window_prompting |= XNegative;
3432 }
3433
3434 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3435 window_prompting |= USPosition;
3436 else
3437 window_prompting |= PPosition;
3438 }
3439
f7b9d4d1
JR
3440 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3441 {
3442 int left, top;
3443 int width, height;
3444
3445 /* It takes both for some WM:s to place it where we want */
3446 window_prompting = USPosition | PPosition;
3447 x_fullscreen_adjust (f, &width, &height, &top, &left);
3448 f->width = width;
3449 f->height = height;
3450 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3451 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3452 f->output_data.w32->left_pos = left;
3453 f->output_data.w32->top_pos = top;
3454 }
3455
ee78dc32
GV
3456 return window_prompting;
3457}
3458
3459\f
3460
fbd6baed 3461extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
3462
3463BOOL
fbd6baed 3464w32_init_class (hinst)
ee78dc32
GV
3465 HINSTANCE hinst;
3466{
3467 WNDCLASS wc;
3468
5ac45f98 3469 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 3470 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
3471 wc.cbClsExtra = 0;
3472 wc.cbWndExtra = WND_EXTRA_BYTES;
3473 wc.hInstance = hinst;
3474 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3475 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 3476 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
3477 wc.lpszMenuName = NULL;
3478 wc.lpszClassName = EMACS_CLASS;
3479
3480 return (RegisterClass (&wc));
3481}
3482
3483HWND
fbd6baed 3484w32_createscrollbar (f, bar)
ee78dc32
GV
3485 struct frame *f;
3486 struct scroll_bar * bar;
3487{
3488 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3489 /* Position and size of scroll bar. */
6fc2811b
JR
3490 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3491 XINT(bar->top),
3492 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3493 XINT(bar->height),
fbd6baed 3494 FRAME_W32_WINDOW (f),
ee78dc32
GV
3495 NULL,
3496 hinst,
3497 NULL));
3498}
3499
3500void
fbd6baed 3501w32_createwindow (f)
ee78dc32
GV
3502 struct frame *f;
3503{
3504 HWND hwnd;
1edf84e7
GV
3505 RECT rect;
3506
3507 rect.left = rect.top = 0;
3508 rect.right = PIXEL_WIDTH (f);
3509 rect.bottom = PIXEL_HEIGHT (f);
3510
3511 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3512 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3513
3514 /* Do first time app init */
3515
3516 if (!hprevinst)
3517 {
fbd6baed 3518 w32_init_class (hinst);
ee78dc32
GV
3519 }
3520
1edf84e7
GV
3521 FRAME_W32_WINDOW (f) = hwnd
3522 = CreateWindow (EMACS_CLASS,
3523 f->namebuf,
9ead1b60 3524 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1edf84e7
GV
3525 f->output_data.w32->left_pos,
3526 f->output_data.w32->top_pos,
3527 rect.right - rect.left,
3528 rect.bottom - rect.top,
3529 NULL,
3530 NULL,
3531 hinst,
3532 NULL);
3533
ee78dc32
GV
3534 if (hwnd)
3535 {
1edf84e7
GV
3536 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3537 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3538 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3539 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
6fc2811b 3540 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
ee78dc32 3541
cb9e33d4
RS
3542 /* Enable drag-n-drop. */
3543 DragAcceptFiles (hwnd, TRUE);
3544
5ac45f98
GV
3545 /* Do this to discard the default setting specified by our parent. */
3546 ShowWindow (hwnd, SW_HIDE);
3c190163 3547 }
3c190163
GV
3548}
3549
ee78dc32
GV
3550void
3551my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3552 W32Msg * wmsg;
ee78dc32
GV
3553 HWND hwnd;
3554 UINT msg;
3555 WPARAM wParam;
3556 LPARAM lParam;
3557{
3558 wmsg->msg.hwnd = hwnd;
3559 wmsg->msg.message = msg;
3560 wmsg->msg.wParam = wParam;
3561 wmsg->msg.lParam = lParam;
3562 wmsg->msg.time = GetMessageTime ();
3563
3564 post_msg (wmsg);
3565}
3566
e9e23e23 3567/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3568 between left and right keys as advertised. We test for this
3569 support dynamically, and set a flag when the support is absent. If
3570 absent, we keep track of the left and right control and alt keys
3571 ourselves. This is particularly necessary on keyboards that rely
3572 upon the AltGr key, which is represented as having the left control
3573 and right alt keys pressed. For these keyboards, we need to know
3574 when the left alt key has been pressed in addition to the AltGr key
3575 so that we can properly support M-AltGr-key sequences (such as M-@
3576 on Swedish keyboards). */
3577
3578#define EMACS_LCONTROL 0
3579#define EMACS_RCONTROL 1
3580#define EMACS_LMENU 2
3581#define EMACS_RMENU 3
3582
3583static int modifiers[4];
3584static int modifiers_recorded;
3585static int modifier_key_support_tested;
3586
3587static void
3588test_modifier_support (unsigned int wparam)
3589{
3590 unsigned int l, r;
3591
3592 if (wparam != VK_CONTROL && wparam != VK_MENU)
3593 return;
3594 if (wparam == VK_CONTROL)
3595 {
3596 l = VK_LCONTROL;
3597 r = VK_RCONTROL;
3598 }
3599 else
3600 {
3601 l = VK_LMENU;
3602 r = VK_RMENU;
3603 }
3604 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3605 modifiers_recorded = 1;
3606 else
3607 modifiers_recorded = 0;
3608 modifier_key_support_tested = 1;
3609}
3610
3611static void
3612record_keydown (unsigned int wparam, unsigned int lparam)
3613{
3614 int i;
3615
3616 if (!modifier_key_support_tested)
3617 test_modifier_support (wparam);
3618
3619 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3620 return;
3621
3622 if (wparam == VK_CONTROL)
3623 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3624 else
3625 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3626
3627 modifiers[i] = 1;
3628}
3629
3630static void
3631record_keyup (unsigned int wparam, unsigned int lparam)
3632{
3633 int i;
3634
3635 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3636 return;
3637
3638 if (wparam == VK_CONTROL)
3639 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3640 else
3641 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3642
3643 modifiers[i] = 0;
3644}
3645
da36a4d6
GV
3646/* Emacs can lose focus while a modifier key has been pressed. When
3647 it regains focus, be conservative and clear all modifiers since
3648 we cannot reconstruct the left and right modifier state. */
3649static void
3650reset_modifiers ()
3651{
8681157a
RS
3652 SHORT ctrl, alt;
3653
adcc3809
GV
3654 if (GetFocus () == NULL)
3655 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3656 return;
8681157a
RS
3657
3658 ctrl = GetAsyncKeyState (VK_CONTROL);
3659 alt = GetAsyncKeyState (VK_MENU);
3660
8681157a
RS
3661 if (!(ctrl & 0x08000))
3662 /* Clear any recorded control modifier state. */
3663 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3664
3665 if (!(alt & 0x08000))
3666 /* Clear any recorded alt modifier state. */
3667 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3668
adcc3809
GV
3669 /* Update the state of all modifier keys, because modifiers used in
3670 hot-key combinations can get stuck on if Emacs loses focus as a
3671 result of a hot-key being pressed. */
3672 {
3673 BYTE keystate[256];
3674
3675#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3676
3677 GetKeyboardState (keystate);
3678 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3679 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3680 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3681 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3682 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3683 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3684 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3685 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3686 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3687 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3688 SetKeyboardState (keystate);
3689 }
da36a4d6
GV
3690}
3691
7830e24b
RS
3692/* Synchronize modifier state with what is reported with the current
3693 keystroke. Even if we cannot distinguish between left and right
3694 modifier keys, we know that, if no modifiers are set, then neither
3695 the left or right modifier should be set. */
3696static void
3697sync_modifiers ()
3698{
3699 if (!modifiers_recorded)
3700 return;
3701
3702 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3703 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3704
3705 if (!(GetKeyState (VK_MENU) & 0x8000))
3706 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3707}
3708
a1a80b40
GV
3709static int
3710modifier_set (int vkey)
3711{
ccc2d29c 3712 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3713 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3714 if (!modifiers_recorded)
3715 return (GetKeyState (vkey) & 0x8000);
3716
3717 switch (vkey)
3718 {
3719 case VK_LCONTROL:
3720 return modifiers[EMACS_LCONTROL];
3721 case VK_RCONTROL:
3722 return modifiers[EMACS_RCONTROL];
3723 case VK_LMENU:
3724 return modifiers[EMACS_LMENU];
3725 case VK_RMENU:
3726 return modifiers[EMACS_RMENU];
a1a80b40
GV
3727 }
3728 return (GetKeyState (vkey) & 0x8000);
3729}
3730
ccc2d29c
GV
3731/* Convert between the modifier bits W32 uses and the modifier bits
3732 Emacs uses. */
3733
3734unsigned int
3735w32_key_to_modifier (int key)
3736{
3737 Lisp_Object key_mapping;
3738
3739 switch (key)
3740 {
3741 case VK_LWIN:
3742 key_mapping = Vw32_lwindow_modifier;
3743 break;
3744 case VK_RWIN:
3745 key_mapping = Vw32_rwindow_modifier;
3746 break;
3747 case VK_APPS:
3748 key_mapping = Vw32_apps_modifier;
3749 break;
3750 case VK_SCROLL:
3751 key_mapping = Vw32_scroll_lock_modifier;
3752 break;
3753 default:
3754 key_mapping = Qnil;
3755 }
3756
adcc3809
GV
3757 /* NB. This code runs in the input thread, asychronously to the lisp
3758 thread, so we must be careful to ensure access to lisp data is
3759 thread-safe. The following code is safe because the modifier
3760 variable values are updated atomically from lisp and symbols are
3761 not relocated by GC. Also, we don't have to worry about seeing GC
3762 markbits here. */
3763 if (EQ (key_mapping, Qhyper))
ccc2d29c 3764 return hyper_modifier;
adcc3809 3765 if (EQ (key_mapping, Qsuper))
ccc2d29c 3766 return super_modifier;
adcc3809 3767 if (EQ (key_mapping, Qmeta))
ccc2d29c 3768 return meta_modifier;
adcc3809 3769 if (EQ (key_mapping, Qalt))
ccc2d29c 3770 return alt_modifier;
adcc3809 3771 if (EQ (key_mapping, Qctrl))
ccc2d29c 3772 return ctrl_modifier;
adcc3809 3773 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3774 return ctrl_modifier;
adcc3809 3775 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3776 return shift_modifier;
3777
3778 /* Don't generate any modifier if not explicitly requested. */
3779 return 0;
3780}
3781
3782unsigned int
3783w32_get_modifiers ()
3784{
3785 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3786 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3787 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3788 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3789 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3790 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3791 (modifier_set (VK_MENU) ?
3792 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3793}
3794
a1a80b40
GV
3795/* We map the VK_* modifiers into console modifier constants
3796 so that we can use the same routines to handle both console
3797 and window input. */
3798
3799static int
ccc2d29c 3800construct_console_modifiers ()
a1a80b40
GV
3801{
3802 int mods;
3803
a1a80b40
GV
3804 mods = 0;
3805 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3806 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3807 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3808 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3809 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3810 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3811 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3812 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3813 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3814 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3815 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3816
3817 return mods;
3818}
3819
ccc2d29c
GV
3820static int
3821w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3822{
ccc2d29c
GV
3823 int mods;
3824
3825 /* Convert to emacs modifiers. */
3826 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3827
3828 return mods;
3829}
da36a4d6 3830
ccc2d29c
GV
3831unsigned int
3832map_keypad_keys (unsigned int virt_key, unsigned int extended)
3833{
3834 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3835 return virt_key;
da36a4d6 3836
ccc2d29c 3837 if (virt_key == VK_RETURN)
da36a4d6
GV
3838 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3839
ccc2d29c
GV
3840 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3841 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3842
3843 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3844 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3845
3846 if (virt_key == VK_CLEAR)
3847 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3848
3849 return virt_key;
3850}
3851
3852/* List of special key combinations which w32 would normally capture,
3853 but emacs should grab instead. Not directly visible to lisp, to
3854 simplify synchronization. Each item is an integer encoding a virtual
3855 key code and modifier combination to capture. */
3856Lisp_Object w32_grabbed_keys;
3857
3858#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3859#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3860#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3861#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3862
3863/* Register hot-keys for reserved key combinations when Emacs has
3864 keyboard focus, since this is the only way Emacs can receive key
3865 combinations like Alt-Tab which are used by the system. */
3866
3867static void
3868register_hot_keys (hwnd)
3869 HWND hwnd;
3870{
3871 Lisp_Object keylist;
3872
3873 /* Use GC_CONSP, since we are called asynchronously. */
3874 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3875 {
3876 Lisp_Object key = XCAR (keylist);
3877
3878 /* Deleted entries get set to nil. */
3879 if (!INTEGERP (key))
3880 continue;
3881
3882 RegisterHotKey (hwnd, HOTKEY_ID (key),
3883 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3884 }
3885}
3886
3887static void
3888unregister_hot_keys (hwnd)
3889 HWND hwnd;
3890{
3891 Lisp_Object keylist;
3892
3893 /* Use GC_CONSP, since we are called asynchronously. */
3894 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3895 {
3896 Lisp_Object key = XCAR (keylist);
3897
3898 if (!INTEGERP (key))
3899 continue;
3900
3901 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3902 }
3903}
3904
5ac45f98
GV
3905/* Main message dispatch loop. */
3906
1edf84e7
GV
3907static void
3908w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3909{
3910 MSG msg;
ccc2d29c
GV
3911 int result;
3912 HWND focus_window;
93fbe8b7
GV
3913
3914 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3915
5ac45f98
GV
3916 while (GetMessage (&msg, NULL, 0, 0))
3917 {
3918 if (msg.hwnd == NULL)
3919 {
3920 switch (msg.message)
3921 {
3ef68e6b
AI
3922 case WM_NULL:
3923 /* Produced by complete_deferred_msg; just ignore. */
3924 break;
5ac45f98 3925 case WM_EMACS_CREATEWINDOW:
fbd6baed 3926 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3927 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3928 abort ();
5ac45f98 3929 break;
dfdb4047
GV
3930 case WM_EMACS_SETLOCALE:
3931 SetThreadLocale (msg.wParam);
3932 /* Reply is not expected. */
3933 break;
ccc2d29c
GV
3934 case WM_EMACS_SETKEYBOARDLAYOUT:
3935 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3936 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3937 result, 0))
3938 abort ();
3939 break;
3940 case WM_EMACS_REGISTER_HOT_KEY:
3941 focus_window = GetFocus ();
3942 if (focus_window != NULL)
3943 RegisterHotKey (focus_window,
3944 HOTKEY_ID (msg.wParam),
3945 HOTKEY_MODIFIERS (msg.wParam),
3946 HOTKEY_VK_CODE (msg.wParam));
3947 /* Reply is not expected. */
3948 break;
3949 case WM_EMACS_UNREGISTER_HOT_KEY:
3950 focus_window = GetFocus ();
3951 if (focus_window != NULL)
3952 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3953 /* Mark item as erased. NB: this code must be
3954 thread-safe. The next line is okay because the cons
3955 cell is never made into garbage and is not relocated by
3956 GC. */
f3fbd155 3957 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
ccc2d29c
GV
3958 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3959 abort ();
3960 break;
adcc3809
GV
3961 case WM_EMACS_TOGGLE_LOCK_KEY:
3962 {
3963 int vk_code = (int) msg.wParam;
3964 int cur_state = (GetKeyState (vk_code) & 1);
3965 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3966
3967 /* NB: This code must be thread-safe. It is safe to
3968 call NILP because symbols are not relocated by GC,
3969 and pointer here is not touched by GC (so the markbit
3970 can't be set). Numbers are safe because they are
3971 immediate values. */
3972 if (NILP (new_state)
3973 || (NUMBERP (new_state)
8edb0a6f 3974 && ((XUINT (new_state)) & 1) != cur_state))
adcc3809
GV
3975 {
3976 one_w32_display_info.faked_key = vk_code;
3977
3978 keybd_event ((BYTE) vk_code,
3979 (BYTE) MapVirtualKey (vk_code, 0),
3980 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3981 keybd_event ((BYTE) vk_code,
3982 (BYTE) MapVirtualKey (vk_code, 0),
3983 KEYEVENTF_EXTENDEDKEY | 0, 0);
3984 keybd_event ((BYTE) vk_code,
3985 (BYTE) MapVirtualKey (vk_code, 0),
3986 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3987 cur_state = !cur_state;
3988 }
3989 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3990 cur_state, 0))
3991 abort ();
3992 }
3993 break;
1edf84e7 3994 default:
1edf84e7 3995 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3996 }
3997 }
3998 else
3999 {
4000 DispatchMessage (&msg);
4001 }
1edf84e7
GV
4002
4003 /* Exit nested loop when our deferred message has completed. */
4004 if (msg_buf->completed)
4005 break;
5ac45f98 4006 }
1edf84e7
GV
4007}
4008
4009deferred_msg * deferred_msg_head;
4010
4011static deferred_msg *
4012find_deferred_msg (HWND hwnd, UINT msg)
4013{
4014 deferred_msg * item;
4015
4016 /* Don't actually need synchronization for read access, since
4017 modification of single pointer is always atomic. */
4018 /* enter_crit (); */
4019
4020 for (item = deferred_msg_head; item != NULL; item = item->next)
4021 if (item->w32msg.msg.hwnd == hwnd
4022 && item->w32msg.msg.message == msg)
4023 break;
4024
4025 /* leave_crit (); */
4026
4027 return item;
4028}
4029
4030static LRESULT
4031send_deferred_msg (deferred_msg * msg_buf,
4032 HWND hwnd,
4033 UINT msg,
4034 WPARAM wParam,
4035 LPARAM lParam)
4036{
4037 /* Only input thread can send deferred messages. */
4038 if (GetCurrentThreadId () != dwWindowsThreadId)
4039 abort ();
4040
4041 /* It is an error to send a message that is already deferred. */
4042 if (find_deferred_msg (hwnd, msg) != NULL)
4043 abort ();
4044
4045 /* Enforced synchronization is not needed because this is the only
4046 function that alters deferred_msg_head, and the following critical
4047 section is guaranteed to only be serially reentered (since only the
4048 input thread can call us). */
4049
4050 /* enter_crit (); */
4051
4052 msg_buf->completed = 0;
4053 msg_buf->next = deferred_msg_head;
4054 deferred_msg_head = msg_buf;
4055 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4056
4057 /* leave_crit (); */
4058
4059 /* Start a new nested message loop to process other messages until
4060 this one is completed. */
4061 w32_msg_pump (msg_buf);
4062
4063 deferred_msg_head = msg_buf->next;
4064
4065 return msg_buf->result;
4066}
4067
4068void
4069complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4070{
4071 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4072
4073 if (msg_buf == NULL)
3ef68e6b
AI
4074 /* Message may have been cancelled, so don't abort(). */
4075 return;
1edf84e7
GV
4076
4077 msg_buf->result = result;
4078 msg_buf->completed = 1;
4079
4080 /* Ensure input thread is woken so it notices the completion. */
4081 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4082}
4083
3ef68e6b
AI
4084void
4085cancel_all_deferred_msgs ()
4086{
4087 deferred_msg * item;
4088
4089 /* Don't actually need synchronization for read access, since
4090 modification of single pointer is always atomic. */
4091 /* enter_crit (); */
4092
4093 for (item = deferred_msg_head; item != NULL; item = item->next)
4094 {
4095 item->result = 0;
4096 item->completed = 1;
4097 }
4098
4099 /* leave_crit (); */
4100
4101 /* Ensure input thread is woken so it notices the completion. */
4102 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4103}
1edf84e7
GV
4104
4105DWORD
4106w32_msg_worker (dw)
4107 DWORD dw;
4108{
4109 MSG msg;
4110 deferred_msg dummy_buf;
4111
4112 /* Ensure our message queue is created */
4113
4114 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 4115
1edf84e7
GV
4116 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4117 abort ();
4118
4119 memset (&dummy_buf, 0, sizeof (dummy_buf));
4120 dummy_buf.w32msg.msg.hwnd = NULL;
4121 dummy_buf.w32msg.msg.message = WM_NULL;
4122
4123 /* This is the inital message loop which should only exit when the
4124 application quits. */
4125 w32_msg_pump (&dummy_buf);
4126
4127 return 0;
5ac45f98
GV
4128}
4129
3ef68e6b
AI
4130static void
4131post_character_message (hwnd, msg, wParam, lParam, modifiers)
4132 HWND hwnd;
4133 UINT msg;
4134 WPARAM wParam;
4135 LPARAM lParam;
4136 DWORD modifiers;
4137
4138{
4139 W32Msg wmsg;
4140
4141 wmsg.dwModifiers = modifiers;
4142
4143 /* Detect quit_char and set quit-flag directly. Note that we
4144 still need to post a message to ensure the main thread will be
4145 woken up if blocked in sys_select(), but we do NOT want to post
4146 the quit_char message itself (because it will usually be as if
4147 the user had typed quit_char twice). Instead, we post a dummy
4148 message that has no particular effect. */
4149 {
4150 int c = wParam;
4151 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4152 c = make_ctrl_char (c) & 0377;
7d081355
AI
4153 if (c == quit_char
4154 || (wmsg.dwModifiers == 0 &&
4155 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
4156 {
4157 Vquit_flag = Qt;
4158
4159 /* The choice of message is somewhat arbitrary, as long as
4160 the main thread handler just ignores it. */
4161 msg = WM_NULL;
4162
4163 /* Interrupt any blocking system calls. */
4164 signal_quit ();
4165
4166 /* As a safety precaution, forcibly complete any deferred
4167 messages. This is a kludge, but I don't see any particularly
4168 clean way to handle the situation where a deferred message is
4169 "dropped" in the lisp thread, and will thus never be
4170 completed, eg. by the user trying to activate the menubar
4171 when the lisp thread is busy, and then typing C-g when the
4172 menubar doesn't open promptly (with the result that the
4173 menubar never responds at all because the deferred
4174 WM_INITMENU message is never completed). Another problem
4175 situation is when the lisp thread calls SendMessage (to send
4176 a window manager command) when a message has been deferred;
4177 the lisp thread gets blocked indefinitely waiting for the
4178 deferred message to be completed, which itself is waiting for
4179 the lisp thread to respond.
4180
4181 Note that we don't want to block the input thread waiting for
4182 a reponse from the lisp thread (although that would at least
4183 solve the deadlock problem above), because we want to be able
4184 to receive C-g to interrupt the lisp thread. */
4185 cancel_all_deferred_msgs ();
4186 }
4187 }
4188
4189 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4190}
4191
ee78dc32
GV
4192/* Main window procedure */
4193
ee78dc32 4194LRESULT CALLBACK
fbd6baed 4195w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
4196 HWND hwnd;
4197 UINT msg;
4198 WPARAM wParam;
4199 LPARAM lParam;
4200{
4201 struct frame *f;
fbd6baed
GV
4202 struct w32_display_info *dpyinfo = &one_w32_display_info;
4203 W32Msg wmsg;
84fb1139 4204 int windows_translate;
576ba81c 4205 int key;
84fb1139 4206
a6085637
KH
4207 /* Note that it is okay to call x_window_to_frame, even though we are
4208 not running in the main lisp thread, because frame deletion
4209 requires the lisp thread to synchronize with this thread. Thus, if
4210 a frame struct is returned, it can be used without concern that the
4211 lisp thread might make it disappear while we are using it.
4212
4213 NB. Walking the frame list in this thread is safe (as long as
4214 writes of Lisp_Object slots are atomic, which they are on Windows).
4215 Although delete-frame can destructively modify the frame list while
4216 we are walking it, a garbage collection cannot occur until after
4217 delete-frame has synchronized with this thread.
4218
4219 It is also safe to use functions that make GDI calls, such as
fbd6baed 4220 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
4221 from the frame struct using get_frame_dc which is thread-aware. */
4222
ee78dc32
GV
4223 switch (msg)
4224 {
4225 case WM_ERASEBKGND:
a6085637
KH
4226 f = x_window_to_frame (dpyinfo, hwnd);
4227 if (f)
4228 {
9badad41 4229 HDC hdc = get_frame_dc (f);
a6085637 4230 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
9badad41
JR
4231 w32_clear_rect (f, hdc, &wmsg.rect);
4232 release_frame_dc (f, hdc);
ce6059da
AI
4233
4234#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4235 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4236 f,
4237 wmsg.rect.left, wmsg.rect.top,
4238 wmsg.rect.right, wmsg.rect.bottom));
ce6059da 4239#endif /* W32_DEBUG_DISPLAY */
a6085637 4240 }
5ac45f98
GV
4241 return 1;
4242 case WM_PALETTECHANGED:
4243 /* ignore our own changes */
4244 if ((HWND)wParam != hwnd)
4245 {
a6085637
KH
4246 f = x_window_to_frame (dpyinfo, hwnd);
4247 if (f)
4248 /* get_frame_dc will realize our palette and force all
4249 frames to be redrawn if needed. */
4250 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
4251 }
4252 return 0;
ee78dc32 4253 case WM_PAINT:
ce6059da 4254 {
55dcfc15
AI
4255 PAINTSTRUCT paintStruct;
4256 RECT update_rect;
aa35b6ad 4257 bzero (&update_rect, sizeof (update_rect));
55dcfc15 4258
18f0b342
AI
4259 f = x_window_to_frame (dpyinfo, hwnd);
4260 if (f == 0)
4261 {
4262 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4263 return 0;
4264 }
4265
55dcfc15
AI
4266 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4267 fails. Apparently this can happen under some
4268 circumstances. */
aa35b6ad 4269 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
55dcfc15
AI
4270 {
4271 enter_crit ();
4272 BeginPaint (hwnd, &paintStruct);
4273
aa35b6ad
JR
4274 /* The rectangles returned by GetUpdateRect and BeginPaint
4275 do not always match. Play it safe by assuming both areas
4276 are invalid. */
4277 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
55dcfc15
AI
4278
4279#if defined (W32_DEBUG_DISPLAY)
18f0b342
AI
4280 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4281 f,
4282 wmsg.rect.left, wmsg.rect.top,
4283 wmsg.rect.right, wmsg.rect.bottom));
4284 DebPrint ((" [update region is %d,%d-%d,%d]\n",
55dcfc15
AI
4285 update_rect.left, update_rect.top,
4286 update_rect.right, update_rect.bottom));
4287#endif
4288 EndPaint (hwnd, &paintStruct);
4289 leave_crit ();
4290
4291 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4292
4293 return 0;
4294 }
c0611964
AI
4295
4296 /* If GetUpdateRect returns 0 (meaning there is no update
4297 region), assume the whole window needs to be repainted. */
4298 GetClientRect(hwnd, &wmsg.rect);
4299 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4300 return 0;
ee78dc32 4301 }
a1a80b40 4302
ccc2d29c
GV
4303 case WM_INPUTLANGCHANGE:
4304 /* Inform lisp thread of keyboard layout changes. */
4305 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4306
4307 /* Clear dead keys in the keyboard state; for simplicity only
4308 preserve modifier key states. */
4309 {
4310 int i;
4311 BYTE keystate[256];
4312
4313 GetKeyboardState (keystate);
4314 for (i = 0; i < 256; i++)
4315 if (1
4316 && i != VK_SHIFT
4317 && i != VK_LSHIFT
4318 && i != VK_RSHIFT
4319 && i != VK_CAPITAL
4320 && i != VK_NUMLOCK
4321 && i != VK_SCROLL
4322 && i != VK_CONTROL
4323 && i != VK_LCONTROL
4324 && i != VK_RCONTROL
4325 && i != VK_MENU
4326 && i != VK_LMENU
4327 && i != VK_RMENU
4328 && i != VK_LWIN
4329 && i != VK_RWIN)
4330 keystate[i] = 0;
4331 SetKeyboardState (keystate);
4332 }
4333 goto dflt;
4334
4335 case WM_HOTKEY:
4336 /* Synchronize hot keys with normal input. */
4337 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4338 return (0);
4339
a1a80b40
GV
4340 case WM_KEYUP:
4341 case WM_SYSKEYUP:
4342 record_keyup (wParam, lParam);
4343 goto dflt;
4344
ee78dc32
GV
4345 case WM_KEYDOWN:
4346 case WM_SYSKEYDOWN:
ccc2d29c
GV
4347 /* Ignore keystrokes we fake ourself; see below. */
4348 if (dpyinfo->faked_key == wParam)
4349 {
4350 dpyinfo->faked_key = 0;
576ba81c
AI
4351 /* Make sure TranslateMessage sees them though (as long as
4352 they don't produce WM_CHAR messages). This ensures that
4353 indicator lights are toggled promptly on Windows 9x, for
4354 example. */
4355 if (lispy_function_keys[wParam] != 0)
4356 {
4357 windows_translate = 1;
4358 goto translate;
4359 }
4360 return 0;
ccc2d29c
GV
4361 }
4362
7830e24b
RS
4363 /* Synchronize modifiers with current keystroke. */
4364 sync_modifiers ();
a1a80b40 4365 record_keydown (wParam, lParam);
ccc2d29c 4366 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
4367
4368 windows_translate = 0;
ccc2d29c
GV
4369
4370 switch (wParam)
4371 {
4372 case VK_LWIN:
4373 if (NILP (Vw32_pass_lwindow_to_system))
4374 {
4375 /* Prevent system from acting on keyup (which opens the
4376 Start menu if no other key was pressed) by simulating a
4377 press of Space which we will ignore. */
4378 if (GetAsyncKeyState (wParam) & 1)
4379 {
adcc3809 4380 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4381 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4382 else
576ba81c
AI
4383 key = VK_SPACE;
4384 dpyinfo->faked_key = key;
4385 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4386 }
4387 }
4388 if (!NILP (Vw32_lwindow_modifier))
4389 return 0;
4390 break;
4391 case VK_RWIN:
4392 if (NILP (Vw32_pass_rwindow_to_system))
4393 {
4394 if (GetAsyncKeyState (wParam) & 1)
4395 {
adcc3809 4396 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 4397 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 4398 else
576ba81c
AI
4399 key = VK_SPACE;
4400 dpyinfo->faked_key = key;
4401 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
4402 }
4403 }
4404 if (!NILP (Vw32_rwindow_modifier))
4405 return 0;
4406 break;
576ba81c 4407 case VK_APPS:
ccc2d29c
GV
4408 if (!NILP (Vw32_apps_modifier))
4409 return 0;
4410 break;
4411 case VK_MENU:
4412 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
4413 /* Prevent DefWindowProc from activating the menu bar if an
4414 Alt key is pressed and released by itself. */
ccc2d29c 4415 return 0;
84fb1139 4416 windows_translate = 1;
ccc2d29c
GV
4417 break;
4418 case VK_CAPITAL:
4419 /* Decide whether to treat as modifier or function key. */
4420 if (NILP (Vw32_enable_caps_lock))
4421 goto disable_lock_key;
adcc3809
GV
4422 windows_translate = 1;
4423 break;
ccc2d29c
GV
4424 case VK_NUMLOCK:
4425 /* Decide whether to treat as modifier or function key. */
4426 if (NILP (Vw32_enable_num_lock))
4427 goto disable_lock_key;
adcc3809
GV
4428 windows_translate = 1;
4429 break;
ccc2d29c
GV
4430 case VK_SCROLL:
4431 /* Decide whether to treat as modifier or function key. */
4432 if (NILP (Vw32_scroll_lock_modifier))
4433 goto disable_lock_key;
adcc3809
GV
4434 windows_translate = 1;
4435 break;
ccc2d29c 4436 disable_lock_key:
adcc3809
GV
4437 /* Ensure the appropriate lock key state (and indicator light)
4438 remains in the same state. We do this by faking another
4439 press of the relevant key. Apparently, this really is the
4440 only way to toggle the state of the indicator lights. */
4441 dpyinfo->faked_key = wParam;
4442 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4443 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4444 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4445 KEYEVENTF_EXTENDEDKEY | 0, 0);
4446 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4447 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4448 /* Ensure indicator lights are updated promptly on Windows 9x
4449 (TranslateMessage apparently does this), after forwarding
4450 input event. */
4451 post_character_message (hwnd, msg, wParam, lParam,
4452 w32_get_key_modifiers (wParam, lParam));
4453 windows_translate = 1;
ccc2d29c
GV
4454 break;
4455 case VK_CONTROL:
4456 case VK_SHIFT:
4457 case VK_PROCESSKEY: /* Generated by IME. */
4458 windows_translate = 1;
4459 break;
adcc3809
GV
4460 case VK_CANCEL:
4461 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4462 which is confusing for purposes of key binding; convert
4463 VK_CANCEL events into VK_PAUSE events. */
4464 wParam = VK_PAUSE;
4465 break;
4466 case VK_PAUSE:
4467 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4468 for purposes of key binding; convert these back into
4469 VK_NUMLOCK events, at least when we want to see NumLock key
4470 presses. (Note that there is never any possibility that
4471 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4472 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4473 wParam = VK_NUMLOCK;
4474 break;
ccc2d29c
GV
4475 default:
4476 /* If not defined as a function key, change it to a WM_CHAR message. */
4477 if (lispy_function_keys[wParam] == 0)
4478 {
adcc3809
GV
4479 DWORD modifiers = construct_console_modifiers ();
4480
ccc2d29c
GV
4481 if (!NILP (Vw32_recognize_altgr)
4482 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4483 {
4484 /* Always let TranslateMessage handle AltGr key chords;
4485 for some reason, ToAscii doesn't always process AltGr
4486 chords correctly. */
4487 windows_translate = 1;
4488 }
adcc3809 4489 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 4490 {
adcc3809
GV
4491 /* Handle key chords including any modifiers other
4492 than shift directly, in order to preserve as much
4493 modifier information as possible. */
ccc2d29c
GV
4494 if ('A' <= wParam && wParam <= 'Z')
4495 {
4496 /* Don't translate modified alphabetic keystrokes,
4497 so the user doesn't need to constantly switch
4498 layout to type control or meta keystrokes when
4499 the normal layout translates alphabetic
4500 characters to non-ascii characters. */
4501 if (!modifier_set (VK_SHIFT))
4502 wParam += ('a' - 'A');
4503 msg = WM_CHAR;
4504 }
4505 else
4506 {
4507 /* Try to handle other keystrokes by determining the
4508 base character (ie. translating the base key plus
4509 shift modifier). */
4510 int add;
4511 int isdead = 0;
4512 KEY_EVENT_RECORD key;
4513
4514 key.bKeyDown = TRUE;
4515 key.wRepeatCount = 1;
4516 key.wVirtualKeyCode = wParam;
4517 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4518 key.uChar.AsciiChar = 0;
adcc3809 4519 key.dwControlKeyState = modifiers;
ccc2d29c
GV
4520
4521 add = w32_kbd_patch_key (&key);
4522 /* 0 means an unrecognised keycode, negative means
4523 dead key. Ignore both. */
4524 while (--add >= 0)
4525 {
4526 /* Forward asciified character sequence. */
4527 post_character_message
4528 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4529 w32_get_key_modifiers (wParam, lParam));
4530 w32_kbd_patch_key (&key);
4531 }
4532 return 0;
4533 }
4534 }
4535 else
4536 {
4537 /* Let TranslateMessage handle everything else. */
4538 windows_translate = 1;
4539 }
4540 }
4541 }
a1a80b40 4542
adcc3809 4543 translate:
84fb1139
KH
4544 if (windows_translate)
4545 {
e9e23e23 4546 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4547
e9e23e23
GV
4548 windows_msg.time = GetMessageTime ();
4549 TranslateMessage (&windows_msg);
84fb1139
KH
4550 goto dflt;
4551 }
4552
ee78dc32
GV
4553 /* Fall through */
4554
4555 case WM_SYSCHAR:
4556 case WM_CHAR:
ccc2d29c
GV
4557 post_character_message (hwnd, msg, wParam, lParam,
4558 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4559 break;
da36a4d6 4560
5ac45f98
GV
4561 /* Simulate middle mouse button events when left and right buttons
4562 are used together, but only if user has two button mouse. */
ee78dc32 4563 case WM_LBUTTONDOWN:
5ac45f98 4564 case WM_RBUTTONDOWN:
7ce9aaca 4565 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4566 goto handle_plain_button;
4567
4568 {
4569 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4570 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4571
3cb20f4a
RS
4572 if (button_state & this)
4573 return 0;
5ac45f98
GV
4574
4575 if (button_state == 0)
4576 SetCapture (hwnd);
4577
4578 button_state |= this;
4579
4580 if (button_state & other)
4581 {
84fb1139 4582 if (mouse_button_timer)
5ac45f98 4583 {
84fb1139
KH
4584 KillTimer (hwnd, mouse_button_timer);
4585 mouse_button_timer = 0;
5ac45f98
GV
4586
4587 /* Generate middle mouse event instead. */
4588 msg = WM_MBUTTONDOWN;
4589 button_state |= MMOUSE;
4590 }
4591 else if (button_state & MMOUSE)
4592 {
4593 /* Ignore button event if we've already generated a
4594 middle mouse down event. This happens if the
4595 user releases and press one of the two buttons
4596 after we've faked a middle mouse event. */
4597 return 0;
4598 }
4599 else
4600 {
4601 /* Flush out saved message. */
84fb1139 4602 post_msg (&saved_mouse_button_msg);
5ac45f98 4603 }
fbd6baed 4604 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4605 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4606
4607 /* Clear message buffer. */
84fb1139 4608 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4609 }
4610 else
4611 {
4612 /* Hold onto message for now. */
84fb1139 4613 mouse_button_timer =
adcc3809
GV
4614 SetTimer (hwnd, MOUSE_BUTTON_ID,
4615 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4616 saved_mouse_button_msg.msg.hwnd = hwnd;
4617 saved_mouse_button_msg.msg.message = msg;
4618 saved_mouse_button_msg.msg.wParam = wParam;
4619 saved_mouse_button_msg.msg.lParam = lParam;
4620 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4621 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4622 }
4623 }
4624 return 0;
4625
ee78dc32 4626 case WM_LBUTTONUP:
5ac45f98 4627 case WM_RBUTTONUP:
7ce9aaca 4628 if (XINT (Vw32_num_mouse_buttons) > 2)
5ac45f98
GV
4629 goto handle_plain_button;
4630
4631 {
4632 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4633 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4634
3cb20f4a
RS
4635 if ((button_state & this) == 0)
4636 return 0;
5ac45f98
GV
4637
4638 button_state &= ~this;
4639
4640 if (button_state & MMOUSE)
4641 {
4642 /* Only generate event when second button is released. */
4643 if ((button_state & other) == 0)
4644 {
4645 msg = WM_MBUTTONUP;
4646 button_state &= ~MMOUSE;
4647
4648 if (button_state) abort ();
4649 }
4650 else
4651 return 0;
4652 }
4653 else
4654 {
4655 /* Flush out saved message if necessary. */
84fb1139 4656 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4657 {
84fb1139 4658 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4659 }
4660 }
fbd6baed 4661 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4662 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4663
4664 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4665 saved_mouse_button_msg.msg.hwnd = 0;
4666 KillTimer (hwnd, mouse_button_timer);
4667 mouse_button_timer = 0;
5ac45f98
GV
4668
4669 if (button_state == 0)
4670 ReleaseCapture ();
4671 }
4672 return 0;
4673
74214547
JR
4674 case WM_XBUTTONDOWN:
4675 case WM_XBUTTONUP:
4676 if (w32_pass_extra_mouse_buttons_to_system)
4677 goto dflt;
4678 /* else fall through and process them. */
ee78dc32
GV
4679 case WM_MBUTTONDOWN:
4680 case WM_MBUTTONUP:
5ac45f98 4681 handle_plain_button:
ee78dc32
GV
4682 {
4683 BOOL up;
1edf84e7 4684 int button;
ee78dc32 4685
74214547 4686 if (parse_button (msg, HIWORD (wParam), &button, &up))
ee78dc32
GV
4687 {
4688 if (up) ReleaseCapture ();
4689 else SetCapture (hwnd);
1edf84e7
GV
4690 button = (button == 0) ? LMOUSE :
4691 ((button == 1) ? MMOUSE : RMOUSE);
4692 if (up)
4693 button_state &= ~button;
4694 else
4695 button_state |= button;
ee78dc32
GV
4696 }
4697 }
4698
fbd6baed 4699 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4700 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
74214547
JR
4701
4702 /* Need to return true for XBUTTON messages, false for others,
4703 to indicate that we processed the message. */
4704 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
5ac45f98 4705
5ac45f98 4706 case WM_MOUSEMOVE:
9eb16b62
JR
4707 /* If the mouse has just moved into the frame, start tracking
4708 it, so we will be notified when it leaves the frame. Mouse
4709 tracking only works under W98 and NT4 and later. On earlier
4710 versions, there is no way of telling when the mouse leaves the
4711 frame, so we just have to put up with help-echo and mouse
4712 highlighting remaining while the frame is not active. */
4713 if (track_mouse_event_fn && !track_mouse_window)
4714 {
4715 TRACKMOUSEEVENT tme;
4716 tme.cbSize = sizeof (tme);
4717 tme.dwFlags = TME_LEAVE;
4718 tme.hwndTrack = hwnd;
4719
4720 track_mouse_event_fn (&tme);
4721 track_mouse_window = hwnd;
4722 }
4723 case WM_VSCROLL:
fbd6baed 4724 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4725 || (msg == WM_MOUSEMOVE && button_state == 0))
4726 {
fbd6baed 4727 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4728 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4729 return 0;
4730 }
4731
4732 /* Hang onto mouse move and scroll messages for a bit, to avoid
4733 sending such events to Emacs faster than it can process them.
4734 If we get more events before the timer from the first message
4735 expires, we just replace the first message. */
4736
4737 if (saved_mouse_move_msg.msg.hwnd == 0)
4738 mouse_move_timer =
adcc3809
GV
4739 SetTimer (hwnd, MOUSE_MOVE_ID,
4740 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4741
4742 /* Hold onto message for now. */
4743 saved_mouse_move_msg.msg.hwnd = hwnd;
4744 saved_mouse_move_msg.msg.message = msg;
4745 saved_mouse_move_msg.msg.wParam = wParam;
4746 saved_mouse_move_msg.msg.lParam = lParam;
4747 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4748 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4749
4750 return 0;
4751
1edf84e7
GV
4752 case WM_MOUSEWHEEL:
4753 wmsg.dwModifiers = w32_get_modifiers ();
4754 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4755 return 0;
4756
cb9e33d4
RS
4757 case WM_DROPFILES:
4758 wmsg.dwModifiers = w32_get_modifiers ();
4759 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4760 return 0;
4761
84fb1139
KH
4762 case WM_TIMER:
4763 /* Flush out saved messages if necessary. */
4764 if (wParam == mouse_button_timer)
5ac45f98 4765 {
84fb1139
KH
4766 if (saved_mouse_button_msg.msg.hwnd)
4767 {
4768 post_msg (&saved_mouse_button_msg);
4769 saved_mouse_button_msg.msg.hwnd = 0;
4770 }
4771 KillTimer (hwnd, mouse_button_timer);
4772 mouse_button_timer = 0;
4773 }
4774 else if (wParam == mouse_move_timer)
4775 {
4776 if (saved_mouse_move_msg.msg.hwnd)
4777 {
4778 post_msg (&saved_mouse_move_msg);
4779 saved_mouse_move_msg.msg.hwnd = 0;
4780 }
4781 KillTimer (hwnd, mouse_move_timer);
4782 mouse_move_timer = 0;
5ac45f98 4783 }
48094ace
JR
4784 else if (wParam == menu_free_timer)
4785 {
4786 KillTimer (hwnd, menu_free_timer);
4787 menu_free_timer = 0;
27605fa7 4788 f = x_window_to_frame (dpyinfo, hwnd);
48094ace
JR
4789 if (!f->output_data.w32->menu_command_in_progress)
4790 {
4791 /* Free memory used by owner-drawn and help-echo strings. */
4792 w32_free_menu_strings (hwnd);
4793 f->output_data.w32->menubar_active = 0;
4794 }
4795 }
5ac45f98 4796 return 0;
84fb1139
KH
4797
4798 case WM_NCACTIVATE:
4799 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4800 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4801 The only indication we get that something happened is receiving
4802 this message afterwards. So this is a good time to reset our
4803 keyboard modifiers' state. */
4804 reset_modifiers ();
4805 goto dflt;
da36a4d6 4806
1edf84e7 4807 case WM_INITMENU:
487163ac
AI
4808 button_state = 0;
4809 ReleaseCapture ();
1edf84e7
GV
4810 /* We must ensure menu bar is fully constructed and up to date
4811 before allowing user interaction with it. To achieve this
4812 we send this message to the lisp thread and wait for a
4813 reply (whose value is not actually needed) to indicate that
4814 the menu bar is now ready for use, so we can now return.
4815
4816 To remain responsive in the meantime, we enter a nested message
4817 loop that can process all other messages.
4818
4819 However, we skip all this if the message results from calling
4820 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4821 thread a message because it is blocked on us at this point. We
4822 set menubar_active before calling TrackPopupMenu to indicate
4823 this (there is no possibility of confusion with real menubar
4824 being active). */
4825
4826 f = x_window_to_frame (dpyinfo, hwnd);
4827 if (f
4828 && (f->output_data.w32->menubar_active
4829 /* We can receive this message even in the absence of a
4830 menubar (ie. when the system menu is activated) - in this
4831 case we do NOT want to forward the message, otherwise it
4832 will cause the menubar to suddenly appear when the user
4833 had requested it to be turned off! */
4834 || f->output_data.w32->menubar_widget == NULL))
4835 return 0;
4836
4837 {
4838 deferred_msg msg_buf;
4839
4840 /* Detect if message has already been deferred; in this case
4841 we cannot return any sensible value to ignore this. */
4842 if (find_deferred_msg (hwnd, msg) != NULL)
4843 abort ();
4844
4845 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4846 }
4847
4848 case WM_EXITMENULOOP:
4849 f = x_window_to_frame (dpyinfo, hwnd);
4850
48094ace
JR
4851 /* If a menu command is not already in progress, check again
4852 after a short delay, since Windows often (always?) sends the
4853 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4854 if (f && !f->output_data.w32->menu_command_in_progress)
4855 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
1edf84e7
GV
4856 goto dflt;
4857
126f2e35 4858 case WM_MENUSELECT:
4e3a1c61
JR
4859 /* Direct handling of help_echo in menus. Should be safe now
4860 that we generate the help_echo by placing a help event in the
4861 keyboard buffer. */
ca56d953 4862 {
ca56d953
JR
4863 HMENU menu = (HMENU) lParam;
4864 UINT menu_item = (UINT) LOWORD (wParam);
4865 UINT flags = (UINT) HIWORD (wParam);
4866
4e3a1c61 4867 w32_menu_display_help (hwnd, menu, menu_item, flags);
ca56d953 4868 }
126f2e35
JR
4869 return 0;
4870
87996783
GV
4871 case WM_MEASUREITEM:
4872 f = x_window_to_frame (dpyinfo, hwnd);
4873 if (f)
4874 {
4875 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4876
4877 if (pMis->CtlType == ODT_MENU)
4878 {
4879 /* Work out dimensions for popup menu titles. */
4880 char * title = (char *) pMis->itemData;
4881 HDC hdc = GetDC (hwnd);
4882 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4883 LOGFONT menu_logfont;
4884 HFONT old_font;
4885 SIZE size;
4886
4887 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4888 menu_logfont.lfWeight = FW_BOLD;
4889 menu_font = CreateFontIndirect (&menu_logfont);
4890 old_font = SelectObject (hdc, menu_font);
4891
dfff8a69
JR
4892 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4893 if (title)
4894 {
4895 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4896 pMis->itemWidth = size.cx;
4897 if (pMis->itemHeight < size.cy)
4898 pMis->itemHeight = size.cy;
4899 }
4900 else
4901 pMis->itemWidth = 0;
87996783
GV
4902
4903 SelectObject (hdc, old_font);
4904 DeleteObject (menu_font);
4905 ReleaseDC (hwnd, hdc);
4906 return TRUE;
4907 }
4908 }
4909 return 0;
4910
4911 case WM_DRAWITEM:
4912 f = x_window_to_frame (dpyinfo, hwnd);
4913 if (f)
4914 {
4915 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4916
4917 if (pDis->CtlType == ODT_MENU)
4918 {
4919 /* Draw popup menu title. */
4920 char * title = (char *) pDis->itemData;
212da13b
JR
4921 if (title)
4922 {
4923 HDC hdc = pDis->hDC;
4924 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4925 LOGFONT menu_logfont;
4926 HFONT old_font;
4927
4928 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4929 menu_logfont.lfWeight = FW_BOLD;
4930 menu_font = CreateFontIndirect (&menu_logfont);
4931 old_font = SelectObject (hdc, menu_font);
4932
4933 /* Always draw title as if not selected. */
4934 ExtTextOut (hdc,
4935 pDis->rcItem.left
4936 + GetSystemMetrics (SM_CXMENUCHECK),
4937 pDis->rcItem.top,
4938 ETO_OPAQUE, &pDis->rcItem,
4939 title, strlen (title), NULL);
4940
4941 SelectObject (hdc, old_font);
4942 DeleteObject (menu_font);
4943 }
87996783
GV
4944 return TRUE;
4945 }
4946 }
4947 return 0;
4948
1edf84e7
GV
4949#if 0
4950 /* Still not right - can't distinguish between clicks in the
4951 client area of the frame from clicks forwarded from the scroll
4952 bars - may have to hook WM_NCHITTEST to remember the mouse
4953 position and then check if it is in the client area ourselves. */
4954 case WM_MOUSEACTIVATE:
4955 /* Discard the mouse click that activates a frame, allowing the
4956 user to click anywhere without changing point (or worse!).
4957 Don't eat mouse clicks on scrollbars though!! */
4958 if (LOWORD (lParam) == HTCLIENT )
4959 return MA_ACTIVATEANDEAT;
4960 goto dflt;
4961#endif
4962
9eb16b62
JR
4963 case WM_MOUSELEAVE:
4964 /* No longer tracking mouse. */
4965 track_mouse_window = NULL;
4966
1edf84e7 4967 case WM_ACTIVATEAPP:
ccc2d29c 4968 case WM_ACTIVATE:
1edf84e7
GV
4969 case WM_WINDOWPOSCHANGED:
4970 case WM_SHOWWINDOW:
4971 /* Inform lisp thread that a frame might have just been obscured
4972 or exposed, so should recheck visibility of all frames. */
4973 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4974 goto dflt;
4975
da36a4d6 4976 case WM_SETFOCUS:
adcc3809
GV
4977 dpyinfo->faked_key = 0;
4978 reset_modifiers ();
ccc2d29c
GV
4979 register_hot_keys (hwnd);
4980 goto command;
8681157a 4981 case WM_KILLFOCUS:
ccc2d29c 4982 unregister_hot_keys (hwnd);
487163ac
AI
4983 button_state = 0;
4984 ReleaseCapture ();
65906840
JR
4985 /* Relinquish the system caret. */
4986 if (w32_system_caret_hwnd)
4987 {
93f2ca61 4988 w32_visible_system_caret_hwnd = NULL;
d285988b
JR
4989 w32_system_caret_hwnd = NULL;
4990 DestroyCaret ();
65906840 4991 }
48094ace
JR
4992 goto command;
4993 case WM_COMMAND:
4994 f = x_window_to_frame (dpyinfo, hwnd);
4995 if (f && HIWORD (wParam) == 0)
4996 {
4997 f->output_data.w32->menu_command_in_progress = 1;
4998 if (menu_free_timer)
4999 {
5000 KillTimer (hwnd, menu_free_timer);
5001 menu_free_timer = 0;
5002 }
5003 }
ee78dc32
GV
5004 case WM_MOVE:
5005 case WM_SIZE:
ccc2d29c 5006 command:
fbd6baed 5007 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
5008 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5009 goto dflt;
8847d890
RS
5010
5011 case WM_CLOSE:
fbd6baed 5012 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
5013 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5014 return 0;
5015
ee78dc32 5016 case WM_WINDOWPOSCHANGING:
bfd6edcc
JR
5017 /* Don't restrict the sizing of tip frames. */
5018 if (hwnd == tip_window)
5019 return 0;
ee78dc32
GV
5020 {
5021 WINDOWPLACEMENT wp;
5022 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
5023
5024 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
5025 GetWindowPlacement (hwnd, &wp);
5026
1edf84e7 5027 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
5028 {
5029 RECT rect;
5030 int wdiff;
5031 int hdiff;
1edf84e7
GV
5032 DWORD font_width;
5033 DWORD line_height;
5034 DWORD internal_border;
5035 DWORD scrollbar_extra;
ee78dc32
GV
5036 RECT wr;
5037
5ac45f98 5038 wp.length = sizeof(wp);
ee78dc32
GV
5039 GetWindowRect (hwnd, &wr);
5040
3c190163 5041 enter_crit ();
ee78dc32 5042
1edf84e7
GV
5043 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5044 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5045 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5046 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 5047
3c190163 5048 leave_crit ();
ee78dc32
GV
5049
5050 memset (&rect, 0, sizeof (rect));
5051 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
5052 GetMenu (hwnd) != NULL);
5053
1edf84e7
GV
5054 /* Force width and height of client area to be exact
5055 multiples of the character cell dimensions. */
5056 wdiff = (lppos->cx - (rect.right - rect.left)
5057 - 2 * internal_border - scrollbar_extra)
5058 % font_width;
5059 hdiff = (lppos->cy - (rect.bottom - rect.top)
5060 - 2 * internal_border)
5061 % line_height;
ee78dc32
GV
5062
5063 if (wdiff || hdiff)
5064 {
5065 /* For right/bottom sizing we can just fix the sizes.
5066 However for top/left sizing we will need to fix the X
5067 and Y positions as well. */
5068
5069 lppos->cx -= wdiff;
5070 lppos->cy -= hdiff;
5071
5072 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 5073 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
5074 {
5075 if (lppos->x != wr.left || lppos->y != wr.top)
5076 {
5077 lppos->x += wdiff;
5078 lppos->y += hdiff;
5079 }
5080 else
5081 {
5082 lppos->flags |= SWP_NOMOVE;
5083 }
5084 }
5085
1edf84e7 5086 return 0;
ee78dc32
GV
5087 }
5088 }
5089 }
ee78dc32
GV
5090
5091 goto dflt;
1edf84e7 5092
b1f918f8
GV
5093 case WM_GETMINMAXINFO:
5094 /* Hack to correct bug that allows Emacs frames to be resized
5095 below the Minimum Tracking Size. */
5096 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
bf853fee
AI
5097 /* Hack to allow resizing the Emacs frame above the screen size.
5098 Note that Windows 9x limits coordinates to 16-bits. */
5099 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5100 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
b1f918f8
GV
5101 return 0;
5102
1edf84e7
GV
5103 case WM_EMACS_CREATESCROLLBAR:
5104 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5105 (struct scroll_bar *) lParam);
5106
5ac45f98 5107 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
5108 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5109
dfdb4047 5110 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
5111 {
5112 HWND foreground_window;
5113 DWORD foreground_thread, retval;
5114
5115 /* On NT 5.0, and apparently Windows 98, it is necessary to
5116 attach to the thread that currently has focus in order to
5117 pull the focus away from it. */
5118 foreground_window = GetForegroundWindow ();
5119 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5120 if (!foreground_window
5121 || foreground_thread == GetCurrentThreadId ()
5122 || !AttachThreadInput (GetCurrentThreadId (),
5123 foreground_thread, TRUE))
5124 foreground_thread = 0;
5125
5126 retval = SetForegroundWindow ((HWND) wParam);
5127
5128 /* Detach from the previous foreground thread. */
5129 if (foreground_thread)
5130 AttachThreadInput (GetCurrentThreadId (),
5131 foreground_thread, FALSE);
5132
5133 return retval;
5134 }
dfdb4047 5135
5ac45f98
GV
5136 case WM_EMACS_SETWINDOWPOS:
5137 {
1edf84e7
GV
5138 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5139 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
5140 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5141 }
1edf84e7 5142
ee78dc32 5143 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 5144 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
5145 return DestroyWindow ((HWND) wParam);
5146
93f2ca61
JR
5147 case WM_EMACS_HIDE_CARET:
5148 return HideCaret (hwnd);
5149
5150 case WM_EMACS_SHOW_CARET:
5151 return ShowCaret (hwnd);
5152
65906840
JR
5153 case WM_EMACS_DESTROY_CARET:
5154 w32_system_caret_hwnd = NULL;
93f2ca61 5155 w32_visible_system_caret_hwnd = NULL;
65906840
JR
5156 return DestroyCaret ();
5157
5158 case WM_EMACS_TRACK_CARET:
5159 /* If there is currently no system caret, create one. */
5160 if (w32_system_caret_hwnd == NULL)
5161 {
93f2ca61
JR
5162 /* Use the default caret width, and avoid changing it
5163 unneccesarily, as it confuses screen reader software. */
65906840 5164 w32_system_caret_hwnd = hwnd;
93f2ca61 5165 CreateCaret (hwnd, NULL, 0,
65906840
JR
5166 w32_system_caret_height);
5167 }
93f2ca61
JR
5168
5169 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5170 return 0;
5171 /* Ensure visible caret gets turned on when requested. */
5172 else if (w32_use_visible_system_caret
5173 && w32_visible_system_caret_hwnd != hwnd)
5174 {
5175 w32_visible_system_caret_hwnd = hwnd;
5176 return ShowCaret (hwnd);
5177 }
5178 /* Ensure visible caret gets turned off when requested. */
5179 else if (!w32_use_visible_system_caret
5180 && w32_visible_system_caret_hwnd)
5181 {
5182 w32_visible_system_caret_hwnd = NULL;
5183 return HideCaret (hwnd);
5184 }
5185 else
5186 return 1;
65906840 5187
1edf84e7
GV
5188 case WM_EMACS_TRACKPOPUPMENU:
5189 {
5190 UINT flags;
5191 POINT *pos;
5192 int retval;
5193 pos = (POINT *)lParam;
5194 flags = TPM_CENTERALIGN;
5195 if (button_state & LMOUSE)
5196 flags |= TPM_LEFTBUTTON;
5197 else if (button_state & RMOUSE)
5198 flags |= TPM_RIGHTBUTTON;
5199
87996783
GV
5200 /* Remember we did a SetCapture on the initial mouse down event,
5201 so for safety, we make sure the capture is cancelled now. */
5202 ReleaseCapture ();
490822ff 5203 button_state = 0;
87996783 5204
1edf84e7
GV
5205 /* Use menubar_active to indicate that WM_INITMENU is from
5206 TrackPopupMenu below, and should be ignored. */
5207 f = x_window_to_frame (dpyinfo, hwnd);
5208 if (f)
5209 f->output_data.w32->menubar_active = 1;
5210
5211 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5212 0, hwnd, NULL))
5213 {
5214 MSG amsg;
5215 /* Eat any mouse messages during popupmenu */
5216 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5217 PM_REMOVE));
5218 /* Get the menu selection, if any */
5219 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5220 {
5221 retval = LOWORD (amsg.wParam);
5222 }
5223 else
5224 {
5225 retval = 0;
5226 }
1edf84e7
GV
5227 }
5228 else
5229 {
5230 retval = -1;
5231 }
5232
5233 return retval;
5234 }
5235
ee78dc32 5236 default:
93fbe8b7
GV
5237 /* Check for messages registered at runtime. */
5238 if (msg == msh_mousewheel)
5239 {
5240 wmsg.dwModifiers = w32_get_modifiers ();
5241 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5242 return 0;
5243 }
5244
ee78dc32
GV
5245 dflt:
5246 return DefWindowProc (hwnd, msg, wParam, lParam);
5247 }
5248
1edf84e7
GV
5249
5250 /* The most common default return code for handled messages is 0. */
5251 return 0;
ee78dc32
GV
5252}
5253
5254void
5255my_create_window (f)
5256 struct frame * f;
5257{
5258 MSG msg;
5259
1edf84e7
GV
5260 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5261 abort ();
ee78dc32
GV
5262 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5263}
5264
ca56d953
JR
5265
5266/* Create a tooltip window. Unlike my_create_window, we do not do this
5267 indirectly via the Window thread, as we do not need to process Window
5268 messages for the tooltip. Creating tooltips indirectly also creates
5269 deadlocks when tooltips are created for menu items. */
5270void
5271my_create_tip_window (f)
5272 struct frame *f;
5273{
bfd6edcc 5274 RECT rect;
ca56d953 5275
bfd6edcc
JR
5276 rect.left = rect.top = 0;
5277 rect.right = PIXEL_WIDTH (f);
5278 rect.bottom = PIXEL_HEIGHT (f);
5279
5280 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5281 FRAME_EXTERNAL_MENU_BAR (f));
5282
5283 tip_window = FRAME_W32_WINDOW (f)
ca56d953
JR
5284 = CreateWindow (EMACS_CLASS,
5285 f->namebuf,
5286 f->output_data.w32->dwStyle,
5287 f->output_data.w32->left_pos,
5288 f->output_data.w32->top_pos,
bfd6edcc
JR
5289 rect.right - rect.left,
5290 rect.bottom - rect.top,
ca56d953
JR
5291 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5292 NULL,
5293 hinst,
5294 NULL);
5295
bfd6edcc 5296 if (tip_window)
ca56d953 5297 {
bfd6edcc
JR
5298 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5299 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5300 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5301 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5302
5303 /* Tip frames have no scrollbars. */
5304 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
ca56d953
JR
5305
5306 /* Do this to discard the default setting specified by our parent. */
bfd6edcc 5307 ShowWindow (tip_window, SW_HIDE);
ca56d953
JR
5308 }
5309}
5310
5311
fbd6baed 5312/* Create and set up the w32 window for frame F. */
ee78dc32
GV
5313
5314static void
fbd6baed 5315w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
5316 struct frame *f;
5317 long window_prompting;
5318 int minibuffer_only;
5319{
5320 BLOCK_INPUT;
5321
5322 /* Use the resource name as the top-level window name
5323 for looking up resources. Make a non-Lisp copy
5324 for the window manager, so GC relocation won't bother it.
5325
5326 Elsewhere we specify the window name for the window manager. */
5327
5328 {
5329 char *str = (char *) XSTRING (Vx_resource_name)->data;
5330 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5331 strcpy (f->namebuf, str);
5332 }
5333
5334 my_create_window (f);
5335
5336 validate_x_resource_name ();
5337
5338 /* x_set_name normally ignores requests to set the name if the
5339 requested name is the same as the current name. This is the one
5340 place where that assumption isn't correct; f->name is set, but
5341 the server hasn't been told. */
5342 {
5343 Lisp_Object name;
5344 int explicit = f->explicit_name;
5345
5346 f->explicit_name = 0;
5347 name = f->name;
5348 f->name = Qnil;
5349 x_set_name (f, name, explicit);
5350 }
5351
5352 UNBLOCK_INPUT;
5353
5354 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5355 initialize_frame_menubar (f);
5356
fbd6baed 5357 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
5358 error ("Unable to create window");
5359}
5360
5361/* Handle the icon stuff for this window. Perhaps later we might
5362 want an x_set_icon_position which can be called interactively as
5363 well. */
5364
5365static void
5366x_icon (f, parms)
5367 struct frame *f;
5368 Lisp_Object parms;
5369{
5370 Lisp_Object icon_x, icon_y;
5371
e9e23e23 5372 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32 5373 icons in the tray. */
6fc2811b
JR
5374 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5375 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
ee78dc32
GV
5376 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5377 {
b7826503
PJ
5378 CHECK_NUMBER (icon_x);
5379 CHECK_NUMBER (icon_y);
ee78dc32
GV
5380 }
5381 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5382 error ("Both left and top icon corners of icon must be specified");
5383
5384 BLOCK_INPUT;
5385
5386 if (! EQ (icon_x, Qunbound))
5387 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5388
1edf84e7
GV
5389#if 0 /* TODO */
5390 /* Start up iconic or window? */
5391 x_wm_set_window_state
6fc2811b 5392 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
1edf84e7
GV
5393 ? IconicState
5394 : NormalState));
5395
5396 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5397 ? f->icon_name
5398 : f->name))->data);
5399#endif
5400
ee78dc32
GV
5401 UNBLOCK_INPUT;
5402}
5403
6fc2811b
JR
5404
5405static void
5406x_make_gc (f)
5407 struct frame *f;
5408{
5409 XGCValues gc_values;
5410
5411 BLOCK_INPUT;
5412
5413 /* Create the GC's of this frame.
5414 Note that many default values are used. */
5415
5416 /* Normal video */
5417 gc_values.font = f->output_data.w32->font;
5418
5419 /* Cursor has cursor-color background, background-color foreground. */
5420 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5421 gc_values.background = f->output_data.w32->cursor_pixel;
5422 f->output_data.w32->cursor_gc
5423 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5424 (GCFont | GCForeground | GCBackground),
5425 &gc_values);
5426
5427 /* Reliefs. */
5428 f->output_data.w32->white_relief.gc = 0;
5429 f->output_data.w32->black_relief.gc = 0;
5430
5431 UNBLOCK_INPUT;
5432}
5433
5434
937e601e
AI
5435/* Handler for signals raised during x_create_frame and
5436 x_create_top_frame. FRAME is the frame which is partially
5437 constructed. */
5438
5439static Lisp_Object
5440unwind_create_frame (frame)
5441 Lisp_Object frame;
5442{
5443 struct frame *f = XFRAME (frame);
5444
5445 /* If frame is ``official'', nothing to do. */
5446 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5447 {
5448#ifdef GLYPH_DEBUG
5449 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5450#endif
5451
5452 x_free_frame_resources (f);
5453
5454 /* Check that reference counts are indeed correct. */
5455 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5456 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
c844a81a
GM
5457
5458 return Qt;
937e601e
AI
5459 }
5460
5461 return Qnil;
5462}
5463
5464
ee78dc32
GV
5465DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5466 1, 1, 0,
74e1aeec
JR
5467 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5468Returns an Emacs frame object.
5469ALIST is an alist of frame parameters.
5470If the parameters specify that the frame should not have a minibuffer,
5471and do not specify a specific minibuffer window to use,
5472then `default-minibuffer-frame' must be a frame whose minibuffer can
5473be shared by the new frame.
5474
5475This function is an internal primitive--use `make-frame' instead. */)
ee78dc32
GV
5476 (parms)
5477 Lisp_Object parms;
5478{
5479 struct frame *f;
5480 Lisp_Object frame, tem;
5481 Lisp_Object name;
5482 int minibuffer_only = 0;
5483 long window_prompting = 0;
5484 int width, height;
dc220243 5485 int count = BINDING_STACK_SIZE ();
1edf84e7 5486 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 5487 Lisp_Object display;
6fc2811b 5488 struct w32_display_info *dpyinfo = NULL;
ee78dc32
GV
5489 Lisp_Object parent;
5490 struct kboard *kb;
5491
4587b026
GV
5492 check_w32 ();
5493
ee78dc32
GV
5494 /* Use this general default value to start with
5495 until we know if this frame has a specified name. */
5496 Vx_resource_name = Vinvocation_name;
5497
6fc2811b 5498 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
ee78dc32
GV
5499 if (EQ (display, Qunbound))
5500 display = Qnil;
5501 dpyinfo = check_x_display_info (display);
5502#ifdef MULTI_KBOARD
5503 kb = dpyinfo->kboard;
5504#else
5505 kb = &the_only_kboard;
5506#endif
5507
6fc2811b 5508 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
ee78dc32
GV
5509 if (!STRINGP (name)
5510 && ! EQ (name, Qunbound)
5511 && ! NILP (name))
5512 error ("Invalid frame name--not a string or nil");
5513
5514 if (STRINGP (name))
5515 Vx_resource_name = name;
5516
5517 /* See if parent window is specified. */
6fc2811b 5518 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
ee78dc32
GV
5519 if (EQ (parent, Qunbound))
5520 parent = Qnil;
5521 if (! NILP (parent))
b7826503 5522 CHECK_NUMBER (parent);
ee78dc32 5523
1edf84e7
GV
5524 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5525 /* No need to protect DISPLAY because that's not used after passing
5526 it to make_frame_without_minibuffer. */
5527 frame = Qnil;
5528 GCPRO4 (parms, parent, name, frame);
1660f34a
JR
5529 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5530 RES_TYPE_SYMBOL);
ee78dc32
GV
5531 if (EQ (tem, Qnone) || NILP (tem))
5532 f = make_frame_without_minibuffer (Qnil, kb, display);
5533 else if (EQ (tem, Qonly))
5534 {
5535 f = make_minibuffer_frame ();
5536 minibuffer_only = 1;
5537 }
5538 else if (WINDOWP (tem))
5539 f = make_frame_without_minibuffer (tem, kb, display);
5540 else
5541 f = make_frame (1);
5542
1edf84e7
GV
5543 XSETFRAME (frame, f);
5544
ee78dc32
GV
5545 /* Note that Windows does support scroll bars. */
5546 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
5547 /* By default, make scrollbars the system standard width. */
5548 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 5549
fbd6baed 5550 f->output_method = output_w32;
6fc2811b
JR
5551 f->output_data.w32 =
5552 (struct w32_output *) xmalloc (sizeof (struct w32_output));
fbd6baed 5553 bzero (f->output_data.w32, sizeof (struct w32_output));
4587b026 5554 FRAME_FONTSET (f) = -1;
937e601e 5555 record_unwind_protect (unwind_create_frame, frame);
4587b026 5556
1edf84e7 5557 f->icon_name
6fc2811b 5558 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
1edf84e7
GV
5559 if (! STRINGP (f->icon_name))
5560 f->icon_name = Qnil;
5561
fbd6baed 5562/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
5563#ifdef MULTI_KBOARD
5564 FRAME_KBOARD (f) = kb;
5565#endif
5566
5567 /* Specify the parent under which to make this window. */
5568
5569 if (!NILP (parent))
5570 {
1660f34a 5571 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
fbd6baed 5572 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
5573 }
5574 else
5575 {
fbd6baed
GV
5576 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5577 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
5578 }
5579
ee78dc32
GV
5580 /* Set the name; the functions to which we pass f expect the name to
5581 be set. */
5582 if (EQ (name, Qunbound) || NILP (name))
5583 {
fbd6baed 5584 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
5585 f->explicit_name = 0;
5586 }
5587 else
5588 {
5589 f->name = name;
5590 f->explicit_name = 1;
5591 /* use the frame's title when getting resources for this frame. */
5592 specbind (Qx_resource_name, name);
5593 }
5594
5595 /* Extract the window parameters from the supplied values
5596 that are needed to determine window geometry. */
5597 {
5598 Lisp_Object font;
5599
6fc2811b
JR
5600 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5601
ee78dc32
GV
5602 BLOCK_INPUT;
5603 /* First, try whatever font the caller has specified. */
5604 if (STRINGP (font))
4587b026
GV
5605 {
5606 tem = Fquery_fontset (font, Qnil);
5607 if (STRINGP (tem))
5608 font = x_new_fontset (f, XSTRING (tem)->data);
5609 else
1075afa9 5610 font = x_new_font (f, XSTRING (font)->data);
4587b026 5611 }
ee78dc32
GV
5612 /* Try out a font which we hope has bold and italic variations. */
5613 if (!STRINGP (font))
e39649be 5614 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
ee78dc32 5615 if (! STRINGP (font))
6fc2811b 5616 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5617 /* If those didn't work, look for something which will at least work. */
5618 if (! STRINGP (font))
6fc2811b 5619 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
ee78dc32
GV
5620 UNBLOCK_INPUT;
5621 if (! STRINGP (font))
1edf84e7 5622 font = build_string ("Fixedsys");
ee78dc32
GV
5623
5624 x_default_parameter (f, parms, Qfont, font,
6fc2811b 5625 "font", "Font", RES_TYPE_STRING);
ee78dc32
GV
5626 }
5627
5628 x_default_parameter (f, parms, Qborder_width, make_number (2),
1660f34a 5629 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5630 /* This defaults to 2 in order to match xterm. We recognize either
5631 internalBorderWidth or internalBorder (which is what xterm calls
5632 it). */
5633 if (NILP (Fassq (Qinternal_border_width, parms)))
5634 {
5635 Lisp_Object value;
5636
6fc2811b 5637 value = w32_get_arg (parms, Qinternal_border_width,
1660f34a 5638 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
ee78dc32
GV
5639 if (! EQ (value, Qunbound))
5640 parms = Fcons (Fcons (Qinternal_border_width, value),
5641 parms);
5642 }
1edf84e7 5643 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32 5644 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
1660f34a
JR
5645 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5646 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5647 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
ee78dc32
GV
5648
5649 /* Also do the stuff which must be set before the window exists. */
5650 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
6fc2811b 5651 "foreground", "Foreground", RES_TYPE_STRING);
ee78dc32 5652 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
6fc2811b 5653 "background", "Background", RES_TYPE_STRING);
ee78dc32 5654 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
6fc2811b 5655 "pointerColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5656 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
6fc2811b 5657 "cursorColor", "Foreground", RES_TYPE_STRING);
ee78dc32 5658 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
6fc2811b
JR
5659 "borderColor", "BorderColor", RES_TYPE_STRING);
5660 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5661 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
dfff8a69
JR
5662 x_default_parameter (f, parms, Qline_spacing, Qnil,
5663 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
41c1bdd9
KS
5664 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5665 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5666 x_default_parameter (f, parms, Qright_fringe, Qnil,
5667 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
6fc2811b 5668
ee78dc32 5669
6fc2811b
JR
5670 /* Init faces before x_default_parameter is called for scroll-bar
5671 parameters because that function calls x_set_scroll_bar_width,
5672 which calls change_frame_size, which calls Fset_window_buffer,
5673 which runs hooks, which call Fvertical_motion. At the end, we
5674 end up in init_iterator with a null face cache, which should not
5675 happen. */
5676 init_frame_faces (f);
5677
ee78dc32 5678 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
6fc2811b 5679 "menuBar", "MenuBar", RES_TYPE_NUMBER);
d3109773 5680 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
6fc2811b 5681 "toolBar", "ToolBar", RES_TYPE_NUMBER);
919f1e88 5682
1edf84e7 5683 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
6fc2811b 5684 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
1edf84e7 5685 x_default_parameter (f, parms, Qtitle, Qnil,
6fc2811b 5686 "title", "Title", RES_TYPE_STRING);
f7b9d4d1
JR
5687 x_default_parameter (f, parms, Qfullscreen, Qnil,
5688 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
ee78dc32 5689
fbd6baed
GV
5690 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5691 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
3cf3436e
JR
5692
5693 /* Add the tool-bar height to the initial frame height so that the
5694 user gets a text display area of the size he specified with -g or
5695 via .Xdefaults. Later changes of the tool-bar height don't
5696 change the frame size. This is done so that users can create
5697 tall Emacs frames without having to guess how tall the tool-bar
5698 will get. */
5699 if (FRAME_TOOL_BAR_LINES (f))
5700 {
5701 int margin, relief, bar_height;
5702
a05e2bae 5703 relief = (tool_bar_button_relief >= 0
3cf3436e
JR
5704 ? tool_bar_button_relief
5705 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5706
5707 if (INTEGERP (Vtool_bar_button_margin)
5708 && XINT (Vtool_bar_button_margin) > 0)
5709 margin = XFASTINT (Vtool_bar_button_margin);
5710 else if (CONSP (Vtool_bar_button_margin)
5711 && INTEGERP (XCDR (Vtool_bar_button_margin))
5712 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5713 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5714 else
5715 margin = 0;
5716
5717 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5718 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5719 }
5720
ee78dc32
GV
5721 window_prompting = x_figure_window_size (f, parms);
5722
5723 if (window_prompting & XNegative)
5724 {
5725 if (window_prompting & YNegative)
fbd6baed 5726 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 5727 else
fbd6baed 5728 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
5729 }
5730 else
5731 {
5732 if (window_prompting & YNegative)
fbd6baed 5733 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 5734 else
fbd6baed 5735 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
5736 }
5737
fbd6baed 5738 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 5739
6fc2811b
JR
5740 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5741 f->no_split = minibuffer_only || EQ (tem, Qt);
5742
fbd6baed 5743 w32_window (f, window_prompting, minibuffer_only);
ee78dc32 5744 x_icon (f, parms);
6fc2811b
JR
5745
5746 x_make_gc (f);
5747
5748 /* Now consider the frame official. */
5749 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5750 Vframe_list = Fcons (frame, Vframe_list);
ee78dc32
GV
5751
5752 /* We need to do this after creating the window, so that the
5753 icon-creation functions can say whose icon they're describing. */
5754 x_default_parameter (f, parms, Qicon_type, Qnil,
6fc2811b 5755 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
ee78dc32
GV
5756
5757 x_default_parameter (f, parms, Qauto_raise, Qnil,
6fc2811b 5758 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5759 x_default_parameter (f, parms, Qauto_lower, Qnil,
6fc2811b 5760 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
ee78dc32 5761 x_default_parameter (f, parms, Qcursor_type, Qbox,
6fc2811b
JR
5762 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5763 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5764 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
ee78dc32
GV
5765
5766 /* Dimensions, especially f->height, must be done via change_frame_size.
5767 Change will not be effected unless different from the current
5768 f->height. */
5769 width = f->width;
5770 height = f->height;
dc220243 5771
1026b400
RS
5772 f->height = 0;
5773 SET_FRAME_WIDTH (f, 0);
6fc2811b
JR
5774 change_frame_size (f, height, width, 1, 0, 0);
5775
6fc2811b
JR
5776 /* Tell the server what size and position, etc, we want, and how
5777 badly we want them. This should be done after we have the menu
5778 bar so that its size can be taken into account. */
ee78dc32
GV
5779 BLOCK_INPUT;
5780 x_wm_set_size_hint (f, window_prompting, 0);
5781 UNBLOCK_INPUT;
5782
815d969e
JR
5783 /* Avoid a bug that causes the new frame to never become visible if
5784 an echo area message is displayed during the following call1. */
5785 specbind(Qredisplay_dont_pause, Qt);
5786
4694d762
JR
5787 /* Set up faces after all frame parameters are known. This call
5788 also merges in face attributes specified for new frames. If we
5789 don't do this, the `menu' face for instance won't have the right
5790 colors, and the menu bar won't appear in the specified colors for
5791 new frames. */
5792 call1 (Qface_set_after_frame_default, frame);
5793
6fc2811b
JR
5794 /* Make the window appear on the frame and enable display, unless
5795 the caller says not to. However, with explicit parent, Emacs
5796 cannot control visibility, so don't try. */
fbd6baed 5797 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
5798 {
5799 Lisp_Object visibility;
5800
6fc2811b 5801 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
ee78dc32
GV
5802 if (EQ (visibility, Qunbound))
5803 visibility = Qt;
5804
5805 if (EQ (visibility, Qicon))
5806 x_iconify_frame (f);
5807 else if (! NILP (visibility))
5808 x_make_frame_visible (f);
5809 else
5810 /* Must have been Qnil. */
5811 ;
5812 }
6fc2811b 5813 UNGCPRO;
9e57df62
GM
5814
5815 /* Make sure windows on this frame appear in calls to next-window
5816 and similar functions. */
5817 Vwindow_list = Qnil;
5818
ee78dc32
GV
5819 return unbind_to (count, frame);
5820}
5821
5822/* FRAME is used only to get a handle on the X display. We don't pass the
5823 display info directly because we're called from frame.c, which doesn't
5824 know about that structure. */
5825Lisp_Object
5826x_get_focus_frame (frame)
5827 struct frame *frame;
5828{
fbd6baed 5829 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5830 Lisp_Object xfocus;
fbd6baed 5831 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5832 return Qnil;
5833
fbd6baed 5834 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5835 return xfocus;
5836}
1edf84e7
GV
5837
5838DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
74e1aeec 5839 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
1edf84e7
GV
5840 (frame)
5841 Lisp_Object frame;
5842{
5843 x_focus_on_frame (check_x_frame (frame));
5844 return Qnil;
5845}
5846
ee78dc32 5847\f
767b1ff0
JR
5848/* Return the charset portion of a font name. */
5849char * xlfd_charset_of_font (char * fontname)
5850{
5851 char *charset, *encoding;
5852
5853 encoding = strrchr(fontname, '-');
ceb12877 5854 if (!encoding || encoding == fontname)
767b1ff0
JR
5855 return NULL;
5856
478ea067
AI
5857 for (charset = encoding - 1; charset >= fontname; charset--)
5858 if (*charset == '-')
5859 break;
767b1ff0 5860
478ea067 5861 if (charset == fontname || strcmp(charset, "-*-*") == 0)
767b1ff0
JR
5862 return NULL;
5863
5864 return charset + 1;
5865}
5866
33d52f9c
GV
5867struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5868 int size, char* filename);
8edb0a6f 5869static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
c7501041
EZ
5870static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5871 char * charset);
5872static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
33d52f9c 5873
8edb0a6f 5874static struct font_info *
33d52f9c 5875w32_load_system_font (f,fontname,size)
55dcfc15
AI
5876 struct frame *f;
5877 char * fontname;
5878 int size;
ee78dc32 5879{
4587b026
GV
5880 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5881 Lisp_Object font_names;
5882
4587b026
GV
5883 /* Get a list of all the fonts that match this name. Once we
5884 have a list of matching fonts, we compare them against the fonts
5885 we already have loaded by comparing names. */
5886 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5887
5888 if (!NILP (font_names))
3c190163 5889 {
4587b026
GV
5890 Lisp_Object tail;
5891 int i;
4587b026
GV
5892
5893 /* First check if any are already loaded, as that is cheaper
5894 than loading another one. */
5895 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 5896 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
6fc2811b
JR
5897 if (dpyinfo->font_table[i].name
5898 && (!strcmp (dpyinfo->font_table[i].name,
5899 XSTRING (XCAR (tail))->data)
5900 || !strcmp (dpyinfo->font_table[i].full_name,
5901 XSTRING (XCAR (tail))->data)))
4587b026 5902 return (dpyinfo->font_table + i);
6fc2811b 5903
8e713be6 5904 fontname = (char *) XSTRING (XCAR (font_names))->data;
4587b026 5905 }
1075afa9 5906 else if (w32_strict_fontnames)
5ca0cd71
GV
5907 {
5908 /* If EnumFontFamiliesEx was available, we got a full list of
5909 fonts back so stop now to avoid the possibility of loading a
5910 random font. If we had to fall back to EnumFontFamilies, the
5911 list is incomplete, so continue whether the font we want was
5912 listed or not. */
5913 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5914 FARPROC enum_font_families_ex
1075afa9 5915 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5916 if (enum_font_families_ex)
5917 return NULL;
5918 }
4587b026
GV
5919
5920 /* Load the font and add it to the table. */
5921 {
767b1ff0 5922 char *full_name, *encoding, *charset;
4587b026
GV
5923 XFontStruct *font;
5924 struct font_info *fontp;
3c190163 5925 LOGFONT lf;
4587b026 5926 BOOL ok;
19c291d3 5927 int codepage;
6fc2811b 5928 int i;
5ac45f98 5929
4587b026 5930 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5931 return (NULL);
5ac45f98 5932
4587b026
GV
5933 if (!*lf.lfFaceName)
5934 /* If no name was specified for the font, we get a random font
5935 from CreateFontIndirect - this is not particularly
5936 desirable, especially since CreateFontIndirect does not
5937 fill out the missing name in lf, so we never know what we
5938 ended up with. */
5939 return NULL;
5940
d65a9cdc
JR
5941 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5942 since those fonts leave garbage behind. */
5943 lf.lfQuality = ANTIALIASED_QUALITY;
5944
3c190163 5945 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
c6be3860 5946 bzero (font, sizeof (*font));
5ac45f98 5947
33d52f9c
GV
5948 /* Set bdf to NULL to indicate that this is a Windows font. */
5949 font->bdf = NULL;
5ac45f98 5950
3c190163 5951 BLOCK_INPUT;
5ac45f98
GV
5952
5953 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5954
1a292d24
AI
5955 if (font->hfont == NULL)
5956 {
5957 ok = FALSE;
5958 }
5959 else
5960 {
5961 HDC hdc;
5962 HANDLE oldobj;
19c291d3
AI
5963
5964 codepage = w32_codepage_for_font (fontname);
1a292d24
AI
5965
5966 hdc = GetDC (dpyinfo->root_window);
5967 oldobj = SelectObject (hdc, font->hfont);
5c6682be 5968
1a292d24 5969 ok = GetTextMetrics (hdc, &font->tm);
5c6682be
JR
5970 if (codepage == CP_UNICODE)
5971 font->double_byte_p = 1;
5972 else
8b77111c
AI
5973 {
5974 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5975 don't report themselves as double byte fonts, when
5976 patently they are. So instead of trusting
5977 GetFontLanguageInfo, we check the properties of the
5978 codepage directly, since that is ultimately what we are
5979 working from anyway. */
5980 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5981 CPINFO cpi = {0};
5982 GetCPInfo (codepage, &cpi);
5983 font->double_byte_p = cpi.MaxCharSize > 1;
5984 }
5c6682be 5985
1a292d24
AI
5986 SelectObject (hdc, oldobj);
5987 ReleaseDC (dpyinfo->root_window, hdc);
6fc2811b
JR
5988 /* Fill out details in lf according to the font that was
5989 actually loaded. */
5990 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5991 lf.lfWidth = font->tm.tmAveCharWidth;
5992 lf.lfWeight = font->tm.tmWeight;
5993 lf.lfItalic = font->tm.tmItalic;
5994 lf.lfCharSet = font->tm.tmCharSet;
5995 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
d88c567c 5996 ? VARIABLE_PITCH : FIXED_PITCH);
6fc2811b
JR
5997 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5998 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
c6be3860
AI
5999
6000 w32_cache_char_metrics (font);
1a292d24 6001 }
5ac45f98 6002
1a292d24 6003 UNBLOCK_INPUT;
5ac45f98 6004
4587b026
GV
6005 if (!ok)
6006 {
1a292d24
AI
6007 w32_unload_font (dpyinfo, font);
6008 return (NULL);
6009 }
ee78dc32 6010
6fc2811b
JR
6011 /* Find a free slot in the font table. */
6012 for (i = 0; i < dpyinfo->n_fonts; ++i)
6013 if (dpyinfo->font_table[i].name == NULL)
6014 break;
6015
6016 /* If no free slot found, maybe enlarge the font table. */
6017 if (i == dpyinfo->n_fonts
6018 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4587b026 6019 {
6fc2811b
JR
6020 int sz;
6021 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6022 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4587b026 6023 dpyinfo->font_table
6fc2811b 6024 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4587b026
GV
6025 }
6026
6fc2811b
JR
6027 fontp = dpyinfo->font_table + i;
6028 if (i == dpyinfo->n_fonts)
6029 ++dpyinfo->n_fonts;
4587b026
GV
6030
6031 /* Now fill in the slots of *FONTP. */
6032 BLOCK_INPUT;
6033 fontp->font = font;
6fc2811b 6034 fontp->font_idx = i;
4587b026
GV
6035 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6036 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6037
767b1ff0
JR
6038 charset = xlfd_charset_of_font (fontname);
6039
19c291d3
AI
6040 /* Cache the W32 codepage for a font. This makes w32_encode_char
6041 (called for every glyph during redisplay) much faster. */
6042 fontp->codepage = codepage;
6043
4587b026
GV
6044 /* Work out the font's full name. */
6045 full_name = (char *)xmalloc (100);
767b1ff0 6046 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4587b026
GV
6047 fontp->full_name = full_name;
6048 else
6049 {
6050 /* If all else fails - just use the name we used to load it. */
6051 xfree (full_name);
6052 fontp->full_name = fontp->name;
6053 }
6054
6055 fontp->size = FONT_WIDTH (font);
6056 fontp->height = FONT_HEIGHT (font);
6057
6058 /* The slot `encoding' specifies how to map a character
6059 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
126f2e35
JR
6060 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6061 (0:0x20..0x7F, 1:0xA0..0xFF,
6062 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4587b026 6063 2:0xA020..0xFF7F). For the moment, we don't know which charset
6fc2811b 6064 uses this font. So, we set information in fontp->encoding[1]
4587b026
GV
6065 which is never used by any charset. If mapping can't be
6066 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
6067
6068 /* SJIS fonts need to be set to type 4, all others seem to work as
6069 type FONT_ENCODING_NOT_DECIDED. */
6070 encoding = strrchr (fontp->name, '-');
d84b082d 6071 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
1c885fe1 6072 fontp->encoding[1] = 4;
33d52f9c 6073 else
1c885fe1 6074 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
6075
6076 /* The following three values are set to 0 under W32, which is
6077 what they get set to if XGetFontProperty fails under X. */
6078 fontp->baseline_offset = 0;
6079 fontp->relative_compose = 0;
33d52f9c 6080 fontp->default_ascent = 0;
4587b026 6081
6fc2811b
JR
6082 /* Set global flag fonts_changed_p to non-zero if the font loaded
6083 has a character with a smaller width than any other character
f7b9d4d1 6084 before, or if the font loaded has a smaller height than any
6fc2811b
JR
6085 other font loaded before. If this happens, it will make a
6086 glyph matrix reallocation necessary. */
f7b9d4d1 6087 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4587b026 6088 UNBLOCK_INPUT;
4587b026
GV
6089 return fontp;
6090 }
6091}
6092
33d52f9c
GV
6093/* Load font named FONTNAME of size SIZE for frame F, and return a
6094 pointer to the structure font_info while allocating it dynamically.
6095 If loading fails, return NULL. */
6096struct font_info *
6097w32_load_font (f,fontname,size)
6098struct frame *f;
6099char * fontname;
6100int size;
6101{
6102 Lisp_Object bdf_fonts;
6103 struct font_info *retval = NULL;
6104
8edb0a6f 6105 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
33d52f9c
GV
6106
6107 while (!retval && CONSP (bdf_fonts))
6108 {
6109 char *bdf_name, *bdf_file;
6110 Lisp_Object bdf_pair;
6111
8e713be6
KR
6112 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6113 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6114 bdf_file = XSTRING (XCDR (bdf_pair))->data;
33d52f9c
GV
6115
6116 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6117
8e713be6 6118 bdf_fonts = XCDR (bdf_fonts);
33d52f9c
GV
6119 }
6120
6121 if (retval)
6122 return retval;
6123
6124 return w32_load_system_font(f, fontname, size);
6125}
6126
6127
ee78dc32 6128void
fbd6baed
GV
6129w32_unload_font (dpyinfo, font)
6130 struct w32_display_info *dpyinfo;
ee78dc32
GV
6131 XFontStruct * font;
6132{
6133 if (font)
6134 {
c6be3860 6135 if (font->per_char) xfree (font->per_char);
33d52f9c
GV
6136 if (font->bdf) w32_free_bdf_font (font->bdf);
6137
3c190163 6138 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
6139 xfree (font);
6140 }
6141}
6142
fbd6baed 6143/* The font conversion stuff between x and w32 */
ee78dc32
GV
6144
6145/* X font string is as follows (from faces.el)
6146 * (let ((- "[-?]")
6147 * (foundry "[^-]+")
6148 * (family "[^-]+")
6149 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6150 * (weight\? "\\([^-]*\\)") ; 1
6151 * (slant "\\([ior]\\)") ; 2
6152 * (slant\? "\\([^-]?\\)") ; 2
6153 * (swidth "\\([^-]*\\)") ; 3
6154 * (adstyle "[^-]*") ; 4
6155 * (pixelsize "[0-9]+")
6156 * (pointsize "[0-9][0-9]+")
6157 * (resx "[0-9][0-9]+")
6158 * (resy "[0-9][0-9]+")
6159 * (spacing "[cmp?*]")
6160 * (avgwidth "[0-9]+")
6161 * (registry "[^-]+")
6162 * (encoding "[^-]+")
6163 * )
ee78dc32 6164 */
ee78dc32 6165
8edb0a6f 6166static LONG
fbd6baed 6167x_to_w32_weight (lpw)
ee78dc32
GV
6168 char * lpw;
6169{
6170 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
6171
6172 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6173 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6174 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6175 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 6176 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
6177 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6178 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6179 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6180 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6181 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 6182 else
5ac45f98 6183 return FW_DONTCARE;
ee78dc32
GV
6184}
6185
5ac45f98 6186
8edb0a6f 6187static char *
fbd6baed 6188w32_to_x_weight (fnweight)
ee78dc32
GV
6189 int fnweight;
6190{
5ac45f98
GV
6191 if (fnweight >= FW_HEAVY) return "heavy";
6192 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6193 if (fnweight >= FW_BOLD) return "bold";
03f8fb34 6194 if (fnweight >= FW_SEMIBOLD) return "demibold";
5ac45f98
GV
6195 if (fnweight >= FW_MEDIUM) return "medium";
6196 if (fnweight >= FW_NORMAL) return "normal";
6197 if (fnweight >= FW_LIGHT) return "light";
6198 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6199 if (fnweight >= FW_THIN) return "thin";
6200 else
6201 return "*";
6202}
6203
8edb0a6f 6204static LONG
fbd6baed 6205x_to_w32_charset (lpcs)
5ac45f98
GV
6206 char * lpcs;
6207{
767b1ff0 6208 Lisp_Object this_entry, w32_charset;
8b77111c
AI
6209 char *charset;
6210 int len = strlen (lpcs);
6211
6212 /* Support "*-#nnn" format for unknown charsets. */
6213 if (strncmp (lpcs, "*-#", 3) == 0)
6214 return atoi (lpcs + 3);
6215
6216 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6217 charset = alloca (len + 1);
6218 strcpy (charset, lpcs);
6219 lpcs = strchr (charset, '*');
6220 if (lpcs)
6221 *lpcs = 0;
4587b026 6222
dfff8a69
JR
6223 /* Look through w32-charset-info-alist for the character set.
6224 Format of each entry is
6225 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6226 */
8b77111c 6227 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
4587b026 6228
767b1ff0
JR
6229 if (NILP(this_entry))
6230 {
6231 /* At startup, we want iso8859-1 fonts to come up properly. */
8b77111c 6232 if (stricmp(charset, "iso8859-1") == 0)
767b1ff0
JR
6233 return ANSI_CHARSET;
6234 else
6235 return DEFAULT_CHARSET;
6236 }
6237
6238 w32_charset = Fcar (Fcdr (this_entry));
6239
d84b082d 6240 /* Translate Lisp symbol to number. */
767b1ff0
JR
6241 if (w32_charset == Qw32_charset_ansi)
6242 return ANSI_CHARSET;
6243 if (w32_charset == Qw32_charset_symbol)
6244 return SYMBOL_CHARSET;
6245 if (w32_charset == Qw32_charset_shiftjis)
6246 return SHIFTJIS_CHARSET;
6247 if (w32_charset == Qw32_charset_hangeul)
6248 return HANGEUL_CHARSET;
6249 if (w32_charset == Qw32_charset_chinesebig5)
6250 return CHINESEBIG5_CHARSET;
6251 if (w32_charset == Qw32_charset_gb2312)
6252 return GB2312_CHARSET;
6253 if (w32_charset == Qw32_charset_oem)
6254 return OEM_CHARSET;
dfff8a69 6255#ifdef JOHAB_CHARSET
767b1ff0
JR
6256 if (w32_charset == Qw32_charset_johab)
6257 return JOHAB_CHARSET;
6258 if (w32_charset == Qw32_charset_easteurope)
6259 return EASTEUROPE_CHARSET;
6260 if (w32_charset == Qw32_charset_turkish)
6261 return TURKISH_CHARSET;
6262 if (w32_charset == Qw32_charset_baltic)
6263 return BALTIC_CHARSET;
6264 if (w32_charset == Qw32_charset_russian)
6265 return RUSSIAN_CHARSET;
6266 if (w32_charset == Qw32_charset_arabic)
6267 return ARABIC_CHARSET;
6268 if (w32_charset == Qw32_charset_greek)
6269 return GREEK_CHARSET;
6270 if (w32_charset == Qw32_charset_hebrew)
6271 return HEBREW_CHARSET;
6272 if (w32_charset == Qw32_charset_vietnamese)
6273 return VIETNAMESE_CHARSET;
6274 if (w32_charset == Qw32_charset_thai)
6275 return THAI_CHARSET;
6276 if (w32_charset == Qw32_charset_mac)
6277 return MAC_CHARSET;
dfff8a69 6278#endif /* JOHAB_CHARSET */
5ac45f98 6279#ifdef UNICODE_CHARSET
767b1ff0
JR
6280 if (w32_charset == Qw32_charset_unicode)
6281 return UNICODE_CHARSET;
5ac45f98 6282#endif
dfff8a69
JR
6283
6284 return DEFAULT_CHARSET;
5ac45f98
GV
6285}
6286
dfff8a69 6287
8edb0a6f 6288static char *
fbd6baed 6289w32_to_x_charset (fncharset)
5ac45f98
GV
6290 int fncharset;
6291{
5e905a57 6292 static char buf[32];
767b1ff0 6293 Lisp_Object charset_type;
1edf84e7 6294
5ac45f98
GV
6295 switch (fncharset)
6296 {
767b1ff0
JR
6297 case ANSI_CHARSET:
6298 /* Handle startup case of w32-charset-info-alist not
6299 being set up yet. */
6300 if (NILP(Vw32_charset_info_alist))
6301 return "iso8859-1";
6302 charset_type = Qw32_charset_ansi;
6303 break;
6304 case DEFAULT_CHARSET:
6305 charset_type = Qw32_charset_default;
6306 break;
6307 case SYMBOL_CHARSET:
6308 charset_type = Qw32_charset_symbol;
6309 break;
6310 case SHIFTJIS_CHARSET:
6311 charset_type = Qw32_charset_shiftjis;
6312 break;
6313 case HANGEUL_CHARSET:
6314 charset_type = Qw32_charset_hangeul;
6315 break;
6316 case GB2312_CHARSET:
6317 charset_type = Qw32_charset_gb2312;
6318 break;
6319 case CHINESEBIG5_CHARSET:
6320 charset_type = Qw32_charset_chinesebig5;
6321 break;
6322 case OEM_CHARSET:
6323 charset_type = Qw32_charset_oem;
6324 break;
4587b026
GV
6325
6326 /* More recent versions of Windows (95 and NT4.0) define more
6327 character sets. */
6328#ifdef EASTEUROPE_CHARSET
767b1ff0
JR
6329 case EASTEUROPE_CHARSET:
6330 charset_type = Qw32_charset_easteurope;
6331 break;
6332 case TURKISH_CHARSET:
6333 charset_type = Qw32_charset_turkish;
6334 break;
6335 case BALTIC_CHARSET:
6336 charset_type = Qw32_charset_baltic;
6337 break;
33d52f9c 6338 case RUSSIAN_CHARSET:
767b1ff0
JR
6339 charset_type = Qw32_charset_russian;
6340 break;
6341 case ARABIC_CHARSET:
6342 charset_type = Qw32_charset_arabic;
6343 break;
6344 case GREEK_CHARSET:
6345 charset_type = Qw32_charset_greek;
6346 break;
6347 case HEBREW_CHARSET:
6348 charset_type = Qw32_charset_hebrew;
6349 break;
6350 case VIETNAMESE_CHARSET:
6351 charset_type = Qw32_charset_vietnamese;
6352 break;
6353 case THAI_CHARSET:
6354 charset_type = Qw32_charset_thai;
6355 break;
6356 case MAC_CHARSET:
6357 charset_type = Qw32_charset_mac;
6358 break;
6359 case JOHAB_CHARSET:
6360 charset_type = Qw32_charset_johab;
6361 break;
4587b026
GV
6362#endif
6363
5ac45f98 6364#ifdef UNICODE_CHARSET
767b1ff0
JR
6365 case UNICODE_CHARSET:
6366 charset_type = Qw32_charset_unicode;
6367 break;
5ac45f98 6368#endif
767b1ff0
JR
6369 default:
6370 /* Encode numerical value of unknown charset. */
6371 sprintf (buf, "*-#%u", fncharset);
6372 return buf;
5ac45f98 6373 }
767b1ff0
JR
6374
6375 {
6376 Lisp_Object rest;
6377 char * best_match = NULL;
6378
6379 /* Look through w32-charset-info-alist for the character set.
6380 Prefer ISO codepages, and prefer lower numbers in the ISO
6381 range. Only return charsets for codepages which are installed.
6382
6383 Format of each entry is
6384 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6385 */
6386 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6387 {
6388 char * x_charset;
6389 Lisp_Object w32_charset;
6390 Lisp_Object codepage;
6391
6392 Lisp_Object this_entry = XCAR (rest);
6393
6394 /* Skip invalid entries in alist. */
6395 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6396 || !CONSP (XCDR (this_entry))
6397 || !SYMBOLP (XCAR (XCDR (this_entry))))
6398 continue;
6399
6400 x_charset = XSTRING (XCAR (this_entry))->data;
6401 w32_charset = XCAR (XCDR (this_entry));
6402 codepage = XCDR (XCDR (this_entry));
6403
6404 /* Look for Same charset and a valid codepage (or non-int
6405 which means ignore). */
6406 if (w32_charset == charset_type
6407 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6408 || IsValidCodePage (XINT (codepage))))
6409 {
6410 /* If we don't have a match already, then this is the
6411 best. */
6412 if (!best_match)
6413 best_match = x_charset;
6414 /* If this is an ISO codepage, and the best so far isn't,
6415 then this is better. */
d84b082d
JR
6416 else if (strnicmp (best_match, "iso", 3) != 0
6417 && strnicmp (x_charset, "iso", 3) == 0)
767b1ff0
JR
6418 best_match = x_charset;
6419 /* If both are ISO8859 codepages, choose the one with the
6420 lowest number in the encoding field. */
d84b082d
JR
6421 else if (strnicmp (best_match, "iso8859-", 8) == 0
6422 && strnicmp (x_charset, "iso8859-", 8) == 0)
767b1ff0
JR
6423 {
6424 int best_enc = atoi (best_match + 8);
6425 int this_enc = atoi (x_charset + 8);
6426 if (this_enc > 0 && this_enc < best_enc)
6427 best_match = x_charset;
6428 }
6429 }
6430 }
6431
6432 /* If no match, encode the numeric value. */
6433 if (!best_match)
6434 {
6435 sprintf (buf, "*-#%u", fncharset);
6436 return buf;
6437 }
6438
5e905a57
JR
6439 strncpy(buf, best_match, 31);
6440 buf[31] = '\0';
767b1ff0
JR
6441 return buf;
6442 }
ee78dc32
GV
6443}
6444
dfff8a69 6445
d84b082d
JR
6446/* Return all the X charsets that map to a font. */
6447static Lisp_Object
6448w32_to_all_x_charsets (fncharset)
6449 int fncharset;
6450{
6451 static char buf[32];
6452 Lisp_Object charset_type;
6453 Lisp_Object retval = Qnil;
6454
6455 switch (fncharset)
6456 {
6457 case ANSI_CHARSET:
6458 /* Handle startup case of w32-charset-info-alist not
6459 being set up yet. */
6460 if (NILP(Vw32_charset_info_alist))
d86c35ee
JR
6461 return Fcons (build_string ("iso8859-1"), Qnil);
6462
d84b082d
JR
6463 charset_type = Qw32_charset_ansi;
6464 break;
6465 case DEFAULT_CHARSET:
6466 charset_type = Qw32_charset_default;
6467 break;
6468 case SYMBOL_CHARSET:
6469 charset_type = Qw32_charset_symbol;
6470 break;
6471 case SHIFTJIS_CHARSET:
6472 charset_type = Qw32_charset_shiftjis;
6473 break;
6474 case HANGEUL_CHARSET:
6475 charset_type = Qw32_charset_hangeul;
6476 break;
6477 case GB2312_CHARSET:
6478 charset_type = Qw32_charset_gb2312;
6479 break;
6480 case CHINESEBIG5_CHARSET:
6481 charset_type = Qw32_charset_chinesebig5;
6482 break;
6483 case OEM_CHARSET:
6484 charset_type = Qw32_charset_oem;
6485 break;
6486
6487 /* More recent versions of Windows (95 and NT4.0) define more
6488 character sets. */
6489#ifdef EASTEUROPE_CHARSET
6490 case EASTEUROPE_CHARSET:
6491 charset_type = Qw32_charset_easteurope;
6492 break;
6493 case TURKISH_CHARSET:
6494 charset_type = Qw32_charset_turkish;
6495 break;
6496 case BALTIC_CHARSET:
6497 charset_type = Qw32_charset_baltic;
6498 break;
6499 case RUSSIAN_CHARSET:
6500 charset_type = Qw32_charset_russian;
6501 break;
6502 case ARABIC_CHARSET:
6503 charset_type = Qw32_charset_arabic;
6504 break;
6505 case GREEK_CHARSET:
6506 charset_type = Qw32_charset_greek;
6507 break;
6508 case HEBREW_CHARSET:
6509 charset_type = Qw32_charset_hebrew;
6510 break;
6511 case VIETNAMESE_CHARSET:
6512 charset_type = Qw32_charset_vietnamese;
6513 break;
6514 case THAI_CHARSET:
6515 charset_type = Qw32_charset_thai;
6516 break;
6517 case MAC_CHARSET:
6518 charset_type = Qw32_charset_mac;
6519 break;
6520 case JOHAB_CHARSET:
6521 charset_type = Qw32_charset_johab;
6522 break;
6523#endif
6524
6525#ifdef UNICODE_CHARSET
6526 case UNICODE_CHARSET:
6527 charset_type = Qw32_charset_unicode;
6528 break;
6529#endif
6530 default:
6531 /* Encode numerical value of unknown charset. */
6532 sprintf (buf, "*-#%u", fncharset);
6533 return Fcons (build_string (buf), Qnil);
6534 }
6535
6536 {
6537 Lisp_Object rest;
6538 /* Look through w32-charset-info-alist for the character set.
6539 Only return charsets for codepages which are installed.
6540
6541 Format of each entry in Vw32_charset_info_alist is
6542 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6543 */
6544 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6545 {
6546 Lisp_Object x_charset;
6547 Lisp_Object w32_charset;
6548 Lisp_Object codepage;
6549
6550 Lisp_Object this_entry = XCAR (rest);
6551
6552 /* Skip invalid entries in alist. */
6553 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6554 || !CONSP (XCDR (this_entry))
6555 || !SYMBOLP (XCAR (XCDR (this_entry))))
6556 continue;
6557
6558 x_charset = XCAR (this_entry);
6559 w32_charset = XCAR (XCDR (this_entry));
6560 codepage = XCDR (XCDR (this_entry));
6561
6562 /* Look for Same charset and a valid codepage (or non-int
6563 which means ignore). */
6564 if (w32_charset == charset_type
6565 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6566 || IsValidCodePage (XINT (codepage))))
6567 {
6568 retval = Fcons (x_charset, retval);
6569 }
6570 }
6571
6572 /* If no match, encode the numeric value. */
6573 if (NILP (retval))
6574 {
6575 sprintf (buf, "*-#%u", fncharset);
6576 return Fcons (build_string (buf), Qnil);
6577 }
6578
6579 return retval;
6580 }
6581}
6582
dfff8a69
JR
6583/* Get the Windows codepage corresponding to the specified font. The
6584 charset info in the font name is used to look up
6585 w32-charset-to-codepage-alist. */
6586int
6587w32_codepage_for_font (char *fontname)
6588{
767b1ff0
JR
6589 Lisp_Object codepage, entry;
6590 char *charset_str, *charset, *end;
dfff8a69 6591
767b1ff0 6592 if (NILP (Vw32_charset_info_alist))
dfff8a69
JR
6593 return CP_DEFAULT;
6594
767b1ff0
JR
6595 /* Extract charset part of font string. */
6596 charset = xlfd_charset_of_font (fontname);
6597
6598 if (!charset)
ceb12877 6599 return CP_UNKNOWN;
767b1ff0 6600
8b77111c 6601 charset_str = (char *) alloca (strlen (charset) + 1);
767b1ff0
JR
6602 strcpy (charset_str, charset);
6603
8b77111c 6604#if 0
dfff8a69
JR
6605 /* Remove leading "*-". */
6606 if (strncmp ("*-", charset_str, 2) == 0)
6607 charset = charset_str + 2;
6608 else
8b77111c 6609#endif
dfff8a69
JR
6610 charset = charset_str;
6611
6612 /* Stop match at wildcard (including preceding '-'). */
6613 if (end = strchr (charset, '*'))
6614 {
6615 if (end > charset && *(end-1) == '-')
6616 end--;
6617 *end = '\0';
6618 }
6619
767b1ff0
JR
6620 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6621 if (NILP (entry))
ceb12877 6622 return CP_UNKNOWN;
767b1ff0
JR
6623
6624 codepage = Fcdr (Fcdr (entry));
6625
6626 if (NILP (codepage))
6627 return CP_8BIT;
6628 else if (XFASTINT (codepage) == XFASTINT (Qt))
6629 return CP_UNICODE;
6630 else if (INTEGERP (codepage))
dfff8a69
JR
6631 return XINT (codepage);
6632 else
ceb12877 6633 return CP_UNKNOWN;
dfff8a69
JR
6634}
6635
6636
8edb0a6f 6637static BOOL
767b1ff0 6638w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
ee78dc32
GV
6639 LOGFONT * lplogfont;
6640 char * lpxstr;
6641 int len;
767b1ff0 6642 char * specific_charset;
ee78dc32 6643{
6fc2811b 6644 char* fonttype;
f46e6225 6645 char *fontname;
3cb20f4a
RS
6646 char height_pixels[8];
6647 char height_dpi[8];
6648 char width_pixels[8];
4587b026 6649 char *fontname_dash;
ac849ba4
JR
6650 int display_resy = (int) one_w32_display_info.resy;
6651 int display_resx = (int) one_w32_display_info.resx;
f46e6225
GV
6652 int bufsz;
6653 struct coding_system coding;
3cb20f4a
RS
6654
6655 if (!lpxstr) abort ();
ee78dc32 6656
3cb20f4a
RS
6657 if (!lplogfont)
6658 return FALSE;
6659
6fc2811b
JR
6660 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6661 fonttype = "raster";
6662 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6663 fonttype = "outline";
6664 else
6665 fonttype = "unknown";
6666
1fa3a200 6667 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
f46e6225 6668 &coding);
aab5ac44
KH
6669 coding.src_multibyte = 0;
6670 coding.dst_multibyte = 1;
f46e6225
GV
6671 coding.mode |= CODING_MODE_LAST_BLOCK;
6672 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6673
6674 fontname = alloca(sizeof(*fontname) * bufsz);
6675 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6676 strlen(lplogfont->lfFaceName), bufsz - 1);
6677 *(fontname + coding.produced) = '\0';
4587b026
GV
6678
6679 /* Replace dashes with underscores so the dashes are not
f46e6225 6680 misinterpreted. */
4587b026
GV
6681 fontname_dash = fontname;
6682 while (fontname_dash = strchr (fontname_dash, '-'))
6683 *fontname_dash = '_';
6684
3cb20f4a 6685 if (lplogfont->lfHeight)
ee78dc32 6686 {
3cb20f4a
RS
6687 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6688 sprintf (height_dpi, "%u",
33d52f9c 6689 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
6690 }
6691 else
ee78dc32 6692 {
3cb20f4a
RS
6693 strcpy (height_pixels, "*");
6694 strcpy (height_dpi, "*");
ee78dc32 6695 }
3cb20f4a
RS
6696 if (lplogfont->lfWidth)
6697 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6698 else
6699 strcpy (width_pixels, "*");
6700
6701 _snprintf (lpxstr, len - 1,
6fc2811b
JR
6702 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6703 fonttype, /* foundry */
4587b026
GV
6704 fontname, /* family */
6705 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6706 lplogfont->lfItalic?'i':'r', /* slant */
6707 /* setwidth name */
6708 /* add style name */
6709 height_pixels, /* pixel size */
6710 height_dpi, /* point size */
33d52f9c
GV
6711 display_resx, /* resx */
6712 display_resy, /* resy */
4587b026
GV
6713 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6714 ? 'p' : 'c', /* spacing */
6715 width_pixels, /* avg width */
767b1ff0
JR
6716 specific_charset ? specific_charset
6717 : w32_to_x_charset (lplogfont->lfCharSet)
6718 /* charset registry and encoding */
3cb20f4a
RS
6719 );
6720
ee78dc32
GV
6721 lpxstr[len - 1] = 0; /* just to be sure */
6722 return (TRUE);
6723}
6724
8edb0a6f 6725static BOOL
fbd6baed 6726x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
6727 char * lpxstr;
6728 LOGFONT * lplogfont;
6729{
f46e6225
GV
6730 struct coding_system coding;
6731
ee78dc32 6732 if (!lplogfont) return (FALSE);
f46e6225 6733
ee78dc32 6734 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 6735
1a292d24 6736 /* Set default value for each field. */
771c47d5 6737#if 1
ee78dc32
GV
6738 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6739 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6740 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
6741#else
6742 /* go for maximum quality */
6743 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6744 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6745 lplogfont->lfQuality = PROOF_QUALITY;
6746#endif
6747
1a292d24
AI
6748 lplogfont->lfCharSet = DEFAULT_CHARSET;
6749 lplogfont->lfWeight = FW_DONTCARE;
6750 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6751
5ac45f98
GV
6752 if (!lpxstr)
6753 return FALSE;
6754
6755 /* Provide a simple escape mechanism for specifying Windows font names
6756 * directly -- if font spec does not beginning with '-', assume this
6757 * format:
6758 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6759 */
ee78dc32 6760
5ac45f98
GV
6761 if (*lpxstr == '-')
6762 {
33d52f9c
GV
6763 int fields, tem;
6764 char name[50], weight[20], slant, pitch, pixels[10], height[10],
8b77111c 6765 width[10], resy[10], remainder[50];
5ac45f98 6766 char * encoding;
ac849ba4 6767 int dpi = (int) one_w32_display_info.resy;
5ac45f98
GV
6768
6769 fields = sscanf (lpxstr,
8b77111c 6770 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
33d52f9c 6771 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
8b77111c
AI
6772 if (fields == EOF)
6773 return (FALSE);
6774
6775 /* In the general case when wildcards cover more than one field,
6776 we don't know which field is which, so don't fill any in.
6777 However, we need to cope with this particular form, which is
6778 generated by font_list_1 (invoked by try_font_list):
6779 "-raster-6x10-*-gb2312*-*"
6780 and make sure to correctly parse the charset field. */
6781 if (fields == 3)
6782 {
6783 fields = sscanf (lpxstr,
6784 "-%*[^-]-%49[^-]-*-%49s",
6785 name, remainder);
6786 }
6787 else if (fields < 9)
6788 {
6789 fields = 0;
6790 remainder[0] = 0;
6791 }
6fc2811b 6792
5ac45f98
GV
6793 if (fields > 0 && name[0] != '*')
6794 {
8ea3e054
RS
6795 int bufsize;
6796 unsigned char *buf;
6797
f46e6225 6798 setup_coding_system
1fa3a200 6799 (Fcheck_coding_system (Vlocale_coding_system), &coding);
aab5ac44
KH
6800 coding.src_multibyte = 1;
6801 coding.dst_multibyte = 1;
8ea3e054
RS
6802 bufsize = encoding_buffer_size (&coding, strlen (name));
6803 buf = (unsigned char *) alloca (bufsize);
f46e6225 6804 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
6805 encode_coding (&coding, name, buf, strlen (name), bufsize);
6806 if (coding.produced >= LF_FACESIZE)
6807 coding.produced = LF_FACESIZE - 1;
6808 buf[coding.produced] = 0;
6809 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
6810 }
6811 else
6812 {
6fc2811b 6813 lplogfont->lfFaceName[0] = '\0';
5ac45f98
GV
6814 }
6815
6816 fields--;
6817
fbd6baed 6818 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6819
6820 fields--;
6821
c8874f14 6822 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5ac45f98
GV
6823
6824 fields--;
6825
6826 if (fields > 0 && pixels[0] != '*')
6827 lplogfont->lfHeight = atoi (pixels);
6828
6829 fields--;
5ac45f98 6830 fields--;
33d52f9c
GV
6831 if (fields > 0 && resy[0] != '*')
6832 {
6fc2811b 6833 tem = atoi (resy);
33d52f9c
GV
6834 if (tem > 0) dpi = tem;
6835 }
5ac45f98 6836
33d52f9c
GV
6837 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6838 lplogfont->lfHeight = atoi (height) * dpi / 720;
6839
6840 if (fields > 0)
5ac45f98
GV
6841 lplogfont->lfPitchAndFamily =
6842 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6843
6844 fields--;
6845
6846 if (fields > 0 && width[0] != '*')
6847 lplogfont->lfWidth = atoi (width) / 10;
6848
6849 fields--;
6850
4587b026 6851 /* Strip the trailing '-' if present. (it shouldn't be, as it
d88c567c 6852 fails the test against xlfd-tight-regexp in fontset.el). */
3c190163 6853 {
5ac45f98
GV
6854 int len = strlen (remainder);
6855 if (len > 0 && remainder[len-1] == '-')
6856 remainder[len-1] = 0;
ee78dc32 6857 }
5ac45f98 6858 encoding = remainder;
8b77111c 6859#if 0
5ac45f98
GV
6860 if (strncmp (encoding, "*-", 2) == 0)
6861 encoding += 2;
8b77111c
AI
6862#endif
6863 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5ac45f98
GV
6864 }
6865 else
6866 {
6867 int fields;
6868 char name[100], height[10], width[10], weight[20];
a1a80b40 6869
5ac45f98
GV
6870 fields = sscanf (lpxstr,
6871 "%99[^:]:%9[^:]:%9[^:]:%19s",
6872 name, height, width, weight);
6873
6874 if (fields == EOF) return (FALSE);
6875
6876 if (fields > 0)
6877 {
6878 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6879 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6880 }
6881 else
6882 {
6883 lplogfont->lfFaceName[0] = 0;
6884 }
6885
6886 fields--;
6887
6888 if (fields > 0)
6889 lplogfont->lfHeight = atoi (height);
6890
6891 fields--;
6892
6893 if (fields > 0)
6894 lplogfont->lfWidth = atoi (width);
6895
6896 fields--;
6897
fbd6baed 6898 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
6899 }
6900
6901 /* This makes TrueType fonts work better. */
6902 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6fc2811b 6903
ee78dc32
GV
6904 return (TRUE);
6905}
6906
d88c567c
JR
6907/* Strip the pixel height and point height from the given xlfd, and
6908 return the pixel height. If no pixel height is specified, calculate
6909 one from the point height, or if that isn't defined either, return
6910 0 (which usually signifies a scalable font).
6911*/
8edb0a6f
JR
6912static int
6913xlfd_strip_height (char *fontname)
d88c567c 6914{
8edb0a6f 6915 int pixel_height, field_number;
d88c567c
JR
6916 char *read_from, *write_to;
6917
6918 xassert (fontname);
6919
6920 pixel_height = field_number = 0;
6921 write_to = NULL;
6922
6923 /* Look for height fields. */
6924 for (read_from = fontname; *read_from; read_from++)
6925 {
6926 if (*read_from == '-')
6927 {
6928 field_number++;
6929 if (field_number == 7) /* Pixel height. */
6930 {
6931 read_from++;
6932 write_to = read_from;
6933
6934 /* Find end of field. */
6935 for (;*read_from && *read_from != '-'; read_from++)
6936 ;
6937
6938 /* Split the fontname at end of field. */
6939 if (*read_from)
6940 {
6941 *read_from = '\0';
6942 read_from++;
6943 }
6944 pixel_height = atoi (write_to);
6945 /* Blank out field. */
6946 if (read_from > write_to)
6947 {
6948 *write_to = '-';
6949 write_to++;
6950 }
767b1ff0 6951 /* If the pixel height field is at the end (partial xlfd),
d88c567c
JR
6952 return now. */
6953 else
6954 return pixel_height;
6955
6956 /* If we got a pixel height, the point height can be
6957 ignored. Just blank it out and break now. */
6958 if (pixel_height)
6959 {
6960 /* Find end of point size field. */
6961 for (; *read_from && *read_from != '-'; read_from++)
6962 ;
6963
6964 if (*read_from)
6965 read_from++;
6966
6967 /* Blank out the point size field. */
6968 if (read_from > write_to)
6969 {
6970 *write_to = '-';
6971 write_to++;
6972 }
6973 else
6974 return pixel_height;
6975
6976 break;
6977 }
6978 /* If the point height is already blank, break now. */
6979 if (*read_from == '-')
6980 {
6981 read_from++;
6982 break;
6983 }
6984 }
6985 else if (field_number == 8)
6986 {
6987 /* If we didn't get a pixel height, try to get the point
6988 height and convert that. */
6989 int point_size;
6990 char *point_size_start = read_from++;
6991
6992 /* Find end of field. */
6993 for (; *read_from && *read_from != '-'; read_from++)
6994 ;
6995
6996 if (*read_from)
6997 {
6998 *read_from = '\0';
6999 read_from++;
7000 }
7001
7002 point_size = atoi (point_size_start);
7003
7004 /* Convert to pixel height. */
7005 pixel_height = point_size
7006 * one_w32_display_info.height_in / 720;
7007
7008 /* Blank out this field and break. */
7009 *write_to = '-';
7010 write_to++;
7011 break;
7012 }
7013 }
7014 }
7015
7016 /* Shift the rest of the font spec into place. */
7017 if (write_to && read_from > write_to)
7018 {
7019 for (; *read_from; read_from++, write_to++)
7020 *write_to = *read_from;
7021 *write_to = '\0';
7022 }
7023
7024 return pixel_height;
7025}
7026
6fc2811b 7027/* Assume parameter 1 is fully qualified, no wildcards. */
8edb0a6f 7028static BOOL
6fc2811b
JR
7029w32_font_match (fontname, pattern)
7030 char * fontname;
7031 char * pattern;
ee78dc32 7032{
e7c72122 7033 char *regex = alloca (strlen (pattern) * 2 + 3);
d88c567c 7034 char *font_name_copy = alloca (strlen (fontname) + 1);
6fc2811b 7035 char *ptr;
ee78dc32 7036
d88c567c
JR
7037 /* Copy fontname so we can modify it during comparison. */
7038 strcpy (font_name_copy, fontname);
7039
6fc2811b
JR
7040 ptr = regex;
7041 *ptr++ = '^';
ee78dc32 7042
6fc2811b
JR
7043 /* Turn pattern into a regexp and do a regexp match. */
7044 for (; *pattern; pattern++)
7045 {
7046 if (*pattern == '?')
7047 *ptr++ = '.';
7048 else if (*pattern == '*')
7049 {
7050 *ptr++ = '.';
7051 *ptr++ = '*';
7052 }
33d52f9c 7053 else
6fc2811b 7054 *ptr++ = *pattern;
ee78dc32 7055 }
6fc2811b
JR
7056 *ptr = '$';
7057 *(ptr + 1) = '\0';
7058
d88c567c
JR
7059 /* Strip out font heights and compare them seperately, since
7060 rounding error can cause mismatches. This also allows a
7061 comparison between a font that declares only a pixel height and a
7062 pattern that declares the point height.
7063 */
7064 {
7065 int font_height, pattern_height;
7066
7067 font_height = xlfd_strip_height (font_name_copy);
7068 pattern_height = xlfd_strip_height (regex);
7069
7070 /* Compare now, and don't bother doing expensive regexp matching
7071 if the heights differ. */
7072 if (font_height && pattern_height && (font_height != pattern_height))
7073 return FALSE;
7074 }
7075
6fc2811b 7076 return (fast_c_string_match_ignore_case (build_string (regex),
d88c567c 7077 font_name_copy) >= 0);
ee78dc32
GV
7078}
7079
5ca0cd71
GV
7080/* Callback functions, and a structure holding info they need, for
7081 listing system fonts on W32. We need one set of functions to do the
7082 job properly, but these don't work on NT 3.51 and earlier, so we
7083 have a second set which don't handle character sets properly to
7084 fall back on.
7085
7086 In both cases, there are two passes made. The first pass gets one
7087 font from each family, the second pass lists all the fonts from
7088 each family. */
7089
ee78dc32
GV
7090typedef struct enumfont_t
7091{
7092 HDC hdc;
7093 int numFonts;
3cb20f4a 7094 LOGFONT logfont;
ee78dc32
GV
7095 XFontStruct *size_ref;
7096 Lisp_Object *pattern;
d84b082d 7097 Lisp_Object list;
ee78dc32
GV
7098 Lisp_Object *tail;
7099} enumfont_t;
7100
d84b082d
JR
7101
7102static void
7103enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7104
7105
8edb0a6f 7106static int CALLBACK
ee78dc32
GV
7107enum_font_cb2 (lplf, lptm, FontType, lpef)
7108 ENUMLOGFONT * lplf;
7109 NEWTEXTMETRIC * lptm;
7110 int FontType;
7111 enumfont_t * lpef;
7112{
66895301
JR
7113 /* Ignore struck out and underlined versions of fonts. */
7114 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7115 return 1;
7116
7117 /* Only return fonts with names starting with @ if they were
7118 explicitly specified, since Microsoft uses an initial @ to
7119 denote fonts for vertical writing, without providing a more
7120 convenient way of identifying them. */
7121 if (lplf->elfLogFont.lfFaceName[0] == '@'
7122 && lpef->logfont.lfFaceName[0] != '@')
5e905a57
JR
7123 return 1;
7124
4587b026
GV
7125 /* Check that the character set matches if it was specified */
7126 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7127 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5e905a57 7128 return 1;
4587b026 7129
ee78dc32
GV
7130 {
7131 char buf[100];
4587b026 7132 Lisp_Object width = Qnil;
d84b082d 7133 Lisp_Object charset_list = Qnil;
767b1ff0 7134 char *charset = NULL;
ee78dc32 7135
6fc2811b
JR
7136 /* Truetype fonts do not report their true metrics until loaded */
7137 if (FontType != RASTER_FONTTYPE)
3cb20f4a 7138 {
6fc2811b
JR
7139 if (!NILP (*(lpef->pattern)))
7140 {
7141 /* Scalable fonts are as big as you want them to be. */
7142 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7143 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7144 width = make_number (lpef->logfont.lfWidth);
7145 }
7146 else
7147 {
7148 lplf->elfLogFont.lfHeight = 0;
7149 lplf->elfLogFont.lfWidth = 0;
7150 }
3cb20f4a 7151 }
6fc2811b 7152
f46e6225
GV
7153 /* Make sure the height used here is the same as everywhere
7154 else (ie character height, not cell height). */
6fc2811b
JR
7155 if (lplf->elfLogFont.lfHeight > 0)
7156 {
7157 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7158 if (FontType == RASTER_FONTTYPE)
7159 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7160 else
7161 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7162 }
4587b026 7163
767b1ff0
JR
7164 if (!NILP (*(lpef->pattern)))
7165 {
7166 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
7167
644cefdf
JR
7168 /* We already checked charsets above, but DEFAULT_CHARSET
7169 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7170 if (charset
7171 && strncmp (charset, "*-*", 3) != 0
7172 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7173 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7174 return 1;
767b1ff0
JR
7175 }
7176
d84b082d
JR
7177 if (charset)
7178 charset_list = Fcons (build_string (charset), Qnil);
7179 else
7180 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
ee78dc32 7181
d84b082d
JR
7182 /* Loop through the charsets. */
7183 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
ee78dc32 7184 {
d84b082d
JR
7185 Lisp_Object this_charset = Fcar (charset_list);
7186 charset = XSTRING (this_charset)->data;
7187
7188 /* List bold and italic variations if w32-enable-synthesized-fonts
7189 is non-nil and this is a plain font. */
7190 if (w32_enable_synthesized_fonts
7191 && lplf->elfLogFont.lfWeight == FW_NORMAL
7192 && lplf->elfLogFont.lfItalic == FALSE)
7193 {
7194 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7195 charset, width);
7196 /* bold. */
7197 lplf->elfLogFont.lfWeight = FW_BOLD;
7198 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7199 charset, width);
7200 /* bold italic. */
7201 lplf->elfLogFont.lfItalic = TRUE;
7202 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7203 charset, width);
7204 /* italic. */
7205 lplf->elfLogFont.lfWeight = FW_NORMAL;
7206 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7207 charset, width);
7208 }
7209 else
7210 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7211 charset, width);
ee78dc32
GV
7212 }
7213 }
6fc2811b 7214
5e905a57 7215 return 1;
ee78dc32
GV
7216}
7217
d84b082d
JR
7218static void
7219enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7220 enumfont_t * lpef;
7221 LOGFONT * logfont;
7222 char * match_charset;
7223 Lisp_Object width;
7224{
7225 char buf[100];
7226
7227 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7228 return;
7229
7230 if (NILP (*(lpef->pattern))
7231 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
7232 {
7233 /* Check if we already listed this font. This may happen if
7234 w32_enable_synthesized_fonts is non-nil, and there are real
7235 bold and italic versions of the font. */
7236 Lisp_Object font_name = build_string (buf);
7237 if (NILP (Fmember (font_name, lpef->list)))
7238 {
7239 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
7240 lpef->tail = &(XCDR (*lpef->tail));
7241 lpef->numFonts++;
7242 }
7243 }
7244}
7245
7246
8edb0a6f 7247static int CALLBACK
ee78dc32
GV
7248enum_font_cb1 (lplf, lptm, FontType, lpef)
7249 ENUMLOGFONT * lplf;
7250 NEWTEXTMETRIC * lptm;
7251 int FontType;
7252 enumfont_t * lpef;
7253{
7254 return EnumFontFamilies (lpef->hdc,
7255 lplf->elfLogFont.lfFaceName,
7256 (FONTENUMPROC) enum_font_cb2,
7257 (LPARAM) lpef);
7258}
7259
7260
8edb0a6f 7261static int CALLBACK
5ca0cd71
GV
7262enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7263 ENUMLOGFONTEX * lplf;
7264 NEWTEXTMETRICEX * lptm;
7265 int font_type;
7266 enumfont_t * lpef;
7267{
7268 /* We are not interested in the extra info we get back from the 'Ex
7269 version - only the fact that we get character set variations
7270 enumerated seperately. */
7271 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7272 font_type, lpef);
7273}
7274
8edb0a6f 7275static int CALLBACK
5ca0cd71
GV
7276enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7277 ENUMLOGFONTEX * lplf;
7278 NEWTEXTMETRICEX * lptm;
7279 int font_type;
7280 enumfont_t * lpef;
7281{
7282 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7283 FARPROC enum_font_families_ex
7284 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7285 /* We don't really expect EnumFontFamiliesEx to disappear once we
7286 get here, so don't bother handling it gracefully. */
7287 if (enum_font_families_ex == NULL)
7288 error ("gdi32.dll has disappeared!");
7289 return enum_font_families_ex (lpef->hdc,
7290 &lplf->elfLogFont,
7291 (FONTENUMPROC) enum_fontex_cb2,
7292 (LPARAM) lpef, 0);
7293}
7294
4587b026
GV
7295/* Interface to fontset handler. (adapted from mw32font.c in Meadow
7296 and xterm.c in Emacs 20.3) */
7297
8edb0a6f 7298static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
7299{
7300 char *fontname, *ptnstr;
7301 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 7302 int n_fonts = 0;
33d52f9c
GV
7303
7304 list = Vw32_bdf_filename_alist;
7305 ptnstr = XSTRING (pattern)->data;
7306
8e713be6 7307 for ( ; CONSP (list); list = XCDR (list))
33d52f9c 7308 {
8e713be6 7309 tem = XCAR (list);
33d52f9c 7310 if (CONSP (tem))
8e713be6 7311 fontname = XSTRING (XCAR (tem))->data;
33d52f9c
GV
7312 else if (STRINGP (tem))
7313 fontname = XSTRING (tem)->data;
7314 else
7315 continue;
7316
7317 if (w32_font_match (fontname, ptnstr))
5ca0cd71 7318 {
8e713be6 7319 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7320 n_fonts++;
7321 if (n_fonts >= max_names)
7322 break;
7323 }
33d52f9c
GV
7324 }
7325
7326 return newlist;
7327}
7328
5ca0cd71 7329
4587b026
GV
7330/* Return a list of names of available fonts matching PATTERN on frame
7331 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7332 to be listed. Frame F NULL means we have not yet created any
7333 frame, which means we can't get proper size info, as we don't have
7334 a device context to use for GetTextMetrics.
7335 MAXNAMES sets a limit on how many fonts to match. */
7336
7337Lisp_Object
dc220243
JR
7338w32_list_fonts (f, pattern, size, maxnames)
7339 struct frame *f;
7340 Lisp_Object pattern;
7341 int size;
7342 int maxnames;
4587b026 7343{
6fc2811b 7344 Lisp_Object patterns, key = Qnil, tem, tpat;
4587b026 7345 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 7346 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 7347 int n_fonts = 0;
396594fe 7348
4587b026
GV
7349 patterns = Fassoc (pattern, Valternate_fontname_alist);
7350 if (NILP (patterns))
7351 patterns = Fcons (pattern, Qnil);
7352
8e713be6 7353 for (; CONSP (patterns); patterns = XCDR (patterns))
4587b026
GV
7354 {
7355 enumfont_t ef;
767b1ff0 7356 int codepage;
4587b026 7357
8e713be6 7358 tpat = XCAR (patterns);
4587b026 7359
767b1ff0
JR
7360 if (!STRINGP (tpat))
7361 continue;
7362
7363 /* Avoid expensive EnumFontFamilies functions if we are not
7364 going to be able to output one of these anyway. */
7365 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7366 if (codepage != CP_8BIT && codepage != CP_UNICODE
ceb12877
AI
7367 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7368 && !IsValidCodePage(codepage))
767b1ff0
JR
7369 continue;
7370
4587b026
GV
7371 /* See if we cached the result for this particular query.
7372 The cache is an alist of the form:
7373 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7374 */
8e713be6 7375 if (tem = XCDR (dpyinfo->name_list_element),
33d52f9c 7376 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
7377 {
7378 list = Fcdr_safe (list);
7379 /* We have a cached list. Don't have to get the list again. */
7380 goto label_cached;
7381 }
7382
7383 BLOCK_INPUT;
7384 /* At first, put PATTERN in the cache. */
7385 list = Qnil;
33d52f9c 7386 ef.pattern = &tpat;
d84b082d 7387 ef.list = list;
33d52f9c 7388 ef.tail = &list;
4587b026 7389 ef.numFonts = 0;
33d52f9c 7390
5ca0cd71
GV
7391 /* Use EnumFontFamiliesEx where it is available, as it knows
7392 about character sets. Fall back to EnumFontFamilies for
7393 older versions of NT that don't support the 'Ex function. */
767b1ff0 7394 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
4587b026 7395 {
5ca0cd71
GV
7396 LOGFONT font_match_pattern;
7397 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7398 FARPROC enum_font_families_ex
7399 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7400
7401 /* We do our own pattern matching so we can handle wildcards. */
7402 font_match_pattern.lfFaceName[0] = 0;
7403 font_match_pattern.lfPitchAndFamily = 0;
7404 /* We can use the charset, because if it is a wildcard it will
7405 be DEFAULT_CHARSET anyway. */
7406 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7407
33d52f9c 7408 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 7409
5ca0cd71
GV
7410 if (enum_font_families_ex)
7411 enum_font_families_ex (ef.hdc,
7412 &font_match_pattern,
7413 (FONTENUMPROC) enum_fontex_cb1,
7414 (LPARAM) &ef, 0);
7415 else
7416 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7417 (LPARAM)&ef);
4587b026 7418
33d52f9c 7419 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
7420 }
7421
7422 UNBLOCK_INPUT;
7423
7424 /* Make a list of the fonts we got back.
7425 Store that in the font cache for the display. */
f3fbd155
KR
7426 XSETCDR (dpyinfo->name_list_element,
7427 Fcons (Fcons (tpat, list),
7428 XCDR (dpyinfo->name_list_element)));
4587b026
GV
7429
7430 label_cached:
7431 if (NILP (list)) continue; /* Try the remaining alternatives. */
7432
7433 newlist = second_best = Qnil;
7434
7435 /* Make a list of the fonts that have the right width. */
8e713be6 7436 for (; CONSP (list); list = XCDR (list))
4587b026
GV
7437 {
7438 int found_size;
8e713be6 7439 tem = XCAR (list);
4587b026
GV
7440
7441 if (!CONSP (tem))
7442 continue;
8e713be6 7443 if (NILP (XCAR (tem)))
4587b026
GV
7444 continue;
7445 if (!size)
7446 {
8e713be6 7447 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7448 n_fonts++;
7449 if (n_fonts >= maxnames)
7450 break;
7451 else
7452 continue;
4587b026 7453 }
8e713be6 7454 if (!INTEGERP (XCDR (tem)))
4587b026
GV
7455 {
7456 /* Since we don't yet know the size of the font, we must
7457 load it and try GetTextMetrics. */
4587b026
GV
7458 W32FontStruct thisinfo;
7459 LOGFONT lf;
7460 HDC hdc;
7461 HANDLE oldobj;
7462
8e713be6 7463 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
4587b026
GV
7464 continue;
7465
7466 BLOCK_INPUT;
33d52f9c 7467 thisinfo.bdf = NULL;
4587b026
GV
7468 thisinfo.hfont = CreateFontIndirect (&lf);
7469 if (thisinfo.hfont == NULL)
7470 continue;
7471
7472 hdc = GetDC (dpyinfo->root_window);
7473 oldobj = SelectObject (hdc, thisinfo.hfont);
7474 if (GetTextMetrics (hdc, &thisinfo.tm))
f3fbd155 7475 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
4587b026 7476 else
f3fbd155 7477 XSETCDR (tem, make_number (0));
4587b026
GV
7478 SelectObject (hdc, oldobj);
7479 ReleaseDC (dpyinfo->root_window, hdc);
7480 DeleteObject(thisinfo.hfont);
7481 UNBLOCK_INPUT;
7482 }
8e713be6 7483 found_size = XINT (XCDR (tem));
4587b026 7484 if (found_size == size)
5ca0cd71 7485 {
8e713be6 7486 newlist = Fcons (XCAR (tem), newlist);
5ca0cd71
GV
7487 n_fonts++;
7488 if (n_fonts >= maxnames)
7489 break;
7490 }
4587b026
GV
7491 /* keep track of the closest matching size in case
7492 no exact match is found. */
7493 else if (found_size > 0)
7494 {
7495 if (NILP (second_best))
7496 second_best = tem;
5ca0cd71 7497
4587b026
GV
7498 else if (found_size < size)
7499 {
8e713be6
KR
7500 if (XINT (XCDR (second_best)) > size
7501 || XINT (XCDR (second_best)) < found_size)
4587b026
GV
7502 second_best = tem;
7503 }
7504 else
7505 {
8e713be6
KR
7506 if (XINT (XCDR (second_best)) > size
7507 && XINT (XCDR (second_best)) >
4587b026
GV
7508 found_size)
7509 second_best = tem;
7510 }
7511 }
7512 }
7513
7514 if (!NILP (newlist))
7515 break;
7516 else if (!NILP (second_best))
7517 {
8e713be6 7518 newlist = Fcons (XCAR (second_best), Qnil);
4587b026
GV
7519 break;
7520 }
7521 }
7522
33d52f9c 7523 /* Include any bdf fonts. */
5ca0cd71 7524 if (n_fonts < maxnames)
33d52f9c
GV
7525 {
7526 Lisp_Object combined[2];
5ca0cd71 7527 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
7528 combined[1] = newlist;
7529 newlist = Fnconc(2, combined);
7530 }
7531
4587b026
GV
7532 return newlist;
7533}
7534
5ca0cd71 7535
4587b026
GV
7536/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7537struct font_info *
7538w32_get_font_info (f, font_idx)
7539 FRAME_PTR f;
7540 int font_idx;
7541{
7542 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7543}
7544
7545
7546struct font_info*
7547w32_query_font (struct frame *f, char *fontname)
7548{
7549 int i;
7550 struct font_info *pfi;
7551
7552 pfi = FRAME_W32_FONT_TABLE (f);
7553
7554 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7555 {
7556 if (strcmp(pfi->name, fontname) == 0) return pfi;
7557 }
7558
7559 return NULL;
7560}
7561
7562/* Find a CCL program for a font specified by FONTP, and set the member
7563 `encoder' of the structure. */
7564
7565void
7566w32_find_ccl_program (fontp)
7567 struct font_info *fontp;
7568{
3545439c 7569 Lisp_Object list, elt;
4587b026 7570
8e713be6 7571 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
4587b026 7572 {
8e713be6 7573 elt = XCAR (list);
4587b026 7574 if (CONSP (elt)
8e713be6
KR
7575 && STRINGP (XCAR (elt))
7576 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
4587b026 7577 >= 0))
3545439c
KH
7578 break;
7579 }
7580 if (! NILP (list))
7581 {
17eedd00
KH
7582 struct ccl_program *ccl
7583 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
3545439c 7584
8e713be6 7585 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
3545439c
KH
7586 xfree (ccl);
7587 else
7588 fontp->font_encoder = ccl;
4587b026
GV
7589 }
7590}
7591
7592\f
8edb0a6f
JR
7593/* Find BDF files in a specified directory. (use GCPRO when calling,
7594 as this calls lisp to get a directory listing). */
7595static Lisp_Object
7596w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7597{
7598 Lisp_Object filelist, list = Qnil;
7599 char fontname[100];
7600
7601 if (!STRINGP(directory))
7602 return Qnil;
7603
7604 filelist = Fdirectory_files (directory, Qt,
7605 build_string (".*\\.[bB][dD][fF]"), Qt);
7606
7607 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7608 {
7609 Lisp_Object filename = XCAR (filelist);
7610 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7611 store_in_alist (&list, build_string (fontname), filename);
7612 }
7613 return list;
7614}
7615
6fc2811b
JR
7616DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7617 1, 1, 0,
b3700ae7
JR
7618 doc: /* Return a list of BDF fonts in DIR.
7619The list is suitable for appending to w32-bdf-filename-alist. Fonts
7620which do not contain an xlfd description will not be included in the
7621list. DIR may be a list of directories. */)
6fc2811b
JR
7622 (directory)
7623 Lisp_Object directory;
7624{
7625 Lisp_Object list = Qnil;
7626 struct gcpro gcpro1, gcpro2;
ee78dc32 7627
6fc2811b
JR
7628 if (!CONSP (directory))
7629 return w32_find_bdf_fonts_in_dir (directory);
ee78dc32 7630
6fc2811b 7631 for ( ; CONSP (directory); directory = XCDR (directory))
ee78dc32 7632 {
6fc2811b
JR
7633 Lisp_Object pair[2];
7634 pair[0] = list;
7635 pair[1] = Qnil;
7636 GCPRO2 (directory, list);
7637 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7638 list = Fnconc( 2, pair );
7639 UNGCPRO;
7640 }
7641 return list;
7642}
ee78dc32 7643
6fc2811b
JR
7644\f
7645DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
74e1aeec 7646 doc: /* Internal function called by `color-defined-p', which see. */)
6fc2811b
JR
7647 (color, frame)
7648 Lisp_Object color, frame;
7649{
7650 XColor foo;
7651 FRAME_PTR f = check_x_frame (frame);
ee78dc32 7652
b7826503 7653 CHECK_STRING (color);
ee78dc32 7654
6fc2811b
JR
7655 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7656 return Qt;
7657 else
7658 return Qnil;
7659}
ee78dc32 7660
2d764c78 7661DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
74e1aeec 7662 doc: /* Internal function called by `color-values', which see. */)
ee78dc32
GV
7663 (color, frame)
7664 Lisp_Object color, frame;
7665{
6fc2811b 7666 XColor foo;
ee78dc32
GV
7667 FRAME_PTR f = check_x_frame (frame);
7668
b7826503 7669 CHECK_STRING (color);
ee78dc32 7670
6fc2811b 7671 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
ee78dc32
GV
7672 {
7673 Lisp_Object rgb[3];
7674
6fc2811b
JR
7675 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7676 | GetRValue (foo.pixel));
7677 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7678 | GetGValue (foo.pixel));
7679 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7680 | GetBValue (foo.pixel));
ee78dc32
GV
7681 return Flist (3, rgb);
7682 }
7683 else
7684 return Qnil;
7685}
7686
2d764c78 7687DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
74e1aeec 7688 doc: /* Internal function called by `display-color-p', which see. */)
ee78dc32
GV
7689 (display)
7690 Lisp_Object display;
7691{
fbd6baed 7692 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7693
7694 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7695 return Qnil;
7696
7697 return Qt;
7698}
7699
74e1aeec
JR
7700DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7701 Sx_display_grayscale_p, 0, 1, 0,
7702 doc: /* Return t if the X display supports shades of gray.
7703Note that color displays do support shades of gray.
7704The optional argument DISPLAY specifies which display to ask about.
7705DISPLAY should be either a frame or a display name (a string).
7706If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7707 (display)
7708 Lisp_Object display;
7709{
fbd6baed 7710 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7711
7712 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7713 return Qnil;
7714
7715 return Qt;
7716}
7717
74e1aeec
JR
7718DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7719 Sx_display_pixel_width, 0, 1, 0,
7720 doc: /* Returns the width in pixels of DISPLAY.
7721The optional argument DISPLAY specifies which display to ask about.
7722DISPLAY should be either a frame or a display name (a string).
7723If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7724 (display)
7725 Lisp_Object display;
7726{
fbd6baed 7727 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7728
7729 return make_number (dpyinfo->width);
7730}
7731
7732DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
74e1aeec
JR
7733 Sx_display_pixel_height, 0, 1, 0,
7734 doc: /* Returns the height in pixels of DISPLAY.
7735The optional argument DISPLAY specifies which display to ask about.
7736DISPLAY should be either a frame or a display name (a string).
7737If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7738 (display)
7739 Lisp_Object display;
7740{
fbd6baed 7741 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7742
7743 return make_number (dpyinfo->height);
7744}
7745
7746DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
74e1aeec
JR
7747 0, 1, 0,
7748 doc: /* Returns the number of bitplanes of DISPLAY.
7749The optional argument DISPLAY specifies which display to ask about.
7750DISPLAY should be either a frame or a display name (a string).
7751If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7752 (display)
7753 Lisp_Object display;
7754{
fbd6baed 7755 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7756
7757 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7758}
7759
7760DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
74e1aeec
JR
7761 0, 1, 0,
7762 doc: /* Returns the number of color cells of DISPLAY.
7763The optional argument DISPLAY specifies which display to ask about.
7764DISPLAY should be either a frame or a display name (a string).
7765If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7766 (display)
7767 Lisp_Object display;
7768{
fbd6baed 7769 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7770 HDC hdc;
7771 int cap;
7772
5ac45f98
GV
7773 hdc = GetDC (dpyinfo->root_window);
7774 if (dpyinfo->has_palette)
7775 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7776 else
7777 cap = GetDeviceCaps (hdc,NUMCOLORS);
abf8c61b 7778
007776bc
JB
7779 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7780 and because probably is more meaningful on Windows anyway */
abf8c61b 7781 if (cap < 0)
007776bc 7782 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
ee78dc32
GV
7783
7784 ReleaseDC (dpyinfo->root_window, hdc);
7785
7786 return make_number (cap);
7787}
7788
7789DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7790 Sx_server_max_request_size,
74e1aeec
JR
7791 0, 1, 0,
7792 doc: /* Returns the maximum request size of the server of DISPLAY.
7793The optional argument DISPLAY specifies which display to ask about.
7794DISPLAY should be either a frame or a display name (a string).
7795If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7796 (display)
7797 Lisp_Object display;
7798{
fbd6baed 7799 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7800
7801 return make_number (1);
7802}
7803
7804DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
74e1aeec
JR
7805 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7806The optional argument DISPLAY specifies which display to ask about.
7807DISPLAY should be either a frame or a display name (a string).
7808If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7809 (display)
7810 Lisp_Object display;
7811{
dfff8a69 7812 return build_string ("Microsoft Corp.");
ee78dc32
GV
7813}
7814
7815DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
74e1aeec
JR
7816 doc: /* Returns the version numbers of the server of DISPLAY.
7817The value is a list of three integers: the major and minor
7818version numbers, and the vendor-specific release
7819number. See also the function `x-server-vendor'.
7820
7821The optional argument DISPLAY specifies which display to ask about.
7822DISPLAY should be either a frame or a display name (a string).
7823If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7824 (display)
7825 Lisp_Object display;
7826{
fbd6baed 7827 return Fcons (make_number (w32_major_version),
58e0f0e4
AI
7828 Fcons (make_number (w32_minor_version),
7829 Fcons (make_number (w32_build_number), Qnil)));
ee78dc32
GV
7830}
7831
7832DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
74e1aeec
JR
7833 doc: /* Returns the number of screens on the server of DISPLAY.
7834The optional argument DISPLAY specifies which display to ask about.
7835DISPLAY should be either a frame or a display name (a string).
7836If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7837 (display)
7838 Lisp_Object display;
7839{
ee78dc32
GV
7840 return make_number (1);
7841}
7842
74e1aeec
JR
7843DEFUN ("x-display-mm-height", Fx_display_mm_height,
7844 Sx_display_mm_height, 0, 1, 0,
7845 doc: /* Returns the height in millimeters of DISPLAY.
7846The optional argument DISPLAY specifies which display to ask about.
7847DISPLAY should be either a frame or a display name (a string).
7848If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7849 (display)
7850 Lisp_Object display;
7851{
fbd6baed 7852 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7853 HDC hdc;
7854 int cap;
7855
5ac45f98 7856 hdc = GetDC (dpyinfo->root_window);
3c190163 7857
ee78dc32 7858 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 7859
ee78dc32
GV
7860 ReleaseDC (dpyinfo->root_window, hdc);
7861
7862 return make_number (cap);
7863}
7864
7865DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
74e1aeec
JR
7866 doc: /* Returns the width in millimeters of DISPLAY.
7867The optional argument DISPLAY specifies which display to ask about.
7868DISPLAY should be either a frame or a display name (a string).
7869If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7870 (display)
7871 Lisp_Object display;
7872{
fbd6baed 7873 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
7874
7875 HDC hdc;
7876 int cap;
7877
5ac45f98 7878 hdc = GetDC (dpyinfo->root_window);
3c190163 7879
ee78dc32 7880 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 7881
ee78dc32
GV
7882 ReleaseDC (dpyinfo->root_window, hdc);
7883
7884 return make_number (cap);
7885}
7886
7887DEFUN ("x-display-backing-store", Fx_display_backing_store,
74e1aeec
JR
7888 Sx_display_backing_store, 0, 1, 0,
7889 doc: /* Returns an indication of whether DISPLAY does backing store.
7890The value may be `always', `when-mapped', or `not-useful'.
7891The optional argument DISPLAY specifies which display to ask about.
7892DISPLAY should be either a frame or a display name (a string).
7893If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7894 (display)
7895 Lisp_Object display;
7896{
7897 return intern ("not-useful");
7898}
7899
7900DEFUN ("x-display-visual-class", Fx_display_visual_class,
74e1aeec
JR
7901 Sx_display_visual_class, 0, 1, 0,
7902 doc: /* Returns the visual class of DISPLAY.
7903The value is one of the symbols `static-gray', `gray-scale',
7904`static-color', `pseudo-color', `true-color', or `direct-color'.
7905
7906The optional argument DISPLAY specifies which display to ask about.
7907DISPLAY should be either a frame or a display name (a string).
7908If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7909 (display)
7910 Lisp_Object display;
7911{
fbd6baed 7912 struct w32_display_info *dpyinfo = check_x_display_info (display);
abf8c61b 7913 Lisp_Object result = Qnil;
ee78dc32 7914
abf8c61b
AI
7915 if (dpyinfo->has_palette)
7916 result = intern ("pseudo-color");
7917 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7918 result = intern ("static-grey");
7919 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7920 result = intern ("static-color");
7921 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7922 result = intern ("true-color");
ee78dc32 7923
abf8c61b 7924 return result;
ee78dc32
GV
7925}
7926
7927DEFUN ("x-display-save-under", Fx_display_save_under,
74e1aeec
JR
7928 Sx_display_save_under, 0, 1, 0,
7929 doc: /* Returns t if DISPLAY supports the save-under feature.
7930The optional argument DISPLAY specifies which display to ask about.
7931DISPLAY should be either a frame or a display name (a string).
7932If omitted or nil, that stands for the selected frame's display. */)
ee78dc32
GV
7933 (display)
7934 Lisp_Object display;
7935{
6fc2811b
JR
7936 return Qnil;
7937}
7938\f
7939int
7940x_pixel_width (f)
7941 register struct frame *f;
7942{
7943 return PIXEL_WIDTH (f);
7944}
7945
7946int
7947x_pixel_height (f)
7948 register struct frame *f;
7949{
7950 return PIXEL_HEIGHT (f);
7951}
7952
7953int
7954x_char_width (f)
7955 register struct frame *f;
7956{
7957 return FONT_WIDTH (f->output_data.w32->font);
7958}
7959
7960int
7961x_char_height (f)
7962 register struct frame *f;
7963{
7964 return f->output_data.w32->line_height;
7965}
7966
7967int
7968x_screen_planes (f)
7969 register struct frame *f;
7970{
7971 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7972}
7973\f
7974/* Return the display structure for the display named NAME.
7975 Open a new connection if necessary. */
7976
7977struct w32_display_info *
7978x_display_info_for_name (name)
7979 Lisp_Object name;
7980{
7981 Lisp_Object names;
7982 struct w32_display_info *dpyinfo;
7983
b7826503 7984 CHECK_STRING (name);
6fc2811b
JR
7985
7986 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7987 dpyinfo;
7988 dpyinfo = dpyinfo->next, names = XCDR (names))
7989 {
7990 Lisp_Object tem;
7991 tem = Fstring_equal (XCAR (XCAR (names)), name);
7992 if (!NILP (tem))
7993 return dpyinfo;
7994 }
7995
7996 /* Use this general default value to start with. */
7997 Vx_resource_name = Vinvocation_name;
7998
7999 validate_x_resource_name ();
8000
8001 dpyinfo = w32_term_init (name, (unsigned char *)0,
8002 (char *) XSTRING (Vx_resource_name)->data);
8003
8004 if (dpyinfo == 0)
8005 error ("Cannot connect to server %s", XSTRING (name)->data);
8006
8007 w32_in_use = 1;
8008 XSETFASTINT (Vwindow_system_version, 3);
8009
8010 return dpyinfo;
8011}
8012
8013DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
74e1aeec
JR
8014 1, 3, 0, doc: /* Open a connection to a server.
8015DISPLAY is the name of the display to connect to.
8016Optional second arg XRM-STRING is a string of resources in xrdb format.
8017If the optional third arg MUST-SUCCEED is non-nil,
8018terminate Emacs if we can't open the connection. */)
6fc2811b
JR
8019 (display, xrm_string, must_succeed)
8020 Lisp_Object display, xrm_string, must_succeed;
8021{
8022 unsigned char *xrm_option;
8023 struct w32_display_info *dpyinfo;
8024
74e1aeec
JR
8025 /* If initialization has already been done, return now to avoid
8026 overwriting critical parts of one_w32_display_info. */
8027 if (w32_in_use)
8028 return Qnil;
8029
b7826503 8030 CHECK_STRING (display);
6fc2811b 8031 if (! NILP (xrm_string))
b7826503 8032 CHECK_STRING (xrm_string);
6fc2811b
JR
8033
8034 if (! EQ (Vwindow_system, intern ("w32")))
8035 error ("Not using Microsoft Windows");
8036
8037 /* Allow color mapping to be defined externally; first look in user's
8038 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8039 {
8040 Lisp_Object color_file;
8041 struct gcpro gcpro1;
8042
8043 color_file = build_string("~/rgb.txt");
8044
8045 GCPRO1 (color_file);
8046
8047 if (NILP (Ffile_readable_p (color_file)))
8048 color_file =
8049 Fexpand_file_name (build_string ("rgb.txt"),
8050 Fsymbol_value (intern ("data-directory")));
8051
8052 Vw32_color_map = Fw32_load_color_file (color_file);
8053
8054 UNGCPRO;
8055 }
8056 if (NILP (Vw32_color_map))
8057 Vw32_color_map = Fw32_default_color_map ();
8058
8059 if (! NILP (xrm_string))
8060 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8061 else
8062 xrm_option = (unsigned char *) 0;
8063
8064 /* Use this general default value to start with. */
8065 /* First remove .exe suffix from invocation-name - it looks ugly. */
8066 {
8067 char basename[ MAX_PATH ], *str;
8068
8069 strcpy (basename, XSTRING (Vinvocation_name)->data);
8070 str = strrchr (basename, '.');
8071 if (str) *str = 0;
8072 Vinvocation_name = build_string (basename);
8073 }
8074 Vx_resource_name = Vinvocation_name;
8075
8076 validate_x_resource_name ();
8077
8078 /* This is what opens the connection and sets x_current_display.
8079 This also initializes many symbols, such as those used for input. */
8080 dpyinfo = w32_term_init (display, xrm_option,
8081 (char *) XSTRING (Vx_resource_name)->data);
8082
8083 if (dpyinfo == 0)
8084 {
8085 if (!NILP (must_succeed))
8086 fatal ("Cannot connect to server %s.\n",
8087 XSTRING (display)->data);
8088 else
8089 error ("Cannot connect to server %s", XSTRING (display)->data);
8090 }
8091
8092 w32_in_use = 1;
8093
8094 XSETFASTINT (Vwindow_system_version, 3);
8095 return Qnil;
8096}
8097
8098DEFUN ("x-close-connection", Fx_close_connection,
8099 Sx_close_connection, 1, 1, 0,
74e1aeec
JR
8100 doc: /* Close the connection to DISPLAY's server.
8101For DISPLAY, specify either a frame or a display name (a string).
8102If DISPLAY is nil, that stands for the selected frame's display. */)
6fc2811b
JR
8103 (display)
8104 Lisp_Object display;
8105{
8106 struct w32_display_info *dpyinfo = check_x_display_info (display);
8107 int i;
8108
8109 if (dpyinfo->reference_count > 0)
8110 error ("Display still has frames on it");
8111
8112 BLOCK_INPUT;
8113 /* Free the fonts in the font table. */
8114 for (i = 0; i < dpyinfo->n_fonts; i++)
8115 if (dpyinfo->font_table[i].name)
8116 {
126f2e35
JR
8117 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8118 xfree (dpyinfo->font_table[i].full_name);
6fc2811b 8119 xfree (dpyinfo->font_table[i].name);
6fc2811b
JR
8120 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8121 }
8122 x_destroy_all_bitmaps (dpyinfo);
8123
8124 x_delete_display (dpyinfo);
8125 UNBLOCK_INPUT;
8126
8127 return Qnil;
8128}
8129
8130DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
74e1aeec 8131 doc: /* Return the list of display names that Emacs has connections to. */)
6fc2811b
JR
8132 ()
8133{
8134 Lisp_Object tail, result;
8135
8136 result = Qnil;
8137 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8138 result = Fcons (XCAR (XCAR (tail)), result);
8139
8140 return result;
8141}
8142
8143DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
0a332240
PJ
8144 doc: /* This is a noop on W32 systems. */)
8145 (on, display)
8146 Lisp_Object display, on;
6fc2811b 8147{
6fc2811b
JR
8148 return Qnil;
8149}
8150
8151\f
6fc2811b
JR
8152/***********************************************************************
8153 Image types
8154 ***********************************************************************/
8155
8156/* Value is the number of elements of vector VECTOR. */
8157
8158#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8159
8160/* List of supported image types. Use define_image_type to add new
8161 types. Use lookup_image_type to find a type for a given symbol. */
8162
8163static struct image_type *image_types;
8164
6fc2811b
JR
8165/* The symbol `image' which is the car of the lists used to represent
8166 images in Lisp. */
8167
8168extern Lisp_Object Qimage;
8169
8170/* The symbol `xbm' which is used as the type symbol for XBM images. */
8171
8172Lisp_Object Qxbm;
8173
8174/* Keywords. */
8175
6fc2811b 8176extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
77814035
KS
8177extern Lisp_Object QCdata, QCtype;
8178Lisp_Object QCascent, QCmargin, QCrelief;
a93f4566 8179Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
3cf3436e 8180Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
6fc2811b
JR
8181
8182/* Other symbols. */
8183
3cf3436e 8184Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
6fc2811b
JR
8185
8186/* Time in seconds after which images should be removed from the cache
8187 if not displayed. */
8188
8189Lisp_Object Vimage_cache_eviction_delay;
8190
8191/* Function prototypes. */
8192
8193static void define_image_type P_ ((struct image_type *type));
8194static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8195static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8196static void x_laplace P_ ((struct frame *, struct image *));
3cf3436e 8197static void x_emboss P_ ((struct frame *, struct image *));
6fc2811b
JR
8198static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8199 Lisp_Object));
8200
dfff8a69 8201
6fc2811b
JR
8202/* Define a new image type from TYPE. This adds a copy of TYPE to
8203 image_types and adds the symbol *TYPE->type to Vimage_types. */
8204
8205static void
8206define_image_type (type)
8207 struct image_type *type;
8208{
8209 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8210 The initialized data segment is read-only. */
8211 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8212 bcopy (type, p, sizeof *p);
8213 p->next = image_types;
8214 image_types = p;
8215 Vimage_types = Fcons (*p->type, Vimage_types);
8216}
8217
8218
8219/* Look up image type SYMBOL, and return a pointer to its image_type
8220 structure. Value is null if SYMBOL is not a known image type. */
8221
8222static INLINE struct image_type *
8223lookup_image_type (symbol)
8224 Lisp_Object symbol;
8225{
8226 struct image_type *type;
8227
8228 for (type = image_types; type; type = type->next)
8229 if (EQ (symbol, *type->type))
8230 break;
8231
8232 return type;
8233}
8234
8235
8236/* Value is non-zero if OBJECT is a valid Lisp image specification. A
8237 valid image specification is a list whose car is the symbol
8238 `image', and whose rest is a property list. The property list must
8239 contain a value for key `:type'. That value must be the name of a
8240 supported image type. The rest of the property list depends on the
8241 image type. */
8242
8243int
8244valid_image_p (object)
8245 Lisp_Object object;
8246{
8247 int valid_p = 0;
8248
8249 if (CONSP (object) && EQ (XCAR (object), Qimage))
8250 {
3cf3436e
JR
8251 Lisp_Object tem;
8252
8253 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8254 if (EQ (XCAR (tem), QCtype))
8255 {
8256 tem = XCDR (tem);
8257 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8258 {
8259 struct image_type *type;
8260 type = lookup_image_type (XCAR (tem));
8261 if (type)
8262 valid_p = type->valid_p (object);
8263 }
8264
8265 break;
8266 }
6fc2811b
JR
8267 }
8268
8269 return valid_p;
8270}
8271
8272
8273/* Log error message with format string FORMAT and argument ARG.
8274 Signaling an error, e.g. when an image cannot be loaded, is not a
8275 good idea because this would interrupt redisplay, and the error
8276 message display would lead to another redisplay. This function
8277 therefore simply displays a message. */
8278
8279static void
8280image_error (format, arg1, arg2)
8281 char *format;
8282 Lisp_Object arg1, arg2;
8283{
8284 add_to_log (format, arg1, arg2);
8285}
8286
8287
8288\f
8289/***********************************************************************
8290 Image specifications
8291 ***********************************************************************/
8292
8293enum image_value_type
8294{
8295 IMAGE_DONT_CHECK_VALUE_TYPE,
8296 IMAGE_STRING_VALUE,
3cf3436e 8297 IMAGE_STRING_OR_NIL_VALUE,
6fc2811b
JR
8298 IMAGE_SYMBOL_VALUE,
8299 IMAGE_POSITIVE_INTEGER_VALUE,
8edb0a6f 8300 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
6fc2811b 8301 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
dfff8a69 8302 IMAGE_ASCENT_VALUE,
6fc2811b
JR
8303 IMAGE_INTEGER_VALUE,
8304 IMAGE_FUNCTION_VALUE,
8305 IMAGE_NUMBER_VALUE,
8306 IMAGE_BOOL_VALUE
8307};
8308
8309/* Structure used when parsing image specifications. */
8310
8311struct image_keyword
8312{
8313 /* Name of keyword. */
8314 char *name;
8315
8316 /* The type of value allowed. */
8317 enum image_value_type type;
8318
8319 /* Non-zero means key must be present. */
8320 int mandatory_p;
8321
8322 /* Used to recognize duplicate keywords in a property list. */
8323 int count;
8324
8325 /* The value that was found. */
8326 Lisp_Object value;
8327};
8328
8329
8330static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8331 int, Lisp_Object));
8332static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8333
8334
8335/* Parse image spec SPEC according to KEYWORDS. A valid image spec
8336 has the format (image KEYWORD VALUE ...). One of the keyword/
8337 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8338 image_keywords structures of size NKEYWORDS describing other
8339 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8340
8341static int
8342parse_image_spec (spec, keywords, nkeywords, type)
8343 Lisp_Object spec;
8344 struct image_keyword *keywords;
8345 int nkeywords;
8346 Lisp_Object type;
8347{
8348 int i;
8349 Lisp_Object plist;
8350
8351 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8352 return 0;
8353
8354 plist = XCDR (spec);
8355 while (CONSP (plist))
8356 {
8357 Lisp_Object key, value;
8358
8359 /* First element of a pair must be a symbol. */
8360 key = XCAR (plist);
8361 plist = XCDR (plist);
8362 if (!SYMBOLP (key))
8363 return 0;
8364
8365 /* There must follow a value. */
8366 if (!CONSP (plist))
8367 return 0;
8368 value = XCAR (plist);
8369 plist = XCDR (plist);
8370
8371 /* Find key in KEYWORDS. Error if not found. */
8372 for (i = 0; i < nkeywords; ++i)
8373 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8374 break;
8375
8376 if (i == nkeywords)
8377 continue;
8378
8379 /* Record that we recognized the keyword. If a keywords
8380 was found more than once, it's an error. */
8381 keywords[i].value = value;
8382 ++keywords[i].count;
8383
8384 if (keywords[i].count > 1)
8385 return 0;
8386
8387 /* Check type of value against allowed type. */
8388 switch (keywords[i].type)
8389 {
8390 case IMAGE_STRING_VALUE:
8391 if (!STRINGP (value))
8392 return 0;
8393 break;
8394
3cf3436e
JR
8395 case IMAGE_STRING_OR_NIL_VALUE:
8396 if (!STRINGP (value) && !NILP (value))
8397 return 0;
8398 break;
8399
6fc2811b
JR
8400 case IMAGE_SYMBOL_VALUE:
8401 if (!SYMBOLP (value))
8402 return 0;
8403 break;
8404
8405 case IMAGE_POSITIVE_INTEGER_VALUE:
8406 if (!INTEGERP (value) || XINT (value) <= 0)
8407 return 0;
8408 break;
8409
8edb0a6f
JR
8410 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8411 if (INTEGERP (value) && XINT (value) >= 0)
8412 break;
8413 if (CONSP (value)
8414 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8415 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8416 break;
8417 return 0;
8418
dfff8a69
JR
8419 case IMAGE_ASCENT_VALUE:
8420 if (SYMBOLP (value) && EQ (value, Qcenter))
8421 break;
8422 else if (INTEGERP (value)
8423 && XINT (value) >= 0
8424 && XINT (value) <= 100)
8425 break;
8426 return 0;
8427
6fc2811b
JR
8428 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8429 if (!INTEGERP (value) || XINT (value) < 0)
8430 return 0;
8431 break;
8432
8433 case IMAGE_DONT_CHECK_VALUE_TYPE:
8434 break;
8435
8436 case IMAGE_FUNCTION_VALUE:
8437 value = indirect_function (value);
8438 if (SUBRP (value)
8439 || COMPILEDP (value)
8440 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8441 break;
8442 return 0;
8443
8444 case IMAGE_NUMBER_VALUE:
8445 if (!INTEGERP (value) && !FLOATP (value))
8446 return 0;
8447 break;
8448
8449 case IMAGE_INTEGER_VALUE:
8450 if (!INTEGERP (value))
8451 return 0;
8452 break;
8453
8454 case IMAGE_BOOL_VALUE:
8455 if (!NILP (value) && !EQ (value, Qt))
8456 return 0;
8457 break;
8458
8459 default:
8460 abort ();
8461 break;
8462 }
8463
8464 if (EQ (key, QCtype) && !EQ (type, value))
8465 return 0;
8466 }
8467
8468 /* Check that all mandatory fields are present. */
8469 for (i = 0; i < nkeywords; ++i)
8470 if (keywords[i].mandatory_p && keywords[i].count == 0)
8471 return 0;
8472
8473 return NILP (plist);
8474}
8475
8476
8477/* Return the value of KEY in image specification SPEC. Value is nil
8478 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8479 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8480
8481static Lisp_Object
8482image_spec_value (spec, key, found)
8483 Lisp_Object spec, key;
8484 int *found;
8485{
8486 Lisp_Object tail;
8487
8488 xassert (valid_image_p (spec));
8489
8490 for (tail = XCDR (spec);
8491 CONSP (tail) && CONSP (XCDR (tail));
8492 tail = XCDR (XCDR (tail)))
8493 {
8494 if (EQ (XCAR (tail), key))
8495 {
8496 if (found)
8497 *found = 1;
8498 return XCAR (XCDR (tail));
8499 }
8500 }
8501
8502 if (found)
8503 *found = 0;
8504 return Qnil;
8505}
8506
8507
ac849ba4
JR
8508DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8509 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8510PIXELS non-nil means return the size in pixels, otherwise return the
8511size in canonical character units.
8512FRAME is the frame on which the image will be displayed. FRAME nil
8513or omitted means use the selected frame. */)
8514 (spec, pixels, frame)
8515 Lisp_Object spec, pixels, frame;
8516{
8517 Lisp_Object size;
8518
8519 size = Qnil;
8520 if (valid_image_p (spec))
8521 {
8522 struct frame *f = check_x_frame (frame);
8523 int id = lookup_image (f, spec);
8524 struct image *img = IMAGE_FROM_ID (f, id);
8525 int width = img->width + 2 * img->hmargin;
8526 int height = img->height + 2 * img->vmargin;
8527
8528 if (NILP (pixels))
8529 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8530 make_float ((double) height / CANON_Y_UNIT (f)));
8531 else
8532 size = Fcons (make_number (width), make_number (height));
8533 }
8534 else
8535 error ("Invalid image specification");
8536
8537 return size;
8538}
8539
8540
8541DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8542 doc: /* Return t if image SPEC has a mask bitmap.
8543FRAME is the frame on which the image will be displayed. FRAME nil
8544or omitted means use the selected frame. */)
8545 (spec, frame)
8546 Lisp_Object spec, frame;
8547{
8548 Lisp_Object mask;
8549
8550 mask = Qnil;
8551 if (valid_image_p (spec))
8552 {
8553 struct frame *f = check_x_frame (frame);
8554 int id = lookup_image (f, spec);
8555 struct image *img = IMAGE_FROM_ID (f, id);
8556 if (img->mask)
8557 mask = Qt;
8558 }
8559 else
8560 error ("Invalid image specification");
8561
8562 return mask;
8563}
6fc2811b
JR
8564
8565\f
8566/***********************************************************************
8567 Image type independent image structures
8568 ***********************************************************************/
8569
8570static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8571static void free_image P_ ((struct frame *f, struct image *img));
8572
8573
8574/* Allocate and return a new image structure for image specification
8575 SPEC. SPEC has a hash value of HASH. */
8576
8577static struct image *
8578make_image (spec, hash)
8579 Lisp_Object spec;
8580 unsigned hash;
8581{
8582 struct image *img = (struct image *) xmalloc (sizeof *img);
8583
8584 xassert (valid_image_p (spec));
8585 bzero (img, sizeof *img);
8586 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8587 xassert (img->type != NULL);
8588 img->spec = spec;
8589 img->data.lisp_val = Qnil;
8590 img->ascent = DEFAULT_IMAGE_ASCENT;
8591 img->hash = hash;
8592 return img;
8593}
8594
8595
8596/* Free image IMG which was used on frame F, including its resources. */
8597
8598static void
8599free_image (f, img)
8600 struct frame *f;
8601 struct image *img;
8602{
8603 if (img)
8604 {
8605 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8606
8607 /* Remove IMG from the hash table of its cache. */
8608 if (img->prev)
8609 img->prev->next = img->next;
8610 else
8611 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8612
8613 if (img->next)
8614 img->next->prev = img->prev;
8615
8616 c->images[img->id] = NULL;
8617
8618 /* Free resources, then free IMG. */
8619 img->type->free (f, img);
8620 xfree (img);
8621 }
8622}
8623
8624
8625/* Prepare image IMG for display on frame F. Must be called before
8626 drawing an image. */
8627
8628void
8629prepare_image_for_display (f, img)
8630 struct frame *f;
8631 struct image *img;
8632{
8633 EMACS_TIME t;
8634
8635 /* We're about to display IMG, so set its timestamp to `now'. */
8636 EMACS_GET_TIME (t);
8637 img->timestamp = EMACS_SECS (t);
8638
8639 /* If IMG doesn't have a pixmap yet, load it now, using the image
8640 type dependent loader function. */
8641 if (img->pixmap == 0 && !img->load_failed_p)
8642 img->load_failed_p = img->type->load (f, img) == 0;
8643}
8644
8645
dfff8a69
JR
8646/* Value is the number of pixels for the ascent of image IMG when
8647 drawn in face FACE. */
8648
8649int
8650image_ascent (img, face)
8651 struct image *img;
8652 struct face *face;
8653{
8edb0a6f 8654 int height = img->height + img->vmargin;
dfff8a69
JR
8655 int ascent;
8656
8657 if (img->ascent == CENTERED_IMAGE_ASCENT)
8658 {
8659 if (face->font)
8660 ascent = height / 2 - (FONT_DESCENT(face->font)
8661 - FONT_BASE(face->font)) / 2;
8662 else
8663 ascent = height / 2;
8664 }
8665 else
ac849ba4 8666 ascent = (int) (height * img->ascent / 100.0);
dfff8a69
JR
8667
8668 return ascent;
8669}
8670
8671
6fc2811b 8672\f
a05e2bae
JR
8673/* Image background colors. */
8674
ac849ba4
JR
8675/* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8676 context with the bitmap selected. */
8677static COLORREF
a05e2bae 8678four_corners_best (ximg, width, height)
ac849ba4 8679 HDC ximg;
a05e2bae
JR
8680 unsigned long width, height;
8681{
ac849ba4 8682 COLORREF corners[4], best;
a05e2bae
JR
8683 int i, best_count;
8684
8685 /* Get the colors at the corners of ximg. */
ac849ba4
JR
8686 corners[0] = GetPixel (ximg, 0, 0);
8687 corners[1] = GetPixel (ximg, width - 1, 0);
8688 corners[2] = GetPixel (ximg, width - 1, height - 1);
8689 corners[3] = GetPixel (ximg, 0, height - 1);
a05e2bae
JR
8690
8691 /* Choose the most frequently found color as background. */
8692 for (i = best_count = 0; i < 4; ++i)
8693 {
8694 int j, n;
8695
8696 for (j = n = 0; j < 4; ++j)
8697 if (corners[i] == corners[j])
8698 ++n;
8699
8700 if (n > best_count)
8701 best = corners[i], best_count = n;
8702 }
8703
8704 return best;
a05e2bae
JR
8705}
8706
8707/* Return the `background' field of IMG. If IMG doesn't have one yet,
8708 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8709 object to use for the heuristic. */
8710
8711unsigned long
8712image_background (img, f, ximg)
8713 struct image *img;
8714 struct frame *f;
8715 XImage *ximg;
8716{
8717 if (! img->background_valid)
8718 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8719 {
8720#if 0 /* TODO: Image support. */
8721 int free_ximg = !ximg;
8722
8723 if (! ximg)
8724 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8725 0, 0, img->width, img->height, ~0, ZPixmap);
8726
8727 img->background = four_corners_best (ximg, img->width, img->height);
8728
8729 if (free_ximg)
8730 XDestroyImage (ximg);
8731
8732 img->background_valid = 1;
8733#endif
8734 }
8735
8736 return img->background;
8737}
8738
8739/* Return the `background_transparent' field of IMG. If IMG doesn't
8740 have one yet, it is guessed heuristically. If non-zero, MASK is an
8741 existing XImage object to use for the heuristic. */
8742
8743int
8744image_background_transparent (img, f, mask)
8745 struct image *img;
8746 struct frame *f;
8747 XImage *mask;
8748{
8749 if (! img->background_transparent_valid)
8750 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8751 {
8752#if 0 /* TODO: Image support. */
8753 if (img->mask)
8754 {
8755 int free_mask = !mask;
8756
8757 if (! mask)
8758 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8759 0, 0, img->width, img->height, ~0, ZPixmap);
8760
8761 img->background_transparent
8762 = !four_corners_best (mask, img->width, img->height);
8763
8764 if (free_mask)
8765 XDestroyImage (mask);
8766 }
8767 else
8768#endif
8769 img->background_transparent = 0;
8770
8771 img->background_transparent_valid = 1;
8772 }
8773
8774 return img->background_transparent;
8775}
8776
8777\f
6fc2811b
JR
8778/***********************************************************************
8779 Helper functions for X image types
8780 ***********************************************************************/
8781
a05e2bae
JR
8782static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8783 int, int));
6fc2811b
JR
8784static void x_clear_image P_ ((struct frame *f, struct image *img));
8785static unsigned long x_alloc_image_color P_ ((struct frame *f,
8786 struct image *img,
8787 Lisp_Object color_name,
8788 unsigned long dflt));
8789
a05e2bae
JR
8790
8791/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8792 free the pixmap if any. MASK_P non-zero means clear the mask
8793 pixmap if any. COLORS_P non-zero means free colors allocated for
8794 the image, if any. */
8795
8796static void
8797x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8798 struct frame *f;
8799 struct image *img;
8800 int pixmap_p, mask_p, colors_p;
8801{
a05e2bae
JR
8802 if (pixmap_p && img->pixmap)
8803 {
ac849ba4
JR
8804 DeleteObject (img->pixmap);
8805 img->pixmap = NULL;
a05e2bae
JR
8806 img->background_valid = 0;
8807 }
8808
8809 if (mask_p && img->mask)
8810 {
ac849ba4
JR
8811 DeleteObject (img->mask);
8812 img->mask = NULL;
a05e2bae
JR
8813 img->background_transparent_valid = 0;
8814 }
8815
8816 if (colors_p && img->ncolors)
8817 {
bf76fe9c 8818#if 0 /* TODO: color table support. */
a05e2bae 8819 x_free_colors (f, img->colors, img->ncolors);
bf76fe9c 8820#endif
a05e2bae
JR
8821 xfree (img->colors);
8822 img->colors = NULL;
8823 img->ncolors = 0;
8824 }
a05e2bae
JR
8825}
8826
6fc2811b
JR
8827/* Free X resources of image IMG which is used on frame F. */
8828
8829static void
8830x_clear_image (f, img)
8831 struct frame *f;
8832 struct image *img;
8833{
6fc2811b
JR
8834 if (img->pixmap)
8835 {
8836 BLOCK_INPUT;
ac849ba4 8837 DeleteObject (img->pixmap);
6fc2811b
JR
8838 img->pixmap = 0;
8839 UNBLOCK_INPUT;
8840 }
8841
8842 if (img->ncolors)
8843 {
ac849ba4
JR
8844#if 0 /* TODO: color table support */
8845
6fc2811b
JR
8846 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8847
8848 /* If display has an immutable color map, freeing colors is not
8849 necessary and some servers don't allow it. So don't do it. */
8850 if (class != StaticColor
8851 && class != StaticGray
8852 && class != TrueColor)
8853 {
8854 Colormap cmap;
8855 BLOCK_INPUT;
8856 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8857 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8858 img->ncolors, 0);
8859 UNBLOCK_INPUT;
8860 }
ac849ba4 8861#endif
6fc2811b
JR
8862
8863 xfree (img->colors);
8864 img->colors = NULL;
8865 img->ncolors = 0;
8866 }
6fc2811b
JR
8867}
8868
8869
8870/* Allocate color COLOR_NAME for image IMG on frame F. If color
8871 cannot be allocated, use DFLT. Add a newly allocated color to
8872 IMG->colors, so that it can be freed again. Value is the pixel
8873 color. */
8874
8875static unsigned long
8876x_alloc_image_color (f, img, color_name, dflt)
8877 struct frame *f;
8878 struct image *img;
8879 Lisp_Object color_name;
8880 unsigned long dflt;
8881{
6fc2811b
JR
8882 XColor color;
8883 unsigned long result;
8884
8885 xassert (STRINGP (color_name));
8886
8887 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8888 {
8889 /* This isn't called frequently so we get away with simply
8890 reallocating the color vector to the needed size, here. */
8891 ++img->ncolors;
8892 img->colors =
8893 (unsigned long *) xrealloc (img->colors,
8894 img->ncolors * sizeof *img->colors);
8895 img->colors[img->ncolors - 1] = color.pixel;
8896 result = color.pixel;
8897 }
8898 else
8899 result = dflt;
8900 return result;
6fc2811b
JR
8901}
8902
8903
8904\f
8905/***********************************************************************
8906 Image Cache
8907 ***********************************************************************/
8908
8909static void cache_image P_ ((struct frame *f, struct image *img));
3cf3436e 8910static void postprocess_image P_ ((struct frame *, struct image *));
6fc2811b
JR
8911
8912
8913/* Return a new, initialized image cache that is allocated from the
8914 heap. Call free_image_cache to free an image cache. */
8915
8916struct image_cache *
8917make_image_cache ()
8918{
8919 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8920 int size;
8921
8922 bzero (c, sizeof *c);
8923 c->size = 50;
8924 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8925 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8926 c->buckets = (struct image **) xmalloc (size);
8927 bzero (c->buckets, size);
8928 return c;
8929}
8930
8931
8932/* Free image cache of frame F. Be aware that X frames share images
8933 caches. */
8934
8935void
8936free_image_cache (f)
8937 struct frame *f;
8938{
8939 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8940 if (c)
8941 {
8942 int i;
8943
8944 /* Cache should not be referenced by any frame when freed. */
8945 xassert (c->refcount == 0);
8946
8947 for (i = 0; i < c->used; ++i)
8948 free_image (f, c->images[i]);
8949 xfree (c->images);
8950 xfree (c);
8951 xfree (c->buckets);
8952 FRAME_X_IMAGE_CACHE (f) = NULL;
8953 }
8954}
8955
8956
8957/* Clear image cache of frame F. FORCE_P non-zero means free all
8958 images. FORCE_P zero means clear only images that haven't been
8959 displayed for some time. Should be called from time to time to
dfff8a69
JR
8960 reduce the number of loaded images. If image-eviction-seconds is
8961 non-nil, this frees images in the cache which weren't displayed for
6fc2811b
JR
8962 at least that many seconds. */
8963
8964void
8965clear_image_cache (f, force_p)
8966 struct frame *f;
8967 int force_p;
8968{
8969 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8970
8971 if (c && INTEGERP (Vimage_cache_eviction_delay))
8972 {
8973 EMACS_TIME t;
8974 unsigned long old;
0327b4cc 8975 int i, nfreed;
6fc2811b
JR
8976
8977 EMACS_GET_TIME (t);
8978 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8979
0327b4cc
JR
8980 /* Block input so that we won't be interrupted by a SIGIO
8981 while being in an inconsistent state. */
8982 BLOCK_INPUT;
8983
8984 for (i = nfreed = 0; i < c->used; ++i)
6fc2811b
JR
8985 {
8986 struct image *img = c->images[i];
8987 if (img != NULL
0327b4cc 8988 && (force_p || (img->timestamp < old)))
6fc2811b
JR
8989 {
8990 free_image (f, img);
0327b4cc 8991 ++nfreed;
6fc2811b
JR
8992 }
8993 }
8994
8995 /* We may be clearing the image cache because, for example,
8996 Emacs was iconified for a longer period of time. In that
8997 case, current matrices may still contain references to
8998 images freed above. So, clear these matrices. */
0327b4cc 8999 if (nfreed)
6fc2811b 9000 {
0327b4cc
JR
9001 Lisp_Object tail, frame;
9002
9003 FOR_EACH_FRAME (tail, frame)
9004 {
9005 struct frame *f = XFRAME (frame);
9006 if (FRAME_W32_P (f)
9007 && FRAME_X_IMAGE_CACHE (f) == c)
9008 clear_current_matrices (f);
9009 }
9010
6fc2811b
JR
9011 ++windows_or_buffers_changed;
9012 }
0327b4cc
JR
9013
9014 UNBLOCK_INPUT;
6fc2811b
JR
9015 }
9016}
9017
9018
9019DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9020 0, 1, 0,
74e1aeec
JR
9021 doc: /* Clear the image cache of FRAME.
9022FRAME nil or omitted means use the selected frame.
9023FRAME t means clear the image caches of all frames. */)
6fc2811b
JR
9024 (frame)
9025 Lisp_Object frame;
9026{
9027 if (EQ (frame, Qt))
9028 {
9029 Lisp_Object tail;
9030
9031 FOR_EACH_FRAME (tail, frame)
9032 if (FRAME_W32_P (XFRAME (frame)))
9033 clear_image_cache (XFRAME (frame), 1);
9034 }
9035 else
9036 clear_image_cache (check_x_frame (frame), 1);
9037
9038 return Qnil;
9039}
9040
9041
3cf3436e
JR
9042/* Compute masks and transform image IMG on frame F, as specified
9043 by the image's specification, */
9044
9045static void
9046postprocess_image (f, img)
9047 struct frame *f;
9048 struct image *img;
9049{
9050#if 0 /* TODO: image support. */
9051 /* Manipulation of the image's mask. */
9052 if (img->pixmap)
9053 {
9054 Lisp_Object conversion, spec;
9055 Lisp_Object mask;
9056
9057 spec = img->spec;
9058
9059 /* `:heuristic-mask t'
9060 `:mask heuristic'
9061 means build a mask heuristically.
9062 `:heuristic-mask (R G B)'
9063 `:mask (heuristic (R G B))'
9064 means build a mask from color (R G B) in the
9065 image.
9066 `:mask nil'
9067 means remove a mask, if any. */
9068
9069 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9070 if (!NILP (mask))
9071 x_build_heuristic_mask (f, img, mask);
9072 else
9073 {
9074 int found_p;
9075
9076 mask = image_spec_value (spec, QCmask, &found_p);
9077
9078 if (EQ (mask, Qheuristic))
9079 x_build_heuristic_mask (f, img, Qt);
9080 else if (CONSP (mask)
9081 && EQ (XCAR (mask), Qheuristic))
9082 {
9083 if (CONSP (XCDR (mask)))
9084 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9085 else
9086 x_build_heuristic_mask (f, img, XCDR (mask));
9087 }
9088 else if (NILP (mask) && found_p && img->mask)
9089 {
ac849ba4 9090 DeleteObject (img->mask);
3cf3436e
JR
9091 img->mask = NULL;
9092 }
9093 }
9094
9095
9096 /* Should we apply an image transformation algorithm? */
9097 conversion = image_spec_value (spec, QCconversion, NULL);
9098 if (EQ (conversion, Qdisabled))
9099 x_disable_image (f, img);
9100 else if (EQ (conversion, Qlaplace))
9101 x_laplace (f, img);
9102 else if (EQ (conversion, Qemboss))
9103 x_emboss (f, img);
9104 else if (CONSP (conversion)
9105 && EQ (XCAR (conversion), Qedge_detection))
9106 {
9107 Lisp_Object tem;
9108 tem = XCDR (conversion);
9109 if (CONSP (tem))
9110 x_edge_detection (f, img,
9111 Fplist_get (tem, QCmatrix),
9112 Fplist_get (tem, QCcolor_adjustment));
9113 }
9114 }
9115#endif
9116}
9117
9118
6fc2811b
JR
9119/* Return the id of image with Lisp specification SPEC on frame F.
9120 SPEC must be a valid Lisp image specification (see valid_image_p). */
9121
9122int
9123lookup_image (f, spec)
9124 struct frame *f;
9125 Lisp_Object spec;
9126{
9127 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9128 struct image *img;
9129 int i;
9130 unsigned hash;
9131 struct gcpro gcpro1;
9132 EMACS_TIME now;
9133
9134 /* F must be a window-system frame, and SPEC must be a valid image
9135 specification. */
9136 xassert (FRAME_WINDOW_P (f));
9137 xassert (valid_image_p (spec));
9138
9139 GCPRO1 (spec);
9140
9141 /* Look up SPEC in the hash table of the image cache. */
9142 hash = sxhash (spec, 0);
9143 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9144
9145 for (img = c->buckets[i]; img; img = img->next)
9146 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9147 break;
9148
9149 /* If not found, create a new image and cache it. */
9150 if (img == NULL)
9151 {
3cf3436e
JR
9152 extern Lisp_Object Qpostscript;
9153
8edb0a6f 9154 BLOCK_INPUT;
6fc2811b
JR
9155 img = make_image (spec, hash);
9156 cache_image (f, img);
9157 img->load_failed_p = img->type->load (f, img) == 0;
6fc2811b
JR
9158
9159 /* If we can't load the image, and we don't have a width and
9160 height, use some arbitrary width and height so that we can
9161 draw a rectangle for it. */
9162 if (img->load_failed_p)
9163 {
9164 Lisp_Object value;
9165
9166 value = image_spec_value (spec, QCwidth, NULL);
9167 img->width = (INTEGERP (value)
9168 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9169 value = image_spec_value (spec, QCheight, NULL);
9170 img->height = (INTEGERP (value)
9171 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9172 }
9173 else
9174 {
9175 /* Handle image type independent image attributes
a05e2bae
JR
9176 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9177 `:background COLOR'. */
9178 Lisp_Object ascent, margin, relief, bg;
6fc2811b
JR
9179
9180 ascent = image_spec_value (spec, QCascent, NULL);
9181 if (INTEGERP (ascent))
9182 img->ascent = XFASTINT (ascent);
dfff8a69
JR
9183 else if (EQ (ascent, Qcenter))
9184 img->ascent = CENTERED_IMAGE_ASCENT;
9185
6fc2811b
JR
9186 margin = image_spec_value (spec, QCmargin, NULL);
9187 if (INTEGERP (margin) && XINT (margin) >= 0)
8edb0a6f
JR
9188 img->vmargin = img->hmargin = XFASTINT (margin);
9189 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9190 && INTEGERP (XCDR (margin)))
9191 {
9192 if (XINT (XCAR (margin)) > 0)
9193 img->hmargin = XFASTINT (XCAR (margin));
9194 if (XINT (XCDR (margin)) > 0)
9195 img->vmargin = XFASTINT (XCDR (margin));
9196 }
6fc2811b
JR
9197
9198 relief = image_spec_value (spec, QCrelief, NULL);
9199 if (INTEGERP (relief))
9200 {
9201 img->relief = XINT (relief);
8edb0a6f
JR
9202 img->hmargin += abs (img->relief);
9203 img->vmargin += abs (img->relief);
6fc2811b
JR
9204 }
9205
a05e2bae
JR
9206 if (! img->background_valid)
9207 {
9208 bg = image_spec_value (img->spec, QCbackground, NULL);
9209 if (!NILP (bg))
9210 {
9211 img->background
9212 = x_alloc_image_color (f, img, bg,
9213 FRAME_BACKGROUND_PIXEL (f));
9214 img->background_valid = 1;
9215 }
9216 }
9217
3cf3436e
JR
9218 /* Do image transformations and compute masks, unless we
9219 don't have the image yet. */
9220 if (!EQ (*img->type->type, Qpostscript))
9221 postprocess_image (f, img);
6fc2811b 9222 }
3cf3436e 9223
8edb0a6f
JR
9224 UNBLOCK_INPUT;
9225 xassert (!interrupt_input_blocked);
6fc2811b
JR
9226 }
9227
9228 /* We're using IMG, so set its timestamp to `now'. */
9229 EMACS_GET_TIME (now);
9230 img->timestamp = EMACS_SECS (now);
9231
9232 UNGCPRO;
9233
9234 /* Value is the image id. */
9235 return img->id;
9236}
9237
9238
9239/* Cache image IMG in the image cache of frame F. */
9240
9241static void
9242cache_image (f, img)
9243 struct frame *f;
9244 struct image *img;
9245{
9246 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9247 int i;
9248
9249 /* Find a free slot in c->images. */
9250 for (i = 0; i < c->used; ++i)
9251 if (c->images[i] == NULL)
9252 break;
9253
9254 /* If no free slot found, maybe enlarge c->images. */
9255 if (i == c->used && c->used == c->size)
9256 {
9257 c->size *= 2;
9258 c->images = (struct image **) xrealloc (c->images,
9259 c->size * sizeof *c->images);
9260 }
9261
9262 /* Add IMG to c->images, and assign IMG an id. */
9263 c->images[i] = img;
9264 img->id = i;
9265 if (i == c->used)
9266 ++c->used;
9267
9268 /* Add IMG to the cache's hash table. */
9269 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9270 img->next = c->buckets[i];
9271 if (img->next)
9272 img->next->prev = img;
9273 img->prev = NULL;
9274 c->buckets[i] = img;
9275}
9276
9277
9278/* Call FN on every image in the image cache of frame F. Used to mark
9279 Lisp Objects in the image cache. */
9280
9281void
9282forall_images_in_image_cache (f, fn)
9283 struct frame *f;
9284 void (*fn) P_ ((struct image *img));
9285{
9286 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9287 {
9288 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9289 if (c)
9290 {
9291 int i;
9292 for (i = 0; i < c->used; ++i)
9293 if (c->images[i])
9294 fn (c->images[i]);
9295 }
9296 }
9297}
9298
9299
9300\f
9301/***********************************************************************
9302 W32 support code
9303 ***********************************************************************/
9304
6fc2811b
JR
9305static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9306 XImage **, Pixmap *));
9307static void x_destroy_x_image P_ ((XImage *));
9308static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9309
9310
9311/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9312 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9313 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
ac849ba4
JR
9314 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9315 DEPTH should indicate the bit depth of the image. Print error
9316 messages via image_error if an error occurs. Value is non-zero if
9317 successful. */
6fc2811b
JR
9318
9319static int
9320x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9321 struct frame *f;
9322 int width, height, depth;
9323 XImage **ximg;
9324 Pixmap *pixmap;
9325{
ac849ba4
JR
9326 BITMAPINFOHEADER *header;
9327 HDC hdc;
9328 int scanline_width_bits;
9329 int remainder;
9330 int palette_colors = 0;
6fc2811b 9331
ac849ba4
JR
9332 if (depth == 0)
9333 depth = 24;
6fc2811b 9334
ac849ba4
JR
9335 if (depth != 1 && depth != 4 && depth != 8
9336 && depth != 16 && depth != 24 && depth != 32)
9337 {
9338 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9339 return 0;
9340 }
9341
9342 scanline_width_bits = width * depth;
9343 remainder = scanline_width_bits % 32;
9344
9345 if (remainder)
9346 scanline_width_bits += 32 - remainder;
9347
9348 /* Bitmaps with a depth less than 16 need a palette. */
9349 /* BITMAPINFO structure already contains the first RGBQUAD. */
9350 if (depth < 16)
9351 palette_colors = 1 << depth - 1;
9352
9353 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
6fc2811b
JR
9354 if (*ximg == NULL)
9355 {
ac849ba4 9356 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
6fc2811b
JR
9357 return 0;
9358 }
9359
ac849ba4
JR
9360 header = &((*ximg)->info.bmiHeader);
9361 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9362 header->biSize = sizeof (*header);
9363 header->biWidth = width;
9364 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9365 header->biPlanes = 1;
9366 header->biBitCount = depth;
9367 header->biCompression = BI_RGB;
9368 header->biClrUsed = palette_colors;
6fc2811b 9369
ac849ba4
JR
9370 hdc = get_frame_dc (f);
9371
9372 /* Create a DIBSection and raster array for the bitmap,
9373 and store its handle in *pixmap. */
9374 *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
9375 &((*ximg)->data), NULL, 0);
9376
9377 /* Realize display palette and garbage all frames. */
9378 release_frame_dc (f, hdc);
9379
9380 if (*pixmap == NULL)
6fc2811b 9381 {
ac849ba4
JR
9382 DWORD err = GetLastError();
9383 Lisp_Object errcode;
9384 /* All system errors are < 10000, so the following is safe. */
9385 XSETINT (errcode, (int) err);
9386 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
6fc2811b 9387 x_destroy_x_image (*ximg);
6fc2811b
JR
9388 return 0;
9389 }
ac849ba4 9390
6fc2811b
JR
9391 return 1;
9392}
9393
9394
9395/* Destroy XImage XIMG. Free XIMG->data. */
9396
9397static void
9398x_destroy_x_image (ximg)
9399 XImage *ximg;
9400{
9401 xassert (interrupt_input_blocked);
9402 if (ximg)
9403 {
ac849ba4 9404 /* Data will be freed by DestroyObject. */
6fc2811b 9405 ximg->data = NULL;
ac849ba4 9406 xfree (ximg);
6fc2811b
JR
9407 }
9408}
9409
9410
9411/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9412 are width and height of both the image and pixmap. */
9413
9414static void
9415x_put_x_image (f, ximg, pixmap, width, height)
9416 struct frame *f;
9417 XImage *ximg;
9418 Pixmap pixmap;
9419{
ac849ba4
JR
9420
9421#if TODO /* W32 specific image code. */
6fc2811b 9422 GC gc;
ac849ba4 9423
6fc2811b
JR
9424 xassert (interrupt_input_blocked);
9425 gc = XCreateGC (NULL, pixmap, 0, NULL);
9426 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9427 XFreeGC (NULL, gc);
6fc2811b 9428#endif
ac849ba4 9429}
6fc2811b
JR
9430
9431\f
9432/***********************************************************************
3cf3436e 9433 File Handling
6fc2811b
JR
9434 ***********************************************************************/
9435
9436static Lisp_Object x_find_image_file P_ ((Lisp_Object));
3cf3436e
JR
9437static char *slurp_file P_ ((char *, int *));
9438
6fc2811b
JR
9439
9440/* Find image file FILE. Look in data-directory, then
9441 x-bitmap-file-path. Value is the full name of the file found, or
9442 nil if not found. */
9443
9444static Lisp_Object
9445x_find_image_file (file)
9446 Lisp_Object file;
9447{
9448 Lisp_Object file_found, search_path;
9449 struct gcpro gcpro1, gcpro2;
9450 int fd;
9451
9452 file_found = Qnil;
9453 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9454 GCPRO2 (file_found, search_path);
9455
9456 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
de2413e9 9457 fd = openp (search_path, file, Qnil, &file_found, Qnil);
6fc2811b 9458
939d6465 9459 if (fd == -1)
6fc2811b
JR
9460 file_found = Qnil;
9461 else
9462 close (fd);
9463
9464 UNGCPRO;
9465 return file_found;
9466}
9467
9468
3cf3436e
JR
9469/* Read FILE into memory. Value is a pointer to a buffer allocated
9470 with xmalloc holding FILE's contents. Value is null if an error
9471 occurred. *SIZE is set to the size of the file. */
9472
9473static char *
9474slurp_file (file, size)
9475 char *file;
9476 int *size;
9477{
9478 FILE *fp = NULL;
9479 char *buf = NULL;
9480 struct stat st;
9481
9482 if (stat (file, &st) == 0
9483 && (fp = fopen (file, "r")) != NULL
9484 && (buf = (char *) xmalloc (st.st_size),
9485 fread (buf, 1, st.st_size, fp) == st.st_size))
9486 {
9487 *size = st.st_size;
9488 fclose (fp);
9489 }
9490 else
9491 {
9492 if (fp)
9493 fclose (fp);
9494 if (buf)
9495 {
9496 xfree (buf);
9497 buf = NULL;
9498 }
9499 }
9500
9501 return buf;
9502}
9503
9504
6fc2811b
JR
9505\f
9506/***********************************************************************
9507 XBM images
9508 ***********************************************************************/
9509
217e5be0 9510static int xbm_scan P_ ((char **, char *, char *, int *));
6fc2811b 9511static int xbm_load P_ ((struct frame *f, struct image *img));
217e5be0
JR
9512static int xbm_load_image P_ ((struct frame *f, struct image *img,
9513 char *, char *));
6fc2811b 9514static int xbm_image_p P_ ((Lisp_Object object));
217e5be0
JR
9515static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
9516 unsigned char **));
9517static int xbm_file_p P_ ((Lisp_Object));
6fc2811b
JR
9518
9519
9520/* Indices of image specification fields in xbm_format, below. */
9521
9522enum xbm_keyword_index
9523{
9524 XBM_TYPE,
9525 XBM_FILE,
9526 XBM_WIDTH,
9527 XBM_HEIGHT,
9528 XBM_DATA,
9529 XBM_FOREGROUND,
9530 XBM_BACKGROUND,
9531 XBM_ASCENT,
9532 XBM_MARGIN,
9533 XBM_RELIEF,
9534 XBM_ALGORITHM,
9535 XBM_HEURISTIC_MASK,
a05e2bae 9536 XBM_MASK,
6fc2811b
JR
9537 XBM_LAST
9538};
9539
9540/* Vector of image_keyword structures describing the format
9541 of valid XBM image specifications. */
9542
9543static struct image_keyword xbm_format[XBM_LAST] =
9544{
9545 {":type", IMAGE_SYMBOL_VALUE, 1},
9546 {":file", IMAGE_STRING_VALUE, 0},
9547 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9548 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9549 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9550 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9551 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9552 {":ascent", IMAGE_ASCENT_VALUE, 0},
8edb0a6f 9553 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 9554 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 9555 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
217e5be0
JR
9556 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9557 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6fc2811b
JR
9558};
9559
9560/* Structure describing the image type XBM. */
9561
9562static struct image_type xbm_type =
9563{
9564 &Qxbm,
9565 xbm_image_p,
9566 xbm_load,
9567 x_clear_image,
9568 NULL
9569};
9570
9571/* Tokens returned from xbm_scan. */
9572
9573enum xbm_token
9574{
9575 XBM_TK_IDENT = 256,
9576 XBM_TK_NUMBER
9577};
9578
9579
9580/* Return non-zero if OBJECT is a valid XBM-type image specification.
9581 A valid specification is a list starting with the symbol `image'
9582 The rest of the list is a property list which must contain an
9583 entry `:type xbm..
9584
9585 If the specification specifies a file to load, it must contain
9586 an entry `:file FILENAME' where FILENAME is a string.
9587
9588 If the specification is for a bitmap loaded from memory it must
9589 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9590 WIDTH and HEIGHT are integers > 0. DATA may be:
9591
9592 1. a string large enough to hold the bitmap data, i.e. it must
9593 have a size >= (WIDTH + 7) / 8 * HEIGHT
9594
9595 2. a bool-vector of size >= WIDTH * HEIGHT
9596
9597 3. a vector of strings or bool-vectors, one for each line of the
9598 bitmap.
9599
217e5be0
JR
9600 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
9601 may not be specified in this case because they are defined in the
9602 XBM file.
9603
6fc2811b
JR
9604 Both the file and data forms may contain the additional entries
9605 `:background COLOR' and `:foreground COLOR'. If not present,
9606 foreground and background of the frame on which the image is
217e5be0 9607 displayed is used. */
6fc2811b
JR
9608
9609static int
9610xbm_image_p (object)
9611 Lisp_Object object;
9612{
9613 struct image_keyword kw[XBM_LAST];
9614
9615 bcopy (xbm_format, kw, sizeof kw);
9616 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9617 return 0;
9618
9619 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9620
9621 if (kw[XBM_FILE].count)
9622 {
9623 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9624 return 0;
9625 }
217e5be0
JR
9626 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
9627 {
9628 /* In-memory XBM file. */
9629 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
9630 return 0;
9631 }
6fc2811b
JR
9632 else
9633 {
9634 Lisp_Object data;
9635 int width, height;
9636
9637 /* Entries for `:width', `:height' and `:data' must be present. */
9638 if (!kw[XBM_WIDTH].count
9639 || !kw[XBM_HEIGHT].count
9640 || !kw[XBM_DATA].count)
9641 return 0;
9642
9643 data = kw[XBM_DATA].value;
9644 width = XFASTINT (kw[XBM_WIDTH].value);
9645 height = XFASTINT (kw[XBM_HEIGHT].value);
9646
9647 /* Check type of data, and width and height against contents of
9648 data. */
9649 if (VECTORP (data))
9650 {
9651 int i;
9652
9653 /* Number of elements of the vector must be >= height. */
9654 if (XVECTOR (data)->size < height)
9655 return 0;
9656
9657 /* Each string or bool-vector in data must be large enough
9658 for one line of the image. */
9659 for (i = 0; i < height; ++i)
9660 {
9661 Lisp_Object elt = XVECTOR (data)->contents[i];
9662
9663 if (STRINGP (elt))
9664 {
9665 if (XSTRING (elt)->size
9666 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9667 return 0;
9668 }
9669 else if (BOOL_VECTOR_P (elt))
9670 {
9671 if (XBOOL_VECTOR (elt)->size < width)
9672 return 0;
9673 }
9674 else
9675 return 0;
9676 }
9677 }
9678 else if (STRINGP (data))
9679 {
9680 if (XSTRING (data)->size
9681 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9682 return 0;
9683 }
9684 else if (BOOL_VECTOR_P (data))
9685 {
9686 if (XBOOL_VECTOR (data)->size < width * height)
9687 return 0;
9688 }
9689 else
9690 return 0;
9691 }
9692
6fc2811b
JR
9693 return 1;
9694}
9695
9696
9697/* Scan a bitmap file. FP is the stream to read from. Value is
9698 either an enumerator from enum xbm_token, or a character for a
9699 single-character token, or 0 at end of file. If scanning an
9700 identifier, store the lexeme of the identifier in SVAL. If
9701 scanning a number, store its value in *IVAL. */
9702
9703static int
3cf3436e
JR
9704xbm_scan (s, end, sval, ival)
9705 char **s, *end;
6fc2811b
JR
9706 char *sval;
9707 int *ival;
9708{
9709 int c;
3cf3436e
JR
9710
9711 loop:
9712
6fc2811b 9713 /* Skip white space. */
3cf3436e 9714 while (*s < end &&(c = *(*s)++, isspace (c)))
6fc2811b
JR
9715 ;
9716
3cf3436e 9717 if (*s >= end)
6fc2811b
JR
9718 c = 0;
9719 else if (isdigit (c))
9720 {
9721 int value = 0, digit;
9722
3cf3436e 9723 if (c == '0' && *s < end)
6fc2811b 9724 {
3cf3436e 9725 c = *(*s)++;
6fc2811b
JR
9726 if (c == 'x' || c == 'X')
9727 {
3cf3436e 9728 while (*s < end)
6fc2811b 9729 {
3cf3436e 9730 c = *(*s)++;
6fc2811b
JR
9731 if (isdigit (c))
9732 digit = c - '0';
9733 else if (c >= 'a' && c <= 'f')
9734 digit = c - 'a' + 10;
9735 else if (c >= 'A' && c <= 'F')
9736 digit = c - 'A' + 10;
9737 else
9738 break;
9739 value = 16 * value + digit;
9740 }
9741 }
9742 else if (isdigit (c))
9743 {
9744 value = c - '0';
3cf3436e
JR
9745 while (*s < end
9746 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9747 value = 8 * value + c - '0';
9748 }
9749 }
9750 else
9751 {
9752 value = c - '0';
3cf3436e
JR
9753 while (*s < end
9754 && (c = *(*s)++, isdigit (c)))
6fc2811b
JR
9755 value = 10 * value + c - '0';
9756 }
9757
3cf3436e
JR
9758 if (*s < end)
9759 *s = *s - 1;
6fc2811b
JR
9760 *ival = value;
9761 c = XBM_TK_NUMBER;
9762 }
9763 else if (isalpha (c) || c == '_')
9764 {
9765 *sval++ = c;
3cf3436e
JR
9766 while (*s < end
9767 && (c = *(*s)++, (isalnum (c) || c == '_')))
6fc2811b
JR
9768 *sval++ = c;
9769 *sval = 0;
3cf3436e
JR
9770 if (*s < end)
9771 *s = *s - 1;
6fc2811b
JR
9772 c = XBM_TK_IDENT;
9773 }
3cf3436e
JR
9774 else if (c == '/' && **s == '*')
9775 {
9776 /* C-style comment. */
9777 ++*s;
9778 while (**s && (**s != '*' || *(*s + 1) != '/'))
9779 ++*s;
9780 if (**s)
9781 {
9782 *s += 2;
9783 goto loop;
9784 }
9785 }
6fc2811b
JR
9786
9787 return c;
9788}
9789
9790
217e5be0
JR
9791/* XBM bits seem to be backward within bytes compared with how
9792 Windows does things. */
9793static unsigned char reflect_byte (unsigned char orig)
9794{
9795 int i;
9796 unsigned char reflected = 0x00;
9797 for (i = 0; i < 8; i++)
9798 {
9799 if (orig & (0x01 << i))
9800 reflected |= 0x80 >> i;
9801 }
9802 return reflected;
9803}
9804
9805
6fc2811b 9806/* Replacement for XReadBitmapFileData which isn't available under old
3cf3436e
JR
9807 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9808 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9809 the image. Return in *DATA the bitmap data allocated with xmalloc.
9810 Value is non-zero if successful. DATA null means just test if
9811 CONTENTS looks like an in-memory XBM file. */
6fc2811b
JR
9812
9813static int
3cf3436e
JR
9814xbm_read_bitmap_data (contents, end, width, height, data)
9815 char *contents, *end;
6fc2811b
JR
9816 int *width, *height;
9817 unsigned char **data;
9818{
3cf3436e 9819 char *s = contents;
6fc2811b
JR
9820 char buffer[BUFSIZ];
9821 int padding_p = 0;
9822 int v10 = 0;
217e5be0 9823 int bytes_in_per_line, bytes_out_per_line, i, nbytes;
6fc2811b
JR
9824 unsigned char *p;
9825 int value;
9826 int LA1;
9827
9828#define match() \
217e5be0 9829 LA1 = xbm_scan (&s, end, buffer, &value)
6fc2811b
JR
9830
9831#define expect(TOKEN) \
9832 if (LA1 != (TOKEN)) \
9833 goto failure; \
9834 else \
9835 match ()
9836
9837#define expect_ident(IDENT) \
9838 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9839 match (); \
9840 else \
9841 goto failure
9842
6fc2811b 9843 *width = *height = -1;
3cf3436e
JR
9844 if (data)
9845 *data = NULL;
9846 LA1 = xbm_scan (&s, end, buffer, &value);
6fc2811b
JR
9847
9848 /* Parse defines for width, height and hot-spots. */
9849 while (LA1 == '#')
9850 {
9851 match ();
9852 expect_ident ("define");
9853 expect (XBM_TK_IDENT);
9854
9855 if (LA1 == XBM_TK_NUMBER);
9856 {
9857 char *p = strrchr (buffer, '_');
9858 p = p ? p + 1 : buffer;
9859 if (strcmp (p, "width") == 0)
9860 *width = value;
9861 else if (strcmp (p, "height") == 0)
9862 *height = value;
9863 }
9864 expect (XBM_TK_NUMBER);
9865 }
9866
9867 if (*width < 0 || *height < 0)
9868 goto failure;
3cf3436e
JR
9869 else if (data == NULL)
9870 goto success;
6fc2811b
JR
9871
9872 /* Parse bits. Must start with `static'. */
9873 expect_ident ("static");
9874 if (LA1 == XBM_TK_IDENT)
9875 {
217e5be0
JR
9876 /* On Windows, all images need padding to 16 bit boundaries. */
9877 if (*width % 16 && *width % 16 < 9)
9878 padding_p = 1;
9879
6fc2811b
JR
9880 if (strcmp (buffer, "unsigned") == 0)
9881 {
9882 match ();
9883 expect_ident ("char");
9884 }
9885 else if (strcmp (buffer, "short") == 0)
9886 {
9887 match ();
9888 v10 = 1;
6fc2811b
JR
9889 }
9890 else if (strcmp (buffer, "char") == 0)
9891 match ();
9892 else
9893 goto failure;
9894 }
9895 else
9896 goto failure;
9897
9898 expect (XBM_TK_IDENT);
9899 expect ('[');
9900 expect (']');
9901 expect ('=');
9902 expect ('{');
9903
217e5be0
JR
9904 /* Bytes per line on input. Only count padding for v10 XBMs. */
9905 bytes_in_per_line = (*width + 7) / 8 + (v10 ? padding_p : 0);
9906 bytes_out_per_line = (*width + 7) / 8 + padding_p;
9907
9908 nbytes = bytes_in_per_line * *height;
9909 p = *data = (char *) xmalloc (bytes_out_per_line * *height);
6fc2811b
JR
9910
9911 if (v10)
9912 {
6fc2811b
JR
9913 for (i = 0; i < nbytes; i += 2)
9914 {
9915 int val = value;
9916 expect (XBM_TK_NUMBER);
9917
217e5be0
JR
9918 *p++ = reflect_byte (val);
9919 if (!padding_p || ((i + 2) % bytes_in_per_line))
9920 *p++ = reflect_byte (value >> 8);
6fc2811b
JR
9921
9922 if (LA1 == ',' || LA1 == '}')
9923 match ();
9924 else
9925 goto failure;
9926 }
9927 }
9928 else
9929 {
9930 for (i = 0; i < nbytes; ++i)
9931 {
9932 int val = value;
9933 expect (XBM_TK_NUMBER);
9934
217e5be0
JR
9935 *p++ = reflect_byte (val);
9936 if (padding_p && ((i + 1) % bytes_in_per_line) == 0)
9937 *p++ = 0;
9938
6fc2811b
JR
9939 if (LA1 == ',' || LA1 == '}')
9940 match ();
9941 else
9942 goto failure;
9943 }
9944 }
9945
3cf3436e 9946 success:
6fc2811b
JR
9947 return 1;
9948
9949 failure:
3cf3436e
JR
9950
9951 if (data && *data)
6fc2811b
JR
9952 {
9953 xfree (*data);
9954 *data = NULL;
9955 }
9956 return 0;
9957
9958#undef match
9959#undef expect
9960#undef expect_ident
9961}
9962
9963
3cf3436e
JR
9964/* Load XBM image IMG which will be displayed on frame F from buffer
9965 CONTENTS. END is the end of the buffer. Value is non-zero if
9966 successful. */
6fc2811b
JR
9967
9968static int
3cf3436e 9969xbm_load_image (f, img, contents, end)
6fc2811b
JR
9970 struct frame *f;
9971 struct image *img;
3cf3436e 9972 char *contents, *end;
6fc2811b
JR
9973{
9974 int rc;
9975 unsigned char *data;
9976 int success_p = 0;
6fc2811b 9977
3cf3436e 9978 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
6fc2811b
JR
9979 if (rc)
9980 {
6fc2811b
JR
9981 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9982 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9983 Lisp_Object value;
9984
9985 xassert (img->width > 0 && img->height > 0);
9986
9987 /* Get foreground and background colors, maybe allocate colors. */
9988 value = image_spec_value (img->spec, QCforeground, NULL);
9989 if (!NILP (value))
9990 foreground = x_alloc_image_color (f, img, value, foreground);
6fc2811b
JR
9991 value = image_spec_value (img->spec, QCbackground, NULL);
9992 if (!NILP (value))
a05e2bae
JR
9993 {
9994 background = x_alloc_image_color (f, img, value, background);
9995 img->background = background;
9996 img->background_valid = 1;
9997 }
6fc2811b 9998 img->pixmap
217e5be0 9999 = CreateBitmap (img->width, img->height, 1, 1, data);
ac849ba4 10000
6fc2811b
JR
10001 xfree (data);
10002
10003 if (img->pixmap == 0)
10004 {
10005 x_clear_image (f, img);
3cf3436e 10006 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
6fc2811b
JR
10007 }
10008 else
10009 success_p = 1;
6fc2811b
JR
10010 }
10011 else
10012 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10013
6fc2811b
JR
10014 return success_p;
10015}
10016
10017
3cf3436e
JR
10018/* Value is non-zero if DATA looks like an in-memory XBM file. */
10019
10020static int
10021xbm_file_p (data)
10022 Lisp_Object data;
10023{
10024 int w, h;
10025 return (STRINGP (data)
10026 && xbm_read_bitmap_data (XSTRING (data)->data,
10027 (XSTRING (data)->data
10028 + STRING_BYTES (XSTRING (data))),
10029 &w, &h, NULL));
10030}
10031
10032
6fc2811b
JR
10033/* Fill image IMG which is used on frame F with pixmap data. Value is
10034 non-zero if successful. */
10035
10036static int
10037xbm_load (f, img)
10038 struct frame *f;
10039 struct image *img;
10040{
10041 int success_p = 0;
10042 Lisp_Object file_name;
10043
10044 xassert (xbm_image_p (img->spec));
10045
10046 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10047 file_name = image_spec_value (img->spec, QCfile, NULL);
10048 if (STRINGP (file_name))
3cf3436e
JR
10049 {
10050 Lisp_Object file;
10051 char *contents;
10052 int size;
10053 struct gcpro gcpro1;
10054
10055 file = x_find_image_file (file_name);
10056 GCPRO1 (file);
10057 if (!STRINGP (file))
10058 {
10059 image_error ("Cannot find image file `%s'", file_name, Qnil);
10060 UNGCPRO;
10061 return 0;
10062 }
10063
10064 contents = slurp_file (XSTRING (file)->data, &size);
10065 if (contents == NULL)
10066 {
10067 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10068 UNGCPRO;
10069 return 0;
10070 }
10071
10072 success_p = xbm_load_image (f, img, contents, contents + size);
10073 UNGCPRO;
10074 }
6fc2811b
JR
10075 else
10076 {
10077 struct image_keyword fmt[XBM_LAST];
10078 Lisp_Object data;
10079 int depth;
10080 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10081 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10082 char *bits;
10083 int parsed_p;
3cf3436e
JR
10084 int in_memory_file_p = 0;
10085
10086 /* See if data looks like an in-memory XBM file. */
10087 data = image_spec_value (img->spec, QCdata, NULL);
10088 in_memory_file_p = xbm_file_p (data);
6fc2811b 10089
217e5be0 10090 /* Parse the image specification. */
6fc2811b
JR
10091 bcopy (xbm_format, fmt, sizeof fmt);
10092 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10093 xassert (parsed_p);
10094
10095 /* Get specified width, and height. */
3cf3436e
JR
10096 if (!in_memory_file_p)
10097 {
10098 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10099 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10100 xassert (img->width > 0 && img->height > 0);
10101 }
217e5be0 10102
6fc2811b 10103 /* Get foreground and background colors, maybe allocate colors. */
3cf3436e
JR
10104 if (fmt[XBM_FOREGROUND].count
10105 && STRINGP (fmt[XBM_FOREGROUND].value))
6fc2811b
JR
10106 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10107 foreground);
3cf3436e
JR
10108 if (fmt[XBM_BACKGROUND].count
10109 && STRINGP (fmt[XBM_BACKGROUND].value))
6fc2811b
JR
10110 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10111 background);
10112
3cf3436e
JR
10113 if (in_memory_file_p)
10114 success_p = xbm_load_image (f, img, XSTRING (data)->data,
10115 (XSTRING (data)->data
10116 + STRING_BYTES (XSTRING (data))));
10117 else
6fc2811b 10118 {
3cf3436e
JR
10119 if (VECTORP (data))
10120 {
10121 int i;
10122 char *p;
10123 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6fc2811b 10124
3cf3436e
JR
10125 p = bits = (char *) alloca (nbytes * img->height);
10126 for (i = 0; i < img->height; ++i, p += nbytes)
10127 {
10128 Lisp_Object line = XVECTOR (data)->contents[i];
10129 if (STRINGP (line))
10130 bcopy (XSTRING (line)->data, p, nbytes);
10131 else
10132 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10133 }
10134 }
10135 else if (STRINGP (data))
10136 bits = XSTRING (data)->data;
10137 else
10138 bits = XBOOL_VECTOR (data)->data;
217e5be0 10139#ifdef TODO /* full image support. */
3cf3436e 10140 /* Create the pixmap. */
a05e2bae 10141 depth = one_w32_display_info.n_cbits;
3cf3436e
JR
10142 img->pixmap
10143 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
10144 FRAME_X_WINDOW (f),
10145 bits,
10146 img->width, img->height,
10147 foreground, background,
10148 depth);
10149#endif
10150 if (img->pixmap)
10151 success_p = 1;
10152 else
6fc2811b 10153 {
3cf3436e
JR
10154 image_error ("Unable to create pixmap for XBM image `%s'",
10155 img->spec, Qnil);
10156 x_clear_image (f, img);
6fc2811b
JR
10157 }
10158 }
6fc2811b
JR
10159 }
10160
10161 return success_p;
10162}
10163
10164
10165\f
10166/***********************************************************************
10167 XPM images
10168 ***********************************************************************/
10169
10170#if HAVE_XPM
10171
10172static int xpm_image_p P_ ((Lisp_Object object));
10173static int xpm_load P_ ((struct frame *f, struct image *img));
10174static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10175
10176#include "X11/xpm.h"
10177
10178/* The symbol `xpm' identifying XPM-format images. */
10179
10180Lisp_Object Qxpm;
10181
10182/* Indices of image specification fields in xpm_format, below. */
10183
10184enum xpm_keyword_index
10185{
10186 XPM_TYPE,
10187 XPM_FILE,
10188 XPM_DATA,
10189 XPM_ASCENT,
10190 XPM_MARGIN,
10191 XPM_RELIEF,
10192 XPM_ALGORITHM,
10193 XPM_HEURISTIC_MASK,
a05e2bae 10194 XPM_MASK,
6fc2811b 10195 XPM_COLOR_SYMBOLS,
a05e2bae 10196 XPM_BACKGROUND,
6fc2811b
JR
10197 XPM_LAST
10198};
10199
10200/* Vector of image_keyword structures describing the format
10201 of valid XPM image specifications. */
10202
10203static struct image_keyword xpm_format[XPM_LAST] =
10204{
10205 {":type", IMAGE_SYMBOL_VALUE, 1},
10206 {":file", IMAGE_STRING_VALUE, 0},
10207 {":data", IMAGE_STRING_VALUE, 0},
10208 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 10209 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 10210 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 10211 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 10212 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
10213 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10214 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10215 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
10216};
10217
10218/* Structure describing the image type XBM. */
10219
10220static struct image_type xpm_type =
10221{
10222 &Qxpm,
10223 xpm_image_p,
10224 xpm_load,
10225 x_clear_image,
10226 NULL
10227};
10228
10229
10230/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10231 for XPM images. Such a list must consist of conses whose car and
10232 cdr are strings. */
10233
10234static int
10235xpm_valid_color_symbols_p (color_symbols)
10236 Lisp_Object color_symbols;
10237{
10238 while (CONSP (color_symbols))
10239 {
10240 Lisp_Object sym = XCAR (color_symbols);
10241 if (!CONSP (sym)
10242 || !STRINGP (XCAR (sym))
10243 || !STRINGP (XCDR (sym)))
10244 break;
10245 color_symbols = XCDR (color_symbols);
10246 }
10247
10248 return NILP (color_symbols);
10249}
10250
10251
10252/* Value is non-zero if OBJECT is a valid XPM image specification. */
10253
10254static int
10255xpm_image_p (object)
10256 Lisp_Object object;
10257{
10258 struct image_keyword fmt[XPM_LAST];
10259 bcopy (xpm_format, fmt, sizeof fmt);
10260 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10261 /* Either `:file' or `:data' must be present. */
10262 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10263 /* Either no `:color-symbols' or it's a list of conses
10264 whose car and cdr are strings. */
10265 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10266 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10267 && (fmt[XPM_ASCENT].count == 0
10268 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10269}
10270
10271
10272/* Load image IMG which will be displayed on frame F. Value is
10273 non-zero if successful. */
10274
10275static int
10276xpm_load (f, img)
10277 struct frame *f;
10278 struct image *img;
10279{
10280 int rc, i;
10281 XpmAttributes attrs;
10282 Lisp_Object specified_file, color_symbols;
10283
10284 /* Configure the XPM lib. Use the visual of frame F. Allocate
10285 close colors. Return colors allocated. */
10286 bzero (&attrs, sizeof attrs);
dfff8a69
JR
10287 attrs.visual = FRAME_X_VISUAL (f);
10288 attrs.colormap = FRAME_X_COLORMAP (f);
6fc2811b 10289 attrs.valuemask |= XpmVisual;
dfff8a69 10290 attrs.valuemask |= XpmColormap;
6fc2811b 10291 attrs.valuemask |= XpmReturnAllocPixels;
dfff8a69 10292#ifdef XpmAllocCloseColors
6fc2811b
JR
10293 attrs.alloc_close_colors = 1;
10294 attrs.valuemask |= XpmAllocCloseColors;
dfff8a69
JR
10295#else
10296 attrs.closeness = 600;
10297 attrs.valuemask |= XpmCloseness;
10298#endif
6fc2811b
JR
10299
10300 /* If image specification contains symbolic color definitions, add
10301 these to `attrs'. */
10302 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10303 if (CONSP (color_symbols))
10304 {
10305 Lisp_Object tail;
10306 XpmColorSymbol *xpm_syms;
10307 int i, size;
10308
10309 attrs.valuemask |= XpmColorSymbols;
10310
10311 /* Count number of symbols. */
10312 attrs.numsymbols = 0;
10313 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10314 ++attrs.numsymbols;
10315
10316 /* Allocate an XpmColorSymbol array. */
10317 size = attrs.numsymbols * sizeof *xpm_syms;
10318 xpm_syms = (XpmColorSymbol *) alloca (size);
10319 bzero (xpm_syms, size);
10320 attrs.colorsymbols = xpm_syms;
10321
10322 /* Fill the color symbol array. */
10323 for (tail = color_symbols, i = 0;
10324 CONSP (tail);
10325 ++i, tail = XCDR (tail))
10326 {
10327 Lisp_Object name = XCAR (XCAR (tail));
10328 Lisp_Object color = XCDR (XCAR (tail));
10329 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10330 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10331 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10332 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10333 }
10334 }
10335
10336 /* Create a pixmap for the image, either from a file, or from a
10337 string buffer containing data in the same format as an XPM file. */
10338 BLOCK_INPUT;
10339 specified_file = image_spec_value (img->spec, QCfile, NULL);
10340 if (STRINGP (specified_file))
10341 {
10342 Lisp_Object file = x_find_image_file (specified_file);
10343 if (!STRINGP (file))
10344 {
10345 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10346 UNBLOCK_INPUT;
10347 return 0;
10348 }
10349
10350 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10351 XSTRING (file)->data, &img->pixmap, &img->mask,
10352 &attrs);
10353 }
10354 else
10355 {
10356 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10357 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10358 XSTRING (buffer)->data,
10359 &img->pixmap, &img->mask,
10360 &attrs);
10361 }
10362 UNBLOCK_INPUT;
10363
10364 if (rc == XpmSuccess)
10365 {
10366 /* Remember allocated colors. */
10367 img->ncolors = attrs.nalloc_pixels;
10368 img->colors = (unsigned long *) xmalloc (img->ncolors
10369 * sizeof *img->colors);
10370 for (i = 0; i < attrs.nalloc_pixels; ++i)
10371 img->colors[i] = attrs.alloc_pixels[i];
10372
10373 img->width = attrs.width;
10374 img->height = attrs.height;
10375 xassert (img->width > 0 && img->height > 0);
10376
10377 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10378 BLOCK_INPUT;
10379 XpmFreeAttributes (&attrs);
10380 UNBLOCK_INPUT;
10381 }
10382 else
10383 {
10384 switch (rc)
10385 {
10386 case XpmOpenFailed:
10387 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10388 break;
10389
10390 case XpmFileInvalid:
10391 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10392 break;
10393
10394 case XpmNoMemory:
10395 image_error ("Out of memory (%s)", img->spec, Qnil);
10396 break;
10397
10398 case XpmColorFailed:
10399 image_error ("Color allocation error (%s)", img->spec, Qnil);
10400 break;
10401
10402 default:
10403 image_error ("Unknown error (%s)", img->spec, Qnil);
10404 break;
10405 }
10406 }
10407
10408 return rc == XpmSuccess;
10409}
10410
10411#endif /* HAVE_XPM != 0 */
10412
10413\f
767b1ff0 10414#if 0 /* TODO : Color tables on W32. */
6fc2811b
JR
10415/***********************************************************************
10416 Color table
10417 ***********************************************************************/
10418
10419/* An entry in the color table mapping an RGB color to a pixel color. */
10420
10421struct ct_color
10422{
10423 int r, g, b;
10424 unsigned long pixel;
10425
10426 /* Next in color table collision list. */
10427 struct ct_color *next;
10428};
10429
10430/* The bucket vector size to use. Must be prime. */
10431
10432#define CT_SIZE 101
10433
10434/* Value is a hash of the RGB color given by R, G, and B. */
10435
10436#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10437
10438/* The color hash table. */
10439
10440struct ct_color **ct_table;
10441
10442/* Number of entries in the color table. */
10443
10444int ct_colors_allocated;
10445
10446/* Function prototypes. */
10447
10448static void init_color_table P_ ((void));
10449static void free_color_table P_ ((void));
10450static unsigned long *colors_in_color_table P_ ((int *n));
10451static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10452static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10453
10454
10455/* Initialize the color table. */
10456
10457static void
10458init_color_table ()
10459{
10460 int size = CT_SIZE * sizeof (*ct_table);
10461 ct_table = (struct ct_color **) xmalloc (size);
10462 bzero (ct_table, size);
10463 ct_colors_allocated = 0;
10464}
10465
10466
10467/* Free memory associated with the color table. */
10468
10469static void
10470free_color_table ()
10471{
10472 int i;
10473 struct ct_color *p, *next;
10474
10475 for (i = 0; i < CT_SIZE; ++i)
10476 for (p = ct_table[i]; p; p = next)
10477 {
10478 next = p->next;
10479 xfree (p);
10480 }
10481
10482 xfree (ct_table);
10483 ct_table = NULL;
10484}
10485
10486
10487/* Value is a pixel color for RGB color R, G, B on frame F. If an
10488 entry for that color already is in the color table, return the
10489 pixel color of that entry. Otherwise, allocate a new color for R,
10490 G, B, and make an entry in the color table. */
10491
10492static unsigned long
10493lookup_rgb_color (f, r, g, b)
10494 struct frame *f;
10495 int r, g, b;
10496{
10497 unsigned hash = CT_HASH_RGB (r, g, b);
10498 int i = hash % CT_SIZE;
10499 struct ct_color *p;
10500
10501 for (p = ct_table[i]; p; p = p->next)
10502 if (p->r == r && p->g == g && p->b == b)
10503 break;
10504
10505 if (p == NULL)
10506 {
10507 COLORREF color;
10508 Colormap cmap;
10509 int rc;
10510
10511 color = PALETTERGB (r, g, b);
10512
10513 ++ct_colors_allocated;
10514
10515 p = (struct ct_color *) xmalloc (sizeof *p);
10516 p->r = r;
10517 p->g = g;
10518 p->b = b;
10519 p->pixel = color;
10520 p->next = ct_table[i];
10521 ct_table[i] = p;
10522 }
10523
10524 return p->pixel;
10525}
10526
10527
10528/* Look up pixel color PIXEL which is used on frame F in the color
10529 table. If not already present, allocate it. Value is PIXEL. */
10530
10531static unsigned long
10532lookup_pixel_color (f, pixel)
10533 struct frame *f;
10534 unsigned long pixel;
10535{
10536 int i = pixel % CT_SIZE;
10537 struct ct_color *p;
10538
10539 for (p = ct_table[i]; p; p = p->next)
10540 if (p->pixel == pixel)
10541 break;
10542
10543 if (p == NULL)
10544 {
10545 XColor color;
10546 Colormap cmap;
10547 int rc;
10548
10549 BLOCK_INPUT;
10550
10551 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10552 color.pixel = pixel;
10553 XQueryColor (NULL, cmap, &color);
10554 rc = x_alloc_nearest_color (f, cmap, &color);
10555 UNBLOCK_INPUT;
10556
10557 if (rc)
10558 {
10559 ++ct_colors_allocated;
10560
10561 p = (struct ct_color *) xmalloc (sizeof *p);
10562 p->r = color.red;
10563 p->g = color.green;
10564 p->b = color.blue;
10565 p->pixel = pixel;
10566 p->next = ct_table[i];
10567 ct_table[i] = p;
10568 }
10569 else
10570 return FRAME_FOREGROUND_PIXEL (f);
10571 }
10572 return p->pixel;
10573}
10574
10575
10576/* Value is a vector of all pixel colors contained in the color table,
10577 allocated via xmalloc. Set *N to the number of colors. */
10578
10579static unsigned long *
10580colors_in_color_table (n)
10581 int *n;
10582{
10583 int i, j;
10584 struct ct_color *p;
10585 unsigned long *colors;
10586
10587 if (ct_colors_allocated == 0)
10588 {
10589 *n = 0;
10590 colors = NULL;
10591 }
10592 else
10593 {
10594 colors = (unsigned long *) xmalloc (ct_colors_allocated
10595 * sizeof *colors);
10596 *n = ct_colors_allocated;
10597
10598 for (i = j = 0; i < CT_SIZE; ++i)
10599 for (p = ct_table[i]; p; p = p->next)
10600 colors[j++] = p->pixel;
10601 }
10602
10603 return colors;
10604}
10605
767b1ff0 10606#endif /* TODO */
6fc2811b
JR
10607
10608\f
10609/***********************************************************************
10610 Algorithms
10611 ***********************************************************************/
3cf3436e
JR
10612static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10613static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10614static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
ac849ba4 10615static void XPutPixel (XImage *, int, int, COLORREF);
3cf3436e
JR
10616
10617/* Non-zero means draw a cross on images having `:conversion
10618 disabled'. */
6fc2811b 10619
3cf3436e 10620int cross_disabled_images;
6fc2811b 10621
3cf3436e
JR
10622/* Edge detection matrices for different edge-detection
10623 strategies. */
6fc2811b 10624
3cf3436e
JR
10625static int emboss_matrix[9] = {
10626 /* x - 1 x x + 1 */
10627 2, -1, 0, /* y - 1 */
10628 -1, 0, 1, /* y */
10629 0, 1, -2 /* y + 1 */
10630};
10631
10632static int laplace_matrix[9] = {
10633 /* x - 1 x x + 1 */
10634 1, 0, 0, /* y - 1 */
10635 0, 0, 0, /* y */
10636 0, 0, -1 /* y + 1 */
10637};
10638
10639/* Value is the intensity of the color whose red/green/blue values
10640 are R, G, and B. */
10641
10642#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10643
10644
10645/* On frame F, return an array of XColor structures describing image
10646 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10647 non-zero means also fill the red/green/blue members of the XColor
10648 structures. Value is a pointer to the array of XColors structures,
10649 allocated with xmalloc; it must be freed by the caller. */
10650
10651static XColor *
10652x_to_xcolors (f, img, rgb_p)
10653 struct frame *f;
10654 struct image *img;
10655 int rgb_p;
10656{
10657 int x, y;
10658 XColor *colors, *p;
10659 XImage *ximg;
10660
10661 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
ac849ba4 10662#if 0 /* TODO: implement image colors. */
3cf3436e
JR
10663 /* Get the X image IMG->pixmap. */
10664 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10665 0, 0, img->width, img->height, ~0, ZPixmap);
10666
10667 /* Fill the `pixel' members of the XColor array. I wished there
10668 were an easy and portable way to circumvent XGetPixel. */
10669 p = colors;
10670 for (y = 0; y < img->height; ++y)
10671 {
10672 XColor *row = p;
10673
10674 for (x = 0; x < img->width; ++x, ++p)
10675 p->pixel = XGetPixel (ximg, x, y);
10676
10677 if (rgb_p)
10678 x_query_colors (f, row, img->width);
10679 }
10680
10681 XDestroyImage (ximg);
ac849ba4 10682#endif
3cf3436e
JR
10683 return colors;
10684}
10685
ac849ba4
JR
10686/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10687 created with CreateDIBSection, with the pointer to the bit values
10688 stored in ximg->data. */
10689
10690static void XPutPixel (ximg, x, y, color)
10691 XImage * ximg;
10692 int x, y;
10693 COLORREF color;
10694{
10695 int width = ximg->info.bmiHeader.biWidth;
10696 int height = ximg->info.bmiHeader.biHeight;
10697 int rowbytes = width * 3;
10698 unsigned char * pixel;
10699
10700 /* Don't support putting pixels in images with palettes. */
10701 xassert (ximg->info.bmiHeader.biBitCount == 24);
10702
10703 /* Ensure scanlines are aligned on 4 byte boundaries. */
10704 if (rowbytes % 4)
10705 rowbytes += 4 - (rowbytes % 4);
10706
10707 pixel = ximg->data + y * rowbytes + x * 3;
10708 *pixel = 255 - GetRValue (color);
10709 *(pixel + 1) = 255 - GetGValue (color);
10710 *(pixel + 2) = 255 - GetBValue (color);
10711}
10712
3cf3436e
JR
10713
10714/* Create IMG->pixmap from an array COLORS of XColor structures, whose
10715 RGB members are set. F is the frame on which this all happens.
10716 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
6fc2811b
JR
10717
10718static void
3cf3436e 10719x_from_xcolors (f, img, colors)
6fc2811b 10720 struct frame *f;
3cf3436e 10721 struct image *img;
6fc2811b 10722 XColor *colors;
6fc2811b 10723{
3cf3436e
JR
10724 int x, y;
10725 XImage *oimg;
10726 Pixmap pixmap;
10727 XColor *p;
ac849ba4 10728#if 0 /* TODO: color tables. */
3cf3436e 10729 init_color_table ();
ac849ba4 10730#endif
3cf3436e
JR
10731 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10732 &oimg, &pixmap);
10733 p = colors;
10734 for (y = 0; y < img->height; ++y)
10735 for (x = 0; x < img->width; ++x, ++p)
10736 {
10737 unsigned long pixel;
ac849ba4 10738#if 0 /* TODO: color tables. */
3cf3436e 10739 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
ac849ba4
JR
10740#else
10741 pixel = PALETTERGB (p->red, p->green, p->blue);
10742#endif
3cf3436e
JR
10743 XPutPixel (oimg, x, y, pixel);
10744 }
6fc2811b 10745
3cf3436e
JR
10746 xfree (colors);
10747 x_clear_image_1 (f, img, 1, 0, 1);
6fc2811b 10748
3cf3436e
JR
10749 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10750 x_destroy_x_image (oimg);
10751 img->pixmap = pixmap;
ac849ba4 10752#if 0 /* TODO: color tables. */
3cf3436e
JR
10753 img->colors = colors_in_color_table (&img->ncolors);
10754 free_color_table ();
ac849ba4 10755#endif
6fc2811b
JR
10756}
10757
10758
3cf3436e
JR
10759/* On frame F, perform edge-detection on image IMG.
10760
10761 MATRIX is a nine-element array specifying the transformation
10762 matrix. See emboss_matrix for an example.
10763
10764 COLOR_ADJUST is a color adjustment added to each pixel of the
10765 outgoing image. */
6fc2811b
JR
10766
10767static void
3cf3436e 10768x_detect_edges (f, img, matrix, color_adjust)
6fc2811b 10769 struct frame *f;
3cf3436e
JR
10770 struct image *img;
10771 int matrix[9], color_adjust;
6fc2811b 10772{
3cf3436e
JR
10773 XColor *colors = x_to_xcolors (f, img, 1);
10774 XColor *new, *p;
10775 int x, y, i, sum;
10776
10777 for (i = sum = 0; i < 9; ++i)
10778 sum += abs (matrix[i]);
10779
10780#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10781
10782 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10783
10784 for (y = 0; y < img->height; ++y)
10785 {
10786 p = COLOR (new, 0, y);
10787 p->red = p->green = p->blue = 0xffff/2;
10788 p = COLOR (new, img->width - 1, y);
10789 p->red = p->green = p->blue = 0xffff/2;
10790 }
6fc2811b 10791
3cf3436e
JR
10792 for (x = 1; x < img->width - 1; ++x)
10793 {
10794 p = COLOR (new, x, 0);
10795 p->red = p->green = p->blue = 0xffff/2;
10796 p = COLOR (new, x, img->height - 1);
10797 p->red = p->green = p->blue = 0xffff/2;
10798 }
10799
10800 for (y = 1; y < img->height - 1; ++y)
10801 {
10802 p = COLOR (new, 1, y);
10803
10804 for (x = 1; x < img->width - 1; ++x, ++p)
10805 {
10806 int r, g, b, y1, x1;
10807
10808 r = g = b = i = 0;
10809 for (y1 = y - 1; y1 < y + 2; ++y1)
10810 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10811 if (matrix[i])
10812 {
10813 XColor *t = COLOR (colors, x1, y1);
10814 r += matrix[i] * t->red;
10815 g += matrix[i] * t->green;
10816 b += matrix[i] * t->blue;
10817 }
10818
10819 r = (r / sum + color_adjust) & 0xffff;
10820 g = (g / sum + color_adjust) & 0xffff;
10821 b = (b / sum + color_adjust) & 0xffff;
10822 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10823 }
10824 }
10825
10826 xfree (colors);
10827 x_from_xcolors (f, img, new);
10828
10829#undef COLOR
10830}
10831
10832
10833/* Perform the pre-defined `emboss' edge-detection on image IMG
10834 on frame F. */
10835
10836static void
10837x_emboss (f, img)
10838 struct frame *f;
10839 struct image *img;
10840{
10841 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
6fc2811b 10842}
3cf3436e 10843
6fc2811b
JR
10844
10845/* Transform image IMG which is used on frame F with a Laplace
10846 edge-detection algorithm. The result is an image that can be used
10847 to draw disabled buttons, for example. */
10848
10849static void
10850x_laplace (f, img)
10851 struct frame *f;
10852 struct image *img;
10853{
3cf3436e
JR
10854 x_detect_edges (f, img, laplace_matrix, 45000);
10855}
6fc2811b 10856
6fc2811b 10857
3cf3436e
JR
10858/* Perform edge-detection on image IMG on frame F, with specified
10859 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
6fc2811b 10860
3cf3436e 10861 MATRIX must be either
6fc2811b 10862
3cf3436e
JR
10863 - a list of at least 9 numbers in row-major form
10864 - a vector of at least 9 numbers
6fc2811b 10865
3cf3436e
JR
10866 COLOR_ADJUST nil means use a default; otherwise it must be a
10867 number. */
6fc2811b 10868
3cf3436e
JR
10869static void
10870x_edge_detection (f, img, matrix, color_adjust)
10871 struct frame *f;
10872 struct image *img;
10873 Lisp_Object matrix, color_adjust;
10874{
10875 int i = 0;
10876 int trans[9];
10877
10878 if (CONSP (matrix))
6fc2811b 10879 {
3cf3436e
JR
10880 for (i = 0;
10881 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10882 ++i, matrix = XCDR (matrix))
10883 trans[i] = XFLOATINT (XCAR (matrix));
10884 }
10885 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10886 {
10887 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10888 trans[i] = XFLOATINT (AREF (matrix, i));
10889 }
10890
10891 if (NILP (color_adjust))
10892 color_adjust = make_number (0xffff / 2);
10893
10894 if (i == 9 && NUMBERP (color_adjust))
10895 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10896}
10897
6fc2811b 10898
3cf3436e 10899/* Transform image IMG on frame F so that it looks disabled. */
6fc2811b 10900
3cf3436e
JR
10901static void
10902x_disable_image (f, img)
10903 struct frame *f;
10904 struct image *img;
10905{
ac849ba4 10906 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3cf3436e 10907
ac849ba4 10908 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
3cf3436e
JR
10909 {
10910 /* Color (or grayscale). Convert to gray, and equalize. Just
10911 drawing such images with a stipple can look very odd, so
10912 we're using this method instead. */
10913 XColor *colors = x_to_xcolors (f, img, 1);
10914 XColor *p, *end;
10915 const int h = 15000;
10916 const int l = 30000;
10917
10918 for (p = colors, end = colors + img->width * img->height;
10919 p < end;
10920 ++p)
6fc2811b 10921 {
3cf3436e
JR
10922 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10923 int i2 = (0xffff - h - l) * i / 0xffff + l;
10924 p->red = p->green = p->blue = i2;
6fc2811b
JR
10925 }
10926
3cf3436e 10927 x_from_xcolors (f, img, colors);
6fc2811b
JR
10928 }
10929
3cf3436e
JR
10930 /* Draw a cross over the disabled image, if we must or if we
10931 should. */
ac849ba4 10932 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
3cf3436e 10933 {
ac849ba4 10934#if 0 /* TODO: full image support */
3cf3436e
JR
10935 Display *dpy = FRAME_X_DISPLAY (f);
10936 GC gc;
6fc2811b 10937
3cf3436e
JR
10938 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10939 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10940 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10941 img->width - 1, img->height - 1);
10942 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10943 img->width - 1, 0);
10944 XFreeGC (dpy, gc);
6fc2811b 10945
3cf3436e
JR
10946 if (img->mask)
10947 {
10948 gc = XCreateGC (dpy, img->mask, 0, NULL);
10949 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10950 XDrawLine (dpy, img->mask, gc, 0, 0,
10951 img->width - 1, img->height - 1);
10952 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10953 img->width - 1, 0);
10954 XFreeGC (dpy, gc);
10955 }
ac849ba4 10956#endif
3cf3436e 10957 }
6fc2811b
JR
10958}
10959
10960
10961/* Build a mask for image IMG which is used on frame F. FILE is the
10962 name of an image file, for error messages. HOW determines how to
10963 determine the background color of IMG. If it is a list '(R G B)',
10964 with R, G, and B being integers >= 0, take that as the color of the
10965 background. Otherwise, determine the background color of IMG
10966 heuristically. Value is non-zero if successful. */
10967
10968static int
10969x_build_heuristic_mask (f, img, how)
10970 struct frame *f;
10971 struct image *img;
10972 Lisp_Object how;
10973{
ac849ba4 10974#if 0 /* TODO: full image support. */
6fc2811b
JR
10975 Display *dpy = FRAME_W32_DISPLAY (f);
10976 XImage *ximg, *mask_img;
a05e2bae
JR
10977 int x, y, rc, use_img_background;
10978 unsigned long bg = 0;
10979
10980 if (img->mask)
10981 {
10982 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10983 img->mask = None;
10984 img->background_transparent_valid = 0;
10985 }
6fc2811b 10986
6fc2811b
JR
10987 /* Create an image and pixmap serving as mask. */
10988 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10989 &mask_img, &img->mask);
10990 if (!rc)
a05e2bae 10991 return 0;
6fc2811b
JR
10992
10993 /* Get the X image of IMG->pixmap. */
10994 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10995 ~0, ZPixmap);
10996
10997 /* Determine the background color of ximg. If HOW is `(R G B)'
a05e2bae
JR
10998 take that as color. Otherwise, use the image's background color. */
10999 use_img_background = 1;
6fc2811b
JR
11000
11001 if (CONSP (how))
11002 {
a05e2bae 11003 int rgb[3], i;
6fc2811b 11004
a05e2bae 11005 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
6fc2811b
JR
11006 {
11007 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
11008 how = XCDR (how);
11009 }
11010
11011 if (i == 3 && NILP (how))
11012 {
11013 char color_name[30];
6fc2811b 11014 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
a05e2bae
JR
11015 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
11016 use_img_background = 0;
6fc2811b
JR
11017 }
11018 }
11019
a05e2bae
JR
11020 if (use_img_background)
11021 bg = four_corners_best (ximg, img->width, img->height);
6fc2811b
JR
11022
11023 /* Set all bits in mask_img to 1 whose color in ximg is different
11024 from the background color bg. */
11025 for (y = 0; y < img->height; ++y)
11026 for (x = 0; x < img->width; ++x)
11027 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
11028
a05e2bae
JR
11029 /* Fill in the background_transparent field while we have the mask handy. */
11030 image_background_transparent (img, f, mask_img);
11031
6fc2811b
JR
11032 /* Put mask_img into img->mask. */
11033 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11034 x_destroy_x_image (mask_img);
11035 XDestroyImage (ximg);
6fc2811b
JR
11036
11037 return 1;
ac849ba4
JR
11038#else
11039 return 0;
11040#endif
6fc2811b 11041}
217e5be0 11042
6fc2811b
JR
11043\f
11044/***********************************************************************
11045 PBM (mono, gray, color)
11046 ***********************************************************************/
6fc2811b
JR
11047
11048static int pbm_image_p P_ ((Lisp_Object object));
11049static int pbm_load P_ ((struct frame *f, struct image *img));
11050static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11051
11052/* The symbol `pbm' identifying images of this type. */
11053
11054Lisp_Object Qpbm;
11055
11056/* Indices of image specification fields in gs_format, below. */
11057
11058enum pbm_keyword_index
11059{
11060 PBM_TYPE,
11061 PBM_FILE,
11062 PBM_DATA,
11063 PBM_ASCENT,
11064 PBM_MARGIN,
11065 PBM_RELIEF,
11066 PBM_ALGORITHM,
11067 PBM_HEURISTIC_MASK,
a05e2bae
JR
11068 PBM_MASK,
11069 PBM_FOREGROUND,
11070 PBM_BACKGROUND,
6fc2811b
JR
11071 PBM_LAST
11072};
11073
11074/* Vector of image_keyword structures describing the format
11075 of valid user-defined image specifications. */
11076
11077static struct image_keyword pbm_format[PBM_LAST] =
11078{
11079 {":type", IMAGE_SYMBOL_VALUE, 1},
11080 {":file", IMAGE_STRING_VALUE, 0},
11081 {":data", IMAGE_STRING_VALUE, 0},
11082 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11083 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11084 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 11085 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
3cf3436e
JR
11086 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11087 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11088 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11089 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11090};
11091
11092/* Structure describing the image type `pbm'. */
11093
11094static struct image_type pbm_type =
11095{
11096 &Qpbm,
11097 pbm_image_p,
11098 pbm_load,
11099 x_clear_image,
11100 NULL
11101};
11102
11103
11104/* Return non-zero if OBJECT is a valid PBM image specification. */
11105
11106static int
11107pbm_image_p (object)
11108 Lisp_Object object;
11109{
11110 struct image_keyword fmt[PBM_LAST];
11111
11112 bcopy (pbm_format, fmt, sizeof fmt);
11113
11114 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
11115 || (fmt[PBM_ASCENT].count
11116 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11117 return 0;
11118
11119 /* Must specify either :data or :file. */
11120 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11121}
11122
11123
11124/* Scan a decimal number from *S and return it. Advance *S while
11125 reading the number. END is the end of the string. Value is -1 at
11126 end of input. */
11127
11128static int
11129pbm_scan_number (s, end)
11130 unsigned char **s, *end;
11131{
11132 int c, val = -1;
11133
11134 while (*s < end)
11135 {
11136 /* Skip white-space. */
11137 while (*s < end && (c = *(*s)++, isspace (c)))
11138 ;
11139
11140 if (c == '#')
11141 {
11142 /* Skip comment to end of line. */
11143 while (*s < end && (c = *(*s)++, c != '\n'))
11144 ;
11145 }
11146 else if (isdigit (c))
11147 {
11148 /* Read decimal number. */
11149 val = c - '0';
11150 while (*s < end && (c = *(*s)++, isdigit (c)))
11151 val = 10 * val + c - '0';
11152 break;
11153 }
11154 else
11155 break;
11156 }
11157
11158 return val;
11159}
11160
11161
11162/* Read FILE into memory. Value is a pointer to a buffer allocated
11163 with xmalloc holding FILE's contents. Value is null if an error
11164 occured. *SIZE is set to the size of the file. */
11165
11166static char *
11167pbm_read_file (file, size)
11168 Lisp_Object file;
11169 int *size;
11170{
11171 FILE *fp = NULL;
11172 char *buf = NULL;
11173 struct stat st;
11174
11175 if (stat (XSTRING (file)->data, &st) == 0
11176 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11177 && (buf = (char *) xmalloc (st.st_size),
11178 fread (buf, 1, st.st_size, fp) == st.st_size))
11179 {
11180 *size = st.st_size;
11181 fclose (fp);
11182 }
11183 else
11184 {
11185 if (fp)
11186 fclose (fp);
11187 if (buf)
11188 {
11189 xfree (buf);
11190 buf = NULL;
11191 }
11192 }
11193
11194 return buf;
11195}
11196
11197
11198/* Load PBM image IMG for use on frame F. */
11199
11200static int
11201pbm_load (f, img)
11202 struct frame *f;
11203 struct image *img;
11204{
11205 int raw_p, x, y;
11206 int width, height, max_color_idx = 0;
11207 XImage *ximg;
11208 Lisp_Object file, specified_file;
11209 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11210 struct gcpro gcpro1;
11211 unsigned char *contents = NULL;
11212 unsigned char *end, *p;
11213 int size;
11214
11215 specified_file = image_spec_value (img->spec, QCfile, NULL);
11216 file = Qnil;
11217 GCPRO1 (file);
11218
11219 if (STRINGP (specified_file))
11220 {
11221 file = x_find_image_file (specified_file);
11222 if (!STRINGP (file))
11223 {
11224 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11225 UNGCPRO;
11226 return 0;
11227 }
11228
3cf3436e 11229 contents = slurp_file (XSTRING (file)->data, &size);
6fc2811b
JR
11230 if (contents == NULL)
11231 {
11232 image_error ("Error reading `%s'", file, Qnil);
11233 UNGCPRO;
11234 return 0;
11235 }
11236
11237 p = contents;
11238 end = contents + size;
11239 }
11240 else
11241 {
11242 Lisp_Object data;
11243 data = image_spec_value (img->spec, QCdata, NULL);
11244 p = XSTRING (data)->data;
11245 end = p + STRING_BYTES (XSTRING (data));
11246 }
11247
11248 /* Check magic number. */
11249 if (end - p < 2 || *p++ != 'P')
11250 {
11251 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11252 error:
11253 xfree (contents);
11254 UNGCPRO;
11255 return 0;
11256 }
11257
6fc2811b
JR
11258 switch (*p++)
11259 {
11260 case '1':
11261 raw_p = 0, type = PBM_MONO;
11262 break;
11263
11264 case '2':
11265 raw_p = 0, type = PBM_GRAY;
11266 break;
11267
11268 case '3':
11269 raw_p = 0, type = PBM_COLOR;
11270 break;
11271
11272 case '4':
11273 raw_p = 1, type = PBM_MONO;
11274 break;
11275
11276 case '5':
11277 raw_p = 1, type = PBM_GRAY;
11278 break;
11279
11280 case '6':
11281 raw_p = 1, type = PBM_COLOR;
11282 break;
11283
11284 default:
11285 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11286 goto error;
11287 }
11288
11289 /* Read width, height, maximum color-component. Characters
11290 starting with `#' up to the end of a line are ignored. */
11291 width = pbm_scan_number (&p, end);
11292 height = pbm_scan_number (&p, end);
11293
11294 if (type != PBM_MONO)
11295 {
11296 max_color_idx = pbm_scan_number (&p, end);
11297 if (raw_p && max_color_idx > 255)
11298 max_color_idx = 255;
11299 }
11300
11301 if (width < 0
11302 || height < 0
11303 || (type != PBM_MONO && max_color_idx < 0))
11304 goto error;
11305
ac849ba4 11306 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
3cf3436e
JR
11307 goto error;
11308
ac849ba4 11309#if 0 /* TODO: color tables. */
6fc2811b
JR
11310 /* Initialize the color hash table. */
11311 init_color_table ();
ac849ba4 11312#endif
6fc2811b
JR
11313
11314 if (type == PBM_MONO)
11315 {
11316 int c = 0, g;
3cf3436e
JR
11317 struct image_keyword fmt[PBM_LAST];
11318 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11319 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11320
11321 /* Parse the image specification. */
11322 bcopy (pbm_format, fmt, sizeof fmt);
11323 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11324
11325 /* Get foreground and background colors, maybe allocate colors. */
11326 if (fmt[PBM_FOREGROUND].count
11327 && STRINGP (fmt[PBM_FOREGROUND].value))
11328 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11329 if (fmt[PBM_BACKGROUND].count
11330 && STRINGP (fmt[PBM_BACKGROUND].value))
a05e2bae
JR
11331 {
11332 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11333 img->background = bg;
11334 img->background_valid = 1;
11335 }
11336
6fc2811b
JR
11337 for (y = 0; y < height; ++y)
11338 for (x = 0; x < width; ++x)
11339 {
11340 if (raw_p)
11341 {
11342 if ((x & 7) == 0)
11343 c = *p++;
11344 g = c & 0x80;
11345 c <<= 1;
11346 }
11347 else
11348 g = pbm_scan_number (&p, end);
11349
3cf3436e 11350 XPutPixel (ximg, x, y, g ? fg : bg);
6fc2811b
JR
11351 }
11352 }
11353 else
11354 {
11355 for (y = 0; y < height; ++y)
11356 for (x = 0; x < width; ++x)
11357 {
11358 int r, g, b;
11359
11360 if (type == PBM_GRAY)
11361 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11362 else if (raw_p)
11363 {
11364 r = *p++;
11365 g = *p++;
11366 b = *p++;
11367 }
11368 else
11369 {
11370 r = pbm_scan_number (&p, end);
11371 g = pbm_scan_number (&p, end);
11372 b = pbm_scan_number (&p, end);
11373 }
11374
11375 if (r < 0 || g < 0 || b < 0)
11376 {
ac849ba4 11377 x_destroy_x_image (ximg);
6fc2811b
JR
11378 image_error ("Invalid pixel value in image `%s'",
11379 img->spec, Qnil);
11380 goto error;
11381 }
11382
11383 /* RGB values are now in the range 0..max_color_idx.
ac849ba4
JR
11384 Scale this to the range 0..0xff supported by W32. */
11385 r = (int) ((double) r * 255 / max_color_idx);
11386 g = (int) ((double) g * 255 / max_color_idx);
11387 b = (int) ((double) b * 255 / max_color_idx);
11388 XPutPixel (ximg, x, y,
11389#if 0 /* TODO: color tables. */
11390 lookup_rgb_color (f, r, g, b));
11391#else
11392 PALETTERGB (r, g, b));
11393#endif
6fc2811b
JR
11394 }
11395 }
ac849ba4
JR
11396
11397#if 0 /* TODO: color tables. */
6fc2811b
JR
11398 /* Store in IMG->colors the colors allocated for the image, and
11399 free the color table. */
11400 img->colors = colors_in_color_table (&img->ncolors);
11401 free_color_table ();
ac849ba4 11402#endif
a05e2bae
JR
11403 /* Maybe fill in the background field while we have ximg handy. */
11404 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11405 IMAGE_BACKGROUND (img, f, ximg);
11406
6fc2811b
JR
11407 /* Put the image into a pixmap. */
11408 x_put_x_image (f, ximg, img->pixmap, width, height);
11409 x_destroy_x_image (ximg);
6fc2811b
JR
11410
11411 img->width = width;
11412 img->height = height;
11413
11414 UNGCPRO;
11415 xfree (contents);
11416 return 1;
11417}
6fc2811b
JR
11418
11419\f
11420/***********************************************************************
11421 PNG
11422 ***********************************************************************/
11423
11424#if HAVE_PNG
11425
11426#include <png.h>
11427
11428/* Function prototypes. */
11429
11430static int png_image_p P_ ((Lisp_Object object));
11431static int png_load P_ ((struct frame *f, struct image *img));
11432
11433/* The symbol `png' identifying images of this type. */
11434
11435Lisp_Object Qpng;
11436
11437/* Indices of image specification fields in png_format, below. */
11438
11439enum png_keyword_index
11440{
11441 PNG_TYPE,
11442 PNG_DATA,
11443 PNG_FILE,
11444 PNG_ASCENT,
11445 PNG_MARGIN,
11446 PNG_RELIEF,
11447 PNG_ALGORITHM,
11448 PNG_HEURISTIC_MASK,
a05e2bae
JR
11449 PNG_MASK,
11450 PNG_BACKGROUND,
6fc2811b
JR
11451 PNG_LAST
11452};
11453
11454/* Vector of image_keyword structures describing the format
11455 of valid user-defined image specifications. */
11456
11457static struct image_keyword png_format[PNG_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},
a05e2bae
JR
11466 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11467 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11468 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11469};
11470
11471/* Structure describing the image type `png'. */
11472
11473static struct image_type png_type =
11474{
11475 &Qpng,
11476 png_image_p,
11477 png_load,
11478 x_clear_image,
11479 NULL
11480};
11481
11482
11483/* Return non-zero if OBJECT is a valid PNG image specification. */
11484
11485static int
11486png_image_p (object)
11487 Lisp_Object object;
11488{
11489 struct image_keyword fmt[PNG_LAST];
11490 bcopy (png_format, fmt, sizeof fmt);
11491
11492 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11493 || (fmt[PNG_ASCENT].count
11494 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11495 return 0;
11496
11497 /* Must specify either the :data or :file keyword. */
11498 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11499}
11500
11501
11502/* Error and warning handlers installed when the PNG library
11503 is initialized. */
11504
11505static void
11506my_png_error (png_ptr, msg)
11507 png_struct *png_ptr;
11508 char *msg;
11509{
11510 xassert (png_ptr != NULL);
11511 image_error ("PNG error: %s", build_string (msg), Qnil);
11512 longjmp (png_ptr->jmpbuf, 1);
11513}
11514
11515
11516static void
11517my_png_warning (png_ptr, msg)
11518 png_struct *png_ptr;
11519 char *msg;
11520{
11521 xassert (png_ptr != NULL);
11522 image_error ("PNG warning: %s", build_string (msg), Qnil);
11523}
11524
6fc2811b
JR
11525/* Memory source for PNG decoding. */
11526
11527struct png_memory_storage
11528{
11529 unsigned char *bytes; /* The data */
11530 size_t len; /* How big is it? */
11531 int index; /* Where are we? */
11532};
11533
11534
11535/* Function set as reader function when reading PNG image from memory.
11536 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11537 bytes from the input to DATA. */
11538
11539static void
11540png_read_from_memory (png_ptr, data, length)
11541 png_structp png_ptr;
11542 png_bytep data;
11543 png_size_t length;
11544{
11545 struct png_memory_storage *tbr
11546 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11547
11548 if (length > tbr->len - tbr->index)
11549 png_error (png_ptr, "Read error");
11550
11551 bcopy (tbr->bytes + tbr->index, data, length);
11552 tbr->index = tbr->index + length;
11553}
11554
6fc2811b
JR
11555/* Load PNG image IMG for use on frame F. Value is non-zero if
11556 successful. */
11557
11558static int
11559png_load (f, img)
11560 struct frame *f;
11561 struct image *img;
11562{
11563 Lisp_Object file, specified_file;
11564 Lisp_Object specified_data;
11565 int x, y, i;
11566 XImage *ximg, *mask_img = NULL;
11567 struct gcpro gcpro1;
11568 png_struct *png_ptr = NULL;
11569 png_info *info_ptr = NULL, *end_info = NULL;
a05e2bae 11570 FILE *volatile fp = NULL;
6fc2811b 11571 png_byte sig[8];
a05e2bae
JR
11572 png_byte *volatile pixels = NULL;
11573 png_byte **volatile rows = NULL;
6fc2811b
JR
11574 png_uint_32 width, height;
11575 int bit_depth, color_type, interlace_type;
11576 png_byte channels;
11577 png_uint_32 row_bytes;
11578 int transparent_p;
11579 char *gamma_str;
11580 double screen_gamma, image_gamma;
11581 int intent;
11582 struct png_memory_storage tbr; /* Data to be read */
11583
11584 /* Find out what file to load. */
11585 specified_file = image_spec_value (img->spec, QCfile, NULL);
11586 specified_data = image_spec_value (img->spec, QCdata, NULL);
11587 file = Qnil;
11588 GCPRO1 (file);
11589
11590 if (NILP (specified_data))
11591 {
11592 file = x_find_image_file (specified_file);
11593 if (!STRINGP (file))
11594 {
11595 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11596 UNGCPRO;
11597 return 0;
11598 }
11599
11600 /* Open the image file. */
11601 fp = fopen (XSTRING (file)->data, "rb");
11602 if (!fp)
11603 {
11604 image_error ("Cannot open image file `%s'", file, Qnil);
11605 UNGCPRO;
11606 fclose (fp);
11607 return 0;
11608 }
11609
11610 /* Check PNG signature. */
11611 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11612 || !png_check_sig (sig, sizeof sig))
11613 {
11614 image_error ("Not a PNG file:` %s'", file, Qnil);
11615 UNGCPRO;
11616 fclose (fp);
11617 return 0;
11618 }
11619 }
11620 else
11621 {
11622 /* Read from memory. */
11623 tbr.bytes = XSTRING (specified_data)->data;
11624 tbr.len = STRING_BYTES (XSTRING (specified_data));
11625 tbr.index = 0;
11626
11627 /* Check PNG signature. */
11628 if (tbr.len < sizeof sig
11629 || !png_check_sig (tbr.bytes, sizeof sig))
11630 {
11631 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11632 UNGCPRO;
11633 return 0;
11634 }
11635
11636 /* Need to skip past the signature. */
11637 tbr.bytes += sizeof (sig);
11638 }
11639
6fc2811b
JR
11640 /* Initialize read and info structs for PNG lib. */
11641 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11642 my_png_error, my_png_warning);
11643 if (!png_ptr)
11644 {
11645 if (fp) fclose (fp);
11646 UNGCPRO;
11647 return 0;
11648 }
11649
11650 info_ptr = png_create_info_struct (png_ptr);
11651 if (!info_ptr)
11652 {
11653 png_destroy_read_struct (&png_ptr, NULL, NULL);
11654 if (fp) fclose (fp);
11655 UNGCPRO;
11656 return 0;
11657 }
11658
11659 end_info = png_create_info_struct (png_ptr);
11660 if (!end_info)
11661 {
11662 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11663 if (fp) fclose (fp);
11664 UNGCPRO;
11665 return 0;
11666 }
11667
11668 /* Set error jump-back. We come back here when the PNG library
11669 detects an error. */
11670 if (setjmp (png_ptr->jmpbuf))
11671 {
11672 error:
11673 if (png_ptr)
11674 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11675 xfree (pixels);
11676 xfree (rows);
11677 if (fp) fclose (fp);
11678 UNGCPRO;
11679 return 0;
11680 }
11681
11682 /* Read image info. */
11683 if (!NILP (specified_data))
11684 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11685 else
11686 png_init_io (png_ptr, fp);
11687
11688 png_set_sig_bytes (png_ptr, sizeof sig);
11689 png_read_info (png_ptr, info_ptr);
11690 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11691 &interlace_type, NULL, NULL);
11692
11693 /* If image contains simply transparency data, we prefer to
11694 construct a clipping mask. */
11695 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11696 transparent_p = 1;
11697 else
11698 transparent_p = 0;
11699
11700 /* This function is easier to write if we only have to handle
11701 one data format: RGB or RGBA with 8 bits per channel. Let's
11702 transform other formats into that format. */
11703
11704 /* Strip more than 8 bits per channel. */
11705 if (bit_depth == 16)
11706 png_set_strip_16 (png_ptr);
11707
11708 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11709 if available. */
11710 png_set_expand (png_ptr);
11711
11712 /* Convert grayscale images to RGB. */
11713 if (color_type == PNG_COLOR_TYPE_GRAY
11714 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11715 png_set_gray_to_rgb (png_ptr);
11716
11717 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11718 gamma_str = getenv ("SCREEN_GAMMA");
11719 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11720
11721 /* Tell the PNG lib to handle gamma correction for us. */
11722
11723#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11724 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11725 /* There is a special chunk in the image specifying the gamma. */
11726 png_set_sRGB (png_ptr, info_ptr, intent);
11727 else
11728#endif
11729 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11730 /* Image contains gamma information. */
11731 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11732 else
11733 /* Use a default of 0.5 for the image gamma. */
11734 png_set_gamma (png_ptr, screen_gamma, 0.5);
11735
11736 /* Handle alpha channel by combining the image with a background
11737 color. Do this only if a real alpha channel is supplied. For
11738 simple transparency, we prefer a clipping mask. */
11739 if (!transparent_p)
11740 {
11741 png_color_16 *image_background;
a05e2bae
JR
11742 Lisp_Object specified_bg
11743 = image_spec_value (img->spec, QCbackground, NULL);
11744
11745
11746 if (STRINGP (specified_bg))
11747 /* The user specified `:background', use that. */
11748 {
11749 COLORREF color;
11750 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11751 {
11752 png_color_16 user_bg;
11753
11754 bzero (&user_bg, sizeof user_bg);
11755 user_bg.red = color.red;
11756 user_bg.green = color.green;
11757 user_bg.blue = color.blue;
6fc2811b 11758
a05e2bae
JR
11759 png_set_background (png_ptr, &user_bg,
11760 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11761 }
11762 }
11763 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
6fc2811b
JR
11764 /* Image contains a background color with which to
11765 combine the image. */
11766 png_set_background (png_ptr, image_background,
11767 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11768 else
11769 {
11770 /* Image does not contain a background color with which
11771 to combine the image data via an alpha channel. Use
11772 the frame's background instead. */
11773 XColor color;
11774 Colormap cmap;
11775 png_color_16 frame_background;
11776
a05e2bae 11777 cmap = FRAME_X_COLORMAP (f);
6fc2811b 11778 color.pixel = FRAME_BACKGROUND_PIXEL (f);
a05e2bae 11779 x_query_color (f, &color);
6fc2811b
JR
11780
11781 bzero (&frame_background, sizeof frame_background);
11782 frame_background.red = color.red;
11783 frame_background.green = color.green;
11784 frame_background.blue = color.blue;
11785
11786 png_set_background (png_ptr, &frame_background,
11787 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11788 }
11789 }
11790
11791 /* Update info structure. */
11792 png_read_update_info (png_ptr, info_ptr);
11793
11794 /* Get number of channels. Valid values are 1 for grayscale images
11795 and images with a palette, 2 for grayscale images with transparency
11796 information (alpha channel), 3 for RGB images, and 4 for RGB
11797 images with alpha channel, i.e. RGBA. If conversions above were
11798 sufficient we should only have 3 or 4 channels here. */
11799 channels = png_get_channels (png_ptr, info_ptr);
11800 xassert (channels == 3 || channels == 4);
11801
11802 /* Number of bytes needed for one row of the image. */
11803 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11804
11805 /* Allocate memory for the image. */
11806 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11807 rows = (png_byte **) xmalloc (height * sizeof *rows);
11808 for (i = 0; i < height; ++i)
11809 rows[i] = pixels + i * row_bytes;
11810
11811 /* Read the entire image. */
11812 png_read_image (png_ptr, rows);
11813 png_read_end (png_ptr, info_ptr);
11814 if (fp)
11815 {
11816 fclose (fp);
11817 fp = NULL;
11818 }
11819
6fc2811b
JR
11820 /* Create the X image and pixmap. */
11821 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11822 &img->pixmap))
a05e2bae 11823 goto error;
6fc2811b
JR
11824
11825 /* Create an image and pixmap serving as mask if the PNG image
11826 contains an alpha channel. */
11827 if (channels == 4
11828 && !transparent_p
11829 && !x_create_x_image_and_pixmap (f, width, height, 1,
11830 &mask_img, &img->mask))
11831 {
11832 x_destroy_x_image (ximg);
11833 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11834 img->pixmap = 0;
6fc2811b
JR
11835 goto error;
11836 }
11837
11838 /* Fill the X image and mask from PNG data. */
11839 init_color_table ();
11840
11841 for (y = 0; y < height; ++y)
11842 {
11843 png_byte *p = rows[y];
11844
11845 for (x = 0; x < width; ++x)
11846 {
11847 unsigned r, g, b;
11848
11849 r = *p++ << 8;
11850 g = *p++ << 8;
11851 b = *p++ << 8;
11852 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11853
11854 /* An alpha channel, aka mask channel, associates variable
11855 transparency with an image. Where other image formats
11856 support binary transparency---fully transparent or fully
11857 opaque---PNG allows up to 254 levels of partial transparency.
11858 The PNG library implements partial transparency by combining
11859 the image with a specified background color.
11860
11861 I'm not sure how to handle this here nicely: because the
11862 background on which the image is displayed may change, for
11863 real alpha channel support, it would be necessary to create
11864 a new image for each possible background.
11865
11866 What I'm doing now is that a mask is created if we have
11867 boolean transparency information. Otherwise I'm using
11868 the frame's background color to combine the image with. */
11869
11870 if (channels == 4)
11871 {
11872 if (mask_img)
11873 XPutPixel (mask_img, x, y, *p > 0);
11874 ++p;
11875 }
11876 }
11877 }
11878
a05e2bae
JR
11879 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11880 /* Set IMG's background color from the PNG image, unless the user
11881 overrode it. */
11882 {
11883 png_color_16 *bg;
11884 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11885 {
11886 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11887 img->background_valid = 1;
11888 }
11889 }
11890
6fc2811b
JR
11891 /* Remember colors allocated for this image. */
11892 img->colors = colors_in_color_table (&img->ncolors);
11893 free_color_table ();
11894
11895 /* Clean up. */
11896 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11897 xfree (rows);
11898 xfree (pixels);
11899
11900 img->width = width;
11901 img->height = height;
11902
a05e2bae
JR
11903 /* Maybe fill in the background field while we have ximg handy. */
11904 IMAGE_BACKGROUND (img, f, ximg);
11905
6fc2811b
JR
11906 /* Put the image into the pixmap, then free the X image and its buffer. */
11907 x_put_x_image (f, ximg, img->pixmap, width, height);
11908 x_destroy_x_image (ximg);
11909
11910 /* Same for the mask. */
11911 if (mask_img)
11912 {
a05e2bae
JR
11913 /* Fill in the background_transparent field while we have the mask
11914 handy. */
11915 image_background_transparent (img, f, mask_img);
11916
6fc2811b
JR
11917 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11918 x_destroy_x_image (mask_img);
11919 }
11920
6fc2811b
JR
11921 UNGCPRO;
11922 return 1;
11923}
11924
11925#endif /* HAVE_PNG != 0 */
11926
11927
11928\f
11929/***********************************************************************
11930 JPEG
11931 ***********************************************************************/
11932
11933#if HAVE_JPEG
11934
11935/* Work around a warning about HAVE_STDLIB_H being redefined in
11936 jconfig.h. */
11937#ifdef HAVE_STDLIB_H
11938#define HAVE_STDLIB_H_1
11939#undef HAVE_STDLIB_H
11940#endif /* HAVE_STLIB_H */
11941
11942#include <jpeglib.h>
11943#include <jerror.h>
11944#include <setjmp.h>
11945
11946#ifdef HAVE_STLIB_H_1
11947#define HAVE_STDLIB_H 1
11948#endif
11949
11950static int jpeg_image_p P_ ((Lisp_Object object));
11951static int jpeg_load P_ ((struct frame *f, struct image *img));
11952
11953/* The symbol `jpeg' identifying images of this type. */
11954
11955Lisp_Object Qjpeg;
11956
11957/* Indices of image specification fields in gs_format, below. */
11958
11959enum jpeg_keyword_index
11960{
11961 JPEG_TYPE,
11962 JPEG_DATA,
11963 JPEG_FILE,
11964 JPEG_ASCENT,
11965 JPEG_MARGIN,
11966 JPEG_RELIEF,
11967 JPEG_ALGORITHM,
11968 JPEG_HEURISTIC_MASK,
a05e2bae
JR
11969 JPEG_MASK,
11970 JPEG_BACKGROUND,
6fc2811b
JR
11971 JPEG_LAST
11972};
11973
11974/* Vector of image_keyword structures describing the format
11975 of valid user-defined image specifications. */
11976
11977static struct image_keyword jpeg_format[JPEG_LAST] =
11978{
11979 {":type", IMAGE_SYMBOL_VALUE, 1},
11980 {":data", IMAGE_STRING_VALUE, 0},
11981 {":file", IMAGE_STRING_VALUE, 0},
11982 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 11983 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 11984 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
11985 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11986 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11987 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11988 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
11989};
11990
11991/* Structure describing the image type `jpeg'. */
11992
11993static struct image_type jpeg_type =
11994{
11995 &Qjpeg,
11996 jpeg_image_p,
11997 jpeg_load,
11998 x_clear_image,
11999 NULL
12000};
12001
12002
12003/* Return non-zero if OBJECT is a valid JPEG image specification. */
12004
12005static int
12006jpeg_image_p (object)
12007 Lisp_Object object;
12008{
12009 struct image_keyword fmt[JPEG_LAST];
12010
12011 bcopy (jpeg_format, fmt, sizeof fmt);
12012
12013 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
12014 || (fmt[JPEG_ASCENT].count
12015 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
12016 return 0;
12017
12018 /* Must specify either the :data or :file keyword. */
12019 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
12020}
12021
12022
12023struct my_jpeg_error_mgr
12024{
12025 struct jpeg_error_mgr pub;
12026 jmp_buf setjmp_buffer;
12027};
12028
12029static void
12030my_error_exit (cinfo)
12031 j_common_ptr cinfo;
12032{
12033 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12034 longjmp (mgr->setjmp_buffer, 1);
12035}
12036
6fc2811b
JR
12037/* Init source method for JPEG data source manager. Called by
12038 jpeg_read_header() before any data is actually read. See
12039 libjpeg.doc from the JPEG lib distribution. */
12040
12041static void
12042our_init_source (cinfo)
12043 j_decompress_ptr cinfo;
12044{
12045}
12046
12047
12048/* Fill input buffer method for JPEG data source manager. Called
12049 whenever more data is needed. We read the whole image in one step,
12050 so this only adds a fake end of input marker at the end. */
12051
12052static boolean
12053our_fill_input_buffer (cinfo)
12054 j_decompress_ptr cinfo;
12055{
12056 /* Insert a fake EOI marker. */
12057 struct jpeg_source_mgr *src = cinfo->src;
12058 static JOCTET buffer[2];
12059
12060 buffer[0] = (JOCTET) 0xFF;
12061 buffer[1] = (JOCTET) JPEG_EOI;
12062
12063 src->next_input_byte = buffer;
12064 src->bytes_in_buffer = 2;
12065 return TRUE;
12066}
12067
12068
12069/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12070 is the JPEG data source manager. */
12071
12072static void
12073our_skip_input_data (cinfo, num_bytes)
12074 j_decompress_ptr cinfo;
12075 long num_bytes;
12076{
12077 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12078
12079 if (src)
12080 {
12081 if (num_bytes > src->bytes_in_buffer)
12082 ERREXIT (cinfo, JERR_INPUT_EOF);
12083
12084 src->bytes_in_buffer -= num_bytes;
12085 src->next_input_byte += num_bytes;
12086 }
12087}
12088
12089
12090/* Method to terminate data source. Called by
12091 jpeg_finish_decompress() after all data has been processed. */
12092
12093static void
12094our_term_source (cinfo)
12095 j_decompress_ptr cinfo;
12096{
12097}
12098
12099
12100/* Set up the JPEG lib for reading an image from DATA which contains
12101 LEN bytes. CINFO is the decompression info structure created for
12102 reading the image. */
12103
12104static void
12105jpeg_memory_src (cinfo, data, len)
12106 j_decompress_ptr cinfo;
12107 JOCTET *data;
12108 unsigned int len;
12109{
12110 struct jpeg_source_mgr *src;
12111
12112 if (cinfo->src == NULL)
12113 {
12114 /* First time for this JPEG object? */
12115 cinfo->src = (struct jpeg_source_mgr *)
12116 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12117 sizeof (struct jpeg_source_mgr));
12118 src = (struct jpeg_source_mgr *) cinfo->src;
12119 src->next_input_byte = data;
12120 }
12121
12122 src = (struct jpeg_source_mgr *) cinfo->src;
12123 src->init_source = our_init_source;
12124 src->fill_input_buffer = our_fill_input_buffer;
12125 src->skip_input_data = our_skip_input_data;
12126 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12127 src->term_source = our_term_source;
12128 src->bytes_in_buffer = len;
12129 src->next_input_byte = data;
12130}
12131
12132
12133/* Load image IMG for use on frame F. Patterned after example.c
12134 from the JPEG lib. */
12135
12136static int
12137jpeg_load (f, img)
12138 struct frame *f;
12139 struct image *img;
12140{
12141 struct jpeg_decompress_struct cinfo;
12142 struct my_jpeg_error_mgr mgr;
12143 Lisp_Object file, specified_file;
12144 Lisp_Object specified_data;
a05e2bae 12145 FILE * volatile fp = NULL;
6fc2811b
JR
12146 JSAMPARRAY buffer;
12147 int row_stride, x, y;
12148 XImage *ximg = NULL;
12149 int rc;
12150 unsigned long *colors;
12151 int width, height;
12152 struct gcpro gcpro1;
12153
12154 /* Open the JPEG file. */
12155 specified_file = image_spec_value (img->spec, QCfile, NULL);
12156 specified_data = image_spec_value (img->spec, QCdata, NULL);
12157 file = Qnil;
12158 GCPRO1 (file);
12159
6fc2811b
JR
12160 if (NILP (specified_data))
12161 {
12162 file = x_find_image_file (specified_file);
12163 if (!STRINGP (file))
12164 {
12165 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12166 UNGCPRO;
12167 return 0;
12168 }
12169
12170 fp = fopen (XSTRING (file)->data, "r");
12171 if (fp == NULL)
12172 {
12173 image_error ("Cannot open `%s'", file, Qnil);
12174 UNGCPRO;
12175 return 0;
12176 }
12177 }
12178
12179 /* Customize libjpeg's error handling to call my_error_exit when an
12180 error is detected. This function will perform a longjmp. */
6fc2811b 12181 cinfo.err = jpeg_std_error (&mgr.pub);
a05e2bae 12182 mgr.pub.error_exit = my_error_exit;
6fc2811b
JR
12183
12184 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12185 {
12186 if (rc == 1)
12187 {
12188 /* Called from my_error_exit. Display a JPEG error. */
12189 char buffer[JMSG_LENGTH_MAX];
12190 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12191 image_error ("Error reading JPEG image `%s': %s", img->spec,
12192 build_string (buffer));
12193 }
12194
12195 /* Close the input file and destroy the JPEG object. */
12196 if (fp)
12197 fclose (fp);
12198 jpeg_destroy_decompress (&cinfo);
6fc2811b
JR
12199
12200 /* If we already have an XImage, free that. */
12201 x_destroy_x_image (ximg);
12202
12203 /* Free pixmap and colors. */
12204 x_clear_image (f, img);
12205
6fc2811b
JR
12206 UNGCPRO;
12207 return 0;
12208 }
12209
12210 /* Create the JPEG decompression object. Let it read from fp.
12211 Read the JPEG image header. */
12212 jpeg_create_decompress (&cinfo);
12213
12214 if (NILP (specified_data))
12215 jpeg_stdio_src (&cinfo, fp);
12216 else
12217 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12218 STRING_BYTES (XSTRING (specified_data)));
12219
12220 jpeg_read_header (&cinfo, TRUE);
12221
12222 /* Customize decompression so that color quantization will be used.
12223 Start decompression. */
12224 cinfo.quantize_colors = TRUE;
12225 jpeg_start_decompress (&cinfo);
12226 width = img->width = cinfo.output_width;
12227 height = img->height = cinfo.output_height;
12228
6fc2811b
JR
12229 /* Create X image and pixmap. */
12230 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12231 &img->pixmap))
a05e2bae 12232 longjmp (mgr.setjmp_buffer, 2);
6fc2811b
JR
12233
12234 /* Allocate colors. When color quantization is used,
12235 cinfo.actual_number_of_colors has been set with the number of
12236 colors generated, and cinfo.colormap is a two-dimensional array
12237 of color indices in the range 0..cinfo.actual_number_of_colors.
12238 No more than 255 colors will be generated. */
12239 {
12240 int i, ir, ig, ib;
12241
12242 if (cinfo.out_color_components > 2)
12243 ir = 0, ig = 1, ib = 2;
12244 else if (cinfo.out_color_components > 1)
12245 ir = 0, ig = 1, ib = 0;
12246 else
12247 ir = 0, ig = 0, ib = 0;
12248
12249 /* Use the color table mechanism because it handles colors that
12250 cannot be allocated nicely. Such colors will be replaced with
12251 a default color, and we don't have to care about which colors
12252 can be freed safely, and which can't. */
12253 init_color_table ();
12254 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12255 * sizeof *colors);
12256
12257 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12258 {
12259 /* Multiply RGB values with 255 because X expects RGB values
12260 in the range 0..0xffff. */
12261 int r = cinfo.colormap[ir][i] << 8;
12262 int g = cinfo.colormap[ig][i] << 8;
12263 int b = cinfo.colormap[ib][i] << 8;
12264 colors[i] = lookup_rgb_color (f, r, g, b);
12265 }
12266
12267 /* Remember those colors actually allocated. */
12268 img->colors = colors_in_color_table (&img->ncolors);
12269 free_color_table ();
12270 }
12271
12272 /* Read pixels. */
12273 row_stride = width * cinfo.output_components;
12274 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12275 row_stride, 1);
12276 for (y = 0; y < height; ++y)
12277 {
12278 jpeg_read_scanlines (&cinfo, buffer, 1);
12279 for (x = 0; x < cinfo.output_width; ++x)
12280 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12281 }
12282
12283 /* Clean up. */
12284 jpeg_finish_decompress (&cinfo);
12285 jpeg_destroy_decompress (&cinfo);
12286 if (fp)
12287 fclose (fp);
12288
a05e2bae
JR
12289 /* Maybe fill in the background field while we have ximg handy. */
12290 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12291 IMAGE_BACKGROUND (img, f, ximg);
12292
6fc2811b
JR
12293 /* Put the image into the pixmap. */
12294 x_put_x_image (f, ximg, img->pixmap, width, height);
12295 x_destroy_x_image (ximg);
12296 UNBLOCK_INPUT;
12297 UNGCPRO;
12298 return 1;
12299}
12300
12301#endif /* HAVE_JPEG */
12302
12303
12304\f
12305/***********************************************************************
12306 TIFF
12307 ***********************************************************************/
12308
12309#if HAVE_TIFF
12310
12311#include <tiffio.h>
12312
12313static int tiff_image_p P_ ((Lisp_Object object));
12314static int tiff_load P_ ((struct frame *f, struct image *img));
12315
12316/* The symbol `tiff' identifying images of this type. */
12317
12318Lisp_Object Qtiff;
12319
12320/* Indices of image specification fields in tiff_format, below. */
12321
12322enum tiff_keyword_index
12323{
12324 TIFF_TYPE,
12325 TIFF_DATA,
12326 TIFF_FILE,
12327 TIFF_ASCENT,
12328 TIFF_MARGIN,
12329 TIFF_RELIEF,
12330 TIFF_ALGORITHM,
12331 TIFF_HEURISTIC_MASK,
a05e2bae
JR
12332 TIFF_MASK,
12333 TIFF_BACKGROUND,
6fc2811b
JR
12334 TIFF_LAST
12335};
12336
12337/* Vector of image_keyword structures describing the format
12338 of valid user-defined image specifications. */
12339
12340static struct image_keyword tiff_format[TIFF_LAST] =
12341{
12342 {":type", IMAGE_SYMBOL_VALUE, 1},
12343 {":data", IMAGE_STRING_VALUE, 0},
12344 {":file", IMAGE_STRING_VALUE, 0},
12345 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12346 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12347 {":relief", IMAGE_INTEGER_VALUE, 0},
a05e2bae
JR
12348 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12349 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12350 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12351 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12352};
12353
12354/* Structure describing the image type `tiff'. */
12355
12356static struct image_type tiff_type =
12357{
12358 &Qtiff,
12359 tiff_image_p,
12360 tiff_load,
12361 x_clear_image,
12362 NULL
12363};
12364
12365
12366/* Return non-zero if OBJECT is a valid TIFF image specification. */
12367
12368static int
12369tiff_image_p (object)
12370 Lisp_Object object;
12371{
12372 struct image_keyword fmt[TIFF_LAST];
12373 bcopy (tiff_format, fmt, sizeof fmt);
12374
12375 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12376 || (fmt[TIFF_ASCENT].count
12377 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12378 return 0;
12379
12380 /* Must specify either the :data or :file keyword. */
12381 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12382}
12383
12384
12385/* Reading from a memory buffer for TIFF images Based on the PNG
12386 memory source, but we have to provide a lot of extra functions.
12387 Blah.
12388
12389 We really only need to implement read and seek, but I am not
12390 convinced that the TIFF library is smart enough not to destroy
12391 itself if we only hand it the function pointers we need to
12392 override. */
12393
12394typedef struct
12395{
12396 unsigned char *bytes;
12397 size_t len;
12398 int index;
12399}
12400tiff_memory_source;
12401
12402static size_t
12403tiff_read_from_memory (data, buf, size)
12404 thandle_t data;
12405 tdata_t buf;
12406 tsize_t size;
12407{
12408 tiff_memory_source *src = (tiff_memory_source *) data;
12409
12410 if (size > src->len - src->index)
12411 return (size_t) -1;
12412 bcopy (src->bytes + src->index, buf, size);
12413 src->index += size;
12414 return size;
12415}
12416
12417static size_t
12418tiff_write_from_memory (data, buf, size)
12419 thandle_t data;
12420 tdata_t buf;
12421 tsize_t size;
12422{
12423 return (size_t) -1;
12424}
12425
12426static toff_t
12427tiff_seek_in_memory (data, off, whence)
12428 thandle_t data;
12429 toff_t off;
12430 int whence;
12431{
12432 tiff_memory_source *src = (tiff_memory_source *) data;
12433 int idx;
12434
12435 switch (whence)
12436 {
12437 case SEEK_SET: /* Go from beginning of source. */
12438 idx = off;
12439 break;
12440
12441 case SEEK_END: /* Go from end of source. */
12442 idx = src->len + off;
12443 break;
12444
12445 case SEEK_CUR: /* Go from current position. */
12446 idx = src->index + off;
12447 break;
12448
12449 default: /* Invalid `whence'. */
12450 return -1;
12451 }
12452
12453 if (idx > src->len || idx < 0)
12454 return -1;
12455
12456 src->index = idx;
12457 return src->index;
12458}
12459
12460static int
12461tiff_close_memory (data)
12462 thandle_t data;
12463{
12464 /* NOOP */
12465 return 0;
12466}
12467
12468static int
12469tiff_mmap_memory (data, pbase, psize)
12470 thandle_t data;
12471 tdata_t *pbase;
12472 toff_t *psize;
12473{
12474 /* It is already _IN_ memory. */
12475 return 0;
12476}
12477
12478static void
12479tiff_unmap_memory (data, base, size)
12480 thandle_t data;
12481 tdata_t base;
12482 toff_t size;
12483{
12484 /* We don't need to do this. */
12485}
12486
12487static toff_t
12488tiff_size_of_memory (data)
12489 thandle_t data;
12490{
12491 return ((tiff_memory_source *) data)->len;
12492}
12493
3cf3436e
JR
12494
12495static void
12496tiff_error_handler (title, format, ap)
12497 const char *title, *format;
12498 va_list ap;
12499{
12500 char buf[512];
12501 int len;
12502
12503 len = sprintf (buf, "TIFF error: %s ", title);
12504 vsprintf (buf + len, format, ap);
12505 add_to_log (buf, Qnil, Qnil);
12506}
12507
12508
12509static void
12510tiff_warning_handler (title, format, ap)
12511 const char *title, *format;
12512 va_list ap;
12513{
12514 char buf[512];
12515 int len;
12516
12517 len = sprintf (buf, "TIFF warning: %s ", title);
12518 vsprintf (buf + len, format, ap);
12519 add_to_log (buf, Qnil, Qnil);
12520}
12521
12522
6fc2811b
JR
12523/* Load TIFF image IMG for use on frame F. Value is non-zero if
12524 successful. */
12525
12526static int
12527tiff_load (f, img)
12528 struct frame *f;
12529 struct image *img;
12530{
12531 Lisp_Object file, specified_file;
12532 Lisp_Object specified_data;
12533 TIFF *tiff;
12534 int width, height, x, y;
12535 uint32 *buf;
12536 int rc;
12537 XImage *ximg;
12538 struct gcpro gcpro1;
12539 tiff_memory_source memsrc;
12540
12541 specified_file = image_spec_value (img->spec, QCfile, NULL);
12542 specified_data = image_spec_value (img->spec, QCdata, NULL);
12543 file = Qnil;
12544 GCPRO1 (file);
12545
3cf3436e
JR
12546 TIFFSetErrorHandler (tiff_error_handler);
12547 TIFFSetWarningHandler (tiff_warning_handler);
12548
6fc2811b
JR
12549 if (NILP (specified_data))
12550 {
12551 /* Read from a file */
12552 file = x_find_image_file (specified_file);
12553 if (!STRINGP (file))
3cf3436e
JR
12554 {
12555 image_error ("Cannot find image file `%s'", file, Qnil);
12556 UNGCPRO;
12557 return 0;
12558 }
12559
6fc2811b
JR
12560 /* Try to open the image file. */
12561 tiff = TIFFOpen (XSTRING (file)->data, "r");
12562 if (tiff == NULL)
3cf3436e
JR
12563 {
12564 image_error ("Cannot open `%s'", file, Qnil);
12565 UNGCPRO;
12566 return 0;
12567 }
6fc2811b
JR
12568 }
12569 else
12570 {
12571 /* Memory source! */
12572 memsrc.bytes = XSTRING (specified_data)->data;
12573 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12574 memsrc.index = 0;
12575
12576 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12577 (TIFFReadWriteProc) tiff_read_from_memory,
12578 (TIFFReadWriteProc) tiff_write_from_memory,
12579 tiff_seek_in_memory,
12580 tiff_close_memory,
12581 tiff_size_of_memory,
12582 tiff_mmap_memory,
12583 tiff_unmap_memory);
12584
12585 if (!tiff)
12586 {
12587 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12588 UNGCPRO;
12589 return 0;
12590 }
12591 }
12592
12593 /* Get width and height of the image, and allocate a raster buffer
12594 of width x height 32-bit values. */
12595 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12596 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12597 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12598
12599 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12600 TIFFClose (tiff);
12601 if (!rc)
12602 {
12603 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12604 xfree (buf);
12605 UNGCPRO;
12606 return 0;
12607 }
12608
6fc2811b
JR
12609 /* Create the X image and pixmap. */
12610 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12611 {
6fc2811b
JR
12612 xfree (buf);
12613 UNGCPRO;
12614 return 0;
12615 }
12616
12617 /* Initialize the color table. */
12618 init_color_table ();
12619
12620 /* Process the pixel raster. Origin is in the lower-left corner. */
12621 for (y = 0; y < height; ++y)
12622 {
12623 uint32 *row = buf + y * width;
12624
12625 for (x = 0; x < width; ++x)
12626 {
12627 uint32 abgr = row[x];
12628 int r = TIFFGetR (abgr) << 8;
12629 int g = TIFFGetG (abgr) << 8;
12630 int b = TIFFGetB (abgr) << 8;
12631 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12632 }
12633 }
12634
12635 /* Remember the colors allocated for the image. Free the color table. */
12636 img->colors = colors_in_color_table (&img->ncolors);
12637 free_color_table ();
12638
a05e2bae
JR
12639 img->width = width;
12640 img->height = height;
12641
12642 /* Maybe fill in the background field while we have ximg handy. */
12643 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12644 IMAGE_BACKGROUND (img, f, ximg);
12645
6fc2811b
JR
12646 /* Put the image into the pixmap, then free the X image and its buffer. */
12647 x_put_x_image (f, ximg, img->pixmap, width, height);
12648 x_destroy_x_image (ximg);
12649 xfree (buf);
6fc2811b
JR
12650
12651 UNGCPRO;
12652 return 1;
12653}
12654
12655#endif /* HAVE_TIFF != 0 */
12656
12657
12658\f
12659/***********************************************************************
12660 GIF
12661 ***********************************************************************/
12662
12663#if HAVE_GIF
12664
12665#include <gif_lib.h>
12666
12667static int gif_image_p P_ ((Lisp_Object object));
12668static int gif_load P_ ((struct frame *f, struct image *img));
12669
12670/* The symbol `gif' identifying images of this type. */
12671
12672Lisp_Object Qgif;
12673
12674/* Indices of image specification fields in gif_format, below. */
12675
12676enum gif_keyword_index
12677{
12678 GIF_TYPE,
12679 GIF_DATA,
12680 GIF_FILE,
12681 GIF_ASCENT,
12682 GIF_MARGIN,
12683 GIF_RELIEF,
12684 GIF_ALGORITHM,
12685 GIF_HEURISTIC_MASK,
a05e2bae 12686 GIF_MASK,
6fc2811b 12687 GIF_IMAGE,
a05e2bae 12688 GIF_BACKGROUND,
6fc2811b
JR
12689 GIF_LAST
12690};
12691
12692/* Vector of image_keyword structures describing the format
12693 of valid user-defined image specifications. */
12694
12695static struct image_keyword gif_format[GIF_LAST] =
12696{
12697 {":type", IMAGE_SYMBOL_VALUE, 1},
12698 {":data", IMAGE_STRING_VALUE, 0},
12699 {":file", IMAGE_STRING_VALUE, 0},
12700 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 12701 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 12702 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 12703 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6fc2811b 12704 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
12705 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12706 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12707 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
12708};
12709
12710/* Structure describing the image type `gif'. */
12711
12712static struct image_type gif_type =
12713{
12714 &Qgif,
12715 gif_image_p,
12716 gif_load,
12717 x_clear_image,
12718 NULL
12719};
12720
12721/* Return non-zero if OBJECT is a valid GIF image specification. */
12722
12723static int
12724gif_image_p (object)
12725 Lisp_Object object;
12726{
12727 struct image_keyword fmt[GIF_LAST];
12728 bcopy (gif_format, fmt, sizeof fmt);
12729
12730 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12731 || (fmt[GIF_ASCENT].count
12732 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12733 return 0;
12734
12735 /* Must specify either the :data or :file keyword. */
12736 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12737}
12738
12739/* Reading a GIF image from memory
12740 Based on the PNG memory stuff to a certain extent. */
12741
12742typedef struct
12743{
12744 unsigned char *bytes;
12745 size_t len;
12746 int index;
12747}
12748gif_memory_source;
12749
12750/* Make the current memory source available to gif_read_from_memory.
12751 It's done this way because not all versions of libungif support
12752 a UserData field in the GifFileType structure. */
12753static gif_memory_source *current_gif_memory_src;
12754
12755static int
12756gif_read_from_memory (file, buf, len)
12757 GifFileType *file;
12758 GifByteType *buf;
12759 int len;
12760{
12761 gif_memory_source *src = current_gif_memory_src;
12762
12763 if (len > src->len - src->index)
12764 return -1;
12765
12766 bcopy (src->bytes + src->index, buf, len);
12767 src->index += len;
12768 return len;
12769}
12770
12771
12772/* Load GIF image IMG for use on frame F. Value is non-zero if
12773 successful. */
12774
12775static int
12776gif_load (f, img)
12777 struct frame *f;
12778 struct image *img;
12779{
12780 Lisp_Object file, specified_file;
12781 Lisp_Object specified_data;
12782 int rc, width, height, x, y, i;
12783 XImage *ximg;
12784 ColorMapObject *gif_color_map;
12785 unsigned long pixel_colors[256];
12786 GifFileType *gif;
12787 struct gcpro gcpro1;
12788 Lisp_Object image;
12789 int ino, image_left, image_top, image_width, image_height;
12790 gif_memory_source memsrc;
12791 unsigned char *raster;
12792
12793 specified_file = image_spec_value (img->spec, QCfile, NULL);
12794 specified_data = image_spec_value (img->spec, QCdata, NULL);
12795 file = Qnil;
dfff8a69 12796 GCPRO1 (file);
6fc2811b
JR
12797
12798 if (NILP (specified_data))
12799 {
12800 file = x_find_image_file (specified_file);
6fc2811b
JR
12801 if (!STRINGP (file))
12802 {
12803 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12804 UNGCPRO;
12805 return 0;
12806 }
12807
12808 /* Open the GIF file. */
12809 gif = DGifOpenFileName (XSTRING (file)->data);
12810 if (gif == NULL)
12811 {
12812 image_error ("Cannot open `%s'", file, Qnil);
12813 UNGCPRO;
12814 return 0;
12815 }
12816 }
12817 else
12818 {
12819 /* Read from memory! */
12820 current_gif_memory_src = &memsrc;
12821 memsrc.bytes = XSTRING (specified_data)->data;
12822 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12823 memsrc.index = 0;
12824
12825 gif = DGifOpen(&memsrc, gif_read_from_memory);
12826 if (!gif)
12827 {
12828 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12829 UNGCPRO;
12830 return 0;
12831 }
12832 }
12833
12834 /* Read entire contents. */
12835 rc = DGifSlurp (gif);
12836 if (rc == GIF_ERROR)
12837 {
12838 image_error ("Error reading `%s'", img->spec, Qnil);
12839 DGifCloseFile (gif);
12840 UNGCPRO;
12841 return 0;
12842 }
12843
12844 image = image_spec_value (img->spec, QCindex, NULL);
12845 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12846 if (ino >= gif->ImageCount)
12847 {
12848 image_error ("Invalid image number `%s' in image `%s'",
12849 image, img->spec);
12850 DGifCloseFile (gif);
12851 UNGCPRO;
12852 return 0;
12853 }
12854
12855 width = img->width = gif->SWidth;
12856 height = img->height = gif->SHeight;
12857
6fc2811b
JR
12858 /* Create the X image and pixmap. */
12859 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12860 {
6fc2811b
JR
12861 DGifCloseFile (gif);
12862 UNGCPRO;
12863 return 0;
12864 }
12865
12866 /* Allocate colors. */
12867 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12868 if (!gif_color_map)
12869 gif_color_map = gif->SColorMap;
12870 init_color_table ();
12871 bzero (pixel_colors, sizeof pixel_colors);
12872
12873 for (i = 0; i < gif_color_map->ColorCount; ++i)
12874 {
12875 int r = gif_color_map->Colors[i].Red << 8;
12876 int g = gif_color_map->Colors[i].Green << 8;
12877 int b = gif_color_map->Colors[i].Blue << 8;
12878 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12879 }
12880
12881 img->colors = colors_in_color_table (&img->ncolors);
12882 free_color_table ();
12883
12884 /* Clear the part of the screen image that are not covered by
12885 the image from the GIF file. Full animated GIF support
12886 requires more than can be done here (see the gif89 spec,
12887 disposal methods). Let's simply assume that the part
12888 not covered by a sub-image is in the frame's background color. */
12889 image_top = gif->SavedImages[ino].ImageDesc.Top;
12890 image_left = gif->SavedImages[ino].ImageDesc.Left;
12891 image_width = gif->SavedImages[ino].ImageDesc.Width;
12892 image_height = gif->SavedImages[ino].ImageDesc.Height;
12893
12894 for (y = 0; y < image_top; ++y)
12895 for (x = 0; x < width; ++x)
12896 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12897
12898 for (y = image_top + image_height; y < height; ++y)
12899 for (x = 0; x < width; ++x)
12900 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12901
12902 for (y = image_top; y < image_top + image_height; ++y)
12903 {
12904 for (x = 0; x < image_left; ++x)
12905 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12906 for (x = image_left + image_width; x < width; ++x)
12907 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12908 }
12909
12910 /* Read the GIF image into the X image. We use a local variable
12911 `raster' here because RasterBits below is a char *, and invites
12912 problems with bytes >= 0x80. */
12913 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12914
12915 if (gif->SavedImages[ino].ImageDesc.Interlace)
12916 {
12917 static int interlace_start[] = {0, 4, 2, 1};
12918 static int interlace_increment[] = {8, 8, 4, 2};
a05e2bae 12919 int pass;
6fc2811b
JR
12920 int row = interlace_start[0];
12921
12922 pass = 0;
12923
12924 for (y = 0; y < image_height; y++)
12925 {
12926 if (row >= image_height)
12927 {
12928 row = interlace_start[++pass];
12929 while (row >= image_height)
12930 row = interlace_start[++pass];
12931 }
12932
12933 for (x = 0; x < image_width; x++)
12934 {
12935 int i = raster[(y * image_width) + x];
12936 XPutPixel (ximg, x + image_left, row + image_top,
12937 pixel_colors[i]);
12938 }
12939
12940 row += interlace_increment[pass];
12941 }
12942 }
12943 else
12944 {
12945 for (y = 0; y < image_height; ++y)
12946 for (x = 0; x < image_width; ++x)
12947 {
12948 int i = raster[y* image_width + x];
12949 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12950 }
12951 }
12952
12953 DGifCloseFile (gif);
a05e2bae
JR
12954
12955 /* Maybe fill in the background field while we have ximg handy. */
12956 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12957 IMAGE_BACKGROUND (img, f, ximg);
12958
6fc2811b
JR
12959 /* Put the image into the pixmap, then free the X image and its buffer. */
12960 x_put_x_image (f, ximg, img->pixmap, width, height);
12961 x_destroy_x_image (ximg);
6fc2811b
JR
12962
12963 UNGCPRO;
12964 return 1;
12965}
12966
12967#endif /* HAVE_GIF != 0 */
12968
12969
12970\f
12971/***********************************************************************
12972 Ghostscript
12973 ***********************************************************************/
12974
3cf3436e
JR
12975Lisp_Object Qpostscript;
12976
6fc2811b
JR
12977#ifdef HAVE_GHOSTSCRIPT
12978static int gs_image_p P_ ((Lisp_Object object));
12979static int gs_load P_ ((struct frame *f, struct image *img));
12980static void gs_clear_image P_ ((struct frame *f, struct image *img));
12981
12982/* The symbol `postscript' identifying images of this type. */
12983
6fc2811b
JR
12984/* Keyword symbols. */
12985
12986Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12987
12988/* Indices of image specification fields in gs_format, below. */
12989
12990enum gs_keyword_index
12991{
12992 GS_TYPE,
12993 GS_PT_WIDTH,
12994 GS_PT_HEIGHT,
12995 GS_FILE,
12996 GS_LOADER,
12997 GS_BOUNDING_BOX,
12998 GS_ASCENT,
12999 GS_MARGIN,
13000 GS_RELIEF,
13001 GS_ALGORITHM,
13002 GS_HEURISTIC_MASK,
a05e2bae
JR
13003 GS_MASK,
13004 GS_BACKGROUND,
6fc2811b
JR
13005 GS_LAST
13006};
13007
13008/* Vector of image_keyword structures describing the format
13009 of valid user-defined image specifications. */
13010
13011static struct image_keyword gs_format[GS_LAST] =
13012{
13013 {":type", IMAGE_SYMBOL_VALUE, 1},
13014 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13015 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13016 {":file", IMAGE_STRING_VALUE, 1},
13017 {":loader", IMAGE_FUNCTION_VALUE, 0},
13018 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
13019 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8edb0a6f 13020 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6fc2811b 13021 {":relief", IMAGE_INTEGER_VALUE, 0},
a93f4566 13022 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
a05e2bae
JR
13023 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13024 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13025 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
6fc2811b
JR
13026};
13027
13028/* Structure describing the image type `ghostscript'. */
13029
13030static struct image_type gs_type =
13031{
13032 &Qpostscript,
13033 gs_image_p,
13034 gs_load,
13035 gs_clear_image,
13036 NULL
13037};
13038
13039
13040/* Free X resources of Ghostscript image IMG which is used on frame F. */
13041
13042static void
13043gs_clear_image (f, img)
13044 struct frame *f;
13045 struct image *img;
13046{
13047 /* IMG->data.ptr_val may contain a recorded colormap. */
13048 xfree (img->data.ptr_val);
13049 x_clear_image (f, img);
13050}
13051
13052
13053/* Return non-zero if OBJECT is a valid Ghostscript image
13054 specification. */
13055
13056static int
13057gs_image_p (object)
13058 Lisp_Object object;
13059{
13060 struct image_keyword fmt[GS_LAST];
13061 Lisp_Object tem;
13062 int i;
13063
13064 bcopy (gs_format, fmt, sizeof fmt);
13065
13066 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
13067 || (fmt[GS_ASCENT].count
13068 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13069 return 0;
13070
13071 /* Bounding box must be a list or vector containing 4 integers. */
13072 tem = fmt[GS_BOUNDING_BOX].value;
13073 if (CONSP (tem))
13074 {
13075 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13076 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13077 return 0;
13078 if (!NILP (tem))
13079 return 0;
13080 }
13081 else if (VECTORP (tem))
13082 {
13083 if (XVECTOR (tem)->size != 4)
13084 return 0;
13085 for (i = 0; i < 4; ++i)
13086 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13087 return 0;
13088 }
13089 else
13090 return 0;
13091
13092 return 1;
13093}
13094
13095
13096/* Load Ghostscript image IMG for use on frame F. Value is non-zero
13097 if successful. */
13098
13099static int
13100gs_load (f, img)
13101 struct frame *f;
13102 struct image *img;
13103{
13104 char buffer[100];
13105 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13106 struct gcpro gcpro1, gcpro2;
13107 Lisp_Object frame;
13108 double in_width, in_height;
13109 Lisp_Object pixel_colors = Qnil;
13110
13111 /* Compute pixel size of pixmap needed from the given size in the
13112 image specification. Sizes in the specification are in pt. 1 pt
13113 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13114 info. */
13115 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13116 in_width = XFASTINT (pt_width) / 72.0;
13117 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13118 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13119 in_height = XFASTINT (pt_height) / 72.0;
13120 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13121
13122 /* Create the pixmap. */
13123 BLOCK_INPUT;
13124 xassert (img->pixmap == 0);
13125 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13126 img->width, img->height,
a05e2bae 13127 one_w32_display_info.n_cbits);
6fc2811b
JR
13128 UNBLOCK_INPUT;
13129
13130 if (!img->pixmap)
13131 {
13132 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13133 return 0;
13134 }
13135
13136 /* Call the loader to fill the pixmap. It returns a process object
13137 if successful. We do not record_unwind_protect here because
13138 other places in redisplay like calling window scroll functions
13139 don't either. Let the Lisp loader use `unwind-protect' instead. */
13140 GCPRO2 (window_and_pixmap_id, pixel_colors);
13141
13142 sprintf (buffer, "%lu %lu",
13143 (unsigned long) FRAME_W32_WINDOW (f),
13144 (unsigned long) img->pixmap);
13145 window_and_pixmap_id = build_string (buffer);
13146
13147 sprintf (buffer, "%lu %lu",
13148 FRAME_FOREGROUND_PIXEL (f),
13149 FRAME_BACKGROUND_PIXEL (f));
13150 pixel_colors = build_string (buffer);
13151
13152 XSETFRAME (frame, f);
13153 loader = image_spec_value (img->spec, QCloader, NULL);
13154 if (NILP (loader))
13155 loader = intern ("gs-load-image");
13156
13157 img->data.lisp_val = call6 (loader, frame, img->spec,
13158 make_number (img->width),
13159 make_number (img->height),
13160 window_and_pixmap_id,
13161 pixel_colors);
13162 UNGCPRO;
13163 return PROCESSP (img->data.lisp_val);
13164}
13165
13166
13167/* Kill the Ghostscript process that was started to fill PIXMAP on
13168 frame F. Called from XTread_socket when receiving an event
13169 telling Emacs that Ghostscript has finished drawing. */
13170
13171void
13172x_kill_gs_process (pixmap, f)
13173 Pixmap pixmap;
13174 struct frame *f;
13175{
13176 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13177 int class, i;
13178 struct image *img;
13179
13180 /* Find the image containing PIXMAP. */
13181 for (i = 0; i < c->used; ++i)
13182 if (c->images[i]->pixmap == pixmap)
13183 break;
13184
3cf3436e
JR
13185 /* Should someone in between have cleared the image cache, for
13186 instance, give up. */
13187 if (i == c->used)
13188 return;
13189
6fc2811b
JR
13190 /* Kill the GS process. We should have found PIXMAP in the image
13191 cache and its image should contain a process object. */
6fc2811b
JR
13192 img = c->images[i];
13193 xassert (PROCESSP (img->data.lisp_val));
13194 Fkill_process (img->data.lisp_val, Qnil);
13195 img->data.lisp_val = Qnil;
13196
13197 /* On displays with a mutable colormap, figure out the colors
13198 allocated for the image by looking at the pixels of an XImage for
13199 img->pixmap. */
13200 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13201 if (class != StaticColor && class != StaticGray && class != TrueColor)
13202 {
13203 XImage *ximg;
13204
13205 BLOCK_INPUT;
13206
13207 /* Try to get an XImage for img->pixmep. */
13208 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13209 0, 0, img->width, img->height, ~0, ZPixmap);
13210 if (ximg)
13211 {
13212 int x, y;
13213
13214 /* Initialize the color table. */
13215 init_color_table ();
13216
13217 /* For each pixel of the image, look its color up in the
13218 color table. After having done so, the color table will
13219 contain an entry for each color used by the image. */
13220 for (y = 0; y < img->height; ++y)
13221 for (x = 0; x < img->width; ++x)
13222 {
13223 unsigned long pixel = XGetPixel (ximg, x, y);
13224 lookup_pixel_color (f, pixel);
13225 }
13226
13227 /* Record colors in the image. Free color table and XImage. */
13228 img->colors = colors_in_color_table (&img->ncolors);
13229 free_color_table ();
13230 XDestroyImage (ximg);
13231
13232#if 0 /* This doesn't seem to be the case. If we free the colors
13233 here, we get a BadAccess later in x_clear_image when
13234 freeing the colors. */
13235 /* We have allocated colors once, but Ghostscript has also
13236 allocated colors on behalf of us. So, to get the
13237 reference counts right, free them once. */
13238 if (img->ncolors)
3cf3436e 13239 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
6fc2811b 13240 img->colors, img->ncolors, 0);
6fc2811b
JR
13241#endif
13242 }
13243 else
13244 image_error ("Cannot get X image of `%s'; colors will not be freed",
13245 img->spec, Qnil);
13246
13247 UNBLOCK_INPUT;
13248 }
3cf3436e
JR
13249
13250 /* Now that we have the pixmap, compute mask and transform the
13251 image if requested. */
13252 BLOCK_INPUT;
13253 postprocess_image (f, img);
13254 UNBLOCK_INPUT;
6fc2811b
JR
13255}
13256
13257#endif /* HAVE_GHOSTSCRIPT */
13258
13259\f
13260/***********************************************************************
13261 Window properties
13262 ***********************************************************************/
13263
13264DEFUN ("x-change-window-property", Fx_change_window_property,
13265 Sx_change_window_property, 2, 3, 0,
74e1aeec
JR
13266 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13267PROP and VALUE must be strings. FRAME nil or omitted means use the
13268selected frame. Value is VALUE. */)
6fc2811b
JR
13269 (prop, value, frame)
13270 Lisp_Object frame, prop, value;
13271{
767b1ff0 13272#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13273 struct frame *f = check_x_frame (frame);
13274 Atom prop_atom;
13275
b7826503
PJ
13276 CHECK_STRING (prop);
13277 CHECK_STRING (value);
6fc2811b
JR
13278
13279 BLOCK_INPUT;
13280 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13281 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13282 prop_atom, XA_STRING, 8, PropModeReplace,
13283 XSTRING (value)->data, XSTRING (value)->size);
13284
13285 /* Make sure the property is set when we return. */
13286 XFlush (FRAME_W32_DISPLAY (f));
13287 UNBLOCK_INPUT;
13288
767b1ff0 13289#endif /* TODO */
6fc2811b
JR
13290
13291 return value;
13292}
13293
13294
13295DEFUN ("x-delete-window-property", Fx_delete_window_property,
13296 Sx_delete_window_property, 1, 2, 0,
74e1aeec
JR
13297 doc: /* Remove window property PROP from X window of FRAME.
13298FRAME nil or omitted means use the selected frame. Value is PROP. */)
6fc2811b
JR
13299 (prop, frame)
13300 Lisp_Object prop, frame;
13301{
767b1ff0 13302#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13303
13304 struct frame *f = check_x_frame (frame);
13305 Atom prop_atom;
13306
b7826503 13307 CHECK_STRING (prop);
6fc2811b
JR
13308 BLOCK_INPUT;
13309 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13310 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13311
13312 /* Make sure the property is removed when we return. */
13313 XFlush (FRAME_W32_DISPLAY (f));
13314 UNBLOCK_INPUT;
767b1ff0 13315#endif /* TODO */
6fc2811b
JR
13316
13317 return prop;
13318}
13319
13320
13321DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13322 1, 2, 0,
74e1aeec
JR
13323 doc: /* Value is the value of window property PROP on FRAME.
13324If FRAME is nil or omitted, use the selected frame. Value is nil
13325if FRAME hasn't a property with name PROP or if PROP has no string
13326value. */)
6fc2811b
JR
13327 (prop, frame)
13328 Lisp_Object prop, frame;
13329{
767b1ff0 13330#if 0 /* TODO : port window properties to W32 */
6fc2811b
JR
13331
13332 struct frame *f = check_x_frame (frame);
13333 Atom prop_atom;
13334 int rc;
13335 Lisp_Object prop_value = Qnil;
13336 char *tmp_data = NULL;
13337 Atom actual_type;
13338 int actual_format;
13339 unsigned long actual_size, bytes_remaining;
13340
b7826503 13341 CHECK_STRING (prop);
6fc2811b
JR
13342 BLOCK_INPUT;
13343 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13344 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13345 prop_atom, 0, 0, False, XA_STRING,
13346 &actual_type, &actual_format, &actual_size,
13347 &bytes_remaining, (unsigned char **) &tmp_data);
13348 if (rc == Success)
13349 {
13350 int size = bytes_remaining;
13351
13352 XFree (tmp_data);
13353 tmp_data = NULL;
13354
13355 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13356 prop_atom, 0, bytes_remaining,
13357 False, XA_STRING,
13358 &actual_type, &actual_format,
13359 &actual_size, &bytes_remaining,
13360 (unsigned char **) &tmp_data);
13361 if (rc == Success)
13362 prop_value = make_string (tmp_data, size);
13363
13364 XFree (tmp_data);
13365 }
13366
13367 UNBLOCK_INPUT;
13368
13369 return prop_value;
13370
767b1ff0 13371#endif /* TODO */
6fc2811b
JR
13372 return Qnil;
13373}
13374
13375
13376\f
13377/***********************************************************************
13378 Busy cursor
13379 ***********************************************************************/
13380
f79e6790 13381/* If non-null, an asynchronous timer that, when it expires, displays
0af913d7 13382 an hourglass cursor on all frames. */
6fc2811b 13383
0af913d7 13384static struct atimer *hourglass_atimer;
6fc2811b 13385
0af913d7 13386/* Non-zero means an hourglass cursor is currently shown. */
6fc2811b 13387
0af913d7 13388static int hourglass_shown_p;
6fc2811b 13389
0af913d7 13390/* Number of seconds to wait before displaying an hourglass cursor. */
6fc2811b 13391
0af913d7 13392static Lisp_Object Vhourglass_delay;
6fc2811b 13393
0af913d7 13394/* Default number of seconds to wait before displaying an hourglass
f79e6790
JR
13395 cursor. */
13396
0af913d7 13397#define DEFAULT_HOURGLASS_DELAY 1
f79e6790
JR
13398
13399/* Function prototypes. */
13400
0af913d7
GM
13401static void show_hourglass P_ ((struct atimer *));
13402static void hide_hourglass P_ ((void));
f79e6790
JR
13403
13404
0af913d7 13405/* Cancel a currently active hourglass timer, and start a new one. */
f79e6790
JR
13406
13407void
0af913d7 13408start_hourglass ()
f79e6790 13409{
767b1ff0 13410#if 0 /* TODO: cursor shape changes. */
f79e6790 13411 EMACS_TIME delay;
dfff8a69 13412 int secs, usecs = 0;
f79e6790 13413
0af913d7 13414 cancel_hourglass ();
f79e6790 13415
0af913d7
GM
13416 if (INTEGERP (Vhourglass_delay)
13417 && XINT (Vhourglass_delay) > 0)
13418 secs = XFASTINT (Vhourglass_delay);
13419 else if (FLOATP (Vhourglass_delay)
13420 && XFLOAT_DATA (Vhourglass_delay) > 0)
dfff8a69
JR
13421 {
13422 Lisp_Object tem;
0af913d7 13423 tem = Ftruncate (Vhourglass_delay, Qnil);
dfff8a69 13424 secs = XFASTINT (tem);
0af913d7 13425 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
dfff8a69 13426 }
f79e6790 13427 else
0af913d7 13428 secs = DEFAULT_HOURGLASS_DELAY;
f79e6790 13429
dfff8a69 13430 EMACS_SET_SECS_USECS (delay, secs, usecs);
0af913d7
GM
13431 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13432 show_hourglass, NULL);
f79e6790
JR
13433#endif
13434}
13435
13436
0af913d7
GM
13437/* Cancel the hourglass cursor timer if active, hide an hourglass
13438 cursor if shown. */
f79e6790
JR
13439
13440void
0af913d7 13441cancel_hourglass ()
f79e6790 13442{
0af913d7 13443 if (hourglass_atimer)
dfff8a69 13444 {
0af913d7
GM
13445 cancel_atimer (hourglass_atimer);
13446 hourglass_atimer = NULL;
dfff8a69
JR
13447 }
13448
0af913d7
GM
13449 if (hourglass_shown_p)
13450 hide_hourglass ();
f79e6790
JR
13451}
13452
13453
0af913d7
GM
13454/* Timer function of hourglass_atimer. TIMER is equal to
13455 hourglass_atimer.
f79e6790 13456
0af913d7
GM
13457 Display an hourglass cursor on all frames by mapping the frames'
13458 hourglass_window. Set the hourglass_p flag in the frames'
13459 output_data.x structure to indicate that an hourglass cursor is
13460 shown on the frames. */
f79e6790
JR
13461
13462static void
0af913d7 13463show_hourglass (timer)
f79e6790 13464 struct atimer *timer;
6fc2811b 13465{
767b1ff0 13466#if 0 /* TODO: cursor shape changes. */
f79e6790 13467 /* The timer implementation will cancel this timer automatically
0af913d7 13468 after this function has run. Set hourglass_atimer to null
f79e6790 13469 so that we know the timer doesn't have to be canceled. */
0af913d7 13470 hourglass_atimer = NULL;
f79e6790 13471
0af913d7 13472 if (!hourglass_shown_p)
6fc2811b
JR
13473 {
13474 Lisp_Object rest, frame;
f79e6790
JR
13475
13476 BLOCK_INPUT;
13477
6fc2811b 13478 FOR_EACH_FRAME (rest, frame)
dc220243 13479 if (FRAME_W32_P (XFRAME (frame)))
6fc2811b
JR
13480 {
13481 struct frame *f = XFRAME (frame);
f79e6790 13482
0af913d7 13483 f->output_data.w32->hourglass_p = 1;
f79e6790 13484
0af913d7 13485 if (!f->output_data.w32->hourglass_window)
6fc2811b
JR
13486 {
13487 unsigned long mask = CWCursor;
13488 XSetWindowAttributes attrs;
f79e6790 13489
0af913d7 13490 attrs.cursor = f->output_data.w32->hourglass_cursor;
f79e6790 13491
0af913d7 13492 f->output_data.w32->hourglass_window
f79e6790 13493 = XCreateWindow (FRAME_X_DISPLAY (f),
6fc2811b
JR
13494 FRAME_OUTER_WINDOW (f),
13495 0, 0, 32000, 32000, 0, 0,
f79e6790
JR
13496 InputOnly,
13497 CopyFromParent,
6fc2811b
JR
13498 mask, &attrs);
13499 }
f79e6790 13500
0af913d7
GM
13501 XMapRaised (FRAME_X_DISPLAY (f),
13502 f->output_data.w32->hourglass_window);
f79e6790 13503 XFlush (FRAME_X_DISPLAY (f));
6fc2811b 13504 }
6fc2811b 13505
0af913d7 13506 hourglass_shown_p = 1;
f79e6790
JR
13507 UNBLOCK_INPUT;
13508 }
13509#endif
6fc2811b
JR
13510}
13511
13512
0af913d7 13513/* Hide the hourglass cursor on all frames, if it is currently shown. */
6fc2811b 13514
f79e6790 13515static void
0af913d7 13516hide_hourglass ()
f79e6790 13517{
767b1ff0 13518#if 0 /* TODO: cursor shape changes. */
0af913d7 13519 if (hourglass_shown_p)
6fc2811b 13520 {
f79e6790
JR
13521 Lisp_Object rest, frame;
13522
13523 BLOCK_INPUT;
13524 FOR_EACH_FRAME (rest, frame)
6fc2811b 13525 {
f79e6790
JR
13526 struct frame *f = XFRAME (frame);
13527
dc220243 13528 if (FRAME_W32_P (f)
f79e6790 13529 /* Watch out for newly created frames. */
0af913d7 13530 && f->output_data.x->hourglass_window)
f79e6790 13531 {
0af913d7
GM
13532 XUnmapWindow (FRAME_X_DISPLAY (f),
13533 f->output_data.x->hourglass_window);
13534 /* Sync here because XTread_socket looks at the
13535 hourglass_p flag that is reset to zero below. */
f79e6790 13536 XSync (FRAME_X_DISPLAY (f), False);
0af913d7 13537 f->output_data.x->hourglass_p = 0;
f79e6790 13538 }
6fc2811b 13539 }
6fc2811b 13540
0af913d7 13541 hourglass_shown_p = 0;
f79e6790
JR
13542 UNBLOCK_INPUT;
13543 }
13544#endif
6fc2811b
JR
13545}
13546
13547
13548\f
13549/***********************************************************************
13550 Tool tips
13551 ***********************************************************************/
13552
13553static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
3cf3436e
JR
13554 Lisp_Object, Lisp_Object));
13555static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13556 Lisp_Object, int, int, int *, int *));
6fc2811b 13557
3cf3436e 13558/* The frame of a currently visible tooltip. */
6fc2811b 13559
937e601e 13560Lisp_Object tip_frame;
6fc2811b
JR
13561
13562/* If non-nil, a timer started that hides the last tooltip when it
13563 fires. */
13564
13565Lisp_Object tip_timer;
13566Window tip_window;
13567
3cf3436e
JR
13568/* If non-nil, a vector of 3 elements containing the last args
13569 with which x-show-tip was called. See there. */
13570
13571Lisp_Object last_show_tip_args;
13572
13573/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13574
13575Lisp_Object Vx_max_tooltip_size;
13576
13577
937e601e
AI
13578static Lisp_Object
13579unwind_create_tip_frame (frame)
13580 Lisp_Object frame;
13581{
c844a81a
GM
13582 Lisp_Object deleted;
13583
13584 deleted = unwind_create_frame (frame);
13585 if (EQ (deleted, Qt))
13586 {
13587 tip_window = NULL;
13588 tip_frame = Qnil;
13589 }
13590
13591 return deleted;
937e601e
AI
13592}
13593
13594
6fc2811b 13595/* Create a frame for a tooltip on the display described by DPYINFO.
3cf3436e
JR
13596 PARMS is a list of frame parameters. TEXT is the string to
13597 display in the tip frame. Value is the frame.
937e601e
AI
13598
13599 Note that functions called here, esp. x_default_parameter can
13600 signal errors, for instance when a specified color name is
13601 undefined. We have to make sure that we're in a consistent state
13602 when this happens. */
6fc2811b
JR
13603
13604static Lisp_Object
3cf3436e 13605x_create_tip_frame (dpyinfo, parms, text)
6fc2811b 13606 struct w32_display_info *dpyinfo;
3cf3436e 13607 Lisp_Object parms, text;
6fc2811b 13608{
6fc2811b
JR
13609 struct frame *f;
13610 Lisp_Object frame, tem;
13611 Lisp_Object name;
13612 long window_prompting = 0;
13613 int width, height;
dc220243 13614 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13615 struct gcpro gcpro1, gcpro2, gcpro3;
13616 struct kboard *kb;
3cf3436e
JR
13617 int face_change_count_before = face_change_count;
13618 Lisp_Object buffer;
13619 struct buffer *old_buffer;
6fc2811b 13620
ca56d953 13621 check_w32 ();
6fc2811b
JR
13622
13623 /* Use this general default value to start with until we know if
13624 this frame has a specified name. */
13625 Vx_resource_name = Vinvocation_name;
13626
13627#ifdef MULTI_KBOARD
13628 kb = dpyinfo->kboard;
13629#else
13630 kb = &the_only_kboard;
13631#endif
13632
13633 /* Get the name of the frame to use for resource lookup. */
13634 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13635 if (!STRINGP (name)
13636 && !EQ (name, Qunbound)
13637 && !NILP (name))
13638 error ("Invalid frame name--not a string or nil");
13639 Vx_resource_name = name;
13640
13641 frame = Qnil;
13642 GCPRO3 (parms, name, frame);
9eb16b62
JR
13643 /* Make a frame without minibuffer nor mode-line. */
13644 f = make_frame (0);
13645 f->wants_modeline = 0;
6fc2811b 13646 XSETFRAME (frame, f);
3cf3436e
JR
13647
13648 buffer = Fget_buffer_create (build_string (" *tip*"));
13649 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13650 old_buffer = current_buffer;
13651 set_buffer_internal_1 (XBUFFER (buffer));
13652 current_buffer->truncate_lines = Qnil;
13653 Ferase_buffer ();
13654 Finsert (1, &text);
13655 set_buffer_internal_1 (old_buffer);
13656
6fc2811b 13657 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
937e601e 13658 record_unwind_protect (unwind_create_tip_frame, frame);
6fc2811b 13659
3cf3436e
JR
13660 /* By setting the output method, we're essentially saying that
13661 the frame is live, as per FRAME_LIVE_P. If we get a signal
13662 from this point on, x_destroy_window might screw up reference
13663 counts etc. */
d88c567c 13664 f->output_method = output_w32;
6fc2811b
JR
13665 f->output_data.w32 =
13666 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13667 bzero (f->output_data.w32, sizeof (struct w32_output));
ca56d953
JR
13668
13669 FRAME_FONTSET (f) = -1;
6fc2811b
JR
13670 f->icon_name = Qnil;
13671
ca56d953 13672#if 0 /* GLYPH_DEBUG TODO: image support. */
937e601e
AI
13673 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13674 dpyinfo_refcount = dpyinfo->reference_count;
13675#endif /* GLYPH_DEBUG */
6fc2811b
JR
13676#ifdef MULTI_KBOARD
13677 FRAME_KBOARD (f) = kb;
13678#endif
13679 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13680 f->output_data.w32->explicit_parent = 0;
13681
13682 /* Set the name; the functions to which we pass f expect the name to
13683 be set. */
13684 if (EQ (name, Qunbound) || NILP (name))
13685 {
ca56d953 13686 f->name = build_string (dpyinfo->w32_id_name);
6fc2811b
JR
13687 f->explicit_name = 0;
13688 }
13689 else
13690 {
13691 f->name = name;
13692 f->explicit_name = 1;
13693 /* use the frame's title when getting resources for this frame. */
13694 specbind (Qx_resource_name, name);
13695 }
13696
6fc2811b
JR
13697 /* Extract the window parameters from the supplied values
13698 that are needed to determine window geometry. */
13699 {
13700 Lisp_Object font;
13701
13702 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13703
13704 BLOCK_INPUT;
13705 /* First, try whatever font the caller has specified. */
13706 if (STRINGP (font))
13707 {
13708 tem = Fquery_fontset (font, Qnil);
13709 if (STRINGP (tem))
13710 font = x_new_fontset (f, XSTRING (tem)->data);
13711 else
13712 font = x_new_font (f, XSTRING (font)->data);
13713 }
13714
13715 /* Try out a font which we hope has bold and italic variations. */
13716 if (!STRINGP (font))
ca56d953 13717 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
6fc2811b 13718 if (! STRINGP (font))
ca56d953 13719 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13720 /* If those didn't work, look for something which will at least work. */
13721 if (! STRINGP (font))
ca56d953 13722 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
6fc2811b
JR
13723 UNBLOCK_INPUT;
13724 if (! STRINGP (font))
ca56d953 13725 font = build_string ("Fixedsys");
6fc2811b
JR
13726
13727 x_default_parameter (f, parms, Qfont, font,
13728 "font", "Font", RES_TYPE_STRING);
13729 }
13730
13731 x_default_parameter (f, parms, Qborder_width, make_number (2),
13732 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
6fc2811b
JR
13733 /* This defaults to 2 in order to match xterm. We recognize either
13734 internalBorderWidth or internalBorder (which is what xterm calls
13735 it). */
13736 if (NILP (Fassq (Qinternal_border_width, parms)))
13737 {
13738 Lisp_Object value;
13739
13740 value = w32_get_arg (parms, Qinternal_border_width,
13741 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13742 if (! EQ (value, Qunbound))
13743 parms = Fcons (Fcons (Qinternal_border_width, value),
13744 parms);
13745 }
bfd6edcc 13746 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
6fc2811b
JR
13747 "internalBorderWidth", "internalBorderWidth",
13748 RES_TYPE_NUMBER);
13749
13750 /* Also do the stuff which must be set before the window exists. */
13751 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13752 "foreground", "Foreground", RES_TYPE_STRING);
13753 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13754 "background", "Background", RES_TYPE_STRING);
13755 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13756 "pointerColor", "Foreground", RES_TYPE_STRING);
13757 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13758 "cursorColor", "Foreground", RES_TYPE_STRING);
13759 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13760 "borderColor", "BorderColor", RES_TYPE_STRING);
13761
13762 /* Init faces before x_default_parameter is called for scroll-bar
13763 parameters because that function calls x_set_scroll_bar_width,
13764 which calls change_frame_size, which calls Fset_window_buffer,
13765 which runs hooks, which call Fvertical_motion. At the end, we
13766 end up in init_iterator with a null face cache, which should not
13767 happen. */
13768 init_frame_faces (f);
ca56d953
JR
13769
13770 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
6fc2811b 13771 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9eb16b62 13772
6fc2811b
JR
13773 window_prompting = x_figure_window_size (f, parms);
13774
9eb16b62
JR
13775 /* No fringes on tip frame. */
13776 f->output_data.w32->fringes_extra = 0;
13777 f->output_data.w32->fringe_cols = 0;
13778 f->output_data.w32->left_fringe_width = 0;
13779 f->output_data.w32->right_fringe_width = 0;
13780
6fc2811b
JR
13781 if (window_prompting & XNegative)
13782 {
13783 if (window_prompting & YNegative)
13784 f->output_data.w32->win_gravity = SouthEastGravity;
13785 else
13786 f->output_data.w32->win_gravity = NorthEastGravity;
13787 }
13788 else
13789 {
13790 if (window_prompting & YNegative)
13791 f->output_data.w32->win_gravity = SouthWestGravity;
13792 else
13793 f->output_data.w32->win_gravity = NorthWestGravity;
13794 }
13795
13796 f->output_data.w32->size_hint_flags = window_prompting;
ca56d953
JR
13797
13798 BLOCK_INPUT;
13799 my_create_tip_window (f);
13800 UNBLOCK_INPUT;
6fc2811b
JR
13801
13802 x_make_gc (f);
13803
13804 x_default_parameter (f, parms, Qauto_raise, Qnil,
13805 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13806 x_default_parameter (f, parms, Qauto_lower, Qnil,
13807 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13808 x_default_parameter (f, parms, Qcursor_type, Qbox,
13809 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13810
13811 /* Dimensions, especially f->height, must be done via change_frame_size.
13812 Change will not be effected unless different from the current
13813 f->height. */
13814 width = f->width;
13815 height = f->height;
13816 f->height = 0;
13817 SET_FRAME_WIDTH (f, 0);
13818 change_frame_size (f, height, width, 1, 0, 0);
13819
3cf3436e
JR
13820 /* Set up faces after all frame parameters are known. This call
13821 also merges in face attributes specified for new frames.
13822
13823 Frame parameters may be changed if .Xdefaults contains
13824 specifications for the default font. For example, if there is an
13825 `Emacs.default.attributeBackground: pink', the `background-color'
13826 attribute of the frame get's set, which let's the internal border
13827 of the tooltip frame appear in pink. Prevent this. */
13828 {
13829 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13830
13831 /* Set tip_frame here, so that */
13832 tip_frame = frame;
13833 call1 (Qface_set_after_frame_default, frame);
13834
13835 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13836 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13837 Qnil));
13838 }
13839
6fc2811b
JR
13840 f->no_split = 1;
13841
13842 UNGCPRO;
13843
13844 /* It is now ok to make the frame official even if we get an error
13845 below. And the frame needs to be on Vframe_list or making it
13846 visible won't work. */
13847 Vframe_list = Fcons (frame, Vframe_list);
13848
13849 /* Now that the frame is official, it counts as a reference to
13850 its display. */
13851 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32 13852
3cf3436e
JR
13853 /* Setting attributes of faces of the tooltip frame from resources
13854 and similar will increment face_change_count, which leads to the
13855 clearing of all current matrices. Since this isn't necessary
13856 here, avoid it by resetting face_change_count to the value it
13857 had before we created the tip frame. */
13858 face_change_count = face_change_count_before;
13859
13860 /* Discard the unwind_protect. */
6fc2811b 13861 return unbind_to (count, frame);
ee78dc32
GV
13862}
13863
3cf3436e
JR
13864
13865/* Compute where to display tip frame F. PARMS is the list of frame
13866 parameters for F. DX and DY are specified offsets from the current
13867 location of the mouse. WIDTH and HEIGHT are the width and height
13868 of the tooltip. Return coordinates relative to the root window of
13869 the display in *ROOT_X, and *ROOT_Y. */
13870
13871static void
13872compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13873 struct frame *f;
13874 Lisp_Object parms, dx, dy;
13875 int width, height;
13876 int *root_x, *root_y;
13877{
3cf3436e 13878 Lisp_Object left, top;
3cf3436e
JR
13879
13880 /* User-specified position? */
13881 left = Fcdr (Fassq (Qleft, parms));
13882 top = Fcdr (Fassq (Qtop, parms));
13883
13884 /* Move the tooltip window where the mouse pointer is. Resize and
13885 show it. */
ca56d953 13886 if (!INTEGERP (left) || !INTEGERP (top))
3cf3436e 13887 {
ca56d953
JR
13888 POINT pt;
13889
3cf3436e 13890 BLOCK_INPUT;
ca56d953
JR
13891 GetCursorPos (&pt);
13892 *root_x = pt.x;
13893 *root_y = pt.y;
3cf3436e
JR
13894 UNBLOCK_INPUT;
13895 }
13896
13897 if (INTEGERP (top))
13898 *root_y = XINT (top);
13899 else if (*root_y + XINT (dy) - height < 0)
13900 *root_y -= XINT (dy);
13901 else
13902 {
13903 *root_y -= height;
13904 *root_y += XINT (dy);
13905 }
13906
13907 if (INTEGERP (left))
13908 *root_x = XINT (left);
72e4adef
JR
13909 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13910 /* It fits to the right of the pointer. */
13911 *root_x += XINT (dx);
13912 else if (width + XINT (dx) <= *root_x)
13913 /* It fits to the left of the pointer. */
3cf3436e
JR
13914 *root_x -= width + XINT (dx);
13915 else
72e4adef
JR
13916 /* Put it left justified on the screen -- it ought to fit that way. */
13917 *root_x = 0;
3cf3436e
JR
13918}
13919
13920
71eab8d1 13921DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
74e1aeec
JR
13922 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13923A tooltip window is a small window displaying a string.
13924
13925FRAME nil or omitted means use the selected frame.
13926
13927PARMS is an optional list of frame parameters which can be
13928used to change the tooltip's appearance.
13929
ca56d953
JR
13930Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13931means use the default timeout of 5 seconds.
74e1aeec 13932
ca56d953 13933If the list of frame parameters PARAMS contains a `left' parameter,
74e1aeec
JR
13934the tooltip is displayed at that x-position. Otherwise it is
13935displayed at the mouse position, with offset DX added (default is 5 if
13936DX isn't specified). Likewise for the y-position; if a `top' frame
13937parameter is specified, it determines the y-position of the tooltip
13938window, otherwise it is displayed at the mouse position, with offset
13939DY added (default is -10).
13940
13941A tooltip's maximum size is specified by `x-max-tooltip-size'.
13942Text larger than the specified size is clipped. */)
71eab8d1
AI
13943 (string, frame, parms, timeout, dx, dy)
13944 Lisp_Object string, frame, parms, timeout, dx, dy;
ee78dc32 13945{
6fc2811b
JR
13946 struct frame *f;
13947 struct window *w;
3cf3436e 13948 int root_x, root_y;
6fc2811b
JR
13949 struct buffer *old_buffer;
13950 struct text_pos pos;
13951 int i, width, height;
6fc2811b
JR
13952 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13953 int old_windows_or_buffers_changed = windows_or_buffers_changed;
ca56d953 13954 int count = BINDING_STACK_SIZE ();
6fc2811b
JR
13955
13956 specbind (Qinhibit_redisplay, Qt);
ee78dc32 13957
dfff8a69 13958 GCPRO4 (string, parms, frame, timeout);
ee78dc32 13959
b7826503 13960 CHECK_STRING (string);
6fc2811b
JR
13961 f = check_x_frame (frame);
13962 if (NILP (timeout))
13963 timeout = make_number (5);
13964 else
b7826503 13965 CHECK_NATNUM (timeout);
ee78dc32 13966
71eab8d1
AI
13967 if (NILP (dx))
13968 dx = make_number (5);
13969 else
b7826503 13970 CHECK_NUMBER (dx);
71eab8d1
AI
13971
13972 if (NILP (dy))
dc220243 13973 dy = make_number (-10);
71eab8d1 13974 else
b7826503 13975 CHECK_NUMBER (dy);
71eab8d1 13976
dc220243
JR
13977 if (NILP (last_show_tip_args))
13978 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13979
13980 if (!NILP (tip_frame))
13981 {
13982 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13983 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13984 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13985
13986 if (EQ (frame, last_frame)
13987 && !NILP (Fequal (last_string, string))
13988 && !NILP (Fequal (last_parms, parms)))
13989 {
13990 struct frame *f = XFRAME (tip_frame);
13991
13992 /* Only DX and DY have changed. */
13993 if (!NILP (tip_timer))
13994 {
13995 Lisp_Object timer = tip_timer;
13996 tip_timer = Qnil;
13997 call1 (Qcancel_timer, timer);
13998 }
13999
14000 BLOCK_INPUT;
ca56d953
JR
14001 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
14002 PIXEL_HEIGHT (f), &root_x, &root_y);
d65a9cdc
JR
14003
14004 /* Put tooltip in topmost group and in position. */
ca56d953
JR
14005 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14006 root_x, root_y, 0, 0,
14007 SWP_NOSIZE | SWP_NOACTIVATE);
d65a9cdc
JR
14008
14009 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14010 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14011 0, 0, 0, 0,
14012 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14013
dc220243
JR
14014 UNBLOCK_INPUT;
14015 goto start_timer;
14016 }
14017 }
14018
6fc2811b
JR
14019 /* Hide a previous tip, if any. */
14020 Fx_hide_tip ();
ee78dc32 14021
dc220243
JR
14022 ASET (last_show_tip_args, 0, string);
14023 ASET (last_show_tip_args, 1, frame);
14024 ASET (last_show_tip_args, 2, parms);
14025
6fc2811b
JR
14026 /* Add default values to frame parameters. */
14027 if (NILP (Fassq (Qname, parms)))
14028 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14029 if (NILP (Fassq (Qinternal_border_width, parms)))
14030 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14031 if (NILP (Fassq (Qborder_width, parms)))
14032 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14033 if (NILP (Fassq (Qborder_color, parms)))
14034 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14035 if (NILP (Fassq (Qbackground_color, parms)))
14036 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14037 parms);
14038
0e3fcdef
JR
14039 /* Block input until the tip has been fully drawn, to avoid crashes
14040 when drawing tips in menus. */
14041 BLOCK_INPUT;
14042
6fc2811b
JR
14043 /* Create a frame for the tooltip, and record it in the global
14044 variable tip_frame. */
ca56d953 14045 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
937e601e 14046 f = XFRAME (frame);
6fc2811b 14047
3cf3436e 14048 /* Set up the frame's root window. */
6fc2811b
JR
14049 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14050 w->left = w->top = make_number (0);
3cf3436e
JR
14051
14052 if (CONSP (Vx_max_tooltip_size)
14053 && INTEGERP (XCAR (Vx_max_tooltip_size))
14054 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14055 && INTEGERP (XCDR (Vx_max_tooltip_size))
14056 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14057 {
14058 w->width = XCAR (Vx_max_tooltip_size);
14059 w->height = XCDR (Vx_max_tooltip_size);
14060 }
14061 else
14062 {
14063 w->width = make_number (80);
14064 w->height = make_number (40);
14065 }
14066
14067 f->window_width = XINT (w->width);
6fc2811b
JR
14068 adjust_glyphs (f);
14069 w->pseudo_window_p = 1;
14070
14071 /* Display the tooltip text in a temporary buffer. */
6fc2811b 14072 old_buffer = current_buffer;
3cf3436e
JR
14073 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14074 current_buffer->truncate_lines = Qnil;
6fc2811b
JR
14075 clear_glyph_matrix (w->desired_matrix);
14076 clear_glyph_matrix (w->current_matrix);
14077 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14078 try_window (FRAME_ROOT_WINDOW (f), pos);
14079
14080 /* Compute width and height of the tooltip. */
14081 width = height = 0;
14082 for (i = 0; i < w->desired_matrix->nrows; ++i)
ee78dc32 14083 {
6fc2811b
JR
14084 struct glyph_row *row = &w->desired_matrix->rows[i];
14085 struct glyph *last;
14086 int row_width;
14087
14088 /* Stop at the first empty row at the end. */
14089 if (!row->enabled_p || !row->displays_text_p)
14090 break;
14091
14092 /* Let the row go over the full width of the frame. */
14093 row->full_width_p = 1;
14094
4e3a1c61
JR
14095#ifdef TODO /* Investigate why some fonts need more width than is
14096 calculated for some tooltips. */
6fc2811b
JR
14097 /* There's a glyph at the end of rows that is use to place
14098 the cursor there. Don't include the width of this glyph. */
14099 if (row->used[TEXT_AREA])
14100 {
14101 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14102 row_width = row->pixel_width - last->pixel_width;
14103 }
14104 else
4e3a1c61 14105#endif
6fc2811b
JR
14106 row_width = row->pixel_width;
14107
ca56d953 14108 /* TODO: find why tips do not draw along baseline as instructed. */
bfd6edcc 14109 height += row->height;
6fc2811b 14110 width = max (width, row_width);
ee78dc32
GV
14111 }
14112
6fc2811b
JR
14113 /* Add the frame's internal border to the width and height the X
14114 window should have. */
14115 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14116 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
ee78dc32 14117
6fc2811b
JR
14118 /* Move the tooltip window where the mouse pointer is. Resize and
14119 show it. */
3cf3436e 14120 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
71eab8d1 14121
bfd6edcc
JR
14122 {
14123 /* Adjust Window size to take border into account. */
14124 RECT rect;
14125 rect.left = rect.top = 0;
14126 rect.right = width;
14127 rect.bottom = height;
14128 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14129 FRAME_EXTERNAL_MENU_BAR (f));
14130
d65a9cdc 14131 /* Position and size tooltip, and put it in the topmost group. */
bfd6edcc
JR
14132 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14133 root_x, root_y, rect.right - rect.left,
14134 rect.bottom - rect.top, SWP_NOACTIVATE);
14135
d65a9cdc
JR
14136 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14137 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14138 0, 0, 0, 0,
14139 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14140
bfd6edcc
JR
14141 /* Let redisplay know that we have made the frame visible already. */
14142 f->async_visible = 1;
14143
14144 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14145 }
ee78dc32 14146
6fc2811b
JR
14147 /* Draw into the window. */
14148 w->must_be_updated_p = 1;
14149 update_single_window (w, 1);
ee78dc32 14150
0e3fcdef
JR
14151 UNBLOCK_INPUT;
14152
6fc2811b
JR
14153 /* Restore original current buffer. */
14154 set_buffer_internal_1 (old_buffer);
14155 windows_or_buffers_changed = old_windows_or_buffers_changed;
ee78dc32 14156
dc220243 14157 start_timer:
6fc2811b
JR
14158 /* Let the tip disappear after timeout seconds. */
14159 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14160 intern ("x-hide-tip"));
ee78dc32 14161
dfff8a69 14162 UNGCPRO;
6fc2811b 14163 return unbind_to (count, Qnil);
ee78dc32
GV
14164}
14165
ee78dc32 14166
6fc2811b 14167DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
74e1aeec
JR
14168 doc: /* Hide the current tooltip window, if there is any.
14169Value is t if tooltip was open, nil otherwise. */)
6fc2811b
JR
14170 ()
14171{
937e601e
AI
14172 int count;
14173 Lisp_Object deleted, frame, timer;
14174 struct gcpro gcpro1, gcpro2;
14175
14176 /* Return quickly if nothing to do. */
14177 if (NILP (tip_timer) && NILP (tip_frame))
14178 return Qnil;
14179
14180 frame = tip_frame;
14181 timer = tip_timer;
14182 GCPRO2 (frame, timer);
14183 tip_frame = tip_timer = deleted = Qnil;
6fc2811b 14184
937e601e 14185 count = BINDING_STACK_SIZE ();
6fc2811b 14186 specbind (Qinhibit_redisplay, Qt);
937e601e 14187 specbind (Qinhibit_quit, Qt);
6fc2811b 14188
937e601e 14189 if (!NILP (timer))
dc220243 14190 call1 (Qcancel_timer, timer);
ee78dc32 14191
937e601e 14192 if (FRAMEP (frame))
6fc2811b 14193 {
937e601e
AI
14194 Fdelete_frame (frame, Qnil);
14195 deleted = Qt;
6fc2811b 14196 }
1edf84e7 14197
937e601e
AI
14198 UNGCPRO;
14199 return unbind_to (count, deleted);
6fc2811b 14200}
5ac45f98 14201
5ac45f98 14202
6fc2811b
JR
14203\f
14204/***********************************************************************
14205 File selection dialog
14206 ***********************************************************************/
14207
14208extern Lisp_Object Qfile_name_history;
14209
14210DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
74e1aeec
JR
14211 doc: /* Read file name, prompting with PROMPT in directory DIR.
14212Use a file selection dialog.
14213Select DEFAULT-FILENAME in the dialog's file selection box, if
14214specified. Ensure that file exists if MUSTMATCH is non-nil. */)
6fc2811b
JR
14215 (prompt, dir, default_filename, mustmatch)
14216 Lisp_Object prompt, dir, default_filename, mustmatch;
14217{
14218 struct frame *f = SELECTED_FRAME ();
14219 Lisp_Object file = Qnil;
14220 int count = specpdl_ptr - specpdl;
14221 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14222 char filename[MAX_PATH + 1];
14223 char init_dir[MAX_PATH + 1];
14224 int use_dialog_p = 1;
14225
14226 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
b7826503
PJ
14227 CHECK_STRING (prompt);
14228 CHECK_STRING (dir);
6fc2811b
JR
14229
14230 /* Create the dialog with PROMPT as title, using DIR as initial
14231 directory and using "*" as pattern. */
14232 dir = Fexpand_file_name (dir, Qnil);
14233 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14234 init_dir[MAX_PATH] = '\0';
14235 unixtodos_filename (init_dir);
14236
14237 if (STRINGP (default_filename))
14238 {
14239 char *file_name_only;
14240 char *full_path_name = XSTRING (default_filename)->data;
5ac45f98 14241
6fc2811b 14242 unixtodos_filename (full_path_name);
5ac45f98 14243
6fc2811b
JR
14244 file_name_only = strrchr (full_path_name, '\\');
14245 if (!file_name_only)
14246 file_name_only = full_path_name;
14247 else
14248 {
14249 file_name_only++;
5ac45f98 14250
6fc2811b
JR
14251 /* If default_file_name is a directory, don't use the open
14252 file dialog, as it does not support selecting
14253 directories. */
14254 if (!(*file_name_only))
14255 use_dialog_p = 0;
14256 }
ee78dc32 14257
6fc2811b
JR
14258 strncpy (filename, file_name_only, MAX_PATH);
14259 filename[MAX_PATH] = '\0';
14260 }
ee78dc32 14261 else
6fc2811b 14262 filename[0] = '\0';
ee78dc32 14263
6fc2811b
JR
14264 if (use_dialog_p)
14265 {
14266 OPENFILENAME file_details;
5ac45f98 14267
6fc2811b
JR
14268 /* Prevent redisplay. */
14269 specbind (Qinhibit_redisplay, Qt);
14270 BLOCK_INPUT;
ee78dc32 14271
6fc2811b
JR
14272 bzero (&file_details, sizeof (file_details));
14273 file_details.lStructSize = sizeof (file_details);
14274 file_details.hwndOwner = FRAME_W32_WINDOW (f);
3cf3436e
JR
14275 /* Undocumented Bug in Common File Dialog:
14276 If a filter is not specified, shell links are not resolved. */
14277 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
6fc2811b
JR
14278 file_details.lpstrFile = filename;
14279 file_details.nMaxFile = sizeof (filename);
14280 file_details.lpstrInitialDir = init_dir;
14281 file_details.lpstrTitle = XSTRING (prompt)->data;
14282 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
ee78dc32 14283
6fc2811b
JR
14284 if (!NILP (mustmatch))
14285 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ee78dc32 14286
6fc2811b
JR
14287 if (GetOpenFileName (&file_details))
14288 {
14289 dostounix_filename (filename);
f8a58bac 14290 file = DECODE_FILE(build_string (filename));
6fc2811b 14291 }
ee78dc32 14292 else
6fc2811b
JR
14293 file = Qnil;
14294
14295 UNBLOCK_INPUT;
14296 file = unbind_to (count, file);
ee78dc32 14297 }
6fc2811b
JR
14298 /* Open File dialog will not allow folders to be selected, so resort
14299 to minibuffer completing reads for directories. */
14300 else
14301 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14302 dir, mustmatch, dir, Qfile_name_history,
14303 default_filename, Qnil);
ee78dc32 14304
6fc2811b 14305 UNGCPRO;
1edf84e7 14306
6fc2811b
JR
14307 /* Make "Cancel" equivalent to C-g. */
14308 if (NILP (file))
14309 Fsignal (Qquit, Qnil);
ee78dc32 14310
dfff8a69 14311 return unbind_to (count, file);
6fc2811b 14312}
ee78dc32 14313
ee78dc32 14314
6fc2811b 14315\f
6fc2811b
JR
14316/***********************************************************************
14317 w32 specialized functions
14318 ***********************************************************************/
ee78dc32 14319
d84b082d 14320DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
74e1aeec
JR
14321 doc: /* Select a font using the W32 font dialog.
14322Returns an X font string corresponding to the selection. */)
d84b082d
JR
14323 (frame, include_proportional)
14324 Lisp_Object frame, include_proportional;
ee78dc32
GV
14325{
14326 FRAME_PTR f = check_x_frame (frame);
14327 CHOOSEFONT cf;
14328 LOGFONT lf;
f46e6225
GV
14329 TEXTMETRIC tm;
14330 HDC hdc;
14331 HANDLE oldobj;
ee78dc32
GV
14332 char buf[100];
14333
14334 bzero (&cf, sizeof (cf));
f46e6225 14335 bzero (&lf, sizeof (lf));
ee78dc32
GV
14336
14337 cf.lStructSize = sizeof (cf);
fbd6baed 14338 cf.hwndOwner = FRAME_W32_WINDOW (f);
d84b082d
JR
14339 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14340
14341 /* Unless include_proportional is non-nil, limit the selection to
14342 monospaced fonts. */
14343 if (NILP (include_proportional))
14344 cf.Flags |= CF_FIXEDPITCHONLY;
14345
ee78dc32
GV
14346 cf.lpLogFont = &lf;
14347
f46e6225
GV
14348 /* Initialize as much of the font details as we can from the current
14349 default font. */
14350 hdc = GetDC (FRAME_W32_WINDOW (f));
14351 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14352 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14353 if (GetTextMetrics (hdc, &tm))
14354 {
14355 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14356 lf.lfWeight = tm.tmWeight;
14357 lf.lfItalic = tm.tmItalic;
14358 lf.lfUnderline = tm.tmUnderlined;
14359 lf.lfStrikeOut = tm.tmStruckOut;
f46e6225
GV
14360 lf.lfCharSet = tm.tmCharSet;
14361 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14362 }
14363 SelectObject (hdc, oldobj);
6fc2811b 14364 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
f46e6225 14365
767b1ff0 14366 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
3c190163 14367 return Qnil;
ee78dc32
GV
14368
14369 return build_string (buf);
14370}
14371
74e1aeec
JR
14372DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14373 Sw32_send_sys_command, 1, 2, 0,
14374 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
d84b082d
JR
14375Some useful values for command are #xf030 to maximise frame (#xf020
14376to minimize), #xf120 to restore frame to original size, and #xf100
14377to activate the menubar for keyboard access. #xf140 activates the
74e1aeec
JR
14378screen saver if defined.
14379
14380If optional parameter FRAME is not specified, use selected frame. */)
1edf84e7
GV
14381 (command, frame)
14382 Lisp_Object command, frame;
14383{
1edf84e7
GV
14384 FRAME_PTR f = check_x_frame (frame);
14385
b7826503 14386 CHECK_NUMBER (command);
1edf84e7 14387
ce6059da 14388 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
14389
14390 return Qnil;
14391}
14392
55dcfc15 14393DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
74e1aeec
JR
14394 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14395This is a wrapper around the ShellExecute system function, which
14396invokes the application registered to handle OPERATION for DOCUMENT.
14397OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14398nil for the default action), and DOCUMENT is typically the name of a
14399document file or URL, but can also be a program executable to run or
14400a directory to open in the Windows Explorer.
14401
14402If DOCUMENT is a program executable, PARAMETERS can be a string
14403containing command line parameters, but otherwise should be nil.
14404
14405SHOW-FLAG can be used to control whether the invoked application is hidden
14406or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14407otherwise it is an integer representing a ShowWindow flag:
14408
14409 0 - start hidden
14410 1 - start normally
14411 3 - start maximized
14412 6 - start minimized */)
55dcfc15
AI
14413 (operation, document, parameters, show_flag)
14414 Lisp_Object operation, document, parameters, show_flag;
14415{
14416 Lisp_Object current_dir;
14417
b7826503 14418 CHECK_STRING (document);
55dcfc15
AI
14419
14420 /* Encode filename and current directory. */
14421 current_dir = ENCODE_FILE (current_buffer->directory);
14422 document = ENCODE_FILE (document);
14423 if ((int) ShellExecute (NULL,
6fc2811b
JR
14424 (STRINGP (operation) ?
14425 XSTRING (operation)->data : NULL),
55dcfc15
AI
14426 XSTRING (document)->data,
14427 (STRINGP (parameters) ?
14428 XSTRING (parameters)->data : NULL),
14429 XSTRING (current_dir)->data,
14430 (INTEGERP (show_flag) ?
14431 XINT (show_flag) : SW_SHOWDEFAULT))
14432 > 32)
14433 return Qt;
90d97e64 14434 error ("ShellExecute failed: %s", w32_strerror (0));
55dcfc15
AI
14435}
14436
ccc2d29c
GV
14437/* Lookup virtual keycode from string representing the name of a
14438 non-ascii keystroke into the corresponding virtual key, using
14439 lispy_function_keys. */
14440static int
14441lookup_vk_code (char *key)
14442{
14443 int i;
14444
14445 for (i = 0; i < 256; i++)
14446 if (lispy_function_keys[i] != 0
14447 && strcmp (lispy_function_keys[i], key) == 0)
14448 return i;
14449
14450 return -1;
14451}
14452
14453/* Convert a one-element vector style key sequence to a hot key
14454 definition. */
14455static int
14456w32_parse_hot_key (key)
14457 Lisp_Object key;
14458{
14459 /* Copied from Fdefine_key and store_in_keymap. */
14460 register Lisp_Object c;
14461 int vk_code;
14462 int lisp_modifiers;
14463 int w32_modifiers;
14464 struct gcpro gcpro1;
14465
b7826503 14466 CHECK_VECTOR (key);
ccc2d29c
GV
14467
14468 if (XFASTINT (Flength (key)) != 1)
14469 return Qnil;
14470
14471 GCPRO1 (key);
14472
14473 c = Faref (key, make_number (0));
14474
14475 if (CONSP (c) && lucid_event_type_list_p (c))
14476 c = Fevent_convert_list (c);
14477
14478 UNGCPRO;
14479
14480 if (! INTEGERP (c) && ! SYMBOLP (c))
14481 error ("Key definition is invalid");
14482
14483 /* Work out the base key and the modifiers. */
14484 if (SYMBOLP (c))
14485 {
14486 c = parse_modifiers (c);
14487 lisp_modifiers = Fcar (Fcdr (c));
14488 c = Fcar (c);
14489 if (!SYMBOLP (c))
14490 abort ();
14491 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
14492 }
14493 else if (INTEGERP (c))
14494 {
14495 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14496 /* Many ascii characters are their own virtual key code. */
14497 vk_code = XINT (c) & CHARACTERBITS;
14498 }
14499
14500 if (vk_code < 0 || vk_code > 255)
14501 return Qnil;
14502
14503 if ((lisp_modifiers & meta_modifier) != 0
14504 && !NILP (Vw32_alt_is_meta))
14505 lisp_modifiers |= alt_modifier;
14506
71eab8d1
AI
14507 /* Supply defs missing from mingw32. */
14508#ifndef MOD_ALT
14509#define MOD_ALT 0x0001
14510#define MOD_CONTROL 0x0002
14511#define MOD_SHIFT 0x0004
14512#define MOD_WIN 0x0008
14513#endif
14514
ccc2d29c
GV
14515 /* Convert lisp modifiers to Windows hot-key form. */
14516 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14517 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14518 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14519 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14520
14521 return HOTKEY (vk_code, w32_modifiers);
14522}
14523
74e1aeec
JR
14524DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14525 Sw32_register_hot_key, 1, 1, 0,
14526 doc: /* Register KEY as a hot-key combination.
14527Certain key combinations like Alt-Tab are reserved for system use on
14528Windows, and therefore are normally intercepted by the system. However,
14529most of these key combinations can be received by registering them as
14530hot-keys, overriding their special meaning.
14531
14532KEY must be a one element key definition in vector form that would be
14533acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14534modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14535is always interpreted as the Windows modifier keys.
14536
14537The return value is the hotkey-id if registered, otherwise nil. */)
ccc2d29c
GV
14538 (key)
14539 Lisp_Object key;
14540{
14541 key = w32_parse_hot_key (key);
14542
14543 if (NILP (Fmemq (key, w32_grabbed_keys)))
14544 {
14545 /* Reuse an empty slot if possible. */
14546 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14547
14548 /* Safe to add new key to list, even if we have focus. */
14549 if (NILP (item))
14550 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14551 else
f3fbd155 14552 XSETCAR (item, key);
ccc2d29c
GV
14553
14554 /* Notify input thread about new hot-key definition, so that it
14555 takes effect without needing to switch focus. */
14556 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14557 (WPARAM) key, 0);
14558 }
14559
14560 return key;
14561}
14562
74e1aeec
JR
14563DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14564 Sw32_unregister_hot_key, 1, 1, 0,
14565 doc: /* Unregister HOTKEY as a hot-key combination. */)
ccc2d29c
GV
14566 (key)
14567 Lisp_Object key;
14568{
14569 Lisp_Object item;
14570
14571 if (!INTEGERP (key))
14572 key = w32_parse_hot_key (key);
14573
14574 item = Fmemq (key, w32_grabbed_keys);
14575
14576 if (!NILP (item))
14577 {
14578 /* Notify input thread about hot-key definition being removed, so
14579 that it takes effect without needing focus switch. */
14580 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14581 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14582 {
14583 MSG msg;
14584 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14585 }
14586 return Qt;
14587 }
14588 return Qnil;
14589}
14590
74e1aeec
JR
14591DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14592 Sw32_registered_hot_keys, 0, 0, 0,
14593 doc: /* Return list of registered hot-key IDs. */)
ccc2d29c
GV
14594 ()
14595{
14596 return Fcopy_sequence (w32_grabbed_keys);
14597}
14598
74e1aeec
JR
14599DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14600 Sw32_reconstruct_hot_key, 1, 1, 0,
14601 doc: /* Convert hot-key ID to a lisp key combination. */)
ccc2d29c
GV
14602 (hotkeyid)
14603 Lisp_Object hotkeyid;
14604{
14605 int vk_code, w32_modifiers;
14606 Lisp_Object key;
14607
b7826503 14608 CHECK_NUMBER (hotkeyid);
ccc2d29c
GV
14609
14610 vk_code = HOTKEY_VK_CODE (hotkeyid);
14611 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14612
14613 if (lispy_function_keys[vk_code])
14614 key = intern (lispy_function_keys[vk_code]);
14615 else
14616 key = make_number (vk_code);
14617
14618 key = Fcons (key, Qnil);
14619 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 14620 key = Fcons (Qshift, key);
ccc2d29c 14621 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 14622 key = Fcons (Qctrl, key);
ccc2d29c 14623 if (w32_modifiers & MOD_ALT)
3ef68e6b 14624 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 14625 if (w32_modifiers & MOD_WIN)
3ef68e6b 14626 key = Fcons (Qhyper, key);
ccc2d29c
GV
14627
14628 return key;
14629}
adcc3809 14630
74e1aeec
JR
14631DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14632 Sw32_toggle_lock_key, 1, 2, 0,
14633 doc: /* Toggle the state of the lock key KEY.
14634KEY can be `capslock', `kp-numlock', or `scroll'.
14635If the optional parameter NEW-STATE is a number, then the state of KEY
14636is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
adcc3809
GV
14637 (key, new_state)
14638 Lisp_Object key, new_state;
14639{
14640 int vk_code;
adcc3809
GV
14641
14642 if (EQ (key, intern ("capslock")))
14643 vk_code = VK_CAPITAL;
14644 else if (EQ (key, intern ("kp-numlock")))
14645 vk_code = VK_NUMLOCK;
14646 else if (EQ (key, intern ("scroll")))
14647 vk_code = VK_SCROLL;
14648 else
14649 return Qnil;
14650
14651 if (!dwWindowsThreadId)
14652 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14653
14654 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14655 (WPARAM) vk_code, (LPARAM) new_state))
14656 {
14657 MSG msg;
14658 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14659 return make_number (msg.wParam);
14660 }
14661 return Qnil;
14662}
ee78dc32 14663\f
2254bcde 14664DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
74e1aeec
JR
14665 doc: /* Return storage information about the file system FILENAME is on.
14666Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14667storage of the file system, FREE is the free storage, and AVAIL is the
14668storage available to a non-superuser. All 3 numbers are in bytes.
14669If the underlying system call fails, value is nil. */)
2254bcde
AI
14670 (filename)
14671 Lisp_Object filename;
14672{
14673 Lisp_Object encoded, value;
14674
b7826503 14675 CHECK_STRING (filename);
2254bcde
AI
14676 filename = Fexpand_file_name (filename, Qnil);
14677 encoded = ENCODE_FILE (filename);
14678
14679 value = Qnil;
14680
14681 /* Determining the required information on Windows turns out, sadly,
14682 to be more involved than one would hope. The original Win32 api
14683 call for this will return bogus information on some systems, but we
14684 must dynamically probe for the replacement api, since that was
14685 added rather late on. */
14686 {
14687 HMODULE hKernel = GetModuleHandle ("kernel32");
14688 BOOL (*pfn_GetDiskFreeSpaceEx)
14689 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14690 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14691
14692 /* On Windows, we may need to specify the root directory of the
14693 volume holding FILENAME. */
14694 char rootname[MAX_PATH];
14695 char *name = XSTRING (encoded)->data;
14696
14697 /* find the root name of the volume if given */
14698 if (isalpha (name[0]) && name[1] == ':')
14699 {
14700 rootname[0] = name[0];
14701 rootname[1] = name[1];
14702 rootname[2] = '\\';
14703 rootname[3] = 0;
14704 }
14705 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14706 {
14707 char *str = rootname;
14708 int slashes = 4;
14709 do
14710 {
14711 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14712 break;
14713 *str++ = *name++;
14714 }
14715 while ( *name );
14716
14717 *str++ = '\\';
14718 *str = 0;
14719 }
14720
14721 if (pfn_GetDiskFreeSpaceEx)
14722 {
ac849ba4
JR
14723 /* Unsigned large integers cannot be cast to double, so
14724 use signed ones instead. */
2254bcde
AI
14725 LARGE_INTEGER availbytes;
14726 LARGE_INTEGER freebytes;
14727 LARGE_INTEGER totalbytes;
14728
14729 if (pfn_GetDiskFreeSpaceEx(rootname,
ac849ba4
JR
14730 (ULARGE_INTEGER *)&availbytes,
14731 (ULARGE_INTEGER *)&totalbytes,
14732 (ULARGE_INTEGER *)&freebytes))
2254bcde
AI
14733 value = list3 (make_float ((double) totalbytes.QuadPart),
14734 make_float ((double) freebytes.QuadPart),
14735 make_float ((double) availbytes.QuadPart));
14736 }
14737 else
14738 {
14739 DWORD sectors_per_cluster;
14740 DWORD bytes_per_sector;
14741 DWORD free_clusters;
14742 DWORD total_clusters;
14743
14744 if (GetDiskFreeSpace(rootname,
14745 &sectors_per_cluster,
14746 &bytes_per_sector,
14747 &free_clusters,
14748 &total_clusters))
14749 value = list3 (make_float ((double) total_clusters
14750 * sectors_per_cluster * bytes_per_sector),
14751 make_float ((double) free_clusters
14752 * sectors_per_cluster * bytes_per_sector),
14753 make_float ((double) free_clusters
14754 * sectors_per_cluster * bytes_per_sector));
14755 }
14756 }
14757
14758 return value;
14759}
14760\f
0e3fcdef
JR
14761/***********************************************************************
14762 Initialization
14763 ***********************************************************************/
14764
14765void
fbd6baed 14766syms_of_w32fns ()
ee78dc32 14767{
9eb16b62
JR
14768 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14769
1edf84e7
GV
14770 /* This is zero if not using MS-Windows. */
14771 w32_in_use = 0;
14772
9eb16b62
JR
14773 /* TrackMouseEvent not available in all versions of Windows, so must load
14774 it dynamically. Do it once, here, instead of every time it is used. */
14775 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14776 track_mouse_window = NULL;
14777
d285988b
JR
14778 w32_visible_system_caret_hwnd = NULL;
14779
ee78dc32
GV
14780 Qauto_raise = intern ("auto-raise");
14781 staticpro (&Qauto_raise);
14782 Qauto_lower = intern ("auto-lower");
14783 staticpro (&Qauto_lower);
ee78dc32
GV
14784 Qbar = intern ("bar");
14785 staticpro (&Qbar);
14786 Qborder_color = intern ("border-color");
14787 staticpro (&Qborder_color);
14788 Qborder_width = intern ("border-width");
14789 staticpro (&Qborder_width);
14790 Qbox = intern ("box");
14791 staticpro (&Qbox);
14792 Qcursor_color = intern ("cursor-color");
14793 staticpro (&Qcursor_color);
14794 Qcursor_type = intern ("cursor-type");
14795 staticpro (&Qcursor_type);
ee78dc32
GV
14796 Qgeometry = intern ("geometry");
14797 staticpro (&Qgeometry);
14798 Qicon_left = intern ("icon-left");
14799 staticpro (&Qicon_left);
14800 Qicon_top = intern ("icon-top");
14801 staticpro (&Qicon_top);
14802 Qicon_type = intern ("icon-type");
14803 staticpro (&Qicon_type);
14804 Qicon_name = intern ("icon-name");
14805 staticpro (&Qicon_name);
14806 Qinternal_border_width = intern ("internal-border-width");
14807 staticpro (&Qinternal_border_width);
14808 Qleft = intern ("left");
14809 staticpro (&Qleft);
1026b400
RS
14810 Qright = intern ("right");
14811 staticpro (&Qright);
ee78dc32
GV
14812 Qmouse_color = intern ("mouse-color");
14813 staticpro (&Qmouse_color);
14814 Qnone = intern ("none");
14815 staticpro (&Qnone);
14816 Qparent_id = intern ("parent-id");
14817 staticpro (&Qparent_id);
14818 Qscroll_bar_width = intern ("scroll-bar-width");
14819 staticpro (&Qscroll_bar_width);
14820 Qsuppress_icon = intern ("suppress-icon");
14821 staticpro (&Qsuppress_icon);
ee78dc32
GV
14822 Qundefined_color = intern ("undefined-color");
14823 staticpro (&Qundefined_color);
14824 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14825 staticpro (&Qvertical_scroll_bars);
14826 Qvisibility = intern ("visibility");
14827 staticpro (&Qvisibility);
14828 Qwindow_id = intern ("window-id");
14829 staticpro (&Qwindow_id);
14830 Qx_frame_parameter = intern ("x-frame-parameter");
14831 staticpro (&Qx_frame_parameter);
14832 Qx_resource_name = intern ("x-resource-name");
14833 staticpro (&Qx_resource_name);
14834 Quser_position = intern ("user-position");
14835 staticpro (&Quser_position);
14836 Quser_size = intern ("user-size");
14837 staticpro (&Quser_size);
6fc2811b
JR
14838 Qscreen_gamma = intern ("screen-gamma");
14839 staticpro (&Qscreen_gamma);
dfff8a69
JR
14840 Qline_spacing = intern ("line-spacing");
14841 staticpro (&Qline_spacing);
14842 Qcenter = intern ("center");
14843 staticpro (&Qcenter);
dc220243
JR
14844 Qcancel_timer = intern ("cancel-timer");
14845 staticpro (&Qcancel_timer);
f7b9d4d1
JR
14846 Qfullscreen = intern ("fullscreen");
14847 staticpro (&Qfullscreen);
14848 Qfullwidth = intern ("fullwidth");
14849 staticpro (&Qfullwidth);
14850 Qfullheight = intern ("fullheight");
14851 staticpro (&Qfullheight);
14852 Qfullboth = intern ("fullboth");
14853 staticpro (&Qfullboth);
ee78dc32 14854
adcc3809
GV
14855 Qhyper = intern ("hyper");
14856 staticpro (&Qhyper);
14857 Qsuper = intern ("super");
14858 staticpro (&Qsuper);
14859 Qmeta = intern ("meta");
14860 staticpro (&Qmeta);
14861 Qalt = intern ("alt");
14862 staticpro (&Qalt);
14863 Qctrl = intern ("ctrl");
14864 staticpro (&Qctrl);
14865 Qcontrol = intern ("control");
14866 staticpro (&Qcontrol);
14867 Qshift = intern ("shift");
14868 staticpro (&Qshift);
f7b9d4d1 14869 /* This is the end of symbol initialization. */
adcc3809 14870
6fc2811b
JR
14871 /* Text property `display' should be nonsticky by default. */
14872 Vtext_property_default_nonsticky
14873 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14874
14875
14876 Qlaplace = intern ("laplace");
14877 staticpro (&Qlaplace);
3cf3436e
JR
14878 Qemboss = intern ("emboss");
14879 staticpro (&Qemboss);
14880 Qedge_detection = intern ("edge-detection");
14881 staticpro (&Qedge_detection);
14882 Qheuristic = intern ("heuristic");
14883 staticpro (&Qheuristic);
14884 QCmatrix = intern (":matrix");
14885 staticpro (&QCmatrix);
14886 QCcolor_adjustment = intern (":color-adjustment");
14887 staticpro (&QCcolor_adjustment);
14888 QCmask = intern (":mask");
14889 staticpro (&QCmask);
6fc2811b 14890
4b817373
RS
14891 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14892 staticpro (&Qface_set_after_frame_default);
14893
ee78dc32
GV
14894 Fput (Qundefined_color, Qerror_conditions,
14895 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14896 Fput (Qundefined_color, Qerror_message,
14897 build_string ("Undefined color"));
14898
ccc2d29c
GV
14899 staticpro (&w32_grabbed_keys);
14900 w32_grabbed_keys = Qnil;
14901
fbd6baed 14902 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
74e1aeec 14903 doc: /* An array of color name mappings for windows. */);
fbd6baed 14904 Vw32_color_map = Qnil;
ee78dc32 14905
fbd6baed 14906 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
74e1aeec
JR
14907 doc: /* Non-nil if alt key presses are passed on to Windows.
14908When non-nil, for example, alt pressed and released and then space will
14909open the System menu. When nil, Emacs silently swallows alt key events. */);
fbd6baed 14910 Vw32_pass_alt_to_system = Qnil;
da36a4d6 14911
fbd6baed 14912 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
74e1aeec
JR
14913 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14914When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
fbd6baed 14915 Vw32_alt_is_meta = Qt;
8c205c63 14916
7d081355 14917 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
74e1aeec 14918 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
7d081355
AI
14919 XSETINT (Vw32_quit_key, 0);
14920
ccc2d29c
GV
14921 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14922 &Vw32_pass_lwindow_to_system,
74e1aeec
JR
14923 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14924When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14925 Vw32_pass_lwindow_to_system = Qt;
14926
14927 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14928 &Vw32_pass_rwindow_to_system,
74e1aeec
JR
14929 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14930When non-nil, the Start menu is opened by tapping the key. */);
ccc2d29c
GV
14931 Vw32_pass_rwindow_to_system = Qt;
14932
adcc3809
GV
14933 DEFVAR_INT ("w32-phantom-key-code",
14934 &Vw32_phantom_key_code,
74e1aeec
JR
14935 doc: /* Virtual key code used to generate \"phantom\" key presses.
14936Value is a number between 0 and 255.
14937
14938Phantom key presses are generated in order to stop the system from
14939acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14940`w32-pass-rwindow-to-system' is nil. */);
ce6059da
AI
14941 /* Although 255 is technically not a valid key code, it works and
14942 means that this hack won't interfere with any real key code. */
14943 Vw32_phantom_key_code = 255;
adcc3809 14944
ccc2d29c
GV
14945 DEFVAR_LISP ("w32-enable-num-lock",
14946 &Vw32_enable_num_lock,
74e1aeec
JR
14947 doc: /* Non-nil if Num Lock should act normally.
14948Set to nil to see Num Lock as the key `kp-numlock'. */);
ccc2d29c
GV
14949 Vw32_enable_num_lock = Qt;
14950
14951 DEFVAR_LISP ("w32-enable-caps-lock",
14952 &Vw32_enable_caps_lock,
74e1aeec
JR
14953 doc: /* Non-nil if Caps Lock should act normally.
14954Set to nil to see Caps Lock as the key `capslock'. */);
ccc2d29c
GV
14955 Vw32_enable_caps_lock = Qt;
14956
14957 DEFVAR_LISP ("w32-scroll-lock-modifier",
14958 &Vw32_scroll_lock_modifier,
74e1aeec
JR
14959 doc: /* Modifier to use for the Scroll Lock on state.
14960The value can be hyper, super, meta, alt, control or shift for the
14961respective modifier, or nil to see Scroll Lock as the key `scroll'.
14962Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14963 Vw32_scroll_lock_modifier = Qt;
14964
14965 DEFVAR_LISP ("w32-lwindow-modifier",
14966 &Vw32_lwindow_modifier,
74e1aeec
JR
14967 doc: /* Modifier to use for the left \"Windows\" key.
14968The value can be hyper, super, meta, alt, control or shift for the
14969respective modifier, or nil to appear as the key `lwindow'.
14970Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14971 Vw32_lwindow_modifier = Qnil;
14972
14973 DEFVAR_LISP ("w32-rwindow-modifier",
14974 &Vw32_rwindow_modifier,
74e1aeec
JR
14975 doc: /* Modifier to use for the right \"Windows\" key.
14976The value can be hyper, super, meta, alt, control or shift for the
14977respective modifier, or nil to appear as the key `rwindow'.
14978Any other value will cause the key to be ignored. */);
ccc2d29c
GV
14979 Vw32_rwindow_modifier = Qnil;
14980
14981 DEFVAR_LISP ("w32-apps-modifier",
14982 &Vw32_apps_modifier,
74e1aeec
JR
14983 doc: /* Modifier to use for the \"Apps\" key.
14984The value can be hyper, super, meta, alt, control or shift for the
14985respective modifier, or nil to appear as the key `apps'.
14986Any other value will cause the key to be ignored. */);
ccc2d29c 14987 Vw32_apps_modifier = Qnil;
da36a4d6 14988
d84b082d 14989 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
74e1aeec 14990 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
d84b082d 14991 w32_enable_synthesized_fonts = 0;
5ac45f98 14992
fbd6baed 14993 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
74e1aeec 14994 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
fbd6baed 14995 Vw32_enable_palette = Qt;
5ac45f98 14996
fbd6baed
GV
14997 DEFVAR_INT ("w32-mouse-button-tolerance",
14998 &Vw32_mouse_button_tolerance,
74e1aeec
JR
14999 doc: /* Analogue of double click interval for faking middle mouse events.
15000The value is the minimum time in milliseconds that must elapse between
15001left/right button down events before they are considered distinct events.
15002If both mouse buttons are depressed within this interval, a middle mouse
15003button down event is generated instead. */);
fbd6baed 15004 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 15005
fbd6baed
GV
15006 DEFVAR_INT ("w32-mouse-move-interval",
15007 &Vw32_mouse_move_interval,
74e1aeec
JR
15008 doc: /* Minimum interval between mouse move events.
15009The value is the minimum time in milliseconds that must elapse between
15010successive mouse move (or scroll bar drag) events before they are
15011reported as lisp events. */);
247be837 15012 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 15013
74214547
JR
15014 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
15015 &w32_pass_extra_mouse_buttons_to_system,
15016 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
15017Recent versions of Windows support mice with up to five buttons.
15018Since most applications don't support these extra buttons, most mouse
15019drivers will allow you to map them to functions at the system level.
15020If this variable is non-nil, Emacs will pass them on, allowing the
15021system to handle them. */);
15022 w32_pass_extra_mouse_buttons_to_system = 0;
15023
ee78dc32
GV
15024 init_x_parm_symbols ();
15025
15026 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
74e1aeec 15027 doc: /* List of directories to search for bitmap files for w32. */);
ee78dc32
GV
15028 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15029
15030 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
74e1aeec
JR
15031 doc: /* The shape of the pointer when over text.
15032Changing the value does not affect existing frames
15033unless you set the mouse color. */);
ee78dc32
GV
15034 Vx_pointer_shape = Qnil;
15035
15036 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
74e1aeec
JR
15037 doc: /* The name Emacs uses to look up resources; for internal use only.
15038`x-get-resource' uses this as the first component of the instance name
15039when requesting resource values.
15040Emacs initially sets `x-resource-name' to the name under which Emacs
15041was invoked, or to the value specified with the `-name' or `-rn'
15042switches, if present. */);
ee78dc32
GV
15043 Vx_resource_name = Qnil;
15044
15045 Vx_nontext_pointer_shape = Qnil;
15046
15047 Vx_mode_pointer_shape = Qnil;
15048
0af913d7 15049 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
74e1aeec
JR
15050 doc: /* The shape of the pointer when Emacs is busy.
15051This variable takes effect when you create a new frame
15052or when you set the mouse color. */);
0af913d7 15053 Vx_hourglass_pointer_shape = Qnil;
6fc2811b 15054
0af913d7 15055 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
74e1aeec 15056 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
0af913d7 15057 display_hourglass_p = 1;
6fc2811b 15058
0af913d7 15059 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
74e1aeec
JR
15060 doc: /* *Seconds to wait before displaying an hourglass pointer.
15061Value must be an integer or float. */);
0af913d7 15062 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
f79e6790 15063
6fc2811b 15064 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
ee78dc32 15065 &Vx_sensitive_text_pointer_shape,
74e1aeec
JR
15066 doc: /* The shape of the pointer when over mouse-sensitive text.
15067This variable takes effect when you create a new frame
15068or when you set the mouse color. */);
ee78dc32
GV
15069 Vx_sensitive_text_pointer_shape = Qnil;
15070
4694d762
JR
15071 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15072 &Vx_window_horizontal_drag_shape,
74e1aeec
JR
15073 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15074This variable takes effect when you create a new frame
15075or when you set the mouse color. */);
4694d762
JR
15076 Vx_window_horizontal_drag_shape = Qnil;
15077
ee78dc32 15078 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
74e1aeec 15079 doc: /* A string indicating the foreground color of the cursor box. */);
ee78dc32
GV
15080 Vx_cursor_fore_pixel = Qnil;
15081
3cf3436e 15082 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
b3700ae7
JR
15083 doc: /* Maximum size for tooltips.
15084Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3cf3436e
JR
15085 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
15086
ee78dc32 15087 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
74e1aeec
JR
15088 doc: /* Non-nil if no window manager is in use.
15089Emacs doesn't try to figure this out; this is always nil
15090unless you set it to something else. */);
ee78dc32
GV
15091 /* We don't have any way to find this out, so set it to nil
15092 and maybe the user would like to set it to t. */
15093 Vx_no_window_manager = Qnil;
15094
4587b026
GV
15095 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15096 &Vx_pixel_size_width_font_regexp,
74e1aeec
JR
15097 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15098
15099Since Emacs gets width of a font matching with this regexp from
15100PIXEL_SIZE field of the name, font finding mechanism gets faster for
15101such a font. This is especially effective for such large fonts as
15102Chinese, Japanese, and Korean. */);
4587b026
GV
15103 Vx_pixel_size_width_font_regexp = Qnil;
15104
6fc2811b 15105 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
74e1aeec
JR
15106 doc: /* Time after which cached images are removed from the cache.
15107When an image has not been displayed this many seconds, remove it
15108from the image cache. Value must be an integer or nil with nil
15109meaning don't clear the cache. */);
6fc2811b
JR
15110 Vimage_cache_eviction_delay = make_number (30 * 60);
15111
33d52f9c
GV
15112 DEFVAR_LISP ("w32-bdf-filename-alist",
15113 &Vw32_bdf_filename_alist,
74e1aeec 15114 doc: /* List of bdf fonts and their corresponding filenames. */);
33d52f9c
GV
15115 Vw32_bdf_filename_alist = Qnil;
15116
1075afa9
GV
15117 DEFVAR_BOOL ("w32-strict-fontnames",
15118 &w32_strict_fontnames,
74e1aeec
JR
15119 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15120Default is nil, which allows old fontnames that are not XLFD compliant,
15121and allows third-party CJK display to work by specifying false charset
15122fields to trick Emacs into translating to Big5, SJIS etc.
15123Setting this to t will prevent wrong fonts being selected when
15124fontsets are automatically created. */);
1075afa9
GV
15125 w32_strict_fontnames = 0;
15126
c0611964
AI
15127 DEFVAR_BOOL ("w32-strict-painting",
15128 &w32_strict_painting,
74e1aeec
JR
15129 doc: /* Non-nil means use strict rules for repainting frames.
15130Set this to nil to get the old behaviour for repainting; this should
15131only be necessary if the default setting causes problems. */);
c0611964
AI
15132 w32_strict_painting = 1;
15133
dfff8a69
JR
15134 DEFVAR_LISP ("w32-charset-info-alist",
15135 &Vw32_charset_info_alist,
b3700ae7
JR
15136 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15137Each entry should be of the form:
74e1aeec
JR
15138
15139 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15140
15141where CHARSET_NAME is a string used in font names to identify the charset,
15142WINDOWS_CHARSET is a symbol that can be one of:
15143w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15144w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15145w32-charset-chinesebig5,
dfff8a69 15146#ifdef JOHAB_CHARSET
74e1aeec
JR
15147w32-charset-johab, w32-charset-hebrew,
15148w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15149w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15150w32-charset-russian, w32-charset-mac, w32-charset-baltic,
dfff8a69
JR
15151#endif
15152#ifdef UNICODE_CHARSET
74e1aeec 15153w32-charset-unicode,
dfff8a69 15154#endif
74e1aeec
JR
15155or w32-charset-oem.
15156CODEPAGE should be an integer specifying the codepage that should be used
15157to display the character set, t to do no translation and output as Unicode,
15158or nil to do no translation and output as 8 bit (or multibyte on far-east
15159versions of Windows) characters. */);
dfff8a69
JR
15160 Vw32_charset_info_alist = Qnil;
15161
15162 staticpro (&Qw32_charset_ansi);
15163 Qw32_charset_ansi = intern ("w32-charset-ansi");
15164 staticpro (&Qw32_charset_symbol);
15165 Qw32_charset_symbol = intern ("w32-charset-symbol");
15166 staticpro (&Qw32_charset_shiftjis);
15167 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
767b1ff0
JR
15168 staticpro (&Qw32_charset_hangeul);
15169 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
dfff8a69
JR
15170 staticpro (&Qw32_charset_chinesebig5);
15171 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15172 staticpro (&Qw32_charset_gb2312);
15173 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15174 staticpro (&Qw32_charset_oem);
15175 Qw32_charset_oem = intern ("w32-charset-oem");
15176
15177#ifdef JOHAB_CHARSET
15178 {
15179 static int w32_extra_charsets_defined = 1;
74e1aeec
JR
15180 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15181 doc: /* Internal variable. */);
dfff8a69
JR
15182
15183 staticpro (&Qw32_charset_johab);
15184 Qw32_charset_johab = intern ("w32-charset-johab");
15185 staticpro (&Qw32_charset_easteurope);
15186 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15187 staticpro (&Qw32_charset_turkish);
15188 Qw32_charset_turkish = intern ("w32-charset-turkish");
15189 staticpro (&Qw32_charset_baltic);
15190 Qw32_charset_baltic = intern ("w32-charset-baltic");
15191 staticpro (&Qw32_charset_russian);
15192 Qw32_charset_russian = intern ("w32-charset-russian");
15193 staticpro (&Qw32_charset_arabic);
15194 Qw32_charset_arabic = intern ("w32-charset-arabic");
15195 staticpro (&Qw32_charset_greek);
15196 Qw32_charset_greek = intern ("w32-charset-greek");
15197 staticpro (&Qw32_charset_hebrew);
15198 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
767b1ff0
JR
15199 staticpro (&Qw32_charset_vietnamese);
15200 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
dfff8a69
JR
15201 staticpro (&Qw32_charset_thai);
15202 Qw32_charset_thai = intern ("w32-charset-thai");
15203 staticpro (&Qw32_charset_mac);
15204 Qw32_charset_mac = intern ("w32-charset-mac");
15205 }
15206#endif
15207
15208#ifdef UNICODE_CHARSET
15209 {
15210 static int w32_unicode_charset_defined = 1;
15211 DEFVAR_BOOL ("w32-unicode-charset-defined",
74e1aeec
JR
15212 &w32_unicode_charset_defined,
15213 doc: /* Internal variable. */);
dfff8a69
JR
15214
15215 staticpro (&Qw32_charset_unicode);
15216 Qw32_charset_unicode = intern ("w32-charset-unicode");
15217#endif
15218
ee78dc32 15219 defsubr (&Sx_get_resource);
767b1ff0 15220#if 0 /* TODO: Port to W32 */
6fc2811b
JR
15221 defsubr (&Sx_change_window_property);
15222 defsubr (&Sx_delete_window_property);
15223 defsubr (&Sx_window_property);
15224#endif
2d764c78 15225 defsubr (&Sxw_display_color_p);
ee78dc32 15226 defsubr (&Sx_display_grayscale_p);
2d764c78
EZ
15227 defsubr (&Sxw_color_defined_p);
15228 defsubr (&Sxw_color_values);
ee78dc32
GV
15229 defsubr (&Sx_server_max_request_size);
15230 defsubr (&Sx_server_vendor);
15231 defsubr (&Sx_server_version);
15232 defsubr (&Sx_display_pixel_width);
15233 defsubr (&Sx_display_pixel_height);
15234 defsubr (&Sx_display_mm_width);
15235 defsubr (&Sx_display_mm_height);
15236 defsubr (&Sx_display_screens);
15237 defsubr (&Sx_display_planes);
15238 defsubr (&Sx_display_color_cells);
15239 defsubr (&Sx_display_visual_class);
15240 defsubr (&Sx_display_backing_store);
15241 defsubr (&Sx_display_save_under);
15242 defsubr (&Sx_parse_geometry);
15243 defsubr (&Sx_create_frame);
ee78dc32
GV
15244 defsubr (&Sx_open_connection);
15245 defsubr (&Sx_close_connection);
15246 defsubr (&Sx_display_list);
15247 defsubr (&Sx_synchronize);
15248
fbd6baed 15249 /* W32 specific functions */
ee78dc32 15250
1edf84e7 15251 defsubr (&Sw32_focus_frame);
fbd6baed
GV
15252 defsubr (&Sw32_select_font);
15253 defsubr (&Sw32_define_rgb_color);
15254 defsubr (&Sw32_default_color_map);
15255 defsubr (&Sw32_load_color_file);
1edf84e7 15256 defsubr (&Sw32_send_sys_command);
55dcfc15 15257 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
15258 defsubr (&Sw32_register_hot_key);
15259 defsubr (&Sw32_unregister_hot_key);
15260 defsubr (&Sw32_registered_hot_keys);
15261 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 15262 defsubr (&Sw32_toggle_lock_key);
33d52f9c 15263 defsubr (&Sw32_find_bdf_fonts);
4587b026 15264
2254bcde
AI
15265 defsubr (&Sfile_system_info);
15266
4587b026
GV
15267 /* Setting callback functions for fontset handler. */
15268 get_font_info_func = w32_get_font_info;
6fc2811b
JR
15269
15270#if 0 /* This function pointer doesn't seem to be used anywhere.
15271 And the pointer assigned has the wrong type, anyway. */
4587b026 15272 list_fonts_func = w32_list_fonts;
6fc2811b
JR
15273#endif
15274
4587b026
GV
15275 load_font_func = w32_load_font;
15276 find_ccl_program_func = w32_find_ccl_program;
15277 query_font_func = w32_query_font;
15278 set_frame_fontset_func = x_set_font;
15279 check_window_system_func = check_w32;
6fc2811b 15280
6fc2811b
JR
15281 /* Images. */
15282 Qxbm = intern ("xbm");
15283 staticpro (&Qxbm);
a93f4566
GM
15284 QCconversion = intern (":conversion");
15285 staticpro (&QCconversion);
6fc2811b
JR
15286 QCheuristic_mask = intern (":heuristic-mask");
15287 staticpro (&QCheuristic_mask);
15288 QCcolor_symbols = intern (":color-symbols");
15289 staticpro (&QCcolor_symbols);
6fc2811b
JR
15290 QCascent = intern (":ascent");
15291 staticpro (&QCascent);
15292 QCmargin = intern (":margin");
15293 staticpro (&QCmargin);
15294 QCrelief = intern (":relief");
15295 staticpro (&QCrelief);
15296 Qpostscript = intern ("postscript");
15297 staticpro (&Qpostscript);
ac849ba4 15298#if 0 /* TODO: These need entries at top of file. */
6fc2811b
JR
15299 QCloader = intern (":loader");
15300 staticpro (&QCloader);
15301 QCbounding_box = intern (":bounding-box");
15302 staticpro (&QCbounding_box);
15303 QCpt_width = intern (":pt-width");
15304 staticpro (&QCpt_width);
15305 QCpt_height = intern (":pt-height");
15306 staticpro (&QCpt_height);
ac849ba4 15307#endif
6fc2811b
JR
15308 QCindex = intern (":index");
15309 staticpro (&QCindex);
15310 Qpbm = intern ("pbm");
15311 staticpro (&Qpbm);
15312
15313#if HAVE_XPM
15314 Qxpm = intern ("xpm");
15315 staticpro (&Qxpm);
15316#endif
15317
15318#if HAVE_JPEG
15319 Qjpeg = intern ("jpeg");
15320 staticpro (&Qjpeg);
15321#endif
15322
15323#if HAVE_TIFF
15324 Qtiff = intern ("tiff");
15325 staticpro (&Qtiff);
15326#endif
15327
15328#if HAVE_GIF
15329 Qgif = intern ("gif");
15330 staticpro (&Qgif);
15331#endif
15332
15333#if HAVE_PNG
15334 Qpng = intern ("png");
15335 staticpro (&Qpng);
15336#endif
15337
15338 defsubr (&Sclear_image_cache);
ac849ba4
JR
15339 defsubr (&Simage_size);
15340 defsubr (&Simage_mask_p);
6fc2811b
JR
15341
15342#if GLYPH_DEBUG
15343 defsubr (&Simagep);
15344 defsubr (&Slookup_image);
15345#endif
6fc2811b 15346
0af913d7
GM
15347 hourglass_atimer = NULL;
15348 hourglass_shown_p = 0;
6fc2811b
JR
15349 defsubr (&Sx_show_tip);
15350 defsubr (&Sx_hide_tip);
6fc2811b 15351 tip_timer = Qnil;
57fa2774
JR
15352 staticpro (&tip_timer);
15353 tip_frame = Qnil;
15354 staticpro (&tip_frame);
6fc2811b 15355
ca56d953
JR
15356 last_show_tip_args = Qnil;
15357 staticpro (&last_show_tip_args);
15358
6fc2811b
JR
15359 defsubr (&Sx_file_dialog);
15360}
15361
15362
15363void
15364init_xfns ()
15365{
15366 image_types = NULL;
15367 Vimage_types = Qnil;
15368
ac849ba4 15369 define_image_type (&pbm_type);
6fc2811b 15370 define_image_type (&xbm_type);
217e5be0 15371#if 0 /* TODO : Image support for W32 */
6fc2811b 15372 define_image_type (&gs_type);
ac849ba4 15373#endif
6fc2811b
JR
15374
15375#if HAVE_XPM
15376 define_image_type (&xpm_type);
15377#endif
15378
15379#if HAVE_JPEG
15380 define_image_type (&jpeg_type);
15381#endif
15382
15383#if HAVE_TIFF
15384 define_image_type (&tiff_type);
15385#endif
919f1e88 15386
6fc2811b
JR
15387#if HAVE_GIF
15388 define_image_type (&gif_type);
15389#endif
15390
15391#if HAVE_PNG
15392 define_image_type (&png_type);
15393#endif
ee78dc32
GV
15394}
15395
15396#undef abort
15397
15398void
fbd6baed 15399w32_abort()
ee78dc32 15400{
5ac45f98
GV
15401 int button;
15402 button = MessageBox (NULL,
15403 "A fatal error has occurred!\n\n"
15404 "Select Abort to exit, Retry to debug, Ignore to continue",
15405 "Emacs Abort Dialog",
15406 MB_ICONEXCLAMATION | MB_TASKMODAL
15407 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15408 switch (button)
15409 {
15410 case IDRETRY:
15411 DebugBreak ();
15412 break;
15413 case IDIGNORE:
15414 break;
15415 case IDABORT:
15416 default:
15417 abort ();
15418 break;
15419 }
ee78dc32 15420}
d573caac 15421
83c75055
GV
15422/* For convenience when debugging. */
15423int
15424w32_last_error()
15425{
15426 return GetLastError ();
15427}