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 plist_get_margin (Lisp_Object plist, Lisp_Object prop)
798 Lisp_Object val = Fplist_get (plist, prop, make_int (1440));
800 invalid_argument ("Margin value must be an integer", val);
802 return MulDiv (XINT (val), 100, 144);
806 plist_set_margin (Lisp_Object plist, Lisp_Object prop, int margin, int mm_p)
808 Lisp_Object val = make_int (MulDiv (margin, 144, mm_p ? 2450 : 100));
809 return Fcons (prop, Fcons (val, plist));
813 mswindows_handle_page_setup_dialog_box (struct frame *f, Lisp_Object keys)
815 Lisp_Object device = Qunbound, settings = Qunbound;
816 Lisp_Object plist = Qnil;
819 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
821 if (EQ (key, Q_device))
823 device = wrap_device (decode_device (value));
824 CHECK_MSPRINTER_DEVICE (device);
826 else if (EQ (key, Q_printer_settings))
828 CHECK_DEVMODE (value);
831 else if (EQ (key, Q_properties))
837 syntax_error ("Unrecognized page-setup dialog keyword", key);
841 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
842 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
843 syntax_error ("Exactly one of :device and :printer-settings must be given",
846 if (UNBOUNDP (device))
850 Lisp_Devmode *ldm = decode_devmode (device);
853 memset (&pd, 0, sizeof (pd));
854 pd.lStructSize = sizeof (pd);
855 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
856 pd.Flags = PSD_MARGINS;
857 pd.rtMargin.left = plist_get_margin (plist, Qleft_margin);
858 pd.rtMargin.top = plist_get_margin (plist, Qtop_margin);
859 pd.rtMargin.right = plist_get_margin (plist, Qright_margin);
860 pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin);
861 pd.hDevMode = devmode_to_hglobal (ldm);
863 if (!PageSetupDlg (&pd))
865 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
870 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
872 /* Finally, build the resulting plist */
874 Lisp_Object result = Qnil;
875 int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
876 result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
878 result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
880 result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
881 result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
887 DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
888 Return the settings object currently used by DEVICE.
889 The object returned is not a copy, but rather a pointer to the
890 original one. Use `msprinter-settings-copy' to create a copy of it.
894 struct device *d = decode_device (device);
895 XSETDEVICE (device, d);
896 CHECK_MSPRINTER_DEVICE (device);
897 return DEVICE_MSPRINTER_DEVMODE (d);
900 DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
901 Select SETTINGS object into a DEVICE.
902 The settings from the settings object are immediately applied to the
903 printer, possibly changing even the target printer itself, and all
904 future changes are applied synchronously to the printer device and the
905 selected printer object, until a different settings object is selected
906 into the same printer.
908 A settings object can be selected to no more than one printer at a time.
910 If the supplied settings object is not specialized, it is specialized
911 for the printer immediately upon selection. The object can be
912 despecialized after it is unselected by calling the function
913 `msprinter-settings-despecialize'.
915 Return value is the previously selected settings object.
920 struct device *d = decode_device (device);
925 XSETDEVICE (device, d);
926 CHECK_MSPRINTER_DEVICE (device);
927 CHECK_DEVMODE (settings);
928 ldm = XDEVMODE (settings);
930 if (!NILP (ldm->device))
931 invalid_operation ("The object is currently selected into a device",
934 /* If the object being selected is de-specialized, then its
935 size is perhaps not enough to receive the new devmode. We can ask
936 for printer's devmode size here, because despecialized settings
937 cannot force switching to a different printer, as they supply no
938 printer name at all. */
939 if (ldm->printer_name == NULL)
942 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
943 DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
945 invalid_operation ("Unable to specialize settings, printer error",
948 assert (XDEVMODE_SIZE (ldm) <= dm_size);
949 ldm->devmode = xrealloc (ldm->devmode, dm_size);
952 /* If we bail out on signal here, no damage is done, except that
953 the storage for the DEVMODE structure might be reallocated to
954 hold a larger one - not a big deal */
955 if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
957 error ("Printer device initialization I/O error, device deleted.");
959 if (ldm->printer_name == NULL)
960 ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
963 Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
964 ldm->device = device;
965 XDEVMODE (old_mode)->device = Qnil;
966 DEVICE_MSPRINTER_DEVMODE (d) = settings;
972 DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
973 Apply settings from a SETTINGS object to a 'msprinter DEVICE.
974 The settings from the settings object are immediately applied to the
975 printer, possibly changing even the target printer itself. The SETTING
976 object is not modified, unlike `msprinter-select-settings', and the
977 supplied object is not changed. The changes are immediately recorded
978 into the settings object which is currently selected into the printer
981 Return value is the currently selected settings object.
985 Lisp_Devmode *ldm_current, *ldm_new;
986 struct device *d = decode_device (device);
991 XSETDEVICE (device, d);
992 CHECK_MSPRINTER_DEVICE (device);
993 CHECK_DEVMODE (settings);
994 ldm_new = XDEVMODE (settings);
995 ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
997 /* If the supplied devmode is not specialized, then the current
998 devmode size will always be sufficient, as the printer does
999 not change. If it is specialized, we must reallocate the current
1000 devmode storage to match with the supplied one, as it has the right
1001 size for the new printer, if it is going to change. The correct
1002 way is to use the largest of the two though, to keep the old
1003 contents unchanged in case of preliminary exit.
1005 if (ldm_new->printer_name)
1006 ldm_current->devmode =
1007 (DEVMODE*) xrealloc (ldm_current->devmode,
1008 max (XDEVMODE_SIZE (ldm_new),
1009 XDEVMODE_SIZE (ldm_current)));
1011 if (!sync_printer_with_devmode (d, ldm_new->devmode,
1012 ldm_current->devmode,
1013 ldm_new->printer_name))
1014 error ("Printer device initialization I/O error, device deleted.");
1016 if (ldm_new->printer_name != NULL)
1018 xfree (ldm_current->printer_name);
1019 ldm_current->printer_name = xstrdup (ldm_new->printer_name);
1023 return DEVICE_MSPRINTER_DEVMODE (d);
1026 /************************************************************************/
1028 /************************************************************************/
1031 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1035 Lisp_Devmode *dm = XDEVMODE (obj);
1037 error ("printing unreadable object #<msprinter-settings 0x%x>",
1039 write_c_string ("#<msprinter-settings", printcharfun);
1040 if (dm->printer_name)
1042 write_c_string (" for \"", printcharfun);
1043 write_c_string (dm->printer_name, printcharfun);
1044 write_c_string ("\"", printcharfun);
1046 if (!NILP (dm->device))
1048 write_c_string (" (currently on ", printcharfun);
1049 print_internal (dm->device, printcharfun, 0);
1050 write_c_string (")", printcharfun);
1052 sprintf (buf, " 0x%x>", dm->header.uid);
1053 write_c_string (buf, printcharfun);
1057 finalize_devmode (void *header, int for_disksave)
1059 Lisp_Devmode *dm = (Lisp_Devmode *) header;
1063 Lisp_Object devmode;
1064 XSETDEVMODE (devmode, dm);
1066 ("Cannot dump XEmacs containing an msprinter-settings object",
1070 assert (NILP (dm->device));
1072 if (dm->printer_name)
1073 xfree (dm->printer_name);
1077 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1079 Lisp_Devmode *dm1 = XDEVMODE (obj1);
1080 Lisp_Devmode *dm2 = XDEVMODE (obj2);
1082 if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1084 if (dm1->devmode == NULL)
1086 if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1088 if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1090 return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1093 static unsigned long
1094 hash_devmode (Lisp_Object obj, int depth)
1096 Lisp_Devmode *dm = XDEVMODE (obj);
1098 return HASH3 (XDEVMODE_SIZE (dm),
1099 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1101 dm->printer_name ? string_hash (dm->printer_name) : 0);
1104 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1105 0/*mark*/, print_devmode, finalize_devmode,
1106 equal_devmode, hash_devmode, 0/*description*/,
1109 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1110 char* src_name, struct device *d)
1115 dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1118 XSETDEVICE (dm->device, d);
1122 dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1124 if (src_devmode != NULL && do_copy)
1126 dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1127 memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1131 dm->devmode = src_devmode;
1134 XSETDEVMODE (ob, dm);
1138 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1139 Create and returns an exact copy of a printer settings object.
1145 CHECK_DEVMODE (settings);
1146 dm = XDEVMODE (settings);
1148 return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1151 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1152 Erase printer-specific settings from a printer settings object.
1159 CHECK_DEVMODE (settings);
1160 ldm = XDEVMODE (settings);
1162 if (!NILP (ldm->device))
1163 invalid_operation ("The object is currently selected into a device",
1168 /* #### TODO. Either remove references to device specific bins,
1169 paper sizes etc, or signal an error of they are present. */
1171 dm->dmDriverExtra = 0;
1172 dm->dmDeviceName[0] = '\0';
1174 if (ldm->printer_name)
1175 xfree (ldm->printer_name);
1180 DEFUN ("mswindows-get-default-printer", Fmswindows_get_default_printer, 0, 0, 0, /*
1181 Return name of the default printer, as string, on nil if there is no default.
1185 return msprinter_default_printer ();
1189 signal_enum_printer_error (void)
1191 invalid_operation ("Error enumerating printers", make_int (GetLastError ()));
1194 DEFUN ("mswindows-printer-list", Fmswindows_printer_list, 0, 0, 0, /*
1195 Return a list of string names of installed printers.
1196 If there is a default printer, it is returned as the first element of
1197 the list. If there is no default printer, the first element of the
1198 list will be nil. The rest of elements are guaranteed to have string
1199 values. Return value is nil if there are no printers installed.
1204 BYTE *data_buf, dummy_byte;
1205 size_t enum_entry_size;
1206 DWORD enum_flags, enum_level, bytes_needed, num_printers;
1207 struct gcpro gcpro1, gcpro2;
1208 Lisp_Object result = Qnil, def_printer = Qnil;
1210 /* Determine OS flavor, to use the fastest enumeration method available */
1211 have_nt = !mswindows_windows9x_p ();
1212 enum_flags = PRINTER_ENUM_LOCAL | (have_nt ? PRINTER_ENUM_CONNECTIONS : 0);
1213 enum_level = have_nt ? 4 : 5;
1214 enum_entry_size = have_nt ? sizeof (PRINTER_INFO_4) : sizeof (PRINTER_INFO_5);
1216 /* Allocate memory for printer enum structure */
1217 ok = EnumPrinters (enum_flags, NULL, enum_level, &dummy_byte, 1,
1218 &bytes_needed, &num_printers);
1220 /* No printers, if just 1 byte is enough */
1223 if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1224 signal_enum_printer_error ();
1226 data_buf = alloca (bytes_needed);
1227 ok = EnumPrinters (enum_flags, NULL, enum_level, data_buf, bytes_needed,
1228 &bytes_needed, &num_printers);
1230 signal_enum_printer_error ();
1232 if (num_printers == 0)
1233 /* Strange but... */
1236 GCPRO2 (result, def_printer);
1238 while (num_printers--)
1240 LPCTSTR printer_name;
1243 PRINTER_INFO_4 *info = (PRINTER_INFO_4*) data_buf;
1244 printer_name = info->pPrinterName;
1248 PRINTER_INFO_5 *info = (PRINTER_INFO_5*) data_buf;
1249 printer_name = info->pPrinterName;
1251 data_buf += enum_entry_size;
1253 result = Fcons (build_ext_string (printer_name, Qmswindows_tstr),
1257 def_printer = msprinter_default_printer ();
1258 result = Fdelete (def_printer, result);
1259 result = Fcons (def_printer, result);
1261 RETURN_UNGCPRO (result);
1265 /************************************************************************/
1266 /* initialization */
1267 /************************************************************************/
1270 syms_of_device_mswindows (void)
1272 INIT_LRECORD_IMPLEMENTATION (devmode);
1274 DEFSUBR (Fmsprinter_get_settings);
1275 DEFSUBR (Fmsprinter_select_settings);
1276 DEFSUBR (Fmsprinter_apply_settings);
1277 DEFSUBR (Fmsprinter_settings_copy);
1278 DEFSUBR (Fmsprinter_settings_despecialize);
1279 DEFSUBR (Fmswindows_get_default_printer);
1280 DEFSUBR (Fmswindows_printer_list);
1282 defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win");
1283 defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win");
1287 console_type_create_device_mswindows (void)
1289 CONSOLE_HAS_METHOD (mswindows, init_device);
1290 CONSOLE_HAS_METHOD (mswindows, finish_init_device);
1291 CONSOLE_HAS_METHOD (mswindows, mark_device);
1292 CONSOLE_HAS_METHOD (mswindows, delete_device);
1293 CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
1294 CONSOLE_HAS_METHOD (mswindows, device_implementation_flags);
1296 CONSOLE_HAS_METHOD (msprinter, init_device);
1297 CONSOLE_HAS_METHOD (msprinter, mark_device);
1298 CONSOLE_HAS_METHOD (msprinter, delete_device);
1299 CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
1300 CONSOLE_HAS_METHOD (msprinter, device_implementation_flags);
1305 vars_of_device_mswindows (void)
1307 DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
1308 Non-nil means convert all-upper case file names to lower case.
1309 This applies when performing completions and file name expansion.
1311 Vmswindows_downcase_file_names = Qnil;
1313 DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
1314 Non-nil means determine accurate link count in file-attributes.
1315 This option slows down file-attributes noticeably, so is disabled by
1316 default. Note that it is only useful for files on NTFS volumes,
1317 where hard links are supported.
1319 Vmswindows_get_true_file_attributes = Qnil;