Release 980201

Sun Feb  1 13:24:54 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [files/drive.c]
	Added Device= parameter to drive configuration.

	* [if1632/relay.c]
	Throw() and Catch() now use the correct CATCHBUF layout (untested).

	* [tools/build.c] [include/stackframe.h] [loader/task.c]
	Moved 16-bit stack pointer into thread database.
	Save current %fs while running 16-bit code.

Fri Jan 30 09:25:49 1998  Martin Boehme  <boehme@informatik.mu-luebeck.de>

	* [graphics/mapping.c]
	Made DPtoLP32 and LPtoDP32 respect world transforms.

	* [graphics/path.c] [graphics/painting.c] [if1632/gdi.spec]
	  [include/path.h]
	More path support.

	* [include/gdi.h] [include/windows.h] [objects/dc.c]
	  [relay/gdi32.spec]
	Support for Get/SetArcDirection and Get/SetWorldTransform

	* [windows/hook.c]
	Fixed a bug in HOOK_Map16To32Common.

Thu Jan 29 23:43:18 1998  Douglas Ridgway <ridgway@taiga.gmcl.com>

	* [graphics/metafiledrv/init.c] [objects/metafile.c]
	Documentation for metafile related API calls. Fixed a bug to avoid
	documenting it.

	* [include/windows.h]
	Declaration for LoadImage.

Thu Jan 29 21:44:45 1998  Huw D M Davies <h.davies1@physics.oxford.ac.uk>

	* [graphics/win16drv/*]
	Changes to printing code to enable use of printer fonts with the
	win3.1 postscript driver. Remember to add printer=on to [wine]
	section of wine.conf . You will also need to disable truetype
	fonts from control panel. Winword 6.0 and Write seem to be happy
	with this...

	* [include/bitmap.h]
	Fix Widthbytes for 15bpp displays.

Tue Jan 27 20:54:08 1998  Kristian Nielsen <kristian.nielsen@risoe.dk>

	* [tsx11/*] [include/ts*] [tools/make_X11wrappers]
	Implemented thread-safe X11 wrappers.

Tue Jan 27 13:54:09 1998  Constantine Sapuntzakis  <csapuntz@tma-1.lcs.mit.edu>

	* [windows/queue.c]
	Forgot to convert thdb to thread_id.

	* [misc/registry.c]
	Sped up Windows 95 registry reading. Changed code to traverse
	registry as a tree rather than read in all possible keys
	(including dead ones). 

Tue Jan 27 12:46:09 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [loader/pe_image.c][Makefile.in][scheduler/thread.c]
	  [libtest/hello5.c]
	Don't exit() on failed to load referenced dlls.
	Fixed static tls allocation for multiple threads.
	WINELIB should now be able to load PE dlls. A sample
	winelib program, that dynamically loads a internal dll
	is included.

	* [graphics/ddraw.c][include/ddraw.h][include/d3d.h]
	Cleaned up and enhanced further. Added several DirectX5
	interface definitions and DirectSurface3 implementation.
	Stubs for D3D (NOT coming soon, just there so it fails safely).

	* [multimedia/dsound.c][include/dsound.h]
	Actually works now for a lot of cases. Some DirectX5 stuff
	added. Still lacking several features.

	* [windows/dinput.c][include/dinput.h]
	Started implementing DirectInput. Doesn't work yet, don't 
	know why.

	* [if1632/thunk.c][misc/callbacks.c]
	  [win32/kernel.c][include/callbacks.h]
	Added WOWCallback16Ex, WOWHandle32.

	* [misc/cpu.c]
	Fixed GetSystemInfo, IsProcessorFeaturePresent.

	* [multimedia/joystick.c][multimedia/time.c]
	Several fixes. Small hack to get timerevents in timeGetTime() loops.

Tue Jan 20 11:26:27 1998  Slaven Rezic  <eserte@cs.tu-berlin.de>

	* [configure.in]
	Fixed check for union semun on FreeBSD systems.

Sun Jan 18 23:05:04 1998  Karl Backström <karl_b@geocities.com>

	* [misc/ole2nls.c] [programs/progman/Sw.rc] [programs/winhelp/Sw.rc]
	  [resources/sysres_Sw.rc]
	Added/updated Swedish language support.

Sun Jan 18 18:49:01 1998  Alex Korobka <alex@trantor.pharm.sunysb.edu>

	* [misc/winsock.c] [misc/winsock_dns.c] [windows/event.c]
	  [windows/win.c] [windows/dce.c] [windows/winpos.c]
	Bug fixes.

Sun Jan 18 12:45:23 1997  Andreas Mohr <100.30936@germany.net>

	* [msdos/int25.c] [msdos/int26.c]
        Implemented "native" absolute disk read/write access.

	* [msdos/int13.c] [msdos/ioports.c]
	Enhanced GET DRIVE PARAMETERS (int13 AH=08).

	* [graphics/win16drv/prtdrv.c] [if1632/gdi.spec]
	Fixed typos, implemented dmEnumDFonts,
	Started implementation of dmRealizeObject.

	* [if1632/compobj.spec] [ole/compobj.c] [relay32/ole32.spec]
	Stubs CoCreateInstance, CoFreeUnusedLibraries, implemented
	CoFileTimeNow.

	* [if1632/kernel.spec] [include/windows.h] [memory/global.c]
	  [memory/string.c] [misc/kernel.c] [misc/Makefile.in]
	  [misc/toolhelp.c] [msdos/int21.c]
	Implemented GlobalHandleNoRIP, GetFreeMemInfo, DebugFillBuffer, 
	stubs GetSetKernelDOSProc, DiagQuery, DiagOutput, ToolHelpHook
	(Undocumented Windows).

	* [if1632/user.spec] [if1632/win32s16.spec] [misc/win32s16.c]
	Misc stubs.

	* [if1632/winaspi.spec] [misc/aspi.c]
	Implemented GetASPIDLLVersion.

	* [if1632/wprocs.spec] [msdos/int20.c] [msdos/Makefile.in]
	Added handler for Int 0x20 (terminate program, _very_ old-fashioned).

	* [misc/w32scomb.c]
	Implemented Get16DLLAddress() partially
	(big thanks to Marcus and Alexandre).

	* [relay32/Makefile.in] [relay32/builtin32.c] [relay32/dplay.spec]
	Added built-in DPLAY.DLL.

	* [relay32/winmm.spec] [multimedia/joystick.c]
	Added joySetThreshold.

	* [misc/windebug.c]
	Added WinNotify.

	* [win32/console.c]
	Stubs CreateConsoleScreenBuffer, SetConsoleActiveScreenBuffer,
	WriteConsoleOutput32A.

	* [windows/user.c]
	Stub SetEventHook.

Sat Jan 17 19:30:35 1998  Matthew Toseland  <Paul.Toseland@btinternet.com>

	* [windows/painting.c]
	Fixed broken restore-to-maximized.

Mon Jan 12 21:25:32 1998  Perceval - Marc Huguet Puig <mhp@tinet.fut.es>

	* [documentation/wine.man] [include/options.h]
	  [misc/main.c] [ole/ole2nls.c] [resources/sysres.c]
	  [resources/sysres_Ca.rc] [resources/Makefile.in]
	Added language catalan. (Afegit l'idioma catalĂ ).
diff --git a/graphics/path.c b/graphics/path.c
index e4e4013..d53acd9 100644
--- a/graphics/path.c
+++ b/graphics/path.c
@@ -1,11 +1,12 @@
 /*
  * Graphics paths (BeginPath, EndPath etc.)
  *
- * Copyright 1997 Martin Boehme
+ * Copyright 1997, 1998 Martin Boehme
  */
 
 #include <assert.h>
 #include <malloc.h>
+#include <math.h>
 
 #include "windows.h"
 #include "winerror.h"
@@ -64,6 +65,22 @@
 static BOOL32 PATH_AddEntry(GdiPath *pPath, POINT32 point, BYTE flags);
 static BOOL32 PATH_ReserveEntries(GdiPath *pPath, INT32 numEntries);
 static BOOL32 PATH_GetPathFromHDC(HDC32 hdc, GdiPath **ppPath);
+static BOOL32 PATH_DoArcPart(GdiPath *pPath, POINT32 corners[],
+   double angleStart, double angleEnd, BOOL32 addMoveTo);
+static void PATH_ScaleNormalizedPoint(POINT32 corners[], double x, double y,
+   POINT32 *pPoint);
+static void PATH_NormalizePoint(POINT32 corners[], const POINT32 *pPoint,
+   double *pX, double *pY);
+
+
+/***********************************************************************
+ *           BeginPath16    (GDI.512)
+ */
+BOOL16 WINAPI BeginPath16(HDC16 hdc)
+{
+   return (BOOL16)BeginPath32((HDC32)hdc);
+}
+
 
 /***********************************************************************
  *           BeginPath32    (GDI32.9)
@@ -95,6 +112,15 @@
 
 
 /***********************************************************************
+ *           EndPath16    (GDI.514)
+ */
+BOOL16 WINAPI EndPath16(HDC16 hdc)
+{
+   return (BOOL16)EndPath32((HDC32)hdc);
+}
+
+
+/***********************************************************************
  *           EndPath32    (GDI32.78)
  */
 BOOL32 WINAPI EndPath32(HDC32 hdc)
@@ -123,6 +149,15 @@
 
 
 /***********************************************************************
+ *           AbortPath16    (GDI.511)
+ */
+BOOL16 WINAPI AbortPath16(HDC16 hdc)
+{
+   return (BOOL16)AbortPath32((HDC32)hdc);
+}
+
+
+/***********************************************************************
  *           AbortPath32    (GDI32.1)
  */
 BOOL32 WINAPI AbortPath32(HDC32 hdc)
@@ -145,6 +180,15 @@
 
 
 /***********************************************************************
+ *           CloseFigure16    (GDI.513)
+ */
+BOOL16 WINAPI CloseFigure16(HDC16 hdc)
+{
+   return (BOOL16)CloseFigure32((HDC32)hdc);
+}
+
+
+/***********************************************************************
  *           CloseFigure32    (GDI32.16)
  */
 BOOL32 WINAPI CloseFigure32(HDC32 hdc)
@@ -178,13 +222,25 @@
 
 
 /***********************************************************************
+ *           GetPath16    (GDI.517)
+ */
+INT16 WINAPI GetPath16(HDC16 hdc, LPPOINT16 pPoints, LPBYTE pTypes,
+   INT16 nSize)
+{
+   /* FIXME: Not implemented */
+   fprintf(stdnimp, "GetPath16: Unimplemented stub\n");
+
+   return 0;
+}
+
+
+/***********************************************************************
  *           GetPath32    (GDI32.210)
  */
 INT32 WINAPI GetPath32(HDC32 hdc, LPPOINT32 pPoints, LPBYTE pTypes,
    INT32 nSize)
 {
    GdiPath *pPath;
-   BOOL32  temp_flag;
    
    /* Get pointer to path */
    if(!PATH_GetPathFromHDC(hdc, &pPath))
@@ -213,10 +269,12 @@
       memcpy(pTypes, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
 
       /* Convert the points to logical coordinates */
-      temp_flag=DPtoLP32(hdc, pPoints, pPath->numEntriesUsed);
-
-      /* Since hdc is valid, conversion should never fail */
-      assert(temp_flag);
+      if(!DPtoLP32(hdc, pPoints, pPath->numEntriesUsed))
+      {
+	 /* FIXME: Is this the correct value? */
+         SetLastError(ERROR_CAN_NOT_COMPLETE);
+         return -1;
+      }
       
       return pPath->numEntriesUsed;
    }
@@ -266,8 +324,9 @@
 /* FIXME: Check that SetLastError is being called correctly */
 {
    GdiPath *pPath;
-   INT32   mapMode;
+   INT32   mapMode, graphicsMode;
    POINT32 ptViewportExt, ptViewportOrg, ptWindowExt, ptWindowOrg;
+   XFORM   xform;
    HRGN32  hrgn;
    
    /* Get pointer to path */
@@ -290,6 +349,9 @@
       /* Since PaintRgn interprets the region as being in logical coordinates
        * but the points we store for the path are already in device
        * coordinates, we have to set the mapping mode to MM_TEXT temporarily.
+       * Using SaveDC to save information about the mapping mode / world
+       * transform would be easier but would require more overhead, especially
+       * now that SaveDC saves the current path.
        */
        
       /* Save the information about the old mapping mode */
@@ -299,13 +361,14 @@
       GetWindowExtEx32(hdc, &ptWindowExt);
       GetWindowOrgEx32(hdc, &ptWindowOrg);
       
-      /* FIXME: Once world transforms become available, we will have to do
-       * a GetWorldTransform, too (along with a SetWorldTransform later on).
-       * Moral: Perhaps I should have used SaveDC right away. The reason why
-       * I didn't is that I wanted to avoid the overhead of a full SaveDC
-       * (especially since SaveDC now saves the current path as well).
+      /* Save world transform
+       * NB: The Windows documentation on world transforms would lead one to
+       * believe that this has to be done only in GM_ADVANCED; however, my
+       * tests show that resetting the graphics mode to GM_COMPATIBLE does
+       * not reset the world transform.
        */
-
+      GetWorldTransform(hdc, &xform);
+      
       /* Set MM_TEXT */
       SetMapMode32(hdc, MM_TEXT);
       
@@ -319,6 +382,12 @@
       SetWindowExtEx32(hdc, ptWindowExt.x, ptWindowExt.y, NULL);
       SetWindowOrgEx32(hdc, ptWindowOrg.x, ptWindowOrg.y, NULL);
 
+      /* Go to GM_ADVANCED temporarily to restore the world transform */
+      graphicsMode=GetGraphicsMode(hdc);
+      SetGraphicsMode(hdc, GM_ADVANCED);
+      SetWorldTransform(hdc, &xform);
+      SetGraphicsMode(hdc, graphicsMode);
+
       /* Empty the path */
       PATH_EmptyPath(pPath);
       return TRUE;
@@ -335,12 +404,12 @@
 /***********************************************************************
  *           SelectClipPath32    (GDI32.296)
  */
-BOOL32 WINAPI SelectClipPath32(HDC32 hdc, int iMode)
+BOOL32 WINAPI SelectClipPath32(HDC32 hdc, INT32 iMode)
 /* FIXME: Check that SetLastError is being called correctly */
 {
    GdiPath *pPath;
    HRGN32  hrgnPath, hrgnClip;
-   BOOL32  success = FALSE;
+   BOOL32  success;
    
    /* Get pointer to path */
    if(!PATH_GetPathFromHDC(hdc, &pPath))
@@ -360,7 +429,9 @@
    if(PATH_PathToRegion(pPath, GetPolyFillMode32(hdc), &hrgnPath))
    {
       hrgnClip=CreateRectRgn32(0, 0, 0, 0);
-      if(hrgnClip!=NULL)
+      if(hrgnClip==NULL)
+         success=FALSE;
+      else
       {
          success=(GetClipRgn32(hdc, hrgnClip)!=-1) &&
 	    (CombineRgn32(hrgnClip, hrgnClip, hrgnPath, iMode)!=ERROR) &&
@@ -510,6 +581,152 @@
    return PATH_AddEntry(pPath, point, PT_LINETO);
 }
 
+/* PATH_Ellipse
+ * 
+ * Should be called when a call to Ellipse is performed on a DC that has
+ * an open path. This adds four Bezier splines representing the ellipse
+ * to the path. Returns TRUE if successful, else FALSE.
+ */
+BOOL32 PATH_Ellipse(HDC32 hdc, INT32 x1, INT32 y1, INT32 x2, INT32 y2)
+{
+   return PATH_Arc(hdc, x1, y1, x2, y2, x1, 0, x1, 0);
+}
+
+/* PATH_Arc
+ *
+ * Should be called when a call to Arc is performed on a DC that has
+ * an open path. This adds up to five Bezier splines representing the arc
+ * to the path. Returns TRUE if successful, else FALSE.
+ */
+BOOL32 PATH_Arc(HDC32 hdc, INT32 x1, INT32 y1, INT32 x2, INT32 y2,
+   INT32 xStart, INT32 yStart, INT32 xEnd, INT32 yEnd)
+{
+   GdiPath *pPath;
+   double  angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
+           /* Initialize angleEndQuadrant to silence gcc's warning */
+   double  x, y;
+   POINT32 corners[2], pointStart, pointEnd;
+   BOOL32  start, end;
+   INT32   temp;
+
+   /* FIXME: This function should check for all possible error returns */
+   
+   /* Get pointer to path */
+   if(!PATH_GetPathFromHDC(hdc, &pPath))
+      return FALSE;
+   
+   /* Check that path is open */
+   if(pPath->state!=PATH_Open)
+      return FALSE;
+
+   /* Check for zero height / width */
+   /* FIXME: Should we do this before or after LPtoDP? */
+   if(x1==x2 || y1==y2)
+      return TRUE;
+   
+   /* In GM_COMPATIBLE, don't include bottom and right edges */
+   if(GetGraphicsMode(hdc)==GM_COMPATIBLE)
+   {
+      /* FIXME: Should we do this before or after LPtoDP? */
+      x2--;
+      y2--;
+   }
+
+   /* Convert points to device coordinates */
+   corners[0].x=x1;
+   corners[0].y=y1;
+   corners[1].x=x2;
+   corners[1].y=y2;
+   pointStart.x=xStart;
+   pointStart.y=yStart;
+   pointEnd.x=xEnd;
+   pointEnd.y=yEnd;
+   if(!LPtoDP32(hdc, corners, 2) || !LPtoDP32(hdc, &pointStart, 1) ||
+      !LPtoDP32(hdc, &pointEnd, 1))
+      return FALSE;
+
+   /* Make sure first corner is top left and right corner is bottom right */
+   /* FIXME: Should we do this before or after LPtoDP? */
+   if(corners[0].x>corners[1].x)
+   {
+      temp=corners[0].x;
+      corners[0].x=corners[1].x;
+      corners[1].x=temp;
+   }
+   if(corners[0].y>corners[1].y)
+   {
+      temp=corners[0].y;
+      corners[0].y=corners[1].y;
+      corners[1].y=temp;
+   }
+
+   /* Compute start and end angle */
+   PATH_NormalizePoint(corners, &pointStart, &x, &y);
+   angleStart=atan2(y, x);
+   PATH_NormalizePoint(corners, &pointEnd, &x, &y);
+   angleEnd=atan2(y, x);
+
+   /* Make sure the end angle is "on the right side" of the start angle */
+   if(GetArcDirection32(hdc)==AD_CLOCKWISE)
+   {
+      if(angleEnd<=angleStart)
+      {
+         angleEnd+=2*M_PI;
+	 assert(angleEnd>=angleStart);
+      }
+   }
+   else
+   {
+      if(angleEnd>=angleStart)
+      {
+         angleEnd-=2*M_PI;
+	 assert(angleEnd<=angleStart);
+      }
+   }
+
+   /* Add the arc to the path with one Bezier spline per quadrant that the
+    * arc spans */
+   start=TRUE;
+   end=FALSE;
+   do
+   {
+      /* Determine the start and end angles for this quadrant */
+      if(start)
+      {
+         angleStartQuadrant=angleStart;
+	 if(GetArcDirection32(hdc)==AD_CLOCKWISE)
+	    angleEndQuadrant=(floor(angleStart/M_PI_2)+1.0)*M_PI_2;
+	 else
+	    angleEndQuadrant=(ceil(angleStart/M_PI_2)-1.0)*M_PI_2;
+      }
+      else
+      {
+	 angleStartQuadrant=angleEndQuadrant;
+	 if(GetArcDirection32(hdc)==AD_CLOCKWISE)
+	    angleEndQuadrant+=M_PI_2;
+	 else
+	    angleEndQuadrant-=M_PI_2;
+      }
+
+      /* Have we reached the last part of the arc? */
+      if((GetArcDirection32(hdc)==AD_CLOCKWISE &&
+         angleEnd<=angleEndQuadrant) ||
+	 (GetArcDirection32(hdc)==AD_COUNTERCLOCKWISE &&
+	 angleEnd>=angleEndQuadrant))
+      {
+	 /* Adjust the end angle for this quadrant */
+         angleEndQuadrant=angleEnd;
+	 end=TRUE;
+      }
+
+      /* Add the Bezier spline to the path */
+      PATH_DoArcPart(pPath, corners, angleStartQuadrant, angleEndQuadrant,
+         start);
+      start=FALSE;
+   }  while(!end);
+
+   return TRUE;
+}
 
 /***********************************************************************
  * Internal functions
@@ -702,3 +919,85 @@
    else
       return FALSE;
 }
+
+/* PATH_DoArcPart
+ *
+ * Creates a Bezier spline that corresponds to part of an arc and appends the
+ * corresponding points to the path. The start and end angles are passed in
+ * "angleStart" and "angleEnd"; these angles should span a quarter circle
+ * at most. If "addMoveTo" is true, a PT_MOVETO entry for the first control
+ * point is added to the path; otherwise, it is assumed that the current
+ * position is equal to the first control point.
+ */
+static BOOL32 PATH_DoArcPart(GdiPath *pPath, POINT32 corners[],
+   double angleStart, double angleEnd, BOOL32 addMoveTo)
+{
+   double  halfAngle, a;
+   double  xNorm[4], yNorm[4];
+   POINT32 point;
+   int     i;
+
+   assert(fabs(angleEnd-angleStart)<=M_PI_2);
+
+   /* FIXME: Is there an easier way of computing this? */
+
+   /* Compute control points */
+   halfAngle=(angleEnd-angleStart)/2.0;
+   a=4.0/3.0*(1-cos(halfAngle))/sin(halfAngle);
+   xNorm[0]=cos(angleStart);
+   yNorm[0]=sin(angleStart);
+   xNorm[1]=xNorm[0] - a*yNorm[0];
+   yNorm[1]=yNorm[0] + a*xNorm[0];
+   xNorm[3]=cos(angleEnd);
+   yNorm[3]=sin(angleEnd);
+   xNorm[2]=xNorm[3] + a*yNorm[3];
+   yNorm[2]=yNorm[3] - a*xNorm[3];
+   
+   /* Add starting point to path if desired */
+   if(addMoveTo)
+   {
+      PATH_ScaleNormalizedPoint(corners, xNorm[0], yNorm[0], &point);
+      if(!PATH_AddEntry(pPath, point, PT_MOVETO))
+         return FALSE;
+   }
+
+   /* Add remaining control points */
+   for(i=1; i<4; i++)
+   {
+      PATH_ScaleNormalizedPoint(corners, xNorm[i], yNorm[i], &point);
+      if(!PATH_AddEntry(pPath, point, PT_BEZIERTO))
+         return FALSE;
+   }
+
+   return TRUE;
+}
+
+/* PATH_ScaleNormalizedPoint
+ *
+ * Scales a normalized point (x, y) with respect to the box whose corners are
+ * passed in "corners". The point is stored in "*pPoint". The normalized
+ * coordinates (-1.0, -1.0) correspond to corners[0], the coordinates
+ * (1.0, 1.0) correspond to corners[1].
+ */
+static void PATH_ScaleNormalizedPoint(POINT32 corners[], double x, double y,
+   POINT32 *pPoint)
+{
+   pPoint->x=(INT32)floor( (double)corners[0].x +
+      (double)(corners[1].x-corners[0].x)*0.5*(x+1.0) );
+   pPoint->y=(INT32)floor( (double)corners[0].y +
+      (double)(corners[1].y-corners[0].y)*0.5*(y+1.0) );
+}
+
+/* PATH_NormalizePoint
+ *
+ * Normalizes a point with respect to the box whose corners are passed in
+ * "corners". The normalized coordinates are stored in "*pX" and "*pY".
+ */
+static void PATH_NormalizePoint(POINT32 corners[], const POINT32 *pPoint,
+   double *pX, double *pY)
+{
+   *pX=(double)(pPoint->x-corners[0].x)/(double)(corners[1].x-corners[0].x) *
+      2.0 - 1.0;
+   *pY=(double)(pPoint->y-corners[0].y)/(double)(corners[1].y-corners[0].y) *
+      2.0 - 1.0;
+}