wine/dlls/wineps/init.c
Marcus Meissner 0c63012b6d Implemented /etc/printcap based printing support.
Changed 'CUPS:printername' to 'LPR:printername'.
Some fixes in AddPrinterW().
2001-05-09 17:10:41 +00:00

642 lines
20 KiB
C

/*
* PostScript driver initialization functions
*
* Copyright 1998 Huw D M Davies
* Copyright 2001 Marcus Meissner
*
*/
#include <string.h>
#include <unistd.h>
#include "gdi.h"
#include "psdrv.h"
#include "debugtools.h"
#include "heap.h"
#include "winreg.h"
#include "winspool.h"
#include "winerror.h"
#include "options.h"
#ifdef HAVE_CUPS
# include <cups/cups.h>
#endif
DEFAULT_DEBUG_CHANNEL(psdrv);
static BOOL PSDRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device,
LPCSTR output, const DEVMODEA* initData );
static BOOL PSDRV_DeleteDC( DC *dc );
static const DC_FUNCTIONS PSDRV_Funcs =
{
NULL, /* pAbortDoc */
NULL, /* pAbortPath */
NULL, /* pAngleArc */
PSDRV_Arc, /* pArc */
NULL, /* pArcTo */
NULL, /* pBeginPath */
NULL, /* pBitBlt */
NULL, /* pBitmapBits */
NULL, /* pChoosePixelFormat */
PSDRV_Chord, /* pChord */
NULL, /* pCloseFigure */
NULL, /* pCreateBitmap */
PSDRV_CreateDC, /* pCreateDC */
NULL, /* pCreateDIBSection */
NULL, /* pCreateDIBSection16 */
PSDRV_DeleteDC, /* pDeleteDC */
NULL, /* pDeleteObject */
NULL, /* pDescribePixelFormat */
PSDRV_DeviceCapabilities, /* pDeviceCapabilities */
PSDRV_Ellipse, /* pEllipse */
PSDRV_EndDoc, /* pEndDoc */
PSDRV_EndPage, /* pEndPage */
NULL, /* pEndPath */
PSDRV_EnumDeviceFonts, /* pEnumDeviceFonts */
PSDRV_Escape, /* pEscape */
NULL, /* pExcludeClipRect */
PSDRV_ExtDeviceMode, /* pExtDeviceMode */
NULL, /* pExtFloodFill */
PSDRV_ExtTextOut, /* pExtTextOut */
NULL, /* pFillPath */
NULL, /* pFillRgn */
NULL, /* pFlattenPath */
NULL, /* pFrameRgn */
PSDRV_GetCharWidth, /* pGetCharWidth */
NULL, /* pGetDCOrgEx */
NULL, /* pGetDeviceGammaRamp */
NULL, /* pGetPixel */
NULL, /* pGetPixelFormat */
PSDRV_GetTextExtentPoint, /* pGetTextExtentPoint */
PSDRV_GetTextMetrics, /* pGetTextMetrics */
NULL, /* pIntersectClipRect */
NULL, /* pInvertRgn */
PSDRV_LineTo, /* pLineTo */
NULL, /* pMoveTo */
NULL, /* pOffsetClipRgn */
NULL, /* pOffsetViewportOrg (optional) */
NULL, /* pOffsetWindowOrg (optional) */
NULL, /* pPaintRgn */
PSDRV_PatBlt, /* pPatBlt */
PSDRV_Pie, /* pPie */
NULL, /* pPolyBezier */
NULL, /* pPolyBezierTo */
NULL, /* pPolyDraw */
PSDRV_PolyPolygon, /* pPolyPolygon */
PSDRV_PolyPolyline, /* pPolyPolyline */
PSDRV_Polygon, /* pPolygon */
PSDRV_Polyline, /* pPolyline */
NULL, /* pPolylineTo */
NULL, /* pRealizePalette */
PSDRV_Rectangle, /* pRectangle */
NULL, /* pRestoreDC */
PSDRV_RoundRect, /* pRoundRect */
NULL, /* pSaveDC */
NULL, /* pScaleViewportExt (optional) */
NULL, /* pScaleWindowExt (optional) */
NULL, /* pSelectClipPath */
NULL, /* pSelectClipRgn */
PSDRV_SelectObject, /* pSelectObject */
NULL, /* pSelectPalette */
PSDRV_SetBkColor, /* pSetBkColor */
NULL, /* pSetBkMode */
PSDRV_SetDeviceClipping, /* pSetDeviceClipping */
NULL, /* pSetDeviceGammaRamp */
NULL, /* pSetDIBitsToDevice */
NULL, /* pSetMapMode (optional) */
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 (optional) */
NULL, /* pSetViewportOrg (optional) */
NULL, /* pSetWindowExt (optional) */
NULL, /* pSetWindowOrg (optional) */
PSDRV_StartDoc, /* pStartDoc */
PSDRV_StartPage, /* pStartPage */
NULL, /* pStretchBlt */
PSDRV_StretchDIBits, /* pStretchDIBits */
NULL, /* pStrokeAndFillPath */
NULL, /* pStrokePath */
NULL, /* pSwapBuffers */
NULL /* pWidenPath */
};
/* Default entries for devcaps */
static DeviceCaps PSDRV_DevCaps = {
/* version */ 0,
/* technology */ DT_RASPRINTER,
/* horzSize */ 210,
/* vertSize */ 297,
/* horzRes */ 4961,
/* vertRes */ 7016,
/* bitsPixel */ 1,
/* planes */ 1,
/* numBrushes */ -1,
/* numPens */ 10,
/* numMarkers */ 0,
/* numFonts */ 39,
/* numColors */ 0xffff,
/* pdeviceSize */ 0,
/* curveCaps */ CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES |
CC_WIDE | CC_STYLED | CC_WIDESTYLED | CC_INTERIORS |
CC_ROUNDRECT,
/* lineCaps */ LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
LC_STYLED | LC_WIDESTYLED | LC_INTERIORS,
/* polygoalnCaps */ PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON |
PC_SCANLINE | PC_WIDE | PC_STYLED | PC_WIDESTYLED |
PC_INTERIORS,
/* textCaps */ TC_CR_ANY, /* psdrv 0x59f7 */
/* clipCaps */ CP_RECTANGLE,
/* rasterCaps */ RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT |
RC_DIBTODEV | RC_STRETCHBLT |
RC_STRETCHDIB, /* psdrv 0x6e99 */
/* aspectX */ 600,
/* aspectY */ 600,
/* aspectXY */ 848,
/* pad1 */ { 0 },
/* logPixelsX */ 600,
/* logPixelsY */ 600,
/* pad2 */ { 0 },
/* palette size */ 0,
/* ..etc */ 0, 0 };
static PSDRV_DEVMODEA DefaultDevmode =
{
{ /* dmPublic */
/* dmDeviceName */ "Wine PostScript Driver",
/* dmSpecVersion */ 0x30a,
/* dmDriverVersion */ 0x001,
/* dmSize */ sizeof(DEVMODEA),
/* dmDriverExtra */ 0,
/* dmFields */ DM_ORIENTATION | DM_PAPERSIZE | DM_SCALE |
DM_COPIES | DM_DEFAULTSOURCE | DM_COLOR |
DM_DUPLEX | DM_YRESOLUTION | DM_TTOPTION,
{ /* u1 */
{ /* s1 */
/* dmOrientation */ DMORIENT_PORTRAIT,
/* dmPaperSize */ DMPAPER_A4,
/* dmPaperLength */ 2969,
/* dmPaperWidth */ 2101
}
},
/* dmScale */ 100, /* ?? */
/* dmCopies */ 1,
/* dmDefaultSource */ DMBIN_AUTO,
/* dmPrintQuality */ 0,
/* dmColor */ DMCOLOR_COLOR,
/* dmDuplex */ 0,
/* dmYResolution */ 0,
/* dmTTOption */ DMTT_SUBDEV,
/* dmCollate */ 0,
/* dmFormName */ "",
/* dmUnusedPadding */ 0,
/* dmBitsPerPel */ 0,
/* dmPelsWidth */ 0,
/* dmPelsHeight */ 0,
/* 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
}
};
HANDLE PSDRV_Heap = 0;
static HANDLE PSDRV_DefaultFont = 0;
static LOGFONTA DefaultLogFont = {
100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0,
DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, ""
};
/*********************************************************************
* PSDRV_Init
*
* Initializes font metrics and registers driver. Called from GDI_Init()
*
*/
BOOL WINAPI PSDRV_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
TRACE("(0x%4x, 0x%08lx, %p)\n", hinst, reason, reserved);
switch(reason) {
case DLL_PROCESS_ATTACH:
PSDRV_Heap = HeapCreate(0, 0x10000, 0);
if (PSDRV_Heap == (HANDLE)NULL)
return FALSE;
if (PSDRV_GetFontMetrics() == FALSE) {
HeapDestroy(PSDRV_Heap);
return FALSE;
}
PSDRV_DefaultFont = CreateFontIndirectA(&DefaultLogFont);
if (PSDRV_DefaultFont == (HANDLE)NULL) {
HeapDestroy(PSDRV_Heap);
return FALSE;
}
/* Register driver as "WINEPS", "WINEPS.DLL" and "WINEPS.DRV"
to allow an easy configuring for users */
if (DRIVER_RegisterDriver("WINEPS", &PSDRV_Funcs) == FALSE) {
HeapDestroy(PSDRV_Heap);
return FALSE;
}
if (DRIVER_RegisterDriver("WINEPS.DLL", &PSDRV_Funcs) == FALSE) {
DRIVER_UnregisterDriver("WINEPS");
HeapDestroy(PSDRV_Heap);
return FALSE;
}
if (DRIVER_RegisterDriver("WINEPS.DRV", &PSDRV_Funcs) == FALSE) {
DRIVER_UnregisterDriver("WINEPS");
DRIVER_UnregisterDriver("WINEPS.DLL");
HeapDestroy(PSDRV_Heap);
return FALSE;
}
break;
case DLL_PROCESS_DETACH:
DeleteObject( PSDRV_DefaultFont );
HeapDestroy( PSDRV_Heap );
DRIVER_UnregisterDriver( "WINEPS" );
DRIVER_UnregisterDriver( "WINEPS.DLL" );
DRIVER_UnregisterDriver( "WINEPS.DRV" );
break;
}
return TRUE;
}
/**********************************************************************
* PSDRV_CreateDC
*/
static BOOL PSDRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device,
LPCSTR output, const DEVMODEA* initData )
{
PSDRV_PDEVICE *physDev;
PRINTERINFO *pi;
DeviceCaps *devCaps;
PAGESIZE *page;
INT width = 0, height = 0;
/* If no device name was specified, retrieve the device name
* from the DEVMODE structure from the DC's physDev.
* (See CreateCompatibleDC) */
if ( !device && dc->physDev )
{
physDev = (PSDRV_PDEVICE *)dc->physDev;
device = physDev->Devmode->dmPublic.dmDeviceName;
}
pi = PSDRV_FindPrinterInfo(device);
TRACE("(%s %s %s %p)\n", driver, device, output, initData);
if(!pi) return FALSE;
if(!pi->Fonts) {
MESSAGE("To use WINEPS you need to install some AFM files.\n");
return FALSE;
}
physDev = (PSDRV_PDEVICE *)HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
sizeof(*physDev) );
if (!physDev) return FALSE;
dc->physDev = physDev;
physDev->pi = pi;
physDev->Devmode = (PSDRV_DEVMODEA *)HeapAlloc( PSDRV_Heap, 0,
sizeof(PSDRV_DEVMODEA) );
if(!physDev->Devmode) {
HeapFree( PSDRV_Heap, 0, physDev );
return FALSE;
}
memcpy( physDev->Devmode, pi->Devmode, sizeof(PSDRV_DEVMODEA) );
if(initData) {
PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODEA *)initData, pi);
}
devCaps = HeapAlloc( PSDRV_Heap, 0, sizeof(PSDRV_DevCaps) );
memcpy(devCaps, &PSDRV_DevCaps, sizeof(PSDRV_DevCaps));
/* Are aspect[XY] and logPixels[XY] correct? */
/* Need to handle different res in x and y => fix ppd */
devCaps->aspectX = devCaps->logPixelsX =
physDev->pi->ppd->DefaultResolution;
devCaps->aspectY = devCaps->logPixelsY =
physDev->pi->ppd->DefaultResolution;
devCaps->aspectXY = (int)hypot( (double)devCaps->aspectX,
(double)devCaps->aspectY );
for(page = pi->ppd->PageSizes; page; page = page->next) {
if(page->WinPage == physDev->Devmode->dmPublic.u1.s1.dmPaperSize)
break;
}
if(!page) {
FIXME("Can't find page\n");
physDev->PageSize.left = 0;
physDev->PageSize.right = 0;
physDev->PageSize.bottom = 0;
physDev->PageSize.top = 0;
} else if(page->ImageableArea) { /* PageSize is in device units */
physDev->PageSize.left = page->ImageableArea->llx *
devCaps->logPixelsX / 72;
physDev->PageSize.right = page->ImageableArea->urx *
devCaps->logPixelsX / 72;
physDev->PageSize.bottom = page->ImageableArea->lly *
devCaps->logPixelsY / 72;
physDev->PageSize.top = page->ImageableArea->ury *
devCaps->logPixelsY / 72;
} else {
physDev->PageSize.left = physDev->PageSize.bottom = 0;
physDev->PageSize.right = page->PaperDimension->x *
devCaps->logPixelsX / 72;
physDev->PageSize.top = page->PaperDimension->y *
devCaps->logPixelsY / 72;
}
TRACE("PageSize = (%d,%d - %d,%d)\n", physDev->PageSize.left, physDev->PageSize.bottom, physDev->PageSize.right, physDev->PageSize.top);
/* these are in device units */
width = physDev->PageSize.right - physDev->PageSize.left;
height = physDev->PageSize.top - physDev->PageSize.bottom;
if(physDev->Devmode->dmPublic.u1.s1.dmOrientation == DMORIENT_PORTRAIT) {
devCaps->horzRes = width;
devCaps->vertRes = height;
} else {
devCaps->horzRes = height;
devCaps->vertRes = width;
}
/* these are in mm */
devCaps->horzSize = (devCaps->horzRes * 25.4) / devCaps->logPixelsX;
devCaps->vertSize = (devCaps->vertRes * 25.4) / devCaps->logPixelsY;
TRACE("devcaps: horzSize = %dmm, vertSize = %dmm, "
"horzRes = %d, vertRes = %d\n",
devCaps->horzSize, devCaps->vertSize,
devCaps->horzRes, devCaps->vertRes);
if(physDev->pi->ppd->ColorDevice) {
devCaps->bitsPixel = 8;
devCaps->numColors = 256;
/* FIXME are these values OK? */
}
/* etc */
dc->devCaps = devCaps;
dc->hVisRgn = CreateRectRgn(0, 0, dc->devCaps->horzRes,
dc->devCaps->vertRes);
dc->hFont = PSDRV_DefaultFont;
physDev->job.output = output ?
HEAP_strdupA( PSDRV_Heap, 0, output ) :
HEAP_strdupA( PSDRV_Heap, 0, "LPT1:" ); /* HACK */
physDev->job.hJob = 0;
return TRUE;
}
/**********************************************************************
* PSDRV_DeleteDC
*/
static BOOL PSDRV_DeleteDC( DC *dc )
{
PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
TRACE("\n");
HeapFree( PSDRV_Heap, 0, physDev->Devmode );
HeapFree( PSDRV_Heap, 0, physDev->job.output );
HeapFree( PSDRV_Heap, 0, (void *)dc->devCaps );
HeapFree( PSDRV_Heap, 0, physDev );
dc->physDev = NULL;
return TRUE;
}
/**********************************************************************
* PSDRV_FindPrinterInfo
*/
PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name)
{
static PRINTERINFO *PSDRV_PrinterList;
DWORD type = REG_BINARY, needed, res, dwPaperSize;
PRINTERINFO *pi = PSDRV_PrinterList, **last = &PSDRV_PrinterList;
FONTNAME *font;
AFM *afm;
HANDLE hPrinter;
const char *ppd = NULL;
char ppdFileName[256];
TRACE("'%s'\n", name);
/*
* If this loop completes, last will point to the 'next' element of the
* final PRINTERINFO in the list
*/
for( ; pi; last = &pi->next, pi = pi->next)
if(!strcmp(pi->FriendlyName, name))
return pi;
pi = *last = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) );
if (pi == NULL)
return NULL;
pi->FriendlyName = HEAP_strdupA( PSDRV_Heap, 0, name );
if (pi->FriendlyName == NULL)
goto fail;
/* Use Get|SetPrinterDataExA instead? */
res = DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
NULL, 0, &needed );
if(res == ERROR_INVALID_PRINTER_NAME || needed != sizeof(DefaultDevmode)) {
pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
if (pi->Devmode == NULL)
goto cleanup;
memcpy(pi->Devmode, &DefaultDevmode, sizeof(DefaultDevmode) );
strcpy(pi->Devmode->dmPublic.dmDeviceName,name);
DrvSetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE,
REG_BINARY, (LPBYTE)&DefaultDevmode, sizeof(DefaultDevmode) );
/* need to do something here AddPrinter?? */
}
else {
pi->Devmode = HeapAlloc( PSDRV_Heap, 0, needed );
DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
(LPBYTE)pi->Devmode, needed, &needed);
}
if (OpenPrinterA (pi->FriendlyName, &hPrinter, NULL) == 0) {
ERR ("OpenPrinterA failed with code %li\n", GetLastError ());
goto cleanup;
}
ppdFileName[0]='\0';
#ifdef HAVE_CUPS
{
ppd = cupsGetPPD(name);
if (ppd) {
strncpy(ppdFileName, ppd, sizeof(ppdFileName));
res = ERROR_SUCCESS;
/* we should unlink() that file later */
} else {
res = ERROR_FILE_NOT_FOUND;
WARN("Did not find ppd for %s\n",name);
}
}
#endif
if (!ppdFileName[0]) {
res = GetPrinterDataA (hPrinter, "PPD File", NULL, ppdFileName,
sizeof(ppdFileName), &needed);
}
/* Look for a ppd file for this printer in the config file.
* First look for the names of the printer, then for 'generic'
*/
if ((res!=ERROR_SUCCESS) &&
!PROFILE_GetWineIniString("ppd",name,"",ppdFileName,sizeof(ppdFileName)) &&
!PROFILE_GetWineIniString("ppd","generic","",ppdFileName,sizeof(ppdFileName))
)
res = ERROR_FILE_NOT_FOUND;
else
res = ERROR_SUCCESS;
if (res != ERROR_SUCCESS) {
ERR ("Error %li getting PPD file name for printer '%s'\n", res, name);
goto closeprinter;
}
ppdFileName[sizeof(ppdFileName) - 1] = '\0';
pi->ppd = PSDRV_ParsePPD(ppdFileName);
if(!pi->ppd) {
MESSAGE("Couldn't find PPD file '%s', expect a crash now!\n",
ppdFileName);
goto closeprinter;
}
/*
* 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 = GetPrinterDataA (hPrinter, "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", name);
else {
ERR ("GetPrinterDataA returned %li\n", res);
goto closeprinter;
}
res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable", NULL,
0, &needed, &pi->FontSubTableSize);
if (res == ERROR_SUCCESS || res == ERROR_FILE_NOT_FOUND) {
TRACE ("No 'FontSubTable' for printer '%s'\n", name);
}
else if (res == ERROR_MORE_DATA) {
pi->FontSubTable = HeapAlloc (PSDRV_Heap, 0, needed);
if (pi->FontSubTable == NULL) {
ERR ("Failed to allocate %li bytes from heap\n", needed);
goto closeprinter;
}
res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable",
(LPBYTE) pi->FontSubTable, needed, &needed,
&pi->FontSubTableSize);
if (res != ERROR_SUCCESS) {
ERR ("EnumPrinterDataExA returned %li\n", res);
goto closeprinter;
}
}
else {
ERR("EnumPrinterDataExA returned %li\n", res);
goto closeprinter;
}
if (ClosePrinter (hPrinter) == 0) {
ERR ("ClosePrinter failed with code %li\n", GetLastError ());
goto cleanup;
}
pi->next = NULL;
pi->Fonts = NULL;
for(font = pi->ppd->InstalledFonts; font; font = font->next) {
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 {
if (PSDRV_AddAFMtoList(&pi->Fonts, afm) == FALSE) {
PSDRV_FreeAFMList(pi->Fonts);
goto cleanup;
}
}
}
if (ppd) unlink(ppd);
return pi;
closeprinter:
ClosePrinter(hPrinter);
cleanup:
if (pi->FontSubTable)
HeapFree(PSDRV_Heap, 0, pi->FontSubTable);
if (pi->FriendlyName)
HeapFree(PSDRV_Heap, 0, pi->FriendlyName);
if (pi->Devmode)
HeapFree(PSDRV_Heap, 0, pi->Devmode);
fail:
HeapFree(PSDRV_Heap, 0, pi);
if (ppd) unlink(ppd);
*last = NULL;
return NULL;
}