]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/dc.cpp
Replaced /'s with \'s as BCC requires \'s for path names
[wxWidgets.git] / src / os2 / dc.cpp
index 7b85941824dbeff829bde59609848c0bbd45eb7c..c0f1fefcd4c7e747bd837345e85cb19c04b8c93b 100644 (file)
@@ -22,6 +22,7 @@
     #include "wx/dcmemory.h"
     #include "wx/log.h"
     #include "wx/icon.h"
+    #include "wx/msgdlg.h"
 #endif
 
 #include "wx/dcprint.h"
 
     IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
 
+//
+// wxWindows uses the Microsoft convention that the origin is the UPPER left.
+// Native OS/2 however in the GPI and PM define the origin as the LOWER left.
+// In order to map OS/2 GPI/PM y coordinates to wxWindows coordinates we must
+// perform the following transformation:
+//
+// Parent object height:     POBJHEIGHT
+// Desried origin:           WXORIGINY
+// Object to place's height: OBJHEIGHT
+//
+// To get the OS2 position from the wxWindows one:
+//
+// OS2Y = POBJHEIGHT - (WXORIGINY + OBJHEIGHT)
+//
+// For OS/2 wxDC's we will always determine m_vRclPaint as the size of the
+// OS/2 Presentation Space associated with the device context.  y is the
+// desired application's y coordinate of the origin in wxWindows space.
+// objy is the height of the object we are going to draw.
+//
+#define OS2Y(y, objy) ((m_vRclPaint.yTop - m_vRclPaint.yBottom) - (y + objy))
+
 // ---------------------------------------------------------------------------
 // constants
 // ---------------------------------------------------------------------------
@@ -127,12 +149,200 @@ int SetBkMode(
 // implementation
 // ===========================================================================
 
+#if wxUSE_DC_CACHEING
+
+/*
+ * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
+ * improve it in due course, either using arrays, or simply storing pointers to one
+ * entry for the bitmap, and two for the DCs. -- JACS
+ */
+
+// ---------------------------------------------------------------------------
+// wxDCCacheEntry
+// ---------------------------------------------------------------------------
+
+wxList wxDC::m_svBitmapCache;
+wxList wxDC::m_svDCCache;
+
+wxDCCacheEntry::wxDCCacheEntry(
+  WXHBITMAP                         hBitmap
+, int                               nWidth
+, int                               nHeight
+, int                               nDepth
+)
+{
+    m_hBitmap = hBitmap;
+    m_hPS     = NULLHANDLE;
+    m_nWidth  = nWidth;
+    m_nHeight = nHeight;
+    m_nDepth  = nDepth;
+} // end of wxDCCacheEntry::wxDCCacheEntry
+
+wxDCCacheEntry::wxDCCacheEntry(
+  HPS                               hPS
+, int                               nDepth
+)
+{
+    m_hBitmap = NULLHANDLE;
+    m_hPS     = hPS;
+    m_nWidth  = 0;
+    m_nHeight = 0;
+    m_nDepth  = nDepth;
+} // end of wxDCCacheEntry::wxDCCacheEntry
+
+wxDCCacheEntry::~wxDCCacheEntry()
+{
+    if (m_hBitmap)
+        ::GpiDeleteBitmap(m_hBitmap);
+    if (m_hPS)
+        ::GpiDestroyPS(m_hPS);
+} // end of wxDCCacheEntry::~wxDCCacheEntry
+
+wxDCCacheEntry* wxDC::FindBitmapInCache(
+  HPS                               hPS
+, int                               nWidth
+, int                               nHeight
+)
+{
+    int                             nDepth = 24 // we'll fix this later ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
+    wxNode*                         pNode = m_svBitmapCache.First();
+    BITMAPINFOHEADER2               vBmpHdr;
+
+    while(pNode)
+    {
+        wxDCCacheEntry*             pEntry = (wxDCCacheEntry*)pNode->Data();
+
+        if (pEntry->m_nDepth == nDepth)
+        {
+            memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
+
+            if (pEntry->m_nWidth < nWidth || pEntry->m_nHeight < nHeight)
+            {
+                ::GpiDeleteBitmap((HBITMAP)pEntry->m_hBitmap);
+                vBmpHdr.cbFix     = sizeof(BITMAPINFOHEADER2);
+                vBmpHdr.cx        = nWidth;
+                vBmpHdr.cy        = nHeight;
+                vBmpHdr.cPlanes   = 1;
+                vBmpHdr.cBitCount = nDepth;
+
+                pEntry->m_hBitmap = (WXHBITMAP) ::GpiCreateBitmap( hPS
+                                                                  ,&vBmpHdr
+                                                                  ,0L, NULL, NULL
+                                                                 );
+                if (!pEntry->m_hBitmap)
+                {
+                    wxLogLastError(wxT("CreateCompatibleBitmap"));
+                }
+                pEntry->m_nWidth  = nWidth;
+                pEntry->m_nHeight = nHeight;
+                return pEntry;
+            }
+            return pEntry;
+        }
+        pNode = pNode->Next();
+    }
+    memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
+    vBmpHdr.cbFix     = sizeof(BITMAPINFOHEADER2);
+    vBmpHdr.cx        = nWidth;
+    vBmpHdr.cy        = nHeight;
+    vBmpHdr.cPlanes   = 1;
+    vBmpHdr.cBitCount = nDepth;
+
+    WXHBITMAP                       hBitmap = (WXHBITMAP) ::GpiCreateBitmap( hPS
+                                                                            ,&vBmpHdr
+                                                                            ,0L, NULL, NULL
+                                                                           );
+    if (!hBitmap)
+    {
+        wxLogLastError(wxT("CreateCompatibleBitmap"));
+    }
+    wxDCCacheEntry*                 pEntry = new wxDCCacheEntry( hBitmap
+                                                                ,nWidth
+                                                                ,nHeight
+                                                                ,nDepth
+                                                               );
+    AddToBitmapCache(pEntry);
+    return pEntry;
+} // end of FindBitmapInCache
+
+wxDCCacheEntry* wxDC::FindDCInCache(
+  wxDCCacheEntry*                   pNotThis
+, HPS                               hPS
+)
+{
+    int                             nDepth = 24; // we'll fix this up later ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
+    wxNode*                         pNode = m_svDCCache.First();
+
+    while(pNode)
+    {
+        wxDCCacheEntry*             pEntry = (wxDCCacheEntry*)pNode->Data();
+
+        //
+        // Don't return the same one as we already have
+        //
+        if (!pNotThis || (pNotThis != pEntry))
+        {
+            if (pEntry->m_nDepth == nDepth)
+            {
+                return pEntry;
+            }
+        }
+        pNode = pNode->Next();
+    }
+    wxDCCacheEntry*                 pEntry = new wxDCCacheEntry( hPS
+                                                                ,nDepth
+                                                               );
+    AddToDCCache(pEntry);
+    return pEntry;
+} // end of wxDC::FindDCInCache
+
+void wxDC::AddToBitmapCache(
+  wxDCCacheEntry*                   pEntry
+)
+{
+    m_svBitmapCache.Append(pEntry);
+} // end of wxDC::AddToBitmapCache
+
+void wxDC::AddToDCCache(
+  wxDCCacheEntry*                   pEntry
+)
+{
+    m_svDCCache.Append(pEntry);
+} // end of wxDC::AddToDCCache
+
+void wxDC::ClearCache()
+{
+    m_svBitmapCache.DeleteContents(TRUE);
+    m_svBitmapCache.Clear();
+    m_svBitmapCache.DeleteContents(FALSE);
+    m_svDCCache.DeleteContents(TRUE);
+    m_svDCCache.Clear();
+    m_svDCCache.DeleteContents(FALSE);
+} // end of wxDC::ClearCache
+
+// Clean up cache at app exit
+class wxDCModule : public wxModule
+{
+public:
+    virtual bool OnInit() { return TRUE; }
+    virtual void OnExit() { wxDC::ClearCache(); }
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxDCModule)
+}; // end of CLASS wxDCModule
+
+IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
+
+#endif // ndef for wxUSE_DC_CACHEING
+
 // ---------------------------------------------------------------------------
 // wxDC
 // ---------------------------------------------------------------------------
 
 wxDC::wxDC(void)
 {
+    wxColour                        vColor;
+
     m_pCanvas      = NULL;
 
     m_hOldBitmap   = 0;
@@ -143,16 +353,46 @@ wxDC::wxDC(void)
 
     m_bOwnsDC      = FALSE;
     m_hDC          = 0;
-    m_nDCCount     = 0;
     m_hOldPS       = NULL;
     m_hPS          = NULL;
     m_bIsPaintTime = FALSE; // True at Paint Time
-    m_brush.GetColour().Set("WHITE");
-}
+
+    vColor.InitFromName("BLACK");
+    m_pen.SetColour(vColor);
+    vColor.Set("WHITE");
+    m_brush.SetColour(vColor);
+} // end of wxDC::wxDC
 
 wxDC::~wxDC(void)
 {
-}
+    if ( m_hDC != 0 )
+    {
+        SelectOldObjects(m_hDC);
+
+        // if we own the HDC, we delete it, otherwise we just release it
+
+        if (m_bOwnsDC)
+        {
+            if(m_hPS)
+            {
+                ::GpiAssociate(m_hPS, NULLHANDLE);
+                ::GpiDestroyPS(m_hPS);
+            }
+            m_hPS = NULLHANDLE;
+            ::DevCloseDC((HDC)m_hDC);
+        }
+        else
+        {
+            //
+            // Just Dissacociate, not destroy if we don't own the DC
+            //
+            if(m_hPS)
+            {
+                ::GpiAssociate(m_hPS, NULLHANDLE);
+            }
+        }
+    }
+} // end of wxDC::~wxDC
 
 // This will select current objects out of the DC,
 // which is what you have to do before deleting the
@@ -187,7 +427,7 @@ void wxDC::SelectOldObjects(
     m_font            = wxNullFont;
     m_backgroundBrush = wxNullBrush;
     m_vSelectedBitmap = wxNullBitmap;
-}
+} // end of wxDC::SelectOldObjects
 
 // ---------------------------------------------------------------------------
 // clipping
@@ -206,19 +446,20 @@ void wxDC::SelectOldObjects(
 }
 
 void wxDC::DoSetClippingRegion(
-  wxCoord                           x
-, wxCoord                           y
-, wxCoord                           width
-, wxCoord                           height
+  wxCoord                           vX
+, wxCoord                           vY
+, wxCoord                           vWidth
+, wxCoord                           vHeight
 )
 {
     RECTL                           vRect;
 
+    vY = OS2Y(vY,vHeight);
     m_clipping    = TRUE;
-    vRect.xLeft   = XLOG2DEV(x);
-    vRect.yTop    = YLOG2DEV(m_vRclPaint.yTop - y);
-    vRect.xRight  = XLOG2DEV(x + width);
-    vRect.yBottom = YLOG2DEV(m_vRclPaint.yTop - (y + height));
+    vRect.xLeft   = vX;
+    vRect.yTop    = vY + vHeight;
+    vRect.xRight  = vX + vWidth;
+    vRect.yBottom = vY;
     ::GpiIntersectClipRectangle(m_hPS, &vRect);
     DO_SET_CLIPPING_BOX()
 } // end of wxDC::DoSetClippingRegion
@@ -301,7 +542,7 @@ int wxDC::GetDepth() const
 void wxDC::Clear()
 {
     ::GpiErase(m_hPS);
-}
+} // end of wxDC::Clear
 
 void wxDC::DoFloodFill(
   wxCoord                           vX
@@ -315,7 +556,7 @@ void wxDC::DoFloodFill(
     LONG                            lOptions;
 
     vPtlPos.x = vX;             // Loads x-coordinate
-    vPtlPos.y = vY;             // Loads y-coordinate
+    vPtlPos.y = OS2Y(vY,0);     // Loads y-coordinate
     ::GpiMove(m_hPS, &vPtlPos); // Sets current position
     lColor = rCol.GetPixel();
     lOptions = FF_BOUNDARY;
@@ -323,7 +564,7 @@ void wxDC::DoFloodFill(
         lOptions = FF_SURFACE;
 
     ::GpiFloodFill(m_hPS, lOptions, lColor);
-}
+} // end of wxDC::DoFloodFill
 
 bool wxDC::DoGetPixel(
   wxCoord                           vX
@@ -335,20 +576,37 @@ bool wxDC::DoGetPixel(
     LONG                            lColor;
 
     vPoint.x = vX;
-    vPoint.y = vY;
+    vPoint.y = OS2Y(vY,0);
     lColor = ::GpiSetPel(m_hPS, &vPoint);
-    pCol->Set((unsigned long)lColor);
-    if(lColor>= 0)
-        return(TRUE);
-    else
-        return(FALSE);
-}
+
+    //
+    // Get the color of the pen
+    //
+    LONG                            lPencolor = 0x00ffffff;
+
+    if (m_pen.Ok())
+    {
+        lPencolor = m_pen.GetColour().GetPixel();
+    }
+
+    //
+    // return the color of the pixel
+    //
+    if(pCol)
+        pCol->Set( GetRValue(lColor)
+                  ,GetGValue(lColor)
+                  ,GetBValue(lColor)
+                 );
+    return(lColor == lPencolor);
+} // end of wxDC::DoGetPixel
 
 void wxDC::DoCrossHair(
   wxCoord                           vX
 , wxCoord                           vY
 )
 {
+    vY = OS2Y(vY,0);
+
     wxCoord                         vX1 = vX - VIEWPORT_EXTENT;
     wxCoord                         vY1 = vY - VIEWPORT_EXTENT;
     wxCoord                         vX2 = vX + VIEWPORT_EXTENT;
@@ -356,22 +614,24 @@ void wxDC::DoCrossHair(
     POINTL                          vPoint[4];
 
     vPoint[0].x = vX1;
-    vPoint[0].y = m_vRclPaint.yTop - vY;
+    vPoint[0].y = vY;
 
     vPoint[1].x = vX2;
-    vPoint[1].y = m_vRclPaint.yTop - vY;
+    vPoint[1].y = vY;
 
     ::GpiMove(m_hPS, &vPoint[0]);
     ::GpiLine(m_hPS, &vPoint[1]);
 
     vPoint[2].x = vX;
-    vPoint[2].y = m_vRclPaint.yTop - vY1;
+    vPoint[2].y = vY1;
 
     vPoint[3].x = vX;
-    vPoint[3].y = m_vRclPaint.yTop - vY2;
+    vPoint[3].y = vY2;
 
     ::GpiMove(m_hPS, &vPoint[2]);
     ::GpiLine(m_hPS, &vPoint[3]);
+    CalcBoundingBox(vX1, vY1);
+    CalcBoundingBox(vX2, vY2);
 } // end of wxDC::DoCrossHair
 
 void wxDC::DoDrawLine(
@@ -383,12 +643,17 @@ void wxDC::DoDrawLine(
 {
     POINTL                          vPoint[2];
 
+    vY1 = OS2Y(vY1,0);
+    vY2 = OS2Y(vY2,0);
+
     vPoint[0].x = vX1;
-    vPoint[0].y = m_vRclPaint.yTop - vY1;
+    vPoint[0].y = vY1;
     vPoint[1].x = vX2;
-    vPoint[1].y = m_vRclPaint.yTop - vY2;
+    vPoint[1].y = vY2;
     ::GpiMove(m_hPS, &vPoint[0]);
     ::GpiLine(m_hPS, &vPoint[1]);
+    CalcBoundingBox(vX1, vY1);
+    CalcBoundingBox(vX2, vY2);
 } // end of wxDC::DoDrawLine
 
 //////////////////////////////////////////////////////////////////////////////
@@ -483,6 +748,12 @@ void wxDC::DoDrawArc(
     vPtlArc[1].x = vX2;
     vPtlArc[1].y = vY2;
     ::GpiPointArc(m_hPS, vPtlArc); // Draws the arc
+    CalcBoundingBox( (vXc - dRadius)
+                    ,(vYc - dRadius)
+                   );
+    CalcBoundingBox( (vXc + dRadius)
+                    ,(vYc + dRadius)
+                   );
 } // end of wxDC::DoDrawArc
 
 void wxDC::DoDrawCheckMark(
@@ -494,6 +765,8 @@ void wxDC::DoDrawCheckMark(
 {
     POINTL                          vPoint[2];
 
+    vY1 = OS2Y(vY1,vHeight);
+
     vPoint[0].x = vX1;
     vPoint[0].y = vY1;
     vPoint[1].x = vX1 + vWidth;
@@ -520,6 +793,16 @@ void wxDC::DoDrawCheckMark(
         ::GpiMove(m_hPS, &vPoint[0]);
         ::GpiLine(m_hPS, &vPoint[1]);
     }
+    CalcBoundingBox( vX1
+                    ,vY1
+                   );
+
+    wxCoord                         vX2 = vX1 + vWidth;
+    wxCoord                         vY2 = vY1 + vHeight;
+
+    CalcBoundingBox( vX2
+                    ,vY2
+                   );
 } // end of wxDC::DoDrawCheckMark
 
 void wxDC::DoDrawPoint(
@@ -528,10 +811,19 @@ void wxDC::DoDrawPoint(
 )
 {
     POINTL                          vPoint;
+    COLORREF                        vColor = 0x00ffffff;
 
+    if (m_pen.Ok())
+    {
+        vColor = m_pen.GetColour().GetPixel();
+    }
+    ::GpiSetColor(m_hPS, vColor);
     vPoint.x = vX;
-    vPoint.y = m_vRclPaint.yTop - vY;
+    vPoint.y = OS2Y(vY,0);
     ::GpiSetPel(m_hPS, &vPoint);
+    CalcBoundingBox( vX
+                    ,vY
+                   );
 } // end of wxDC::DoDrawPoint
 
 void wxDC::DoDrawPolygon(
@@ -588,8 +880,8 @@ void wxDC::DoDrawPolygon(
 
     for(i = 0; i < n; i++)
     {
-        vPlgn.aPointl[i].x = vPoints[i].x; // +xoffset;
-        vPlgn.aPointl[i].y = vPoints[i].y; // +yoffset;
+        vPlgn.aPointl[i].x = vPoints[i].x;         // +xoffset;
+        vPlgn.aPointl[i].y = OS2Y(vPoints[i].y,0); // +yoffset;
     }
     flModel = POLYGON_BOUNDARY;
     if(nFillStyle == wxWINDING_RULE)
@@ -598,7 +890,7 @@ void wxDC::DoDrawPolygon(
         flModel |= POLYGON_ALTERNATE;
 
     vPoint.x = vXoffset;
-    vPoint.y = vYoffset;
+    vPoint.y = OS2Y(vYoffset,0);
 
     ::GpiSetColor(m_hPS, lBorderColor);
     ::GpiMove(m_hPS, &vPoint);
@@ -613,21 +905,46 @@ void wxDC::DoDrawLines(
 , wxCoord                           vYoffset
 )
 {
-    int                             i;
     POINTL                          vPoint;
 
-    vPoint.x = vPoints[0].x + vXoffset;
-    vPoint.y = vPoints[0].y + vYoffset;
-    ::GpiMove(m_hPS, &vPoint);
+    if (vXoffset != 0L || vXoffset != 0L)
+    {
+        int                             i;
+
+        vPoint.x = vPoints[0].x + vXoffset;
+        vPoint.y = OS2Y(vPoints[0].y + vYoffset,0);
+        ::GpiMove(m_hPS, &vPoint);
 
-    LONG                            lBorderColor = m_pen.GetColour().GetPixel();
+        LONG                            lBorderColor = m_pen.GetColour().GetPixel();
 
-    ::GpiSetColor(m_hPS, lBorderColor);
-    for(i = 1; i < n; i++)
+        ::GpiSetColor(m_hPS, lBorderColor);
+        for(i = 1; i < n; i++)
+        {
+            vPoint.x = vPoints[i].x + vXoffset;
+            vPoint.y = OS2Y(vPoints[i].y + vYoffset,0);
+            ::GpiLine(m_hPS, &vPoint);
+        }
+    }
+    else
     {
-        vPoint.x = vPoints[0].x + vXoffset;
-        vPoint.y = vPoints[0].y + vYoffset;
-        ::GpiLine(m_hPS, &vPoint);
+        int                         i;
+
+        CalcBoundingBox( vPoints[i].x
+                        ,vPoints[i].y
+                       );
+        vPoint.x = vPoints[0].x;
+        vPoint.y = OS2Y(vPoints[0].y,0);
+        ::GpiMove(m_hPS, &vPoint);
+
+        for (i = 0; i < n; i++)
+        {
+            CalcBoundingBox( vPoints[i].x
+                            ,vPoints[i].y
+                           );
+            vPoint.x = vPoints[i].x;
+            vPoint.y = OS2Y(vPoints[i].y,0);
+            ::GpiLine(m_hPS, &vPoint);
+        }
     }
 } // end of wxDC::DoDrawLines
 
@@ -644,10 +961,15 @@ void wxDC::DoDrawRectangle(
     LONG                            lBorderColor;
     int                             nIsTRANSPARENT = 0;
 
+    vY = OS2Y(vY,vHeight);
+
+    wxCoord                         vX2 = vX + vWidth;
+    wxCoord                         vY2 = vY + vHeight;
+
     vPoint[0].x = vX;
-    vPoint[0].y = m_vRclPaint.yTop - (vY + vHeight);
+    vPoint[0].y = vY;
     vPoint[1].x = vX + vWidth;
-    vPoint[1].y = m_vRclPaint.yTop - vY;
+    vPoint[1].y = vY + vHeight;
     ::GpiMove(m_hPS, &vPoint[0]);
     lColor       = m_brush.GetColour().GetPixel();
     lBorderColor = m_pen.GetColour().GetPixel();
@@ -684,9 +1006,9 @@ void wxDC::DoDrawRectangle(
                       ,lColor
                      );
         vPoint[0].x = vX + 1;
-        vPoint[0].y = m_vRclPaint.yTop - (vY + vHeight) + 1;
-        vPoint[1].x = vX + vWidth - 2;
-        vPoint[1].y = m_vRclPaint.yTop - (vY + 2);
+        vPoint[0].y = vY + 1;
+        vPoint[1].x = vX + vWidth - 1;
+        vPoint[1].y = vY + vHeight - 1;
         ::GpiMove(m_hPS, &vPoint[0]);
         ::GpiBox( m_hPS
                  ,lControl
@@ -695,6 +1017,8 @@ void wxDC::DoDrawRectangle(
                  ,0L
                 );
     }
+    CalcBoundingBox(vX, vY);
+    CalcBoundingBox(vX2, vY2);
 } // end of wxDC::DoDrawRectangle
 
 void wxDC::DoDrawRoundedRectangle(
@@ -708,6 +1032,11 @@ void wxDC::DoDrawRoundedRectangle(
     POINTL                          vPoint[2];
     LONG                            lControl;
 
+    vY = OS2Y(vY,vHeight);
+
+    wxCoord                         vX2 = (vX + vWidth);
+    wxCoord                         vY2 = (vY + vHeight);
+
     vPoint[0].x = vX;
     vPoint[0].y = YLOG2DEV(vY) - vHeight;
     vPoint[1].x = vX + vWidth;
@@ -723,6 +1052,8 @@ void wxDC::DoDrawRoundedRectangle(
              ,(LONG)dRadius // horizontal corner radius
              ,(LONG)dRadius // vertical corner radius
             );
+    CalcBoundingBox(vX, vY);
+    CalcBoundingBox(vX2, vY2);
 } // end of wxDC::DoDrawRoundedRectangle
 
 // Draw Ellipse within box (x,y) - (x+width, y+height)
@@ -737,6 +1068,8 @@ void wxDC::DoDrawEllipse(
     FIXED                           vFxMult; // Multiplier for ellipse
     ARCPARAMS                       vArcp;   // Structure for arc parameters
 
+    vY = OS2Y(vY,vHeight);
+
     vArcp.lR = 0;
     vArcp.lQ = vHeight/2;
     vArcp.lP = vWidth/2;
@@ -758,6 +1091,12 @@ void wxDC::DoDrawEllipse(
                  ,DRO_OUTLINE
                  ,vFxMult
                 ); // Draws full arc with center at current position
+
+    wxCoord                         vX2 = (vX + vWidth);
+    wxCoord                         vY2 = (vY + vHeight);
+
+    CalcBoundingBox(vX, vY);
+    CalcBoundingBox(vX2, vY2);
 } // end of wxDC::DoDrawEllipse
 
 void wxDC::DoDrawEllipticArc(
@@ -778,6 +1117,8 @@ void wxDC::DoDrawEllipticArc(
     double                          dFractPart;
     double                          dRadius;
 
+    vY = OS2Y(vY,vHeight);
+
     dFractPart = modf(dSa,&dIntPart);
     vFSa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) );
     dFractPart = modf(dEa - dSa, &dIntPart);
@@ -811,6 +1152,11 @@ void wxDC::DoDrawEllipticArc(
                     ,vFSa
                     ,vFSweepa
                    );
+    wxCoord                         vX2 = (vX + vWidth);
+    wxCoord                         vY2 = (vY + vHeight);
+
+    CalcBoundingBox(vX, vY);
+    CalcBoundingBox(vX2, vY2);
 } // end of wxDC::DoDrawEllipticArc
 
 void wxDC::DoDrawIcon(
@@ -819,6 +1165,7 @@ void wxDC::DoDrawIcon(
 , wxCoord                           vY
 )
 {
+    vY = OS2Y(vY,rIcon.GetHeight());
     wxCHECK_RET( rIcon.Ok(), wxT("invalid icon in DrawIcon") );
 
     ::WinDrawPointer( GetHPS()
@@ -827,6 +1174,8 @@ void wxDC::DoDrawIcon(
                      ,(HPOINTER)GetHiconOf(rIcon)
                      ,DP_NORMAL
                     );
+    CalcBoundingBox(vX, vY);
+    CalcBoundingBox(vX + rIcon.GetWidth(), vY + rIcon.GetHeight());
 } // end of wxDC::DoDrawIcon
 
 void wxDC::DoDrawBitmap(
@@ -854,11 +1203,18 @@ void wxDC::DoDrawText(
 , wxCoord                           vY
 )
 {
+    wxCoord                         vWidth;
+    wxCoord                         vHeight;
+
     DrawAnyText( rsText
                 ,vX
                 ,vY
                );
-}
+
+    CalcBoundingBox(vX, vY);
+    GetTextExtent(rsText, &vWidth, &vHeight);
+    CalcBoundingBox((vX + vWidth), (vY + vHeight));
+} // end of wxDC::DoDrawText
 
 void wxDC::DrawAnyText(
   const wxString&                   rsText
@@ -869,6 +1225,8 @@ void wxDC::DrawAnyText(
     int                             nOldBackground = 0;
     POINTL                          vPtlStart;
     LONG                            lHits;
+    wxCoord                         vTextX = 0;
+    wxCoord                         vTextY = 0;
 
     //
     // prepare for drawing the text
@@ -893,8 +1251,12 @@ void wxDC::DrawAnyText(
     SetBkMode( m_hPS
               ,m_backgroundMode
              );
+    GetTextExtent( rsText
+                  ,&vTextX
+                  ,&vTextY
+                 );
     vPtlStart.x = vX;
-    vPtlStart.y = vY;
+    vPtlStart.y = OS2Y(vY,vTextY);
 
     lHits = ::GpiCharStringAt( m_hPS
                               ,&vPtlStart
@@ -991,10 +1353,26 @@ void wxDC::DoDrawRotatedText(
 // set GDI objects
 // ---------------------------------------------------------------------------
 
-void wxDC::SetPalette(const wxPalette& palette)
+void wxDC::SetPalette(
+  const wxPalette&                  rPalette
+)
 {
-   // TODO
-}
+    if (m_hOldFont)
+    {
+        m_hOldFont = 0;
+    }
+    m_palette = rPalette;
+    if (!rPalette.Ok())
+    {
+        if (m_hOldFont)
+        {
+            m_hOldFont = 0;
+        }
+    }
+    HPALETTE                    hOldPal = ::GpiSelectPalette((HDC) m_hPS, (HPALETTE) m_palette.GetHPALETTE());
+    if (!m_hOldPalette)
+        m_hOldPalette = (WXHPALETTE)hOldPal;
+} // end of wxDC::SetPalette
 
 void wxDC::SetFont(
   const wxFont&                     rFont
@@ -1070,15 +1448,15 @@ void wxDC::SetBrush(
 {
     wxCHECK_RET( Ok(), wxT("invalid window dc") );
 
-    if (m_brush == rBrush)
-        return;
-    m_brush = rBrush;
-    if (!m_brush.Ok())
-        return;
-
     if (m_hOldBrush)
         m_hOldBrush = 0L;
     m_brush = rBrush;
+    if (!m_brush.Ok())
+    if (m_brush == rBrush)
+        return;
+    if (!m_brush.Ok())
+        if (m_hOldBrush)
+            m_hOldBrush = 0L;
 
     if (!m_brush.Ok())
     {
@@ -1095,77 +1473,153 @@ void wxDC::SetBrush(
         {
             m_brush.SetPS(m_hPS);
             if (!m_hOldBrush)
-                m_hOldBrush = m_brush.GetPS();
+                m_hOldBrush = (WXHWND)m_brush.GetPS();
         }
     }
 } // end of wxDC::SetBrush
 
-void wxDC::SetBackground(const wxBrush& brush)
+void wxDC::SetBackground(
+  const wxBrush&                    rBrush
+)
 {
-   // TODO
-}
+    m_backgroundBrush = rBrush;
+    if (!m_backgroundBrush.Ok())
+        return;
+    if (m_pCanvas)
+    {
+        bool                        bCustomColours = TRUE;
+
+        //
+        // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
+        // change background colours from the control-panel specified colours.
+        //
+        if (m_pCanvas->IsKindOf(CLASSINFO(wxWindow)) &&
+            ((m_pCanvas->GetWindowStyleFlag() & wxUSER_COLOURS) != wxUSER_COLOURS))
+            bCustomColours = FALSE;
+        if (bCustomColours)
+        {
+            if (m_backgroundBrush.GetStyle()==wxTRANSPARENT)
+            {
+                m_pCanvas->SetTransparent(TRUE);
+            }
+            else
+            {
+                //
+                // Setting the background brush of a DC
+                // doesn't affect the window background colour. However,
+                // I'm leaving in the transparency setting because it's needed by
+                // various controls (e.g. wxStaticText) to determine whether to draw
+                // transparently or not. TODO: maybe this should be a new function
+                // wxWindow::SetTransparency(). Should that apply to the child itself, or the
+                // parent?
+                // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
+                //
+                m_pCanvas->SetTransparent(FALSE);
+            }
+        }
+    }
+    COLORREF                        vNewColor = m_backgroundBrush.GetColour().GetPixel();
+    (void)::GpiSetBackColor((HPS)m_hPS, (LONG)vNewColor);
+} // end of wxDC::SetBackground
 
 void wxDC::SetBackgroundMode(
   int                               nMode
 )
 {
     m_backgroundMode = nMode;
-}
+} // end of wxDC::SetBackgroundMode
 
-void wxDC::SetLogicalFunction(int function)
+void wxDC::SetLogicalFunction(
+  int                               nFunction
+)
 {
-   // TODO
-}
+    m_logicalFunction = nFunction;
+    SetRop((WXHDC)m_hDC);
+} // wxDC::SetLogicalFunction
 
-void wxDC::SetRop(WXHDC dc)
+void wxDC::SetRop(
+  WXHDC                             hDC
+)
 {
-    if (!dc || m_logicalFunction < 0)
+    if (!hDC || m_logicalFunction < 0)
         return;
 
-    int c_rop;
-    // These may be wrong
+    LONG                            lCRop;
     switch (m_logicalFunction)
     {
-// TODO: Figure this stuff out
-        //    case wxXOR: c_rop = R2_XORPEN; break;
-//    case wxXOR: c_rop = R2_NOTXORPEN; break;
-//    case wxINVERT: c_rop = R2_NOT; break;
-//    case wxOR_REVERSE: c_rop = R2_MERGEPENNOT; break;
-//    case wxAND_REVERSE: c_rop = R2_MASKPENNOT; break;
-//    case wxCLEAR: c_rop = R2_WHITE; break;
-//    case wxSET: c_rop = R2_BLACK; break;
-//    case wxSRC_INVERT: c_rop = R2_NOTCOPYPEN; break;
-//    case wxOR_INVERT: c_rop = R2_MERGENOTPEN; break;
-//    case wxAND: c_rop = R2_MASKPEN; break;
-//    case wxOR: c_rop = R2_MERGEPEN; break;
-//    case wxAND_INVERT: c_rop = R2_MASKNOTPEN; break;
-//    case wxEQUIV:
-//    case wxNAND:
-//    case wxCOPY:
-    default:
-//      c_rop = R2_COPYPEN;
-        break;
+        case wxXOR:
+            lCRop = FM_XOR;
+            break;
+
+        case wxINVERT:
+            lCRop = FM_INVERT;
+            break;
+
+        case wxOR_REVERSE:
+            lCRop = FM_MERGESRCNOT;
+            break;
+
+        case wxAND_REVERSE:
+            lCRop = FM_NOTMASKSRC;
+            break;
+
+        case wxCLEAR:
+            lCRop = FM_ONE;
+            break;
+
+        case wxSET:
+            lCRop = FM_ZERO;
+            break;
+
+        case wxSRC_INVERT:
+            lCRop = FM_MERGENOTSRC;
+            break;
+
+        case wxOR_INVERT:
+            lCRop = FM_MERGESRCNOT;
+            break;
+
+        case wxAND:
+            lCRop = FM_AND;
+            break;
+
+        case wxOR:
+            lCRop = FM_OR;
+            break;
+
+        case wxAND_INVERT:
+            lCRop = FM_SUBTRACT;
+            break;
+
+        case wxEQUIV:
+        case wxNAND:
+        case wxCOPY:
+        default:
+            lCRop = FM_OVERPAINT;
+            break;
     }
-//    SetROP2((HDC) dc, c_rop);
-}
+    ::GpiSetMix((HPS)hDC, lCRop);
+} // end of wxDC::SetRop
 
-bool wxDC::StartDoc(const wxString& message)
+bool wxDC::StartDoc(
+  const wxString&                   rsMessage
+)
 {
     // We might be previewing, so return TRUE to let it continue.
     return TRUE;
-}
+} // end of wxDC::StartDoc
 
 void wxDC::EndDoc()
 {
-}
+} // end of wxDC::EndDoc
 
 void wxDC::StartPage()
 {
-}
+} // end of wxDC::StartPage
 
 void wxDC::EndPage()
 {
-}
+} // end of wxDC::EndPage
 
 // ---------------------------------------------------------------------------
 // text metrics
@@ -1268,60 +1722,156 @@ void wxDC::DoGetTextExtent(
         *pvExternalLeading = vFM.lExternalLeading;
 }
 
-void wxDC::SetMapMode( int mode )
+void wxDC::SetMapMode(
+  int                               nMode
+)
 {
-    // TODO:
-};
+    int                             nPixelWidth = 0;
+    int                             nPixelHeight = 0;
+    int                             nMmWidth = 1;
+    int                             nMmHeight = 1;
+    LONG                            lArray[CAPS_VERTICAL_RESOLUTION];
+
+    m_mappingMode = nMode;
 
-void wxDC::SetUserScale(double x, double y)
+    if(::DevQueryCaps( m_hDC
+                      ,CAPS_FAMILY
+                      ,CAPS_VERTICAL_RESOLUTION
+                      ,lArray
+                     ))
+    {
+        LONG                        lHorzRes;
+        LONG                        lVertRes;
+
+        nPixelWidth    = lArray[CAPS_WIDTH];
+        nPixelHeight   = lArray[CAPS_HEIGHT];
+        lHorzRes  = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
+        lVertRes  = lArray[CAPS_VERTICAL_RESOLUTION];   // returns pel/meter
+        nMmWidth  = (lHorzRes/1000) * nPixelWidth;
+        nMmWidth = (lVertRes/1000) * nPixelHeight;
+    }
+    if ((nPixelWidth == 0) || (nPixelHeight == 0) || (nMmWidth == 0) || (nMmHeight == 0))
+    {
+        return;
+    }
+
+    double                          dMm2pixelsX = nPixelWidth/nMmWidth;
+    double                          dMm2pixelsY = nPixelHeight/nMmHeight;
+
+    switch (nMode)
+    {
+        case wxMM_TWIPS:
+            m_logicalScaleX = (twips2mm * dMm2pixelsX);
+            m_logicalScaleY = (twips2mm * dMm2pixelsY);
+            break;
+
+        case wxMM_POINTS:
+            m_logicalScaleX = (pt2mm * dMm2pixelsX);
+            m_logicalScaleY = (pt2mm * dMm2pixelsY);
+            break;
+
+        case wxMM_METRIC:
+            m_logicalScaleX = dMm2pixelsX;
+            m_logicalScaleY = dMm2pixelsY;
+            break;
+
+        case wxMM_LOMETRIC:
+            m_logicalScaleX = (dMm2pixelsX/10.0);
+            m_logicalScaleY = (dMm2pixelsY/10.0);
+            break;
+
+        case wxMM_TEXT:
+        default:
+            m_logicalScaleX = 1.0;
+            m_logicalScaleY = 1.0;
+            break;
+    }
+    SIZEL                           vSize;
+    ULONG                           ulOptions;
+
+    ulOptions = ::GpiQueryPS(m_hPS, &vSize);
+    if (!ulOptions & PU_ARBITRARY)
+    {
+        ulOptions = PU_ARBITRARY | GPIF_DEFAULT;
+        ::GpiSetPS(m_hPS, &vSize, ulOptions);
+    }
+    m_nWindowExtX = (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT);
+    m_nWindowExtY = (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT);
+    // ????
+}; // end of wxDC::SetMapMode
+
+void wxDC::SetUserScale(
+  double                            dX
+, double                            dY
+)
 {
-    m_userScaleX = x;
-    m_userScaleY = y;
+    m_userScaleX = dX;
+    m_userScaleY = dY;
 
     SetMapMode(m_mappingMode);
-}
+} // end of wxDC::SetUserScale
 
-void wxDC::SetAxisOrientation(bool xLeftRight, bool yBottomUp)
+void wxDC::SetAxisOrientation(
+  bool                              bXLeftRight
+, bool                              bYBottomUp
+)
 {
-    m_signX = xLeftRight ? 1 : -1;
-    m_signY = yBottomUp ? -1 : 1;
+    m_signX = bXLeftRight ? 1 : -1;
+    m_signY = bYBottomUp ? -1 : 1;
 
     SetMapMode(m_mappingMode);
-}
+} // end of wxDC::SetAxisOrientation
 
-void wxDC::SetSystemScale(double x, double y)
+void wxDC::SetSystemScale(
+  double                            dX
+, double                            dY
+)
 {
-    m_scaleX = x;
-    m_scaleY = y;
+    m_scaleX = dX;
+    m_scaleY = dY;
 
     SetMapMode(m_mappingMode);
-}
+} // end of wxDC::SetSystemScale
 
-void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
+void wxDC::SetLogicalOrigin(
+  wxCoord                           vX
+, wxCoord                           vY
+)
 {
-    // TODO:
-};
+    RECTL                           vRect;
+
+    ::GpiQueryPageViewport( m_hPS
+                           ,&vRect
+                          );
+    vRect.xRight -= vX;
+    vRect.yTop += vY;
+    vRect.xLeft = vX;
+    vRect.yBottom = vY;
+    ::GpiSetPageViewport( m_hPS
+                         ,&vRect
+                        );
+}; // end of wxDC::SetLogicalOrigin
 
 void wxDC::SetDeviceOrigin(
-  wxCoord                           x
-, wxCoord                           y
+  wxCoord                           vX
+, wxCoord                           vY
 )
 {
     RECTL                           vRect;
 
-    m_deviceOriginX = x;
-    m_deviceOriginY = y;
+    m_deviceOriginX = vX;
+    m_deviceOriginY = vY;
     ::GpiQueryPageViewport( m_hPS
                            ,&vRect
                           );
-    vRect.xLeft += x;
-    vRect.xRight += x;
-    vRect.yBottom -= y;
-    vRect.yTop -= y;
+    vRect.xLeft += vX;
+    vRect.xRight += vX;
+    vRect.yBottom -= vY;
+    vRect.yTop -= vY;
     ::GpiSetPageViewport( m_hPS
                          ,&vRect
                         );
-};
+}; // end of wxDC::SetDeviceOrigin
 
 // ---------------------------------------------------------------------------
 // coordinates transformations
@@ -1381,6 +1931,8 @@ bool wxDC::DoBlit(
 , wxCoord                           vYsrc
 , int                               nRop
 , bool                              bUseMask
+, wxCoord                           vXsrcMask
+, wxCoord                           vYsrcMask
 )
 {
     wxMask*                         pMask = NULL;
@@ -1463,14 +2015,10 @@ bool wxDC::DoBlit(
         HPS                             hPSBuffer;
         DEVOPENSTRUC                    vDOP = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
         BITMAPINFOHEADER2               vBmpHdr;
+        HBITMAP                         hBufBitmap;
         SIZEL                           vSize = {0, 0};
         LONG                            rc;
 
-        hDCMask = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
-        hDCBuffer = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
-        hPSMask = ::GpiCreatePS(vHabmain, hDCMask, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
-        hPSBuffer = ::GpiCreatePS(vHabmain, hDCBuffer, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
-
         memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
         vBmpHdr.cbFix     = sizeof(BITMAPINFOHEADER2);
         vBmpHdr.cx        = vWidth;
@@ -1478,7 +2026,37 @@ bool wxDC::DoBlit(
         vBmpHdr.cPlanes   = 1;
         vBmpHdr.cBitCount = 24;
 
-        HBITMAP                         hBufBitmap = ::GpiCreateBitmap(GetHPS(), &vBmpHdr, 0L, NULL, NULL);
+#if wxUSE_DC_CACHEING
+        if (TRUE)
+        {
+            //
+            // create a temp buffer bitmap and DCs to access it and the mask
+            //
+            wxDCCacheEntry*         pDCCacheEntry1    = FindDCInCache( NULL
+                                                                      ,pSource->GetHPS()
+                                                                     );
+            wxDCCacheEntry*         pDCCacheEntry2    = FindDCInCache( pDCCacheEntry1
+                                                                      ,GetHPS()
+                                                                     );
+            wxDCCacheEntry*         pBitmapCacheEntry = FindBitmapInCache( GetHPS()
+                                                                          ,vWidth
+                                                                          ,vHeight
+                                                                         );
+
+            hPSMask = pDCCacheEntry1->m_hPS;
+            hDCBuffer = (HDC)pDCCacheEntry2->m_hPS;
+            hBufBitmap = (HBITMAP)pBitmapCacheEntry->m_hBitmap;
+        }
+        else
+#endif
+        {
+            hDCMask = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
+            hDCBuffer = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
+            hPSMask = ::GpiCreatePS(vHabmain, hDCMask, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
+            hPSBuffer = ::GpiCreatePS(vHabmain, hDCBuffer, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
+            hBufBitmap = ::GpiCreateBitmap(GetHPS(), &vBmpHdr, 0L, NULL, NULL);
+        }
+
         POINTL                          aPoint1[4] = { 0, 0
                                                       ,vWidth, vHeight
                                                       ,vXdest, vYdest
@@ -1597,11 +2175,13 @@ bool wxDC::DoBlit(
         //
         ::GpiSetBitmap(hPSMask, NULLHANDLE);
         ::GpiSetBitmap(hPSBuffer, NULLHANDLE);
+#if !wxUSE_DC_CACHEING
         ::GpiDestroyPS(hPSMask);
         ::GpiDestroyPS(hPSBuffer);
         ::DevCloseDC(hDCMask);
         ::DevCloseDC(hDCBuffer);
         ::GpiDeleteBitmap(hBufBitmap);
+#endif
         bSuccess = TRUE;
     }
     else // no mask, just BitBlt() it
@@ -1635,28 +2215,86 @@ bool wxDC::DoBlit(
     return bSuccess;
 }
 
-void wxDC::DoGetSize( int* width, int* height ) const
+void wxDC::DoGetSize(
+  int*                              pnWidth
+, int*                              pnHeight
+) const
 {
-    // TODO:
-};
+    LONG                            lArray[CAPS_HEIGHT];
+
+    if(::DevQueryCaps( m_hDC
+                      ,CAPS_FAMILY
+                      ,CAPS_HEIGHT
+                      ,lArray
+                     ))
+    {
+        *pnWidth  = lArray[CAPS_WIDTH];
+        *pnHeight = lArray[CAPS_HEIGHT];
+    }
+}; // end of wxDC::DoGetSize(
 
-void wxDC::DoGetSizeMM( int* width, int* height ) const
+void wxDC::DoGetSizeMM(
+  int*                              pnWidth
+, int*                              pnHeight
+) const
 {
-    // TODO:
-};
+    LONG                            lArray[CAPS_VERTICAL_RESOLUTION];
+
+    if(::DevQueryCaps( m_hDC
+                      ,CAPS_FAMILY
+                      ,CAPS_VERTICAL_RESOLUTION
+                      ,lArray
+                     ))
+    {
+        int                         nWidth;
+        int                         nHeight;
+        int                         nHorzRes;
+        int                         nVertRes;
+
+        nWidth    = lArray[CAPS_WIDTH];
+        nHeight   = lArray[CAPS_HEIGHT];
+        nHorzRes  = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
+        nVertRes  = lArray[CAPS_VERTICAL_RESOLUTION];   // returns pel/meter
+        nWidth  = (nHorzRes/1000) * nWidth;
+        nHeight = (nVertRes/1000) * nHeight;
+    }
+}; // end of wxDC::DoGetSizeMM
 
 wxSize wxDC::GetPPI() const
 {
-   int x = 1;
-   int y = 1;
-   // TODO:
-   return (wxSize(x,y));
-}
+    LONG                            lArray[CAPS_VERTICAL_RESOLUTION];
+    int                             nWidth;
+    int                             nHeight;
+
+    if(::DevQueryCaps( m_hDC
+                      ,CAPS_FAMILY
+                      ,CAPS_VERTICAL_RESOLUTION
+                      ,lArray
+                     ))
+    {
+        int                         nPelWidth;
+        int                         nPelHeight;
+        int                         nHorzRes;
+        int                         nVertRes;
+
+        nPelWidth  = lArray[CAPS_WIDTH];
+        nPelHeight = lArray[CAPS_HEIGHT];
+        nHorzRes   = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
+        nVertRes   = lArray[CAPS_VERTICAL_RESOLUTION];   // returns pel/meter
+        nWidth   = (nHorzRes/39.3) * nPelWidth;
+        nHeight  = (nVertRes/39.3) * nPelHeight;
+    }
+    return (wxSize(nWidth,nHeight));
+} // end of wxDC::GetPPI
 
-void wxDC::SetLogicalScale( double x, double y )
+void wxDC::SetLogicalScale(
+  double                            dX
+, double                            dY
+)
 {
-    // TODO:
-};
+    m_logicalScaleX = dX;
+    m_logicalScaleY = dY;
+}; // end of wxDC::SetLogicalScale
 
 #if WXWIN_COMPATIBILITY
 void wxDC::DoGetTextExtent(const wxString& string, float *x, float *y,