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"
43 /* #### Andy, these includes might break cygwin compilation - kkm*/
47 #if !(defined (CYGWIN) || defined(MINGW))
48 # include <objbase.h> /* For CoInitialize */
51 /* win32 DDE management library globals */
53 DWORD mswindows_dde_mlid;
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 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 allocate_devmode (DEVMODE* src_devmode, int do_copy,
72 char* src_name, struct device *d);
74 /************************************************************************/
76 /************************************************************************/
79 build_syscolor_string (int idx)
81 return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
85 build_syscolor_cons (int index1, int index2)
87 Lisp_Object color1, color2;
90 color1 = build_syscolor_string (index1);
91 color2 = build_syscolor_string (index2);
92 RETURN_UNGCPRO (Fcons (color1, color2));
96 build_sysmetrics_cons (int index1, int index2)
98 return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
99 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
103 build_devicecaps_cons (HDC hdc, int index1, int index2)
105 return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
106 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
110 /************************************************************************/
111 /* display methods */
112 /************************************************************************/
115 mswindows_init_device (struct device *d, Lisp_Object props)
120 DEVICE_CLASS (d) = Qcolor;
121 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
125 d->device_data = xnew_and_zero (struct mswindows_device);
126 hdc = CreateCompatibleDC (NULL);
128 DEVICE_MSWINDOWS_HCDC(d) = hdc;
129 DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
130 DEVICE_MSWINDOWS_UPDATE_TICK (d) = GetTickCount ();
132 /* Register the main window class */
133 wc.cbSize = sizeof (WNDCLASSEX);
134 wc.style = CS_OWNDC; /* One DC per window */
135 wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
137 wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
138 /* This must match whatever is passed to CreateWIndowEx, NULL is ok
141 wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS);
142 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
143 /* Background brush is only used during sizing, when XEmacs cannot
145 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
146 wc.lpszMenuName = NULL;
148 wc.lpszClassName = XEMACS_CLASS;
149 wc.hIconSm = (HICON) LoadImage (GetModuleHandle (NULL), XEMACS_CLASS,
150 IMAGE_ICON, 16, 16, 0);
151 RegisterClassEx (&wc);
155 /* Register the main window class */
156 wc.cbSize = sizeof (WNDCLASSEX);
157 wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc;
158 wc.lpszClassName = XEMACS_CONTROL_CLASS;
160 RegisterClassEx (&wc);
163 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
164 InitCommonControls ();
169 mswindows_finish_init_device (struct device *d, Lisp_Object props)
171 /* Initialize DDE management library and our related globals. We execute a
172 * dde Open("file") by simulating a drop, so this depends on dnd support. */
173 #ifdef HAVE_DRAGNDROP
174 # if !(defined(CYGWIN) || defined(MINGW))
178 mswindows_dde_mlid = 0;
179 DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
180 APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
181 CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS,
184 mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
186 mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
188 mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
189 TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
190 DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
195 mswindows_delete_device (struct device *d)
197 #ifdef HAVE_DRAGNDROP
198 DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_UNREGISTER);
199 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_item_open);
200 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_topic_system);
201 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_service);
202 DdeUninitialize (mswindows_dde_mlid);
204 # if !(defined(CYGWIN) || defined(MINGW))
209 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
210 xfree (d->device_data);
214 mswindows_get_workspace_coords (RECT *rc)
216 SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
220 mswindows_mark_device (struct device *d)
222 mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
226 mswindows_device_system_metrics (struct device *d,
227 enum device_metrics m)
229 const HDC hdc = DEVICE_MSWINDOWS_HCDC(d);
234 return Fcons (make_int (GetDeviceCaps (hdc, HORZRES)),
235 make_int (GetDeviceCaps (hdc, VERTRES)));
238 return Fcons (make_int (GetDeviceCaps (hdc, LOGPIXELSX)),
239 make_int (GetDeviceCaps (hdc, LOGPIXELSY)));
241 case DM_size_device_mm:
242 return Fcons (make_int (GetDeviceCaps (hdc, HORZSIZE)),
243 make_int (GetDeviceCaps (hdc, VERTSIZE)));
245 case DM_num_bit_planes:
246 /* this is what X means by bitplanes therefore we ought to be
247 consistent. num planes is always 1 under mswindows and
249 return make_int (GetDeviceCaps (hdc, BITSPIXEL));
251 case DM_num_color_cells:
252 /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
253 what should we return for a non-palette-based device? */
254 return make_int (GetDeviceCaps (hdc, SIZEPALETTE));
258 #define FROB(met, fore, back) \
260 return build_syscolor_cons (fore, back);
262 FROB (color_default, COLOR_WINDOWTEXT, COLOR_WINDOW);
263 FROB (color_select, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
264 FROB (color_balloon, COLOR_INFOTEXT, COLOR_INFOBK);
265 FROB (color_3d_face, COLOR_BTNTEXT, COLOR_BTNFACE);
266 FROB (color_3d_light, COLOR_3DHILIGHT, COLOR_3DLIGHT);
267 FROB (color_3d_dark, COLOR_3DDKSHADOW, COLOR_3DSHADOW);
268 FROB (color_menu, COLOR_MENUTEXT, COLOR_MENU);
269 FROB (color_menu_highlight, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
270 FROB (color_menu_button, COLOR_MENUTEXT, COLOR_MENU);
271 FROB (color_menu_disabled, COLOR_GRAYTEXT, COLOR_MENU);
272 FROB (color_toolbar, COLOR_BTNTEXT, COLOR_BTNFACE);
273 FROB (color_scrollbar, COLOR_CAPTIONTEXT, COLOR_SCROLLBAR);
274 FROB (color_desktop, -1, COLOR_DESKTOP);
275 FROB (color_workspace, -1, COLOR_APPWORKSPACE);
279 #define FROB(met, index1, index2) \
281 return build_sysmetrics_cons (index1, index2);
283 FROB (size_cursor, SM_CXCURSOR, SM_CYCURSOR);
284 FROB (size_scrollbar, SM_CXVSCROLL, SM_CYHSCROLL);
285 FROB (size_menu, -1, SM_CYMENU);
286 FROB (size_icon, SM_CXICON, SM_CYICON);
287 FROB (size_icon_small, SM_CXSMICON, SM_CYSMICON);
290 case DM_size_workspace:
293 mswindows_get_workspace_coords (&rc);
294 return Fcons (make_int (rc.right - rc.left),
295 make_int (rc.bottom - rc.top));
298 case DM_offset_workspace:
301 mswindows_get_workspace_coords (&rc);
302 return Fcons (make_int (rc.left), make_int (rc.top));
306 case DM_size_toolbar:
307 case DM_size_toolbar_button:
308 case DM_size_toolbar_border:
312 #define FROB(met, index) \
314 return make_int (GetSystemMetrics (index));
316 FROB (mouse_buttons, SM_CMOUSEBUTTONS);
317 FROB (swap_buttons, SM_SWAPBUTTON);
318 FROB (show_sounds, SM_SHOWSOUNDS);
319 FROB (slow_device, SM_SLOWMACHINE);
320 FROB (security, SM_SECURE);
325 /* Do not know such property */
330 mswindows_device_implementation_flags (void)
332 return XDEVIMPF_PIXEL_GEOMETRY;
336 /************************************************************************/
337 /* printer helpers */
338 /************************************************************************/
341 signal_open_printer_error (struct device *d)
343 signal_simple_error ("Failed to open printer", DEVICE_CONNECTION (d));
347 /* Helper function */
349 msprinter_init_device_internal (struct device *d, char* printer_name)
351 DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
353 if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
355 DEVICE_MSPRINTER_HPRINTER (d) = NULL;
359 DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
361 if (DEVICE_MSPRINTER_HDC (d) == NULL)
364 DEVICE_MSPRINTER_HCDC(d) =
365 CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
367 DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
368 * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
369 > 1) ? Qcolor : Qmono;
374 msprinter_delete_device_internal (struct device *d)
376 if (DEVICE_MSPRINTER_HPRINTER (d))
377 ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
378 if (DEVICE_MSPRINTER_HDC (d))
379 DeleteDC (DEVICE_MSPRINTER_HDC (d));
380 if (DEVICE_MSPRINTER_HCDC (d))
381 DeleteDC (DEVICE_MSPRINTER_HCDC (d));
382 if (DEVICE_MSPRINTER_NAME (d))
383 xfree (DEVICE_MSPRINTER_NAME (d));
385 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
388 static int msprinter_reinit_device (struct device *d, char* devname)
390 msprinter_delete_device_internal (d);
391 return msprinter_init_device_internal (d, devname);
395 /************************************************************************/
396 /* printer methods */
397 /************************************************************************/
400 msprinter_init_device (struct device *d, Lisp_Object props)
406 d->device_data = xnew_and_zero (struct msprinter_device);
408 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
409 DEVICE_MSPRINTER_DEVMODE(d) = Qnil;
411 /* We do not use printer fon list as we do with the display
412 device. Rather, we allow GDI to pick the closest match to the
414 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
416 CHECK_STRING (DEVICE_CONNECTION (d));
418 TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
419 C_STRING_ALLOCA, printer_name,
422 if (!msprinter_init_device_internal (d, printer_name))
423 signal_open_printer_error (d);
425 /* Determinie DEVMODE size and store the default DEVMODE */
426 dm_size = DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
427 printer_name, NULL, NULL, 0);
429 signal_open_printer_error (d);
431 pdm = (DEVMODE*) xmalloc (dm_size);
432 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
434 NULL, DM_OUT_BUFFER);
436 assert (DEVMODE_SIZE (pdm) <= dm_size);
438 DEVICE_MSPRINTER_DEVMODE(d) =
439 allocate_devmode (pdm, 0, printer_name, d);
444 msprinter_delete_device (struct device *d)
448 msprinter_delete_device_internal (d);
450 /* Disassociate the selected devmode with the device */
451 if (!NILP (DEVICE_MSPRINTER_DEVMODE (d)))
453 XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d))->device = Qnil;
454 DEVICE_MSPRINTER_DEVMODE (d) = Qnil;
457 xfree (d->device_data);
462 msprinter_device_system_metrics (struct device *d,
463 enum device_metrics m)
467 /* Device sizes - pixel and mm */
468 #define FROB(met, index1, index2) \
470 return build_devicecaps_cons \
471 (DEVICE_MSPRINTER_HDC(d), index1, index2);
473 FROB (size_device, PHYSICALWIDTH, PHYSICALHEIGHT);
474 FROB (size_device_mm, HORZSIZE, VERTSIZE);
475 FROB (size_workspace, HORZRES, VERTRES);
476 FROB (offset_workspace, PHYSICALOFFSETX, PHYSICALOFFSETY);
477 FROB (device_dpi, LOGPIXELSX, LOGPIXELSY);
480 case DM_num_bit_planes:
481 /* this is what X means by bitplanes therefore we ought to be
482 consistent. num planes is always 1 under mswindows and
484 return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
486 case DM_num_color_cells: /* Prnters are non-palette devices */
487 case DM_slow_device: /* Animation would be a really bad idea */
488 case DM_security: /* Not provided by windows */
492 /* Do not know such property */
497 msprinter_mark_device (struct device *d)
499 mark_object (DEVICE_MSPRINTER_FONTLIST (d));
500 mark_object (DEVICE_MSPRINTER_DEVMODE (d));
504 msprinter_device_implementation_flags (void)
506 return ( XDEVIMPF_PIXEL_GEOMETRY
507 | XDEVIMPF_IS_A_PRINTER
508 | XDEVIMPF_NO_AUTO_REDISPLAY
509 | XDEVIMPF_FRAMELESS_OK );
512 /************************************************************************/
513 /* printer Lisp subroutines */
514 /************************************************************************/
517 global_free_2_maybe (HGLOBAL hg1, HGLOBAL hg2)
526 devmode_to_hglobal (Lisp_Devmode *ldm)
528 HGLOBAL hg = GlobalAlloc (GHND, XDEVMODE_SIZE (ldm));
529 memcpy (GlobalLock (hg), ldm->devmode, XDEVMODE_SIZE (ldm));
534 /* Returns 0 if the printer has been deleted due to a fatal I/O error,
537 sync_printer_with_devmode (struct device* d, DEVMODE* devmode_in,
538 DEVMODE* devmode_out, char* devname)
540 /* Change connection if the device changed */
542 && stricmp (devname, DEVICE_MSPRINTER_NAME(d)) != 0)
544 Lisp_Object new_connection = build_ext_string (devname, Qmswindows_tstr);
547 GCPRO1 (new_connection);
548 DEVICE_CONNECTION (d) = Qnil;
549 if (!NILP (Ffind_device (new_connection, Qmsprinter)))
551 /* We are in trouble - second msprinter for the same device.
552 Nothing wrong on the Windows side, just forge a unique
553 connection name. Use the memory address of d as a unique
555 char* new_connext = alloca (strlen (devname + 11));
556 sprintf (new_connext, "%s:%X", devname, d->header.uid);
557 new_connection = build_ext_string (devname, Qmswindows_tstr);
559 DEVICE_CONNECTION (d) = new_connection;
562 /* Reinitialize printer. The device can pop off in process */
563 if (!msprinter_reinit_device (d, devname))
566 delete_device_internal (d, 1, 0, 1);
571 /* Apply the new devmode to the printer */
572 DocumentProperties (NULL,
573 DEVICE_MSPRINTER_HPRINTER(d),
574 DEVICE_MSPRINTER_NAME(d),
575 devmode_out, devmode_in,
576 DM_IN_BUFFER | DM_OUT_BUFFER);
578 /* #### ResetDC fails sometimes, Bill only knows why.
579 The solution below looks more like a workaround to me,
580 although it might be fine. --kkm */
581 if (ResetDC (DEVICE_MSPRINTER_HDC (d), devmode_out) == NULL)
583 DeleteDC (DEVICE_MSPRINTER_HDC (d));
584 DEVICE_MSPRINTER_HDC (d) =
585 CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode_out);
592 handle_devmode_changes (Lisp_Devmode *ldm, HGLOBAL hDevNames, HGLOBAL hDevMode)
594 DEVNAMES* devnames = (DEVNAMES*) GlobalLock (hDevNames);
595 char *new_name = devnames ? (char*)devnames + devnames->wDeviceOffset : NULL;
596 DEVMODE* devmode = (DEVMODE*) GlobalLock (hDevMode);
598 /* Size and name may have changed */
599 ldm->devmode = xrealloc (ldm->devmode, DEVMODE_SIZE (devmode));
602 if (ldm->printer_name)
603 xfree (ldm->printer_name);
604 ldm->printer_name = xstrdup (new_name);
607 if (!NILP (ldm->device))
609 /* Apply the new devmode to the printer and get a compete one back */
610 struct device *d = XDEVICE (ldm->device);
611 if (!sync_printer_with_devmode (d, devmode, ldm->devmode, new_name))
613 global_free_2_maybe (hDevNames, hDevMode);
614 error ("Printer device initialization I/O error, device deleted.");
619 /* Just copy the devmode structure */
620 memcpy (ldm->devmode, devmode, DEVMODE_SIZE (devmode));
625 ensure_not_printing (struct device *d)
627 if (!NILP (DEVICE_FRAME_LIST (d)))
630 XSETDEVICE (device, d);
631 signal_simple_error ("Cannot change settings while print job is active",
636 static Lisp_Devmode *
637 decode_devmode (Lisp_Object dev)
640 return XDEVMODE (dev);
643 struct device* d = decode_device (dev);
645 XSETDEVICE (device, d);
646 CHECK_MSPRINTER_DEVICE (device);
647 ensure_not_printing (d);
648 return XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
653 * DEV can be either a printer or devmode
654 * PRINT_P is non-zero for the Print dialog, zero for the
658 print_dialog_worker (Lisp_Object dev, int print_p)
660 Lisp_Devmode *ldm = decode_devmode (dev);
663 memset (&pd, 0, sizeof (pd));
664 pd.lStructSize = sizeof (pd);
665 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
666 pd.hDevMode = devmode_to_hglobal (ldm);
667 pd.Flags = (PD_NOSELECTION | PD_USEDEVMODECOPIESANDCOLLATE
668 | (print_p ? 0 : PD_PRINTSETUP));
670 pd.nMaxPage = 0xFFFF;
674 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
678 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
680 /* Finally, build the resulting plist */
682 Lisp_Object result = Qnil;
686 /* Do consing in reverse order.
689 result = Fcons (Qcopies, Fcons (make_int (pd.nCopies), result));
692 if (print_p && (pd.Flags & PD_PAGENUMS))
694 result = Fcons (Qto_page, Fcons (make_int (pd.nToPage), result));
695 result = Fcons (Qfrom_page, Fcons (make_int (pd.nFromPage), result));
699 result = Fcons (Qname,
700 Fcons (build_ext_string (ldm->printer_name,
705 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
710 DEFUN ("msprinter-print-setup-dialog", Fmsprinter_print_setup_dialog, 1, 1, 0, /*
711 Invoke Windows standard Printer Setup dialog.
712 This dialog is usually invoked when the user selects the Printer Setup
715 DEVICE must be either an 'msprinter device, or a printer settings
716 object. The function brings up the Printer Setup dialog, where the user
717 can select a different printer and/or change printer options.
718 Connection name can change as a result of selecting a different printer
719 device. If a printer is specified, then changes are stored into the
720 settings object currently selected into that printer. If a settings
721 object is supplied, then changes are recorded into it, and, it it is
722 selected into a printer, then changes are propagated to that printer
725 Return value is nil if the user has canceled the dialog. Otherwise, it
726 is a new plist, with the following properties:
727 name Printer device name, even if unchanged by the user.
729 The printer device is destroyed and an error is signaled if new printer
730 is selected by the user, but cannot be initialized.
732 See also `msprinter-print-dialog' and `msprinter-page-setup-dialog'.
736 return print_dialog_worker (device, 0);
739 DEFUN ("msprinter-print-dialog", Fmsprinter_print_dialog, 1, 1, 0, /*
740 Invoke Windows standard Print dialog.
741 This dialog is usually invoked when the user selects the Print command.
742 After the user presses OK, the program should start actual printout.
744 DEVICE must be either an 'msprinter device, or a printer settings
745 object. The function brings up the Print dialog, where the user can
746 select a different printer and/or change printer options. Connection
747 name can change as a result of selecting a different printer device. If
748 a printer is specified, then changes are stored into the settings object
749 currently selected into that printer. If a settings object is supplied,
750 then changes are recorded into it, and, it it is selected into a
751 printer, then changes are propagated to that printer
754 Return value is nil if the user has canceled the dialog. Otherwise, it
755 is a new plist, with the following properties:
756 name Printer device name, even if unchanged by the user.
757 from-page First page to print, 1-based. If not specified by the user,
758 then this value is not included in the plist.
759 to-page Last page to print, inclusive, 1-based. If not specified by
760 the user, then this value is not included in the plist.
761 copies Number of copies to print. Always returned.
763 The DEVICE is destroyed and an error is signaled in case of
764 initialization problem with the new printer.
766 See also `msprinter-setup-print-dialog' and
767 `msprinter-page-setup-dialog'.
771 return print_dialog_worker (device, 1);
776 plist_get_margin (Lisp_Object plist, Lisp_Object prop)
778 Lisp_Object val = Fplist_get (plist, prop, make_int (1440));
780 signal_simple_error ("Margin value must be an integer", val);
782 return MulDiv (XINT (val), 100, 144);
786 plist_set_margin (Lisp_Object plist, Lisp_Object prop, int margin, int mm_p)
788 Lisp_Object val = make_int (MulDiv (margin, 144, mm_p ? 2450 : 100));
789 return Fcons (prop, Fcons (val, plist));
792 DEFUN ("msprinter-page-setup-dialog", Fmsprinter_page_setup_dialog, 1, 2, 0, /*
793 Invoke Windows standard Page Setup dialog.
794 This dialog is usually invoked in response to Page Setup command, and
795 used to chose such parameters as page orientation, print margins etc.
796 Note that this dialog contains the "Printer" button, which invokes
797 Printer Setup dialog (see `msprinter-print-setup-dialog') so that the
798 user can update the printer options or even select a different printer
801 DEVICE must be either an 'msprinter device, or a printer settings
802 object. The function brings up the Page Setup dialog, where the user
803 can select a different printer and/or change printer options.
804 Connection name can change as a result of selecting a different printer
805 device. If a printer is specified, then changes are stored into the
806 settings object currently selected into that printer. If a settings
807 object is supplied, then changes are recorded into it, and, it it is
808 selected into a printer, then changes are propagated to that printer
811 PLIST is a plist of job properties;
812 see `default-msprinter-frame-plist' for the complete list. The plist
813 is used to initialize the dialog.
815 Return value is nil if the user has canceled the dialog. Otherwise,
816 it is a new plist, containing the new list of properties.
818 The DEVICE is destroyed and an error is signaled in case of
819 initialization problem with the new printer.
821 See also `msprinter-print-setup-dialog' and `msprinter-print-dialog'.
825 Lisp_Devmode *ldm = decode_devmode (device);
828 memset (&pd, 0, sizeof (pd));
829 pd.lStructSize = sizeof (pd);
830 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
831 pd.Flags = PSD_MARGINS;
832 pd.rtMargin.left = plist_get_margin (plist, Qleft_margin);
833 pd.rtMargin.top = plist_get_margin (plist, Qtop_margin);
834 pd.rtMargin.right = plist_get_margin (plist, Qright_margin);
835 pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin);
836 pd.hDevMode = devmode_to_hglobal (ldm);
838 if (!PageSetupDlg (&pd))
840 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
845 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
847 /* Finally, build the resulting plist */
849 Lisp_Object result = Qnil;
850 int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
851 result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom, mm_p);
852 result = plist_set_margin (result, Qright_margin, pd.rtMargin.right, mm_p);
853 result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
854 result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
859 DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
860 Return the settings object currently used by DEVICE.
861 The object returned is not a copy, but rather a pointer to the
862 original one. Use `msprinter-settings-copy' to create a copy of it.
866 struct device *d = decode_device (device);
867 XSETDEVICE (device, d);
868 CHECK_MSPRINTER_DEVICE (device);
869 return DEVICE_MSPRINTER_DEVMODE (d);
872 DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
873 Select SETTINGS object into a DEVICE.
874 The settings from the settings object are immediately applied to the
875 printer, possibly changing even the target printer itself, and all
876 future changes are applied synchronously to the printer device and the
877 selected printer object, until a different settings object is selected
878 into the same printer.
880 A settings object can be selected to no more than one printer at a time.
882 If the supplied settings object is not specialized, it is specialized
883 for the printer immediately upon selection. The object can be
884 despecialized after it is unselected by calling the function
885 `msprinter-settings-despecialize'.
887 Return value is the previously selected settings object.
892 struct device *d = decode_device (device);
897 XSETDEVICE (device, d);
898 CHECK_MSPRINTER_DEVICE (device);
899 CHECK_DEVMODE (settings);
900 ldm = XDEVMODE (settings);
902 if (!NILP (ldm->device))
903 signal_simple_error ("The object is currently selected into a device",
906 /* If the object being selected is de-specialized, then its
907 size is perhaps not enough to receive the new devmode. We can ask
908 for printer's devmode size here, because despecialized settings
909 cannot force switching to a different printer, as they supply no
910 printer name at all. */
911 if (ldm->printer_name == NULL)
914 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
915 DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
917 signal_simple_error ("Unable to specialize settings, printer error",
920 assert (XDEVMODE_SIZE (ldm) <= dm_size);
921 ldm->devmode = xrealloc (ldm->devmode, dm_size);
924 /* If we bail out on signal here, no damage is done, except that
925 the stirage for the DEVMODE structure might be reallocated to
926 hold a larger one - not a big deal */
927 if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
929 error ("Printer device initialization I/O error, device deleted.");
931 if (ldm->printer_name == NULL)
932 ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
935 Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
936 ldm->device = device;
937 XDEVMODE (old_mode)->device = Qnil;
938 DEVICE_MSPRINTER_DEVMODE (d) = settings;
944 DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
945 Apply settings from a SETTINGS object to a 'msprinter DEVICE.
946 The settings from the settings object are immediately applied to the
947 printer, possibly changing even the target printer itself. The SETTING
948 object is not modified, unlike `msprinter-select-settings', and the
949 supplied object is not changed. The changes are immediately recorded
950 into the settings object which is currently selected into the printer
953 Return value is the currently selected settings object.
957 Lisp_Devmode *ldm_current, *ldm_new;
958 struct device *d = decode_device (device);
963 XSETDEVICE (device, d);
964 CHECK_MSPRINTER_DEVICE (device);
965 CHECK_DEVMODE (settings);
966 ldm_new = XDEVMODE (settings);
967 ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
969 /* If the supplied devmode is not specialized, then the current
970 devmode size will always be sufficient, as the printer does
971 not change. If it is specialized, we must reallocate the cuttent
972 devmode storage to match with the supplied one, as it has the right
973 size for the new printer, if it is going to change. The correct
974 way is to use the largest of the two though, to keep the old
975 contents unchanged in case of preliminary exit.
977 if (ldm_new->printer_name)
978 ldm_current->devmode =
979 (DEVMODE*) xrealloc (ldm_current->devmode,
980 max (XDEVMODE_SIZE (ldm_new),
981 XDEVMODE_SIZE (ldm_current)));
983 if (!sync_printer_with_devmode (d, ldm_new->devmode,
984 ldm_current->devmode,
985 ldm_new->printer_name))
986 error ("Printer device initialization I/O error, device deleted.");
988 if (ldm_new->printer_name != NULL)
990 xfree (ldm_current->printer_name);
991 ldm_current->printer_name = xstrdup (ldm_new->printer_name);
994 return DEVICE_MSPRINTER_DEVMODE (d);
997 /************************************************************************/
999 /************************************************************************/
1002 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1006 Lisp_Devmode *dm = XDEVMODE (obj);
1008 error ("printing unreadable object #<msprinter-settings 0x%x>",
1010 write_c_string ("#<msprinter-settings", printcharfun);
1011 if (dm->printer_name)
1013 write_c_string (" for \"", printcharfun);
1014 write_c_string (dm->printer_name, printcharfun);
1015 write_c_string ("\"", printcharfun);
1017 if (!NILP (dm->device))
1019 write_c_string (" (currently on ", printcharfun);
1020 print_internal (dm->device, printcharfun, 0);
1021 write_c_string (")", printcharfun);
1023 sprintf (buf, " 0x%x>", dm->header.uid);
1024 write_c_string (buf, printcharfun);
1028 finalize_devmode (void *header, int for_disksave)
1030 Lisp_Devmode *dm = (Lisp_Devmode *) header;
1034 Lisp_Object devmode;
1035 XSETDEVMODE (devmode, dm);
1036 signal_simple_error (
1037 "Cannot dump XEmacs containing an msprinter-settings object",
1041 assert (NILP (dm->device));
1043 if (dm->printer_name)
1044 xfree (dm->printer_name);
1048 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1050 Lisp_Devmode *dm1 = XDEVMODE (obj1);
1051 Lisp_Devmode *dm2 = XDEVMODE (obj2);
1053 if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1055 if (dm1->devmode == NULL)
1057 if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1059 if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1061 return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1064 static unsigned long
1065 hash_devmode (Lisp_Object obj, int depth)
1067 Lisp_Devmode *dm = XDEVMODE (obj);
1069 return HASH3 (XDEVMODE_SIZE (dm),
1070 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1072 dm->printer_name ? string_hash (dm->printer_name) : 0);
1075 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1076 0/*mark*/, print_devmode, finalize_devmode,
1077 equal_devmode, hash_devmode, 0/*description*/,
1080 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1081 char* src_name, struct device *d)
1086 dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1089 XSETDEVICE (dm->device, d);
1093 dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1095 if (src_devmode != NULL && do_copy)
1097 dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1098 memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1102 dm->devmode = src_devmode;
1105 XSETDEVMODE (ob, dm);
1109 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1110 Create and returns an exact copy of a printer settings object.
1116 CHECK_DEVMODE (settings);
1117 dm = XDEVMODE (settings);
1119 return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1122 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1123 Erase printer-specific settings from a printer settings object.
1130 CHECK_DEVMODE (settings);
1131 ldm = XDEVMODE (settings);
1133 if (!NILP (ldm->device))
1134 signal_simple_error ("The object is currently selected into a device",
1139 /* #### TODO. Either remove references to device specific bins,
1140 paper sizes etc, or signal an error of they are present. */
1142 dm->dmDriverExtra = 0;
1143 dm->dmDeviceName[0] = '\0';
1145 if (ldm->printer_name)
1146 xfree (ldm->printer_name);
1152 /************************************************************************/
1153 /* initialization */
1154 /************************************************************************/
1157 syms_of_device_mswindows (void)
1159 INIT_LRECORD_IMPLEMENTATION (devmode);
1161 DEFSUBR (Fmsprinter_print_setup_dialog);
1162 DEFSUBR (Fmsprinter_print_dialog);
1163 DEFSUBR (Fmsprinter_page_setup_dialog);
1164 DEFSUBR (Fmsprinter_get_settings);
1165 DEFSUBR (Fmsprinter_select_settings);
1166 DEFSUBR (Fmsprinter_apply_settings);
1167 DEFSUBR (Fmsprinter_settings_copy);
1168 DEFSUBR (Fmsprinter_settings_despecialize);
1170 defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win");
1171 defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win");
1175 console_type_create_device_mswindows (void)
1177 CONSOLE_HAS_METHOD (mswindows, init_device);
1178 CONSOLE_HAS_METHOD (mswindows, finish_init_device);
1179 CONSOLE_HAS_METHOD (mswindows, mark_device);
1180 CONSOLE_HAS_METHOD (mswindows, delete_device);
1181 CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
1182 CONSOLE_HAS_METHOD (mswindows, device_implementation_flags);
1184 CONSOLE_HAS_METHOD (msprinter, init_device);
1185 CONSOLE_HAS_METHOD (msprinter, mark_device);
1186 CONSOLE_HAS_METHOD (msprinter, delete_device);
1187 CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
1188 CONSOLE_HAS_METHOD (msprinter, device_implementation_flags);
1193 vars_of_device_mswindows (void)
1195 DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
1196 Non-nil means convert all-upper case file names to lower case.
1197 This applies when performing completions and file name expansion.
1199 Vmswindows_downcase_file_names = Qnil;
1201 DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
1202 Non-nil means determine accurate link count in file-attributes.
1203 This option slows down file-attributes noticeably, so is disabled by
1204 default. Note that it is only useful for files on NTFS volumes,
1205 where hard links are supported.
1207 Vmswindows_get_true_file_attributes = Qnil;