[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dcobjs.c
index 75cde41..6975b60 100644 (file)
@@ -251,89 +251,119 @@ NtGdiSelectPen(
 HBITMAP
 APIENTRY
 NtGdiSelectBitmap(
-    IN HDC hDC,
-    IN HBITMAP hBmp)
+    IN HDC hdc,
+    IN HBITMAP hbmp)
 {
-    PDC pDC;
+    PDC pdc;
     PDC_ATTR pdcattr;
-    HBITMAP hOrgBmp;
-    PSURFACE psurfBmp, psurfOld;
+    HBITMAP hbmpOld;
+    PSURFACE psurfNew;
     HRGN hVisRgn;
+    SIZEL sizlBitmap = {1, 1};
+    HDC hdcOld;
+    ASSERT_NOGDILOCKS();
 
-    if (hDC == NULL || hBmp == NULL) return NULL;
+    /* Verify parameters */
+    if (hdc == NULL || hbmp == NULL) return NULL;
 
-    pDC = DC_LockDc(hDC);
-    if (!pDC)
+    /* First lock the DC */
+    pdc = DC_LockDc(hdc);
+    if (!pdc)
     {
         return NULL;
     }
-    pdcattr = pDC->pdcattr;
+    pdcattr = pdc->pdcattr;
 
-    /* must be memory dc to select bitmap */
-    if (pDC->dctype != DC_TYPE_MEMORY)
+    /* Must be a memory dc to select a bitmap */
+    if (pdc->dctype != DC_TYPE_MEMORY)
     {
-        DC_UnlockDc(pDC);
+        DC_UnlockDc(pdc);
         return NULL;
     }
 
-    psurfBmp = SURFACE_LockSurface(hBmp);
-    if (!psurfBmp)
+    /* Check if there was a bitmap selected before */
+    if (pdc->dclevel.pSurface)
     {
-        DC_UnlockDc(pDC);
-        return NULL;
+        /* Return its handle */
+        hbmpOld = pdc->dclevel.pSurface->BaseObject.hHmgr;
+    }
+    else
+    {
+        /* Return default bitmap */
+        hbmpOld = StockObjects[DEFAULT_BITMAP];
     }
 
-    /* Get the handle for the old bitmap */
-    ASSERT(pDC->dclevel.pSurface);
-    hOrgBmp = pDC->dclevel.pSurface->BaseObject.hHmgr;
-
-       /* Lock it, to be sure while we mess with it*/
-       psurfOld = SURFACE_LockSurface(hOrgBmp);
-
-       /* Reset hdc, this surface isn't selected anymore */
-       psurfOld->hdc = NULL;
+    /* Check if the default bitmap was passed */
+    if (hbmp == StockObjects[DEFAULT_BITMAP])
+    {
+        psurfNew = NULL;
 
-    /* Release the old bitmap, reference the new */
-    DC_vSelectSurface(pDC, psurfBmp);
+        // HACK
+        psurfNew = SURFACE_ShareLockSurface(hbmp);
+    }
+    else
+    {
+        /* Reference the new bitmap and check if it's valid */
+        psurfNew = SURFACE_ShareLockSurface(hbmp);
+        if (!psurfNew)
+        {
+            DC_UnlockDc(pdc);
+            return NULL;
+        }
 
-       /* And unlock it, now we're done */
-       SURFACE_UnlockSurface(psurfOld);
+        /* Set the bitmp's hdc */
+        hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0);
+        if (hdcOld != NULL && hdcOld != hdc)
+        {
+            /* The bitmap is already selected, fail */
+            SURFACE_ShareUnlockSurface(psurfNew);
+            DC_UnlockDc(pdc);
+            return NULL;
+        }
 
-    // If Info DC this is zero and pSurface is moved to DC->pSurfInfo.
-    psurfBmp->hdc = hDC;
+        /* Get the bitmap size */
+        sizlBitmap = psurfNew->SurfObj.sizlBitmap;
 
+        /* Check if the bitmap is a dibsection */
+        if(psurfNew->hSecure)
+        {
+            /* Set DIBSECTION attribute */
+            pdcattr->ulDirty_ |= DC_DIBSECTION;
+        }
+        else
+        {
+            pdcattr->ulDirty_ &= ~DC_DIBSECTION;
+        }
+    }
 
-    /* FIXME; improve by using a region without a handle and selecting it */
-    hVisRgn = IntSysCreateRectRgn( 0,
-                                   0,
-                                   psurfBmp->SurfObj.sizlBitmap.cx,
-                                   psurfBmp->SurfObj.sizlBitmap.cy);
+    /* Select the new surface, release the old */
+    DC_vSelectSurface(pdc, psurfNew);
 
-    if(psurfBmp->hSecure)
-    {
-        /* Set DIBSECTION attribute */
-        pdcattr->ulDirty_ |= DC_DIBSECTION;
-    }
-    else
-    {
-        pdcattr->ulDirty_ &= ~DC_DIBSECTION;
-    }
+    /* Set the new size */
+    pdc->dclevel.sizl = sizlBitmap;
 
-    /* Release the exclusive lock */
-    SURFACE_UnlockSurface(psurfBmp);
+    /* Release one reference we added */
+    SURFACE_ShareUnlockSurface(psurfNew);
 
-    /* Mark the brushes invalid */
+    /* Mark the dc brushes invalid */
     pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
 
-    DC_UnlockDc(pDC);
+    /* Unlock the DC */
+    DC_UnlockDc(pdc);
 
+    /* FIXME; improve by using a region without a handle and selecting it */
+    hVisRgn = IntSysCreateRectRgn( 0,
+                                   0,
+                                   sizlBitmap.cx,
+                                   sizlBitmap.cy);
     if (hVisRgn)
     {
-        GdiSelectVisRgn(hDC, hVisRgn);
+        GdiSelectVisRgn(hdc, hVisRgn);
         REGION_FreeRgnByHandle(hVisRgn);
     }
 
-    return hOrgBmp;
+    /* Return the old bitmp handle */
+    return hbmpOld;
 }