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