Release 0.3.0

Fri Sep  3 11:52:18 1993  Bob Amstadt

	* [windows/timer.c]
	Changed to use CallWindowProc() rather directly calling callback.

	* [windows/event.c]
	Implemented SetCapture() and ReleaseCapture()

	* [windows/keyboard.c]
	Created stub for GetKeyState()

	* [objects/linedda.c]
	Created stub for LineDDA()

	* [if1632/callback.c]
	Created callback handler for LineDDA callback procedure.

	* [if1632/callback.c]
	Created FreeProcInstance()

Fri Sep  3 08:36:52 1993  David Metcalfe

	* [loader/signal.c]
	Patch to and code for INT 1A

Thu Sep  2 00:31:54 1993  Alexandre Julliard

	* [objects/font.c] [objects/text.c]
	More text support: implemented justification and underlining.

	* [windows/clipping.c] [objects/clipping.c]
	Moved low-level clipping functions to objects/clipping.c.

	* [windows/clipping.c] [windows/event.c] [windows/message.c]
	Implemented window update regions.

	* [windows/dc.c] [objects/dcvalues.c]
	Moved some device-independent DC functions to objects/dcvalues.c.

	* [windows/graphics.c]
	Implemented InvertRect() and GetPixel().

Sat Aug 28 08:40:23 1993  Eric Youngdale

	* [include/neexe.h] [loader/wine.c]
	Added code to handle relocation type 4.

	* [loader/signal.h] [loader/wine.c] [loader/selector.c]
	Added support for dos interrupts.

Thu 26 Aug 19:15:00 1993  Eric Youngdale

	* [loader/selector.c]
	Fixed bug dealing with loading DLLs.

Thu Aug 26 19:22:40 1993  Alexandre Julliard

        * [include/gdi.h] [objects/font.c] [windows/dc.c]
        Beginning of real font support.

        * [windows/graphics.c]
        Implemented PatBlt().

        * [memory/global.c]
        Corrected a bug with linked list handling in GlobalAlloc().

        * [objects/bitmap.c]
        Corrected a bug in BITMAP_SelectObject().

Tue Aug 24 19:22:40 1993  David Metcalfe

        * [controls/Command*] [controls/Label*] [controls[MenuButto*]
	  [controls/SmeMenuButt*]
	Change code to support & as a special character in menu item text.

Tue Aug 24 19:22:40 1993  Alexandre Julliard

	* [include/gdi.h] [windows/dc.c]
	Heavily modified the DC structure for better device-independence.

	* [objects/bitmap.c]
	Implemented bitmap dimensions.

	* [windows/dc.c] [windows/dce.c]
	Implemented DC state saving and restoring.

	* [windows/dc.c]
	Implemented ROP mode.

	* [windows/graphics.c]
	Implemented FillRect().

Mon Aug 23 22:08:34 1993  Bob Amstadt  (bob at pooh)

	* [misc/xt.c]
	Fixed bug in InvalidateRect().  Solitaire attempted to
	clear window before it was realized.

	* [loader/resource.c]
	Began rewrite of LoadBitmap().

	* [loader/wine.c]
	Fixed code which set Argv and Argc global variables.

	* [loader/selector.c]
	Added code to set up command line arguments.

	* [include/neexe.h]
	Fixed error in PSP structure.

Tue Aug 17 20:41:12 1993  Alexandre Julliard

	* [include/gdi.h] [windows/dc.c]
	Implemented device capabilities.

	* [objects/region.c]
	Implemented EqualRgn() and CombineRgn().

	* [windows/clipping.c]
	Implemented Save/RestoreVisRgn().

	* [windows/graphics.c]
	Implemented PaintRgn() and FillRgn().

	* [windows/mapping.c]
	Implemented mapping modes.

Tue Aug 10 14:07:38 1993  Alexandre Julliard

	* [if1632/user.spec] [misc/rect.c]
	Implemented rectangle API functions.

	* [if1632/gdi.spec] [include/gdi.h] [objects/region.c]
	Implemented regions.

	* [windows/class.c]
	Corrected a typo in UnregisterClass().

	* [windows/clipping.c] [windows/dc.c]
	Implemented DC clipping and visible region.

Tue Aug 10 20:57:56 1993  Bob Amstadt  (bob at pooh)

	* [controls/menu.c] [windows/win.c]
	SetMenu(), GetMenu(), CheckMenuItem() implemented

Thu Aug  5 22:33:22 1993  Bob Amstadt  (bob at pooh)

	* [controls/menu.c] [windows/win.c]
	Many improvements menus.  LoadMenu() should work.

Wed Aug  4 14:55:36 1993  Alexandre Julliard

        * [objects/dib.c]
        Started the implementation of device-independent bitmaps.

        * [objects/bitmap.c]
        Added support for multiple bitmap depths.

        * [objects/brush.c]
        Implemented pattern brushes.

        * [windows/dc.c] [windows/graphics.c]
        Implemented some GDI graphics primitives.

Tue Aug  3 21:16:47 1993  Bob Amstadt  (bob at pooh)

	* [controls/menu.c] [windows/win.c] [include/menu.h]
	Code to load class menus from executable file.

	* [if1632/user.spec]
	Fixed specification of SendMessage() and PostMessage.

Mon Jul 26 21:53:24 1993  Alexandre Julliard

	* [if1632/call.S]
	Corrected a bug in KERNEL_InitTask().

	* [include/windows.h]
	Added a lot of constants.

	* [loader/selector.c]
	Corrected a bug in segment allocation in CreateSelectors().

	* [objects/bitmap.c]
	Implemented SelectObject() for bitmaps.

	* [objects/brush.c]
	Implemented hatched brushes and SelectObject().

	* [objects/gdiobj.c]
	Removed linked list (not needed).

	* [objects/palette.c]
	Implemented system palette creation and misc. palette API functions.

	* [windows/timer.c]
	Implemented timers.

	* [windows/dc.c]
	Implemented memory device contexts.

Tue Jul 20 10:38:59 1993  Bob Amstadt  (bob at pooh)

        * [dos.c]
	Split DOS3Call() out of kernel.c.  Added support for get date
	and time functions.

	* [call.S]
	Added function ReturnFromRegisterFunc() to allow DOS calls
	to return values in registers.

	* [regfunc.h]
	Macros to access registers saved on stack.

Tue Jul 20 10:38:59 1993  Alexandre Julliard

        * [win.c]
        Corrected allocation of the WM_CREATE data structure.

        * [dce.c] [dce.h]
        Implemented DCE handling.

        * [bitmap.c] [brush.c] [dc.c] [font.c] [gdi.h] [gdi.spec] 
          [gdiobj.c] [palette.c] [pen.c]
        Implemented the GDI objects data structures and allocation.

        * [windows.h]
        Added several structures and constants for GDI objects.

Mon Jul 19 12:51:10 1993  Bob Amstadt  (bob at pooh)

	* [ldtlib.c]
	Modified system calls to match Linus' new interface for
	the LDT modification.

	* [win.c]
	Fixed bug with WM_CREATE message.

	* [heap.c] [kernel.spec]
	Completed local heap allocation functions.

	* [global.c]
	Created function GlobalQuickAlloc() for easy allocation from DLLs
diff --git a/objects/Makefile b/objects/Makefile
new file mode 100644
index 0000000..ad4d119
--- /dev/null
+++ b/objects/Makefile
@@ -0,0 +1,19 @@
+CFLAGS=$(COPTS) $(DEBUGOPTS) -I$(INCLUDE_DIR)
+
+OBJS=bitmap.o brush.o font.o gdiobj.o palette.o pen.o dib.o region.o \
+	text.o dcvalues.o clipping.o bitblt.o linedda.o
+
+default: objects.o
+
+objects.o: $(OBJS)
+	$(LD) -r -o objects.o $(OBJS)
+
+clean:
+	rm -f *.o *~ *.s dll_* *.a
+
+depend:
+	$(CC) $(CFLAGS) -M *.c > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/objects/bitblt.c b/objects/bitblt.c
new file mode 100644
index 0000000..53e9ba1
--- /dev/null
+++ b/objects/bitblt.c
@@ -0,0 +1,111 @@
+/*
+ * GDI bit-blit operations
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+
+#include "gdi.h"
+
+extern const int DC_XROPfunction[];
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+
+/***********************************************************************
+ *           PatBlt    (GDI.29)
+ */
+BOOL PatBlt( HDC hdc, short left, short top,
+	     short width, short height, DWORD rop)
+{
+    int x1, x2, y1, y2;
+    
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return FALSE;
+#ifdef DEBUG_GDI
+    printf( "PatBlt: %d %d,%d %dx%d %06x\n",
+	    hdc, left, top, width, height, rop );
+#endif
+
+    rop >>= 16;
+    if (!DC_SetupGCForBrush( dc )) rop &= 0x0f;
+    else rop = (rop & 0x03) | ((rop >> 4) & 0x0c);
+    XSetFunction( XT_display, dc->u.x.gc, DC_XROPfunction[rop] );
+
+    x1 = XLPTODP( dc, left );
+    x2 = XLPTODP( dc, left + width );
+    y1 = YLPTODP( dc, top );
+    y2 = YLPTODP( dc, top + height );
+    XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc,
+		   MIN(x1,x2), MIN(y1,y2), abs(x2-x1), abs(y2-y1) );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           BitBlt    (GDI.34)
+ */
+BOOL BitBlt( HDC hdcDest, short xDest, short yDest, short width, short height,
+	     HDC hdcSrc, short xSrc, short ySrc, DWORD rop )
+{
+    int xs1, xs2, ys1, ys2;
+    int xd1, xd2, yd1, yd2;
+    DC *dcDest, *dcSrc;
+
+#ifdef DEBUG_GDI    
+    printf( "BitBlt: %d %d,%d %dx%d %d %d,%d %08x\n",
+	   hdcDest, xDest, yDest, width, height, hdcSrc, xSrc, ySrc, rop );
+#endif
+
+    if ((rop & 0xcc0000) == ((rop & 0x330000) << 2))
+	return PatBlt( hdcDest, xDest, yDest, width, height, rop );
+
+    rop >>= 16;
+    if ((rop & 0x0f) != (rop >> 4))
+    {
+	printf( "BitBlt: Unimplemented ROP %02x\n", rop );
+	return FALSE;
+    }
+    
+    dcDest = (DC *) GDI_GetObjPtr( hdcDest, DC_MAGIC );
+    if (!dcDest) return FALSE;
+    dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC );
+    if (!dcSrc) return FALSE;
+
+    xs1 = XLPTODP( dcSrc, xSrc );
+    xs2 = XLPTODP( dcSrc, xSrc + width );
+    ys1 = YLPTODP( dcSrc, ySrc );
+    ys2 = YLPTODP( dcSrc, ySrc + height );
+    xd1 = XLPTODP( dcDest, xDest );
+    xd2 = XLPTODP( dcDest, xDest + width );
+    yd1 = YLPTODP( dcDest, yDest );
+    yd2 = YLPTODP( dcDest, yDest + height );
+
+    if ((abs(xs2-xs1) != abs(xd2-xd1)) || (abs(ys2-ys1) != abs(yd2-yd1)))
+	return FALSE;  /* Should call StretchBlt here */
+    
+    DC_SetupGCForText( dcDest );
+    XSetFunction( XT_display, dcDest->u.x.gc, DC_XROPfunction[rop & 0x0f] );
+    if (dcSrc->w.bitsPerPixel == dcDest->w.bitsPerPixel)
+    {
+	XCopyArea( XT_display, dcSrc->u.x.drawable,
+		   dcDest->u.x.drawable, dcDest->u.x.gc,
+		   MIN(xs1,xs2), MIN(ys1,ys2), abs(xs2-xs1), abs(ys2-ys1),
+		   MIN(xd1,xd2), MIN(yd1,yd2) );
+    }
+    else
+    {
+	if (dcSrc->w.bitsPerPixel != 1) return FALSE;
+	XCopyPlane( XT_display, dcSrc->u.x.drawable,
+		    dcDest->u.x.drawable, dcDest->u.x.gc,
+		    MIN(xs1,xs2), MIN(ys1,ys2), abs(xs2-xs1), abs(ys2-ys1),
+		    MIN(xd1,xd2), MIN(yd1,yd2), 1 );
+    }
+    return TRUE;
+}
diff --git a/objects/bitmap.c b/objects/bitmap.c
new file mode 100644
index 0000000..9de4c1c
--- /dev/null
+++ b/objects/bitmap.c
@@ -0,0 +1,423 @@
+/*
+ * GDI bitmap objects
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include "gdi.h"
+
+/* A GDI bitmap object contains a handle to a packed BITMAP,
+ * which is stored on the global heap.
+ * A packed BITMAP is a BITMAP structure followed by the bitmap bits.
+ */
+
+  /* Handle of the bitmap selected by default in a memory DC */
+HBITMAP BITMAP_hbitmapMemDC;
+
+  /* List of supported depths */
+static int depthCount;
+static int * depthList;
+
+  /* List of GC used for bitmap to pixmap operations (one for each depth) */
+static GC * bitmapGC;
+
+
+/***********************************************************************
+ *           BITMAP_Init
+ */
+BOOL BITMAP_Init()
+{
+    int i;
+    Pixmap tmpPixmap;
+    
+    depthList = XListDepths( XT_display, DefaultScreen(XT_display), 
+			     &depthCount );
+    if (!depthList || !depthCount) return FALSE;
+    if (!(bitmapGC = (GC *) malloc( depthCount * sizeof(GC) ))) return FALSE;
+    
+      /* Create the necessary GCs */
+    
+    for (i = 0; i < depthCount; i++)
+    {
+	tmpPixmap = XCreatePixmap( XT_display, DefaultRootWindow(XT_display),
+				  1, 1, depthList[i] );
+	if (tmpPixmap)
+	{
+	    bitmapGC[i] = XCreateGC( XT_display, tmpPixmap, 0, NULL );
+	    XFreePixmap( XT_display, tmpPixmap );
+	}
+	else bitmapGC[i] = 0;
+    }
+
+    BITMAP_hbitmapMemDC = CreateBitmap( 1, 1, 1, 1, NULL );
+    return (BITMAP_hbitmapMemDC != 0);
+}
+
+
+/***********************************************************************
+ *           BITMAP_FindGCForDepth
+ *
+ * Return a GC appropriate for operations with the given depth.
+ */
+GC BITMAP_FindGCForDepth( int depth )
+{
+    int i;
+    for (i = 0; i < depthCount; i++)
+	if (depthList[i] == depth) return bitmapGC[i];
+    return 0;
+}
+
+
+/***********************************************************************
+ *           BITMAP_BmpToImage
+ *
+ * Create an XImage pointing to the bitmap data.
+ */
+XImage * BITMAP_BmpToImage( BITMAP * bmp, void * bmpData )
+{
+    XImage * image;
+
+    image = XCreateImage( XT_display, DefaultVisualOfScreen(XT_screen),
+			  bmp->bmBitsPixel, ZPixmap, 0, bmpData,
+			  bmp->bmWidth, bmp->bmHeight, 16, bmp->bmWidthBytes );
+    if (!image) return 0;
+    image->byte_order = MSBFirst;
+    image->bitmap_bit_order = MSBFirst;
+    image->bitmap_unit = 16;
+    _XInitImageFuncPtrs(image);
+    return image;
+}
+
+
+/***********************************************************************
+ *           BITMAP_CopyToPixmap
+ *
+ * Copy the content of the bitmap to the pixmap. Both must have the same depth.
+ */
+BOOL BITMAP_CopyToPixmap( BITMAP * bmp, Pixmap pixmap,
+			  int x, int y, int width, int height )
+{
+    GC gc;
+    XImage * image;
+    
+    gc = BITMAP_FindGCForDepth( bmp->bmBitsPixel );
+    if (!gc) return FALSE;
+    
+    image = BITMAP_BmpToImage( bmp, ((char *)bmp) + sizeof(BITMAP) );
+    if (!image) return FALSE;
+
+#ifdef DEBUG_GDI
+    printf( "BITMAP_CopyToPixmap: %dx%d %d colors -> %d,%d %dx%d\n",
+	    bmp->bmWidth, bmp->bmHeight, 1 << bmp->bmBitsPixel, x, y, width, height );
+#endif
+    XPutImage(XT_display, pixmap, gc, image, 0, 0, x, y, width, height); 
+    image->data = NULL;
+    XDestroyImage( image );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           BITMAP_CopyFromPixmap
+ *
+ * Copy the content of the pixmap to the bitmap. Both must have
+ * the same dimensions and depth.
+ */
+BOOL BITMAP_CopyFromPixmap( BITMAP * bmp, Pixmap pixmap )
+{
+    XImage *image = BITMAP_BmpToImage( bmp, ((char *)bmp) + sizeof(BITMAP) );
+    if (!image) return FALSE;
+
+#ifdef DEBUG_GDI
+    printf( "BITMAP_CopyFromPixmap: %dx%d %d colors\n",
+	    bmp->bmWidth, bmp->bmHeight, 1 << bmp->bmBitsPixel );
+#endif    
+    XGetSubImage( XT_display, pixmap, 0, 0, bmp->bmWidth, bmp->bmHeight,
+		  AllPlanes, ZPixmap, image, 0, 0 );
+    image->data = NULL;
+    XDestroyImage( image );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           CreateBitmap    (GDI.48)
+ */
+HBITMAP CreateBitmap( short width, short height, 
+		      BYTE planes, BYTE bpp, LPSTR bits )
+{
+    BITMAP bitmap = { 0, width, height, 0, planes, bpp, bits };
+#ifdef DEBUG_GDI
+    printf( "CreateBitmap: %dx%d, %d colors\n", 
+	     width, height, 1 << (planes*bpp) );
+#endif
+    if (!width || !height) return 0;
+    if ((planes != 1) && (bpp != 1)) return 0;
+    bitmap.bmWidthBytes = (width * bpp + 15) / 16 * 2;
+    return CreateBitmapIndirect( &bitmap );
+}
+
+
+/***********************************************************************
+ *           CreateCompatibleBitmap    (GDI.51)
+ */
+HBITMAP CreateCompatibleBitmap( HDC hdc, short width, short height )
+{
+    HBITMAP hbitmap;
+    DC * dc;
+#ifdef DEBUG_GDI
+    printf( "CreateCompatibleBitmap: %d %dx%d\n", hdc, width, height );
+#endif
+    dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return 0;
+    hbitmap = CreateBitmap( width, height, dc->w.planes, dc->w.bitsPerPixel, NULL);
+    return hbitmap;
+}
+
+
+/***********************************************************************
+ *           CreateBitmapIndirect    (GDI.49)
+ */
+HBITMAP CreateBitmapIndirect( BITMAP * bmp )
+{
+    BITMAPOBJ * bmpObjPtr;
+    char * bmpPtr;
+    HBITMAP hbitmap;
+    int size = bmp->bmPlanes * bmp->bmHeight * bmp->bmWidthBytes;
+    
+      /* Create the BITMAPOBJ */
+
+    hbitmap = GDI_AllocObject( sizeof(BITMAPOBJ), BITMAP_MAGIC );
+    if (!hbitmap) return 0;
+    bmpObjPtr = (BITMAPOBJ *) GDI_HEAP_ADDR( hbitmap );
+    
+      /* Create the bitmap in global heap */
+
+    bmpObjPtr->hBitmap = GlobalAlloc( GMEM_MOVEABLE, sizeof(BITMAP) + size );
+    if (!bmpObjPtr->hBitmap)
+    {
+	GDI_FreeObject( hbitmap );
+	return 0;
+    }
+    bmpPtr = (char *) GlobalLock( bmpObjPtr->hBitmap );
+    memcpy( bmpPtr, bmp, sizeof(BITMAP) );
+    ((BITMAP *)bmpPtr)->bmBits = NULL;
+    if (bmp->bmBits) memcpy( bmpPtr + sizeof(BITMAP), bmp->bmBits, size );
+    GlobalUnlock( bmpObjPtr->hBitmap );
+
+    bmpObjPtr->bSelected = FALSE;
+    bmpObjPtr->hdc       = 0;
+    bmpObjPtr->size.cx   = 0;
+    bmpObjPtr->size.cy   = 0;
+    return hbitmap;
+}
+
+
+/***********************************************************************
+ *           BITMAP_GetSetBitmapBits
+ */
+LONG BITMAP_GetSetBitmapBits( HBITMAP hbitmap, LONG count,
+			      LPSTR buffer, int set )
+{
+    BITMAPOBJ * bmpObjPtr;
+    BITMAP * bmp;
+    DC * dc = NULL;
+    int maxSize;
+    
+    if (!count) return 0;
+    bmpObjPtr = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
+    if (!bmpObjPtr) return 0;
+    if (!(bmp = (BITMAP *) GlobalLock( bmpObjPtr->hBitmap ))) return 0;
+    
+    if (bmpObjPtr->bSelected) 
+	dc = (DC *) GDI_GetObjPtr( bmpObjPtr->hdc, DC_MAGIC );
+
+    maxSize = bmp->bmPlanes * bmp->bmHeight * bmp->bmWidthBytes;
+    if (count > maxSize) count = maxSize;
+    	
+    if (set)
+    {
+	memcpy( bmp+1, buffer, count );
+	if (dc) BITMAP_CopyToPixmap( bmp, dc->u.x.drawable,
+				     0, 0, bmp->bmWidth, bmp->bmHeight );
+    }
+    else
+    {
+	if (dc) BITMAP_CopyFromPixmap( bmp, dc->u.x.drawable );
+	memcpy( buffer, bmp+1, count );
+    }
+    GlobalUnlock( bmpObjPtr->hBitmap );
+    return hbitmap;
+}
+
+
+/***********************************************************************
+ *           GetBitmapBits    (GDI.74)
+ */
+LONG GetBitmapBits( HBITMAP hbitmap, LONG count, LPSTR buffer )
+{
+    return BITMAP_GetSetBitmapBits( hbitmap, count, buffer, 0 );
+}
+
+
+/***********************************************************************
+ *           SetBitmapBits    (GDI.106)
+ */
+LONG SetBitmapBits( HBITMAP hbitmap, LONG count, LPSTR buffer )
+{
+    return BITMAP_GetSetBitmapBits( hbitmap, count, buffer, 1 );
+}
+
+
+/***********************************************************************
+ *           BMP_DeleteObject
+ */
+BOOL BMP_DeleteObject( HBITMAP hbitmap, BITMAPOBJ * bitmap )
+{
+      /* Free bitmap on global heap */
+    GlobalFree( bitmap->hBitmap );
+    return GDI_FreeObject( hbitmap );
+}
+
+	
+/***********************************************************************
+ *           BMP_GetObject
+ */
+int BMP_GetObject( BITMAPOBJ * bitmap, int count, LPSTR buffer )
+{
+    char * bmpPtr = (char *) GlobalLock( bitmap->hBitmap );    
+    if (count > sizeof(BITMAP)) count = sizeof(BITMAP);
+    memcpy( buffer, bmpPtr, count );
+    GlobalUnlock( bitmap->hBitmap );
+    return count;
+}
+
+    
+/***********************************************************************
+ *           BITMAP_UnselectBitmap
+ *
+ * Unselect the bitmap from the DC. Used by SelectObject and DeleteDC.
+ */
+BOOL BITMAP_UnselectBitmap( DC * dc )
+{
+    BITMAPOBJ * bmp;
+    BITMAP * bmpPtr;
+
+    if (!dc->w.hBitmap) return TRUE;
+    bmp = (BITMAPOBJ *) GDI_GetObjPtr( dc->w.hBitmap, BITMAP_MAGIC );
+    if (!bmp) return FALSE;
+    
+    if (!(bmpPtr = (BITMAP *) GlobalLock( bmp->hBitmap ))) return FALSE;
+    
+    BITMAP_CopyFromPixmap( bmpPtr, dc->u.x.drawable );
+    XFreePixmap( XT_display, dc->u.x.drawable );
+    bmp->bSelected = FALSE;
+    bmp->hdc       = 0;
+    GlobalUnlock( bmp->hBitmap );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           BITMAP_SelectObject
+ */
+HBITMAP BITMAP_SelectObject( HDC hdc, DC * dc, HBITMAP hbitmap,
+			     BITMAPOBJ * bitmap )
+{
+    BITMAP * bmp;
+    HBITMAP prevHandle = dc->w.hBitmap;
+    
+    if (!(dc->w.flags & DC_MEMORY)) return 0;
+    if (bitmap->bSelected && hbitmap != BITMAP_hbitmapMemDC) return 0;
+    if (!(bmp = (BITMAP *) GlobalLock( bitmap->hBitmap ))) return 0;
+
+      /* Make sure the bitmap has the right format */
+
+    if ((bmp->bmPlanes != 1) || !BITMAP_FindGCForDepth( bmp->bmBitsPixel ))
+    {
+	GlobalUnlock( bitmap->hBitmap );
+	return 0;
+    }
+    
+      /* Unselect the previous bitmap */
+
+    if (!BITMAP_UnselectBitmap( dc ))
+    {
+	GlobalUnlock( bitmap->hBitmap );
+	return 0;
+    }
+    
+      /* Create the pixmap */
+    
+    dc->u.x.drawable   = XCreatePixmap( XT_display,
+				        DefaultRootWindow( XT_display ), 
+				        bmp->bmWidth, bmp->bmHeight,
+				        bmp->bmBitsPixel );
+    BITMAP_CopyToPixmap( bmp, dc->u.x.drawable,
+			 0, 0, bmp->bmWidth, bmp->bmHeight );
+
+      /* Change GC depth if needed */
+
+    if (dc->w.bitsPerPixel != bmp->bmBitsPixel)
+    {
+	XFreeGC( XT_display, dc->u.x.gc );
+	dc->u.x.gc = XCreateGC( XT_display, dc->u.x.drawable, 0, NULL );
+	dc->w.bitsPerPixel = bmp->bmBitsPixel;
+	DC_SetDeviceInfo( hdc, dc );
+    }
+    
+    GlobalUnlock( bitmap->hBitmap );
+    dc->w.hBitmap     = hbitmap;
+    bitmap->bSelected = TRUE;
+    bitmap->hdc       = hdc;
+    return prevHandle;
+}
+
+
+/***********************************************************************
+ *           GetBitmapDimensionEx    (GDI.468)
+ */
+BOOL GetBitmapDimensionEx( HBITMAP hbitmap, LPSIZE size )
+{
+    BITMAPOBJ * bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
+    if (!bmp) return FALSE;
+    *size = bmp->size;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           GetBitmapDimension    (GDI.162)
+ */
+DWORD GetBitmapDimension( HBITMAP hbitmap )
+{
+    SIZE size;
+    if (!GetBitmapDimensionEx( hbitmap, &size )) return 0;
+    return size.cx | (size.cy << 16);
+}
+
+/***********************************************************************
+ *           SetBitmapDimensionEx    (GDI.478)
+ */
+BOOL SetBitmapDimensionEx( HBITMAP hbitmap, short x, short y, LPSIZE prevSize )
+{
+    BITMAPOBJ * bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
+    if (!bmp) return FALSE;
+    if (prevSize) *prevSize = bmp->size;
+    bmp->size.cx = x;
+    bmp->size.cy = y;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           SetBitmapDimension    (GDI.163)
+ */
+DWORD SetBitmapDimension( HBITMAP hbitmap, short x, short y )
+{
+    SIZE size;
+    if (!SetBitmapDimensionEx( hbitmap, x, y, &size )) return 0;
+    return size.cx | (size.cy << 16);    
+}
diff --git a/objects/brush.c b/objects/brush.c
new file mode 100644
index 0000000..11a430b
--- /dev/null
+++ b/objects/brush.c
@@ -0,0 +1,270 @@
+/*
+ * GDI brush objects
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include "gdi.h"
+
+extern Display * XT_display;
+extern Screen * XT_screen;
+
+#define NB_HATCH_STYLES  6
+
+static char HatchBrushes[NB_HATCH_STYLES][8] =
+{
+    { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HS_HORIZONTAL */
+    { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HS_VERTICAL   */
+    { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HS_FDIAGONAL  */
+    { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HS_BDIAGONAL  */
+    { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HS_CROSS      */
+    { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }  /* HS_DIAGCROSS  */
+};
+
+extern XImage * BITMAP_BmpToImage( BITMAP *, void * );
+
+/***********************************************************************
+ *           CreateBrushIndirect    (GDI.50)
+ */
+HBRUSH CreateBrushIndirect( LOGBRUSH * brush )
+{
+    BRUSHOBJ * brushPtr;
+    HBRUSH hbrush = GDI_AllocObject( sizeof(BRUSHOBJ), BRUSH_MAGIC );
+    if (!hbrush) return 0;
+    brushPtr = (BRUSHOBJ *) GDI_HEAP_ADDR( hbrush );
+    memcpy( &brushPtr->logbrush, brush, sizeof(LOGBRUSH) );
+    return hbrush;
+}
+
+
+/***********************************************************************
+ *           CreateHatchBrush    (GDI.58)
+ */
+HBRUSH CreateHatchBrush( short style, COLORREF color )
+{
+    LOGBRUSH logbrush = { BS_HATCHED, color, style };
+#ifdef DEBUG_GDI
+    printf( "CreateHatchBrush: %d %06x\n", style, color );
+#endif
+    if ((style < 0) || (style >= NB_HATCH_STYLES)) return 0;
+    return CreateBrushIndirect( &logbrush );
+}
+
+
+/***********************************************************************
+ *           CreatePatternBrush    (GDI.60)
+ */
+HBRUSH CreatePatternBrush( HBITMAP hbitmap )
+{
+    LOGBRUSH logbrush = { BS_PATTERN, 0, 0 };
+    BITMAPOBJ * bmpObj;
+    BITMAP * bmp;
+    
+#ifdef DEBUG_GDI
+    printf( "CreatePatternBrush: %d\n", hbitmap );
+#endif
+
+      /* Make a copy of the bitmap */
+
+    if (!(bmpObj = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
+	return 0;
+    if (!(bmp = (BITMAP *) GlobalLock( bmpObj->hBitmap ))) return 0;    
+    logbrush.lbHatch = CreateBitmap( bmp->bmWidth, bmp->bmHeight,
+				     bmp->bmPlanes, bmp->bmBitsPixel,
+				     ((char *)bmp) + sizeof(BITMAP) );
+    GlobalUnlock( bmpObj->hBitmap );
+    if (!logbrush.lbHatch) return 0;
+    return CreateBrushIndirect( &logbrush );
+}
+
+
+/***********************************************************************
+ *           CreateDIBPatternBrush    (GDI.445)
+ */
+HBRUSH CreateDIBPatternBrush( HANDLE hbitmap, WORD coloruse )
+{
+    LOGBRUSH logbrush = { BS_DIBPATTERN, coloruse, 0 };
+    BITMAPINFO *info, *newInfo;
+    int size;
+    
+#ifdef DEBUG_GDI
+    printf( "CreateDIBPatternBrush: %d\n", hbitmap );
+#endif
+
+      /* Make a copy of the bitmap */
+
+    if (!(info = (BITMAPINFO *) GlobalLock( hbitmap ))) return 0;
+
+    size = info->bmiHeader.biSizeImage;
+    if (!size)
+	size = (info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) / 32
+	         * 8 * info->bmiHeader.biHeight;
+    size += DIB_BitmapInfoSize( info, coloruse );
+
+    if (!(logbrush.lbHatch = GlobalAlloc( GMEM_MOVEABLE, size )))
+    {
+	GlobalUnlock( hbitmap );
+	return 0;
+    }
+    newInfo = (BITMAPINFO *) GlobalLock( logbrush.lbHatch );
+    memcpy( newInfo, info, size );
+    GlobalUnlock( logbrush.lbHatch );
+    GlobalUnlock( hbitmap );
+    return CreateBrushIndirect( &logbrush );
+}
+
+
+/***********************************************************************
+ *           CreateSolidBrush    (GDI.66)
+ */
+HBRUSH CreateSolidBrush( COLORREF color )
+{
+    LOGBRUSH logbrush = { BS_SOLID, color, 0 };
+#ifdef DEBUG_GDI
+    printf( "CreateSolidBrush: %06x\n", color );
+#endif
+    return CreateBrushIndirect( &logbrush );
+}
+
+
+/***********************************************************************
+ *           SetBrushOrg    (GDI.148)
+ */
+DWORD SetBrushOrg( HDC hdc, short x, short y )
+{
+    DWORD retval;
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return FALSE;
+    retval = dc->w.brushOrgX | (dc->w.brushOrgY << 16);
+    dc->w.brushOrgX = x;
+    dc->w.brushOrgY = y;
+    return retval;
+}
+
+
+/***********************************************************************
+ *           BRUSH_DeleteObject
+ */
+BOOL BRUSH_DeleteObject( HBRUSH hbrush, BRUSHOBJ * brush )
+{
+    switch(brush->logbrush.lbStyle)
+    {
+      case BS_PATTERN:
+	  DeleteObject( brush->logbrush.lbHatch );
+	  break;
+      case BS_DIBPATTERN:
+	  GlobalFree( brush->logbrush.lbHatch );
+	  break;
+    }
+    return GDI_FreeObject( hbrush );
+}
+
+
+/***********************************************************************
+ *           BRUSH_GetObject
+ */
+int BRUSH_GetObject( BRUSHOBJ * brush, int count, LPSTR buffer )
+{
+    if (count > sizeof(LOGBRUSH)) count = sizeof(LOGBRUSH);
+    memcpy( buffer, &brush->logbrush, count );
+    return count;
+}
+
+
+/***********************************************************************
+ *           BRUSH_SelectPatternBrush
+ */
+BOOL BRUSH_SelectPatternBrush( DC * dc, HBITMAP hbitmap )
+{
+    BITMAPOBJ * bmpObjPtr;
+    BITMAP * bmp;
+    
+    bmpObjPtr = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
+    if (!bmpObjPtr) return FALSE;
+    if (!(bmp = (BITMAP *) GlobalLock( bmpObjPtr->hBitmap ))) return FALSE;
+
+    dc->u.x.brush.pixmap = XCreatePixmap( XT_display,
+					  DefaultRootWindow(XT_display),
+					  8, 8, bmp->bmBitsPixel );
+    BITMAP_CopyToPixmap( bmp, dc->u.x.brush.pixmap, 0, 0, 8, 8 );
+    
+    if (bmp->bmBitsPixel > 1)
+    {
+	dc->u.x.brush.fillStyle = FillTiled;
+	XSetTile( XT_display, dc->u.x.gc, dc->u.x.brush.pixmap );
+	dc->u.x.brush.pixel = 0;  /* Ignored */
+    }
+    else
+    {
+	dc->u.x.brush.fillStyle = FillOpaqueStippled;
+	XSetStipple( XT_display, dc->u.x.gc, dc->u.x.brush.pixmap );
+	dc->u.x.brush.pixel = -1;  /* Special case (see DC_SetupGCForBrush) */
+    }
+    return TRUE;
+}
+
+
+
+/***********************************************************************
+ *           BRUSH_SelectObject
+ */
+HBRUSH BRUSH_SelectObject( HDC hdc, DC * dc, HBRUSH hbrush, BRUSHOBJ * brush )
+{
+    HBITMAP hBitmap;
+    BITMAPINFO * bmpInfo;
+    HBRUSH prevHandle = dc->w.hBrush;
+    
+    dc->w.hBrush = hbrush;
+
+    if (dc->u.x.brush.pixmap)
+    {
+	XFreePixmap( XT_display, dc->u.x.brush.pixmap );
+	dc->u.x.brush.pixmap = 0;
+    }
+    dc->u.x.brush.style = brush->logbrush.lbStyle;
+    
+    switch(brush->logbrush.lbStyle)
+    {
+      case BS_SOLID:
+      case BS_NULL:
+	dc->u.x.brush.pixel = GetNearestPaletteIndex( dc->w.hPalette, 
+						 brush->logbrush.lbColor );
+	dc->u.x.brush.fillStyle = FillSolid;
+	break;
+	
+      case BS_HATCHED:
+	dc->u.x.brush.pixel = GetNearestPaletteIndex( dc->w.hPalette, 
+						 brush->logbrush.lbColor );
+	dc->u.x.brush.pixmap = XCreateBitmapFromData(XT_display, 
+					DefaultRootWindow(XT_display),
+					HatchBrushes[brush->logbrush.lbHatch],
+					8, 8 );
+	XSetStipple( XT_display, dc->u.x.gc, dc->u.x.brush.pixmap );
+	dc->u.x.brush.fillStyle = FillStippled;
+	break;
+	
+      case BS_PATTERN:
+	BRUSH_SelectPatternBrush( dc, brush->logbrush.lbHatch );
+	break;
+
+      case BS_DIBPATTERN:
+	if ((bmpInfo = (BITMAPINFO *) GlobalLock( brush->logbrush.lbHatch )))
+	{
+	    int size = DIB_BitmapInfoSize( bmpInfo, brush->logbrush.lbColor );
+	    hBitmap = CreateDIBitmap( hdc, &bmpInfo->bmiHeader, CBM_INIT,
+				      ((char *)bmpInfo) + size, bmpInfo,
+				      (WORD) brush->logbrush.lbColor );
+	    BRUSH_SelectPatternBrush( dc, hBitmap );
+	    DeleteObject( hBitmap );
+	    GlobalUnlock( brush->logbrush.lbHatch );	    
+	}
+	
+	break;
+    }
+    
+    return prevHandle;
+}
+
+
diff --git a/objects/clipping.c b/objects/clipping.c
new file mode 100644
index 0000000..ec9de9c
--- /dev/null
+++ b/objects/clipping.c
@@ -0,0 +1,354 @@
+/*
+ * DC clipping functions
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include <stdio.h>
+#include "gdi.h"
+
+
+/***********************************************************************
+ *           CLIPPING_UpdateGCRegion
+ *
+ * Update the GC clip region when the ClipRgn of VisRgn have changed.
+ */
+static void CLIPPING_UpdateGCRegion( DC * dc )
+{
+    if (!dc->w.hGCClipRgn) dc->w.hGCClipRgn = CreateRectRgn(0,0,0,0);
+
+    if (!dc->w.hVisRgn)
+    {
+	if (!dc->w.hClipRgn)
+	{
+	    DeleteObject( dc->w.hGCClipRgn );
+	    dc->w.hGCClipRgn = 0;
+	}
+	else
+	    CombineRgn( dc->w.hGCClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
+    }
+    else
+    {
+	if (!dc->w.hClipRgn)
+	    CombineRgn( dc->w.hGCClipRgn, dc->w.hVisRgn, 0, RGN_COPY );
+	else
+	    CombineRgn( dc->w.hGCClipRgn, dc->w.hClipRgn, dc->w.hVisRgn, RGN_AND );
+    }
+    
+    if (dc->w.hGCClipRgn)
+    {
+	RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hGCClipRgn, REGION_MAGIC );
+	XSetClipMask( XT_display, dc->u.x.gc, obj->region.pixmap );
+	XSetClipOrigin( XT_display, dc->u.x.gc,
+		        obj->region.box.left, obj->region.box.top );
+    }
+    else
+    {
+	XSetClipMask( XT_display, dc->u.x.gc, None );
+	XSetClipOrigin( XT_display, dc->u.x.gc, 0, 0 );
+    }	
+}
+
+
+/***********************************************************************
+ *           CLIPPING_SelectRgn
+ *
+ * Helper function for SelectClipRgn() and SelectVisRgn().
+ */
+static int CLIPPING_SelectRgn( DC * dc, HRGN * hrgnPrev, HRGN hrgn )
+{
+    int retval;
+    
+    if (hrgn)
+    {
+	if (!*hrgnPrev) *hrgnPrev = CreateRectRgn(0,0,0,0);
+	retval = CombineRgn( *hrgnPrev, hrgn, 0, RGN_COPY );
+    }
+    else
+    {
+	if (*hrgnPrev) DeleteObject( *hrgnPrev );
+	*hrgnPrev = 0;
+	retval = SIMPLEREGION; /* Clip region == client area */
+    }
+    CLIPPING_UpdateGCRegion( dc );
+    return retval;
+}
+
+
+/***********************************************************************
+ *           SelectClipRgn    (GDI.44)
+ */
+int SelectClipRgn( HDC hdc, HRGN hrgn )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;
+    
+#ifdef DEBUG_CLIPPING
+    printf( "SelectClipRgn: %d %d\n", hdc, hrgn );
+#endif
+    return CLIPPING_SelectRgn( dc, &dc->w.hClipRgn, hrgn );
+}
+
+
+/***********************************************************************
+ *           SelectVisRgn    (GDI.105)
+ */
+int SelectVisRgn( HDC hdc, HRGN hrgn )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;
+    
+#ifdef DEBUG_CLIPPING
+    printf( "SelectVisRgn: %d %d\n", hdc, hrgn );
+#endif
+    return CLIPPING_SelectRgn( dc, &dc->w.hVisRgn, hrgn );
+}
+
+
+/***********************************************************************
+ *           OffsetClipRgn    (GDI.32)
+ */
+int OffsetClipRgn( HDC hdc, short x, short y )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "OffsetClipRgn: %d %d,%d\n", hdc, x, y );
+#endif
+
+    if (dc->w.hClipRgn)
+    {
+	int retval = OffsetRgn( dc->w.hClipRgn, x, y );
+	CLIPPING_UpdateGCRegion( dc );
+	return retval;
+    }
+    else return SIMPLEREGION; /* Clip region == client area */
+}
+
+
+/***********************************************************************
+ *           OffsetVisRgn    (GDI.102)
+ */
+int OffsetVisRgn( HDC hdc, short x, short y )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "OffsetVisRgn: %d %d,%d\n", hdc, x, y );
+#endif
+
+    if (dc->w.hVisRgn)
+    {
+	int retval = OffsetRgn( dc->w.hVisRgn, x, y );
+	CLIPPING_UpdateGCRegion( dc );
+	return retval;
+    }
+    else return SIMPLEREGION; /* Clip region == client area */
+}
+
+
+/***********************************************************************
+ *           CLIPPING_IntersectRect
+ *
+ * Helper function for {Intersect,Exclude}{Clip,Vis}Rect
+ */
+int CLIPPING_IntersectRect( DC * dc, HRGN * hrgn, short left, short top,
+			    short right, short bottom, int exclude )
+{
+    HRGN tempRgn, newRgn;
+    RGNOBJ *newObj, *prevObj;
+    int retval;
+
+    if (!*hrgn) return NULLREGION;
+    if (!(newRgn = CreateRectRgn( 0, 0, 0, 0))) return ERROR;
+    if (!(tempRgn = CreateRectRgn( left, top, right, bottom )))
+    {
+	DeleteObject( newRgn );
+	return ERROR;
+    }
+    retval = CombineRgn( newRgn, *hrgn, tempRgn, exclude ? RGN_DIFF : RGN_AND);
+    newObj = (RGNOBJ *) GDI_GetObjPtr( newRgn, REGION_MAGIC );
+    prevObj = (RGNOBJ *) GDI_GetObjPtr( *hrgn, REGION_MAGIC );
+    if (newObj && prevObj) newObj->header.hNext = prevObj->header.hNext;
+    DeleteObject( tempRgn );
+    DeleteObject( *hrgn );
+    *hrgn = newRgn;    
+    CLIPPING_UpdateGCRegion( dc );
+    return retval;
+}
+
+
+/***********************************************************************
+ *           ExcludeClipRect    (GDI.21)
+ */
+int ExcludeClipRect( HDC hdc, short left, short top,
+		     short right, short bottom )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "ExcludeClipRect: %d %dx%d,%dx%d\n",
+	    hdc, left, top, right, bottom );
+#endif
+    return CLIPPING_IntersectRect( dc, &dc->w.hClipRgn, left, top,
+				   right, bottom, 1 );
+}
+
+
+/***********************************************************************
+ *           IntersectClipRect    (GDI.22)
+ */
+int IntersectClipRect( HDC hdc, short left, short top,
+		       short right, short bottom )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "IntersectClipRect: %d %dx%d,%dx%d\n",
+	    hdc, left, top, right, bottom );
+#endif
+    return CLIPPING_IntersectRect( dc, &dc->w.hClipRgn, left, top,
+				   right, bottom, 0 );
+}
+
+
+/***********************************************************************
+ *           ExcludeVisRect    (GDI.73)
+ */
+int ExcludeVisRect( HDC hdc, short left, short top,
+		    short right, short bottom )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "ExcludeVisRect: %d %dx%d,%dx%d\n",
+	    hdc, left, top, right, bottom );
+#endif
+    return CLIPPING_IntersectRect( dc, &dc->w.hVisRgn, left, top,
+				   right, bottom, 1 );
+}
+
+
+/***********************************************************************
+ *           IntersectVisRect    (GDI.98)
+ */
+int IntersectVisRect( HDC hdc, short left, short top,
+		      short right, short bottom )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "IntersectVisRect: %d %dx%d,%dx%d\n",
+	    hdc, left, top, right, bottom );
+#endif
+    return CLIPPING_IntersectRect( dc, &dc->w.hVisRgn, left, top,
+				   right, bottom, 0 );
+}
+
+
+/***********************************************************************
+ *           PtVisible    (GDI.103)
+ */
+BOOL PtVisible( HDC hdc, short x, short y )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "PtVisible: %d %d,%d\n", hdc, x, y );
+#endif
+    if (!dc->w.hClipRgn) return FALSE;
+    return PtInRegion( dc->w.hClipRgn, x, y );
+}
+
+
+/***********************************************************************
+ *           RectVisible    (GDI.104)
+ */
+BOOL RectVisible( HDC hdc, LPRECT rect )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "RectVisible: %d %p\n", hdc, rect );
+#endif
+    if (!dc->w.hClipRgn) return FALSE;
+    return RectInRegion( dc->w.hClipRgn, rect );
+}
+
+
+/***********************************************************************
+ *           GetClipBox    (GDI.77)
+ */
+int GetClipBox( HDC hdc, LPRECT rect )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "GetClipBox: %d %p\n", hdc, rect );
+#endif
+
+    if (dc->w.hGCClipRgn) return GetRgnBox( dc->w.hGCClipRgn, rect );
+    else
+    {
+	Window root;
+	int width, height, x, y, border, depth;
+	XGetGeometry( XT_display, dc->u.x.drawable, &root, &x, &y, 
+		      &width, &height, &border, &depth );
+	rect->top = rect->left = 0;
+	rect->right  = width & 0xffff;
+	rect->bottom = height & 0xffff;
+	return SIMPLEREGION;
+    }
+}
+
+
+/***********************************************************************
+ *           SaveVisRgn    (GDI.129)
+ */
+HRGN SaveVisRgn( HDC hdc )
+{
+    HRGN copy;
+    RGNOBJ *obj, *copyObj;
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return 0;
+#ifdef DEBUG_CLIPPING
+    printf( "SaveVisRgn: %d\n", hdc );
+#endif
+    if (!dc->w.hVisRgn) return 0;
+    if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
+	return 0;
+    if (!(copy = CreateRectRgn( 0, 0, 0, 0 ))) return 0;
+    CombineRgn( copy, dc->w.hVisRgn, 0, RGN_COPY );
+    if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC )))
+	return 0;
+    copyObj->header.hNext = obj->header.hNext;
+    obj->header.hNext = copy;
+    return copy;
+}
+
+
+/***********************************************************************
+ *           RestoreVisRgn    (GDI.130)
+ */
+int RestoreVisRgn( HDC hdc )
+{
+    HRGN saved;
+    RGNOBJ *obj, *savedObj;
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return ERROR;    
+#ifdef DEBUG_CLIPPING
+    printf( "RestoreVisRgn: %d\n", hdc );
+#endif
+    if (!dc->w.hVisRgn) return ERROR;
+    if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
+	return ERROR;
+    if (!(saved = obj->header.hNext)) return ERROR;
+    if (!(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC )))
+	return ERROR;
+    DeleteObject( dc->w.hVisRgn );
+    dc->w.hVisRgn = saved;
+    CLIPPING_UpdateGCRegion( dc );
+    return savedObj->region.type;
+}
diff --git a/objects/dcvalues.c b/objects/dcvalues.c
new file mode 100644
index 0000000..b496e2e
--- /dev/null
+++ b/objects/dcvalues.c
@@ -0,0 +1,142 @@
+/*
+ * DC device-independent Get/SetXXX functions
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include "gdi.h"
+
+  /* Default DC values */
+const WIN_DC_INFO DCVAL_defaultValues =
+{
+    0,                      /* flags */
+    NULL,                   /* devCaps */
+    0,                      /* hMetaFile */
+    0,                      /* hClipRgn */
+    0,                      /* hVisRgn */
+    0,                      /* hGCClipRgn */
+    STOCK_BLACK_PEN,        /* hPen */
+    STOCK_WHITE_BRUSH,      /* hBrush */
+    STOCK_SYSTEM_FONT,      /* hFont */
+    0,                      /* hBitmap */
+    0,                      /* hDevice */
+    STOCK_DEFAULT_PALETTE,  /* hPalette */
+    R2_COPYPEN,             /* ROPmode */
+    ALTERNATE,              /* polyFillMode */
+    BLACKONWHITE,           /* stretchBltMode */
+    ABSOLUTE,               /* relAbsMode */
+    OPAQUE,                 /* backgroundMode */
+    RGB( 255, 255, 255 ),   /* backgroundColor */
+    RGB( 0, 0, 0 ),         /* textColor */
+    0,                      /* backgroundPixel */
+    0,                      /* textPixel */
+    0,                      /* brushOrgX */
+    0,                      /* brushOrgY */
+    TA_LEFT | TA_TOP | TA_NOUPDATECP,  /* textAlign */
+    0,                      /* charExtra */
+    0,                      /* breakTotalExtra */
+    0,                      /* breakCount */
+    0,                      /* breakExtra */
+    0,                      /* breakRem */
+    1,                      /* planes */
+    1,                      /* bitsPerPixel */
+    MM_TEXT,                /* MapMode */
+    0,                      /* DCOrgX */
+    0,                      /* DCOrgY */
+    0,                      /* CursPosX */
+    0,                      /* CursPosY */
+    0,                      /* WndOrgX */
+    0,                      /* WndOrgY */
+    1,                      /* WndExtX */
+    1,                      /* WndExtY */
+    0,                      /* VportOrgX */
+    0,                      /* VportOrgY */
+    1,                      /* VportExtX */
+    1                       /* VportExtY */
+};
+
+
+#define DC_GET_VAL( func_type, func_name, dc_field ) \
+func_type func_name( HDC hdc ) \
+{ \
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); \
+    if (!dc) return 0; \
+    return dc->w.dc_field; \
+}
+
+#define DC_GET_X_Y( func_type, func_name, ret_x, ret_y ) \
+func_type func_name( HDC hdc ) \
+{ \
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); \
+    if (!dc) return 0; \
+    return dc->w.ret_x | (dc->w.ret_y << 16); \
+}
+
+#define DC_GET_VAL_EX( func_name, ret_x, ret_y ) \
+BOOL func_name( HDC hdc, LPPOINT pt ) \
+{ \
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); \
+    if (!dc) return FALSE; \
+    pt->x = dc->w.ret_x; \
+    pt->y = dc->w.ret_y; \
+    return TRUE; \
+}
+
+#define DC_SET_VAL( func_type, func_name, dc_field ) \
+func_type func_name( HDC hdc, func_type val ) \
+{ \
+    func_type prevVal; \
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); \
+    if (!dc) return 0; \
+    prevVal = dc->w.dc_field; \
+    dc->w.dc_field = val; \
+    return prevVal; \
+}
+
+#define DC_SET_MODE( func_name, dc_field, min_val, max_val ) \
+WORD func_name( HDC hdc, WORD mode ) \
+{ \
+    WORD prevMode; \
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); \
+    if (!dc) return 0; \
+    if ((mode < min_val) || (mode > max_val)) return 0; \
+    prevMode = dc->w.dc_field; \
+    dc->w.dc_field = mode; \
+    return prevMode; \
+}
+
+
+DC_SET_MODE( SetBkMode, backgroundMode, TRANSPARENT, OPAQUE )     /* GDI.2 */
+DC_SET_MODE( SetROP2, ROPmode, R2_BLACK, R2_WHITE )               /* GDI.4 */
+DC_SET_MODE( SetRelAbs, relAbsMode, ABSOLUTE, RELATIVE )          /* GDI.5 */
+DC_SET_MODE( SetPolyFillMode, polyFillMode, ALTERNATE, WINDING )  /* GDI.6 */
+DC_SET_MODE( SetStretchBltMode, stretchBltMode,
+	     BLACKONWHITE, COLORONCOLOR )                         /* GDI.7 */
+DC_GET_VAL( COLORREF, GetBkColor, backgroundColor )               /* GDI.75 */
+DC_GET_VAL( WORD, GetBkMode, backgroundMode )                     /* GDI.76 */
+DC_GET_X_Y( DWORD, GetCurrentPosition, CursPosX, CursPosY )       /* GDI.78 */
+DC_GET_X_Y( DWORD, GetDCOrg, DCOrgX, DCOrgY )                     /* GDI.79 */
+DC_GET_VAL( WORD, GetMapMode, MapMode )                           /* GDI.81 */
+DC_GET_VAL( WORD, GetPolyFillMode, polyFillMode )                 /* GDI.84 */
+DC_GET_VAL( WORD, GetROP2, ROPmode )                              /* GDI.85 */
+DC_GET_VAL( WORD, GetRelAbs, relAbsMode )                         /* GDI.86 */
+DC_GET_VAL( WORD, GetStretchBltMode, stretchBltMode )             /* GDI.88 */
+DC_GET_VAL( COLORREF, GetTextColor, textColor )                   /* GDI.90 */
+DC_GET_X_Y( DWORD, GetViewportExt, VportExtX, VportExtY )         /* GDI.94 */
+DC_GET_X_Y( DWORD, GetViewportOrg, VportOrgX, VportOrgY )         /* GDI.95 */
+DC_GET_X_Y( DWORD, GetWindowExt, WndExtX, WndExtY )               /* GDI.96 */
+DC_GET_X_Y( DWORD, GetWindowOrg, WndOrgX, WndOrgY )               /* GDI.97 */
+DC_GET_VAL( HRGN, InquireVisRgn, hVisRgn )                        /* GDI.131 */
+DC_GET_X_Y( DWORD, GetBrushOrg, brushOrgX, brushOrgY )            /* GDI.149 */
+DC_GET_VAL( HRGN, GetClipRgn, hClipRgn )                          /* GDI.173 */
+DC_GET_VAL( WORD, GetTextAlign, textAlign )                       /* GDI.345 */
+DC_SET_VAL( WORD, SetTextAlign, textAlign )                       /* GDI.346 */
+DC_GET_VAL( HFONT, GetCurLogFont, hFont )                         /* GDI.411 */
+DC_GET_VAL_EX( GetBrushOrgEx, brushOrgX, brushOrgY )              /* GDI.469 */
+DC_GET_VAL_EX( GetCurrentPositionEx, CursPosX, CursPosY )         /* GDI.470 */
+DC_GET_VAL_EX( GetViewportExtEx, VportExtX, VportExtY )           /* GDI.472 */
+DC_GET_VAL_EX( GetViewportOrgEx, VportOrgX, VportOrgY )           /* GDI.473 */
+DC_GET_VAL_EX( GetWindowExtEx, WndExtX, WndExtY )                 /* GDI.474 */
+DC_GET_VAL_EX( GetWindowOrgEx, WndOrgX, WndOrgY )                 /* GDI.475 */
diff --git a/objects/dib.c b/objects/dib.c
new file mode 100644
index 0000000..839f0b5
--- /dev/null
+++ b/objects/dib.c
@@ -0,0 +1,203 @@
+/*
+ * GDI device independent bitmaps
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include <stdlib.h>
+
+#include "gdi.h"
+
+
+extern XImage * BITMAP_BmpToImage( BITMAP *, void * );
+
+
+/***********************************************************************
+ *           DIB_BitmapInfoSize
+ *
+ * Return the size of the bitmap info structure.
+ */
+int DIB_BitmapInfoSize( BITMAPINFO * info, WORD coloruse )
+{
+    int size = info->bmiHeader.biClrUsed;
+    if (!size && (info->bmiHeader.biBitCount != 24))
+	size = 1 << info->bmiHeader.biBitCount;
+    if (coloruse == DIB_RGB_COLORS) 
+	size = info->bmiHeader.biSize + size * sizeof(RGBQUAD);
+    else
+	size = info->bmiHeader.biSize + size * sizeof(WORD);
+    return size;
+}
+
+
+/***********************************************************************
+ *           DIB_DIBmpToImage
+ *
+ * Create an XImage pointing to the bitmap data.
+ */
+XImage * DIB_DIBmpToImage( BITMAPINFOHEADER * bmp, void * bmpData )
+{
+    XImage * image;
+    int bytesPerLine = (bmp->biWidth * bmp->biBitCount + 31) / 32 * 4;
+    
+    image = XCreateImage( XT_display, DefaultVisualOfScreen( XT_screen ),
+			  bmp->biBitCount, ZPixmap, 0, bmpData,
+			  bmp->biWidth, bmp->biHeight, 32, bytesPerLine );
+    if (!image) return 0;
+    image->byte_order = MSBFirst;
+    image->bitmap_bit_order = MSBFirst;
+    image->bitmap_unit = 16;
+    _XInitImageFuncPtrs(image);
+    return image;
+}
+
+
+/***********************************************************************
+ *           SetDIBits    (GDI.440)
+ */
+int SetDIBits( HDC hdc, HBITMAP hbitmap, WORD startscan, WORD lines,
+	       LPSTR bits, BITMAPINFO * info, WORD coloruse )
+{
+    DC * dc;
+    BITMAPOBJ * bmpObj;
+    BITMAP * bmp;
+    WORD * colorMapping;
+    RGBQUAD * rgbPtr;
+    XImage * bmpImage, * dibImage;
+    int i, x, y, pixel, colors;
+        
+    if (!lines) return 0;
+    if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
+    if (!(bmpObj = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
+	return 0;
+    if (!(bmp = (BITMAP *) GlobalLock( bmpObj->hBitmap ))) return 0;
+
+      /* Build the color mapping table */
+
+    if (info->bmiHeader.biBitCount == 24) colorMapping = NULL;
+    else if (coloruse == DIB_RGB_COLORS)
+    {
+	colors = info->bmiHeader.biClrUsed;
+	if (!colors) colors = 1 << info->bmiHeader.biBitCount;
+	if (!(colorMapping = (WORD *)malloc( colors * sizeof(WORD) )))
+	{
+	    GlobalUnlock( bmpObj->hBitmap );
+	    return 0;
+	}
+	for (i = 0, rgbPtr = info->bmiColors; i < colors; i++, rgbPtr++)
+	    colorMapping[i] = GetNearestPaletteIndex( dc->w.hPalette, 
+						     RGB(rgbPtr->rgbRed,
+							 rgbPtr->rgbGreen,
+							 rgbPtr->rgbBlue) );
+    }
+    else colorMapping = (WORD *)info->bmiColors;
+
+      /* Transfer the pixels (very slow...) */
+
+    bmpImage = BITMAP_BmpToImage( bmp, ((char *)bmp) + sizeof(BITMAP) );
+    dibImage = DIB_DIBmpToImage( &info->bmiHeader, bits );
+
+    for (y = 0; y < lines; y++)
+    {
+	for (x = 0; x < info->bmiHeader.biWidth; x++)
+	{
+	    pixel = XGetPixel( dibImage, x, y );
+	    if (colorMapping) pixel = colorMapping[pixel];
+	    else pixel = GetNearestPaletteIndex(dc->w.hPalette,(COLORREF)pixel);
+	    XPutPixel( bmpImage, x, bmp->bmHeight - startscan - y - 1, pixel );
+	}
+    }
+
+    bmpImage->data = NULL;
+    dibImage->data = NULL;
+    XDestroyImage( bmpImage );
+    XDestroyImage( dibImage );
+
+    if (colorMapping && (coloruse == DIB_RGB_COLORS)) free(colorMapping);
+    
+    GlobalUnlock( bmpObj->hBitmap );
+    return lines;
+}
+
+
+/***********************************************************************
+ *           GetDIBits    (GDI.441)
+ */
+int GetDIBits( HDC hdc, HBITMAP hbitmap, WORD startscan, WORD lines,
+	       LPSTR bits, BITMAPINFO * info, WORD coloruse )
+{
+    DC * dc;
+    BITMAPOBJ * bmpObj;
+    BITMAP * bmp;
+    PALETTEENTRY * palEntry;
+    PALETTEOBJ * palette;
+    XImage * bmpImage, * dibImage;
+    int i, x, y;
+        
+    if (!lines) return 0;
+    if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
+    if (!(bmpObj = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
+	return 0;
+    if (!(palette = (PALETTEOBJ*)GDI_GetObjPtr( dc->w.hPalette, PALETTE_MAGIC )))
+	return 0;
+    if (!(bmp = (BITMAP *) GlobalLock( bmpObj->hBitmap ))) return 0;
+
+      /* Transfer color info */
+    
+    palEntry = palette->logpalette.palPalEntry;
+    for (i = 0; i < info->bmiHeader.biClrUsed; i++, palEntry++)
+    {
+	if (coloruse == DIB_RGB_COLORS)
+	{
+	    info->bmiColors[i].rgbRed      = palEntry->peRed;
+	    info->bmiColors[i].rgbGreen    = palEntry->peGreen;
+	    info->bmiColors[i].rgbBlue     = palEntry->peBlue;
+	    info->bmiColors[i].rgbReserved = 0;
+	}
+	else ((WORD *)info->bmiColors)[i] = (WORD)i;
+    }
+    
+      /* Transfer the pixels (very slow...) */
+
+    if (bits)
+    {	
+	bmpImage = BITMAP_BmpToImage( bmp, ((char *)bmp) + sizeof(BITMAP) );
+	dibImage = DIB_DIBmpToImage( &info->bmiHeader, bits );
+
+	for (y = 0; y < lines; y++)
+	{
+	    for (x = 0; x < info->bmiHeader.biWidth; x++)
+	    {
+		XPutPixel( dibImage, x, y,
+		         XGetPixel(bmpImage, x, bmp->bmHeight-startscan-y-1) );
+		
+	    }
+	}
+	
+	bmpImage->data = NULL;
+	dibImage->data = NULL;
+	XDestroyImage( bmpImage );
+	XDestroyImage( dibImage );
+    }
+
+    GlobalUnlock( bmpObj->hBitmap );
+    return lines;
+}
+
+
+/***********************************************************************
+ *           CreateDIBitmap    (GDI.442)
+ */
+HBITMAP CreateDIBitmap( HDC hdc, BITMAPINFOHEADER * header, DWORD init,
+		        LPSTR bits, BITMAPINFO * data, WORD coloruse )
+{
+    HBITMAP handle;
+    
+    handle = CreateCompatibleBitmap( hdc, header->biWidth, header->biHeight );
+    if (!handle) return 0;
+    if (init == CBM_INIT) SetDIBits( hdc, handle, 0, header->biHeight,
+				    bits, data, coloruse );
+    return handle;
+}
diff --git a/objects/font.c b/objects/font.c
new file mode 100644
index 0000000..c30fcec
--- /dev/null
+++ b/objects/font.c
@@ -0,0 +1,332 @@
+/*
+ * GDI font objects
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include "gdi.h"
+
+extern Display * XT_display;
+extern Screen * XT_screen;
+
+
+/***********************************************************************
+ *           FONT_MatchFont
+ *
+ * Find a X font matching the logical font.
+ */
+XFontStruct * FONT_MatchFont( DC * dc, LOGFONT * font )
+{
+    char pattern[100];
+    char *family, *weight, *charset;
+    char **names;
+    char slant, spacing;
+    int width, height, count;
+    XFontStruct * fontStruct;
+    
+    weight = (font->lfWeight > 550) ? "bold" : "medium";
+    slant = font->lfItalic ? 'i' : 'r';
+    height = font->lfHeight * 10;
+    width = font->lfWidth * 10;
+    spacing = (font->lfPitchAndFamily & FIXED_PITCH) ? 'm' :
+	      (font->lfPitchAndFamily & VARIABLE_PITCH) ? 'p' : '*';
+    charset = (font->lfCharSet == ANSI_CHARSET) ? "iso8859-1" : "*";
+    family = font->lfFaceName;
+    if (!*family) switch(font->lfPitchAndFamily & 0xf0)
+    {
+      case FF_ROMAN:      family = "times"; break;
+      case FF_SWISS:      family = "helvetica"; break;
+      case FF_MODERN:     family = "courier"; break;
+      case FF_SCRIPT:     family = "*"; break;
+      case FF_DECORATIVE: family = "*"; break;
+      default:            family = "*"; break;
+    }
+    
+    sprintf( pattern, "-*-%s-%s-%c-normal--*-%d-*-*-%c-%d-%s",
+	    family, weight, slant, height, spacing, width, charset );
+#ifdef DEBUG_FONT
+    printf( "FONT_MatchFont: '%s'\n", pattern );
+#endif
+    names = XListFonts( XT_display, pattern, 1, &count );
+    if (!count)
+    {
+#ifdef DEBUG_FONT
+	printf( "        No matching font found\n" );	
+#endif
+	return NULL;
+    }
+#ifdef DEBUG_FONT
+    printf( "        Found '%s'\n", *names );
+#endif
+    fontStruct = XLoadQueryFont( XT_display, *names );
+    XFreeFontNames( names );
+    return fontStruct;
+}
+
+
+/***********************************************************************
+ *           FONT_GetMetrics
+ */
+void FONT_GetMetrics( LOGFONT * logfont, XFontStruct * xfont,
+		      TEXTMETRIC * metrics )
+{    
+    int average, i;
+    unsigned long prop;
+	
+    metrics->tmAscent  = xfont->ascent;
+    metrics->tmDescent = xfont->descent;
+    metrics->tmHeight  = xfont->ascent + xfont->descent;
+
+    metrics->tmInternalLeading  = 0;
+    if (XGetFontProperty( xfont, XA_X_HEIGHT, &prop ))
+	metrics->tmInternalLeading = xfont->ascent - (short)prop;
+    metrics->tmExternalLeading  = 0;
+    metrics->tmMaxCharWidth     = xfont->max_bounds.width;
+    metrics->tmWeight           = logfont->lfWeight;
+    metrics->tmItalic           = logfont->lfItalic;
+    metrics->tmUnderlined       = logfont->lfUnderline;
+    metrics->tmStruckOut        = logfont->lfStrikeOut;
+    metrics->tmFirstChar        = xfont->min_char_or_byte2;
+    metrics->tmLastChar         = xfont->max_char_or_byte2;
+    metrics->tmDefaultChar      = xfont->default_char;
+    metrics->tmBreakChar        = ' ';
+    metrics->tmPitchAndFamily   = logfont->lfPitchAndFamily;
+    metrics->tmCharSet          = logfont->lfCharSet;
+    metrics->tmOverhang         = 0;
+    metrics->tmDigitizedAspectX = 1;
+    metrics->tmDigitizedAspectY = 1;
+
+    if (xfont->per_char) average = metrics->tmMaxCharWidth;
+    else
+    {
+	XCharStruct * charPtr = xfont->per_char;
+	average = 0;
+	for (i = metrics->tmFirstChar; i <= metrics->tmLastChar; i++)
+	{
+	    average += charPtr->width;
+	    charPtr++;
+	}
+	average /= metrics->tmLastChar - metrics->tmFirstChar + 1;
+    }
+    metrics->tmAveCharWidth = average;
+}
+
+
+/***********************************************************************
+ *           CreateFontIndirect    (GDI.57)
+ */
+HFONT CreateFontIndirect( LOGFONT * font )
+{
+    FONTOBJ * fontPtr;
+    HFONT hfont = GDI_AllocObject( sizeof(FONTOBJ), FONT_MAGIC );
+    if (!hfont) return 0;
+    fontPtr = (FONTOBJ *) GDI_HEAP_ADDR( hfont );
+    memcpy( &fontPtr->logfont, font, sizeof(LOGFONT) );
+    return hfont;
+}
+
+
+/***********************************************************************
+ *           CreateFont    (GDI.56)
+ */
+HFONT CreateFont( int height, int width, int esc, int orient, int weight,
+		  BYTE italic, BYTE underline, BYTE strikeout, BYTE charset,
+		  BYTE outpres, BYTE clippres, BYTE quality, BYTE pitch,
+		  LPSTR name )
+{
+    LOGFONT logfont = { height, width, esc, orient, weight, italic, underline,
+		    strikeout, charset, outpres, clippres, quality, pitch, };
+    strncpy( logfont.lfFaceName, name, LF_FACESIZE );
+    return CreateFontIndirect( &logfont );
+}
+
+
+/***********************************************************************
+ *           FONT_GetObject
+ */
+int FONT_GetObject( FONTOBJ * font, int count, LPSTR buffer )
+{
+    if (count > sizeof(LOGFONT)) count = sizeof(LOGFONT);
+    memcpy( buffer, &font->logfont, count );
+    return count;
+}
+
+
+/***********************************************************************
+ *           FONT_SelectObject
+ */
+HFONT FONT_SelectObject( DC * dc, HFONT hfont, FONTOBJ * font )
+{
+    static X_PHYSFONT stockFonts[LAST_STOCK_FONT-FIRST_STOCK_FONT+1];
+    X_PHYSFONT * stockPtr;
+    HFONT prevHandle = dc->w.hFont;
+    XFontStruct * fontStruct;
+
+      /* Load font if necessary */
+
+    if ((hfont >= FIRST_STOCK_FONT) && (hfont <= LAST_STOCK_FONT))
+	stockPtr = &stockFonts[hfont - FIRST_STOCK_FONT];
+    else stockPtr = NULL;
+    
+    if (!stockPtr || !stockPtr->fstruct)
+    {
+	fontStruct = FONT_MatchFont( dc, &font->logfont );
+    }
+    else
+    {
+	fontStruct = stockPtr->fstruct;
+#ifdef DEBUG_FONT
+	printf( "FONT_SelectObject: Loaded font from cache %x %p\n",
+	        hfont, fontStruct );
+#endif
+    }	
+    if (!fontStruct) return 0;
+
+      /* Free previous font */
+
+    if ((prevHandle < FIRST_STOCK_FONT) || (prevHandle > LAST_STOCK_FONT))
+    {
+	if (dc->u.x.font.fstruct)
+	    XFreeFont( XT_display, dc->u.x.font.fstruct );
+    }
+
+      /* Store font */
+
+    dc->w.hFont = hfont;
+    if (stockPtr)
+    {
+	if (!stockPtr->fstruct)
+	{
+	    stockPtr->fstruct = fontStruct;
+	    FONT_GetMetrics( &font->logfont, fontStruct, &stockPtr->metrics );
+	}
+	memcpy( &dc->u.x.font, stockPtr, sizeof(*stockPtr) );
+    }
+    else
+    {
+	dc->u.x.font.fstruct = fontStruct;
+	FONT_GetMetrics( &font->logfont, fontStruct, &dc->u.x.font.metrics );
+    }
+    return prevHandle;
+}
+
+
+/***********************************************************************
+ *           GetTextCharacterExtra    (GDI.89)
+ */
+short GetTextCharacterExtra( HDC hdc )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return 0;
+    return abs( (dc->w.charExtra * dc->w.WndExtX + dc->w.VportExtX / 2)
+	         / dc->w.VportExtX );
+}
+
+
+/***********************************************************************
+ *           SetTextCharacterExtra    (GDI.8)
+ */
+short SetTextCharacterExtra( HDC hdc, short extra )
+{
+    short prev;
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return 0;
+    extra = (extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX;    
+    prev = dc->w.charExtra;
+    dc->w.charExtra = abs(extra);
+    return (prev * dc->w.WndExtX + dc->w.VportExtX / 2) / dc->w.VportExtX;
+}
+
+
+/***********************************************************************
+ *           SetTextJustification    (GDI.10)
+ */
+short SetTextJustification( HDC hdc, short extra, short breaks )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return 0;
+
+    extra = abs((extra * dc->w.VportExtX + dc->w.WndExtX / 2) / dc->w.WndExtX);
+    if (!extra) breaks = 0;
+    dc->w.breakTotalExtra = extra;
+    dc->w.breakCount = breaks;
+    if (breaks)
+    {	
+	dc->w.breakExtra = extra / breaks;
+	dc->w.breakRem   = extra - (dc->w.breakCount * dc->w.breakExtra);
+    }
+    else
+    {
+	dc->w.breakExtra = 0;
+	dc->w.breakRem   = 0;
+    }
+    return 1;
+}
+
+
+/***********************************************************************
+ *           GetTextExtent    (GDI.91)
+ */
+DWORD GetTextExtent( HDC hdc, LPSTR str, short count )
+{
+    SIZE size;
+    if (!GetTextExtentPoint( hdc, str, count, &size )) return 0;
+    return size.cx | (size.cy << 16);
+}
+
+
+/***********************************************************************
+ *           GetTextExtentPoint    (GDI.471)
+ */
+BOOL GetTextExtentPoint( HDC hdc, LPSTR str, short count, LPSIZE size )
+{
+    int dir, ascent, descent;
+    XCharStruct info;
+
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return FALSE;
+    XTextExtents( dc->u.x.font.fstruct, str, count, &dir,
+		  &ascent, &descent, &info );
+    size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
+		    * dc->w.WndExtX / dc->w.VportExtX);
+    size->cy = abs((dc->u.x.font.fstruct->ascent+dc->u.x.font.fstruct->descent)
+		    * dc->w.WndExtY / dc->w.VportExtY);
+
+#ifdef DEBUG_FONT
+    printf( "GetTextExtentPoint(%d '%s' %d %p): returning %d,%d\n",
+	    hdc, str, count, size, size->cx, size->cy );
+#endif
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           GetTextMetrics    (GDI.93)
+ */
+BOOL GetTextMetrics( HDC hdc, LPTEXTMETRIC metrics )
+{
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return FALSE;
+    memcpy( metrics, &dc->u.x.font.metrics, sizeof(*metrics) );
+
+    metrics->tmAscent  = abs( metrics->tmAscent
+			      * dc->w.WndExtY / dc->w.VportExtY );
+    metrics->tmDescent = abs( metrics->tmDescent
+			      * dc->w.WndExtY / dc->w.VportExtY );
+    metrics->tmHeight  = metrics->tmAscent + metrics->tmDescent;
+    metrics->tmInternalLeading = abs( metrics->tmInternalLeading
+				      * dc->w.WndExtY / dc->w.VportExtY );
+    metrics->tmExternalLeading = abs( metrics->tmExternalLeading
+				      * dc->w.WndExtY / dc->w.VportExtY );
+    metrics->tmMaxCharWidth    = abs( metrics->tmMaxCharWidth 
+				      * dc->w.WndExtX / dc->w.VportExtX );
+    metrics->tmAveCharWidth    = abs( metrics->tmAveCharWidth
+				      * dc->w.WndExtX / dc->w.VportExtX );
+    return TRUE;
+}
+
diff --git a/objects/gdiobj.c b/objects/gdiobj.c
new file mode 100644
index 0000000..55237c3
--- /dev/null
+++ b/objects/gdiobj.c
@@ -0,0 +1,380 @@
+/*
+ * GDI functions
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include "gdi.h"
+
+extern Display * XT_display;
+extern Screen * XT_screen;
+
+MDESC *GDI_Heap = NULL;
+
+
+/***********************************************************************
+ *          GDI stock objects 
+ */
+
+static BRUSHOBJ WhiteBrush =
+{
+    { 0, BRUSH_MAGIC, 1, 0 },          /* header */
+    { BS_SOLID, RGB(255,255,255), 0 }  /* logbrush */
+};
+
+static BRUSHOBJ LtGrayBrush =
+{
+    { 0, BRUSH_MAGIC, 1, 0 },          /* header */
+    { BS_SOLID, RGB(192,192,192), 0 }  /* logbrush */
+};
+
+static BRUSHOBJ GrayBrush =
+{
+    { 0, BRUSH_MAGIC, 1, 0 },          /* header */
+    { BS_SOLID, RGB(128,128,128), 0 }  /* logbrush */
+};
+
+static BRUSHOBJ DkGrayBrush =
+{
+    { 0, BRUSH_MAGIC, 1, 0 },       /* header */
+    { BS_SOLID, RGB(64,64,64), 0 }  /* logbrush */
+};
+
+static BRUSHOBJ BlackBrush =
+{
+    { 0, BRUSH_MAGIC, 1, 0 },    /* header */
+    { BS_SOLID, RGB(0,0,0), 0 }  /* logbrush */
+};
+
+static BRUSHOBJ NullBrush =
+{
+    { 0, BRUSH_MAGIC, 1, 0 },  /* header */
+    { BS_NULL, 0, 0 }          /* logbrush */
+};
+
+static PENOBJ WhitePen =
+{
+    { 0, PEN_MAGIC, 1, 0 },                  /* header */
+    { PS_SOLID, { 1, 0 }, RGB(255,255,255) } /* logpen */
+};
+
+static PENOBJ BlackPen =
+{
+    { 0, PEN_MAGIC, 1, 0 },            /* header */
+    { PS_SOLID, { 1, 0 }, RGB(0,0,0) } /* logpen */
+};
+
+static PENOBJ NullPen =
+{
+    { 0, PEN_MAGIC, 1, 0 },   /* header */
+    { PS_NULL, { 1, 0 }, 0 }  /* logpen */
+};
+
+static FONTOBJ OEMFixedFont =
+{
+    { 0, FONT_MAGIC, 1, 0 },   /* header */
+    { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
+      0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
+};
+
+static FONTOBJ AnsiFixedFont =
+{
+    { 0, FONT_MAGIC, 1, 0 },   /* header */
+    { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+      0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
+};
+
+static FONTOBJ AnsiVarFont =
+{
+    { 0, FONT_MAGIC, 1, 0 },   /* header */
+    { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+      0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "" }
+};
+
+static FONTOBJ SystemFont =
+{
+    { 0, FONT_MAGIC, 1, 0 },   /* header */
+    { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+      0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "" }
+};
+
+static FONTOBJ DeviceDefaultFont =
+{
+    { 0, FONT_MAGIC, 1, 0 },   /* header */
+    { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+      0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "" }
+};
+
+static FONTOBJ SystemFixedFont =
+{
+    { 0, FONT_MAGIC, 1, 0 },   /* header */
+    { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+      0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
+};
+
+
+static GDIOBJHDR * StockObjects[NB_STOCK_OBJECTS] =
+{
+    (GDIOBJHDR *) &WhiteBrush,
+    (GDIOBJHDR *) &LtGrayBrush,
+    (GDIOBJHDR *) &GrayBrush,
+    (GDIOBJHDR *) &DkGrayBrush,
+    (GDIOBJHDR *) &BlackBrush,
+    (GDIOBJHDR *) &NullBrush,
+    (GDIOBJHDR *) &WhitePen,
+    (GDIOBJHDR *) &BlackPen,
+    (GDIOBJHDR *) &NullPen,
+    NULL,
+    (GDIOBJHDR *) &OEMFixedFont,
+    (GDIOBJHDR *) &AnsiFixedFont,
+    (GDIOBJHDR *) &AnsiVarFont,
+    (GDIOBJHDR *) &SystemFont,
+    (GDIOBJHDR *) &DeviceDefaultFont,
+    NULL,            /* DEFAULT_PALETTE created by PALETTE_Init */
+    (GDIOBJHDR *) &SystemFixedFont
+};
+
+extern GDIOBJHDR * PALETTE_systemPalette;
+
+
+/***********************************************************************
+ *           GDI_Init
+ *
+ * GDI initialisation.
+ */
+BOOL GDI_Init()
+{
+    struct segment_descriptor_s * s;
+
+      /* Create GDI heap */
+
+    s = GetNextSegment( 0, 0x10000 );
+    if (s == NULL) return FALSE;
+    HEAP_Init( &GDI_Heap, s->base_addr, GDI_HEAP_SIZE );
+    free(s);
+
+      /* Create default palette */
+
+    PALETTE_Init();
+    StockObjects[DEFAULT_PALETTE] = PALETTE_systemPalette;
+
+      /* Create default bitmap */
+
+    if (!BITMAP_Init()) return FALSE;
+
+      /* Initialise regions */
+
+    if (!REGION_Init()) return FALSE;
+    
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           GDI_FindPrevObject
+ *
+ * Return the GDI object whose hNext field points to obj.
+ */
+HANDLE GDI_FindPrevObject( HANDLE first, HANDLE obj )
+{
+    HANDLE handle;
+        
+    for (handle = first; handle && (handle != obj); )
+    {
+	GDIOBJHDR * header = (GDIOBJHDR *) GDI_HEAP_ADDR( handle );
+	handle = header->hNext;
+    }
+    return handle;
+}
+
+
+/***********************************************************************
+ *           GDI_AllocObject
+ */
+HANDLE GDI_AllocObject( WORD size, WORD magic )
+{
+    static DWORD count = 0;
+    GDIOBJHDR * obj;
+    HANDLE handle = GDI_HEAP_ALLOC( GMEM_MOVEABLE, size );
+    if (!handle) return 0;
+    
+    obj = (GDIOBJHDR *) GDI_HEAP_ADDR( handle );
+    obj->hNext   = 0;
+    obj->wMagic  = magic;
+    obj->dwCount = ++count;
+    return handle;
+}
+
+
+/***********************************************************************
+ *           GDI_FreeObject
+ */
+BOOL GDI_FreeObject( HANDLE handle )
+{
+    GDIOBJHDR * object;
+    HANDLE prev;
+
+      /* Can't free stock objects */
+    if (handle >= FIRST_STOCK_HANDLE) return FALSE;
+    
+    object = (GDIOBJHDR *) GDI_HEAP_ADDR( handle );
+    if (!object) return FALSE;
+
+      /* Free object */
+    
+    GDI_HEAP_FREE( handle );
+    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.
+ */
+GDIOBJHDR * GDI_GetObjPtr( HANDLE handle, WORD magic )
+{
+    GDIOBJHDR * ptr = NULL;
+
+    if (handle >= FIRST_STOCK_HANDLE)
+    {
+	if (handle < FIRST_STOCK_HANDLE + NB_STOCK_OBJECTS)
+	    ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
+    }
+    else ptr = (GDIOBJHDR *) GDI_HEAP_ADDR( handle );
+    if (!ptr) return NULL;
+    if (ptr->wMagic != magic) return NULL;
+    return ptr;
+}
+
+
+/***********************************************************************
+ *           DeleteObject    (GDI.69)
+ */
+BOOL DeleteObject( HANDLE obj )
+{
+      /* Check if object is valid */
+
+    GDIOBJHDR * header = (GDIOBJHDR *) GDI_HEAP_ADDR( obj );
+    if (!header) return FALSE;
+
+#ifdef DEBUG_GDI
+    printf( "DeleteObject: %d\n", obj );
+#endif
+
+      /* Delete object */
+
+    switch(header->wMagic)
+    {
+      case PEN_MAGIC:     return GDI_FreeObject( obj );
+      case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, header );
+      case FONT_MAGIC:    return GDI_FreeObject( obj );
+      case PALETTE_MAGIC: return GDI_FreeObject( obj );
+      case BITMAP_MAGIC:  return BMP_DeleteObject( obj, header );
+      case REGION_MAGIC:  return REGION_DeleteObject( obj, header );
+    }
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           GetStockObject    (GDI.87)
+ */
+HANDLE GetStockObject( int obj )
+{
+    if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
+    if (!StockObjects[obj]) return 0;
+#ifdef DEBUG_GDI
+    printf( "GetStockObject: returning %04x\n", FIRST_STOCK_HANDLE + obj );
+#endif
+    return FIRST_STOCK_HANDLE + obj;
+}
+
+
+/***********************************************************************
+ *           GetObject    (GDI.82)
+ */
+int GetObject( HANDLE handle, int count, LPSTR buffer )
+{
+    GDIOBJHDR * ptr = NULL;
+#ifdef DEBUG_GDI
+    printf( "GetObject: %04x %d %08x\n", handle, count, buffer );
+#endif
+    if (!count) return 0;
+
+    if (handle >= FIRST_STOCK_HANDLE)
+    {
+	if (handle < FIRST_STOCK_HANDLE + NB_STOCK_OBJECTS)
+	    ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
+    }
+    else ptr = (GDIOBJHDR *) GDI_HEAP_ADDR( handle );
+    if (!ptr) return 0;
+    
+    switch(ptr->wMagic)
+    {
+      case PEN_MAGIC:
+	  return PEN_GetObject( (PENOBJ *)ptr, count, buffer );
+      case BRUSH_MAGIC: 
+	  return BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
+      case BITMAP_MAGIC: 
+	  return BMP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
+      case FONT_MAGIC:
+	  return FONT_GetObject( (FONTOBJ *)ptr, count, buffer );
+      case PALETTE_MAGIC:
+	  return PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           SelectObject    (GDI.45)
+ */
+HANDLE SelectObject( HDC hdc, HANDLE handle )
+{
+    GDIOBJHDR * ptr = NULL;
+    DC * dc;
+    
+#ifdef DEBUG_GDI
+    printf( "SelectObject: %d %04x\n", hdc, handle );
+#endif
+    if (handle >= FIRST_STOCK_HANDLE)
+    {
+	if (handle < FIRST_STOCK_HANDLE + NB_STOCK_OBJECTS)
+	    ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
+    }
+    else ptr = (GDIOBJHDR *) GDI_HEAP_ADDR( handle );
+    if (!ptr) return 0;
+    
+    dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return 0;
+    
+    switch(ptr->wMagic)
+    {
+      case PEN_MAGIC:
+	  return PEN_SelectObject( dc, handle, (PENOBJ *)ptr );
+      case BRUSH_MAGIC:
+	  return BRUSH_SelectObject( hdc, dc, handle, (BRUSHOBJ *)ptr );
+      case BITMAP_MAGIC:
+	  return BITMAP_SelectObject( hdc, dc, handle, (BITMAPOBJ *)ptr );
+      case FONT_MAGIC:
+	  return FONT_SelectObject( dc, handle, (FONTOBJ *)ptr );	  
+      case REGION_MAGIC:
+	  return SelectClipRgn( hdc, handle );
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           UnrealizeObject    (GDI.150)
+ */
+BOOL UnrealizeObject( HANDLE handle )
+{
+#ifdef DEBUG_GDI
+    printf( "UnrealizeObject: %04x\n", handle );
+#endif
+    return TRUE;
+}
diff --git a/objects/linedda.c b/objects/linedda.c
new file mode 100644
index 0000000..f95ea48
--- /dev/null
+++ b/objects/linedda.c
@@ -0,0 +1,19 @@
+/*
+ * LineDDA
+ *
+ * Copyright 1993 Bob Amstadt
+ */
+
+static char Copyright[] = "Copyright  Bob Amstadt, 1993";
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "win.h"
+
+/**********************************************************************
+ *		LineDDA		(GDI.100)
+ */
+void LineDDA(short nXStart, short nYStart, short nXEnd, short nYEnd,
+	     FARPROC callback, long lParam)
+{
+}
diff --git a/objects/palette.c b/objects/palette.c
new file mode 100644
index 0000000..bdde29d
--- /dev/null
+++ b/objects/palette.c
@@ -0,0 +1,191 @@
+/*
+ * GDI palette objects
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include <stdlib.h>
+#include <values.h>
+#include <X11/Xlib.h>
+
+#include "gdi.h"
+
+extern Display * XT_display;
+extern Screen * XT_screen;
+
+
+#define NB_RESERVED_COLORS  17
+static char * ReservedColors[NB_RESERVED_COLORS] =
+{
+    "black",
+    "gray25",
+    "gray50",
+    "gray75",
+    "white",
+    "red1",
+    "red4",
+    "green1",
+    "green4",
+    "blue1",
+    "blue4",
+    "cyan1",
+    "cyan4",
+    "magenta1",
+    "magenta4",
+    "yellow1",
+    "yellow4"
+};
+
+GDIOBJHDR * PALETTE_systemPalette;
+
+static int SysColorPixels[NB_RESERVED_COLORS];
+
+
+/***********************************************************************
+ *           PALETTE_Init
+ */
+BOOL PALETTE_Init()
+{
+    int i, size, pixel;
+    XColor serverColor, exactColor;
+    HPALETTE hpalette;
+    LOGPALETTE * palPtr;
+
+    size = DefaultVisual(XT_display,DefaultScreen(XT_display))->map_entries;
+    palPtr = malloc( sizeof(LOGPALETTE) + (size-1)*sizeof(PALETTEENTRY) );
+    if (!palPtr) return FALSE;
+    palPtr->palVersion = 0x300;
+    palPtr->palNumEntries = size;
+    memset( palPtr->palPalEntry, 0xff, size*sizeof(PALETTEENTRY) );
+    
+    for (i = 0; i < NB_RESERVED_COLORS; i++)
+    {
+	if (XAllocNamedColor( XT_display,
+			      DefaultColormapOfScreen( XT_screen ),
+			      ReservedColors[i], 
+			      &serverColor, &exactColor ))
+	{
+	    pixel = serverColor.pixel;
+	    palPtr->palPalEntry[pixel].peRed   = serverColor.red >> 8;
+	    palPtr->palPalEntry[pixel].peGreen = serverColor.green >> 8;
+	    palPtr->palPalEntry[pixel].peBlue  = serverColor.blue >> 8;
+	    palPtr->palPalEntry[pixel].peFlags = 0;
+	}
+    }
+    hpalette = CreatePalette( palPtr );
+    PALETTE_systemPalette = (GDIOBJHDR *) GDI_HEAP_ADDR( hpalette );
+    free( palPtr );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           CreatePalette    (GDI.360)
+ */
+HPALETTE CreatePalette( LOGPALETTE * palette )
+{
+    PALETTEOBJ * palettePtr;
+    HPALETTE hpalette;
+    int size;
+
+    size = sizeof(LOGPALETTE) + (palette->palNumEntries - 1) * sizeof(PALETTEENTRY);
+    hpalette = GDI_AllocObject( sizeof(GDIOBJHDR) + size, PALETTE_MAGIC );
+    if (!hpalette) return 0;
+    palettePtr = (PALETTEOBJ *) GDI_HEAP_ADDR( hpalette );
+    memcpy( &palettePtr->logpalette, palette, size );
+    return hpalette;
+}
+
+
+/***********************************************************************
+ *           GetPaletteEntries    (GDI.363)
+ */
+WORD GetPaletteEntries( HPALETTE hpalette, WORD start, WORD count,
+		        LPPALETTEENTRY entries )
+{
+    PALETTEOBJ * palPtr;
+    int numEntries;
+        
+    palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
+    if (!palPtr) return 0;
+    numEntries = palPtr->logpalette.palNumEntries;
+    if (start >= numEntries) return 0;
+    if (start+count > numEntries) count = numEntries - start;
+    memcpy( entries, &palPtr->logpalette.palPalEntry[start],
+	    count * sizeof(PALETTEENTRY) );
+    return count;
+}
+
+
+/***********************************************************************
+ *           SetPaletteEntries    (GDI.364)
+ */
+WORD SetPaletteEntries( HPALETTE hpalette, WORD start, WORD count,
+		        LPPALETTEENTRY entries )
+{
+    PALETTEOBJ * palPtr;
+    int numEntries;
+        
+    palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
+    if (!palPtr) return 0;
+    numEntries = palPtr->logpalette.palNumEntries;
+    if (start >= numEntries) return 0;
+    if (start+count > numEntries) count = numEntries - start;
+    memcpy( &palPtr->logpalette.palPalEntry[start], entries,
+	    count * sizeof(PALETTEENTRY) );
+    return count;
+}
+
+
+/***********************************************************************
+ *           GetNearestPaletteIndex    (GDI.370)
+ */
+WORD GetNearestPaletteIndex( HPALETTE hpalette, COLORREF color )
+{
+    int i, minDist, dist;
+    WORD index = 0;
+    BYTE r, g, b;
+    PALETTEENTRY * entry;
+    PALETTEOBJ * palPtr;
+    
+    palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
+    if (!palPtr) return 0;
+    
+    r = GetRValue(color);
+    g = GetGValue(color);
+    b = GetBValue(color);
+    entry = palPtr->logpalette.palPalEntry;
+    for (i = 0, minDist = MAXINT; i < palPtr->logpalette.palNumEntries; i++)
+    {
+	if (entry->peFlags != 0xff)
+	{
+	    dist = (r - entry->peRed) * (r - entry->peRed) +
+		   (g - entry->peGreen) * (g - entry->peGreen) +
+		   (b - entry->peBlue) * (b - entry->peBlue);	
+	    if (dist < minDist)
+	    {
+		minDist = dist;
+		index = i;
+	    }
+	}
+	entry++;
+    }
+#ifdef DEBUG_GDI
+    printf( "GetNearestPaletteIndex(%x,%06x) : returning %d\n", 
+	     hpalette, color, index );
+#endif
+    return index;
+}
+
+
+/***********************************************************************
+ *           PALETTE_GetObject
+ */
+int PALETTE_GetObject( PALETTEOBJ * palette, int count, LPSTR buffer )
+{
+    if (count > sizeof(WORD)) count = sizeof(WORD);
+    memcpy( buffer, &palette->logpalette.palNumEntries, count );
+    return count;
+}
diff --git a/objects/pen.c b/objects/pen.c
new file mode 100644
index 0000000..fa49ef3
--- /dev/null
+++ b/objects/pen.c
@@ -0,0 +1,93 @@
+/*
+ * GDI pen objects
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include "gdi.h"
+
+extern Display * XT_display;
+extern Screen * XT_screen;
+
+
+/***********************************************************************
+ *           CreatePen    (GDI.61)
+ */
+HPEN CreatePen( short style, short width, COLORREF color )
+{
+    LOGPEN logpen = { style, { width, 0 }, color };
+#ifdef DEBUG_GDI
+    printf( "CreatePen: %d %d %06x\n", style, width, color );
+#endif
+    return CreatePenIndirect( &logpen );
+}
+
+
+/***********************************************************************
+ *           CreatePenIndirect    (GDI.62)
+ */
+HPEN CreatePenIndirect( LOGPEN * pen )
+{
+    PENOBJ * penPtr;
+    HPEN hpen;
+
+    if (pen->lopnStyle > PS_INSIDEFRAME) return 0;
+    hpen = GDI_AllocObject( sizeof(PENOBJ), PEN_MAGIC );
+    if (!hpen) return 0;
+    penPtr = (PENOBJ *) GDI_HEAP_ADDR( hpen );    
+    memcpy( &penPtr->logpen, pen, sizeof(LOGPEN) );
+    return hpen;
+}
+
+
+/***********************************************************************
+ *           PEN_GetObject
+ */
+int PEN_GetObject( PENOBJ * pen, int count, LPSTR buffer )
+{
+    if (count > sizeof(LOGPEN)) count = sizeof(LOGPEN);
+    memcpy( buffer, &pen->logpen, count );
+    return count;
+}
+
+
+/***********************************************************************
+ *           PEN_SelectObject
+ */
+HPEN PEN_SelectObject( DC * dc, HPEN hpen, PENOBJ * pen )
+{
+    static char dash_dash[]       = { 5, 3 };      /* -----   -----   -----  */
+    static char dash_dot[]        = { 2, 2 };      /* --  --  --  --  --  -- */
+    static char dash_dashdot[]    = { 4,3,2,3 };   /* ----   --   ----   --  */
+    static char dash_dashdotdot[] = { 4,2,2,2,2,2 };  /* ----  --  --  ----  */
+
+    HPEN prevHandle = dc->w.hPen;
+    dc->w.hPen = hpen;
+
+    dc->u.x.pen.style = pen->logpen.lopnStyle;
+    dc->u.x.pen.width = pen->logpen.lopnWidth.x * dc->w.VportExtX
+	                  / dc->w.WndExtX;
+    if (dc->u.x.pen.width < 0) dc->u.x.pen.width = -dc->u.x.pen.width;
+    if (dc->u.x.pen.width == 1) dc->u.x.pen.width = 0;  /* Faster */
+    dc->u.x.pen.pixel = GetNearestPaletteIndex( dc->w.hPalette,
+					        pen->logpen.lopnColor );    
+    switch(pen->logpen.lopnStyle)
+    {
+      case PS_DASH:
+	XSetDashes( XT_display, dc->u.x.gc, 0, dash_dash, 2 );
+	break;
+      case PS_DOT:
+	XSetDashes( XT_display, dc->u.x.gc, 0, dash_dot, 2 );
+	break;
+      case PS_DASHDOT:
+	XSetDashes( XT_display, dc->u.x.gc, 0, dash_dashdot, 4 );
+	break;
+      case PS_DASHDOTDOT:
+	XSetDashes( XT_display, dc->u.x.gc, 0, dash_dashdotdot, 6 );
+	break;
+    }
+    
+    return prevHandle;
+}
diff --git a/objects/region.c b/objects/region.c
new file mode 100644
index 0000000..2c22ee4
--- /dev/null
+++ b/objects/region.c
@@ -0,0 +1,614 @@
+/*
+ * GDI region objects
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gdi.h"
+
+
+  /* GC used for region operations */
+static GC regionGC = 0;
+
+
+/***********************************************************************
+ *           REGION_Init
+ */
+BOOL REGION_Init()
+{
+    Pixmap tmpPixmap;
+
+      /* CreateGC needs a drawable */
+    tmpPixmap = XCreatePixmap( XT_display, DefaultRootWindow(XT_display),
+			       1, 1, 1 );
+    if (tmpPixmap)
+    {
+	regionGC = XCreateGC( XT_display, tmpPixmap, 0, NULL );
+	XFreePixmap( XT_display, tmpPixmap );
+	if (!regionGC) return FALSE;
+	XSetForeground( XT_display, regionGC, 1 );
+	return TRUE;
+    }
+    else return FALSE;
+}
+
+
+/***********************************************************************
+ *           REGION_SetRect
+ *
+ * Set the bounding box of the region and create the pixmap.
+ * The hrgn must be valid.
+ */
+static BOOL REGION_SetRect( HRGN hrgn, LPRECT rect )
+{
+    int width, height;
+
+      /* Fill region */
+
+    REGION * region = &((RGNOBJ *)GDI_HEAP_ADDR( hrgn ))->region;
+    width  = rect->right - rect->left;
+    height = rect->bottom - rect->top;
+    if ((width <= 0) || (height <= 0))
+    {
+	region->type       = NULLREGION;
+	region->box.left   = 0;
+	region->box.right  = 0;
+	region->box.top    = 0;
+	region->box.bottom = 0;
+	region->pixmap     = 0;
+	return TRUE;
+    }
+    region->type = SIMPLEREGION;
+    region->box  = *rect;
+    
+      /* Create pixmap */
+
+    region->pixmap = XCreatePixmap( XT_display, DefaultRootWindow(XT_display),
+				    width, height, 1 );
+    if (!region->pixmap) return FALSE;
+
+      /* Fill pixmap */
+
+    XSetFunction( XT_display, regionGC, GXclear );
+    XFillRectangle( XT_display, region->pixmap, regionGC,
+		    0, 0, width, height );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           REGION_DeleteObject
+ */
+BOOL REGION_DeleteObject( HRGN hrgn, RGNOBJ * obj )
+{
+    if (obj->region.pixmap) XFreePixmap( XT_display, obj->region.pixmap );
+    return GDI_FreeObject( hrgn );
+}
+
+
+/***********************************************************************
+ *           OffsetRgn    (GDI.101)
+ */
+int OffsetRgn( HRGN hrgn, short x, short y )
+{
+    RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
+    if (!obj) return ERROR;
+#ifdef DEBUG_REGION
+    printf( "OffsetRgn: %d %d,%d\n", hrgn, x, y );
+#endif
+    OffsetRect( &obj->region.box, x, y );
+    return obj->region.type;
+}
+
+
+/***********************************************************************
+ *           GetRgnBox    (GDI.134)
+ */
+int GetRgnBox( HRGN hrgn, LPRECT rect )
+{
+    RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
+    if (!obj) return ERROR;
+#ifdef DEBUG_REGION
+    printf( "GetRgnBox: %d\n", hrgn );
+#endif
+    *rect = obj->region.box;
+    return obj->region.type;
+}
+
+
+/***********************************************************************
+ *           CreateRectRgn    (GDI.64)
+ */
+HRGN CreateRectRgn( short left, short top, short right, short bottom )
+{
+    RECT rect = { left, top, right, bottom };    
+    return CreateRectRgnIndirect( &rect );
+}
+
+
+/***********************************************************************
+ *           CreateRectRgnIndirect    (GDI.65)
+ */
+HRGN CreateRectRgnIndirect( LPRECT rect )
+{
+    RGNOBJ * rgnObj;
+    HRGN hrgn;
+
+#ifdef DEBUG_REGION
+    printf( "CreateRectRgnIndirect: %d,%d-%d,%d\n",
+	    rect->left, rect->top, rect->right, rect->bottom );
+#endif
+    
+      /* Create region */
+
+    if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
+    if (!REGION_SetRect( hrgn, rect ))
+    {
+	GDI_FreeObject( hrgn );
+	return 0;
+    }
+    rgnObj = (RGNOBJ *) GDI_HEAP_ADDR( hrgn );
+
+      /* Fill pixmap */
+    
+    if (rgnObj->region.type != NULLREGION)
+    {
+	int width  = rgnObj->region.box.right - rgnObj->region.box.left;
+	int height = rgnObj->region.box.bottom - rgnObj->region.box.top;
+	XSetFunction( XT_display, regionGC, GXcopy );
+	XFillRectangle( XT_display, rgnObj->region.pixmap, regionGC,
+		        0, 0, width, height );
+    }
+    
+    return hrgn;
+}
+
+
+/***********************************************************************
+ *           CreateRoundRectRgn    (GDI.444)
+ */
+HRGN CreateRoundRectRgn( short left, short top, short right, short bottom,
+			 short ellipse_width, short ellipse_height )
+{
+    RECT rect = { left, top, right, bottom };    
+    RGNOBJ * rgnObj;
+    HRGN hrgn;
+
+#ifdef DEBUG_REGION
+    printf( "CreateRoundRectRgn: %d,%d-%d,%d %dx%d\n",
+	    left, top, right, bottom, ellipse_width, ellipse_height );
+#endif
+    
+      /* Create region */
+
+    if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
+    if (!REGION_SetRect( hrgn, &rect ))
+    {
+	GDI_FreeObject( hrgn );
+	return 0;
+    }
+    rgnObj = (RGNOBJ *) GDI_HEAP_ADDR( hrgn );
+
+      /* Fill pixmap */
+    
+    if (rgnObj->region.type != NULLREGION)
+    {
+	int width  = rgnObj->region.box.right - rgnObj->region.box.left;
+	int height = rgnObj->region.box.bottom - rgnObj->region.box.top;
+	XSetFunction( XT_display, regionGC, GXcopy );
+	XFillRectangle( XT_display, rgnObj->region.pixmap, regionGC,
+		        0, ellipse_height / 2,
+		        width, height - ellipse_height );
+	XFillRectangle( XT_display, rgnObj->region.pixmap, regionGC,
+		        ellipse_width / 2, 0,
+		        width - ellipse_width, height );
+	XFillArc( XT_display, rgnObj->region.pixmap, regionGC,
+		  0, 0,
+		  ellipse_width, ellipse_height, 0, 360*64 );
+	XFillArc( XT_display, rgnObj->region.pixmap, regionGC,
+		  width - ellipse_width, 0,
+		  ellipse_width, ellipse_height, 0, 360*64 );
+	XFillArc( XT_display, rgnObj->region.pixmap, regionGC,
+		  0, height - ellipse_height,
+		  ellipse_width, ellipse_height, 0, 360*64 );
+	XFillArc( XT_display, rgnObj->region.pixmap, regionGC,
+		  width - ellipse_width, height - ellipse_height,
+		  ellipse_width, ellipse_height, 0, 360*64 );
+    }
+    
+    return hrgn;
+}
+
+
+/***********************************************************************
+ *           SetRectRgn    (GDI.172)
+ */
+void SetRectRgn( HRGN hrgn, short left, short top, short right, short bottom )
+{
+    RECT rect = { left, top, right, bottom };    
+    RGNOBJ * rgnObj;
+
+#ifdef DEBUG_REGION
+    printf( "SetRectRgn: %d %d,%d-%d,%d\n", hrgn, left, top, right, bottom );
+#endif
+    
+      /* Free previous pixmap */
+
+    if (!(rgnObj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
+    if (rgnObj->region.pixmap) 
+	XFreePixmap( XT_display, rgnObj->region.pixmap );
+
+    if (!REGION_SetRect( hrgn, &rect )) return;
+
+      /* Fill pixmap */
+    
+    if (rgnObj->region.type != NULLREGION)
+    {
+	int width  = rgnObj->region.box.right - rgnObj->region.box.left;
+	int height = rgnObj->region.box.bottom - rgnObj->region.box.top;
+	XSetFunction( XT_display, regionGC, GXcopy );
+	XFillRectangle( XT_display, rgnObj->region.pixmap, regionGC,
+		        0, 0, width, height );
+    }
+}
+
+
+/***********************************************************************
+ *           CreateEllipticRgn    (GDI.54)
+ */
+HRGN CreateEllipticRgn( short left, short top, short right, short bottom )
+{
+    RECT rect = { left, top, right, bottom };    
+    return CreateEllipticRgnIndirect( &rect );
+}
+
+
+/***********************************************************************
+ *           CreateEllipticRgnIndirect    (GDI.55)
+ */
+HRGN CreateEllipticRgnIndirect( LPRECT rect )
+{
+    RGNOBJ * rgnObj;
+    HRGN hrgn;
+
+#ifdef DEBUG_REGION
+    printf( "CreateEllipticRgnIndirect: %d,%d-%d,%d\n",
+	    rect->left, rect->top, rect->right, rect->bottom );
+#endif
+    
+      /* Create region */
+
+    if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
+    if (!REGION_SetRect( hrgn, rect ))
+    {
+	GDI_FreeObject( hrgn );
+	return 0;
+    }
+    rgnObj = (RGNOBJ *) GDI_HEAP_ADDR( hrgn );
+
+      /* Fill pixmap */
+    
+    if (rgnObj->region.type != NULLREGION)
+    {
+	int width  = rgnObj->region.box.right - rgnObj->region.box.left;
+	int height = rgnObj->region.box.bottom - rgnObj->region.box.top;
+	XSetFunction( XT_display, regionGC, GXcopy );
+	XFillArc( XT_display, rgnObj->region.pixmap, regionGC,
+		  0, 0, width, height, 0, 360*64 );
+    }
+    
+    return hrgn;
+}
+
+
+/***********************************************************************
+ *           CreatePolygonRgn    (GDI.63)
+ */
+HRGN CreatePolygonRgn( POINT * points, short count, short mode )
+{
+    return CreatePolyPolygonRgn( points, &count, 1, mode );
+}
+
+
+/***********************************************************************
+ *           CreatePolyPolygonRgn    (GDI.451)
+ */
+HRGN CreatePolyPolygonRgn( POINT * points, short * count,
+			   short nbpolygons, short mode )
+{
+    RGNOBJ * rgnObj;
+    HRGN hrgn;
+    RECT box;
+    int i, j, totalPoints;
+    POINT * pt;
+    XPoint * xpoints;
+    
+    if (!nbpolygons) return 0;
+#ifdef DEBUG_REGION
+    printf( "CreatePolyPolygonRgn: %d polygons\n", nbpolygons );
+#endif
+    
+      /* Find bounding box */
+
+    box.top   = box.left   = 32767;
+    box.right = box.bottom = 0;
+    for (i = totalPoints = 0, pt = points; i < nbpolygons; i++)
+    {
+	totalPoints += count[i];
+	for (j = 0; j < count[i]; j++, pt++)
+	{
+	    if (pt->x < box.left) box.left = pt->x;
+	    if (pt->x > box.right) box.right = pt->x;
+	    if (pt->y < box.top) box.top = pt->y;
+	    if (pt->y > box.bottom) box.bottom = pt->y;
+	}
+    }        
+    if (!totalPoints) return 0;
+    
+      /* Build points array */
+
+    xpoints = (XPoint *) malloc( sizeof(XPoint) * totalPoints );
+    if (!xpoints) return 0;
+    for (i = 0, pt = points; i < totalPoints; i++, pt++)
+    {
+	xpoints[i].x = pt->x - box.left;
+	xpoints[i].y = pt->y - box.top;
+    }
+
+      /* Create region */
+
+    if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )) ||
+	!REGION_SetRect( hrgn, &box ))
+    {
+	if (hrgn) GDI_FreeObject( hrgn );
+	free( xpoints );
+	return 0;
+    }
+    rgnObj = (RGNOBJ *) GDI_HEAP_ADDR( hrgn );
+
+      /* Fill pixmap */
+
+    if (rgnObj->region.type != NULLREGION)
+    {
+	XSetFunction( XT_display, regionGC, GXcopy );
+	if (mode == WINDING) XSetFillRule( XT_display, regionGC, WindingRule );
+	else XSetFillRule( XT_display, regionGC, EvenOddRule );
+	for (i = j = 0; i < nbpolygons; i++)
+	{
+	    XFillPolygon( XT_display, rgnObj->region.pixmap, regionGC,
+			  &xpoints[j], count[i], Complex, CoordModeOrigin );
+	    j += count[i];
+	}
+    }
+    
+    free( xpoints );
+    return hrgn;
+}
+
+
+/***********************************************************************
+ *           PtInRegion    (GDI.161)
+ */
+BOOL PtInRegion( HRGN hrgn, short x, short y )
+{
+    XImage * image;
+    BOOL res;
+    RGNOBJ * obj;
+    POINT pt = { x, y };
+    
+    if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
+    if (!PtInRect( &obj->region.box, pt )) return FALSE;
+    image = XGetImage( XT_display, obj->region.pixmap,
+		       x - obj->region.box.left, y - obj->region.box.top,
+		       1, 1, AllPlanes, ZPixmap );
+    if (!image) return FALSE;
+    res = (XGetPixel( image, 0, 0 ) != 0);
+    XDestroyImage( image );
+    return res;
+}
+
+
+/***********************************************************************
+ *           RectInRegion    (GDI.181)
+ */
+BOOL RectInRegion( HRGN hrgn, LPRECT rect )
+{
+    XImage * image;
+    RGNOBJ * obj;
+    RECT intersect;
+    int x, y;
+    
+    if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
+    if (!IntersectRect( &intersect, &obj->region.box, rect )) return FALSE;
+    
+    image = XGetImage( XT_display, obj->region.pixmap,
+		       intersect.left - obj->region.box.left,
+		       intersect.top - obj->region.box.top,
+		       intersect.right - intersect.left,
+		       intersect.bottom - intersect.top,
+		       AllPlanes, ZPixmap );
+    if (!image) return FALSE;
+    for (y = 0; y < image->height; y++)
+	for (x = 0; x < image->width; x++)
+	    if (XGetPixel( image, x, y ) != 0)
+	    {
+		XDestroyImage( image );
+		return TRUE;
+	    }
+    
+    XDestroyImage( image );
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           EqualRgn    (GDI.72)
+ */
+BOOL EqualRgn( HRGN rgn1, HRGN rgn2 )
+{
+    RGNOBJ *obj1, *obj2;
+    XImage *image1, *image2;
+    int width, height, x, y;
+
+      /* Compare bounding boxes */
+
+    if (!(obj1 = (RGNOBJ *) GDI_GetObjPtr( rgn1, REGION_MAGIC ))) return FALSE;
+    if (!(obj2 = (RGNOBJ *) GDI_GetObjPtr( rgn2, REGION_MAGIC ))) return FALSE;
+    if (obj1->region.type == NULLREGION)
+	return (obj2->region.type == NULLREGION);
+    else if (obj2->region.type == NULLREGION) return FALSE;
+    if (!EqualRect( &obj1->region.box, &obj2->region.box )) return FALSE;
+
+      /* Get pixmap contents */
+
+    width  = obj1->region.box.right - obj1->region.box.left;
+    height = obj1->region.box.bottom - obj1->region.box.top;
+    image1 = XGetImage( XT_display, obj1->region.pixmap,
+		        0, 0, width, height, AllPlanes, ZPixmap );
+    if (!image1) return FALSE;
+    image2 = XGetImage( XT_display, obj2->region.pixmap,
+		        0, 0, width, height, AllPlanes, ZPixmap );
+    if (!image2)
+    {
+	XDestroyImage( image1 );
+	return FALSE;
+    }
+    
+      /* Compare pixmaps */
+    for (y = 0; y < height; y++)
+	for (x = 0; x < width; x++)
+	    if (XGetPixel( image1, x, y ) != XGetPixel( image2, x, y))
+	    {
+		XDestroyImage( image1 );
+		XDestroyImage( image2 );
+		return FALSE;
+	    }
+    
+    XDestroyImage( image1 );
+    XDestroyImage( image2 );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           REGION_CopyIntersection
+ *
+ * Copy to dest->pixmap the area of src->pixmap delimited by
+ * the intersection of dest and src regions, using the current GC function.
+ */
+void REGION_CopyIntersection( REGION * dest, REGION * src )
+{
+    RECT inter;
+    if (!IntersectRect( &inter, &dest->box, &src->box )) return;
+    XCopyArea( XT_display, src->pixmap, dest->pixmap, regionGC,
+	       inter.left - src->box.left, inter.top - src->box.top,
+	       inter.right - inter.left, inter.bottom - inter.top,
+	       inter.left - dest->box.left, inter.top - dest->box.top );
+}
+
+
+/***********************************************************************
+ *           CombineRgn    (GDI.451)
+ */
+int CombineRgn( HRGN hDest, HRGN hSrc1, HRGN hSrc2, short mode )
+{
+    RGNOBJ *destObj, *src1Obj, *src2Obj;
+    REGION * region;
+    int width, height;
+    BOOL res;
+    
+#ifdef DEBUG_REGION
+    printf( "CombineRgn: %d %d %d %d\n", hDest, hSrc1, hSrc2, mode );
+#endif
+    
+    if (!(destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC )))
+	return ERROR;
+    if (!(src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC )))
+	return ERROR;
+    if (mode != RGN_COPY)
+	if (!(src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC )))
+	    return ERROR;
+    region = &destObj->region;
+
+    switch(mode)
+    {
+      case RGN_AND:
+	res = IntersectRect( &region->box, &src1Obj->region.box,
+			     &src2Obj->region.box );
+	break;
+
+      case RGN_OR:
+      case RGN_XOR:
+	res = UnionRect( &region->box, &src1Obj->region.box,
+			 &src2Obj->region.box );
+	break;
+
+      case RGN_DIFF:
+	res = SubtractRect( &region->box, &src1Obj->region.box,
+			    &src2Obj->region.box );
+	break;
+
+      case RGN_COPY:
+	region->box  = src1Obj->region.box;
+	region->type = src1Obj->region.type;
+	res = (region->type != NULLREGION);
+	break;
+
+      default:
+	return ERROR;
+    }
+
+    if (region->pixmap) XFreePixmap( XT_display, region->pixmap );    
+    if (!res)
+    {
+	region->type   = NULLREGION;
+	region->pixmap = 0;
+	return NULLREGION;
+    }
+    
+    width  = region->box.right - region->box.left;
+    height = region->box.bottom - region->box.top;
+    region->pixmap = XCreatePixmap( XT_display, DefaultRootWindow(XT_display),
+				    width, height, 1 );
+
+    switch(mode)
+    {
+      case RGN_AND:
+	  XSetFunction( XT_display, regionGC, GXcopy );
+	  REGION_CopyIntersection( region, &src1Obj->region );
+	  XSetFunction( XT_display, regionGC, GXand );
+	  REGION_CopyIntersection( region, &src2Obj->region );
+	  return COMPLEXREGION;
+
+      case RGN_OR:
+      case RGN_XOR:
+	  XSetFunction( XT_display, regionGC, GXclear );
+	  XFillRectangle( XT_display, region->pixmap, regionGC,
+			  0, 0, width, height );
+	  XSetFunction( XT_display, regionGC, (mode == RGN_OR) ? GXor : GXxor);
+	  REGION_CopyIntersection( region, &src1Obj->region );
+	  REGION_CopyIntersection( region, &src2Obj->region );
+	  return COMPLEXREGION;
+	  
+      case RGN_DIFF:
+	  XSetFunction( XT_display, regionGC, GXclear );
+	  XFillRectangle( XT_display, region->pixmap, regionGC,
+			  0, 0, width, height );
+	  XSetFunction( XT_display, regionGC, GXcopy );
+	  REGION_CopyIntersection( region, &src1Obj->region );
+	  XSetFunction( XT_display, regionGC, GXandInverted );
+	  REGION_CopyIntersection( region, &src2Obj->region );
+	  return COMPLEXREGION;
+	  
+      case RGN_COPY:
+	  XSetFunction( XT_display, regionGC, GXcopy );
+	  XCopyArea( XT_display, src1Obj->region.pixmap, region->pixmap,
+		     regionGC, 0, 0, width, height, 0, 0 );
+	  return region->type;
+    }
+    return ERROR;
+}
diff --git a/objects/text.c b/objects/text.c
new file mode 100644
index 0000000..43b095a
--- /dev/null
+++ b/objects/text.c
@@ -0,0 +1,168 @@
+/*
+ * text functions
+ *
+ * Copyright 1993 Alexandre Julliard
+ */
+
+static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Core.h>
+#include <X11/Shell.h>
+#include <X11/Xatom.h>
+
+#include "message.h"
+#include "callback.h"
+#include "win.h"
+#include "gdi.h"
+
+
+/***********************************************************************
+ *           DrawText    (USER.85)
+ */
+int DrawText( HDC hdc, LPSTR str, int count, LPRECT rect, WORD flags )
+{
+    int x = rect->left, y = rect->top;
+    if (flags & DT_CENTER) x = (rect->left + rect->right) / 2;
+    if (flags & DT_VCENTER) y = (rect->top + rect->bottom) / 2;
+    if (count == -1) count = strlen(str);
+
+    if (!TextOut( hdc, x, y, str, count )) return 0;
+    return 1;
+}
+
+
+/***********************************************************************
+ *           TextOut    (GDI.33)
+ */
+BOOL TextOut( HDC hdc, short x, short y, LPSTR str, short count )
+{
+    int dir, ascent, descent, i;
+    XCharStruct info;
+    XFontStruct *font;
+
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return FALSE;
+    if (!DC_SetupGCForText( dc )) return TRUE;
+    font = dc->u.x.font.fstruct;
+
+    if (dc->w.textAlign & TA_UPDATECP)
+    {
+	x = dc->w.CursPosX;
+	y = dc->w.CursPosY;
+    }
+#ifdef DEBUG_TEXT
+    printf( "TextOut: %d,%d '%s'\n", x, y, str );
+#endif
+    x = XLPTODP( dc, x );
+    y = YLPTODP( dc, y );
+
+    XTextExtents( font, str, count, &dir, &ascent, &descent, &info );
+    info.width += count*dc->w.charExtra + dc->w.breakExtra*dc->w.breakCount;
+
+      /* Compute starting position */
+
+    switch( dc->w.textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) )
+    {
+      case TA_LEFT:
+ 	  if (dc->w.textAlign & TA_UPDATECP)
+	      dc->w.CursPosX = XDPTOLP( dc, x + info.width );
+	  break;
+      case TA_RIGHT:
+	  x -= info.width;
+	  if (dc->w.textAlign & TA_UPDATECP) dc->w.CursPosX = XDPTOLP( dc, x );
+	  break;
+      case TA_CENTER:
+	  x -= info.width / 2;
+	  break;
+    }
+    switch( dc->w.textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
+    {
+      case TA_TOP:
+	  y += font->ascent;
+	  break;
+      case TA_BOTTOM:
+	  y -= font->descent;
+	  break;
+      case TA_BASELINE:
+	  break;
+    }
+
+      /* Draw text */
+
+    if (!dc->w.charExtra && !dc->w.breakExtra)
+    {
+	if (dc->w.backgroundMode == TRANSPARENT)
+	    XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc, 
+			 x, y, str, count );
+	else
+	    XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc,
+			      x, y, str, count );
+    }
+    else
+    {
+	char * p = str;
+	int xchar = x;
+	for (i = 0; i < count; i++, p++)
+	{
+	    XCharStruct * charStr;
+	    unsigned char ch = *p;
+	    int extraWidth;
+	    
+	    if ((ch < font->min_char_or_byte2)||(ch > font->max_char_or_byte2))
+		ch = font->default_char;
+	    if (!font->per_char) charStr = &font->min_bounds;
+	    else charStr = font->per_char + ch - font->min_char_or_byte2;
+
+	    extraWidth = dc->w.charExtra;
+	    if (ch == dc->u.x.font.metrics.tmBreakChar)
+		extraWidth += dc->w.breakExtra;
+
+	    if (dc->w.backgroundMode == TRANSPARENT)
+		XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc,
+			     xchar, y, p, 1 );
+	    else
+	    {
+		XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc,
+				  xchar, y, p, 1 );
+		XSetForeground( XT_display, dc->u.x.gc, dc->w.backgroundPixel);
+		XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc,
+			        xchar + charStr->width, y - font->ascent,
+			        extraWidth, font->ascent + font->descent );
+		XSetForeground( XT_display, dc->u.x.gc, dc->w.textPixel );
+	    }
+	    xchar += charStr->width + extraWidth;
+	}
+    }
+
+      /* Draw underline and strike-out if needed */
+
+    if (dc->u.x.font.metrics.tmUnderlined)
+    {
+	long linePos, lineWidth;       
+	if (!XGetFontProperty( font, XA_UNDERLINE_POSITION, &linePos ))
+	    linePos = font->descent-1;
+	if (!XGetFontProperty( font, XA_UNDERLINE_THICKNESS, &lineWidth ))
+	    lineWidth = 0;
+	else if (lineWidth == 1) lineWidth = 0;
+	XSetLineAttributes( XT_display, dc->u.x.gc, lineWidth,
+			    LineSolid, CapRound, JoinBevel ); 
+	XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc,
+		   x, y + linePos, x + info.width, y + linePos );
+    }
+    if (dc->u.x.font.metrics.tmStruckOut)
+    {
+	long lineAscent, lineDescent;
+	if (!XGetFontProperty( font, XA_STRIKEOUT_ASCENT, &lineAscent ))
+	    lineAscent = font->ascent / 3;
+	if (!XGetFontProperty( font, XA_STRIKEOUT_DESCENT, &lineDescent ))
+	    lineDescent = -lineAscent;
+	XSetLineAttributes( XT_display, dc->u.x.gc, lineAscent + lineDescent,
+			    LineSolid, CapRound, JoinBevel ); 
+	XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc,
+		   x, y - lineAscent, x + info.width, y - lineAscent );
+    }
+    
+    return TRUE;
+}