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 HSZ mswindows_dde_service;
54 HSZ mswindows_dde_topic_system;
55 HSZ mswindows_dde_item_open;
58 /* Control conversion of upper case file names to lower case.
59 nil means no, t means yes. */
60 Lisp_Object Vmswindows_downcase_file_names;
62 /* Control whether xemacs_stat() attempts to determine file type and link count
63 exactly, at the expense of slower operation. Since true hard links
64 are supported on NTFS volumes, this is only relevant on NT. */
65 Lisp_Object Vmswindows_get_true_file_attributes;
67 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
68 Lisp_Object Qdevmodep;
70 static Lisp_Object Q_allow_selection;
71 static Lisp_Object Q_allow_pages;
72 static Lisp_Object Q_selected_page_button;
73 static Lisp_Object Qselected_page_button;
75 static Lisp_Object allocate_devmode (DEVMODE* src_devmode, int do_copy,
76 char* src_name, struct device *d);
78 /************************************************************************/
80 /************************************************************************/
83 build_syscolor_string (int idx)
85 return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
89 build_syscolor_cons (int index1, int index2)
91 Lisp_Object color1, color2;
94 color1 = build_syscolor_string (index1);
95 color2 = build_syscolor_string (index2);
96 RETURN_UNGCPRO (Fcons (color1, color2));
100 build_sysmetrics_cons (int index1, int index2)
102 return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
103 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
107 build_devicecaps_cons (HDC hdc, int index1, int index2)
109 return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
110 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
114 /************************************************************************/
115 /* display methods */
116 /************************************************************************/
119 mswindows_init_device (struct device *d, Lisp_Object props)
124 DEVICE_CLASS (d) = Qcolor;
125 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
129 d->device_data = xnew_and_zero (struct mswindows_device);
130 hdc = CreateCompatibleDC (NULL);
132 DEVICE_MSWINDOWS_HCDC(d) = hdc;
133 DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
134 DEVICE_MSWINDOWS_UPDATE_TICK (d) = GetTickCount ();
136 /* Register the main window class */
137 wc.cbSize = sizeof (WNDCLASSEX);
138 wc.style = CS_OWNDC; /* One DC per window */
139 wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
141 wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
142 /* This must match whatever is passed to CreateWIndowEx, NULL is ok
145 wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS);
146 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
147 /* Background brush is only used during sizing, when XEmacs cannot
149 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
150 wc.lpszMenuName = NULL;
152 wc.lpszClassName = XEMACS_CLASS;
153 if (xLoadImageA) /* not in NT 3.5 */
154 wc.hIconSm = (HICON) xLoadImageA (GetModuleHandle (NULL), XEMACS_CLASS,
155 IMAGE_ICON, 16, 16, 0);
159 if (xRegisterClassExA) /* not in NT 3.5 */
160 xRegisterClassExA (&wc);
162 RegisterClassA ((WNDCLASS *) &wc.style);
166 /* Register the main window class */
167 wc.cbSize = sizeof (WNDCLASSEX);
168 wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc;
169 wc.lpszClassName = XEMACS_CONTROL_CLASS;
171 if (xRegisterClassExA) /* not in NT 3.5 */
172 xRegisterClassExA (&wc);
174 RegisterClassA ((WNDCLASS *) &wc.style);
177 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
178 InitCommonControls ();
183 mswindows_finish_init_device (struct device *d, Lisp_Object props)
185 /* Initialize DDE management library and our related globals. We execute a
186 * dde Open("file") by simulating a drop, so this depends on dnd support. */
187 #ifdef HAVE_DRAGNDROP
188 # if !(defined(CYGWIN) || defined(MINGW))
192 mswindows_dde_mlid = 0;
193 DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
194 APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
195 CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS,
198 mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
200 mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
202 mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
203 TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
204 DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
209 mswindows_delete_device (struct device *d)
211 #ifdef HAVE_DRAGNDROP
212 DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_UNREGISTER);
213 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_item_open);
214 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_topic_system);
215 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_service);
216 DdeUninitialize (mswindows_dde_mlid);
218 # if !(defined(CYGWIN) || defined(MINGW))
223 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
224 xfree (d->device_data);
228 mswindows_get_workspace_coords (RECT *rc)
230 SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
234 mswindows_mark_device (struct device *d)
236 mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
240 mswindows_device_system_metrics (struct device *d,
241 enum device_metrics m)
243 const HDC hdc = DEVICE_MSWINDOWS_HCDC(d);
248 return Fcons (make_int (GetDeviceCaps (hdc, HORZRES)),
249 make_int (GetDeviceCaps (hdc, VERTRES)));
252 return Fcons (make_int (GetDeviceCaps (hdc, LOGPIXELSX)),
253 make_int (GetDeviceCaps (hdc, LOGPIXELSY)));
255 case DM_size_device_mm:
256 return Fcons (make_int (GetDeviceCaps (hdc, HORZSIZE)),
257 make_int (GetDeviceCaps (hdc, VERTSIZE)));
259 case DM_num_bit_planes:
260 /* this is what X means by bitplanes therefore we ought to be
261 consistent. num planes is always 1 under mswindows and
263 return make_int (GetDeviceCaps (hdc, BITSPIXEL));
265 case DM_num_color_cells:
266 /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
267 what should we return for a non-palette-based device? */
268 return make_int (GetDeviceCaps (hdc, SIZEPALETTE));
272 #define FROB(met, fore, back) \
274 return build_syscolor_cons (fore, back);
276 FROB (color_default, COLOR_WINDOWTEXT, COLOR_WINDOW);
277 FROB (color_select, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
278 FROB (color_balloon, COLOR_INFOTEXT, COLOR_INFOBK);
279 FROB (color_3d_face, COLOR_BTNTEXT, COLOR_BTNFACE);
280 FROB (color_3d_light, COLOR_3DHILIGHT, COLOR_3DLIGHT);
281 FROB (color_3d_dark, COLOR_3DDKSHADOW, COLOR_3DSHADOW);
282 FROB (color_menu, COLOR_MENUTEXT, COLOR_MENU);
283 FROB (color_menu_highlight, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
284 FROB (color_menu_button, COLOR_MENUTEXT, COLOR_MENU);
285 FROB (color_menu_disabled, COLOR_GRAYTEXT, COLOR_MENU);
286 FROB (color_toolbar, COLOR_BTNTEXT, COLOR_BTNFACE);
287 FROB (color_scrollbar, COLOR_CAPTIONTEXT, COLOR_SCROLLBAR);
288 FROB (color_desktop, -1, COLOR_DESKTOP);
289 FROB (color_workspace, -1, COLOR_APPWORKSPACE);
293 #define FROB(met, index1, index2) \
295 return build_sysmetrics_cons (index1, index2);
297 FROB (size_cursor, SM_CXCURSOR, SM_CYCURSOR);
298 FROB (size_scrollbar, SM_CXVSCROLL, SM_CYHSCROLL);
299 FROB (size_menu, -1, SM_CYMENU);
300 FROB (size_icon, SM_CXICON, SM_CYICON);
301 FROB (size_icon_small, SM_CXSMICON, SM_CYSMICON);
304 case DM_size_workspace:
307 mswindows_get_workspace_coords (&rc);
308 return Fcons (make_int (rc.right - rc.left),
309 make_int (rc.bottom - rc.top));
312 case DM_offset_workspace:
315 mswindows_get_workspace_coords (&rc);
316 return Fcons (make_int (rc.left), make_int (rc.top));
320 case DM_size_toolbar:
321 case DM_size_toolbar_button:
322 case DM_size_toolbar_border:
326 #define FROB(met, index) \
328 return make_int (GetSystemMetrics (index));
330 FROB (mouse_buttons, SM_CMOUSEBUTTONS);
331 FROB (swap_buttons, SM_SWAPBUTTON);
332 FROB (show_sounds, SM_SHOWSOUNDS);
333 FROB (slow_device, SM_SLOWMACHINE);
334 FROB (security, SM_SECURE);
339 /* Do not know such property */
344 mswindows_device_implementation_flags (void)
346 return XDEVIMPF_PIXEL_GEOMETRY;
350 /************************************************************************/
351 /* printer helpers */
352 /************************************************************************/
355 signal_open_printer_error (struct device *d)
357 invalid_operation ("Failed to open printer", DEVICE_CONNECTION (d));
361 /* Helper function */
363 msprinter_init_device_internal (struct device *d, char* printer_name)
365 DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
367 if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
369 DEVICE_MSPRINTER_HPRINTER (d) = NULL;
373 DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
375 if (DEVICE_MSPRINTER_HDC (d) == NULL)
378 DEVICE_MSPRINTER_HCDC(d) =
379 CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
381 DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
382 * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
383 > 1) ? Qcolor : Qmono;
388 msprinter_delete_device_internal (struct device *d)
390 if (DEVICE_MSPRINTER_HPRINTER (d))
391 ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
392 if (DEVICE_MSPRINTER_HDC (d))
393 DeleteDC (DEVICE_MSPRINTER_HDC (d));
394 if (DEVICE_MSPRINTER_HCDC (d))
395 DeleteDC (DEVICE_MSPRINTER_HCDC (d));
396 if (DEVICE_MSPRINTER_NAME (d))
397 xfree (DEVICE_MSPRINTER_NAME (d));
399 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
403 msprinter_reinit_device (struct device *d, char* devname)
405 msprinter_delete_device_internal (d);
406 return msprinter_init_device_internal (d, devname);
410 msprinter_default_printer (void)
415 if (GetProfileString (XETEXT ("windows"), XETEXT ("device"), NULL, name,
416 sizeof (name) / XETCHAR_SIZE) <= 0)
418 EXTERNAL_TO_C_STRING (name, nameint, Qmswindows_tstr);
424 return build_string (name);
428 /************************************************************************/
429 /* printer methods */
430 /************************************************************************/
433 msprinter_init_device (struct device *d, Lisp_Object props)
439 d->device_data = xnew_and_zero (struct msprinter_device);
441 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
442 DEVICE_MSPRINTER_DEVMODE(d) = Qnil;
444 /* We do not use printer fon list as we do with the display
445 device. Rather, we allow GDI to pick the closest match to the
447 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
449 CHECK_STRING (DEVICE_CONNECTION (d));
451 TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
452 C_STRING_ALLOCA, printer_name,
455 if (!msprinter_init_device_internal (d, printer_name))
456 signal_open_printer_error (d);
458 /* Determine DEVMODE size and store the default DEVMODE */
459 dm_size = DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER (d),
460 printer_name, NULL, NULL, 0);
462 signal_open_printer_error (d);
464 pdm = (DEVMODE*) xmalloc (dm_size);
465 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
467 NULL, DM_OUT_BUFFER);
469 assert (DEVMODE_SIZE (pdm) <= dm_size);
471 DEVICE_MSPRINTER_DEVMODE(d) =
472 allocate_devmode (pdm, 0, printer_name, d);
477 msprinter_delete_device (struct device *d)
481 msprinter_delete_device_internal (d);
483 /* Disassociate the selected devmode with the device */
484 if (!NILP (DEVICE_MSPRINTER_DEVMODE (d)))
486 XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d))->device = Qnil;
487 DEVICE_MSPRINTER_DEVMODE (d) = Qnil;
490 xfree (d->device_data);
495 msprinter_device_system_metrics (struct device *d,
496 enum device_metrics m)
500 /* Device sizes - pixel and mm */
501 #define FROB(met, index1, index2) \
503 return build_devicecaps_cons \
504 (DEVICE_MSPRINTER_HDC(d), index1, index2);
506 FROB (size_device, PHYSICALWIDTH, PHYSICALHEIGHT);
507 FROB (size_device_mm, HORZSIZE, VERTSIZE);
508 FROB (size_workspace, HORZRES, VERTRES);
509 FROB (offset_workspace, PHYSICALOFFSETX, PHYSICALOFFSETY);
510 FROB (device_dpi, LOGPIXELSX, LOGPIXELSY);
513 case DM_num_bit_planes:
514 /* this is what X means by bitplanes therefore we ought to be
515 consistent. num planes is always 1 under mswindows and
517 return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
519 case DM_num_color_cells: /* Printers are non-palette devices */
520 case DM_slow_device: /* Animation would be a really bad idea */
521 case DM_security: /* Not provided by windows */
525 /* Do not know such property */
530 msprinter_mark_device (struct device *d)
532 mark_object (DEVICE_MSPRINTER_FONTLIST (d));
533 mark_object (DEVICE_MSPRINTER_DEVMODE (d));
537 msprinter_device_implementation_flags (void)
539 return ( XDEVIMPF_PIXEL_GEOMETRY
540 | XDEVIMPF_IS_A_PRINTER
541 | XDEVIMPF_NO_AUTO_REDISPLAY
542 | XDEVIMPF_FRAMELESS_OK );
545 /************************************************************************/
546 /* printer Lisp subroutines */
547 /************************************************************************/
550 global_free_2_maybe (HGLOBAL hg1, HGLOBAL hg2)
559 devmode_to_hglobal (Lisp_Devmode *ldm)
561 HGLOBAL hg = GlobalAlloc (GHND, XDEVMODE_SIZE (ldm));
562 memcpy (GlobalLock (hg), ldm->devmode, XDEVMODE_SIZE (ldm));
567 /* Returns 0 if the printer has been deleted due to a fatal I/O error,
570 sync_printer_with_devmode (struct device* d, DEVMODE* devmode_in,
571 DEVMODE* devmode_out, char* devname)
573 /* Change connection if the device changed */
575 && stricmp (devname, DEVICE_MSPRINTER_NAME(d)) != 0)
577 Lisp_Object new_connection = build_ext_string (devname, Qmswindows_tstr);
580 GCPRO1 (new_connection);
581 DEVICE_CONNECTION (d) = Qnil;
582 if (!NILP (Ffind_device (new_connection, Qmsprinter)))
584 /* We are in trouble - second msprinter for the same device.
585 Nothing wrong on the Windows side, just forge a unique
586 connection name. Use the memory address of d as a unique
588 char* new_connext = alloca (strlen (devname + 11));
589 sprintf (new_connext, "%s:%X", devname, d->header.uid);
590 new_connection = build_ext_string (devname, Qmswindows_tstr);
592 DEVICE_CONNECTION (d) = new_connection;
595 /* Reinitialize printer. The device can pop off in process */
596 if (!msprinter_reinit_device (d, devname))
599 delete_device_internal (d, 1, 0, 1);
604 /* Apply the new devmode to the printer */
605 DocumentProperties (NULL,
606 DEVICE_MSPRINTER_HPRINTER(d),
607 DEVICE_MSPRINTER_NAME(d),
608 devmode_out, devmode_in,
609 DM_IN_BUFFER | DM_OUT_BUFFER);
611 /* #### ResetDC fails sometimes, Bill only knows why.
612 The solution below looks more like a workaround to me,
613 although it might be fine. --kkm */
614 if (ResetDC (DEVICE_MSPRINTER_HDC (d), devmode_out) == NULL)
616 DeleteDC (DEVICE_MSPRINTER_HDC (d));
617 DEVICE_MSPRINTER_HDC (d) =
618 CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode_out);
625 handle_devmode_changes (Lisp_Devmode *ldm, HGLOBAL hDevNames, HGLOBAL hDevMode)
627 DEVNAMES* devnames = (DEVNAMES*) GlobalLock (hDevNames);
628 char *new_name = devnames ? (char*)devnames + devnames->wDeviceOffset : NULL;
629 DEVMODE* devmode = (DEVMODE*) GlobalLock (hDevMode);
631 /* Size and name may have changed */
632 ldm->devmode = xrealloc (ldm->devmode, DEVMODE_SIZE (devmode));
635 if (ldm->printer_name)
636 xfree (ldm->printer_name);
637 ldm->printer_name = xstrdup (new_name);
640 if (!NILP (ldm->device))
642 /* Apply the new devmode to the printer and get a compete one back */
643 struct device *d = XDEVICE (ldm->device);
644 if (!sync_printer_with_devmode (d, devmode, ldm->devmode, new_name))
646 global_free_2_maybe (hDevNames, hDevMode);
647 error ("Printer device initialization I/O error, device deleted.");
652 /* Just copy the devmode structure */
653 memcpy (ldm->devmode, devmode, DEVMODE_SIZE (devmode));
658 ensure_not_printing (struct device *d)
660 if (!NILP (DEVICE_FRAME_LIST (d)))
663 XSETDEVICE (device, d);
664 invalid_operation ("Cannot change settings while print job is active",
669 static Lisp_Devmode *
670 decode_devmode (Lisp_Object dev)
673 return XDEVMODE (dev);
676 ensure_not_printing (XDEVICE (dev));
677 return XDEVMODE (DEVICE_MSPRINTER_DEVMODE (XDEVICE (dev)));
682 * DEV can be either a printer or devmode
685 print_dialog_worker (Lisp_Object dev, DWORD flags)
687 Lisp_Devmode *ldm = decode_devmode (dev);
690 memset (&pd, 0, sizeof (pd));
691 pd.lStructSize = sizeof (pd);
692 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
693 pd.hDevMode = devmode_to_hglobal (ldm);
694 pd.Flags = flags | PD_USEDEVMODECOPIESANDCOLLATE;
696 pd.nMaxPage = 0xFFFF;
700 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
704 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
706 /* Finally, build the resulting plist */
708 Lisp_Object result = Qnil;
712 /* Do consing in reverse order.
714 result = Fcons (Qcopies, Fcons (make_int (pd.nCopies), result));
717 if (pd.Flags & PD_PAGENUMS)
719 result = Fcons (Qto_page, Fcons (make_int (pd.nToPage), result));
720 result = Fcons (Qfrom_page, Fcons (make_int (pd.nFromPage), result));
721 result = Fcons (Qselected_page_button, Fcons (Qpages, result));
723 else if (pd.Flags & PD_SELECTION)
724 result = Fcons (Qselected_page_button, Fcons (Qselection, result));
726 result = Fcons (Qselected_page_button, Fcons (Qall, result));
729 result = Fcons (Qname, Fcons (build_ext_string (ldm->printer_name,
734 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
740 mswindows_handle_print_dialog_box (struct frame *f, Lisp_Object keys)
742 Lisp_Object device = Qunbound, settings = Qunbound;
743 DWORD flags = PD_NOSELECTION;
746 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
748 if (EQ (key, Q_device))
750 device = wrap_device (decode_device (value));
751 CHECK_MSPRINTER_DEVICE (device);
753 else if (EQ (key, Q_printer_settings))
755 CHECK_DEVMODE (value);
758 else if (EQ (key, Q_allow_pages))
761 flags |= PD_NOPAGENUMS;
763 else if (EQ (key, Q_allow_selection))
766 flags &= ~PD_NOSELECTION;
768 else if (EQ (key, Q_selected_page_button))
770 if (EQ (value, Qselection))
771 flags |= PD_SELECTION;
772 else if (EQ (value, Qpages))
773 flags |= PD_PAGENUMS;
774 else if (!EQ (value, Qall))
775 invalid_argument ("Invalid value for :selected-page-button",
779 syntax_error ("Unrecognized print-dialog keyword", key);
783 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
784 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
785 syntax_error ("Exactly one of :device and :printer-settings must be given",
788 return print_dialog_worker (!UNBOUNDP (device) ? device : settings, flags);
792 mswindows_get_default_margin (Lisp_Object prop)
794 if (EQ (prop, Qleft_margin)) return 1440;
795 if (EQ (prop, Qright_margin)) return 1440;
796 if (EQ (prop, Qtop_margin)) return 720;
797 if (EQ (prop, Qbottom_margin)) return 720;
803 plist_get_margin (Lisp_Object plist, Lisp_Object prop)
806 Fplist_get (plist, prop, make_int (mswindows_get_default_margin (prop)));
808 invalid_argument ("Margin value must be an integer", val);
810 return MulDiv (XINT (val), 100, 144);
814 plist_set_margin (Lisp_Object plist, Lisp_Object prop, int margin, int mm_p)
816 Lisp_Object val = make_int (MulDiv (margin, 144, mm_p ? 2450 : 100));
817 return Fcons (prop, Fcons (val, plist));
821 mswindows_handle_page_setup_dialog_box (struct frame *f, Lisp_Object keys)
823 Lisp_Object device = Qunbound, settings = Qunbound;
824 Lisp_Object plist = Qnil;
827 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
829 if (EQ (key, Q_device))
831 device = wrap_device (decode_device (value));
832 CHECK_MSPRINTER_DEVICE (device);
834 else if (EQ (key, Q_printer_settings))
836 CHECK_DEVMODE (value);
839 else if (EQ (key, Q_properties))
845 syntax_error ("Unrecognized page-setup dialog keyword", key);
849 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
850 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
851 syntax_error ("Exactly one of :device and :printer-settings must be given",
854 if (UNBOUNDP (device))
858 Lisp_Devmode *ldm = decode_devmode (device);
861 memset (&pd, 0, sizeof (pd));
862 pd.lStructSize = sizeof (pd);
863 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
864 pd.Flags = PSD_MARGINS;
865 pd.rtMargin.left = plist_get_margin (plist, Qleft_margin);
866 pd.rtMargin.top = plist_get_margin (plist, Qtop_margin);
867 pd.rtMargin.right = plist_get_margin (plist, Qright_margin);
868 pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin);
869 pd.hDevMode = devmode_to_hglobal (ldm);
871 if (!PageSetupDlg (&pd))
873 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
878 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
880 /* Finally, build the resulting plist */
882 Lisp_Object result = Qnil;
883 int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
884 result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
886 result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
888 result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
889 result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
895 DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
896 Return the settings object currently used by DEVICE.
897 The object returned is not a copy, but rather a pointer to the
898 original one. Use `msprinter-settings-copy' to create a copy of it.
902 struct device *d = decode_device (device);
903 XSETDEVICE (device, d);
904 CHECK_MSPRINTER_DEVICE (device);
905 return DEVICE_MSPRINTER_DEVMODE (d);
908 DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
909 Select SETTINGS object into a DEVICE.
910 The settings from the settings object are immediately applied to the
911 printer, possibly changing even the target printer itself, and all
912 future changes are applied synchronously to the printer device and the
913 selected printer object, until a different settings object is selected
914 into the same printer.
916 A settings object can be selected to no more than one printer at a time.
918 If the supplied settings object is not specialized, it is specialized
919 for the printer immediately upon selection. The object can be
920 despecialized after it is unselected by calling the function
921 `msprinter-settings-despecialize'.
923 Return value is the previously selected settings object.
928 struct device *d = decode_device (device);
933 XSETDEVICE (device, d);
934 CHECK_MSPRINTER_DEVICE (device);
935 CHECK_DEVMODE (settings);
936 ldm = XDEVMODE (settings);
938 if (!NILP (ldm->device))
939 invalid_operation ("The object is currently selected into a device",
942 /* If the object being selected is de-specialized, then its
943 size is perhaps not enough to receive the new devmode. We can ask
944 for printer's devmode size here, because despecialized settings
945 cannot force switching to a different printer, as they supply no
946 printer name at all. */
947 if (ldm->printer_name == NULL)
950 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
951 DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
953 invalid_operation ("Unable to specialize settings, printer error",
956 assert (XDEVMODE_SIZE (ldm) <= dm_size);
957 ldm->devmode = xrealloc (ldm->devmode, dm_size);
960 /* If we bail out on signal here, no damage is done, except that
961 the storage for the DEVMODE structure might be reallocated to
962 hold a larger one - not a big deal */
963 if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
965 error ("Printer device initialization I/O error, device deleted.");
967 if (ldm->printer_name == NULL)
968 ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
971 Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
972 ldm->device = device;
973 XDEVMODE (old_mode)->device = Qnil;
974 DEVICE_MSPRINTER_DEVMODE (d) = settings;
980 DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
981 Apply settings from a SETTINGS object to a 'msprinter DEVICE.
982 The settings from the settings object are immediately applied to the
983 printer, possibly changing even the target printer itself. The SETTING
984 object is not modified, unlike `msprinter-select-settings', and the
985 supplied object is not changed. The changes are immediately recorded
986 into the settings object which is currently selected into the printer
989 Return value is the currently selected settings object.
993 Lisp_Devmode *ldm_current, *ldm_new;
994 struct device *d = decode_device (device);
999 XSETDEVICE (device, d);
1000 CHECK_MSPRINTER_DEVICE (device);
1001 CHECK_DEVMODE (settings);
1002 ldm_new = XDEVMODE (settings);
1003 ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
1005 /* If the supplied devmode is not specialized, then the current
1006 devmode size will always be sufficient, as the printer does
1007 not change. If it is specialized, we must reallocate the current
1008 devmode storage to match with the supplied one, as it has the right
1009 size for the new printer, if it is going to change. The correct
1010 way is to use the largest of the two though, to keep the old
1011 contents unchanged in case of preliminary exit.
1013 if (ldm_new->printer_name)
1014 ldm_current->devmode =
1015 (DEVMODE*) xrealloc (ldm_current->devmode,
1016 max (XDEVMODE_SIZE (ldm_new),
1017 XDEVMODE_SIZE (ldm_current)));
1019 if (!sync_printer_with_devmode (d, ldm_new->devmode,
1020 ldm_current->devmode,
1021 ldm_new->printer_name))
1022 error ("Printer device initialization I/O error, device deleted.");
1024 if (ldm_new->printer_name != NULL)
1026 xfree (ldm_current->printer_name);
1027 ldm_current->printer_name = xstrdup (ldm_new->printer_name);
1031 return DEVICE_MSPRINTER_DEVMODE (d);
1034 /************************************************************************/
1036 /************************************************************************/
1039 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1043 Lisp_Devmode *dm = XDEVMODE (obj);
1045 error ("printing unreadable object #<msprinter-settings 0x%x>",
1047 write_c_string ("#<msprinter-settings", printcharfun);
1048 if (dm->printer_name)
1050 write_c_string (" for \"", printcharfun);
1051 write_c_string (dm->printer_name, printcharfun);
1052 write_c_string ("\"", printcharfun);
1054 if (!NILP (dm->device))
1056 write_c_string (" (currently on ", printcharfun);
1057 print_internal (dm->device, printcharfun, 0);
1058 write_c_string (")", printcharfun);
1060 sprintf (buf, " 0x%x>", dm->header.uid);
1061 write_c_string (buf, printcharfun);
1065 finalize_devmode (void *header, int for_disksave)
1067 Lisp_Devmode *dm = (Lisp_Devmode *) header;
1071 Lisp_Object devmode;
1072 XSETDEVMODE (devmode, dm);
1074 ("Cannot dump XEmacs containing an msprinter-settings object",
1078 assert (NILP (dm->device));
1080 if (dm->printer_name)
1081 xfree (dm->printer_name);
1085 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1087 Lisp_Devmode *dm1 = XDEVMODE (obj1);
1088 Lisp_Devmode *dm2 = XDEVMODE (obj2);
1090 if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1092 if (dm1->devmode == NULL)
1094 if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1096 if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1098 return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1101 static unsigned long
1102 hash_devmode (Lisp_Object obj, int depth)
1104 Lisp_Devmode *dm = XDEVMODE (obj);
1106 return HASH3 (XDEVMODE_SIZE (dm),
1107 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1109 dm->printer_name ? string_hash (dm->printer_name) : 0);
1112 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1113 0/*mark*/, print_devmode, finalize_devmode,
1114 equal_devmode, hash_devmode, 0/*description*/,
1117 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1118 char* src_name, struct device *d)
1123 dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1126 XSETDEVICE (dm->device, d);
1130 dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1132 if (src_devmode != NULL && do_copy)
1134 dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1135 memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1139 dm->devmode = src_devmode;
1142 XSETDEVMODE (ob, dm);
1146 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1147 Create and returns an exact copy of a printer settings object.
1153 CHECK_DEVMODE (settings);
1154 dm = XDEVMODE (settings);
1156 return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1159 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1160 Erase printer-specific settings from a printer settings object.
1167 CHECK_DEVMODE (settings);
1168 ldm = XDEVMODE (settings);
1170 if (!NILP (ldm->device))
1171 invalid_operation ("The object is currently selected into a device",
1176 /* #### TODO. Either remove references to device specific bins,
1177 paper sizes etc, or signal an error of they are present. */
1179 dm->dmDriverExtra = 0;
1180 dm->dmDeviceName[0] = '\0';
1182 if (ldm->printer_name)
1183 xfree (ldm->printer_name);
1188 DEFUN ("mswindows-get-default-printer", Fmswindows_get_default_printer, 0, 0, 0, /*
1189 Return name of the default printer, as string, on nil if there is no default.
1193 return msprinter_default_printer ();
1197 signal_enum_printer_error (void)
1199 invalid_operation ("Error enumerating printers", make_int (GetLastError ()));
1202 DEFUN ("mswindows-printer-list", Fmswindows_printer_list, 0, 0, 0, /*
1203 Return a list of string names of installed printers.
1204 If there is a default printer, it is returned as the first element of
1205 the list. If there is no default printer, the first element of the
1206 list will be nil. The rest of elements are guaranteed to have string
1207 values. Return value is nil if there are no printers installed.
1212 BYTE *data_buf, dummy_byte;
1213 size_t enum_entry_size;
1214 DWORD enum_flags, enum_level, bytes_needed, num_printers;
1215 struct gcpro gcpro1, gcpro2;
1216 Lisp_Object result = Qnil, def_printer = Qnil;
1218 /* Determine OS flavor, to use the fastest enumeration method available */
1219 have_nt = !mswindows_windows9x_p ();
1220 enum_flags = PRINTER_ENUM_LOCAL | (have_nt ? PRINTER_ENUM_CONNECTIONS : 0);
1221 enum_level = have_nt ? 4 : 5;
1222 enum_entry_size = have_nt ? sizeof (PRINTER_INFO_4) : sizeof (PRINTER_INFO_5);
1224 /* Allocate memory for printer enum structure */
1225 ok = EnumPrinters (enum_flags, NULL, enum_level, &dummy_byte, 1,
1226 &bytes_needed, &num_printers);
1228 /* No printers, if just 1 byte is enough */
1231 if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1232 signal_enum_printer_error ();
1234 data_buf = alloca (bytes_needed);
1235 ok = EnumPrinters (enum_flags, NULL, enum_level, data_buf, bytes_needed,
1236 &bytes_needed, &num_printers);
1238 signal_enum_printer_error ();
1240 if (num_printers == 0)
1241 /* Strange but... */
1244 GCPRO2 (result, def_printer);
1246 while (num_printers--)
1248 LPCTSTR printer_name;
1251 PRINTER_INFO_4 *info = (PRINTER_INFO_4*) data_buf;
1252 printer_name = info->pPrinterName;
1256 PRINTER_INFO_5 *info = (PRINTER_INFO_5*) data_buf;
1257 printer_name = info->pPrinterName;
1259 data_buf += enum_entry_size;
1261 result = Fcons (build_ext_string (printer_name, Qmswindows_tstr),
1265 def_printer = msprinter_default_printer ();
1266 result = Fdelete (def_printer, result);
1267 result = Fcons (def_printer, result);
1269 RETURN_UNGCPRO (result);
1273 /************************************************************************/
1274 /* initialization */
1275 /************************************************************************/
1278 syms_of_device_mswindows (void)
1280 INIT_LRECORD_IMPLEMENTATION (devmode);
1282 DEFSUBR (Fmsprinter_get_settings);
1283 DEFSUBR (Fmsprinter_select_settings);
1284 DEFSUBR (Fmsprinter_apply_settings);
1285 DEFSUBR (Fmsprinter_settings_copy);
1286 DEFSUBR (Fmsprinter_settings_despecialize);
1287 DEFSUBR (Fmswindows_get_default_printer);
1288 DEFSUBR (Fmswindows_printer_list);
1290 DEFKEYWORD (Q_allow_selection);
1291 DEFKEYWORD (Q_allow_pages);
1292 DEFKEYWORD (Q_selected_page_button);
1293 DEFSYMBOL (Qselected_page_button);
1295 DEFSYMBOL (Qinit_pre_mswindows_win);
1296 DEFSYMBOL (Qinit_post_mswindows_win);
1300 console_type_create_device_mswindows (void)
1302 CONSOLE_HAS_METHOD (mswindows, init_device);
1303 CONSOLE_HAS_METHOD (mswindows, finish_init_device);
1304 CONSOLE_HAS_METHOD (mswindows, mark_device);
1305 CONSOLE_HAS_METHOD (mswindows, delete_device);
1306 CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
1307 CONSOLE_HAS_METHOD (mswindows, device_implementation_flags);
1309 CONSOLE_HAS_METHOD (msprinter, init_device);
1310 CONSOLE_HAS_METHOD (msprinter, mark_device);
1311 CONSOLE_HAS_METHOD (msprinter, delete_device);
1312 CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
1313 CONSOLE_HAS_METHOD (msprinter, device_implementation_flags);
1318 vars_of_device_mswindows (void)
1320 DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
1321 Non-nil means convert all-upper case file names to lower case.
1322 This applies when performing completions and file name expansion.
1324 Vmswindows_downcase_file_names = Qnil;
1326 DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
1327 Non-nil means determine accurate link count in file-attributes.
1328 This option slows down file-attributes noticeably, so is disabled by
1329 default. Note that it is only useful for files on NTFS volumes,
1330 where hard links are supported.
1332 Vmswindows_get_true_file_attributes = Qnil;