Hopefully fixes #79835
[mono.git] / mcs / class / System.Drawing / System.Drawing.Printing / PrintingServicesUnix.cs
index 09ec7d2a63a8df626b9c4195bb425001c5497ca2..afcf9b29c8d22f5a95a02ccc738791d3c72a7671 100644 (file)
@@ -39,6 +39,8 @@ namespace System.Drawing.Printing
        {
                private Hashtable doc_info = new Hashtable ();
                private bool cups_installed;
+               private string printer_name;
+               private bool is_printer_valid;
 
                internal PrintingServicesUnix ()
                {
@@ -58,6 +60,21 @@ namespace System.Drawing.Printing
 
                        cups_installed = true;
                }
+               
+               internal override bool IsPrinterValid(string printer, bool force)
+               {
+                       if (!cups_installed || printer == null | printer == String.Empty)
+                               return false;
+
+                       if (!force && this.printer_name != null && String.Intern(this.printer_name).Equals(printer))
+                               return is_printer_valid;
+
+                       IntPtr ptr = cupsGetPPD (printer);
+                       string ppd_filename = Marshal.PtrToStringAnsi (ptr);
+                       is_printer_valid = ppd_filename != null;
+                       this.printer_name = printer; 
+                       return is_printer_valid;
+               }
 
                // Methods
                internal override void LoadPrinterSettings (string printer, PrinterSettings settings)
@@ -136,7 +153,6 @@ namespace System.Drawing.Printing
                        PPD_FILE ppd;
                        PPD_SIZE size;
                        PaperSize ps;
-                       PaperKind kind = PaperKind.Custom;
 
                        settings.PaperSizes.Clear ();
 
@@ -154,8 +170,7 @@ namespace System.Drawing.Printing
                                w = size.width * 100 / 72;
                                h = size.length * 100 / 72;
                                ps = new PaperSize (real_name, (int) w, (int) h);
-                               // TODO: Convert from name to paper kind enum
-                               ps.SetKind (kind);
+                               ps.SetKind (GetPaperKind ((int) w, (int) h));
                                settings.PaperSizes.Add (ps);
                        }
 
@@ -214,7 +229,12 @@ namespace System.Drawing.Printing
                        DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
 
                        gr.Graphics.Dispose (); // Dispose object to force surface finish
-                       cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, 0, IntPtr.Zero);
+
+                       IntPtr options;
+                       int options_count = GetCupsOptions (doc.settings, doc.default_page_settings, out options);
+
+                       cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, options_count, options);
+                       cupsFreeOptions (options_count, options);
                        doc_info.Remove (gr.Hdc);
                        if (tmpfile != null) {
                                try { File.Delete (tmpfile); }
@@ -230,7 +250,9 @@ namespace System.Drawing.Printing
                        return true;
                }
 
-               internal override IntPtr CreateGraphicsContext (PrinterSettings settings)
+               // Unfortunately, PrinterSettings and PageSettings couldn't be referencing each other,
+               // thus we need to pass them separately
+               internal override IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings)
                {
                        IntPtr graphics = IntPtr.Zero;
                        string name;
@@ -245,19 +267,37 @@ namespace System.Drawing.Printing
                                name = settings.PrintFileName;
 
                        GdipGetPostScriptGraphicsContext (name,
-                               settings.DefaultPageSettings.PaperSize.Width / 100 * 72,
-                               settings.DefaultPageSettings.PaperSize.Height / 100 * 72, 
+                               default_page_settings.PaperSize.Width / 100 * 72,
+                               default_page_settings.PaperSize.Height / 100 * 72, 
                                // Harcoded dpy's
                                300, 300, ref graphics);
 
                        DOCINFO doc = new DOCINFO ();
                        doc.filename = name.ToString();
                        doc.settings = settings;
+                       doc.default_page_settings = default_page_settings;
                        doc_info.Add (graphics, doc);
 
                        return graphics;
                }
 
+               internal int GetCupsOptions (PrinterSettings printer_settings, PageSettings page_settings, out IntPtr options)
+               {
+                       options = IntPtr.Zero;
+
+                       PaperSize size = page_settings.PaperSize;
+                       int width = size.Width * 72 / 100;
+                       int height = size.Height * 72 / 100;
+
+                       string options_string =
+                               "copies=" + printer_settings.Copies + " " + 
+                               "Collate=" + printer_settings.Collate + " " +
+                               "ColorModel=" + (page_settings.Color ? "Color" : "Black") + " " +
+                               "PageSize=" + String.Format ("Custom.{0}x{1}", width, height);
+
+                       return cupsParseOptions (options_string, 0, ref options);
+               }
+
                // Properties
 
                internal override PrinterSettings.StringCollection InstalledPrinters {
@@ -293,7 +333,9 @@ namespace System.Drawing.Printing
                                        return string.Empty;
 
                                str = cupsGetDefault ();
-                               return Marshal.PtrToStringAnsi (str);
+                               if (str == IntPtr.Zero)
+                                       return Marshal.PtrToStringAnsi (str);
+                               return String.Empty;
                        }
                }
 
@@ -319,17 +361,143 @@ namespace System.Drawing.Printing
                                choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr_choice, typeof (PPD_CHOICE));
                                ptr_choice = new IntPtr (ptr_choice.ToInt64 () + Marshal.SizeOf (choice));
                                if (name.Equals (choice.choice)) {
-                                       rslt = choice.text;
+                                       // Special case for custom size (cups returns NULL for it)
+                                       if (name == "Custom" && choice.text == null)
+                                               rslt = "Custom";
+                                       else
+                                               rslt = choice.text;
+
                                        break;
                                }
                        }
                        return rslt;
                }
 
-               // TODO
+               private PaperKind GetPaperKind (int width, int height)
+               {
+                       if (width == 827 && height == 1169)
+                               return PaperKind.A4;
+                       if (width == 583 && height == 827)
+                               return PaperKind.A5;
+                       if (width == 717 && height == 1012)
+                               return PaperKind.B5;
+                       if (width == 693 && height == 984)
+                               return PaperKind.B5Envelope;
+                       if (width == 638 && height == 902)
+                               return PaperKind.C5Envelope;
+                       if (width == 449 && height == 638)
+                               return PaperKind.C6Envelope;
+                       if (width == 1700 && height == 2200)
+                               return PaperKind.CSheet;
+                       if (width == 433 && height == 866)
+                               return PaperKind.DLEnvelope;
+                       if (width == 2200 && height == 3400)
+                               return PaperKind.DSheet;
+                       if (width == 3400 && height == 4400)
+                               return PaperKind.ESheet;
+                       if (width == 725 && height == 1050)
+                               return PaperKind.Executive;
+                       if (width == 850 && height == 1300)
+                               return PaperKind.Folio;
+                       if (width == 850 && height == 1200)
+                               return PaperKind.GermanStandardFanfold;
+                       if (width == 1700 && height == 1100)
+                               return PaperKind.Ledger;
+                       if (width == 850 && height == 1400)
+                               return PaperKind.Legal;
+                       if (width == 927 && height == 1500)
+                               return PaperKind.LegalExtra;
+                       if (width == 850 && height == 1100)
+                               return PaperKind.Letter;
+                       if (width == 927 && height == 1200)
+                               return PaperKind.LetterExtra;
+                       if (width == 850 && height == 1269)
+                               return PaperKind.LetterPlus;
+                       if (width == 387 && height == 750)
+                               return PaperKind.MonarchEnvelope;
+                       if (width == 387 && height == 887)
+                               return PaperKind.Number9Envelope;
+                       if (width == 413 && height == 950)
+                               return PaperKind.Number10Envelope;
+                       if (width == 450 && height == 1037)
+                               return PaperKind.Number11Envelope;
+                       if (width == 475 && height == 1100)
+                               return PaperKind.Number12Envelope;
+                       if (width == 500 && height == 1150)
+                               return PaperKind.Number14Envelope;
+                       if (width == 363 && height == 650)
+                               return PaperKind.PersonalEnvelope;
+                       if (width == 1000 && height == 1100)
+                               return PaperKind.Standard10x11;
+                       if (width == 1000 && height == 1400)
+                               return PaperKind.Standard10x14;
+                       if (width == 1100 && height == 1700)
+                               return PaperKind.Standard11x17;
+                       if (width == 1200 && height == 1100)
+                               return PaperKind.Standard12x11;
+                       if (width == 1500 && height == 1100)
+                               return PaperKind.Standard15x11;
+                       if (width == 900 && height == 1100)
+                               return PaperKind.Standard9x11;
+                       if (width == 550 && height == 850)
+                               return PaperKind.Statement;
+                       if (width == 1100 && height == 1700)
+                               return PaperKind.Tabloid;
+                       if (width == 1487 && height == 1100)
+                               return PaperKind.USStandardFanfold;
+
+                       return PaperKind.Custom;
+               }
+
                internal override void GetPrintDialogInfo (string printer, ref string port, ref string type, ref string status, ref string comment)
                {                       
-                       status = "Ready";                       
+                       int printers, state = -1;
+                       CUPS_DESTS cups_dests;
+                       CUPS_OPTIONS options;
+                       string str;
+                       IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer, ptr_options;
+                       
+                       if (cups_installed == false)
+                               return;
+
+                       printers = cupsGetDests (ref dests);
+
+                       ptr_printers = dests;
+                       for (int i = 0; i < printers; i++) {
+                               cups_dests = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS));
+                               str = Marshal.PtrToStringAnsi (cups_dests.name);
+                               ptr_printers = new IntPtr (ptr_printers.ToInt64 () + 20 /*size of CUPS_DEST*/);
+                               if (str != printer)
+                                       continue;
+
+                               ptr_options = cups_dests.options;
+                               for (int o = 0; o < cups_dests.num_options; o ++) {
+                                       options = (CUPS_OPTIONS) Marshal.PtrToStructure (ptr_options, typeof (CUPS_OPTIONS));
+                                       str = Marshal.PtrToStringAnsi (options.name);                                   
+                                       if (str == "printer-state") {
+                                               state = Int32.Parse (Marshal.PtrToStringAnsi (options.val));
+                                       } else {
+                                               if (str == "printer-info")
+                                                       comment = Marshal.PtrToStringAnsi (options.val);
+                                       }
+                                       ptr_options = new IntPtr (ptr_options.ToInt64 () + 8 /*size of CUPS_DEST*/);
+                               }
+                               
+                       }
+
+                       Marshal.FreeHGlobal (dests);
+
+                       if (state == 4) {
+                               status = "Printing";
+                       }
+                       else {
+                               if (state == 5) {
+                                       status = "Stopped";
+                               }
+                               else {
+                                       status =  "Ready";
+                               }
+                       }                       
                }
 
                //
@@ -360,6 +528,12 @@ namespace System.Drawing.Printing
                [DllImport("libcups")]
                static extern void ppdClose (IntPtr ppd);
 
+               [DllImport ("libcups", CharSet=CharSet.Ansi)]
+               static extern int cupsParseOptions (string arg, int number_of_options, ref IntPtr options);
+
+               [DllImport("libcups")]
+               static extern void cupsFreeOptions (int number_options, IntPtr options);
+
                [DllImport("gdiplus.dll", CharSet=CharSet.Ansi)]
                static extern int GdipGetPostScriptGraphicsContext (string filename, int with, int height, double dpix, double dpiy, ref IntPtr graphics);
 
@@ -371,6 +545,7 @@ namespace System.Drawing.Printing
                public struct DOCINFO
                {
                        public PrinterSettings settings;
+                       public PageSettings default_page_settings;
                        public string title;
                        public string filename;
                }
@@ -460,6 +635,22 @@ namespace System.Drawing.Printing
 
                        /* There is more data after this that we are not using*/
                }
+
+
+               public struct CUPS_OPTIONS
+               {
+                       public IntPtr name;
+                       public IntPtr val;
+               }
+               
+               public struct CUPS_DESTS
+               {
+                       public IntPtr   name;
+                       public IntPtr   instance;
+                       public int      is_default;
+                       public int      num_options;
+                       public IntPtr   options;
+               }
        }
 }