/*---------------------------------------------------------------- THREADS1.C -- Demonstrates off-screen drawing in second thread (c) 1990, Ziff Communications Co. PC Magazine * Charles Petzold, 1/89 ----------------------------------------------------------------*/ #define INCL_GPI #define INCL_DOSPROCESS #include #include #include #include #define FONTNAME "Tms Rmn Bold" #define XFONTSIZE 500 // in points #define YFONTSIZE 500 #define TEXT "PC" #define TEXTLEN (LONG) strlen (TEXT) #define BKGNDCOLOR CLR_BLUE #define DIVISIONS 64 // number of spline areas #define LCID_FONT 1L #define ID_PATH 1L #define STACKSIZE (4096 * sizeof (int)) #define RGB(r,g,b) (((LONG) (r) << 16) | ((g) << 8) | (b)) #define WM_BITMAP_CREATED (WM_USER + 0) typedef struct { int aiThreadStack[STACKSIZE / sizeof (int)] ; HBITMAP hbm ; HWND hwndNotify ; } THREADPARAMS ; MPARAM EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ; VOID FAR SecondThread (THREADPARAMS *) ; HBITMAP CreateBitmap (HAB) ; VOID DrawImage (HPS, SIZEL *) ; LONG CreateVectorFont (HPS, LONG, CHAR *) ; VOID Message (HWND, SHORT, CHAR *) ; int main (void) { static CHAR szClientClass[] = "Threads1" ; static ULONG flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST ; HAB hab ; HMQ hmq ; HWND hwndFrame, hwndClient ; QMSG qmsg ; hab = WinInitialize (0) ; hmq = WinCreateMsgQueue (hab, 0) ; WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ; hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE, &flFrameFlags, szClientClass, NULL, 0L, NULL, 0, &hwndClient) ; while (WinGetMsg (hab, &qmsg, NULL, 0, 0)) WinDispatchMsg (hab, &qmsg) ; WinDestroyWindow (hwndFrame) ; WinDestroyMsgQueue (hmq) ; WinTerminate (hab) ; return 0 ; } MPARAM EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { static BOOL fError = FALSE ; static HBITMAP hbm ; BITMAPINFOHEADER bmp ; HPS hps ; POINTL ptl ; RECTL rclClient ; THREADPARAMS *ptp ; switch (msg) { case WM_CREATE: // allocate memory for thread structure if ((ptp = malloc (sizeof (THREADPARAMS))) == NULL) { Message (hwnd, MB_ICONEXCLAMATION, "Cannot allocate memory for thread!") ; return 0 ; } ptp->hwndNotify = hwnd ; // start the thread if (_beginthread (SecondThread, ptp->aiThreadStack, STACKSIZE, ptp) == -1) { free (ptp) ; Message (hwnd, MB_ICONEXCLAMATION, "Cannot create print thread!") ; return 0 ; } return 0 ; case WM_BITMAP_CREATED: ptp = PVOIDFROMMP (mp1) ; hbm = ptp->hbm ; free (ptp) ; if (hbm == NULL) fError = TRUE ; WinInvalidateRect (hwnd, NULL, FALSE) ; return 0 ; case WM_PAINT: hps = WinBeginPaint (hwnd, NULL, NULL) ; WinQueryWindowRect (hwnd, &rclClient) ; if (fError == TRUE) WinDrawText (hps, -1, "Error occurred during bitmap creation.", &rclClient, 0L, 0L, DT_CENTER | DT_VCENTER | DT_TEXTATTRS | DT_ERASERECT) ; else if (hbm == NULL) WinDrawText (hps, -1, "Bitmap being created....", &rclClient, 0L, 0L, DT_CENTER | DT_VCENTER | DT_TEXTATTRS | DT_ERASERECT) ; else { WinFillRect (hps, &rclClient, BKGNDCOLOR) ; GpiQueryBitmapParameters (hbm, &bmp) ; ptl.x = (rclClient.xRight - bmp.cx) / 2 ; ptl.y = (rclClient.yTop - bmp.cy) / 2 ; WinDrawBitmap (hps, hbm, NULL, &ptl, 0L, 0L, DBM_NORMAL) ; } WinEndPaint (hps) ; return 0 ; case WM_DESTROY: if (hbm != NULL) GpiDeleteBitmap (hbm) ; return 0 ; } return WinDefWindowProc (hwnd, msg, mp1, mp2) ; } VOID FAR SecondThread (THREADPARAMS *ptp) { HAB hab ; hab = WinInitialize (0) ; ptp->hbm = CreateBitmap (hab) ; // create bitmap DosEnterCritSec () ; WinPostMsg (ptp->hwndNotify, WM_BITMAP_CREATED, // post message MPFROMP (ptp), NULL) ; WinTerminate (hab) ; _endthread () ; } HBITMAP CreateBitmap (HAB hab) { BITMAPINFOHEADER bmp ; HBITMAP hbm ; HDC hdcMemory ; HPS hpsMemory ; LONG alBitmapFormat[2] ; POINTL aptlTextBox[TXTBOX_COUNT] ; SIZEF sizfx ; SIZEL sizl ; // create memory presentation space hdcMemory = DevOpenDC (hab, OD_MEMORY, "*", 0L, NULL, NULL) ; sizl.cx = 0 ; sizl.cy = 0 ; hpsMemory = GpiCreatePS (hab, hdcMemory, &sizl, PU_TWIPS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC) ; // create font, select it in PS, and size it CreateVectorFont (hpsMemory, LCID_FONT, FONTNAME) ; GpiSetCharSet (hpsMemory, LCID_FONT) ; sizfx.cx = MAKEFIXED (XFONTSIZE * 20, 0) ; sizfx.cy = MAKEFIXED (YFONTSIZE * 20, 0) ; GpiSetCharBox (hpsMemory, &sizfx) ; // obtain text dimensions and delete font GpiQueryTextBox (hpsMemory, TEXTLEN, TEXT, TXTBOX_COUNT, aptlTextBox) ; GpiSetCharSet (hpsMemory, LCID_DEFAULT) ; GpiDeleteSetId (hpsMemory, LCID_FONT) ; // convert text dimensions to device coordinates sizl.cx = aptlTextBox[TXTBOX_CONCAT].x ; sizl.cy = aptlTextBox[TXTBOX_TOPLEFT].y - aptlTextBox[TXTBOX_BOTTOMLEFT].y ; GpiConvert (hpsMemory, CVTC_PAGE, CVTC_DEVICE, 1L, (PPOINTL) &sizl) ; // create bitmap and set it in the PS GpiQueryDeviceBitmapFormats (hpsMemory, 2L, alBitmapFormat) ; bmp.cbFix = 12 ; bmp.cx = (SHORT) sizl.cx ; bmp.cy = (SHORT) sizl.cy ; bmp.cPlanes = (SHORT) alBitmapFormat[0] ; bmp.cBitCount = (SHORT) alBitmapFormat[1] ; hbm = GpiCreateBitmap (hpsMemory, &bmp, 0L, NULL, NULL) ; // convert bitmap size back to page coordinates GpiConvert (hpsMemory, CVTC_DEVICE, CVTC_PAGE, 1L, (PPOINTL) &sizl) ; // draw the text on the bitmap if (hbm != NULL) { GpiSetBitmap (hpsMemory, hbm) ; DrawImage (hpsMemory, &sizl) ; GpiSetBitmap (hpsMemory, NULL) ; } // clean up GpiDestroyPS (hpsMemory) ; DevCloseDC (hdcMemory) ; return hbm ; } VOID DrawImage (HPS hps, SIZEL *psizl) { INT i ; LONG lColor ; POINTL ptl, aptl[8], aptlTextBox[TXTBOX_COUNT] ; SIZEF sizfx ; // color the background GpiSetColor (hps, BKGNDCOLOR) ; ptl.x = 0 ; ptl.y = 0 ; GpiMove (hps, &ptl) ; ptl.x = psizl->cx ; ptl.y = psizl->cy ; GpiBox (hps, DRO_FILL, &ptl, 0L, 0L) ; // create font, select it in PS, and size it CreateVectorFont (hps, LCID_FONT, FONTNAME) ; GpiSetCharSet (hps, LCID_FONT) ; sizfx.cx = MAKEFIXED (XFONTSIZE * 20, 0) ; sizfx.cy = MAKEFIXED (YFONTSIZE * 20, 0) ; GpiSetCharBox (hps, &sizfx) ; // create clipping path based on text outline GpiBeginPath (hps, ID_PATH) ; GpiQueryTextBox (hps, TEXTLEN, TEXT, TXTBOX_COUNT, aptlTextBox) ; ptl.x = 0 ; ptl.y = -aptlTextBox[TXTBOX_BOTTOMLEFT].y ; GpiCharStringAt (hps, &ptl, TEXTLEN, TEXT) ; GpiEndPath (hps) ; GpiSetClipPath (hps, ID_PATH, SCP_AND | SCP_ALTERNATE) ; // switch to RGB colors GpiCreateLogColorTable (hps, 0L, LCOLF_RGB, 0L, 0L, NULL) ; for (i = 0 ; i < DIVISIONS ; i++) { // set the color if (i < DIVISIONS / 2) lColor = RGB (i * 512 / DIVISIONS, 0, 0) ; else lColor = RGB (255, i * 512 / DIVISIONS - 256, i * 512 / DIVISIONS - 256) ; GpiSetColor (hps, lColor) ; // define coordinates for spline curves aptl[0].x = 0 ; aptl[0].y = i * psizl->cy / DIVISIONS ; aptl[1].x = psizl->cx / 4 ; aptl[1].y = aptl[0].y + psizl->cy / 2 ; aptl[2].x = 3 * psizl->cx / 4 ; aptl[2].y = aptl[0].y - psizl->cy / 2 ; aptl[3].x = psizl->cx ; aptl[3].y = aptl[0].y ; aptl[4].x = psizl->cx ; aptl[4].y = (i + 1) * psizl->cy / DIVISIONS ; aptl[5].x = 3 * psizl->cx / 4 ; aptl[5].y = aptl[4].y - psizl->cy / 2 ; aptl[6].x = psizl->cx / 4 ; aptl[6].y = aptl[4].y + psizl->cy / 2 ; aptl[7].x = 0 ; aptl[7].y = aptl[4].y ; // draw the curves in an area bracket GpiBeginArea (hps, BA_NOBOUNDARY | BA_ALTERNATE) ; GpiMove (hps, aptl) ; // set current position GpiPolySpline (hps, 3L, aptl + 1) ; // draw one spline GpiLine (hps, aptl + 4) ; // draw line GpiPolySpline (hps, 3L, aptl + 5) ; // draw second spline GpiLine (hps, aptl) ; // line to beginning GpiEndArea (hps) ; } // Clean up GpiCreateLogColorTable (hps, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, NULL) ; GpiSetCharSet (hps, LCID_DEFAULT) ; GpiDeleteSetId (hps, LCID_FONT) ; } LONG CreateVectorFont (HPS hps, LONG lcid, CHAR *szFacename) { FATTRS fat ; // set up FATTRS structure fat.usRecordLength = sizeof fat ; fat.fsSelection = 0 ; fat.lMatch = 0 ; fat.idRegistry = 0 ; fat.usCodePage = GpiQueryCp (hps) ; fat.lMaxBaselineExt = 0 ; fat.lAveCharWidth = 0 ; fat.fsType = 0 ; fat.fsFontUse = FATTR_FONTUSE_OUTLINE | FATTR_FONTUSE_TRANSFORMABLE ; strcpy (fat.szFacename, szFacename) ; // create the font return GpiCreateLogFont (hps, NULL, lcid, &fat) ; } VOID Message (HWND hwnd, SHORT sIcon, CHAR *pszMessage) { WinMessageBox (HWND_DESKTOP, hwnd, pszMessage, "Thread1", 0, sIcon | MB_OK | MB_MOVEABLE) ; }