XEmacs 21.2.32 "Kastor & Polydeukes".
[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 */
30
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "console-msw.h"
36 #include "console-stream.h"
37 #include "objects-msw.h"
38 #include "events.h"
39 #include "faces.h"
40 #include "frame.h"
41 #include "sysdep.h"
42
43 #if (defined (__CYGWIN32__) || defined(__MINGW32__)) && \
44         CYGWIN_VERSION_DLL_MAJOR < 21
45 extern BOOL WINAPI DdeFreeStringHandle(DWORD,HSZ);
46 #else
47 #include <winspool.h>
48 #endif
49
50 #if !(defined (__CYGWIN32__) || defined(__MINGW32__))
51 # include <objbase.h>   /* For CoInitialize */
52 #endif
53
54 /* win32 DDE management library globals */
55 #ifdef HAVE_DRAGNDROP
56 DWORD mswindows_dde_mlid;
57 HSZ mswindows_dde_service;
58 HSZ mswindows_dde_topic_system;
59 HSZ mswindows_dde_item_open;
60 #endif
61
62 /* Control conversion of upper case file names to lower case.
63    nil means no, t means yes. */
64 Lisp_Object Vmswindows_downcase_file_names;
65
66 /* Control whether stat() attempts to determine file type and link count
67    exactly, at the expense of slower operation.  Since true hard links
68    are supported on NTFS volumes, this is only relevant on NT.  */
69 Lisp_Object Vmswindows_get_true_file_attributes;
70
71 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
72
73
74 /************************************************************************/
75 /*                               helpers                                */
76 /************************************************************************/
77
78 static Lisp_Object
79 build_syscolor_string (int idx)
80 {
81   return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
82 }
83
84 static Lisp_Object
85 build_syscolor_cons (int index1, int index2)
86 {
87   Lisp_Object color1, color2;
88   struct gcpro gcpro1;
89   GCPRO1 (color1);
90   color1 = build_syscolor_string (index1);
91   color2 = build_syscolor_string (index2);
92   RETURN_UNGCPRO (Fcons (color1, color2));
93 }
94
95 static Lisp_Object
96 build_sysmetrics_cons (int index1, int index2)
97 {
98   return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
99                 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
100 }
101
102 static Lisp_Object
103 build_devicecaps_cons (HDC hdc, int index1, int index2)
104 {
105   return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
106                 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
107 }
108
109
110 \f
111 /************************************************************************/
112 /*                          display methods                             */
113 /************************************************************************/
114
115 static void
116 mswindows_init_device (struct device *d, Lisp_Object props)
117 {
118   WNDCLASSEX wc;
119   HDC hdc;
120
121   DEVICE_CLASS (d) = Qcolor;
122   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
123   init_baud_rate (d);
124   init_one_device (d);
125
126   d->device_data = xnew_and_zero (struct mswindows_device);
127   hdc = CreateCompatibleDC (NULL);
128   assert (hdc!=NULL);
129   DEVICE_MSWINDOWS_LOGPIXELSX(d) =  GetDeviceCaps(hdc, LOGPIXELSX);
130   DEVICE_MSWINDOWS_LOGPIXELSY(d) =  GetDeviceCaps(hdc, LOGPIXELSY);
131   DEVICE_MSWINDOWS_PLANES(d) = GetDeviceCaps(hdc, PLANES);
132   /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
133      what should we return for a non-palette-based device? */
134   DEVICE_MSWINDOWS_CELLS(d) = GetDeviceCaps(hdc, SIZEPALETTE);
135   DEVICE_MSWINDOWS_HORZRES(d) = GetDeviceCaps(hdc, HORZRES);
136   DEVICE_MSWINDOWS_VERTRES(d) = GetDeviceCaps(hdc, VERTRES);
137   DEVICE_MSWINDOWS_HORZSIZE(d) = GetDeviceCaps(hdc, HORZSIZE);
138   DEVICE_MSWINDOWS_VERTSIZE(d) = GetDeviceCaps(hdc, VERTSIZE);
139   DEVICE_MSWINDOWS_BITSPIXEL(d) = GetDeviceCaps(hdc, BITSPIXEL);
140   DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
141   
142   DEVICE_MSWINDOWS_HCDC(d) = hdc;
143
144   /* Register the main window class */
145   wc.cbSize = sizeof (WNDCLASSEX);
146   wc.style = CS_OWNDC;  /* One DC per window */
147   wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
148   wc.cbClsExtra = 0;
149   wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
150   /* This must match whatever is passed to CreateWIndowEx, NULL is ok
151      for this. */
152   wc.hInstance = NULL;  
153   wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS);
154   wc.hCursor = LoadCursor (NULL, IDC_ARROW);
155   /* Background brush is only used during sizing, when XEmacs cannot
156      take over */
157   wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
158   wc.lpszMenuName = NULL;
159
160   wc.lpszClassName = XEMACS_CLASS;
161   wc.hIconSm = (HICON) LoadImage (GetModuleHandle (NULL), XEMACS_CLASS,
162                           IMAGE_ICON, 16, 16, 0);
163   RegisterClassEx (&wc);
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   RegisterClassEx (&wc);
173 #endif
174
175 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
176   InitCommonControls ();
177 #endif
178 }
179
180 static void
181 mswindows_finish_init_device (struct device *d, Lisp_Object props)
182 {
183   /* Initialize DDE management library and our related globals. We execute a
184    * dde Open("file") by simulating a drop, so this depends on dnd support. */
185 #ifdef HAVE_DRAGNDROP
186 # if !(defined(__CYGWIN32__) || defined(__MINGW32__))
187   CoInitialize (NULL);
188 # endif
189
190   mswindows_dde_mlid = 0;
191   DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
192                  APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
193                  CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS,
194                  0);
195   
196   mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
197                                                  XEMACS_CLASS, 0);
198   mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
199                                                       SZDDESYS_TOPIC, 0);
200   mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
201                                                    TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
202   DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
203 #endif
204 }
205
206 static void
207 mswindows_delete_device (struct device *d)
208 {
209 #ifdef HAVE_DRAGNDROP
210   DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_UNREGISTER);
211   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_item_open);
212   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_topic_system);
213   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_service);
214   DdeUninitialize (mswindows_dde_mlid);
215
216 # if !(defined(__CYGWIN32__) || defined(__MINGW32__))
217   CoUninitialize ();
218 # endif
219 #endif
220
221   DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
222   free (d->device_data);
223 }
224
225 void
226 msw_get_workspace_coords (RECT *rc)
227 {
228   SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
229 }
230
231 static void
232 mswindows_mark_device (struct device *d)
233 {
234   mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
235 }
236
237 static Lisp_Object
238 mswindows_device_system_metrics (struct device *d,
239                                  enum device_metrics m)
240 {
241   switch (m)
242     {
243     case DM_size_device:
244       return Fcons (make_int (DEVICE_MSWINDOWS_HORZRES(d)),
245                     make_int (DEVICE_MSWINDOWS_VERTRES(d)));
246       break;
247     case DM_device_dpi:
248       return Fcons (make_int (DEVICE_MSWINDOWS_LOGPIXELSX(d)),
249                     make_int (DEVICE_MSWINDOWS_LOGPIXELSY(d)));
250       break;
251     case DM_size_device_mm:
252       return Fcons (make_int (DEVICE_MSWINDOWS_HORZSIZE(d)),
253                     make_int (DEVICE_MSWINDOWS_VERTSIZE(d)));
254       break;
255     case DM_num_bit_planes:
256       /* this is what X means by bitplanes therefore we ought to be
257          consistent. num planes is always 1 under mswindows and
258          therefore useless */
259       return make_int (DEVICE_MSWINDOWS_BITSPIXEL(d));
260       break;
261     case DM_num_color_cells:
262       return make_int (DEVICE_MSWINDOWS_CELLS(d));
263       break;
264
265       /*** Colors ***/
266 #define FROB(met, fore, back)                           \
267     case DM_##met:                                      \
268       return build_syscolor_cons (fore, back);
269       
270       FROB (color_default, COLOR_WINDOWTEXT, COLOR_WINDOW);
271       FROB (color_select, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
272       FROB (color_balloon, COLOR_INFOTEXT, COLOR_INFOBK);
273       FROB (color_3d_face, COLOR_BTNTEXT, COLOR_BTNFACE);
274       FROB (color_3d_light, COLOR_3DHILIGHT, COLOR_3DLIGHT);
275       FROB (color_3d_dark, COLOR_3DDKSHADOW, COLOR_3DSHADOW);
276       FROB (color_menu, COLOR_MENUTEXT, COLOR_MENU);
277       FROB (color_menu_highlight, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
278       FROB (color_menu_button, COLOR_MENUTEXT, COLOR_MENU);
279       FROB (color_menu_disabled, COLOR_GRAYTEXT, COLOR_MENU);
280       FROB (color_toolbar, COLOR_BTNTEXT, COLOR_BTNFACE);
281       FROB (color_scrollbar, COLOR_CAPTIONTEXT, COLOR_SCROLLBAR);
282       FROB (color_desktop, -1, COLOR_DESKTOP);
283       FROB (color_workspace, -1, COLOR_APPWORKSPACE);
284 #undef FROB
285
286       /*** Sizes ***/
287 #define FROB(met, index1, index2)                       \
288     case DM_##met:                                      \
289       return build_sysmetrics_cons (index1, index2);
290
291       FROB (size_cursor, SM_CXCURSOR, SM_CYCURSOR);
292       FROB (size_scrollbar, SM_CXVSCROLL, SM_CYHSCROLL);
293       FROB (size_menu, -1, SM_CYMENU);
294       FROB (size_icon, SM_CXICON, SM_CYICON);
295       FROB (size_icon_small, SM_CXSMICON, SM_CYSMICON);
296 #undef FROB
297
298     case DM_size_workspace:
299       {
300         RECT rc;
301         msw_get_workspace_coords (&rc);
302         return Fcons (make_int (rc.right - rc.left),
303                       make_int (rc.bottom - rc.top));
304       }
305
306     case DM_offset_workspace:
307       {
308         RECT rc;
309         msw_get_workspace_coords (&rc);
310         return Fcons (make_int (rc.left), make_int (rc.top));
311       }
312
313       /*
314         case DM_size_toolbar:
315         case DM_size_toolbar_button:
316         case DM_size_toolbar_border:
317       */
318
319       /*** Features ***/
320 #define FROB(met, index)                        \
321     case DM_##met:                              \
322       return make_int (GetSystemMetrics (index));
323
324       FROB (mouse_buttons, SM_CMOUSEBUTTONS);
325       FROB (swap_buttons, SM_SWAPBUTTON);
326       FROB (show_sounds, SM_SHOWSOUNDS);
327       FROB (slow_device, SM_SLOWMACHINE);
328       FROB (security, SM_SECURE);
329 #undef FROB
330
331     }
332
333   /* Do not know such property */
334   return Qunbound;
335 }
336
337 static unsigned int
338 mswindows_device_implementation_flags (void)
339 {
340   return XDEVIMPF_PIXEL_GEOMETRY;
341 }
342
343 \f
344 /************************************************************************/
345 /*                          printer methods                             */
346 /************************************************************************/
347
348 static void
349 signal_open_printer_error (struct device *d)
350 {
351   signal_simple_error ("Failed to open printer", DEVICE_CONNECTION (d));
352 }
353
354 static void
355 msprinter_init_device (struct device *d, Lisp_Object props)
356 {
357   char* printer_name;
358
359   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
360
361   CHECK_STRING (DEVICE_CONNECTION (d));
362
363   TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
364                       C_STRING_ALLOCA, printer_name,
365                       Qctext);
366
367   d->device_data = xnew_and_zero (struct msprinter_device);
368
369   DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
370
371   if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
372     {
373       DEVICE_MSPRINTER_HPRINTER (d) = NULL;
374       signal_open_printer_error (d);
375     }
376
377   DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
378                                        NULL, NULL);
379   if (DEVICE_MSPRINTER_HDC (d) == NULL)
380     signal_open_printer_error (d);
381
382   DEVICE_MSPRINTER_HCDC(d) =
383     CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
384
385   /* Determinie DEVMODE size and store the default DEVMODE */
386   DEVICE_MSPRINTER_DEVMODE_SIZE(d) =
387     DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
388                         printer_name, NULL, NULL, 0);
389   if (DEVICE_MSPRINTER_DEVMODE_SIZE(d) <= 0)
390     signal_open_printer_error (d);
391
392   DEVICE_MSPRINTER_DEVMODE(d) =
393     (DEVMODE*) xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d));
394   DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
395                       printer_name, DEVICE_MSPRINTER_DEVMODE(d),
396                       NULL, DM_OUT_BUFFER);
397
398   /* We do not use printer fon list as we do with the display
399      device. Rather, we allow GDI to pick the closest match to the
400      display font. */
401   DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
402
403   DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
404                       * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
405                       > 1) ? Qcolor : Qmono;
406 }
407
408 static Lisp_Object
409 msprinter_device_system_metrics (struct device *d,
410                                  enum device_metrics m)
411 {
412   switch (m)
413     {
414       /* Device sizes - pixel and mm */
415 #define FROB(met, index1, index2)                       \
416     case DM_##met:                                      \
417       return build_devicecaps_cons                      \
418          (DEVICE_MSPRINTER_HDC(d), index1, index2);
419
420       FROB (size_device, PHYSICALWIDTH, PHYSICALHEIGHT);
421       FROB (size_device_mm, HORZSIZE, VERTSIZE);
422       FROB (size_workspace, HORZRES, VERTRES);
423       FROB (offset_workspace, PHYSICALOFFSETX, PHYSICALOFFSETY);
424       FROB (device_dpi, LOGPIXELSX, LOGPIXELSY);
425 #undef FROB
426
427     case DM_num_bit_planes:
428       /* this is what X means by bitplanes therefore we ought to be
429          consistent. num planes is always 1 under mswindows and
430          therefore useless */
431       return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
432
433     case DM_num_color_cells:    /* Prnters are non-palette devices */
434     case DM_slow_device:        /* Animation would be a really bad idea */
435     case DM_security:           /* Not provided by windows */
436       return Qzero;
437     }
438
439   /* Do not know such property */
440   return Qunbound;
441 }
442
443 static void
444 msprinter_delete_device (struct device *d)
445 {
446   if (d->device_data)
447     {
448       if (DEVICE_MSPRINTER_HPRINTER (d))
449         ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
450       if (DEVICE_MSPRINTER_HDC (d))
451         DeleteDC (DEVICE_MSPRINTER_HDC (d));
452       if (DEVICE_MSPRINTER_HCDC (d))
453         DeleteDC (DEVICE_MSPRINTER_HCDC (d));
454       if (DEVICE_MSPRINTER_NAME (d))
455         free (DEVICE_MSPRINTER_NAME (d));
456       if (DEVICE_MSPRINTER_DEVMODE (d))
457         free (DEVICE_MSPRINTER_DEVMODE (d));
458       if (DEVICE_MSPRINTER_DEVMODE_MIRROR (d))
459         free (DEVICE_MSPRINTER_DEVMODE_MIRROR (d));
460
461       free (d->device_data);
462     }
463 }
464
465 static void
466 msprinter_mark_device (struct device *d)
467 {
468   mark_object (DEVICE_MSPRINTER_FONTLIST (d));
469 }
470
471 static unsigned int
472 msprinter_device_implementation_flags (void)
473 {
474   return (  XDEVIMPF_PIXEL_GEOMETRY
475           | XDEVIMPF_IS_A_PRINTER
476           | XDEVIMPF_NO_AUTO_REDISPLAY
477           | XDEVIMPF_FRAMELESS_OK );
478 }
479
480 \f
481 /************************************************************************/
482 /*                      printer external functions                      */
483 /************************************************************************/
484
485 /* 
486  * Return a copy of default DEVMODE. The copy returned is in
487  * a static buffer which will be overwritten by next call.
488  */
489 DEVMODE*
490 msprinter_get_devmode_copy (struct device *d)
491 {
492   assert (DEVICE_MSPRINTER_P (d));
493
494   if (DEVICE_MSPRINTER_DEVMODE_MIRROR(d) == NULL)
495     DEVICE_MSPRINTER_DEVMODE_MIRROR(d) = 
496       (DEVMODE*) xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d));
497
498   memcpy (DEVICE_MSPRINTER_DEVMODE_MIRROR(d),
499           DEVICE_MSPRINTER_DEVMODE(d),
500           DEVICE_MSPRINTER_DEVMODE_SIZE(d));
501
502   return DEVICE_MSPRINTER_DEVMODE_MIRROR(d);
503 }
504
505 /*
506  * Apply settings from the DEVMODE. The settings are considered
507  * incremental to the default DEVMODE, so that changes in the
508  * passed structure supercede parameters of the printer.
509  *
510  * The passed structure is overwritten by the fuction call;
511  * complete printer settings are returned.
512  */
513 void
514 msprinter_apply_devmode (struct device *d, DEVMODE *devmode)
515 {
516   assert (DEVICE_MSPRINTER_P (d));
517
518   DocumentProperties (NULL,
519                       DEVICE_MSPRINTER_HPRINTER(d),
520                       DEVICE_MSPRINTER_NAME(d),
521                       devmode, devmode,
522                       DM_IN_BUFFER | DM_OUT_BUFFER);
523
524   /* #### ResetDC fails sometimes, Bill only know s why.
525      The solution below looks more like a workaround to me,
526      although it might be fine. --kkm */
527   if (ResetDC (DEVICE_MSPRINTER_HDC (d), devmode) == NULL)
528     {
529       DeleteDC (DEVICE_MSPRINTER_HDC (d));
530       DEVICE_MSPRINTER_HDC (d) =
531         CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode);
532     }
533 }
534
535 \f
536 /************************************************************************/
537 /*                            initialization                            */
538 /************************************************************************/
539
540 void
541 syms_of_device_mswindows (void)
542 {
543   defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win");
544   defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win");
545 }
546
547 void
548 console_type_create_device_mswindows (void)
549 {
550   CONSOLE_HAS_METHOD (mswindows, init_device);
551   CONSOLE_HAS_METHOD (mswindows, finish_init_device);
552   CONSOLE_HAS_METHOD (mswindows, mark_device);
553   CONSOLE_HAS_METHOD (mswindows, delete_device);
554   CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
555   CONSOLE_HAS_METHOD (mswindows, device_implementation_flags);
556
557   CONSOLE_HAS_METHOD (msprinter, init_device);
558   CONSOLE_HAS_METHOD (msprinter, mark_device);
559   CONSOLE_HAS_METHOD (msprinter, delete_device);
560   CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
561   CONSOLE_HAS_METHOD (msprinter, device_implementation_flags);
562 }
563
564
565 void
566 vars_of_device_mswindows (void)
567 {
568   DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
569 Non-nil means convert all-upper case file names to lower case.
570 This applies when performing completions and file name expansion.
571 */ );
572   Vmswindows_downcase_file_names = Qnil;
573
574   DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
575 Non-nil means determine accurate link count in file-attributes.
576 This option slows down file-attributes noticeably, so is disabled by
577 default.  Note that it is only useful for files on NTFS volumes,
578 where hard links are supported.
579 */ );
580   Vmswindows_get_true_file_attributes = Qnil;
581 }