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.
29 Print support added by Kirill Katsnelson, July 2000.
36 #include "console-msw.h"
37 #include "console-stream.h"
38 #include "objects-msw.h"
46 #if !(defined (CYGWIN) || defined(MINGW))
47 #include <objbase.h> /* For CoInitialize */
50 /* win32 DDE management library globals */
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;
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;
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;
68 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
69 Lisp_Object Qdevmodep;
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;
76 static Lisp_Object allocate_devmode (DEVMODE* src_devmode, int do_copy,
77 char* src_name, struct device *d);
79 /************************************************************************/
81 /************************************************************************/
84 build_syscolor_string (int idx)
86 return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
90 build_syscolor_cons (int index1, int index2)
92 Lisp_Object color1, color2;
95 color1 = build_syscolor_string (index1);
96 color2 = build_syscolor_string (index2);
97 RETURN_UNGCPRO (Fcons (color1, color2));
101 build_sysmetrics_cons (int index1, int index2)
103 return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
104 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
108 build_devicecaps_cons (HDC hdc, int index1, int index2)
110 return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
111 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
115 /************************************************************************/
116 /* display methods */
117 /************************************************************************/
120 mswindows_init_device (struct device *d, Lisp_Object props)
125 DEVICE_CLASS (d) = Qcolor;
126 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
130 d->device_data = xnew_and_zero (struct mswindows_device);
131 hdc = CreateCompatibleDC (NULL);
133 DEVICE_MSWINDOWS_HCDC(d) = hdc;
134 DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
135 DEVICE_MSWINDOWS_UPDATE_TICK (d) = GetTickCount ();
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;
142 wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
143 /* This must match whatever is passed to CreateWIndowEx, NULL is ok
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
150 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
151 wc.lpszMenuName = NULL;
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);
160 if (xRegisterClassExA) /* not in NT 3.5 */
161 xRegisterClassExA (&wc);
163 RegisterClassA ((WNDCLASS *) &wc.style);
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;
172 if (xRegisterClassExA) /* not in NT 3.5 */
173 xRegisterClassExA (&wc);
175 RegisterClassA ((WNDCLASS *) &wc.style);
178 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
179 InitCommonControls ();
183 #ifdef HAVE_DRAGNDROP
185 mswindows_init_dde ()
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))
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,
200 mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
202 mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
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);
211 init_mswindows_very_early()
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
218 mswindows_init_dde();
223 mswindows_finish_init_device (struct device *d, Lisp_Object props)
225 #ifdef HAVE_DRAGNDROP
226 /* Tell pending clients we are ready. */
227 mswindows_dde_enable = 1;
232 mswindows_delete_device (struct device *d)
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);
241 # if !(defined(CYGWIN) || defined(MINGW))
246 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
247 xfree (d->device_data);
251 mswindows_get_workspace_coords (RECT *rc)
253 SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
257 mswindows_mark_device (struct device *d)
259 mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
263 mswindows_device_system_metrics (struct device *d,
264 enum device_metrics m)
266 const HDC hdc = DEVICE_MSWINDOWS_HCDC(d);
271 return Fcons (make_int (GetDeviceCaps (hdc, HORZRES)),
272 make_int (GetDeviceCaps (hdc, VERTRES)));
275 return Fcons (make_int (GetDeviceCaps (hdc, LOGPIXELSX)),
276 make_int (GetDeviceCaps (hdc, LOGPIXELSY)));
278 case DM_size_device_mm:
279 return Fcons (make_int (GetDeviceCaps (hdc, HORZSIZE)),
280 make_int (GetDeviceCaps (hdc, VERTSIZE)));
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
286 return make_int (GetDeviceCaps (hdc, BITSPIXEL));
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));
295 #define FROB(met, fore, back) \
297 return build_syscolor_cons (fore, back);
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);
316 #define FROB(met, index1, index2) \
318 return build_sysmetrics_cons (index1, index2);
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);
327 case DM_size_workspace:
330 mswindows_get_workspace_coords (&rc);
331 return Fcons (make_int (rc.right - rc.left),
332 make_int (rc.bottom - rc.top));
335 case DM_offset_workspace:
338 mswindows_get_workspace_coords (&rc);
339 return Fcons (make_int (rc.left), make_int (rc.top));
343 case DM_size_toolbar:
344 case DM_size_toolbar_button:
345 case DM_size_toolbar_border:
349 #define FROB(met, index) \
351 return make_int (GetSystemMetrics (index));
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);
362 /* Do not know such property */
367 /************************************************************************/
368 /* printer helpers */
369 /************************************************************************/
372 signal_open_printer_error (struct device *d)
374 invalid_operation ("Failed to open printer", DEVICE_CONNECTION (d));
378 /* Helper function */
380 msprinter_init_device_internal (struct device *d, char* printer_name)
382 DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
384 if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
386 DEVICE_MSPRINTER_HPRINTER (d) = NULL;
390 DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
392 if (DEVICE_MSPRINTER_HDC (d) == NULL)
395 DEVICE_MSPRINTER_HCDC(d) =
396 CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
398 DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
399 * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
400 > 1) ? Qcolor : Qmono;
405 msprinter_delete_device_internal (struct device *d)
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));
416 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
420 msprinter_reinit_device (struct device *d, char* devname)
422 msprinter_delete_device_internal (d);
423 return msprinter_init_device_internal (d, devname);
427 msprinter_default_printer (void)
432 if (GetProfileString (XETEXT ("windows"), XETEXT ("device"), NULL, name,
433 sizeof (name) / XETCHAR_SIZE) <= 0)
435 EXTERNAL_TO_C_STRING (name, nameint, Qmswindows_tstr);
441 return build_string (name);
445 /************************************************************************/
446 /* printer methods */
447 /************************************************************************/
450 msprinter_init_device (struct device *d, Lisp_Object props)
456 d->device_data = xnew_and_zero (struct msprinter_device);
458 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
459 DEVICE_MSPRINTER_DEVMODE(d) = Qnil;
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
464 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
466 CHECK_STRING (DEVICE_CONNECTION (d));
468 TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
469 C_STRING_ALLOCA, printer_name,
472 if (!msprinter_init_device_internal (d, printer_name))
473 signal_open_printer_error (d);
475 /* Determine DEVMODE size and store the default DEVMODE */
476 dm_size = DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER (d),
477 printer_name, NULL, NULL, 0);
479 signal_open_printer_error (d);
481 pdm = (DEVMODE*) xmalloc (dm_size);
482 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
484 NULL, DM_OUT_BUFFER);
486 assert (DEVMODE_SIZE (pdm) <= dm_size);
488 DEVICE_MSPRINTER_DEVMODE(d) =
489 allocate_devmode (pdm, 0, printer_name, d);
494 msprinter_delete_device (struct device *d)
498 msprinter_delete_device_internal (d);
500 /* Disassociate the selected devmode with the device */
501 if (!NILP (DEVICE_MSPRINTER_DEVMODE (d)))
503 XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d))->device = Qnil;
504 DEVICE_MSPRINTER_DEVMODE (d) = Qnil;
507 xfree (d->device_data);
512 msprinter_device_system_metrics (struct device *d,
513 enum device_metrics m)
517 /* Device sizes - pixel and mm */
518 #define FROB(met, index1, index2) \
520 return build_devicecaps_cons \
521 (DEVICE_MSPRINTER_HDC(d), index1, index2);
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);
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
534 return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
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 */
542 /* Do not know such property */
547 msprinter_mark_device (struct device *d)
549 mark_object (DEVICE_MSPRINTER_FONTLIST (d));
550 mark_object (DEVICE_MSPRINTER_DEVMODE (d));
554 /************************************************************************/
555 /* printer Lisp subroutines */
556 /************************************************************************/
559 global_free_2_maybe (HGLOBAL hg1, HGLOBAL hg2)
568 devmode_to_hglobal (Lisp_Devmode *ldm)
570 HGLOBAL hg = GlobalAlloc (GHND, XDEVMODE_SIZE (ldm));
571 memcpy (GlobalLock (hg), ldm->devmode, XDEVMODE_SIZE (ldm));
576 /* Returns 0 if the printer has been deleted due to a fatal I/O error,
579 sync_printer_with_devmode (struct device* d, DEVMODE* devmode_in,
580 DEVMODE* devmode_out, char* devname)
582 /* Change connection if the device changed */
584 && stricmp (devname, DEVICE_MSPRINTER_NAME(d)) != 0)
586 Lisp_Object new_connection = build_ext_string (devname, Qmswindows_tstr);
589 GCPRO1 (new_connection);
590 DEVICE_CONNECTION (d) = Qnil;
591 if (!NILP (Ffind_device (new_connection, Qmsprinter)))
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
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);
601 DEVICE_CONNECTION (d) = new_connection;
604 /* Reinitialize printer. The device can pop off in process */
605 if (!msprinter_reinit_device (d, devname))
608 delete_device_internal (d, 1, 0, 1);
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);
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)
625 DeleteDC (DEVICE_MSPRINTER_HDC (d));
626 DEVICE_MSPRINTER_HDC (d) =
627 CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode_out);
634 handle_devmode_changes (Lisp_Devmode *ldm, HGLOBAL hDevNames, HGLOBAL hDevMode)
636 DEVNAMES* devnames = (DEVNAMES*) GlobalLock (hDevNames);
637 char *new_name = devnames ? (char*)devnames + devnames->wDeviceOffset : NULL;
638 DEVMODE* devmode = (DEVMODE*) GlobalLock (hDevMode);
640 /* Size and name may have changed */
641 ldm->devmode = xrealloc (ldm->devmode, DEVMODE_SIZE (devmode));
644 if (ldm->printer_name)
645 xfree (ldm->printer_name);
646 ldm->printer_name = xstrdup (new_name);
649 if (!NILP (ldm->device))
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))
655 global_free_2_maybe (hDevNames, hDevMode);
656 error ("Printer device initialization I/O error, device deleted.");
661 /* Just copy the devmode structure */
662 memcpy (ldm->devmode, devmode, DEVMODE_SIZE (devmode));
667 ensure_not_printing (struct device *d)
669 if (!NILP (DEVICE_FRAME_LIST (d)))
672 XSETDEVICE (device, d);
673 invalid_operation ("Cannot change settings while print job is active",
678 static Lisp_Devmode *
679 decode_devmode (Lisp_Object dev)
682 return XDEVMODE (dev);
685 ensure_not_printing (XDEVICE (dev));
686 return XDEVMODE (DEVICE_MSPRINTER_DEVMODE (XDEVICE (dev)));
691 * DEV can be either a printer or devmode
694 print_dialog_worker (Lisp_Object dev, DWORD flags)
696 Lisp_Devmode *ldm = decode_devmode (dev);
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;
705 pd.nMaxPage = 0xFFFF;
709 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
713 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
715 /* Finally, build the resulting plist */
717 Lisp_Object result = Qnil;
721 /* Do consing in reverse order.
723 result = Fcons (Qcopies, Fcons (make_int (pd.nCopies), result));
726 if (pd.Flags & PD_PAGENUMS)
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));
732 else if (pd.Flags & PD_SELECTION)
733 result = Fcons (Qselected_page_button, Fcons (Qselection, result));
735 result = Fcons (Qselected_page_button, Fcons (Qall, result));
738 result = Fcons (Qname, Fcons (build_ext_string (ldm->printer_name,
743 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
749 mswindows_handle_print_dialog_box (struct frame *f, Lisp_Object keys)
751 Lisp_Object device = Qunbound, settings = Qunbound;
752 DWORD flags = PD_NOSELECTION;
755 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
757 if (EQ (key, Q_device))
759 device = wrap_device (decode_device (value));
760 CHECK_MSPRINTER_DEVICE (device);
762 else if (EQ (key, Q_printer_settings))
764 CHECK_DEVMODE (value);
767 else if (EQ (key, Q_allow_pages))
770 flags |= PD_NOPAGENUMS;
772 else if (EQ (key, Q_allow_selection))
775 flags &= ~PD_NOSELECTION;
777 else if (EQ (key, Q_selected_page_button))
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",
788 syntax_error ("Unrecognized print-dialog keyword", key);
792 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
793 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
794 syntax_error ("Exactly one of :device and :printer-settings must be given",
797 return print_dialog_worker (!UNBOUNDP (device) ? device : settings, flags);
801 mswindows_get_default_margin (Lisp_Object prop)
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;
812 plist_get_margin (Lisp_Object plist, Lisp_Object prop)
815 Fplist_get (plist, prop, make_int (mswindows_get_default_margin (prop)));
817 invalid_argument ("Margin value must be an integer", val);
819 return MulDiv (XINT (val), 100, 144);
823 plist_set_margin (Lisp_Object plist, Lisp_Object prop, int margin, int mm_p)
825 Lisp_Object val = make_int (MulDiv (margin, 144, mm_p ? 2450 : 100));
826 return Fcons (prop, Fcons (val, plist));
830 mswindows_handle_page_setup_dialog_box (struct frame *f, Lisp_Object keys)
832 Lisp_Object device = Qunbound, settings = Qunbound;
833 Lisp_Object plist = Qnil;
836 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
838 if (EQ (key, Q_device))
840 device = wrap_device (decode_device (value));
841 CHECK_MSPRINTER_DEVICE (device);
843 else if (EQ (key, Q_printer_settings))
845 CHECK_DEVMODE (value);
848 else if (EQ (key, Q_properties))
854 syntax_error ("Unrecognized page-setup dialog keyword", key);
858 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
859 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
860 syntax_error ("Exactly one of :device and :printer-settings must be given",
863 if (UNBOUNDP (device))
867 Lisp_Devmode *ldm = decode_devmode (device);
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);
880 if (!PageSetupDlg (&pd))
882 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
887 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
889 /* Finally, build the resulting plist */
891 Lisp_Object result = Qnil;
892 int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
893 result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
895 result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
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);
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.
911 struct device *d = decode_device (device);
912 XSETDEVICE (device, d);
913 CHECK_MSPRINTER_DEVICE (device);
914 return DEVICE_MSPRINTER_DEVMODE (d);
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.
925 A settings object can be selected to no more than one printer at a time.
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'.
932 Return value is the previously selected settings object.
937 struct device *d = decode_device (device);
942 XSETDEVICE (device, d);
943 CHECK_MSPRINTER_DEVICE (device);
944 CHECK_DEVMODE (settings);
945 ldm = XDEVMODE (settings);
947 if (!NILP (ldm->device))
948 invalid_operation ("The object is currently selected into a device",
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)
959 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
960 DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
962 invalid_operation ("Unable to specialize settings, printer error",
965 assert (XDEVMODE_SIZE (ldm) <= dm_size);
966 ldm->devmode = xrealloc (ldm->devmode, dm_size);
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,
974 error ("Printer device initialization I/O error, device deleted.");
976 if (ldm->printer_name == NULL)
977 ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
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;
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
998 Return value is the currently selected settings object.
1002 Lisp_Devmode *ldm_current, *ldm_new;
1003 struct device *d = decode_device (device);
1005 struct gcpro gcpro1;
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));
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.
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)));
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.");
1033 if (ldm_new->printer_name != NULL)
1035 xfree (ldm_current->printer_name);
1036 ldm_current->printer_name = xstrdup (ldm_new->printer_name);
1040 return DEVICE_MSPRINTER_DEVMODE (d);
1043 /************************************************************************/
1045 /************************************************************************/
1048 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1052 Lisp_Devmode *dm = XDEVMODE (obj);
1054 error ("printing unreadable object #<msprinter-settings 0x%x>",
1056 write_c_string ("#<msprinter-settings", printcharfun);
1057 if (dm->printer_name)
1059 write_c_string (" for \"", printcharfun);
1060 write_c_string (dm->printer_name, printcharfun);
1061 write_c_string ("\"", printcharfun);
1063 if (!NILP (dm->device))
1065 write_c_string (" (currently on ", printcharfun);
1066 print_internal (dm->device, printcharfun, 0);
1067 write_c_string (")", printcharfun);
1069 sprintf (buf, " 0x%x>", dm->header.uid);
1070 write_c_string (buf, printcharfun);
1074 finalize_devmode (void *header, int for_disksave)
1076 Lisp_Devmode *dm = (Lisp_Devmode *) header;
1080 Lisp_Object devmode;
1081 XSETDEVMODE (devmode, dm);
1083 ("Cannot dump XEmacs containing an msprinter-settings object",
1087 assert (NILP (dm->device));
1089 if (dm->printer_name)
1090 xfree (dm->printer_name);
1094 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1096 Lisp_Devmode *dm1 = XDEVMODE (obj1);
1097 Lisp_Devmode *dm2 = XDEVMODE (obj2);
1099 if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1101 if (dm1->devmode == NULL)
1103 if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1105 if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1107 return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1110 static unsigned long
1111 hash_devmode (Lisp_Object obj, int depth)
1113 Lisp_Devmode *dm = XDEVMODE (obj);
1115 return HASH3 (XDEVMODE_SIZE (dm),
1116 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1118 dm->printer_name ? string_hash (dm->printer_name) : 0);
1121 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1122 0/*mark*/, print_devmode, finalize_devmode,
1123 equal_devmode, hash_devmode, 0/*description*/,
1126 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1127 char* src_name, struct device *d)
1132 dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1135 XSETDEVICE (dm->device, d);
1139 dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1141 if (src_devmode != NULL && do_copy)
1143 dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1144 memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1148 dm->devmode = src_devmode;
1151 XSETDEVMODE (ob, dm);
1155 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1156 Create and returns an exact copy of a printer settings object.
1162 CHECK_DEVMODE (settings);
1163 dm = XDEVMODE (settings);
1165 return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1168 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1169 Erase printer-specific settings from a printer settings object.
1176 CHECK_DEVMODE (settings);
1177 ldm = XDEVMODE (settings);
1179 if (!NILP (ldm->device))
1180 invalid_operation ("The object is currently selected into a device",
1185 /* #### TODO. Either remove references to device specific bins,
1186 paper sizes etc, or signal an error of they are present. */
1188 dm->dmDriverExtra = 0;
1189 dm->dmDeviceName[0] = '\0';
1191 if (ldm->printer_name)
1192 xfree (ldm->printer_name);
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.
1202 return msprinter_default_printer ();
1206 signal_enum_printer_error (void)
1208 invalid_operation ("Error enumerating printers", make_int (GetLastError ()));
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.
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;
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);
1233 /* Allocate memory for printer enum structure */
1234 ok = EnumPrinters (enum_flags, NULL, enum_level, &dummy_byte, 1,
1235 &bytes_needed, &num_printers);
1237 /* No printers, if just 1 byte is enough */
1240 if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1241 signal_enum_printer_error ();
1243 data_buf = alloca (bytes_needed);
1244 ok = EnumPrinters (enum_flags, NULL, enum_level, data_buf, bytes_needed,
1245 &bytes_needed, &num_printers);
1247 signal_enum_printer_error ();
1249 if (num_printers == 0)
1250 /* Strange but... */
1253 GCPRO2 (result, def_printer);
1255 while (num_printers--)
1257 LPCTSTR printer_name;
1260 PRINTER_INFO_4 *info = (PRINTER_INFO_4*) data_buf;
1261 printer_name = info->pPrinterName;
1265 PRINTER_INFO_5 *info = (PRINTER_INFO_5*) data_buf;
1266 printer_name = info->pPrinterName;
1268 data_buf += enum_entry_size;
1270 result = Fcons (build_ext_string (printer_name, Qmswindows_tstr),
1274 def_printer = msprinter_default_printer ();
1275 result = Fdelete (def_printer, result);
1276 result = Fcons (def_printer, result);
1278 RETURN_UNGCPRO (result);
1282 /************************************************************************/
1283 /* initialization */
1284 /************************************************************************/
1287 syms_of_device_mswindows (void)
1289 INIT_LRECORD_IMPLEMENTATION (devmode);
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);
1299 DEFKEYWORD (Q_allow_selection);
1300 DEFKEYWORD (Q_allow_pages);
1301 DEFKEYWORD (Q_selected_page_button);
1302 DEFSYMBOL (Qselected_page_button);
1304 DEFSYMBOL (Qinit_pre_mswindows_win);
1305 DEFSYMBOL (Qinit_post_mswindows_win);
1309 console_type_create_device_mswindows (void)
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);
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));
1331 vars_of_device_mswindows (void)
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.
1337 Vmswindows_downcase_file_names = Qnil;
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.
1345 Vmswindows_get_true_file_attributes = Qnil;