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