/* * Windows Device Context initialisation functions * * Copyright 1996 John Harvey */ #include #include #include #include #include #include #include #include "windows.h" #include "module.h" #include "win16drv.h" #include "gdi.h" #include "bitmap.h" #include "heap.h" #include "color.h" #include "font.h" #include "callback.h" #include "stddebug.h" #include "debug.h" #define SUPPORT_REALIZED_FONTS 1 #pragma pack(1) typedef struct { SHORT nSize; SEGPTR lpindata; SEGPTR lpFont; SEGPTR lpXForm; SEGPTR lpDrawMode; } EXTTEXTDATA, *LPEXTTEXTDATA; #pragma pack(4) SEGPTR win16drv_SegPtr_TextXForm; LPTEXTXFORM16 win16drv_TextXFormP; SEGPTR win16drv_SegPtr_DrawMode; LPDRAWMODE win16drv_DrawModeP; static BOOL32 WIN16DRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device, LPCSTR output, const DEVMODE16* initData ); static INT32 WIN16DRV_Escape( DC *dc, INT32 nEscape, INT32 cbInput, SEGPTR lpInData, SEGPTR lpOutData ); static const DC_FUNCTIONS WIN16DRV_Funcs = { NULL, /* pArc */ NULL, /* pBitBlt */ NULL, /* pChord */ WIN16DRV_CreateDC, /* pCreateDC */ NULL, /* pDeleteDC */ NULL, /* pDeleteObject */ NULL, /* pEllipse */ NULL, /* pEnumDeviceFonts */ WIN16DRV_Escape, /* pEscape */ NULL, /* pExcludeClipRect */ NULL, /* pExcludeVisRect */ NULL, /* pExtFloodFill */ WIN16DRV_ExtTextOut, /* pExtTextOut */ WIN16DRV_GetCharWidth, /* pGetCharWidth */ NULL, /* pGetPixel */ WIN16DRV_GetTextExtentPoint, /* pGetTextExtentPoint */ WIN16DRV_GetTextMetrics, /* pGetTextMetrics */ NULL, /* pIntersectClipRect */ NULL, /* pIntersectVisRect */ WIN16DRV_LineTo, /* pLineTo */ WIN16DRV_MoveToEx, /* pMoveToEx */ NULL, /* pOffsetClipRgn */ NULL, /* pOffsetViewportOrgEx */ NULL, /* pOffsetWindowOrgEx */ NULL, /* pPaintRgn */ WIN16DRV_PatBlt, /* pPatBlt */ NULL, /* pPie */ NULL, /* pPolyPolygon */ WIN16DRV_Polygon, /* pPolygon */ NULL, /* pPolyline */ NULL, /* pRealizePalette */ WIN16DRV_Rectangle, /* pRectangle */ NULL, /* pRestoreDC */ NULL, /* pRoundRect */ NULL, /* pSaveDC */ NULL, /* pScaleViewportExtEx */ NULL, /* pScaleWindowExtEx */ NULL, /* pSelectClipRgn */ WIN16DRV_SelectObject, /* pSelectObject */ NULL, /* pSelectPalette */ NULL, /* pSetBkColor */ NULL, /* pSetBkMode */ NULL, /* pSetDeviceClipping */ NULL, /* pSetDIBitsToDevice */ NULL, /* pSetMapMode */ NULL, /* pSetMapperFlags */ NULL, /* pSetPixel */ NULL, /* pSetPolyFillMode */ NULL, /* pSetROP2 */ NULL, /* pSetRelAbs */ NULL, /* pSetStretchBltMode */ NULL, /* pSetTextAlign */ NULL, /* pSetTextCharacterExtra */ NULL, /* pSetTextColor */ NULL, /* pSetTextJustification */ NULL, /* pSetViewportExtEx */ NULL, /* pSetViewportOrgEx */ NULL, /* pSetWindowExtEx */ NULL, /* pSetWindowOrgEx */ NULL, /* pStretchBlt */ NULL /* pStretchDIBits */ }; /********************************************************************** * WIN16DRV_Init */ BOOL32 WIN16DRV_Init(void) { return DRIVER_RegisterDriver( NULL /* generic driver */, &WIN16DRV_Funcs ); } /* Tempory functions, for initialising structures */ /* These values should be calculated, not hardcoded */ void InitTextXForm(LPTEXTXFORM16 lpTextXForm) { lpTextXForm->txfHeight = 0x0001; lpTextXForm->txfWidth = 0x000c; lpTextXForm->txfEscapement = 0x0000; lpTextXForm->txfOrientation = 0x0000; lpTextXForm->txfWeight = 0x0190; lpTextXForm->txfItalic = 0x00; lpTextXForm->txfUnderline = 0x00; lpTextXForm->txfStrikeOut = 0x00; lpTextXForm->txfOutPrecision = 0x02; lpTextXForm->txfClipPrecision = 0x01; lpTextXForm->txfAccelerator = 0x0001; lpTextXForm->txfOverhang = 0x0000; } void InitDrawMode(LPDRAWMODE lpDrawMode) { lpDrawMode->Rop2 = 0x000d; lpDrawMode->bkMode = 0x0001; lpDrawMode->bkColor = 0x3fffffff; lpDrawMode->TextColor = 0x20000000; lpDrawMode->TBreakExtra = 0x0000; lpDrawMode->BreakExtra = 0x0000; lpDrawMode->BreakErr = 0x0000; lpDrawMode->BreakRem = 0x0000; lpDrawMode->BreakCount = 0x0000; lpDrawMode->CharExtra = 0x0000; lpDrawMode->LbkColor = 0x00ffffff; lpDrawMode->LTextColor = 0x00000000; } /* * EnumCallback (GDI.158) * * This is the callback function used when EnumDFonts is called. * (The printer drivers uses it to pass info on available fonts). * * lpvClientData is the pointer passed to EnumDFonts, which points to a WEPFC * structure (WEPFC = WINE_ENUM_PRINTER_FONT_CALLBACK). This structure * contains infomation on how to store the data passed . * * There are two modes: * 1) Just count the number of fonts available. * 2) Store all font data passed. */ WORD WINAPI WineEnumDFontCallback(LPLOGFONT16 lpLogFont, LPTEXTMETRIC16 lpTextMetrics, WORD wFontType, LONG lpvClientData) { int wRet = 0; WEPFC *pWEPFC = (WEPFC *)lpvClientData; /* Make sure we have the right structure */ if (pWEPFC != NULL ) { dprintf_win16drv(stddeb, "mode is 0x%x\n",pWEPFC->nMode); switch (pWEPFC->nMode) { /* Count how many fonts */ case 1: pWEPFC->nCount++; break; /* Store the fonts in the printer driver structure */ case 2: { PRINTER_FONTS_INFO *pPFI; dprintf_win16drv(stddeb, "WineEnumDFontCallback: Found %s %x\n", lpLogFont->lfFaceName, wFontType); pPFI = &pWEPFC->pLPD->paPrinterFonts[pWEPFC->nCount]; memcpy(&(pPFI->lf), lpLogFont, sizeof(LOGFONT16)); memcpy(&(pPFI->tm), lpTextMetrics, sizeof(TEXTMETRIC16)); pWEPFC->nCount++; } break; } wRet = 1; } dprintf_win16drv(stddeb, "WineEnumDFontCallback: returnd %d\n", wRet); return wRet; } BOOL32 WIN16DRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device, LPCSTR output, const DEVMODE16* initData ) { LOADED_PRINTER_DRIVER *pLPD; WORD wRet; DeviceCaps *printerDevCaps; FARPROC16 pfnCallback; int nPDEVICEsize; PDEVICE_HEADER *pPDH; WIN16DRV_PDEVICE *physDev; int numFonts; /* Realizing fonts */ int nSize; char printerEnabled[20]; PROFILE_GetWineIniString( "wine", "printer", "off", printerEnabled, sizeof(printerEnabled) ); if (lstrcmpi32A(printerEnabled,"on")) { printf("WIN16DRV_CreateDC disabled in wine.conf file\n"); return FALSE; } dprintf_win16drv(stddeb, "In creatdc for (%s,%s,%s) initData 0x%p\n",driver, device, output, initData); physDev = (WIN16DRV_PDEVICE *)HeapAlloc( SystemHeap, 0, sizeof(*physDev) ); if (!physDev) return FALSE; dc->physDev = physDev; pLPD = LoadPrinterDriver(driver); if (pLPD == NULL) { dprintf_win16drv(stddeb, "LPGDI_CreateDC: Failed to find printer driver\n"); HeapFree( SystemHeap, 0, physDev ); return FALSE; } dprintf_win16drv(stddeb, "windevCreateDC pLPD 0x%p\n", pLPD); /* Now Get the device capabilities from the printer driver */ printerDevCaps = (DeviceCaps *) malloc(sizeof(DeviceCaps)); memset(printerDevCaps, 0, sizeof(DeviceCaps)); /* Get GDIINFO which is the same as a DeviceCaps structure */ wRet = PRTDRV_Enable(printerDevCaps, GETGDIINFO, device, driver, output,NULL); /* Add this to the DC */ dc->w.devCaps = printerDevCaps; dc->w.hVisRgn = CreateRectRgn32(0, 0, dc->w.devCaps->horzRes, dc->w.devCaps->vertRes); dc->w.bitsPerPixel = dc->w.devCaps->bitsPixel; printf("Got devcaps width %d height %d bits %d planes %d\n", dc->w.devCaps->horzRes, dc->w.devCaps->vertRes, dc->w.devCaps->bitsPixel, dc->w.devCaps->planes); /* Now we allocate enough memory for the PDEVICE structure */ /* The size of this varies between printer drivers */ /* This PDEVICE is used by the printer DRIVER not by the GDI so must */ /* be accessable from 16 bit code */ nPDEVICEsize = dc->w.devCaps->pdeviceSize + sizeof(PDEVICE_HEADER); /* TTD Shouldn't really do pointer arithmetic on segment points */ physDev->segptrPDEVICE = WIN16_GlobalLock16(GlobalAlloc16(GHND, nPDEVICEsize))+sizeof(PDEVICE_HEADER); *((BYTE *)PTR_SEG_TO_LIN(physDev->segptrPDEVICE)+0) = 'N'; *((BYTE *)PTR_SEG_TO_LIN(physDev->segptrPDEVICE)+1) = 'B'; /* Set up the header */ pPDH = (PDEVICE_HEADER *)((BYTE*)PTR_SEG_TO_LIN(physDev->segptrPDEVICE) - sizeof(PDEVICE_HEADER)); pPDH->pLPD = pLPD; dprintf_win16drv(stddeb, "PRTDRV_Enable: PDEVICE allocated %08lx\n",(DWORD)(physDev->segptrPDEVICE)); /* Now get the printer driver to initialise this data */ wRet = PRTDRV_Enable((LPVOID)physDev->segptrPDEVICE, INITPDEVICE, device, driver, output, NULL); /* Now enumerate the fonts supported by the printer driver*/ /* GDI.158 is EnumCallback, which is called by the 16bit printer driver */ /* passing information on the available fonts */ if (pLPD->paPrinterFonts == NULL) { pfnCallback = MODULE_GetEntryPoint( GetModuleHandle16("GDI"), 158 ); if (pfnCallback != NULL) { WEPFC wepfc; wepfc.nMode = 1; wepfc.nCount = 0; wepfc.pLPD = pLPD; /* First count the number of fonts */ PRTDRV_EnumDFonts(physDev->segptrPDEVICE, NULL, pfnCallback, (void *)&wepfc); /* Allocate a buffer to store all of the fonts */ pLPD->nPrinterFonts = wepfc.nCount; dprintf_win16drv(stddeb, "Got %d fonts\n",wepfc.nCount); if (wepfc.nCount > 0) { pLPD->paPrinterFonts = malloc(sizeof(PRINTER_FONTS_INFO) * wepfc.nCount); /* Now get all of the fonts */ wepfc.nMode = 2; wepfc.nCount = 0; PRTDRV_EnumDFonts(physDev->segptrPDEVICE, NULL, pfnCallback, (void *)&wepfc); numFonts = wepfc.nCount; } else { /* If the number of fonts returned are zero we can not continue */ fprintf( stderr, "No fonts? Aborting CreateDC...\n"); return FALSE; } } } /* Select the first font into the DC */ /* Set up the logfont */ memcpy(&physDev->lf, &pLPD->paPrinterFonts[0].lf, sizeof(LOGFONT16)); /* Set up the textmetrics */ memcpy(&physDev->tm, &pLPD->paPrinterFonts[0].tm, sizeof(TEXTMETRIC16)); win16drv_SegPtr_TextXForm = WIN16_GlobalLock16(GlobalAlloc16(GHND, sizeof(TEXTXFORM16))); win16drv_TextXFormP = PTR_SEG_TO_LIN(win16drv_SegPtr_TextXForm); InitTextXForm(win16drv_TextXFormP); #ifdef SUPPORT_REALIZED_FONTS /* TTD should calculate this */ /* First get the size of the realized font */ nSize = PRTDRV_RealizeObject(physDev->segptrPDEVICE, DRVOBJ_FONT, &pLPD->paPrinterFonts[0], NULL, 0); physDev->segptrFontInfo = WIN16_GlobalLock16(GlobalAlloc16(GHND, nSize)); /* Realize the font */ PRTDRV_RealizeObject(physDev->segptrPDEVICE, DRVOBJ_FONT, &pLPD->paPrinterFonts[0], (LPVOID)physDev->segptrFontInfo, win16drv_SegPtr_TextXForm); /* Quick look at structure */ if (physDev->segptrFontInfo) { FONTINFO16 *p = (FONTINFO16 *)PTR_SEG_TO_LIN(physDev->segptrFontInfo); dprintf_win16drv(stddeb, "T:%d VR:%d HR:%d, F:%d L:%d\n", p->dfType, p->dfVertRes, p->dfHorizRes, p->dfFirstCHAR, p->dfLastCHAR ); } #endif /* TTD Lots more to do here */ win16drv_SegPtr_DrawMode = WIN16_GlobalLock16(GlobalAlloc16(GHND, sizeof(DRAWMODE))); win16drv_DrawModeP = PTR_SEG_TO_LIN(win16drv_SegPtr_DrawMode); InitDrawMode(win16drv_DrawModeP); return TRUE; } extern BOOL32 WIN16DRV_PatBlt( struct tagDC *dc, INT32 left, INT32 top, INT32 width, INT32 height, DWORD rop ) { WIN16DRV_PDEVICE *physDev = (WIN16DRV_PDEVICE *)dc->physDev; BOOL32 bRet = 0; bRet = PRTDRV_StretchBlt( physDev->segptrPDEVICE, left, top, width, height, NULL, 0, 0, width, height, PATCOPY, physDev->segptrBrushInfo, win16drv_SegPtr_DrawMode, NULL); return bRet; } /* * Escape (GDI.38) */ static INT32 WIN16DRV_Escape( DC *dc, INT32 nEscape, INT32 cbInput, SEGPTR lpInData, SEGPTR lpOutData ) { WIN16DRV_PDEVICE *physDev = (WIN16DRV_PDEVICE *)dc->physDev; int nRet = 0; /* We should really process the nEscape parameter, but for now just pass it all to the driver */ if (dc != NULL && physDev->segptrPDEVICE != 0) { switch(nEscape) { case ENABLEPAIRKERNING: fprintf(stderr,"Escape: ENABLEPAIRKERNING ignored.\n"); nRet = 1; break; case SETABORTPROC: printf("Escape: SetAbortProc ignored should be stored in dc somewhere\n"); /* Make calling application believe this worked */ nRet = 1; break; case NEXTBAND: { LPPOINT16 newInData = SEGPTR_NEW(POINT16); nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape, SEGPTR_GET(newInData), lpOutData); SEGPTR_FREE(newInData); break; } case GETEXTENDEDTEXTMETRICS: { EXTTEXTDATA *textData = SEGPTR_NEW(EXTTEXTDATA); textData->nSize = cbInput; textData->lpindata = lpInData; textData->lpFont = physDev->segptrFontInfo; textData->lpXForm = win16drv_SegPtr_TextXForm; textData->lpDrawMode = win16drv_SegPtr_DrawMode; nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape, SEGPTR_GET(textData), lpOutData); SEGPTR_FREE(textData); } break; case STARTDOC: nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape, lpInData, lpOutData); if (nRet != -1) { HDC32 *tmpHdc = SEGPTR_NEW(HDC32); #define SETPRINTERDC SETABORTPROC *tmpHdc = dc->hSelf; PRTDRV_Control(physDev->segptrPDEVICE, SETPRINTERDC, SEGPTR_GET(tmpHdc), (SEGPTR)NULL); SEGPTR_FREE(tmpHdc); } break; default: nRet = PRTDRV_Control(physDev->segptrPDEVICE, nEscape, lpInData, lpOutData); break; } } else fprintf(stderr, "Escape(nEscape = %04x)\n", nEscape); return nRet; } /****************** misc. printer releated functions */ /* * The following function should implement a queing system */ #ifndef HPQ #define HPQ WORD #endif struct hpq { struct hpq *next; int tag; int key; }; static struct hpq *hpqueue; HPQ WINAPI CreatePQ(int size) { printf("CreatePQ: %d\n",size); return 1; } int WINAPI DeletePQ(HPQ hPQ) { printf("DeletePQ: %x\n", hPQ); return 0; } int WINAPI ExtractPQ(HPQ hPQ) { struct hpq *queue, *prev, *current, *currentPrev; int key = 0, tag = -1; currentPrev = prev = NULL; queue = current = hpqueue; if (current) key = current->key; while (current) { currentPrev = current; current = current->next; if (current) { if (current->key < key) { queue = current; prev = currentPrev; } } } if (queue) { tag = queue->tag; if (prev) prev->next = queue->next; else hpqueue = queue->next; free(queue); } printf("ExtractPQ: %x got tag %d key %d\n", hPQ, tag, key); return tag; } int WINAPI InsertPQ(HPQ hPQ, int tag, int key) { struct hpq *queueItem = malloc(sizeof(struct hpq)); queueItem->next = hpqueue; hpqueue = queueItem; queueItem->key = key; queueItem->tag = tag; printf("InsertPQ: %x %d %d\n", hPQ, tag, key); return TRUE; } int WINAPI MinPQ(HPQ hPQ) { printf("MinPQ: %x\n", hPQ); return 0; } int WINAPI SizePQ(HPQ hPQ, int sizechange) { printf("SizePQ: %x %d\n", hPQ, sizechange); return -1; } /* * The following functions implement part of the spooling process to * print manager. I would like to see wine have a version of print managers * that used LPR/LPD. For simplicity print jobs will be sent to a file for * now. */ typedef struct PRINTJOB { char *pszOutput; char *pszTitle; HDC16 hDC; HANDLE16 hHandle; int nIndex; int fd; } PRINTJOB, *PPRINTJOB; #define MAX_PRINT_JOBS 1 #define SP_OK 1 PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS]; static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle) { return gPrintJobsTable[0]; } /* TTD Need to do some DOS->UNIX file conversion here */ static int CreateSpoolFile(LPSTR pszOutput) { int fd=-1; char psCmd[1024]; char *psCmdP = psCmd; /* TTD convert the 'output device' into a spool file name */ if (pszOutput == NULL || *pszOutput == '\0') return -1; PROFILE_GetWineIniString( "spooler", pszOutput, "", psCmd, sizeof(psCmd) ); printf("Got printerSpoolCOmmand \"%s\"\n",psCmd); if (!*psCmd) psCmdP = pszOutput; else { while (*psCmdP && isspace(*psCmdP)) { psCmdP++; }; if (!*psCmdP) return -1; } if (*psCmdP == '|') { int fds[2]; if (pipe(fds)) return -1; if (fork() == 0) { psCmdP++; printf("In child need to exec %s\n",psCmdP); close(0); dup2(fds[0],0); close (fds[1]); system(psCmdP); exit(0); } close (fds[0]); fd = fds[1]; printf("Need to execut a command and pipe the output to it\n"); } else { printf("Just assume its a file\n"); if ((fd = open(psCmdP, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0) { printf("Failed to create spool file %s, errno = %d\n", psCmdP, errno); } } return fd; } static int FreePrintJob(HANDLE16 hJob) { int nRet = SP_ERROR; PPRINTJOB pPrintJob; pPrintJob = FindPrintJobFromHandle(hJob); if (pPrintJob != NULL) { gPrintJobsTable[pPrintJob->nIndex] = NULL; free(pPrintJob->pszOutput); free(pPrintJob->pszTitle); if (pPrintJob->fd >= 0) close(pPrintJob->fd); free(pPrintJob); nRet = SP_OK; } return nRet; } HANDLE16 WINAPI OpenJob(LPSTR lpOutput, LPSTR lpTitle, HDC16 hDC) { HANDLE16 hHandle = (HANDLE16)SP_ERROR; PPRINTJOB pPrintJob; dprintf_win16drv(stddeb, "OpenJob: \"%s\" \"%s\" %04x\n", lpOutput, lpTitle, hDC); pPrintJob = gPrintJobsTable[0]; if (pPrintJob == NULL) { int fd; /* Try an create a spool file */ fd = CreateSpoolFile(lpOutput); if (fd >= 0) { hHandle = 1; pPrintJob = malloc(sizeof(PRINTJOB)); memset(pPrintJob, 0, sizeof(PRINTJOB)); pPrintJob->pszOutput = strdup(lpOutput); pPrintJob->pszTitle = strdup(lpTitle); pPrintJob->hDC = hDC; pPrintJob->fd = fd; pPrintJob->nIndex = 0; pPrintJob->hHandle = hHandle; gPrintJobsTable[pPrintJob->nIndex] = pPrintJob; } } dprintf_win16drv(stddeb, "OpenJob: return %04x\n", hHandle); return hHandle; } int WINAPI CloseJob(HANDLE16 hJob) { int nRet = SP_ERROR; PPRINTJOB pPrintJob = NULL; dprintf_win16drv(stddeb, "CloseJob: %04x\n", hJob); pPrintJob = FindPrintJobFromHandle(hJob); if (pPrintJob != NULL) { /* Close the spool file */ close(pPrintJob->fd); FreePrintJob(hJob); nRet = 1; } return nRet; } int WINAPI WriteSpool(HANDLE16 hJob, LPSTR lpData, WORD cch) { int nRet = SP_ERROR; PPRINTJOB pPrintJob = NULL; dprintf_win16drv(stddeb, "WriteSpool: %04x %08lx %04x\n", hJob, (DWORD)lpData, cch); pPrintJob = FindPrintJobFromHandle(hJob); if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch) { if (write(pPrintJob->fd, lpData, cch) != cch) nRet = SP_OUTOFDISK; else nRet = cch; } return nRet; } int WINAPI WriteDialog(HANDLE16 hJob, LPSTR lpMsg, WORD cchMsg) { int nRet = 0; dprintf_win16drv(stddeb, "WriteDialog: %04x %04x \"%s\"\n", hJob, cchMsg, lpMsg); nRet = MessageBox16(0, lpMsg, "Printing Error", MB_OKCANCEL); return nRet; } int WINAPI DeleteJob(HANDLE16 hJob, WORD wNotUsed) { int nRet; dprintf_win16drv(stddeb, "DeleteJob: %04x\n", hJob); nRet = FreePrintJob(hJob); return nRet; } /* * The following two function would allow a page to be sent to the printer * when it has been processed. For simplicity they havn't been implemented. * This means a whole job has to be processed before it is sent to the printer. */ int WINAPI StartSpoolPage(HANDLE16 hJob) { dprintf_win16drv(stddeb, "StartSpoolPage GDI.246 unimplemented\n"); return 1; } int WINAPI EndSpoolPage(HANDLE16 hJob) { dprintf_win16drv(stddeb, "EndSpoolPage GDI.247 unimplemented\n"); return 1; } DWORD WINAPI GetSpoolJob(int nOption, LONG param) { DWORD retval = 0; dprintf_win16drv(stddeb, "In GetSpoolJob param 0x%lx noption %d\n",param, nOption); return retval; }