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.
5 This file is part of XEmacs.
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
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
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. */
22 /* Synched up with: Not in FSF. */
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.
35 #include "console-msw.h"
36 #include "console-stream.h"
37 #include "objects-msw.h"
45 #if !(defined (CYGWIN) || defined(MINGW))
46 #include <objbase.h> /* For CoInitialize */
49 /* win32 DDE management library globals */
51 DWORD mswindows_dde_mlid;
52 HSZ mswindows_dde_service;
53 HSZ mswindows_dde_topic_system;
54 HSZ mswindows_dde_item_open;
57 /* Control conversion of upper case file names to lower case.
58 nil means no, t means yes. */
59 Lisp_Object Vmswindows_downcase_file_names;
61 /* Control whether xemacs_stat() attempts to determine file type and link count
62 exactly, at the expense of slower operation. Since true hard links
63 are supported on NTFS volumes, this is only relevant on NT. */
64 Lisp_Object Vmswindows_get_true_file_attributes;
66 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
67 Lisp_Object Qdevmodep;
69 static Lisp_Object allocate_devmode (DEVMODE* src_devmode, int do_copy,
70 char* src_name, struct device *d);
72 /************************************************************************/
74 /************************************************************************/
77 build_syscolor_string (int idx)
79 return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
83 build_syscolor_cons (int index1, int index2)
85 Lisp_Object color1, color2;
88 color1 = build_syscolor_string (index1);
89 color2 = build_syscolor_string (index2);
90 RETURN_UNGCPRO (Fcons (color1, color2));
94 build_sysmetrics_cons (int index1, int index2)
96 return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
97 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
101 build_devicecaps_cons (HDC hdc, int index1, int index2)
103 return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
104 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
108 /************************************************************************/
109 /* display methods */
110 /************************************************************************/
113 mswindows_init_device (struct device *d, Lisp_Object props)
118 DEVICE_CLASS (d) = Qcolor;
119 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
123 d->device_data = xnew_and_zero (struct mswindows_device);
124 hdc = CreateCompatibleDC (NULL);
126 DEVICE_MSWINDOWS_HCDC(d) = hdc;
127 DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
128 DEVICE_MSWINDOWS_UPDATE_TICK (d) = GetTickCount ();
130 /* Register the main window class */
131 wc.cbSize = sizeof (WNDCLASSEX);
132 wc.style = CS_OWNDC; /* One DC per window */
133 wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
135 wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
136 /* This must match whatever is passed to CreateWIndowEx, NULL is ok
139 wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS);
140 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
141 /* Background brush is only used during sizing, when XEmacs cannot
143 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
144 wc.lpszMenuName = NULL;
146 wc.lpszClassName = XEMACS_CLASS;
147 if (xLoadImageA) /* not in NT 3.5 */
148 wc.hIconSm = (HICON) xLoadImageA (GetModuleHandle (NULL), XEMACS_CLASS,
149 IMAGE_ICON, 16, 16, 0);
153 if (xRegisterClassExA) /* not in NT 3.5 */
154 xRegisterClassExA (&wc);
156 RegisterClassA ((WNDCLASS *) &wc.style);
160 /* Register the main window class */
161 wc.cbSize = sizeof (WNDCLASSEX);
162 wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc;
163 wc.lpszClassName = XEMACS_CONTROL_CLASS;
165 if (xRegisterClassExA) /* not in NT 3.5 */
166 xRegisterClassExA (&wc);
168 RegisterClassA ((WNDCLASS *) &wc.style);
171 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
172 InitCommonControls ();
177 mswindows_finish_init_device (struct device *d, Lisp_Object props)
179 /* Initialize DDE management library and our related globals. We execute a
180 * dde Open("file") by simulating a drop, so this depends on dnd support. */
181 #ifdef HAVE_DRAGNDROP
182 # if !(defined(CYGWIN) || defined(MINGW))
186 mswindows_dde_mlid = 0;
187 DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
188 APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
189 CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS,
192 mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
194 mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
196 mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
197 TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
198 DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
203 mswindows_delete_device (struct device *d)
205 #ifdef HAVE_DRAGNDROP
206 DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_UNREGISTER);
207 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_item_open);
208 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_topic_system);
209 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_service);
210 DdeUninitialize (mswindows_dde_mlid);
212 # if !(defined(CYGWIN) || defined(MINGW))
217 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
218 xfree (d->device_data);
222 mswindows_get_workspace_coords (RECT *rc)
224 SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
228 mswindows_mark_device (struct device *d)
230 mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
234 mswindows_device_system_metrics (struct device *d,
235 enum device_metrics m)
237 const HDC hdc = DEVICE_MSWINDOWS_HCDC(d);
242 return Fcons (make_int (GetDeviceCaps (hdc, HORZRES)),
243 make_int (GetDeviceCaps (hdc, VERTRES)));
246 return Fcons (make_int (GetDeviceCaps (hdc, LOGPIXELSX)),
247 make_int (GetDeviceCaps (hdc, LOGPIXELSY)));
249 case DM_size_device_mm:
250 return Fcons (make_int (GetDeviceCaps (hdc, HORZSIZE)),
251 make_int (GetDeviceCaps (hdc, VERTSIZE)));
253 case DM_num_bit_planes:
254 /* this is what X means by bitplanes therefore we ought to be
255 consistent. num planes is always 1 under mswindows and
257 return make_int (GetDeviceCaps (hdc, BITSPIXEL));
259 case DM_num_color_cells:
260 /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
261 what should we return for a non-palette-based device? */
262 return make_int (GetDeviceCaps (hdc, SIZEPALETTE));
266 #define FROB(met, fore, back) \
268 return build_syscolor_cons (fore, back);
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);
287 #define FROB(met, index1, index2) \
289 return build_sysmetrics_cons (index1, index2);
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);
298 case DM_size_workspace:
301 mswindows_get_workspace_coords (&rc);
302 return Fcons (make_int (rc.right - rc.left),
303 make_int (rc.bottom - rc.top));
306 case DM_offset_workspace:
309 mswindows_get_workspace_coords (&rc);
310 return Fcons (make_int (rc.left), make_int (rc.top));
314 case DM_size_toolbar:
315 case DM_size_toolbar_button:
316 case DM_size_toolbar_border:
320 #define FROB(met, index) \
322 return make_int (GetSystemMetrics (index));
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);
333 /* Do not know such property */
338 mswindows_device_implementation_flags (void)
340 return XDEVIMPF_PIXEL_GEOMETRY;
344 /************************************************************************/
345 /* printer helpers */
346 /************************************************************************/
349 signal_open_printer_error (struct device *d)
351 invalid_operation ("Failed to open printer", DEVICE_CONNECTION (d));
355 /* Helper function */
357 msprinter_init_device_internal (struct device *d, char* printer_name)
359 DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
361 if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
363 DEVICE_MSPRINTER_HPRINTER (d) = NULL;
367 DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
369 if (DEVICE_MSPRINTER_HDC (d) == NULL)
372 DEVICE_MSPRINTER_HCDC(d) =
373 CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
375 DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
376 * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
377 > 1) ? Qcolor : Qmono;
382 msprinter_delete_device_internal (struct device *d)
384 if (DEVICE_MSPRINTER_HPRINTER (d))
385 ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
386 if (DEVICE_MSPRINTER_HDC (d))
387 DeleteDC (DEVICE_MSPRINTER_HDC (d));
388 if (DEVICE_MSPRINTER_HCDC (d))
389 DeleteDC (DEVICE_MSPRINTER_HCDC (d));
390 if (DEVICE_MSPRINTER_NAME (d))
391 xfree (DEVICE_MSPRINTER_NAME (d));
393 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
397 msprinter_reinit_device (struct device *d, char* devname)
399 msprinter_delete_device_internal (d);
400 return msprinter_init_device_internal (d, devname);
404 msprinter_default_printer (void)
409 if (GetProfileString (XETEXT ("windows"), XETEXT ("device"), NULL, name,
410 sizeof (name) / XETCHAR_SIZE) <= 0)
412 EXTERNAL_TO_C_STRING (name, nameint, Qmswindows_tstr);
418 return build_string (name);
422 /************************************************************************/
423 /* printer methods */
424 /************************************************************************/
427 msprinter_init_device (struct device *d, Lisp_Object props)
433 d->device_data = xnew_and_zero (struct msprinter_device);
435 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
436 DEVICE_MSPRINTER_DEVMODE(d) = Qnil;
438 /* We do not use printer fon list as we do with the display
439 device. Rather, we allow GDI to pick the closest match to the
441 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
443 CHECK_STRING (DEVICE_CONNECTION (d));
445 TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
446 C_STRING_ALLOCA, printer_name,
449 if (!msprinter_init_device_internal (d, printer_name))
450 signal_open_printer_error (d);
452 /* Determine DEVMODE size and store the default DEVMODE */
453 dm_size = DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER (d),
454 printer_name, NULL, NULL, 0);
456 signal_open_printer_error (d);
458 pdm = (DEVMODE*) xmalloc (dm_size);
459 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
461 NULL, DM_OUT_BUFFER);
463 assert (DEVMODE_SIZE (pdm) <= dm_size);
465 DEVICE_MSPRINTER_DEVMODE(d) =
466 allocate_devmode (pdm, 0, printer_name, d);
471 msprinter_delete_device (struct device *d)
475 msprinter_delete_device_internal (d);
477 /* Disassociate the selected devmode with the device */
478 if (!NILP (DEVICE_MSPRINTER_DEVMODE (d)))
480 XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d))->device = Qnil;
481 DEVICE_MSPRINTER_DEVMODE (d) = Qnil;
484 xfree (d->device_data);
489 msprinter_device_system_metrics (struct device *d,
490 enum device_metrics m)
494 /* Device sizes - pixel and mm */
495 #define FROB(met, index1, index2) \
497 return build_devicecaps_cons \
498 (DEVICE_MSPRINTER_HDC(d), index1, index2);
500 FROB (size_device, PHYSICALWIDTH, PHYSICALHEIGHT);
501 FROB (size_device_mm, HORZSIZE, VERTSIZE);
502 FROB (size_workspace, HORZRES, VERTRES);
503 FROB (offset_workspace, PHYSICALOFFSETX, PHYSICALOFFSETY);
504 FROB (device_dpi, LOGPIXELSX, LOGPIXELSY);
507 case DM_num_bit_planes:
508 /* this is what X means by bitplanes therefore we ought to be
509 consistent. num planes is always 1 under mswindows and
511 return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
513 case DM_num_color_cells: /* Printers are non-palette devices */
514 case DM_slow_device: /* Animation would be a really bad idea */
515 case DM_security: /* Not provided by windows */
519 /* Do not know such property */
524 msprinter_mark_device (struct device *d)
526 mark_object (DEVICE_MSPRINTER_FONTLIST (d));
527 mark_object (DEVICE_MSPRINTER_DEVMODE (d));
531 msprinter_device_implementation_flags (void)
533 return ( XDEVIMPF_PIXEL_GEOMETRY
534 | XDEVIMPF_IS_A_PRINTER
535 | XDEVIMPF_NO_AUTO_REDISPLAY
536 | XDEVIMPF_FRAMELESS_OK );
539 /************************************************************************/
540 /* printer Lisp subroutines */
541 /************************************************************************/
544 global_free_2_maybe (HGLOBAL hg1, HGLOBAL hg2)
553 devmode_to_hglobal (Lisp_Devmode *ldm)
555 HGLOBAL hg = GlobalAlloc (GHND, XDEVMODE_SIZE (ldm));
556 memcpy (GlobalLock (hg), ldm->devmode, XDEVMODE_SIZE (ldm));
561 /* Returns 0 if the printer has been deleted due to a fatal I/O error,
564 sync_printer_with_devmode (struct device* d, DEVMODE* devmode_in,
565 DEVMODE* devmode_out, char* devname)
567 /* Change connection if the device changed */
569 && stricmp (devname, DEVICE_MSPRINTER_NAME(d)) != 0)
571 Lisp_Object new_connection = build_ext_string (devname, Qmswindows_tstr);
574 GCPRO1 (new_connection);
575 DEVICE_CONNECTION (d) = Qnil;
576 if (!NILP (Ffind_device (new_connection, Qmsprinter)))
578 /* We are in trouble - second msprinter for the same device.
579 Nothing wrong on the Windows side, just forge a unique
580 connection name. Use the memory address of d as a unique
582 char* new_connext = alloca (strlen (devname + 11));
583 sprintf (new_connext, "%s:%X", devname, d->header.uid);
584 new_connection = build_ext_string (devname, Qmswindows_tstr);
586 DEVICE_CONNECTION (d) = new_connection;
589 /* Reinitialize printer. The device can pop off in process */
590 if (!msprinter_reinit_device (d, devname))
593 delete_device_internal (d, 1, 0, 1);
598 /* Apply the new devmode to the printer */
599 DocumentProperties (NULL,
600 DEVICE_MSPRINTER_HPRINTER(d),
601 DEVICE_MSPRINTER_NAME(d),
602 devmode_out, devmode_in,
603 DM_IN_BUFFER | DM_OUT_BUFFER);
605 /* #### ResetDC fails sometimes, Bill only knows why.
606 The solution below looks more like a workaround to me,
607 although it might be fine. --kkm */
608 if (ResetDC (DEVICE_MSPRINTER_HDC (d), devmode_out) == NULL)
610 DeleteDC (DEVICE_MSPRINTER_HDC (d));
611 DEVICE_MSPRINTER_HDC (d) =
612 CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode_out);
619 handle_devmode_changes (Lisp_Devmode *ldm, HGLOBAL hDevNames, HGLOBAL hDevMode)
621 DEVNAMES* devnames = (DEVNAMES*) GlobalLock (hDevNames);
622 char *new_name = devnames ? (char*)devnames + devnames->wDeviceOffset : NULL;
623 DEVMODE* devmode = (DEVMODE*) GlobalLock (hDevMode);
625 /* Size and name may have changed */
626 ldm->devmode = xrealloc (ldm->devmode, DEVMODE_SIZE (devmode));
629 if (ldm->printer_name)
630 xfree (ldm->printer_name);
631 ldm->printer_name = xstrdup (new_name);
634 if (!NILP (ldm->device))
636 /* Apply the new devmode to the printer and get a compete one back */
637 struct device *d = XDEVICE (ldm->device);
638 if (!sync_printer_with_devmode (d, devmode, ldm->devmode, new_name))
640 global_free_2_maybe (hDevNames, hDevMode);
641 error ("Printer device initialization I/O error, device deleted.");
646 /* Just copy the devmode structure */
647 memcpy (ldm->devmode, devmode, DEVMODE_SIZE (devmode));
652 ensure_not_printing (struct device *d)
654 if (!NILP (DEVICE_FRAME_LIST (d)))
657 XSETDEVICE (device, d);
658 invalid_operation ("Cannot change settings while print job is active",
663 static Lisp_Devmode *
664 decode_devmode (Lisp_Object dev)
667 return XDEVMODE (dev);
670 ensure_not_printing (XDEVICE (dev));
671 return XDEVMODE (DEVICE_MSPRINTER_DEVMODE (XDEVICE (dev)));
676 * DEV can be either a printer or devmode
677 * PRINT_P is non-zero for the Print dialog, zero for the
681 print_dialog_worker (Lisp_Object dev, int print_p)
683 Lisp_Devmode *ldm = decode_devmode (dev);
686 memset (&pd, 0, sizeof (pd));
687 pd.lStructSize = sizeof (pd);
688 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
689 pd.hDevMode = devmode_to_hglobal (ldm);
690 pd.Flags = (PD_NOSELECTION | PD_USEDEVMODECOPIESANDCOLLATE
691 | (print_p ? 0 : PD_PRINTSETUP));
693 pd.nMaxPage = 0xFFFF;
697 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
701 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
703 /* Finally, build the resulting plist */
705 Lisp_Object result = Qnil;
709 /* Do consing in reverse order.
712 result = Fcons (Qcopies, Fcons (make_int (pd.nCopies), result));
715 if (print_p && (pd.Flags & PD_PAGENUMS))
717 result = Fcons (Qto_page, Fcons (make_int (pd.nToPage), result));
718 result = Fcons (Qfrom_page, Fcons (make_int (pd.nFromPage), result));
722 result = Fcons (Qname,
723 Fcons (build_ext_string (ldm->printer_name,
728 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
734 mswindows_handle_print_setup_dialog_box (struct frame *f, Lisp_Object keys)
736 Lisp_Object device = Qunbound, settings = Qunbound;
739 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
741 if (EQ (key, Q_device))
743 device = wrap_device (decode_device (value));
744 CHECK_MSPRINTER_DEVICE (device);
746 else if (EQ (key, Q_printer_settings))
748 CHECK_DEVMODE (value);
752 syntax_error ("Unrecognized print-dialog keyword", key);
756 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
757 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
758 syntax_error ("Exactly one of :device and :printer-settings must be given",
761 return print_dialog_worker (!UNBOUNDP (device) ? device : settings, 0);
765 mswindows_handle_print_dialog_box (struct frame *f, Lisp_Object keys)
767 Lisp_Object device = Qunbound, settings = Qunbound;
770 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
772 if (EQ (key, Q_device))
774 device = wrap_device (decode_device (value));
775 CHECK_MSPRINTER_DEVICE (device);
777 else if (EQ (key, Q_printer_settings))
779 CHECK_DEVMODE (value);
783 syntax_error ("Unrecognized print-dialog keyword", key);
787 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
788 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
789 syntax_error ("Exactly one of :device and :printer-settings must be given",
792 return print_dialog_worker (!UNBOUNDP (device) ? device : settings, 1);
796 mswindows_get_default_margin (Lisp_Object prop)
798 if (EQ (prop, Qleft_margin)) return 1440;
799 if (EQ (prop, Qright_margin)) return 1440;
800 if (EQ (prop, Qtop_margin)) return 720;
801 if (EQ (prop, Qbottom_margin)) return 720;
807 plist_get_margin (Lisp_Object plist, Lisp_Object prop)
810 Fplist_get (plist, prop, make_int (mswindows_get_default_margin (prop)));
812 invalid_argument ("Margin value must be an integer", val);
814 return MulDiv (XINT (val), 100, 144);
818 plist_set_margin (Lisp_Object plist, Lisp_Object prop, int margin, int mm_p)
820 Lisp_Object val = make_int (MulDiv (margin, 144, mm_p ? 2450 : 100));
821 return Fcons (prop, Fcons (val, plist));
825 mswindows_handle_page_setup_dialog_box (struct frame *f, Lisp_Object keys)
827 Lisp_Object device = Qunbound, settings = Qunbound;
828 Lisp_Object plist = Qnil;
831 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
833 if (EQ (key, Q_device))
835 device = wrap_device (decode_device (value));
836 CHECK_MSPRINTER_DEVICE (device);
838 else if (EQ (key, Q_printer_settings))
840 CHECK_DEVMODE (value);
843 else if (EQ (key, Q_properties))
849 syntax_error ("Unrecognized page-setup dialog keyword", key);
853 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
854 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
855 syntax_error ("Exactly one of :device and :printer-settings must be given",
858 if (UNBOUNDP (device))
862 Lisp_Devmode *ldm = decode_devmode (device);
865 memset (&pd, 0, sizeof (pd));
866 pd.lStructSize = sizeof (pd);
867 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
868 pd.Flags = PSD_MARGINS;
869 pd.rtMargin.left = plist_get_margin (plist, Qleft_margin);
870 pd.rtMargin.top = plist_get_margin (plist, Qtop_margin);
871 pd.rtMargin.right = plist_get_margin (plist, Qright_margin);
872 pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin);
873 pd.hDevMode = devmode_to_hglobal (ldm);
875 if (!PageSetupDlg (&pd))
877 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
882 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
884 /* Finally, build the resulting plist */
886 Lisp_Object result = Qnil;
887 int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
888 result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
890 result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
892 result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
893 result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
899 DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
900 Return the settings object currently used by DEVICE.
901 The object returned is not a copy, but rather a pointer to the
902 original one. Use `msprinter-settings-copy' to create a copy of it.
906 struct device *d = decode_device (device);
907 XSETDEVICE (device, d);
908 CHECK_MSPRINTER_DEVICE (device);
909 return DEVICE_MSPRINTER_DEVMODE (d);
912 DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
913 Select SETTINGS object into a DEVICE.
914 The settings from the settings object are immediately applied to the
915 printer, possibly changing even the target printer itself, and all
916 future changes are applied synchronously to the printer device and the
917 selected printer object, until a different settings object is selected
918 into the same printer.
920 A settings object can be selected to no more than one printer at a time.
922 If the supplied settings object is not specialized, it is specialized
923 for the printer immediately upon selection. The object can be
924 despecialized after it is unselected by calling the function
925 `msprinter-settings-despecialize'.
927 Return value is the previously selected settings object.
932 struct device *d = decode_device (device);
937 XSETDEVICE (device, d);
938 CHECK_MSPRINTER_DEVICE (device);
939 CHECK_DEVMODE (settings);
940 ldm = XDEVMODE (settings);
942 if (!NILP (ldm->device))
943 invalid_operation ("The object is currently selected into a device",
946 /* If the object being selected is de-specialized, then its
947 size is perhaps not enough to receive the new devmode. We can ask
948 for printer's devmode size here, because despecialized settings
949 cannot force switching to a different printer, as they supply no
950 printer name at all. */
951 if (ldm->printer_name == NULL)
954 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
955 DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
957 invalid_operation ("Unable to specialize settings, printer error",
960 assert (XDEVMODE_SIZE (ldm) <= dm_size);
961 ldm->devmode = xrealloc (ldm->devmode, dm_size);
964 /* If we bail out on signal here, no damage is done, except that
965 the storage for the DEVMODE structure might be reallocated to
966 hold a larger one - not a big deal */
967 if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
969 error ("Printer device initialization I/O error, device deleted.");
971 if (ldm->printer_name == NULL)
972 ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
975 Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
976 ldm->device = device;
977 XDEVMODE (old_mode)->device = Qnil;
978 DEVICE_MSPRINTER_DEVMODE (d) = settings;
984 DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
985 Apply settings from a SETTINGS object to a 'msprinter DEVICE.
986 The settings from the settings object are immediately applied to the
987 printer, possibly changing even the target printer itself. The SETTING
988 object is not modified, unlike `msprinter-select-settings', and the
989 supplied object is not changed. The changes are immediately recorded
990 into the settings object which is currently selected into the printer
993 Return value is the currently selected settings object.
997 Lisp_Devmode *ldm_current, *ldm_new;
998 struct device *d = decode_device (device);
1000 struct gcpro gcpro1;
1003 XSETDEVICE (device, d);
1004 CHECK_MSPRINTER_DEVICE (device);
1005 CHECK_DEVMODE (settings);
1006 ldm_new = XDEVMODE (settings);
1007 ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
1009 /* If the supplied devmode is not specialized, then the current
1010 devmode size will always be sufficient, as the printer does
1011 not change. If it is specialized, we must reallocate the current
1012 devmode storage to match with the supplied one, as it has the right
1013 size for the new printer, if it is going to change. The correct
1014 way is to use the largest of the two though, to keep the old
1015 contents unchanged in case of preliminary exit.
1017 if (ldm_new->printer_name)
1018 ldm_current->devmode =
1019 (DEVMODE*) xrealloc (ldm_current->devmode,
1020 max (XDEVMODE_SIZE (ldm_new),
1021 XDEVMODE_SIZE (ldm_current)));
1023 if (!sync_printer_with_devmode (d, ldm_new->devmode,
1024 ldm_current->devmode,
1025 ldm_new->printer_name))
1026 error ("Printer device initialization I/O error, device deleted.");
1028 if (ldm_new->printer_name != NULL)
1030 xfree (ldm_current->printer_name);
1031 ldm_current->printer_name = xstrdup (ldm_new->printer_name);
1035 return DEVICE_MSPRINTER_DEVMODE (d);
1038 /************************************************************************/
1040 /************************************************************************/
1043 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1047 Lisp_Devmode *dm = XDEVMODE (obj);
1049 error ("printing unreadable object #<msprinter-settings 0x%x>",
1051 write_c_string ("#<msprinter-settings", printcharfun);
1052 if (dm->printer_name)
1054 write_c_string (" for \"", printcharfun);
1055 write_c_string (dm->printer_name, printcharfun);
1056 write_c_string ("\"", printcharfun);
1058 if (!NILP (dm->device))
1060 write_c_string (" (currently on ", printcharfun);
1061 print_internal (dm->device, printcharfun, 0);
1062 write_c_string (")", printcharfun);
1064 sprintf (buf, " 0x%x>", dm->header.uid);
1065 write_c_string (buf, printcharfun);
1069 finalize_devmode (void *header, int for_disksave)
1071 Lisp_Devmode *dm = (Lisp_Devmode *) header;
1075 Lisp_Object devmode;
1076 XSETDEVMODE (devmode, dm);
1078 ("Cannot dump XEmacs containing an msprinter-settings object",
1082 assert (NILP (dm->device));
1084 if (dm->printer_name)
1085 xfree (dm->printer_name);
1089 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1091 Lisp_Devmode *dm1 = XDEVMODE (obj1);
1092 Lisp_Devmode *dm2 = XDEVMODE (obj2);
1094 if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1096 if (dm1->devmode == NULL)
1098 if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1100 if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1102 return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1105 static unsigned long
1106 hash_devmode (Lisp_Object obj, int depth)
1108 Lisp_Devmode *dm = XDEVMODE (obj);
1110 return HASH3 (XDEVMODE_SIZE (dm),
1111 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1113 dm->printer_name ? string_hash (dm->printer_name) : 0);
1116 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1117 0/*mark*/, print_devmode, finalize_devmode,
1118 equal_devmode, hash_devmode, 0/*description*/,
1121 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1122 char* src_name, struct device *d)
1127 dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1130 XSETDEVICE (dm->device, d);
1134 dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1136 if (src_devmode != NULL && do_copy)
1138 dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1139 memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1143 dm->devmode = src_devmode;
1146 XSETDEVMODE (ob, dm);
1150 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1151 Create and returns an exact copy of a printer settings object.
1157 CHECK_DEVMODE (settings);
1158 dm = XDEVMODE (settings);
1160 return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1163 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1164 Erase printer-specific settings from a printer settings object.
1171 CHECK_DEVMODE (settings);
1172 ldm = XDEVMODE (settings);
1174 if (!NILP (ldm->device))
1175 invalid_operation ("The object is currently selected into a device",
1180 /* #### TODO. Either remove references to device specific bins,
1181 paper sizes etc, or signal an error of they are present. */
1183 dm->dmDriverExtra = 0;
1184 dm->dmDeviceName[0] = '\0';
1186 if (ldm->printer_name)
1187 xfree (ldm->printer_name);
1192 DEFUN ("mswindows-get-default-printer", Fmswindows_get_default_printer, 0, 0, 0, /*
1193 Return name of the default printer, as string, on nil if there is no default.
1197 return msprinter_default_printer ();
1201 signal_enum_printer_error (void)
1203 invalid_operation ("Error enumerating printers", make_int (GetLastError ()));
1206 DEFUN ("mswindows-printer-list", Fmswindows_printer_list, 0, 0, 0, /*
1207 Return a list of string names of installed printers.
1208 If there is a default printer, it is returned as the first element of
1209 the list. If there is no default printer, the first element of the
1210 list will be nil. The rest of elements are guaranteed to have string
1211 values. Return value is nil if there are no printers installed.
1216 BYTE *data_buf, dummy_byte;
1217 size_t enum_entry_size;
1218 DWORD enum_flags, enum_level, bytes_needed, num_printers;
1219 struct gcpro gcpro1, gcpro2;
1220 Lisp_Object result = Qnil, def_printer = Qnil;
1222 /* Determine OS flavor, to use the fastest enumeration method available */
1223 have_nt = !mswindows_windows9x_p ();
1224 enum_flags = PRINTER_ENUM_LOCAL | (have_nt ? PRINTER_ENUM_CONNECTIONS : 0);
1225 enum_level = have_nt ? 4 : 5;
1226 enum_entry_size = have_nt ? sizeof (PRINTER_INFO_4) : sizeof (PRINTER_INFO_5);
1228 /* Allocate memory for printer enum structure */
1229 ok = EnumPrinters (enum_flags, NULL, enum_level, &dummy_byte, 1,
1230 &bytes_needed, &num_printers);
1232 /* No printers, if just 1 byte is enough */
1235 if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1236 signal_enum_printer_error ();
1238 data_buf = alloca (bytes_needed);
1239 ok = EnumPrinters (enum_flags, NULL, enum_level, data_buf, bytes_needed,
1240 &bytes_needed, &num_printers);
1242 signal_enum_printer_error ();
1244 if (num_printers == 0)
1245 /* Strange but... */
1248 GCPRO2 (result, def_printer);
1250 while (num_printers--)
1252 LPCTSTR printer_name;
1255 PRINTER_INFO_4 *info = (PRINTER_INFO_4*) data_buf;
1256 printer_name = info->pPrinterName;
1260 PRINTER_INFO_5 *info = (PRINTER_INFO_5*) data_buf;
1261 printer_name = info->pPrinterName;
1263 data_buf += enum_entry_size;
1265 result = Fcons (build_ext_string (printer_name, Qmswindows_tstr),
1269 def_printer = msprinter_default_printer ();
1270 result = Fdelete (def_printer, result);
1271 result = Fcons (def_printer, result);
1273 RETURN_UNGCPRO (result);
1277 /************************************************************************/
1278 /* initialization */
1279 /************************************************************************/
1282 syms_of_device_mswindows (void)
1284 INIT_LRECORD_IMPLEMENTATION (devmode);
1286 DEFSUBR (Fmsprinter_get_settings);
1287 DEFSUBR (Fmsprinter_select_settings);
1288 DEFSUBR (Fmsprinter_apply_settings);
1289 DEFSUBR (Fmsprinter_settings_copy);
1290 DEFSUBR (Fmsprinter_settings_despecialize);
1291 DEFSUBR (Fmswindows_get_default_printer);
1292 DEFSUBR (Fmswindows_printer_list);
1294 defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win");
1295 defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win");
1299 console_type_create_device_mswindows (void)
1301 CONSOLE_HAS_METHOD (mswindows, init_device);
1302 CONSOLE_HAS_METHOD (mswindows, finish_init_device);
1303 CONSOLE_HAS_METHOD (mswindows, mark_device);
1304 CONSOLE_HAS_METHOD (mswindows, delete_device);
1305 CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
1306 CONSOLE_HAS_METHOD (mswindows, device_implementation_flags);
1308 CONSOLE_HAS_METHOD (msprinter, init_device);
1309 CONSOLE_HAS_METHOD (msprinter, mark_device);
1310 CONSOLE_HAS_METHOD (msprinter, delete_device);
1311 CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
1312 CONSOLE_HAS_METHOD (msprinter, device_implementation_flags);
1317 vars_of_device_mswindows (void)
1319 DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
1320 Non-nil means convert all-upper case file names to lower case.
1321 This applies when performing completions and file name expansion.
1323 Vmswindows_downcase_file_names = Qnil;
1325 DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
1326 Non-nil means determine accurate link count in file-attributes.
1327 This option slows down file-attributes noticeably, so is disabled by
1328 default. Note that it is only useful for files on NTFS volumes,
1329 where hard links are supported.
1331 Vmswindows_get_true_file_attributes = Qnil;