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