3 // Copyright (C) 2005, 2007 Novell, Inc. http://www.novell.com
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // Jordi Mas i Hernandez, jordimash@gmail.com
29 using System.Runtime.InteropServices;
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Drawing.Printing;
33 using System.ComponentModel;
34 using System.Drawing.Imaging;
38 namespace System.Drawing.Printing
40 internal class PrintingServicesUnix : PrintingServices
42 #region Private Fields
44 private static Hashtable doc_info = new Hashtable ();
45 private static bool cups_installed;
47 //private string printer_name;
49 private static Hashtable installed_printers;
50 private static string default_printer = String.Empty;
56 internal PrintingServicesUnix () {
59 static PrintingServicesUnix () {
60 installed_printers = new Hashtable ();
61 CheckCupsInstalled ();
68 internal static PrinterSettings.StringCollection InstalledPrinters {
71 PrinterSettings.StringCollection list = new PrinterSettings.StringCollection (new string[] {});
72 foreach (object key in installed_printers.Keys) {
73 list.Add (key.ToString());
79 internal override string DefaultPrinter {
81 if (installed_printers.Count == 0)
83 return default_printer;
93 /// Do a cups call to check if it is installed
95 private static void CheckCupsInstalled ()
100 catch (DllNotFoundException) {
101 Console.WriteLine("libcups not found. To have printing support, you need cups installed");
102 cups_installed = false;
106 cups_installed = true;
110 /// Open the printer's PPD file
112 /// <param name="printer">Printer name, returned from cupsGetDests</param>
113 private IntPtr OpenPrinter (string printer)
116 IntPtr ptr = cupsGetPPD (printer);
117 string ppd_filename = Marshal.PtrToStringAnsi (ptr);
118 IntPtr ppd_handle = ppdOpenFile (ppd_filename);
122 Console.WriteLine ("There was an error opening the printer {0}. Please check your cups installation.");
128 /// Close the printer file
130 /// <param name="handle">PPD handle</param>
131 private void ClosePrinter (ref IntPtr handle)
134 if (handle != IntPtr.Zero)
138 handle = IntPtr.Zero;
142 private static int OpenDests (ref IntPtr ptr) {
144 return cupsGetDests (ref ptr);
152 private static void CloseDests (ref IntPtr ptr, int count) {
154 if (ptr != IntPtr.Zero)
155 cupsFreeDests (count, ptr);
163 /// Checks if a printer has a valid PPD file. Caches the result unless force is true
165 /// <param name="force">Does the check disregarding the last cached value if true</param>
166 internal override bool IsPrinterValid(string printer)
168 if (!cups_installed || printer == null | printer == String.Empty)
171 return installed_printers.Contains (printer);
173 if (!force && this.printer_name != null && String.Intern(this.printer_name).Equals(printer))
174 return is_printer_valid;
176 IntPtr ptr = cupsGetPPD (printer);
177 string ppd_filename = Marshal.PtrToStringAnsi (ptr);
178 is_printer_valid = ppd_filename != null;
179 this.printer_name = printer;
180 return is_printer_valid;
185 /// Loads the printer settings and initializes the PrinterSettings and PageSettings fields
187 /// <param name="printer">Printer name</param>
188 /// <param name="settings">PrinterSettings object to initialize</param>
189 internal override void LoadPrinterSettings (string printer, PrinterSettings settings)
191 if (cups_installed == false || (printer == null) || (printer == String.Empty))
194 if (installed_printers.Count == 0)
197 if (((SysPrn.Printer)installed_printers[printer]).Settings != null) {
198 SysPrn.Printer p = (SysPrn.Printer) installed_printers[printer];
199 settings.can_duplex = p.Settings.can_duplex;
200 settings.is_plotter = p.Settings.is_plotter;
201 settings.landscape_angle = p.Settings.landscape_angle;
202 settings.maximum_copies = p.Settings.maximum_copies;
203 settings.paper_sizes = p.Settings.paper_sizes;
204 settings.paper_sources = p.Settings.paper_sources;
205 settings.printer_capabilities = p.Settings.printer_capabilities;
206 settings.printer_resolutions = p.Settings.printer_resolutions;
207 settings.supports_color = p.Settings.supports_color;
211 settings.PrinterCapabilities.Clear ();
213 IntPtr dests = IntPtr.Zero, ptr = IntPtr.Zero, ptr_printer, ppd_handle = IntPtr.Zero;
214 string name = String.Empty;
215 CUPS_DESTS printer_dest;
217 int ret = 0, cups_dests_size;
218 NameValueCollection options, paper_names, paper_sources;
221 ret = OpenDests (ref dests);
225 cups_dests_size = Marshal.SizeOf (typeof(CUPS_DESTS));
227 for (int i = 0; i < ret; i++) {
228 ptr_printer = (IntPtr) Marshal.ReadIntPtr (ptr);
229 if (Marshal.PtrToStringAnsi (ptr_printer).Equals(printer)) {
233 ptr = (IntPtr) ((long)ptr + cups_dests_size);
236 if (!name.Equals(printer)) {
240 ppd_handle = OpenPrinter (printer);
241 if (ppd_handle == IntPtr.Zero)
244 printer_dest = (CUPS_DESTS) Marshal.PtrToStructure (ptr, typeof (CUPS_DESTS));
245 options = new NameValueCollection();
246 paper_names = new NameValueCollection();
247 paper_sources = new NameValueCollection();
250 LoadPrinterOptions (printer_dest.options, printer_dest.num_options, ppd_handle, options,
251 paper_names, out defsize,
252 paper_sources, out defsource);
254 if (settings.paper_sizes == null)
255 settings.paper_sizes = new PrinterSettings.PaperSizeCollection (new PaperSize [] {});
257 settings.paper_sizes.Clear();
259 if (settings.paper_sources == null)
260 settings.paper_sources = new PrinterSettings.PaperSourceCollection (new PaperSource [] {});
262 settings.paper_sources.Clear();
264 settings.DefaultPageSettings.PaperSource = LoadPrinterPaperSources (settings, defsource, paper_sources);
265 settings.DefaultPageSettings.PaperSize = LoadPrinterPaperSizes (ppd_handle, settings, defsize, paper_names);
266 LoadPrinterResolutionsAndDefault (printer, settings, ppd_handle);
268 ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
269 settings.landscape_angle = ppd.landscape;
270 settings.supports_color = (ppd.color_device == 0) ? false : true;
271 settings.can_duplex = options["Duplex"] != null;
273 ClosePrinter (ref ppd_handle);
275 ((SysPrn.Printer)installed_printers[printer]).Settings = settings;
278 CloseDests (ref dests, ret);
283 /// Loads the global options of a printer plus the paper types and trays supported,
284 /// and sets the default paper size and source tray.
286 /// <param name="options">The options field of a printer's CUPS_DESTS structure</param>
287 /// <param name="numOptions">The number of options of the printer</param>
288 /// <param name="ppd">A ppd handle for the printer, returned by ppdOpen</param>
289 /// <param name="list">The list of options</param>
290 /// <param name="paper_names">A list of types of paper (PageSize)</param>
291 /// <param name="defsize">The default paper size, set by LoadOptionList</param>
292 /// <param name="paper_sources">A list of trays(InputSlot) </param>
293 /// <param name="defsource">The default source tray, set by LoadOptionList</param>
294 private static void LoadPrinterOptions(IntPtr options, int numOptions, IntPtr ppd,
295 NameValueCollection list,
296 NameValueCollection paper_names, out string defsize,
297 NameValueCollection paper_sources, out string defsource)
299 CUPS_OPTIONS cups_options;
300 string option_name, option_value;
301 int cups_size = Marshal.SizeOf(typeof(CUPS_OPTIONS));
303 LoadOptionList (ppd, "PageSize", paper_names, out defsize);
304 LoadOptionList (ppd, "InputSlot", paper_sources, out defsource);
306 for (int j = 0; j < numOptions; j++)
308 cups_options = (CUPS_OPTIONS) Marshal.PtrToStructure(options, typeof(CUPS_OPTIONS));
309 option_name = Marshal.PtrToStringAnsi(cups_options.name);
310 option_value = Marshal.PtrToStringAnsi(cups_options.val);
312 if (option_name == "PageSize") defsize = option_value;
313 else if (option_name == "InputSlot") defsource = option_value;
315 Console.WriteLine("{0} = {1}", option_name, option_value);
318 list.Add(option_name, option_value);
320 options = (IntPtr) ((long)options + cups_size);
325 /// Loads the global options of a printer.
327 /// <param name="options">The options field of a printer's CUPS_DESTS structure</param>
328 /// <param name="numOptions">The number of options of the printer</param>
329 private static NameValueCollection LoadPrinterOptions(IntPtr options, int numOptions)
331 CUPS_OPTIONS cups_options;
332 string option_name, option_value;
333 int cups_size = Marshal.SizeOf (typeof(CUPS_OPTIONS));
334 NameValueCollection list = new NameValueCollection ();
335 for (int j = 0; j < numOptions; j++)
337 cups_options = (CUPS_OPTIONS) Marshal.PtrToStructure(options, typeof(CUPS_OPTIONS));
338 option_name = Marshal.PtrToStringAnsi (cups_options.name);
339 option_value = Marshal.PtrToStringAnsi (cups_options.val);
342 Console.WriteLine("{0} = {1}", option_name, option_value);
345 list.Add (option_name, option_value);
347 options = (IntPtr) ((long)options + cups_size);
353 /// Loads a printer's options (selection of paper sizes, paper sources, etc)
354 /// and sets the default option from the selected list.
356 /// <param name="ppd">Printer ppd file handle</param>
357 /// <param name="option_name">Name of the option group to load</param>
358 /// <param name="list">List of loaded options</param>
359 /// <param name="defoption">The default option from the loaded options list</param>
360 private static void LoadOptionList (IntPtr ppd, string option_name, NameValueCollection list, out string defoption) {
362 IntPtr ptr = IntPtr.Zero;
363 PPD_OPTION ppd_option;
365 int choice_size = Marshal.SizeOf(typeof(PPD_CHOICE));
368 ptr = ppdFindOption (ppd, option_name);
369 if (ptr != IntPtr.Zero)
371 ppd_option = (PPD_OPTION) Marshal.PtrToStructure (ptr, typeof (PPD_OPTION));
373 Console.WriteLine (" OPTION key:{0} def:{1} text: {2}", ppd_option.keyword, ppd_option.defchoice, ppd_option.text);
375 defoption = ppd_option.defchoice;
376 ptr = ppd_option.choices;
377 for (int c = 0; c < ppd_option.num_choices; c++) {
378 choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr, typeof (PPD_CHOICE));
379 list.Add(choice.choice, choice.text);
381 Console.WriteLine (" choice:{0} - text: {1}", choice.choice, choice.text);
384 ptr = (IntPtr) ((long)ptr + choice_size);
390 /// Loads a printer's available resolutions
392 /// <param name="printer">Printer name</param>
393 /// <param name="settings">PrinterSettings object to fill</param>
394 internal override void LoadPrinterResolutions (string printer, PrinterSettings settings)
396 IntPtr ppd_handle = OpenPrinter (printer);
397 if (ppd_handle == IntPtr.Zero)
400 LoadPrinterResolutionsAndDefault (printer, settings, ppd_handle);
402 ClosePrinter (ref ppd_handle);
406 /// Create a PrinterResolution from a string Resolution that is set in the PPD option.
407 /// An example of Resolution is "600x600dpi" or "600dpi". Returns null if malformed or "Unknown".
409 private PrinterResolution ParseResolution (string resolution)
411 if (String.IsNullOrEmpty (resolution))
414 int dpiIndex = resolution.IndexOf ("dpi");
417 // Resolution is "Unknown" or unparsable
420 resolution = resolution.Substring (0, dpiIndex);
422 int x_resolution, y_resolution;
424 if (resolution.Contains ("x")) {
425 string[] resolutions = resolution.Split (new[] {'x'});
426 x_resolution = Convert.ToInt32 (resolutions [0]);
427 y_resolution = Convert.ToInt32 (resolutions [1]);
429 x_resolution = Convert.ToInt32 (resolution);
430 y_resolution = x_resolution;
432 } catch (Exception) {
436 return new PrinterResolution (x_resolution, y_resolution, PrinterResolutionKind.Custom);
440 /// Loads a printer's paper sizes. Returns the default PaperSize, and fills a list of paper_names for use in dialogues
442 /// <param name="ppd_handle">PPD printer file handle</param>
443 /// <param name="settings">PrinterSettings object to fill</param>
444 /// <param name="def_size">Default paper size, from the global options of the printer</param>
445 /// <param name="paper_names">List of available paper sizes that gets filled</param>
446 private PaperSize LoadPrinterPaperSizes(IntPtr ppd_handle, PrinterSettings settings,
447 string def_size, NameValueCollection paper_names)
455 PaperSize defsize = new PaperSize ("A4", 827, 1169, GetPaperKind (827, 1169), true);
456 ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
459 for (int i = 0; i < ppd.num_sizes; i++) {
460 size = (PPD_SIZE) Marshal.PtrToStructure (ptr, typeof (PPD_SIZE));
461 real_name = paper_names[size.name];
462 w = size.width * 100 / 72;
463 h = size.length * 100 / 72;
464 PaperKind kind = GetPaperKind ((int) w, (int) h);
465 ps = new PaperSize (real_name, (int) w, (int) h, kind, def_size == kind.ToString ());
467 if (def_size == ps.Kind.ToString ())
469 settings.paper_sizes.Add (ps);
470 ptr = (IntPtr) ((long)ptr + Marshal.SizeOf (size));
478 /// Loads a printer's paper sources (trays). Returns the default PaperSource, and fills a list of paper_sources for use in dialogues
480 /// <param name="settings">PrinterSettings object to fill</param>
481 /// <param name="def_source">Default paper source, from the global options of the printer</param>
482 /// <param name="paper_sources">List of available paper sizes that gets filled</param>
483 private PaperSource LoadPrinterPaperSources (PrinterSettings settings, string def_source,
484 NameValueCollection paper_sources)
486 PaperSourceKind kind;
487 PaperSource defsource = null;
488 foreach(string source in paper_sources) {
492 kind = PaperSourceKind.AutomaticFeed;
495 kind = PaperSourceKind.AutomaticFeed;
498 kind = PaperSourceKind.AutomaticFeed;
501 kind = PaperSourceKind.Envelope;
504 kind = PaperSourceKind.Manual;
507 kind = PaperSourceKind.Custom;
510 settings.paper_sources.Add (new PaperSource (paper_sources[source], kind, def_source == source));
511 if (def_source == source)
512 defsource = settings.paper_sources[settings.paper_sources.Count-1];
515 if (defsource == null && settings.paper_sources.Count > 0)
516 return settings.paper_sources[0];
521 /// Sets the available resolutions and default resolution from a
522 /// printer's PPD file into settings.
524 private void LoadPrinterResolutionsAndDefault (string printer,
525 PrinterSettings settings, IntPtr ppd_handle)
527 if (settings.printer_resolutions == null)
528 settings.printer_resolutions = new PrinterSettings.PrinterResolutionCollection (new PrinterResolution [] {});
530 settings.printer_resolutions.Clear ();
532 var printer_resolutions = new NameValueCollection ();
533 string defresolution;
534 LoadOptionList (ppd_handle, "Resolution", printer_resolutions, out defresolution);
535 foreach (var resolution in printer_resolutions.Keys) {
536 var new_resolution = ParseResolution (resolution.ToString ());
537 settings.PrinterResolutions.Add (new_resolution);
540 var default_resolution = ParseResolution (defresolution);
542 if (default_resolution == null)
543 default_resolution = ParseResolution ("300dpi");
544 if (printer_resolutions.Count == 0)
545 settings.PrinterResolutions.Add (default_resolution);
547 settings.DefaultPageSettings.PrinterResolution = default_resolution;
552 /// <param name="load"></param>
553 /// <param name="def_printer"></param>
554 private static void LoadPrinters()
556 installed_printers.Clear ();
557 if (cups_installed == false)
560 IntPtr dests = IntPtr.Zero, ptr_printers;
563 int cups_dests_size = Marshal.SizeOf(typeof(CUPS_DESTS));
564 string name, first, type, status, comment;
565 first = type = status = comment = String.Empty;
569 n_printers = OpenDests (ref dests);
571 ptr_printers = dests;
572 for (int i = 0; i < n_printers; i++) {
573 printer = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS));
574 name = Marshal.PtrToStringAnsi (printer.name);
576 if (printer.is_default == 1)
577 default_printer = name;
579 if (first.Equals (String.Empty))
582 NameValueCollection options = LoadPrinterOptions(printer.options, printer.num_options);
584 if (options["printer-state"] != null)
585 state = Int32.Parse(options["printer-state"]);
587 if (options["printer-comment"] != null)
588 comment = options["printer-state"];
602 installed_printers.Add (name, new SysPrn.Printer (String.Empty, type, status, comment));
604 ptr_printers = (IntPtr) ((long)ptr_printers + cups_dests_size);
609 CloseDests (ref dests, n_printers);
612 if (default_printer.Equals (String.Empty))
613 default_printer = first;
617 /// Gets a printer's settings for use in the print dialogue
619 /// <param name="printer"></param>
620 /// <param name="port"></param>
621 /// <param name="type"></param>
622 /// <param name="status"></param>
623 /// <param name="comment"></param>
624 internal override void GetPrintDialogInfo (string printer, ref string port, ref string type, ref string status, ref string comment) {
625 int count = 0, state = -1;
627 CUPS_DESTS cups_dests;
628 IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer;
629 int cups_dests_size = Marshal.SizeOf(typeof(CUPS_DESTS));
631 if (cups_installed == false)
635 count = OpenDests (ref dests);
640 ptr_printers = dests;
642 for (int i = 0; i < count; i++) {
643 ptr_printer = (IntPtr) Marshal.ReadIntPtr (ptr_printers);
644 if (Marshal.PtrToStringAnsi (ptr_printer).Equals(printer)) {
648 ptr_printers = (IntPtr) ((long)ptr_printers + cups_dests_size);
654 cups_dests = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS));
656 NameValueCollection options = LoadPrinterOptions(cups_dests.options, cups_dests.num_options);
658 if (options["printer-state"] != null)
659 state = Int32.Parse(options["printer-state"]);
661 if (options["printer-comment"] != null)
662 comment = options["printer-state"];
677 CloseDests (ref dests, count);
682 /// Returns the appropriate PaperKind for the width and height
684 /// <param name="width"></param>
685 /// <param name="height"></param>
686 private PaperKind GetPaperKind (int width, int height)
688 if (width == 827 && height == 1169)
690 if (width == 583 && height == 827)
692 if (width == 717 && height == 1012)
694 if (width == 693 && height == 984)
695 return PaperKind.B5Envelope;
696 if (width == 638 && height == 902)
697 return PaperKind.C5Envelope;
698 if (width == 449 && height == 638)
699 return PaperKind.C6Envelope;
700 if (width == 1700 && height == 2200)
701 return PaperKind.CSheet;
702 if (width == 433 && height == 866)
703 return PaperKind.DLEnvelope;
704 if (width == 2200 && height == 3400)
705 return PaperKind.DSheet;
706 if (width == 3400 && height == 4400)
707 return PaperKind.ESheet;
708 if (width == 725 && height == 1050)
709 return PaperKind.Executive;
710 if (width == 850 && height == 1300)
711 return PaperKind.Folio;
712 if (width == 850 && height == 1200)
713 return PaperKind.GermanStandardFanfold;
714 if (width == 1700 && height == 1100)
715 return PaperKind.Ledger;
716 if (width == 850 && height == 1400)
717 return PaperKind.Legal;
718 if (width == 927 && height == 1500)
719 return PaperKind.LegalExtra;
720 if (width == 850 && height == 1100)
721 return PaperKind.Letter;
722 if (width == 927 && height == 1200)
723 return PaperKind.LetterExtra;
724 if (width == 850 && height == 1269)
725 return PaperKind.LetterPlus;
726 if (width == 387 && height == 750)
727 return PaperKind.MonarchEnvelope;
728 if (width == 387 && height == 887)
729 return PaperKind.Number9Envelope;
730 if (width == 413 && height == 950)
731 return PaperKind.Number10Envelope;
732 if (width == 450 && height == 1037)
733 return PaperKind.Number11Envelope;
734 if (width == 475 && height == 1100)
735 return PaperKind.Number12Envelope;
736 if (width == 500 && height == 1150)
737 return PaperKind.Number14Envelope;
738 if (width == 363 && height == 650)
739 return PaperKind.PersonalEnvelope;
740 if (width == 1000 && height == 1100)
741 return PaperKind.Standard10x11;
742 if (width == 1000 && height == 1400)
743 return PaperKind.Standard10x14;
744 if (width == 1100 && height == 1700)
745 return PaperKind.Standard11x17;
746 if (width == 1200 && height == 1100)
747 return PaperKind.Standard12x11;
748 if (width == 1500 && height == 1100)
749 return PaperKind.Standard15x11;
750 if (width == 900 && height == 1100)
751 return PaperKind.Standard9x11;
752 if (width == 550 && height == 850)
753 return PaperKind.Statement;
754 if (width == 1100 && height == 1700)
755 return PaperKind.Tabloid;
756 if (width == 1487 && height == 1100)
757 return PaperKind.USStandardFanfold;
759 return PaperKind.Custom;
764 #region Print job methods
766 static string tmpfile;
769 /// Gets a pointer to an options list parsed from the printer's current settings, to use when setting up the printing job
771 /// <param name="printer_settings"></param>
772 /// <param name="page_settings"></param>
773 /// <param name="options"></param>
774 internal static int GetCupsOptions (PrinterSettings printer_settings, PageSettings page_settings, out IntPtr options)
776 options = IntPtr.Zero;
778 PaperSize size = page_settings.PaperSize;
779 int width = size.Width * 72 / 100;
780 int height = size.Height * 72 / 100;
782 StringBuilder sb = new StringBuilder();
784 "copies=" + printer_settings.Copies + " " +
785 "Collate=" + printer_settings.Collate + " " +
786 "ColorModel=" + (page_settings.Color ? "Color" : "Black") + " " +
787 "PageSize=" + String.Format ("Custom.{0}x{1}", width, height) + " " +
788 "landscape=" + page_settings.Landscape
791 if (printer_settings.CanDuplex)
793 if (printer_settings.Duplex == Duplex.Simplex)
794 sb.Append(" Duplex=None");
796 sb.Append(" Duplex=DuplexNoTumble");
799 return cupsParseOptions (sb.ToString(), 0, ref options);
802 internal static bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file)
804 DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
805 doc.title = doc_name;
809 internal static bool EndDoc (GraphicsPrinter gr)
811 DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
813 gr.Graphics.Dispose (); // Dispose object to force surface finish
816 int options_count = GetCupsOptions (doc.settings, doc.default_page_settings, out options);
818 cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, options_count, options);
819 cupsFreeOptions (options_count, options);
820 doc_info.Remove (gr.Hdc);
821 if (tmpfile != null) {
822 try { File.Delete (tmpfile); }
828 internal static bool StartPage (GraphicsPrinter gr)
833 internal static bool EndPage (GraphicsPrinter gr)
835 GdipGetPostScriptSavePage (gr.Hdc);
839 // Unfortunately, PrinterSettings and PageSettings couldn't be referencing each other,
840 // thus we need to pass them separately
841 internal static IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings)
843 IntPtr graphics = IntPtr.Zero;
845 if (!settings.PrintToFile) {
846 StringBuilder sb = new StringBuilder (1024);
847 int length = sb.Capacity;
848 cupsTempFd (sb, length);
849 name = sb.ToString ();
853 name = settings.PrintFileName;
855 PaperSize psize = default_page_settings.PaperSize;
857 if (default_page_settings.Landscape) { // Swap in case of landscape
858 width = psize.Height;
859 height = psize.Width;
862 height = psize.Height;
865 GdipGetPostScriptGraphicsContext (name,
868 default_page_settings.PrinterResolution.X,
869 default_page_settings.PrinterResolution.Y, ref graphics);
871 DOCINFO doc = new DOCINFO ();
873 doc.settings = settings;
874 doc.default_page_settings = default_page_settings;
875 doc_info.Add (graphics, doc);
884 [DllImport("libcups", CharSet=CharSet.Ansi)]
885 static extern int cupsGetDests (ref IntPtr dests);
887 // [DllImport("libcups", CharSet=CharSet.Ansi)]
888 // static extern void cupsGetDest (string name, string instance, int num_dests, ref IntPtr dests);
890 [DllImport("libcups")]
891 static extern void cupsFreeDests (int num_dests, IntPtr dests);
893 [DllImport("libcups", CharSet=CharSet.Ansi)]
894 static extern IntPtr cupsTempFd (StringBuilder sb, int len);
896 [DllImport("libcups", CharSet=CharSet.Ansi)]
897 static extern IntPtr cupsGetDefault ();
899 [DllImport("libcups", CharSet=CharSet.Ansi)]
900 static extern int cupsPrintFile (string printer, string filename, string title, int num_options, IntPtr options);
902 [DllImport("libcups", CharSet=CharSet.Ansi)]
903 static extern IntPtr cupsGetPPD (string printer);
905 [DllImport("libcups", CharSet=CharSet.Ansi)]
906 static extern IntPtr ppdOpenFile (string filename);
908 [DllImport("libcups", CharSet=CharSet.Ansi)]
909 static extern IntPtr ppdFindOption (IntPtr ppd_file, string keyword);
911 [DllImport("libcups")]
912 static extern void ppdClose (IntPtr ppd);
914 [DllImport ("libcups", CharSet=CharSet.Ansi)]
915 static extern int cupsParseOptions (string arg, int number_of_options, ref IntPtr options);
917 [DllImport("libcups")]
918 static extern void cupsFreeOptions (int number_options, IntPtr options);
920 [DllImport("gdiplus.dll", CharSet=CharSet.Ansi)]
921 static extern int GdipGetPostScriptGraphicsContext (string filename, int with, int height, double dpix, double dpiy, ref IntPtr graphics);
923 [DllImport("gdiplus.dll")]
924 static extern int GdipGetPostScriptSavePage (IntPtr graphics);
929 public struct DOCINFO
931 public PrinterSettings settings;
932 public PageSettings default_page_settings;
934 public string filename;
937 public struct PPD_SIZE
940 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
950 public struct PPD_GROUP
952 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)]
954 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
956 public int num_options;
957 public IntPtr options;
958 public int num_subgroups;
959 public IntPtr subgrups;
962 public struct PPD_OPTION
964 public byte conflicted;
965 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
966 public string keyword;
967 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
968 public string defchoice;
969 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
974 public int num_choices;
975 public IntPtr choices;
978 public struct PPD_CHOICE
981 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
982 public string choice;
983 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
986 public IntPtr option;
989 public struct PPD_FILE
991 public int language_level;
992 public int color_device;
993 public int variable_sizes;
994 public int accurate_screens;
995 public int contone_only;
996 public int landscape;
997 public int model_number;
998 public int manual_copies;
999 public int throughput;
1000 public int colorspace;
1001 public IntPtr patches;
1002 public int num_emulations;
1003 public IntPtr emulations;
1004 public IntPtr jcl_begin;
1005 public IntPtr jcl_ps;
1006 public IntPtr jcl_end;
1007 public IntPtr lang_encoding;
1008 public IntPtr lang_version;
1009 public IntPtr modelname;
1010 public IntPtr ttrasterizer;
1011 public IntPtr manufacturer;
1012 public IntPtr product;
1013 public IntPtr nickname;
1014 public IntPtr shortnickname;
1015 public int num_groups;
1016 public IntPtr groups;
1017 public int num_sizes;
1018 public IntPtr sizes;
1020 /* There is more data after this that we are not using*/
1024 public struct CUPS_OPTIONS
1030 public struct CUPS_DESTS
1033 public IntPtr instance;
1034 public int is_default;
1035 public int num_options;
1036 public IntPtr options;
1042 class GlobalPrintingServicesUnix : GlobalPrintingServices
1044 internal override PrinterSettings.StringCollection InstalledPrinters {
1046 return PrintingServicesUnix.InstalledPrinters;
1050 internal override IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings)
1052 return PrintingServicesUnix.CreateGraphicsContext (settings, default_page_settings);
1055 internal override bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file)
1057 return PrintingServicesUnix.StartDoc (gr, doc_name, output_file);
1060 internal override bool EndDoc (GraphicsPrinter gr)
1062 return PrintingServicesUnix.EndDoc (gr);
1065 internal override bool StartPage (GraphicsPrinter gr)
1067 return PrintingServicesUnix.StartPage (gr);
1070 internal override bool EndPage (GraphicsPrinter gr)
1072 return PrintingServicesUnix.EndPage (gr);