XEmacs 21.4.5 "Civil Service".
[chise/xemacs-chise.git.1] / src / device-msw.c
1 /* device functions for mswindows.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with: Not in FSF. */
23
24 /* Authorship:
25
26    Original authors: Jamie Zawinski and the FSF
27    Rewritten by Ben Wing and Chuck Thompson.
28    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
29    Print support added by Kirill Katsnelson, July 2000.
30 */
31
32
33 #include <config.h>
34 #include "lisp.h"
35
36 #include "console-msw.h"
37 #include "console-stream.h"
38 #include "objects-msw.h"
39 #include "events.h"
40 #include "faces.h"
41 #include "frame.h"
42 #include "sysdep.h"
43
44 #include <commdlg.h>
45
46 #if !(defined (CYGWIN) || defined(MINGW))
47 #include <objbase.h>    /* For CoInitialize */
48 #endif
49
50 /* win32 DDE management library globals */
51 #ifdef HAVE_DRAGNDROP
52 DWORD mswindows_dde_mlid;
53 int mswindows_dde_enable;
54 HSZ mswindows_dde_service;
55 HSZ mswindows_dde_topic_system;
56 HSZ mswindows_dde_item_open;
57 #endif
58
59 /* Control conversion of upper case file names to lower case.
60    nil means no, t means yes. */
61 Lisp_Object Vmswindows_downcase_file_names;
62
63 /* Control whether xemacs_stat() attempts to determine file type and link count
64    exactly, at the expense of slower operation.  Since true hard links
65    are supported on NTFS volumes, this is only relevant on NT.  */
66 Lisp_Object Vmswindows_get_true_file_attributes;
67
68 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
69 Lisp_Object Qdevmodep;
70
71 static Lisp_Object Q_allow_selection;
72 static Lisp_Object Q_allow_pages;
73 static Lisp_Object Q_selected_page_button;
74 static Lisp_Object Qselected_page_button;
75
76 static Lisp_Object allocate_devmode (DEVMODE* src_devmode, int do_copy,
77                                      char* src_name, struct device *d);
78
79 /************************************************************************/
80 /*                               helpers                                */
81 /************************************************************************/
82
83 static Lisp_Object
84 build_syscolor_string (int idx)
85 {
86   return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
87 }
88
89 static Lisp_Object
90 build_syscolor_cons (int index1, int index2)
91 {
92   Lisp_Object color1, color2;
93   struct gcpro gcpro1;
94   GCPRO1 (color1);
95   color1 = build_syscolor_string (index1);
96   color2 = build_syscolor_string (index2);
97   RETURN_UNGCPRO (Fcons (color1, color2));
98 }
99
100 static Lisp_Object
101 build_sysmetrics_cons (int index1, int index2)
102 {
103   return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
104                 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
105 }
106
107 static Lisp_Object
108 build_devicecaps_cons (HDC hdc, int index1, int index2)
109 {
110   return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
111                 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
112 }
113
114 \f
115 /************************************************************************/
116 /*                          display methods                             */
117 /************************************************************************/
118
119 static void
120 mswindows_init_device (struct device *d, Lisp_Object props)
121 {
122   WNDCLASSEX wc;
123   HDC hdc;
124
125   DEVICE_CLASS (d) = Qcolor;
126   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
127   init_baud_rate (d);
128   init_one_device (d);
129
130   d->device_data = xnew_and_zero (struct mswindows_device);
131   hdc = CreateCompatibleDC (NULL);
132   assert (hdc!=NULL);
133   DEVICE_MSWINDOWS_HCDC(d) = hdc;
134   DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
135   DEVICE_MSWINDOWS_UPDATE_TICK (d) = GetTickCount ();
136
137   /* Register the main window class */
138   wc.cbSize = sizeof (WNDCLASSEX);
139   wc.style = CS_OWNDC;  /* One DC per window */
140   wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
141   wc.cbClsExtra = 0;
142   wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
143   /* This must match whatever is passed to CreateWIndowEx, NULL is ok
144      for this. */
145   wc.hInstance = NULL;
146   wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS);
147   wc.hCursor = LoadCursor (NULL, IDC_ARROW);
148   /* Background brush is only used during sizing, when XEmacs cannot
149      take over */
150   wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
151   wc.lpszMenuName = NULL;
152
153   wc.lpszClassName = XEMACS_CLASS;
154   if (xLoadImageA) /* not in NT 3.5 */
155     wc.hIconSm = (HICON) xLoadImageA (GetModuleHandle (NULL), XEMACS_CLASS,
156                                       IMAGE_ICON, 16, 16, 0);
157   else
158     wc.hIconSm = 0;
159
160   if (xRegisterClassExA)  /* not in NT 3.5 */
161     xRegisterClassExA (&wc);
162   else
163     RegisterClassA ((WNDCLASS *) &wc.style);
164
165 #ifdef HAVE_WIDGETS
166   xzero (wc);
167   /* Register the main window class */
168   wc.cbSize = sizeof (WNDCLASSEX);
169   wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc;
170   wc.lpszClassName = XEMACS_CONTROL_CLASS;
171   wc.hInstance = NULL;
172   if (xRegisterClassExA)  /* not in NT 3.5 */
173     xRegisterClassExA (&wc);
174   else
175     RegisterClassA ((WNDCLASS *) &wc.style);
176 #endif
177
178 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
179   InitCommonControls ();
180 #endif
181 }
182
183 #ifdef HAVE_DRAGNDROP
184 static void
185 mswindows_init_dde ()
186 {
187   /* Initialize DDE management library and our related globals. We execute a
188    * dde Open("file") by simulating a drop, so this depends on dnd support. */
189 # if !(defined(CYGWIN) || defined(MINGW))
190   CoInitialize (NULL);
191 # endif
192
193   mswindows_dde_mlid = 0;
194   mswindows_dde_enable = 0;
195   DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
196                  APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
197                  CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS,
198                  0);
199
200   mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
201                                                  XEMACS_CLASS, 0);
202   mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
203                                                       SZDDESYS_TOPIC, 0);
204   mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
205                                                    TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
206   DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
207 }
208 #endif
209
210 void 
211 init_mswindows_very_early()
212 {
213 #ifdef HAVE_DRAGNDROP
214   /* Initializing dde when the device is created is too late - the
215      client will give up waiting.  Instead we initialize here and tell
216      the client we're too busy until the rest of initialization has
217      happened. */
218   mswindows_init_dde();
219 #endif
220 }
221
222 static void
223 mswindows_finish_init_device (struct device *d, Lisp_Object props)
224 {
225 #ifdef HAVE_DRAGNDROP
226   /* Tell pending clients we are ready. */
227   mswindows_dde_enable = 1;
228 #endif
229 }
230
231 static void
232 mswindows_delete_device (struct device *d)
233 {
234 #ifdef HAVE_DRAGNDROP
235   DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_UNREGISTER);
236   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_item_open);
237   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_topic_system);
238   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_service);
239   DdeUninitialize (mswindows_dde_mlid);
240
241 # if !(defined(CYGWIN) || defined(MINGW))
242   CoUninitialize ();
243 # endif
244 #endif
245
246   DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
247   xfree (d->device_data);
248 }
249
250 void
251 mswindows_get_workspace_coords (RECT *rc)
252 {
253   SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
254 }
255
256 static void
257 mswindows_mark_device (struct device *d)
258 {
259   mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
260 }
261
262 static Lisp_Object
263 mswindows_device_system_metrics (struct device *d,
264                                  enum device_metrics m)
265 {
266   const HDC hdc = DEVICE_MSWINDOWS_HCDC(d);
267
268   switch (m)
269     {
270     case DM_size_device:
271       return Fcons (make_int (GetDeviceCaps (hdc, HORZRES)),
272                     make_int (GetDeviceCaps (hdc, VERTRES)));
273       break;
274     case DM_device_dpi:
275       return Fcons (make_int (GetDeviceCaps (hdc, LOGPIXELSX)),
276                     make_int (GetDeviceCaps (hdc, LOGPIXELSY)));
277       break;
278     case DM_size_device_mm:
279       return Fcons (make_int (GetDeviceCaps (hdc, HORZSIZE)),
280                     make_int (GetDeviceCaps (hdc, VERTSIZE)));
281       break;
282     case DM_num_bit_planes:
283       /* this is what X means by bitplanes therefore we ought to be
284          consistent. num planes is always 1 under mswindows and
285          therefore useless */
286       return make_int (GetDeviceCaps (hdc, BITSPIXEL));
287       break;
288     case DM_num_color_cells:
289       /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
290          what should we return for a non-palette-based device? */
291       return make_int (GetDeviceCaps (hdc, SIZEPALETTE));
292       break;
293
294       /*** Colors ***/
295 #define FROB(met, fore, back)                           \
296     case DM_##met:                                      \
297       return build_syscolor_cons (fore, back);
298
299       FROB (color_default, COLOR_WINDOWTEXT, COLOR_WINDOW);
300       FROB (color_select, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
301       FROB (color_balloon, COLOR_INFOTEXT, COLOR_INFOBK);
302       FROB (color_3d_face, COLOR_BTNTEXT, COLOR_BTNFACE);
303       FROB (color_3d_light, COLOR_3DHILIGHT, COLOR_3DLIGHT);
304       FROB (color_3d_dark, COLOR_3DDKSHADOW, COLOR_3DSHADOW);
305       FROB (color_menu, COLOR_MENUTEXT, COLOR_MENU);
306       FROB (color_menu_highlight, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
307       FROB (color_menu_button, COLOR_MENUTEXT, COLOR_MENU);
308       FROB (color_menu_disabled, COLOR_GRAYTEXT, COLOR_MENU);
309       FROB (color_toolbar, COLOR_BTNTEXT, COLOR_BTNFACE);
310       FROB (color_scrollbar, COLOR_CAPTIONTEXT, COLOR_SCROLLBAR);
311       FROB (color_desktop, -1, COLOR_DESKTOP);
312       FROB (color_workspace, -1, COLOR_APPWORKSPACE);
313 #undef FROB
314
315       /*** Sizes ***/
316 #define FROB(met, index1, index2)                       \
317     case DM_##met:                                      \
318       return build_sysmetrics_cons (index1, index2);
319
320       FROB (size_cursor, SM_CXCURSOR, SM_CYCURSOR);
321       FROB (size_scrollbar, SM_CXVSCROLL, SM_CYHSCROLL);
322       FROB (size_menu, -1, SM_CYMENU);
323       FROB (size_icon, SM_CXICON, SM_CYICON);
324       FROB (size_icon_small, SM_CXSMICON, SM_CYSMICON);
325 #undef FROB
326
327     case DM_size_workspace:
328       {
329         RECT rc;
330         mswindows_get_workspace_coords (&rc);
331         return Fcons (make_int (rc.right - rc.left),
332                       make_int (rc.bottom - rc.top));
333       }
334
335     case DM_offset_workspace:
336       {
337         RECT rc;
338         mswindows_get_workspace_coords (&rc);
339         return Fcons (make_int (rc.left), make_int (rc.top));
340       }
341
342       /*
343         case DM_size_toolbar:
344         case DM_size_toolbar_button:
345         case DM_size_toolbar_border:
346       */
347
348       /*** Features ***/
349 #define FROB(met, index)                        \
350     case DM_##met:                              \
351       return make_int (GetSystemMetrics (index));
352
353       FROB (mouse_buttons, SM_CMOUSEBUTTONS);
354       FROB (swap_buttons, SM_SWAPBUTTON);
355       FROB (show_sounds, SM_SHOWSOUNDS);
356       FROB (slow_device, SM_SLOWMACHINE);
357       FROB (security, SM_SECURE);
358 #undef FROB
359
360     }
361
362   /* Do not know such property */
363   return Qunbound;
364 }
365
366 \f
367 /************************************************************************/
368 /*                          printer helpers                             */
369 /************************************************************************/
370
371 static void
372 signal_open_printer_error (struct device *d)
373 {
374   invalid_operation ("Failed to open printer", DEVICE_CONNECTION (d));
375 }
376
377
378 /* Helper function */
379 static int
380 msprinter_init_device_internal (struct device *d, char* printer_name)
381 {
382   DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
383
384   if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
385     {
386       DEVICE_MSPRINTER_HPRINTER (d) = NULL;
387       return 0;
388     }
389
390   DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
391                                        NULL, NULL);
392   if (DEVICE_MSPRINTER_HDC (d) == NULL)
393     return 0;
394
395   DEVICE_MSPRINTER_HCDC(d) =
396     CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
397
398   DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
399                       * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
400                       > 1) ? Qcolor : Qmono;
401   return 1;
402 }
403
404 static void
405 msprinter_delete_device_internal (struct device *d)
406 {
407   if (DEVICE_MSPRINTER_HPRINTER (d))
408     ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
409   if (DEVICE_MSPRINTER_HDC (d))
410     DeleteDC (DEVICE_MSPRINTER_HDC (d));
411   if (DEVICE_MSPRINTER_HCDC (d))
412     DeleteDC (DEVICE_MSPRINTER_HCDC (d));
413   if (DEVICE_MSPRINTER_NAME (d))
414     xfree (DEVICE_MSPRINTER_NAME (d));
415
416   DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
417 }
418
419 static int
420 msprinter_reinit_device (struct device *d, char* devname)
421 {
422   msprinter_delete_device_internal (d);
423   return msprinter_init_device_internal (d, devname);
424 }
425
426 Lisp_Object
427 msprinter_default_printer (void)
428 {
429   Extbyte name[666];
430   Bufbyte *nameint;
431
432   if (GetProfileString (XETEXT ("windows"), XETEXT ("device"), NULL, name,
433                         sizeof (name) / XETCHAR_SIZE) <= 0)
434     return Qnil;
435   EXTERNAL_TO_C_STRING (name, nameint, Qmswindows_tstr);
436
437   if (name[0] == '\0')
438     return Qnil;
439   strtok (name, ",");
440
441   return build_string (name);
442 }
443
444 \f
445 /************************************************************************/
446 /*                          printer methods                             */
447 /************************************************************************/
448
449 static void
450 msprinter_init_device (struct device *d, Lisp_Object props)
451 {
452   char* printer_name;
453   DEVMODE *pdm;
454   size_t dm_size;
455
456   d->device_data = xnew_and_zero (struct msprinter_device);
457
458   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
459   DEVICE_MSPRINTER_DEVMODE(d) = Qnil;
460
461   /* We do not use printer fon list as we do with the display
462      device. Rather, we allow GDI to pick the closest match to the
463      display font. */
464   DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
465
466   CHECK_STRING (DEVICE_CONNECTION (d));
467
468   TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
469                       C_STRING_ALLOCA, printer_name,
470                       Qmswindows_tstr);
471
472   if (!msprinter_init_device_internal (d, printer_name))
473     signal_open_printer_error (d);
474
475   /* Determine DEVMODE size and store the default DEVMODE */
476   dm_size = DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER (d),
477                                 printer_name, NULL, NULL, 0);
478   if (dm_size <= 0)
479     signal_open_printer_error (d);
480
481   pdm = (DEVMODE*) xmalloc (dm_size);
482   DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
483                       printer_name, pdm,
484                       NULL, DM_OUT_BUFFER);
485
486   assert (DEVMODE_SIZE (pdm) <= dm_size);
487
488   DEVICE_MSPRINTER_DEVMODE(d) =
489     allocate_devmode (pdm, 0, printer_name, d);
490
491 }
492
493 static void
494 msprinter_delete_device (struct device *d)
495 {
496   if (d->device_data)
497     {
498       msprinter_delete_device_internal (d);
499
500       /* Disassociate the selected devmode with the device */
501       if (!NILP (DEVICE_MSPRINTER_DEVMODE (d)))
502         {
503           XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d))->device = Qnil;
504           DEVICE_MSPRINTER_DEVMODE (d) = Qnil;
505         }
506
507       xfree (d->device_data);
508     }
509 }
510
511 static Lisp_Object
512 msprinter_device_system_metrics (struct device *d,
513                                  enum device_metrics m)
514 {
515   switch (m)
516     {
517       /* Device sizes - pixel and mm */
518 #define FROB(met, index1, index2)                       \
519     case DM_##met:                                      \
520       return build_devicecaps_cons                      \
521          (DEVICE_MSPRINTER_HDC(d), index1, index2);
522
523       FROB (size_device, PHYSICALWIDTH, PHYSICALHEIGHT);
524       FROB (size_device_mm, HORZSIZE, VERTSIZE);
525       FROB (size_workspace, HORZRES, VERTRES);
526       FROB (offset_workspace, PHYSICALOFFSETX, PHYSICALOFFSETY);
527       FROB (device_dpi, LOGPIXELSX, LOGPIXELSY);
528 #undef FROB
529
530     case DM_num_bit_planes:
531       /* this is what X means by bitplanes therefore we ought to be
532          consistent. num planes is always 1 under mswindows and
533          therefore useless */
534       return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
535
536     case DM_num_color_cells:    /* Printers are non-palette devices */
537     case DM_slow_device:        /* Animation would be a really bad idea */
538     case DM_security:           /* Not provided by windows */
539       return Qzero;
540     }
541
542   /* Do not know such property */
543   return Qunbound;
544 }
545
546 static void
547 msprinter_mark_device (struct device *d)
548 {
549   mark_object (DEVICE_MSPRINTER_FONTLIST (d));
550   mark_object (DEVICE_MSPRINTER_DEVMODE (d));
551 }
552
553 \f
554 /************************************************************************/
555 /*                      printer Lisp subroutines                        */
556 /************************************************************************/
557
558 static void
559 global_free_2_maybe (HGLOBAL hg1, HGLOBAL hg2)
560 {
561   if (hg1 != NULL)
562     GlobalFree (hg1);
563   if (hg2 != NULL)
564     GlobalFree (hg2);
565 }
566
567 static HGLOBAL
568 devmode_to_hglobal (Lisp_Devmode *ldm)
569 {
570   HGLOBAL hg = GlobalAlloc (GHND, XDEVMODE_SIZE (ldm));
571   memcpy (GlobalLock (hg), ldm->devmode, XDEVMODE_SIZE (ldm));
572   GlobalUnlock (hg);
573   return hg;
574 }
575
576 /* Returns 0 if the printer has been deleted due to a fatal I/O error,
577    1 otherwise. */
578 static int
579 sync_printer_with_devmode (struct device* d, DEVMODE* devmode_in,
580                            DEVMODE* devmode_out, char* devname)
581 {
582   /* Change connection if the device changed */
583   if (devname != NULL
584       && stricmp (devname, DEVICE_MSPRINTER_NAME(d)) != 0)
585     {
586       Lisp_Object new_connection = build_ext_string (devname, Qmswindows_tstr);
587       struct gcpro gcpro1;
588
589       GCPRO1 (new_connection);
590       DEVICE_CONNECTION (d) = Qnil;
591       if (!NILP (Ffind_device (new_connection, Qmsprinter)))
592         {
593           /* We are in trouble - second msprinter for the same device.
594              Nothing wrong on the Windows side, just forge a unique
595              connection name. Use the memory address of d as a unique
596              suffix. */
597           char* new_connext = alloca (strlen (devname + 11));
598           sprintf (new_connext, "%s:%X", devname, d->header.uid);
599           new_connection = build_ext_string (devname, Qmswindows_tstr);
600         }
601       DEVICE_CONNECTION (d) = new_connection;
602       UNGCPRO;
603
604       /* Reinitialize printer. The device can pop off in process */
605       if (!msprinter_reinit_device (d, devname))
606         {
607           /* Kaboom! */
608           delete_device_internal (d, 1, 0, 1);
609           return 0;
610         }
611     }
612
613   /* Apply the new devmode to the printer */
614   DocumentProperties (NULL,
615                       DEVICE_MSPRINTER_HPRINTER(d),
616                       DEVICE_MSPRINTER_NAME(d),
617                       devmode_out, devmode_in,
618                       DM_IN_BUFFER | DM_OUT_BUFFER);
619
620   /* #### ResetDC fails sometimes, Bill only knows why.
621      The solution below looks more like a workaround to me,
622      although it might be fine. --kkm */
623   if (ResetDC (DEVICE_MSPRINTER_HDC (d), devmode_out) == NULL)
624     {
625       DeleteDC (DEVICE_MSPRINTER_HDC (d));
626       DEVICE_MSPRINTER_HDC (d) =
627         CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode_out);
628     }
629
630   return 1;
631 }
632
633 static void
634 handle_devmode_changes (Lisp_Devmode *ldm, HGLOBAL hDevNames, HGLOBAL hDevMode)
635 {
636   DEVNAMES* devnames = (DEVNAMES*) GlobalLock (hDevNames);
637   char *new_name = devnames ? (char*)devnames + devnames->wDeviceOffset : NULL;
638   DEVMODE* devmode = (DEVMODE*) GlobalLock (hDevMode);
639
640   /* Size and name may have changed */
641   ldm->devmode = xrealloc (ldm->devmode, DEVMODE_SIZE (devmode));
642   if (new_name)
643     {
644       if (ldm->printer_name)
645         xfree (ldm->printer_name);
646       ldm->printer_name = xstrdup (new_name);
647     }
648
649   if (!NILP (ldm->device))
650     {
651       /* Apply the new devmode to the printer and get a compete one back */
652       struct device *d = XDEVICE (ldm->device);
653       if (!sync_printer_with_devmode (d, devmode, ldm->devmode, new_name))
654         {
655           global_free_2_maybe (hDevNames, hDevMode);
656           error ("Printer device initialization I/O error, device deleted.");
657         }
658     }
659   else
660     {
661       /* Just copy the devmode structure */
662       memcpy (ldm->devmode, devmode, DEVMODE_SIZE (devmode));
663     }
664 }
665
666 static void
667 ensure_not_printing (struct device *d)
668 {
669   if (!NILP (DEVICE_FRAME_LIST (d)))
670   {
671     Lisp_Object device;
672     XSETDEVICE (device, d);
673     invalid_operation ("Cannot change settings while print job is active",
674                        device);
675   }
676 }
677
678 static Lisp_Devmode *
679 decode_devmode (Lisp_Object dev)
680 {
681   if (DEVMODEP (dev))
682     return XDEVMODE (dev);
683   else
684     {
685       ensure_not_printing (XDEVICE (dev));
686       return XDEVMODE (DEVICE_MSPRINTER_DEVMODE (XDEVICE (dev)));
687     }
688 }
689
690 /*
691  * DEV can be either a printer or devmode
692  */
693 static Lisp_Object
694 print_dialog_worker (Lisp_Object dev, DWORD flags)
695 {
696   Lisp_Devmode *ldm = decode_devmode (dev);
697   PRINTDLG pd;
698
699   memset (&pd, 0, sizeof (pd));
700   pd.lStructSize = sizeof (pd);
701   pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
702   pd.hDevMode = devmode_to_hglobal (ldm);
703   pd.Flags = flags | PD_USEDEVMODECOPIESANDCOLLATE;
704   pd.nMinPage = 0;
705   pd.nMaxPage = 0xFFFF;
706
707   if (!PrintDlg (&pd))
708     {
709       global_free_2_maybe (pd.hDevNames, pd.hDevMode);
710       return Qnil;
711     }
712
713   handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
714
715   /* Finally, build the resulting plist */
716   {
717     Lisp_Object result = Qnil;
718     struct gcpro gcpro1;
719     GCPRO1 (result);
720
721     /* Do consing in reverse order.
722        Number of copies */
723     result = Fcons (Qcopies, Fcons (make_int (pd.nCopies), result));
724
725     /* Page range */
726     if (pd.Flags & PD_PAGENUMS)
727       {
728         result = Fcons (Qto_page, Fcons (make_int (pd.nToPage), result));
729         result = Fcons (Qfrom_page, Fcons (make_int (pd.nFromPage), result));
730         result = Fcons (Qselected_page_button, Fcons (Qpages, result));
731       }
732     else if (pd.Flags & PD_SELECTION)
733       result = Fcons (Qselected_page_button, Fcons (Qselection, result));
734     else
735       result = Fcons (Qselected_page_button, Fcons (Qall, result));
736
737     /* Device name */
738     result = Fcons (Qname, Fcons (build_ext_string (ldm->printer_name,
739                                                     Qmswindows_tstr),
740                                   result));
741     UNGCPRO;
742
743     global_free_2_maybe (pd.hDevNames, pd.hDevMode);
744     return result;
745   }
746 }
747
748 Lisp_Object
749 mswindows_handle_print_dialog_box (struct frame *f, Lisp_Object keys)
750 {
751   Lisp_Object device = Qunbound, settings = Qunbound;
752   DWORD flags = PD_NOSELECTION;
753
754   {
755     EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
756       {
757         if (EQ (key, Q_device))
758           {
759             device = wrap_device (decode_device (value));
760             CHECK_MSPRINTER_DEVICE (device);
761           }
762         else if (EQ (key, Q_printer_settings))
763           {
764             CHECK_DEVMODE (value);
765             settings = value;
766           }
767         else if (EQ (key, Q_allow_pages))
768           {
769             if (NILP (value))
770               flags |= PD_NOPAGENUMS;
771           }
772         else if (EQ (key, Q_allow_selection))
773           {
774             if (!NILP (value))
775               flags &= ~PD_NOSELECTION;
776           }
777         else if (EQ (key, Q_selected_page_button))
778           {
779             if (EQ (value, Qselection))
780               flags |= PD_SELECTION;
781             else if (EQ (value, Qpages))
782               flags |= PD_PAGENUMS;
783             else if (!EQ (value, Qall))
784               invalid_argument ("Invalid value for :selected-page-button",
785                                 value);
786           }
787         else
788           syntax_error ("Unrecognized print-dialog keyword", key);
789       }
790   }
791
792   if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
793       (!UNBOUNDP (device) && !UNBOUNDP (settings)))
794     syntax_error ("Exactly one of :device and :printer-settings must be given",
795                   keys);
796
797   return print_dialog_worker (!UNBOUNDP (device) ? device : settings, flags);
798 }
799
800 int
801 mswindows_get_default_margin (Lisp_Object prop)
802 {
803   if (EQ (prop, Qleft_margin)) return 1440;
804   if (EQ (prop, Qright_margin)) return 1440;
805   if (EQ (prop, Qtop_margin)) return 720;
806   if (EQ (prop, Qbottom_margin)) return 720;
807   abort ();
808   return 0;
809 }
810
811 static int
812 plist_get_margin (Lisp_Object plist, Lisp_Object prop)
813 {
814   Lisp_Object val =
815     Fplist_get (plist, prop, make_int (mswindows_get_default_margin (prop)));
816   if (!INTP (val))
817     invalid_argument ("Margin value must be an integer", val);
818
819   return MulDiv (XINT (val), 100, 144);
820 }
821
822 static Lisp_Object
823 plist_set_margin (Lisp_Object plist, Lisp_Object prop, int margin, int mm_p)
824 {
825   Lisp_Object val = make_int (MulDiv (margin, 144, mm_p ? 2450 : 100));
826   return Fcons (prop, Fcons (val, plist));
827 }
828
829 Lisp_Object
830 mswindows_handle_page_setup_dialog_box (struct frame *f, Lisp_Object keys)
831 {
832   Lisp_Object device = Qunbound, settings = Qunbound;
833   Lisp_Object plist = Qnil;
834
835   {
836     EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
837       {
838         if (EQ (key, Q_device))
839           {
840             device = wrap_device (decode_device (value));
841             CHECK_MSPRINTER_DEVICE (device);
842           }
843         else if (EQ (key, Q_printer_settings))
844           {
845             CHECK_DEVMODE (value);
846             settings = value;
847           }
848         else if (EQ (key, Q_properties))
849           {
850             CHECK_LIST (value);
851             plist = value;
852           }
853         else
854           syntax_error ("Unrecognized page-setup dialog keyword", key);
855       }
856   }
857
858   if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
859       (!UNBOUNDP (device) && !UNBOUNDP (settings)))
860     syntax_error ("Exactly one of :device and :printer-settings must be given",
861                   keys);
862
863   if (UNBOUNDP (device))
864     device = settings;
865
866   {
867     Lisp_Devmode *ldm = decode_devmode (device);
868     PAGESETUPDLG pd;
869
870     memset (&pd, 0, sizeof (pd));
871     pd.lStructSize = sizeof (pd);
872     pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
873     pd.Flags = PSD_MARGINS;
874     pd.rtMargin.left   = plist_get_margin (plist, Qleft_margin);
875     pd.rtMargin.top    = plist_get_margin (plist, Qtop_margin);
876     pd.rtMargin.right  = plist_get_margin (plist, Qright_margin);
877     pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin);
878     pd.hDevMode = devmode_to_hglobal (ldm);
879
880     if (!PageSetupDlg (&pd))
881       {
882         global_free_2_maybe (pd.hDevNames, pd.hDevMode);
883         return Qnil;
884       }
885
886     if (pd.hDevMode)
887       handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
888
889     /* Finally, build the resulting plist */
890     {
891       Lisp_Object result = Qnil;
892       int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
893       result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
894                                  mm_p);
895       result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
896                                  mm_p);
897       result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
898       result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
899       return result;
900     }
901   }
902 }
903
904 DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
905 Return the settings object currently used by DEVICE.
906 The object returned is not a copy, but rather a pointer to the
907 original one. Use `msprinter-settings-copy' to create a copy of it.
908 */
909         (device))
910 {
911   struct device *d = decode_device (device);
912   XSETDEVICE (device, d);
913   CHECK_MSPRINTER_DEVICE (device);
914   return DEVICE_MSPRINTER_DEVMODE (d);
915 }
916
917 DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
918 Select SETTINGS object into a DEVICE.
919 The settings from the settings object are immediately applied to the
920 printer, possibly changing even the target printer itself, and all
921 future changes are applied synchronously to the printer device and the
922 selected printer object, until a different settings object is selected
923 into the same printer.
924
925 A settings object can be selected to no more than one printer at a time.
926
927 If the supplied settings object is not specialized, it is specialized
928 for the printer immediately upon selection. The object can be
929 despecialized after it is unselected by calling the function
930 `msprinter-settings-despecialize'.
931
932 Return value is the previously selected settings object.
933 */
934         (device, settings))
935 {
936   Lisp_Devmode *ldm;
937   struct device *d = decode_device (device);
938
939   struct gcpro gcpro1;
940   GCPRO1 (settings);
941
942   XSETDEVICE (device, d);
943   CHECK_MSPRINTER_DEVICE (device);
944   CHECK_DEVMODE (settings);
945   ldm = XDEVMODE (settings);
946
947   if (!NILP (ldm->device))
948     invalid_operation ("The object is currently selected into a device",
949                        settings);
950
951   /* If the object being selected is de-specialized, then its
952      size is perhaps not enough to receive the new devmode. We can ask
953      for printer's devmode size here, because despecialized settings
954      cannot force switching to a different printer, as they supply no
955      printer name at all. */
956   if (ldm->printer_name == NULL)
957     {
958       size_t dm_size =
959         DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
960                             DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
961       if (dm_size <= 0)
962         invalid_operation ("Unable to specialize settings, printer error",
963                            device);
964
965       assert (XDEVMODE_SIZE (ldm) <= dm_size);
966       ldm->devmode = xrealloc (ldm->devmode, dm_size);
967     }
968
969   /* If we bail out on signal here, no damage is done, except that
970      the storage for the DEVMODE structure might be reallocated to
971      hold a larger one - not a big deal */
972   if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
973                                   ldm->printer_name))
974     error ("Printer device initialization I/O error, device deleted.");
975
976   if (ldm->printer_name == NULL)
977     ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
978
979   {
980     Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
981     ldm->device = device;
982     XDEVMODE (old_mode)->device = Qnil;
983     DEVICE_MSPRINTER_DEVMODE (d) = settings;
984     UNGCPRO;
985     return old_mode;
986   }
987 }
988
989 DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
990 Apply settings from a SETTINGS object to a 'msprinter DEVICE.
991 The settings from the settings object are immediately applied to the
992 printer, possibly changing even the target printer itself. The SETTING
993 object is not modified, unlike `msprinter-select-settings', and the
994 supplied object is not changed.  The changes are immediately recorded
995 into the settings object which is currently selected into the printer
996 device.
997
998 Return value is the currently selected settings object.
999 */
1000         (device, settings))
1001 {
1002   Lisp_Devmode *ldm_current, *ldm_new;
1003   struct device *d = decode_device (device);
1004
1005   struct gcpro gcpro1;
1006   GCPRO1 (settings);
1007
1008   XSETDEVICE (device, d);
1009   CHECK_MSPRINTER_DEVICE (device);
1010   CHECK_DEVMODE (settings);
1011   ldm_new = XDEVMODE (settings);
1012   ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
1013
1014   /* If the supplied devmode is not specialized, then the current
1015      devmode size will always be sufficient, as the printer does
1016      not change.  If it is specialized, we must reallocate the current
1017      devmode storage to match with the supplied one, as it has the right
1018      size for the new printer, if it is going to change.  The correct
1019      way is to use the largest of the two though, to keep the old
1020      contents unchanged in case of preliminary exit.
1021   */
1022   if (ldm_new->printer_name)
1023     ldm_current->devmode =
1024       (DEVMODE*) xrealloc (ldm_current->devmode,
1025                            max (XDEVMODE_SIZE (ldm_new),
1026                                 XDEVMODE_SIZE (ldm_current)));
1027
1028   if (!sync_printer_with_devmode (d, ldm_new->devmode,
1029                                   ldm_current->devmode,
1030                                   ldm_new->printer_name))
1031     error ("Printer device initialization I/O error, device deleted.");
1032
1033   if (ldm_new->printer_name != NULL)
1034     {
1035       xfree (ldm_current->printer_name);
1036       ldm_current->printer_name = xstrdup (ldm_new->printer_name);
1037     }
1038
1039   UNGCPRO;
1040   return DEVICE_MSPRINTER_DEVMODE (d);
1041 }
1042 \f
1043 /************************************************************************/
1044 /*                                devmode                               */
1045 /************************************************************************/
1046
1047 static void
1048 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1049                int escapeflag)
1050 {
1051   char buf[100];
1052   Lisp_Devmode *dm = XDEVMODE (obj);
1053   if (print_readably)
1054     error ("printing unreadable object #<msprinter-settings 0x%x>",
1055            dm->header.uid);
1056   write_c_string ("#<msprinter-settings", printcharfun);
1057   if (dm->printer_name)
1058     {
1059       write_c_string (" for \"", printcharfun);
1060       write_c_string (dm->printer_name, printcharfun);
1061       write_c_string ("\"", printcharfun);
1062     }
1063   if (!NILP (dm->device))
1064     {
1065       write_c_string (" (currently on ", printcharfun);
1066       print_internal (dm->device, printcharfun, 0);
1067       write_c_string (")", printcharfun);
1068     }
1069   sprintf (buf, " 0x%x>", dm->header.uid);
1070   write_c_string (buf, printcharfun);
1071 }
1072
1073 static void
1074 finalize_devmode (void *header, int for_disksave)
1075 {
1076   Lisp_Devmode *dm = (Lisp_Devmode *) header;
1077
1078   if (for_disksave)
1079     {
1080       Lisp_Object devmode;
1081       XSETDEVMODE (devmode, dm);
1082       invalid_operation
1083         ("Cannot dump XEmacs containing an msprinter-settings object",
1084          devmode);
1085     }
1086
1087   assert (NILP (dm->device));
1088
1089   if (dm->printer_name)
1090     xfree (dm->printer_name);
1091 }
1092
1093 static int
1094 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1095 {
1096   Lisp_Devmode *dm1 = XDEVMODE (obj1);
1097   Lisp_Devmode *dm2 = XDEVMODE (obj2);
1098
1099   if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1100     return 0;
1101   if (dm1->devmode == NULL)
1102     return 1;
1103   if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1104     return 0;
1105   if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1106     return 1;
1107   return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1108 }
1109
1110 static unsigned long
1111 hash_devmode (Lisp_Object obj, int depth)
1112 {
1113   Lisp_Devmode *dm = XDEVMODE (obj);
1114
1115   return HASH3 (XDEVMODE_SIZE (dm),
1116                 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1117                 : 0,
1118                 dm->printer_name ? string_hash (dm->printer_name) : 0);
1119 }
1120
1121 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1122                                0/*mark*/, print_devmode, finalize_devmode,
1123                                equal_devmode, hash_devmode, 0/*description*/,
1124                                Lisp_Devmode);
1125 static Lisp_Object
1126 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1127                   char* src_name, struct device *d)
1128 {
1129   Lisp_Devmode *dm;
1130   Lisp_Object ob;
1131
1132   dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1133
1134   if (d)
1135     XSETDEVICE (dm->device, d);
1136   else
1137     dm->device = Qnil;
1138
1139   dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1140
1141   if (src_devmode != NULL && do_copy)
1142     {
1143       dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1144       memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1145     }
1146   else
1147     {
1148       dm->devmode = src_devmode;
1149     }
1150
1151   XSETDEVMODE (ob, dm);
1152   return ob;
1153 }
1154
1155 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1156 Create and returns an exact copy of a printer settings object.
1157 */
1158        (settings))
1159 {
1160   Lisp_Devmode *dm;
1161
1162   CHECK_DEVMODE (settings);
1163   dm = XDEVMODE (settings);
1164
1165   return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1166 }
1167
1168 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1169 Erase printer-specific settings from a printer settings object.
1170 */
1171        (settings))
1172 {
1173   Lisp_Devmode *ldm;
1174   DEVMODE *dm;
1175
1176   CHECK_DEVMODE (settings);
1177   ldm = XDEVMODE (settings);
1178
1179   if (!NILP (ldm->device))
1180     invalid_operation ("The object is currently selected into a device",
1181                        settings);
1182
1183   dm = ldm->devmode;
1184
1185   /* #### TODO. Either remove references to device specific bins,
1186      paper sizes etc, or signal an error of they are present. */
1187
1188   dm->dmDriverExtra = 0;
1189   dm->dmDeviceName[0] = '\0';
1190
1191   if (ldm->printer_name)
1192     xfree (ldm->printer_name);
1193
1194   return Qnil;
1195 }
1196
1197 DEFUN ("mswindows-get-default-printer", Fmswindows_get_default_printer, 0, 0, 0, /*
1198 Return name of the default printer, as string, on nil if there is no default.
1199 */
1200        ())
1201 {
1202   return msprinter_default_printer ();
1203 }
1204
1205 static void
1206 signal_enum_printer_error (void)
1207 {
1208   invalid_operation ("Error enumerating printers", make_int (GetLastError ()));
1209 }
1210
1211 DEFUN ("mswindows-printer-list", Fmswindows_printer_list, 0, 0, 0, /*
1212 Return a list of string names of installed printers.
1213 If there is a default printer, it is returned as the first element of
1214 the list.  If there is no default printer, the first element of the
1215 list will be nil.  The rest of elements are guaranteed to have string
1216 values.  Return value is nil if there are no printers installed.
1217 */
1218        ())
1219 {
1220   int have_nt, ok;
1221   BYTE *data_buf, dummy_byte;
1222   size_t enum_entry_size;
1223   DWORD enum_flags, enum_level, bytes_needed, num_printers;
1224   struct gcpro gcpro1, gcpro2;
1225   Lisp_Object result = Qnil, def_printer = Qnil;
1226
1227   /* Determine OS flavor, to use the fastest enumeration method available */
1228   have_nt = !mswindows_windows9x_p ();
1229   enum_flags = PRINTER_ENUM_LOCAL | (have_nt ? PRINTER_ENUM_CONNECTIONS : 0);
1230   enum_level = have_nt ? 4 : 5;
1231   enum_entry_size = have_nt ? sizeof (PRINTER_INFO_4) : sizeof (PRINTER_INFO_5);
1232
1233   /* Allocate memory for printer enum structure */
1234   ok = EnumPrinters (enum_flags, NULL, enum_level, &dummy_byte, 1,
1235                      &bytes_needed, &num_printers);
1236   if (ok)
1237     /* No printers, if just 1 byte is enough */
1238     return Qnil;
1239
1240   if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1241     signal_enum_printer_error ();
1242
1243   data_buf = alloca (bytes_needed);
1244   ok = EnumPrinters (enum_flags, NULL, enum_level, data_buf, bytes_needed,
1245                      &bytes_needed, &num_printers);
1246   if (!ok)
1247     signal_enum_printer_error ();
1248
1249   if (num_printers == 0)
1250     /* Strange but... */
1251     return Qnil;
1252
1253   GCPRO2 (result, def_printer);
1254
1255   while (num_printers--)
1256     {
1257       LPCTSTR printer_name;
1258       if (have_nt)
1259         {
1260           PRINTER_INFO_4 *info = (PRINTER_INFO_4*) data_buf;
1261           printer_name = info->pPrinterName;
1262         }
1263       else
1264         {
1265           PRINTER_INFO_5 *info = (PRINTER_INFO_5*) data_buf;
1266           printer_name = info->pPrinterName;
1267         }
1268       data_buf += enum_entry_size;
1269
1270       result = Fcons (build_ext_string (printer_name, Qmswindows_tstr),
1271                       result);
1272     }
1273
1274   def_printer = msprinter_default_printer ();
1275   result = Fdelete (def_printer, result);
1276   result = Fcons (def_printer, result);
1277
1278   RETURN_UNGCPRO (result);
1279 }
1280
1281 \f
1282 /************************************************************************/
1283 /*                            initialization                            */
1284 /************************************************************************/
1285
1286 void
1287 syms_of_device_mswindows (void)
1288 {
1289   INIT_LRECORD_IMPLEMENTATION (devmode);
1290
1291   DEFSUBR (Fmsprinter_get_settings);
1292   DEFSUBR (Fmsprinter_select_settings);
1293   DEFSUBR (Fmsprinter_apply_settings);
1294   DEFSUBR (Fmsprinter_settings_copy);
1295   DEFSUBR (Fmsprinter_settings_despecialize);
1296   DEFSUBR (Fmswindows_get_default_printer);
1297   DEFSUBR (Fmswindows_printer_list);
1298
1299   DEFKEYWORD (Q_allow_selection);
1300   DEFKEYWORD (Q_allow_pages);
1301   DEFKEYWORD (Q_selected_page_button);
1302   DEFSYMBOL (Qselected_page_button);
1303
1304   DEFSYMBOL (Qinit_pre_mswindows_win);
1305   DEFSYMBOL (Qinit_post_mswindows_win);
1306 }
1307
1308 void
1309 console_type_create_device_mswindows (void)
1310 {
1311   CONSOLE_HAS_METHOD (mswindows, init_device);
1312   CONSOLE_HAS_METHOD (mswindows, finish_init_device);
1313   CONSOLE_HAS_METHOD (mswindows, mark_device);
1314   CONSOLE_HAS_METHOD (mswindows, delete_device);
1315   CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
1316   CONSOLE_IMPLEMENTATION_FLAGS (mswindows, XDEVIMPF_PIXEL_GEOMETRY);
1317
1318   CONSOLE_HAS_METHOD (msprinter, init_device);
1319   CONSOLE_HAS_METHOD (msprinter, mark_device);
1320   CONSOLE_HAS_METHOD (msprinter, delete_device);
1321   CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
1322   CONSOLE_IMPLEMENTATION_FLAGS (msprinter, (XDEVIMPF_PIXEL_GEOMETRY
1323                                             | XDEVIMPF_IS_A_PRINTER
1324                                             | XDEVIMPF_NO_AUTO_REDISPLAY
1325                                             | XDEVIMPF_DONT_PREEMPT_REDISPLAY
1326                                             | XDEVIMPF_FRAMELESS_OK));
1327 }
1328
1329
1330 void
1331 vars_of_device_mswindows (void)
1332 {
1333   DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
1334 Non-nil means convert all-upper case file names to lower case.
1335 This applies when performing completions and file name expansion.
1336 */ );
1337   Vmswindows_downcase_file_names = Qnil;
1338
1339   DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
1340 Non-nil means determine accurate link count in file-attributes.
1341 This option slows down file-attributes noticeably, so is disabled by
1342 default.  Note that it is only useful for files on NTFS volumes,
1343 where hard links are supported.
1344 */ );
1345   Vmswindows_get_true_file_attributes = Qnil;
1346 }