* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System.Drawing / System.Drawing.Printing / PrintingServicesUnix.cs
1 //
2 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Author:
24 //
25 //      Jordi Mas i Hernandez, jordimash@gmail.com
26 //
27
28 using System.Runtime.InteropServices;
29 using System.Collections;
30 using System.Drawing.Printing;
31 using System.ComponentModel;
32 using System.Drawing.Imaging;
33 using System.Text;
34
35 namespace System.Drawing.Printing
36 {
37         internal class PrintingServicesUnix : PrintingServices
38         {
39                 private Hashtable doc_info = new Hashtable ();
40                 private bool cups_installed;
41
42                 internal PrintingServicesUnix ()
43                 {
44                         CheckCupsInstalled ();
45                 }
46
47                 private void CheckCupsInstalled ()
48                 {
49                         try {
50                                 cupsGetDefault ();
51                         }
52                         catch (DllNotFoundException) {
53                                 Console.WriteLine("libcups not found. To have printing support, you need cups installed");
54                                 cups_installed = false;
55                                 return;
56                         }
57
58                         cups_installed = true;
59                 }
60
61                 // Methods
62                 internal override void LoadPrinterSettings (string printer, PrinterSettings settings)
63                 {
64                         IntPtr ptr, ppd_handle;
65                         string ppd_filename;
66                         PPD_FILE ppd;
67
68                         if (cups_installed == false || (printer == null) || (printer == String.Empty)) {
69                                 return;
70                         }
71
72                         ptr = cupsGetPPD (printer);
73                         ppd_filename = Marshal.PtrToStringAnsi (ptr);
74                         ppd_handle = ppdOpenFile (ppd_filename);
75                         //Console.WriteLine ("File: {0}", ppd_filename);
76
77                         ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
78                         settings.landscape_angle = ppd.landscape;
79                         settings.supports_color = (ppd.color_device == 0) ? false : true;
80                         ppdClose (ppd_handle);
81                 }
82
83                 internal override void LoadPrinterResolutions (string printer, PrinterSettings settings)
84                 {
85                         settings.PrinterResolutions.Clear ();
86                         LoadDefaultResolutions (settings.PrinterResolutions);
87                 }
88
89                 internal override void LoadPrinterPaperSizes (string printer, PrinterSettings settings)
90                 {
91                         IntPtr ptr, ppd_handle;
92                         string ppd_filename, real_name;
93                         PPD_FILE ppd;
94                         PPD_SIZE size;
95                         PaperSize ps;
96                         PaperKind kind = PaperKind.Custom;
97
98                         settings.PaperSizes.Clear ();
99
100                         ptr = cupsGetPPD (printer);
101                         ppd_filename = Marshal.PtrToStringAnsi (ptr);
102                         ppd_handle = ppdOpenFile (ppd_filename);
103
104                         ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
105                         ptr = ppd.sizes;
106                         float w, h;
107                         for (int i = 0; i < ppd.num_sizes; i++) {
108                                 size = (PPD_SIZE) Marshal.PtrToStructure (ptr, typeof (PPD_SIZE));
109                                 real_name = GetPaperSizeName (ppd, size.name);
110                                 ptr = new IntPtr (ptr.ToInt64 () + Marshal.SizeOf (size));
111
112                                 w = size.width * 100 / 72;
113                                 h = size.length * 100 / 72;
114                                 ps = new PaperSize (real_name, (int) w, (int) h);
115                                 // TODO: Convert from name to paper kind enum
116                                 ps.SetKind (kind);
117                                 settings.PaperSizes.Add (ps);
118                         }
119
120                         ppdClose (ppd_handle);
121                 }
122
123                 internal override bool StartPage (GraphicsPrinter gr)
124                 {
125                         return true;
126                 }
127
128                 internal override bool EndPage (GraphicsPrinter gr)
129                 {
130                         GdipGetPostScriptSavePage (gr.Hdc);
131                         return true;
132                 }
133
134                 internal override bool EndDoc (GraphicsPrinter gr)
135                 {
136                         DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
137
138                         gr.Graphics.Dispose (); // Dispose object to force surface finish
139                         cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, 0, IntPtr.Zero);
140                         doc_info.Remove (gr.Hdc);
141                         //TODO: Delete temporary file created
142                         return true;
143                 }
144
145                 internal override bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file)
146                 {
147                         DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
148                         doc.title = doc_name;
149                         return true;
150                 }
151
152                 internal override IntPtr CreateGraphicsContext (PrinterSettings settings)
153                 {
154                         IntPtr graphics = IntPtr.Zero;
155                         StringBuilder name = new StringBuilder (1024);
156                         int length = name.Capacity;
157                         cupsTempFile (name, length);
158                 
159                         GdipGetPostScriptGraphicsContext (name.ToString(),
160                                 settings.DefaultPageSettings.PaperSize.Width / 100 * 72,
161                                 settings.DefaultPageSettings.PaperSize.Height / 100 * 72, 
162                                 // Harcoded dpy's
163                                 300, 300, ref graphics);
164
165                         DOCINFO doc = new DOCINFO ();
166                         doc.filename = name.ToString();
167                         doc.settings = settings;
168                         doc_info.Add (graphics, doc);
169
170                         return graphics;
171                 }
172
173                 // Properties
174
175                 internal override PrinterSettings.StringCollection InstalledPrinters {
176                         get {
177                                 int n_printers;
178                                 IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer;
179                                 string str;
180                                 PrinterSettings.StringCollection col = new PrinterSettings.StringCollection (new string[] {});
181
182                                 if (cups_installed == false)
183                                         return col;
184
185                                 n_printers = cupsGetDests (ref dests);
186
187                                 ptr_printers = dests;
188                                 for (int i = 0; i < n_printers; i++) {
189                                         ptr_printer = (IntPtr) Marshal.ReadInt32 (ptr_printers);
190                                         str = Marshal.PtrToStringAnsi (ptr_printer);
191                                         Marshal.FreeHGlobal (ptr_printer);
192                                         ptr_printers = new IntPtr (ptr_printers.ToInt64 () + 20 /*size of CUPS_DEST*/);
193                                         col.Add (str);
194                                 }
195                                 Marshal.FreeHGlobal (dests);
196                                 return col;
197                         }
198                 }
199
200                 internal override string DefaultPrinter {
201                         get {
202                                 IntPtr str;
203
204                                 if (cups_installed == false)
205                                         return string.Empty;
206
207                                 str = cupsGetDefault ();
208                                 return Marshal.PtrToStringAnsi (str);
209                         }
210                 }
211
212                 // Private functions
213
214                 private string GetPaperSizeName (PPD_FILE ppd, string name)
215                 {
216                         string rslt = name;
217                         PPD_GROUP group;
218                         PPD_OPTION option;
219                         PPD_CHOICE choice;
220                         IntPtr ptr, ptr_opt, ptr_choice;
221
222                         ptr = ppd.groups;
223                         for (int i = 0; i < ppd.num_groups; i++) {
224                                 group = (PPD_GROUP) Marshal.PtrToStructure (ptr, typeof (PPD_GROUP));
225                                 //Console.WriteLine ("Size text:{0} name:{1} opts {2}", group.text, group.name, group.num_options);
226                                 ptr = new IntPtr (ptr.ToInt64 () + Marshal.SizeOf (group));
227
228                                 ptr_opt = group.options;
229                                 for (int n = 0; n < group.num_options; n++) {
230                                         option = (PPD_OPTION) Marshal.PtrToStructure (ptr_opt, typeof (PPD_OPTION));
231                                         ptr_opt = new IntPtr (ptr_opt.ToInt64 () + Marshal.SizeOf (option));
232                                         //Console.WriteLine ("   key:{0} def:{1} text: {2}", option.keyword, option.defchoice, option.text);
233
234                                         if (!option.keyword.Equals ("PageSize"))
235                                                 continue;
236
237                                         ptr_choice = option.choices;
238                                         for (int c = 0; c < option.num_choices; c++) {
239                                                 choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr_choice, typeof (PPD_CHOICE));
240                                                 ptr_choice = new IntPtr (ptr_choice.ToInt64 () + Marshal.SizeOf (choice));
241                                                 //Console.WriteLine ("       choice:{0} - text: {1}", choice.choice, choice.text);
242                                                 if (name.Equals (choice.choice)) {
243                                                         rslt = choice.text;
244                                                         break;
245                                                 }
246                                         }
247                                 }
248                         }
249
250                         return rslt;
251                 }
252
253                 // TODO
254                 internal override void GetPrintDialogInfo (string printer, ref string port, ref string type, ref string status, ref string comment)
255                 {                       
256                         status = "Ready";                       
257                 }
258
259                 //
260                 // DllImports
261                 //
262
263                 [DllImport("libcups", CharSet=CharSet.Ansi)]
264                 static extern int cupsGetDests (ref IntPtr dests);
265
266                 [DllImport("libcups", CharSet=CharSet.Ansi)]
267                 static extern IntPtr cupsTempFile (StringBuilder sb, int len);
268
269                 [DllImport("libcups", CharSet=CharSet.Ansi)]
270                 static extern IntPtr cupsGetDefault ();
271
272                 [DllImport("libcups", CharSet=CharSet.Ansi)]
273                 static extern int cupsPrintFile (string printer, string filename, string title, int num_options, IntPtr options);
274
275                 [DllImport("libcups", CharSet=CharSet.Ansi)]
276                 static extern IntPtr cupsGetPPD (string printer);
277
278                 [DllImport("libcups", CharSet=CharSet.Ansi)]
279                 static extern IntPtr ppdOpenFile (string filename);
280
281                 [DllImport("libcups")]
282                 static extern void ppdClose (IntPtr ppd);
283
284                 [DllImport("libgdiplus", CharSet=CharSet.Ansi)]
285                 static extern int GdipGetPostScriptGraphicsContext (string filename, int with, int height, double dpix, double dpiy, ref IntPtr graphics);
286
287                 [DllImport("libgdiplus")]
288                 static extern int GdipGetPostScriptSavePage (IntPtr graphics);
289
290
291                 //Struct
292                 public struct DOCINFO
293                 {
294                         public PrinterSettings settings;
295                         public string title;
296                         public string filename;
297                 }
298
299                 public struct PPD_SIZE
300                 {
301                         public  int marked;
302                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
303                         public  string name;
304                         public  float width;
305                         public  float length;
306                         public  float left;
307                         public  float bottom;
308                         public  float right;
309                         public  float top;
310                 }
311
312                 public struct PPD_GROUP
313                 {
314                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)]
315                         public string text;
316                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
317                         public string name;
318                         public int num_options;
319                         public IntPtr options;
320                         public int num_subgroups;
321                         public IntPtr subgrups;
322                 }
323
324                 public struct PPD_OPTION
325                 {
326                         public byte     conflicted;
327                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
328                         public string   keyword;
329                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
330                         public string   defchoice;
331                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
332                         public string   text;
333                         public int      ui;
334                         public int      section;
335                         public float    order;
336                         public int      num_choices;
337                         public IntPtr   choices;
338                 }
339
340                 public struct PPD_CHOICE
341                 {
342                         public byte     marked;
343                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
344                         public string   choice;
345                         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
346                         public string   text;
347                         public IntPtr   code;
348                         public IntPtr   option;
349                 }
350
351                 public struct PPD_FILE
352                 {
353                         public int      language_level;
354                         public int      color_device;
355                         public int      variable_sizes;
356                         public int      accurate_screens;
357                         public int      contone_only;
358                         public int      landscape;
359                         public int      model_number;
360                         public int      manual_copies;
361                         public int      throughput;
362                         public int      colorspace;
363                         public IntPtr   patches;
364                         public int      num_emulations;
365                         public IntPtr   emulations;
366                         public IntPtr   jcl_begin;
367                         public IntPtr   jcl_ps;
368                         public IntPtr   jcl_end;
369                         public IntPtr   lang_encoding;
370                         public IntPtr   lang_version;
371                         public IntPtr   modelname;
372                         public IntPtr   ttrasterizer;
373                         public IntPtr   manufacturer;
374                         public IntPtr   product;
375                         public IntPtr   nickname;
376                         public IntPtr   shortnickname;
377                         public int      num_groups;
378                         public IntPtr   groups;
379                         public int      num_sizes;
380                         public IntPtr   sizes;
381
382                         /* There is more data after this that we are not using*/
383                 }
384         }
385 }
386