Authors: Alexandre Julliard <julliard@codeweavers.com> (for Corel), Albert den Haan <albertd@corel.com>
Added syslevel locking for GDI operations.
Propagate the changes through the graphics code.

diff --git a/objects/gdiobj.c b/objects/gdiobj.c
index b08f395..a94cd15 100644
--- a/objects/gdiobj.c
+++ b/objects/gdiobj.c
@@ -6,9 +6,15 @@
 
 #include "config.h"
 
+#include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 
+#include "windef.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/winbase16.h"
+
 #include "bitmap.h"
 #include "brush.h"
 #include "dc.h"
@@ -21,8 +27,7 @@
 #include "debugtools.h"
 #include "gdi.h"
 #include "tweak.h"
-#include "windef.h"
-#include "wingdi.h"
+#include "syslevel.h"
 
 DEFAULT_DEBUG_CHANNEL(gdi);
 
@@ -177,6 +182,10 @@
 
 HBITMAP hPseudoStockBitmap; /* 1x1 bitmap for memory DCs */
 
+static SYSLEVEL GDI_level;
+static WORD GDI_HeapSel;
+
+
 /******************************************************************************
  *
  *   void  ReadFontInformation(
@@ -308,7 +317,8 @@
  */
 #define FixStockFontSizeW FixStockFontSizeA
 
-
+#define TRACE_SEC(handle,text) \
+   TRACE("(%04x): " text " %ld\n", (handle), GDI_level.crst.RecursionCount)
 
 /***********************************************************************
  *           GDI_Init
@@ -318,6 +328,14 @@
 BOOL GDI_Init(void)
 {
     BOOL systemIsBold = (TWEAK_WineLook == WIN31_LOOK);
+    HPALETTE16 hpalette;
+    HINSTANCE16 instance;
+
+    _CreateSysLevel( &GDI_level, 3 );
+
+    /* create GDI heap */
+    if ((instance = LoadLibrary16( "GDI.EXE" )) < 32) return FALSE;
+    GDI_HeapSel = GlobalHandleToSel16( instance );
 
     /* Kill some warnings.  */
     (void)align_OEMFixedFont;
@@ -340,12 +358,9 @@
     /* Create default palette */
 
     /* DR well *this* palette can't be moveable (?) */
-    {
-    HPALETTE16 hpalette = PALETTE_Init();
-    if( !hpalette )
-        return FALSE;
-    StockObjects[DEFAULT_PALETTE] = (GDIOBJHDR *)GDI_HEAP_LOCK( hpalette );
-    }
+    hpalette = PALETTE_Init();
+    if( !hpalette ) return FALSE;
+    StockObjects[DEFAULT_PALETTE] = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, hpalette );
 
     hPseudoStockBitmap = CreateBitmap( 1, 1, 1, 1, NULL ); 
     return TRUE;
@@ -355,75 +370,121 @@
 /***********************************************************************
  *           GDI_AllocObject
  */
-HGDIOBJ GDI_AllocObject( WORD size, WORD magic )
+void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle )
 {
     static DWORD count = 0;
-    GDIOBJHDR * obj;
-    HGDIOBJ16 handle;
-    if ( magic == DC_MAGIC || magic == METAFILE_DC_MAGIC )
-      handle = GDI_HEAP_ALLOC( size );
-    else 
-      handle = GDI_HEAP_ALLOC_MOVEABLE( size );
-    if (!handle) return 0;
-    obj = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
+    GDIOBJHDR *obj;
+
+    _EnterSysLevel( &GDI_level );
+    if (!(*handle = LOCAL_Alloc( GDI_HeapSel, LMEM_MOVEABLE, size )))
+    {
+        _LeaveSysLevel( &GDI_level );
+        return NULL;
+    }
+    obj = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, *handle );
     obj->hNext   = 0;
     obj->wMagic  = magic;
     obj->dwCount = ++count;
-    GDI_HEAP_UNLOCK( handle );
-    return handle;
+
+    TRACE_SEC( *handle, "enter" );
+    return obj;
 }
 
 
 /***********************************************************************
+ *           GDI_ReallocObject
+ *
+ * The object ptr must have been obtained with GDI_GetObjPtr.
+ * The new pointer must be released with GDI_ReleaseObj.
+ */
+void *GDI_ReallocObject( WORD size, HGDIOBJ handle, void *object )
+{
+    HGDIOBJ new_handle;
+
+    LOCAL_Unlock( GDI_HeapSel, handle );
+    if (!(new_handle = LOCAL_ReAlloc( GDI_HeapSel, handle, size, LMEM_MOVEABLE )))
+    {
+        TRACE_SEC( handle, "leave" );
+        _LeaveSysLevel( &GDI_level );
+        return NULL;
+    }
+    assert( new_handle == handle );  /* moveable handle cannot change */
+    return LOCAL_Lock( GDI_HeapSel, handle );
+}
+ 
+
+/***********************************************************************
  *           GDI_FreeObject
  */
-BOOL GDI_FreeObject( HGDIOBJ handle )
+BOOL GDI_FreeObject( HGDIOBJ handle, void *ptr )
 {
-    GDIOBJHDR * object;
+    GDIOBJHDR *object = ptr;
 
-      /* Can't free stock objects */
-    if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
-        return TRUE;
-    
-    object = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
-    if (!object) return FALSE;
-    object->wMagic = 0;  /* Mark it as invalid */
- 
-      /* Free object */
-    
-    GDI_HEAP_FREE( handle );
+    /* can't free stock objects */
+    if (handle < FIRST_STOCK_HANDLE)
+    {
+        object->wMagic = 0;  /* Mark it as invalid */
+        LOCAL_Unlock( GDI_HeapSel, handle );
+        LOCAL_Free( GDI_HeapSel, handle );
+    }
+    TRACE_SEC( handle, "leave" );
+    _LeaveSysLevel( &GDI_level );
     return TRUE;
 }
 
+
 /***********************************************************************
  *           GDI_GetObjPtr
  *
  * Return a pointer to the GDI object associated to the handle.
  * Return NULL if the object has the wrong magic number.
- * Movable GDI objects are locked in memory: it is up to the caller to unlock
- * it after the caller is done with the pointer.
+ * The object must be released with GDI_ReleaseObj.
  */
-GDIOBJHDR * GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
+void *GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
 {
-    GDIOBJHDR * ptr = NULL;
+    GDIOBJHDR *ptr = NULL;
+
+    _EnterSysLevel( &GDI_level );
 
     if (handle >= FIRST_STOCK_HANDLE)
     {
         if (handle <= LAST_STOCK_HANDLE) ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
+        if (ptr && (magic != MAGIC_DONTCARE) && (ptr->wMagic != magic)) ptr = NULL;
     }
-    else 
-      ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
-    if (!ptr) return NULL;
-    if ((magic != MAGIC_DONTCARE) && (ptr->wMagic != magic)) 
+    else
     {
-      GDI_HEAP_UNLOCK( handle );
-      return NULL;
+        ptr = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, handle );
+        if (ptr && (magic != MAGIC_DONTCARE) && (ptr->wMagic != magic))
+        {
+            LOCAL_Unlock( GDI_HeapSel, handle );
+            ptr = NULL;
+        }
     }
+
+    if (!ptr)
+    {
+        _LeaveSysLevel( &GDI_level );
+        SetLastError( ERROR_INVALID_HANDLE );
+    }
+    else TRACE_SEC( handle, "enter" );
+
     return ptr;
 }
 
 
 /***********************************************************************
+ *           GDI_ReleaseObj
+ *
+ */
+void GDI_ReleaseObj( HGDIOBJ handle )
+{
+    if (handle < FIRST_STOCK_HANDLE) LOCAL_Unlock( GDI_HeapSel, handle );
+    TRACE_SEC( handle, "leave" );
+    _LeaveSysLevel( &GDI_level );
+}
+
+
+/***********************************************************************
  *           DeleteObject16    (GDI.69)
  */
 BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
@@ -441,10 +502,12 @@
 
     GDIOBJHDR * header;
     if (HIWORD(obj)) return FALSE;
-    if ((obj >= FIRST_STOCK_HANDLE) && (obj <= LAST_STOCK_HANDLE))
+    if ((obj >= FIRST_STOCK_HANDLE) && (obj <= LAST_STOCK_HANDLE)) {
+	TRACE("Preserving Stock object %04x\n", obj );
+	/* NOTE: No GDI_Release is necessary */
         return TRUE;
-    if (obj == hPseudoStockBitmap) return TRUE;
-    if (!(header = (GDIOBJHDR *) GDI_HEAP_LOCK( obj ))) return FALSE;
+    }
+    if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
 
     TRACE("%04x\n", obj );
 
@@ -452,19 +515,22 @@
 
     switch(header->wMagic)
     {
-      case PEN_MAGIC:     return GDI_FreeObject( obj );
+      case PEN_MAGIC:     return GDI_FreeObject( obj, header );
       case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header );
-      case FONT_MAGIC:    return GDI_FreeObject( obj );
+      case FONT_MAGIC:    return GDI_FreeObject( obj, header );
       case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header);
       case BITMAP_MAGIC:  return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header);
       case REGION_MAGIC:  return REGION_DeleteObject( obj, (RGNOBJ*)header );
-      case DC_MAGIC:      return DeleteDC(obj);
+      case DC_MAGIC:
+          GDI_ReleaseObj( obj );
+          return DeleteDC(obj);
       case 0 :
         WARN("Already deleted\n");
         break;
       default:
         WARN("Unknown magic number (%d)\n",header->wMagic);
     }
+    GDI_ReleaseObj( obj );
     return FALSE;
 }
 
@@ -482,11 +548,12 @@
  */
 HGDIOBJ WINAPI GetStockObject( INT obj )
 {
+    HGDIOBJ ret;
     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
     if (!StockObjects[obj]) return 0;
-    TRACE("returning %d\n",
-                FIRST_STOCK_HANDLE + obj );
-    return (HGDIOBJ16)(FIRST_STOCK_HANDLE + obj);
+    ret = (HGDIOBJ16)(FIRST_STOCK_HANDLE + obj);
+    TRACE("returning %4x\n", ret );
+    return ret;
 }
 
 
@@ -527,7 +594,7 @@
 	result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
 	break;
       }
-    GDI_HEAP_UNLOCK( handle );
+    GDI_ReleaseObj( handle );
     return result;
 }
 
@@ -585,7 +652,7 @@
           ERR("Invalid GDI Magic %04x\n", ptr->wMagic);
 	  return 0;
     }
-    GDI_HEAP_UNLOCK( handle );
+    GDI_ReleaseObj( handle );
     return result;
 }
 
@@ -630,7 +697,7 @@
                    ptr->wMagic );
           break;
     }
-    GDI_HEAP_UNLOCK( handle );
+    GDI_ReleaseObj( handle );
     return result;
 }
 
@@ -688,7 +755,7 @@
 			   ptr->wMagic );
 	  break;
     }
-    GDI_HEAP_UNLOCK( handle );
+    GDI_ReleaseObj( handle );
     return result;
 }
 
@@ -697,21 +764,25 @@
  */
 HANDLE WINAPI GetCurrentObject(HDC hdc,UINT type)
 {
+    HANDLE ret = 0;
     DC * dc = DC_GetDCPtr( hdc );
 
-    if (!dc) 
-    	return 0;
+    if (dc) 
+    {
     switch (type) {
-    case OBJ_PEN:	return dc->w.hPen;
-    case OBJ_BRUSH:	return dc->w.hBrush;
-    case OBJ_PAL:	return dc->w.hPalette;
-    case OBJ_FONT:	return dc->w.hFont;
-    case OBJ_BITMAP:	return dc->w.hBitmap;
+	case OBJ_PEN:	 ret = dc->w.hPen; break;
+	case OBJ_BRUSH:	 ret = dc->w.hBrush; break;
+	case OBJ_PAL:	 ret = dc->w.hPalette; break;
+	case OBJ_FONT:	 ret = dc->w.hFont; break;
+	case OBJ_BITMAP: ret = dc->w.hBitmap; break;
     default:
     	/* the SDK only mentions those above */
     	WARN("(%08x,%d): unknown type.\n",hdc,type);
-	return 0;
+	    break;
+        }
+        GDI_ReleaseObj( hdc );
     }
+    return ret;
 }
 
 
@@ -729,10 +800,14 @@
  */
 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
 {
-    DC * dc = DC_GetDCPtr( hdc );
-    if (!dc || !dc->funcs->pSelectObject) return 0;
+    HGDIOBJ ret = 0;
+    DC * dc = DC_GetDCUpdate( hdc );
+    if (!dc) return 0;
     TRACE("hdc=%04x %04x\n", hdc, handle );
-    return dc->funcs->pSelectObject( dc, handle );
+    if (dc->funcs->pSelectObject)
+        ret = dc->funcs->pSelectObject( dc, handle );
+    GDI_ReleaseObj( hdc );
+    return ret;
 }
 
 
@@ -753,7 +828,7 @@
     BOOL result = TRUE;
   /* Check if object is valid */
 
-    GDIOBJHDR * header = (GDIOBJHDR *) GDI_HEAP_LOCK( obj );
+    GDIOBJHDR * header = GDI_GetObjPtr( obj, MAGIC_DONTCARE );
     if (!header) return FALSE;
 
     TRACE("%04x\n", obj );
@@ -770,7 +845,7 @@
         /* Windows resets the brush origin. We don't need to. */
         break;
     }
-    GDI_HEAP_UNLOCK( obj );
+    GDI_ReleaseObj( obj );
     return result;
 }
 
@@ -939,54 +1014,13 @@
 {
     UINT16 magic = 0;
 
-    if (handle >= FIRST_STOCK_HANDLE ) 
+    GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
+    if (object)
     {
-        switch (handle)
-        {
-        case STOCK_WHITE_BRUSH:
-        case STOCK_LTGRAY_BRUSH:
-        case STOCK_GRAY_BRUSH:
-        case STOCK_DKGRAY_BRUSH:
-        case STOCK_BLACK_BRUSH:
-        case STOCK_HOLLOW_BRUSH:
-            magic = BRUSH_MAGIC;
-            break;
-
-        case STOCK_WHITE_PEN:
-        case STOCK_BLACK_PEN:
-        case STOCK_NULL_PEN :
-            magic = PEN_MAGIC;
-            break;
-
-        case STOCK_OEM_FIXED_FONT:
-        case STOCK_ANSI_FIXED_FONT:
-        case STOCK_ANSI_VAR_FONT:
-        case STOCK_SYSTEM_FONT:
-        case STOCK_DEVICE_DEFAULT_FONT:
-        case STOCK_SYSTEM_FIXED_FONT:
-        case STOCK_DEFAULT_GUI_FONT:
-            magic = FONT_MAGIC;
-            break;
-
-        case STOCK_DEFAULT_PALETTE:
-            magic = PALETTE_MAGIC;
-            break;
-        }
+        magic = object->wMagic - PEN_MAGIC + 1;
+        GDI_ReleaseObj( handle );
     }
-    else
-    {
-	GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
-	if (object)
-	{
-	    magic = object->wMagic;
-	    GDI_HEAP_UNLOCK( handle );
-	}
-    }
-
-    if (magic >= PEN_MAGIC && magic <= METAFILE_DC_MAGIC)
-        return magic - PEN_MAGIC + 1;
-    else
-        return FALSE;
+    return magic;
 }