Exemplo n.º 1
0
int GetCursorHeight(void)
{
    int iAnd, iXor, dy = 16;
    WORD wMask[128];
    ICONINFO ii;
    BITMAP bm;
    PCURSOR pcur;
    long lOffset = 0;

    if ((pcur = PtiCurrent()->pq->spcurCurrent) == NULL) {
        return dy;
    }

    if (!_InternalGetIconInfo(pcur, &ii, NULL, NULL, NULL, FALSE)) {
        return dy;
    }

    if (!GreExtGetObjectW(ii.hbmMask, sizeof(bm), (LPSTR)&bm)) {
        goto Bail;
    }

    /*
     * Use the AND mask to get the cursor height if the XOR mask is there.
     */
    if (!GreGetBitmapBits(ii.hbmMask, sizeof(wMask), (BYTE*)wMask, &lOffset)) {
        goto Bail;
    }

    iAnd = (int)(bm.bmWidth * bm.bmHeight / bitsizeof(WORD));

    if (ii.hbmColor == NULL) {
        /*
         * if no color (XOR) bitmap, then the hbmMask is a double height bitmap
         * with the cursor and the mask stacked.
         */

        iXor = iAnd - 1;
        iAnd /= 2;
    } else {
        iXor = 0;
    }

    if (iAnd >= sizeof(wMask)) {
        iAnd = sizeof(wMask) - 1;
    }

    if (iXor >= sizeof(wMask)) {
        iXor = 0;
    }

    for (iAnd--; iAnd >= 0; iAnd--) {
        if ((iXor != 0 && wMask[iXor--] != 0) || wMask[iAnd] != 0xFFFF) {
            break;
        }
    }

    /*
     * Compute the distance between the pointer's lowest point and hotspot.
     */
    dy = (iAnd + 1) * bitsizeof(WORD) / (int)bm.bmWidth - (int)ii.yHotspot;

Bail:
    if (ii.hbmColor) {
        GreDeleteObject(ii.hbmColor);
    }

    if (ii.hbmMask) {
        GreDeleteObject(ii.hbmMask);
    }

    return dy;
}
Exemplo n.º 2
0
HBITMAP xxxExpandBitmap(
    HBITMAP hbm)
{
    int         nx;
    int         ny;
    BITMAP      bm;
    HBITMAP     hbmNew;
    HBITMAP     hbmD;
    LPRECT      lprc;
    RECT        rc;
    PMONITOR    pMonitor;
    TL          tlpMonitor;


    /*
     * Get the dimensions of the screen and bitmap we'll
     * be dealing with.  We'll adjust the xScreen/yScreen
     * to reflect the new surface size.  The default adjustment
     * is to stretch the image to fit the screen.
     */
    GreExtGetObjectW(hbm, sizeof(bm), (PBITMAP)&bm);

    pMonitor = GetPrimaryMonitor();
    lprc = &pMonitor->rcMonitor;
    nx = (lprc->right / TILE_XMINSIZE) / bm.bmWidth;
    ny = (lprc->bottom / TILE_YMINSIZE) / bm.bmHeight;

    if (nx == 0)
        nx++;

    if (ny == 0)
        ny++;

    if ((nx + ny) <= 2)
        return hbm;


    /*
     * Create the surface for the new-bitmap.
     */
    rc.left = rc.top = 0;
    rc.right = nx * bm.bmWidth;
    rc.bottom = ny * bm.bmHeight;
    hbmD = GreSelectBitmap(ghdcMem, hbm);
    hbmNew = GreCreateCompatibleBitmap(ghdcMem, rc.right, rc.bottom);
    GreSelectBitmap(ghdcMem, hbmD);

    if (hbmNew == NULL)
        return hbm;

    if (hbmD = GreSelectBitmap(ghdcMem2, hbmNew)) {
        /*
         * Expand the bitmap to the new surface.
         */
        ThreadLockAlways(pMonitor, &tlpMonitor);
        xxxDrawWallpaper(NULL, ghdcMem2, pMonitor, &rc);
        ThreadUnlock(&tlpMonitor);
        GreSelectBitmap(ghdcMem2, hbmD);
    }

    GreDeleteObject(hbm);

    GreSetBitmapOwner(hbmNew, OBJECT_OWNER_PUBLIC);

    return hbmNew;
}
Exemplo n.º 3
0
BOOL xxxLoadDesktopWallpaper(
    LPWSTR lpszFile)
{
    UINT           LR_flags;
    int            dxDesired;
    int            dyDesired;
    BITMAP         bm;
    UNICODE_STRING strName;


    /*
     * If the bitmap is somewhat large (big bpp), then we'll deal
     * with it as a real-dib.  We'll also do this for 8bpp since it
     * can utilize a palette.  Chicago uses DIBSECTIONS since it can
     * count on the one-process handling the drawing.  Since, NT can
     * have different processes doing the drawing, we can't use sections.
     */
    LR_flags = LR_LOADFROMFILE;

    if (gpDispInfo->fAnyPalette || gpsi->BitCount >= 8) {
        LR_flags |= LR_CREATEREALDIB;
    }


    /*
     * If we're stretching, then we will ask the loaddib code to do
     * it.
     */
    if (gwWPStyle & DTF_STRETCH) {
        PMONITOR    pMonitor;
        int         dxMonitor, dyMonitor;

        dxDesired = INT_MAX;
        dyDesired = INT_MAX;
        for (   pMonitor = gpDispInfo->pMonitorFirst;
                pMonitor;
                pMonitor = pMonitor->pMonitorNext) {

            if (!(pMonitor->dwMONFlags & MONF_VISIBLE))
                continue;

            dxMonitor = pMonitor->rcMonitor.right - pMonitor->rcMonitor.left;
            dxDesired = min(dxDesired, dxMonitor);
            dyMonitor = pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top;
            dyDesired = min(dyDesired, dyMonitor);
        }
    } else {
        dxDesired = dyDesired = 0;
    }

    /*
     * Make a callback to the client to perform the loading.
     * Saves us some code.
     */
    RtlInitUnicodeString(&strName, lpszFile);

    ghbmWallpaper = xxxClientLoadImage(
            &strName,
            0,
            IMAGE_BITMAP,
            dxDesired,
            dyDesired,
            LR_flags,
            TRUE);

    if (ghbmWallpaper == NULL)
        return FALSE;

    /*
     * If it's a palette-display, then we will derive the global
     * wallpaper palette from the bitmap.
     */
    if (gpDispInfo->fAnyPalette) {
        ghpalWallpaper = CreatePaletteFromBitmap(ghbmWallpaper);
    }

    /*
     * If the DIB is a higher bitdepth than the display, convert it to
     * a DDB, otherwise keep it as DIB.  This way it takes the least
     * amount of memory and provides a identity-translation blt.
     *
     */
    GreExtGetObjectW(ghbmWallpaper, sizeof(bm), &bm);

    if (    gpDispInfo->cMonitors == 1 &&
            gpsi->BitCount <= bm.bmPlanes * bm.bmBitsPixel) {

        ghbmWallpaper = ConvertToDDB(
                gpDispInfo->hdcScreen,
                ghbmWallpaper,
                ghpalWallpaper);
    }

    /*
     * Expand bitmap if we are going to tile it.  Mark the bitmap
     * as public, so any process can party with it.  This must
     * preceed the expand, since it performs a xxxDrawWallpaper
     * call that can leave the section.
     */
    GreSetBitmapOwner(ghbmWallpaper, OBJECT_OWNER_PUBLIC);

    if (gwWPStyle & DTF_TILE) {
        ghbmWallpaper = xxxExpandBitmap(ghbmWallpaper);
    }

    return TRUE;
}
Exemplo n.º 4
0
BOOL
TileWallpaper(HDC hdc, LPCRECT lprc, BOOL fOffset)
{
    int     xO;
    int     yO;
    int     x;
    int     y;
    BITMAP  bm;
    HBITMAP hbmT = NULL;
    POINT   ptOffset;

    if (fOffset) {
        ptOffset.x = gsrcWallpaper.x;
        ptOffset.y = gsrcWallpaper.y;
    } else {
        ptOffset.x = 0;
        ptOffset.y = 0;
    }

    /*
     * We need to get the dimensions of the bitmap here rather than rely on
     * the dimensions in srcWallpaper because this function may
     * be called as part of ExpandBitmap, before srcWallpaper is
     * set.
     */
    if (GreExtGetObjectW(ghbmWallpaper, sizeof(BITMAP), (PBITMAP)&bm)) {
        xO = lprc->left - (lprc->left % bm.bmWidth) + (ptOffset.x % bm.bmWidth);
        if (xO > lprc->left) {
            xO -= bm.bmWidth;
        }

        yO = lprc->top - (lprc->top % bm.bmHeight) + (ptOffset.y % bm.bmHeight);
        if (yO > lprc->top) {
            yO -= bm.bmHeight;
        }

        /*
         *  Tile the bitmap to the surface.
         */
        if (hbmT = GreSelectBitmap(ghdcMem, ghbmWallpaper)) {
            for (y = yO; y < lprc->bottom; y += bm.bmHeight) {
                for (x = xO; x < lprc->right; x += bm.bmWidth) {
                    GreBitBlt(hdc,
                              x,
                              y,
                              bm.bmWidth,
                              bm.bmHeight,
                              ghdcMem,
                              0,
                              0,
                              SRCCOPY,
                              0);
                }
            }

            GreSelectBitmap(ghdcMem, hbmT);
        }
    }

    return (hbmT != NULL);
}
Exemplo n.º 5
0
HBITMAP ConvertToDDB(
    HDC      hdc,
    HBITMAP  hbmOld,
    HPALETTE hpal)
{
    BITMAP  bm;
    HBITMAP hbmNew;

    /*
     * This object must be a REALDIB type bitmap.
     */
    GreExtGetObjectW(hbmOld, sizeof(bm), &bm);

    /*
     * Create the new wallpaper-surface.
     */
    if (hbmNew = GreCreateCompatibleBitmap(hdc, bm.bmWidth, bm.bmHeight)) {

        HPALETTE hpalDst;
        HPALETTE hpalSrc;
        HBITMAP  hbmDst;
        HBITMAP  hbmSrc;
        UINT     bpp;
        BOOL     fHalftone = FALSE;

        /*
         * Select in the surfaces.
         */
        hbmDst = GreSelectBitmap(ghdcMem2, hbmNew);
        hbmSrc = GreSelectBitmap(ghdcMem, hbmOld);

        /*
         * Determine image bits/pixel.
         */
        bpp = (bm.bmPlanes * bm.bmBitsPixel);

        /*
         * Use the palette if given.  If the image is of a greater
         * resolution than the device, then we're going to go through
         * a halftone-palette to get better colors.
         */
        if (hpal) {

            hpalDst = _SelectPalette(ghdcMem2, hpal, FALSE);
            hpalSrc = _SelectPalette(ghdcMem, hpal, FALSE);

            xxxRealizePalette(ghdcMem2);

            /*
             * Set the halftoning for the destination.  This is done
             * for images of greater resolution than the device.
             */
            if (bpp > gpsi->BitCount) {
                fHalftone = TRUE;
                DoHTColorAdjust(ghdcMem2);
            }
        }

        /*
         * Set the stretchbltmode.  This is more necessary when doing
         * halftoning.  Since otherwise, the colors won't translate
         * correctly.
         */
        SetBestStretchMode(ghdcMem2, bpp, fHalftone);

        /*
         * Set the new surface bits.  Use StretchBlt() so the SBMode
         * will be used in color-translation.
         */
        GreStretchBlt(ghdcMem2,
                      0,
                      0,
                      bm.bmWidth,
                      bm.bmHeight,
                      ghdcMem,
                      0,
                      0,
                      bm.bmWidth,
                      bm.bmHeight,
                      SRCCOPY,
                      0);

        /*
         * Restore palettes.
         */
        if (hpal) {
            _SelectPalette(ghdcMem2, hpalDst, FALSE);
            _SelectPalette(ghdcMem, hpalSrc, FALSE);
        }

        /*
         * Restore the surfaces.
         */
        GreSelectBitmap(ghdcMem2, hbmDst);
        GreSelectBitmap(ghdcMem, hbmSrc);
        GreDeleteObject(hbmOld);

        GreSetBitmapOwner(hbmNew, OBJECT_OWNER_PUBLIC);

    } else {
        hbmNew = hbmOld;
    }

    return hbmNew;
}
Exemplo n.º 6
0
BOOL xxxSetDeskWallpaper(PUNICODE_STRING pProfileUserName,
    LPWSTR lpszFile)
{
    BITMAP       bm;
    UINT         WallpaperStyle2;
    PWND         pwndShell;
    TL           tl;
    PTHREADINFO  ptiCurrent = PtiCurrent();
    PDESKTOP     pdesk;
    BOOL         fRet = FALSE;
    HBITMAP      hbmOld;

    PROFINTINFO  apsi[] = {
        {PMAP_DESKTOP, (LPWSTR)STR_TILEWALL , 0, &gwWPStyle    },
        {PMAP_DESKTOP, (LPWSTR)STR_DTSTYLE  , 0, &WallpaperStyle2   },
        {PMAP_DESKTOP, (LPWSTR)STR_DTORIGINX, 0, &gsrcWallpaper.x },
        {PMAP_DESKTOP, (LPWSTR)STR_DTORIGINY, 0, &gsrcWallpaper.y },
        {0,            NULL,                  0, NULL               }
    };

    pdesk = ptiCurrent->rpdesk;
    hbmOld = ghbmWallpaper;

    /*
     * Get the shell-window.  This could be NULL on system
     * initialization.  We will use this to do palette realization.
     */
    pwndShell = (pdesk ? pdesk->pDeskInfo->spwndShell : NULL);

    if ((lpszFile == SETWALLPAPER_METRICS) && !(gwWPStyle & DTF_STRETCH)) {

        gsrcWallpaper.x = 0;
        gsrcWallpaper.y = 0;

        if (ghbmWallpaper)
            goto CreateNewWallpaper;

        goto Metric_Change;
    }

CreateNewWallpaper:

    /*
     * Delete the old wallpaper and palette if the exist.
     */
    if (ghpalWallpaper) {
        GreDeleteObject(ghpalWallpaper);
        ghpalWallpaper = NULL;
    }

    if (ghbmWallpaper) {
        GreDeleteObject(ghbmWallpaper);
        ghbmWallpaper = NULL;
    }

    /*
     * Kill any SPBs no matter what.
     * Works if we're switching from/to palettized wallpaper.
     * Fixes a lot of problems because palette doesn't change, shell
     * paints funny on desktop, etc.
     */
    FreeAllSpbs();

    /*
     * If this is a metric-change (and stretched), then we need to
     * reload it.  However, since we are called from the winlogon process
     * during a desktop-switch, we would be mapped to the wrong Luid
     * when we attempt to grab the name from GetDeskWallpaperName.  This
     * would use the Luid from the DEFAULT user rather than the current
     * logged on user.  In order to avoid this, we cache the wallpaer
     * name so that on METRIC-CHANGES we use the current-user's wallpaper.
     *
     * NOTE: we assume that prior to any METRIC change, we have already
     * setup the ghbmWallpaper and lpszCached.  This is usually done
     * either on logon or during user desktop-changes through conrol-Panel.
     */
    if (lpszFile == SETWALLPAPER_METRICS) {

        UserAssert(gpszWall != NULL);

        goto LoadWallpaper;
    }

    /*
     * Free the cached handle.
     */
    if (gpszWall) {
        UserFreePool(gpszWall);
        gpszWall = NULL;
    }

    /*
     * Load the wallpaper-name.  If this returns FALSE, then
     * the user specified (None).  We will return true to force
     * the repainting of the desktop.
     */
    gpszWall = GetDeskWallpaperName(pProfileUserName,lpszFile);
    if (!gpszWall) {
        fRet = TRUE;
        goto SDW_Exit;
    }

    /*
     * Retrieve the default settings from the registry.
     *
     * If tile is indicated, then normalize style to not include
     * FIT/STRETCH which are center-only styles.  Likewise, if
     * we are centered, then normalize out the TILE bit.
     */
    FastGetProfileIntsW(pProfileUserName, apsi);

    gwWPStyle &= DTF_TILE;
    if (!(gwWPStyle & DTF_TILE)) {
        gwWPStyle = WallpaperStyle2 & DTF_STRETCH;
    }

    /*
     * Load the wallpaper.  This makes a callback to the client to
     * perform the bitmap-creation.
     */

LoadWallpaper:

    if (xxxLoadDesktopWallpaper(gpszWall) == FALSE) {
        gwWPStyle = 0;
        goto SDW_Exit;
    }

    /*
     * If we have a palette, then we need to do the correct realization and
     * notification.
     */
    if (ghpalWallpaper != NULL) {
        PWND pwndSend;

        if (pwndShell) {
            pwndSend = pwndShell;
        } else {
            pwndSend = (pdesk ? pdesk->pDeskInfo->spwnd : NULL);
        }

        /*
         * Update the desktop with the new bitmap.  This cleans
         * out the system-palette so colors can be realized.
         */
        GreRealizeDefaultPalette(gpDispInfo->hdcScreen, TRUE);

        /*
         * Don't broadcast if system initialization is occuring.  Otherwise
         * this gives the shell first-crack at realizing its colors
         * correctly.
         */
        if (pwndSend) {
            HWND hwnd = HW(pwndSend);

            ThreadLockAlways(pwndSend, &tl);
            xxxSendNotifyMessage(pwndSend, WM_PALETTECHANGED, (WPARAM)hwnd, 0);
            ThreadUnlock(&tl);
        }
    }

Metric_Change:
    if (fRet = GreExtGetObjectW(ghbmWallpaper, sizeof(bm), (PBITMAP)&bm)) {
        gsrcWallpaper.cx = bm.bmWidth;
        gsrcWallpaper.cy = bm.bmHeight;
    }
    // fall-through

SDW_Exit:

    /*
     * Notify the shell-window that the wallpaper changed.
     */
    if ((pwndShell != NULL) &&
        ((hbmOld && !ghbmWallpaper) || (!hbmOld && ghbmWallpaper))) {

        ThreadLockAlways(pwndShell, &tl);
        xxxSendNotifyMessage(pwndShell,
                             WM_SHELLNOTIFY,
                             SHELLNOTIFY_WALLPAPERCHANGED,
                             (LPARAM)ghbmWallpaper);
        ThreadUnlock(&tl);
    }

    return fRet;
}
Exemplo n.º 7
0
/***************************************************************************\
* xxxItemSize
*
* Calc the dimensions of bitmaps and strings. Loword of returned
* value contains width, high word contains height of item.
*
* History:
*  07-23-96 GerardoB - fixed up for 5.0
\***************************************************************************/
BOOL xxxMNItemSize(
    PMENU pMenu,
    PWND pwndNotify,
    HDC hdc,
    PITEM pItem,
    BOOL fPopup,
    LPPOINT lppt)
{
    BITMAP bmp;
    int width = 0;
    int height = 0;
    DWORD xRightJustify;
    LPWSTR lpMenuString;
    HFONT               hfnOld;
    int                 tcExtra;

    UNREFERENCED_PARAMETER(pMenu);

    CheckLock(pMenu);
    CheckLock(pwndNotify);

    if (!fPopup) {

        /*
         * Save off the height of the top menu bar since we will used this often
         * if the pItem is not in a popup.  (ie.  it is in the top level menu bar)
         */
        height = SYSMET(CYMENUSIZE);
    }

    hfnOld = NULL;
    if (TestMFS(pItem, MFS_DEFAULT)) {
        if (ghMenuFontDef)
            hfnOld = GreSelectFont(hdc, ghMenuFontDef);
        else {
            tcExtra = GreGetTextCharacterExtra(hdc);
            GreSetTextCharacterExtra(hdc, tcExtra + 1 + (gcxMenuFontChar / gpsi->cxSysFontChar));
        }
    }

    /*
     * Compute bitmap dimensions if needed
     */
    if (pItem->hbmp != NULL)  {
        if (pItem->hbmp == HBMMENU_CALLBACK) {
            xxxMNGetBitmapSize(pItem, pwndNotify);
        } else if (pItem->cxBmp == MNIS_MEASUREBMP) {
            if (TestMFS(pItem, MFS_CACHEDBMP)) {
                pItem->cxBmp = SYSMET(CXMENUSIZE);
                pItem->cyBmp = SYSMET(CYMENUSIZE);
                if (pItem->hbmp == HBMMENU_SYSTEM) {
                    pItem->cxBmp += SYSMET(CXEDGE);
                    /*
                     * Chicago/Memphis only stretch the width,
                     * not the height.  NT Bug 124779.  FritzS
                     */
                 //  pItem->cyBmp += SYSMET(CXEDGE);
                }
            } else {
                if (GreExtGetObjectW(pItem->hbmp, sizeof(BITMAP), (LPSTR)&bmp)) {
                    pItem->cxBmp = bmp.bmWidth;
                    pItem->cyBmp = bmp.bmHeight;
                } else {
                    /*
                     * If the bitmap is not useable, this is as good a default
                     * as any.
                     */
                    pItem->cxBmp = SYSMET(CXMENUSIZE);
                    pItem->cyBmp = SYSMET(CYMENUSIZE);
                }
            }
        }
        width = pItem->cxBmp;
        /*
         * Remember the max bitmap width to align the text in all items.
         */
        pMenu->cxTextAlign = max(pMenu->cxTextAlign, (DWORD)width);
        /*
         * In menu bars, we force the item to be at least CYMNSIZE.
         * Fixes many, many problems w/ apps that fake own MDI.
         */
        if (fPopup) {
            height = pItem->cyBmp;
        } else {
            height = max((int)pItem->cyBmp, height);
        }
    } else if (TestMFT(pItem, MFT_OWNERDRAW)) {
        // This is an ownerdraw item -- the width and height are stored in
        // cxBmp and cyBmp
        xxxMNGetBitmapSize(pItem, pwndNotify);
        width = pItem->cxBmp;
        //
        // Ignore height with menu bar now--that's set by user.
        //
        if (fPopup) {
            height = pItem->cyBmp;
            // If this item has a popup (hierarchical) menu associated with it, then
            // reserve room for the bitmap that tells the user that a hierarchical
            // menu exists here.
            // B#2966, t-arthb

            UserAssert(fPopup == (TestMF(pMenu, MFISPOPUP) != 0));

            width = width + (gcxMenuFontChar << 1);
        }
    }

    if ((pItem->lpstr != NULL) && (!TestMFT(pItem, MFT_OWNERDRAW)) ) {
        SIZE size;

        /*
         * This menu item contains a string
         */

        /*
         * We want to keep the menu bar height if this isn't a popup.
         */
        if (fPopup) {
            /* The thickness of mnemonic underscore is CYBORDER and the gap
             * between the characters and the underscore is another CYBORDER
             */
            height = max(height, gcyMenuFontChar + gcyMenuFontExternLeading + SYSMET(CYEDGE));
        }

        lpMenuString = TextPointer(pItem->lpstr);
        xRightJustify = FindCharPosition(lpMenuString, TEXT('\t'));

        xxxPSMGetTextExtent(hdc, lpMenuString, xRightJustify, &size);

        if (width) {
            width += MNXSPACE + size.cx;
        } else {
            width =  size.cx;
        }
    }

    if (fPopup && !TestMFT(pItem, MFT_OWNERDRAW)) {
        /*
         *  Add on space for checkmark, then horz spacing for default & disabled
         *   plus some left margin.
         */
        if (TestMF(pMenu, MNS_CHECKORBMP) || !TestMF(pMenu, MNS_NOCHECK)) {
            width += gpsi->oembmi[OBI_MENUCHECK].cx;
        }
        width += MNXSPACE + MNLEFTMARGIN + 2;
        height += 2;
    }

    if (TestMFS(pItem, MFS_DEFAULT)) {
        if (hfnOld)
            GreSelectFont(hdc, hfnOld);
        else
            GreSetTextCharacterExtra(hdc, tcExtra);
    }

    /*
     * Loword contains width, high word contains height of item.
     */
    lppt->x = width;
    lppt->y = height;

    return(TestMFT(pItem, MFT_OWNERDRAW));
}
Exemplo n.º 8
0
/***************************************************************************\
*
*  DrawState()
*
*  Generic state drawing routine.  Does simple drawing into same DC if
*  normal state;  uses offscreen bitmap otherwise.
*
*  We do drawing for these simple types ourselves:
*      (1) Text
*          lData is string pointer.
*          wData is string length
*      (2) Icon
*          LOWORD(lData) is hIcon
*      (3) Bitmap
*          LOWORD(lData) is hBitmap
*      (4) Glyph (internal)
*          LOWORD(lData) is OBI_ value, one of
*              OBI_CHECKMARK
*              OBI_BULLET
*              OBI_MENUARROW
*          right now
*
*  Other types are required to draw via the callback function, and are
*  allowed to stick whatever they want in lData and wData.
*
*  We apply the following effects onto the image:
*      (1) Normal      (nothing)
*      (2) Default     (drop shadow)
*      (3) Union       (gray string dither)
*      (4) Disabled    (embossed)
*
*  Note that we do NOT stretch anything.  We just clip.
*
\***************************************************************************/
BOOL _DrawState(
    HDC           hdcDraw,
    HBRUSH        hbrFore,
    DRAWSTATEPROC qfnCallBack,
    LPARAM        lData,
    WPARAM        wData,
    int           x,
    int           y,
    int           cx,
    int           cy,
    UINT          uFlags)
{
    HFONT   hFont;
    HFONT   hFontSave = NULL;
    HDC     hdcT;
    HBITMAP hbmpT;
    POINT   ptOrg;
    BOOL    fResult;

    /*
     * These require monochrome conversion
     *
     * Enforce monochrome: embossed doesn't look great with 2 color displays
     */
    if ((uFlags & DSS_DISABLED) &&
        ((oemInfo.BitCount == 1) || SYSMET(SLOWMACHINE))) {

        uFlags &= ~DSS_DISABLED;
        uFlags |= DSS_UNION;
    }

    if (uFlags & (DSS_DISABLED | DSS_DEFAULT | DSS_UNION))
        uFlags |= DSS_MONO;

    /*
     * Get drawing sizes etc. AND VALIDATE.
     */
    switch (uFlags & DST_TYPEMASK) {

        case DST_GLYPH:

            /*
             * LOWORD(lData) is OBI_ value.
             */
            UserAssert(LOWORD(lData) < (WORD)OBI_COUNT);

            if (!cx)
                cx = oemInfo.bm[LOWORD(lData)].cx;

            if (!cy)
                cy = oemInfo.bm[LOWORD(lData)].cy;
            break;

        case DST_BITMAP:
            /*
             *  (lData) is hbmp.
             */
//            if (IsGDIObject((HBITMAP)LOWORD(lData)) != GDIOBJ_BITMAP)
//                return FALSE;

            if (!cx || !cy) {
                BITMAP bmp;

                try {

                    GreExtGetObjectW((HBITMAP)lData, sizeof(BITMAP), &bmp);

                    if (!cx)
                        cx = bmp.bmWidth;

                    if (!cy)
                        cy = bmp.bmHeight;

                } except (EXCEPTION_EXECUTE_HANDLER) {
                   return FALSE;
                }
            }
            break;

        case DST_ICON:

            /*
             * lData is picon.
             */
            if (!cx || !cy) {

                if (!cx)
                    cx = ((PICON)lData)->cx;

                if (!cy)
                    cy = ((PICON)lData)->cy / 2;  // Icons are double height in NT
            }
            break;

        case DST_TEXT:

            /*
             * lData is LPSTR
             * NOTE THAT WE DO NOT VALIDATE lData, DUE TO COMPATIBILITY
             * WITH GRAYSTRING().  THIS _SHOULD_ FAULT IF YOU PASS IN NULL.
             *
             * wData is cch.
             */
            if (!wData)
                wData = wcslen((LPWSTR)lData);

            if (!cx || !cy) {

                SIZE size;

                /*
                 * Make sure we use right dc w/ right font.
                 */
                GreGetTextExtentW(hdcDraw,
                                  (LPWSTR)lData,
                                  wData,
                                  &size,
                                  GGTE_WIN3_EXTENT);

                if (!cx)
                    cx = size.cx;
                if (!cy)
                    cy = size.cy;
            }

            /*
             * Now, pretend we're complex if qfnCallBack is supplied AND
             * we're supporting GrayString().
             */
//            if ((uFlags & DST_GRAYSTRING) && SELECTOROF(qfnCallBack)) {
//                uFlags &= ~DST_TYPEMASK;
//                uFlags |= DST_COMPLEX;
//            }
            break;

        case DST_PREFIXTEXT:

            if (lData==0) {
                RIPMSG0(RIP_ERROR, "DrawState: NULL DST_PREFIXTEXT string");
                return FALSE;
            }

            if (!wData)
                wData = wcslen((LPWSTR)lData);

            if (!cx || !cy) {

                SIZE size;

                PSMGetTextExtent(hdcDraw, (LPWSTR)lData, wData, &size);

                if (!cx)
                    cx = size.cx;
                if (!cy)
                    cy = size.cy;
            }

            /*
             * Add on height for prefix
             */
            cy += 2*SYSMET(CYBORDER);
            break;

        case DST_COMPLEX:
            if (qfnCallBack == NULL) {
                RIPMSG0(RIP_ERROR, "DrawState: invalid callback for DST_COMPLEX");
                return(FALSE);
            }
            break;

        default:
            RIPMSG0(RIP_ERROR, "DrawState: invalid DST_ type");
            return FALSE;
    }