Use an icon with a transparent background, to be in
[bpt/emacs.git] / src / w32fns.c
CommitLineData
e9e23e23 1/* Graphical user interface functions for the Microsoft W32 API.
8681157a 2 Copyright (C) 1989, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
ee78dc32
GV
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
ee78dc32
GV
20
21/* Added by Kevin Gallo */
22
ee78dc32 23#include <config.h>
1edf84e7
GV
24
25#include <signal.h>
ee78dc32 26#include <stdio.h>
1edf84e7
GV
27#include <limits.h>
28#include <errno.h>
ee78dc32
GV
29
30#include "lisp.h"
4587b026
GV
31#include "charset.h"
32#include "fontset.h"
ee78dc32
GV
33#include "w32term.h"
34#include "frame.h"
35#include "window.h"
36#include "buffer.h"
37#include "dispextern.h"
38#include "keyboard.h"
39#include "blockinput.h"
57bda87a 40#include "epaths.h"
489f9371 41#include "w32heap.h"
ee78dc32 42#include "termhooks.h"
4587b026 43#include "coding.h"
ee78dc32
GV
44
45#include <commdlg.h>
cb9e33d4 46#include <shellapi.h>
ee78dc32
GV
47
48extern void abort ();
49extern void free_frame_menubar ();
50extern struct scroll_bar *x_window_to_scroll_bar ();
adcc3809 51extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
5ac45f98 52extern int quit_char;
ee78dc32 53
ccc2d29c
GV
54extern char *lispy_function_keys[];
55
ee78dc32 56/* The colormap for converting color names to RGB values */
fbd6baed 57Lisp_Object Vw32_color_map;
ee78dc32 58
da36a4d6 59/* Non nil if alt key presses are passed on to Windows. */
fbd6baed 60Lisp_Object Vw32_pass_alt_to_system;
da36a4d6 61
8c205c63
RS
62/* Non nil if alt key is translated to meta_modifier, nil if it is translated
63 to alt_modifier. */
fbd6baed 64Lisp_Object Vw32_alt_is_meta;
8c205c63 65
7d081355
AI
66/* If non-zero, the windows virtual key code for an alternative quit key. */
67Lisp_Object Vw32_quit_key;
68
ccc2d29c
GV
69/* Non nil if left window key events are passed on to Windows (this only
70 affects whether "tapping" the key opens the Start menu). */
71Lisp_Object Vw32_pass_lwindow_to_system;
72
73/* Non nil if right window key events are passed on to Windows (this
74 only affects whether "tapping" the key opens the Start menu). */
75Lisp_Object Vw32_pass_rwindow_to_system;
76
adcc3809
GV
77/* Virtual key code used to generate "phantom" key presses in order
78 to stop system from acting on Windows key events. */
79Lisp_Object Vw32_phantom_key_code;
80
ccc2d29c
GV
81/* Modifier associated with the left "Windows" key, or nil to act as a
82 normal key. */
83Lisp_Object Vw32_lwindow_modifier;
84
85/* Modifier associated with the right "Windows" key, or nil to act as a
86 normal key. */
87Lisp_Object Vw32_rwindow_modifier;
88
89/* Modifier associated with the "Apps" key, or nil to act as a normal
90 key. */
91Lisp_Object Vw32_apps_modifier;
92
93/* Value is nil if Num Lock acts as a function key. */
94Lisp_Object Vw32_enable_num_lock;
95
96/* Value is nil if Caps Lock acts as a function key. */
97Lisp_Object Vw32_enable_caps_lock;
98
99/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
100Lisp_Object Vw32_scroll_lock_modifier;
da36a4d6 101
5ac45f98
GV
102/* Switch to control whether we inhibit requests for italicised fonts (which
103 are synthesized, look ugly, and are trashed by cursor movement under NT). */
fbd6baed 104Lisp_Object Vw32_enable_italics;
5ac45f98
GV
105
106/* Enable palette management. */
fbd6baed 107Lisp_Object Vw32_enable_palette;
5ac45f98
GV
108
109/* Control how close left/right button down events must be to
110 be converted to a middle button down event. */
fbd6baed 111Lisp_Object Vw32_mouse_button_tolerance;
5ac45f98 112
84fb1139
KH
113/* Minimum interval between mouse movement (and scroll bar drag)
114 events that are passed on to the event loop. */
fbd6baed 115Lisp_Object Vw32_mouse_move_interval;
84fb1139 116
ee78dc32
GV
117/* The name we're using in resource queries. */
118Lisp_Object Vx_resource_name;
119
120/* Non nil if no window manager is in use. */
121Lisp_Object Vx_no_window_manager;
122
123/* The background and shape of the mouse pointer, and shape when not
124 over text or in the modeline. */
125Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
126/* The shape when over mouse-sensitive text. */
127Lisp_Object Vx_sensitive_text_pointer_shape;
128
129/* Color of chars displayed in cursor box. */
130Lisp_Object Vx_cursor_fore_pixel;
131
1edf84e7
GV
132/* Nonzero if using Windows. */
133static int w32_in_use;
134
ee78dc32
GV
135/* Search path for bitmap files. */
136Lisp_Object Vx_bitmap_file_path;
137
4587b026
GV
138/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
139Lisp_Object Vx_pixel_size_width_font_regexp;
140
33d52f9c
GV
141/* Alist of bdf fonts and the files that define them. */
142Lisp_Object Vw32_bdf_filename_alist;
143
f46e6225
GV
144Lisp_Object Vw32_system_coding_system;
145
f46e6225 146/* A flag to control whether fonts are matched strictly or not. */
1075afa9
GV
147int w32_strict_fontnames;
148
c0611964
AI
149/* A flag to control whether we should only repaint if GetUpdateRect
150 indicates there is an update region. */
151int w32_strict_painting;
152
ee78dc32
GV
153/* Evaluate this expression to rebuild the section of syms_of_w32fns
154 that initializes and staticpros the symbols declared below. Note
155 that Emacs 18 has a bug that keeps C-x C-e from being able to
156 evaluate this expression.
157
158(progn
159 ;; Accumulate a list of the symbols we want to initialize from the
160 ;; declarations at the top of the file.
161 (goto-char (point-min))
162 (search-forward "/\*&&& symbols declared here &&&*\/\n")
163 (let (symbol-list)
164 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
165 (setq symbol-list
166 (cons (buffer-substring (match-beginning 1) (match-end 1))
167 symbol-list))
168 (forward-line 1))
169 (setq symbol-list (nreverse symbol-list))
170 ;; Delete the section of syms_of_... where we initialize the symbols.
171 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
172 (let ((start (point)))
173 (while (looking-at "^ Q")
174 (forward-line 2))
175 (kill-region start (point)))
176 ;; Write a new symbol initialization section.
177 (while symbol-list
178 (insert (format " %s = intern (\"" (car symbol-list)))
179 (let ((start (point)))
180 (insert (substring (car symbol-list) 1))
181 (subst-char-in-region start (point) ?_ ?-))
182 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
183 (setq symbol-list (cdr symbol-list)))))
184
185 */
186
187/*&&& symbols declared here &&&*/
188Lisp_Object Qauto_raise;
189Lisp_Object Qauto_lower;
190Lisp_Object Qbackground_color;
191Lisp_Object Qbar;
192Lisp_Object Qborder_color;
193Lisp_Object Qborder_width;
194Lisp_Object Qbox;
195Lisp_Object Qcursor_color;
196Lisp_Object Qcursor_type;
ee78dc32
GV
197Lisp_Object Qforeground_color;
198Lisp_Object Qgeometry;
199Lisp_Object Qicon_left;
200Lisp_Object Qicon_top;
201Lisp_Object Qicon_type;
202Lisp_Object Qicon_name;
203Lisp_Object Qinternal_border_width;
204Lisp_Object Qleft;
1026b400 205Lisp_Object Qright;
ee78dc32
GV
206Lisp_Object Qmouse_color;
207Lisp_Object Qnone;
208Lisp_Object Qparent_id;
209Lisp_Object Qscroll_bar_width;
210Lisp_Object Qsuppress_icon;
211Lisp_Object Qtop;
212Lisp_Object Qundefined_color;
213Lisp_Object Qvertical_scroll_bars;
214Lisp_Object Qvisibility;
215Lisp_Object Qwindow_id;
216Lisp_Object Qx_frame_parameter;
217Lisp_Object Qx_resource_name;
218Lisp_Object Quser_position;
219Lisp_Object Quser_size;
220Lisp_Object Qdisplay;
221
adcc3809
GV
222Lisp_Object Qhyper;
223Lisp_Object Qsuper;
224Lisp_Object Qmeta;
225Lisp_Object Qalt;
226Lisp_Object Qctrl;
227Lisp_Object Qcontrol;
228Lisp_Object Qshift;
229
5ac45f98
GV
230/* State variables for emulating a three button mouse. */
231#define LMOUSE 1
232#define MMOUSE 2
233#define RMOUSE 4
234
235static int button_state = 0;
fbd6baed 236static W32Msg saved_mouse_button_msg;
84fb1139 237static unsigned mouse_button_timer; /* non-zero when timer is active */
fbd6baed 238static W32Msg saved_mouse_move_msg;
84fb1139
KH
239static unsigned mouse_move_timer;
240
93fbe8b7
GV
241/* W95 mousewheel handler */
242unsigned int msh_mousewheel = 0;
243
84fb1139
KH
244#define MOUSE_BUTTON_ID 1
245#define MOUSE_MOVE_ID 2
5ac45f98 246
ee78dc32
GV
247/* The below are defined in frame.c. */
248extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
1edf84e7 249extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
ee78dc32
GV
250
251extern Lisp_Object Vwindow_system_version;
252
4b817373
RS
253Lisp_Object Qface_set_after_frame_default;
254
ee78dc32
GV
255extern Lisp_Object last_mouse_scroll_bar;
256extern int last_mouse_scroll_bar_pos;
5ac45f98 257
fbd6baed
GV
258/* From w32term.c. */
259extern Lisp_Object Vw32_num_mouse_buttons;
ccc2d29c 260extern Lisp_Object Vw32_recognize_altgr;
5ac45f98 261
ee78dc32 262\f
1edf84e7
GV
263/* Error if we are not connected to MS-Windows. */
264void
265check_w32 ()
266{
267 if (! w32_in_use)
268 error ("MS-Windows not in use or not initialized");
269}
270
271/* Nonzero if we can use mouse menus.
272 You should not call this unless HAVE_MENUS is defined. */
273
274int
275have_menus_p ()
276{
277 return w32_in_use;
278}
279
ee78dc32 280/* Extract a frame as a FRAME_PTR, defaulting to the selected frame
fbd6baed 281 and checking validity for W32. */
ee78dc32
GV
282
283FRAME_PTR
284check_x_frame (frame)
285 Lisp_Object frame;
286{
287 FRAME_PTR f;
288
289 if (NILP (frame))
290 f = selected_frame;
291 else
292 {
293 CHECK_LIVE_FRAME (frame, 0);
294 f = XFRAME (frame);
295 }
fbd6baed
GV
296 if (! FRAME_W32_P (f))
297 error ("non-w32 frame used");
ee78dc32
GV
298 return f;
299}
300
301/* Let the user specify an display with a frame.
fbd6baed 302 nil stands for the selected frame--or, if that is not a w32 frame,
ee78dc32
GV
303 the first display on the list. */
304
fbd6baed 305static struct w32_display_info *
ee78dc32
GV
306check_x_display_info (frame)
307 Lisp_Object frame;
308{
309 if (NILP (frame))
310 {
fbd6baed
GV
311 if (FRAME_W32_P (selected_frame))
312 return FRAME_W32_DISPLAY_INFO (selected_frame);
ee78dc32 313 else
fbd6baed 314 return &one_w32_display_info;
ee78dc32
GV
315 }
316 else if (STRINGP (frame))
317 return x_display_info_for_name (frame);
318 else
319 {
320 FRAME_PTR f;
321
322 CHECK_LIVE_FRAME (frame, 0);
323 f = XFRAME (frame);
fbd6baed
GV
324 if (! FRAME_W32_P (f))
325 error ("non-w32 frame used");
326 return FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
327 }
328}
329\f
fbd6baed 330/* Return the Emacs frame-object corresponding to an w32 window.
ee78dc32
GV
331 It could be the frame's main window or an icon window. */
332
333/* This function can be called during GC, so use GC_xxx type test macros. */
334
335struct frame *
336x_window_to_frame (dpyinfo, wdesc)
fbd6baed 337 struct w32_display_info *dpyinfo;
ee78dc32
GV
338 HWND wdesc;
339{
340 Lisp_Object tail, frame;
341 struct frame *f;
342
343 for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr)
344 {
345 frame = XCONS (tail)->car;
346 if (!GC_FRAMEP (frame))
347 continue;
348 f = XFRAME (frame);
349 if (f->output_data.nothing == 1
fbd6baed 350 || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
ee78dc32 351 continue;
fbd6baed 352 if (FRAME_W32_WINDOW (f) == wdesc)
ee78dc32
GV
353 return f;
354 }
355 return 0;
356}
357
358\f
359
360/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
361 id, which is just an int that this section returns. Bitmaps are
362 reference counted so they can be shared among frames.
363
364 Bitmap indices are guaranteed to be > 0, so a negative number can
365 be used to indicate no bitmap.
366
367 If you use x_create_bitmap_from_data, then you must keep track of
368 the bitmaps yourself. That is, creating a bitmap from the same
369 data more than once will not be caught. */
370
371
372/* Functions to access the contents of a bitmap, given an id. */
373
374int
375x_bitmap_height (f, id)
376 FRAME_PTR f;
377 int id;
378{
fbd6baed 379 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
ee78dc32
GV
380}
381
382int
383x_bitmap_width (f, id)
384 FRAME_PTR f;
385 int id;
386{
fbd6baed 387 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
ee78dc32
GV
388}
389
390int
391x_bitmap_pixmap (f, id)
392 FRAME_PTR f;
393 int id;
394{
fbd6baed 395 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
ee78dc32
GV
396}
397
398
399/* Allocate a new bitmap record. Returns index of new record. */
400
401static int
402x_allocate_bitmap_record (f)
403 FRAME_PTR f;
404{
fbd6baed 405 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
406 int i;
407
408 if (dpyinfo->bitmaps == NULL)
409 {
410 dpyinfo->bitmaps_size = 10;
411 dpyinfo->bitmaps
fbd6baed 412 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
413 dpyinfo->bitmaps_last = 1;
414 return 1;
415 }
416
417 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
418 return ++dpyinfo->bitmaps_last;
419
420 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
421 if (dpyinfo->bitmaps[i].refcount == 0)
422 return i + 1;
423
424 dpyinfo->bitmaps_size *= 2;
425 dpyinfo->bitmaps
fbd6baed
GV
426 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
427 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
ee78dc32
GV
428 return ++dpyinfo->bitmaps_last;
429}
430
431/* Add one reference to the reference count of the bitmap with id ID. */
432
433void
434x_reference_bitmap (f, id)
435 FRAME_PTR f;
436 int id;
437{
fbd6baed 438 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
ee78dc32
GV
439}
440
441/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
442
443int
444x_create_bitmap_from_data (f, bits, width, height)
445 struct frame *f;
446 char *bits;
447 unsigned int width, height;
448{
fbd6baed 449 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
450 Pixmap bitmap;
451 int id;
452
453 bitmap = CreateBitmap (width, height,
fbd6baed
GV
454 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
455 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
ee78dc32
GV
456 bits);
457
458 if (! bitmap)
459 return -1;
460
461 id = x_allocate_bitmap_record (f);
462 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
463 dpyinfo->bitmaps[id - 1].file = NULL;
464 dpyinfo->bitmaps[id - 1].hinst = NULL;
465 dpyinfo->bitmaps[id - 1].refcount = 1;
466 dpyinfo->bitmaps[id - 1].depth = 1;
467 dpyinfo->bitmaps[id - 1].height = height;
468 dpyinfo->bitmaps[id - 1].width = width;
469
470 return id;
471}
472
473/* Create bitmap from file FILE for frame F. */
474
475int
476x_create_bitmap_from_file (f, file)
477 struct frame *f;
478 Lisp_Object file;
479{
480 return -1;
481#if 0
fbd6baed 482 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
483 unsigned int width, height;
484 Pixmap bitmap;
485 int xhot, yhot, result, id;
486 Lisp_Object found;
487 int fd;
488 char *filename;
489 HINSTANCE hinst;
490
491 /* Look for an existing bitmap with the same name. */
492 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
493 {
494 if (dpyinfo->bitmaps[id].refcount
495 && dpyinfo->bitmaps[id].file
496 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
497 {
498 ++dpyinfo->bitmaps[id].refcount;
499 return id + 1;
500 }
501 }
502
503 /* Search bitmap-file-path for the file, if appropriate. */
504 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
505 if (fd < 0)
506 return -1;
5d7fed93
GV
507 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
508 if (fd == 0)
509 return -1;
ee78dc32
GV
510 close (fd);
511
512 filename = (char *) XSTRING (found)->data;
513
514 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
515
516 if (hinst == NULL)
517 return -1;
518
519
fbd6baed 520 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
ee78dc32
GV
521 filename, &width, &height, &bitmap, &xhot, &yhot);
522 if (result != BitmapSuccess)
523 return -1;
524
525 id = x_allocate_bitmap_record (f);
526 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
527 dpyinfo->bitmaps[id - 1].refcount = 1;
528 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
529 dpyinfo->bitmaps[id - 1].depth = 1;
530 dpyinfo->bitmaps[id - 1].height = height;
531 dpyinfo->bitmaps[id - 1].width = width;
532 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
533
534 return id;
535#endif
536}
537
538/* Remove reference to bitmap with id number ID. */
539
33d52f9c 540void
ee78dc32
GV
541x_destroy_bitmap (f, id)
542 FRAME_PTR f;
543 int id;
544{
fbd6baed 545 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
ee78dc32
GV
546
547 if (id > 0)
548 {
549 --dpyinfo->bitmaps[id - 1].refcount;
550 if (dpyinfo->bitmaps[id - 1].refcount == 0)
551 {
552 BLOCK_INPUT;
553 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
554 if (dpyinfo->bitmaps[id - 1].file)
555 {
556 free (dpyinfo->bitmaps[id - 1].file);
557 dpyinfo->bitmaps[id - 1].file = NULL;
558 }
559 UNBLOCK_INPUT;
560 }
561 }
562}
563
564/* Free all the bitmaps for the display specified by DPYINFO. */
565
566static void
567x_destroy_all_bitmaps (dpyinfo)
fbd6baed 568 struct w32_display_info *dpyinfo;
ee78dc32
GV
569{
570 int i;
571 for (i = 0; i < dpyinfo->bitmaps_last; i++)
572 if (dpyinfo->bitmaps[i].refcount > 0)
573 {
574 DeleteObject (dpyinfo->bitmaps[i].pixmap);
575 if (dpyinfo->bitmaps[i].file)
576 free (dpyinfo->bitmaps[i].file);
577 }
578 dpyinfo->bitmaps_last = 0;
579}
580\f
fbd6baed 581/* Connect the frame-parameter names for W32 frames
ee78dc32
GV
582 to the ways of passing the parameter values to the window system.
583
584 The name of a parameter, as a Lisp symbol,
585 has an `x-frame-parameter' property which is an integer in Lisp
586 but can be interpreted as an `enum x_frame_parm' in C. */
587
588enum x_frame_parm
589{
590 X_PARM_FOREGROUND_COLOR,
591 X_PARM_BACKGROUND_COLOR,
592 X_PARM_MOUSE_COLOR,
593 X_PARM_CURSOR_COLOR,
594 X_PARM_BORDER_COLOR,
595 X_PARM_ICON_TYPE,
596 X_PARM_FONT,
597 X_PARM_BORDER_WIDTH,
598 X_PARM_INTERNAL_BORDER_WIDTH,
599 X_PARM_NAME,
600 X_PARM_AUTORAISE,
601 X_PARM_AUTOLOWER,
602 X_PARM_VERT_SCROLL_BAR,
603 X_PARM_VISIBILITY,
604 X_PARM_MENU_BAR_LINES
605};
606
607
608struct x_frame_parm_table
609{
610 char *name;
611 void (*setter)( /* struct frame *frame, Lisp_Object val, oldval */ );
612};
613
614void x_set_foreground_color ();
615void x_set_background_color ();
616void x_set_mouse_color ();
617void x_set_cursor_color ();
618void x_set_border_color ();
619void x_set_cursor_type ();
620void x_set_icon_type ();
621void x_set_icon_name ();
622void x_set_font ();
623void x_set_border_width ();
624void x_set_internal_border_width ();
625void x_explicitly_set_name ();
626void x_set_autoraise ();
627void x_set_autolower ();
628void x_set_vertical_scroll_bars ();
629void x_set_visibility ();
630void x_set_menu_bar_lines ();
631void x_set_scroll_bar_width ();
1edf84e7 632void x_set_title ();
ee78dc32
GV
633void x_set_unsplittable ();
634
635static struct x_frame_parm_table x_frame_parms[] =
636{
1edf84e7
GV
637 "auto-raise", x_set_autoraise,
638 "auto-lower", x_set_autolower,
ee78dc32 639 "background-color", x_set_background_color,
ee78dc32 640 "border-color", x_set_border_color,
1edf84e7
GV
641 "border-width", x_set_border_width,
642 "cursor-color", x_set_cursor_color,
ee78dc32 643 "cursor-type", x_set_cursor_type,
ee78dc32 644 "font", x_set_font,
1edf84e7
GV
645 "foreground-color", x_set_foreground_color,
646 "icon-name", x_set_icon_name,
647 "icon-type", x_set_icon_type,
ee78dc32 648 "internal-border-width", x_set_internal_border_width,
ee78dc32 649 "menu-bar-lines", x_set_menu_bar_lines,
1edf84e7
GV
650 "mouse-color", x_set_mouse_color,
651 "name", x_explicitly_set_name,
ee78dc32 652 "scroll-bar-width", x_set_scroll_bar_width,
1edf84e7 653 "title", x_set_title,
ee78dc32 654 "unsplittable", x_set_unsplittable,
1edf84e7
GV
655 "vertical-scroll-bars", x_set_vertical_scroll_bars,
656 "visibility", x_set_visibility,
ee78dc32
GV
657};
658
659/* Attach the `x-frame-parameter' properties to
fbd6baed 660 the Lisp symbol names of parameters relevant to W32. */
ee78dc32
GV
661
662init_x_parm_symbols ()
663{
664 int i;
665
666 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
667 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
668 make_number (i));
669}
670\f
671/* Change the parameters of FRAME as specified by ALIST.
672 If a parameter is not specially recognized, do nothing;
673 otherwise call the `x_set_...' function for that parameter. */
674
675void
676x_set_frame_parameters (f, alist)
677 FRAME_PTR f;
678 Lisp_Object alist;
679{
680 Lisp_Object tail;
681
682 /* If both of these parameters are present, it's more efficient to
683 set them both at once. So we wait until we've looked at the
684 entire list before we set them. */
b839712d 685 int width, height;
ee78dc32
GV
686
687 /* Same here. */
688 Lisp_Object left, top;
689
690 /* Same with these. */
691 Lisp_Object icon_left, icon_top;
692
693 /* Record in these vectors all the parms specified. */
694 Lisp_Object *parms;
695 Lisp_Object *values;
696 int i;
697 int left_no_change = 0, top_no_change = 0;
698 int icon_left_no_change = 0, icon_top_no_change = 0;
699
5878523b
RS
700 struct gcpro gcpro1, gcpro2;
701
ee78dc32
GV
702 i = 0;
703 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
704 i++;
705
706 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
707 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
708
709 /* Extract parm names and values into those vectors. */
710
711 i = 0;
712 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
713 {
714 Lisp_Object elt, prop, val;
715
716 elt = Fcar (tail);
717 parms[i] = Fcar (elt);
718 values[i] = Fcdr (elt);
719 i++;
720 }
721
5878523b
RS
722 /* TAIL and ALIST are not used again below here. */
723 alist = tail = Qnil;
724
725 GCPRO2 (*parms, *values);
726 gcpro1.nvars = i;
727 gcpro2.nvars = i;
728
729 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
730 because their values appear in VALUES and strings are not valid. */
b839712d 731 top = left = Qunbound;
ee78dc32
GV
732 icon_left = icon_top = Qunbound;
733
b839712d
RS
734 /* Provide default values for HEIGHT and WIDTH. */
735 width = FRAME_WIDTH (f);
736 height = FRAME_HEIGHT (f);
737
ee78dc32
GV
738 /* Now process them in reverse of specified order. */
739 for (i--; i >= 0; i--)
740 {
741 Lisp_Object prop, val;
742
743 prop = parms[i];
744 val = values[i];
745
b839712d
RS
746 if (EQ (prop, Qwidth) && NUMBERP (val))
747 width = XFASTINT (val);
748 else if (EQ (prop, Qheight) && NUMBERP (val))
749 height = XFASTINT (val);
ee78dc32
GV
750 else if (EQ (prop, Qtop))
751 top = val;
752 else if (EQ (prop, Qleft))
753 left = val;
754 else if (EQ (prop, Qicon_top))
755 icon_top = val;
756 else if (EQ (prop, Qicon_left))
757 icon_left = val;
758 else
759 {
760 register Lisp_Object param_index, old_value;
761
762 param_index = Fget (prop, Qx_frame_parameter);
763 old_value = get_frame_param (f, prop);
764 store_frame_param (f, prop, val);
765 if (NATNUMP (param_index)
766 && (XFASTINT (param_index)
767 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
3c190163 768 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
ee78dc32
GV
769 }
770 }
771
772 /* Don't die if just one of these was set. */
773 if (EQ (left, Qunbound))
774 {
775 left_no_change = 1;
fbd6baed
GV
776 if (f->output_data.w32->left_pos < 0)
777 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
ee78dc32 778 else
fbd6baed 779 XSETINT (left, f->output_data.w32->left_pos);
ee78dc32
GV
780 }
781 if (EQ (top, Qunbound))
782 {
783 top_no_change = 1;
fbd6baed
GV
784 if (f->output_data.w32->top_pos < 0)
785 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
ee78dc32 786 else
fbd6baed 787 XSETINT (top, f->output_data.w32->top_pos);
ee78dc32
GV
788 }
789
790 /* If one of the icon positions was not set, preserve or default it. */
791 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
792 {
793 icon_left_no_change = 1;
794 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
795 if (NILP (icon_left))
796 XSETINT (icon_left, 0);
797 }
798 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
799 {
800 icon_top_no_change = 1;
801 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
802 if (NILP (icon_top))
803 XSETINT (icon_top, 0);
804 }
805
ee78dc32
GV
806 /* Don't set these parameters unless they've been explicitly
807 specified. The window might be mapped or resized while we're in
808 this function, and we don't want to override that unless the lisp
809 code has asked for it.
810
811 Don't set these parameters unless they actually differ from the
812 window's current parameters; the window may not actually exist
813 yet. */
814 {
815 Lisp_Object frame;
816
817 check_frame_size (f, &height, &width);
818
819 XSETFRAME (frame, f);
820
b839712d
RS
821 if (XINT (width) != FRAME_WIDTH (f)
822 || XINT (height) != FRAME_HEIGHT (f))
823 Fset_frame_size (frame, make_number (width), make_number (height));
ee78dc32
GV
824
825 if ((!NILP (left) || !NILP (top))
826 && ! (left_no_change && top_no_change)
fbd6baed
GV
827 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
828 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
ee78dc32
GV
829 {
830 int leftpos = 0;
831 int toppos = 0;
832
833 /* Record the signs. */
fbd6baed 834 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 835 if (EQ (left, Qminus))
fbd6baed 836 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
837 else if (INTEGERP (left))
838 {
839 leftpos = XINT (left);
840 if (leftpos < 0)
fbd6baed 841 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
842 }
843 else if (CONSP (left) && EQ (XCONS (left)->car, Qminus)
844 && CONSP (XCONS (left)->cdr)
845 && INTEGERP (XCONS (XCONS (left)->cdr)->car))
846 {
847 leftpos = - XINT (XCONS (XCONS (left)->cdr)->car);
fbd6baed 848 f->output_data.w32->size_hint_flags |= XNegative;
ee78dc32
GV
849 }
850 else if (CONSP (left) && EQ (XCONS (left)->car, Qplus)
851 && CONSP (XCONS (left)->cdr)
852 && INTEGERP (XCONS (XCONS (left)->cdr)->car))
853 {
854 leftpos = XINT (XCONS (XCONS (left)->cdr)->car);
855 }
856
857 if (EQ (top, Qminus))
fbd6baed 858 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
859 else if (INTEGERP (top))
860 {
861 toppos = XINT (top);
862 if (toppos < 0)
fbd6baed 863 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
864 }
865 else if (CONSP (top) && EQ (XCONS (top)->car, Qminus)
866 && CONSP (XCONS (top)->cdr)
867 && INTEGERP (XCONS (XCONS (top)->cdr)->car))
868 {
869 toppos = - XINT (XCONS (XCONS (top)->cdr)->car);
fbd6baed 870 f->output_data.w32->size_hint_flags |= YNegative;
ee78dc32
GV
871 }
872 else if (CONSP (top) && EQ (XCONS (top)->car, Qplus)
873 && CONSP (XCONS (top)->cdr)
874 && INTEGERP (XCONS (XCONS (top)->cdr)->car))
875 {
876 toppos = XINT (XCONS (XCONS (top)->cdr)->car);
877 }
878
879
880 /* Store the numeric value of the position. */
fbd6baed
GV
881 f->output_data.w32->top_pos = toppos;
882 f->output_data.w32->left_pos = leftpos;
ee78dc32 883
fbd6baed 884 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
885
886 /* Actually set that position, and convert to absolute. */
887 x_set_offset (f, leftpos, toppos, -1);
888 }
889
890 if ((!NILP (icon_left) || !NILP (icon_top))
891 && ! (icon_left_no_change && icon_top_no_change))
892 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
893 }
5878523b
RS
894
895 UNGCPRO;
ee78dc32
GV
896}
897
898/* Store the screen positions of frame F into XPTR and YPTR.
899 These are the positions of the containing window manager window,
900 not Emacs's own window. */
901
902void
903x_real_positions (f, xptr, yptr)
904 FRAME_PTR f;
905 int *xptr, *yptr;
906{
907 POINT pt;
3c190163
GV
908
909 {
910 RECT rect;
ee78dc32 911
fbd6baed
GV
912 GetClientRect(FRAME_W32_WINDOW(f), &rect);
913 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
ee78dc32 914
3c190163
GV
915 pt.x = rect.left;
916 pt.y = rect.top;
917 }
ee78dc32 918
fbd6baed 919 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
ee78dc32
GV
920
921 *xptr = pt.x;
922 *yptr = pt.y;
923}
924
925/* Insert a description of internally-recorded parameters of frame X
926 into the parameter alist *ALISTPTR that is to be given to the user.
fbd6baed 927 Only parameters that are specific to W32
ee78dc32
GV
928 and whose values are not correctly recorded in the frame's
929 param_alist need to be considered here. */
930
931x_report_frame_params (f, alistptr)
932 struct frame *f;
933 Lisp_Object *alistptr;
934{
935 char buf[16];
936 Lisp_Object tem;
937
938 /* Represent negative positions (off the top or left screen edge)
939 in a way that Fmodify_frame_parameters will understand correctly. */
fbd6baed
GV
940 XSETINT (tem, f->output_data.w32->left_pos);
941 if (f->output_data.w32->left_pos >= 0)
ee78dc32
GV
942 store_in_alist (alistptr, Qleft, tem);
943 else
944 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
945
fbd6baed
GV
946 XSETINT (tem, f->output_data.w32->top_pos);
947 if (f->output_data.w32->top_pos >= 0)
ee78dc32
GV
948 store_in_alist (alistptr, Qtop, tem);
949 else
950 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
951
952 store_in_alist (alistptr, Qborder_width,
fbd6baed 953 make_number (f->output_data.w32->border_width));
ee78dc32 954 store_in_alist (alistptr, Qinternal_border_width,
fbd6baed
GV
955 make_number (f->output_data.w32->internal_border_width));
956 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
ee78dc32
GV
957 store_in_alist (alistptr, Qwindow_id,
958 build_string (buf));
959 store_in_alist (alistptr, Qicon_name, f->icon_name);
960 FRAME_SAMPLE_VISIBILITY (f);
961 store_in_alist (alistptr, Qvisibility,
962 (FRAME_VISIBLE_P (f) ? Qt
963 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
964 store_in_alist (alistptr, Qdisplay,
fbd6baed 965 XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->car);
ee78dc32
GV
966}
967\f
968
fbd6baed 969DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
5ac45f98 970 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
fbd6baed 971This adds or updates a named color to w32-color-map, making it available for use.\n\
5ac45f98
GV
972The original entry's RGB ref is returned, or nil if the entry is new.")
973 (red, green, blue, name)
974 Lisp_Object red, green, blue, name;
ee78dc32 975{
5ac45f98
GV
976 Lisp_Object rgb;
977 Lisp_Object oldrgb = Qnil;
978 Lisp_Object entry;
979
980 CHECK_NUMBER (red, 0);
981 CHECK_NUMBER (green, 0);
982 CHECK_NUMBER (blue, 0);
983 CHECK_STRING (name, 0);
ee78dc32 984
5ac45f98 985 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
ee78dc32 986
5ac45f98 987 BLOCK_INPUT;
ee78dc32 988
fbd6baed
GV
989 /* replace existing entry in w32-color-map or add new entry. */
990 entry = Fassoc (name, Vw32_color_map);
5ac45f98
GV
991 if (NILP (entry))
992 {
993 entry = Fcons (name, rgb);
fbd6baed 994 Vw32_color_map = Fcons (entry, Vw32_color_map);
5ac45f98
GV
995 }
996 else
997 {
998 oldrgb = Fcdr (entry);
999 Fsetcdr (entry, rgb);
1000 }
1001
1002 UNBLOCK_INPUT;
1003
1004 return (oldrgb);
ee78dc32
GV
1005}
1006
fbd6baed 1007DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
5ac45f98 1008 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
fbd6baed 1009Assign this value to w32-color-map to replace the existing color map.\n\
5ac45f98
GV
1010\
1011The file should define one named RGB color per line like so:\
1012 R G B name\n\
1013where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1014 (filename)
1015 Lisp_Object filename;
1016{
1017 FILE *fp;
1018 Lisp_Object cmap = Qnil;
1019 Lisp_Object abspath;
1020
1021 CHECK_STRING (filename, 0);
1022 abspath = Fexpand_file_name (filename, Qnil);
1023
1024 fp = fopen (XSTRING (filename)->data, "rt");
1025 if (fp)
1026 {
1027 char buf[512];
1028 int red, green, blue;
1029 int num;
1030
1031 BLOCK_INPUT;
1032
1033 while (fgets (buf, sizeof (buf), fp) != NULL) {
1034 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1035 {
1036 char *name = buf + num;
1037 num = strlen (name) - 1;
1038 if (name[num] == '\n')
1039 name[num] = 0;
1040 cmap = Fcons (Fcons (build_string (name),
1041 make_number (RGB (red, green, blue))),
1042 cmap);
1043 }
1044 }
1045 fclose (fp);
1046
1047 UNBLOCK_INPUT;
1048 }
1049
1050 return cmap;
1051}
ee78dc32 1052
fbd6baed 1053/* The default colors for the w32 color map */
ee78dc32
GV
1054typedef struct colormap_t
1055{
1056 char *name;
1057 COLORREF colorref;
1058} colormap_t;
1059
fbd6baed 1060colormap_t w32_color_map[] =
ee78dc32 1061{
1da8a614
GV
1062 {"snow" , PALETTERGB (255,250,250)},
1063 {"ghost white" , PALETTERGB (248,248,255)},
1064 {"GhostWhite" , PALETTERGB (248,248,255)},
1065 {"white smoke" , PALETTERGB (245,245,245)},
1066 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1067 {"gainsboro" , PALETTERGB (220,220,220)},
1068 {"floral white" , PALETTERGB (255,250,240)},
1069 {"FloralWhite" , PALETTERGB (255,250,240)},
1070 {"old lace" , PALETTERGB (253,245,230)},
1071 {"OldLace" , PALETTERGB (253,245,230)},
1072 {"linen" , PALETTERGB (250,240,230)},
1073 {"antique white" , PALETTERGB (250,235,215)},
1074 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1075 {"papaya whip" , PALETTERGB (255,239,213)},
1076 {"PapayaWhip" , PALETTERGB (255,239,213)},
1077 {"blanched almond" , PALETTERGB (255,235,205)},
1078 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1079 {"bisque" , PALETTERGB (255,228,196)},
1080 {"peach puff" , PALETTERGB (255,218,185)},
1081 {"PeachPuff" , PALETTERGB (255,218,185)},
1082 {"navajo white" , PALETTERGB (255,222,173)},
1083 {"NavajoWhite" , PALETTERGB (255,222,173)},
1084 {"moccasin" , PALETTERGB (255,228,181)},
1085 {"cornsilk" , PALETTERGB (255,248,220)},
1086 {"ivory" , PALETTERGB (255,255,240)},
1087 {"lemon chiffon" , PALETTERGB (255,250,205)},
1088 {"LemonChiffon" , PALETTERGB (255,250,205)},
1089 {"seashell" , PALETTERGB (255,245,238)},
1090 {"honeydew" , PALETTERGB (240,255,240)},
1091 {"mint cream" , PALETTERGB (245,255,250)},
1092 {"MintCream" , PALETTERGB (245,255,250)},
1093 {"azure" , PALETTERGB (240,255,255)},
1094 {"alice blue" , PALETTERGB (240,248,255)},
1095 {"AliceBlue" , PALETTERGB (240,248,255)},
1096 {"lavender" , PALETTERGB (230,230,250)},
1097 {"lavender blush" , PALETTERGB (255,240,245)},
1098 {"LavenderBlush" , PALETTERGB (255,240,245)},
1099 {"misty rose" , PALETTERGB (255,228,225)},
1100 {"MistyRose" , PALETTERGB (255,228,225)},
1101 {"white" , PALETTERGB (255,255,255)},
1102 {"black" , PALETTERGB ( 0, 0, 0)},
1103 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1104 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1105 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1106 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1107 {"dim gray" , PALETTERGB (105,105,105)},
1108 {"DimGray" , PALETTERGB (105,105,105)},
1109 {"dim grey" , PALETTERGB (105,105,105)},
1110 {"DimGrey" , PALETTERGB (105,105,105)},
1111 {"slate gray" , PALETTERGB (112,128,144)},
1112 {"SlateGray" , PALETTERGB (112,128,144)},
1113 {"slate grey" , PALETTERGB (112,128,144)},
1114 {"SlateGrey" , PALETTERGB (112,128,144)},
1115 {"light slate gray" , PALETTERGB (119,136,153)},
1116 {"LightSlateGray" , PALETTERGB (119,136,153)},
1117 {"light slate grey" , PALETTERGB (119,136,153)},
1118 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1119 {"gray" , PALETTERGB (190,190,190)},
1120 {"grey" , PALETTERGB (190,190,190)},
1121 {"light grey" , PALETTERGB (211,211,211)},
1122 {"LightGrey" , PALETTERGB (211,211,211)},
1123 {"light gray" , PALETTERGB (211,211,211)},
1124 {"LightGray" , PALETTERGB (211,211,211)},
1125 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1126 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1127 {"navy" , PALETTERGB ( 0, 0,128)},
1128 {"navy blue" , PALETTERGB ( 0, 0,128)},
1129 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1130 {"cornflower blue" , PALETTERGB (100,149,237)},
1131 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1132 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1133 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1134 {"slate blue" , PALETTERGB (106, 90,205)},
1135 {"SlateBlue" , PALETTERGB (106, 90,205)},
1136 {"medium slate blue" , PALETTERGB (123,104,238)},
1137 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1138 {"light slate blue" , PALETTERGB (132,112,255)},
1139 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1140 {"medium blue" , PALETTERGB ( 0, 0,205)},
1141 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1142 {"royal blue" , PALETTERGB ( 65,105,225)},
1143 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1144 {"blue" , PALETTERGB ( 0, 0,255)},
1145 {"dodger blue" , PALETTERGB ( 30,144,255)},
1146 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1147 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1148 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1149 {"sky blue" , PALETTERGB (135,206,235)},
1150 {"SkyBlue" , PALETTERGB (135,206,235)},
1151 {"light sky blue" , PALETTERGB (135,206,250)},
1152 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1153 {"steel blue" , PALETTERGB ( 70,130,180)},
1154 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1155 {"light steel blue" , PALETTERGB (176,196,222)},
1156 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1157 {"light blue" , PALETTERGB (173,216,230)},
1158 {"LightBlue" , PALETTERGB (173,216,230)},
1159 {"powder blue" , PALETTERGB (176,224,230)},
1160 {"PowderBlue" , PALETTERGB (176,224,230)},
1161 {"pale turquoise" , PALETTERGB (175,238,238)},
1162 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1163 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1164 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1165 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1166 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1167 {"turquoise" , PALETTERGB ( 64,224,208)},
1168 {"cyan" , PALETTERGB ( 0,255,255)},
1169 {"light cyan" , PALETTERGB (224,255,255)},
1170 {"LightCyan" , PALETTERGB (224,255,255)},
1171 {"cadet blue" , PALETTERGB ( 95,158,160)},
1172 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1173 {"medium aquamarine" , PALETTERGB (102,205,170)},
1174 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1175 {"aquamarine" , PALETTERGB (127,255,212)},
1176 {"dark green" , PALETTERGB ( 0,100, 0)},
1177 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1178 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1179 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1180 {"dark sea green" , PALETTERGB (143,188,143)},
1181 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1182 {"sea green" , PALETTERGB ( 46,139, 87)},
1183 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1184 {"medium sea green" , PALETTERGB ( 60,179,113)},
1185 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1186 {"light sea green" , PALETTERGB ( 32,178,170)},
1187 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1188 {"pale green" , PALETTERGB (152,251,152)},
1189 {"PaleGreen" , PALETTERGB (152,251,152)},
1190 {"spring green" , PALETTERGB ( 0,255,127)},
1191 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1192 {"lawn green" , PALETTERGB (124,252, 0)},
1193 {"LawnGreen" , PALETTERGB (124,252, 0)},
1194 {"green" , PALETTERGB ( 0,255, 0)},
1195 {"chartreuse" , PALETTERGB (127,255, 0)},
1196 {"medium spring green" , PALETTERGB ( 0,250,154)},
1197 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1198 {"green yellow" , PALETTERGB (173,255, 47)},
1199 {"GreenYellow" , PALETTERGB (173,255, 47)},
1200 {"lime green" , PALETTERGB ( 50,205, 50)},
1201 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1202 {"yellow green" , PALETTERGB (154,205, 50)},
1203 {"YellowGreen" , PALETTERGB (154,205, 50)},
1204 {"forest green" , PALETTERGB ( 34,139, 34)},
1205 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1206 {"olive drab" , PALETTERGB (107,142, 35)},
1207 {"OliveDrab" , PALETTERGB (107,142, 35)},
1208 {"dark khaki" , PALETTERGB (189,183,107)},
1209 {"DarkKhaki" , PALETTERGB (189,183,107)},
1210 {"khaki" , PALETTERGB (240,230,140)},
1211 {"pale goldenrod" , PALETTERGB (238,232,170)},
1212 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1213 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1214 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1215 {"light yellow" , PALETTERGB (255,255,224)},
1216 {"LightYellow" , PALETTERGB (255,255,224)},
1217 {"yellow" , PALETTERGB (255,255, 0)},
1218 {"gold" , PALETTERGB (255,215, 0)},
1219 {"light goldenrod" , PALETTERGB (238,221,130)},
1220 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1221 {"goldenrod" , PALETTERGB (218,165, 32)},
1222 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1223 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1224 {"rosy brown" , PALETTERGB (188,143,143)},
1225 {"RosyBrown" , PALETTERGB (188,143,143)},
1226 {"indian red" , PALETTERGB (205, 92, 92)},
1227 {"IndianRed" , PALETTERGB (205, 92, 92)},
1228 {"saddle brown" , PALETTERGB (139, 69, 19)},
1229 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1230 {"sienna" , PALETTERGB (160, 82, 45)},
1231 {"peru" , PALETTERGB (205,133, 63)},
1232 {"burlywood" , PALETTERGB (222,184,135)},
1233 {"beige" , PALETTERGB (245,245,220)},
1234 {"wheat" , PALETTERGB (245,222,179)},
1235 {"sandy brown" , PALETTERGB (244,164, 96)},
1236 {"SandyBrown" , PALETTERGB (244,164, 96)},
1237 {"tan" , PALETTERGB (210,180,140)},
1238 {"chocolate" , PALETTERGB (210,105, 30)},
1239 {"firebrick" , PALETTERGB (178,34, 34)},
1240 {"brown" , PALETTERGB (165,42, 42)},
1241 {"dark salmon" , PALETTERGB (233,150,122)},
1242 {"DarkSalmon" , PALETTERGB (233,150,122)},
1243 {"salmon" , PALETTERGB (250,128,114)},
1244 {"light salmon" , PALETTERGB (255,160,122)},
1245 {"LightSalmon" , PALETTERGB (255,160,122)},
1246 {"orange" , PALETTERGB (255,165, 0)},
1247 {"dark orange" , PALETTERGB (255,140, 0)},
1248 {"DarkOrange" , PALETTERGB (255,140, 0)},
1249 {"coral" , PALETTERGB (255,127, 80)},
1250 {"light coral" , PALETTERGB (240,128,128)},
1251 {"LightCoral" , PALETTERGB (240,128,128)},
1252 {"tomato" , PALETTERGB (255, 99, 71)},
1253 {"orange red" , PALETTERGB (255, 69, 0)},
1254 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1255 {"red" , PALETTERGB (255, 0, 0)},
1256 {"hot pink" , PALETTERGB (255,105,180)},
1257 {"HotPink" , PALETTERGB (255,105,180)},
1258 {"deep pink" , PALETTERGB (255, 20,147)},
1259 {"DeepPink" , PALETTERGB (255, 20,147)},
1260 {"pink" , PALETTERGB (255,192,203)},
1261 {"light pink" , PALETTERGB (255,182,193)},
1262 {"LightPink" , PALETTERGB (255,182,193)},
1263 {"pale violet red" , PALETTERGB (219,112,147)},
1264 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1265 {"maroon" , PALETTERGB (176, 48, 96)},
1266 {"medium violet red" , PALETTERGB (199, 21,133)},
1267 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1268 {"violet red" , PALETTERGB (208, 32,144)},
1269 {"VioletRed" , PALETTERGB (208, 32,144)},
1270 {"magenta" , PALETTERGB (255, 0,255)},
1271 {"violet" , PALETTERGB (238,130,238)},
1272 {"plum" , PALETTERGB (221,160,221)},
1273 {"orchid" , PALETTERGB (218,112,214)},
1274 {"medium orchid" , PALETTERGB (186, 85,211)},
1275 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1276 {"dark orchid" , PALETTERGB (153, 50,204)},
1277 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1278 {"dark violet" , PALETTERGB (148, 0,211)},
1279 {"DarkViolet" , PALETTERGB (148, 0,211)},
1280 {"blue violet" , PALETTERGB (138, 43,226)},
1281 {"BlueViolet" , PALETTERGB (138, 43,226)},
1282 {"purple" , PALETTERGB (160, 32,240)},
1283 {"medium purple" , PALETTERGB (147,112,219)},
1284 {"MediumPurple" , PALETTERGB (147,112,219)},
1285 {"thistle" , PALETTERGB (216,191,216)},
1286 {"gray0" , PALETTERGB ( 0, 0, 0)},
1287 {"grey0" , PALETTERGB ( 0, 0, 0)},
1288 {"dark grey" , PALETTERGB (169,169,169)},
1289 {"DarkGrey" , PALETTERGB (169,169,169)},
1290 {"dark gray" , PALETTERGB (169,169,169)},
1291 {"DarkGray" , PALETTERGB (169,169,169)},
1292 {"dark blue" , PALETTERGB ( 0, 0,139)},
1293 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1294 {"dark cyan" , PALETTERGB ( 0,139,139)},
1295 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1296 {"dark magenta" , PALETTERGB (139, 0,139)},
1297 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1298 {"dark red" , PALETTERGB (139, 0, 0)},
1299 {"DarkRed" , PALETTERGB (139, 0, 0)},
1300 {"light green" , PALETTERGB (144,238,144)},
1301 {"LightGreen" , PALETTERGB (144,238,144)},
ee78dc32
GV
1302};
1303
fbd6baed 1304DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
ee78dc32
GV
1305 0, 0, 0, "Return the default color map.")
1306 ()
1307{
1308 int i;
fbd6baed 1309 colormap_t *pc = w32_color_map;
ee78dc32
GV
1310 Lisp_Object cmap;
1311
1312 BLOCK_INPUT;
1313
1314 cmap = Qnil;
1315
fbd6baed 1316 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
ee78dc32
GV
1317 pc++, i++)
1318 cmap = Fcons (Fcons (build_string (pc->name),
1319 make_number (pc->colorref)),
1320 cmap);
1321
1322 UNBLOCK_INPUT;
1323
1324 return (cmap);
1325}
ee78dc32
GV
1326
1327Lisp_Object
fbd6baed 1328w32_to_x_color (rgb)
ee78dc32
GV
1329 Lisp_Object rgb;
1330{
1331 Lisp_Object color;
1332
1333 CHECK_NUMBER (rgb, 0);
1334
1335 BLOCK_INPUT;
1336
fbd6baed 1337 color = Frassq (rgb, Vw32_color_map);
ee78dc32
GV
1338
1339 UNBLOCK_INPUT;
1340
1341 if (!NILP (color))
1342 return (Fcar (color));
1343 else
1344 return Qnil;
1345}
1346
5d7fed93
GV
1347COLORREF
1348w32_color_map_lookup (colorname)
1349 char *colorname;
1350{
1351 Lisp_Object tail, ret = Qnil;
1352
1353 BLOCK_INPUT;
1354
1355 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1356 {
1357 register Lisp_Object elt, tem;
1358
1359 elt = Fcar (tail);
1360 if (!CONSP (elt)) continue;
1361
1362 tem = Fcar (elt);
1363
1364 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1365 {
1366 ret = XUINT (Fcdr (elt));
1367 break;
1368 }
1369
1370 QUIT;
1371 }
1372
1373
1374 UNBLOCK_INPUT;
1375
1376 return ret;
1377}
1378
ee78dc32 1379COLORREF
fbd6baed 1380x_to_w32_color (colorname)
ee78dc32
GV
1381 char * colorname;
1382{
1383 register Lisp_Object tail, ret = Qnil;
1384
1385 BLOCK_INPUT;
1edf84e7
GV
1386
1387 if (colorname[0] == '#')
1388 {
1389 /* Could be an old-style RGB Device specification. */
1390 char *color;
1391 int size;
1392 color = colorname + 1;
1393
1394 size = strlen(color);
1395 if (size == 3 || size == 6 || size == 9 || size == 12)
1396 {
1397 UINT colorval;
1398 int i, pos;
1399 pos = 0;
1400 size /= 3;
1401 colorval = 0;
1402
1403 for (i = 0; i < 3; i++)
1404 {
1405 char *end;
1406 char t;
1407 unsigned long value;
1408
1409 /* The check for 'x' in the following conditional takes into
1410 account the fact that strtol allows a "0x" in front of
1411 our numbers, and we don't. */
1412 if (!isxdigit(color[0]) || color[1] == 'x')
1413 break;
1414 t = color[size];
1415 color[size] = '\0';
1416 value = strtoul(color, &end, 16);
1417 color[size] = t;
1418 if (errno == ERANGE || end - color != size)
1419 break;
1420 switch (size)
1421 {
1422 case 1:
1423 value = value * 0x10;
1424 break;
1425 case 2:
1426 break;
1427 case 3:
1428 value /= 0x10;
1429 break;
1430 case 4:
1431 value /= 0x100;
1432 break;
1433 }
1434 colorval |= (value << pos);
1435 pos += 0x8;
1436 if (i == 2)
1437 {
1438 UNBLOCK_INPUT;
1439 return (colorval);
1440 }
1441 color = end;
1442 }
1443 }
1444 }
1445 else if (strnicmp(colorname, "rgb:", 4) == 0)
1446 {
1447 char *color;
1448 UINT colorval;
1449 int i, pos;
1450 pos = 0;
1451
1452 colorval = 0;
1453 color = colorname + 4;
1454 for (i = 0; i < 3; i++)
1455 {
1456 char *end;
1457 unsigned long value;
1458
1459 /* The check for 'x' in the following conditional takes into
1460 account the fact that strtol allows a "0x" in front of
1461 our numbers, and we don't. */
1462 if (!isxdigit(color[0]) || color[1] == 'x')
1463 break;
1464 value = strtoul(color, &end, 16);
1465 if (errno == ERANGE)
1466 break;
1467 switch (end - color)
1468 {
1469 case 1:
1470 value = value * 0x10 + value;
1471 break;
1472 case 2:
1473 break;
1474 case 3:
1475 value /= 0x10;
1476 break;
1477 case 4:
1478 value /= 0x100;
1479 break;
1480 default:
1481 value = ULONG_MAX;
1482 }
1483 if (value == ULONG_MAX)
1484 break;
1485 colorval |= (value << pos);
1486 pos += 0x8;
1487 if (i == 2)
1488 {
1489 if (*end != '\0')
1490 break;
1491 UNBLOCK_INPUT;
1492 return (colorval);
1493 }
1494 if (*end != '/')
1495 break;
1496 color = end + 1;
1497 }
1498 }
1499 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1500 {
1501 /* This is an RGB Intensity specification. */
1502 char *color;
1503 UINT colorval;
1504 int i, pos;
1505 pos = 0;
1506
1507 colorval = 0;
1508 color = colorname + 5;
1509 for (i = 0; i < 3; i++)
1510 {
1511 char *end;
1512 double value;
1513 UINT val;
1514
1515 value = strtod(color, &end);
1516 if (errno == ERANGE)
1517 break;
1518 if (value < 0.0 || value > 1.0)
1519 break;
1520 val = (UINT)(0x100 * value);
1521 /* We used 0x100 instead of 0xFF to give an continuous
1522 range between 0.0 and 1.0 inclusive. The next statement
1523 fixes the 1.0 case. */
1524 if (val == 0x100)
1525 val = 0xFF;
1526 colorval |= (val << pos);
1527 pos += 0x8;
1528 if (i == 2)
1529 {
1530 if (*end != '\0')
1531 break;
1532 UNBLOCK_INPUT;
1533 return (colorval);
1534 }
1535 if (*end != '/')
1536 break;
1537 color = end + 1;
1538 }
1539 }
1540 /* I am not going to attempt to handle any of the CIE color schemes
1541 or TekHVC, since I don't know the algorithms for conversion to
1542 RGB. */
f695b4b1
GV
1543
1544 /* If we fail to lookup the color name in w32_color_map, then check the
1545 colorname to see if it can be crudely approximated: If the X color
1546 ends in a number (e.g., "darkseagreen2"), strip the number and
1547 return the result of looking up the base color name. */
1548 ret = w32_color_map_lookup (colorname);
1549 if (NILP (ret))
ee78dc32 1550 {
f695b4b1 1551 int len = strlen (colorname);
ee78dc32 1552
f695b4b1
GV
1553 if (isdigit (colorname[len - 1]))
1554 {
1555 char *ptr, *approx = alloca (len);
ee78dc32 1556
f695b4b1
GV
1557 strcpy (approx, colorname);
1558 ptr = &approx[len - 1];
1559 while (ptr > approx && isdigit (*ptr))
1560 *ptr-- = '\0';
ee78dc32 1561
f695b4b1 1562 ret = w32_color_map_lookup (approx);
ee78dc32 1563 }
ee78dc32
GV
1564 }
1565
1566 UNBLOCK_INPUT;
ee78dc32
GV
1567 return ret;
1568}
1569
5ac45f98
GV
1570
1571void
fbd6baed 1572w32_regenerate_palette (FRAME_PTR f)
5ac45f98 1573{
fbd6baed 1574 struct w32_palette_entry * list;
5ac45f98
GV
1575 LOGPALETTE * log_palette;
1576 HPALETTE new_palette;
1577 int i;
1578
1579 /* don't bother trying to create palette if not supported */
fbd6baed 1580 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
5ac45f98
GV
1581 return;
1582
1583 log_palette = (LOGPALETTE *)
1584 alloca (sizeof (LOGPALETTE) +
fbd6baed 1585 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
5ac45f98 1586 log_palette->palVersion = 0x300;
fbd6baed 1587 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98 1588
fbd6baed 1589 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1590 for (i = 0;
fbd6baed 1591 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
5ac45f98
GV
1592 i++, list = list->next)
1593 log_palette->palPalEntry[i] = list->entry;
1594
1595 new_palette = CreatePalette (log_palette);
1596
1597 enter_crit ();
1598
fbd6baed
GV
1599 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1600 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1601 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
5ac45f98
GV
1602
1603 /* Realize display palette and garbage all frames. */
1604 release_frame_dc (f, get_frame_dc (f));
1605
1606 leave_crit ();
1607}
1608
fbd6baed
GV
1609#define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1610#define SET_W32_COLOR(pe, color) \
5ac45f98
GV
1611 do \
1612 { \
1613 pe.peRed = GetRValue (color); \
1614 pe.peGreen = GetGValue (color); \
1615 pe.peBlue = GetBValue (color); \
1616 pe.peFlags = 0; \
1617 } while (0)
1618
1619#if 0
1620/* Keep these around in case we ever want to track color usage. */
1621void
fbd6baed 1622w32_map_color (FRAME_PTR f, COLORREF color)
5ac45f98 1623{
fbd6baed 1624 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1625
fbd6baed 1626 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1627 return;
1628
1629 /* check if color is already mapped */
1630 while (list)
1631 {
fbd6baed 1632 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1633 {
1634 ++list->refcount;
1635 return;
1636 }
1637 list = list->next;
1638 }
1639
1640 /* not already mapped, so add to list and recreate Windows palette */
fbd6baed
GV
1641 list = (struct w32_palette_entry *)
1642 xmalloc (sizeof (struct w32_palette_entry));
1643 SET_W32_COLOR (list->entry, color);
5ac45f98 1644 list->refcount = 1;
fbd6baed
GV
1645 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1646 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1647 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1648
1649 /* set flag that palette must be regenerated */
fbd6baed 1650 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1651}
1652
1653void
fbd6baed 1654w32_unmap_color (FRAME_PTR f, COLORREF color)
5ac45f98 1655{
fbd6baed
GV
1656 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1657 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98 1658
fbd6baed 1659 if (NILP (Vw32_enable_palette))
5ac45f98
GV
1660 return;
1661
1662 /* check if color is already mapped */
1663 while (list)
1664 {
fbd6baed 1665 if (W32_COLOR (list->entry) == color)
5ac45f98
GV
1666 {
1667 if (--list->refcount == 0)
1668 {
1669 *prev = list->next;
1670 xfree (list);
fbd6baed 1671 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
5ac45f98
GV
1672 break;
1673 }
1674 else
1675 return;
1676 }
1677 prev = &list->next;
1678 list = list->next;
1679 }
1680
1681 /* set flag that palette must be regenerated */
fbd6baed 1682 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1683}
1684#endif
1685
ee78dc32
GV
1686/* Decide if color named COLOR is valid for the display associated with
1687 the selected frame; if so, return the rgb values in COLOR_DEF.
1688 If ALLOC is nonzero, allocate a new colormap cell. */
1689
1690int
1691defined_color (f, color, color_def, alloc)
1692 FRAME_PTR f;
1693 char *color;
1694 COLORREF *color_def;
1695 int alloc;
1696{
1697 register Lisp_Object tem;
3c190163 1698
fbd6baed 1699 tem = x_to_w32_color (color);
3c190163 1700
ee78dc32
GV
1701 if (!NILP (tem))
1702 {
fbd6baed 1703 if (!NILP (Vw32_enable_palette))
5ac45f98 1704 {
fbd6baed
GV
1705 struct w32_palette_entry * entry =
1706 FRAME_W32_DISPLAY_INFO (f)->color_list;
1707 struct w32_palette_entry ** prev =
1708 &FRAME_W32_DISPLAY_INFO (f)->color_list;
5ac45f98
GV
1709
1710 /* check if color is already mapped */
1711 while (entry)
1712 {
fbd6baed 1713 if (W32_COLOR (entry->entry) == XUINT (tem))
5ac45f98
GV
1714 break;
1715 prev = &entry->next;
1716 entry = entry->next;
1717 }
1718
1719 if (entry == NULL && alloc)
1720 {
1721 /* not already mapped, so add to list */
fbd6baed
GV
1722 entry = (struct w32_palette_entry *)
1723 xmalloc (sizeof (struct w32_palette_entry));
1724 SET_W32_COLOR (entry->entry, XUINT (tem));
5ac45f98
GV
1725 entry->next = NULL;
1726 *prev = entry;
fbd6baed 1727 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
5ac45f98
GV
1728
1729 /* set flag that palette must be regenerated */
fbd6baed 1730 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
5ac45f98
GV
1731 }
1732 }
1733 /* Ensure COLORREF value is snapped to nearest color in (default)
1734 palette by simulating the PALETTERGB macro. This works whether
1735 or not the display device has a palette. */
8847d890 1736 *color_def = XUINT (tem) | 0x2000000;
ee78dc32 1737 return 1;
5ac45f98 1738 }
7fb46567 1739 else
3c190163
GV
1740 {
1741 return 0;
1742 }
ee78dc32
GV
1743}
1744
1745/* Given a string ARG naming a color, compute a pixel value from it
1746 suitable for screen F.
1747 If F is not a color screen, return DEF (default) regardless of what
1748 ARG says. */
1749
1750int
1751x_decode_color (f, arg, def)
1752 FRAME_PTR f;
1753 Lisp_Object arg;
1754 int def;
1755{
1756 COLORREF cdef;
1757
1758 CHECK_STRING (arg, 0);
1759
1760 if (strcmp (XSTRING (arg)->data, "black") == 0)
1761 return BLACK_PIX_DEFAULT (f);
1762 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1763 return WHITE_PIX_DEFAULT (f);
1764
fbd6baed 1765 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
ee78dc32
GV
1766 return def;
1767
1768 /* defined_color is responsible for coping with failures
1769 by looking for a near-miss. */
1770 if (defined_color (f, XSTRING (arg)->data, &cdef, 1))
1771 return cdef;
1772
1773 /* defined_color failed; return an ultimate default. */
1774 return def;
1775}
1776\f
1777/* Functions called only from `x_set_frame_param'
1778 to set individual parameters.
1779
fbd6baed 1780 If FRAME_W32_WINDOW (f) is 0,
ee78dc32
GV
1781 the frame is being created and its window does not exist yet.
1782 In that case, just record the parameter's new value
1783 in the standard place; do not attempt to change the window. */
1784
1785void
1786x_set_foreground_color (f, arg, oldval)
1787 struct frame *f;
1788 Lisp_Object arg, oldval;
1789{
fbd6baed 1790 f->output_data.w32->foreground_pixel
ee78dc32 1791 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
5ac45f98 1792
fbd6baed 1793 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
1794 {
1795 recompute_basic_faces (f);
1796 if (FRAME_VISIBLE_P (f))
1797 redraw_frame (f);
1798 }
1799}
1800
1801void
1802x_set_background_color (f, arg, oldval)
1803 struct frame *f;
1804 Lisp_Object arg, oldval;
1805{
1806 Pixmap temp;
1807 int mask;
1808
fbd6baed 1809 f->output_data.w32->background_pixel
ee78dc32
GV
1810 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1811
fbd6baed 1812 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1813 {
fbd6baed 1814 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX, f->output_data.w32->background_pixel);
ee78dc32
GV
1815
1816 recompute_basic_faces (f);
1817
1818 if (FRAME_VISIBLE_P (f))
1819 redraw_frame (f);
1820 }
1821}
1822
1823void
1824x_set_mouse_color (f, arg, oldval)
1825 struct frame *f;
1826 Lisp_Object arg, oldval;
1827{
1828#if 0
1829 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
1830#endif
dfc465d3 1831 int count;
ee78dc32
GV
1832 int mask_color;
1833
1834 if (!EQ (Qnil, arg))
fbd6baed 1835 f->output_data.w32->mouse_pixel
ee78dc32 1836 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
fbd6baed 1837 mask_color = f->output_data.w32->background_pixel;
ee78dc32 1838 /* No invisible pointers. */
fbd6baed
GV
1839 if (mask_color == f->output_data.w32->mouse_pixel
1840 && mask_color == f->output_data.w32->background_pixel)
1841 f->output_data.w32->mouse_pixel = f->output_data.w32->foreground_pixel;
ee78dc32
GV
1842
1843#if 0
1844 BLOCK_INPUT;
1845
1846 /* It's not okay to crash if the user selects a screwy cursor. */
fadca6c6 1847 count = x_catch_errors (FRAME_W32_DISPLAY (f));
ee78dc32
GV
1848
1849 if (!EQ (Qnil, Vx_pointer_shape))
1850 {
1851 CHECK_NUMBER (Vx_pointer_shape, 0);
fbd6baed 1852 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
ee78dc32
GV
1853 }
1854 else
fbd6baed
GV
1855 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1856 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
ee78dc32
GV
1857
1858 if (!EQ (Qnil, Vx_nontext_pointer_shape))
1859 {
1860 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
fbd6baed 1861 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
1862 XINT (Vx_nontext_pointer_shape));
1863 }
1864 else
fbd6baed
GV
1865 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
1866 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
ee78dc32
GV
1867
1868 if (!EQ (Qnil, Vx_mode_pointer_shape))
1869 {
1870 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
fbd6baed 1871 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
1872 XINT (Vx_mode_pointer_shape));
1873 }
1874 else
fbd6baed
GV
1875 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1876 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
ee78dc32
GV
1877
1878 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
1879 {
1880 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
1881 cross_cursor
fbd6baed 1882 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
ee78dc32
GV
1883 XINT (Vx_sensitive_text_pointer_shape));
1884 }
1885 else
fbd6baed 1886 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
ee78dc32
GV
1887
1888 /* Check and report errors with the above calls. */
fbd6baed 1889 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
fadca6c6 1890 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
ee78dc32
GV
1891
1892 {
1893 XColor fore_color, back_color;
1894
fbd6baed 1895 fore_color.pixel = f->output_data.w32->mouse_pixel;
ee78dc32 1896 back_color.pixel = mask_color;
fbd6baed
GV
1897 XQueryColor (FRAME_W32_DISPLAY (f),
1898 DefaultColormap (FRAME_W32_DISPLAY (f),
1899 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 1900 &fore_color);
fbd6baed
GV
1901 XQueryColor (FRAME_W32_DISPLAY (f),
1902 DefaultColormap (FRAME_W32_DISPLAY (f),
1903 DefaultScreen (FRAME_W32_DISPLAY (f))),
ee78dc32 1904 &back_color);
fbd6baed 1905 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
ee78dc32 1906 &fore_color, &back_color);
fbd6baed 1907 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
ee78dc32 1908 &fore_color, &back_color);
fbd6baed 1909 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
ee78dc32 1910 &fore_color, &back_color);
fbd6baed 1911 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
ee78dc32
GV
1912 &fore_color, &back_color);
1913 }
1914
fbd6baed 1915 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32 1916 {
fbd6baed 1917 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
ee78dc32
GV
1918 }
1919
fbd6baed
GV
1920 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
1921 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
1922 f->output_data.w32->text_cursor = cursor;
1923
1924 if (nontext_cursor != f->output_data.w32->nontext_cursor
1925 && f->output_data.w32->nontext_cursor != 0)
1926 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
1927 f->output_data.w32->nontext_cursor = nontext_cursor;
1928
1929 if (mode_cursor != f->output_data.w32->modeline_cursor
1930 && f->output_data.w32->modeline_cursor != 0)
1931 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
1932 f->output_data.w32->modeline_cursor = mode_cursor;
1933 if (cross_cursor != f->output_data.w32->cross_cursor
1934 && f->output_data.w32->cross_cursor != 0)
1935 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
1936 f->output_data.w32->cross_cursor = cross_cursor;
1937
1938 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
1939 UNBLOCK_INPUT;
1940#endif
1941}
1942
1943void
1944x_set_cursor_color (f, arg, oldval)
1945 struct frame *f;
1946 Lisp_Object arg, oldval;
1947{
1948 unsigned long fore_pixel;
1949
1950 if (!EQ (Vx_cursor_fore_pixel, Qnil))
1951 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
1952 WHITE_PIX_DEFAULT (f));
1953 else
fbd6baed
GV
1954 fore_pixel = f->output_data.w32->background_pixel;
1955 f->output_data.w32->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
ee78dc32
GV
1956
1957 /* Make sure that the cursor color differs from the background color. */
fbd6baed 1958 if (f->output_data.w32->cursor_pixel == f->output_data.w32->background_pixel)
ee78dc32 1959 {
fbd6baed
GV
1960 f->output_data.w32->cursor_pixel = f->output_data.w32->mouse_pixel;
1961 if (f->output_data.w32->cursor_pixel == fore_pixel)
1962 fore_pixel = f->output_data.w32->background_pixel;
ee78dc32 1963 }
fbd6baed 1964 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
ee78dc32 1965
fbd6baed 1966 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
1967 {
1968 if (FRAME_VISIBLE_P (f))
1969 {
1970 x_display_cursor (f, 0);
1971 x_display_cursor (f, 1);
1972 }
1973 }
1974}
1975
33d52f9c
GV
1976/* Set the border-color of frame F to pixel value PIX.
1977 Note that this does not fully take effect if done before
1978 F has an window. */
1979void
1980x_set_border_pixel (f, pix)
1981 struct frame *f;
1982 int pix;
1983{
1984 f->output_data.w32->border_pixel = pix;
1985
1986 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
1987 {
1988 if (FRAME_VISIBLE_P (f))
1989 redraw_frame (f);
1990 }
1991}
1992
ee78dc32
GV
1993/* Set the border-color of frame F to value described by ARG.
1994 ARG can be a string naming a color.
1995 The border-color is used for the border that is drawn by the server.
1996 Note that this does not fully take effect if done before
1997 F has a window; it must be redone when the window is created. */
1998
1999void
2000x_set_border_color (f, arg, oldval)
2001 struct frame *f;
2002 Lisp_Object arg, oldval;
2003{
2004 unsigned char *str;
2005 int pix;
2006
2007 CHECK_STRING (arg, 0);
2008 str = XSTRING (arg)->data;
2009
2010 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2011
2012 x_set_border_pixel (f, pix);
2013}
2014
ee78dc32
GV
2015void
2016x_set_cursor_type (f, arg, oldval)
2017 FRAME_PTR f;
2018 Lisp_Object arg, oldval;
2019{
2020 if (EQ (arg, Qbar))
2021 {
2022 FRAME_DESIRED_CURSOR (f) = bar_cursor;
fbd6baed 2023 f->output_data.w32->cursor_width = 2;
ee78dc32
GV
2024 }
2025 else if (CONSP (arg) && EQ (XCONS (arg)->car, Qbar)
2026 && INTEGERP (XCONS (arg)->cdr))
2027 {
2028 FRAME_DESIRED_CURSOR (f) = bar_cursor;
fbd6baed 2029 f->output_data.w32->cursor_width = XINT (XCONS (arg)->cdr);
ee78dc32
GV
2030 }
2031 else
2032 /* Treat anything unknown as "box cursor".
2033 It was bad to signal an error; people have trouble fixing
2034 .Xdefaults with Emacs, when it has something bad in it. */
2035 FRAME_DESIRED_CURSOR (f) = filled_box_cursor;
2036
2037 /* Make sure the cursor gets redrawn. This is overkill, but how
2038 often do people change cursor types? */
2039 update_mode_lines++;
2040}
2041
2042void
2043x_set_icon_type (f, arg, oldval)
2044 struct frame *f;
2045 Lisp_Object arg, oldval;
2046{
2047#if 0
2048 Lisp_Object tem;
2049 int result;
2050
2051 if (STRINGP (arg))
2052 {
2053 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2054 return;
2055 }
2056 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2057 return;
2058
2059 BLOCK_INPUT;
2060 if (NILP (arg))
2061 result = x_text_icon (f,
2062 (char *) XSTRING ((!NILP (f->icon_name)
2063 ? f->icon_name
2064 : f->name))->data);
2065 else
2066 result = x_bitmap_icon (f, arg);
2067
2068 if (result)
2069 {
2070 UNBLOCK_INPUT;
2071 error ("No icon window available");
2072 }
2073
2074 /* If the window was unmapped (and its icon was mapped),
2075 the new icon is not mapped, so map the window in its stead. */
2076 if (FRAME_VISIBLE_P (f))
2077 {
2078#ifdef USE_X_TOOLKIT
fbd6baed 2079 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2080#endif
fbd6baed 2081 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2082 }
2083
fbd6baed 2084 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2085 UNBLOCK_INPUT;
2086#endif
2087}
2088
2089/* Return non-nil if frame F wants a bitmap icon. */
2090
2091Lisp_Object
2092x_icon_type (f)
2093 FRAME_PTR f;
2094{
2095 Lisp_Object tem;
2096
2097 tem = assq_no_quit (Qicon_type, f->param_alist);
2098 if (CONSP (tem))
2099 return XCONS (tem)->cdr;
2100 else
2101 return Qnil;
2102}
2103
2104void
2105x_set_icon_name (f, arg, oldval)
2106 struct frame *f;
2107 Lisp_Object arg, oldval;
2108{
2109 Lisp_Object tem;
2110 int result;
2111
2112 if (STRINGP (arg))
2113 {
2114 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2115 return;
2116 }
2117 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2118 return;
2119
2120 f->icon_name = arg;
2121
2122#if 0
fbd6baed 2123 if (f->output_data.w32->icon_bitmap != 0)
ee78dc32
GV
2124 return;
2125
2126 BLOCK_INPUT;
2127
2128 result = x_text_icon (f,
1edf84e7 2129 (char *) XSTRING ((!NILP (f->icon_name)
ee78dc32 2130 ? f->icon_name
1edf84e7
GV
2131 : !NILP (f->title)
2132 ? f->title
ee78dc32
GV
2133 : f->name))->data);
2134
2135 if (result)
2136 {
2137 UNBLOCK_INPUT;
2138 error ("No icon window available");
2139 }
2140
2141 /* If the window was unmapped (and its icon was mapped),
2142 the new icon is not mapped, so map the window in its stead. */
2143 if (FRAME_VISIBLE_P (f))
2144 {
2145#ifdef USE_X_TOOLKIT
fbd6baed 2146 XtPopup (f->output_data.w32->widget, XtGrabNone);
ee78dc32 2147#endif
fbd6baed 2148 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
ee78dc32
GV
2149 }
2150
fbd6baed 2151 XFlush (FRAME_W32_DISPLAY (f));
ee78dc32
GV
2152 UNBLOCK_INPUT;
2153#endif
2154}
2155
2156extern Lisp_Object x_new_font ();
4587b026 2157extern Lisp_Object x_new_fontset();
ee78dc32
GV
2158
2159void
2160x_set_font (f, arg, oldval)
2161 struct frame *f;
2162 Lisp_Object arg, oldval;
2163{
2164 Lisp_Object result;
4587b026 2165 Lisp_Object fontset_name;
4b817373 2166 Lisp_Object frame;
ee78dc32
GV
2167
2168 CHECK_STRING (arg, 1);
2169
4587b026
GV
2170 fontset_name = Fquery_fontset (arg, Qnil);
2171
ee78dc32 2172 BLOCK_INPUT;
4587b026
GV
2173 result = (STRINGP (fontset_name)
2174 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2175 : x_new_font (f, XSTRING (arg)->data));
ee78dc32
GV
2176 UNBLOCK_INPUT;
2177
2178 if (EQ (result, Qnil))
2179 error ("Font \"%s\" is not defined", XSTRING (arg)->data);
2180 else if (EQ (result, Qt))
2181 error ("the characters of the given font have varying widths");
2182 else if (STRINGP (result))
2183 {
2184 recompute_basic_faces (f);
2185 store_frame_param (f, Qfont, result);
2186 }
2187 else
2188 abort ();
4b817373
RS
2189
2190 XSETFRAME (frame, f);
2191 call1 (Qface_set_after_frame_default, frame);
ee78dc32
GV
2192}
2193
2194void
2195x_set_border_width (f, arg, oldval)
2196 struct frame *f;
2197 Lisp_Object arg, oldval;
2198{
2199 CHECK_NUMBER (arg, 0);
2200
fbd6baed 2201 if (XINT (arg) == f->output_data.w32->border_width)
ee78dc32
GV
2202 return;
2203
fbd6baed 2204 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2205 error ("Cannot change the border width of a window");
2206
fbd6baed 2207 f->output_data.w32->border_width = XINT (arg);
ee78dc32
GV
2208}
2209
2210void
2211x_set_internal_border_width (f, arg, oldval)
2212 struct frame *f;
2213 Lisp_Object arg, oldval;
2214{
2215 int mask;
fbd6baed 2216 int old = f->output_data.w32->internal_border_width;
ee78dc32
GV
2217
2218 CHECK_NUMBER (arg, 0);
fbd6baed
GV
2219 f->output_data.w32->internal_border_width = XINT (arg);
2220 if (f->output_data.w32->internal_border_width < 0)
2221 f->output_data.w32->internal_border_width = 0;
ee78dc32 2222
fbd6baed 2223 if (f->output_data.w32->internal_border_width == old)
ee78dc32
GV
2224 return;
2225
fbd6baed 2226 if (FRAME_W32_WINDOW (f) != 0)
ee78dc32
GV
2227 {
2228 BLOCK_INPUT;
2229 x_set_window_size (f, 0, f->width, f->height);
2230 UNBLOCK_INPUT;
2231 SET_FRAME_GARBAGED (f);
2232 }
2233}
2234
2235void
2236x_set_visibility (f, value, oldval)
2237 struct frame *f;
2238 Lisp_Object value, oldval;
2239{
2240 Lisp_Object frame;
2241 XSETFRAME (frame, f);
2242
2243 if (NILP (value))
2244 Fmake_frame_invisible (frame, Qt);
2245 else if (EQ (value, Qicon))
2246 Ficonify_frame (frame);
2247 else
2248 Fmake_frame_visible (frame);
2249}
2250
2251void
2252x_set_menu_bar_lines (f, value, oldval)
2253 struct frame *f;
2254 Lisp_Object value, oldval;
2255{
2256 int nlines;
2257 int olines = FRAME_MENU_BAR_LINES (f);
2258
2259 /* Right now, menu bars don't work properly in minibuf-only frames;
2260 most of the commands try to apply themselves to the minibuffer
2261 frame itslef, and get an error because you can't switch buffers
2262 in or split the minibuffer window. */
2263 if (FRAME_MINIBUF_ONLY_P (f))
2264 return;
2265
2266 if (INTEGERP (value))
2267 nlines = XINT (value);
2268 else
2269 nlines = 0;
2270
2271 FRAME_MENU_BAR_LINES (f) = 0;
2272 if (nlines)
2273 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2274 else
2275 {
2276 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2277 free_frame_menubar (f);
2278 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1edf84e7
GV
2279
2280 /* Adjust the frame size so that the client (text) dimensions
2281 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2282 set correctly. */
2283 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
ee78dc32
GV
2284 }
2285}
2286
2287/* Change the name of frame F to NAME. If NAME is nil, set F's name to
fbd6baed 2288 w32_id_name.
ee78dc32
GV
2289
2290 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2291 name; if NAME is a string, set F's name to NAME and set
2292 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2293
2294 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2295 suggesting a new name, which lisp code should override; if
2296 F->explicit_name is set, ignore the new name; otherwise, set it. */
2297
2298void
2299x_set_name (f, name, explicit)
2300 struct frame *f;
2301 Lisp_Object name;
2302 int explicit;
2303{
2304 /* Make sure that requests from lisp code override requests from
2305 Emacs redisplay code. */
2306 if (explicit)
2307 {
2308 /* If we're switching from explicit to implicit, we had better
2309 update the mode lines and thereby update the title. */
2310 if (f->explicit_name && NILP (name))
2311 update_mode_lines = 1;
2312
2313 f->explicit_name = ! NILP (name);
2314 }
2315 else if (f->explicit_name)
2316 return;
2317
fbd6baed 2318 /* If NAME is nil, set the name to the w32_id_name. */
ee78dc32
GV
2319 if (NILP (name))
2320 {
2321 /* Check for no change needed in this very common case
2322 before we do any consing. */
fbd6baed 2323 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
ee78dc32
GV
2324 XSTRING (f->name)->data))
2325 return;
fbd6baed 2326 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
ee78dc32
GV
2327 }
2328 else
2329 CHECK_STRING (name, 0);
2330
2331 /* Don't change the name if it's already NAME. */
2332 if (! NILP (Fstring_equal (name, f->name)))
2333 return;
2334
1edf84e7
GV
2335 f->name = name;
2336
2337 /* For setting the frame title, the title parameter should override
2338 the name parameter. */
2339 if (! NILP (f->title))
2340 name = f->title;
2341
fbd6baed 2342 if (FRAME_W32_WINDOW (f))
ee78dc32
GV
2343 {
2344 BLOCK_INPUT;
fbd6baed 2345 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
ee78dc32
GV
2346 UNBLOCK_INPUT;
2347 }
ee78dc32
GV
2348}
2349
2350/* This function should be called when the user's lisp code has
2351 specified a name for the frame; the name will override any set by the
2352 redisplay code. */
2353void
2354x_explicitly_set_name (f, arg, oldval)
2355 FRAME_PTR f;
2356 Lisp_Object arg, oldval;
2357{
2358 x_set_name (f, arg, 1);
2359}
2360
2361/* This function should be called by Emacs redisplay code to set the
2362 name; names set this way will never override names set by the user's
2363 lisp code. */
2364void
2365x_implicitly_set_name (f, arg, oldval)
2366 FRAME_PTR f;
2367 Lisp_Object arg, oldval;
2368{
2369 x_set_name (f, arg, 0);
2370}
1edf84e7
GV
2371\f
2372/* Change the title of frame F to NAME.
2373 If NAME is nil, use the frame name as the title.
2374
2375 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2376 name; if NAME is a string, set F's name to NAME and set
2377 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2378
2379 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2380 suggesting a new name, which lisp code should override; if
2381 F->explicit_name is set, ignore the new name; otherwise, set it. */
ee78dc32 2382
1edf84e7
GV
2383void
2384x_set_title (f, name)
2385 struct frame *f;
2386 Lisp_Object name;
2387{
2388 /* Don't change the title if it's already NAME. */
2389 if (EQ (name, f->title))
2390 return;
2391
2392 update_mode_lines = 1;
2393
2394 f->title = name;
2395
2396 if (NILP (name))
2397 name = f->name;
2398
2399 if (FRAME_W32_WINDOW (f))
2400 {
2401 BLOCK_INPUT;
2402 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2403 UNBLOCK_INPUT;
2404 }
2405}
2406\f
ee78dc32
GV
2407void
2408x_set_autoraise (f, arg, oldval)
2409 struct frame *f;
2410 Lisp_Object arg, oldval;
2411{
2412 f->auto_raise = !EQ (Qnil, arg);
2413}
2414
2415void
2416x_set_autolower (f, arg, oldval)
2417 struct frame *f;
2418 Lisp_Object arg, oldval;
2419{
2420 f->auto_lower = !EQ (Qnil, arg);
2421}
2422
2423void
2424x_set_unsplittable (f, arg, oldval)
2425 struct frame *f;
2426 Lisp_Object arg, oldval;
2427{
2428 f->no_split = !NILP (arg);
2429}
2430
2431void
2432x_set_vertical_scroll_bars (f, arg, oldval)
2433 struct frame *f;
2434 Lisp_Object arg, oldval;
2435{
1026b400
RS
2436 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2437 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2438 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2439 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
ee78dc32 2440 {
1026b400
RS
2441 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2442 vertical_scroll_bar_none :
87996783
GV
2443 /* Put scroll bars on the right by default, as is conventional
2444 on MS-Windows. */
2445 EQ (Qleft, arg)
2446 ? vertical_scroll_bar_left
2447 : vertical_scroll_bar_right;
ee78dc32
GV
2448
2449 /* We set this parameter before creating the window for the
2450 frame, so we can get the geometry right from the start.
2451 However, if the window hasn't been created yet, we shouldn't
2452 call x_set_window_size. */
fbd6baed 2453 if (FRAME_W32_WINDOW (f))
ee78dc32
GV
2454 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2455 }
2456}
2457
2458void
2459x_set_scroll_bar_width (f, arg, oldval)
2460 struct frame *f;
2461 Lisp_Object arg, oldval;
2462{
2463 if (NILP (arg))
2464 {
2465 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
2466 FRAME_SCROLL_BAR_COLS (f) = 2;
2467 }
2468 else if (INTEGERP (arg) && XINT (arg) > 0
2469 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2470 {
fbd6baed 2471 int wid = FONT_WIDTH (f->output_data.w32->font);
ee78dc32
GV
2472 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2473 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
fbd6baed 2474 if (FRAME_W32_WINDOW (f))
ee78dc32
GV
2475 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2476 }
2477}
2478\f
2479/* Subroutines of creating an frame. */
2480
2481/* Make sure that Vx_resource_name is set to a reasonable value.
2482 Fix it up, or set it to `emacs' if it is too hopeless. */
2483
2484static void
2485validate_x_resource_name ()
2486{
2487 int len;
2488 /* Number of valid characters in the resource name. */
2489 int good_count = 0;
2490 /* Number of invalid characters in the resource name. */
2491 int bad_count = 0;
2492 Lisp_Object new;
2493 int i;
2494
2495 if (STRINGP (Vx_resource_name))
2496 {
2497 unsigned char *p = XSTRING (Vx_resource_name)->data;
2498 int i;
2499
2500 len = XSTRING (Vx_resource_name)->size;
2501
2502 /* Only letters, digits, - and _ are valid in resource names.
2503 Count the valid characters and count the invalid ones. */
2504 for (i = 0; i < len; i++)
2505 {
2506 int c = p[i];
2507 if (! ((c >= 'a' && c <= 'z')
2508 || (c >= 'A' && c <= 'Z')
2509 || (c >= '0' && c <= '9')
2510 || c == '-' || c == '_'))
2511 bad_count++;
2512 else
2513 good_count++;
2514 }
2515 }
2516 else
2517 /* Not a string => completely invalid. */
2518 bad_count = 5, good_count = 0;
2519
2520 /* If name is valid already, return. */
2521 if (bad_count == 0)
2522 return;
2523
2524 /* If name is entirely invalid, or nearly so, use `emacs'. */
2525 if (good_count == 0
2526 || (good_count == 1 && bad_count > 0))
2527 {
2528 Vx_resource_name = build_string ("emacs");
2529 return;
2530 }
2531
2532 /* Name is partly valid. Copy it and replace the invalid characters
2533 with underscores. */
2534
2535 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2536
2537 for (i = 0; i < len; i++)
2538 {
2539 int c = XSTRING (new)->data[i];
2540 if (! ((c >= 'a' && c <= 'z')
2541 || (c >= 'A' && c <= 'Z')
2542 || (c >= '0' && c <= '9')
2543 || c == '-' || c == '_'))
2544 XSTRING (new)->data[i] = '_';
2545 }
2546}
2547
2548
2549extern char *x_get_string_resource ();
2550
2551DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2552 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2553This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2554class, where INSTANCE is the name under which Emacs was invoked, or\n\
2555the name specified by the `-name' or `-rn' command-line arguments.\n\
2556\n\
2557The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2558class, respectively. You must specify both of them or neither.\n\
2559If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2560and the class is `Emacs.CLASS.SUBCLASS'.")
2561 (attribute, class, component, subclass)
2562 Lisp_Object attribute, class, component, subclass;
2563{
2564 register char *value;
2565 char *name_key;
2566 char *class_key;
2567
2568 CHECK_STRING (attribute, 0);
2569 CHECK_STRING (class, 0);
2570
2571 if (!NILP (component))
2572 CHECK_STRING (component, 1);
2573 if (!NILP (subclass))
2574 CHECK_STRING (subclass, 2);
2575 if (NILP (component) != NILP (subclass))
2576 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2577
2578 validate_x_resource_name ();
2579
2580 /* Allocate space for the components, the dots which separate them,
2581 and the final '\0'. Make them big enough for the worst case. */
2582 name_key = (char *) alloca (XSTRING (Vx_resource_name)->size
2583 + (STRINGP (component)
2584 ? XSTRING (component)->size : 0)
2585 + XSTRING (attribute)->size
2586 + 3);
2587
2588 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2589 + XSTRING (class)->size
2590 + (STRINGP (subclass)
2591 ? XSTRING (subclass)->size : 0)
2592 + 3);
2593
2594 /* Start with emacs.FRAMENAME for the name (the specific one)
2595 and with `Emacs' for the class key (the general one). */
2596 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2597 strcpy (class_key, EMACS_CLASS);
2598
2599 strcat (class_key, ".");
2600 strcat (class_key, XSTRING (class)->data);
2601
2602 if (!NILP (component))
2603 {
2604 strcat (class_key, ".");
2605 strcat (class_key, XSTRING (subclass)->data);
2606
2607 strcat (name_key, ".");
2608 strcat (name_key, XSTRING (component)->data);
2609 }
2610
2611 strcat (name_key, ".");
2612 strcat (name_key, XSTRING (attribute)->data);
2613
2614 value = x_get_string_resource (Qnil,
2615 name_key, class_key);
2616
2617 if (value != (char *) 0)
2618 return build_string (value);
2619 else
2620 return Qnil;
2621}
2622
2623/* Used when C code wants a resource value. */
2624
2625char *
2626x_get_resource_string (attribute, class)
2627 char *attribute, *class;
2628{
2629 register char *value;
2630 char *name_key;
2631 char *class_key;
2632
2633 /* Allocate space for the components, the dots which separate them,
2634 and the final '\0'. */
2635 name_key = (char *) alloca (XSTRING (Vinvocation_name)->size
2636 + strlen (attribute) + 2);
2637 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2638 + strlen (class) + 2);
2639
2640 sprintf (name_key, "%s.%s",
2641 XSTRING (Vinvocation_name)->data,
2642 attribute);
2643 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2644
2645 return x_get_string_resource (selected_frame,
2646 name_key, class_key);
2647}
2648
2649/* Types we might convert a resource string into. */
2650enum resource_types
2651 {
2652 number, boolean, string, symbol
2653 };
2654
2655/* Return the value of parameter PARAM.
2656
2657 First search ALIST, then Vdefault_frame_alist, then the X defaults
2658 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2659
2660 Convert the resource to the type specified by desired_type.
2661
2662 If no default is specified, return Qunbound. If you call
2663 x_get_arg, make sure you deal with Qunbound in a reasonable way,
2664 and don't let it get stored in any Lisp-visible variables! */
2665
2666static Lisp_Object
2667x_get_arg (alist, param, attribute, class, type)
2668 Lisp_Object alist, param;
2669 char *attribute;
2670 char *class;
2671 enum resource_types type;
2672{
2673 register Lisp_Object tem;
2674
2675 tem = Fassq (param, alist);
2676 if (EQ (tem, Qnil))
2677 tem = Fassq (param, Vdefault_frame_alist);
2678 if (EQ (tem, Qnil))
2679 {
2680
2681 if (attribute)
2682 {
2683 tem = Fx_get_resource (build_string (attribute),
2684 build_string (class),
2685 Qnil, Qnil);
2686
2687 if (NILP (tem))
2688 return Qunbound;
2689
2690 switch (type)
2691 {
2692 case number:
2693 return make_number (atoi (XSTRING (tem)->data));
2694
2695 case boolean:
2696 tem = Fdowncase (tem);
2697 if (!strcmp (XSTRING (tem)->data, "on")
2698 || !strcmp (XSTRING (tem)->data, "true"))
2699 return Qt;
2700 else
2701 return Qnil;
2702
2703 case string:
2704 return tem;
2705
2706 case symbol:
2707 /* As a special case, we map the values `true' and `on'
2708 to Qt, and `false' and `off' to Qnil. */
2709 {
2710 Lisp_Object lower;
2711 lower = Fdowncase (tem);
2712 if (!strcmp (XSTRING (lower)->data, "on")
2713 || !strcmp (XSTRING (lower)->data, "true"))
2714 return Qt;
2715 else if (!strcmp (XSTRING (lower)->data, "off")
2716 || !strcmp (XSTRING (lower)->data, "false"))
2717 return Qnil;
2718 else
2719 return Fintern (tem, Qnil);
2720 }
2721
2722 default:
2723 abort ();
2724 }
2725 }
2726 else
2727 return Qunbound;
2728 }
2729 return Fcdr (tem);
2730}
2731
2732/* Record in frame F the specified or default value according to ALIST
2733 of the parameter named PARAM (a Lisp symbol).
2734 If no value is specified for PARAM, look for an X default for XPROP
2735 on the frame named NAME.
2736 If that is not found either, use the value DEFLT. */
2737
2738static Lisp_Object
2739x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
2740 struct frame *f;
2741 Lisp_Object alist;
2742 Lisp_Object prop;
2743 Lisp_Object deflt;
2744 char *xprop;
2745 char *xclass;
2746 enum resource_types type;
2747{
2748 Lisp_Object tem;
2749
2750 tem = x_get_arg (alist, prop, xprop, xclass, type);
2751 if (EQ (tem, Qunbound))
2752 tem = deflt;
2753 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
2754 return tem;
2755}
2756\f
2757DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
2758 "Parse an X-style geometry string STRING.\n\
2759Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
2760The properties returned may include `top', `left', `height', and `width'.\n\
2761The value of `left' or `top' may be an integer,\n\
2762or a list (+ N) meaning N pixels relative to top/left corner,\n\
2763or a list (- N) meaning -N pixels relative to bottom/right corner.")
2764 (string)
2765 Lisp_Object string;
2766{
2767 int geometry, x, y;
2768 unsigned int width, height;
2769 Lisp_Object result;
2770
2771 CHECK_STRING (string, 0);
2772
2773 geometry = XParseGeometry ((char *) XSTRING (string)->data,
2774 &x, &y, &width, &height);
2775
2776 result = Qnil;
2777 if (geometry & XValue)
2778 {
2779 Lisp_Object element;
2780
2781 if (x >= 0 && (geometry & XNegative))
2782 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
2783 else if (x < 0 && ! (geometry & XNegative))
2784 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
2785 else
2786 element = Fcons (Qleft, make_number (x));
2787 result = Fcons (element, result);
2788 }
2789
2790 if (geometry & YValue)
2791 {
2792 Lisp_Object element;
2793
2794 if (y >= 0 && (geometry & YNegative))
2795 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
2796 else if (y < 0 && ! (geometry & YNegative))
2797 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
2798 else
2799 element = Fcons (Qtop, make_number (y));
2800 result = Fcons (element, result);
2801 }
2802
2803 if (geometry & WidthValue)
2804 result = Fcons (Fcons (Qwidth, make_number (width)), result);
2805 if (geometry & HeightValue)
2806 result = Fcons (Fcons (Qheight, make_number (height)), result);
2807
2808 return result;
2809}
2810
2811/* Calculate the desired size and position of this window,
2812 and return the flags saying which aspects were specified.
2813
2814 This function does not make the coordinates positive. */
2815
2816#define DEFAULT_ROWS 40
2817#define DEFAULT_COLS 80
2818
2819static int
2820x_figure_window_size (f, parms)
2821 struct frame *f;
2822 Lisp_Object parms;
2823{
2824 register Lisp_Object tem0, tem1, tem2;
2825 int height, width, left, top;
2826 register int geometry;
2827 long window_prompting = 0;
2828
2829 /* Default values if we fall through.
2830 Actually, if that happens we should get
2831 window manager prompting. */
1026b400 2832 SET_FRAME_WIDTH (f, DEFAULT_COLS);
ee78dc32
GV
2833 f->height = DEFAULT_ROWS;
2834 /* Window managers expect that if program-specified
2835 positions are not (0,0), they're intentional, not defaults. */
fbd6baed
GV
2836 f->output_data.w32->top_pos = 0;
2837 f->output_data.w32->left_pos = 0;
ee78dc32
GV
2838
2839 tem0 = x_get_arg (parms, Qheight, 0, 0, number);
2840 tem1 = x_get_arg (parms, Qwidth, 0, 0, number);
2841 tem2 = x_get_arg (parms, Quser_size, 0, 0, number);
2842 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
2843 {
2844 if (!EQ (tem0, Qunbound))
2845 {
2846 CHECK_NUMBER (tem0, 0);
2847 f->height = XINT (tem0);
2848 }
2849 if (!EQ (tem1, Qunbound))
2850 {
2851 CHECK_NUMBER (tem1, 0);
1026b400 2852 SET_FRAME_WIDTH (f, XINT (tem1));
ee78dc32
GV
2853 }
2854 if (!NILP (tem2) && !EQ (tem2, Qunbound))
2855 window_prompting |= USSize;
2856 else
2857 window_prompting |= PSize;
2858 }
2859
fbd6baed 2860 f->output_data.w32->vertical_scroll_bar_extra
ee78dc32
GV
2861 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
2862 ? 0
2863 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
2864 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
fbd6baed
GV
2865 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
2866 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
2867 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
ee78dc32
GV
2868
2869 tem0 = x_get_arg (parms, Qtop, 0, 0, number);
2870 tem1 = x_get_arg (parms, Qleft, 0, 0, number);
2871 tem2 = x_get_arg (parms, Quser_position, 0, 0, number);
2872 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
2873 {
2874 if (EQ (tem0, Qminus))
2875 {
fbd6baed 2876 f->output_data.w32->top_pos = 0;
ee78dc32
GV
2877 window_prompting |= YNegative;
2878 }
2879 else if (CONSP (tem0) && EQ (XCONS (tem0)->car, Qminus)
2880 && CONSP (XCONS (tem0)->cdr)
2881 && INTEGERP (XCONS (XCONS (tem0)->cdr)->car))
2882 {
fbd6baed 2883 f->output_data.w32->top_pos = - XINT (XCONS (XCONS (tem0)->cdr)->car);
ee78dc32
GV
2884 window_prompting |= YNegative;
2885 }
2886 else if (CONSP (tem0) && EQ (XCONS (tem0)->car, Qplus)
2887 && CONSP (XCONS (tem0)->cdr)
2888 && INTEGERP (XCONS (XCONS (tem0)->cdr)->car))
2889 {
fbd6baed 2890 f->output_data.w32->top_pos = XINT (XCONS (XCONS (tem0)->cdr)->car);
ee78dc32
GV
2891 }
2892 else if (EQ (tem0, Qunbound))
fbd6baed 2893 f->output_data.w32->top_pos = 0;
ee78dc32
GV
2894 else
2895 {
2896 CHECK_NUMBER (tem0, 0);
fbd6baed
GV
2897 f->output_data.w32->top_pos = XINT (tem0);
2898 if (f->output_data.w32->top_pos < 0)
ee78dc32
GV
2899 window_prompting |= YNegative;
2900 }
2901
2902 if (EQ (tem1, Qminus))
2903 {
fbd6baed 2904 f->output_data.w32->left_pos = 0;
ee78dc32
GV
2905 window_prompting |= XNegative;
2906 }
2907 else if (CONSP (tem1) && EQ (XCONS (tem1)->car, Qminus)
2908 && CONSP (XCONS (tem1)->cdr)
2909 && INTEGERP (XCONS (XCONS (tem1)->cdr)->car))
2910 {
fbd6baed 2911 f->output_data.w32->left_pos = - XINT (XCONS (XCONS (tem1)->cdr)->car);
ee78dc32
GV
2912 window_prompting |= XNegative;
2913 }
2914 else if (CONSP (tem1) && EQ (XCONS (tem1)->car, Qplus)
2915 && CONSP (XCONS (tem1)->cdr)
2916 && INTEGERP (XCONS (XCONS (tem1)->cdr)->car))
2917 {
fbd6baed 2918 f->output_data.w32->left_pos = XINT (XCONS (XCONS (tem1)->cdr)->car);
ee78dc32
GV
2919 }
2920 else if (EQ (tem1, Qunbound))
fbd6baed 2921 f->output_data.w32->left_pos = 0;
ee78dc32
GV
2922 else
2923 {
2924 CHECK_NUMBER (tem1, 0);
fbd6baed
GV
2925 f->output_data.w32->left_pos = XINT (tem1);
2926 if (f->output_data.w32->left_pos < 0)
ee78dc32
GV
2927 window_prompting |= XNegative;
2928 }
2929
2930 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
2931 window_prompting |= USPosition;
2932 else
2933 window_prompting |= PPosition;
2934 }
2935
2936 return window_prompting;
2937}
2938
2939\f
2940
fbd6baed 2941extern LRESULT CALLBACK w32_wnd_proc ();
ee78dc32
GV
2942
2943BOOL
fbd6baed 2944w32_init_class (hinst)
ee78dc32
GV
2945 HINSTANCE hinst;
2946{
2947 WNDCLASS wc;
2948
5ac45f98 2949 wc.style = CS_HREDRAW | CS_VREDRAW;
fbd6baed 2950 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
ee78dc32
GV
2951 wc.cbClsExtra = 0;
2952 wc.cbWndExtra = WND_EXTRA_BYTES;
2953 wc.hInstance = hinst;
2954 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
2955 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
4587b026 2956 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
ee78dc32
GV
2957 wc.lpszMenuName = NULL;
2958 wc.lpszClassName = EMACS_CLASS;
2959
2960 return (RegisterClass (&wc));
2961}
2962
2963HWND
fbd6baed 2964w32_createscrollbar (f, bar)
ee78dc32
GV
2965 struct frame *f;
2966 struct scroll_bar * bar;
2967{
2968 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
2969 /* Position and size of scroll bar. */
2970 XINT(bar->left), XINT(bar->top),
2971 XINT(bar->width), XINT(bar->height),
fbd6baed 2972 FRAME_W32_WINDOW (f),
ee78dc32
GV
2973 NULL,
2974 hinst,
2975 NULL));
2976}
2977
2978void
fbd6baed 2979w32_createwindow (f)
ee78dc32
GV
2980 struct frame *f;
2981{
2982 HWND hwnd;
1edf84e7
GV
2983 RECT rect;
2984
2985 rect.left = rect.top = 0;
2986 rect.right = PIXEL_WIDTH (f);
2987 rect.bottom = PIXEL_HEIGHT (f);
2988
2989 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
2990 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
2991
2992 /* Do first time app init */
2993
2994 if (!hprevinst)
2995 {
fbd6baed 2996 w32_init_class (hinst);
ee78dc32
GV
2997 }
2998
1edf84e7
GV
2999 FRAME_W32_WINDOW (f) = hwnd
3000 = CreateWindow (EMACS_CLASS,
3001 f->namebuf,
3002 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3003 f->output_data.w32->left_pos,
3004 f->output_data.w32->top_pos,
3005 rect.right - rect.left,
3006 rect.bottom - rect.top,
3007 NULL,
3008 NULL,
3009 hinst,
3010 NULL);
3011
ee78dc32
GV
3012 if (hwnd)
3013 {
1edf84e7
GV
3014 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3015 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3016 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3017 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
fbd6baed 3018 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, f->output_data.w32->background_pixel);
ee78dc32 3019
cb9e33d4
RS
3020 /* Enable drag-n-drop. */
3021 DragAcceptFiles (hwnd, TRUE);
3022
5ac45f98
GV
3023 /* Do this to discard the default setting specified by our parent. */
3024 ShowWindow (hwnd, SW_HIDE);
3c190163 3025 }
3c190163
GV
3026}
3027
ee78dc32
GV
3028void
3029my_post_msg (wmsg, hwnd, msg, wParam, lParam)
fbd6baed 3030 W32Msg * wmsg;
ee78dc32
GV
3031 HWND hwnd;
3032 UINT msg;
3033 WPARAM wParam;
3034 LPARAM lParam;
3035{
3036 wmsg->msg.hwnd = hwnd;
3037 wmsg->msg.message = msg;
3038 wmsg->msg.wParam = wParam;
3039 wmsg->msg.lParam = lParam;
3040 wmsg->msg.time = GetMessageTime ();
3041
3042 post_msg (wmsg);
3043}
3044
e9e23e23 3045/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
a1a80b40
GV
3046 between left and right keys as advertised. We test for this
3047 support dynamically, and set a flag when the support is absent. If
3048 absent, we keep track of the left and right control and alt keys
3049 ourselves. This is particularly necessary on keyboards that rely
3050 upon the AltGr key, which is represented as having the left control
3051 and right alt keys pressed. For these keyboards, we need to know
3052 when the left alt key has been pressed in addition to the AltGr key
3053 so that we can properly support M-AltGr-key sequences (such as M-@
3054 on Swedish keyboards). */
3055
3056#define EMACS_LCONTROL 0
3057#define EMACS_RCONTROL 1
3058#define EMACS_LMENU 2
3059#define EMACS_RMENU 3
3060
3061static int modifiers[4];
3062static int modifiers_recorded;
3063static int modifier_key_support_tested;
3064
3065static void
3066test_modifier_support (unsigned int wparam)
3067{
3068 unsigned int l, r;
3069
3070 if (wparam != VK_CONTROL && wparam != VK_MENU)
3071 return;
3072 if (wparam == VK_CONTROL)
3073 {
3074 l = VK_LCONTROL;
3075 r = VK_RCONTROL;
3076 }
3077 else
3078 {
3079 l = VK_LMENU;
3080 r = VK_RMENU;
3081 }
3082 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3083 modifiers_recorded = 1;
3084 else
3085 modifiers_recorded = 0;
3086 modifier_key_support_tested = 1;
3087}
3088
3089static void
3090record_keydown (unsigned int wparam, unsigned int lparam)
3091{
3092 int i;
3093
3094 if (!modifier_key_support_tested)
3095 test_modifier_support (wparam);
3096
3097 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3098 return;
3099
3100 if (wparam == VK_CONTROL)
3101 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3102 else
3103 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3104
3105 modifiers[i] = 1;
3106}
3107
3108static void
3109record_keyup (unsigned int wparam, unsigned int lparam)
3110{
3111 int i;
3112
3113 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3114 return;
3115
3116 if (wparam == VK_CONTROL)
3117 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3118 else
3119 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3120
3121 modifiers[i] = 0;
3122}
3123
da36a4d6
GV
3124/* Emacs can lose focus while a modifier key has been pressed. When
3125 it regains focus, be conservative and clear all modifiers since
3126 we cannot reconstruct the left and right modifier state. */
3127static void
3128reset_modifiers ()
3129{
8681157a
RS
3130 SHORT ctrl, alt;
3131
adcc3809
GV
3132 if (GetFocus () == NULL)
3133 /* Emacs doesn't have keyboard focus. Do nothing. */
da36a4d6 3134 return;
8681157a
RS
3135
3136 ctrl = GetAsyncKeyState (VK_CONTROL);
3137 alt = GetAsyncKeyState (VK_MENU);
3138
8681157a
RS
3139 if (!(ctrl & 0x08000))
3140 /* Clear any recorded control modifier state. */
3141 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3142
3143 if (!(alt & 0x08000))
3144 /* Clear any recorded alt modifier state. */
3145 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3146
adcc3809
GV
3147 /* Update the state of all modifier keys, because modifiers used in
3148 hot-key combinations can get stuck on if Emacs loses focus as a
3149 result of a hot-key being pressed. */
3150 {
3151 BYTE keystate[256];
3152
3153#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3154
3155 GetKeyboardState (keystate);
3156 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3157 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3158 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3159 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3160 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3161 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3162 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3163 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3164 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3165 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3166 SetKeyboardState (keystate);
3167 }
da36a4d6
GV
3168}
3169
7830e24b
RS
3170/* Synchronize modifier state with what is reported with the current
3171 keystroke. Even if we cannot distinguish between left and right
3172 modifier keys, we know that, if no modifiers are set, then neither
3173 the left or right modifier should be set. */
3174static void
3175sync_modifiers ()
3176{
3177 if (!modifiers_recorded)
3178 return;
3179
3180 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3181 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3182
3183 if (!(GetKeyState (VK_MENU) & 0x8000))
3184 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3185}
3186
a1a80b40
GV
3187static int
3188modifier_set (int vkey)
3189{
ccc2d29c 3190 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
891560d6 3191 return (GetKeyState (vkey) & 0x1);
a1a80b40
GV
3192 if (!modifiers_recorded)
3193 return (GetKeyState (vkey) & 0x8000);
3194
3195 switch (vkey)
3196 {
3197 case VK_LCONTROL:
3198 return modifiers[EMACS_LCONTROL];
3199 case VK_RCONTROL:
3200 return modifiers[EMACS_RCONTROL];
3201 case VK_LMENU:
3202 return modifiers[EMACS_LMENU];
3203 case VK_RMENU:
3204 return modifiers[EMACS_RMENU];
a1a80b40
GV
3205 }
3206 return (GetKeyState (vkey) & 0x8000);
3207}
3208
ccc2d29c
GV
3209/* Convert between the modifier bits W32 uses and the modifier bits
3210 Emacs uses. */
3211
3212unsigned int
3213w32_key_to_modifier (int key)
3214{
3215 Lisp_Object key_mapping;
3216
3217 switch (key)
3218 {
3219 case VK_LWIN:
3220 key_mapping = Vw32_lwindow_modifier;
3221 break;
3222 case VK_RWIN:
3223 key_mapping = Vw32_rwindow_modifier;
3224 break;
3225 case VK_APPS:
3226 key_mapping = Vw32_apps_modifier;
3227 break;
3228 case VK_SCROLL:
3229 key_mapping = Vw32_scroll_lock_modifier;
3230 break;
3231 default:
3232 key_mapping = Qnil;
3233 }
3234
adcc3809
GV
3235 /* NB. This code runs in the input thread, asychronously to the lisp
3236 thread, so we must be careful to ensure access to lisp data is
3237 thread-safe. The following code is safe because the modifier
3238 variable values are updated atomically from lisp and symbols are
3239 not relocated by GC. Also, we don't have to worry about seeing GC
3240 markbits here. */
3241 if (EQ (key_mapping, Qhyper))
ccc2d29c 3242 return hyper_modifier;
adcc3809 3243 if (EQ (key_mapping, Qsuper))
ccc2d29c 3244 return super_modifier;
adcc3809 3245 if (EQ (key_mapping, Qmeta))
ccc2d29c 3246 return meta_modifier;
adcc3809 3247 if (EQ (key_mapping, Qalt))
ccc2d29c 3248 return alt_modifier;
adcc3809 3249 if (EQ (key_mapping, Qctrl))
ccc2d29c 3250 return ctrl_modifier;
adcc3809 3251 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
ccc2d29c 3252 return ctrl_modifier;
adcc3809 3253 if (EQ (key_mapping, Qshift))
ccc2d29c
GV
3254 return shift_modifier;
3255
3256 /* Don't generate any modifier if not explicitly requested. */
3257 return 0;
3258}
3259
3260unsigned int
3261w32_get_modifiers ()
3262{
3263 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3264 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3265 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3266 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3267 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3268 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3269 (modifier_set (VK_MENU) ?
3270 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3271}
3272
a1a80b40
GV
3273/* We map the VK_* modifiers into console modifier constants
3274 so that we can use the same routines to handle both console
3275 and window input. */
3276
3277static int
ccc2d29c 3278construct_console_modifiers ()
a1a80b40
GV
3279{
3280 int mods;
3281
a1a80b40
GV
3282 mods = 0;
3283 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3284 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
ccc2d29c
GV
3285 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3286 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
a1a80b40
GV
3287 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3288 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3289 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3290 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
ccc2d29c
GV
3291 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3292 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3293 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
a1a80b40
GV
3294
3295 return mods;
3296}
3297
ccc2d29c
GV
3298static int
3299w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
da36a4d6 3300{
ccc2d29c
GV
3301 int mods;
3302
3303 /* Convert to emacs modifiers. */
3304 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3305
3306 return mods;
3307}
da36a4d6 3308
ccc2d29c
GV
3309unsigned int
3310map_keypad_keys (unsigned int virt_key, unsigned int extended)
3311{
3312 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3313 return virt_key;
da36a4d6 3314
ccc2d29c 3315 if (virt_key == VK_RETURN)
da36a4d6
GV
3316 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3317
ccc2d29c
GV
3318 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3319 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3320
3321 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3322 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3323
3324 if (virt_key == VK_CLEAR)
3325 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3326
3327 return virt_key;
3328}
3329
3330/* List of special key combinations which w32 would normally capture,
3331 but emacs should grab instead. Not directly visible to lisp, to
3332 simplify synchronization. Each item is an integer encoding a virtual
3333 key code and modifier combination to capture. */
3334Lisp_Object w32_grabbed_keys;
3335
3336#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3337#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3338#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3339#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3340
3341/* Register hot-keys for reserved key combinations when Emacs has
3342 keyboard focus, since this is the only way Emacs can receive key
3343 combinations like Alt-Tab which are used by the system. */
3344
3345static void
3346register_hot_keys (hwnd)
3347 HWND hwnd;
3348{
3349 Lisp_Object keylist;
3350
3351 /* Use GC_CONSP, since we are called asynchronously. */
3352 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3353 {
3354 Lisp_Object key = XCAR (keylist);
3355
3356 /* Deleted entries get set to nil. */
3357 if (!INTEGERP (key))
3358 continue;
3359
3360 RegisterHotKey (hwnd, HOTKEY_ID (key),
3361 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3362 }
3363}
3364
3365static void
3366unregister_hot_keys (hwnd)
3367 HWND hwnd;
3368{
3369 Lisp_Object keylist;
3370
3371 /* Use GC_CONSP, since we are called asynchronously. */
3372 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3373 {
3374 Lisp_Object key = XCAR (keylist);
3375
3376 if (!INTEGERP (key))
3377 continue;
3378
3379 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3380 }
3381}
3382
5ac45f98
GV
3383/* Main message dispatch loop. */
3384
1edf84e7
GV
3385static void
3386w32_msg_pump (deferred_msg * msg_buf)
5ac45f98
GV
3387{
3388 MSG msg;
ccc2d29c
GV
3389 int result;
3390 HWND focus_window;
93fbe8b7
GV
3391
3392 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
5ac45f98 3393
5ac45f98
GV
3394 while (GetMessage (&msg, NULL, 0, 0))
3395 {
3396 if (msg.hwnd == NULL)
3397 {
3398 switch (msg.message)
3399 {
3ef68e6b
AI
3400 case WM_NULL:
3401 /* Produced by complete_deferred_msg; just ignore. */
3402 break;
5ac45f98 3403 case WM_EMACS_CREATEWINDOW:
fbd6baed 3404 w32_createwindow ((struct frame *) msg.wParam);
1edf84e7
GV
3405 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3406 abort ();
5ac45f98 3407 break;
dfdb4047
GV
3408 case WM_EMACS_SETLOCALE:
3409 SetThreadLocale (msg.wParam);
3410 /* Reply is not expected. */
3411 break;
ccc2d29c
GV
3412 case WM_EMACS_SETKEYBOARDLAYOUT:
3413 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3414 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3415 result, 0))
3416 abort ();
3417 break;
3418 case WM_EMACS_REGISTER_HOT_KEY:
3419 focus_window = GetFocus ();
3420 if (focus_window != NULL)
3421 RegisterHotKey (focus_window,
3422 HOTKEY_ID (msg.wParam),
3423 HOTKEY_MODIFIERS (msg.wParam),
3424 HOTKEY_VK_CODE (msg.wParam));
3425 /* Reply is not expected. */
3426 break;
3427 case WM_EMACS_UNREGISTER_HOT_KEY:
3428 focus_window = GetFocus ();
3429 if (focus_window != NULL)
3430 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
adcc3809
GV
3431 /* Mark item as erased. NB: this code must be
3432 thread-safe. The next line is okay because the cons
3433 cell is never made into garbage and is not relocated by
3434 GC. */
ccc2d29c
GV
3435 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3436 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3437 abort ();
3438 break;
adcc3809
GV
3439 case WM_EMACS_TOGGLE_LOCK_KEY:
3440 {
3441 int vk_code = (int) msg.wParam;
3442 int cur_state = (GetKeyState (vk_code) & 1);
3443 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3444
3445 /* NB: This code must be thread-safe. It is safe to
3446 call NILP because symbols are not relocated by GC,
3447 and pointer here is not touched by GC (so the markbit
3448 can't be set). Numbers are safe because they are
3449 immediate values. */
3450 if (NILP (new_state)
3451 || (NUMBERP (new_state)
3452 && (XUINT (new_state)) & 1 != cur_state))
3453 {
3454 one_w32_display_info.faked_key = vk_code;
3455
3456 keybd_event ((BYTE) vk_code,
3457 (BYTE) MapVirtualKey (vk_code, 0),
3458 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3459 keybd_event ((BYTE) vk_code,
3460 (BYTE) MapVirtualKey (vk_code, 0),
3461 KEYEVENTF_EXTENDEDKEY | 0, 0);
3462 keybd_event ((BYTE) vk_code,
3463 (BYTE) MapVirtualKey (vk_code, 0),
3464 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3465 cur_state = !cur_state;
3466 }
3467 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3468 cur_state, 0))
3469 abort ();
3470 }
3471 break;
1edf84e7 3472 default:
1edf84e7 3473 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
5ac45f98
GV
3474 }
3475 }
3476 else
3477 {
3478 DispatchMessage (&msg);
3479 }
1edf84e7
GV
3480
3481 /* Exit nested loop when our deferred message has completed. */
3482 if (msg_buf->completed)
3483 break;
5ac45f98 3484 }
1edf84e7
GV
3485}
3486
3487deferred_msg * deferred_msg_head;
3488
3489static deferred_msg *
3490find_deferred_msg (HWND hwnd, UINT msg)
3491{
3492 deferred_msg * item;
3493
3494 /* Don't actually need synchronization for read access, since
3495 modification of single pointer is always atomic. */
3496 /* enter_crit (); */
3497
3498 for (item = deferred_msg_head; item != NULL; item = item->next)
3499 if (item->w32msg.msg.hwnd == hwnd
3500 && item->w32msg.msg.message == msg)
3501 break;
3502
3503 /* leave_crit (); */
3504
3505 return item;
3506}
3507
3508static LRESULT
3509send_deferred_msg (deferred_msg * msg_buf,
3510 HWND hwnd,
3511 UINT msg,
3512 WPARAM wParam,
3513 LPARAM lParam)
3514{
3515 /* Only input thread can send deferred messages. */
3516 if (GetCurrentThreadId () != dwWindowsThreadId)
3517 abort ();
3518
3519 /* It is an error to send a message that is already deferred. */
3520 if (find_deferred_msg (hwnd, msg) != NULL)
3521 abort ();
3522
3523 /* Enforced synchronization is not needed because this is the only
3524 function that alters deferred_msg_head, and the following critical
3525 section is guaranteed to only be serially reentered (since only the
3526 input thread can call us). */
3527
3528 /* enter_crit (); */
3529
3530 msg_buf->completed = 0;
3531 msg_buf->next = deferred_msg_head;
3532 deferred_msg_head = msg_buf;
3533 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3534
3535 /* leave_crit (); */
3536
3537 /* Start a new nested message loop to process other messages until
3538 this one is completed. */
3539 w32_msg_pump (msg_buf);
3540
3541 deferred_msg_head = msg_buf->next;
3542
3543 return msg_buf->result;
3544}
3545
3546void
3547complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3548{
3549 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3550
3551 if (msg_buf == NULL)
3ef68e6b
AI
3552 /* Message may have been cancelled, so don't abort(). */
3553 return;
1edf84e7
GV
3554
3555 msg_buf->result = result;
3556 msg_buf->completed = 1;
3557
3558 /* Ensure input thread is woken so it notices the completion. */
3559 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3560}
3561
3ef68e6b
AI
3562void
3563cancel_all_deferred_msgs ()
3564{
3565 deferred_msg * item;
3566
3567 /* Don't actually need synchronization for read access, since
3568 modification of single pointer is always atomic. */
3569 /* enter_crit (); */
3570
3571 for (item = deferred_msg_head; item != NULL; item = item->next)
3572 {
3573 item->result = 0;
3574 item->completed = 1;
3575 }
3576
3577 /* leave_crit (); */
3578
3579 /* Ensure input thread is woken so it notices the completion. */
3580 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3581}
1edf84e7
GV
3582
3583DWORD
3584w32_msg_worker (dw)
3585 DWORD dw;
3586{
3587 MSG msg;
3588 deferred_msg dummy_buf;
3589
3590 /* Ensure our message queue is created */
3591
3592 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5ac45f98 3593
1edf84e7
GV
3594 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3595 abort ();
3596
3597 memset (&dummy_buf, 0, sizeof (dummy_buf));
3598 dummy_buf.w32msg.msg.hwnd = NULL;
3599 dummy_buf.w32msg.msg.message = WM_NULL;
3600
3601 /* This is the inital message loop which should only exit when the
3602 application quits. */
3603 w32_msg_pump (&dummy_buf);
3604
3605 return 0;
5ac45f98
GV
3606}
3607
3ef68e6b
AI
3608static void
3609post_character_message (hwnd, msg, wParam, lParam, modifiers)
3610 HWND hwnd;
3611 UINT msg;
3612 WPARAM wParam;
3613 LPARAM lParam;
3614 DWORD modifiers;
3615
3616{
3617 W32Msg wmsg;
3618
3619 wmsg.dwModifiers = modifiers;
3620
3621 /* Detect quit_char and set quit-flag directly. Note that we
3622 still need to post a message to ensure the main thread will be
3623 woken up if blocked in sys_select(), but we do NOT want to post
3624 the quit_char message itself (because it will usually be as if
3625 the user had typed quit_char twice). Instead, we post a dummy
3626 message that has no particular effect. */
3627 {
3628 int c = wParam;
3629 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3630 c = make_ctrl_char (c) & 0377;
7d081355
AI
3631 if (c == quit_char
3632 || (wmsg.dwModifiers == 0 &&
3633 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3ef68e6b
AI
3634 {
3635 Vquit_flag = Qt;
3636
3637 /* The choice of message is somewhat arbitrary, as long as
3638 the main thread handler just ignores it. */
3639 msg = WM_NULL;
3640
3641 /* Interrupt any blocking system calls. */
3642 signal_quit ();
3643
3644 /* As a safety precaution, forcibly complete any deferred
3645 messages. This is a kludge, but I don't see any particularly
3646 clean way to handle the situation where a deferred message is
3647 "dropped" in the lisp thread, and will thus never be
3648 completed, eg. by the user trying to activate the menubar
3649 when the lisp thread is busy, and then typing C-g when the
3650 menubar doesn't open promptly (with the result that the
3651 menubar never responds at all because the deferred
3652 WM_INITMENU message is never completed). Another problem
3653 situation is when the lisp thread calls SendMessage (to send
3654 a window manager command) when a message has been deferred;
3655 the lisp thread gets blocked indefinitely waiting for the
3656 deferred message to be completed, which itself is waiting for
3657 the lisp thread to respond.
3658
3659 Note that we don't want to block the input thread waiting for
3660 a reponse from the lisp thread (although that would at least
3661 solve the deadlock problem above), because we want to be able
3662 to receive C-g to interrupt the lisp thread. */
3663 cancel_all_deferred_msgs ();
3664 }
3665 }
3666
3667 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3668}
3669
ee78dc32
GV
3670/* Main window procedure */
3671
ee78dc32 3672LRESULT CALLBACK
fbd6baed 3673w32_wnd_proc (hwnd, msg, wParam, lParam)
ee78dc32
GV
3674 HWND hwnd;
3675 UINT msg;
3676 WPARAM wParam;
3677 LPARAM lParam;
3678{
3679 struct frame *f;
fbd6baed
GV
3680 struct w32_display_info *dpyinfo = &one_w32_display_info;
3681 W32Msg wmsg;
84fb1139 3682 int windows_translate;
576ba81c 3683 int key;
84fb1139 3684
a6085637
KH
3685 /* Note that it is okay to call x_window_to_frame, even though we are
3686 not running in the main lisp thread, because frame deletion
3687 requires the lisp thread to synchronize with this thread. Thus, if
3688 a frame struct is returned, it can be used without concern that the
3689 lisp thread might make it disappear while we are using it.
3690
3691 NB. Walking the frame list in this thread is safe (as long as
3692 writes of Lisp_Object slots are atomic, which they are on Windows).
3693 Although delete-frame can destructively modify the frame list while
3694 we are walking it, a garbage collection cannot occur until after
3695 delete-frame has synchronized with this thread.
3696
3697 It is also safe to use functions that make GDI calls, such as
fbd6baed 3698 w32_clear_rect, because these functions must obtain a DC handle
a6085637
KH
3699 from the frame struct using get_frame_dc which is thread-aware. */
3700
ee78dc32
GV
3701 switch (msg)
3702 {
3703 case WM_ERASEBKGND:
a6085637
KH
3704 f = x_window_to_frame (dpyinfo, hwnd);
3705 if (f)
3706 {
3707 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
fbd6baed 3708 w32_clear_rect (f, NULL, &wmsg.rect);
ce6059da
AI
3709
3710#if defined (W32_DEBUG_DISPLAY)
3711 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
3712 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
3713 wmsg.rect.bottom));
3714#endif /* W32_DEBUG_DISPLAY */
a6085637 3715 }
5ac45f98
GV
3716 return 1;
3717 case WM_PALETTECHANGED:
3718 /* ignore our own changes */
3719 if ((HWND)wParam != hwnd)
3720 {
a6085637
KH
3721 f = x_window_to_frame (dpyinfo, hwnd);
3722 if (f)
3723 /* get_frame_dc will realize our palette and force all
3724 frames to be redrawn if needed. */
3725 release_frame_dc (f, get_frame_dc (f));
5ac45f98
GV
3726 }
3727 return 0;
ee78dc32 3728 case WM_PAINT:
ce6059da 3729 {
55dcfc15
AI
3730 PAINTSTRUCT paintStruct;
3731 RECT update_rect;
3732
3733 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
3734 fails. Apparently this can happen under some
3735 circumstances. */
c0611964 3736 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
55dcfc15
AI
3737 {
3738 enter_crit ();
3739 BeginPaint (hwnd, &paintStruct);
3740
c0611964
AI
3741 if (w32_strict_painting)
3742 /* The rectangles returned by GetUpdateRect and BeginPaint
3743 do not always match. GetUpdateRect seems to be the
3744 more reliable of the two. */
3745 wmsg.rect = update_rect;
3746 else
3747 wmsg.rect = paintStruct.rcPaint;
55dcfc15
AI
3748
3749#if defined (W32_DEBUG_DISPLAY)
3750 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
3751 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
3752 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
3753 update_rect.left, update_rect.top,
3754 update_rect.right, update_rect.bottom));
3755#endif
3756 EndPaint (hwnd, &paintStruct);
3757 leave_crit ();
3758
3759 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3760
3761 return 0;
3762 }
c0611964
AI
3763
3764 /* If GetUpdateRect returns 0 (meaning there is no update
3765 region), assume the whole window needs to be repainted. */
3766 GetClientRect(hwnd, &wmsg.rect);
3767 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3768 return 0;
ee78dc32 3769 }
a1a80b40 3770
ccc2d29c
GV
3771 case WM_INPUTLANGCHANGE:
3772 /* Inform lisp thread of keyboard layout changes. */
3773 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3774
3775 /* Clear dead keys in the keyboard state; for simplicity only
3776 preserve modifier key states. */
3777 {
3778 int i;
3779 BYTE keystate[256];
3780
3781 GetKeyboardState (keystate);
3782 for (i = 0; i < 256; i++)
3783 if (1
3784 && i != VK_SHIFT
3785 && i != VK_LSHIFT
3786 && i != VK_RSHIFT
3787 && i != VK_CAPITAL
3788 && i != VK_NUMLOCK
3789 && i != VK_SCROLL
3790 && i != VK_CONTROL
3791 && i != VK_LCONTROL
3792 && i != VK_RCONTROL
3793 && i != VK_MENU
3794 && i != VK_LMENU
3795 && i != VK_RMENU
3796 && i != VK_LWIN
3797 && i != VK_RWIN)
3798 keystate[i] = 0;
3799 SetKeyboardState (keystate);
3800 }
3801 goto dflt;
3802
3803 case WM_HOTKEY:
3804 /* Synchronize hot keys with normal input. */
3805 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
3806 return (0);
3807
a1a80b40
GV
3808 case WM_KEYUP:
3809 case WM_SYSKEYUP:
3810 record_keyup (wParam, lParam);
3811 goto dflt;
3812
ee78dc32
GV
3813 case WM_KEYDOWN:
3814 case WM_SYSKEYDOWN:
ccc2d29c
GV
3815 /* Ignore keystrokes we fake ourself; see below. */
3816 if (dpyinfo->faked_key == wParam)
3817 {
3818 dpyinfo->faked_key = 0;
576ba81c
AI
3819 /* Make sure TranslateMessage sees them though (as long as
3820 they don't produce WM_CHAR messages). This ensures that
3821 indicator lights are toggled promptly on Windows 9x, for
3822 example. */
3823 if (lispy_function_keys[wParam] != 0)
3824 {
3825 windows_translate = 1;
3826 goto translate;
3827 }
3828 return 0;
ccc2d29c
GV
3829 }
3830
7830e24b
RS
3831 /* Synchronize modifiers with current keystroke. */
3832 sync_modifiers ();
a1a80b40 3833 record_keydown (wParam, lParam);
ccc2d29c 3834 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
84fb1139
KH
3835
3836 windows_translate = 0;
ccc2d29c
GV
3837
3838 switch (wParam)
3839 {
3840 case VK_LWIN:
3841 if (NILP (Vw32_pass_lwindow_to_system))
3842 {
3843 /* Prevent system from acting on keyup (which opens the
3844 Start menu if no other key was pressed) by simulating a
3845 press of Space which we will ignore. */
3846 if (GetAsyncKeyState (wParam) & 1)
3847 {
adcc3809 3848 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 3849 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 3850 else
576ba81c
AI
3851 key = VK_SPACE;
3852 dpyinfo->faked_key = key;
3853 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
3854 }
3855 }
3856 if (!NILP (Vw32_lwindow_modifier))
3857 return 0;
3858 break;
3859 case VK_RWIN:
3860 if (NILP (Vw32_pass_rwindow_to_system))
3861 {
3862 if (GetAsyncKeyState (wParam) & 1)
3863 {
adcc3809 3864 if (NUMBERP (Vw32_phantom_key_code))
576ba81c 3865 key = XUINT (Vw32_phantom_key_code) & 255;
adcc3809 3866 else
576ba81c
AI
3867 key = VK_SPACE;
3868 dpyinfo->faked_key = key;
3869 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
ccc2d29c
GV
3870 }
3871 }
3872 if (!NILP (Vw32_rwindow_modifier))
3873 return 0;
3874 break;
576ba81c 3875 case VK_APPS:
ccc2d29c
GV
3876 if (!NILP (Vw32_apps_modifier))
3877 return 0;
3878 break;
3879 case VK_MENU:
3880 if (NILP (Vw32_pass_alt_to_system))
adcc3809
GV
3881 /* Prevent DefWindowProc from activating the menu bar if an
3882 Alt key is pressed and released by itself. */
ccc2d29c 3883 return 0;
84fb1139 3884 windows_translate = 1;
ccc2d29c
GV
3885 break;
3886 case VK_CAPITAL:
3887 /* Decide whether to treat as modifier or function key. */
3888 if (NILP (Vw32_enable_caps_lock))
3889 goto disable_lock_key;
adcc3809
GV
3890 windows_translate = 1;
3891 break;
ccc2d29c
GV
3892 case VK_NUMLOCK:
3893 /* Decide whether to treat as modifier or function key. */
3894 if (NILP (Vw32_enable_num_lock))
3895 goto disable_lock_key;
adcc3809
GV
3896 windows_translate = 1;
3897 break;
ccc2d29c
GV
3898 case VK_SCROLL:
3899 /* Decide whether to treat as modifier or function key. */
3900 if (NILP (Vw32_scroll_lock_modifier))
3901 goto disable_lock_key;
adcc3809
GV
3902 windows_translate = 1;
3903 break;
ccc2d29c 3904 disable_lock_key:
adcc3809
GV
3905 /* Ensure the appropriate lock key state (and indicator light)
3906 remains in the same state. We do this by faking another
3907 press of the relevant key. Apparently, this really is the
3908 only way to toggle the state of the indicator lights. */
3909 dpyinfo->faked_key = wParam;
3910 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3911 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3912 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3913 KEYEVENTF_EXTENDEDKEY | 0, 0);
3914 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3915 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3916 /* Ensure indicator lights are updated promptly on Windows 9x
3917 (TranslateMessage apparently does this), after forwarding
3918 input event. */
3919 post_character_message (hwnd, msg, wParam, lParam,
3920 w32_get_key_modifiers (wParam, lParam));
3921 windows_translate = 1;
ccc2d29c
GV
3922 break;
3923 case VK_CONTROL:
3924 case VK_SHIFT:
3925 case VK_PROCESSKEY: /* Generated by IME. */
3926 windows_translate = 1;
3927 break;
adcc3809
GV
3928 case VK_CANCEL:
3929 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
3930 which is confusing for purposes of key binding; convert
3931 VK_CANCEL events into VK_PAUSE events. */
3932 wParam = VK_PAUSE;
3933 break;
3934 case VK_PAUSE:
3935 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
3936 for purposes of key binding; convert these back into
3937 VK_NUMLOCK events, at least when we want to see NumLock key
3938 presses. (Note that there is never any possibility that
3939 VK_PAUSE with Ctrl really is C-Pause as per above.) */
3940 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
3941 wParam = VK_NUMLOCK;
3942 break;
ccc2d29c
GV
3943 default:
3944 /* If not defined as a function key, change it to a WM_CHAR message. */
3945 if (lispy_function_keys[wParam] == 0)
3946 {
adcc3809
GV
3947 DWORD modifiers = construct_console_modifiers ();
3948
ccc2d29c
GV
3949 if (!NILP (Vw32_recognize_altgr)
3950 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
3951 {
3952 /* Always let TranslateMessage handle AltGr key chords;
3953 for some reason, ToAscii doesn't always process AltGr
3954 chords correctly. */
3955 windows_translate = 1;
3956 }
adcc3809 3957 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
ccc2d29c 3958 {
adcc3809
GV
3959 /* Handle key chords including any modifiers other
3960 than shift directly, in order to preserve as much
3961 modifier information as possible. */
ccc2d29c
GV
3962 if ('A' <= wParam && wParam <= 'Z')
3963 {
3964 /* Don't translate modified alphabetic keystrokes,
3965 so the user doesn't need to constantly switch
3966 layout to type control or meta keystrokes when
3967 the normal layout translates alphabetic
3968 characters to non-ascii characters. */
3969 if (!modifier_set (VK_SHIFT))
3970 wParam += ('a' - 'A');
3971 msg = WM_CHAR;
3972 }
3973 else
3974 {
3975 /* Try to handle other keystrokes by determining the
3976 base character (ie. translating the base key plus
3977 shift modifier). */
3978 int add;
3979 int isdead = 0;
3980 KEY_EVENT_RECORD key;
3981
3982 key.bKeyDown = TRUE;
3983 key.wRepeatCount = 1;
3984 key.wVirtualKeyCode = wParam;
3985 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
3986 key.uChar.AsciiChar = 0;
adcc3809 3987 key.dwControlKeyState = modifiers;
ccc2d29c
GV
3988
3989 add = w32_kbd_patch_key (&key);
3990 /* 0 means an unrecognised keycode, negative means
3991 dead key. Ignore both. */
3992 while (--add >= 0)
3993 {
3994 /* Forward asciified character sequence. */
3995 post_character_message
3996 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
3997 w32_get_key_modifiers (wParam, lParam));
3998 w32_kbd_patch_key (&key);
3999 }
4000 return 0;
4001 }
4002 }
4003 else
4004 {
4005 /* Let TranslateMessage handle everything else. */
4006 windows_translate = 1;
4007 }
4008 }
4009 }
a1a80b40 4010
adcc3809 4011 translate:
84fb1139
KH
4012 if (windows_translate)
4013 {
e9e23e23 4014 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
84fb1139 4015
e9e23e23
GV
4016 windows_msg.time = GetMessageTime ();
4017 TranslateMessage (&windows_msg);
84fb1139
KH
4018 goto dflt;
4019 }
4020
ee78dc32
GV
4021 /* Fall through */
4022
4023 case WM_SYSCHAR:
4024 case WM_CHAR:
ccc2d29c
GV
4025 post_character_message (hwnd, msg, wParam, lParam,
4026 w32_get_key_modifiers (wParam, lParam));
ee78dc32 4027 break;
da36a4d6 4028
5ac45f98
GV
4029 /* Simulate middle mouse button events when left and right buttons
4030 are used together, but only if user has two button mouse. */
ee78dc32 4031 case WM_LBUTTONDOWN:
5ac45f98 4032 case WM_RBUTTONDOWN:
fbd6baed 4033 if (XINT (Vw32_num_mouse_buttons) == 3)
5ac45f98
GV
4034 goto handle_plain_button;
4035
4036 {
4037 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4038 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4039
3cb20f4a
RS
4040 if (button_state & this)
4041 return 0;
5ac45f98
GV
4042
4043 if (button_state == 0)
4044 SetCapture (hwnd);
4045
4046 button_state |= this;
4047
4048 if (button_state & other)
4049 {
84fb1139 4050 if (mouse_button_timer)
5ac45f98 4051 {
84fb1139
KH
4052 KillTimer (hwnd, mouse_button_timer);
4053 mouse_button_timer = 0;
5ac45f98
GV
4054
4055 /* Generate middle mouse event instead. */
4056 msg = WM_MBUTTONDOWN;
4057 button_state |= MMOUSE;
4058 }
4059 else if (button_state & MMOUSE)
4060 {
4061 /* Ignore button event if we've already generated a
4062 middle mouse down event. This happens if the
4063 user releases and press one of the two buttons
4064 after we've faked a middle mouse event. */
4065 return 0;
4066 }
4067 else
4068 {
4069 /* Flush out saved message. */
84fb1139 4070 post_msg (&saved_mouse_button_msg);
5ac45f98 4071 }
fbd6baed 4072 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4073 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4074
4075 /* Clear message buffer. */
84fb1139 4076 saved_mouse_button_msg.msg.hwnd = 0;
5ac45f98
GV
4077 }
4078 else
4079 {
4080 /* Hold onto message for now. */
84fb1139 4081 mouse_button_timer =
adcc3809
GV
4082 SetTimer (hwnd, MOUSE_BUTTON_ID,
4083 XINT (Vw32_mouse_button_tolerance), NULL);
84fb1139
KH
4084 saved_mouse_button_msg.msg.hwnd = hwnd;
4085 saved_mouse_button_msg.msg.message = msg;
4086 saved_mouse_button_msg.msg.wParam = wParam;
4087 saved_mouse_button_msg.msg.lParam = lParam;
4088 saved_mouse_button_msg.msg.time = GetMessageTime ();
fbd6baed 4089 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4090 }
4091 }
4092 return 0;
4093
ee78dc32 4094 case WM_LBUTTONUP:
5ac45f98 4095 case WM_RBUTTONUP:
fbd6baed 4096 if (XINT (Vw32_num_mouse_buttons) == 3)
5ac45f98
GV
4097 goto handle_plain_button;
4098
4099 {
4100 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4101 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4102
3cb20f4a
RS
4103 if ((button_state & this) == 0)
4104 return 0;
5ac45f98
GV
4105
4106 button_state &= ~this;
4107
4108 if (button_state & MMOUSE)
4109 {
4110 /* Only generate event when second button is released. */
4111 if ((button_state & other) == 0)
4112 {
4113 msg = WM_MBUTTONUP;
4114 button_state &= ~MMOUSE;
4115
4116 if (button_state) abort ();
4117 }
4118 else
4119 return 0;
4120 }
4121 else
4122 {
4123 /* Flush out saved message if necessary. */
84fb1139 4124 if (saved_mouse_button_msg.msg.hwnd)
5ac45f98 4125 {
84fb1139 4126 post_msg (&saved_mouse_button_msg);
5ac45f98
GV
4127 }
4128 }
fbd6baed 4129 wmsg.dwModifiers = w32_get_modifiers ();
5ac45f98
GV
4130 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4131
4132 /* Always clear message buffer and cancel timer. */
84fb1139
KH
4133 saved_mouse_button_msg.msg.hwnd = 0;
4134 KillTimer (hwnd, mouse_button_timer);
4135 mouse_button_timer = 0;
5ac45f98
GV
4136
4137 if (button_state == 0)
4138 ReleaseCapture ();
4139 }
4140 return 0;
4141
ee78dc32
GV
4142 case WM_MBUTTONDOWN:
4143 case WM_MBUTTONUP:
5ac45f98 4144 handle_plain_button:
ee78dc32
GV
4145 {
4146 BOOL up;
1edf84e7 4147 int button;
ee78dc32 4148
1edf84e7 4149 if (parse_button (msg, &button, &up))
ee78dc32
GV
4150 {
4151 if (up) ReleaseCapture ();
4152 else SetCapture (hwnd);
1edf84e7
GV
4153 button = (button == 0) ? LMOUSE :
4154 ((button == 1) ? MMOUSE : RMOUSE);
4155 if (up)
4156 button_state &= ~button;
4157 else
4158 button_state |= button;
ee78dc32
GV
4159 }
4160 }
4161
fbd6baed 4162 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32 4163 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5ac45f98
GV
4164 return 0;
4165
84fb1139 4166 case WM_VSCROLL:
5ac45f98 4167 case WM_MOUSEMOVE:
fbd6baed 4168 if (XINT (Vw32_mouse_move_interval) <= 0
84fb1139
KH
4169 || (msg == WM_MOUSEMOVE && button_state == 0))
4170 {
fbd6baed 4171 wmsg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4172 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4173 return 0;
4174 }
4175
4176 /* Hang onto mouse move and scroll messages for a bit, to avoid
4177 sending such events to Emacs faster than it can process them.
4178 If we get more events before the timer from the first message
4179 expires, we just replace the first message. */
4180
4181 if (saved_mouse_move_msg.msg.hwnd == 0)
4182 mouse_move_timer =
adcc3809
GV
4183 SetTimer (hwnd, MOUSE_MOVE_ID,
4184 XINT (Vw32_mouse_move_interval), NULL);
84fb1139
KH
4185
4186 /* Hold onto message for now. */
4187 saved_mouse_move_msg.msg.hwnd = hwnd;
4188 saved_mouse_move_msg.msg.message = msg;
4189 saved_mouse_move_msg.msg.wParam = wParam;
4190 saved_mouse_move_msg.msg.lParam = lParam;
4191 saved_mouse_move_msg.msg.time = GetMessageTime ();
fbd6baed 4192 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
84fb1139
KH
4193
4194 return 0;
4195
1edf84e7
GV
4196 case WM_MOUSEWHEEL:
4197 wmsg.dwModifiers = w32_get_modifiers ();
4198 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4199 return 0;
4200
cb9e33d4
RS
4201 case WM_DROPFILES:
4202 wmsg.dwModifiers = w32_get_modifiers ();
4203 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4204 return 0;
4205
84fb1139
KH
4206 case WM_TIMER:
4207 /* Flush out saved messages if necessary. */
4208 if (wParam == mouse_button_timer)
5ac45f98 4209 {
84fb1139
KH
4210 if (saved_mouse_button_msg.msg.hwnd)
4211 {
4212 post_msg (&saved_mouse_button_msg);
4213 saved_mouse_button_msg.msg.hwnd = 0;
4214 }
4215 KillTimer (hwnd, mouse_button_timer);
4216 mouse_button_timer = 0;
4217 }
4218 else if (wParam == mouse_move_timer)
4219 {
4220 if (saved_mouse_move_msg.msg.hwnd)
4221 {
4222 post_msg (&saved_mouse_move_msg);
4223 saved_mouse_move_msg.msg.hwnd = 0;
4224 }
4225 KillTimer (hwnd, mouse_move_timer);
4226 mouse_move_timer = 0;
5ac45f98 4227 }
5ac45f98 4228 return 0;
84fb1139
KH
4229
4230 case WM_NCACTIVATE:
4231 /* Windows doesn't send us focus messages when putting up and
e9e23e23 4232 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
84fb1139
KH
4233 The only indication we get that something happened is receiving
4234 this message afterwards. So this is a good time to reset our
4235 keyboard modifiers' state. */
4236 reset_modifiers ();
4237 goto dflt;
da36a4d6 4238
1edf84e7 4239 case WM_INITMENU:
487163ac
AI
4240 button_state = 0;
4241 ReleaseCapture ();
1edf84e7
GV
4242 /* We must ensure menu bar is fully constructed and up to date
4243 before allowing user interaction with it. To achieve this
4244 we send this message to the lisp thread and wait for a
4245 reply (whose value is not actually needed) to indicate that
4246 the menu bar is now ready for use, so we can now return.
4247
4248 To remain responsive in the meantime, we enter a nested message
4249 loop that can process all other messages.
4250
4251 However, we skip all this if the message results from calling
4252 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4253 thread a message because it is blocked on us at this point. We
4254 set menubar_active before calling TrackPopupMenu to indicate
4255 this (there is no possibility of confusion with real menubar
4256 being active). */
4257
4258 f = x_window_to_frame (dpyinfo, hwnd);
4259 if (f
4260 && (f->output_data.w32->menubar_active
4261 /* We can receive this message even in the absence of a
4262 menubar (ie. when the system menu is activated) - in this
4263 case we do NOT want to forward the message, otherwise it
4264 will cause the menubar to suddenly appear when the user
4265 had requested it to be turned off! */
4266 || f->output_data.w32->menubar_widget == NULL))
4267 return 0;
4268
4269 {
4270 deferred_msg msg_buf;
4271
4272 /* Detect if message has already been deferred; in this case
4273 we cannot return any sensible value to ignore this. */
4274 if (find_deferred_msg (hwnd, msg) != NULL)
4275 abort ();
4276
4277 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4278 }
4279
4280 case WM_EXITMENULOOP:
4281 f = x_window_to_frame (dpyinfo, hwnd);
4282
4283 /* Indicate that menubar can be modified again. */
4284 if (f)
4285 f->output_data.w32->menubar_active = 0;
4286 goto dflt;
4287
87996783
GV
4288 case WM_MEASUREITEM:
4289 f = x_window_to_frame (dpyinfo, hwnd);
4290 if (f)
4291 {
4292 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4293
4294 if (pMis->CtlType == ODT_MENU)
4295 {
4296 /* Work out dimensions for popup menu titles. */
4297 char * title = (char *) pMis->itemData;
4298 HDC hdc = GetDC (hwnd);
4299 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4300 LOGFONT menu_logfont;
4301 HFONT old_font;
4302 SIZE size;
4303
4304 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4305 menu_logfont.lfWeight = FW_BOLD;
4306 menu_font = CreateFontIndirect (&menu_logfont);
4307 old_font = SelectObject (hdc, menu_font);
4308
4309 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4310 pMis->itemWidth = size.cx;
4311 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4312 if (pMis->itemHeight < size.cy)
4313 pMis->itemHeight = size.cy;
4314
4315 SelectObject (hdc, old_font);
4316 DeleteObject (menu_font);
4317 ReleaseDC (hwnd, hdc);
4318 return TRUE;
4319 }
4320 }
4321 return 0;
4322
4323 case WM_DRAWITEM:
4324 f = x_window_to_frame (dpyinfo, hwnd);
4325 if (f)
4326 {
4327 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4328
4329 if (pDis->CtlType == ODT_MENU)
4330 {
4331 /* Draw popup menu title. */
4332 char * title = (char *) pDis->itemData;
4333 HDC hdc = pDis->hDC;
4334 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4335 LOGFONT menu_logfont;
4336 HFONT old_font;
4337
4338 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4339 menu_logfont.lfWeight = FW_BOLD;
4340 menu_font = CreateFontIndirect (&menu_logfont);
4341 old_font = SelectObject (hdc, menu_font);
4342
4343 /* Always draw title as if not selected. */
4344 ExtTextOut (hdc,
4345 pDis->rcItem.left + GetSystemMetrics (SM_CXMENUCHECK),
4346 pDis->rcItem.top,
4347 ETO_OPAQUE, &pDis->rcItem,
4348 title, strlen (title), NULL);
4349
4350 SelectObject (hdc, old_font);
4351 DeleteObject (menu_font);
4352 return TRUE;
4353 }
4354 }
4355 return 0;
4356
1edf84e7
GV
4357#if 0
4358 /* Still not right - can't distinguish between clicks in the
4359 client area of the frame from clicks forwarded from the scroll
4360 bars - may have to hook WM_NCHITTEST to remember the mouse
4361 position and then check if it is in the client area ourselves. */
4362 case WM_MOUSEACTIVATE:
4363 /* Discard the mouse click that activates a frame, allowing the
4364 user to click anywhere without changing point (or worse!).
4365 Don't eat mouse clicks on scrollbars though!! */
4366 if (LOWORD (lParam) == HTCLIENT )
4367 return MA_ACTIVATEANDEAT;
4368 goto dflt;
4369#endif
4370
1edf84e7 4371 case WM_ACTIVATEAPP:
ccc2d29c 4372 case WM_ACTIVATE:
1edf84e7
GV
4373 case WM_WINDOWPOSCHANGED:
4374 case WM_SHOWWINDOW:
4375 /* Inform lisp thread that a frame might have just been obscured
4376 or exposed, so should recheck visibility of all frames. */
4377 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4378 goto dflt;
4379
da36a4d6 4380 case WM_SETFOCUS:
adcc3809
GV
4381 dpyinfo->faked_key = 0;
4382 reset_modifiers ();
ccc2d29c
GV
4383 register_hot_keys (hwnd);
4384 goto command;
8681157a 4385 case WM_KILLFOCUS:
ccc2d29c 4386 unregister_hot_keys (hwnd);
487163ac
AI
4387 button_state = 0;
4388 ReleaseCapture ();
ee78dc32
GV
4389 case WM_MOVE:
4390 case WM_SIZE:
ee78dc32 4391 case WM_COMMAND:
ccc2d29c 4392 command:
fbd6baed 4393 wmsg.dwModifiers = w32_get_modifiers ();
ee78dc32
GV
4394 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4395 goto dflt;
8847d890
RS
4396
4397 case WM_CLOSE:
fbd6baed 4398 wmsg.dwModifiers = w32_get_modifiers ();
8847d890
RS
4399 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4400 return 0;
4401
ee78dc32
GV
4402 case WM_WINDOWPOSCHANGING:
4403 {
4404 WINDOWPLACEMENT wp;
4405 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
1edf84e7
GV
4406
4407 wp.length = sizeof (WINDOWPLACEMENT);
ee78dc32
GV
4408 GetWindowPlacement (hwnd, &wp);
4409
1edf84e7 4410 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
ee78dc32
GV
4411 {
4412 RECT rect;
4413 int wdiff;
4414 int hdiff;
1edf84e7
GV
4415 DWORD font_width;
4416 DWORD line_height;
4417 DWORD internal_border;
4418 DWORD scrollbar_extra;
ee78dc32
GV
4419 RECT wr;
4420
5ac45f98 4421 wp.length = sizeof(wp);
ee78dc32
GV
4422 GetWindowRect (hwnd, &wr);
4423
3c190163 4424 enter_crit ();
ee78dc32 4425
1edf84e7
GV
4426 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4427 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4428 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4429 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
ee78dc32 4430
3c190163 4431 leave_crit ();
ee78dc32
GV
4432
4433 memset (&rect, 0, sizeof (rect));
4434 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4435 GetMenu (hwnd) != NULL);
4436
1edf84e7
GV
4437 /* Force width and height of client area to be exact
4438 multiples of the character cell dimensions. */
4439 wdiff = (lppos->cx - (rect.right - rect.left)
4440 - 2 * internal_border - scrollbar_extra)
4441 % font_width;
4442 hdiff = (lppos->cy - (rect.bottom - rect.top)
4443 - 2 * internal_border)
4444 % line_height;
ee78dc32
GV
4445
4446 if (wdiff || hdiff)
4447 {
4448 /* For right/bottom sizing we can just fix the sizes.
4449 However for top/left sizing we will need to fix the X
4450 and Y positions as well. */
4451
4452 lppos->cx -= wdiff;
4453 lppos->cy -= hdiff;
4454
4455 if (wp.showCmd != SW_SHOWMAXIMIZED
1edf84e7 4456 && (lppos->flags & SWP_NOMOVE) == 0)
ee78dc32
GV
4457 {
4458 if (lppos->x != wr.left || lppos->y != wr.top)
4459 {
4460 lppos->x += wdiff;
4461 lppos->y += hdiff;
4462 }
4463 else
4464 {
4465 lppos->flags |= SWP_NOMOVE;
4466 }
4467 }
4468
1edf84e7 4469 return 0;
ee78dc32
GV
4470 }
4471 }
4472 }
ee78dc32
GV
4473
4474 goto dflt;
1edf84e7 4475
b1f918f8
GV
4476 case WM_GETMINMAXINFO:
4477 /* Hack to correct bug that allows Emacs frames to be resized
4478 below the Minimum Tracking Size. */
4479 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4480 return 0;
4481
1edf84e7
GV
4482 case WM_EMACS_CREATESCROLLBAR:
4483 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4484 (struct scroll_bar *) lParam);
4485
5ac45f98 4486 case WM_EMACS_SHOWWINDOW:
1edf84e7
GV
4487 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4488
dfdb4047 4489 case WM_EMACS_SETFOREGROUND:
ce6059da
AI
4490 {
4491 HWND foreground_window;
4492 DWORD foreground_thread, retval;
4493
4494 /* On NT 5.0, and apparently Windows 98, it is necessary to
4495 attach to the thread that currently has focus in order to
4496 pull the focus away from it. */
4497 foreground_window = GetForegroundWindow ();
4498 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4499 if (!foreground_window
4500 || foreground_thread == GetCurrentThreadId ()
4501 || !AttachThreadInput (GetCurrentThreadId (),
4502 foreground_thread, TRUE))
4503 foreground_thread = 0;
4504
4505 retval = SetForegroundWindow ((HWND) wParam);
4506
4507 /* Detach from the previous foreground thread. */
4508 if (foreground_thread)
4509 AttachThreadInput (GetCurrentThreadId (),
4510 foreground_thread, FALSE);
4511
4512 return retval;
4513 }
dfdb4047 4514
5ac45f98
GV
4515 case WM_EMACS_SETWINDOWPOS:
4516 {
1edf84e7
GV
4517 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4518 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5ac45f98
GV
4519 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4520 }
1edf84e7 4521
ee78dc32 4522 case WM_EMACS_DESTROYWINDOW:
cb9e33d4 4523 DragAcceptFiles ((HWND) wParam, FALSE);
1edf84e7
GV
4524 return DestroyWindow ((HWND) wParam);
4525
4526 case WM_EMACS_TRACKPOPUPMENU:
4527 {
4528 UINT flags;
4529 POINT *pos;
4530 int retval;
4531 pos = (POINT *)lParam;
4532 flags = TPM_CENTERALIGN;
4533 if (button_state & LMOUSE)
4534 flags |= TPM_LEFTBUTTON;
4535 else if (button_state & RMOUSE)
4536 flags |= TPM_RIGHTBUTTON;
4537
87996783
GV
4538 /* Remember we did a SetCapture on the initial mouse down event,
4539 so for safety, we make sure the capture is cancelled now. */
4540 ReleaseCapture ();
490822ff 4541 button_state = 0;
87996783 4542
1edf84e7
GV
4543 /* Use menubar_active to indicate that WM_INITMENU is from
4544 TrackPopupMenu below, and should be ignored. */
4545 f = x_window_to_frame (dpyinfo, hwnd);
4546 if (f)
4547 f->output_data.w32->menubar_active = 1;
4548
4549 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4550 0, hwnd, NULL))
4551 {
4552 MSG amsg;
4553 /* Eat any mouse messages during popupmenu */
4554 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4555 PM_REMOVE));
4556 /* Get the menu selection, if any */
4557 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4558 {
4559 retval = LOWORD (amsg.wParam);
4560 }
4561 else
4562 {
4563 retval = 0;
4564 }
1edf84e7
GV
4565 }
4566 else
4567 {
4568 retval = -1;
4569 }
4570
4571 return retval;
4572 }
4573
ee78dc32 4574 default:
93fbe8b7
GV
4575 /* Check for messages registered at runtime. */
4576 if (msg == msh_mousewheel)
4577 {
4578 wmsg.dwModifiers = w32_get_modifiers ();
4579 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4580 return 0;
4581 }
4582
ee78dc32
GV
4583 dflt:
4584 return DefWindowProc (hwnd, msg, wParam, lParam);
4585 }
4586
1edf84e7
GV
4587
4588 /* The most common default return code for handled messages is 0. */
4589 return 0;
ee78dc32
GV
4590}
4591
4592void
4593my_create_window (f)
4594 struct frame * f;
4595{
4596 MSG msg;
4597
1edf84e7
GV
4598 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4599 abort ();
ee78dc32
GV
4600 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4601}
4602
fbd6baed 4603/* Create and set up the w32 window for frame F. */
ee78dc32
GV
4604
4605static void
fbd6baed 4606w32_window (f, window_prompting, minibuffer_only)
ee78dc32
GV
4607 struct frame *f;
4608 long window_prompting;
4609 int minibuffer_only;
4610{
4611 BLOCK_INPUT;
4612
4613 /* Use the resource name as the top-level window name
4614 for looking up resources. Make a non-Lisp copy
4615 for the window manager, so GC relocation won't bother it.
4616
4617 Elsewhere we specify the window name for the window manager. */
4618
4619 {
4620 char *str = (char *) XSTRING (Vx_resource_name)->data;
4621 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4622 strcpy (f->namebuf, str);
4623 }
4624
4625 my_create_window (f);
4626
4627 validate_x_resource_name ();
4628
4629 /* x_set_name normally ignores requests to set the name if the
4630 requested name is the same as the current name. This is the one
4631 place where that assumption isn't correct; f->name is set, but
4632 the server hasn't been told. */
4633 {
4634 Lisp_Object name;
4635 int explicit = f->explicit_name;
4636
4637 f->explicit_name = 0;
4638 name = f->name;
4639 f->name = Qnil;
4640 x_set_name (f, name, explicit);
4641 }
4642
4643 UNBLOCK_INPUT;
4644
4645 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4646 initialize_frame_menubar (f);
4647
fbd6baed 4648 if (FRAME_W32_WINDOW (f) == 0)
ee78dc32
GV
4649 error ("Unable to create window");
4650}
4651
4652/* Handle the icon stuff for this window. Perhaps later we might
4653 want an x_set_icon_position which can be called interactively as
4654 well. */
4655
4656static void
4657x_icon (f, parms)
4658 struct frame *f;
4659 Lisp_Object parms;
4660{
4661 Lisp_Object icon_x, icon_y;
4662
e9e23e23 4663 /* Set the position of the icon. Note that Windows 95 groups all
ee78dc32
GV
4664 icons in the tray. */
4665 icon_x = x_get_arg (parms, Qicon_left, 0, 0, number);
4666 icon_y = x_get_arg (parms, Qicon_top, 0, 0, number);
4667 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4668 {
4669 CHECK_NUMBER (icon_x, 0);
4670 CHECK_NUMBER (icon_y, 0);
4671 }
4672 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4673 error ("Both left and top icon corners of icon must be specified");
4674
4675 BLOCK_INPUT;
4676
4677 if (! EQ (icon_x, Qunbound))
4678 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4679
1edf84e7
GV
4680#if 0 /* TODO */
4681 /* Start up iconic or window? */
4682 x_wm_set_window_state
4683 (f, (EQ (x_get_arg (parms, Qvisibility, 0, 0, symbol), Qicon)
4684 ? IconicState
4685 : NormalState));
4686
4687 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4688 ? f->icon_name
4689 : f->name))->data);
4690#endif
4691
ee78dc32
GV
4692 UNBLOCK_INPUT;
4693}
4694
4695DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
4696 1, 1, 0,
4697 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
4698Returns an Emacs frame object.\n\
4699ALIST is an alist of frame parameters.\n\
4700If the parameters specify that the frame should not have a minibuffer,\n\
4701and do not specify a specific minibuffer window to use,\n\
4702then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
4703be shared by the new frame.\n\
4704\n\
4705This function is an internal primitive--use `make-frame' instead.")
4706 (parms)
4707 Lisp_Object parms;
4708{
4709 struct frame *f;
4710 Lisp_Object frame, tem;
4711 Lisp_Object name;
4712 int minibuffer_only = 0;
4713 long window_prompting = 0;
4714 int width, height;
4715 int count = specpdl_ptr - specpdl;
1edf84e7 4716 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
ee78dc32 4717 Lisp_Object display;
fbd6baed 4718 struct w32_display_info *dpyinfo;
ee78dc32
GV
4719 Lisp_Object parent;
4720 struct kboard *kb;
4721
4587b026
GV
4722 check_w32 ();
4723
ee78dc32
GV
4724 /* Use this general default value to start with
4725 until we know if this frame has a specified name. */
4726 Vx_resource_name = Vinvocation_name;
4727
4728 display = x_get_arg (parms, Qdisplay, 0, 0, string);
4729 if (EQ (display, Qunbound))
4730 display = Qnil;
4731 dpyinfo = check_x_display_info (display);
4732#ifdef MULTI_KBOARD
4733 kb = dpyinfo->kboard;
4734#else
4735 kb = &the_only_kboard;
4736#endif
4737
1edf84e7 4738 name = x_get_arg (parms, Qname, "name", "Name", string);
ee78dc32
GV
4739 if (!STRINGP (name)
4740 && ! EQ (name, Qunbound)
4741 && ! NILP (name))
4742 error ("Invalid frame name--not a string or nil");
4743
4744 if (STRINGP (name))
4745 Vx_resource_name = name;
4746
4747 /* See if parent window is specified. */
4748 parent = x_get_arg (parms, Qparent_id, NULL, NULL, number);
4749 if (EQ (parent, Qunbound))
4750 parent = Qnil;
4751 if (! NILP (parent))
4752 CHECK_NUMBER (parent, 0);
4753
1edf84e7
GV
4754 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4755 /* No need to protect DISPLAY because that's not used after passing
4756 it to make_frame_without_minibuffer. */
4757 frame = Qnil;
4758 GCPRO4 (parms, parent, name, frame);
ee78dc32
GV
4759 tem = x_get_arg (parms, Qminibuffer, 0, 0, symbol);
4760 if (EQ (tem, Qnone) || NILP (tem))
4761 f = make_frame_without_minibuffer (Qnil, kb, display);
4762 else if (EQ (tem, Qonly))
4763 {
4764 f = make_minibuffer_frame ();
4765 minibuffer_only = 1;
4766 }
4767 else if (WINDOWP (tem))
4768 f = make_frame_without_minibuffer (tem, kb, display);
4769 else
4770 f = make_frame (1);
4771
1edf84e7
GV
4772 XSETFRAME (frame, f);
4773
ee78dc32
GV
4774 /* Note that Windows does support scroll bars. */
4775 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5ac45f98
GV
4776 /* By default, make scrollbars the system standard width. */
4777 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
ee78dc32 4778
fbd6baed
GV
4779 f->output_method = output_w32;
4780 f->output_data.w32 = (struct w32_output *) xmalloc (sizeof (struct w32_output));
4781 bzero (f->output_data.w32, sizeof (struct w32_output));
ee78dc32 4782
4587b026
GV
4783 FRAME_FONTSET (f) = -1;
4784
1edf84e7
GV
4785 f->icon_name
4786 = x_get_arg (parms, Qicon_name, "iconName", "Title", string);
4787 if (! STRINGP (f->icon_name))
4788 f->icon_name = Qnil;
4789
fbd6baed 4790/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
ee78dc32
GV
4791#ifdef MULTI_KBOARD
4792 FRAME_KBOARD (f) = kb;
4793#endif
4794
4795 /* Specify the parent under which to make this window. */
4796
4797 if (!NILP (parent))
4798 {
fbd6baed
GV
4799 f->output_data.w32->parent_desc = (Window) parent;
4800 f->output_data.w32->explicit_parent = 1;
ee78dc32
GV
4801 }
4802 else
4803 {
fbd6baed
GV
4804 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
4805 f->output_data.w32->explicit_parent = 0;
ee78dc32
GV
4806 }
4807
4808 /* Note that the frame has no physical cursor right now. */
4809 f->phys_cursor_x = -1;
4810
4811 /* Set the name; the functions to which we pass f expect the name to
4812 be set. */
4813 if (EQ (name, Qunbound) || NILP (name))
4814 {
fbd6baed 4815 f->name = build_string (dpyinfo->w32_id_name);
ee78dc32
GV
4816 f->explicit_name = 0;
4817 }
4818 else
4819 {
4820 f->name = name;
4821 f->explicit_name = 1;
4822 /* use the frame's title when getting resources for this frame. */
4823 specbind (Qx_resource_name, name);
4824 }
4825
4587b026
GV
4826 /* Create fontsets from `global_fontset_alist' before handling fonts. */
4827 for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCONS (tem)->cdr)
4828 fs_register_fontset (f, XCONS (tem)->car);
4829
ee78dc32
GV
4830 /* Extract the window parameters from the supplied values
4831 that are needed to determine window geometry. */
4832 {
4833 Lisp_Object font;
4834
4835 font = x_get_arg (parms, Qfont, "font", "Font", string);
4836 BLOCK_INPUT;
4837 /* First, try whatever font the caller has specified. */
4838 if (STRINGP (font))
4587b026
GV
4839 {
4840 tem = Fquery_fontset (font, Qnil);
4841 if (STRINGP (tem))
4842 font = x_new_fontset (f, XSTRING (tem)->data);
4843 else
1075afa9 4844 font = x_new_font (f, XSTRING (font)->data);
4587b026 4845 }
ee78dc32
GV
4846 /* Try out a font which we hope has bold and italic variations. */
4847 if (!STRINGP (font))
4587b026 4848 font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
ee78dc32 4849 if (! STRINGP (font))
4587b026 4850 font = x_new_font (f, "-*-Courier-normal-r-*-*-*-97-*-*-c-*-iso8859-1");
ee78dc32
GV
4851 /* If those didn't work, look for something which will at least work. */
4852 if (! STRINGP (font))
4587b026 4853 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-*-*-90-*-c-*-iso8859-1");
ee78dc32
GV
4854 UNBLOCK_INPUT;
4855 if (! STRINGP (font))
1edf84e7 4856 font = build_string ("Fixedsys");
ee78dc32
GV
4857
4858 x_default_parameter (f, parms, Qfont, font,
4859 "font", "Font", string);
4860 }
4861
4862 x_default_parameter (f, parms, Qborder_width, make_number (2),
4863 "borderwidth", "BorderWidth", number);
4864 /* This defaults to 2 in order to match xterm. We recognize either
4865 internalBorderWidth or internalBorder (which is what xterm calls
4866 it). */
4867 if (NILP (Fassq (Qinternal_border_width, parms)))
4868 {
4869 Lisp_Object value;
4870
4871 value = x_get_arg (parms, Qinternal_border_width,
4872 "internalBorder", "BorderWidth", number);
4873 if (! EQ (value, Qunbound))
4874 parms = Fcons (Fcons (Qinternal_border_width, value),
4875 parms);
4876 }
1edf84e7 4877 /* Default internalBorderWidth to 0 on Windows to match other programs. */
ee78dc32
GV
4878 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
4879 "internalBorderWidth", "BorderWidth", number);
4880 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
4881 "verticalScrollBars", "ScrollBars", boolean);
4882
4883 /* Also do the stuff which must be set before the window exists. */
4884 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
4885 "foreground", "Foreground", string);
4886 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
4887 "background", "Background", string);
4888 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
4889 "pointerColor", "Foreground", string);
4890 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
4891 "cursorColor", "Foreground", string);
4892 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
4893 "borderColor", "BorderColor", string);
4894
4895 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
4896 "menuBar", "MenuBar", number);
4897 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4898 "scrollBarWidth", "ScrollBarWidth", number);
1edf84e7
GV
4899 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
4900 "bufferPredicate", "BufferPredicate", symbol);
4901 x_default_parameter (f, parms, Qtitle, Qnil,
4902 "title", "Title", string);
ee78dc32 4903
fbd6baed
GV
4904 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
4905 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
ee78dc32
GV
4906 window_prompting = x_figure_window_size (f, parms);
4907
4908 if (window_prompting & XNegative)
4909 {
4910 if (window_prompting & YNegative)
fbd6baed 4911 f->output_data.w32->win_gravity = SouthEastGravity;
ee78dc32 4912 else
fbd6baed 4913 f->output_data.w32->win_gravity = NorthEastGravity;
ee78dc32
GV
4914 }
4915 else
4916 {
4917 if (window_prompting & YNegative)
fbd6baed 4918 f->output_data.w32->win_gravity = SouthWestGravity;
ee78dc32 4919 else
fbd6baed 4920 f->output_data.w32->win_gravity = NorthWestGravity;
ee78dc32
GV
4921 }
4922
fbd6baed 4923 f->output_data.w32->size_hint_flags = window_prompting;
ee78dc32 4924
fbd6baed 4925 w32_window (f, window_prompting, minibuffer_only);
ee78dc32
GV
4926 x_icon (f, parms);
4927 init_frame_faces (f);
4928
4929 /* We need to do this after creating the window, so that the
4930 icon-creation functions can say whose icon they're describing. */
4931 x_default_parameter (f, parms, Qicon_type, Qnil,
4932 "bitmapIcon", "BitmapIcon", symbol);
4933
4934 x_default_parameter (f, parms, Qauto_raise, Qnil,
4935 "autoRaise", "AutoRaiseLower", boolean);
4936 x_default_parameter (f, parms, Qauto_lower, Qnil,
4937 "autoLower", "AutoRaiseLower", boolean);
4938 x_default_parameter (f, parms, Qcursor_type, Qbox,
4939 "cursorType", "CursorType", symbol);
4940
4941 /* Dimensions, especially f->height, must be done via change_frame_size.
4942 Change will not be effected unless different from the current
4943 f->height. */
4944 width = f->width;
4945 height = f->height;
1026b400
RS
4946 f->height = 0;
4947 SET_FRAME_WIDTH (f, 0);
ee78dc32
GV
4948 change_frame_size (f, height, width, 1, 0);
4949
4950 /* Tell the server what size and position, etc, we want,
4951 and how badly we want them. */
4952 BLOCK_INPUT;
4953 x_wm_set_size_hint (f, window_prompting, 0);
4954 UNBLOCK_INPUT;
4955
4956 tem = x_get_arg (parms, Qunsplittable, 0, 0, boolean);
4957 f->no_split = minibuffer_only || EQ (tem, Qt);
4958
4959 UNGCPRO;
4960
4961 /* It is now ok to make the frame official
4962 even if we get an error below.
4963 And the frame needs to be on Vframe_list
4964 or making it visible won't work. */
4965 Vframe_list = Fcons (frame, Vframe_list);
4966
4967 /* Now that the frame is official, it counts as a reference to
4968 its display. */
fbd6baed 4969 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
ee78dc32
GV
4970
4971 /* Make the window appear on the frame and enable display,
4972 unless the caller says not to. However, with explicit parent,
4973 Emacs cannot control visibility, so don't try. */
fbd6baed 4974 if (! f->output_data.w32->explicit_parent)
ee78dc32
GV
4975 {
4976 Lisp_Object visibility;
4977
4978 visibility = x_get_arg (parms, Qvisibility, 0, 0, symbol);
4979 if (EQ (visibility, Qunbound))
4980 visibility = Qt;
4981
4982 if (EQ (visibility, Qicon))
4983 x_iconify_frame (f);
4984 else if (! NILP (visibility))
4985 x_make_frame_visible (f);
4986 else
4987 /* Must have been Qnil. */
4988 ;
4989 }
4990
4991 return unbind_to (count, frame);
4992}
4993
4994/* FRAME is used only to get a handle on the X display. We don't pass the
4995 display info directly because we're called from frame.c, which doesn't
4996 know about that structure. */
4997Lisp_Object
4998x_get_focus_frame (frame)
4999 struct frame *frame;
5000{
fbd6baed 5001 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
ee78dc32 5002 Lisp_Object xfocus;
fbd6baed 5003 if (! dpyinfo->w32_focus_frame)
ee78dc32
GV
5004 return Qnil;
5005
fbd6baed 5006 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
ee78dc32
GV
5007 return xfocus;
5008}
1edf84e7
GV
5009
5010DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5011 "Give FRAME input focus, raising to foreground if necessary.")
5012 (frame)
5013 Lisp_Object frame;
5014{
5015 x_focus_on_frame (check_x_frame (frame));
5016 return Qnil;
5017}
5018
ee78dc32 5019\f
33d52f9c
GV
5020struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5021 int size, char* filename);
5022
4587b026 5023struct font_info *
33d52f9c 5024w32_load_system_font (f,fontname,size)
55dcfc15
AI
5025 struct frame *f;
5026 char * fontname;
5027 int size;
ee78dc32 5028{
4587b026
GV
5029 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5030 Lisp_Object font_names;
5031
4587b026
GV
5032 /* Get a list of all the fonts that match this name. Once we
5033 have a list of matching fonts, we compare them against the fonts
5034 we already have loaded by comparing names. */
5035 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5036
5037 if (!NILP (font_names))
3c190163 5038 {
4587b026
GV
5039 Lisp_Object tail;
5040 int i;
4587b026
GV
5041#if 0 /* This code has nasty side effects that cause Emacs to crash. */
5042
5043 /* First check if any are already loaded, as that is cheaper
5044 than loading another one. */
5045 for (i = 0; i < dpyinfo->n_fonts; i++)
5046 for (tail = font_names; CONSP (tail); tail = XCONS (tail)->cdr)
5047 if (!strcmp (dpyinfo->font_table[i].name,
5048 XSTRING (XCONS (tail)->car)->data)
5049 || !strcmp (dpyinfo->font_table[i].full_name,
5050 XSTRING (XCONS (tail)->car)->data))
5051 return (dpyinfo->font_table + i);
5052#endif
4587b026
GV
5053 fontname = (char *) XSTRING (XCONS (font_names)->car)->data;
5054 }
1075afa9 5055 else if (w32_strict_fontnames)
5ca0cd71
GV
5056 {
5057 /* If EnumFontFamiliesEx was available, we got a full list of
5058 fonts back so stop now to avoid the possibility of loading a
5059 random font. If we had to fall back to EnumFontFamilies, the
5060 list is incomplete, so continue whether the font we want was
5061 listed or not. */
5062 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5063 FARPROC enum_font_families_ex
1075afa9 5064 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5ca0cd71
GV
5065 if (enum_font_families_ex)
5066 return NULL;
5067 }
4587b026
GV
5068
5069 /* Load the font and add it to the table. */
5070 {
33d52f9c 5071 char *full_name, *encoding;
4587b026
GV
5072 XFontStruct *font;
5073 struct font_info *fontp;
3c190163 5074 LOGFONT lf;
4587b026 5075 BOOL ok;
5ac45f98 5076
4587b026 5077 if (!fontname || !x_to_w32_font (fontname, &lf))
3c190163 5078 return (NULL);
5ac45f98 5079
4587b026
GV
5080 if (!*lf.lfFaceName)
5081 /* If no name was specified for the font, we get a random font
5082 from CreateFontIndirect - this is not particularly
5083 desirable, especially since CreateFontIndirect does not
5084 fill out the missing name in lf, so we never know what we
5085 ended up with. */
5086 return NULL;
5087
3c190163 5088 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5ac45f98 5089
33d52f9c
GV
5090 /* Set bdf to NULL to indicate that this is a Windows font. */
5091 font->bdf = NULL;
5ac45f98 5092
3c190163 5093 BLOCK_INPUT;
5ac45f98
GV
5094
5095 font->hfont = CreateFontIndirect (&lf);
ee78dc32 5096
1a292d24
AI
5097 if (font->hfont == NULL)
5098 {
5099 ok = FALSE;
5100 }
5101 else
5102 {
5103 HDC hdc;
5104 HANDLE oldobj;
5105
5106 hdc = GetDC (dpyinfo->root_window);
5107 oldobj = SelectObject (hdc, font->hfont);
5108 ok = GetTextMetrics (hdc, &font->tm);
5109 SelectObject (hdc, oldobj);
5110 ReleaseDC (dpyinfo->root_window, hdc);
55dcfc15
AI
5111
5112 /* [andrewi, 25-Apr-99] A number of fixed pitch fonts,
5113 eg. Courier New and perhaps others, report a max width which
5114 is larger than the average character width, at least on some
5115 NT systems (I don't understand why - my best guess is that it
5116 results from installing the CJK language packs for NT4).
5117 Unfortunately, this forces the redisplay code in dumpglyphs
5118 to draw text character by character.
5119
5120 I don't like this hack, but it seems better to force the max
5121 width to match the average width if the font is marked as
5122 fixed pitch, for the sake of redisplay performance. */
5123
5124 if ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0)
5125 font->tm.tmMaxCharWidth = font->tm.tmAveCharWidth;
1a292d24 5126 }
5ac45f98 5127
1a292d24 5128 UNBLOCK_INPUT;
5ac45f98 5129
4587b026
GV
5130 if (!ok)
5131 {
1a292d24
AI
5132 w32_unload_font (dpyinfo, font);
5133 return (NULL);
5134 }
ee78dc32 5135
4587b026
GV
5136 /* Do we need to create the table? */
5137 if (dpyinfo->font_table_size == 0)
5138 {
5139 dpyinfo->font_table_size = 16;
5140 dpyinfo->font_table
5141 = (struct font_info *) xmalloc (dpyinfo->font_table_size
5142 * sizeof (struct font_info));
5143 }
5144 /* Do we need to grow the table? */
5145 else if (dpyinfo->n_fonts
5146 >= dpyinfo->font_table_size)
5147 {
5148 dpyinfo->font_table_size *= 2;
5149 dpyinfo->font_table
5150 = (struct font_info *) xrealloc (dpyinfo->font_table,
5151 (dpyinfo->font_table_size
5152 * sizeof (struct font_info)));
5153 }
5154
5155 fontp = dpyinfo->font_table + dpyinfo->n_fonts;
5156
5157 /* Now fill in the slots of *FONTP. */
5158 BLOCK_INPUT;
5159 fontp->font = font;
5160 fontp->font_idx = dpyinfo->n_fonts;
5161 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5162 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5163
5164 /* Work out the font's full name. */
5165 full_name = (char *)xmalloc (100);
5166 if (full_name && w32_to_x_font (&lf, full_name, 100))
5167 fontp->full_name = full_name;
5168 else
5169 {
5170 /* If all else fails - just use the name we used to load it. */
5171 xfree (full_name);
5172 fontp->full_name = fontp->name;
5173 }
5174
5175 fontp->size = FONT_WIDTH (font);
5176 fontp->height = FONT_HEIGHT (font);
5177
5178 /* The slot `encoding' specifies how to map a character
5179 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5180 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
5181 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
5182 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
5183 2:0xA020..0xFF7F). For the moment, we don't know which charset
5184 uses this font. So, we set informatoin in fontp->encoding[1]
5185 which is never used by any charset. If mapping can't be
5186 decided, set FONT_ENCODING_NOT_DECIDED. */
33d52f9c
GV
5187
5188 /* SJIS fonts need to be set to type 4, all others seem to work as
5189 type FONT_ENCODING_NOT_DECIDED. */
5190 encoding = strrchr (fontp->name, '-');
5191 if (encoding && stricmp (encoding+1, "sjis") == 0)
1c885fe1 5192 fontp->encoding[1] = 4;
33d52f9c 5193 else
1c885fe1 5194 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
4587b026
GV
5195
5196 /* The following three values are set to 0 under W32, which is
5197 what they get set to if XGetFontProperty fails under X. */
5198 fontp->baseline_offset = 0;
5199 fontp->relative_compose = 0;
33d52f9c 5200 fontp->default_ascent = 0;
4587b026
GV
5201
5202 UNBLOCK_INPUT;
5203 dpyinfo->n_fonts++;
5204
5205 return fontp;
5206 }
5207}
5208
33d52f9c
GV
5209/* Load font named FONTNAME of size SIZE for frame F, and return a
5210 pointer to the structure font_info while allocating it dynamically.
5211 If loading fails, return NULL. */
5212struct font_info *
5213w32_load_font (f,fontname,size)
5214struct frame *f;
5215char * fontname;
5216int size;
5217{
5218 Lisp_Object bdf_fonts;
5219 struct font_info *retval = NULL;
5220
5221 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5222
5223 while (!retval && CONSP (bdf_fonts))
5224 {
5225 char *bdf_name, *bdf_file;
5226 Lisp_Object bdf_pair;
5227
5228 bdf_name = XSTRING (XCONS (bdf_fonts)->car)->data;
5229 bdf_pair = Fassoc (XCONS (bdf_fonts)->car, Vw32_bdf_filename_alist);
5230 bdf_file = XSTRING (XCONS (bdf_pair)->cdr)->data;
5231
5232 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5233
5234 bdf_fonts = XCONS (bdf_fonts)->cdr;
5235 }
5236
5237 if (retval)
5238 return retval;
5239
5240 return w32_load_system_font(f, fontname, size);
5241}
5242
5243
ee78dc32 5244void
fbd6baed
GV
5245w32_unload_font (dpyinfo, font)
5246 struct w32_display_info *dpyinfo;
ee78dc32
GV
5247 XFontStruct * font;
5248{
5249 if (font)
5250 {
33d52f9c
GV
5251 if (font->bdf) w32_free_bdf_font (font->bdf);
5252
3c190163 5253 if (font->hfont) DeleteObject(font->hfont);
ee78dc32
GV
5254 xfree (font);
5255 }
5256}
5257
fbd6baed 5258/* The font conversion stuff between x and w32 */
ee78dc32
GV
5259
5260/* X font string is as follows (from faces.el)
5261 * (let ((- "[-?]")
5262 * (foundry "[^-]+")
5263 * (family "[^-]+")
5264 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5265 * (weight\? "\\([^-]*\\)") ; 1
5266 * (slant "\\([ior]\\)") ; 2
5267 * (slant\? "\\([^-]?\\)") ; 2
5268 * (swidth "\\([^-]*\\)") ; 3
5269 * (adstyle "[^-]*") ; 4
5270 * (pixelsize "[0-9]+")
5271 * (pointsize "[0-9][0-9]+")
5272 * (resx "[0-9][0-9]+")
5273 * (resy "[0-9][0-9]+")
5274 * (spacing "[cmp?*]")
5275 * (avgwidth "[0-9]+")
5276 * (registry "[^-]+")
5277 * (encoding "[^-]+")
5278 * )
5279 * (setq x-font-regexp
5280 * (concat "\\`\\*?[-?*]"
5281 * foundry - family - weight\? - slant\? - swidth - adstyle -
5282 * pixelsize - pointsize - resx - resy - spacing - registry -
5283 * encoding "[-?*]\\*?\\'"
5284 * ))
5285 * (setq x-font-regexp-head
5286 * (concat "\\`[-?*]" foundry - family - weight\? - slant\?
5287 * "\\([-*?]\\|\\'\\)"))
5288 * (setq x-font-regexp-slant (concat - slant -))
5289 * (setq x-font-regexp-weight (concat - weight -))
5290 * nil)
5291 */
5292
5293#define FONT_START "[-?]"
5294#define FONT_FOUNDRY "[^-]+"
5295#define FONT_FAMILY "\\([^-]+\\)" /* 1 */
5296#define FONT_WEIGHT "\\(bold\\|demibold\\|medium\\)" /* 2 */
5297#define FONT_WEIGHT_Q "\\([^-]*\\)" /* 2 */
5298#define FONT_SLANT "\\([ior]\\)" /* 3 */
5299#define FONT_SLANT_Q "\\([^-]?\\)" /* 3 */
5300#define FONT_SWIDTH "\\([^-]*\\)" /* 4 */
5301#define FONT_ADSTYLE "[^-]*"
5302#define FONT_PIXELSIZE "[^-]*"
5303#define FONT_POINTSIZE "\\([0-9][0-9]+\\|\\*\\)" /* 5 */
5304#define FONT_RESX "[0-9][0-9]+"
5305#define FONT_RESY "[0-9][0-9]+"
5306#define FONT_SPACING "[cmp?*]"
5307#define FONT_AVGWIDTH "[0-9]+"
5308#define FONT_REGISTRY "[^-]+"
5309#define FONT_ENCODING "[^-]+"
5310
5311#define FONT_REGEXP ("\\`\\*?[-?*]" \
5312 FONT_FOUNDRY "-" \
5313 FONT_FAMILY "-" \
5314 FONT_WEIGHT_Q "-" \
5315 FONT_SLANT_Q "-" \
5316 FONT_SWIDTH "-" \
5317 FONT_ADSTYLE "-" \
5318 FONT_PIXELSIZE "-" \
5319 FONT_POINTSIZE "-" \
5320 "[-?*]\\|\\'")
5321
5322#define FONT_REGEXP_HEAD ("\\`[-?*]" \
5323 FONT_FOUNDRY "-" \
5324 FONT_FAMILY "-" \
5325 FONT_WEIGHT_Q "-" \
5326 FONT_SLANT_Q \
5327 "\\([-*?]\\|\\'\\)")
5328
5329#define FONT_REGEXP_SLANT "-" FONT_SLANT "-"
5330#define FONT_REGEXP_WEIGHT "-" FONT_WEIGHT "-"
5331
5332LONG
fbd6baed 5333x_to_w32_weight (lpw)
ee78dc32
GV
5334 char * lpw;
5335{
5336 if (!lpw) return (FW_DONTCARE);
5ac45f98
GV
5337
5338 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5339 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5340 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5341 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
1edf84e7 5342 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5ac45f98
GV
5343 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5344 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5345 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5346 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5347 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
ee78dc32 5348 else
5ac45f98 5349 return FW_DONTCARE;
ee78dc32
GV
5350}
5351
5ac45f98 5352
ee78dc32 5353char *
fbd6baed 5354w32_to_x_weight (fnweight)
ee78dc32
GV
5355 int fnweight;
5356{
5ac45f98
GV
5357 if (fnweight >= FW_HEAVY) return "heavy";
5358 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5359 if (fnweight >= FW_BOLD) return "bold";
5360 if (fnweight >= FW_SEMIBOLD) return "semibold";
5361 if (fnweight >= FW_MEDIUM) return "medium";
5362 if (fnweight >= FW_NORMAL) return "normal";
5363 if (fnweight >= FW_LIGHT) return "light";
5364 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5365 if (fnweight >= FW_THIN) return "thin";
5366 else
5367 return "*";
5368}
5369
5370LONG
fbd6baed 5371x_to_w32_charset (lpcs)
5ac45f98
GV
5372 char * lpcs;
5373{
5374 if (!lpcs) return (0);
5375
1a292d24
AI
5376 if (stricmp (lpcs,"ansi") == 0) return ANSI_CHARSET;
5377 else if (stricmp (lpcs,"iso8859-1") == 0) return ANSI_CHARSET;
33d52f9c 5378 else if (stricmp (lpcs, "ms-symbol") == 0) return SYMBOL_CHARSET;
1c885fe1
AI
5379 /* Map all Japanese charsets to the Windows Shift-JIS charset. */
5380 else if (strnicmp (lpcs, "jis", 3) == 0) return SHIFTJIS_CHARSET;
ce6059da
AI
5381 /* Map all GB charsets to the Windows GB2312 charset. */
5382 else if (strnicmp (lpcs, "gb2312", 6) == 0) return GB2312_CHARSET;
5383 /* Map all Big5 charsets to the Windows Big5 charset. */
5384 else if (strnicmp (lpcs, "big5", 4) == 0) return CHINESEBIG5_CHARSET;
33d52f9c 5385 else if (stricmp (lpcs, "ksc5601.1987") == 0) return HANGEUL_CHARSET;
33d52f9c 5386 else if (stricmp (lpcs, "ms-oem") == 0) return OEM_CHARSET;
4587b026
GV
5387
5388#ifdef EASTEUROPE_CHARSET
5389 else if (stricmp (lpcs, "iso8859-2") == 0) return EASTEUROPE_CHARSET;
5390 else if (stricmp (lpcs, "iso8859-3") == 0) return TURKISH_CHARSET;
5391 else if (stricmp (lpcs, "iso8859-4") == 0) return BALTIC_CHARSET;
5392 else if (stricmp (lpcs, "iso8859-5") == 0) return RUSSIAN_CHARSET;
5393 else if (stricmp (lpcs, "koi8") == 0) return RUSSIAN_CHARSET;
5394 else if (stricmp (lpcs, "iso8859-6") == 0) return ARABIC_CHARSET;
5395 else if (stricmp (lpcs, "iso8859-7") == 0) return GREEK_CHARSET;
5396 else if (stricmp (lpcs, "iso8859-8") == 0) return HEBREW_CHARSET;
a4e691ee 5397 else if (stricmp (lpcs, "iso8859-9") == 0) return TURKISH_CHARSET;
ce6059da
AI
5398#ifndef VIETNAMESE_CHARSET
5399#define VIETNAMESE_CHARSET 163
5400#endif
5401 /* Map all Viscii charsets to the Windows Vietnamese charset. */
5402 else if (strnicmp (lpcs, "viscii", 6) == 0) return VIETNAMESE_CHARSET;
5403 else if (strnicmp (lpcs, "vscii", 5) == 0) return VIETNAMESE_CHARSET;
5404 /* Map all TIS charsets to the Windows Thai charset. */
5405 else if (strnicmp (lpcs, "tis620", 6) == 0) return THAI_CHARSET;
4587b026 5406 else if (stricmp (lpcs, "mac") == 0) return MAC_CHARSET;
33d52f9c 5407 else if (stricmp (lpcs, "ksc5601.1992") == 0) return JOHAB_CHARSET;
ce6059da
AI
5408 /* For backwards compatibility with previous 20.4 pretests, map
5409 non-specific KSC charsets to the Windows Hangeul charset. */
5410 else if (strnicmp (lpcs, "ksc5601", 7) == 0) return HANGEUL_CHARSET;
33d52f9c 5411 else if (stricmp (lpcs, "johab") == 0) return JOHAB_CHARSET;
4587b026
GV
5412#endif
5413
5ac45f98 5414#ifdef UNICODE_CHARSET
1a292d24
AI
5415 else if (stricmp (lpcs,"iso10646") == 0) return UNICODE_CHARSET;
5416 else if (stricmp (lpcs, "unicode") == 0) return UNICODE_CHARSET;
5ac45f98 5417#endif
1a292d24 5418 else if (lpcs[0] == '#') return atoi (lpcs + 1);
5ac45f98 5419 else
1edf84e7 5420 return DEFAULT_CHARSET;
5ac45f98
GV
5421}
5422
5423char *
fbd6baed 5424w32_to_x_charset (fncharset)
5ac45f98
GV
5425 int fncharset;
5426{
1edf84e7
GV
5427 static char buf[16];
5428
5ac45f98
GV
5429 switch (fncharset)
5430 {
4587b026
GV
5431 /* ansi is considered iso8859-1, as most modern ansi fonts are. */
5432 case ANSI_CHARSET: return "iso8859-1";
5433 case DEFAULT_CHARSET: return "ascii-*";
33d52f9c 5434 case SYMBOL_CHARSET: return "ms-symbol";
a4e691ee 5435 case SHIFTJIS_CHARSET: return "jisx0208-sjis";
33d52f9c 5436 case HANGEUL_CHARSET: return "ksc5601.1987-*";
4587b026
GV
5437 case GB2312_CHARSET: return "gb2312-*";
5438 case CHINESEBIG5_CHARSET: return "big5-*";
33d52f9c 5439 case OEM_CHARSET: return "ms-oem";
4587b026
GV
5440
5441 /* More recent versions of Windows (95 and NT4.0) define more
5442 character sets. */
5443#ifdef EASTEUROPE_CHARSET
5444 case EASTEUROPE_CHARSET: return "iso8859-2";
a4e691ee 5445 case TURKISH_CHARSET: return "iso8859-9";
4587b026 5446 case BALTIC_CHARSET: return "iso8859-4";
33d52f9c
GV
5447
5448 /* W95 with international support but not IE4 often has the
5449 KOI8-R codepage but not ISO8859-5. */
5450 case RUSSIAN_CHARSET:
5451 if (!IsValidCodePage(28595) && IsValidCodePage(20886))
5452 return "koi8-r";
5453 else
5454 return "iso8859-5";
4587b026
GV
5455 case ARABIC_CHARSET: return "iso8859-6";
5456 case GREEK_CHARSET: return "iso8859-7";
5457 case HEBREW_CHARSET: return "iso8859-8";
5458 case VIETNAMESE_CHARSET: return "viscii1.1-*";
5459 case THAI_CHARSET: return "tis620-*";
33d52f9c
GV
5460 case MAC_CHARSET: return "mac-*";
5461 case JOHAB_CHARSET: return "ksc5601.1992-*";
a4e691ee 5462
4587b026
GV
5463#endif
5464
5ac45f98 5465#ifdef UNICODE_CHARSET
4587b026 5466 case UNICODE_CHARSET: return "iso10646-unicode";
5ac45f98
GV
5467#endif
5468 }
1edf84e7 5469 /* Encode numerical value of unknown charset. */
4587b026 5470 sprintf (buf, "*-#%u", fncharset);
1edf84e7 5471 return buf;
ee78dc32
GV
5472}
5473
5474BOOL
fbd6baed 5475w32_to_x_font (lplogfont, lpxstr, len)
ee78dc32
GV
5476 LOGFONT * lplogfont;
5477 char * lpxstr;
5478 int len;
5479{
f46e6225 5480 char *fontname;
3cb20f4a
RS
5481 char height_pixels[8];
5482 char height_dpi[8];
5483 char width_pixels[8];
4587b026 5484 char *fontname_dash;
33d52f9c
GV
5485 int display_resy = one_w32_display_info.height_in;
5486 int display_resx = one_w32_display_info.width_in;
f46e6225
GV
5487 int bufsz;
5488 struct coding_system coding;
3cb20f4a
RS
5489
5490 if (!lpxstr) abort ();
ee78dc32 5491
3cb20f4a
RS
5492 if (!lplogfont)
5493 return FALSE;
5494
f46e6225
GV
5495 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
5496 &coding);
5497 coding.mode |= CODING_MODE_LAST_BLOCK;
5498 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
5499
5500 fontname = alloca(sizeof(*fontname) * bufsz);
5501 decode_coding (&coding, lplogfont->lfFaceName, fontname,
5502 strlen(lplogfont->lfFaceName), bufsz - 1);
5503 *(fontname + coding.produced) = '\0';
4587b026
GV
5504
5505 /* Replace dashes with underscores so the dashes are not
f46e6225 5506 misinterpreted. */
4587b026
GV
5507 fontname_dash = fontname;
5508 while (fontname_dash = strchr (fontname_dash, '-'))
5509 *fontname_dash = '_';
5510
3cb20f4a 5511 if (lplogfont->lfHeight)
ee78dc32 5512 {
3cb20f4a
RS
5513 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
5514 sprintf (height_dpi, "%u",
33d52f9c 5515 abs (lplogfont->lfHeight) * 720 / display_resy);
5ac45f98
GV
5516 }
5517 else
ee78dc32 5518 {
3cb20f4a
RS
5519 strcpy (height_pixels, "*");
5520 strcpy (height_dpi, "*");
ee78dc32 5521 }
3cb20f4a
RS
5522 if (lplogfont->lfWidth)
5523 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5524 else
5525 strcpy (width_pixels, "*");
5526
5527 _snprintf (lpxstr, len - 1,
33d52f9c 5528 "-*-%s-%s-%c-*-*-%s-%s-%d-%d-%c-%s-%s",
4587b026
GV
5529 /* foundry */
5530 fontname, /* family */
5531 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5532 lplogfont->lfItalic?'i':'r', /* slant */
5533 /* setwidth name */
5534 /* add style name */
5535 height_pixels, /* pixel size */
5536 height_dpi, /* point size */
33d52f9c
GV
5537 display_resx, /* resx */
5538 display_resy, /* resy */
4587b026
GV
5539 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5540 ? 'p' : 'c', /* spacing */
5541 width_pixels, /* avg width */
5542 w32_to_x_charset (lplogfont->lfCharSet) /* charset registry
5543 and encoding*/
3cb20f4a
RS
5544 );
5545
ee78dc32
GV
5546 lpxstr[len - 1] = 0; /* just to be sure */
5547 return (TRUE);
5548}
5549
5550BOOL
fbd6baed 5551x_to_w32_font (lpxstr, lplogfont)
ee78dc32
GV
5552 char * lpxstr;
5553 LOGFONT * lplogfont;
5554{
f46e6225
GV
5555 struct coding_system coding;
5556
ee78dc32 5557 if (!lplogfont) return (FALSE);
f46e6225 5558
ee78dc32 5559 memset (lplogfont, 0, sizeof (*lplogfont));
5ac45f98 5560
1a292d24 5561 /* Set default value for each field. */
771c47d5 5562#if 1
ee78dc32
GV
5563 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5564 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5565 lplogfont->lfQuality = DEFAULT_QUALITY;
5ac45f98
GV
5566#else
5567 /* go for maximum quality */
5568 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5569 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5570 lplogfont->lfQuality = PROOF_QUALITY;
5571#endif
5572
1a292d24
AI
5573 lplogfont->lfCharSet = DEFAULT_CHARSET;
5574 lplogfont->lfWeight = FW_DONTCARE;
5575 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5576
5ac45f98
GV
5577 if (!lpxstr)
5578 return FALSE;
5579
5580 /* Provide a simple escape mechanism for specifying Windows font names
5581 * directly -- if font spec does not beginning with '-', assume this
5582 * format:
5583 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5584 */
ee78dc32 5585
5ac45f98
GV
5586 if (*lpxstr == '-')
5587 {
33d52f9c
GV
5588 int fields, tem;
5589 char name[50], weight[20], slant, pitch, pixels[10], height[10],
5590 width[10], resy[10], remainder[20];
5ac45f98 5591 char * encoding;
33d52f9c 5592 int dpi = one_w32_display_info.height_in;
5ac45f98
GV
5593
5594 fields = sscanf (lpxstr,
33d52f9c
GV
5595 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
5596 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5ac45f98
GV
5597 if (fields == EOF) return (FALSE);
5598
5599 if (fields > 0 && name[0] != '*')
5600 {
8ea3e054
RS
5601 int bufsize;
5602 unsigned char *buf;
5603
f46e6225
GV
5604 setup_coding_system
5605 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
8ea3e054
RS
5606 bufsize = encoding_buffer_size (&coding, strlen (name));
5607 buf = (unsigned char *) alloca (bufsize);
f46e6225 5608 coding.mode |= CODING_MODE_LAST_BLOCK;
8ea3e054
RS
5609 encode_coding (&coding, name, buf, strlen (name), bufsize);
5610 if (coding.produced >= LF_FACESIZE)
5611 coding.produced = LF_FACESIZE - 1;
5612 buf[coding.produced] = 0;
5613 strcpy (lplogfont->lfFaceName, buf);
5ac45f98
GV
5614 }
5615 else
5616 {
5617 lplogfont->lfFaceName[0] = 0;
5618 }
5619
5620 fields--;
5621
fbd6baed 5622 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
5623
5624 fields--;
5625
fbd6baed 5626 if (!NILP (Vw32_enable_italics))
5ac45f98
GV
5627 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5628
5629 fields--;
5630
5631 if (fields > 0 && pixels[0] != '*')
5632 lplogfont->lfHeight = atoi (pixels);
5633
5634 fields--;
5ac45f98 5635 fields--;
33d52f9c
GV
5636 if (fields > 0 && resy[0] != '*')
5637 {
5638 tem = atoi (pixels);
5639 if (tem > 0) dpi = tem;
5640 }
5ac45f98 5641
33d52f9c
GV
5642 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
5643 lplogfont->lfHeight = atoi (height) * dpi / 720;
5644
5645 if (fields > 0)
5ac45f98
GV
5646 lplogfont->lfPitchAndFamily =
5647 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
5648
5649 fields--;
5650
5651 if (fields > 0 && width[0] != '*')
5652 lplogfont->lfWidth = atoi (width) / 10;
5653
5654 fields--;
5655
4587b026
GV
5656 /* Strip the trailing '-' if present. (it shouldn't be, as it
5657 fails the test against xlfn-tight-regexp in fontset.el). */
3c190163 5658 {
5ac45f98
GV
5659 int len = strlen (remainder);
5660 if (len > 0 && remainder[len-1] == '-')
5661 remainder[len-1] = 0;
ee78dc32 5662 }
5ac45f98
GV
5663 encoding = remainder;
5664 if (strncmp (encoding, "*-", 2) == 0)
5665 encoding += 2;
fbd6baed 5666 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
5ac45f98
GV
5667 }
5668 else
5669 {
5670 int fields;
5671 char name[100], height[10], width[10], weight[20];
a1a80b40 5672
5ac45f98
GV
5673 fields = sscanf (lpxstr,
5674 "%99[^:]:%9[^:]:%9[^:]:%19s",
5675 name, height, width, weight);
5676
5677 if (fields == EOF) return (FALSE);
5678
5679 if (fields > 0)
5680 {
5681 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
5682 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
5683 }
5684 else
5685 {
5686 lplogfont->lfFaceName[0] = 0;
5687 }
5688
5689 fields--;
5690
5691 if (fields > 0)
5692 lplogfont->lfHeight = atoi (height);
5693
5694 fields--;
5695
5696 if (fields > 0)
5697 lplogfont->lfWidth = atoi (width);
5698
5699 fields--;
5700
fbd6baed 5701 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5ac45f98
GV
5702 }
5703
5704 /* This makes TrueType fonts work better. */
5705 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
ee78dc32
GV
5706
5707 return (TRUE);
5708}
5709
5710BOOL
fbd6baed 5711w32_font_match (lpszfont1, lpszfont2)
ee78dc32
GV
5712 char * lpszfont1;
5713 char * lpszfont2;
5714{
33d52f9c
GV
5715 char * s1 = lpszfont1, *e1, *w1;
5716 char * s2 = lpszfont2, *e2, *w2;
ee78dc32
GV
5717
5718 if (s1 == NULL || s2 == NULL) return (FALSE);
5719
5720 if (*s1 == '-') s1++;
5721 if (*s2 == '-') s2++;
5722
5723 while (1)
5724 {
33d52f9c 5725 int len1, len2, len3=0;
ee78dc32
GV
5726
5727 e1 = strchr (s1, '-');
5728 e2 = strchr (s2, '-');
33d52f9c
GV
5729 w1 = strchr (s1, '*');
5730 w2 = strchr (s2, '*');
ee78dc32 5731
33d52f9c
GV
5732 if (e1 == NULL)
5733 len1 = strlen (s1);
5734 else
ee78dc32 5735 len1 = e1 - s1;
33d52f9c
GV
5736 if (e2 == NULL)
5737 len2 = strlen (s1);
5738 else
ee78dc32
GV
5739 len2 = e2 - s2;
5740
33d52f9c
GV
5741 if (w1 && w1 < e1)
5742 len3 = w1 - s1;
5743 if (w2 && w2 < e2 && ( len3 == 0 || (w2 - s2) < len3))
5744 len3 = w2 - s2;
5745
5746 /* Whole field is not a wildcard, and ...*/
5747 if (*s1 != '*' && *s2 != '*' && *s1 != '-' && *s2 != '-'
5748 /* Lengths are different and there are no wildcards, or ... */
5749 && ((len1 != len2 && len3 == 0) ||
5750 /* strings don't match up until first wildcard or end. */
5751 strnicmp (s1, s2, len3 > 0 ? len3 : len1) != 0))
ee78dc32
GV
5752 return (FALSE);
5753
33d52f9c
GV
5754 if (e1 == NULL || e2 == NULL)
5755 return (TRUE);
5756
ee78dc32
GV
5757 s1 = e1 + 1;
5758 s2 = e2 + 1;
5759 }
5760}
5761
5ca0cd71
GV
5762/* Callback functions, and a structure holding info they need, for
5763 listing system fonts on W32. We need one set of functions to do the
5764 job properly, but these don't work on NT 3.51 and earlier, so we
5765 have a second set which don't handle character sets properly to
5766 fall back on.
5767
5768 In both cases, there are two passes made. The first pass gets one
5769 font from each family, the second pass lists all the fonts from
5770 each family. */
5771
ee78dc32
GV
5772typedef struct enumfont_t
5773{
5774 HDC hdc;
5775 int numFonts;
3cb20f4a 5776 LOGFONT logfont;
ee78dc32
GV
5777 XFontStruct *size_ref;
5778 Lisp_Object *pattern;
ee78dc32
GV
5779 Lisp_Object *tail;
5780} enumfont_t;
5781
5782int CALLBACK
5783enum_font_cb2 (lplf, lptm, FontType, lpef)
5784 ENUMLOGFONT * lplf;
5785 NEWTEXTMETRIC * lptm;
5786 int FontType;
5787 enumfont_t * lpef;
5788{
1edf84e7 5789 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
ee78dc32
GV
5790 return (1);
5791
4587b026
GV
5792 /* Check that the character set matches if it was specified */
5793 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
5794 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
5795 return (1);
5796
5797 /* We want all fonts cached, so don't compare sizes just yet */
ee78dc32
GV
5798 /* if (!lpef->size_ref || lptm->tmMaxCharWidth == FONT_WIDTH (lpef->size_ref)) */
5799 {
5800 char buf[100];
4587b026 5801 Lisp_Object width = Qnil;
ee78dc32 5802
779a69a8 5803 if (!NILP (*(lpef->pattern)) && FontType != RASTER_FONTTYPE)
3cb20f4a 5804 {
4587b026 5805 /* Scalable fonts are as big as you want them to be. */
3cb20f4a
RS
5806 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
5807 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
5808 }
f46e6225
GV
5809 /* Make sure the height used here is the same as everywhere
5810 else (ie character height, not cell height). */
5811 else if (lplf->elfLogFont.lfHeight > 0)
5812 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
3cb20f4a 5813
4587b026
GV
5814 /* The MaxCharWidth is not valid at this stage for scalable fonts. */
5815 if (FontType == RASTER_FONTTYPE)
5816 width = make_number (lptm->tmMaxCharWidth);
5817
33d52f9c
GV
5818 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100))
5819 return (0);
ee78dc32 5820
5ca0cd71
GV
5821 if (NILP (*(lpef->pattern))
5822 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
ee78dc32 5823 {
4587b026
GV
5824 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
5825 lpef->tail = &(XCONS (*lpef->tail)->cdr);
ee78dc32
GV
5826 lpef->numFonts++;
5827 }
5828 }
5829
5830 return (1);
5831}
5832
5833int CALLBACK
5834enum_font_cb1 (lplf, lptm, FontType, lpef)
5835 ENUMLOGFONT * lplf;
5836 NEWTEXTMETRIC * lptm;
5837 int FontType;
5838 enumfont_t * lpef;
5839{
5840 return EnumFontFamilies (lpef->hdc,
5841 lplf->elfLogFont.lfFaceName,
5842 (FONTENUMPROC) enum_font_cb2,
5843 (LPARAM) lpef);
5844}
5845
5846
5ca0cd71
GV
5847int CALLBACK
5848enum_fontex_cb2 (lplf, lptm, font_type, lpef)
5849 ENUMLOGFONTEX * lplf;
5850 NEWTEXTMETRICEX * lptm;
5851 int font_type;
5852 enumfont_t * lpef;
5853{
5854 /* We are not interested in the extra info we get back from the 'Ex
5855 version - only the fact that we get character set variations
5856 enumerated seperately. */
5857 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
5858 font_type, lpef);
5859}
5860
5861int CALLBACK
5862enum_fontex_cb1 (lplf, lptm, font_type, lpef)
5863 ENUMLOGFONTEX * lplf;
5864 NEWTEXTMETRICEX * lptm;
5865 int font_type;
5866 enumfont_t * lpef;
5867{
5868 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5869 FARPROC enum_font_families_ex
5870 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
5871 /* We don't really expect EnumFontFamiliesEx to disappear once we
5872 get here, so don't bother handling it gracefully. */
5873 if (enum_font_families_ex == NULL)
5874 error ("gdi32.dll has disappeared!");
5875 return enum_font_families_ex (lpef->hdc,
5876 &lplf->elfLogFont,
5877 (FONTENUMPROC) enum_fontex_cb2,
5878 (LPARAM) lpef, 0);
5879}
5880
4587b026
GV
5881/* Interface to fontset handler. (adapted from mw32font.c in Meadow
5882 and xterm.c in Emacs 20.3) */
5883
5ca0cd71 5884Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
33d52f9c
GV
5885{
5886 char *fontname, *ptnstr;
5887 Lisp_Object list, tem, newlist = Qnil;
55dcfc15 5888 int n_fonts = 0;
33d52f9c
GV
5889
5890 list = Vw32_bdf_filename_alist;
5891 ptnstr = XSTRING (pattern)->data;
5892
5893 for ( ; CONSP (list); list = XCONS (list)->cdr)
5894 {
5895 tem = XCONS (list)->car;
5896 if (CONSP (tem))
5897 fontname = XSTRING (XCONS (tem)->car)->data;
5898 else if (STRINGP (tem))
5899 fontname = XSTRING (tem)->data;
5900 else
5901 continue;
5902
5903 if (w32_font_match (fontname, ptnstr))
5ca0cd71
GV
5904 {
5905 newlist = Fcons (XCONS (tem)->car, newlist);
5906 n_fonts++;
5907 if (n_fonts >= max_names)
5908 break;
5909 }
33d52f9c
GV
5910 }
5911
5912 return newlist;
5913}
5914
5ca0cd71
GV
5915Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
5916 int size, int max_names);
5917
4587b026
GV
5918/* Return a list of names of available fonts matching PATTERN on frame
5919 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
5920 to be listed. Frame F NULL means we have not yet created any
5921 frame, which means we can't get proper size info, as we don't have
5922 a device context to use for GetTextMetrics.
5923 MAXNAMES sets a limit on how many fonts to match. */
5924
5925Lisp_Object
5926w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
5927{
33d52f9c 5928 Lisp_Object patterns, key, tem, tpat;
4587b026 5929 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
33d52f9c 5930 struct w32_display_info *dpyinfo = &one_w32_display_info;
5ca0cd71 5931 int n_fonts = 0;
396594fe 5932
4587b026
GV
5933 patterns = Fassoc (pattern, Valternate_fontname_alist);
5934 if (NILP (patterns))
5935 patterns = Fcons (pattern, Qnil);
5936
5937 for (; CONSP (patterns); patterns = XCONS (patterns)->cdr)
5938 {
5939 enumfont_t ef;
5940
33d52f9c 5941 tpat = XCONS (patterns)->car;
4587b026
GV
5942
5943 /* See if we cached the result for this particular query.
5944 The cache is an alist of the form:
5945 ((PATTERN (FONTNAME . WIDTH) ...) ...)
5946 */
33d52f9c
GV
5947 if (tem = XCONS (dpyinfo->name_list_element)->cdr,
5948 !NILP (list = Fassoc (tpat, tem)))
4587b026
GV
5949 {
5950 list = Fcdr_safe (list);
5951 /* We have a cached list. Don't have to get the list again. */
5952 goto label_cached;
5953 }
5954
5955 BLOCK_INPUT;
5956 /* At first, put PATTERN in the cache. */
5957 list = Qnil;
33d52f9c
GV
5958 ef.pattern = &tpat;
5959 ef.tail = &list;
4587b026 5960 ef.numFonts = 0;
33d52f9c 5961
5ca0cd71
GV
5962 /* Use EnumFontFamiliesEx where it is available, as it knows
5963 about character sets. Fall back to EnumFontFamilies for
5964 older versions of NT that don't support the 'Ex function. */
33d52f9c 5965 x_to_w32_font (STRINGP (tpat) ? XSTRING (tpat)->data :
4587b026
GV
5966 NULL, &ef.logfont);
5967 {
5ca0cd71
GV
5968 LOGFONT font_match_pattern;
5969 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5970 FARPROC enum_font_families_ex
5971 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
5972
5973 /* We do our own pattern matching so we can handle wildcards. */
5974 font_match_pattern.lfFaceName[0] = 0;
5975 font_match_pattern.lfPitchAndFamily = 0;
5976 /* We can use the charset, because if it is a wildcard it will
5977 be DEFAULT_CHARSET anyway. */
5978 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
5979
33d52f9c 5980 ef.hdc = GetDC (dpyinfo->root_window);
4587b026 5981
5ca0cd71
GV
5982 if (enum_font_families_ex)
5983 enum_font_families_ex (ef.hdc,
5984 &font_match_pattern,
5985 (FONTENUMPROC) enum_fontex_cb1,
5986 (LPARAM) &ef, 0);
5987 else
5988 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
5989 (LPARAM)&ef);
4587b026 5990
33d52f9c 5991 ReleaseDC (dpyinfo->root_window, ef.hdc);
4587b026
GV
5992 }
5993
5994 UNBLOCK_INPUT;
5995
5996 /* Make a list of the fonts we got back.
5997 Store that in the font cache for the display. */
33d52f9c
GV
5998 XCONS (dpyinfo->name_list_element)->cdr
5999 = Fcons (Fcons (tpat, list),
6000 XCONS (dpyinfo->name_list_element)->cdr);
4587b026
GV
6001
6002 label_cached:
6003 if (NILP (list)) continue; /* Try the remaining alternatives. */
6004
6005 newlist = second_best = Qnil;
6006
6007 /* Make a list of the fonts that have the right width. */
6008 for (; CONSP (list); list = XCONS (list)->cdr)
6009 {
6010 int found_size;
6011 tem = XCONS (list)->car;
6012
6013 if (!CONSP (tem))
6014 continue;
6015 if (NILP (XCONS (tem)->car))
6016 continue;
6017 if (!size)
6018 {
6019 newlist = Fcons (XCONS (tem)->car, newlist);
5ca0cd71
GV
6020 n_fonts++;
6021 if (n_fonts >= maxnames)
6022 break;
6023 else
6024 continue;
4587b026
GV
6025 }
6026 if (!INTEGERP (XCONS (tem)->cdr))
6027 {
6028 /* Since we don't yet know the size of the font, we must
6029 load it and try GetTextMetrics. */
4587b026
GV
6030 W32FontStruct thisinfo;
6031 LOGFONT lf;
6032 HDC hdc;
6033 HANDLE oldobj;
6034
6035 if (!x_to_w32_font (XSTRING (XCONS (tem)->car)->data, &lf))
6036 continue;
6037
6038 BLOCK_INPUT;
33d52f9c 6039 thisinfo.bdf = NULL;
4587b026
GV
6040 thisinfo.hfont = CreateFontIndirect (&lf);
6041 if (thisinfo.hfont == NULL)
6042 continue;
6043
6044 hdc = GetDC (dpyinfo->root_window);
6045 oldobj = SelectObject (hdc, thisinfo.hfont);
6046 if (GetTextMetrics (hdc, &thisinfo.tm))
6047 XCONS (tem)->cdr = make_number (FONT_WIDTH (&thisinfo));
6048 else
6049 XCONS (tem)->cdr = make_number (0);
6050 SelectObject (hdc, oldobj);
6051 ReleaseDC (dpyinfo->root_window, hdc);
6052 DeleteObject(thisinfo.hfont);
6053 UNBLOCK_INPUT;
6054 }
6055 found_size = XINT (XCONS (tem)->cdr);
6056 if (found_size == size)
5ca0cd71
GV
6057 {
6058 newlist = Fcons (XCONS (tem)->car, newlist);
6059 n_fonts++;
6060 if (n_fonts >= maxnames)
6061 break;
6062 }
4587b026
GV
6063 /* keep track of the closest matching size in case
6064 no exact match is found. */
6065 else if (found_size > 0)
6066 {
6067 if (NILP (second_best))
6068 second_best = tem;
5ca0cd71 6069
4587b026
GV
6070 else if (found_size < size)
6071 {
6072 if (XINT (XCONS (second_best)->cdr) > size
6073 || XINT (XCONS (second_best)->cdr) < found_size)
6074 second_best = tem;
6075 }
6076 else
6077 {
6078 if (XINT (XCONS (second_best)->cdr) > size
6079 && XINT (XCONS (second_best)->cdr) >
6080 found_size)
6081 second_best = tem;
6082 }
6083 }
6084 }
6085
6086 if (!NILP (newlist))
6087 break;
6088 else if (!NILP (second_best))
6089 {
6090 newlist = Fcons (XCONS (second_best)->car, Qnil);
6091 break;
6092 }
6093 }
6094
33d52f9c 6095 /* Include any bdf fonts. */
5ca0cd71 6096 if (n_fonts < maxnames)
33d52f9c
GV
6097 {
6098 Lisp_Object combined[2];
5ca0cd71 6099 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
33d52f9c
GV
6100 combined[1] = newlist;
6101 newlist = Fnconc(2, combined);
6102 }
6103
5ca0cd71
GV
6104 /* If we can't find a font that matches, check if Windows would be
6105 able to synthesize it from a different style. */
6106 if (NILP (newlist) && !NILP (Vw32_enable_italics))
6107 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6108
4587b026
GV
6109 return newlist;
6110}
6111
5ca0cd71
GV
6112Lisp_Object
6113w32_list_synthesized_fonts (f, pattern, size, max_names)
6114 FRAME_PTR f;
6115 Lisp_Object pattern;
6116 int size;
6117 int max_names;
6118{
6119 int fields;
6120 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6121 char style[20], slant;
6122 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6123
6124 full_pattn = XSTRING (pattern)->data;
6125
6126 pattn_part2 = alloca (XSTRING (pattern)->size);
6127 /* Allow some space for wildcard expansion. */
6128 new_pattn = alloca (XSTRING (pattern)->size + 100);
6129
6130 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6131 foundary, family, style, &slant, pattn_part2);
6132 if (fields == EOF || fields < 5)
6133 return Qnil;
6134
6135 /* If the style and slant are wildcards already there is no point
6136 checking again (and we don't want to keep recursing). */
6137 if (*style == '*' && slant == '*')
6138 return Qnil;
6139
6140 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6141
6142 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6143
6144 for ( ; CONSP (matches); matches = XCONS (matches)->cdr)
6145 {
6146 tem = XCONS (matches)->car;
6147 if (!STRINGP (tem))
6148 continue;
6149
6150 full_pattn = XSTRING (tem)->data;
6151 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6152 foundary, family, pattn_part2);
6153 if (fields == EOF || fields < 3)
6154 continue;
6155
6156 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6157 slant, pattn_part2);
6158
6159 synthed_matches = Fcons (build_string (new_pattn),
6160 synthed_matches);
6161 }
6162
6163 return synthed_matches;
6164}
6165
6166
4587b026
GV
6167/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6168struct font_info *
6169w32_get_font_info (f, font_idx)
6170 FRAME_PTR f;
6171 int font_idx;
6172{
6173 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6174}
6175
6176
6177struct font_info*
6178w32_query_font (struct frame *f, char *fontname)
6179{
6180 int i;
6181 struct font_info *pfi;
6182
6183 pfi = FRAME_W32_FONT_TABLE (f);
6184
6185 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6186 {
6187 if (strcmp(pfi->name, fontname) == 0) return pfi;
6188 }
6189
6190 return NULL;
6191}
6192
6193/* Find a CCL program for a font specified by FONTP, and set the member
6194 `encoder' of the structure. */
6195
6196void
6197w32_find_ccl_program (fontp)
6198 struct font_info *fontp;
6199{
6200 extern Lisp_Object Vfont_ccl_encoder_alist, Vccl_program_table;
6201 extern Lisp_Object Qccl_program_idx;
6202 extern Lisp_Object resolve_symbol_ccl_program ();
6203 Lisp_Object list, elt, ccl_prog, ccl_id;
6204
6205 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCONS (list)->cdr)
6206 {
6207 elt = XCONS (list)->car;
6208 if (CONSP (elt)
6209 && STRINGP (XCONS (elt)->car)
6210 && (fast_c_string_match_ignore_case (XCONS (elt)->car, fontp->name)
6211 >= 0))
6212 {
6213 if (SYMBOLP (XCONS (elt)->cdr) &&
6214 (!NILP (ccl_id = Fget (XCONS (elt)->cdr, Qccl_program_idx))))
6215 {
6216 ccl_prog = XVECTOR (Vccl_program_table)->contents[XUINT (ccl_id)];
6217 if (!CONSP (ccl_prog)) continue;
6218 ccl_prog = XCONS (ccl_prog)->cdr;
6219 }
6220 else
6221 {
6222 ccl_prog = XCONS (elt)->cdr;
6223 if (!VECTORP (ccl_prog)) continue;
6224 }
6225
6226 fontp->font_encoder
6227 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
6228 setup_ccl_program (fontp->font_encoder,
6229 resolve_symbol_ccl_program (ccl_prog));
6230 break;
6231 }
6232 }
6233}
6234
6235\f
6236#if 1
6237#include "x-list-font.c"
6238#else
4b817373 6239DEFUN ("x-list-fonts", Fx_list_fonts, Sx_list_fonts, 1, 4, 0,
ee78dc32
GV
6240 "Return a list of the names of available fonts matching PATTERN.\n\
6241If optional arguments FACE and FRAME are specified, return only fonts\n\
6242the same size as FACE on FRAME.\n\
6243\n\
6244PATTERN is a string, perhaps with wildcard characters;\n\
6245 the * character matches any substring, and\n\
6246 the ? character matches any single character.\n\
6247 PATTERN is case-insensitive.\n\
6248FACE is a face name--a symbol.\n\
6249\n\
6250The return value is a list of strings, suitable as arguments to\n\
6251set-face-font.\n\
6252\n\
6253Fonts Emacs can't use (i.e. proportional fonts) may or may not be excluded\n\
4b817373
RS
6254even if they match PATTERN and FACE.\n\
6255\n\
6256The optional fourth argument MAXIMUM sets a limit on how many\n\
6257fonts to match. The first MAXIMUM fonts are reported.")
6258 (pattern, face, frame, maximum)
6259 Lisp_Object pattern, face, frame, maximum;
ee78dc32
GV
6260{
6261 int num_fonts;
6262 char **names;
6263 XFontStruct *info;
6264 XFontStruct *size_ref;
6265 Lisp_Object namelist;
6266 Lisp_Object list;
6267 FRAME_PTR f;
6268 enumfont_t ef;
6269
6270 CHECK_STRING (pattern, 0);
6271 if (!NILP (face))
6272 CHECK_SYMBOL (face, 1);
6273
6274 f = check_x_frame (frame);
6275
6276 /* Determine the width standard for comparison with the fonts we find. */
6277
6278 if (NILP (face))
6279 size_ref = 0;
6280 else
6281 {
6282 int face_id;
6283
6284 /* Don't die if we get called with a terminal frame. */
fbd6baed
GV
6285 if (! FRAME_W32_P (f))
6286 error ("non-w32 frame used in `x-list-fonts'");
ee78dc32
GV
6287
6288 face_id = face_name_id_number (f, face);
6289
6290 if (face_id < 0 || face_id >= FRAME_N_PARAM_FACES (f)
6291 || FRAME_PARAM_FACES (f) [face_id] == 0)
fbd6baed 6292 size_ref = f->output_data.w32->font;
ee78dc32
GV
6293 else
6294 {
6295 size_ref = FRAME_PARAM_FACES (f) [face_id]->font;
6296 if (size_ref == (XFontStruct *) (~0))
fbd6baed 6297 size_ref = f->output_data.w32->font;
ee78dc32
GV
6298 }
6299 }
6300
6301 /* See if we cached the result for this particular query. */
6302 list = Fassoc (pattern,
fbd6baed 6303 XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr);
ee78dc32
GV
6304
6305 /* We have info in the cache for this PATTERN. */
6306 if (!NILP (list))
6307 {
6308 Lisp_Object tem, newlist;
6309
6310 /* We have info about this pattern. */
6311 list = XCONS (list)->cdr;
6312
6313 if (size_ref == 0)
6314 return list;
6315
6316 BLOCK_INPUT;
6317
6318 /* Filter the cached info and return just the fonts that match FACE. */
6319 newlist = Qnil;
6320 for (tem = list; CONSP (tem); tem = XCONS (tem)->cdr)
6321 {
4587b026
GV
6322 struct font_info *fontinf;
6323 XFontStruct *thisinfo = NULL;
ee78dc32 6324
4587b026
GV
6325 fontinf = w32_load_font (f, XSTRING (XCONS (tem)->car)->data, 0);
6326 if (fontinf)
6327 thisinfo = (XFontStruct *)fontinf->font;
ee78dc32
GV
6328 if (thisinfo && same_size_fonts (thisinfo, size_ref))
6329 newlist = Fcons (XCONS (tem)->car, newlist);
6330
fbd6baed 6331 w32_unload_font (FRAME_W32_DISPLAY_INFO (f), thisinfo);
ee78dc32
GV
6332 }
6333
6334 UNBLOCK_INPUT;
6335
6336 return newlist;
6337 }
6338
6339 BLOCK_INPUT;
6340
6341 namelist = Qnil;
6342 ef.pattern = &pattern;
33d52f9c 6343 ef.tail &namelist;
ee78dc32 6344 ef.numFonts = 0;
fbd6baed 6345 x_to_w32_font (STRINGP (pattern) ? XSTRING (pattern)->data : NULL, &ef.logfont);
ee78dc32
GV
6346
6347 {
fbd6baed 6348 ef.hdc = GetDC (FRAME_W32_WINDOW (f));
ee78dc32
GV
6349
6350 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1, (LPARAM)&ef);
6351
fbd6baed 6352 ReleaseDC (FRAME_W32_WINDOW (f), ef.hdc);
ee78dc32
GV
6353 }
6354
6355 UNBLOCK_INPUT;
6356
6357 if (ef.numFonts)
6358 {
6359 int i;
6360 Lisp_Object cur;
6361
6362 /* Make a list of all the fonts we got back.
6363 Store that in the font cache for the display. */
fbd6baed 6364 XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr
ee78dc32 6365 = Fcons (Fcons (pattern, namelist),
fbd6baed 6366 XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr);
ee78dc32
GV
6367
6368 /* Make a list of the fonts that have the right width. */
6369 list = Qnil;
6370 cur=namelist;
6371 for (i = 0; i < ef.numFonts; i++)
6372 {
6373 int keeper;
6374
6375 if (!size_ref)
6376 keeper = 1;
6377 else
6378 {
4587b026
GV
6379 struct font_info *fontinf;
6380 XFontStruct *thisinfo = NULL;
ee78dc32
GV
6381
6382 BLOCK_INPUT;
4587b026
GV
6383 fontinf = w32_load_font (f, XSTRING (Fcar (cur))->data, 0);
6384 if (fontinf)
6385 thisinfo = (XFontStruct *)fontinf->font;
ee78dc32
GV
6386
6387 keeper = thisinfo && same_size_fonts (thisinfo, size_ref);
6388
fbd6baed 6389 w32_unload_font (FRAME_W32_DISPLAY_INFO (f), thisinfo);
ee78dc32
GV
6390
6391 UNBLOCK_INPUT;
6392 }
6393 if (keeper)
6394 list = Fcons (build_string (XSTRING (Fcar (cur))->data), list);
6395
6396 cur = Fcdr (cur);
6397 }
6398 list = Fnreverse (list);
6399 }
6400
6401 return list;
6402}
4587b026 6403#endif
ee78dc32 6404\f
33d52f9c
GV
6405DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6406 1, 1, 0,
6407 "Return a list of BDF fonts in DIR, suitable for appending to\n\
6408w32-bdf-filename-alist. Fonts which do not contain an xfld description\n\
6409will not be included in the list. DIR may be a list of directories.")
6410 (directory)
6411 Lisp_Object directory;
6412{
6413 Lisp_Object list = Qnil;
6414 struct gcpro gcpro1, gcpro2;
6415
6416 if (!CONSP (directory))
6417 return w32_find_bdf_fonts_in_dir (directory);
6418
6419 for ( ; CONSP (directory); directory = XCONS (directory)->cdr)
6420 {
6421 Lisp_Object pair[2];
6422 pair[0] = list;
6423 pair[1] = Qnil;
6424 GCPRO2 (directory, list);
6425 pair[1] = w32_find_bdf_fonts_in_dir( XCONS (directory)->car );
6426 list = Fnconc( 2, pair );
6427 UNGCPRO;
6428 }
6429 return list;
6430}
6431
6432/* Find BDF files in a specified directory. (use GCPRO when calling,
6433 as this calls lisp to get a directory listing). */
6434Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
6435{
6436 Lisp_Object filelist, list = Qnil;
6437 char fontname[100];
6438
6439 if (!STRINGP(directory))
6440 return Qnil;
6441
6442 filelist = Fdirectory_files (directory, Qt,
6443 build_string (".*\\.[bB][dD][fF]"), Qt);
6444
6445 for ( ; CONSP(filelist); filelist = XCONS (filelist)->cdr)
6446 {
6447 Lisp_Object filename = XCONS (filelist)->car;
6448 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
6449 store_in_alist (&list, build_string (fontname), filename);
6450 }
6451 return list;
6452}
6453
6454\f
ee78dc32
GV
6455DEFUN ("x-color-defined-p", Fx_color_defined_p, Sx_color_defined_p, 1, 2, 0,
6456 "Return non-nil if color COLOR is supported on frame FRAME.\n\
6457If FRAME is omitted or nil, use the selected frame.")
6458 (color, frame)
6459 Lisp_Object color, frame;
6460{
6461 COLORREF foo;
6462 FRAME_PTR f = check_x_frame (frame);
6463
6464 CHECK_STRING (color, 1);
6465
6466 if (defined_color (f, XSTRING (color)->data, &foo, 0))
6467 return Qt;
6468 else
6469 return Qnil;
6470}
6471
6472DEFUN ("x-color-values", Fx_color_values, Sx_color_values, 1, 2, 0,
6473 "Return a description of the color named COLOR on frame FRAME.\n\
6474The value is a list of integer RGB values--(RED GREEN BLUE).\n\
6475These values appear to range from 0 to 65280 or 65535, depending\n\
6476on the system; white is (65280 65280 65280) or (65535 65535 65535).\n\
6477If FRAME is omitted or nil, use the selected frame.")
6478 (color, frame)
6479 Lisp_Object color, frame;
6480{
6481 COLORREF foo;
6482 FRAME_PTR f = check_x_frame (frame);
6483
6484 CHECK_STRING (color, 1);
6485
6486 if (defined_color (f, XSTRING (color)->data, &foo, 0))
6487 {
6488 Lisp_Object rgb[3];
6489
1edf84e7
GV
6490 rgb[0] = make_number ((GetRValue (foo) << 8) | GetRValue (foo));
6491 rgb[1] = make_number ((GetGValue (foo) << 8) | GetGValue (foo));
6492 rgb[2] = make_number ((GetBValue (foo) << 8) | GetBValue (foo));
ee78dc32
GV
6493 return Flist (3, rgb);
6494 }
6495 else
6496 return Qnil;
6497}
6498
6499DEFUN ("x-display-color-p", Fx_display_color_p, Sx_display_color_p, 0, 1, 0,
6500 "Return t if the X display supports color.\n\
6501The optional argument DISPLAY specifies which display to ask about.\n\
6502DISPLAY should be either a frame or a display name (a string).\n\
6503If omitted or nil, that stands for the selected frame's display.")
6504 (display)
6505 Lisp_Object display;
6506{
fbd6baed 6507 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6508
6509 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6510 return Qnil;
6511
6512 return Qt;
6513}
6514
6515DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
6516 0, 1, 0,
6517 "Return t if the X display supports shades of gray.\n\
6518Note that color displays do support shades of gray.\n\
6519The optional argument DISPLAY specifies which display to ask about.\n\
6520DISPLAY should be either a frame or a display name (a string).\n\
6521If omitted or nil, that stands for the selected frame's display.")
6522 (display)
6523 Lisp_Object display;
6524{
fbd6baed 6525 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6526
6527 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6528 return Qnil;
6529
6530 return Qt;
6531}
6532
6533DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
6534 0, 1, 0,
6535 "Returns the width in pixels of the X display DISPLAY.\n\
6536The optional argument DISPLAY specifies which display to ask about.\n\
6537DISPLAY should be either a frame or a display name (a string).\n\
6538If omitted or nil, that stands for the selected frame's display.")
6539 (display)
6540 Lisp_Object display;
6541{
fbd6baed 6542 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6543
6544 return make_number (dpyinfo->width);
6545}
6546
6547DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
6548 Sx_display_pixel_height, 0, 1, 0,
6549 "Returns the height in pixels of the X display DISPLAY.\n\
6550The optional argument DISPLAY specifies which display to ask about.\n\
6551DISPLAY should be either a frame or a display name (a string).\n\
6552If omitted or nil, that stands for the selected frame's display.")
6553 (display)
6554 Lisp_Object display;
6555{
fbd6baed 6556 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6557
6558 return make_number (dpyinfo->height);
6559}
6560
6561DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
6562 0, 1, 0,
6563 "Returns the number of bitplanes of the display DISPLAY.\n\
6564The optional argument DISPLAY specifies which display to ask about.\n\
6565DISPLAY should be either a frame or a display name (a string).\n\
6566If omitted or nil, that stands for the selected frame's display.")
6567 (display)
6568 Lisp_Object display;
6569{
fbd6baed 6570 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6571
6572 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6573}
6574
6575DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
6576 0, 1, 0,
6577 "Returns the number of color cells of the display DISPLAY.\n\
6578The optional argument DISPLAY specifies which display to ask about.\n\
6579DISPLAY should be either a frame or a display name (a string).\n\
6580If omitted or nil, that stands for the selected frame's display.")
6581 (display)
6582 Lisp_Object display;
6583{
fbd6baed 6584 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6585 HDC hdc;
6586 int cap;
6587
5ac45f98
GV
6588 hdc = GetDC (dpyinfo->root_window);
6589 if (dpyinfo->has_palette)
6590 cap = GetDeviceCaps (hdc,SIZEPALETTE);
6591 else
6592 cap = GetDeviceCaps (hdc,NUMCOLORS);
ee78dc32
GV
6593
6594 ReleaseDC (dpyinfo->root_window, hdc);
6595
6596 return make_number (cap);
6597}
6598
6599DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6600 Sx_server_max_request_size,
6601 0, 1, 0,
6602 "Returns the maximum request size of the server of display DISPLAY.\n\
6603The optional argument DISPLAY specifies which display to ask about.\n\
6604DISPLAY should be either a frame or a display name (a string).\n\
6605If omitted or nil, that stands for the selected frame's display.")
6606 (display)
6607 Lisp_Object display;
6608{
fbd6baed 6609 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6610
6611 return make_number (1);
6612}
6613
6614DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
fbd6baed 6615 "Returns the vendor ID string of the W32 system (Microsoft).\n\
ee78dc32
GV
6616The optional argument DISPLAY specifies which display to ask about.\n\
6617DISPLAY should be either a frame or a display name (a string).\n\
6618If omitted or nil, that stands for the selected frame's display.")
6619 (display)
6620 Lisp_Object display;
6621{
fbd6baed 6622 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6623 char *vendor = "Microsoft Corp.";
6624
6625 if (! vendor) vendor = "";
6626 return build_string (vendor);
6627}
6628
6629DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
6630 "Returns the version numbers of the server of display DISPLAY.\n\
6631The value is a list of three integers: the major and minor\n\
6632version numbers, and the vendor-specific release\n\
6633number. See also the function `x-server-vendor'.\n\n\
6634The optional argument DISPLAY specifies which display to ask about.\n\
6635DISPLAY should be either a frame or a display name (a string).\n\
6636If omitted or nil, that stands for the selected frame's display.")
6637 (display)
6638 Lisp_Object display;
6639{
fbd6baed 6640 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32 6641
fbd6baed
GV
6642 return Fcons (make_number (w32_major_version),
6643 Fcons (make_number (w32_minor_version), Qnil));
ee78dc32
GV
6644}
6645
6646DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
6647 "Returns the number of screens on the server of display DISPLAY.\n\
6648The optional argument DISPLAY specifies which display to ask about.\n\
6649DISPLAY should be either a frame or a display name (a string).\n\
6650If omitted or nil, that stands for the selected frame's display.")
6651 (display)
6652 Lisp_Object display;
6653{
fbd6baed 6654 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6655
6656 return make_number (1);
6657}
6658
6659DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
6660 "Returns the height in millimeters of the X display DISPLAY.\n\
6661The optional argument DISPLAY specifies which display to ask about.\n\
6662DISPLAY should be either a frame or a display name (a string).\n\
6663If omitted or nil, that stands for the selected frame's display.")
6664 (display)
6665 Lisp_Object display;
6666{
fbd6baed 6667 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6668 HDC hdc;
6669 int cap;
6670
5ac45f98 6671 hdc = GetDC (dpyinfo->root_window);
3c190163 6672
ee78dc32 6673 cap = GetDeviceCaps (hdc, VERTSIZE);
3c190163 6674
ee78dc32
GV
6675 ReleaseDC (dpyinfo->root_window, hdc);
6676
6677 return make_number (cap);
6678}
6679
6680DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
6681 "Returns the width in millimeters of the X display DISPLAY.\n\
6682The optional argument DISPLAY specifies which display to ask about.\n\
6683DISPLAY should be either a frame or a display name (a string).\n\
6684If omitted or nil, that stands for the selected frame's display.")
6685 (display)
6686 Lisp_Object display;
6687{
fbd6baed 6688 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6689
6690 HDC hdc;
6691 int cap;
6692
5ac45f98 6693 hdc = GetDC (dpyinfo->root_window);
3c190163 6694
ee78dc32 6695 cap = GetDeviceCaps (hdc, HORZSIZE);
3c190163 6696
ee78dc32
GV
6697 ReleaseDC (dpyinfo->root_window, hdc);
6698
6699 return make_number (cap);
6700}
6701
6702DEFUN ("x-display-backing-store", Fx_display_backing_store,
6703 Sx_display_backing_store, 0, 1, 0,
6704 "Returns an indication of whether display DISPLAY does backing store.\n\
6705The value may be `always', `when-mapped', or `not-useful'.\n\
6706The optional argument DISPLAY specifies which display to ask about.\n\
6707DISPLAY should be either a frame or a display name (a string).\n\
6708If omitted or nil, that stands for the selected frame's display.")
6709 (display)
6710 Lisp_Object display;
6711{
6712 return intern ("not-useful");
6713}
6714
6715DEFUN ("x-display-visual-class", Fx_display_visual_class,
6716 Sx_display_visual_class, 0, 1, 0,
6717 "Returns the visual class of the display DISPLAY.\n\
6718The value is one of the symbols `static-gray', `gray-scale',\n\
6719`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
6720The optional argument DISPLAY specifies which display to ask about.\n\
6721DISPLAY should be either a frame or a display name (a string).\n\
6722If omitted or nil, that stands for the selected frame's display.")
6723 (display)
6724 Lisp_Object display;
6725{
fbd6baed 6726 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6727
6728#if 0
6729 switch (dpyinfo->visual->class)
6730 {
6731 case StaticGray: return (intern ("static-gray"));
6732 case GrayScale: return (intern ("gray-scale"));
6733 case StaticColor: return (intern ("static-color"));
6734 case PseudoColor: return (intern ("pseudo-color"));
6735 case TrueColor: return (intern ("true-color"));
6736 case DirectColor: return (intern ("direct-color"));
6737 default:
6738 error ("Display has an unknown visual class");
6739 }
6740#endif
6741
6742 error ("Display has an unknown visual class");
6743}
6744
6745DEFUN ("x-display-save-under", Fx_display_save_under,
6746 Sx_display_save_under, 0, 1, 0,
6747 "Returns t if the display DISPLAY supports the save-under feature.\n\
6748The optional argument DISPLAY specifies which display to ask about.\n\
6749DISPLAY should be either a frame or a display name (a string).\n\
6750If omitted or nil, that stands for the selected frame's display.")
6751 (display)
6752 Lisp_Object display;
6753{
fbd6baed 6754 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6755
6756 return Qnil;
6757}
6758\f
6759int
6760x_pixel_width (f)
6761 register struct frame *f;
6762{
6763 return PIXEL_WIDTH (f);
6764}
6765
6766int
6767x_pixel_height (f)
6768 register struct frame *f;
6769{
6770 return PIXEL_HEIGHT (f);
6771}
6772
6773int
6774x_char_width (f)
6775 register struct frame *f;
6776{
fbd6baed 6777 return FONT_WIDTH (f->output_data.w32->font);
ee78dc32
GV
6778}
6779
6780int
6781x_char_height (f)
6782 register struct frame *f;
6783{
fbd6baed 6784 return f->output_data.w32->line_height;
ee78dc32
GV
6785}
6786
6787int
6788x_screen_planes (frame)
6789 Lisp_Object frame;
6790{
fbd6baed
GV
6791 return (FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes *
6792 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits);
ee78dc32
GV
6793}
6794\f
6795/* Return the display structure for the display named NAME.
6796 Open a new connection if necessary. */
6797
fbd6baed 6798struct w32_display_info *
ee78dc32
GV
6799x_display_info_for_name (name)
6800 Lisp_Object name;
6801{
6802 Lisp_Object names;
fbd6baed 6803 struct w32_display_info *dpyinfo;
ee78dc32
GV
6804
6805 CHECK_STRING (name, 0);
6806
fbd6baed 6807 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
ee78dc32
GV
6808 dpyinfo;
6809 dpyinfo = dpyinfo->next, names = XCONS (names)->cdr)
6810 {
6811 Lisp_Object tem;
6812 tem = Fstring_equal (XCONS (XCONS (names)->car)->car, name);
6813 if (!NILP (tem))
6814 return dpyinfo;
6815 }
6816
6817 /* Use this general default value to start with. */
6818 Vx_resource_name = Vinvocation_name;
6819
6820 validate_x_resource_name ();
6821
fbd6baed 6822 dpyinfo = w32_term_init (name, (unsigned char *)0,
ee78dc32
GV
6823 (char *) XSTRING (Vx_resource_name)->data);
6824
6825 if (dpyinfo == 0)
6826 error ("Cannot connect to server %s", XSTRING (name)->data);
6827
1edf84e7 6828 w32_in_use = 1;
ee78dc32
GV
6829 XSETFASTINT (Vwindow_system_version, 3);
6830
6831 return dpyinfo;
6832}
6833
6834DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
6835 1, 3, 0, "Open a connection to a server.\n\
6836DISPLAY is the name of the display to connect to.\n\
6837Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
6838If the optional third arg MUST-SUCCEED is non-nil,\n\
6839terminate Emacs if we can't open the connection.")
6840 (display, xrm_string, must_succeed)
6841 Lisp_Object display, xrm_string, must_succeed;
6842{
6843 unsigned int n_planes;
6844 unsigned char *xrm_option;
fbd6baed 6845 struct w32_display_info *dpyinfo;
ee78dc32
GV
6846
6847 CHECK_STRING (display, 0);
6848 if (! NILP (xrm_string))
6849 CHECK_STRING (xrm_string, 1);
6850
1edf84e7
GV
6851 if (! EQ (Vwindow_system, intern ("w32")))
6852 error ("Not using Microsoft Windows");
6853
5ac45f98
GV
6854 /* Allow color mapping to be defined externally; first look in user's
6855 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
6856 {
6857 Lisp_Object color_file;
6858 struct gcpro gcpro1;
6859
6860 color_file = build_string("~/rgb.txt");
6861
6862 GCPRO1 (color_file);
6863
6864 if (NILP (Ffile_readable_p (color_file)))
6865 color_file =
6866 Fexpand_file_name (build_string ("rgb.txt"),
6867 Fsymbol_value (intern ("data-directory")));
6868
fbd6baed 6869 Vw32_color_map = Fw32_load_color_file (color_file);
5ac45f98
GV
6870
6871 UNGCPRO;
6872 }
fbd6baed
GV
6873 if (NILP (Vw32_color_map))
6874 Vw32_color_map = Fw32_default_color_map ();
ee78dc32
GV
6875
6876 if (! NILP (xrm_string))
6877 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
6878 else
6879 xrm_option = (unsigned char *) 0;
6880
6881 /* Use this general default value to start with. */
5ac45f98
GV
6882 /* First remove .exe suffix from invocation-name - it looks ugly. */
6883 {
6884 char basename[ MAX_PATH ], *str;
6885
6886 strcpy (basename, XSTRING (Vinvocation_name)->data);
6887 str = strrchr (basename, '.');
6888 if (str) *str = 0;
6889 Vinvocation_name = build_string (basename);
6890 }
ee78dc32
GV
6891 Vx_resource_name = Vinvocation_name;
6892
6893 validate_x_resource_name ();
6894
6895 /* This is what opens the connection and sets x_current_display.
6896 This also initializes many symbols, such as those used for input. */
fbd6baed 6897 dpyinfo = w32_term_init (display, xrm_option,
ee78dc32
GV
6898 (char *) XSTRING (Vx_resource_name)->data);
6899
6900 if (dpyinfo == 0)
6901 {
6902 if (!NILP (must_succeed))
3c190163
GV
6903 fatal ("Cannot connect to server %s.\n",
6904 XSTRING (display)->data);
ee78dc32
GV
6905 else
6906 error ("Cannot connect to server %s", XSTRING (display)->data);
6907 }
6908
1edf84e7
GV
6909 w32_in_use = 1;
6910
ee78dc32
GV
6911 XSETFASTINT (Vwindow_system_version, 3);
6912 return Qnil;
6913}
6914
6915DEFUN ("x-close-connection", Fx_close_connection,
6916 Sx_close_connection, 1, 1, 0,
6917 "Close the connection to DISPLAY's server.\n\
6918For DISPLAY, specify either a frame or a display name (a string).\n\
6919If DISPLAY is nil, that stands for the selected frame's display.")
6920 (display)
6921 Lisp_Object display;
6922{
fbd6baed
GV
6923 struct w32_display_info *dpyinfo = check_x_display_info (display);
6924 struct w32_display_info *tail;
ee78dc32
GV
6925 int i;
6926
6927 if (dpyinfo->reference_count > 0)
6928 error ("Display still has frames on it");
6929
6930 BLOCK_INPUT;
6931 /* Free the fonts in the font table. */
6932 for (i = 0; i < dpyinfo->n_fonts; i++)
6933 {
6934 if (dpyinfo->font_table[i].name)
6935 free (dpyinfo->font_table[i].name);
6936 /* Don't free the full_name string;
6937 it is always shared with something else. */
fbd6baed 6938 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
ee78dc32
GV
6939 }
6940 x_destroy_all_bitmaps (dpyinfo);
6941
6942 x_delete_display (dpyinfo);
6943 UNBLOCK_INPUT;
6944
6945 return Qnil;
6946}
6947
6948DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
6949 "Return the list of display names that Emacs has connections to.")
6950 ()
6951{
6952 Lisp_Object tail, result;
6953
6954 result = Qnil;
fbd6baed 6955 for (tail = w32_display_name_list; ! NILP (tail); tail = XCONS (tail)->cdr)
ee78dc32
GV
6956 result = Fcons (XCONS (XCONS (tail)->car)->car, result);
6957
6958 return result;
6959}
6960
6961DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
6962 "If ON is non-nil, report errors as soon as the erring request is made.\n\
6963If ON is nil, allow buffering of requests.\n\
fbd6baed 6964This is a noop on W32 systems.\n\
ee78dc32
GV
6965The optional second argument DISPLAY specifies which display to act on.\n\
6966DISPLAY should be either a frame or a display name (a string).\n\
6967If DISPLAY is omitted or nil, that stands for the selected frame's display.")
6968 (on, display)
6969 Lisp_Object display, on;
6970{
fbd6baed 6971 struct w32_display_info *dpyinfo = check_x_display_info (display);
ee78dc32
GV
6972
6973 return Qnil;
6974}
6975
6976\f
fbd6baed 6977/* These are the w32 specialized functions */
ee78dc32 6978
fbd6baed
GV
6979DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
6980 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
ee78dc32
GV
6981 (frame)
6982 Lisp_Object frame;
6983{
6984 FRAME_PTR f = check_x_frame (frame);
6985 CHOOSEFONT cf;
6986 LOGFONT lf;
f46e6225
GV
6987 TEXTMETRIC tm;
6988 HDC hdc;
6989 HANDLE oldobj;
ee78dc32
GV
6990 char buf[100];
6991
6992 bzero (&cf, sizeof (cf));
f46e6225 6993 bzero (&lf, sizeof (lf));
ee78dc32
GV
6994
6995 cf.lStructSize = sizeof (cf);
fbd6baed 6996 cf.hwndOwner = FRAME_W32_WINDOW (f);
ee78dc32
GV
6997 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST | CF_SCREENFONTS;
6998 cf.lpLogFont = &lf;
6999
f46e6225
GV
7000 /* Initialize as much of the font details as we can from the current
7001 default font. */
7002 hdc = GetDC (FRAME_W32_WINDOW (f));
7003 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
7004 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
7005 if (GetTextMetrics (hdc, &tm))
7006 {
7007 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
7008 lf.lfWeight = tm.tmWeight;
7009 lf.lfItalic = tm.tmItalic;
7010 lf.lfUnderline = tm.tmUnderlined;
7011 lf.lfStrikeOut = tm.tmStruckOut;
7012 lf.lfPitchAndFamily = tm.tmPitchAndFamily;
7013 lf.lfCharSet = tm.tmCharSet;
7014 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
7015 }
7016 SelectObject (hdc, oldobj);
7017 ReleaseDC (FRAME_W32_WINDOW(f), hdc);
7018
fbd6baed 7019 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100))
3c190163 7020 return Qnil;
ee78dc32
GV
7021
7022 return build_string (buf);
7023}
7024
1edf84e7
GV
7025DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
7026 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
7027Some useful values for command are 0xf030 to maximise frame (0xf020\n\
7028to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
7029to activate the menubar for keyboard access. 0xf140 activates the\n\
7030screen saver if defined.\n\
7031\n\
7032If optional parameter FRAME is not specified, use selected frame.")
7033 (command, frame)
7034 Lisp_Object command, frame;
7035{
7036 WPARAM code;
7037 FRAME_PTR f = check_x_frame (frame);
7038
7039 CHECK_NUMBER (command, 0);
7040
ce6059da 7041 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
1edf84e7
GV
7042
7043 return Qnil;
7044}
7045
55dcfc15
AI
7046DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
7047 "Get Windows to perform OPERATION on DOCUMENT.\n\
7048This is a wrapper around the ShellExecute system function, which\n\
7049invokes the application registered to handle OPERATION for DOCUMENT.\n\
7050OPERATION is typically \"open\", \"print\" or \"explore\", and DOCUMENT\n\
7051is typically the name of a document file or URL, but can also be a\n\
7052program executable to run or a directory to open in the Windows Explorer.\n\
7053\n\
7054If DOCUMENT is a program executable, PARAMETERS can be a list of command\n\
7055line parameters, but otherwise should be nil.\n\
7056\n\
7057SHOW-FLAG can be used to control whether the invoked application is hidden\n\
7058or minimized. If SHOw-FLAG is nil, the application is displayed normally,\n\
7059otherwise it is an integer representing a ShowWindow flag:\n\
7060\n\
7061 0 - start hidden\n\
7062 1 - start normally\n\
7063 3 - start maximized\n\
7064 6 - start minimized")
7065 (operation, document, parameters, show_flag)
7066 Lisp_Object operation, document, parameters, show_flag;
7067{
7068 Lisp_Object current_dir;
7069
7070 CHECK_STRING (operation, 0);
7071 CHECK_STRING (document, 0);
7072
7073 /* Encode filename and current directory. */
7074 current_dir = ENCODE_FILE (current_buffer->directory);
7075 document = ENCODE_FILE (document);
7076 if ((int) ShellExecute (NULL,
7077 XSTRING (operation)->data,
7078 XSTRING (document)->data,
7079 (STRINGP (parameters) ?
7080 XSTRING (parameters)->data : NULL),
7081 XSTRING (current_dir)->data,
7082 (INTEGERP (show_flag) ?
7083 XINT (show_flag) : SW_SHOWDEFAULT))
7084 > 32)
7085 return Qt;
7086 error ("ShellExecute failed");
7087}
7088
ccc2d29c
GV
7089/* Lookup virtual keycode from string representing the name of a
7090 non-ascii keystroke into the corresponding virtual key, using
7091 lispy_function_keys. */
7092static int
7093lookup_vk_code (char *key)
7094{
7095 int i;
7096
7097 for (i = 0; i < 256; i++)
7098 if (lispy_function_keys[i] != 0
7099 && strcmp (lispy_function_keys[i], key) == 0)
7100 return i;
7101
7102 return -1;
7103}
7104
7105/* Convert a one-element vector style key sequence to a hot key
7106 definition. */
7107static int
7108w32_parse_hot_key (key)
7109 Lisp_Object key;
7110{
7111 /* Copied from Fdefine_key and store_in_keymap. */
7112 register Lisp_Object c;
7113 int vk_code;
7114 int lisp_modifiers;
7115 int w32_modifiers;
7116 struct gcpro gcpro1;
7117
7118 CHECK_VECTOR (key, 0);
7119
7120 if (XFASTINT (Flength (key)) != 1)
7121 return Qnil;
7122
7123 GCPRO1 (key);
7124
7125 c = Faref (key, make_number (0));
7126
7127 if (CONSP (c) && lucid_event_type_list_p (c))
7128 c = Fevent_convert_list (c);
7129
7130 UNGCPRO;
7131
7132 if (! INTEGERP (c) && ! SYMBOLP (c))
7133 error ("Key definition is invalid");
7134
7135 /* Work out the base key and the modifiers. */
7136 if (SYMBOLP (c))
7137 {
7138 c = parse_modifiers (c);
7139 lisp_modifiers = Fcar (Fcdr (c));
7140 c = Fcar (c);
7141 if (!SYMBOLP (c))
7142 abort ();
7143 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
7144 }
7145 else if (INTEGERP (c))
7146 {
7147 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
7148 /* Many ascii characters are their own virtual key code. */
7149 vk_code = XINT (c) & CHARACTERBITS;
7150 }
7151
7152 if (vk_code < 0 || vk_code > 255)
7153 return Qnil;
7154
7155 if ((lisp_modifiers & meta_modifier) != 0
7156 && !NILP (Vw32_alt_is_meta))
7157 lisp_modifiers |= alt_modifier;
7158
7159 /* Convert lisp modifiers to Windows hot-key form. */
7160 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
7161 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
7162 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
7163 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
7164
7165 return HOTKEY (vk_code, w32_modifiers);
7166}
7167
7168DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
7169 "Register KEY as a hot-key combination.\n\
7170Certain key combinations like Alt-Tab are reserved for system use on\n\
7171Windows, and therefore are normally intercepted by the system. However,\n\
7172most of these key combinations can be received by registering them as\n\
7173hot-keys, overriding their special meaning.\n\
7174\n\
7175KEY must be a one element key definition in vector form that would be\n\
7176acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
7177modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
7178is always interpreted as the Windows modifier keys.\n\
7179\n\
7180The return value is the hotkey-id if registered, otherwise nil.")
7181 (key)
7182 Lisp_Object key;
7183{
7184 key = w32_parse_hot_key (key);
7185
7186 if (NILP (Fmemq (key, w32_grabbed_keys)))
7187 {
7188 /* Reuse an empty slot if possible. */
7189 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
7190
7191 /* Safe to add new key to list, even if we have focus. */
7192 if (NILP (item))
7193 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
7194 else
7195 XCAR (item) = key;
7196
7197 /* Notify input thread about new hot-key definition, so that it
7198 takes effect without needing to switch focus. */
7199 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
7200 (WPARAM) key, 0);
7201 }
7202
7203 return key;
7204}
7205
7206DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
7207 "Unregister HOTKEY as a hot-key combination.")
7208 (key)
7209 Lisp_Object key;
7210{
7211 Lisp_Object item;
7212
7213 if (!INTEGERP (key))
7214 key = w32_parse_hot_key (key);
7215
7216 item = Fmemq (key, w32_grabbed_keys);
7217
7218 if (!NILP (item))
7219 {
7220 /* Notify input thread about hot-key definition being removed, so
7221 that it takes effect without needing focus switch. */
7222 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
7223 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
7224 {
7225 MSG msg;
7226 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
7227 }
7228 return Qt;
7229 }
7230 return Qnil;
7231}
7232
7233DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
7234 "Return list of registered hot-key IDs.")
7235 ()
7236{
7237 return Fcopy_sequence (w32_grabbed_keys);
7238}
7239
7240DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
7241 "Convert hot-key ID to a lisp key combination.")
7242 (hotkeyid)
7243 Lisp_Object hotkeyid;
7244{
7245 int vk_code, w32_modifiers;
7246 Lisp_Object key;
7247
7248 CHECK_NUMBER (hotkeyid, 0);
7249
7250 vk_code = HOTKEY_VK_CODE (hotkeyid);
7251 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
7252
7253 if (lispy_function_keys[vk_code])
7254 key = intern (lispy_function_keys[vk_code]);
7255 else
7256 key = make_number (vk_code);
7257
7258 key = Fcons (key, Qnil);
7259 if (w32_modifiers & MOD_SHIFT)
3ef68e6b 7260 key = Fcons (Qshift, key);
ccc2d29c 7261 if (w32_modifiers & MOD_CONTROL)
3ef68e6b 7262 key = Fcons (Qctrl, key);
ccc2d29c 7263 if (w32_modifiers & MOD_ALT)
3ef68e6b 7264 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
ccc2d29c 7265 if (w32_modifiers & MOD_WIN)
3ef68e6b 7266 key = Fcons (Qhyper, key);
ccc2d29c
GV
7267
7268 return key;
7269}
adcc3809
GV
7270
7271DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
7272 "Toggle the state of the lock key KEY.\n\
7273KEY can be `capslock', `kp-numlock', or `scroll'.\n\
7274If the optional parameter NEW-STATE is a number, then the state of KEY\n\
7275is set to off if the low bit of NEW-STATE is zero, otherwise on.")
7276 (key, new_state)
7277 Lisp_Object key, new_state;
7278{
7279 int vk_code;
7280 int cur_state;
7281
7282 if (EQ (key, intern ("capslock")))
7283 vk_code = VK_CAPITAL;
7284 else if (EQ (key, intern ("kp-numlock")))
7285 vk_code = VK_NUMLOCK;
7286 else if (EQ (key, intern ("scroll")))
7287 vk_code = VK_SCROLL;
7288 else
7289 return Qnil;
7290
7291 if (!dwWindowsThreadId)
7292 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
7293
7294 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
7295 (WPARAM) vk_code, (LPARAM) new_state))
7296 {
7297 MSG msg;
7298 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
7299 return make_number (msg.wParam);
7300 }
7301 return Qnil;
7302}
ee78dc32 7303\f
fbd6baed 7304syms_of_w32fns ()
ee78dc32 7305{
1edf84e7
GV
7306 /* This is zero if not using MS-Windows. */
7307 w32_in_use = 0;
7308
ee78dc32
GV
7309 /* The section below is built by the lisp expression at the top of the file,
7310 just above where these variables are declared. */
7311 /*&&& init symbols here &&&*/
7312 Qauto_raise = intern ("auto-raise");
7313 staticpro (&Qauto_raise);
7314 Qauto_lower = intern ("auto-lower");
7315 staticpro (&Qauto_lower);
7316 Qbackground_color = intern ("background-color");
7317 staticpro (&Qbackground_color);
7318 Qbar = intern ("bar");
7319 staticpro (&Qbar);
7320 Qborder_color = intern ("border-color");
7321 staticpro (&Qborder_color);
7322 Qborder_width = intern ("border-width");
7323 staticpro (&Qborder_width);
7324 Qbox = intern ("box");
7325 staticpro (&Qbox);
7326 Qcursor_color = intern ("cursor-color");
7327 staticpro (&Qcursor_color);
7328 Qcursor_type = intern ("cursor-type");
7329 staticpro (&Qcursor_type);
ee78dc32
GV
7330 Qforeground_color = intern ("foreground-color");
7331 staticpro (&Qforeground_color);
7332 Qgeometry = intern ("geometry");
7333 staticpro (&Qgeometry);
7334 Qicon_left = intern ("icon-left");
7335 staticpro (&Qicon_left);
7336 Qicon_top = intern ("icon-top");
7337 staticpro (&Qicon_top);
7338 Qicon_type = intern ("icon-type");
7339 staticpro (&Qicon_type);
7340 Qicon_name = intern ("icon-name");
7341 staticpro (&Qicon_name);
7342 Qinternal_border_width = intern ("internal-border-width");
7343 staticpro (&Qinternal_border_width);
7344 Qleft = intern ("left");
7345 staticpro (&Qleft);
1026b400
RS
7346 Qright = intern ("right");
7347 staticpro (&Qright);
ee78dc32
GV
7348 Qmouse_color = intern ("mouse-color");
7349 staticpro (&Qmouse_color);
7350 Qnone = intern ("none");
7351 staticpro (&Qnone);
7352 Qparent_id = intern ("parent-id");
7353 staticpro (&Qparent_id);
7354 Qscroll_bar_width = intern ("scroll-bar-width");
7355 staticpro (&Qscroll_bar_width);
7356 Qsuppress_icon = intern ("suppress-icon");
7357 staticpro (&Qsuppress_icon);
7358 Qtop = intern ("top");
7359 staticpro (&Qtop);
7360 Qundefined_color = intern ("undefined-color");
7361 staticpro (&Qundefined_color);
7362 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
7363 staticpro (&Qvertical_scroll_bars);
7364 Qvisibility = intern ("visibility");
7365 staticpro (&Qvisibility);
7366 Qwindow_id = intern ("window-id");
7367 staticpro (&Qwindow_id);
7368 Qx_frame_parameter = intern ("x-frame-parameter");
7369 staticpro (&Qx_frame_parameter);
7370 Qx_resource_name = intern ("x-resource-name");
7371 staticpro (&Qx_resource_name);
7372 Quser_position = intern ("user-position");
7373 staticpro (&Quser_position);
7374 Quser_size = intern ("user-size");
7375 staticpro (&Quser_size);
7376 Qdisplay = intern ("display");
7377 staticpro (&Qdisplay);
7378 /* This is the end of symbol initialization. */
7379
adcc3809
GV
7380 Qhyper = intern ("hyper");
7381 staticpro (&Qhyper);
7382 Qsuper = intern ("super");
7383 staticpro (&Qsuper);
7384 Qmeta = intern ("meta");
7385 staticpro (&Qmeta);
7386 Qalt = intern ("alt");
7387 staticpro (&Qalt);
7388 Qctrl = intern ("ctrl");
7389 staticpro (&Qctrl);
7390 Qcontrol = intern ("control");
7391 staticpro (&Qcontrol);
7392 Qshift = intern ("shift");
7393 staticpro (&Qshift);
7394
4b817373
RS
7395 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
7396 staticpro (&Qface_set_after_frame_default);
7397
ee78dc32
GV
7398 Fput (Qundefined_color, Qerror_conditions,
7399 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
7400 Fput (Qundefined_color, Qerror_message,
7401 build_string ("Undefined color"));
7402
ccc2d29c
GV
7403 staticpro (&w32_grabbed_keys);
7404 w32_grabbed_keys = Qnil;
7405
fbd6baed 7406 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
ccc2d29c 7407 "An array of color name mappings for windows.");
fbd6baed 7408 Vw32_color_map = Qnil;
ee78dc32 7409
fbd6baed 7410 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
da36a4d6
GV
7411 "Non-nil if alt key presses are passed on to Windows.\n\
7412When non-nil, for example, alt pressed and released and then space will\n\
7413open the System menu. When nil, Emacs silently swallows alt key events.");
fbd6baed 7414 Vw32_pass_alt_to_system = Qnil;
da36a4d6 7415
fbd6baed 7416 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
8c205c63
RS
7417 "Non-nil if the alt key is to be considered the same as the meta key.\n\
7418When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
fbd6baed 7419 Vw32_alt_is_meta = Qt;
8c205c63 7420
7d081355
AI
7421 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
7422 "If non-zero, the virtual key code for an alternative quit key.");
7423 XSETINT (Vw32_quit_key, 0);
7424
ccc2d29c
GV
7425 DEFVAR_LISP ("w32-pass-lwindow-to-system",
7426 &Vw32_pass_lwindow_to_system,
7427 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
7428When non-nil, the Start menu is opened by tapping the key.");
7429 Vw32_pass_lwindow_to_system = Qt;
7430
7431 DEFVAR_LISP ("w32-pass-rwindow-to-system",
7432 &Vw32_pass_rwindow_to_system,
7433 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
7434When non-nil, the Start menu is opened by tapping the key.");
7435 Vw32_pass_rwindow_to_system = Qt;
7436
adcc3809
GV
7437 DEFVAR_INT ("w32-phantom-key-code",
7438 &Vw32_phantom_key_code,
7439 "Virtual key code used to generate \"phantom\" key presses.\n\
7440Value is a number between 0 and 255.\n\
7441\n\
7442Phantom key presses are generated in order to stop the system from\n\
7443acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
7444`w32-pass-rwindow-to-system' is nil.");
ce6059da
AI
7445 /* Although 255 is technically not a valid key code, it works and
7446 means that this hack won't interfere with any real key code. */
7447 Vw32_phantom_key_code = 255;
adcc3809 7448
ccc2d29c
GV
7449 DEFVAR_LISP ("w32-enable-num-lock",
7450 &Vw32_enable_num_lock,
7451 "Non-nil if Num Lock should act normally.\n\
7452Set to nil to see Num Lock as the key `kp-numlock'.");
7453 Vw32_enable_num_lock = Qt;
7454
7455 DEFVAR_LISP ("w32-enable-caps-lock",
7456 &Vw32_enable_caps_lock,
7457 "Non-nil if Caps Lock should act normally.\n\
7458Set to nil to see Caps Lock as the key `capslock'.");
7459 Vw32_enable_caps_lock = Qt;
7460
7461 DEFVAR_LISP ("w32-scroll-lock-modifier",
7462 &Vw32_scroll_lock_modifier,
7463 "Modifier to use for the Scroll Lock on state.\n\
7464The value can be hyper, super, meta, alt, control or shift for the\n\
7465respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
7466Any other value will cause the key to be ignored.");
7467 Vw32_scroll_lock_modifier = Qt;
7468
7469 DEFVAR_LISP ("w32-lwindow-modifier",
7470 &Vw32_lwindow_modifier,
7471 "Modifier to use for the left \"Windows\" key.\n\
7472The value can be hyper, super, meta, alt, control or shift for the\n\
7473respective modifier, or nil to appear as the key `lwindow'.\n\
7474Any other value will cause the key to be ignored.");
7475 Vw32_lwindow_modifier = Qnil;
7476
7477 DEFVAR_LISP ("w32-rwindow-modifier",
7478 &Vw32_rwindow_modifier,
7479 "Modifier to use for the right \"Windows\" key.\n\
7480The value can be hyper, super, meta, alt, control or shift for the\n\
7481respective modifier, or nil to appear as the key `rwindow'.\n\
7482Any other value will cause the key to be ignored.");
7483 Vw32_rwindow_modifier = Qnil;
7484
7485 DEFVAR_LISP ("w32-apps-modifier",
7486 &Vw32_apps_modifier,
7487 "Modifier to use for the \"Apps\" key.\n\
7488The value can be hyper, super, meta, alt, control or shift for the\n\
7489respective modifier, or nil to appear as the key `apps'.\n\
7490Any other value will cause the key to be ignored.");
7491 Vw32_apps_modifier = Qnil;
da36a4d6 7492
fbd6baed 7493 DEFVAR_LISP ("w32-enable-italics", &Vw32_enable_italics,
5ac45f98 7494 "Non-nil enables selection of artificially italicized fonts.");
fbd6baed 7495 Vw32_enable_italics = Qnil;
5ac45f98 7496
fbd6baed 7497 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
5ac45f98 7498 "Non-nil enables Windows palette management to map colors exactly.");
fbd6baed 7499 Vw32_enable_palette = Qt;
5ac45f98 7500
fbd6baed
GV
7501 DEFVAR_INT ("w32-mouse-button-tolerance",
7502 &Vw32_mouse_button_tolerance,
5ac45f98
GV
7503 "Analogue of double click interval for faking middle mouse events.\n\
7504The value is the minimum time in milliseconds that must elapse between\n\
7505left/right button down events before they are considered distinct events.\n\
7506If both mouse buttons are depressed within this interval, a middle mouse\n\
7507button down event is generated instead.");
fbd6baed 7508 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
5ac45f98 7509
fbd6baed
GV
7510 DEFVAR_INT ("w32-mouse-move-interval",
7511 &Vw32_mouse_move_interval,
84fb1139
KH
7512 "Minimum interval between mouse move events.\n\
7513The value is the minimum time in milliseconds that must elapse between\n\
7514successive mouse move (or scroll bar drag) events before they are\n\
7515reported as lisp events.");
247be837 7516 XSETINT (Vw32_mouse_move_interval, 0);
84fb1139 7517
ee78dc32
GV
7518 init_x_parm_symbols ();
7519
7520 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
fbd6baed 7521 "List of directories to search for bitmap files for w32.");
ee78dc32
GV
7522 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
7523
7524 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
7525 "The shape of the pointer when over text.\n\
7526Changing the value does not affect existing frames\n\
7527unless you set the mouse color.");
7528 Vx_pointer_shape = Qnil;
7529
7530 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
7531 "The name Emacs uses to look up resources; for internal use only.\n\
7532`x-get-resource' uses this as the first component of the instance name\n\
7533when requesting resource values.\n\
7534Emacs initially sets `x-resource-name' to the name under which Emacs\n\
7535was invoked, or to the value specified with the `-name' or `-rn'\n\
7536switches, if present.");
7537 Vx_resource_name = Qnil;
7538
7539 Vx_nontext_pointer_shape = Qnil;
7540
7541 Vx_mode_pointer_shape = Qnil;
7542
7543 DEFVAR_INT ("x-sensitive-text-pointer-shape",
7544 &Vx_sensitive_text_pointer_shape,
7545 "The shape of the pointer when over mouse-sensitive text.\n\
7546This variable takes effect when you create a new frame\n\
7547or when you set the mouse color.");
7548 Vx_sensitive_text_pointer_shape = Qnil;
7549
7550 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
7551 "A string indicating the foreground color of the cursor box.");
7552 Vx_cursor_fore_pixel = Qnil;
7553
7554 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
7555 "Non-nil if no window manager is in use.\n\
7556Emacs doesn't try to figure this out; this is always nil\n\
7557unless you set it to something else.");
7558 /* We don't have any way to find this out, so set it to nil
7559 and maybe the user would like to set it to t. */
7560 Vx_no_window_manager = Qnil;
7561
4587b026
GV
7562 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
7563 &Vx_pixel_size_width_font_regexp,
7564 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
7565\n\
7566Since Emacs gets width of a font matching with this regexp from\n\
7567PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
7568such a font. This is especially effective for such large fonts as\n\
7569Chinese, Japanese, and Korean.");
7570 Vx_pixel_size_width_font_regexp = Qnil;
7571
33d52f9c
GV
7572 DEFVAR_LISP ("w32-bdf-filename-alist",
7573 &Vw32_bdf_filename_alist,
7574 "List of bdf fonts and their corresponding filenames.");
7575 Vw32_bdf_filename_alist = Qnil;
7576
1075afa9
GV
7577 DEFVAR_BOOL ("w32-strict-fontnames",
7578 &w32_strict_fontnames,
7579 "Non-nil means only use fonts that are exact matches for those requested.\n\
7580Default is nil, which allows old fontnames that are not XLFD compliant,\n\
7581and allows third-party CJK display to work by specifying false charset\n\
7582fields to trick Emacs into translating to Big5, SJIS etc.\n\
7583Setting this to t will prevent wrong fonts being selected when\n\
7584fontsets are automatically created.");
7585 w32_strict_fontnames = 0;
7586
c0611964
AI
7587 DEFVAR_BOOL ("w32-strict-painting",
7588 &w32_strict_painting,
7589 "Non-nil means use strict rules for repainting frames.\n\
7590Set this to nil to get the old behaviour for repainting; this should\n\
7591only be necessary if the default setting causes problems.");
7592 w32_strict_painting = 1;
7593
f46e6225
GV
7594 DEFVAR_LISP ("w32-system-coding-system",
7595 &Vw32_system_coding_system,
7596 "Coding system used by Windows system functions, such as for font names.");
7597 Vw32_system_coding_system = Qnil;
7598
ee78dc32
GV
7599 defsubr (&Sx_get_resource);
7600 defsubr (&Sx_list_fonts);
7601 defsubr (&Sx_display_color_p);
7602 defsubr (&Sx_display_grayscale_p);
7603 defsubr (&Sx_color_defined_p);
7604 defsubr (&Sx_color_values);
7605 defsubr (&Sx_server_max_request_size);
7606 defsubr (&Sx_server_vendor);
7607 defsubr (&Sx_server_version);
7608 defsubr (&Sx_display_pixel_width);
7609 defsubr (&Sx_display_pixel_height);
7610 defsubr (&Sx_display_mm_width);
7611 defsubr (&Sx_display_mm_height);
7612 defsubr (&Sx_display_screens);
7613 defsubr (&Sx_display_planes);
7614 defsubr (&Sx_display_color_cells);
7615 defsubr (&Sx_display_visual_class);
7616 defsubr (&Sx_display_backing_store);
7617 defsubr (&Sx_display_save_under);
7618 defsubr (&Sx_parse_geometry);
7619 defsubr (&Sx_create_frame);
ee78dc32
GV
7620 defsubr (&Sx_open_connection);
7621 defsubr (&Sx_close_connection);
7622 defsubr (&Sx_display_list);
7623 defsubr (&Sx_synchronize);
7624
fbd6baed 7625 /* W32 specific functions */
ee78dc32 7626
1edf84e7 7627 defsubr (&Sw32_focus_frame);
fbd6baed
GV
7628 defsubr (&Sw32_select_font);
7629 defsubr (&Sw32_define_rgb_color);
7630 defsubr (&Sw32_default_color_map);
7631 defsubr (&Sw32_load_color_file);
1edf84e7 7632 defsubr (&Sw32_send_sys_command);
55dcfc15 7633 defsubr (&Sw32_shell_execute);
ccc2d29c
GV
7634 defsubr (&Sw32_register_hot_key);
7635 defsubr (&Sw32_unregister_hot_key);
7636 defsubr (&Sw32_registered_hot_keys);
7637 defsubr (&Sw32_reconstruct_hot_key);
adcc3809 7638 defsubr (&Sw32_toggle_lock_key);
33d52f9c 7639 defsubr (&Sw32_find_bdf_fonts);
4587b026
GV
7640
7641 /* Setting callback functions for fontset handler. */
7642 get_font_info_func = w32_get_font_info;
7643 list_fonts_func = w32_list_fonts;
7644 load_font_func = w32_load_font;
7645 find_ccl_program_func = w32_find_ccl_program;
7646 query_font_func = w32_query_font;
7647 set_frame_fontset_func = x_set_font;
7648 check_window_system_func = check_w32;
ee78dc32
GV
7649}
7650
7651#undef abort
7652
7653void
fbd6baed 7654w32_abort()
ee78dc32 7655{
5ac45f98
GV
7656 int button;
7657 button = MessageBox (NULL,
7658 "A fatal error has occurred!\n\n"
7659 "Select Abort to exit, Retry to debug, Ignore to continue",
7660 "Emacs Abort Dialog",
7661 MB_ICONEXCLAMATION | MB_TASKMODAL
7662 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
7663 switch (button)
7664 {
7665 case IDRETRY:
7666 DebugBreak ();
7667 break;
7668 case IDIGNORE:
7669 break;
7670 case IDABORT:
7671 default:
7672 abort ();
7673 break;
7674 }
ee78dc32 7675}
d573caac 7676
83c75055
GV
7677/* For convenience when debugging. */
7678int
7679w32_last_error()
7680{
7681 return GetLastError ();
7682}