gdi32: Add a priority mechanism for pushing drivers on the stack in a defined order.
[wine] / dlls / wineps.drv / init.c
1 /*
2  *      PostScript driver initialization functions
3  *
4  *      Copyright 1998 Huw D M Davies
5  *      Copyright 2001 Marcus Meissner
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #include <string.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_CUPS_CUPS_H
31 # include <cups/cups.h>
32 #endif
33
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "winreg.h"
41 #include "winnls.h"
42 #include "psdrv.h"
43 #include "winspool.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
48
49 #ifdef SONAME_LIBCUPS
50 static void *cupshandle = NULL;
51 #endif
52
53 static const PSDRV_DEVMODE DefaultDevmode =
54 {
55   { /* dmPublic */
56 /* dmDeviceName */      {'W','i','n','e',' ','P','o','s','t','S','c','r','i','p','t',' ','D','r','i','v','e','r',0},
57 /* dmSpecVersion */     0x30a,
58 /* dmDriverVersion */   0x001,
59 /* dmSize */            sizeof(DEVMODEW),
60 /* dmDriverExtra */     sizeof(PSDRV_DEVMODE)-sizeof(DEVMODEW),
61 /* dmFields */          DM_ORIENTATION | DM_PAPERSIZE | DM_SCALE |
62                         DM_COPIES | DM_DEFAULTSOURCE | DM_COLOR |
63                         DM_YRESOLUTION | DM_TTOPTION,
64    { /* u1 */
65      { /* s1 */
66 /* dmOrientation */     DMORIENT_PORTRAIT,
67 /* dmPaperSize */       DMPAPER_LETTER,
68 /* dmPaperLength */     2794,
69 /* dmPaperWidth */      2159,
70 /* dmScale */           100, /* ?? */
71 /* dmCopies */          1,
72 /* dmDefaultSource */   DMBIN_AUTO,
73 /* dmPrintQuality */    0
74      }
75    },
76 /* dmColor */           DMCOLOR_COLOR,
77 /* dmDuplex */          DMDUP_SIMPLEX,
78 /* dmYResolution */     0,
79 /* dmTTOption */        DMTT_SUBDEV,
80 /* dmCollate */         0,
81 /* dmFormName */        {},
82 /* dmUnusedPadding */   0,
83 /* dmBitsPerPel */      0,
84 /* dmPelsWidth */       0,
85 /* dmPelsHeight */      0,
86    { /* u2 */
87 /* dmDisplayFlags */    0
88    },
89 /* dmDisplayFrequency */ 0,
90 /* dmICMMethod */       0,
91 /* dmICMIntent */       0,
92 /* dmMediaType */       0,
93 /* dmDitherType */      0,
94 /* dmReserved1 */       0,
95 /* dmReserved2 */       0,
96 /* dmPanningWidth */    0,
97 /* dmPanningHeight */   0
98   },
99   { /* dmDocPrivate */
100     /* dummy */ 0
101   },
102   { /* dmDrvPrivate */
103     /* numInstalledOptions */ 0
104   }
105 };
106
107 HINSTANCE PSDRV_hInstance = 0;
108 HANDLE PSDRV_Heap = 0;
109
110 static HFONT PSDRV_DefaultFont = 0;
111 static const LOGFONTA DefaultLogFont = {
112     100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0,
113     DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, ""
114 };
115
116 static const struct gdi_dc_funcs psdrv_funcs;
117
118 /*********************************************************************
119  *           DllMain
120  *
121  * Initializes font metrics and registers driver. wineps dll entry point.
122  *
123  */
124 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
125 {
126     TRACE("(%p, %d, %p)\n", hinst, reason, reserved);
127
128     switch(reason) {
129
130         case DLL_PROCESS_ATTACH:
131             PSDRV_hInstance = hinst;
132             DisableThreadLibraryCalls(hinst);
133
134             PSDRV_Heap = HeapCreate(0, 0x10000, 0);
135             if (PSDRV_Heap == NULL)
136                 return FALSE;
137
138             if (PSDRV_GetFontMetrics() == FALSE) {
139                 HeapDestroy(PSDRV_Heap);
140                 return FALSE;
141             }
142
143             PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont);
144             if (PSDRV_DefaultFont == NULL) {
145                 HeapDestroy(PSDRV_Heap);
146                 return FALSE;
147             }
148 #ifdef SONAME_LIBCUPS
149             /* dynamically load CUPS if not yet loaded */
150             if (!cupshandle) {
151                 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
152                 if (!cupshandle) cupshandle = (void*)-1;
153             }
154 #endif
155             break;
156
157         case DLL_PROCESS_DETACH:
158
159             DeleteObject( PSDRV_DefaultFont );
160             HeapDestroy( PSDRV_Heap );
161 #ifdef SONAME_LIBCUPS
162             if (cupshandle && (cupshandle != (void*)-1)) {
163                 wine_dlclose(cupshandle, NULL, 0);
164                 cupshandle = NULL;
165             }
166 #endif
167             break;
168     }
169
170     return TRUE;
171 }
172
173 static void PSDRV_UpdateDevCaps( PSDRV_PDEVICE *physDev )
174 {
175     PAGESIZE *page;
176     INT width = 0, height = 0;
177
178     if(physDev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) {
179         LIST_FOR_EACH_ENTRY(page, &physDev->pi->ppd->PageSizes, PAGESIZE, entry) {
180             if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize)
181                 break;
182         }
183
184         if(&page->entry == &physDev->pi->ppd->PageSizes) {
185             FIXME("Can't find page\n");
186             physDev->ImageableArea.left = 0;
187             physDev->ImageableArea.right = 0;
188             physDev->ImageableArea.bottom = 0;
189             physDev->ImageableArea.top = 0;
190             physDev->PageSize.cx = 0;
191             physDev->PageSize.cy = 0;
192         } else if(page->ImageableArea) {
193           /* physDev sizes in device units; ppd sizes in 1/72" */
194             physDev->ImageableArea.left = page->ImageableArea->llx *
195               physDev->logPixelsX / 72;
196             physDev->ImageableArea.right = page->ImageableArea->urx *
197               physDev->logPixelsX / 72;
198             physDev->ImageableArea.bottom = page->ImageableArea->lly *
199               physDev->logPixelsY / 72;
200             physDev->ImageableArea.top = page->ImageableArea->ury *
201               physDev->logPixelsY / 72;
202             physDev->PageSize.cx = page->PaperDimension->x *
203               physDev->logPixelsX / 72;
204             physDev->PageSize.cy = page->PaperDimension->y *
205               physDev->logPixelsY / 72;
206         } else {
207             physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0;
208             physDev->ImageableArea.right = physDev->PageSize.cx =
209               page->PaperDimension->x * physDev->logPixelsX / 72;
210             physDev->ImageableArea.top = physDev->PageSize.cy =
211               page->PaperDimension->y * physDev->logPixelsY / 72;
212         }
213     } else if((physDev->Devmode->dmPublic.dmFields & DM_PAPERLENGTH) &&
214               (physDev->Devmode->dmPublic.dmFields & DM_PAPERWIDTH)) {
215       /* physDev sizes in device units; Devmode sizes in 1/10 mm */
216         physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0;
217         physDev->ImageableArea.right = physDev->PageSize.cx =
218           physDev->Devmode->dmPublic.u1.s1.dmPaperWidth *
219           physDev->logPixelsX / 254;
220         physDev->ImageableArea.top = physDev->PageSize.cy =
221           physDev->Devmode->dmPublic.u1.s1.dmPaperLength *
222           physDev->logPixelsY / 254;
223     } else {
224         FIXME("Odd dmFields %x\n", physDev->Devmode->dmPublic.dmFields);
225         physDev->ImageableArea.left = 0;
226         physDev->ImageableArea.right = 0;
227         physDev->ImageableArea.bottom = 0;
228         physDev->ImageableArea.top = 0;
229         physDev->PageSize.cx = 0;
230         physDev->PageSize.cy = 0;
231     }
232
233     TRACE("ImageableArea = %d,%d - %d,%d: PageSize = %dx%d\n",
234           physDev->ImageableArea.left, physDev->ImageableArea.bottom,
235           physDev->ImageableArea.right, physDev->ImageableArea.top,
236           physDev->PageSize.cx, physDev->PageSize.cy);
237
238     /* these are in device units */
239     width = physDev->ImageableArea.right - physDev->ImageableArea.left;
240     height = physDev->ImageableArea.top - physDev->ImageableArea.bottom;
241
242     if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT) {
243         physDev->horzRes = width;
244         physDev->vertRes = height;
245     } else {
246         physDev->horzRes = height;
247         physDev->vertRes = width;
248     }
249
250     /* these are in mm */
251     physDev->horzSize = (physDev->horzRes * 25.4) / physDev->logPixelsX;
252     physDev->vertSize = (physDev->vertRes * 25.4) / physDev->logPixelsY;
253
254     TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, "
255           "horzRes = %d, vertRes = %d\n",
256           physDev->horzSize, physDev->vertSize,
257           physDev->horzRes, physDev->vertRes);
258 }
259
260 static PSDRV_PDEVICE *create_psdrv_physdev( PRINTERINFO *pi )
261 {
262     PSDRV_PDEVICE *physDev;
263
264     physDev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev) );
265     if (!physDev) return NULL;
266
267     physDev->Devmode = HeapAlloc( GetProcessHeap(), 0, sizeof(PSDRV_DEVMODE) );
268     if (!physDev->Devmode)
269     {
270         HeapFree( GetProcessHeap(), 0, physDev );
271         return NULL;
272     }
273
274     *physDev->Devmode = *pi->Devmode;
275     physDev->pi = pi;
276     physDev->logPixelsX = pi->ppd->DefaultResolution;
277     physDev->logPixelsY = pi->ppd->DefaultResolution;
278     return physDev;
279 }
280
281 /**********************************************************************
282  *           PSDRV_CreateDC
283  */
284 static BOOL PSDRV_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
285                             LPCWSTR output, const DEVMODEW* initData )
286 {
287     PSDRV_PDEVICE *physDev;
288     PRINTERINFO *pi;
289
290     TRACE("(%s %s %s %p)\n", debugstr_w(driver), debugstr_w(device),
291                              debugstr_w(output), initData);
292
293     if (!device) return FALSE;
294     pi = PSDRV_FindPrinterInfo( device );
295     if(!pi) return FALSE;
296
297     if(!pi->Fonts) {
298         RASTERIZER_STATUS status;
299         if(!GetRasterizerCaps(&status, sizeof(status)) ||
300            !(status.wFlags & TT_AVAILABLE) ||
301            !(status.wFlags & TT_ENABLED)) {
302             MESSAGE("Disabling printer %s since it has no builtin fonts and there are no TrueType fonts available.\n",
303                     debugstr_w(device));
304             return FALSE;
305         }
306     }
307
308     if (!(physDev = create_psdrv_physdev( pi ))) return FALSE;
309
310     if (output && *output) physDev->job.output = strdupW( output );
311
312     if(initData)
313         PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODE *)initData, pi);
314
315     PSDRV_UpdateDevCaps(physDev);
316     SelectObject( (*pdev)->hdc, PSDRV_DefaultFont );
317     push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
318     return TRUE;
319 }
320
321
322 /**********************************************************************
323  *           PSDRV_CreateCompatibleDC
324  */
325 static BOOL PSDRV_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
326 {
327     HDC hdc = (*pdev)->hdc;
328     PSDRV_PDEVICE *physDev, *orig_dev = get_psdrv_dev( orig );
329     PRINTERINFO *pi = PSDRV_FindPrinterInfo( orig_dev->pi->friendly_name );
330
331     if (!pi) return FALSE;
332     if (!(physDev = create_psdrv_physdev( pi ))) return FALSE;
333     PSDRV_MergeDevmodes( physDev->Devmode, orig_dev->Devmode, pi );
334     PSDRV_UpdateDevCaps(physDev);
335     SelectObject( hdc, PSDRV_DefaultFont );
336     push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
337     return TRUE;
338 }
339
340
341
342 /**********************************************************************
343  *           PSDRV_DeleteDC
344  */
345 static BOOL PSDRV_DeleteDC( PHYSDEV dev )
346 {
347     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
348
349     TRACE("\n");
350
351     HeapFree( GetProcessHeap(), 0, physDev->Devmode );
352     HeapFree( GetProcessHeap(), 0, physDev->job.output );
353     HeapFree( GetProcessHeap(), 0, physDev );
354
355     return TRUE;
356 }
357
358
359 /**********************************************************************
360  *           ResetDC   (WINEPS.@)
361  */
362 static HDC PSDRV_ResetDC( PHYSDEV dev, const DEVMODEW *lpInitData )
363 {
364     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
365
366     if (lpInitData)
367     {
368         PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODE *)lpInitData, physDev->pi);
369         PSDRV_UpdateDevCaps(physDev);
370     }
371     return dev->hdc;
372 }
373
374 /***********************************************************************
375  *           GetDeviceCaps    (WINEPS.@)
376  */
377 static INT PSDRV_GetDeviceCaps( PHYSDEV dev, INT cap )
378 {
379     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
380
381     switch(cap)
382     {
383     case DRIVERVERSION:
384         return 0;
385     case TECHNOLOGY:
386         return DT_RASPRINTER;
387     case HORZSIZE:
388         return MulDiv(physDev->horzSize, 100,
389                       physDev->Devmode->dmPublic.u1.s1.dmScale);
390     case VERTSIZE:
391         return MulDiv(physDev->vertSize, 100,
392                       physDev->Devmode->dmPublic.u1.s1.dmScale);
393     case HORZRES:
394     case DESKTOPHORZRES:
395         return physDev->horzRes;
396     case VERTRES:
397     case DESKTOPVERTRES:
398         return physDev->vertRes;
399     case BITSPIXEL:
400         return (physDev->pi->ppd->ColorDevice != CD_False) ? 32 : 1;
401     case PLANES:
402         return 1;
403     case NUMBRUSHES:
404         return -1;
405     case NUMPENS:
406         return 10;
407     case NUMMARKERS:
408         return 0;
409     case NUMFONTS:
410         return 39;
411     case NUMCOLORS:
412         return -1;
413     case PDEVICESIZE:
414         return sizeof(PSDRV_PDEVICE);
415     case CURVECAPS:
416         return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
417                 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
418     case LINECAPS:
419         return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
420                 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
421     case POLYGONALCAPS:
422         return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
423                 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
424     case TEXTCAPS:
425         return TC_CR_ANY | TC_VA_ABLE; /* psdrv 0x59f7 */
426     case CLIPCAPS:
427         return CP_RECTANGLE;
428     case RASTERCAPS:
429         return (RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DIBTODEV |
430                 RC_STRETCHBLT | RC_STRETCHDIB); /* psdrv 0x6e99 */
431     /* Are aspect[XY] and logPixels[XY] correct? */
432     /* Need to handle different res in x and y => fix ppd */
433     case ASPECTX:
434     case ASPECTY:
435         return physDev->pi->ppd->DefaultResolution;
436     case ASPECTXY:
437         return (int)hypot( (double)physDev->pi->ppd->DefaultResolution,
438                            (double)physDev->pi->ppd->DefaultResolution );
439     case LOGPIXELSX:
440         return MulDiv(physDev->logPixelsX,
441                       physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
442     case LOGPIXELSY:
443         return MulDiv(physDev->logPixelsY,
444                       physDev->Devmode->dmPublic.u1.s1.dmScale, 100);
445     case SIZEPALETTE:
446         return 0;
447     case NUMRESERVED:
448         return 0;
449     case COLORRES:
450         return 0;
451     case PHYSICALWIDTH:
452         return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
453           physDev->PageSize.cy : physDev->PageSize.cx;
454     case PHYSICALHEIGHT:
455         return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ?
456           physDev->PageSize.cx : physDev->PageSize.cy;
457     case PHYSICALOFFSETX:
458       if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
459           if(physDev->pi->ppd->LandscapeOrientation == -90)
460               return physDev->PageSize.cy - physDev->ImageableArea.top;
461           else
462               return physDev->ImageableArea.bottom;
463       }
464       return physDev->ImageableArea.left;
465
466     case PHYSICALOFFSETY:
467       if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) {
468           if(physDev->pi->ppd->LandscapeOrientation == -90)
469               return physDev->PageSize.cx - physDev->ImageableArea.right;
470           else
471               return physDev->ImageableArea.left;
472       }
473       return physDev->PageSize.cy - physDev->ImageableArea.top;
474
475     case SCALINGFACTORX:
476     case SCALINGFACTORY:
477     case VREFRESH:
478     case BLTALIGNMENT:
479         return 0;
480     case SHADEBLENDCAPS:
481         return SB_NONE;
482     default:
483         FIXME("(%p): unsupported capability %d, will return 0\n", dev->hdc, cap );
484         return 0;
485     }
486 }
487
488 static PRINTER_ENUM_VALUESA *load_font_sub_table( HANDLE printer, DWORD *num_entries )
489 {
490     DWORD res, needed, num;
491     PRINTER_ENUM_VALUESA *table = NULL;
492     static const char fontsubkey[] = "PrinterDriverData\\FontSubTable";
493
494     *num_entries = 0;
495
496     res = EnumPrinterDataExA( printer, fontsubkey, NULL, 0, &needed, &num );
497     if (res != ERROR_MORE_DATA) return NULL;
498
499     table = HeapAlloc( PSDRV_Heap, 0, needed );
500     if (!table) return NULL;
501
502     res = EnumPrinterDataExA( printer, fontsubkey, (LPBYTE)table, needed, &needed, &num );
503     if (res != ERROR_SUCCESS)
504     {
505         HeapFree( PSDRV_Heap, 0, table );
506         return NULL;
507     }
508
509     *num_entries = num;
510     return table;
511 }
512
513 static PSDRV_DEVMODE *get_printer_devmode( HANDLE printer )
514 {
515     DWORD needed, dm_size;
516     BOOL res;
517     PRINTER_INFO_9W *info;
518     PSDRV_DEVMODE *dm;
519
520     GetPrinterW( printer, 9, NULL, 0, &needed );
521     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
522
523     info = HeapAlloc( PSDRV_Heap, 0, needed );
524     res = GetPrinterW( printer, 9, (BYTE *)info, needed, &needed );
525     if (!res || !info->pDevMode)
526     {
527         HeapFree( PSDRV_Heap, 0, info );
528         return NULL;
529     }
530
531     /* sanity check the sizes */
532     dm_size = info->pDevMode->dmSize + info->pDevMode->dmDriverExtra;
533     if ((char *)info->pDevMode - (char *)info + dm_size > needed)
534     {
535         HeapFree( PSDRV_Heap, 0, info );
536         return NULL;
537     }
538
539     dm = (PSDRV_DEVMODE*)info;
540     memmove( dm, info->pDevMode, dm_size );
541     return dm;
542 }
543
544 static PSDRV_DEVMODE *get_devmode( HANDLE printer, const WCHAR *name, BOOL *is_default )
545 {
546     PSDRV_DEVMODE *dm = get_printer_devmode( printer );
547
548     *is_default = FALSE;
549
550     if (dm && dm->dmPublic.dmSize + dm->dmPublic.dmDriverExtra >= sizeof(DefaultDevmode))
551     {
552         TRACE( "Retrieved devmode from winspool\n" );
553         return dm;
554     }
555     HeapFree( PSDRV_Heap, 0, dm );
556
557     TRACE( "Using default devmode\n" );
558     dm = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
559     if (dm)
560     {
561         *dm = DefaultDevmode;
562         lstrcpynW( (WCHAR *)dm->dmPublic.dmDeviceName, name, CCHDEVICENAME );
563         *is_default = TRUE;
564     }
565     return dm;
566 }
567
568 static BOOL set_devmode( HANDLE printer, PSDRV_DEVMODE *dm )
569 {
570     PRINTER_INFO_9W info;
571     info.pDevMode = &dm->dmPublic;
572
573     return SetPrinterW( printer, 9, (BYTE *)&info, 0 );
574 }
575
576 static inline char *expand_env_string( char *str, DWORD type )
577 {
578     if (type == REG_EXPAND_SZ)
579     {
580         char *tmp;
581         DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
582         tmp = HeapAlloc( GetProcessHeap(), 0, needed );
583         if (tmp)
584         {
585             ExpandEnvironmentStringsA( str, tmp, needed );
586             HeapFree( GetProcessHeap(), 0, str );
587             return tmp;
588         }
589     }
590     return str;
591 }
592
593 static char *get_ppd_filename( HANDLE printer, const char *nameA, BOOL *needs_unlink )
594 {
595     char *ret = NULL;
596     DWORD needed, err, type;
597     HKEY hkey;
598     const char *data_dir, *filename;
599
600     *needs_unlink = FALSE;
601
602 #ifdef SONAME_LIBCUPS
603     if (cupshandle != (void*)-1)
604     {
605         typeof(cupsGetPPD) *pcupsGetPPD;
606
607         pcupsGetPPD = wine_dlsym( cupshandle, "cupsGetPPD", NULL, 0 );
608         if (pcupsGetPPD)
609         {
610             filename = pcupsGetPPD( nameA );
611
612             if (filename)
613             {
614                 needed = strlen( filename ) + 1;
615                 ret = HeapAlloc( GetProcessHeap(), 0, needed );
616                 memcpy( ret, filename, needed );
617                 *needs_unlink = TRUE;
618                 return ret;
619             }
620             else
621                 WARN( "CUPS did not find ppd for %s\n", debugstr_a(nameA) );
622         }
623     }
624 #endif
625
626     err = GetPrinterDataExA( printer, "PrinterDriverData", "PPD File", NULL, NULL, 0, &needed );
627     if (err == ERROR_MORE_DATA)
628     {
629         ret = HeapAlloc( GetProcessHeap(), 0, needed );
630         if (!ret) return NULL;
631         GetPrinterDataExA( printer, "PrinterDriverData", "PPD File", &type,
632                            (BYTE *)ret, needed, &needed );
633         return expand_env_string( ret, type );
634     }
635
636     /* Look for a ppd file for this printer in the config file.
637      * First look under that printer's name, and then under 'generic'
638      */
639     /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
640     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files", &hkey ) == ERROR_SUCCESS )
641     {
642         const char *value_name = NULL;
643
644         if (RegQueryValueExA( hkey, nameA, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
645             value_name = nameA;
646         else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
647             value_name = "generic";
648
649         if (value_name)
650         {
651             ret = HeapAlloc( GetProcessHeap(), 0, needed );
652             if (!ret) return NULL;
653             RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
654         }
655         RegCloseKey( hkey );
656         if (ret) return expand_env_string( ret, type );
657     }
658
659     if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
660     else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
661     else
662     {
663         ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(nameA) );
664         return NULL;
665     }
666     ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 );
667     if (ret)
668     {
669         strcpy( ret, data_dir );
670         strcat( ret, filename );
671     }
672
673     return ret;
674 }
675
676 static struct list printer_list = LIST_INIT( printer_list );
677
678 /**********************************************************************
679  *              PSDRV_FindPrinterInfo
680  */
681 PRINTERINFO *PSDRV_FindPrinterInfo(LPCWSTR name)
682 {
683     DWORD needed, res, dwPaperSize;
684     PRINTERINFO *pi;
685     FONTNAME *font;
686     const AFM *afm;
687     HANDLE hPrinter = 0;
688     char *ppd_filename = NULL, *nameA = NULL;
689     BOOL using_default_devmode = FALSE, needs_unlink = FALSE;
690     int len;
691
692     TRACE("'%s'\n", debugstr_w(name));
693
694     LIST_FOR_EACH_ENTRY( pi, &printer_list, PRINTERINFO, entry )
695     {
696         if (!strcmpW( pi->friendly_name, name ))
697             return pi;
698     }
699
700     pi = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) );
701     if (pi == NULL) return NULL;
702
703     if (!(pi->friendly_name = HeapAlloc( PSDRV_Heap, 0, (strlenW(name)+1)*sizeof(WCHAR) ))) goto fail;
704     strcpyW( pi->friendly_name, name );
705
706     if (OpenPrinterW( pi->friendly_name, &hPrinter, NULL ) == 0) {
707         ERR ("OpenPrinter failed with code %i\n", GetLastError ());
708         goto fail;
709     }
710
711     len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL );
712     nameA = HeapAlloc( GetProcessHeap(), 0, len );
713     WideCharToMultiByte( CP_ACP, 0, name, -1, nameA, len, NULL, NULL );
714
715     pi->Devmode = get_devmode( hPrinter, name, &using_default_devmode );
716     if (!pi->Devmode) goto fail;
717
718     ppd_filename = get_ppd_filename( hPrinter, nameA, &needs_unlink );
719     if (!ppd_filename) goto fail;
720
721     pi->ppd = PSDRV_ParsePPD( ppd_filename );
722     if (!pi->ppd)
723     {
724         WARN( "Couldn't parse PPD file '%s'\n", ppd_filename );
725         goto fail;
726     }
727
728     if(using_default_devmode) {
729         DWORD papersize;
730
731         if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER,
732                           (LPWSTR)&papersize, sizeof(papersize)/sizeof(WCHAR))) {
733             PSDRV_DEVMODE dm;
734             memset(&dm, 0, sizeof(dm));
735             dm.dmPublic.dmFields = DM_PAPERSIZE;
736             dm.dmPublic.u1.s1.dmPaperSize = papersize;
737             PSDRV_MergeDevmodes(pi->Devmode, &dm, pi);
738         }
739
740         set_devmode( hPrinter, pi->Devmode );
741     }
742
743     if(pi->ppd->DefaultPageSize) { /* We'll let the ppd override the devmode */
744         PSDRV_DEVMODE dm;
745         memset(&dm, 0, sizeof(dm));
746         dm.dmPublic.dmFields = DM_PAPERSIZE;
747         dm.dmPublic.u1.s1.dmPaperSize = pi->ppd->DefaultPageSize->WinPage;
748         PSDRV_MergeDevmodes(pi->Devmode, &dm, pi);
749     }
750
751     /*
752      *  This is a hack.  The default paper size should be read in as part of
753      *  the Devmode structure, but Wine doesn't currently provide a convenient
754      *  way to configure printers.
755      */
756     res = GetPrinterDataExA(hPrinter, "PrinterDriverData", "Paper Size", NULL,
757                             (LPBYTE)&dwPaperSize, sizeof(DWORD), &needed);
758     if (res == ERROR_SUCCESS)
759         pi->Devmode->dmPublic.u1.s1.dmPaperSize = (SHORT) dwPaperSize;
760     else if (res == ERROR_FILE_NOT_FOUND)
761         TRACE ("No 'Paper Size' for printer '%s'\n", debugstr_w(name));
762     else {
763         ERR ("GetPrinterDataA returned %i\n", res);
764         goto fail;
765     }
766
767     /* Duplex is indicated by the setting of the DM_DUPLEX bit in dmFields.
768        WinDuplex == 0 is a special case which means that the ppd has a
769        *DefaultDuplex: NotCapable entry.  In this case we'll try not to confuse
770        apps and set dmDuplex to DMDUP_SIMPLEX but leave the DM_DUPLEX clear.
771        PSDRV_WriteHeader understands this and copes. */
772     pi->Devmode->dmPublic.dmFields &= ~DM_DUPLEX;
773     if(pi->ppd->DefaultDuplex) {
774         pi->Devmode->dmPublic.dmDuplex = pi->ppd->DefaultDuplex->WinDuplex;
775         if(pi->Devmode->dmPublic.dmDuplex != 0)
776             pi->Devmode->dmPublic.dmFields |= DM_DUPLEX;
777         else
778             pi->Devmode->dmPublic.dmDuplex = DMDUP_SIMPLEX;
779     }
780
781     pi->FontSubTable = load_font_sub_table( hPrinter, &pi->FontSubTableSize );
782
783     LIST_FOR_EACH_ENTRY( font, &pi->ppd->InstalledFonts, FONTNAME, entry )
784     {
785         afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name);
786         if(!afm) {
787             TRACE( "Couldn't find AFM file for installed printer font '%s' - "
788                     "ignoring\n", font->Name);
789         }
790         else {
791             BOOL added;
792             if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) {
793                 PSDRV_FreeAFMList(pi->Fonts);
794                 goto fail;
795             }
796         }
797
798     }
799     ClosePrinter( hPrinter );
800     HeapFree( GetProcessHeap(), 0, nameA );
801     if (needs_unlink) unlink( ppd_filename );
802     HeapFree( GetProcessHeap(), 0, ppd_filename );
803     list_add_head( &printer_list, &pi->entry );
804     return pi;
805
806 fail:
807     if (hPrinter) ClosePrinter( hPrinter );
808     HeapFree(PSDRV_Heap, 0, pi->FontSubTable);
809     HeapFree(PSDRV_Heap, 0, pi->friendly_name);
810     HeapFree(PSDRV_Heap, 0, pi->Devmode);
811     HeapFree(PSDRV_Heap, 0, pi);
812     HeapFree( GetProcessHeap(), 0, nameA );
813     if (needs_unlink) unlink( ppd_filename );
814     HeapFree( GetProcessHeap(), 0, ppd_filename );
815     return NULL;
816 }
817
818
819 static const struct gdi_dc_funcs psdrv_funcs =
820 {
821     NULL,                               /* pAbortDoc */
822     NULL,                               /* pAbortPath */
823     NULL,                               /* pAlphaBlend */
824     NULL,                               /* pAngleArc */
825     PSDRV_Arc,                          /* pArc */
826     NULL,                               /* pArcTo */
827     NULL,                               /* pBeginPath */
828     NULL,                               /* pBlendImage */
829     NULL,                               /* pChoosePixelFormat */
830     PSDRV_Chord,                        /* pChord */
831     NULL,                               /* pCloseFigure */
832     NULL,                               /* pCopyBitmap */
833     NULL,                               /* pCreateBitmap */
834     PSDRV_CreateCompatibleDC,           /* pCreateCompatibleDC */
835     PSDRV_CreateDC,                     /* pCreateDC */
836     NULL,                               /* pDeleteBitmap */
837     PSDRV_DeleteDC,                     /* pDeleteDC */
838     NULL,                               /* pDeleteObject */
839     NULL,                               /* pDescribePixelFormat */
840     PSDRV_DeviceCapabilities,           /* pDeviceCapabilities */
841     PSDRV_Ellipse,                      /* pEllipse */
842     PSDRV_EndDoc,                       /* pEndDoc */
843     PSDRV_EndPage,                      /* pEndPage */
844     NULL,                               /* pEndPath */
845     PSDRV_EnumFonts,                    /* pEnumFonts */
846     NULL,                               /* pEnumICMProfiles */
847     NULL,                               /* pExcludeClipRect */
848     PSDRV_ExtDeviceMode,                /* pExtDeviceMode */
849     PSDRV_ExtEscape,                    /* pExtEscape */
850     NULL,                               /* pExtFloodFill */
851     NULL,                               /* pExtSelectClipRgn */
852     PSDRV_ExtTextOut,                   /* pExtTextOut */
853     PSDRV_FillPath,                     /* pFillPath */
854     NULL,                               /* pFillRgn */
855     NULL,                               /* pFlattenPath */
856     NULL,                               /* pFontIsLinked */
857     NULL,                               /* pFrameRgn */
858     NULL,                               /* pGdiComment */
859     NULL,                               /* pGdiRealizationInfo */
860     NULL,                               /* pGetBoundsRect */
861     NULL,                               /* pGetCharABCWidths */
862     NULL,                               /* pGetCharABCWidthsI */
863     PSDRV_GetCharWidth,                 /* pGetCharWidth */
864     PSDRV_GetDeviceCaps,                /* pGetDeviceCaps */
865     NULL,                               /* pGetDeviceGammaRamp */
866     NULL,                               /* pGetFontData */
867     NULL,                               /* pGetFontUnicodeRanges */
868     NULL,                               /* pGetGlyphIndices */
869     NULL,                               /* pGetGlyphOutline */
870     NULL,                               /* pGetICMProfile */
871     NULL,                               /* pGetImage */
872     NULL,                               /* pGetKerningPairs */
873     NULL,                               /* pGetNearestColor */
874     NULL,                               /* pGetOutlineTextMetrics */
875     NULL,                               /* pGetPixel */
876     NULL,                               /* pGetPixelFormat */
877     NULL,                               /* pGetSystemPaletteEntries */
878     NULL,                               /* pGetTextCharsetInfo */
879     PSDRV_GetTextExtentExPoint,         /* pGetTextExtentExPoint */
880     NULL,                               /* pGetTextExtentExPointI */
881     NULL,                               /* pGetTextFace */
882     PSDRV_GetTextMetrics,               /* pGetTextMetrics */
883     NULL,                               /* pGradientFill */
884     NULL,                               /* pIntersectClipRect */
885     NULL,                               /* pInvertRgn */
886     PSDRV_LineTo,                       /* pLineTo */
887     NULL,                               /* pModifyWorldTransform */
888     NULL,                               /* pMoveTo */
889     NULL,                               /* pOffsetClipRgn */
890     NULL,                               /* pOffsetViewportOrg */
891     NULL,                               /* pOffsetWindowOrg */
892     PSDRV_PaintRgn,                     /* pPaintRgn */
893     PSDRV_PatBlt,                       /* pPatBlt */
894     PSDRV_Pie,                          /* pPie */
895     PSDRV_PolyBezier,                   /* pPolyBezier */
896     PSDRV_PolyBezierTo,                 /* pPolyBezierTo */
897     NULL,                               /* pPolyDraw */
898     PSDRV_PolyPolygon,                  /* pPolyPolygon */
899     PSDRV_PolyPolyline,                 /* pPolyPolyline */
900     NULL,                               /* pPolygon */
901     NULL,                               /* pPolyline */
902     NULL,                               /* pPolylineTo */
903     PSDRV_PutImage,                     /* pPutImage */
904     NULL,                               /* pRealizeDefaultPalette */
905     NULL,                               /* pRealizePalette */
906     PSDRV_Rectangle,                    /* pRectangle */
907     PSDRV_ResetDC,                      /* pResetDC */
908     NULL,                               /* pRestoreDC */
909     PSDRV_RoundRect,                    /* pRoundRect */
910     NULL,                               /* pSaveDC */
911     NULL,                               /* pScaleViewportExt */
912     NULL,                               /* pScaleWindowExt */
913     NULL,                               /* pSelectBitmap */
914     PSDRV_SelectBrush,                  /* pSelectBrush */
915     NULL,                               /* pSelectClipPath */
916     PSDRV_SelectFont,                   /* pSelectFont */
917     NULL,                               /* pSelectPalette */
918     PSDRV_SelectPen,                    /* pSelectPen */
919     NULL,                               /* pSetArcDirection */
920     PSDRV_SetBkColor,                   /* pSetBkColor */
921     NULL,                               /* pSetBkMode */
922     NULL,                               /* pSetBoundsRect */
923     PSDRV_SetDCBrushColor,              /* pSetDCBrushColor */
924     PSDRV_SetDCPenColor,                /* pSetDCPenColor */
925     NULL,                               /* pSetDIBitsToDevice */
926     NULL,                               /* pSetDeviceClipping */
927     NULL,                               /* pSetDeviceGammaRamp */
928     NULL,                               /* pSetLayout */
929     NULL,                               /* pSetMapMode */
930     NULL,                               /* pSetMapperFlags */
931     PSDRV_SetPixel,                     /* pSetPixel */
932     NULL,                               /* pSetPixelFormat */
933     NULL,                               /* pSetPolyFillMode */
934     NULL,                               /* pSetROP2 */
935     NULL,                               /* pSetRelAbs */
936     NULL,                               /* pSetStretchBltMode */
937     NULL,                               /* pSetTextAlign */
938     NULL,                               /* pSetTextCharacterExtra */
939     PSDRV_SetTextColor,                 /* pSetTextColor */
940     NULL,                               /* pSetTextJustification */
941     NULL,                               /* pSetViewportExt */
942     NULL,                               /* pSetViewportOrg */
943     NULL,                               /* pSetWindowExt */
944     NULL,                               /* pSetWindowOrg */
945     NULL,                               /* pSetWorldTransform */
946     PSDRV_StartDoc,                     /* pStartDoc */
947     PSDRV_StartPage,                    /* pStartPage */
948     NULL,                               /* pStretchBlt */
949     NULL,                               /* pStretchDIBits */
950     PSDRV_StrokeAndFillPath,            /* pStrokeAndFillPath */
951     PSDRV_StrokePath,                   /* pStrokePath */
952     NULL,                               /* pSwapBuffers */
953     NULL,                               /* pUnrealizePalette */
954     NULL,                               /* pWidenPath */
955     NULL,                               /* pwglCopyContext */
956     NULL,                               /* pwglCreateContext */
957     NULL,                               /* pwglCreateContextAttribsARB */
958     NULL,                               /* pwglDeleteContext */
959     NULL,                               /* pwglGetPbufferDCARB */
960     NULL,                               /* pwglGetProcAddress */
961     NULL,                               /* pwglMakeContextCurrentARB */
962     NULL,                               /* pwglMakeCurrent */
963     NULL,                               /* pwglSetPixelFormatWINE */
964     NULL,                               /* pwglShareLists */
965     NULL,                               /* pwglUseFontBitmapsA */
966     NULL,                               /* pwglUseFontBitmapsW */
967     GDI_PRIORITY_GRAPHICS_DRV           /* priority */
968 };
969
970
971 /******************************************************************************
972  *      PSDRV_get_gdi_driver
973  */
974 const struct gdi_dc_funcs * CDECL PSDRV_get_gdi_driver( unsigned int version )
975 {
976     if (version != WINE_GDI_DRIVER_VERSION)
977     {
978         ERR( "version mismatch, gdi32 wants %u but wineps has %u\n", version, WINE_GDI_DRIVER_VERSION );
979         return NULL;
980     }
981     return &psdrv_funcs;
982 }