| /* |
| * PostScript driver initialization functions |
| * |
| * Copyright 1998 Huw D M Davies |
| * Copyright 2001 Marcus Meissner |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdarg.h> |
| #include <string.h> |
| #ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
| #endif |
| #ifdef HAVE_CUPS_CUPS_H |
| # include <cups/cups.h> |
| #endif |
| |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winerror.h" |
| #include "winreg.h" |
| #include "winnls.h" |
| #include "psdrv.h" |
| #include "winspool.h" |
| #include "wine/library.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(psdrv); |
| |
| #ifdef SONAME_LIBCUPS |
| static void *cupshandle = NULL; |
| #endif |
| |
| static const PSDRV_DEVMODE DefaultDevmode = |
| { |
| { /* dmPublic */ |
| /* dmDeviceName */ {'W','i','n','e',' ','P','o','s','t','S','c','r','i','p','t',' ','D','r','i','v','e','r',0}, |
| /* dmSpecVersion */ 0x30a, |
| /* dmDriverVersion */ 0x001, |
| /* dmSize */ sizeof(DEVMODEW), |
| /* dmDriverExtra */ sizeof(PSDRV_DEVMODE)-sizeof(DEVMODEW), |
| /* dmFields */ DM_ORIENTATION | DM_PAPERSIZE | DM_SCALE | |
| DM_COPIES | DM_DEFAULTSOURCE | DM_COLOR | |
| DM_YRESOLUTION | DM_TTOPTION, |
| { /* u1 */ |
| { /* s1 */ |
| /* dmOrientation */ DMORIENT_PORTRAIT, |
| /* dmPaperSize */ DMPAPER_LETTER, |
| /* dmPaperLength */ 2794, |
| /* dmPaperWidth */ 2159, |
| /* dmScale */ 100, /* ?? */ |
| /* dmCopies */ 1, |
| /* dmDefaultSource */ DMBIN_AUTO, |
| /* dmPrintQuality */ 0 |
| } |
| }, |
| /* dmColor */ DMCOLOR_COLOR, |
| /* dmDuplex */ DMDUP_SIMPLEX, |
| /* dmYResolution */ 0, |
| /* dmTTOption */ DMTT_SUBDEV, |
| /* dmCollate */ 0, |
| /* dmFormName */ {}, |
| /* dmUnusedPadding */ 0, |
| /* dmBitsPerPel */ 0, |
| /* dmPelsWidth */ 0, |
| /* dmPelsHeight */ 0, |
| { /* u2 */ |
| /* dmDisplayFlags */ 0 |
| }, |
| /* dmDisplayFrequency */ 0, |
| /* dmICMMethod */ 0, |
| /* dmICMIntent */ 0, |
| /* dmMediaType */ 0, |
| /* dmDitherType */ 0, |
| /* dmReserved1 */ 0, |
| /* dmReserved2 */ 0, |
| /* dmPanningWidth */ 0, |
| /* dmPanningHeight */ 0 |
| }, |
| { /* dmDocPrivate */ |
| /* dummy */ 0 |
| }, |
| { /* dmDrvPrivate */ |
| /* numInstalledOptions */ 0 |
| } |
| }; |
| |
| HINSTANCE PSDRV_hInstance = 0; |
| HANDLE PSDRV_Heap = 0; |
| |
| static HFONT PSDRV_DefaultFont = 0; |
| static const LOGFONTA DefaultLogFont = { |
| 100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0, |
| DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" |
| }; |
| |
| static const struct gdi_dc_funcs psdrv_funcs; |
| |
| /********************************************************************* |
| * DllMain |
| * |
| * Initializes font metrics and registers driver. wineps dll entry point. |
| * |
| */ |
| BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) |
| { |
| TRACE("(%p, %d, %p)\n", hinst, reason, reserved); |
| |
| switch(reason) { |
| |
| case DLL_PROCESS_ATTACH: |
| PSDRV_hInstance = hinst; |
| DisableThreadLibraryCalls(hinst); |
| |
| PSDRV_Heap = HeapCreate(0, 0x10000, 0); |
| if (PSDRV_Heap == NULL) |
| return FALSE; |
| |
| if (PSDRV_GetFontMetrics() == FALSE) { |
| HeapDestroy(PSDRV_Heap); |
| return FALSE; |
| } |
| |
| PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont); |
| if (PSDRV_DefaultFont == NULL) { |
| HeapDestroy(PSDRV_Heap); |
| return FALSE; |
| } |
| #ifdef SONAME_LIBCUPS |
| /* dynamically load CUPS if not yet loaded */ |
| if (!cupshandle) { |
| cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0); |
| if (!cupshandle) cupshandle = (void*)-1; |
| } |
| #endif |
| break; |
| |
| case DLL_PROCESS_DETACH: |
| |
| DeleteObject( PSDRV_DefaultFont ); |
| HeapDestroy( PSDRV_Heap ); |
| #ifdef SONAME_LIBCUPS |
| if (cupshandle && (cupshandle != (void*)-1)) { |
| wine_dlclose(cupshandle, NULL, 0); |
| cupshandle = NULL; |
| } |
| #endif |
| break; |
| } |
| |
| return TRUE; |
| } |
| |
| static void PSDRV_UpdateDevCaps( PSDRV_PDEVICE *physDev ) |
| { |
| PAGESIZE *page; |
| INT width = 0, height = 0; |
| |
| if(physDev->Devmode->dmPublic.dmFields & DM_PAPERSIZE) { |
| LIST_FOR_EACH_ENTRY(page, &physDev->pi->ppd->PageSizes, PAGESIZE, entry) { |
| if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize) |
| break; |
| } |
| |
| if(&page->entry == &physDev->pi->ppd->PageSizes) { |
| FIXME("Can't find page\n"); |
| physDev->ImageableArea.left = 0; |
| physDev->ImageableArea.right = 0; |
| physDev->ImageableArea.bottom = 0; |
| physDev->ImageableArea.top = 0; |
| physDev->PageSize.cx = 0; |
| physDev->PageSize.cy = 0; |
| } else if(page->ImageableArea) { |
| /* physDev sizes in device units; ppd sizes in 1/72" */ |
| physDev->ImageableArea.left = page->ImageableArea->llx * |
| physDev->logPixelsX / 72; |
| physDev->ImageableArea.right = page->ImageableArea->urx * |
| physDev->logPixelsX / 72; |
| physDev->ImageableArea.bottom = page->ImageableArea->lly * |
| physDev->logPixelsY / 72; |
| physDev->ImageableArea.top = page->ImageableArea->ury * |
| physDev->logPixelsY / 72; |
| physDev->PageSize.cx = page->PaperDimension->x * |
| physDev->logPixelsX / 72; |
| physDev->PageSize.cy = page->PaperDimension->y * |
| physDev->logPixelsY / 72; |
| } else { |
| physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0; |
| physDev->ImageableArea.right = physDev->PageSize.cx = |
| page->PaperDimension->x * physDev->logPixelsX / 72; |
| physDev->ImageableArea.top = physDev->PageSize.cy = |
| page->PaperDimension->y * physDev->logPixelsY / 72; |
| } |
| } else if((physDev->Devmode->dmPublic.dmFields & DM_PAPERLENGTH) && |
| (physDev->Devmode->dmPublic.dmFields & DM_PAPERWIDTH)) { |
| /* physDev sizes in device units; Devmode sizes in 1/10 mm */ |
| physDev->ImageableArea.left = physDev->ImageableArea.bottom = 0; |
| physDev->ImageableArea.right = physDev->PageSize.cx = |
| physDev->Devmode->dmPublic.u1.s1.dmPaperWidth * |
| physDev->logPixelsX / 254; |
| physDev->ImageableArea.top = physDev->PageSize.cy = |
| physDev->Devmode->dmPublic.u1.s1.dmPaperLength * |
| physDev->logPixelsY / 254; |
| } else { |
| FIXME("Odd dmFields %x\n", physDev->Devmode->dmPublic.dmFields); |
| physDev->ImageableArea.left = 0; |
| physDev->ImageableArea.right = 0; |
| physDev->ImageableArea.bottom = 0; |
| physDev->ImageableArea.top = 0; |
| physDev->PageSize.cx = 0; |
| physDev->PageSize.cy = 0; |
| } |
| |
| TRACE("ImageableArea = %d,%d - %d,%d: PageSize = %dx%d\n", |
| physDev->ImageableArea.left, physDev->ImageableArea.bottom, |
| physDev->ImageableArea.right, physDev->ImageableArea.top, |
| physDev->PageSize.cx, physDev->PageSize.cy); |
| |
| /* these are in device units */ |
| width = physDev->ImageableArea.right - physDev->ImageableArea.left; |
| height = physDev->ImageableArea.top - physDev->ImageableArea.bottom; |
| |
| if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT) { |
| physDev->horzRes = width; |
| physDev->vertRes = height; |
| } else { |
| physDev->horzRes = height; |
| physDev->vertRes = width; |
| } |
| |
| /* these are in mm */ |
| physDev->horzSize = (physDev->horzRes * 25.4) / physDev->logPixelsX; |
| physDev->vertSize = (physDev->vertRes * 25.4) / physDev->logPixelsY; |
| |
| TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, " |
| "horzRes = %d, vertRes = %d\n", |
| physDev->horzSize, physDev->vertSize, |
| physDev->horzRes, physDev->vertRes); |
| } |
| |
| static PSDRV_PDEVICE *create_psdrv_physdev( PRINTERINFO *pi ) |
| { |
| PSDRV_PDEVICE *physDev; |
| |
| physDev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev) ); |
| if (!physDev) return NULL; |
| |
| physDev->Devmode = HeapAlloc( GetProcessHeap(), 0, sizeof(PSDRV_DEVMODE) ); |
| if (!physDev->Devmode) |
| { |
| HeapFree( GetProcessHeap(), 0, physDev ); |
| return NULL; |
| } |
| |
| *physDev->Devmode = *pi->Devmode; |
| physDev->pi = pi; |
| physDev->logPixelsX = pi->ppd->DefaultResolution; |
| physDev->logPixelsY = pi->ppd->DefaultResolution; |
| return physDev; |
| } |
| |
| /********************************************************************** |
| * PSDRV_CreateDC |
| */ |
| static BOOL PSDRV_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device, |
| LPCWSTR output, const DEVMODEW* initData ) |
| { |
| PSDRV_PDEVICE *physDev; |
| PRINTERINFO *pi; |
| |
| TRACE("(%s %s %s %p)\n", debugstr_w(driver), debugstr_w(device), |
| debugstr_w(output), initData); |
| |
| if (!device) return FALSE; |
| pi = PSDRV_FindPrinterInfo( device ); |
| if(!pi) return FALSE; |
| |
| if(!pi->Fonts) { |
| RASTERIZER_STATUS status; |
| if(!GetRasterizerCaps(&status, sizeof(status)) || |
| !(status.wFlags & TT_AVAILABLE) || |
| !(status.wFlags & TT_ENABLED)) { |
| MESSAGE("Disabling printer %s since it has no builtin fonts and there are no TrueType fonts available.\n", |
| debugstr_w(device)); |
| return FALSE; |
| } |
| } |
| |
| if (!(physDev = create_psdrv_physdev( pi ))) return FALSE; |
| |
| if (output && *output) physDev->job.output = strdupW( output ); |
| |
| if(initData) |
| PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODE *)initData, pi); |
| |
| PSDRV_UpdateDevCaps(physDev); |
| SelectObject( (*pdev)->hdc, PSDRV_DefaultFont ); |
| push_dc_driver( pdev, &physDev->dev, &psdrv_funcs ); |
| return TRUE; |
| } |
| |
| |
| /********************************************************************** |
| * PSDRV_CreateCompatibleDC |
| */ |
| static BOOL PSDRV_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev ) |
| { |
| HDC hdc = (*pdev)->hdc; |
| PSDRV_PDEVICE *physDev, *orig_dev = get_psdrv_dev( orig ); |
| PRINTERINFO *pi = PSDRV_FindPrinterInfo( orig_dev->pi->friendly_name ); |
| |
| if (!pi) return FALSE; |
| if (!(physDev = create_psdrv_physdev( pi ))) return FALSE; |
| PSDRV_MergeDevmodes( physDev->Devmode, orig_dev->Devmode, pi ); |
| PSDRV_UpdateDevCaps(physDev); |
| SelectObject( hdc, PSDRV_DefaultFont ); |
| push_dc_driver( pdev, &physDev->dev, &psdrv_funcs ); |
| return TRUE; |
| } |
| |
| |
| |
| /********************************************************************** |
| * PSDRV_DeleteDC |
| */ |
| static BOOL PSDRV_DeleteDC( PHYSDEV dev ) |
| { |
| PSDRV_PDEVICE *physDev = get_psdrv_dev( dev ); |
| |
| TRACE("\n"); |
| |
| HeapFree( GetProcessHeap(), 0, physDev->Devmode ); |
| HeapFree( GetProcessHeap(), 0, physDev->job.output ); |
| HeapFree( GetProcessHeap(), 0, physDev ); |
| |
| return TRUE; |
| } |
| |
| |
| /********************************************************************** |
| * ResetDC (WINEPS.@) |
| */ |
| static HDC PSDRV_ResetDC( PHYSDEV dev, const DEVMODEW *lpInitData ) |
| { |
| PSDRV_PDEVICE *physDev = get_psdrv_dev( dev ); |
| |
| if (lpInitData) |
| { |
| PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODE *)lpInitData, physDev->pi); |
| PSDRV_UpdateDevCaps(physDev); |
| } |
| return dev->hdc; |
| } |
| |
| /*********************************************************************** |
| * GetDeviceCaps (WINEPS.@) |
| */ |
| static INT PSDRV_GetDeviceCaps( PHYSDEV dev, INT cap ) |
| { |
| PSDRV_PDEVICE *physDev = get_psdrv_dev( dev ); |
| |
| switch(cap) |
| { |
| case DRIVERVERSION: |
| return 0; |
| case TECHNOLOGY: |
| return DT_RASPRINTER; |
| case HORZSIZE: |
| return MulDiv(physDev->horzSize, 100, |
| physDev->Devmode->dmPublic.u1.s1.dmScale); |
| case VERTSIZE: |
| return MulDiv(physDev->vertSize, 100, |
| physDev->Devmode->dmPublic.u1.s1.dmScale); |
| case HORZRES: |
| case DESKTOPHORZRES: |
| return physDev->horzRes; |
| case VERTRES: |
| case DESKTOPVERTRES: |
| return physDev->vertRes; |
| case BITSPIXEL: |
| return (physDev->pi->ppd->ColorDevice != CD_False) ? 32 : 1; |
| case PLANES: |
| return 1; |
| case NUMBRUSHES: |
| return -1; |
| case NUMPENS: |
| return 10; |
| case NUMMARKERS: |
| return 0; |
| case NUMFONTS: |
| return 39; |
| case NUMCOLORS: |
| return -1; |
| case PDEVICESIZE: |
| return sizeof(PSDRV_PDEVICE); |
| case CURVECAPS: |
| return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE | |
| CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT); |
| case LINECAPS: |
| return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE | |
| LC_STYLED | LC_WIDESTYLED | LC_INTERIORS); |
| case POLYGONALCAPS: |
| return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE | |
| PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS); |
| case TEXTCAPS: |
| return TC_CR_ANY | TC_VA_ABLE; /* psdrv 0x59f7 */ |
| case CLIPCAPS: |
| return CP_RECTANGLE; |
| case RASTERCAPS: |
| return (RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DIBTODEV | |
| RC_STRETCHBLT | RC_STRETCHDIB); /* psdrv 0x6e99 */ |
| /* Are aspect[XY] and logPixels[XY] correct? */ |
| /* Need to handle different res in x and y => fix ppd */ |
| case ASPECTX: |
| case ASPECTY: |
| return physDev->pi->ppd->DefaultResolution; |
| case ASPECTXY: |
| return (int)hypot( (double)physDev->pi->ppd->DefaultResolution, |
| (double)physDev->pi->ppd->DefaultResolution ); |
| case LOGPIXELSX: |
| return MulDiv(physDev->logPixelsX, |
| physDev->Devmode->dmPublic.u1.s1.dmScale, 100); |
| case LOGPIXELSY: |
| return MulDiv(physDev->logPixelsY, |
| physDev->Devmode->dmPublic.u1.s1.dmScale, 100); |
| case SIZEPALETTE: |
| return 0; |
| case NUMRESERVED: |
| return 0; |
| case COLORRES: |
| return 0; |
| case PHYSICALWIDTH: |
| return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ? |
| physDev->PageSize.cy : physDev->PageSize.cx; |
| case PHYSICALHEIGHT: |
| return (physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) ? |
| physDev->PageSize.cx : physDev->PageSize.cy; |
| case PHYSICALOFFSETX: |
| if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) { |
| if(physDev->pi->ppd->LandscapeOrientation == -90) |
| return physDev->PageSize.cy - physDev->ImageableArea.top; |
| else |
| return physDev->ImageableArea.bottom; |
| } |
| return physDev->ImageableArea.left; |
| |
| case PHYSICALOFFSETY: |
| if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_LANDSCAPE) { |
| if(physDev->pi->ppd->LandscapeOrientation == -90) |
| return physDev->PageSize.cx - physDev->ImageableArea.right; |
| else |
| return physDev->ImageableArea.left; |
| } |
| return physDev->PageSize.cy - physDev->ImageableArea.top; |
| |
| case SCALINGFACTORX: |
| case SCALINGFACTORY: |
| case VREFRESH: |
| case BLTALIGNMENT: |
| return 0; |
| case SHADEBLENDCAPS: |
| return SB_NONE; |
| default: |
| FIXME("(%p): unsupported capability %d, will return 0\n", dev->hdc, cap ); |
| return 0; |
| } |
| } |
| |
| static PRINTER_ENUM_VALUESA *load_font_sub_table( HANDLE printer, DWORD *num_entries ) |
| { |
| DWORD res, needed, num; |
| PRINTER_ENUM_VALUESA *table = NULL; |
| static const char fontsubkey[] = "PrinterDriverData\\FontSubTable"; |
| |
| *num_entries = 0; |
| |
| res = EnumPrinterDataExA( printer, fontsubkey, NULL, 0, &needed, &num ); |
| if (res != ERROR_MORE_DATA) return NULL; |
| |
| table = HeapAlloc( PSDRV_Heap, 0, needed ); |
| if (!table) return NULL; |
| |
| res = EnumPrinterDataExA( printer, fontsubkey, (LPBYTE)table, needed, &needed, &num ); |
| if (res != ERROR_SUCCESS) |
| { |
| HeapFree( PSDRV_Heap, 0, table ); |
| return NULL; |
| } |
| |
| *num_entries = num; |
| return table; |
| } |
| |
| static PSDRV_DEVMODE *get_printer_devmode( HANDLE printer ) |
| { |
| DWORD needed, dm_size; |
| BOOL res; |
| PRINTER_INFO_9W *info; |
| PSDRV_DEVMODE *dm; |
| |
| GetPrinterW( printer, 9, NULL, 0, &needed ); |
| if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL; |
| |
| info = HeapAlloc( PSDRV_Heap, 0, needed ); |
| res = GetPrinterW( printer, 9, (BYTE *)info, needed, &needed ); |
| if (!res || !info->pDevMode) |
| { |
| HeapFree( PSDRV_Heap, 0, info ); |
| return NULL; |
| } |
| |
| /* sanity check the sizes */ |
| dm_size = info->pDevMode->dmSize + info->pDevMode->dmDriverExtra; |
| if ((char *)info->pDevMode - (char *)info + dm_size > needed) |
| { |
| HeapFree( PSDRV_Heap, 0, info ); |
| return NULL; |
| } |
| |
| dm = (PSDRV_DEVMODE*)info; |
| memmove( dm, info->pDevMode, dm_size ); |
| return dm; |
| } |
| |
| static PSDRV_DEVMODE *get_devmode( HANDLE printer, const WCHAR *name, BOOL *is_default ) |
| { |
| PSDRV_DEVMODE *dm = get_printer_devmode( printer ); |
| |
| *is_default = FALSE; |
| |
| if (dm && dm->dmPublic.dmSize + dm->dmPublic.dmDriverExtra >= sizeof(DefaultDevmode)) |
| { |
| TRACE( "Retrieved devmode from winspool\n" ); |
| return dm; |
| } |
| HeapFree( PSDRV_Heap, 0, dm ); |
| |
| TRACE( "Using default devmode\n" ); |
| dm = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) ); |
| if (dm) |
| { |
| *dm = DefaultDevmode; |
| lstrcpynW( (WCHAR *)dm->dmPublic.dmDeviceName, name, CCHDEVICENAME ); |
| *is_default = TRUE; |
| } |
| return dm; |
| } |
| |
| static BOOL set_devmode( HANDLE printer, PSDRV_DEVMODE *dm ) |
| { |
| PRINTER_INFO_9W info; |
| info.pDevMode = &dm->dmPublic; |
| |
| return SetPrinterW( printer, 9, (BYTE *)&info, 0 ); |
| } |
| |
| static inline char *expand_env_string( char *str, DWORD type ) |
| { |
| if (type == REG_EXPAND_SZ) |
| { |
| char *tmp; |
| DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 ); |
| tmp = HeapAlloc( GetProcessHeap(), 0, needed ); |
| if (tmp) |
| { |
| ExpandEnvironmentStringsA( str, tmp, needed ); |
| HeapFree( GetProcessHeap(), 0, str ); |
| return tmp; |
| } |
| } |
| return str; |
| } |
| |
| static char *get_ppd_filename( HANDLE printer, const char *nameA, BOOL *needs_unlink ) |
| { |
| char *ret = NULL; |
| DWORD needed, err, type; |
| HKEY hkey; |
| const char *data_dir, *filename; |
| |
| *needs_unlink = FALSE; |
| |
| #ifdef SONAME_LIBCUPS |
| if (cupshandle != (void*)-1) |
| { |
| typeof(cupsGetPPD) *pcupsGetPPD; |
| |
| pcupsGetPPD = wine_dlsym( cupshandle, "cupsGetPPD", NULL, 0 ); |
| if (pcupsGetPPD) |
| { |
| filename = pcupsGetPPD( nameA ); |
| |
| if (filename) |
| { |
| needed = strlen( filename ) + 1; |
| ret = HeapAlloc( GetProcessHeap(), 0, needed ); |
| memcpy( ret, filename, needed ); |
| *needs_unlink = TRUE; |
| return ret; |
| } |
| else |
| WARN( "CUPS did not find ppd for %s\n", debugstr_a(nameA) ); |
| } |
| } |
| #endif |
| |
| err = GetPrinterDataExA( printer, "PrinterDriverData", "PPD File", NULL, NULL, 0, &needed ); |
| if (err == ERROR_MORE_DATA) |
| { |
| ret = HeapAlloc( GetProcessHeap(), 0, needed ); |
| if (!ret) return NULL; |
| GetPrinterDataExA( printer, "PrinterDriverData", "PPD File", &type, |
| (BYTE *)ret, needed, &needed ); |
| return expand_env_string( ret, type ); |
| } |
| |
| /* Look for a ppd file for this printer in the config file. |
| * First look under that printer's name, and then under 'generic' |
| */ |
| /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */ |
| if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files", &hkey ) == ERROR_SUCCESS ) |
| { |
| const char *value_name = NULL; |
| |
| if (RegQueryValueExA( hkey, nameA, 0, NULL, NULL, &needed ) == ERROR_SUCCESS) |
| value_name = nameA; |
| else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS) |
| value_name = "generic"; |
| |
| if (value_name) |
| { |
| ret = HeapAlloc( GetProcessHeap(), 0, needed ); |
| if (!ret) return NULL; |
| RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed ); |
| } |
| RegCloseKey( hkey ); |
| if (ret) return expand_env_string( ret, type ); |
| } |
| |
| if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd"; |
| else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd"; |
| else |
| { |
| ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(nameA) ); |
| return NULL; |
| } |
| ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 ); |
| if (ret) |
| { |
| strcpy( ret, data_dir ); |
| strcat( ret, filename ); |
| } |
| |
| return ret; |
| } |
| |
| static struct list printer_list = LIST_INIT( printer_list ); |
| |
| /********************************************************************** |
| * PSDRV_FindPrinterInfo |
| */ |
| PRINTERINFO *PSDRV_FindPrinterInfo(LPCWSTR name) |
| { |
| DWORD needed, res, dwPaperSize; |
| PRINTERINFO *pi; |
| FONTNAME *font; |
| const AFM *afm; |
| HANDLE hPrinter = 0; |
| char *ppd_filename = NULL, *nameA = NULL; |
| BOOL using_default_devmode = FALSE, needs_unlink = FALSE; |
| int len; |
| |
| TRACE("'%s'\n", debugstr_w(name)); |
| |
| LIST_FOR_EACH_ENTRY( pi, &printer_list, PRINTERINFO, entry ) |
| { |
| if (!strcmpW( pi->friendly_name, name )) |
| return pi; |
| } |
| |
| pi = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) ); |
| if (pi == NULL) return NULL; |
| |
| if (!(pi->friendly_name = HeapAlloc( PSDRV_Heap, 0, (strlenW(name)+1)*sizeof(WCHAR) ))) goto fail; |
| strcpyW( pi->friendly_name, name ); |
| |
| if (OpenPrinterW( pi->friendly_name, &hPrinter, NULL ) == 0) { |
| ERR ("OpenPrinter failed with code %i\n", GetLastError ()); |
| goto fail; |
| } |
| |
| len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL ); |
| nameA = HeapAlloc( GetProcessHeap(), 0, len ); |
| WideCharToMultiByte( CP_ACP, 0, name, -1, nameA, len, NULL, NULL ); |
| |
| pi->Devmode = get_devmode( hPrinter, name, &using_default_devmode ); |
| if (!pi->Devmode) goto fail; |
| |
| ppd_filename = get_ppd_filename( hPrinter, nameA, &needs_unlink ); |
| if (!ppd_filename) goto fail; |
| |
| pi->ppd = PSDRV_ParsePPD( ppd_filename ); |
| if (!pi->ppd) |
| { |
| WARN( "Couldn't parse PPD file '%s'\n", ppd_filename ); |
| goto fail; |
| } |
| |
| if(using_default_devmode) { |
| DWORD papersize; |
| |
| if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER, |
| (LPWSTR)&papersize, sizeof(papersize)/sizeof(WCHAR))) { |
| PSDRV_DEVMODE dm; |
| memset(&dm, 0, sizeof(dm)); |
| dm.dmPublic.dmFields = DM_PAPERSIZE; |
| dm.dmPublic.u1.s1.dmPaperSize = papersize; |
| PSDRV_MergeDevmodes(pi->Devmode, &dm, pi); |
| } |
| |
| set_devmode( hPrinter, pi->Devmode ); |
| } |
| |
| if(pi->ppd->DefaultPageSize) { /* We'll let the ppd override the devmode */ |
| PSDRV_DEVMODE dm; |
| memset(&dm, 0, sizeof(dm)); |
| dm.dmPublic.dmFields = DM_PAPERSIZE; |
| dm.dmPublic.u1.s1.dmPaperSize = pi->ppd->DefaultPageSize->WinPage; |
| PSDRV_MergeDevmodes(pi->Devmode, &dm, pi); |
| } |
| |
| /* |
| * This is a hack. The default paper size should be read in as part of |
| * the Devmode structure, but Wine doesn't currently provide a convenient |
| * way to configure printers. |
| */ |
| res = GetPrinterDataExA(hPrinter, "PrinterDriverData", "Paper Size", NULL, |
| (LPBYTE)&dwPaperSize, sizeof(DWORD), &needed); |
| if (res == ERROR_SUCCESS) |
| pi->Devmode->dmPublic.u1.s1.dmPaperSize = (SHORT) dwPaperSize; |
| else if (res == ERROR_FILE_NOT_FOUND) |
| TRACE ("No 'Paper Size' for printer '%s'\n", debugstr_w(name)); |
| else { |
| ERR ("GetPrinterDataA returned %i\n", res); |
| goto fail; |
| } |
| |
| /* Duplex is indicated by the setting of the DM_DUPLEX bit in dmFields. |
| WinDuplex == 0 is a special case which means that the ppd has a |
| *DefaultDuplex: NotCapable entry. In this case we'll try not to confuse |
| apps and set dmDuplex to DMDUP_SIMPLEX but leave the DM_DUPLEX clear. |
| PSDRV_WriteHeader understands this and copes. */ |
| pi->Devmode->dmPublic.dmFields &= ~DM_DUPLEX; |
| if(pi->ppd->DefaultDuplex) { |
| pi->Devmode->dmPublic.dmDuplex = pi->ppd->DefaultDuplex->WinDuplex; |
| if(pi->Devmode->dmPublic.dmDuplex != 0) |
| pi->Devmode->dmPublic.dmFields |= DM_DUPLEX; |
| else |
| pi->Devmode->dmPublic.dmDuplex = DMDUP_SIMPLEX; |
| } |
| |
| pi->FontSubTable = load_font_sub_table( hPrinter, &pi->FontSubTableSize ); |
| |
| LIST_FOR_EACH_ENTRY( font, &pi->ppd->InstalledFonts, FONTNAME, entry ) |
| { |
| afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name); |
| if(!afm) { |
| TRACE( "Couldn't find AFM file for installed printer font '%s' - " |
| "ignoring\n", font->Name); |
| } |
| else { |
| BOOL added; |
| if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) { |
| PSDRV_FreeAFMList(pi->Fonts); |
| goto fail; |
| } |
| } |
| |
| } |
| ClosePrinter( hPrinter ); |
| HeapFree( GetProcessHeap(), 0, nameA ); |
| if (needs_unlink) unlink( ppd_filename ); |
| HeapFree( GetProcessHeap(), 0, ppd_filename ); |
| list_add_head( &printer_list, &pi->entry ); |
| return pi; |
| |
| fail: |
| if (hPrinter) ClosePrinter( hPrinter ); |
| HeapFree(PSDRV_Heap, 0, pi->FontSubTable); |
| HeapFree(PSDRV_Heap, 0, pi->friendly_name); |
| HeapFree(PSDRV_Heap, 0, pi->Devmode); |
| HeapFree(PSDRV_Heap, 0, pi); |
| HeapFree( GetProcessHeap(), 0, nameA ); |
| if (needs_unlink) unlink( ppd_filename ); |
| HeapFree( GetProcessHeap(), 0, ppd_filename ); |
| return NULL; |
| } |
| |
| |
| static const struct gdi_dc_funcs psdrv_funcs = |
| { |
| NULL, /* pAbortDoc */ |
| NULL, /* pAbortPath */ |
| NULL, /* pAlphaBlend */ |
| NULL, /* pAngleArc */ |
| PSDRV_Arc, /* pArc */ |
| NULL, /* pArcTo */ |
| NULL, /* pBeginPath */ |
| NULL, /* pBlendImage */ |
| NULL, /* pChoosePixelFormat */ |
| PSDRV_Chord, /* pChord */ |
| NULL, /* pCloseFigure */ |
| NULL, /* pCopyBitmap */ |
| NULL, /* pCreateBitmap */ |
| PSDRV_CreateCompatibleDC, /* pCreateCompatibleDC */ |
| PSDRV_CreateDC, /* pCreateDC */ |
| NULL, /* pDeleteBitmap */ |
| PSDRV_DeleteDC, /* pDeleteDC */ |
| NULL, /* pDeleteObject */ |
| NULL, /* pDescribePixelFormat */ |
| PSDRV_DeviceCapabilities, /* pDeviceCapabilities */ |
| PSDRV_Ellipse, /* pEllipse */ |
| PSDRV_EndDoc, /* pEndDoc */ |
| PSDRV_EndPage, /* pEndPage */ |
| NULL, /* pEndPath */ |
| PSDRV_EnumFonts, /* pEnumFonts */ |
| NULL, /* pEnumICMProfiles */ |
| NULL, /* pExcludeClipRect */ |
| PSDRV_ExtDeviceMode, /* pExtDeviceMode */ |
| PSDRV_ExtEscape, /* pExtEscape */ |
| NULL, /* pExtFloodFill */ |
| NULL, /* pExtSelectClipRgn */ |
| PSDRV_ExtTextOut, /* pExtTextOut */ |
| PSDRV_FillPath, /* pFillPath */ |
| NULL, /* pFillRgn */ |
| NULL, /* pFlattenPath */ |
| NULL, /* pFontIsLinked */ |
| NULL, /* pFrameRgn */ |
| NULL, /* pGdiComment */ |
| NULL, /* pGdiRealizationInfo */ |
| NULL, /* pGetBoundsRect */ |
| NULL, /* pGetCharABCWidths */ |
| NULL, /* pGetCharABCWidthsI */ |
| PSDRV_GetCharWidth, /* pGetCharWidth */ |
| PSDRV_GetDeviceCaps, /* pGetDeviceCaps */ |
| NULL, /* pGetDeviceGammaRamp */ |
| NULL, /* pGetFontData */ |
| NULL, /* pGetFontUnicodeRanges */ |
| NULL, /* pGetGlyphIndices */ |
| NULL, /* pGetGlyphOutline */ |
| NULL, /* pGetICMProfile */ |
| NULL, /* pGetImage */ |
| NULL, /* pGetKerningPairs */ |
| NULL, /* pGetNearestColor */ |
| NULL, /* pGetOutlineTextMetrics */ |
| NULL, /* pGetPixel */ |
| NULL, /* pGetPixelFormat */ |
| NULL, /* pGetSystemPaletteEntries */ |
| NULL, /* pGetTextCharsetInfo */ |
| PSDRV_GetTextExtentExPoint, /* pGetTextExtentExPoint */ |
| NULL, /* pGetTextExtentExPointI */ |
| NULL, /* pGetTextFace */ |
| PSDRV_GetTextMetrics, /* pGetTextMetrics */ |
| NULL, /* pGradientFill */ |
| NULL, /* pIntersectClipRect */ |
| NULL, /* pInvertRgn */ |
| PSDRV_LineTo, /* pLineTo */ |
| NULL, /* pModifyWorldTransform */ |
| NULL, /* pMoveTo */ |
| NULL, /* pOffsetClipRgn */ |
| NULL, /* pOffsetViewportOrg */ |
| NULL, /* pOffsetWindowOrg */ |
| PSDRV_PaintRgn, /* pPaintRgn */ |
| PSDRV_PatBlt, /* pPatBlt */ |
| PSDRV_Pie, /* pPie */ |
| PSDRV_PolyBezier, /* pPolyBezier */ |
| PSDRV_PolyBezierTo, /* pPolyBezierTo */ |
| NULL, /* pPolyDraw */ |
| PSDRV_PolyPolygon, /* pPolyPolygon */ |
| PSDRV_PolyPolyline, /* pPolyPolyline */ |
| NULL, /* pPolygon */ |
| NULL, /* pPolyline */ |
| NULL, /* pPolylineTo */ |
| PSDRV_PutImage, /* pPutImage */ |
| NULL, /* pRealizeDefaultPalette */ |
| NULL, /* pRealizePalette */ |
| PSDRV_Rectangle, /* pRectangle */ |
| PSDRV_ResetDC, /* pResetDC */ |
| NULL, /* pRestoreDC */ |
| PSDRV_RoundRect, /* pRoundRect */ |
| NULL, /* pSaveDC */ |
| NULL, /* pScaleViewportExt */ |
| NULL, /* pScaleWindowExt */ |
| NULL, /* pSelectBitmap */ |
| PSDRV_SelectBrush, /* pSelectBrush */ |
| NULL, /* pSelectClipPath */ |
| PSDRV_SelectFont, /* pSelectFont */ |
| NULL, /* pSelectPalette */ |
| PSDRV_SelectPen, /* pSelectPen */ |
| NULL, /* pSetArcDirection */ |
| PSDRV_SetBkColor, /* pSetBkColor */ |
| NULL, /* pSetBkMode */ |
| PSDRV_SetDCBrushColor, /* pSetDCBrushColor */ |
| PSDRV_SetDCPenColor, /* pSetDCPenColor */ |
| NULL, /* pSetDIBitsToDevice */ |
| NULL, /* pSetDeviceClipping */ |
| NULL, /* pSetDeviceGammaRamp */ |
| NULL, /* pSetLayout */ |
| NULL, /* pSetMapMode */ |
| NULL, /* pSetMapperFlags */ |
| PSDRV_SetPixel, /* pSetPixel */ |
| NULL, /* pSetPixelFormat */ |
| NULL, /* pSetPolyFillMode */ |
| NULL, /* pSetROP2 */ |
| NULL, /* pSetRelAbs */ |
| NULL, /* pSetStretchBltMode */ |
| NULL, /* pSetTextAlign */ |
| NULL, /* pSetTextCharacterExtra */ |
| PSDRV_SetTextColor, /* pSetTextColor */ |
| NULL, /* pSetTextJustification */ |
| NULL, /* pSetViewportExt */ |
| NULL, /* pSetViewportOrg */ |
| NULL, /* pSetWindowExt */ |
| NULL, /* pSetWindowOrg */ |
| NULL, /* pSetWorldTransform */ |
| PSDRV_StartDoc, /* pStartDoc */ |
| PSDRV_StartPage, /* pStartPage */ |
| NULL, /* pStretchBlt */ |
| NULL, /* pStretchDIBits */ |
| PSDRV_StrokeAndFillPath, /* pStrokeAndFillPath */ |
| PSDRV_StrokePath, /* pStrokePath */ |
| NULL, /* pSwapBuffers */ |
| NULL, /* pUnrealizePalette */ |
| NULL, /* pWidenPath */ |
| /* OpenGL not supported */ |
| }; |
| |
| |
| /****************************************************************************** |
| * PSDRV_get_gdi_driver |
| */ |
| const struct gdi_dc_funcs * CDECL PSDRV_get_gdi_driver( unsigned int version ) |
| { |
| if (version != WINE_GDI_DRIVER_VERSION) |
| { |
| ERR( "version mismatch, gdi32 wants %u but wineps has %u\n", version, WINE_GDI_DRIVER_VERSION ); |
| return NULL; |
| } |
| return &psdrv_funcs; |
| } |