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, int mm_p)
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), mm_p ? 254 : 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 ? 254 : 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);
872 GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_IMEASURE,
873 measure, sizeof(measure));
874 data = (strcmp (measure, "0"));
876 memset (&pd, 0, sizeof (pd));
877 pd.lStructSize = sizeof (pd);
878 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
879 pd.Flags = PSD_MARGINS;
880 pd.rtMargin.left = plist_get_margin (plist, Qleft_margin, !data);
881 pd.rtMargin.top = plist_get_margin (plist, Qtop_margin, !data);
882 pd.rtMargin.right = plist_get_margin (plist, Qright_margin, !data);
883 pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin, !data);
884 pd.hDevMode = devmode_to_hglobal (ldm);
886 if (!PageSetupDlg (&pd))
888 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
893 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
895 /* Finally, build the resulting plist */
897 Lisp_Object result = Qnil;
898 int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
899 result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
901 result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
903 result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
904 result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
910 DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
911 Return the settings object currently used by DEVICE.
912 The object returned is not a copy, but rather a pointer to the
913 original one. Use `msprinter-settings-copy' to create a copy of it.
917 struct device *d = decode_device (device);
918 XSETDEVICE (device, d);
919 CHECK_MSPRINTER_DEVICE (device);
920 return DEVICE_MSPRINTER_DEVMODE (d);
923 DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
924 Select SETTINGS object into a DEVICE.
925 The settings from the settings object are immediately applied to the
926 printer, possibly changing even the target printer itself, and all
927 future changes are applied synchronously to the printer device and the
928 selected printer object, until a different settings object is selected
929 into the same printer.
931 A settings object can be selected to no more than one printer at a time.
933 If the supplied settings object is not specialized, it is specialized
934 for the printer immediately upon selection. The object can be
935 despecialized after it is unselected by calling the function
936 `msprinter-settings-despecialize'.
938 Return value is the previously selected settings object.
943 struct device *d = decode_device (device);
948 XSETDEVICE (device, d);
949 CHECK_MSPRINTER_DEVICE (device);
950 CHECK_DEVMODE (settings);
951 ldm = XDEVMODE (settings);
953 if (!NILP (ldm->device))
954 invalid_operation ("The object is currently selected into a device",
957 /* If the object being selected is de-specialized, then its
958 size is perhaps not enough to receive the new devmode. We can ask
959 for printer's devmode size here, because despecialized settings
960 cannot force switching to a different printer, as they supply no
961 printer name at all. */
962 if (ldm->printer_name == NULL)
965 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
966 DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
968 invalid_operation ("Unable to specialize settings, printer error",
971 assert (XDEVMODE_SIZE (ldm) <= dm_size);
972 ldm->devmode = xrealloc (ldm->devmode, dm_size);
975 /* If we bail out on signal here, no damage is done, except that
976 the storage for the DEVMODE structure might be reallocated to
977 hold a larger one - not a big deal */
978 if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
980 error ("Printer device initialization I/O error, device deleted.");
982 if (ldm->printer_name == NULL)
983 ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
986 Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
987 ldm->device = device;
988 XDEVMODE (old_mode)->device = Qnil;
989 DEVICE_MSPRINTER_DEVMODE (d) = settings;
995 DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
996 Apply settings from a SETTINGS object to a 'msprinter DEVICE.
997 The settings from the settings object are immediately applied to the
998 printer, possibly changing even the target printer itself. The SETTING
999 object is not modified, unlike `msprinter-select-settings', and the
1000 supplied object is not changed. The changes are immediately recorded
1001 into the settings object which is currently selected into the printer
1004 Return value is the currently selected settings object.
1008 Lisp_Devmode *ldm_current, *ldm_new;
1009 struct device *d = decode_device (device);
1011 struct gcpro gcpro1;
1014 XSETDEVICE (device, d);
1015 CHECK_MSPRINTER_DEVICE (device);
1016 CHECK_DEVMODE (settings);
1017 ldm_new = XDEVMODE (settings);
1018 ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
1020 /* If the supplied devmode is not specialized, then the current
1021 devmode size will always be sufficient, as the printer does
1022 not change. If it is specialized, we must reallocate the current
1023 devmode storage to match with the supplied one, as it has the right
1024 size for the new printer, if it is going to change. The correct
1025 way is to use the largest of the two though, to keep the old
1026 contents unchanged in case of preliminary exit.
1028 if (ldm_new->printer_name)
1029 ldm_current->devmode =
1030 (DEVMODE*) xrealloc (ldm_current->devmode,
1031 max (XDEVMODE_SIZE (ldm_new),
1032 XDEVMODE_SIZE (ldm_current)));
1034 if (!sync_printer_with_devmode (d, ldm_new->devmode,
1035 ldm_current->devmode,
1036 ldm_new->printer_name))
1037 error ("Printer device initialization I/O error, device deleted.");
1039 if (ldm_new->printer_name != NULL)
1041 xfree (ldm_current->printer_name);
1042 ldm_current->printer_name = xstrdup (ldm_new->printer_name);
1046 return DEVICE_MSPRINTER_DEVMODE (d);
1049 /************************************************************************/
1051 /************************************************************************/
1054 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1058 Lisp_Devmode *dm = XDEVMODE (obj);
1060 error ("printing unreadable object #<msprinter-settings 0x%x>",
1062 write_c_string ("#<msprinter-settings", printcharfun);
1063 if (dm->printer_name)
1065 write_c_string (" for \"", printcharfun);
1066 write_c_string (dm->printer_name, printcharfun);
1067 write_c_string ("\"", printcharfun);
1069 if (!NILP (dm->device))
1071 write_c_string (" (currently on ", printcharfun);
1072 print_internal (dm->device, printcharfun, 0);
1073 write_c_string (")", printcharfun);
1075 sprintf (buf, " 0x%x>", dm->header.uid);
1076 write_c_string (buf, printcharfun);
1080 finalize_devmode (void *header, int for_disksave)
1082 Lisp_Devmode *dm = (Lisp_Devmode *) header;
1086 Lisp_Object devmode;
1087 XSETDEVMODE (devmode, dm);
1089 ("Cannot dump XEmacs containing an msprinter-settings object",
1093 assert (NILP (dm->device));
1095 if (dm->printer_name)
1096 xfree (dm->printer_name);
1100 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1102 Lisp_Devmode *dm1 = XDEVMODE (obj1);
1103 Lisp_Devmode *dm2 = XDEVMODE (obj2);
1105 if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1107 if (dm1->devmode == NULL)
1109 if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1111 if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1113 return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1116 static unsigned long
1117 hash_devmode (Lisp_Object obj, int depth)
1119 Lisp_Devmode *dm = XDEVMODE (obj);
1121 return HASH3 (XDEVMODE_SIZE (dm),
1122 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1124 dm->printer_name ? string_hash (dm->printer_name) : 0);
1127 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1128 0/*mark*/, print_devmode, finalize_devmode,
1129 equal_devmode, hash_devmode, 0/*description*/,
1132 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1133 char* src_name, struct device *d)
1138 dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1141 XSETDEVICE (dm->device, d);
1145 dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1147 if (src_devmode != NULL && do_copy)
1149 dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1150 memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1154 dm->devmode = src_devmode;
1157 XSETDEVMODE (ob, dm);
1161 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1162 Create and returns an exact copy of a printer settings object.
1168 CHECK_DEVMODE (settings);
1169 dm = XDEVMODE (settings);
1171 return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1174 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1175 Erase printer-specific settings from a printer settings object.
1182 CHECK_DEVMODE (settings);
1183 ldm = XDEVMODE (settings);
1185 if (!NILP (ldm->device))
1186 invalid_operation ("The object is currently selected into a device",
1191 /* #### TODO. Either remove references to device specific bins,
1192 paper sizes etc, or signal an error of they are present. */
1194 dm->dmDriverExtra = 0;
1195 dm->dmDeviceName[0] = '\0';
1197 if (ldm->printer_name)
1198 xfree (ldm->printer_name);
1203 DEFUN ("mswindows-get-default-printer", Fmswindows_get_default_printer, 0, 0, 0, /*
1204 Return name of the default printer, as string, on nil if there is no default.
1208 return msprinter_default_printer ();
1212 signal_enum_printer_error (void)
1214 invalid_operation ("Error enumerating printers", make_int (GetLastError ()));
1217 DEFUN ("mswindows-printer-list", Fmswindows_printer_list, 0, 0, 0, /*
1218 Return a list of string names of installed printers.
1219 If there is a default printer, it is returned as the first element of
1220 the list. If there is no default printer, the first element of the
1221 list will be nil. The rest of elements are guaranteed to have string
1222 values. Return value is nil if there are no printers installed.
1227 BYTE *data_buf, dummy_byte;
1228 size_t enum_entry_size;
1229 DWORD enum_flags, enum_level, bytes_needed, num_printers;
1230 struct gcpro gcpro1, gcpro2;
1231 Lisp_Object result = Qnil, def_printer = Qnil;
1233 /* Determine OS flavor, to use the fastest enumeration method available */
1234 have_nt = !mswindows_windows9x_p ();
1235 enum_flags = PRINTER_ENUM_LOCAL | (have_nt ? PRINTER_ENUM_CONNECTIONS : 0);
1236 enum_level = have_nt ? 4 : 5;
1237 enum_entry_size = have_nt ? sizeof (PRINTER_INFO_4) : sizeof (PRINTER_INFO_5);
1239 /* Allocate memory for printer enum structure */
1240 ok = EnumPrinters (enum_flags, NULL, enum_level, &dummy_byte, 1,
1241 &bytes_needed, &num_printers);
1243 /* No printers, if just 1 byte is enough */
1246 if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1247 signal_enum_printer_error ();
1249 data_buf = alloca (bytes_needed);
1250 ok = EnumPrinters (enum_flags, NULL, enum_level, data_buf, bytes_needed,
1251 &bytes_needed, &num_printers);
1253 signal_enum_printer_error ();
1255 if (num_printers == 0)
1256 /* Strange but... */
1259 GCPRO2 (result, def_printer);
1261 while (num_printers--)
1263 LPCTSTR printer_name;
1266 PRINTER_INFO_4 *info = (PRINTER_INFO_4*) data_buf;
1267 printer_name = info->pPrinterName;
1271 PRINTER_INFO_5 *info = (PRINTER_INFO_5*) data_buf;
1272 printer_name = info->pPrinterName;
1274 data_buf += enum_entry_size;
1276 result = Fcons (build_ext_string (printer_name, Qmswindows_tstr),
1280 def_printer = msprinter_default_printer ();
1281 result = Fdelete (def_printer, result);
1282 result = Fcons (def_printer, result);
1284 RETURN_UNGCPRO (result);
1288 /************************************************************************/
1289 /* initialization */
1290 /************************************************************************/
1293 syms_of_device_mswindows (void)
1295 INIT_LRECORD_IMPLEMENTATION (devmode);
1297 DEFSUBR (Fmsprinter_get_settings);
1298 DEFSUBR (Fmsprinter_select_settings);
1299 DEFSUBR (Fmsprinter_apply_settings);
1300 DEFSUBR (Fmsprinter_settings_copy);
1301 DEFSUBR (Fmsprinter_settings_despecialize);
1302 DEFSUBR (Fmswindows_get_default_printer);
1303 DEFSUBR (Fmswindows_printer_list);
1305 DEFKEYWORD (Q_allow_selection);
1306 DEFKEYWORD (Q_allow_pages);
1307 DEFKEYWORD (Q_selected_page_button);
1308 DEFSYMBOL (Qselected_page_button);
1310 DEFSYMBOL (Qinit_pre_mswindows_win);
1311 DEFSYMBOL (Qinit_post_mswindows_win);
1315 console_type_create_device_mswindows (void)
1317 CONSOLE_HAS_METHOD (mswindows, init_device);
1318 CONSOLE_HAS_METHOD (mswindows, finish_init_device);
1319 CONSOLE_HAS_METHOD (mswindows, mark_device);
1320 CONSOLE_HAS_METHOD (mswindows, delete_device);
1321 CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
1322 CONSOLE_IMPLEMENTATION_FLAGS (mswindows, XDEVIMPF_PIXEL_GEOMETRY);
1324 CONSOLE_HAS_METHOD (msprinter, init_device);
1325 CONSOLE_HAS_METHOD (msprinter, mark_device);
1326 CONSOLE_HAS_METHOD (msprinter, delete_device);
1327 CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
1328 CONSOLE_IMPLEMENTATION_FLAGS (msprinter, (XDEVIMPF_PIXEL_GEOMETRY
1329 | XDEVIMPF_IS_A_PRINTER
1330 | XDEVIMPF_NO_AUTO_REDISPLAY
1331 | XDEVIMPF_DONT_PREEMPT_REDISPLAY
1332 | XDEVIMPF_FRAMELESS_OK));
1337 vars_of_device_mswindows (void)
1339 DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
1340 Non-nil means convert all-upper case file names to lower case.
1341 This applies when performing completions and file name expansion.
1343 Vmswindows_downcase_file_names = Qnil;
1345 DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
1346 Non-nil means determine accurate link count in file-attributes.
1347 This option slows down file-attributes noticeably, so is disabled by
1348 default. Note that it is only useful for files on NTFS volumes,
1349 where hard links are supported.
1351 Vmswindows_get_true_file_attributes = Qnil;