+Lisp_Object
+mswindows_handle_page_setup_dialog_box (struct frame *f, Lisp_Object keys)
+{
+ Lisp_Object device = Qunbound, settings = Qunbound;
+ Lisp_Object plist = Qnil;
+
+ {
+ EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
+ {
+ if (EQ (key, Q_device))
+ {
+ device = wrap_device (decode_device (value));
+ CHECK_MSPRINTER_DEVICE (device);
+ }
+ else if (EQ (key, Q_printer_settings))
+ {
+ CHECK_DEVMODE (value);
+ settings = value;
+ }
+ else if (EQ (key, Q_properties))
+ {
+ CHECK_LIST (value);
+ plist = value;
+ }
+ else
+ syntax_error ("Unrecognized page-setup dialog keyword", key);
+ }
+ }
+
+ if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
+ (!UNBOUNDP (device) && !UNBOUNDP (settings)))
+ syntax_error ("Exactly one of :device and :printer-settings must be given",
+ keys);
+
+ if (UNBOUNDP (device))
+ device = settings;
+
+ {
+ Lisp_Devmode *ldm = decode_devmode (device);
+ PAGESETUPDLG pd;
+ TCHAR measure[2];
+ int data;
+
+ GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_IMEASURE,
+ measure, sizeof(measure));
+ data = (strcmp (measure, "0"));
+
+ memset (&pd, 0, sizeof (pd));
+ pd.lStructSize = sizeof (pd);
+ pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
+ pd.Flags = PSD_MARGINS;
+ pd.rtMargin.left = plist_get_margin (plist, Qleft_margin, !data);
+ pd.rtMargin.top = plist_get_margin (plist, Qtop_margin, !data);
+ pd.rtMargin.right = plist_get_margin (plist, Qright_margin, !data);
+ pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin, !data);
+ pd.hDevMode = devmode_to_hglobal (ldm);
+
+ if (!PageSetupDlg (&pd))
+ {
+ global_free_2_maybe (pd.hDevNames, pd.hDevMode);
+ return Qnil;
+ }
+
+ if (pd.hDevMode)
+ handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
+
+ /* Finally, build the resulting plist */
+ {
+ Lisp_Object result = Qnil;
+ int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
+ result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
+ mm_p);
+ result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
+ mm_p);
+ result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
+ result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
+ return result;
+ }
+ }
+}
+
+DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
+Return the settings object currently used by DEVICE.
+The object returned is not a copy, but rather a pointer to the
+original one. Use `msprinter-settings-copy' to create a copy of it.
+*/
+ (device))
+{
+ struct device *d = decode_device (device);
+ XSETDEVICE (device, d);
+ CHECK_MSPRINTER_DEVICE (device);
+ return DEVICE_MSPRINTER_DEVMODE (d);
+}
+
+DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
+Select SETTINGS object into a DEVICE.
+The settings from the settings object are immediately applied to the
+printer, possibly changing even the target printer itself, and all
+future changes are applied synchronously to the printer device and the
+selected printer object, until a different settings object is selected
+into the same printer.
+
+A settings object can be selected to no more than one printer at a time.
+
+If the supplied settings object is not specialized, it is specialized
+for the printer immediately upon selection. The object can be
+despecialized after it is unselected by calling the function
+`msprinter-settings-despecialize'.
+
+Return value is the previously selected settings object.
+*/
+ (device, settings))
+{
+ Lisp_Devmode *ldm;
+ struct device *d = decode_device (device);
+
+ struct gcpro gcpro1;
+ GCPRO1 (settings);
+
+ XSETDEVICE (device, d);
+ CHECK_MSPRINTER_DEVICE (device);
+ CHECK_DEVMODE (settings);
+ ldm = XDEVMODE (settings);
+
+ if (!NILP (ldm->device))
+ invalid_operation ("The object is currently selected into a device",
+ settings);
+
+ /* If the object being selected is de-specialized, then its
+ size is perhaps not enough to receive the new devmode. We can ask
+ for printer's devmode size here, because despecialized settings
+ cannot force switching to a different printer, as they supply no
+ printer name at all. */
+ if (ldm->printer_name == NULL)
+ {
+ size_t dm_size =
+ DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
+ DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
+ if (dm_size <= 0)
+ invalid_operation ("Unable to specialize settings, printer error",
+ device);
+
+ assert (XDEVMODE_SIZE (ldm) <= dm_size);
+ ldm->devmode = xrealloc (ldm->devmode, dm_size);
+ }
+
+ /* If we bail out on signal here, no damage is done, except that
+ the storage for the DEVMODE structure might be reallocated to
+ hold a larger one - not a big deal */
+ if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
+ ldm->printer_name))
+ error ("Printer device initialization I/O error, device deleted.");
+
+ if (ldm->printer_name == NULL)
+ ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
+
+ {
+ Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
+ ldm->device = device;
+ XDEVMODE (old_mode)->device = Qnil;
+ DEVICE_MSPRINTER_DEVMODE (d) = settings;
+ UNGCPRO;
+ return old_mode;
+ }
+}
+
+DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
+Apply settings from a SETTINGS object to a 'msprinter DEVICE.
+The settings from the settings object are immediately applied to the
+printer, possibly changing even the target printer itself. The SETTING
+object is not modified, unlike `msprinter-select-settings', and the
+supplied object is not changed. The changes are immediately recorded
+into the settings object which is currently selected into the printer
+device.
+
+Return value is the currently selected settings object.
+*/
+ (device, settings))
+{
+ Lisp_Devmode *ldm_current, *ldm_new;
+ struct device *d = decode_device (device);
+
+ struct gcpro gcpro1;
+ GCPRO1 (settings);
+
+ XSETDEVICE (device, d);
+ CHECK_MSPRINTER_DEVICE (device);
+ CHECK_DEVMODE (settings);
+ ldm_new = XDEVMODE (settings);
+ ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
+
+ /* If the supplied devmode is not specialized, then the current
+ devmode size will always be sufficient, as the printer does
+ not change. If it is specialized, we must reallocate the current
+ devmode storage to match with the supplied one, as it has the right
+ size for the new printer, if it is going to change. The correct
+ way is to use the largest of the two though, to keep the old
+ contents unchanged in case of preliminary exit.
+ */
+ if (ldm_new->printer_name)
+ ldm_current->devmode =
+ (DEVMODE*) xrealloc (ldm_current->devmode,
+ max (XDEVMODE_SIZE (ldm_new),
+ XDEVMODE_SIZE (ldm_current)));
+
+ if (!sync_printer_with_devmode (d, ldm_new->devmode,
+ ldm_current->devmode,
+ ldm_new->printer_name))
+ error ("Printer device initialization I/O error, device deleted.");
+
+ if (ldm_new->printer_name != NULL)
+ {
+ xfree (ldm_current->printer_name);
+ ldm_current->printer_name = xstrdup (ldm_new->printer_name);
+ }
+
+ UNGCPRO;
+ return DEVICE_MSPRINTER_DEVMODE (d);
+}